aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAldo Cortesi <aldo@nullcube.com>2014-12-30 21:51:07 +1300
committerAldo Cortesi <aldo@nullcube.com>2014-12-30 21:51:07 +1300
commitbc8687deb5f0f9273fc771e79b070f3b49e39fed (patch)
tree07e67eb7c9f732c0419e57b337c31d2372d12cff
parentd2c7411f065435e2b2b62a70447cb01895fe69d1 (diff)
downloadmitmproxy-bc8687deb5f0f9273fc771e79b070f3b49e39fed.tar.gz
mitmproxy-bc8687deb5f0f9273fc771e79b070f3b49e39fed.tar.bz2
mitmproxy-bc8687deb5f0f9273fc771e79b070f3b49e39fed.zip
Basic conversion: browserified web app now works.
-rw-r--r--libmproxy/web/static/app.css (renamed from libmproxy/web/static/css/app.css)2
-rw-r--r--libmproxy/web/static/app.js3774
-rw-r--r--libmproxy/web/static/js/app.js4153
-rw-r--r--libmproxy/web/static/js/vendor.js39553
-rw-r--r--libmproxy/web/static/vendor.css (renamed from libmproxy/web/static/css/vendor.css)2
-rw-r--r--libmproxy/web/static/vendor.js40961
-rw-r--r--libmproxy/web/templates/index.html8
-rw-r--r--web/gulpfile.js320
-rw-r--r--web/gulpfile.old.js179
-rw-r--r--web/package.json27
-rw-r--r--web/src/fonts/fontawesome-webfont.eotbin0 -> 56006 bytes
-rw-r--r--web/src/fonts/fontawesome-webfont.svg520
-rw-r--r--web/src/fonts/fontawesome-webfont.ttfbin0 -> 112160 bytes
-rw-r--r--web/src/fonts/fontawesome-webfont.woffbin0 -> 65452 bytes
-rw-r--r--web/src/index.html11
-rw-r--r--web/src/js/actions.js6
-rw-r--r--web/src/js/app.js10
-rw-r--r--web/src/js/components/flowdetail.jsx.js4
-rw-r--r--web/src/js/components/flowtable-columns.jsx.js14
-rw-r--r--web/src/js/components/flowtable.jsx.js11
-rw-r--r--web/src/js/components/footer.jsx.js4
-rw-r--r--web/src/js/components/header.jsx.js16
-rw-r--r--web/src/js/components/mainview.jsx.js16
-rw-r--r--web/src/js/components/proxyapp.jsx.js28
-rw-r--r--web/src/js/components/utils.jsx.js14
-rw-r--r--web/src/js/components/virtualscroll.jsx.js6
-rw-r--r--web/src/js/connection.js14
-rw-r--r--web/src/js/dispatcher.js4
-rw-r--r--web/src/js/filt/filt.js10
-rw-r--r--web/src/js/flow/utils.js9
-rw-r--r--web/src/js/store/store.js38
-rw-r--r--web/src/js/store/view.js14
-rw-r--r--web/src/js/utils.js14
33 files changed, 45859 insertions, 43883 deletions
diff --git a/libmproxy/web/static/css/app.css b/libmproxy/web/static/app.css
index 554fffb1..b106b4bd 100644
--- a/libmproxy/web/static/css/app.css
+++ b/libmproxy/web/static/app.css
@@ -333,4 +333,4 @@ footer {
padding: 0px 10px 3px;
}
-/*# sourceMappingURL=../css/app.css.map */ \ No newline at end of file
+/*# sourceMappingURL=app.css.map */ \ No newline at end of file
diff --git a/libmproxy/web/static/app.js b/libmproxy/web/static/app.js
new file mode 100644
index 00000000..e21e3856
--- /dev/null
+++ b/libmproxy/web/static/app.js
@@ -0,0 +1,3774 @@
+(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+var ActionTypes = {
+ // Connection
+ CONNECTION_OPEN: "connection_open",
+ CONNECTION_CLOSE: "connection_close",
+ CONNECTION_ERROR: "connection_error",
+
+ // Stores
+ SETTINGS_STORE: "settings",
+ EVENT_STORE: "events",
+ FLOW_STORE: "flows",
+};
+
+var StoreCmds = {
+ ADD: "add",
+ UPDATE: "update",
+ REMOVE: "remove",
+ RESET: "reset"
+};
+
+var ConnectionActions = {
+ open: function () {
+ AppDispatcher.dispatchViewAction({
+ type: ActionTypes.CONNECTION_OPEN
+ });
+ },
+ close: function () {
+ AppDispatcher.dispatchViewAction({
+ type: ActionTypes.CONNECTION_CLOSE
+ });
+ },
+ error: function () {
+ AppDispatcher.dispatchViewAction({
+ type: ActionTypes.CONNECTION_ERROR
+ });
+ }
+};
+
+var SettingsActions = {
+ update: function (settings) {
+
+ jQuery.ajax({
+ type: "PUT",
+ url: "/settings",
+ data: settings
+ });
+
+ /*
+ //Facebook Flux: We do an optimistic update on the client already.
+ AppDispatcher.dispatchViewAction({
+ type: ActionTypes.SETTINGS_STORE,
+ cmd: StoreCmds.UPDATE,
+ data: settings
+ });
+ */
+ }
+};
+
+var EventLogActions_event_id = 0;
+var EventLogActions = {
+ add_event: function (message) {
+ AppDispatcher.dispatchViewAction({
+ type: ActionTypes.EVENT_STORE,
+ cmd: StoreCmds.ADD,
+ data: {
+ message: message,
+ level: "web",
+ id: "viewAction-" + EventLogActions_event_id++
+ }
+ });
+ }
+};
+
+var FlowActions = {
+ accept: function (flow) {
+ jQuery.post("/flows/" + flow.id + "/accept");
+ },
+ accept_all: function(){
+ jQuery.post("/flows/accept");
+ },
+ "delete": function(flow){
+ jQuery.ajax({
+ type:"DELETE",
+ url: "/flows/" + flow.id
+ });
+ },
+ duplicate: function(flow){
+ jQuery.post("/flows/" + flow.id + "/duplicate");
+ },
+ replay: function(flow){
+ jQuery.post("/flows/" + flow.id + "/replay");
+ },
+ revert: function(flow){
+ jQuery.post("/flows/" + flow.id + "/revert");
+ },
+ update: function (flow) {
+ AppDispatcher.dispatchViewAction({
+ type: ActionTypes.FLOW_STORE,
+ cmd: StoreCmds.UPDATE,
+ data: flow
+ });
+ },
+ clear: function(){
+ jQuery.post("/clear");
+ }
+};
+
+Query = {
+ FILTER: "f",
+ HIGHLIGHT: "h",
+ SHOW_EVENTLOG: "e"
+};
+
+module.exports = {
+ ActionTypes: ActionTypes,
+ ConnectionActions: ConnectionActions
+
+};
+},{}],2:[function(require,module,exports){
+
+var React = require("react");
+var ReactRouter = require("react-router");
+var $ = require("jquery");
+
+var Connection = require("./connection");
+var proxyapp = require("./components/proxyapp.jsx.js");
+
+$(function () {
+ window.ws = new Connection("/updates");
+
+ ReactRouter.run(proxyapp.routes, function (Handler) {
+ React.render(React.createElement(Handler, null), document.body);
+ });
+});
+},{"./components/proxyapp.jsx.js":8,"./connection":11,"jquery":"jquery","react":"react","react-router":"react-router"}],3:[function(require,module,exports){
+var React = require("react");
+var flowutils = require("../flow/utils.js");
+var utils = require("../utils.js");
+
+var TLSColumn = React.createClass({displayName: "TLSColumn",
+ statics: {
+ renderTitle: function () {
+ return React.createElement("th", {key: "tls", className: "col-tls"});
+ }
+ },
+ render: function () {
+ var flow = this.props.flow;
+ var ssl = (flow.request.scheme == "https");
+ var classes;
+ if (ssl) {
+ classes = "col-tls col-tls-https";
+ } else {
+ classes = "col-tls col-tls-http";
+ }
+ return React.createElement("td", {className: classes});
+ }
+});
+
+
+var IconColumn = React.createClass({displayName: "IconColumn",
+ statics: {
+ renderTitle: function () {
+ return React.createElement("th", {key: "icon", className: "col-icon"});
+ }
+ },
+ render: function () {
+ var flow = this.props.flow;
+
+ var icon;
+ if (flow.response) {
+ var contentType = flowutils.ResponseUtils.getContentType(flow.response);
+
+ //TODO: We should assign a type to the flow somewhere else.
+ if (flow.response.code == 304) {
+ icon = "resource-icon-not-modified";
+ } else if (300 <= flow.response.code && flow.response.code < 400) {
+ icon = "resource-icon-redirect";
+ } else if (contentType && contentType.indexOf("image") >= 0) {
+ icon = "resource-icon-image";
+ } else if (contentType && contentType.indexOf("javascript") >= 0) {
+ icon = "resource-icon-js";
+ } else if (contentType && contentType.indexOf("css") >= 0) {
+ icon = "resource-icon-css";
+ } else if (contentType && contentType.indexOf("html") >= 0) {
+ icon = "resource-icon-document";
+ }
+ }
+ if (!icon) {
+ icon = "resource-icon-plain";
+ }
+
+
+ icon += " resource-icon";
+ return React.createElement("td", {className: "col-icon"},
+ React.createElement("div", {className: icon})
+ );
+ }
+});
+
+var PathColumn = React.createClass({displayName: "PathColumn",
+ statics: {
+ renderTitle: function () {
+ return React.createElement("th", {key: "path", className: "col-path"}, "Path");
+ }
+ },
+ render: function () {
+ var flow = this.props.flow;
+ return React.createElement("td", {className: "col-path"},
+ flow.request.is_replay ? React.createElement("i", {className: "fa fa-fw fa-repeat pull-right"}) : null,
+ flow.intercepted ? React.createElement("i", {className: "fa fa-fw fa-pause pull-right"}) : null,
+ flow.request.scheme + "://" + flow.request.host + flow.request.path
+ );
+ }
+});
+
+
+var MethodColumn = React.createClass({displayName: "MethodColumn",
+ statics: {
+ renderTitle: function () {
+ return React.createElement("th", {key: "method", className: "col-method"}, "Method");
+ }
+ },
+ render: function () {
+ var flow = this.props.flow;
+ return React.createElement("td", {className: "col-method"}, flow.request.method);
+ }
+});
+
+
+var StatusColumn = React.createClass({displayName: "StatusColumn",
+ statics: {
+ renderTitle: function () {
+ return React.createElement("th", {key: "status", className: "col-status"}, "Status");
+ }
+ },
+ render: function () {
+ var flow = this.props.flow;
+ var status;
+ if (flow.response) {
+ status = flow.response.code;
+ } else {
+ status = null;
+ }
+ return React.createElement("td", {className: "col-status"}, status);
+ }
+});
+
+
+var SizeColumn = React.createClass({displayName: "SizeColumn",
+ statics: {
+ renderTitle: function () {
+ return React.createElement("th", {key: "size", className: "col-size"}, "Size");
+ }
+ },
+ render: function () {
+ var flow = this.props.flow;
+
+ var total = flow.request.contentLength;
+ if (flow.response) {
+ total += flow.response.contentLength || 0;
+ }
+ var size = utils.formatSize(total);
+ return React.createElement("td", {className: "col-size"}, size);
+ }
+});
+
+
+var TimeColumn = React.createClass({displayName: "TimeColumn",
+ statics: {
+ renderTitle: function () {
+ return React.createElement("th", {key: "time", className: "col-time"}, "Time");
+ }
+ },
+ render: function () {
+ var flow = this.props.flow;
+ var time;
+ if (flow.response) {
+ time = utils.formatTimeDelta(1000 * (flow.response.timestamp_end - flow.request.timestamp_start));
+ } else {
+ time = "...";
+ }
+ return React.createElement("td", {className: "col-time"}, time);
+ }
+});
+
+
+var all_columns = [
+ TLSColumn,
+ IconColumn,
+ PathColumn,
+ MethodColumn,
+ StatusColumn,
+ SizeColumn,
+ TimeColumn];
+
+
+module.exports = all_columns;
+
+
+
+},{"../flow/utils.js":14,"../utils.js":17,"react":"react"}],4:[function(require,module,exports){
+var React = require("react");
+var utils = require("./utils.jsx.js");
+var VirtualScrollMixin = require("./virtualscroll.jsx.js");
+var flowtable_columns = require("./flowtable-columns.jsx.js");
+
+var FlowRow = React.createClass({displayName: "FlowRow",
+ render: function () {
+ var flow = this.props.flow;
+ var columns = this.props.columns.map(function (Column) {
+ return React.createElement(Column, {key: Column.displayName, flow: flow});
+ }.bind(this));
+ var className = "";
+ if (this.props.selected) {
+ className += " selected";
+ }
+ if (this.props.highlighted) {
+ className += " highlighted";
+ }
+ if (flow.intercepted) {
+ className += " intercepted";
+ }
+ if (flow.request) {
+ className += " has-request";
+ }
+ if (flow.response) {
+ className += " has-response";
+ }
+
+ return (
+ React.createElement("tr", {className: className, onClick: this.props.selectFlow.bind(null, flow)},
+ columns
+ ));
+ },
+ shouldComponentUpdate: function (nextProps) {
+ return true;
+ // Further optimization could be done here
+ // by calling forceUpdate on flow updates, selection changes and column changes.
+ //return (
+ //(this.props.columns.length !== nextProps.columns.length) ||
+ //(this.props.selected !== nextProps.selected)
+ //);
+ }
+});
+
+var FlowTableHead = React.createClass({displayName: "FlowTableHead",
+ render: function () {
+ var columns = this.props.columns.map(function (column) {
+ return column.renderTitle();
+ }.bind(this));
+ return React.createElement("thead", null,
+ React.createElement("tr", null, columns)
+ );
+ }
+});
+
+
+var ROW_HEIGHT = 32;
+
+var FlowTable = React.createClass({displayName: "FlowTable",
+ mixins: [utils.StickyHeadMixin, utils.AutoScrollMixin, VirtualScrollMixin],
+ getInitialState: function () {
+ return {
+ columns: flowtable_columns
+ };
+ },
+ componentWillMount: function () {
+ if (this.props.view) {
+ this.props.view.addListener("add update remove recalculate", this.onChange);
+ }
+ },
+ componentWillReceiveProps: function (nextProps) {
+ if (nextProps.view !== this.props.view) {
+ if (this.props.view) {
+ this.props.view.removeListener("add update remove recalculate");
+ }
+ nextProps.view.addListener("add update remove recalculate", this.onChange);
+ }
+ },
+ getDefaultProps: function () {
+ return {
+ rowHeight: ROW_HEIGHT
+ };
+ },
+ onScrollFlowTable: function () {
+ this.adjustHead();
+ this.onScroll();
+ },
+ onChange: function () {
+ this.forceUpdate();
+ },
+ scrollIntoView: function (flow) {
+ this.scrollRowIntoView(
+ this.props.view.index(flow),
+ this.refs.body.getDOMNode().offsetTop
+ );
+ },
+ renderRow: function (flow) {
+ var selected = (flow === this.props.selected);
+ var highlighted =
+ (
+ this.props.view._highlight &&
+ this.props.view._highlight[flow.id]
+ );
+
+ return React.createElement(FlowRow, {key: flow.id,
+ ref: flow.id,
+ flow: flow,
+ columns: this.state.columns,
+ selected: selected,
+ highlighted: highlighted,
+ selectFlow: this.props.selectFlow}
+ );
+ },
+ render: function () {
+ //console.log("render flowtable", this.state.start, this.state.stop, this.props.selected);
+ var flows = this.props.view ? this.props.view.list : [];
+
+ var rows = this.renderRows(flows);
+
+ return (
+ React.createElement("div", {className: "flow-table", onScroll: this.onScrollFlowTable},
+ React.createElement("table", null,
+ React.createElement(FlowTableHead, {ref: "head",
+ columns: this.state.columns}),
+ React.createElement("tbody", {ref: "body"},
+ this.getPlaceholderTop(flows.length),
+ rows,
+ this.getPlaceholderBottom(flows.length)
+ )
+ )
+ )
+ );
+ }
+});
+
+module.exports = FlowTable;
+
+},{"./flowtable-columns.jsx.js":3,"./utils.jsx.js":9,"./virtualscroll.jsx.js":10,"react":"react"}],5:[function(require,module,exports){
+var React = require("react");
+
+var Footer = React.createClass({displayName: "Footer",
+ render: function () {
+ var mode = this.props.settings.mode;
+ var intercept = this.props.settings.intercept;
+ return (
+ React.createElement("footer", null,
+ mode != "regular" ? React.createElement("span", {className: "label label-success"}, mode, " mode") : null,
+ " ",
+ intercept ? React.createElement("span", {className: "label label-success"}, "Intercept: ", intercept) : null
+ )
+ );
+ }
+});
+
+module.exports = Footer;
+},{"react":"react"}],6:[function(require,module,exports){
+var React = require("react");
+var $ = require("jquery");
+
+var utils = require("./utils.jsx.js");
+
+var FilterDocs = React.createClass({displayName: "FilterDocs",
+ statics: {
+ xhr: false,
+ doc: false
+ },
+ componentWillMount: function () {
+ if (!FilterDocs.doc) {
+ FilterDocs.xhr = $.getJSON("/filter-help").done(function (doc) {
+ FilterDocs.doc = doc;
+ FilterDocs.xhr = false;
+ });
+ }
+ if (FilterDocs.xhr) {
+ FilterDocs.xhr.done(function () {
+ this.forceUpdate();
+ }.bind(this));
+ }
+ },
+ render: function () {
+ if (!FilterDocs.doc) {
+ return React.createElement("i", {className: "fa fa-spinner fa-spin"});
+ } else {
+ var commands = FilterDocs.doc.commands.map(function (c) {
+ return React.createElement("tr", null,
+ React.createElement("td", null, c[0].replace(" ", '\u00a0')),
+ React.createElement("td", null, c[1])
+ );
+ });
+ commands.push(React.createElement("tr", null,
+ React.createElement("td", {colSpan: "2"},
+ React.createElement("a", {href: "https://mitmproxy.org/doc/features/filters.html",
+ target: "_blank"},
+ React.createElement("i", {className: "fa fa-external-link"}),
+ "  mitmproxy docs")
+ )
+ ));
+ return React.createElement("table", {className: "table table-condensed"},
+ React.createElement("tbody", null, commands)
+ );
+ }
+ }
+});
+var FilterInput = React.createClass({displayName: "FilterInput",
+ getInitialState: function () {
+ // Consider both focus and mouseover for showing/hiding the tooltip,
+ // because onBlur of the input is triggered before the click on the tooltip
+ // finalized, hiding the tooltip just as the user clicks on it.
+ return {
+ value: this.props.value,
+ focus: false,
+ mousefocus: false
+ };
+ },
+ componentWillReceiveProps: function (nextProps) {
+ this.setState({value: nextProps.value});
+ },
+ onChange: function (e) {
+ var nextValue = e.target.value;
+ this.setState({
+ value: nextValue
+ });
+ // Only propagate valid filters upwards.
+ if (this.isValid(nextValue)) {
+ this.props.onChange(nextValue);
+ }
+ },
+ isValid: function (filt) {
+ try {
+ Filt.parse(filt || this.state.value);
+ return true;
+ } catch (e) {
+ return false;
+ }
+ },
+ getDesc: function () {
+ var desc;
+ try {
+ desc = Filt.parse(this.state.value).desc;
+ } catch (e) {
+ desc = "" + e;
+ }
+ if (desc !== "true") {
+ return desc;
+ } else {
+ return (
+ React.createElement(FilterDocs, null)
+ );
+ }
+ },
+ onFocus: function () {
+ this.setState({focus: true});
+ },
+ onBlur: function () {
+ this.setState({focus: false});
+ },
+ onMouseEnter: function () {
+ this.setState({mousefocus: true});
+ },
+ onMouseLeave: function () {
+ this.setState({mousefocus: false});
+ },
+ onKeyDown: function (e) {
+ if (e.keyCode === Key.ESC || e.keyCode === Key.ENTER) {
+ this.blur();
+ // If closed using ESC/ENTER, hide the tooltip.
+ this.setState({mousefocus: false});
+ }
+ },
+ blur: function () {
+ this.refs.input.getDOMNode().blur();
+ },
+ focus: function () {
+ this.refs.input.getDOMNode().select();
+ },
+ render: function () {
+ var isValid = this.isValid();
+ var icon = "fa fa-fw fa-" + this.props.type;
+ var groupClassName = "filter-input input-group" + (isValid ? "" : " has-error");
+
+ var popover;
+ if (this.state.focus || this.state.mousefocus) {
+ popover = (
+ React.createElement("div", {className: "popover bottom", onMouseEnter: this.onMouseEnter, onMouseLeave: this.onMouseLeave},
+ React.createElement("div", {className: "arrow"}),
+ React.createElement("div", {className: "popover-content"},
+ this.getDesc()
+ )
+ )
+ );
+ }
+
+ return (
+ React.createElement("div", {className: groupClassName},
+ React.createElement("span", {className: "input-group-addon"},
+ React.createElement("i", {className: icon, style: {color: this.props.color}})
+ ),
+ React.createElement("input", {type: "text", placeholder: this.props.placeholder, className: "form-control",
+ ref: "input",
+ onChange: this.onChange,
+ onFocus: this.onFocus,
+ onBlur: this.onBlur,
+ onKeyDown: this.onKeyDown,
+ value: this.state.value}),
+ popover
+ )
+ );
+ }
+});
+
+var MainMenu = React.createClass({displayName: "MainMenu",
+ mixins: [utils.Navigation, utils.State],
+ statics: {
+ title: "Start",
+ route: "flows"
+ },
+ onFilterChange: function (val) {
+ var d = {};
+ d[Query.FILTER] = val;
+ this.setQuery(d);
+ },
+ onHighlightChange: function (val) {
+ var d = {};
+ d[Query.HIGHLIGHT] = val;
+ this.setQuery(d);
+ },
+ onInterceptChange: function (val) {
+ SettingsActions.update({intercept: val});
+ },
+ render: function () {
+ var filter = this.getQuery()[Query.FILTER] || "";
+ var highlight = this.getQuery()[Query.HIGHLIGHT] || "";
+ var intercept = this.props.settings.intercept || "";
+
+ return (
+ React.createElement("div", null,
+ React.createElement("div", {className: "menu-row"},
+ React.createElement(FilterInput, {
+ placeholder: "Filter",
+ type: "filter",
+ color: "black",
+ value: filter,
+ onChange: this.onFilterChange}),
+ React.createElement(FilterInput, {
+ placeholder: "Highlight",
+ type: "tag",
+ color: "hsl(48, 100%, 50%)",
+ value: highlight,
+ onChange: this.onHighlightChange}),
+ React.createElement(FilterInput, {
+ placeholder: "Intercept",
+ type: "pause",
+ color: "hsl(208, 56%, 53%)",
+ value: intercept,
+ onChange: this.onInterceptChange})
+ ),
+ React.createElement("div", {className: "clearfix"})
+ )
+ );
+ }
+});
+
+
+var ViewMenu = React.createClass({displayName: "ViewMenu",
+ statics: {
+ title: "View",
+ route: "flows"
+ },
+ mixins: [utils.Navigation, utils.State],
+ toggleEventLog: function () {
+ var d = {};
+
+ if (this.getQuery()[Query.SHOW_EVENTLOG]) {
+ d[Query.SHOW_EVENTLOG] = undefined;
+ } else {
+ d[Query.SHOW_EVENTLOG] = "t"; // any non-false value will do it, keep it short
+ }
+
+ this.setQuery(d);
+ },
+ render: function () {
+ var showEventLog = this.getQuery()[Query.SHOW_EVENTLOG];
+ return (
+ React.createElement("div", null,
+ React.createElement("button", {
+ className: "btn " + (showEventLog ? "btn-primary" : "btn-default"),
+ onClick: this.toggleEventLog},
+ React.createElement("i", {className: "fa fa-database"}),
+ " Show Eventlog"
+ ),
+ React.createElement("span", null, " ")
+ )
+ );
+ }
+});
+
+
+var ReportsMenu = React.createClass({displayName: "ReportsMenu",
+ statics: {
+ title: "Visualization",
+ route: "reports"
+ },
+ render: function () {
+ return React.createElement("div", null, "Reports Menu");
+ }
+});
+
+var FileMenu = React.createClass({displayName: "FileMenu",
+ getInitialState: function () {
+ return {
+ showFileMenu: false
+ };
+ },
+ handleFileClick: function (e) {
+ e.preventDefault();
+ if (!this.state.showFileMenu) {
+ var close = function () {
+ this.setState({showFileMenu: false});
+ document.removeEventListener("click", close);
+ }.bind(this);
+ document.addEventListener("click", close);
+
+ this.setState({
+ showFileMenu: true
+ });
+ }
+ },
+ handleNewClick: function (e) {
+ e.preventDefault();
+ if (confirm("Delete all flows?")) {
+ FlowActions.clear();
+ }
+ },
+ handleOpenClick: function (e) {
+ e.preventDefault();
+ console.error("unimplemented: handleOpenClick");
+ },
+ handleSaveClick: function (e) {
+ e.preventDefault();
+ console.error("unimplemented: handleSaveClick");
+ },
+ handleShutdownClick: function (e) {
+ e.preventDefault();
+ console.error("unimplemented: handleShutdownClick");
+ },
+ render: function () {
+ var fileMenuClass = "dropdown pull-left" + (this.state.showFileMenu ? " open" : "");
+
+ return (
+ React.createElement("div", {className: fileMenuClass},
+ React.createElement("a", {href: "#", className: "special", onClick: this.handleFileClick}, " File "),
+ React.createElement("ul", {className: "dropdown-menu", role: "menu"},
+ React.createElement("li", null,
+ React.createElement("a", {href: "#", onClick: this.handleNewClick},
+ React.createElement("i", {className: "fa fa-fw fa-file"}),
+ "New"
+ )
+ ),
+ React.createElement("li", {role: "presentation", className: "divider"}),
+ React.createElement("li", null,
+ React.createElement("a", {href: "http://mitm.it/", target: "_blank"},
+ React.createElement("i", {className: "fa fa-fw fa-external-link"}),
+ "Install Certificates..."
+ )
+ )
+ /*
+ <li>
+ <a href="#" onClick={this.handleOpenClick}>
+ <i className="fa fa-fw fa-folder-open"></i>
+ Open
+ </a>
+ </li>
+ <li>
+ <a href="#" onClick={this.handleSaveClick}>
+ <i className="fa fa-fw fa-save"></i>
+ Save
+ </a>
+ </li>
+ <li role="presentation" className="divider"></li>
+ <li>
+ <a href="#" onClick={this.handleShutdownClick}>
+ <i className="fa fa-fw fa-plug"></i>
+ Shutdown
+ </a>
+ </li>
+ */
+ )
+ )
+ );
+ }
+});
+
+
+var header_entries = [MainMenu, ViewMenu /*, ReportsMenu */];
+
+
+var Header = React.createClass({displayName: "Header",
+ mixins: [utils.Navigation],
+ getInitialState: function () {
+ return {
+ active: header_entries[0]
+ };
+ },
+ handleClick: function (active, e) {
+ e.preventDefault();
+ this.replaceWith(active.route);
+ this.setState({active: active});
+ },
+ render: function () {
+ var header = header_entries.map(function (entry, i) {
+ var classes = React.addons.classSet({
+ active: entry == this.state.active
+ });
+ return (
+ React.createElement("a", {key: i,
+ href: "#",
+ className: classes,
+ onClick: this.handleClick.bind(this, entry)
+ },
+ entry.title
+ )
+ );
+ }.bind(this));
+
+ return (
+ React.createElement("header", null,
+ React.createElement("div", {className: "title-bar"},
+ "mitmproxy ", this.props.settings.version
+ ),
+ React.createElement("nav", {className: "nav-tabs nav-tabs-lg"},
+ React.createElement(FileMenu, null),
+ header
+ ),
+ React.createElement("div", {className: "menu"},
+ React.createElement(this.state.active, {settings: this.props.settings})
+ )
+ )
+ );
+ }
+});
+
+
+module.exports = {
+ Header: Header
+}
+},{"./utils.jsx.js":9,"jquery":"jquery","react":"react"}],7:[function(require,module,exports){
+var React = require("react");
+
+var utils = require("./utils.jsx.js");
+var views = require("../store/view.js");
+var Filt = require("../filt/filt.js");
+FlowTable = require("./flowtable.jsx.js");
+
+
+var MainView = React.createClass({displayName: "MainView",
+ mixins: [utils.Navigation, utils.State],
+ getInitialState: function () {
+ this.onQueryChange(Query.FILTER, function () {
+ this.state.view.recalculate(this.getViewFilt(), this.getViewSort());
+ }.bind(this));
+ this.onQueryChange(Query.HIGHLIGHT, function () {
+ this.state.view.recalculate(this.getViewFilt(), this.getViewSort());
+ }.bind(this));
+ return {
+ flows: []
+ };
+ },
+ getViewFilt: function () {
+ try {
+ var filt = Filt.parse(this.getQuery()[Query.FILTER] || "");
+ var highlightStr = this.getQuery()[Query.HIGHLIGHT];
+ var highlight = highlightStr ? Filt.parse(highlightStr) : false;
+ } catch (e) {
+ console.error("Error when processing filter: " + e);
+ }
+
+ return function filter_and_highlight(flow) {
+ if (!this._highlight) {
+ this._highlight = {};
+ }
+ this._highlight[flow.id] = highlight && highlight(flow);
+ return filt(flow);
+ };
+ },
+ getViewSort: function () {
+ },
+ componentWillReceiveProps: function (nextProps) {
+ if (nextProps.flowStore !== this.props.flowStore) {
+ this.closeView();
+ this.openView(nextProps.flowStore);
+ }
+ },
+ openView: function (store) {
+ var view = new views.StoreView(store, this.getViewFilt(), this.getViewSort());
+ this.setState({
+ view: view
+ });
+
+ view.addListener("recalculate", this.onRecalculate);
+ view.addListener("add update remove", this.onUpdate);
+ view.addListener("remove", this.onRemove);
+ },
+ onRecalculate: function () {
+ this.forceUpdate();
+ var selected = this.getSelected();
+ if (selected) {
+ this.refs.flowTable.scrollIntoView(selected);
+ }
+ },
+ onUpdate: function (flow) {
+ if (flow.id === this.getParams().flowId) {
+ this.forceUpdate();
+ }
+ },
+ onRemove: function (flow_id, index) {
+ if (flow_id === this.getParams().flowId) {
+ var flow_to_select = this.state.view.list[Math.min(index, this.state.view.list.length -1)];
+ this.selectFlow(flow_to_select);
+ }
+ },
+ closeView: function () {
+ this.state.view.close();
+ },
+ componentWillMount: function () {
+ this.openView(this.props.flowStore);
+ },
+ componentWillUnmount: function () {
+ this.closeView();
+ },
+ selectFlow: function (flow) {
+ if (flow) {
+ this.replaceWith(
+ "flow",
+ {
+ flowId: flow.id,
+ detailTab: this.getParams().detailTab || "request"
+ }
+ );
+ this.refs.flowTable.scrollIntoView(flow);
+ } else {
+ this.replaceWith("flows", {});
+ }
+ },
+ selectFlowRelative: function (shift) {
+ var flows = this.state.view.list;
+ var index;
+ if (!this.getParams().flowId) {
+ if (shift > 0) {
+ index = flows.length - 1;
+ } else {
+ index = 0;
+ }
+ } else {
+ var currFlowId = this.getParams().flowId;
+ var i = flows.length;
+ while (i--) {
+ if (flows[i].id === currFlowId) {
+ index = i;
+ break;
+ }
+ }
+ index = Math.min(
+ Math.max(0, index + shift),
+ flows.length - 1);
+ }
+ this.selectFlow(flows[index]);
+ },
+ onKeyDown: function (e) {
+ var flow = this.getSelected();
+ if (e.ctrlKey) {
+ return;
+ }
+ switch (e.keyCode) {
+ case Key.K:
+ case Key.UP:
+ this.selectFlowRelative(-1);
+ break;
+ case Key.J:
+ case Key.DOWN:
+ this.selectFlowRelative(+1);
+ break;
+ case Key.SPACE:
+ case Key.PAGE_DOWN:
+ this.selectFlowRelative(+10);
+ break;
+ case Key.PAGE_UP:
+ this.selectFlowRelative(-10);
+ break;
+ case Key.END:
+ this.selectFlowRelative(+1e10);
+ break;
+ case Key.HOME:
+ this.selectFlowRelative(-1e10);
+ break;
+ case Key.ESC:
+ this.selectFlow(null);
+ break;
+ case Key.H:
+ case Key.LEFT:
+ if (this.refs.flowDetails) {
+ this.refs.flowDetails.nextTab(-1);
+ }
+ break;
+ case Key.L:
+ case Key.TAB:
+ case Key.RIGHT:
+ if (this.refs.flowDetails) {
+ this.refs.flowDetails.nextTab(+1);
+ }
+ break;
+ case Key.C:
+ if (e.shiftKey) {
+ FlowActions.clear();
+ }
+ break;
+ case Key.D:
+ if (flow) {
+ if (e.shiftKey) {
+ FlowActions.duplicate(flow);
+ } else {
+ FlowActions.delete(flow);
+ }
+ }
+ break;
+ case Key.A:
+ if (e.shiftKey) {
+ FlowActions.accept_all();
+ } else if (flow && flow.intercepted) {
+ FlowActions.accept(flow);
+ }
+ break;
+ case Key.R:
+ if (!e.shiftKey && flow) {
+ FlowActions.replay(flow);
+ }
+ break;
+ case Key.V:
+ if(e.shiftKey && flow && flow.modified) {
+ FlowActions.revert(flow);
+ }
+ break;
+ default:
+ console.debug("keydown", e.keyCode);
+ return;
+ }
+ e.preventDefault();
+ },
+ getSelected: function () {
+ return this.props.flowStore.get(this.getParams().flowId);
+ },
+ render: function () {
+ var selected = this.getSelected();
+
+ var details;
+ if (selected) {
+ details = [
+ React.createElement(Splitter, {key: "splitter"}),
+ React.createElement(FlowDetail, {key: "flowDetails", ref: "flowDetails", flow: selected})
+ ];
+ } else {
+ details = null;
+ }
+
+ return (
+ React.createElement("div", {className: "main-view", onKeyDown: this.onKeyDown, tabIndex: "0"},
+ React.createElement(FlowTable, {ref: "flowTable",
+ view: this.state.view,
+ selectFlow: this.selectFlow,
+ selected: selected}),
+ details
+ )
+ );
+ }
+});
+
+module.exports = MainView;
+
+},{"../filt/filt.js":13,"../store/view.js":16,"./flowtable.jsx.js":4,"./utils.jsx.js":9,"react":"react"}],8:[function(require,module,exports){
+var React = require("react");
+var ReactRouter = require("react-router");
+var _ = require("lodash");
+
+var utils = require("./utils.jsx.js");
+var MainView = require("./mainview.jsx.js");
+var Footer = require("./footer.jsx.js");
+var header = require("./header.jsx.js");
+var store = require("../store/store.js");
+
+
+//TODO: Move out of here, just a stub.
+var Reports = React.createClass({displayName: "Reports",
+ render: function () {
+ return React.createElement("div", null, "ReportEditor");
+ }
+});
+
+
+var ProxyAppMain = React.createClass({displayName: "ProxyAppMain",
+ mixins: [utils.State],
+ getInitialState: function () {
+ var eventStore = new store.EventLogStore();
+ var flowStore = new store.FlowStore();
+ var settings = new store.SettingsStore();
+
+ // Default Settings before fetch
+ _.extend(settings.dict,{
+ });
+ return {
+ settings: settings,
+ flowStore: flowStore,
+ eventStore: eventStore
+ };
+ },
+ componentDidMount: function () {
+ this.state.settings.addListener("recalculate", this.onSettingsChange);
+ window.app = this;
+ },
+ componentWillUnmount: function () {
+ this.state.settings.removeListener("recalculate", this.onSettingsChange);
+ },
+ onSettingsChange: function(){
+ this.setState({
+ settings: this.state.settings
+ });
+ },
+ render: function () {
+
+ var eventlog;
+ if (this.getQuery()[Query.SHOW_EVENTLOG]) {
+ eventlog = [
+ React.createElement(Splitter, {key: "splitter", axis: "y"}),
+ React.createElement(EventLog, {key: "eventlog", eventStore: this.state.eventStore})
+ ];
+ } else {
+ eventlog = null;
+ }
+
+ return (
+ React.createElement("div", {id: "container"},
+ React.createElement(header.Header, {settings: this.state.settings.dict}),
+ React.createElement(RouteHandler, {settings: this.state.settings.dict, flowStore: this.state.flowStore}),
+ eventlog,
+ React.createElement(Footer, {settings: this.state.settings.dict})
+ )
+ );
+ }
+});
+
+
+var Route = ReactRouter.Route;
+var RouteHandler = ReactRouter.RouteHandler;
+var Redirect = ReactRouter.Redirect;
+var DefaultRoute = ReactRouter.DefaultRoute;
+var NotFoundRoute = ReactRouter.NotFoundRoute;
+
+
+var routes = (
+ React.createElement(Route, {path: "/", handler: ProxyAppMain},
+ React.createElement(Route, {name: "flows", path: "flows", handler: MainView}),
+ React.createElement(Route, {name: "flow", path: "flows/:flowId/:detailTab", handler: MainView}),
+ React.createElement(Route, {name: "reports", handler: Reports}),
+ React.createElement(Redirect, {path: "/", to: "flows"})
+ )
+);
+
+module.exports = {
+ routes: routes
+};
+
+
+},{"../store/store.js":15,"./footer.jsx.js":5,"./header.jsx.js":6,"./mainview.jsx.js":7,"./utils.jsx.js":9,"lodash":"lodash","react":"react","react-router":"react-router"}],9:[function(require,module,exports){
+var React = require("react");
+var ReactRouter = require("react-router");
+var _ = require("lodash");
+
+//React utils. For other utilities, see ../utils.js
+
+// http://blog.vjeux.com/2013/javascript/scroll-position-with-react.html (also contains inverse example)
+var AutoScrollMixin = {
+ componentWillUpdate: function () {
+ var node = this.getDOMNode();
+ this._shouldScrollBottom = (
+ node.scrollTop !== 0 &&
+ node.scrollTop + node.clientHeight === node.scrollHeight
+ );
+ },
+ componentDidUpdate: function () {
+ if (this._shouldScrollBottom) {
+ var node = this.getDOMNode();
+ node.scrollTop = node.scrollHeight;
+ }
+ },
+};
+
+
+var StickyHeadMixin = {
+ adjustHead: function () {
+ // Abusing CSS transforms to set the element
+ // referenced as head into some kind of position:sticky.
+ var head = this.refs.head.getDOMNode();
+ head.style.transform = "translate(0," + this.getDOMNode().scrollTop + "px)";
+ }
+};
+
+
+var Navigation = _.extend({}, ReactRouter.Navigation, {
+ setQuery: function (dict) {
+ var q = this.context.getCurrentQuery();
+ for(var i in dict){
+ if(dict.hasOwnProperty(i)){
+ q[i] = dict[i] || undefined; //falsey values shall be removed.
+ }
+ }
+ q._ = "_"; // workaround for https://github.com/rackt/react-router/pull/599
+ this.replaceWith(this.context.getCurrentPath(), this.context.getCurrentParams(), q);
+ },
+ replaceWith: function(routeNameOrPath, params, query) {
+ if(routeNameOrPath === undefined){
+ routeNameOrPath = this.context.getCurrentPath();
+ }
+ if(params === undefined){
+ params = this.context.getCurrentParams();
+ }
+ if(query === undefined){
+ query = this.context.getCurrentQuery();
+ }
+ ReactRouter.Navigation.replaceWith.call(this, routeNameOrPath, params, query);
+ }
+});
+_.extend(Navigation.contextTypes, ReactRouter.State.contextTypes);
+
+var State = _.extend({}, ReactRouter.State, {
+ getInitialState: function () {
+ this._query = this.context.getCurrentQuery();
+ this._queryWatches = [];
+ return null;
+ },
+ onQueryChange: function (key, callback) {
+ this._queryWatches.push({
+ key: key,
+ callback: callback
+ });
+ },
+ componentWillReceiveProps: function (nextProps, nextState) {
+ var q = this.context.getCurrentQuery();
+ for (var i = 0; i < this._queryWatches.length; i++) {
+ var watch = this._queryWatches[i];
+ if (this._query[watch.key] !== q[watch.key]) {
+ watch.callback(this._query[watch.key], q[watch.key], watch.key);
+ }
+ }
+ this._query = q;
+ }
+});
+
+var Splitter = React.createClass({displayName: "Splitter",
+ getDefaultProps: function () {
+ return {
+ axis: "x"
+ };
+ },
+ getInitialState: function () {
+ return {
+ applied: false,
+ startX: false,
+ startY: false
+ };
+ },
+ onMouseDown: function (e) {
+ this.setState({
+ startX: e.pageX,
+ startY: e.pageY
+ });
+ window.addEventListener("mousemove", this.onMouseMove);
+ window.addEventListener("mouseup", this.onMouseUp);
+ // Occasionally, only a dragEnd event is triggered, but no mouseUp.
+ window.addEventListener("dragend", this.onDragEnd);
+ },
+ onDragEnd: function () {
+ this.getDOMNode().style.transform = "";
+ window.removeEventListener("dragend", this.onDragEnd);
+ window.removeEventListener("mouseup", this.onMouseUp);
+ window.removeEventListener("mousemove", this.onMouseMove);
+ },
+ onMouseUp: function (e) {
+ this.onDragEnd();
+
+ var node = this.getDOMNode();
+ var prev = node.previousElementSibling;
+ var next = node.nextElementSibling;
+
+ var dX = e.pageX - this.state.startX;
+ var dY = e.pageY - this.state.startY;
+ var flexBasis;
+ if (this.props.axis === "x") {
+ flexBasis = prev.offsetWidth + dX;
+ } else {
+ flexBasis = prev.offsetHeight + dY;
+ }
+
+ prev.style.flex = "0 0 " + Math.max(0, flexBasis) + "px";
+ next.style.flex = "1 1 auto";
+
+ this.setState({
+ applied: true
+ });
+ this.onResize();
+ },
+ onMouseMove: function (e) {
+ var dX = 0, dY = 0;
+ if (this.props.axis === "x") {
+ dX = e.pageX - this.state.startX;
+ } else {
+ dY = e.pageY - this.state.startY;
+ }
+ this.getDOMNode().style.transform = "translate(" + dX + "px," + dY + "px)";
+ },
+ onResize: function () {
+ // Trigger a global resize event. This notifies components that employ virtual scrolling
+ // that their viewport may have changed.
+ window.setTimeout(function () {
+ window.dispatchEvent(new CustomEvent("resize"));
+ }, 1);
+ },
+ reset: function (willUnmount) {
+ if (!this.state.applied) {
+ return;
+ }
+ var node = this.getDOMNode();
+ var prev = node.previousElementSibling;
+ var next = node.nextElementSibling;
+
+ prev.style.flex = "";
+ next.style.flex = "";
+
+ if (!willUnmount) {
+ this.setState({
+ applied: false
+ });
+ }
+ this.onResize();
+ },
+ componentWillUnmount: function () {
+ this.reset(true);
+ },
+ render: function () {
+ var className = "splitter";
+ if (this.props.axis === "x") {
+ className += " splitter-x";
+ } else {
+ className += " splitter-y";
+ }
+ return (
+ React.createElement("div", {className: className},
+ React.createElement("div", {onMouseDown: this.onMouseDown, draggable: "true"})
+ )
+ );
+ }
+});
+
+module.exports = {
+ State: State,
+ Navigation: Navigation,
+ StickyHeadMixin: StickyHeadMixin,
+ AutoScrollMixin: AutoScrollMixin,
+ Splitter: Splitter
+}
+},{"lodash":"lodash","react":"react","react-router":"react-router"}],10:[function(require,module,exports){
+var React = require("react");
+
+var VirtualScrollMixin = {
+ getInitialState: function () {
+ return {
+ start: 0,
+ stop: 0
+ };
+ },
+ componentWillMount: function () {
+ if (!this.props.rowHeight) {
+ console.warn("VirtualScrollMixin: No rowHeight specified", this);
+ }
+ },
+ getPlaceholderTop: function (total) {
+ var Tag = this.props.placeholderTagName || "tr";
+ // When a large trunk of elements is removed from the button, start may be far off the viewport.
+ // To make this issue less severe, limit the top placeholder to the total number of rows.
+ var style = {
+ height: Math.min(this.state.start, total) * this.props.rowHeight
+ };
+ var spacer = React.createElement(Tag, {key: "placeholder-top", style: style});
+
+ if (this.state.start % 2 === 1) {
+ // fix even/odd rows
+ return [spacer, React.createElement(Tag, {key: "placeholder-top-2"})];
+ } else {
+ return spacer;
+ }
+ },
+ getPlaceholderBottom: function (total) {
+ var Tag = this.props.placeholderTagName || "tr";
+ var style = {
+ height: Math.max(0, total - this.state.stop) * this.props.rowHeight
+ };
+ return React.createElement(Tag, {key: "placeholder-bottom", style: style});
+ },
+ componentDidMount: function () {
+ this.onScroll();
+ window.addEventListener('resize', this.onScroll);
+ },
+ componentWillUnmount: function(){
+ window.removeEventListener('resize', this.onScroll);
+ },
+ onScroll: function () {
+ var viewport = this.getDOMNode();
+ var top = viewport.scrollTop;
+ var height = viewport.offsetHeight;
+ var start = Math.floor(top / this.props.rowHeight);
+ var stop = start + Math.ceil(height / (this.props.rowHeightMin || this.props.rowHeight));
+
+ this.setState({
+ start: start,
+ stop: stop
+ });
+ },
+ renderRows: function (elems) {
+ var rows = [];
+ var max = Math.min(elems.length, this.state.stop);
+
+ for (var i = this.state.start; i < max; i++) {
+ var elem = elems[i];
+ rows.push(this.renderRow(elem));
+ }
+ return rows;
+ },
+ scrollRowIntoView: function (index, head_height) {
+
+ var row_top = (index * this.props.rowHeight) + head_height;
+ var row_bottom = row_top + this.props.rowHeight;
+
+ var viewport = this.getDOMNode();
+ var viewport_top = viewport.scrollTop;
+ var viewport_bottom = viewport_top + viewport.offsetHeight;
+
+ // Account for pinned thead
+ if (row_top - head_height < viewport_top) {
+ viewport.scrollTop = row_top - head_height;
+ } else if (row_bottom > viewport_bottom) {
+ viewport.scrollTop = row_bottom - viewport.offsetHeight;
+ }
+ },
+};
+
+module.exports = VirtualScrollMixin;
+},{"react":"react"}],11:[function(require,module,exports){
+
+var actions = require("./actions.js");
+
+function Connection(url) {
+ if (url[0] === "/") {
+ url = location.origin.replace("http", "ws") + url;
+ }
+
+ var ws = new WebSocket(url);
+ ws.onopen = function () {
+ actions.ConnectionActions.open();
+ };
+ ws.onmessage = function (message) {
+ var m = JSON.parse(message.data);
+ AppDispatcher.dispatchServerAction(m);
+ };
+ ws.onerror = function () {
+ actions.ConnectionActions.error();
+ EventLogActions.add_event("WebSocket connection error.");
+ };
+ ws.onclose = function () {
+ actions.ConnectionActions.close();
+ EventLogActions.add_event("WebSocket connection closed.");
+ };
+ return ws;
+}
+
+module.exports = Connection;
+},{"./actions.js":1}],12:[function(require,module,exports){
+const PayloadSources = {
+ VIEW: "view",
+ SERVER: "server"
+};
+
+
+function Dispatcher() {
+ this.callbacks = [];
+}
+Dispatcher.prototype.register = function (callback) {
+ this.callbacks.push(callback);
+};
+Dispatcher.prototype.unregister = function (callback) {
+ var index = this.callbacks.indexOf(callback);
+ if (index >= 0) {
+ this.callbacks.splice(index, 1);
+ }
+};
+Dispatcher.prototype.dispatch = function (payload) {
+ console.debug("dispatch", payload);
+ for (var i = 0; i < this.callbacks.length; i++) {
+ this.callbacks[i](payload);
+ }
+};
+
+
+AppDispatcher = new Dispatcher();
+AppDispatcher.dispatchViewAction = function (action) {
+ action.source = PayloadSources.VIEW;
+ this.dispatch(action);
+};
+AppDispatcher.dispatchServerAction = function (action) {
+ action.source = PayloadSources.SERVER;
+ this.dispatch(action);
+};
+
+module.exports = {
+ AppDispatcher: AppDispatcher
+};
+},{}],13:[function(require,module,exports){
+/* jshint ignore:start */
+Filt = (function() {
+ /*
+ * Generated by PEG.js 0.8.0.
+ *
+ * http://pegjs.majda.cz/
+ */
+
+ function peg$subclass(child, parent) {
+ function ctor() { this.constructor = child; }
+ ctor.prototype = parent.prototype;
+ child.prototype = new ctor();
+ }
+
+ function SyntaxError(message, expected, found, offset, line, column) {
+ this.message = message;
+ this.expected = expected;
+ this.found = found;
+ this.offset = offset;
+ this.line = line;
+ this.column = column;
+
+ this.name = "SyntaxError";
+ }
+
+ peg$subclass(SyntaxError, Error);
+
+ function parse(input) {
+ var options = arguments.length > 1 ? arguments[1] : {},
+
+ peg$FAILED = {},
+
+ peg$startRuleFunctions = { start: peg$parsestart },
+ peg$startRuleFunction = peg$parsestart,
+
+ peg$c0 = { type: "other", description: "filter expression" },
+ peg$c1 = peg$FAILED,
+ peg$c2 = function(orExpr) { return orExpr; },
+ peg$c3 = [],
+ peg$c4 = function() {return trueFilter; },
+ peg$c5 = { type: "other", description: "whitespace" },
+ peg$c6 = /^[ \t\n\r]/,
+ peg$c7 = { type: "class", value: "[ \\t\\n\\r]", description: "[ \\t\\n\\r]" },
+ peg$c8 = { type: "other", description: "control character" },
+ peg$c9 = /^[|&!()~"]/,
+ peg$c10 = { type: "class", value: "[|&!()~\"]", description: "[|&!()~\"]" },
+ peg$c11 = { type: "other", description: "optional whitespace" },
+ peg$c12 = "|",
+ peg$c13 = { type: "literal", value: "|", description: "\"|\"" },
+ peg$c14 = function(first, second) { return or(first, second); },
+ peg$c15 = "&",
+ peg$c16 = { type: "literal", value: "&", description: "\"&\"" },
+ peg$c17 = function(first, second) { return and(first, second); },
+ peg$c18 = "!",
+ peg$c19 = { type: "literal", value: "!", description: "\"!\"" },
+ peg$c20 = function(expr) { return not(expr); },
+ peg$c21 = "(",
+ peg$c22 = { type: "literal", value: "(", description: "\"(\"" },
+ peg$c23 = ")",
+ peg$c24 = { type: "literal", value: ")", description: "\")\"" },
+ peg$c25 = function(expr) { return binding(expr); },
+ peg$c26 = "~a",
+ peg$c27 = { type: "literal", value: "~a", description: "\"~a\"" },
+ peg$c28 = function() { return assetFilter; },
+ peg$c29 = "~e",
+ peg$c30 = { type: "literal", value: "~e", description: "\"~e\"" },
+ peg$c31 = function() { return errorFilter; },
+ peg$c32 = "~q",
+ peg$c33 = { type: "literal", value: "~q", description: "\"~q\"" },
+ peg$c34 = function() { return noResponseFilter; },
+ peg$c35 = "~s",
+ peg$c36 = { type: "literal", value: "~s", description: "\"~s\"" },
+ peg$c37 = function() { return responseFilter; },
+ peg$c38 = "true",
+ peg$c39 = { type: "literal", value: "true", description: "\"true\"" },
+ peg$c40 = function() { return trueFilter; },
+ peg$c41 = "false",
+ peg$c42 = { type: "literal", value: "false", description: "\"false\"" },
+ peg$c43 = function() { return falseFilter; },
+ peg$c44 = "~c",
+ peg$c45 = { type: "literal", value: "~c", description: "\"~c\"" },
+ peg$c46 = function(s) { return responseCode(s); },
+ peg$c47 = "~d",
+ peg$c48 = { type: "literal", value: "~d", description: "\"~d\"" },
+ peg$c49 = function(s) { return domain(s); },
+ peg$c50 = "~h",
+ peg$c51 = { type: "literal", value: "~h", description: "\"~h\"" },
+ peg$c52 = function(s) { return header(s); },
+ peg$c53 = "~hq",
+ peg$c54 = { type: "literal", value: "~hq", description: "\"~hq\"" },
+ peg$c55 = function(s) { return requestHeader(s); },
+ peg$c56 = "~hs",
+ peg$c57 = { type: "literal", value: "~hs", description: "\"~hs\"" },
+ peg$c58 = function(s) { return responseHeader(s); },
+ peg$c59 = "~m",
+ peg$c60 = { type: "literal", value: "~m", description: "\"~m\"" },
+ peg$c61 = function(s) { return method(s); },
+ peg$c62 = "~t",
+ peg$c63 = { type: "literal", value: "~t", description: "\"~t\"" },
+ peg$c64 = function(s) { return contentType(s); },
+ peg$c65 = "~tq",
+ peg$c66 = { type: "literal", value: "~tq", description: "\"~tq\"" },
+ peg$c67 = function(s) { return requestContentType(s); },
+ peg$c68 = "~ts",
+ peg$c69 = { type: "literal", value: "~ts", description: "\"~ts\"" },
+ peg$c70 = function(s) { return responseContentType(s); },
+ peg$c71 = "~u",
+ peg$c72 = { type: "literal", value: "~u", description: "\"~u\"" },
+ peg$c73 = function(s) { return url(s); },
+ peg$c74 = { type: "other", description: "integer" },
+ peg$c75 = null,
+ peg$c76 = /^['"]/,
+ peg$c77 = { type: "class", value: "['\"]", description: "['\"]" },
+ peg$c78 = /^[0-9]/,
+ peg$c79 = { type: "class", value: "[0-9]", description: "[0-9]" },
+ peg$c80 = function(digits) { return parseInt(digits.join(""), 10); },
+ peg$c81 = { type: "other", description: "string" },
+ peg$c82 = "\"",
+ peg$c83 = { type: "literal", value: "\"", description: "\"\\\"\"" },
+ peg$c84 = function(chars) { return chars.join(""); },
+ peg$c85 = "'",
+ peg$c86 = { type: "literal", value: "'", description: "\"'\"" },
+ peg$c87 = void 0,
+ peg$c88 = /^["\\]/,
+ peg$c89 = { type: "class", value: "[\"\\\\]", description: "[\"\\\\]" },
+ peg$c90 = { type: "any", description: "any character" },
+ peg$c91 = function(char) { return char; },
+ peg$c92 = "\\",
+ peg$c93 = { type: "literal", value: "\\", description: "\"\\\\\"" },
+ peg$c94 = /^['\\]/,
+ peg$c95 = { type: "class", value: "['\\\\]", description: "['\\\\]" },
+ peg$c96 = /^['"\\]/,
+ peg$c97 = { type: "class", value: "['\"\\\\]", description: "['\"\\\\]" },
+ peg$c98 = "n",
+ peg$c99 = { type: "literal", value: "n", description: "\"n\"" },
+ peg$c100 = function() { return "\n"; },
+ peg$c101 = "r",
+ peg$c102 = { type: "literal", value: "r", description: "\"r\"" },
+ peg$c103 = function() { return "\r"; },
+ peg$c104 = "t",
+ peg$c105 = { type: "literal", value: "t", description: "\"t\"" },
+ peg$c106 = function() { return "\t"; },
+
+ peg$currPos = 0,
+ peg$reportedPos = 0,
+ peg$cachedPos = 0,
+ peg$cachedPosDetails = { line: 1, column: 1, seenCR: false },
+ peg$maxFailPos = 0,
+ peg$maxFailExpected = [],
+ peg$silentFails = 0,
+
+ peg$result;
+
+ if ("startRule" in options) {
+ if (!(options.startRule in peg$startRuleFunctions)) {
+ throw new Error("Can't start parsing from rule \"" + options.startRule + "\".");
+ }
+
+ peg$startRuleFunction = peg$startRuleFunctions[options.startRule];
+ }
+
+ function text() {
+ return input.substring(peg$reportedPos, peg$currPos);
+ }
+
+ function offset() {
+ return peg$reportedPos;
+ }
+
+ function line() {
+ return peg$computePosDetails(peg$reportedPos).line;
+ }
+
+ function column() {
+ return peg$computePosDetails(peg$reportedPos).column;
+ }
+
+ function expected(description) {
+ throw peg$buildException(
+ null,
+ [{ type: "other", description: description }],
+ peg$reportedPos
+ );
+ }
+
+ function error(message) {
+ throw peg$buildException(message, null, peg$reportedPos);
+ }
+
+ function peg$computePosDetails(pos) {
+ function advance(details, startPos, endPos) {
+ var p, ch;
+
+ for (p = startPos; p < endPos; p++) {
+ ch = input.charAt(p);
+ if (ch === "\n") {
+ if (!details.seenCR) { details.line++; }
+ details.column = 1;
+ details.seenCR = false;
+ } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") {
+ details.line++;
+ details.column = 1;
+ details.seenCR = true;
+ } else {
+ details.column++;
+ details.seenCR = false;
+ }
+ }
+ }
+
+ if (peg$cachedPos !== pos) {
+ if (peg$cachedPos > pos) {
+ peg$cachedPos = 0;
+ peg$cachedPosDetails = { line: 1, column: 1, seenCR: false };
+ }
+ advance(peg$cachedPosDetails, peg$cachedPos, pos);
+ peg$cachedPos = pos;
+ }
+
+ return peg$cachedPosDetails;
+ }
+
+ function peg$fail(expected) {
+ if (peg$currPos < peg$maxFailPos) { return; }
+
+ if (peg$currPos > peg$maxFailPos) {
+ peg$maxFailPos = peg$currPos;
+ peg$maxFailExpected = [];
+ }
+
+ peg$maxFailExpected.push(expected);
+ }
+
+ function peg$buildException(message, expected, pos) {
+ function cleanupExpected(expected) {
+ var i = 1;
+
+ expected.sort(function(a, b) {
+ if (a.description < b.description) {
+ return -1;
+ } else if (a.description > b.description) {
+ return 1;
+ } else {
+ return 0;
+ }
+ });
+
+ while (i < expected.length) {
+ if (expected[i - 1] === expected[i]) {
+ expected.splice(i, 1);
+ } else {
+ i++;
+ }
+ }
+ }
+
+ function buildMessage(expected, found) {
+ function stringEscape(s) {
+ function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); }
+
+ return s
+ .replace(/\\/g, '\\\\')
+ .replace(/"/g, '\\"')
+ .replace(/\x08/g, '\\b')
+ .replace(/\t/g, '\\t')
+ .replace(/\n/g, '\\n')
+ .replace(/\f/g, '\\f')
+ .replace(/\r/g, '\\r')
+ .replace(/[\x00-\x07\x0B\x0E\x0F]/g, function(ch) { return '\\x0' + hex(ch); })
+ .replace(/[\x10-\x1F\x80-\xFF]/g, function(ch) { return '\\x' + hex(ch); })
+ .replace(/[\u0180-\u0FFF]/g, function(ch) { return '\\u0' + hex(ch); })
+ .replace(/[\u1080-\uFFFF]/g, function(ch) { return '\\u' + hex(ch); });
+ }
+
+ var expectedDescs = new Array(expected.length),
+ expectedDesc, foundDesc, i;
+
+ for (i = 0; i < expected.length; i++) {
+ expectedDescs[i] = expected[i].description;
+ }
+
+ expectedDesc = expected.length > 1
+ ? expectedDescs.slice(0, -1).join(", ")
+ + " or "
+ + expectedDescs[expected.length - 1]
+ : expectedDescs[0];
+
+ foundDesc = found ? "\"" + stringEscape(found) + "\"" : "end of input";
+
+ return "Expected " + expectedDesc + " but " + foundDesc + " found.";
+ }
+
+ var posDetails = peg$computePosDetails(pos),
+ found = pos < input.length ? input.charAt(pos) : null;
+
+ if (expected !== null) {
+ cleanupExpected(expected);
+ }
+
+ return new SyntaxError(
+ message !== null ? message : buildMessage(expected, found),
+ expected,
+ found,
+ pos,
+ posDetails.line,
+ posDetails.column
+ );
+ }
+
+ function peg$parsestart() {
+ var s0, s1, s2, s3;
+
+ peg$silentFails++;
+ s0 = peg$currPos;
+ s1 = peg$parse__();
+ if (s1 !== peg$FAILED) {
+ s2 = peg$parseOrExpr();
+ if (s2 !== peg$FAILED) {
+ s3 = peg$parse__();
+ if (s3 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c2(s2);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ s1 = [];
+ if (s1 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c4();
+ }
+ s0 = s1;
+ }
+ peg$silentFails--;
+ if (s0 === peg$FAILED) {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c0); }
+ }
+
+ return s0;
+ }
+
+ function peg$parsews() {
+ var s0, s1;
+
+ peg$silentFails++;
+ if (peg$c6.test(input.charAt(peg$currPos))) {
+ s0 = input.charAt(peg$currPos);
+ peg$currPos++;
+ } else {
+ s0 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c7); }
+ }
+ peg$silentFails--;
+ if (s0 === peg$FAILED) {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c5); }
+ }
+
+ return s0;
+ }
+
+ function peg$parsecc() {
+ var s0, s1;
+
+ peg$silentFails++;
+ if (peg$c9.test(input.charAt(peg$currPos))) {
+ s0 = input.charAt(peg$currPos);
+ peg$currPos++;
+ } else {
+ s0 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c10); }
+ }
+ peg$silentFails--;
+ if (s0 === peg$FAILED) {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c8); }
+ }
+
+ return s0;
+ }
+
+ function peg$parse__() {
+ var s0, s1;
+
+ peg$silentFails++;
+ s0 = [];
+ s1 = peg$parsews();
+ while (s1 !== peg$FAILED) {
+ s0.push(s1);
+ s1 = peg$parsews();
+ }
+ peg$silentFails--;
+ if (s0 === peg$FAILED) {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c11); }
+ }
+
+ return s0;
+ }
+
+ function peg$parseOrExpr() {
+ var s0, s1, s2, s3, s4, s5;
+
+ s0 = peg$currPos;
+ s1 = peg$parseAndExpr();
+ if (s1 !== peg$FAILED) {
+ s2 = peg$parse__();
+ if (s2 !== peg$FAILED) {
+ if (input.charCodeAt(peg$currPos) === 124) {
+ s3 = peg$c12;
+ peg$currPos++;
+ } else {
+ s3 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c13); }
+ }
+ if (s3 !== peg$FAILED) {
+ s4 = peg$parse__();
+ if (s4 !== peg$FAILED) {
+ s5 = peg$parseOrExpr();
+ if (s5 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c14(s1, s5);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ if (s0 === peg$FAILED) {
+ s0 = peg$parseAndExpr();
+ }
+
+ return s0;
+ }
+
+ function peg$parseAndExpr() {
+ var s0, s1, s2, s3, s4, s5;
+
+ s0 = peg$currPos;
+ s1 = peg$parseNotExpr();
+ if (s1 !== peg$FAILED) {
+ s2 = peg$parse__();
+ if (s2 !== peg$FAILED) {
+ if (input.charCodeAt(peg$currPos) === 38) {
+ s3 = peg$c15;
+ peg$currPos++;
+ } else {
+ s3 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c16); }
+ }
+ if (s3 !== peg$FAILED) {
+ s4 = peg$parse__();
+ if (s4 !== peg$FAILED) {
+ s5 = peg$parseAndExpr();
+ if (s5 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c17(s1, s5);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ s1 = peg$parseNotExpr();
+ if (s1 !== peg$FAILED) {
+ s2 = [];
+ s3 = peg$parsews();
+ if (s3 !== peg$FAILED) {
+ while (s3 !== peg$FAILED) {
+ s2.push(s3);
+ s3 = peg$parsews();
+ }
+ } else {
+ s2 = peg$c1;
+ }
+ if (s2 !== peg$FAILED) {
+ s3 = peg$parseAndExpr();
+ if (s3 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c17(s1, s3);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ if (s0 === peg$FAILED) {
+ s0 = peg$parseNotExpr();
+ }
+ }
+
+ return s0;
+ }
+
+ function peg$parseNotExpr() {
+ var s0, s1, s2, s3;
+
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 33) {
+ s1 = peg$c18;
+ peg$currPos++;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c19); }
+ }
+ if (s1 !== peg$FAILED) {
+ s2 = peg$parse__();
+ if (s2 !== peg$FAILED) {
+ s3 = peg$parseNotExpr();
+ if (s3 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c20(s3);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ if (s0 === peg$FAILED) {
+ s0 = peg$parseBindingExpr();
+ }
+
+ return s0;
+ }
+
+ function peg$parseBindingExpr() {
+ var s0, s1, s2, s3, s4, s5;
+
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 40) {
+ s1 = peg$c21;
+ peg$currPos++;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c22); }
+ }
+ if (s1 !== peg$FAILED) {
+ s2 = peg$parse__();
+ if (s2 !== peg$FAILED) {
+ s3 = peg$parseOrExpr();
+ if (s3 !== peg$FAILED) {
+ s4 = peg$parse__();
+ if (s4 !== peg$FAILED) {
+ if (input.charCodeAt(peg$currPos) === 41) {
+ s5 = peg$c23;
+ peg$currPos++;
+ } else {
+ s5 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c24); }
+ }
+ if (s5 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c25(s3);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ if (s0 === peg$FAILED) {
+ s0 = peg$parseExpr();
+ }
+
+ return s0;
+ }
+
+ function peg$parseExpr() {
+ var s0;
+
+ s0 = peg$parseNullaryExpr();
+ if (s0 === peg$FAILED) {
+ s0 = peg$parseUnaryExpr();
+ }
+
+ return s0;
+ }
+
+ function peg$parseNullaryExpr() {
+ var s0, s1;
+
+ s0 = peg$parseBooleanLiteral();
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ if (input.substr(peg$currPos, 2) === peg$c26) {
+ s1 = peg$c26;
+ peg$currPos += 2;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c27); }
+ }
+ if (s1 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c28();
+ }
+ s0 = s1;
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ if (input.substr(peg$currPos, 2) === peg$c29) {
+ s1 = peg$c29;
+ peg$currPos += 2;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c30); }
+ }
+ if (s1 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c31();
+ }
+ s0 = s1;
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ if (input.substr(peg$currPos, 2) === peg$c32) {
+ s1 = peg$c32;
+ peg$currPos += 2;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c33); }
+ }
+ if (s1 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c34();
+ }
+ s0 = s1;
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ if (input.substr(peg$currPos, 2) === peg$c35) {
+ s1 = peg$c35;
+ peg$currPos += 2;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c36); }
+ }
+ if (s1 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c37();
+ }
+ s0 = s1;
+ }
+ }
+ }
+ }
+
+ return s0;
+ }
+
+ function peg$parseBooleanLiteral() {
+ var s0, s1;
+
+ s0 = peg$currPos;
+ if (input.substr(peg$currPos, 4) === peg$c38) {
+ s1 = peg$c38;
+ peg$currPos += 4;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c39); }
+ }
+ if (s1 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c40();
+ }
+ s0 = s1;
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ if (input.substr(peg$currPos, 5) === peg$c41) {
+ s1 = peg$c41;
+ peg$currPos += 5;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c42); }
+ }
+ if (s1 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c43();
+ }
+ s0 = s1;
+ }
+
+ return s0;
+ }
+
+ function peg$parseUnaryExpr() {
+ var s0, s1, s2, s3;
+
+ s0 = peg$currPos;
+ if (input.substr(peg$currPos, 2) === peg$c44) {
+ s1 = peg$c44;
+ peg$currPos += 2;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c45); }
+ }
+ if (s1 !== peg$FAILED) {
+ s2 = [];
+ s3 = peg$parsews();
+ if (s3 !== peg$FAILED) {
+ while (s3 !== peg$FAILED) {
+ s2.push(s3);
+ s3 = peg$parsews();
+ }
+ } else {
+ s2 = peg$c1;
+ }
+ if (s2 !== peg$FAILED) {
+ s3 = peg$parseIntegerLiteral();
+ if (s3 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c46(s3);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ if (input.substr(peg$currPos, 2) === peg$c47) {
+ s1 = peg$c47;
+ peg$currPos += 2;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c48); }
+ }
+ if (s1 !== peg$FAILED) {
+ s2 = [];
+ s3 = peg$parsews();
+ if (s3 !== peg$FAILED) {
+ while (s3 !== peg$FAILED) {
+ s2.push(s3);
+ s3 = peg$parsews();
+ }
+ } else {
+ s2 = peg$c1;
+ }
+ if (s2 !== peg$FAILED) {
+ s3 = peg$parseStringLiteral();
+ if (s3 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c49(s3);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ if (input.substr(peg$currPos, 2) === peg$c50) {
+ s1 = peg$c50;
+ peg$currPos += 2;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c51); }
+ }
+ if (s1 !== peg$FAILED) {
+ s2 = [];
+ s3 = peg$parsews();
+ if (s3 !== peg$FAILED) {
+ while (s3 !== peg$FAILED) {
+ s2.push(s3);
+ s3 = peg$parsews();
+ }
+ } else {
+ s2 = peg$c1;
+ }
+ if (s2 !== peg$FAILED) {
+ s3 = peg$parseStringLiteral();
+ if (s3 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c52(s3);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ if (input.substr(peg$currPos, 3) === peg$c53) {
+ s1 = peg$c53;
+ peg$currPos += 3;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c54); }
+ }
+ if (s1 !== peg$FAILED) {
+ s2 = [];
+ s3 = peg$parsews();
+ if (s3 !== peg$FAILED) {
+ while (s3 !== peg$FAILED) {
+ s2.push(s3);
+ s3 = peg$parsews();
+ }
+ } else {
+ s2 = peg$c1;
+ }
+ if (s2 !== peg$FAILED) {
+ s3 = peg$parseStringLiteral();
+ if (s3 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c55(s3);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ if (input.substr(peg$currPos, 3) === peg$c56) {
+ s1 = peg$c56;
+ peg$currPos += 3;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c57); }
+ }
+ if (s1 !== peg$FAILED) {
+ s2 = [];
+ s3 = peg$parsews();
+ if (s3 !== peg$FAILED) {
+ while (s3 !== peg$FAILED) {
+ s2.push(s3);
+ s3 = peg$parsews();
+ }
+ } else {
+ s2 = peg$c1;
+ }
+ if (s2 !== peg$FAILED) {
+ s3 = peg$parseStringLiteral();
+ if (s3 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c58(s3);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ if (input.substr(peg$currPos, 2) === peg$c59) {
+ s1 = peg$c59;
+ peg$currPos += 2;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c60); }
+ }
+ if (s1 !== peg$FAILED) {
+ s2 = [];
+ s3 = peg$parsews();
+ if (s3 !== peg$FAILED) {
+ while (s3 !== peg$FAILED) {
+ s2.push(s3);
+ s3 = peg$parsews();
+ }
+ } else {
+ s2 = peg$c1;
+ }
+ if (s2 !== peg$FAILED) {
+ s3 = peg$parseStringLiteral();
+ if (s3 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c61(s3);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ if (input.substr(peg$currPos, 2) === peg$c62) {
+ s1 = peg$c62;
+ peg$currPos += 2;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c63); }
+ }
+ if (s1 !== peg$FAILED) {
+ s2 = [];
+ s3 = peg$parsews();
+ if (s3 !== peg$FAILED) {
+ while (s3 !== peg$FAILED) {
+ s2.push(s3);
+ s3 = peg$parsews();
+ }
+ } else {
+ s2 = peg$c1;
+ }
+ if (s2 !== peg$FAILED) {
+ s3 = peg$parseStringLiteral();
+ if (s3 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c64(s3);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ if (input.substr(peg$currPos, 3) === peg$c65) {
+ s1 = peg$c65;
+ peg$currPos += 3;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c66); }
+ }
+ if (s1 !== peg$FAILED) {
+ s2 = [];
+ s3 = peg$parsews();
+ if (s3 !== peg$FAILED) {
+ while (s3 !== peg$FAILED) {
+ s2.push(s3);
+ s3 = peg$parsews();
+ }
+ } else {
+ s2 = peg$c1;
+ }
+ if (s2 !== peg$FAILED) {
+ s3 = peg$parseStringLiteral();
+ if (s3 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c67(s3);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ if (input.substr(peg$currPos, 3) === peg$c68) {
+ s1 = peg$c68;
+ peg$currPos += 3;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c69); }
+ }
+ if (s1 !== peg$FAILED) {
+ s2 = [];
+ s3 = peg$parsews();
+ if (s3 !== peg$FAILED) {
+ while (s3 !== peg$FAILED) {
+ s2.push(s3);
+ s3 = peg$parsews();
+ }
+ } else {
+ s2 = peg$c1;
+ }
+ if (s2 !== peg$FAILED) {
+ s3 = peg$parseStringLiteral();
+ if (s3 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c70(s3);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ if (input.substr(peg$currPos, 2) === peg$c71) {
+ s1 = peg$c71;
+ peg$currPos += 2;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c72); }
+ }
+ if (s1 !== peg$FAILED) {
+ s2 = [];
+ s3 = peg$parsews();
+ if (s3 !== peg$FAILED) {
+ while (s3 !== peg$FAILED) {
+ s2.push(s3);
+ s3 = peg$parsews();
+ }
+ } else {
+ s2 = peg$c1;
+ }
+ if (s2 !== peg$FAILED) {
+ s3 = peg$parseStringLiteral();
+ if (s3 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c73(s3);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ s1 = peg$parseStringLiteral();
+ if (s1 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c73(s1);
+ }
+ s0 = s1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return s0;
+ }
+
+ function peg$parseIntegerLiteral() {
+ var s0, s1, s2, s3;
+
+ peg$silentFails++;
+ s0 = peg$currPos;
+ if (peg$c76.test(input.charAt(peg$currPos))) {
+ s1 = input.charAt(peg$currPos);
+ peg$currPos++;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c77); }
+ }
+ if (s1 === peg$FAILED) {
+ s1 = peg$c75;
+ }
+ if (s1 !== peg$FAILED) {
+ s2 = [];
+ if (peg$c78.test(input.charAt(peg$currPos))) {
+ s3 = input.charAt(peg$currPos);
+ peg$currPos++;
+ } else {
+ s3 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c79); }
+ }
+ if (s3 !== peg$FAILED) {
+ while (s3 !== peg$FAILED) {
+ s2.push(s3);
+ if (peg$c78.test(input.charAt(peg$currPos))) {
+ s3 = input.charAt(peg$currPos);
+ peg$currPos++;
+ } else {
+ s3 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c79); }
+ }
+ }
+ } else {
+ s2 = peg$c1;
+ }
+ if (s2 !== peg$FAILED) {
+ if (peg$c76.test(input.charAt(peg$currPos))) {
+ s3 = input.charAt(peg$currPos);
+ peg$currPos++;
+ } else {
+ s3 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c77); }
+ }
+ if (s3 === peg$FAILED) {
+ s3 = peg$c75;
+ }
+ if (s3 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c80(s2);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ peg$silentFails--;
+ if (s0 === peg$FAILED) {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c74); }
+ }
+
+ return s0;
+ }
+
+ function peg$parseStringLiteral() {
+ var s0, s1, s2, s3;
+
+ peg$silentFails++;
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 34) {
+ s1 = peg$c82;
+ peg$currPos++;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c83); }
+ }
+ if (s1 !== peg$FAILED) {
+ s2 = [];
+ s3 = peg$parseDoubleStringChar();
+ while (s3 !== peg$FAILED) {
+ s2.push(s3);
+ s3 = peg$parseDoubleStringChar();
+ }
+ if (s2 !== peg$FAILED) {
+ if (input.charCodeAt(peg$currPos) === 34) {
+ s3 = peg$c82;
+ peg$currPos++;
+ } else {
+ s3 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c83); }
+ }
+ if (s3 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c84(s2);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 39) {
+ s1 = peg$c85;
+ peg$currPos++;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c86); }
+ }
+ if (s1 !== peg$FAILED) {
+ s2 = [];
+ s3 = peg$parseSingleStringChar();
+ while (s3 !== peg$FAILED) {
+ s2.push(s3);
+ s3 = peg$parseSingleStringChar();
+ }
+ if (s2 !== peg$FAILED) {
+ if (input.charCodeAt(peg$currPos) === 39) {
+ s3 = peg$c85;
+ peg$currPos++;
+ } else {
+ s3 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c86); }
+ }
+ if (s3 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c84(s2);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ s1 = peg$currPos;
+ peg$silentFails++;
+ s2 = peg$parsecc();
+ peg$silentFails--;
+ if (s2 === peg$FAILED) {
+ s1 = peg$c87;
+ } else {
+ peg$currPos = s1;
+ s1 = peg$c1;
+ }
+ if (s1 !== peg$FAILED) {
+ s2 = [];
+ s3 = peg$parseUnquotedStringChar();
+ if (s3 !== peg$FAILED) {
+ while (s3 !== peg$FAILED) {
+ s2.push(s3);
+ s3 = peg$parseUnquotedStringChar();
+ }
+ } else {
+ s2 = peg$c1;
+ }
+ if (s2 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c84(s2);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ }
+ }
+ peg$silentFails--;
+ if (s0 === peg$FAILED) {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c81); }
+ }
+
+ return s0;
+ }
+
+ function peg$parseDoubleStringChar() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ s1 = peg$currPos;
+ peg$silentFails++;
+ if (peg$c88.test(input.charAt(peg$currPos))) {
+ s2 = input.charAt(peg$currPos);
+ peg$currPos++;
+ } else {
+ s2 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c89); }
+ }
+ peg$silentFails--;
+ if (s2 === peg$FAILED) {
+ s1 = peg$c87;
+ } else {
+ peg$currPos = s1;
+ s1 = peg$c1;
+ }
+ if (s1 !== peg$FAILED) {
+ if (input.length > peg$currPos) {
+ s2 = input.charAt(peg$currPos);
+ peg$currPos++;
+ } else {
+ s2 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c90); }
+ }
+ if (s2 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c91(s2);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 92) {
+ s1 = peg$c92;
+ peg$currPos++;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c93); }
+ }
+ if (s1 !== peg$FAILED) {
+ s2 = peg$parseEscapeSequence();
+ if (s2 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c91(s2);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ }
+
+ return s0;
+ }
+
+ function peg$parseSingleStringChar() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ s1 = peg$currPos;
+ peg$silentFails++;
+ if (peg$c94.test(input.charAt(peg$currPos))) {
+ s2 = input.charAt(peg$currPos);
+ peg$currPos++;
+ } else {
+ s2 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c95); }
+ }
+ peg$silentFails--;
+ if (s2 === peg$FAILED) {
+ s1 = peg$c87;
+ } else {
+ peg$currPos = s1;
+ s1 = peg$c1;
+ }
+ if (s1 !== peg$FAILED) {
+ if (input.length > peg$currPos) {
+ s2 = input.charAt(peg$currPos);
+ peg$currPos++;
+ } else {
+ s2 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c90); }
+ }
+ if (s2 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c91(s2);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 92) {
+ s1 = peg$c92;
+ peg$currPos++;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c93); }
+ }
+ if (s1 !== peg$FAILED) {
+ s2 = peg$parseEscapeSequence();
+ if (s2 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c91(s2);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ }
+
+ return s0;
+ }
+
+ function peg$parseUnquotedStringChar() {
+ var s0, s1, s2;
+
+ s0 = peg$currPos;
+ s1 = peg$currPos;
+ peg$silentFails++;
+ s2 = peg$parsews();
+ peg$silentFails--;
+ if (s2 === peg$FAILED) {
+ s1 = peg$c87;
+ } else {
+ peg$currPos = s1;
+ s1 = peg$c1;
+ }
+ if (s1 !== peg$FAILED) {
+ if (input.length > peg$currPos) {
+ s2 = input.charAt(peg$currPos);
+ peg$currPos++;
+ } else {
+ s2 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c90); }
+ }
+ if (s2 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c91(s2);
+ s0 = s1;
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$c1;
+ }
+
+ return s0;
+ }
+
+ function peg$parseEscapeSequence() {
+ var s0, s1;
+
+ if (peg$c96.test(input.charAt(peg$currPos))) {
+ s0 = input.charAt(peg$currPos);
+ peg$currPos++;
+ } else {
+ s0 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c97); }
+ }
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 110) {
+ s1 = peg$c98;
+ peg$currPos++;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c99); }
+ }
+ if (s1 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c100();
+ }
+ s0 = s1;
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 114) {
+ s1 = peg$c101;
+ peg$currPos++;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c102); }
+ }
+ if (s1 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c103();
+ }
+ s0 = s1;
+ if (s0 === peg$FAILED) {
+ s0 = peg$currPos;
+ if (input.charCodeAt(peg$currPos) === 116) {
+ s1 = peg$c104;
+ peg$currPos++;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) { peg$fail(peg$c105); }
+ }
+ if (s1 !== peg$FAILED) {
+ peg$reportedPos = s0;
+ s1 = peg$c106();
+ }
+ s0 = s1;
+ }
+ }
+ }
+
+ return s0;
+ }
+
+
+ function or(first, second) {
+ // Add explicit function names to ease debugging.
+ function orFilter() {
+ return first.apply(this, arguments) || second.apply(this, arguments);
+ }
+ orFilter.desc = first.desc + " or " + second.desc;
+ return orFilter;
+ }
+ function and(first, second) {
+ function andFilter() {
+ return first.apply(this, arguments) && second.apply(this, arguments);
+ }
+ andFilter.desc = first.desc + " and " + second.desc;
+ return andFilter;
+ }
+ function not(expr) {
+ function notFilter() {
+ return !expr.apply(this, arguments);
+ }
+ notFilter.desc = "not " + expr.desc;
+ return notFilter;
+ }
+ function binding(expr) {
+ function bindingFilter() {
+ return expr.apply(this, arguments);
+ }
+ bindingFilter.desc = "(" + expr.desc + ")";
+ return bindingFilter;
+ }
+ function trueFilter(flow) {
+ return true;
+ }
+ trueFilter.desc = "true";
+ function falseFilter(flow) {
+ return false;
+ }
+ falseFilter.desc = "false";
+
+ var ASSET_TYPES = [
+ new RegExp("text/javascript"),
+ new RegExp("application/x-javascript"),
+ new RegExp("application/javascript"),
+ new RegExp("text/css"),
+ new RegExp("image/.*"),
+ new RegExp("application/x-shockwave-flash")
+ ];
+ function assetFilter(flow) {
+ if (flow.response) {
+ var ct = ResponseUtils.getContentType(flow.response);
+ var i = ASSET_TYPES.length;
+ while (i--) {
+ if (ASSET_TYPES[i].test(ct)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ assetFilter.desc = "is asset";
+ function responseCode(code){
+ function responseCodeFilter(flow){
+ return flow.response && flow.response.code === code;
+ }
+ responseCodeFilter.desc = "resp. code is " + code;
+ return responseCodeFilter;
+ }
+ function domain(regex){
+ regex = new RegExp(regex, "i");
+ function domainFilter(flow){
+ return flow.request && regex.test(flow.request.host);
+ }
+ domainFilter.desc = "domain matches " + regex;
+ return domainFilter;
+ }
+ function errorFilter(flow){
+ return !!flow.error;
+ }
+ errorFilter.desc = "has error";
+ function header(regex){
+ regex = new RegExp(regex, "i");
+ function headerFilter(flow){
+ return (
+ (flow.request && RequestUtils.match_header(flow.request, regex))
+ ||
+ (flow.response && ResponseUtils.match_header(flow.response, regex))
+ );
+ }
+ headerFilter.desc = "header matches " + regex;
+ return headerFilter;
+ }
+ function requestHeader(regex){
+ regex = new RegExp(regex, "i");
+ function requestHeaderFilter(flow){
+ return (flow.request && RequestUtils.match_header(flow.request, regex));
+ }
+ requestHeaderFilter.desc = "req. header matches " + regex;
+ return requestHeaderFilter;
+ }
+ function responseHeader(regex){
+ regex = new RegExp(regex, "i");
+ function responseHeaderFilter(flow){
+ return (flow.response && ResponseUtils.match_header(flow.response, regex));
+ }
+ responseHeaderFilter.desc = "resp. header matches " + regex;
+ return responseHeaderFilter;
+ }
+ function method(regex){
+ regex = new RegExp(regex, "i");
+ function methodFilter(flow){
+ return flow.request && regex.test(flow.request.method);
+ }
+ methodFilter.desc = "method matches " + regex;
+ return methodFilter;
+ }
+ function noResponseFilter(flow){
+ return flow.request && !flow.response;
+ }
+ noResponseFilter.desc = "has no response";
+ function responseFilter(flow){
+ return !!flow.response;
+ }
+ responseFilter.desc = "has response";
+
+ function contentType(regex){
+ regex = new RegExp(regex, "i");
+ function contentTypeFilter(flow){
+ return (
+ (flow.request && regex.test(RequestUtils.getContentType(flow.request)))
+ ||
+ (flow.response && regex.test(ResponseUtils.getContentType(flow.response)))
+ );
+ }
+ contentTypeFilter.desc = "content type matches " + regex;
+ return contentTypeFilter;
+ }
+ function requestContentType(regex){
+ regex = new RegExp(regex, "i");
+ function requestContentTypeFilter(flow){
+ return flow.request && regex.test(RequestUtils.getContentType(flow.request));
+ }
+ requestContentTypeFilter.desc = "req. content type matches " + regex;
+ return requestContentTypeFilter;
+ }
+ function responseContentType(regex){
+ regex = new RegExp(regex, "i");
+ function responseContentTypeFilter(flow){
+ return flow.response && regex.test(ResponseUtils.getContentType(flow.response));
+ }
+ responseContentTypeFilter.desc = "resp. content type matches " + regex;
+ return responseContentTypeFilter;
+ }
+ function url(regex){
+ regex = new RegExp(regex, "i");
+ function urlFilter(flow){
+ return flow.request && regex.test(RequestUtils.pretty_url(flow.request));
+ }
+ urlFilter.desc = "url matches " + regex;
+ return urlFilter;
+ }
+
+
+ peg$result = peg$startRuleFunction();
+
+ if (peg$result !== peg$FAILED && peg$currPos === input.length) {
+ return peg$result;
+ } else {
+ if (peg$result !== peg$FAILED && peg$currPos < input.length) {
+ peg$fail({ type: "end", description: "end of input" });
+ }
+
+ throw peg$buildException(null, peg$maxFailExpected, peg$maxFailPos);
+ }
+ }
+
+ return {
+ SyntaxError: SyntaxError,
+ parse: parse
+ };
+})();
+/* jshint ignore:end */
+
+module.exports = Filt;
+
+},{}],14:[function(require,module,exports){
+var _ = require("lodash");
+
+var _MessageUtils = {
+ getContentType: function (message) {
+ return this.get_first_header(message, /^Content-Type$/i);
+ },
+ get_first_header: function (message, regex) {
+ //FIXME: Cache Invalidation.
+ if (!message._headerLookups)
+ Object.defineProperty(message, "_headerLookups", {
+ value: {},
+ configurable: false,
+ enumerable: false,
+ writable: false
+ });
+ if (!(regex in message._headerLookups)) {
+ var header;
+ for (var i = 0; i < message.headers.length; i++) {
+ if (!!message.headers[i][0].match(regex)) {
+ header = message.headers[i];
+ break;
+ }
+ }
+ message._headerLookups[regex] = header ? header[1] : undefined;
+ }
+ return message._headerLookups[regex];
+ },
+ match_header: function (message, regex) {
+ var headers = message.headers;
+ var i = headers.length;
+ while (i--) {
+ if (regex.test(headers[i].join(" "))) {
+ return headers[i];
+ }
+ }
+ return false;
+ }
+};
+
+var defaultPorts = {
+ "http": 80,
+ "https": 443
+};
+
+var RequestUtils = _.extend(_MessageUtils, {
+ pretty_host: function (request) {
+ //FIXME: Add hostheader
+ return request.host;
+ },
+ pretty_url: function (request) {
+ var port = "";
+ if (defaultPorts[request.scheme] !== request.port) {
+ port = ":" + request.port;
+ }
+ return request.scheme + "://" + this.pretty_host(request) + port + request.path;
+ }
+});
+
+var ResponseUtils = _.extend(_MessageUtils, {});
+
+
+module.exports = {
+ ResponseUtils: ResponseUtils
+}
+},{"lodash":"lodash"}],15:[function(require,module,exports){
+
+var _ = require("lodash");
+var $ = require("jquery");
+
+var utils = require("../utils.js");
+var actions = require("../actions.js");
+var dispatcher = require("../dispatcher.js");
+
+
+function ListStore() {
+ utils.EventEmitter.call(this);
+ this.reset();
+}
+_.extend(ListStore.prototype, utils.EventEmitter.prototype, {
+ add: function (elem) {
+ if (elem.id in this._pos_map) {
+ return;
+ }
+ this._pos_map[elem.id] = this.list.length;
+ this.list.push(elem);
+ this.emit("add", elem);
+ },
+ update: function (elem) {
+ if (!(elem.id in this._pos_map)) {
+ return;
+ }
+ this.list[this._pos_map[elem.id]] = elem;
+ this.emit("update", elem);
+ },
+ remove: function (elem_id) {
+ if (!(elem_id in this._pos_map)) {
+ return;
+ }
+ this.list.splice(this._pos_map[elem_id], 1);
+ this._build_map();
+ this.emit("remove", elem_id);
+ },
+ reset: function (elems) {
+ this.list = elems || [];
+ this._build_map();
+ this.emit("recalculate");
+ },
+ _build_map: function () {
+ this._pos_map = {};
+ for (var i = 0; i < this.list.length; i++) {
+ var elem = this.list[i];
+ this._pos_map[elem.id] = i;
+ }
+ },
+ get: function (elem_id) {
+ return this.list[this._pos_map[elem_id]];
+ },
+ index: function (elem_id) {
+ return this._pos_map[elem_id];
+ }
+});
+
+
+function DictStore() {
+ utils.EventEmitter.call(this);
+ this.reset();
+}
+_.extend(DictStore.prototype, utils.EventEmitter.prototype, {
+ update: function (dict) {
+ _.merge(this.dict, dict);
+ this.emit("recalculate");
+ },
+ reset: function (dict) {
+ this.dict = dict || {};
+ this.emit("recalculate");
+ }
+});
+
+function LiveStoreMixin(type) {
+ this.type = type;
+
+ this._updates_before_fetch = undefined;
+ this._fetchxhr = false;
+
+ this.handle = this.handle.bind(this);
+ dispatcher.AppDispatcher.register(this.handle);
+
+ // Avoid double-fetch on startup.
+ if (!(window.ws && window.ws.readyState === WebSocket.CONNECTING)) {
+ this.fetch();
+ }
+}
+_.extend(LiveStoreMixin.prototype, {
+ handle: function (event) {
+ if (event.type === actions.ActionTypes.CONNECTION_OPEN) {
+ return this.fetch();
+ }
+ if (event.type === this.type) {
+ if (event.cmd === StoreCmds.RESET) {
+ this.fetch(event.data);
+ } else if (this._updates_before_fetch) {
+ console.log("defer update", event);
+ this._updates_before_fetch.push(event);
+ } else {
+ this[event.cmd](event.data);
+ }
+ }
+ },
+ close: function () {
+ dispatcher.AppDispatcher.unregister(this.handle);
+ },
+ fetch: function (data) {
+ console.log("fetch " + this.type);
+ if (this._fetchxhr) {
+ this._fetchxhr.abort();
+ }
+ this._updates_before_fetch = []; // (JS: empty array is true)
+ if (data) {
+ this.handle_fetch(data);
+ } else {
+ this._fetchxhr = $.getJSON("/" + this.type)
+ .done(function (message) {
+ this.handle_fetch(message.data);
+ }.bind(this))
+ .fail(function () {
+ EventLogActions.add_event("Could not fetch " + this.type);
+ }.bind(this));
+ }
+ },
+ handle_fetch: function (data) {
+ this._fetchxhr = false;
+ console.log(this.type + " fetched.", this._updates_before_fetch);
+ this.reset(data);
+ var updates = this._updates_before_fetch;
+ this._updates_before_fetch = false;
+ for (var i = 0; i < updates.length; i++) {
+ this.handle(updates[i]);
+ }
+ },
+});
+
+function LiveListStore(type) {
+ ListStore.call(this);
+ LiveStoreMixin.call(this, type);
+}
+_.extend(LiveListStore.prototype, ListStore.prototype, LiveStoreMixin.prototype);
+
+function LiveDictStore(type) {
+ DictStore.call(this);
+ LiveStoreMixin.call(this, type);
+}
+_.extend(LiveDictStore.prototype, DictStore.prototype, LiveStoreMixin.prototype);
+
+
+function FlowStore() {
+ return new LiveListStore(actions.ActionTypes.FLOW_STORE);
+}
+
+function SettingsStore() {
+ return new LiveDictStore(actions.ActionTypes.SETTINGS_STORE);
+}
+
+function EventLogStore() {
+ LiveListStore.call(this, actions.ActionTypes.EVENT_STORE);
+}
+_.extend(EventLogStore.prototype, LiveListStore.prototype, {
+ fetch: function(){
+ LiveListStore.prototype.fetch.apply(this, arguments);
+
+ // Make sure to display updates even if fetching all events failed.
+ // This way, we can send "fetch failed" log messages to the log.
+ if(this._fetchxhr){
+ this._fetchxhr.fail(function(){
+ this.handle_fetch(null);
+ }.bind(this));
+ }
+ }
+});
+
+
+module.exports = {
+ EventLogStore: EventLogStore,
+ SettingsStore: SettingsStore,
+ FlowStore: FlowStore
+};
+},{"../actions.js":1,"../dispatcher.js":12,"../utils.js":17,"jquery":"jquery","lodash":"lodash"}],16:[function(require,module,exports){
+var _ = require("lodash");
+
+var utils = require("../utils.js");
+
+function SortByStoreOrder(elem) {
+ return this.store.index(elem.id);
+}
+
+var default_sort = SortByStoreOrder;
+var default_filt = function(elem){
+ return true;
+};
+
+function StoreView(store, filt, sortfun) {
+ utils.EventEmitter.call(this);
+ filt = filt || default_filt;
+ sortfun = sortfun || default_sort;
+
+ this.store = store;
+
+ this.add = this.add.bind(this);
+ this.update = this.update.bind(this);
+ this.remove = this.remove.bind(this);
+ this.recalculate = this.recalculate.bind(this);
+ this.store.addListener("add", this.add);
+ this.store.addListener("update", this.update);
+ this.store.addListener("remove", this.remove);
+ this.store.addListener("recalculate", this.recalculate);
+
+ this.recalculate(filt, sortfun);
+}
+
+_.extend(StoreView.prototype, utils.EventEmitter.prototype, {
+ close: function () {
+ this.store.removeListener("add", this.add);
+ this.store.removeListener("update", this.update);
+ this.store.removeListener("remove", this.remove);
+ this.store.removeListener("recalculate", this.recalculate);
+ },
+ recalculate: function (filt, sortfun) {
+ if (filt) {
+ this.filt = filt.bind(this);
+ }
+ if (sortfun) {
+ this.sortfun = sortfun.bind(this);
+ }
+
+ this.list = this.store.list.filter(this.filt);
+ this.list.sort(function (a, b) {
+ return this.sortfun(a) - this.sortfun(b);
+ }.bind(this));
+ this.emit("recalculate");
+ },
+ index: function (elem) {
+ return _.sortedIndex(this.list, elem, this.sortfun);
+ },
+ add: function (elem) {
+ if (this.filt(elem)) {
+ var idx = this.index(elem);
+ if (idx === this.list.length) { //happens often, .push is way faster.
+ this.list.push(elem);
+ } else {
+ this.list.splice(idx, 0, elem);
+ }
+ this.emit("add", elem, idx);
+ }
+ },
+ update: function (elem) {
+ var idx;
+ var i = this.list.length;
+ // Search from the back, we usually update the latest entries.
+ while (i--) {
+ if (this.list[i].id === elem.id) {
+ idx = i;
+ break;
+ }
+ }
+
+ if (idx === -1) { //not contained in list
+ this.add(elem);
+ } else if (!this.filt(elem)) {
+ this.remove(elem.id);
+ } else {
+ if (this.sortfun(this.list[idx]) !== this.sortfun(elem)) { //sortpos has changed
+ this.remove(this.list[idx]);
+ this.add(elem);
+ } else {
+ this.list[idx] = elem;
+ this.emit("update", elem, idx);
+ }
+ }
+ },
+ remove: function (elem_id) {
+ var idx = this.list.length;
+ while (idx--) {
+ if (this.list[idx].id === elem_id) {
+ this.list.splice(idx, 1);
+ this.emit("remove", elem_id, idx);
+ break;
+ }
+ }
+ }
+});
+
+module.exports = {
+ StoreView: StoreView
+};
+},{"../utils.js":17,"lodash":"lodash"}],17:[function(require,module,exports){
+var $ = require("jquery");
+
+
+var Key = {
+ UP: 38,
+ DOWN: 40,
+ PAGE_UP: 33,
+ PAGE_DOWN: 34,
+ HOME: 36,
+ END: 35,
+ LEFT: 37,
+ RIGHT: 39,
+ ENTER: 13,
+ ESC: 27,
+ TAB: 9,
+ SPACE: 32,
+ BACKSPACE: 8,
+};
+// Add A-Z
+for (var i = 65; i <= 90; i++) {
+ Key[String.fromCharCode(i)] = i;
+}
+
+
+var formatSize = function (bytes) {
+ var size = bytes;
+ var prefix = ["B", "KB", "MB", "GB", "TB"];
+ var i = 0;
+ while (Math.abs(size) >= 1024 && i < prefix.length - 1) {
+ i++;
+ size = size / 1024;
+ }
+ return (Math.floor(size * 100) / 100.0).toFixed(2) + prefix[i];
+};
+
+
+var formatTimeDelta = function (milliseconds) {
+ var time = milliseconds;
+ var prefix = ["ms", "s", "min", "h"];
+ var div = [1000, 60, 60];
+ var i = 0;
+ while (Math.abs(time) >= div[i] && i < div.length) {
+ time = time / div[i];
+ i++;
+ }
+ return Math.round(time) + prefix[i];
+};
+
+
+var formatTimeStamp = function (seconds) {
+ var ts = (new Date(seconds * 1000)).toISOString();
+ return ts.replace("T", " ").replace("Z", "");
+};
+
+
+function EventEmitter() {
+ this.listeners = {};
+}
+EventEmitter.prototype.emit = function (event) {
+ if (!(event in this.listeners)) {
+ return;
+ }
+ var args = Array.prototype.slice.call(arguments, 1);
+ this.listeners[event].forEach(function (listener) {
+ listener.apply(this, args);
+ }.bind(this));
+};
+EventEmitter.prototype.addListener = function (events, f) {
+ events.split(" ").forEach(function (event) {
+ this.listeners[event] = this.listeners[event] || [];
+ this.listeners[event].push(f);
+ }.bind(this));
+};
+EventEmitter.prototype.removeListener = function (events, f) {
+ if (!(events in this.listeners)) {
+ return false;
+ }
+ events.split(" ").forEach(function (event) {
+ var index = this.listeners[event].indexOf(f);
+ if (index >= 0) {
+ this.listeners[event].splice(index, 1);
+ }
+ }.bind(this));
+};
+
+
+function getCookie(name) {
+ var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
+ return r ? r[1] : undefined;
+}
+var xsrf = $.param({_xsrf: getCookie("_xsrf")});
+
+//Tornado XSRF Protection.
+$.ajaxPrefilter(function (options) {
+ if (["post", "put", "delete"].indexOf(options.type.toLowerCase()) >= 0 && options.url[0] === "/") {
+ if (options.data) {
+ options.data += ("&" + xsrf);
+ } else {
+ options.data = xsrf;
+ }
+ }
+});
+// Log AJAX Errors
+$(document).ajaxError(function (event, jqXHR, ajaxSettings, thrownError) {
+ var message = jqXHR.responseText;
+ console.error(message, arguments);
+ EventLogActions.add_event(thrownError + ": " + message);
+ window.alert(message);
+});
+
+module.exports = {
+ EventEmitter: EventEmitter,
+ formatSize: formatSize,
+ formatTimeDelta: formatTimeDelta,
+ formatTimeStamp: formatTimeStamp
+};
+},{"jquery":"jquery"}]},{},[2])
+//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcmMvanMvYWN0aW9ucy5qcyIsInNyYy9qcy9hcHAuanMiLCJzcmMvanMvY29tcG9uZW50cy9mbG93dGFibGUtY29sdW1ucy5qc3guanMiLCJzcmMvanMvY29tcG9uZW50cy9mbG93dGFibGUuanN4LmpzIiwic3JjL2pzL2NvbXBvbmVudHMvZm9vdGVyLmpzeC5qcyIsInNyYy9qcy9jb21wb25lbnRzL2hlYWRlci5qc3guanMiLCJzcmMvanMvY29tcG9uZW50cy9tYWludmlldy5qc3guanMiLCJzcmMvanMvY29tcG9uZW50cy9wcm94eWFwcC5qc3guanMiLCJzcmMvanMvY29tcG9uZW50cy91dGlscy5qc3guanMiLCJzcmMvanMvY29tcG9uZW50cy92aXJ0dWFsc2Nyb2xsLmpzeC5qcyIsInNyYy9qcy9jb25uZWN0aW9uLmpzIiwic3JjL2pzL2Rpc3BhdGNoZXIuanMiLCJzcmMvanMvZmlsdC9maWx0LmpzIiwic3JjL2pzL2Zsb3cvdXRpbHMuanMiLCJzcmMvanMvc3RvcmUvc3RvcmUuanMiLCJzcmMvanMvc3RvcmUvdmlldy5qcyIsInNyYy9qcy91dGlscy5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4SUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwWUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuTUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2h2REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCJ2YXIgQWN0aW9uVHlwZXMgPSB7XG4gICAgLy8gQ29ubmVjdGlvblxuICAgIENPTk5FQ1RJT05fT1BFTjogXCJjb25uZWN0aW9uX29wZW5cIixcbiAgICBDT05ORUNUSU9OX0NMT1NFOiBcImNvbm5lY3Rpb25fY2xvc2VcIixcbiAgICBDT05ORUNUSU9OX0VSUk9SOiBcImNvbm5lY3Rpb25fZXJyb3JcIixcblxuICAgIC8vIFN0b3Jlc1xuICAgIFNFVFRJTkdTX1NUT1JFOiBcInNldHRpbmdzXCIsXG4gICAgRVZFTlRfU1RPUkU6IFwiZXZlbnRzXCIsXG4gICAgRkxPV19TVE9SRTogXCJmbG93c1wiLFxufTtcblxudmFyIFN0b3JlQ21kcyA9IHtcbiAgICBBREQ6IFwiYWRkXCIsXG4gICAgVVBEQVRFOiBcInVwZGF0ZVwiLFxuICAgIFJFTU9WRTogXCJyZW1vdmVcIixcbiAgICBSRVNFVDogXCJyZXNldFwiXG59O1xuXG52YXIgQ29ubmVjdGlvbkFjdGlvbnMgPSB7XG4gICAgb3BlbjogZnVuY3Rpb24gKCkge1xuICAgICAgICBBcHBEaXNwYXRjaGVyLmRpc3BhdGNoVmlld0FjdGlvbih7XG4gICAgICAgICAgICB0eXBlOiBBY3Rpb25UeXBlcy5DT05ORUNUSU9OX09QRU5cbiAgICAgICAgfSk7XG4gICAgfSxcbiAgICBjbG9zZTogZnVuY3Rpb24gKCkge1xuICAgICAgICBBcHBEaXNwYXRjaGVyLmRpc3BhdGNoVmlld0FjdGlvbih7XG4gICAgICAgICAgICB0eXBlOiBBY3Rpb25UeXBlcy5DT05ORUNUSU9OX0NMT1NFXG4gICAgICAgIH0pO1xuICAgIH0sXG4gICAgZXJyb3I6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgQXBwRGlzcGF0Y2hlci5kaXNwYXRjaFZpZXdBY3Rpb24oe1xuICAgICAgICAgICAgdHlwZTogQWN0aW9uVHlwZXMuQ09OTkVDVElPTl9FUlJPUlxuICAgICAgICB9KTtcbiAgICB9XG59O1xuXG52YXIgU2V0dGluZ3NBY3Rpb25zID0ge1xuICAgIHVwZGF0ZTogZnVuY3Rpb24gKHNldHRpbmdzKSB7XG5cbiAgICAgICAgalF1ZXJ5LmFqYXgoe1xuICAgICAgICAgICAgdHlwZTogXCJQVVRcIixcbiAgICAgICAgICAgIHVybDogXCIvc2V0dGluZ3NcIixcbiAgICAgICAgICAgIGRhdGE6IHNldHRpbmdzXG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8qXG4gICAgICAgIC8vRmFjZWJvb2sgRmx1eDogV2UgZG8gYW4gb3B0aW1pc3RpYyB1cGRhdGUgb24gdGhlIGNsaWVudCBhbHJlYWR5LlxuICAgICAgICBBcHBEaXNwYXRjaGVyLmRpc3BhdGNoVmlld0FjdGlvbih7XG4gICAgICAgICAgICB0eXBlOiBBY3Rpb25UeXBlcy5TRVRUSU5HU19TVE9SRSxcbiAgICAgICAgICAgIGNtZDogU3RvcmVDbWRzLlVQREFURSxcbiAgICAgICAgICAgIGRhdGE6IHNldHRpbmdzXG4gICAgICAgIH0pO1xuICAgICAgICAqL1xuICAgIH1cbn07XG5cbnZhciBFdmVudExvZ0FjdGlvbnNfZXZlbnRfaWQgPSAwO1xudmFyIEV2ZW50TG9nQWN0aW9ucyA9IHtcbiAgICBhZGRfZXZlbnQ6IGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgIEFwcERpc3BhdGNoZXIuZGlzcGF0Y2hWaWV3QWN0aW9uKHtcbiAgICAgICAgICAgIHR5cGU6IEFjdGlvblR5cGVzLkVWRU5UX1NUT1JFLFxuICAgICAgICAgICAgY21kOiBTdG9yZUNtZHMuQURELFxuICAgICAgICAgICAgZGF0YToge1xuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IG1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgbGV2ZWw6IFwid2ViXCIsXG4gICAgICAgICAgICAgICAgaWQ6IFwidmlld0FjdGlvbi1cIiArIEV2ZW50TG9nQWN0aW9uc19ldmVudF9pZCsrXG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cbn07XG5cbnZhciBGbG93QWN0aW9ucyA9IHtcbiAgICBhY2NlcHQ6IGZ1bmN0aW9uIChmbG93KSB7XG4gICAgICAgIGpRdWVyeS5wb3N0KFwiL2Zsb3dzL1wiICsgZmxvdy5pZCArIFwiL2FjY2VwdFwiKTtcbiAgICB9LFxuICAgIGFjY2VwdF9hbGw6IGZ1bmN0aW9uKCl7XG4gICAgICAgIGpRdWVyeS5wb3N0KFwiL2Zsb3dzL2FjY2VwdFwiKTtcbiAgICB9LFxuICAgIFwiZGVsZXRlXCI6IGZ1bmN0aW9uKGZsb3cpe1xuICAgICAgICBqUXVlcnkuYWpheCh7XG4gICAgICAgICAgICB0eXBlOlwiREVMRVRFXCIsXG4gICAgICAgICAgICB1cmw6IFwiL2Zsb3dzL1wiICsgZmxvdy5pZFxuICAgICAgICB9KTtcbiAgICB9LFxuICAgIGR1cGxpY2F0ZTogZnVuY3Rpb24oZmxvdyl7XG4gICAgICAgIGpRdWVyeS5wb3N0KFwiL2Zsb3dzL1wiICsgZmxvdy5pZCArIFwiL2R1cGxpY2F0ZVwiKTtcbiAgICB9LFxuICAgIHJlcGxheTogZnVuY3Rpb24oZmxvdyl7XG4gICAgICAgIGpRdWVyeS5wb3N0KFwiL2Zsb3dzL1wiICsgZmxvdy5pZCArIFwiL3JlcGxheVwiKTtcbiAgICB9LFxuICAgIHJldmVydDogZnVuY3Rpb24oZmxvdyl7XG4gICAgICAgIGpRdWVyeS5wb3N0KFwiL2Zsb3dzL1wiICsgZmxvdy5pZCArIFwiL3JldmVydFwiKTtcbiAgICB9LFxuICAgIHVwZGF0ZTogZnVuY3Rpb24gKGZsb3cpIHtcbiAgICAgICAgQXBwRGlzcGF0Y2hlci5kaXNwYXRjaFZpZXdBY3Rpb24oe1xuICAgICAgICAgICAgdHlwZTogQWN0aW9uVHlwZXMuRkxPV19TVE9SRSxcbiAgICAgICAgICAgIGNtZDogU3RvcmVDbWRzLlVQREFURSxcbiAgICAgICAgICAgIGRhdGE6IGZsb3dcbiAgICAgICAgfSk7XG4gICAgfSxcbiAgICBjbGVhcjogZnVuY3Rpb24oKXtcbiAgICAgICAgalF1ZXJ5LnBvc3QoXCIvY2xlYXJcIik7XG4gICAgfVxufTtcblxuUXVlcnkgPSB7XG4gICAgRklMVEVSOiBcImZcIixcbiAgICBISUdITElHSFQ6IFwiaFwiLFxuICAgIFNIT1dfRVZFTlRMT0c6IFwiZVwiXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBBY3Rpb25UeXBlczogQWN0aW9uVHlwZXMsXG4gICAgQ29ubmVjdGlvbkFjdGlvbnM6IENvbm5lY3Rpb25BY3Rpb25zXG5cbn07IiwiXG52YXIgUmVhY3QgPSByZXF1aXJlKFwicmVhY3RcIik7XG52YXIgUmVhY3RSb3V0ZXIgPSByZXF1aXJlKFwicmVhY3Qtcm91dGVyXCIpO1xudmFyICQgPSByZXF1aXJlKFwianF1ZXJ5XCIpO1xuXG52YXIgQ29ubmVjdGlvbiA9IHJlcXVpcmUoXCIuL2Nvbm5lY3Rpb25cIik7XG52YXIgcHJveHlhcHAgPSByZXF1aXJlKFwiLi9jb21wb25lbnRzL3Byb3h5YXBwLmpzeC5qc1wiKTtcblxuJChmdW5jdGlvbiAoKSB7XG4gICAgd2luZG93LndzID0gbmV3IENvbm5lY3Rpb24oXCIvdXBkYXRlc1wiKTtcblxuICAgIFJlYWN0Um91dGVyLnJ1bihwcm94eWFwcC5yb3V0ZXMsIGZ1bmN0aW9uIChIYW5kbGVyKSB7XG4gICAgICAgIFJlYWN0LnJlbmRlcihSZWFjdC5jcmVhdGVFbGVtZW50KEhhbmRsZXIsIG51bGwpLCBkb2N1bWVudC5ib2R5KTtcbiAgICB9KTtcbn0pOyIsInZhciBSZWFjdCA9IHJlcXVpcmUoXCJyZWFjdFwiKTtcbnZhciBmbG93dXRpbHMgPSByZXF1aXJlKFwiLi4vZmxvdy91dGlscy5qc1wiKTtcbnZhciB1dGlscyA9IHJlcXVpcmUoXCIuLi91dGlscy5qc1wiKTtcblxudmFyIFRMU0NvbHVtbiA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtkaXNwbGF5TmFtZTogXCJUTFNDb2x1bW5cIixcbiAgICBzdGF0aWNzOiB7XG4gICAgICAgIHJlbmRlclRpdGxlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gUmVhY3QuY3JlYXRlRWxlbWVudChcInRoXCIsIHtrZXk6IFwidGxzXCIsIGNsYXNzTmFtZTogXCJjb2wtdGxzXCJ9KTtcbiAgICAgICAgfVxuICAgIH0sXG4gICAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBmbG93ID0gdGhpcy5wcm9wcy5mbG93O1xuICAgICAgICB2YXIgc3NsID0gKGZsb3cucmVxdWVzdC5zY2hlbWUgPT0gXCJodHRwc1wiKTtcbiAgICAgICAgdmFyIGNsYXNzZXM7XG4gICAgICAgIGlmIChzc2wpIHtcbiAgICAgICAgICAgIGNsYXNzZXMgPSBcImNvbC10bHMgY29sLXRscy1odHRwc1wiO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY2xhc3NlcyA9IFwiY29sLXRscyBjb2wtdGxzLWh0dHBcIjtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gUmVhY3QuY3JlYXRlRWxlbWVudChcInRkXCIsIHtjbGFzc05hbWU6IGNsYXNzZXN9KTtcbiAgICB9XG59KTtcblxuXG52YXIgSWNvbkNvbHVtbiA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtkaXNwbGF5TmFtZTogXCJJY29uQ29sdW1uXCIsXG4gICAgc3RhdGljczoge1xuICAgICAgICByZW5kZXJUaXRsZTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJ0aFwiLCB7a2V5OiBcImljb25cIiwgY2xhc3NOYW1lOiBcImNvbC1pY29uXCJ9KTtcbiAgICAgICAgfVxuICAgIH0sXG4gICAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBmbG93ID0gdGhpcy5wcm9wcy5mbG93O1xuXG4gICAgICAgIHZhciBpY29uO1xuICAgICAgICBpZiAoZmxvdy5yZXNwb25zZSkge1xuICAgICAgICAgICAgdmFyIGNvbnRlbnRUeXBlID0gZmxvd3V0aWxzLlJlc3BvbnNlVXRpbHMuZ2V0Q29udGVudFR5cGUoZmxvdy5yZXNwb25zZSk7XG5cbiAgICAgICAgICAgIC8vVE9ETzogV2Ugc2hvdWxkIGFzc2lnbiBhIHR5cGUgdG8gdGhlIGZsb3cgc29tZXdoZXJlIGVsc2UuXG4gICAgICAgICAgICBpZiAoZmxvdy5yZXNwb25zZS5jb2RlID09IDMwNCkge1xuICAgICAgICAgICAgICAgIGljb24gPSBcInJlc291cmNlLWljb24tbm90LW1vZGlmaWVkXCI7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKDMwMCA8PSBmbG93LnJlc3BvbnNlLmNvZGUgJiYgZmxvdy5yZXNwb25zZS5jb2RlIDwgNDAwKSB7XG4gICAgICAgICAgICAgICAgaWNvbiA9IFwicmVzb3VyY2UtaWNvbi1yZWRpcmVjdFwiO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChjb250ZW50VHlwZSAmJiBjb250ZW50VHlwZS5pbmRleE9mKFwiaW1hZ2VcIikgPj0gMCkge1xuICAgICAgICAgICAgICAgIGljb24gPSBcInJlc291cmNlLWljb24taW1hZ2VcIjtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoY29udGVudFR5cGUgJiYgY29udGVudFR5cGUuaW5kZXhPZihcImphdmFzY3JpcHRcIikgPj0gMCkge1xuICAgICAgICAgICAgICAgIGljb24gPSBcInJlc291cmNlLWljb24tanNcIjtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoY29udGVudFR5cGUgJiYgY29udGVudFR5cGUuaW5kZXhPZihcImNzc1wiKSA+PSAwKSB7XG4gICAgICAgICAgICAgICAgaWNvbiA9IFwicmVzb3VyY2UtaWNvbi1jc3NcIjtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoY29udGVudFR5cGUgJiYgY29udGVudFR5cGUuaW5kZXhPZihcImh0bWxcIikgPj0gMCkge1xuICAgICAgICAgICAgICAgIGljb24gPSBcInJlc291cmNlLWljb24tZG9jdW1lbnRcIjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoIWljb24pIHtcbiAgICAgICAgICAgIGljb24gPSBcInJlc291cmNlLWljb24tcGxhaW5cIjtcbiAgICAgICAgfVxuXG5cbiAgICAgICAgaWNvbiArPSBcIiByZXNvdXJjZS1pY29uXCI7XG4gICAgICAgIHJldHVybiBSZWFjdC5jcmVhdGVFbGVtZW50KFwidGRcIiwge2NsYXNzTmFtZTogXCJjb2wtaWNvblwifSwgXG4gICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFwiZGl2XCIsIHtjbGFzc05hbWU6IGljb259KVxuICAgICAgICApO1xuICAgIH1cbn0pO1xuXG52YXIgUGF0aENvbHVtbiA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtkaXNwbGF5TmFtZTogXCJQYXRoQ29sdW1uXCIsXG4gICAgc3RhdGljczoge1xuICAgICAgICByZW5kZXJUaXRsZTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJ0aFwiLCB7a2V5OiBcInBhdGhcIiwgY2xhc3NOYW1lOiBcImNvbC1wYXRoXCJ9LCBcIlBhdGhcIik7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgZmxvdyA9IHRoaXMucHJvcHMuZmxvdztcbiAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJ0ZFwiLCB7Y2xhc3NOYW1lOiBcImNvbC1wYXRoXCJ9LCBcbiAgICAgICAgICAgIGZsb3cucmVxdWVzdC5pc19yZXBsYXkgPyBSZWFjdC5jcmVhdGVFbGVtZW50KFwiaVwiLCB7Y2xhc3NOYW1lOiBcImZhIGZhLWZ3IGZhLXJlcGVhdCBwdWxsLXJpZ2h0XCJ9KSA6IG51bGwsIFxuICAgICAgICAgICAgZmxvdy5pbnRlcmNlcHRlZCA/IFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJpXCIsIHtjbGFzc05hbWU6IFwiZmEgZmEtZncgZmEtcGF1c2UgcHVsbC1yaWdodFwifSkgOiBudWxsLCBcbiAgICAgICAgICAgIGZsb3cucmVxdWVzdC5zY2hlbWUgKyBcIjovL1wiICsgZmxvdy5yZXF1ZXN0Lmhvc3QgKyBmbG93LnJlcXVlc3QucGF0aFxuICAgICAgICApO1xuICAgIH1cbn0pO1xuXG5cbnZhciBNZXRob2RDb2x1bW4gPSBSZWFjdC5jcmVhdGVDbGFzcyh7ZGlzcGxheU5hbWU6IFwiTWV0aG9kQ29sdW1uXCIsXG4gICAgc3RhdGljczoge1xuICAgICAgICByZW5kZXJUaXRsZTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJ0aFwiLCB7a2V5OiBcIm1ldGhvZFwiLCBjbGFzc05hbWU6IFwiY29sLW1ldGhvZFwifSwgXCJNZXRob2RcIik7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgZmxvdyA9IHRoaXMucHJvcHMuZmxvdztcbiAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJ0ZFwiLCB7Y2xhc3NOYW1lOiBcImNvbC1tZXRob2RcIn0sIGZsb3cucmVxdWVzdC5tZXRob2QpO1xuICAgIH1cbn0pO1xuXG5cbnZhciBTdGF0dXNDb2x1bW4gPSBSZWFjdC5jcmVhdGVDbGFzcyh7ZGlzcGxheU5hbWU6IFwiU3RhdHVzQ29sdW1uXCIsXG4gICAgc3RhdGljczoge1xuICAgICAgICByZW5kZXJUaXRsZTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJ0aFwiLCB7a2V5OiBcInN0YXR1c1wiLCBjbGFzc05hbWU6IFwiY29sLXN0YXR1c1wifSwgXCJTdGF0dXNcIik7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgZmxvdyA9IHRoaXMucHJvcHMuZmxvdztcbiAgICAgICAgdmFyIHN0YXR1cztcbiAgICAgICAgaWYgKGZsb3cucmVzcG9uc2UpIHtcbiAgICAgICAgICAgIHN0YXR1cyA9IGZsb3cucmVzcG9uc2UuY29kZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHN0YXR1cyA9IG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJ0ZFwiLCB7Y2xhc3NOYW1lOiBcImNvbC1zdGF0dXNcIn0sIHN0YXR1cyk7XG4gICAgfVxufSk7XG5cblxudmFyIFNpemVDb2x1bW4gPSBSZWFjdC5jcmVhdGVDbGFzcyh7ZGlzcGxheU5hbWU6IFwiU2l6ZUNvbHVtblwiLFxuICAgIHN0YXRpY3M6IHtcbiAgICAgICAgcmVuZGVyVGl0bGU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBSZWFjdC5jcmVhdGVFbGVtZW50KFwidGhcIiwge2tleTogXCJzaXplXCIsIGNsYXNzTmFtZTogXCJjb2wtc2l6ZVwifSwgXCJTaXplXCIpO1xuICAgICAgICB9XG4gICAgfSxcbiAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGZsb3cgPSB0aGlzLnByb3BzLmZsb3c7XG5cbiAgICAgICAgdmFyIHRvdGFsID0gZmxvdy5yZXF1ZXN0LmNvbnRlbnRMZW5ndGg7XG4gICAgICAgIGlmIChmbG93LnJlc3BvbnNlKSB7XG4gICAgICAgICAgICB0b3RhbCArPSBmbG93LnJlc3BvbnNlLmNvbnRlbnRMZW5ndGggfHwgMDtcbiAgICAgICAgfVxuICAgICAgICB2YXIgc2l6ZSA9IHV0aWxzLmZvcm1hdFNpemUodG90YWwpO1xuICAgICAgICByZXR1cm4gUmVhY3QuY3JlYXRlRWxlbWVudChcInRkXCIsIHtjbGFzc05hbWU6IFwiY29sLXNpemVcIn0sIHNpemUpO1xuICAgIH1cbn0pO1xuXG5cbnZhciBUaW1lQ29sdW1uID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIlRpbWVDb2x1bW5cIixcbiAgICBzdGF0aWNzOiB7XG4gICAgICAgIHJlbmRlclRpdGxlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gUmVhY3QuY3JlYXRlRWxlbWVudChcInRoXCIsIHtrZXk6IFwidGltZVwiLCBjbGFzc05hbWU6IFwiY29sLXRpbWVcIn0sIFwiVGltZVwiKTtcbiAgICAgICAgfVxuICAgIH0sXG4gICAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBmbG93ID0gdGhpcy5wcm9wcy5mbG93O1xuICAgICAgICB2YXIgdGltZTtcbiAgICAgICAgaWYgKGZsb3cucmVzcG9uc2UpIHtcbiAgICAgICAgICAgIHRpbWUgPSB1dGlscy5mb3JtYXRUaW1lRGVsdGEoMTAwMCAqIChmbG93LnJlc3BvbnNlLnRpbWVzdGFtcF9lbmQgLSBmbG93LnJlcXVlc3QudGltZXN0YW1wX3N0YXJ0KSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aW1lID0gXCIuLi5cIjtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gUmVhY3QuY3JlYXRlRWxlbWVudChcInRkXCIsIHtjbGFzc05hbWU6IFwiY29sLXRpbWVcIn0sIHRpbWUpO1xuICAgIH1cbn0pO1xuXG5cbnZhciBhbGxfY29sdW1ucyA9IFtcbiAgICBUTFNDb2x1bW4sXG4gICAgSWNvbkNvbHVtbixcbiAgICBQYXRoQ29sdW1uLFxuICAgIE1ldGhvZENvbHVtbixcbiAgICBTdGF0dXNDb2x1bW4sXG4gICAgU2l6ZUNvbHVtbixcbiAgICBUaW1lQ29sdW1uXTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IGFsbF9jb2x1bW5zO1xuXG5cbiIsInZhciBSZWFjdCA9IHJlcXVpcmUoXCJyZWFjdFwiKTtcbnZhciB1dGlscyA9IHJlcXVpcmUoXCIuL3V0aWxzLmpzeC5qc1wiKTtcbnZhciBWaXJ0dWFsU2Nyb2xsTWl4aW4gPSByZXF1aXJlKFwiLi92aXJ0dWFsc2Nyb2xsLmpzeC5qc1wiKTtcbnZhciBmbG93dGFibGVfY29sdW1ucyA9IHJlcXVpcmUoXCIuL2Zsb3d0YWJsZS1jb2x1bW5zLmpzeC5qc1wiKTtcblxudmFyIEZsb3dSb3cgPSBSZWFjdC5jcmVhdGVDbGFzcyh7ZGlzcGxheU5hbWU6IFwiRmxvd1Jvd1wiLFxuICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgZmxvdyA9IHRoaXMucHJvcHMuZmxvdztcbiAgICAgICAgdmFyIGNvbHVtbnMgPSB0aGlzLnByb3BzLmNvbHVtbnMubWFwKGZ1bmN0aW9uIChDb2x1bW4pIHtcbiAgICAgICAgICAgIHJldHVybiBSZWFjdC5jcmVhdGVFbGVtZW50KENvbHVtbiwge2tleTogQ29sdW1uLmRpc3BsYXlOYW1lLCBmbG93OiBmbG93fSk7XG4gICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgICAgIHZhciBjbGFzc05hbWUgPSBcIlwiO1xuICAgICAgICBpZiAodGhpcy5wcm9wcy5zZWxlY3RlZCkge1xuICAgICAgICAgICAgY2xhc3NOYW1lICs9IFwiIHNlbGVjdGVkXCI7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMucHJvcHMuaGlnaGxpZ2h0ZWQpIHtcbiAgICAgICAgICAgIGNsYXNzTmFtZSArPSBcIiBoaWdobGlnaHRlZFwiO1xuICAgICAgICB9XG4gICAgICAgIGlmIChmbG93LmludGVyY2VwdGVkKSB7XG4gICAgICAgICAgICBjbGFzc05hbWUgKz0gXCIgaW50ZXJjZXB0ZWRcIjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZmxvdy5yZXF1ZXN0KSB7XG4gICAgICAgICAgICBjbGFzc05hbWUgKz0gXCIgaGFzLXJlcXVlc3RcIjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZmxvdy5yZXNwb25zZSkge1xuICAgICAgICAgICAgY2xhc3NOYW1lICs9IFwiIGhhcy1yZXNwb25zZVwiO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJ0clwiLCB7Y2xhc3NOYW1lOiBjbGFzc05hbWUsIG9uQ2xpY2s6IHRoaXMucHJvcHMuc2VsZWN0Rmxvdy5iaW5kKG51bGwsIGZsb3cpfSwgXG4gICAgICAgICAgICAgICAgY29sdW1uc1xuICAgICAgICAgICAgKSk7XG4gICAgfSxcbiAgICBzaG91bGRDb21wb25lbnRVcGRhdGU6IGZ1bmN0aW9uIChuZXh0UHJvcHMpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIC8vIEZ1cnRoZXIgb3B0aW1pemF0aW9uIGNvdWxkIGJlIGRvbmUgaGVyZVxuICAgICAgICAvLyBieSBjYWxsaW5nIGZvcmNlVXBkYXRlIG9uIGZsb3cgdXBkYXRlcywgc2VsZWN0aW9uIGNoYW5nZXMgYW5kIGNvbHVtbiBjaGFuZ2VzLlxuICAgICAgICAvL3JldHVybiAoXG4gICAgICAgIC8vKHRoaXMucHJvcHMuY29sdW1ucy5sZW5ndGggIT09IG5leHRQcm9wcy5jb2x1bW5zLmxlbmd0aCkgfHxcbiAgICAgICAgLy8odGhpcy5wcm9wcy5zZWxlY3RlZCAhPT0gbmV4dFByb3BzLnNlbGVjdGVkKVxuICAgICAgICAvLyk7XG4gICAgfVxufSk7XG5cbnZhciBGbG93VGFibGVIZWFkID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIkZsb3dUYWJsZUhlYWRcIixcbiAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGNvbHVtbnMgPSB0aGlzLnByb3BzLmNvbHVtbnMubWFwKGZ1bmN0aW9uIChjb2x1bW4pIHtcbiAgICAgICAgICAgIHJldHVybiBjb2x1bW4ucmVuZGVyVGl0bGUoKTtcbiAgICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJ0aGVhZFwiLCBudWxsLCBcbiAgICAgICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJ0clwiLCBudWxsLCBjb2x1bW5zKVxuICAgICAgICApO1xuICAgIH1cbn0pO1xuXG5cbnZhciBST1dfSEVJR0hUID0gMzI7XG5cbnZhciBGbG93VGFibGUgPSBSZWFjdC5jcmVhdGVDbGFzcyh7ZGlzcGxheU5hbWU6IFwiRmxvd1RhYmxlXCIsXG4gICAgbWl4aW5zOiBbdXRpbHMuU3RpY2t5SGVhZE1peGluLCB1dGlscy5BdXRvU2Nyb2xsTWl4aW4sIFZpcnR1YWxTY3JvbGxNaXhpbl0sXG4gICAgZ2V0SW5pdGlhbFN0YXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBjb2x1bW5zOiBmbG93dGFibGVfY29sdW1uc1xuICAgICAgICB9O1xuICAgIH0sXG4gICAgY29tcG9uZW50V2lsbE1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICh0aGlzLnByb3BzLnZpZXcpIHtcbiAgICAgICAgICAgIHRoaXMucHJvcHMudmlldy5hZGRMaXN0ZW5lcihcImFkZCB1cGRhdGUgcmVtb3ZlIHJlY2FsY3VsYXRlXCIsIHRoaXMub25DaGFuZ2UpO1xuICAgICAgICB9XG4gICAgfSxcbiAgICBjb21wb25lbnRXaWxsUmVjZWl2ZVByb3BzOiBmdW5jdGlvbiAobmV4dFByb3BzKSB7XG4gICAgICAgIGlmIChuZXh0UHJvcHMudmlldyAhPT0gdGhpcy5wcm9wcy52aWV3KSB7XG4gICAgICAgICAgICBpZiAodGhpcy5wcm9wcy52aWV3KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5wcm9wcy52aWV3LnJlbW92ZUxpc3RlbmVyKFwiYWRkIHVwZGF0ZSByZW1vdmUgcmVjYWxjdWxhdGVcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBuZXh0UHJvcHMudmlldy5hZGRMaXN0ZW5lcihcImFkZCB1cGRhdGUgcmVtb3ZlIHJlY2FsY3VsYXRlXCIsIHRoaXMub25DaGFuZ2UpO1xuICAgICAgICB9XG4gICAgfSxcbiAgICBnZXREZWZhdWx0UHJvcHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHJvd0hlaWdodDogUk9XX0hFSUdIVFxuICAgICAgICB9O1xuICAgIH0sXG4gICAgb25TY3JvbGxGbG93VGFibGU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5hZGp1c3RIZWFkKCk7XG4gICAgICAgIHRoaXMub25TY3JvbGwoKTtcbiAgICB9LFxuICAgIG9uQ2hhbmdlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuZm9yY2VVcGRhdGUoKTtcbiAgICB9LFxuICAgIHNjcm9sbEludG9WaWV3OiBmdW5jdGlvbiAoZmxvdykge1xuICAgICAgICB0aGlzLnNjcm9sbFJvd0ludG9WaWV3KFxuICAgICAgICAgICAgdGhpcy5wcm9wcy52aWV3LmluZGV4KGZsb3cpLFxuICAgICAgICAgICAgdGhpcy5yZWZzLmJvZHkuZ2V0RE9NTm9kZSgpLm9mZnNldFRvcFxuICAgICAgICApO1xuICAgIH0sXG4gICAgcmVuZGVyUm93OiBmdW5jdGlvbiAoZmxvdykge1xuICAgICAgICB2YXIgc2VsZWN0ZWQgPSAoZmxvdyA9PT0gdGhpcy5wcm9wcy5zZWxlY3RlZCk7XG4gICAgICAgIHZhciBoaWdobGlnaHRlZCA9XG4gICAgICAgICAgICAoXG4gICAgICAgICAgICB0aGlzLnByb3BzLnZpZXcuX2hpZ2hsaWdodCAmJlxuICAgICAgICAgICAgdGhpcy5wcm9wcy52aWV3Ll9oaWdobGlnaHRbZmxvdy5pZF1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRmxvd1Jvdywge2tleTogZmxvdy5pZCwgXG4gICAgICAgICAgICByZWY6IGZsb3cuaWQsIFxuICAgICAgICAgICAgZmxvdzogZmxvdywgXG4gICAgICAgICAgICBjb2x1bW5zOiB0aGlzLnN0YXRlLmNvbHVtbnMsIFxuICAgICAgICAgICAgc2VsZWN0ZWQ6IHNlbGVjdGVkLCBcbiAgICAgICAgICAgIGhpZ2hsaWdodGVkOiBoaWdobGlnaHRlZCwgXG4gICAgICAgICAgICBzZWxlY3RGbG93OiB0aGlzLnByb3BzLnNlbGVjdEZsb3d9XG4gICAgICAgICk7XG4gICAgfSxcbiAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgLy9jb25zb2xlLmxvZyhcInJlbmRlciBmbG93dGFibGVcIiwgdGhpcy5zdGF0ZS5zdGFydCwgdGhpcy5zdGF0ZS5zdG9wLCB0aGlzLnByb3BzLnNlbGVjdGVkKTtcbiAgICAgICAgdmFyIGZsb3dzID0gdGhpcy5wcm9wcy52aWV3ID8gdGhpcy5wcm9wcy52aWV3Lmxpc3QgOiBbXTtcblxuICAgICAgICB2YXIgcm93cyA9IHRoaXMucmVuZGVyUm93cyhmbG93cyk7XG5cbiAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwge2NsYXNzTmFtZTogXCJmbG93LXRhYmxlXCIsIG9uU2Nyb2xsOiB0aGlzLm9uU2Nyb2xsRmxvd1RhYmxlfSwgXG4gICAgICAgICAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChcInRhYmxlXCIsIG51bGwsIFxuICAgICAgICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KEZsb3dUYWJsZUhlYWQsIHtyZWY6IFwiaGVhZFwiLCBcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbnM6IHRoaXMuc3RhdGUuY29sdW1uc30pLCBcbiAgICAgICAgICAgICAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChcInRib2R5XCIsIHtyZWY6IFwiYm9keVwifSwgXG4gICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5nZXRQbGFjZWhvbGRlclRvcChmbG93cy5sZW5ndGgpLCBcbiAgICAgICAgICAgICAgICAgICAgICAgIHJvd3MsIFxuICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZ2V0UGxhY2Vob2xkZXJCb3R0b20oZmxvd3MubGVuZ3RoKSBcbiAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgIClcbiAgICAgICAgKTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBGbG93VGFibGU7XG4iLCJ2YXIgUmVhY3QgPSByZXF1aXJlKFwicmVhY3RcIik7XG5cbnZhciBGb290ZXIgPSBSZWFjdC5jcmVhdGVDbGFzcyh7ZGlzcGxheU5hbWU6IFwiRm9vdGVyXCIsXG4gICAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBtb2RlID0gdGhpcy5wcm9wcy5zZXR0aW5ncy5tb2RlO1xuICAgICAgICB2YXIgaW50ZXJjZXB0ID0gdGhpcy5wcm9wcy5zZXR0aW5ncy5pbnRlcmNlcHQ7XG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFwiZm9vdGVyXCIsIG51bGwsIFxuICAgICAgICAgICAgICAgIG1vZGUgIT0gXCJyZWd1bGFyXCIgPyBSZWFjdC5jcmVhdGVFbGVtZW50KFwic3BhblwiLCB7Y2xhc3NOYW1lOiBcImxhYmVsIGxhYmVsLXN1Y2Nlc3NcIn0sIG1vZGUsIFwiIG1vZGVcIikgOiBudWxsLCBcbiAgICAgICAgICAgICAgICBcIsKgXCIsIFxuICAgICAgICAgICAgICAgIGludGVyY2VwdCA/IFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJzcGFuXCIsIHtjbGFzc05hbWU6IFwibGFiZWwgbGFiZWwtc3VjY2Vzc1wifSwgXCJJbnRlcmNlcHQ6IFwiLCBpbnRlcmNlcHQpIDogbnVsbFxuICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEZvb3RlcjsiLCJ2YXIgUmVhY3QgPSByZXF1aXJlKFwicmVhY3RcIik7XG52YXIgJCA9IHJlcXVpcmUoXCJqcXVlcnlcIik7XG5cbnZhciB1dGlscyA9IHJlcXVpcmUoXCIuL3V0aWxzLmpzeC5qc1wiKTtcblxudmFyIEZpbHRlckRvY3MgPSBSZWFjdC5jcmVhdGVDbGFzcyh7ZGlzcGxheU5hbWU6IFwiRmlsdGVyRG9jc1wiLFxuICAgIHN0YXRpY3M6IHtcbiAgICAgICAgeGhyOiBmYWxzZSxcbiAgICAgICAgZG9jOiBmYWxzZVxuICAgIH0sXG4gICAgY29tcG9uZW50V2lsbE1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICghRmlsdGVyRG9jcy5kb2MpIHtcbiAgICAgICAgICAgIEZpbHRlckRvY3MueGhyID0gJC5nZXRKU09OKFwiL2ZpbHRlci1oZWxwXCIpLmRvbmUoZnVuY3Rpb24gKGRvYykge1xuICAgICAgICAgICAgICAgIEZpbHRlckRvY3MuZG9jID0gZG9jO1xuICAgICAgICAgICAgICAgIEZpbHRlckRvY3MueGhyID0gZmFsc2U7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoRmlsdGVyRG9jcy54aHIpIHtcbiAgICAgICAgICAgIEZpbHRlckRvY3MueGhyLmRvbmUoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHRoaXMuZm9yY2VVcGRhdGUoKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoIUZpbHRlckRvY3MuZG9jKSB7XG4gICAgICAgICAgICByZXR1cm4gUmVhY3QuY3JlYXRlRWxlbWVudChcImlcIiwge2NsYXNzTmFtZTogXCJmYSBmYS1zcGlubmVyIGZhLXNwaW5cIn0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdmFyIGNvbW1hbmRzID0gRmlsdGVyRG9jcy5kb2MuY29tbWFuZHMubWFwKGZ1bmN0aW9uIChjKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJ0clwiLCBudWxsLCBcbiAgICAgICAgICAgICAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChcInRkXCIsIG51bGwsIGNbMF0ucmVwbGFjZShcIiBcIiwgJ1xcdTAwYTAnKSksIFxuICAgICAgICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFwidGRcIiwgbnVsbCwgY1sxXSlcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBjb21tYW5kcy5wdXNoKFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJ0clwiLCBudWxsLCBcbiAgICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFwidGRcIiwge2NvbFNwYW46IFwiMlwifSwgXG4gICAgICAgICAgICAgICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJhXCIsIHtocmVmOiBcImh0dHBzOi8vbWl0bXByb3h5Lm9yZy9kb2MvZmVhdHVyZXMvZmlsdGVycy5odG1sXCIsIFxuICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0OiBcIl9ibGFua1wifSwgXG4gICAgICAgICAgICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFwiaVwiLCB7Y2xhc3NOYW1lOiBcImZhIGZhLWV4dGVybmFsLWxpbmtcIn0pLCBcbiAgICAgICAgICAgICAgICAgICAgXCLCoCBtaXRtcHJveHkgZG9jc1wiKVxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICkpO1xuICAgICAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJ0YWJsZVwiLCB7Y2xhc3NOYW1lOiBcInRhYmxlIHRhYmxlLWNvbmRlbnNlZFwifSwgXG4gICAgICAgICAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChcInRib2R5XCIsIG51bGwsIGNvbW1hbmRzKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xudmFyIEZpbHRlcklucHV0ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIkZpbHRlcklucHV0XCIsXG4gICAgZ2V0SW5pdGlhbFN0YXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIC8vIENvbnNpZGVyIGJvdGggZm9jdXMgYW5kIG1vdXNlb3ZlciBmb3Igc2hvd2luZy9oaWRpbmcgdGhlIHRvb2x0aXAsXG4gICAgICAgIC8vIGJlY2F1c2Ugb25CbHVyIG9mIHRoZSBpbnB1dCBpcyB0cmlnZ2VyZWQgYmVmb3JlIHRoZSBjbGljayBvbiB0aGUgdG9vbHRpcFxuICAgICAgICAvLyBmaW5hbGl6ZWQsIGhpZGluZyB0aGUgdG9vbHRpcCBqdXN0IGFzIHRoZSB1c2VyIGNsaWNrcyBvbiBpdC5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHZhbHVlOiB0aGlzLnByb3BzLnZhbHVlLFxuICAgICAgICAgICAgZm9jdXM6IGZhbHNlLFxuICAgICAgICAgICAgbW91c2Vmb2N1czogZmFsc2VcbiAgICAgICAgfTtcbiAgICB9LFxuICAgIGNvbXBvbmVudFdpbGxSZWNlaXZlUHJvcHM6IGZ1bmN0aW9uIChuZXh0UHJvcHMpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7dmFsdWU6IG5leHRQcm9wcy52YWx1ZX0pO1xuICAgIH0sXG4gICAgb25DaGFuZ2U6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIHZhciBuZXh0VmFsdWUgPSBlLnRhcmdldC52YWx1ZTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICB2YWx1ZTogbmV4dFZhbHVlXG4gICAgICAgIH0pO1xuICAgICAgICAvLyBPbmx5IHByb3BhZ2F0ZSB2YWxpZCBmaWx0ZXJzIHVwd2FyZHMuXG4gICAgICAgIGlmICh0aGlzLmlzVmFsaWQobmV4dFZhbHVlKSkge1xuICAgICAgICAgICAgdGhpcy5wcm9wcy5vbkNoYW5nZShuZXh0VmFsdWUpO1xuICAgICAgICB9XG4gICAgfSxcbiAgICBpc1ZhbGlkOiBmdW5jdGlvbiAoZmlsdCkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgRmlsdC5wYXJzZShmaWx0IHx8IHRoaXMuc3RhdGUudmFsdWUpO1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgIH0sXG4gICAgZ2V0RGVzYzogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgZGVzYztcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGRlc2MgPSBGaWx0LnBhcnNlKHRoaXMuc3RhdGUudmFsdWUpLmRlc2M7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGRlc2MgPSBcIlwiICsgZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZGVzYyAhPT0gXCJ0cnVlXCIpIHtcbiAgICAgICAgICAgIHJldHVybiBkZXNjO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KEZpbHRlckRvY3MsIG51bGwpXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgfSxcbiAgICBvbkZvY3VzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe2ZvY3VzOiB0cnVlfSk7XG4gICAgfSxcbiAgICBvbkJsdXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7Zm9jdXM6IGZhbHNlfSk7XG4gICAgfSxcbiAgICBvbk1vdXNlRW50ZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7bW91c2Vmb2N1czogdHJ1ZX0pO1xuICAgIH0sXG4gICAgb25Nb3VzZUxlYXZlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe21vdXNlZm9jdXM6IGZhbHNlfSk7XG4gICAgfSxcbiAgICBvbktleURvd246IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGlmIChlLmtleUNvZGUgPT09IEtleS5FU0MgfHwgZS5rZXlDb2RlID09PSBLZXkuRU5URVIpIHtcbiAgICAgICAgICAgIHRoaXMuYmx1cigpO1xuICAgICAgICAgICAgLy8gSWYgY2xvc2VkIHVzaW5nIEVTQy9FTlRFUiwgaGlkZSB0aGUgdG9vbHRpcC5cbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe21vdXNlZm9jdXM6IGZhbHNlfSk7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIGJsdXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5yZWZzLmlucHV0LmdldERPTU5vZGUoKS5ibHVyKCk7XG4gICAgfSxcbiAgICBmb2N1czogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLnJlZnMuaW5wdXQuZ2V0RE9NTm9kZSgpLnNlbGVjdCgpO1xuICAgIH0sXG4gICAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBpc1ZhbGlkID0gdGhpcy5pc1ZhbGlkKCk7XG4gICAgICAgIHZhciBpY29uID0gXCJmYSBmYS1mdyBmYS1cIiArIHRoaXMucHJvcHMudHlwZTtcbiAgICAgICAgdmFyIGdyb3VwQ2xhc3NOYW1lID0gXCJmaWx0ZXItaW5wdXQgaW5wdXQtZ3JvdXBcIiArIChpc1ZhbGlkID8gXCJcIiA6IFwiIGhhcy1lcnJvclwiKTtcblxuICAgICAgICB2YXIgcG9wb3ZlcjtcbiAgICAgICAgaWYgKHRoaXMuc3RhdGUuZm9jdXMgfHwgdGhpcy5zdGF0ZS5tb3VzZWZvY3VzKSB7XG4gICAgICAgICAgICBwb3BvdmVyID0gKFxuICAgICAgICAgICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwge2NsYXNzTmFtZTogXCJwb3BvdmVyIGJvdHRvbVwiLCBvbk1vdXNlRW50ZXI6IHRoaXMub25Nb3VzZUVudGVyLCBvbk1vdXNlTGVhdmU6IHRoaXMub25Nb3VzZUxlYXZlfSwgXG4gICAgICAgICAgICAgICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwge2NsYXNzTmFtZTogXCJhcnJvd1wifSksIFxuICAgICAgICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFwiZGl2XCIsIHtjbGFzc05hbWU6IFwicG9wb3Zlci1jb250ZW50XCJ9LCBcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5nZXREZXNjKClcbiAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChcImRpdlwiLCB7Y2xhc3NOYW1lOiBncm91cENsYXNzTmFtZX0sIFxuICAgICAgICAgICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJzcGFuXCIsIHtjbGFzc05hbWU6IFwiaW5wdXQtZ3JvdXAtYWRkb25cIn0sIFxuICAgICAgICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFwiaVwiLCB7Y2xhc3NOYW1lOiBpY29uLCBzdHlsZToge2NvbG9yOiB0aGlzLnByb3BzLmNvbG9yfX0pXG4gICAgICAgICAgICAgICAgKSwgXG4gICAgICAgICAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChcImlucHV0XCIsIHt0eXBlOiBcInRleHRcIiwgcGxhY2Vob2xkZXI6IHRoaXMucHJvcHMucGxhY2Vob2xkZXIsIGNsYXNzTmFtZTogXCJmb3JtLWNvbnRyb2xcIiwgXG4gICAgICAgICAgICAgICAgICAgIHJlZjogXCJpbnB1dFwiLCBcbiAgICAgICAgICAgICAgICAgICAgb25DaGFuZ2U6IHRoaXMub25DaGFuZ2UsIFxuICAgICAgICAgICAgICAgICAgICBvbkZvY3VzOiB0aGlzLm9uRm9jdXMsIFxuICAgICAgICAgICAgICAgICAgICBvbkJsdXI6IHRoaXMub25CbHVyLCBcbiAgICAgICAgICAgICAgICAgICAgb25LZXlEb3duOiB0aGlzLm9uS2V5RG93biwgXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlOiB0aGlzLnN0YXRlLnZhbHVlfSksIFxuICAgICAgICAgICAgICAgIHBvcG92ZXJcbiAgICAgICAgICAgIClcbiAgICAgICAgKTtcbiAgICB9XG59KTtcblxudmFyIE1haW5NZW51ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIk1haW5NZW51XCIsXG4gICAgbWl4aW5zOiBbdXRpbHMuTmF2aWdhdGlvbiwgdXRpbHMuU3RhdGVdLFxuICAgIHN0YXRpY3M6IHtcbiAgICAgICAgdGl0bGU6IFwiU3RhcnRcIixcbiAgICAgICAgcm91dGU6IFwiZmxvd3NcIlxuICAgIH0sXG4gICAgb25GaWx0ZXJDaGFuZ2U6IGZ1bmN0aW9uICh2YWwpIHtcbiAgICAgICAgdmFyIGQgPSB7fTtcbiAgICAgICAgZFtRdWVyeS5GSUxURVJdID0gdmFsO1xuICAgICAgICB0aGlzLnNldFF1ZXJ5KGQpO1xuICAgIH0sXG4gICAgb25IaWdobGlnaHRDaGFuZ2U6IGZ1bmN0aW9uICh2YWwpIHtcbiAgICAgICAgdmFyIGQgPSB7fTtcbiAgICAgICAgZFtRdWVyeS5ISUdITElHSFRdID0gdmFsO1xuICAgICAgICB0aGlzLnNldFF1ZXJ5KGQpO1xuICAgIH0sXG4gICAgb25JbnRlcmNlcHRDaGFuZ2U6IGZ1bmN0aW9uICh2YWwpIHtcbiAgICAgICAgU2V0dGluZ3NBY3Rpb25zLnVwZGF0ZSh7aW50ZXJjZXB0OiB2YWx9KTtcbiAgICB9LFxuICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgZmlsdGVyID0gdGhpcy5nZXRRdWVyeSgpW1F1ZXJ5LkZJTFRFUl0gfHwgXCJcIjtcbiAgICAgICAgdmFyIGhpZ2hsaWdodCA9IHRoaXMuZ2V0UXVlcnkoKVtRdWVyeS5ISUdITElHSFRdIHx8IFwiXCI7XG4gICAgICAgIHZhciBpbnRlcmNlcHQgPSB0aGlzLnByb3BzLnNldHRpbmdzLmludGVyY2VwdCB8fCBcIlwiO1xuXG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFwiZGl2XCIsIG51bGwsIFxuICAgICAgICAgICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwge2NsYXNzTmFtZTogXCJtZW51LXJvd1wifSwgXG4gICAgICAgICAgICAgICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRmlsdGVySW5wdXQsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyOiBcIkZpbHRlclwiLCBcbiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6IFwiZmlsdGVyXCIsIFxuICAgICAgICAgICAgICAgICAgICAgICAgY29sb3I6IFwiYmxhY2tcIiwgXG4gICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZTogZmlsdGVyLCBcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uQ2hhbmdlOiB0aGlzLm9uRmlsdGVyQ2hhbmdlfSksIFxuICAgICAgICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KEZpbHRlcklucHV0LCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcjogXCJIaWdobGlnaHRcIiwgXG4gICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiBcInRhZ1wiLCBcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yOiBcImhzbCg0OCwgMTAwJSwgNTAlKVwiLCBcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlOiBoaWdobGlnaHQsIFxuICAgICAgICAgICAgICAgICAgICAgICAgb25DaGFuZ2U6IHRoaXMub25IaWdobGlnaHRDaGFuZ2V9KSwgXG4gICAgICAgICAgICAgICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRmlsdGVySW5wdXQsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyOiBcIkludGVyY2VwdFwiLCBcbiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6IFwicGF1c2VcIiwgXG4gICAgICAgICAgICAgICAgICAgICAgICBjb2xvcjogXCJoc2woMjA4LCA1NiUsIDUzJSlcIiwgXG4gICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZTogaW50ZXJjZXB0LCBcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uQ2hhbmdlOiB0aGlzLm9uSW50ZXJjZXB0Q2hhbmdlfSlcbiAgICAgICAgICAgICAgICApLCBcbiAgICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFwiZGl2XCIsIHtjbGFzc05hbWU6IFwiY2xlYXJmaXhcIn0pXG4gICAgICAgICAgICApXG4gICAgICAgICk7XG4gICAgfVxufSk7XG5cblxudmFyIFZpZXdNZW51ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIlZpZXdNZW51XCIsXG4gICAgc3RhdGljczoge1xuICAgICAgICB0aXRsZTogXCJWaWV3XCIsXG4gICAgICAgIHJvdXRlOiBcImZsb3dzXCJcbiAgICB9LFxuICAgIG1peGluczogW3V0aWxzLk5hdmlnYXRpb24sIHV0aWxzLlN0YXRlXSxcbiAgICB0b2dnbGVFdmVudExvZzogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgZCA9IHt9O1xuXG4gICAgICAgIGlmICh0aGlzLmdldFF1ZXJ5KClbUXVlcnkuU0hPV19FVkVOVExPR10pIHtcbiAgICAgICAgICAgIGRbUXVlcnkuU0hPV19FVkVOVExPR10gPSB1bmRlZmluZWQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBkW1F1ZXJ5LlNIT1dfRVZFTlRMT0ddID0gXCJ0XCI7IC8vIGFueSBub24tZmFsc2UgdmFsdWUgd2lsbCBkbyBpdCwga2VlcCBpdCBzaG9ydFxuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXRRdWVyeShkKTtcbiAgICB9LFxuICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2hvd0V2ZW50TG9nID0gdGhpcy5nZXRRdWVyeSgpW1F1ZXJ5LlNIT1dfRVZFTlRMT0ddO1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChcImRpdlwiLCBudWxsLCBcbiAgICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFwiYnV0dG9uXCIsIHtcbiAgICAgICAgICAgICAgICAgICAgY2xhc3NOYW1lOiBcImJ0biBcIiArIChzaG93RXZlbnRMb2cgPyBcImJ0bi1wcmltYXJ5XCIgOiBcImJ0bi1kZWZhdWx0XCIpLCBcbiAgICAgICAgICAgICAgICAgICAgb25DbGljazogdGhpcy50b2dnbGVFdmVudExvZ30sIFxuICAgICAgICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFwiaVwiLCB7Y2xhc3NOYW1lOiBcImZhIGZhLWRhdGFiYXNlXCJ9KSwgXG4gICAgICAgICAgICAgICAgXCLCoFNob3cgRXZlbnRsb2dcIlxuICAgICAgICAgICAgICAgICksIFxuICAgICAgICAgICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJzcGFuXCIsIG51bGwsIFwiIFwiKVxuICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgIH1cbn0pO1xuXG5cbnZhciBSZXBvcnRzTWVudSA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtkaXNwbGF5TmFtZTogXCJSZXBvcnRzTWVudVwiLFxuICAgIHN0YXRpY3M6IHtcbiAgICAgICAgdGl0bGU6IFwiVmlzdWFsaXphdGlvblwiLFxuICAgICAgICByb3V0ZTogXCJyZXBvcnRzXCJcbiAgICB9LFxuICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gUmVhY3QuY3JlYXRlRWxlbWVudChcImRpdlwiLCBudWxsLCBcIlJlcG9ydHMgTWVudVwiKTtcbiAgICB9XG59KTtcblxudmFyIEZpbGVNZW51ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIkZpbGVNZW51XCIsXG4gICAgZ2V0SW5pdGlhbFN0YXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzaG93RmlsZU1lbnU6IGZhbHNlXG4gICAgICAgIH07XG4gICAgfSxcbiAgICBoYW5kbGVGaWxlQ2xpY2s6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgaWYgKCF0aGlzLnN0YXRlLnNob3dGaWxlTWVudSkge1xuICAgICAgICAgICAgdmFyIGNsb3NlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe3Nob3dGaWxlTWVudTogZmFsc2V9KTtcbiAgICAgICAgICAgICAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKFwiY2xpY2tcIiwgY2xvc2UpO1xuICAgICAgICAgICAgfS5iaW5kKHRoaXMpO1xuICAgICAgICAgICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsIGNsb3NlKTtcblxuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgc2hvd0ZpbGVNZW51OiB0cnVlXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH0sXG4gICAgaGFuZGxlTmV3Q2xpY2s6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgaWYgKGNvbmZpcm0oXCJEZWxldGUgYWxsIGZsb3dzP1wiKSkge1xuICAgICAgICAgICAgRmxvd0FjdGlvbnMuY2xlYXIoKTtcbiAgICAgICAgfVxuICAgIH0sXG4gICAgaGFuZGxlT3BlbkNsaWNrOiBmdW5jdGlvbiAoZSkge1xuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXCJ1bmltcGxlbWVudGVkOiBoYW5kbGVPcGVuQ2xpY2tcIik7XG4gICAgfSxcbiAgICBoYW5kbGVTYXZlQ2xpY2s6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgY29uc29sZS5lcnJvcihcInVuaW1wbGVtZW50ZWQ6IGhhbmRsZVNhdmVDbGlja1wiKTtcbiAgICB9LFxuICAgIGhhbmRsZVNodXRkb3duQ2xpY2s6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgY29uc29sZS5lcnJvcihcInVuaW1wbGVtZW50ZWQ6IGhhbmRsZVNodXRkb3duQ2xpY2tcIik7XG4gICAgfSxcbiAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGZpbGVNZW51Q2xhc3MgPSBcImRyb3Bkb3duIHB1bGwtbGVmdFwiICsgKHRoaXMuc3RhdGUuc2hvd0ZpbGVNZW51ID8gXCIgb3BlblwiIDogXCJcIik7XG5cbiAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwge2NsYXNzTmFtZTogZmlsZU1lbnVDbGFzc30sIFxuICAgICAgICAgICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJhXCIsIHtocmVmOiBcIiNcIiwgY2xhc3NOYW1lOiBcInNwZWNpYWxcIiwgb25DbGljazogdGhpcy5oYW5kbGVGaWxlQ2xpY2t9LCBcIiBGaWxlIFwiKSwgXG4gICAgICAgICAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChcInVsXCIsIHtjbGFzc05hbWU6IFwiZHJvcGRvd24tbWVudVwiLCByb2xlOiBcIm1lbnVcIn0sIFxuICAgICAgICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFwibGlcIiwgbnVsbCwgXG4gICAgICAgICAgICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFwiYVwiLCB7aHJlZjogXCIjXCIsIG9uQ2xpY2s6IHRoaXMuaGFuZGxlTmV3Q2xpY2t9LCBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFwiaVwiLCB7Y2xhc3NOYW1lOiBcImZhIGZhLWZ3IGZhLWZpbGVcIn0pLCBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIk5ld1wiXG4gICAgICAgICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgICAgICksIFxuICAgICAgICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFwibGlcIiwge3JvbGU6IFwicHJlc2VudGF0aW9uXCIsIGNsYXNzTmFtZTogXCJkaXZpZGVyXCJ9KSwgXG4gICAgICAgICAgICAgICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJsaVwiLCBudWxsLCBcbiAgICAgICAgICAgICAgICAgICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJhXCIsIHtocmVmOiBcImh0dHA6Ly9taXRtLml0L1wiLCB0YXJnZXQ6IFwiX2JsYW5rXCJ9LCBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFwiaVwiLCB7Y2xhc3NOYW1lOiBcImZhIGZhLWZ3IGZhLWV4dGVybmFsLWxpbmtcIn0pLCBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIkluc3RhbGwgQ2VydGlmaWNhdGVzLi4uXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgIC8qXG4gICAgICAgICAgICAgICAgIDxsaT5cbiAgICAgICAgICAgICAgICAgPGEgaHJlZj1cIiNcIiBvbkNsaWNrPXt0aGlzLmhhbmRsZU9wZW5DbGlja30+XG4gICAgICAgICAgICAgICAgIDxpIGNsYXNzTmFtZT1cImZhIGZhLWZ3IGZhLWZvbGRlci1vcGVuXCI+PC9pPlxuICAgICAgICAgICAgICAgICBPcGVuXG4gICAgICAgICAgICAgICAgIDwvYT5cbiAgICAgICAgICAgICAgICAgPC9saT5cbiAgICAgICAgICAgICAgICAgPGxpPlxuICAgICAgICAgICAgICAgICA8YSBocmVmPVwiI1wiIG9uQ2xpY2s9e3RoaXMuaGFuZGxlU2F2ZUNsaWNrfT5cbiAgICAgICAgICAgICAgICAgPGkgY2xhc3NOYW1lPVwiZmEgZmEtZncgZmEtc2F2ZVwiPjwvaT5cbiAgICAgICAgICAgICAgICAgU2F2ZVxuICAgICAgICAgICAgICAgICA8L2E+XG4gICAgICAgICAgICAgICAgIDwvbGk+XG4gICAgICAgICAgICAgICAgIDxsaSByb2xlPVwicHJlc2VudGF0aW9uXCIgY2xhc3NOYW1lPVwiZGl2aWRlclwiPjwvbGk+XG4gICAgICAgICAgICAgICAgIDxsaT5cbiAgICAgICAgICAgICAgICAgPGEgaHJlZj1cIiNcIiBvbkNsaWNrPXt0aGlzLmhhbmRsZVNodXRkb3duQ2xpY2t9PlxuICAgICAgICAgICAgICAgICA8aSBjbGFzc05hbWU9XCJmYSBmYS1mdyBmYS1wbHVnXCI+PC9pPlxuICAgICAgICAgICAgICAgICBTaHV0ZG93blxuICAgICAgICAgICAgICAgICA8L2E+XG4gICAgICAgICAgICAgICAgIDwvbGk+XG4gICAgICAgICAgICAgICAgICovXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgIH1cbn0pO1xuXG5cbnZhciBoZWFkZXJfZW50cmllcyA9IFtNYWluTWVudSwgVmlld01lbnUgLyosIFJlcG9ydHNNZW51ICovXTtcblxuXG52YXIgSGVhZGVyID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIkhlYWRlclwiLFxuICAgIG1peGluczogW3V0aWxzLk5hdmlnYXRpb25dLFxuICAgIGdldEluaXRpYWxTdGF0ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgYWN0aXZlOiBoZWFkZXJfZW50cmllc1swXVxuICAgICAgICB9O1xuICAgIH0sXG4gICAgaGFuZGxlQ2xpY2s6IGZ1bmN0aW9uIChhY3RpdmUsIGUpIHtcbiAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICB0aGlzLnJlcGxhY2VXaXRoKGFjdGl2ZS5yb3V0ZSk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe2FjdGl2ZTogYWN0aXZlfSk7XG4gICAgfSxcbiAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGhlYWRlciA9IGhlYWRlcl9lbnRyaWVzLm1hcChmdW5jdGlvbiAoZW50cnksIGkpIHtcbiAgICAgICAgICAgIHZhciBjbGFzc2VzID0gUmVhY3QuYWRkb25zLmNsYXNzU2V0KHtcbiAgICAgICAgICAgICAgICBhY3RpdmU6IGVudHJ5ID09IHRoaXMuc3RhdGUuYWN0aXZlXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChcImFcIiwge2tleTogaSwgXG4gICAgICAgICAgICAgICAgICAgIGhyZWY6IFwiI1wiLCBcbiAgICAgICAgICAgICAgICAgICAgY2xhc3NOYW1lOiBjbGFzc2VzLCBcbiAgICAgICAgICAgICAgICAgICAgb25DbGljazogdGhpcy5oYW5kbGVDbGljay5iaW5kKHRoaXMsIGVudHJ5KVxuICAgICAgICAgICAgICAgIH0sIFxuICAgICAgICAgICAgICAgICAgICAgZW50cnkudGl0bGVcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICApO1xuICAgICAgICB9LmJpbmQodGhpcykpO1xuXG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFwiaGVhZGVyXCIsIG51bGwsIFxuICAgICAgICAgICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwge2NsYXNzTmFtZTogXCJ0aXRsZS1iYXJcIn0sIFxuICAgICAgICAgICAgICAgICAgICBcIm1pdG1wcm94eSBcIiwgIHRoaXMucHJvcHMuc2V0dGluZ3MudmVyc2lvblxuICAgICAgICAgICAgICAgICksIFxuICAgICAgICAgICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJuYXZcIiwge2NsYXNzTmFtZTogXCJuYXYtdGFicyBuYXYtdGFicy1sZ1wifSwgXG4gICAgICAgICAgICAgICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRmlsZU1lbnUsIG51bGwpLCBcbiAgICAgICAgICAgICAgICAgICAgaGVhZGVyXG4gICAgICAgICAgICAgICAgKSwgXG4gICAgICAgICAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChcImRpdlwiLCB7Y2xhc3NOYW1lOiBcIm1lbnVcIn0sIFxuICAgICAgICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KHRoaXMuc3RhdGUuYWN0aXZlLCB7c2V0dGluZ3M6IHRoaXMucHJvcHMuc2V0dGluZ3N9KVxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgIClcbiAgICAgICAgKTtcbiAgICB9XG59KTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBIZWFkZXI6IEhlYWRlclxufSIsInZhciBSZWFjdCA9IHJlcXVpcmUoXCJyZWFjdFwiKTtcblxudmFyIHV0aWxzID0gcmVxdWlyZShcIi4vdXRpbHMuanN4LmpzXCIpO1xudmFyIHZpZXdzID0gcmVxdWlyZShcIi4uL3N0b3JlL3ZpZXcuanNcIik7XG52YXIgRmlsdCA9IHJlcXVpcmUoXCIuLi9maWx0L2ZpbHQuanNcIik7XG5GbG93VGFibGUgPSByZXF1aXJlKFwiLi9mbG93dGFibGUuanN4LmpzXCIpO1xuXG5cbnZhciBNYWluVmlldyA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtkaXNwbGF5TmFtZTogXCJNYWluVmlld1wiLFxuICAgIG1peGluczogW3V0aWxzLk5hdmlnYXRpb24sIHV0aWxzLlN0YXRlXSxcbiAgICBnZXRJbml0aWFsU3RhdGU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5vblF1ZXJ5Q2hhbmdlKFF1ZXJ5LkZJTFRFUiwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdGhpcy5zdGF0ZS52aWV3LnJlY2FsY3VsYXRlKHRoaXMuZ2V0Vmlld0ZpbHQoKSwgdGhpcy5nZXRWaWV3U29ydCgpKTtcbiAgICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICAgICAgdGhpcy5vblF1ZXJ5Q2hhbmdlKFF1ZXJ5LkhJR0hMSUdIVCwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdGhpcy5zdGF0ZS52aWV3LnJlY2FsY3VsYXRlKHRoaXMuZ2V0Vmlld0ZpbHQoKSwgdGhpcy5nZXRWaWV3U29ydCgpKTtcbiAgICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGZsb3dzOiBbXVxuICAgICAgICB9O1xuICAgIH0sXG4gICAgZ2V0Vmlld0ZpbHQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHZhciBmaWx0ID0gRmlsdC5wYXJzZSh0aGlzLmdldFF1ZXJ5KClbUXVlcnkuRklMVEVSXSB8fCBcIlwiKTtcbiAgICAgICAgICAgIHZhciBoaWdobGlnaHRTdHIgPSB0aGlzLmdldFF1ZXJ5KClbUXVlcnkuSElHSExJR0hUXTtcbiAgICAgICAgICAgIHZhciBoaWdobGlnaHQgPSBoaWdobGlnaHRTdHIgPyBGaWx0LnBhcnNlKGhpZ2hsaWdodFN0cikgOiBmYWxzZTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkVycm9yIHdoZW4gcHJvY2Vzc2luZyBmaWx0ZXI6IFwiICsgZSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZnVuY3Rpb24gZmlsdGVyX2FuZF9oaWdobGlnaHQoZmxvdykge1xuICAgICAgICAgICAgaWYgKCF0aGlzLl9oaWdobGlnaHQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9oaWdobGlnaHQgPSB7fTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuX2hpZ2hsaWdodFtmbG93LmlkXSA9IGhpZ2hsaWdodCAmJiBoaWdobGlnaHQoZmxvdyk7XG4gICAgICAgICAgICByZXR1cm4gZmlsdChmbG93KTtcbiAgICAgICAgfTtcbiAgICB9LFxuICAgIGdldFZpZXdTb3J0OiBmdW5jdGlvbiAoKSB7XG4gICAgfSxcbiAgICBjb21wb25lbnRXaWxsUmVjZWl2ZVByb3BzOiBmdW5jdGlvbiAobmV4dFByb3BzKSB7XG4gICAgICAgIGlmIChuZXh0UHJvcHMuZmxvd1N0b3JlICE9PSB0aGlzLnByb3BzLmZsb3dTdG9yZSkge1xuICAgICAgICAgICAgdGhpcy5jbG9zZVZpZXcoKTtcbiAgICAgICAgICAgIHRoaXMub3BlblZpZXcobmV4dFByb3BzLmZsb3dTdG9yZSk7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIG9wZW5WaWV3OiBmdW5jdGlvbiAoc3RvcmUpIHtcbiAgICAgICAgdmFyIHZpZXcgPSBuZXcgdmlld3MuU3RvcmVWaWV3KHN0b3JlLCB0aGlzLmdldFZpZXdGaWx0KCksIHRoaXMuZ2V0Vmlld1NvcnQoKSk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgdmlldzogdmlld1xuICAgICAgICB9KTtcblxuICAgICAgICB2aWV3LmFkZExpc3RlbmVyKFwicmVjYWxjdWxhdGVcIiwgdGhpcy5vblJlY2FsY3VsYXRlKTtcbiAgICAgICAgdmlldy5hZGRMaXN0ZW5lcihcImFkZCB1cGRhdGUgcmVtb3ZlXCIsIHRoaXMub25VcGRhdGUpO1xuICAgICAgICB2aWV3LmFkZExpc3RlbmVyKFwicmVtb3ZlXCIsIHRoaXMub25SZW1vdmUpO1xuICAgIH0sXG4gICAgb25SZWNhbGN1bGF0ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLmZvcmNlVXBkYXRlKCk7XG4gICAgICAgIHZhciBzZWxlY3RlZCA9IHRoaXMuZ2V0U2VsZWN0ZWQoKTtcbiAgICAgICAgaWYgKHNlbGVjdGVkKSB7XG4gICAgICAgICAgICB0aGlzLnJlZnMuZmxvd1RhYmxlLnNjcm9sbEludG9WaWV3KHNlbGVjdGVkKTtcbiAgICAgICAgfVxuICAgIH0sXG4gICAgb25VcGRhdGU6IGZ1bmN0aW9uIChmbG93KSB7XG4gICAgICAgIGlmIChmbG93LmlkID09PSB0aGlzLmdldFBhcmFtcygpLmZsb3dJZCkge1xuICAgICAgICAgICAgdGhpcy5mb3JjZVVwZGF0ZSgpO1xuICAgICAgICB9XG4gICAgfSxcbiAgICBvblJlbW92ZTogZnVuY3Rpb24gKGZsb3dfaWQsIGluZGV4KSB7XG4gICAgICAgIGlmIChmbG93X2lkID09PSB0aGlzLmdldFBhcmFtcygpLmZsb3dJZCkge1xuICAgICAgICAgICAgdmFyIGZsb3dfdG9fc2VsZWN0ID0gdGhpcy5zdGF0ZS52aWV3Lmxpc3RbTWF0aC5taW4oaW5kZXgsIHRoaXMuc3RhdGUudmlldy5saXN0Lmxlbmd0aCAtMSldO1xuICAgICAgICAgICAgdGhpcy5zZWxlY3RGbG93KGZsb3dfdG9fc2VsZWN0KTtcbiAgICAgICAgfVxuICAgIH0sXG4gICAgY2xvc2VWaWV3OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuc3RhdGUudmlldy5jbG9zZSgpO1xuICAgIH0sXG4gICAgY29tcG9uZW50V2lsbE1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMub3BlblZpZXcodGhpcy5wcm9wcy5mbG93U3RvcmUpO1xuICAgIH0sXG4gICAgY29tcG9uZW50V2lsbFVubW91bnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5jbG9zZVZpZXcoKTtcbiAgICB9LFxuICAgIHNlbGVjdEZsb3c6IGZ1bmN0aW9uIChmbG93KSB7XG4gICAgICAgIGlmIChmbG93KSB7XG4gICAgICAgICAgICB0aGlzLnJlcGxhY2VXaXRoKFxuICAgICAgICAgICAgICAgIFwiZmxvd1wiLFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgZmxvd0lkOiBmbG93LmlkLFxuICAgICAgICAgICAgICAgICAgICBkZXRhaWxUYWI6IHRoaXMuZ2V0UGFyYW1zKCkuZGV0YWlsVGFiIHx8IFwicmVxdWVzdFwiXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHRoaXMucmVmcy5mbG93VGFibGUuc2Nyb2xsSW50b1ZpZXcoZmxvdyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLnJlcGxhY2VXaXRoKFwiZmxvd3NcIiwge30pO1xuICAgICAgICB9XG4gICAgfSxcbiAgICBzZWxlY3RGbG93UmVsYXRpdmU6IGZ1bmN0aW9uIChzaGlmdCkge1xuICAgICAgICB2YXIgZmxvd3MgPSB0aGlzLnN0YXRlLnZpZXcubGlzdDtcbiAgICAgICAgdmFyIGluZGV4O1xuICAgICAgICBpZiAoIXRoaXMuZ2V0UGFyYW1zKCkuZmxvd0lkKSB7XG4gICAgICAgICAgICBpZiAoc2hpZnQgPiAwKSB7XG4gICAgICAgICAgICAgICAgaW5kZXggPSBmbG93cy5sZW5ndGggLSAxO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpbmRleCA9IDA7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB2YXIgY3VyckZsb3dJZCA9IHRoaXMuZ2V0UGFyYW1zKCkuZmxvd0lkO1xuICAgICAgICAgICAgdmFyIGkgPSBmbG93cy5sZW5ndGg7XG4gICAgICAgICAgICB3aGlsZSAoaS0tKSB7XG4gICAgICAgICAgICAgICAgaWYgKGZsb3dzW2ldLmlkID09PSBjdXJyRmxvd0lkKSB7XG4gICAgICAgICAgICAgICAgICAgIGluZGV4ID0gaTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaW5kZXggPSBNYXRoLm1pbihcbiAgICAgICAgICAgICAgICBNYXRoLm1heCgwLCBpbmRleCArIHNoaWZ0KSxcbiAgICAgICAgICAgICAgICBmbG93cy5sZW5ndGggLSAxKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnNlbGVjdEZsb3coZmxvd3NbaW5kZXhdKTtcbiAgICB9LFxuICAgIG9uS2V5RG93bjogZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgdmFyIGZsb3cgPSB0aGlzLmdldFNlbGVjdGVkKCk7XG4gICAgICAgIGlmIChlLmN0cmxLZXkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBzd2l0Y2ggKGUua2V5Q29kZSkge1xuICAgICAgICAgICAgY2FzZSBLZXkuSzpcbiAgICAgICAgICAgIGNhc2UgS2V5LlVQOlxuICAgICAgICAgICAgICAgIHRoaXMuc2VsZWN0Rmxvd1JlbGF0aXZlKC0xKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgS2V5Lko6XG4gICAgICAgICAgICBjYXNlIEtleS5ET1dOOlxuICAgICAgICAgICAgICAgIHRoaXMuc2VsZWN0Rmxvd1JlbGF0aXZlKCsxKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgS2V5LlNQQUNFOlxuICAgICAgICAgICAgY2FzZSBLZXkuUEFHRV9ET1dOOlxuICAgICAgICAgICAgICAgIHRoaXMuc2VsZWN0Rmxvd1JlbGF0aXZlKCsxMCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIEtleS5QQUdFX1VQOlxuICAgICAgICAgICAgICAgIHRoaXMuc2VsZWN0Rmxvd1JlbGF0aXZlKC0xMCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIEtleS5FTkQ6XG4gICAgICAgICAgICAgICAgdGhpcy5zZWxlY3RGbG93UmVsYXRpdmUoKzFlMTApO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBLZXkuSE9NRTpcbiAgICAgICAgICAgICAgICB0aGlzLnNlbGVjdEZsb3dSZWxhdGl2ZSgtMWUxMCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIEtleS5FU0M6XG4gICAgICAgICAgICAgICAgdGhpcy5zZWxlY3RGbG93KG51bGwpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBLZXkuSDpcbiAgICAgICAgICAgIGNhc2UgS2V5LkxFRlQ6XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMucmVmcy5mbG93RGV0YWlscykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnJlZnMuZmxvd0RldGFpbHMubmV4dFRhYigtMSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBLZXkuTDpcbiAgICAgICAgICAgIGNhc2UgS2V5LlRBQjpcbiAgICAgICAgICAgIGNhc2UgS2V5LlJJR0hUOlxuICAgICAgICAgICAgICAgIGlmICh0aGlzLnJlZnMuZmxvd0RldGFpbHMpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZWZzLmZsb3dEZXRhaWxzLm5leHRUYWIoKzEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgS2V5LkM6XG4gICAgICAgICAgICAgICAgaWYgKGUuc2hpZnRLZXkpIHtcbiAgICAgICAgICAgICAgICAgICAgRmxvd0FjdGlvbnMuY2xlYXIoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIEtleS5EOlxuICAgICAgICAgICAgICAgIGlmIChmbG93KSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChlLnNoaWZ0S2V5KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBGbG93QWN0aW9ucy5kdXBsaWNhdGUoZmxvdyk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBGbG93QWN0aW9ucy5kZWxldGUoZmxvdyk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIEtleS5BOlxuICAgICAgICAgICAgICAgIGlmIChlLnNoaWZ0S2V5KSB7XG4gICAgICAgICAgICAgICAgICAgIEZsb3dBY3Rpb25zLmFjY2VwdF9hbGwoKTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGZsb3cgJiYgZmxvdy5pbnRlcmNlcHRlZCkge1xuICAgICAgICAgICAgICAgICAgICBGbG93QWN0aW9ucy5hY2NlcHQoZmxvdyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBLZXkuUjpcbiAgICAgICAgICAgICAgICBpZiAoIWUuc2hpZnRLZXkgJiYgZmxvdykge1xuICAgICAgICAgICAgICAgICAgICBGbG93QWN0aW9ucy5yZXBsYXkoZmxvdyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBLZXkuVjpcbiAgICAgICAgICAgICAgICBpZihlLnNoaWZ0S2V5ICYmIGZsb3cgJiYgZmxvdy5tb2RpZmllZCkge1xuICAgICAgICAgICAgICAgICAgICBGbG93QWN0aW9ucy5yZXZlcnQoZmxvdyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICBjb25zb2xlLmRlYnVnKFwia2V5ZG93blwiLCBlLmtleUNvZGUpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgfSxcbiAgICBnZXRTZWxlY3RlZDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5wcm9wcy5mbG93U3RvcmUuZ2V0KHRoaXMuZ2V0UGFyYW1zKCkuZmxvd0lkKTtcbiAgICB9LFxuICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2VsZWN0ZWQgPSB0aGlzLmdldFNlbGVjdGVkKCk7XG5cbiAgICAgICAgdmFyIGRldGFpbHM7XG4gICAgICAgIGlmIChzZWxlY3RlZCkge1xuICAgICAgICAgICAgZGV0YWlscyA9IFtcbiAgICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFNwbGl0dGVyLCB7a2V5OiBcInNwbGl0dGVyXCJ9KSxcbiAgICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KEZsb3dEZXRhaWwsIHtrZXk6IFwiZmxvd0RldGFpbHNcIiwgcmVmOiBcImZsb3dEZXRhaWxzXCIsIGZsb3c6IHNlbGVjdGVkfSlcbiAgICAgICAgICAgIF07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBkZXRhaWxzID0gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFwiZGl2XCIsIHtjbGFzc05hbWU6IFwibWFpbi12aWV3XCIsIG9uS2V5RG93bjogdGhpcy5vbktleURvd24sIHRhYkluZGV4OiBcIjBcIn0sIFxuICAgICAgICAgICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRmxvd1RhYmxlLCB7cmVmOiBcImZsb3dUYWJsZVwiLCBcbiAgICAgICAgICAgICAgICAgICAgdmlldzogdGhpcy5zdGF0ZS52aWV3LCBcbiAgICAgICAgICAgICAgICAgICAgc2VsZWN0RmxvdzogdGhpcy5zZWxlY3RGbG93LCBcbiAgICAgICAgICAgICAgICAgICAgc2VsZWN0ZWQ6IHNlbGVjdGVkfSksIFxuICAgICAgICAgICAgICAgIGRldGFpbHNcbiAgICAgICAgICAgIClcbiAgICAgICAgKTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBNYWluVmlldztcbiIsInZhciBSZWFjdCA9IHJlcXVpcmUoXCJyZWFjdFwiKTtcbnZhciBSZWFjdFJvdXRlciA9IHJlcXVpcmUoXCJyZWFjdC1yb3V0ZXJcIik7XG52YXIgXyA9IHJlcXVpcmUoXCJsb2Rhc2hcIik7XG5cbnZhciB1dGlscyA9IHJlcXVpcmUoXCIuL3V0aWxzLmpzeC5qc1wiKTtcbnZhciBNYWluVmlldyA9IHJlcXVpcmUoXCIuL21haW52aWV3LmpzeC5qc1wiKTtcbnZhciBGb290ZXIgPSByZXF1aXJlKFwiLi9mb290ZXIuanN4LmpzXCIpO1xudmFyIGhlYWRlciA9IHJlcXVpcmUoXCIuL2hlYWRlci5qc3guanNcIik7XG52YXIgc3RvcmUgPSByZXF1aXJlKFwiLi4vc3RvcmUvc3RvcmUuanNcIik7XG5cblxuLy9UT0RPOiBNb3ZlIG91dCBvZiBoZXJlLCBqdXN0IGEgc3R1Yi5cbnZhciBSZXBvcnRzID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIlJlcG9ydHNcIixcbiAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgbnVsbCwgXCJSZXBvcnRFZGl0b3JcIik7XG4gICAgfVxufSk7XG5cblxudmFyIFByb3h5QXBwTWFpbiA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtkaXNwbGF5TmFtZTogXCJQcm94eUFwcE1haW5cIixcbiAgICBtaXhpbnM6IFt1dGlscy5TdGF0ZV0sXG4gICAgZ2V0SW5pdGlhbFN0YXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBldmVudFN0b3JlID0gbmV3IHN0b3JlLkV2ZW50TG9nU3RvcmUoKTtcbiAgICAgICAgdmFyIGZsb3dTdG9yZSA9IG5ldyBzdG9yZS5GbG93U3RvcmUoKTtcbiAgICAgICAgdmFyIHNldHRpbmdzID0gbmV3IHN0b3JlLlNldHRpbmdzU3RvcmUoKTtcblxuICAgICAgICAvLyBEZWZhdWx0IFNldHRpbmdzIGJlZm9yZSBmZXRjaFxuICAgICAgICBfLmV4dGVuZChzZXR0aW5ncy5kaWN0LHtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzZXR0aW5nczogc2V0dGluZ3MsXG4gICAgICAgICAgICBmbG93U3RvcmU6IGZsb3dTdG9yZSxcbiAgICAgICAgICAgIGV2ZW50U3RvcmU6IGV2ZW50U3RvcmVcbiAgICAgICAgfTtcbiAgICB9LFxuICAgIGNvbXBvbmVudERpZE1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuc3RhdGUuc2V0dGluZ3MuYWRkTGlzdGVuZXIoXCJyZWNhbGN1bGF0ZVwiLCB0aGlzLm9uU2V0dGluZ3NDaGFuZ2UpO1xuICAgICAgICB3aW5kb3cuYXBwID0gdGhpcztcbiAgICB9LFxuICAgIGNvbXBvbmVudFdpbGxVbm1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuc3RhdGUuc2V0dGluZ3MucmVtb3ZlTGlzdGVuZXIoXCJyZWNhbGN1bGF0ZVwiLCB0aGlzLm9uU2V0dGluZ3NDaGFuZ2UpO1xuICAgIH0sXG4gICAgb25TZXR0aW5nc0NoYW5nZTogZnVuY3Rpb24oKXtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBzZXR0aW5nczogdGhpcy5zdGF0ZS5zZXR0aW5nc1xuICAgICAgICB9KTtcbiAgICB9LFxuICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuXG4gICAgICAgIHZhciBldmVudGxvZztcbiAgICAgICAgaWYgKHRoaXMuZ2V0UXVlcnkoKVtRdWVyeS5TSE9XX0VWRU5UTE9HXSkge1xuICAgICAgICAgICAgZXZlbnRsb2cgPSBbXG4gICAgICAgICAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChTcGxpdHRlciwge2tleTogXCJzcGxpdHRlclwiLCBheGlzOiBcInlcIn0pLFxuICAgICAgICAgICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRXZlbnRMb2csIHtrZXk6IFwiZXZlbnRsb2dcIiwgZXZlbnRTdG9yZTogdGhpcy5zdGF0ZS5ldmVudFN0b3JlfSlcbiAgICAgICAgICAgIF07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBldmVudGxvZyA9IG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChcImRpdlwiLCB7aWQ6IFwiY29udGFpbmVyXCJ9LCBcbiAgICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KGhlYWRlci5IZWFkZXIsIHtzZXR0aW5nczogdGhpcy5zdGF0ZS5zZXR0aW5ncy5kaWN0fSksIFxuICAgICAgICAgICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoUm91dGVIYW5kbGVyLCB7c2V0dGluZ3M6IHRoaXMuc3RhdGUuc2V0dGluZ3MuZGljdCwgZmxvd1N0b3JlOiB0aGlzLnN0YXRlLmZsb3dTdG9yZX0pLCBcbiAgICAgICAgICAgICAgICBldmVudGxvZywgXG4gICAgICAgICAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChGb290ZXIsIHtzZXR0aW5nczogdGhpcy5zdGF0ZS5zZXR0aW5ncy5kaWN0fSlcbiAgICAgICAgICAgIClcbiAgICAgICAgKTtcbiAgICB9XG59KTtcblxuXG52YXIgUm91dGUgPSBSZWFjdFJvdXRlci5Sb3V0ZTtcbnZhciBSb3V0ZUhhbmRsZXIgPSBSZWFjdFJvdXRlci5Sb3V0ZUhhbmRsZXI7XG52YXIgUmVkaXJlY3QgPSBSZWFjdFJvdXRlci5SZWRpcmVjdDtcbnZhciBEZWZhdWx0Um91dGUgPSBSZWFjdFJvdXRlci5EZWZhdWx0Um91dGU7XG52YXIgTm90Rm91bmRSb3V0ZSA9IFJlYWN0Um91dGVyLk5vdEZvdW5kUm91dGU7XG5cblxudmFyIHJvdXRlcyA9IChcbiAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFJvdXRlLCB7cGF0aDogXCIvXCIsIGhhbmRsZXI6IFByb3h5QXBwTWFpbn0sIFxuICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFJvdXRlLCB7bmFtZTogXCJmbG93c1wiLCBwYXRoOiBcImZsb3dzXCIsIGhhbmRsZXI6IE1haW5WaWV3fSksIFxuICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFJvdXRlLCB7bmFtZTogXCJmbG93XCIsIHBhdGg6IFwiZmxvd3MvOmZsb3dJZC86ZGV0YWlsVGFiXCIsIGhhbmRsZXI6IE1haW5WaWV3fSksIFxuICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFJvdXRlLCB7bmFtZTogXCJyZXBvcnRzXCIsIGhhbmRsZXI6IFJlcG9ydHN9KSwgXG4gICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoUmVkaXJlY3QsIHtwYXRoOiBcIi9cIiwgdG86IFwiZmxvd3NcIn0pXG4gICAgKVxuKTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgcm91dGVzOiByb3V0ZXNcbn07XG5cbiIsInZhciBSZWFjdCA9IHJlcXVpcmUoXCJyZWFjdFwiKTtcbnZhciBSZWFjdFJvdXRlciA9IHJlcXVpcmUoXCJyZWFjdC1yb3V0ZXJcIik7XG52YXIgXyA9IHJlcXVpcmUoXCJsb2Rhc2hcIik7XG5cbi8vUmVhY3QgdXRpbHMuIEZvciBvdGhlciB1dGlsaXRpZXMsIHNlZSAuLi91dGlscy5qc1xuXG4vLyBodHRwOi8vYmxvZy52amV1eC5jb20vMjAxMy9qYXZhc2NyaXB0L3Njcm9sbC1wb3NpdGlvbi13aXRoLXJlYWN0Lmh0bWwgKGFsc28gY29udGFpbnMgaW52ZXJzZSBleGFtcGxlKVxudmFyIEF1dG9TY3JvbGxNaXhpbiA9IHtcbiAgICBjb21wb25lbnRXaWxsVXBkYXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBub2RlID0gdGhpcy5nZXRET01Ob2RlKCk7XG4gICAgICAgIHRoaXMuX3Nob3VsZFNjcm9sbEJvdHRvbSA9IChcbiAgICAgICAgICAgIG5vZGUuc2Nyb2xsVG9wICE9PSAwICYmXG4gICAgICAgICAgICBub2RlLnNjcm9sbFRvcCArIG5vZGUuY2xpZW50SGVpZ2h0ID09PSBub2RlLnNjcm9sbEhlaWdodFxuICAgICAgICApO1xuICAgIH0sXG4gICAgY29tcG9uZW50RGlkVXBkYXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICh0aGlzLl9zaG91bGRTY3JvbGxCb3R0b20pIHtcbiAgICAgICAgICAgIHZhciBub2RlID0gdGhpcy5nZXRET01Ob2RlKCk7XG4gICAgICAgICAgICBub2RlLnNjcm9sbFRvcCA9IG5vZGUuc2Nyb2xsSGVpZ2h0O1xuICAgICAgICB9XG4gICAgfSxcbn07XG5cblxudmFyIFN0aWNreUhlYWRNaXhpbiA9IHtcbiAgICBhZGp1c3RIZWFkOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIC8vIEFidXNpbmcgQ1NTIHRyYW5zZm9ybXMgdG8gc2V0IHRoZSBlbGVtZW50XG4gICAgICAgIC8vIHJlZmVyZW5jZWQgYXMgaGVhZCBpbnRvIHNvbWUga2luZCBvZiBwb3NpdGlvbjpzdGlja3kuXG4gICAgICAgIHZhciBoZWFkID0gdGhpcy5yZWZzLmhlYWQuZ2V0RE9NTm9kZSgpO1xuICAgICAgICBoZWFkLnN0eWxlLnRyYW5zZm9ybSA9IFwidHJhbnNsYXRlKDAsXCIgKyB0aGlzLmdldERPTU5vZGUoKS5zY3JvbGxUb3AgKyBcInB4KVwiO1xuICAgIH1cbn07XG5cblxudmFyIE5hdmlnYXRpb24gPSBfLmV4dGVuZCh7fSwgUmVhY3RSb3V0ZXIuTmF2aWdhdGlvbiwge1xuICAgIHNldFF1ZXJ5OiBmdW5jdGlvbiAoZGljdCkge1xuICAgICAgICB2YXIgcSA9IHRoaXMuY29udGV4dC5nZXRDdXJyZW50UXVlcnkoKTtcbiAgICAgICAgZm9yKHZhciBpIGluIGRpY3Qpe1xuICAgICAgICAgICAgaWYoZGljdC5oYXNPd25Qcm9wZXJ0eShpKSl7XG4gICAgICAgICAgICAgICAgcVtpXSA9IGRpY3RbaV0gfHwgdW5kZWZpbmVkOyAvL2ZhbHNleSB2YWx1ZXMgc2hhbGwgYmUgcmVtb3ZlZC5cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBxLl8gPSBcIl9cIjsgLy8gd29ya2Fyb3VuZCBmb3IgaHR0cHM6Ly9naXRodWIuY29tL3JhY2t0L3JlYWN0LXJvdXRlci9wdWxsLzU5OVxuICAgICAgICB0aGlzLnJlcGxhY2VXaXRoKHRoaXMuY29udGV4dC5nZXRDdXJyZW50UGF0aCgpLCB0aGlzLmNvbnRleHQuZ2V0Q3VycmVudFBhcmFtcygpLCBxKTtcbiAgICB9LFxuICAgIHJlcGxhY2VXaXRoOiBmdW5jdGlvbihyb3V0ZU5hbWVPclBhdGgsIHBhcmFtcywgcXVlcnkpIHtcbiAgICAgICAgaWYocm91dGVOYW1lT3JQYXRoID09PSB1bmRlZmluZWQpe1xuICAgICAgICAgICAgcm91dGVOYW1lT3JQYXRoID0gdGhpcy5jb250ZXh0LmdldEN1cnJlbnRQYXRoKCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYocGFyYW1zID09PSB1bmRlZmluZWQpe1xuICAgICAgICAgICAgcGFyYW1zID0gdGhpcy5jb250ZXh0LmdldEN1cnJlbnRQYXJhbXMoKTtcbiAgICAgICAgfVxuICAgICAgICBpZihxdWVyeSA9PT0gdW5kZWZpbmVkKXtcbiAgICAgICAgICAgIHF1ZXJ5ID0gdGhpcy5jb250ZXh0LmdldEN1cnJlbnRRdWVyeSgpO1xuICAgICAgICB9XG4gICAgICAgIFJlYWN0Um91dGVyLk5hdmlnYXRpb24ucmVwbGFjZVdpdGguY2FsbCh0aGlzLCByb3V0ZU5hbWVPclBhdGgsIHBhcmFtcywgcXVlcnkpO1xuICAgIH1cbn0pO1xuXy5leHRlbmQoTmF2aWdhdGlvbi5jb250ZXh0VHlwZXMsIFJlYWN0Um91dGVyLlN0YXRlLmNvbnRleHRUeXBlcyk7XG5cbnZhciBTdGF0ZSA9IF8uZXh0ZW5kKHt9LCBSZWFjdFJvdXRlci5TdGF0ZSwge1xuICAgIGdldEluaXRpYWxTdGF0ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLl9xdWVyeSA9IHRoaXMuY29udGV4dC5nZXRDdXJyZW50UXVlcnkoKTtcbiAgICAgICAgdGhpcy5fcXVlcnlXYXRjaGVzID0gW107XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH0sXG4gICAgb25RdWVyeUNoYW5nZTogZnVuY3Rpb24gKGtleSwgY2FsbGJhY2spIHtcbiAgICAgICAgdGhpcy5fcXVlcnlXYXRjaGVzLnB1c2goe1xuICAgICAgICAgICAga2V5OiBrZXksXG4gICAgICAgICAgICBjYWxsYmFjazogY2FsbGJhY2tcbiAgICAgICAgfSk7XG4gICAgfSxcbiAgICBjb21wb25lbnRXaWxsUmVjZWl2ZVByb3BzOiBmdW5jdGlvbiAobmV4dFByb3BzLCBuZXh0U3RhdGUpIHtcbiAgICAgICAgdmFyIHEgPSB0aGlzLmNvbnRleHQuZ2V0Q3VycmVudFF1ZXJ5KCk7XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5fcXVlcnlXYXRjaGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICB2YXIgd2F0Y2ggPSB0aGlzLl9xdWVyeVdhdGNoZXNbaV07XG4gICAgICAgICAgICBpZiAodGhpcy5fcXVlcnlbd2F0Y2gua2V5XSAhPT0gcVt3YXRjaC5rZXldKSB7XG4gICAgICAgICAgICAgICAgd2F0Y2guY2FsbGJhY2sodGhpcy5fcXVlcnlbd2F0Y2gua2V5XSwgcVt3YXRjaC5rZXldLCB3YXRjaC5rZXkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHRoaXMuX3F1ZXJ5ID0gcTtcbiAgICB9XG59KTtcblxudmFyIFNwbGl0dGVyID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIlNwbGl0dGVyXCIsXG4gICAgZ2V0RGVmYXVsdFByb3BzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBheGlzOiBcInhcIlxuICAgICAgICB9O1xuICAgIH0sXG4gICAgZ2V0SW5pdGlhbFN0YXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBhcHBsaWVkOiBmYWxzZSxcbiAgICAgICAgICAgIHN0YXJ0WDogZmFsc2UsXG4gICAgICAgICAgICBzdGFydFk6IGZhbHNlXG4gICAgICAgIH07XG4gICAgfSxcbiAgICBvbk1vdXNlRG93bjogZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBzdGFydFg6IGUucGFnZVgsXG4gICAgICAgICAgICBzdGFydFk6IGUucGFnZVlcbiAgICAgICAgfSk7XG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwibW91c2Vtb3ZlXCIsIHRoaXMub25Nb3VzZU1vdmUpO1xuICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcIm1vdXNldXBcIiwgdGhpcy5vbk1vdXNlVXApO1xuICAgICAgICAvLyBPY2Nhc2lvbmFsbHksIG9ubHkgYSBkcmFnRW5kIGV2ZW50IGlzIHRyaWdnZXJlZCwgYnV0IG5vIG1vdXNlVXAuXG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwiZHJhZ2VuZFwiLCB0aGlzLm9uRHJhZ0VuZCk7XG4gICAgfSxcbiAgICBvbkRyYWdFbmQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5nZXRET01Ob2RlKCkuc3R5bGUudHJhbnNmb3JtID0gXCJcIjtcbiAgICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJkcmFnZW5kXCIsIHRoaXMub25EcmFnRW5kKTtcbiAgICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJtb3VzZXVwXCIsIHRoaXMub25Nb3VzZVVwKTtcbiAgICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJtb3VzZW1vdmVcIiwgdGhpcy5vbk1vdXNlTW92ZSk7XG4gICAgfSxcbiAgICBvbk1vdXNlVXA6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIHRoaXMub25EcmFnRW5kKCk7XG5cbiAgICAgICAgdmFyIG5vZGUgPSB0aGlzLmdldERPTU5vZGUoKTtcbiAgICAgICAgdmFyIHByZXYgPSBub2RlLnByZXZpb3VzRWxlbWVudFNpYmxpbmc7XG4gICAgICAgIHZhciBuZXh0ID0gbm9kZS5uZXh0RWxlbWVudFNpYmxpbmc7XG5cbiAgICAgICAgdmFyIGRYID0gZS5wYWdlWCAtIHRoaXMuc3RhdGUuc3RhcnRYO1xuICAgICAgICB2YXIgZFkgPSBlLnBhZ2VZIC0gdGhpcy5zdGF0ZS5zdGFydFk7XG4gICAgICAgIHZhciBmbGV4QmFzaXM7XG4gICAgICAgIGlmICh0aGlzLnByb3BzLmF4aXMgPT09IFwieFwiKSB7XG4gICAgICAgICAgICBmbGV4QmFzaXMgPSBwcmV2Lm9mZnNldFdpZHRoICsgZFg7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBmbGV4QmFzaXMgPSBwcmV2Lm9mZnNldEhlaWdodCArIGRZO1xuICAgICAgICB9XG5cbiAgICAgICAgcHJldi5zdHlsZS5mbGV4ID0gXCIwIDAgXCIgKyBNYXRoLm1heCgwLCBmbGV4QmFzaXMpICsgXCJweFwiO1xuICAgICAgICBuZXh0LnN0eWxlLmZsZXggPSBcIjEgMSBhdXRvXCI7XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBhcHBsaWVkOiB0cnVlXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLm9uUmVzaXplKCk7XG4gICAgfSxcbiAgICBvbk1vdXNlTW92ZTogZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgdmFyIGRYID0gMCwgZFkgPSAwO1xuICAgICAgICBpZiAodGhpcy5wcm9wcy5heGlzID09PSBcInhcIikge1xuICAgICAgICAgICAgZFggPSBlLnBhZ2VYIC0gdGhpcy5zdGF0ZS5zdGFydFg7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBkWSA9IGUucGFnZVkgLSB0aGlzLnN0YXRlLnN0YXJ0WTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmdldERPTU5vZGUoKS5zdHlsZS50cmFuc2Zvcm0gPSBcInRyYW5zbGF0ZShcIiArIGRYICsgXCJweCxcIiArIGRZICsgXCJweClcIjtcbiAgICB9LFxuICAgIG9uUmVzaXplOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIC8vIFRyaWdnZXIgYSBnbG9iYWwgcmVzaXplIGV2ZW50LiBUaGlzIG5vdGlmaWVzIGNvbXBvbmVudHMgdGhhdCBlbXBsb3kgdmlydHVhbCBzY3JvbGxpbmdcbiAgICAgICAgLy8gdGhhdCB0aGVpciB2aWV3cG9ydCBtYXkgaGF2ZSBjaGFuZ2VkLlxuICAgICAgICB3aW5kb3cuc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB3aW5kb3cuZGlzcGF0Y2hFdmVudChuZXcgQ3VzdG9tRXZlbnQoXCJyZXNpemVcIikpO1xuICAgICAgICB9LCAxKTtcbiAgICB9LFxuICAgIHJlc2V0OiBmdW5jdGlvbiAod2lsbFVubW91bnQpIHtcbiAgICAgICAgaWYgKCF0aGlzLnN0YXRlLmFwcGxpZWQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB2YXIgbm9kZSA9IHRoaXMuZ2V0RE9NTm9kZSgpO1xuICAgICAgICB2YXIgcHJldiA9IG5vZGUucHJldmlvdXNFbGVtZW50U2libGluZztcbiAgICAgICAgdmFyIG5leHQgPSBub2RlLm5leHRFbGVtZW50U2libGluZztcblxuICAgICAgICBwcmV2LnN0eWxlLmZsZXggPSBcIlwiO1xuICAgICAgICBuZXh0LnN0eWxlLmZsZXggPSBcIlwiO1xuXG4gICAgICAgIGlmICghd2lsbFVubW91bnQpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgIGFwcGxpZWQ6IGZhbHNlXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLm9uUmVzaXplKCk7XG4gICAgfSxcbiAgICBjb21wb25lbnRXaWxsVW5tb3VudDogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLnJlc2V0KHRydWUpO1xuICAgIH0sXG4gICAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBjbGFzc05hbWUgPSBcInNwbGl0dGVyXCI7XG4gICAgICAgIGlmICh0aGlzLnByb3BzLmF4aXMgPT09IFwieFwiKSB7XG4gICAgICAgICAgICBjbGFzc05hbWUgKz0gXCIgc3BsaXR0ZXIteFwiO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY2xhc3NOYW1lICs9IFwiIHNwbGl0dGVyLXlcIjtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChcImRpdlwiLCB7Y2xhc3NOYW1lOiBjbGFzc05hbWV9LCBcbiAgICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFwiZGl2XCIsIHtvbk1vdXNlRG93bjogdGhpcy5vbk1vdXNlRG93biwgZHJhZ2dhYmxlOiBcInRydWVcIn0pXG4gICAgICAgICAgICApXG4gICAgICAgICk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIFN0YXRlOiBTdGF0ZSxcbiAgICBOYXZpZ2F0aW9uOiBOYXZpZ2F0aW9uLFxuICAgIFN0aWNreUhlYWRNaXhpbjogU3RpY2t5SGVhZE1peGluLFxuICAgIEF1dG9TY3JvbGxNaXhpbjogQXV0b1Njcm9sbE1peGluLFxuICAgIFNwbGl0dGVyOiBTcGxpdHRlclxufSIsInZhciBSZWFjdCA9IHJlcXVpcmUoXCJyZWFjdFwiKTtcblxudmFyIFZpcnR1YWxTY3JvbGxNaXhpbiA9IHtcbiAgICBnZXRJbml0aWFsU3RhdGU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN0YXJ0OiAwLFxuICAgICAgICAgICAgc3RvcDogMFxuICAgICAgICB9O1xuICAgIH0sXG4gICAgY29tcG9uZW50V2lsbE1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICghdGhpcy5wcm9wcy5yb3dIZWlnaHQpIHtcbiAgICAgICAgICAgIGNvbnNvbGUud2FybihcIlZpcnR1YWxTY3JvbGxNaXhpbjogTm8gcm93SGVpZ2h0IHNwZWNpZmllZFwiLCB0aGlzKTtcbiAgICAgICAgfVxuICAgIH0sXG4gICAgZ2V0UGxhY2Vob2xkZXJUb3A6IGZ1bmN0aW9uICh0b3RhbCkge1xuICAgICAgICB2YXIgVGFnID0gdGhpcy5wcm9wcy5wbGFjZWhvbGRlclRhZ05hbWUgfHwgXCJ0clwiO1xuICAgICAgICAvLyBXaGVuIGEgbGFyZ2UgdHJ1bmsgb2YgZWxlbWVudHMgaXMgcmVtb3ZlZCBmcm9tIHRoZSBidXR0b24sIHN0YXJ0IG1heSBiZSBmYXIgb2ZmIHRoZSB2aWV3cG9ydC5cbiAgICAgICAgLy8gVG8gbWFrZSB0aGlzIGlzc3VlIGxlc3Mgc2V2ZXJlLCBsaW1pdCB0aGUgdG9wIHBsYWNlaG9sZGVyIHRvIHRoZSB0b3RhbCBudW1iZXIgb2Ygcm93cy5cbiAgICAgICAgdmFyIHN0eWxlID0ge1xuICAgICAgICAgICAgaGVpZ2h0OiBNYXRoLm1pbih0aGlzLnN0YXRlLnN0YXJ0LCB0b3RhbCkgKiB0aGlzLnByb3BzLnJvd0hlaWdodFxuICAgICAgICB9O1xuICAgICAgICB2YXIgc3BhY2VyID0gUmVhY3QuY3JlYXRlRWxlbWVudChUYWcsIHtrZXk6IFwicGxhY2Vob2xkZXItdG9wXCIsIHN0eWxlOiBzdHlsZX0pO1xuXG4gICAgICAgIGlmICh0aGlzLnN0YXRlLnN0YXJ0ICUgMiA9PT0gMSkge1xuICAgICAgICAgICAgLy8gZml4IGV2ZW4vb2RkIHJvd3NcbiAgICAgICAgICAgIHJldHVybiBbc3BhY2VyLCBSZWFjdC5jcmVhdGVFbGVtZW50KFRhZywge2tleTogXCJwbGFjZWhvbGRlci10b3AtMlwifSldO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHNwYWNlcjtcbiAgICAgICAgfVxuICAgIH0sXG4gICAgZ2V0UGxhY2Vob2xkZXJCb3R0b206IGZ1bmN0aW9uICh0b3RhbCkge1xuICAgICAgICB2YXIgVGFnID0gdGhpcy5wcm9wcy5wbGFjZWhvbGRlclRhZ05hbWUgfHwgXCJ0clwiO1xuICAgICAgICB2YXIgc3R5bGUgPSB7XG4gICAgICAgICAgICBoZWlnaHQ6IE1hdGgubWF4KDAsIHRvdGFsIC0gdGhpcy5zdGF0ZS5zdG9wKSAqIHRoaXMucHJvcHMucm93SGVpZ2h0XG4gICAgICAgIH07XG4gICAgICAgIHJldHVybiBSZWFjdC5jcmVhdGVFbGVtZW50KFRhZywge2tleTogXCJwbGFjZWhvbGRlci1ib3R0b21cIiwgc3R5bGU6IHN0eWxlfSk7XG4gICAgfSxcbiAgICBjb21wb25lbnREaWRNb3VudDogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLm9uU2Nyb2xsKCk7XG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdyZXNpemUnLCB0aGlzLm9uU2Nyb2xsKTtcbiAgICB9LFxuICAgIGNvbXBvbmVudFdpbGxVbm1vdW50OiBmdW5jdGlvbigpe1xuICAgICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcigncmVzaXplJywgdGhpcy5vblNjcm9sbCk7XG4gICAgfSxcbiAgICBvblNjcm9sbDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgdmlld3BvcnQgPSB0aGlzLmdldERPTU5vZGUoKTtcbiAgICAgICAgdmFyIHRvcCA9IHZpZXdwb3J0LnNjcm9sbFRvcDtcbiAgICAgICAgdmFyIGhlaWdodCA9IHZpZXdwb3J0Lm9mZnNldEhlaWdodDtcbiAgICAgICAgdmFyIHN0YXJ0ID0gTWF0aC5mbG9vcih0b3AgLyB0aGlzLnByb3BzLnJvd0hlaWdodCk7XG4gICAgICAgIHZhciBzdG9wID0gc3RhcnQgKyBNYXRoLmNlaWwoaGVpZ2h0IC8gKHRoaXMucHJvcHMucm93SGVpZ2h0TWluIHx8IHRoaXMucHJvcHMucm93SGVpZ2h0KSk7XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBzdGFydDogc3RhcnQsXG4gICAgICAgICAgICBzdG9wOiBzdG9wXG4gICAgICAgIH0pO1xuICAgIH0sXG4gICAgcmVuZGVyUm93czogZnVuY3Rpb24gKGVsZW1zKSB7XG4gICAgICAgIHZhciByb3dzID0gW107XG4gICAgICAgIHZhciBtYXggPSBNYXRoLm1pbihlbGVtcy5sZW5ndGgsIHRoaXMuc3RhdGUuc3RvcCk7XG5cbiAgICAgICAgZm9yICh2YXIgaSA9IHRoaXMuc3RhdGUuc3RhcnQ7IGkgPCBtYXg7IGkrKykge1xuICAgICAgICAgICAgdmFyIGVsZW0gPSBlbGVtc1tpXTtcbiAgICAgICAgICAgIHJvd3MucHVzaCh0aGlzLnJlbmRlclJvdyhlbGVtKSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJvd3M7XG4gICAgfSxcbiAgICBzY3JvbGxSb3dJbnRvVmlldzogZnVuY3Rpb24gKGluZGV4LCBoZWFkX2hlaWdodCkge1xuXG4gICAgICAgIHZhciByb3dfdG9wID0gKGluZGV4ICogdGhpcy5wcm9wcy5yb3dIZWlnaHQpICsgaGVhZF9oZWlnaHQ7XG4gICAgICAgIHZhciByb3dfYm90dG9tID0gcm93X3RvcCArIHRoaXMucHJvcHMucm93SGVpZ2h0O1xuXG4gICAgICAgIHZhciB2aWV3cG9ydCA9IHRoaXMuZ2V0RE9NTm9kZSgpO1xuICAgICAgICB2YXIgdmlld3BvcnRfdG9wID0gdmlld3BvcnQuc2Nyb2xsVG9wO1xuICAgICAgICB2YXIgdmlld3BvcnRfYm90dG9tID0gdmlld3BvcnRfdG9wICsgdmlld3BvcnQub2Zmc2V0SGVpZ2h0O1xuXG4gICAgICAgIC8vIEFjY291bnQgZm9yIHBpbm5lZCB0aGVhZFxuICAgICAgICBpZiAocm93X3RvcCAtIGhlYWRfaGVpZ2h0IDwgdmlld3BvcnRfdG9wKSB7XG4gICAgICAgICAgICB2aWV3cG9ydC5zY3JvbGxUb3AgPSByb3dfdG9wIC0gaGVhZF9oZWlnaHQ7XG4gICAgICAgIH0gZWxzZSBpZiAocm93X2JvdHRvbSA+IHZpZXdwb3J0X2JvdHRvbSkge1xuICAgICAgICAgICAgdmlld3BvcnQuc2Nyb2xsVG9wID0gcm93X2JvdHRvbSAtIHZpZXdwb3J0Lm9mZnNldEhlaWdodDtcbiAgICAgICAgfVxuICAgIH0sXG59O1xuXG5tb2R1bGUuZXhwb3J0cyAgPSBWaXJ0dWFsU2Nyb2xsTWl4aW47IiwiXG52YXIgYWN0aW9ucyA9IHJlcXVpcmUoXCIuL2FjdGlvbnMuanNcIik7XG5cbmZ1bmN0aW9uIENvbm5lY3Rpb24odXJsKSB7XG4gICAgaWYgKHVybFswXSA9PT0gXCIvXCIpIHtcbiAgICAgICAgdXJsID0gbG9jYXRpb24ub3JpZ2luLnJlcGxhY2UoXCJodHRwXCIsIFwid3NcIikgKyB1cmw7XG4gICAgfVxuXG4gICAgdmFyIHdzID0gbmV3IFdlYlNvY2tldCh1cmwpO1xuICAgIHdzLm9ub3BlbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYWN0aW9ucy5Db25uZWN0aW9uQWN0aW9ucy5vcGVuKCk7XG4gICAgfTtcbiAgICB3cy5vbm1lc3NhZ2UgPSBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICB2YXIgbSA9IEpTT04ucGFyc2UobWVzc2FnZS5kYXRhKTtcbiAgICAgICAgQXBwRGlzcGF0Y2hlci5kaXNwYXRjaFNlcnZlckFjdGlvbihtKTtcbiAgICB9O1xuICAgIHdzLm9uZXJyb3IgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGFjdGlvbnMuQ29ubmVjdGlvbkFjdGlvbnMuZXJyb3IoKTtcbiAgICAgICAgRXZlbnRMb2dBY3Rpb25zLmFkZF9ldmVudChcIldlYlNvY2tldCBjb25uZWN0aW9uIGVycm9yLlwiKTtcbiAgICB9O1xuICAgIHdzLm9uY2xvc2UgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGFjdGlvbnMuQ29ubmVjdGlvbkFjdGlvbnMuY2xvc2UoKTtcbiAgICAgICAgRXZlbnRMb2dBY3Rpb25zLmFkZF9ldmVudChcIldlYlNvY2tldCBjb25uZWN0aW9uIGNsb3NlZC5cIik7XG4gICAgfTtcbiAgICByZXR1cm4gd3M7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gQ29ubmVjdGlvbjsiLCJjb25zdCBQYXlsb2FkU291cmNlcyA9IHtcbiAgICBWSUVXOiBcInZpZXdcIixcbiAgICBTRVJWRVI6IFwic2VydmVyXCJcbn07XG5cblxuZnVuY3Rpb24gRGlzcGF0Y2hlcigpIHtcbiAgICB0aGlzLmNhbGxiYWNrcyA9IFtdO1xufVxuRGlzcGF0Y2hlci5wcm90b3R5cGUucmVnaXN0ZXIgPSBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgICB0aGlzLmNhbGxiYWNrcy5wdXNoKGNhbGxiYWNrKTtcbn07XG5EaXNwYXRjaGVyLnByb3RvdHlwZS51bnJlZ2lzdGVyID0gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gICAgdmFyIGluZGV4ID0gdGhpcy5jYWxsYmFja3MuaW5kZXhPZihjYWxsYmFjayk7XG4gICAgaWYgKGluZGV4ID49IDApIHtcbiAgICAgICAgdGhpcy5jYWxsYmFja3Muc3BsaWNlKGluZGV4LCAxKTtcbiAgICB9XG59O1xuRGlzcGF0Y2hlci5wcm90b3R5cGUuZGlzcGF0Y2ggPSBmdW5jdGlvbiAocGF5bG9hZCkge1xuICAgIGNvbnNvbGUuZGVidWcoXCJkaXNwYXRjaFwiLCBwYXlsb2FkKTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMuY2FsbGJhY2tzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHRoaXMuY2FsbGJhY2tzW2ldKHBheWxvYWQpO1xuICAgIH1cbn07XG5cblxuQXBwRGlzcGF0Y2hlciA9IG5ldyBEaXNwYXRjaGVyKCk7XG5BcHBEaXNwYXRjaGVyLmRpc3BhdGNoVmlld0FjdGlvbiA9IGZ1bmN0aW9uIChhY3Rpb24pIHtcbiAgICBhY3Rpb24uc291cmNlID0gUGF5bG9hZFNvdXJjZXMuVklFVztcbiAgICB0aGlzLmRpc3BhdGNoKGFjdGlvbik7XG59O1xuQXBwRGlzcGF0Y2hlci5kaXNwYXRjaFNlcnZlckFjdGlvbiA9IGZ1bmN0aW9uIChhY3Rpb24pIHtcbiAgICBhY3Rpb24uc291cmNlID0gUGF5bG9hZFNvdXJjZXMuU0VSVkVSO1xuICAgIHRoaXMuZGlzcGF0Y2goYWN0aW9uKTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIEFwcERpc3BhdGNoZXI6IEFwcERpc3BhdGNoZXJcbn07IiwiLyoganNoaW50IGlnbm9yZTpzdGFydCAqL1xuRmlsdCA9IChmdW5jdGlvbigpIHtcbiAgLypcbiAgICogR2VuZXJhdGVkIGJ5IFBFRy5qcyAwLjguMC5cbiAgICpcbiAgICogaHR0cDovL3BlZ2pzLm1hamRhLmN6L1xuICAgKi9cblxuICBmdW5jdGlvbiBwZWckc3ViY2xhc3MoY2hpbGQsIHBhcmVudCkge1xuICAgIGZ1bmN0aW9uIGN0b3IoKSB7IHRoaXMuY29uc3RydWN0b3IgPSBjaGlsZDsgfVxuICAgIGN0b3IucHJvdG90eXBlID0gcGFyZW50LnByb3RvdHlwZTtcbiAgICBjaGlsZC5wcm90b3R5cGUgPSBuZXcgY3RvcigpO1xuICB9XG5cbiAgZnVuY3Rpb24gU3ludGF4RXJyb3IobWVzc2FnZSwgZXhwZWN0ZWQsIGZvdW5kLCBvZmZzZXQsIGxpbmUsIGNvbHVtbikge1xuICAgIHRoaXMubWVzc2FnZSAgPSBtZXNzYWdlO1xuICAgIHRoaXMuZXhwZWN0ZWQgPSBleHBlY3RlZDtcbiAgICB0aGlzLmZvdW5kICAgID0gZm91bmQ7XG4gICAgdGhpcy5vZmZzZXQgICA9IG9mZnNldDtcbiAgICB0aGlzLmxpbmUgICAgID0gbGluZTtcbiAgICB0aGlzLmNvbHVtbiAgID0gY29sdW1uO1xuXG4gICAgdGhpcy5uYW1lICAgICA9IFwiU3ludGF4RXJyb3JcIjtcbiAgfVxuXG4gIHBlZyRzdWJjbGFzcyhTeW50YXhFcnJvciwgRXJyb3IpO1xuXG4gIGZ1bmN0aW9uIHBhcnNlKGlucHV0KSB7XG4gICAgdmFyIG9wdGlvbnMgPSBhcmd1bWVudHMubGVuZ3RoID4gMSA/IGFyZ3VtZW50c1sxXSA6IHt9LFxuXG4gICAgICAgIHBlZyRGQUlMRUQgPSB7fSxcblxuICAgICAgICBwZWckc3RhcnRSdWxlRnVuY3Rpb25zID0geyBzdGFydDogcGVnJHBhcnNlc3RhcnQgfSxcbiAgICAgICAgcGVnJHN0YXJ0UnVsZUZ1bmN0aW9uICA9IHBlZyRwYXJzZXN0YXJ0LFxuXG4gICAgICAgIHBlZyRjMCA9IHsgdHlwZTogXCJvdGhlclwiLCBkZXNjcmlwdGlvbjogXCJmaWx0ZXIgZXhwcmVzc2lvblwiIH0sXG4gICAgICAgIHBlZyRjMSA9IHBlZyRGQUlMRUQsXG4gICAgICAgIHBlZyRjMiA9IGZ1bmN0aW9uKG9yRXhwcikgeyByZXR1cm4gb3JFeHByOyB9LFxuICAgICAgICBwZWckYzMgPSBbXSxcbiAgICAgICAgcGVnJGM0ID0gZnVuY3Rpb24oKSB7cmV0dXJuIHRydWVGaWx0ZXI7IH0sXG4gICAgICAgIHBlZyRjNSA9IHsgdHlwZTogXCJvdGhlclwiLCBkZXNjcmlwdGlvbjogXCJ3aGl0ZXNwYWNlXCIgfSxcbiAgICAgICAgcGVnJGM2ID0gL15bIFxcdFxcblxccl0vLFxuICAgICAgICBwZWckYzcgPSB7IHR5cGU6IFwiY2xhc3NcIiwgdmFsdWU6IFwiWyBcXFxcdFxcXFxuXFxcXHJdXCIsIGRlc2NyaXB0aW9uOiBcIlsgXFxcXHRcXFxcblxcXFxyXVwiIH0sXG4gICAgICAgIHBlZyRjOCA9IHsgdHlwZTogXCJvdGhlclwiLCBkZXNjcmlwdGlvbjogXCJjb250cm9sIGNoYXJhY3RlclwiIH0sXG4gICAgICAgIHBlZyRjOSA9IC9eW3wmISgpflwiXS8sXG4gICAgICAgIHBlZyRjMTAgPSB7IHR5cGU6IFwiY2xhc3NcIiwgdmFsdWU6IFwiW3wmISgpflxcXCJdXCIsIGRlc2NyaXB0aW9uOiBcIlt8JiEoKX5cXFwiXVwiIH0sXG4gICAgICAgIHBlZyRjMTEgPSB7IHR5cGU6IFwib3RoZXJcIiwgZGVzY3JpcHRpb246IFwib3B0aW9uYWwgd2hpdGVzcGFjZVwiIH0sXG4gICAgICAgIHBlZyRjMTIgPSBcInxcIixcbiAgICAgICAgcGVnJGMxMyA9IHsgdHlwZTogXCJsaXRlcmFsXCIsIHZhbHVlOiBcInxcIiwgZGVzY3JpcHRpb246IFwiXFxcInxcXFwiXCIgfSxcbiAgICAgICAgcGVnJGMxNCA9IGZ1bmN0aW9uKGZpcnN0LCBzZWNvbmQpIHsgcmV0dXJuIG9yKGZpcnN0LCBzZWNvbmQpOyB9LFxuICAgICAgICBwZWckYzE1ID0gXCImXCIsXG4gICAgICAgIHBlZyRjMTYgPSB7IHR5cGU6IFwibGl0ZXJhbFwiLCB2YWx1ZTogXCImXCIsIGRlc2NyaXB0aW9uOiBcIlxcXCImXFxcIlwiIH0sXG4gICAgICAgIHBlZyRjMTcgPSBmdW5jdGlvbihmaXJzdCwgc2Vjb25kKSB7IHJldHVybiBhbmQoZmlyc3QsIHNlY29uZCk7IH0sXG4gICAgICAgIHBlZyRjMTggPSBcIiFcIixcbiAgICAgICAgcGVnJGMxOSA9IHsgdHlwZTogXCJsaXRlcmFsXCIsIHZhbHVlOiBcIiFcIiwgZGVzY3JpcHRpb246IFwiXFxcIiFcXFwiXCIgfSxcbiAgICAgICAgcGVnJGMyMCA9IGZ1bmN0aW9uKGV4cHIpIHsgcmV0dXJuIG5vdChleHByKTsgfSxcbiAgICAgICAgcGVnJGMyMSA9IFwiKFwiLFxuICAgICAgICBwZWckYzIyID0geyB0eXBlOiBcImxpdGVyYWxcIiwgdmFsdWU6IFwiKFwiLCBkZXNjcmlwdGlvbjogXCJcXFwiKFxcXCJcIiB9LFxuICAgICAgICBwZWckYzIzID0gXCIpXCIsXG4gICAgICAgIHBlZyRjMjQgPSB7IHR5cGU6IFwibGl0ZXJhbFwiLCB2YWx1ZTogXCIpXCIsIGRlc2NyaXB0aW9uOiBcIlxcXCIpXFxcIlwiIH0sXG4gICAgICAgIHBlZyRjMjUgPSBmdW5jdGlvbihleHByKSB7IHJldHVybiBiaW5kaW5nKGV4cHIpOyB9LFxuICAgICAgICBwZWckYzI2ID0gXCJ+YVwiLFxuICAgICAgICBwZWckYzI3ID0geyB0eXBlOiBcImxpdGVyYWxcIiwgdmFsdWU6IFwifmFcIiwgZGVzY3JpcHRpb246IFwiXFxcIn5hXFxcIlwiIH0sXG4gICAgICAgIHBlZyRjMjggPSBmdW5jdGlvbigpIHsgcmV0dXJuIGFzc2V0RmlsdGVyOyB9LFxuICAgICAgICBwZWckYzI5ID0gXCJ+ZVwiLFxuICAgICAgICBwZWckYzMwID0geyB0eXBlOiBcImxpdGVyYWxcIiwgdmFsdWU6IFwifmVcIiwgZGVzY3JpcHRpb246IFwiXFxcIn5lXFxcIlwiIH0sXG4gICAgICAgIHBlZyRjMzEgPSBmdW5jdGlvbigpIHsgcmV0dXJuIGVycm9yRmlsdGVyOyB9LFxuICAgICAgICBwZWckYzMyID0gXCJ+cVwiLFxuICAgICAgICBwZWckYzMzID0geyB0eXBlOiBcImxpdGVyYWxcIiwgdmFsdWU6IFwifnFcIiwgZGVzY3JpcHRpb246IFwiXFxcIn5xXFxcIlwiIH0sXG4gICAgICAgIHBlZyRjMzQgPSBmdW5jdGlvbigpIHsgcmV0dXJuIG5vUmVzcG9uc2VGaWx0ZXI7IH0sXG4gICAgICAgIHBlZyRjMzUgPSBcIn5zXCIsXG4gICAgICAgIHBlZyRjMzYgPSB7IHR5cGU6IFwibGl0ZXJhbFwiLCB2YWx1ZTogXCJ+c1wiLCBkZXNjcmlwdGlvbjogXCJcXFwifnNcXFwiXCIgfSxcbiAgICAgICAgcGVnJGMzNyA9IGZ1bmN0aW9uKCkgeyByZXR1cm4gcmVzcG9uc2VGaWx0ZXI7IH0sXG4gICAgICAgIHBlZyRjMzggPSBcInRydWVcIixcbiAgICAgICAgcGVnJGMzOSA9IHsgdHlwZTogXCJsaXRlcmFsXCIsIHZhbHVlOiBcInRydWVcIiwgZGVzY3JpcHRpb246IFwiXFxcInRydWVcXFwiXCIgfSxcbiAgICAgICAgcGVnJGM0MCA9IGZ1bmN0aW9uKCkgeyByZXR1cm4gdHJ1ZUZpbHRlcjsgfSxcbiAgICAgICAgcGVnJGM0MSA9IFwiZmFsc2VcIixcbiAgICAgICAgcGVnJGM0MiA9IHsgdHlwZTogXCJsaXRlcmFsXCIsIHZhbHVlOiBcImZhbHNlXCIsIGRlc2NyaXB0aW9uOiBcIlxcXCJmYWxzZVxcXCJcIiB9LFxuICAgICAgICBwZWckYzQzID0gZnVuY3Rpb24oKSB7IHJldHVybiBmYWxzZUZpbHRlcjsgfSxcbiAgICAgICAgcGVnJGM0NCA9IFwifmNcIixcbiAgICAgICAgcGVnJGM0NSA9IHsgdHlwZTogXCJsaXRlcmFsXCIsIHZhbHVlOiBcIn5jXCIsIGRlc2NyaXB0aW9uOiBcIlxcXCJ+Y1xcXCJcIiB9LFxuICAgICAgICBwZWckYzQ2ID0gZnVuY3Rpb24ocykgeyByZXR1cm4gcmVzcG9uc2VDb2RlKHMpOyB9LFxuICAgICAgICBwZWckYzQ3ID0gXCJ+ZFwiLFxuICAgICAgICBwZWckYzQ4ID0geyB0eXBlOiBcImxpdGVyYWxcIiwgdmFsdWU6IFwifmRcIiwgZGVzY3JpcHRpb246IFwiXFxcIn5kXFxcIlwiIH0sXG4gICAgICAgIHBlZyRjNDkgPSBmdW5jdGlvbihzKSB7IHJldHVybiBkb21haW4ocyk7IH0sXG4gICAgICAgIHBlZyRjNTAgPSBcIn5oXCIsXG4gICAgICAgIHBlZyRjNTEgPSB7IHR5cGU6IFwibGl0ZXJhbFwiLCB2YWx1ZTogXCJ+aFwiLCBkZXNjcmlwdGlvbjogXCJcXFwifmhcXFwiXCIgfSxcbiAgICAgICAgcGVnJGM1MiA9IGZ1bmN0aW9uKHMpIHsgcmV0dXJuIGhlYWRlcihzKTsgfSxcbiAgICAgICAgcGVnJGM1MyA9IFwifmhxXCIsXG4gICAgICAgIHBlZyRjNTQgPSB7IHR5cGU6IFwibGl0ZXJhbFwiLCB2YWx1ZTogXCJ+aHFcIiwgZGVzY3JpcHRpb246IFwiXFxcIn5ocVxcXCJcIiB9LFxuICAgICAgICBwZWckYzU1ID0gZnVuY3Rpb24ocykgeyByZXR1cm4gcmVxdWVzdEhlYWRlcihzKTsgfSxcbiAgICAgICAgcGVnJGM1NiA9IFwifmhzXCIsXG4gICAgICAgIHBlZyRjNTcgPSB7IHR5cGU6IFwibGl0ZXJhbFwiLCB2YWx1ZTogXCJ+aHNcIiwgZGVzY3JpcHRpb246IFwiXFxcIn5oc1xcXCJcIiB9LFxuICAgICAgICBwZWckYzU4ID0gZnVuY3Rpb24ocykgeyByZXR1cm4gcmVzcG9uc2VIZWFkZXIocyk7IH0sXG4gICAgICAgIHBlZyRjNTkgPSBcIn5tXCIsXG4gICAgICAgIHBlZyRjNjAgPSB7IHR5cGU6IFwibGl0ZXJhbFwiLCB2YWx1ZTogXCJ+bVwiLCBkZXNjcmlwdGlvbjogXCJcXFwifm1cXFwiXCIgfSxcbiAgICAgICAgcGVnJGM2MSA9IGZ1bmN0aW9uKHMpIHsgcmV0dXJuIG1ldGhvZChzKTsgfSxcbiAgICAgICAgcGVnJGM2MiA9IFwifnRcIixcbiAgICAgICAgcGVnJGM2MyA9IHsgdHlwZTogXCJsaXRlcmFsXCIsIHZhbHVlOiBcIn50XCIsIGRlc2NyaXB0aW9uOiBcIlxcXCJ+dFxcXCJcIiB9LFxuICAgICAgICBwZWckYzY0ID0gZnVuY3Rpb24ocykgeyByZXR1cm4gY29udGVudFR5cGUocyk7IH0sXG4gICAgICAgIHBlZyRjNjUgPSBcIn50cVwiLFxuICAgICAgICBwZWckYzY2ID0geyB0eXBlOiBcImxpdGVyYWxcIiwgdmFsdWU6IFwifnRxXCIsIGRlc2NyaXB0aW9uOiBcIlxcXCJ+dHFcXFwiXCIgfSxcbiAgICAgICAgcGVnJGM2NyA9IGZ1bmN0aW9uKHMpIHsgcmV0dXJuIHJlcXVlc3RDb250ZW50VHlwZShzKTsgfSxcbiAgICAgICAgcGVnJGM2OCA9IFwifnRzXCIsXG4gICAgICAgIHBlZyRjNjkgPSB7IHR5cGU6IFwibGl0ZXJhbFwiLCB2YWx1ZTogXCJ+dHNcIiwgZGVzY3JpcHRpb246IFwiXFxcIn50c1xcXCJcIiB9LFxuICAgICAgICBwZWckYzcwID0gZnVuY3Rpb24ocykgeyByZXR1cm4gcmVzcG9uc2VDb250ZW50VHlwZShzKTsgfSxcbiAgICAgICAgcGVnJGM3MSA9IFwifnVcIixcbiAgICAgICAgcGVnJGM3MiA9IHsgdHlwZTogXCJsaXRlcmFsXCIsIHZhbHVlOiBcIn51XCIsIGRlc2NyaXB0aW9uOiBcIlxcXCJ+dVxcXCJcIiB9LFxuICAgICAgICBwZWckYzczID0gZnVuY3Rpb24ocykgeyByZXR1cm4gdXJsKHMpOyB9LFxuICAgICAgICBwZWckYzc0ID0geyB0eXBlOiBcIm90aGVyXCIsIGRlc2NyaXB0aW9uOiBcImludGVnZXJcIiB9LFxuICAgICAgICBwZWckYzc1ID0gbnVsbCxcbiAgICAgICAgcGVnJGM3NiA9IC9eWydcIl0vLFxuICAgICAgICBwZWckYzc3ID0geyB0eXBlOiBcImNsYXNzXCIsIHZhbHVlOiBcIlsnXFxcIl1cIiwgZGVzY3JpcHRpb246IFwiWydcXFwiXVwiIH0sXG4gICAgICAgIHBlZyRjNzggPSAvXlswLTldLyxcbiAgICAgICAgcGVnJGM3OSA9IHsgdHlwZTogXCJjbGFzc1wiLCB2YWx1ZTogXCJbMC05XVwiLCBkZXNjcmlwdGlvbjogXCJbMC05XVwiIH0sXG4gICAgICAgIHBlZyRjODAgPSBmdW5jdGlvbihkaWdpdHMpIHsgcmV0dXJuIHBhcnNlSW50KGRpZ2l0cy5qb2luKFwiXCIpLCAxMCk7IH0sXG4gICAgICAgIHBlZyRjODEgPSB7IHR5cGU6IFwib3RoZXJcIiwgZGVzY3JpcHRpb246IFwic3RyaW5nXCIgfSxcbiAgICAgICAgcGVnJGM4MiA9IFwiXFxcIlwiLFxuICAgICAgICBwZWckYzgzID0geyB0eXBlOiBcImxpdGVyYWxcIiwgdmFsdWU6IFwiXFxcIlwiLCBkZXNjcmlwdGlvbjogXCJcXFwiXFxcXFxcXCJcXFwiXCIgfSxcbiAgICAgICAgcGVnJGM4NCA9IGZ1bmN0aW9uKGNoYXJzKSB7IHJldHVybiBjaGFycy5qb2luKFwiXCIpOyB9LFxuICAgICAgICBwZWckYzg1ID0gXCInXCIsXG4gICAgICAgIHBlZyRjODYgPSB7IHR5cGU6IFwibGl0ZXJhbFwiLCB2YWx1ZTogXCInXCIsIGRlc2NyaXB0aW9uOiBcIlxcXCInXFxcIlwiIH0sXG4gICAgICAgIHBlZyRjODcgPSB2b2lkIDAsXG4gICAgICAgIHBlZyRjODggPSAvXltcIlxcXFxdLyxcbiAgICAgICAgcGVnJGM4OSA9IHsgdHlwZTogXCJjbGFzc1wiLCB2YWx1ZTogXCJbXFxcIlxcXFxcXFxcXVwiLCBkZXNjcmlwdGlvbjogXCJbXFxcIlxcXFxcXFxcXVwiIH0sXG4gICAgICAgIHBlZyRjOTAgPSB7IHR5cGU6IFwiYW55XCIsIGRlc2NyaXB0aW9uOiBcImFueSBjaGFyYWN0ZXJcIiB9LFxuICAgICAgICBwZWckYzkxID0gZnVuY3Rpb24oY2hhcikgeyByZXR1cm4gY2hhcjsgfSxcbiAgICAgICAgcGVnJGM5MiA9IFwiXFxcXFwiLFxuICAgICAgICBwZWckYzkzID0geyB0eXBlOiBcImxpdGVyYWxcIiwgdmFsdWU6IFwiXFxcXFwiLCBkZXNjcmlwdGlvbjogXCJcXFwiXFxcXFxcXFxcXFwiXCIgfSxcbiAgICAgICAgcGVnJGM5NCA9IC9eWydcXFxcXS8sXG4gICAgICAgIHBlZyRjOTUgPSB7IHR5cGU6IFwiY2xhc3NcIiwgdmFsdWU6IFwiWydcXFxcXFxcXF1cIiwgZGVzY3JpcHRpb246IFwiWydcXFxcXFxcXF1cIiB9LFxuICAgICAgICBwZWckYzk2ID0gL15bJ1wiXFxcXF0vLFxuICAgICAgICBwZWckYzk3ID0geyB0eXBlOiBcImNsYXNzXCIsIHZhbHVlOiBcIlsnXFxcIlxcXFxcXFxcXVwiLCBkZXNjcmlwdGlvbjogXCJbJ1xcXCJcXFxcXFxcXF1cIiB9LFxuICAgICAgICBwZWckYzk4ID0gXCJuXCIsXG4gICAgICAgIHBlZyRjOTkgPSB7IHR5cGU6IFwibGl0ZXJhbFwiLCB2YWx1ZTogXCJuXCIsIGRlc2NyaXB0aW9uOiBcIlxcXCJuXFxcIlwiIH0sXG4gICAgICAgIHBlZyRjMTAwID0gZnVuY3Rpb24oKSB7IHJldHVybiBcIlxcblwiOyB9LFxuICAgICAgICBwZWckYzEwMSA9IFwiclwiLFxuICAgICAgICBwZWckYzEwMiA9IHsgdHlwZTogXCJsaXRlcmFsXCIsIHZhbHVlOiBcInJcIiwgZGVzY3JpcHRpb246IFwiXFxcInJcXFwiXCIgfSxcbiAgICAgICAgcGVnJGMxMDMgPSBmdW5jdGlvbigpIHsgcmV0dXJuIFwiXFxyXCI7IH0sXG4gICAgICAgIHBlZyRjMTA0ID0gXCJ0XCIsXG4gICAgICAgIHBlZyRjMTA1ID0geyB0eXBlOiBcImxpdGVyYWxcIiwgdmFsdWU6IFwidFwiLCBkZXNjcmlwdGlvbjogXCJcXFwidFxcXCJcIiB9LFxuICAgICAgICBwZWckYzEwNiA9IGZ1bmN0aW9uKCkgeyByZXR1cm4gXCJcXHRcIjsgfSxcblxuICAgICAgICBwZWckY3VyclBvcyAgICAgICAgICA9IDAsXG4gICAgICAgIHBlZyRyZXBvcnRlZFBvcyAgICAgID0gMCxcbiAgICAgICAgcGVnJGNhY2hlZFBvcyAgICAgICAgPSAwLFxuICAgICAgICBwZWckY2FjaGVkUG9zRGV0YWlscyA9IHsgbGluZTogMSwgY29sdW1uOiAxLCBzZWVuQ1I6IGZhbHNlIH0sXG4gICAgICAgIHBlZyRtYXhGYWlsUG9zICAgICAgID0gMCxcbiAgICAgICAgcGVnJG1heEZhaWxFeHBlY3RlZCAgPSBbXSxcbiAgICAgICAgcGVnJHNpbGVudEZhaWxzICAgICAgPSAwLFxuXG4gICAgICAgIHBlZyRyZXN1bHQ7XG5cbiAgICBpZiAoXCJzdGFydFJ1bGVcIiBpbiBvcHRpb25zKSB7XG4gICAgICBpZiAoIShvcHRpb25zLnN0YXJ0UnVsZSBpbiBwZWckc3RhcnRSdWxlRnVuY3Rpb25zKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDYW4ndCBzdGFydCBwYXJzaW5nIGZyb20gcnVsZSBcXFwiXCIgKyBvcHRpb25zLnN0YXJ0UnVsZSArIFwiXFxcIi5cIik7XG4gICAgICB9XG5cbiAgICAgIHBlZyRzdGFydFJ1bGVGdW5jdGlvbiA9IHBlZyRzdGFydFJ1bGVGdW5jdGlvbnNbb3B0aW9ucy5zdGFydFJ1bGVdO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHRleHQoKSB7XG4gICAgICByZXR1cm4gaW5wdXQuc3Vic3RyaW5nKHBlZyRyZXBvcnRlZFBvcywgcGVnJGN1cnJQb3MpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIG9mZnNldCgpIHtcbiAgICAgIHJldHVybiBwZWckcmVwb3J0ZWRQb3M7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gbGluZSgpIHtcbiAgICAgIHJldHVybiBwZWckY29tcHV0ZVBvc0RldGFpbHMocGVnJHJlcG9ydGVkUG9zKS5saW5lO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGNvbHVtbigpIHtcbiAgICAgIHJldHVybiBwZWckY29tcHV0ZVBvc0RldGFpbHMocGVnJHJlcG9ydGVkUG9zKS5jb2x1bW47XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZXhwZWN0ZWQoZGVzY3JpcHRpb24pIHtcbiAgICAgIHRocm93IHBlZyRidWlsZEV4Y2VwdGlvbihcbiAgICAgICAgbnVsbCxcbiAgICAgICAgW3sgdHlwZTogXCJvdGhlclwiLCBkZXNjcmlwdGlvbjogZGVzY3JpcHRpb24gfV0sXG4gICAgICAgIHBlZyRyZXBvcnRlZFBvc1xuICAgICAgKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBlcnJvcihtZXNzYWdlKSB7XG4gICAgICB0aHJvdyBwZWckYnVpbGRFeGNlcHRpb24obWVzc2FnZSwgbnVsbCwgcGVnJHJlcG9ydGVkUG9zKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBwZWckY29tcHV0ZVBvc0RldGFpbHMocG9zKSB7XG4gICAgICBmdW5jdGlvbiBhZHZhbmNlKGRldGFpbHMsIHN0YXJ0UG9zLCBlbmRQb3MpIHtcbiAgICAgICAgdmFyIHAsIGNoO1xuXG4gICAgICAgIGZvciAocCA9IHN0YXJ0UG9zOyBwIDwgZW5kUG9zOyBwKyspIHtcbiAgICAgICAgICBjaCA9IGlucHV0LmNoYXJBdChwKTtcbiAgICAgICAgICBpZiAoY2ggPT09IFwiXFxuXCIpIHtcbiAgICAgICAgICAgIGlmICghZGV0YWlscy5zZWVuQ1IpIHsgZGV0YWlscy5saW5lKys7IH1cbiAgICAgICAgICAgIGRldGFpbHMuY29sdW1uID0gMTtcbiAgICAgICAgICAgIGRldGFpbHMuc2VlbkNSID0gZmFsc2U7XG4gICAgICAgICAgfSBlbHNlIGlmIChjaCA9PT0gXCJcXHJcIiB8fCBjaCA9PT0gXCJcXHUyMDI4XCIgfHwgY2ggPT09IFwiXFx1MjAyOVwiKSB7XG4gICAgICAgICAgICBkZXRhaWxzLmxpbmUrKztcbiAgICAgICAgICAgIGRldGFpbHMuY29sdW1uID0gMTtcbiAgICAgICAgICAgIGRldGFpbHMuc2VlbkNSID0gdHJ1ZTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZGV0YWlscy5jb2x1bW4rKztcbiAgICAgICAgICAgIGRldGFpbHMuc2VlbkNSID0gZmFsc2U7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChwZWckY2FjaGVkUG9zICE9PSBwb3MpIHtcbiAgICAgICAgaWYgKHBlZyRjYWNoZWRQb3MgPiBwb3MpIHtcbiAgICAgICAgICBwZWckY2FjaGVkUG9zID0gMDtcbiAgICAgICAgICBwZWckY2FjaGVkUG9zRGV0YWlscyA9IHsgbGluZTogMSwgY29sdW1uOiAxLCBzZWVuQ1I6IGZhbHNlIH07XG4gICAgICAgIH1cbiAgICAgICAgYWR2YW5jZShwZWckY2FjaGVkUG9zRGV0YWlscywgcGVnJGNhY2hlZFBvcywgcG9zKTtcbiAgICAgICAgcGVnJGNhY2hlZFBvcyA9IHBvcztcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHBlZyRjYWNoZWRQb3NEZXRhaWxzO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHBlZyRmYWlsKGV4cGVjdGVkKSB7XG4gICAgICBpZiAocGVnJGN1cnJQb3MgPCBwZWckbWF4RmFpbFBvcykgeyByZXR1cm47IH1cblxuICAgICAgaWYgKHBlZyRjdXJyUG9zID4gcGVnJG1heEZhaWxQb3MpIHtcbiAgICAgICAgcGVnJG1heEZhaWxQb3MgPSBwZWckY3VyclBvcztcbiAgICAgICAgcGVnJG1heEZhaWxFeHBlY3RlZCA9IFtdO1xuICAgICAgfVxuXG4gICAgICBwZWckbWF4RmFpbEV4cGVjdGVkLnB1c2goZXhwZWN0ZWQpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHBlZyRidWlsZEV4Y2VwdGlvbihtZXNzYWdlLCBleHBlY3RlZCwgcG9zKSB7XG4gICAgICBmdW5jdGlvbiBjbGVhbnVwRXhwZWN0ZWQoZXhwZWN0ZWQpIHtcbiAgICAgICAgdmFyIGkgPSAxO1xuXG4gICAgICAgIGV4cGVjdGVkLnNvcnQoZnVuY3Rpb24oYSwgYikge1xuICAgICAgICAgIGlmIChhLmRlc2NyaXB0aW9uIDwgYi5kZXNjcmlwdGlvbikge1xuICAgICAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgICAgIH0gZWxzZSBpZiAoYS5kZXNjcmlwdGlvbiA+IGIuZGVzY3JpcHRpb24pIHtcbiAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gMDtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHdoaWxlIChpIDwgZXhwZWN0ZWQubGVuZ3RoKSB7XG4gICAgICAgICAgaWYgKGV4cGVjdGVkW2kgLSAxXSA9PT0gZXhwZWN0ZWRbaV0pIHtcbiAgICAgICAgICAgIGV4cGVjdGVkLnNwbGljZShpLCAxKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaSsrO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBmdW5jdGlvbiBidWlsZE1lc3NhZ2UoZXhwZWN0ZWQsIGZvdW5kKSB7XG4gICAgICAgIGZ1bmN0aW9uIHN0cmluZ0VzY2FwZShzKSB7XG4gICAgICAgICAgZnVuY3Rpb24gaGV4KGNoKSB7IHJldHVybiBjaC5jaGFyQ29kZUF0KDApLnRvU3RyaW5nKDE2KS50b1VwcGVyQ2FzZSgpOyB9XG5cbiAgICAgICAgICByZXR1cm4gc1xuICAgICAgICAgICAgLnJlcGxhY2UoL1xcXFwvZywgICAnXFxcXFxcXFwnKVxuICAgICAgICAgICAgLnJlcGxhY2UoL1wiL2csICAgICdcXFxcXCInKVxuICAgICAgICAgICAgLnJlcGxhY2UoL1xceDA4L2csICdcXFxcYicpXG4gICAgICAgICAgICAucmVwbGFjZSgvXFx0L2csICAgJ1xcXFx0JylcbiAgICAgICAgICAgIC5yZXBsYWNlKC9cXG4vZywgICAnXFxcXG4nKVxuICAgICAgICAgICAgLnJlcGxhY2UoL1xcZi9nLCAgICdcXFxcZicpXG4gICAgICAgICAgICAucmVwbGFjZSgvXFxyL2csICAgJ1xcXFxyJylcbiAgICAgICAgICAgIC5yZXBsYWNlKC9bXFx4MDAtXFx4MDdcXHgwQlxceDBFXFx4MEZdL2csIGZ1bmN0aW9uKGNoKSB7IHJldHVybiAnXFxcXHgwJyArIGhleChjaCk7IH0pXG4gICAgICAgICAgICAucmVwbGFjZSgvW1xceDEwLVxceDFGXFx4ODAtXFx4RkZdL2csICAgIGZ1bmN0aW9uKGNoKSB7IHJldHVybiAnXFxcXHgnICArIGhleChjaCk7IH0pXG4gICAgICAgICAgICAucmVwbGFjZSgvW1xcdTAxODAtXFx1MEZGRl0vZywgICAgICAgICBmdW5jdGlvbihjaCkgeyByZXR1cm4gJ1xcXFx1MCcgKyBoZXgoY2gpOyB9KVxuICAgICAgICAgICAgLnJlcGxhY2UoL1tcXHUxMDgwLVxcdUZGRkZdL2csICAgICAgICAgZnVuY3Rpb24oY2gpIHsgcmV0dXJuICdcXFxcdScgICsgaGV4KGNoKTsgfSk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgZXhwZWN0ZWREZXNjcyA9IG5ldyBBcnJheShleHBlY3RlZC5sZW5ndGgpLFxuICAgICAgICAgICAgZXhwZWN0ZWREZXNjLCBmb3VuZERlc2MsIGk7XG5cbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGV4cGVjdGVkLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgZXhwZWN0ZWREZXNjc1tpXSA9IGV4cGVjdGVkW2ldLmRlc2NyaXB0aW9uO1xuICAgICAgICB9XG5cbiAgICAgICAgZXhwZWN0ZWREZXNjID0gZXhwZWN0ZWQubGVuZ3RoID4gMVxuICAgICAgICAgID8gZXhwZWN0ZWREZXNjcy5zbGljZSgwLCAtMSkuam9pbihcIiwgXCIpXG4gICAgICAgICAgICAgICsgXCIgb3IgXCJcbiAgICAgICAgICAgICAgKyBleHBlY3RlZERlc2NzW2V4cGVjdGVkLmxlbmd0aCAtIDFdXG4gICAgICAgICAgOiBleHBlY3RlZERlc2NzWzBdO1xuXG4gICAgICAgIGZvdW5kRGVzYyA9IGZvdW5kID8gXCJcXFwiXCIgKyBzdHJpbmdFc2NhcGUoZm91bmQpICsgXCJcXFwiXCIgOiBcImVuZCBvZiBpbnB1dFwiO1xuXG4gICAgICAgIHJldHVybiBcIkV4cGVjdGVkIFwiICsgZXhwZWN0ZWREZXNjICsgXCIgYnV0IFwiICsgZm91bmREZXNjICsgXCIgZm91bmQuXCI7XG4gICAgICB9XG5cbiAgICAgIHZhciBwb3NEZXRhaWxzID0gcGVnJGNvbXB1dGVQb3NEZXRhaWxzKHBvcyksXG4gICAgICAgICAgZm91bmQgICAgICA9IHBvcyA8IGlucHV0Lmxlbmd0aCA/IGlucHV0LmNoYXJBdChwb3MpIDogbnVsbDtcblxuICAgICAgaWYgKGV4cGVjdGVkICE9PSBudWxsKSB7XG4gICAgICAgIGNsZWFudXBFeHBlY3RlZChleHBlY3RlZCk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBuZXcgU3ludGF4RXJyb3IoXG4gICAgICAgIG1lc3NhZ2UgIT09IG51bGwgPyBtZXNzYWdlIDogYnVpbGRNZXNzYWdlKGV4cGVjdGVkLCBmb3VuZCksXG4gICAgICAgIGV4cGVjdGVkLFxuICAgICAgICBmb3VuZCxcbiAgICAgICAgcG9zLFxuICAgICAgICBwb3NEZXRhaWxzLmxpbmUsXG4gICAgICAgIHBvc0RldGFpbHMuY29sdW1uXG4gICAgICApO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHBlZyRwYXJzZXN0YXJ0KCkge1xuICAgICAgdmFyIHMwLCBzMSwgczIsIHMzO1xuXG4gICAgICBwZWckc2lsZW50RmFpbHMrKztcbiAgICAgIHMwID0gcGVnJGN1cnJQb3M7XG4gICAgICBzMSA9IHBlZyRwYXJzZV9fKCk7XG4gICAgICBpZiAoczEgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgczIgPSBwZWckcGFyc2VPckV4cHIoKTtcbiAgICAgICAgaWYgKHMyICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgczMgPSBwZWckcGFyc2VfXygpO1xuICAgICAgICAgIGlmIChzMyAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgcGVnJHJlcG9ydGVkUG9zID0gczA7XG4gICAgICAgICAgICBzMSA9IHBlZyRjMihzMik7XG4gICAgICAgICAgICBzMCA9IHMxO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgfVxuICAgICAgaWYgKHMwID09PSBwZWckRkFJTEVEKSB7XG4gICAgICAgIHMwID0gcGVnJGN1cnJQb3M7XG4gICAgICAgIHMxID0gW107XG4gICAgICAgIGlmIChzMSAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgIHBlZyRyZXBvcnRlZFBvcyA9IHMwO1xuICAgICAgICAgIHMxID0gcGVnJGM0KCk7XG4gICAgICAgIH1cbiAgICAgICAgczAgPSBzMTtcbiAgICAgIH1cbiAgICAgIHBlZyRzaWxlbnRGYWlscy0tO1xuICAgICAgaWYgKHMwID09PSBwZWckRkFJTEVEKSB7XG4gICAgICAgIHMxID0gcGVnJEZBSUxFRDtcbiAgICAgICAgaWYgKHBlZyRzaWxlbnRGYWlscyA9PT0gMCkgeyBwZWckZmFpbChwZWckYzApOyB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBzMDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBwZWckcGFyc2V3cygpIHtcbiAgICAgIHZhciBzMCwgczE7XG5cbiAgICAgIHBlZyRzaWxlbnRGYWlscysrO1xuICAgICAgaWYgKHBlZyRjNi50ZXN0KGlucHV0LmNoYXJBdChwZWckY3VyclBvcykpKSB7XG4gICAgICAgIHMwID0gaW5wdXQuY2hhckF0KHBlZyRjdXJyUG9zKTtcbiAgICAgICAgcGVnJGN1cnJQb3MrKztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHMwID0gcGVnJEZBSUxFRDtcbiAgICAgICAgaWYgKHBlZyRzaWxlbnRGYWlscyA9PT0gMCkgeyBwZWckZmFpbChwZWckYzcpOyB9XG4gICAgICB9XG4gICAgICBwZWckc2lsZW50RmFpbHMtLTtcbiAgICAgIGlmIChzMCA9PT0gcGVnJEZBSUxFRCkge1xuICAgICAgICBzMSA9IHBlZyRGQUlMRUQ7XG4gICAgICAgIGlmIChwZWckc2lsZW50RmFpbHMgPT09IDApIHsgcGVnJGZhaWwocGVnJGM1KTsgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gczA7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcGVnJHBhcnNlY2MoKSB7XG4gICAgICB2YXIgczAsIHMxO1xuXG4gICAgICBwZWckc2lsZW50RmFpbHMrKztcbiAgICAgIGlmIChwZWckYzkudGVzdChpbnB1dC5jaGFyQXQocGVnJGN1cnJQb3MpKSkge1xuICAgICAgICBzMCA9IGlucHV0LmNoYXJBdChwZWckY3VyclBvcyk7XG4gICAgICAgIHBlZyRjdXJyUG9zKys7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzMCA9IHBlZyRGQUlMRUQ7XG4gICAgICAgIGlmIChwZWckc2lsZW50RmFpbHMgPT09IDApIHsgcGVnJGZhaWwocGVnJGMxMCk7IH1cbiAgICAgIH1cbiAgICAgIHBlZyRzaWxlbnRGYWlscy0tO1xuICAgICAgaWYgKHMwID09PSBwZWckRkFJTEVEKSB7XG4gICAgICAgIHMxID0gcGVnJEZBSUxFRDtcbiAgICAgICAgaWYgKHBlZyRzaWxlbnRGYWlscyA9PT0gMCkgeyBwZWckZmFpbChwZWckYzgpOyB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBzMDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBwZWckcGFyc2VfXygpIHtcbiAgICAgIHZhciBzMCwgczE7XG5cbiAgICAgIHBlZyRzaWxlbnRGYWlscysrO1xuICAgICAgczAgPSBbXTtcbiAgICAgIHMxID0gcGVnJHBhcnNld3MoKTtcbiAgICAgIHdoaWxlIChzMSAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICBzMC5wdXNoKHMxKTtcbiAgICAgICAgczEgPSBwZWckcGFyc2V3cygpO1xuICAgICAgfVxuICAgICAgcGVnJHNpbGVudEZhaWxzLS07XG4gICAgICBpZiAoczAgPT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgczEgPSBwZWckRkFJTEVEO1xuICAgICAgICBpZiAocGVnJHNpbGVudEZhaWxzID09PSAwKSB7IHBlZyRmYWlsKHBlZyRjMTEpOyB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBzMDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBwZWckcGFyc2VPckV4cHIoKSB7XG4gICAgICB2YXIgczAsIHMxLCBzMiwgczMsIHM0LCBzNTtcblxuICAgICAgczAgPSBwZWckY3VyclBvcztcbiAgICAgIHMxID0gcGVnJHBhcnNlQW5kRXhwcigpO1xuICAgICAgaWYgKHMxICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgIHMyID0gcGVnJHBhcnNlX18oKTtcbiAgICAgICAgaWYgKHMyICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgaWYgKGlucHV0LmNoYXJDb2RlQXQocGVnJGN1cnJQb3MpID09PSAxMjQpIHtcbiAgICAgICAgICAgIHMzID0gcGVnJGMxMjtcbiAgICAgICAgICAgIHBlZyRjdXJyUG9zKys7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHMzID0gcGVnJEZBSUxFRDtcbiAgICAgICAgICAgIGlmIChwZWckc2lsZW50RmFpbHMgPT09IDApIHsgcGVnJGZhaWwocGVnJGMxMyk7IH1cbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKHMzICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICBzNCA9IHBlZyRwYXJzZV9fKCk7XG4gICAgICAgICAgICBpZiAoczQgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgICAgczUgPSBwZWckcGFyc2VPckV4cHIoKTtcbiAgICAgICAgICAgICAgaWYgKHM1ICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgcGVnJHJlcG9ydGVkUG9zID0gczA7XG4gICAgICAgICAgICAgICAgczEgPSBwZWckYzE0KHMxLCBzNSk7XG4gICAgICAgICAgICAgICAgczAgPSBzMTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICAgICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICAgICAgICBzMCA9IHBlZyRjMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcGVnJGN1cnJQb3MgPSBzMDtcbiAgICAgICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICBzMCA9IHBlZyRjMTtcbiAgICAgIH1cbiAgICAgIGlmIChzMCA9PT0gcGVnJEZBSUxFRCkge1xuICAgICAgICBzMCA9IHBlZyRwYXJzZUFuZEV4cHIoKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHMwO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHBlZyRwYXJzZUFuZEV4cHIoKSB7XG4gICAgICB2YXIgczAsIHMxLCBzMiwgczMsIHM0LCBzNTtcblxuICAgICAgczAgPSBwZWckY3VyclBvcztcbiAgICAgIHMxID0gcGVnJHBhcnNlTm90RXhwcigpO1xuICAgICAgaWYgKHMxICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgIHMyID0gcGVnJHBhcnNlX18oKTtcbiAgICAgICAgaWYgKHMyICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgaWYgKGlucHV0LmNoYXJDb2RlQXQocGVnJGN1cnJQb3MpID09PSAzOCkge1xuICAgICAgICAgICAgczMgPSBwZWckYzE1O1xuICAgICAgICAgICAgcGVnJGN1cnJQb3MrKztcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgczMgPSBwZWckRkFJTEVEO1xuICAgICAgICAgICAgaWYgKHBlZyRzaWxlbnRGYWlscyA9PT0gMCkgeyBwZWckZmFpbChwZWckYzE2KTsgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoczMgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgIHM0ID0gcGVnJHBhcnNlX18oKTtcbiAgICAgICAgICAgIGlmIChzNCAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgICBzNSA9IHBlZyRwYXJzZUFuZEV4cHIoKTtcbiAgICAgICAgICAgICAgaWYgKHM1ICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgcGVnJHJlcG9ydGVkUG9zID0gczA7XG4gICAgICAgICAgICAgICAgczEgPSBwZWckYzE3KHMxLCBzNSk7XG4gICAgICAgICAgICAgICAgczAgPSBzMTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICAgICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICAgICAgICBzMCA9IHBlZyRjMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcGVnJGN1cnJQb3MgPSBzMDtcbiAgICAgICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICBzMCA9IHBlZyRjMTtcbiAgICAgIH1cbiAgICAgIGlmIChzMCA9PT0gcGVnJEZBSUxFRCkge1xuICAgICAgICBzMCA9IHBlZyRjdXJyUG9zO1xuICAgICAgICBzMSA9IHBlZyRwYXJzZU5vdEV4cHIoKTtcbiAgICAgICAgaWYgKHMxICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgczIgPSBbXTtcbiAgICAgICAgICBzMyA9IHBlZyRwYXJzZXdzKCk7XG4gICAgICAgICAgaWYgKHMzICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICB3aGlsZSAoczMgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgICAgczIucHVzaChzMyk7XG4gICAgICAgICAgICAgIHMzID0gcGVnJHBhcnNld3MoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgczIgPSBwZWckYzE7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChzMiAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgczMgPSBwZWckcGFyc2VBbmRFeHByKCk7XG4gICAgICAgICAgICBpZiAoczMgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgICAgcGVnJHJlcG9ydGVkUG9zID0gczA7XG4gICAgICAgICAgICAgIHMxID0gcGVnJGMxNyhzMSwgczMpO1xuICAgICAgICAgICAgICBzMCA9IHMxO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgcGVnJGN1cnJQb3MgPSBzMDtcbiAgICAgICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICBzMCA9IHBlZyRjMTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcGVnJGN1cnJQb3MgPSBzMDtcbiAgICAgICAgICBzMCA9IHBlZyRjMTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoczAgPT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICBzMCA9IHBlZyRwYXJzZU5vdEV4cHIoKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gczA7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcGVnJHBhcnNlTm90RXhwcigpIHtcbiAgICAgIHZhciBzMCwgczEsIHMyLCBzMztcblxuICAgICAgczAgPSBwZWckY3VyclBvcztcbiAgICAgIGlmIChpbnB1dC5jaGFyQ29kZUF0KHBlZyRjdXJyUG9zKSA9PT0gMzMpIHtcbiAgICAgICAgczEgPSBwZWckYzE4O1xuICAgICAgICBwZWckY3VyclBvcysrO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgczEgPSBwZWckRkFJTEVEO1xuICAgICAgICBpZiAocGVnJHNpbGVudEZhaWxzID09PSAwKSB7IHBlZyRmYWlsKHBlZyRjMTkpOyB9XG4gICAgICB9XG4gICAgICBpZiAoczEgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgczIgPSBwZWckcGFyc2VfXygpO1xuICAgICAgICBpZiAoczIgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICBzMyA9IHBlZyRwYXJzZU5vdEV4cHIoKTtcbiAgICAgICAgICBpZiAoczMgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgIHBlZyRyZXBvcnRlZFBvcyA9IHMwO1xuICAgICAgICAgICAgczEgPSBwZWckYzIwKHMzKTtcbiAgICAgICAgICAgIHMwID0gczE7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICBzMCA9IHBlZyRjMTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcGVnJGN1cnJQb3MgPSBzMDtcbiAgICAgICAgICBzMCA9IHBlZyRjMTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcGVnJGN1cnJQb3MgPSBzMDtcbiAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICB9XG4gICAgICBpZiAoczAgPT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgczAgPSBwZWckcGFyc2VCaW5kaW5nRXhwcigpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gczA7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcGVnJHBhcnNlQmluZGluZ0V4cHIoKSB7XG4gICAgICB2YXIgczAsIHMxLCBzMiwgczMsIHM0LCBzNTtcblxuICAgICAgczAgPSBwZWckY3VyclBvcztcbiAgICAgIGlmIChpbnB1dC5jaGFyQ29kZUF0KHBlZyRjdXJyUG9zKSA9PT0gNDApIHtcbiAgICAgICAgczEgPSBwZWckYzIxO1xuICAgICAgICBwZWckY3VyclBvcysrO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgczEgPSBwZWckRkFJTEVEO1xuICAgICAgICBpZiAocGVnJHNpbGVudEZhaWxzID09PSAwKSB7IHBlZyRmYWlsKHBlZyRjMjIpOyB9XG4gICAgICB9XG4gICAgICBpZiAoczEgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgczIgPSBwZWckcGFyc2VfXygpO1xuICAgICAgICBpZiAoczIgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICBzMyA9IHBlZyRwYXJzZU9yRXhwcigpO1xuICAgICAgICAgIGlmIChzMyAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgczQgPSBwZWckcGFyc2VfXygpO1xuICAgICAgICAgICAgaWYgKHM0ICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgIGlmIChpbnB1dC5jaGFyQ29kZUF0KHBlZyRjdXJyUG9zKSA9PT0gNDEpIHtcbiAgICAgICAgICAgICAgICBzNSA9IHBlZyRjMjM7XG4gICAgICAgICAgICAgICAgcGVnJGN1cnJQb3MrKztcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBzNSA9IHBlZyRGQUlMRUQ7XG4gICAgICAgICAgICAgICAgaWYgKHBlZyRzaWxlbnRGYWlscyA9PT0gMCkgeyBwZWckZmFpbChwZWckYzI0KTsgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGlmIChzNSAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgICAgIHBlZyRyZXBvcnRlZFBvcyA9IHMwO1xuICAgICAgICAgICAgICAgIHMxID0gcGVnJGMyNShzMyk7XG4gICAgICAgICAgICAgICAgczAgPSBzMTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICAgICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICAgICAgICBzMCA9IHBlZyRjMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcGVnJGN1cnJQb3MgPSBzMDtcbiAgICAgICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICBzMCA9IHBlZyRjMTtcbiAgICAgIH1cbiAgICAgIGlmIChzMCA9PT0gcGVnJEZBSUxFRCkge1xuICAgICAgICBzMCA9IHBlZyRwYXJzZUV4cHIoKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHMwO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHBlZyRwYXJzZUV4cHIoKSB7XG4gICAgICB2YXIgczA7XG5cbiAgICAgIHMwID0gcGVnJHBhcnNlTnVsbGFyeUV4cHIoKTtcbiAgICAgIGlmIChzMCA9PT0gcGVnJEZBSUxFRCkge1xuICAgICAgICBzMCA9IHBlZyRwYXJzZVVuYXJ5RXhwcigpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gczA7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcGVnJHBhcnNlTnVsbGFyeUV4cHIoKSB7XG4gICAgICB2YXIgczAsIHMxO1xuXG4gICAgICBzMCA9IHBlZyRwYXJzZUJvb2xlYW5MaXRlcmFsKCk7XG4gICAgICBpZiAoczAgPT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgczAgPSBwZWckY3VyclBvcztcbiAgICAgICAgaWYgKGlucHV0LnN1YnN0cihwZWckY3VyclBvcywgMikgPT09IHBlZyRjMjYpIHtcbiAgICAgICAgICBzMSA9IHBlZyRjMjY7XG4gICAgICAgICAgcGVnJGN1cnJQb3MgKz0gMjtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzMSA9IHBlZyRGQUlMRUQ7XG4gICAgICAgICAgaWYgKHBlZyRzaWxlbnRGYWlscyA9PT0gMCkgeyBwZWckZmFpbChwZWckYzI3KTsgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChzMSAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgIHBlZyRyZXBvcnRlZFBvcyA9IHMwO1xuICAgICAgICAgIHMxID0gcGVnJGMyOCgpO1xuICAgICAgICB9XG4gICAgICAgIHMwID0gczE7XG4gICAgICAgIGlmIChzMCA9PT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgIHMwID0gcGVnJGN1cnJQb3M7XG4gICAgICAgICAgaWYgKGlucHV0LnN1YnN0cihwZWckY3VyclBvcywgMikgPT09IHBlZyRjMjkpIHtcbiAgICAgICAgICAgIHMxID0gcGVnJGMyOTtcbiAgICAgICAgICAgIHBlZyRjdXJyUG9zICs9IDI7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHMxID0gcGVnJEZBSUxFRDtcbiAgICAgICAgICAgIGlmIChwZWckc2lsZW50RmFpbHMgPT09IDApIHsgcGVnJGZhaWwocGVnJGMzMCk7IH1cbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKHMxICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICBwZWckcmVwb3J0ZWRQb3MgPSBzMDtcbiAgICAgICAgICAgIHMxID0gcGVnJGMzMSgpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBzMCA9IHMxO1xuICAgICAgICAgIGlmIChzMCA9PT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgczAgPSBwZWckY3VyclBvcztcbiAgICAgICAgICAgIGlmIChpbnB1dC5zdWJzdHIocGVnJGN1cnJQb3MsIDIpID09PSBwZWckYzMyKSB7XG4gICAgICAgICAgICAgIHMxID0gcGVnJGMzMjtcbiAgICAgICAgICAgICAgcGVnJGN1cnJQb3MgKz0gMjtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHMxID0gcGVnJEZBSUxFRDtcbiAgICAgICAgICAgICAgaWYgKHBlZyRzaWxlbnRGYWlscyA9PT0gMCkgeyBwZWckZmFpbChwZWckYzMzKTsgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHMxICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgIHBlZyRyZXBvcnRlZFBvcyA9IHMwO1xuICAgICAgICAgICAgICBzMSA9IHBlZyRjMzQoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHMwID0gczE7XG4gICAgICAgICAgICBpZiAoczAgPT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgICAgczAgPSBwZWckY3VyclBvcztcbiAgICAgICAgICAgICAgaWYgKGlucHV0LnN1YnN0cihwZWckY3VyclBvcywgMikgPT09IHBlZyRjMzUpIHtcbiAgICAgICAgICAgICAgICBzMSA9IHBlZyRjMzU7XG4gICAgICAgICAgICAgICAgcGVnJGN1cnJQb3MgKz0gMjtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBzMSA9IHBlZyRGQUlMRUQ7XG4gICAgICAgICAgICAgICAgaWYgKHBlZyRzaWxlbnRGYWlscyA9PT0gMCkgeyBwZWckZmFpbChwZWckYzM2KTsgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGlmIChzMSAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgICAgIHBlZyRyZXBvcnRlZFBvcyA9IHMwO1xuICAgICAgICAgICAgICAgIHMxID0gcGVnJGMzNygpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHMwID0gczE7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBzMDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBwZWckcGFyc2VCb29sZWFuTGl0ZXJhbCgpIHtcbiAgICAgIHZhciBzMCwgczE7XG5cbiAgICAgIHMwID0gcGVnJGN1cnJQb3M7XG4gICAgICBpZiAoaW5wdXQuc3Vic3RyKHBlZyRjdXJyUG9zLCA0KSA9PT0gcGVnJGMzOCkge1xuICAgICAgICBzMSA9IHBlZyRjMzg7XG4gICAgICAgIHBlZyRjdXJyUG9zICs9IDQ7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzMSA9IHBlZyRGQUlMRUQ7XG4gICAgICAgIGlmIChwZWckc2lsZW50RmFpbHMgPT09IDApIHsgcGVnJGZhaWwocGVnJGMzOSk7IH1cbiAgICAgIH1cbiAgICAgIGlmIChzMSAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICBwZWckcmVwb3J0ZWRQb3MgPSBzMDtcbiAgICAgICAgczEgPSBwZWckYzQwKCk7XG4gICAgICB9XG4gICAgICBzMCA9IHMxO1xuICAgICAgaWYgKHMwID09PSBwZWckRkFJTEVEKSB7XG4gICAgICAgIHMwID0gcGVnJGN1cnJQb3M7XG4gICAgICAgIGlmIChpbnB1dC5zdWJzdHIocGVnJGN1cnJQb3MsIDUpID09PSBwZWckYzQxKSB7XG4gICAgICAgICAgczEgPSBwZWckYzQxO1xuICAgICAgICAgIHBlZyRjdXJyUG9zICs9IDU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgczEgPSBwZWckRkFJTEVEO1xuICAgICAgICAgIGlmIChwZWckc2lsZW50RmFpbHMgPT09IDApIHsgcGVnJGZhaWwocGVnJGM0Mik7IH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoczEgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICBwZWckcmVwb3J0ZWRQb3MgPSBzMDtcbiAgICAgICAgICBzMSA9IHBlZyRjNDMoKTtcbiAgICAgICAgfVxuICAgICAgICBzMCA9IHMxO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gczA7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcGVnJHBhcnNlVW5hcnlFeHByKCkge1xuICAgICAgdmFyIHMwLCBzMSwgczIsIHMzO1xuXG4gICAgICBzMCA9IHBlZyRjdXJyUG9zO1xuICAgICAgaWYgKGlucHV0LnN1YnN0cihwZWckY3VyclBvcywgMikgPT09IHBlZyRjNDQpIHtcbiAgICAgICAgczEgPSBwZWckYzQ0O1xuICAgICAgICBwZWckY3VyclBvcyArPSAyO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgczEgPSBwZWckRkFJTEVEO1xuICAgICAgICBpZiAocGVnJHNpbGVudEZhaWxzID09PSAwKSB7IHBlZyRmYWlsKHBlZyRjNDUpOyB9XG4gICAgICB9XG4gICAgICBpZiAoczEgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgczIgPSBbXTtcbiAgICAgICAgczMgPSBwZWckcGFyc2V3cygpO1xuICAgICAgICBpZiAoczMgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICB3aGlsZSAoczMgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgIHMyLnB1c2goczMpO1xuICAgICAgICAgICAgczMgPSBwZWckcGFyc2V3cygpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzMiA9IHBlZyRjMTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoczIgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICBzMyA9IHBlZyRwYXJzZUludGVnZXJMaXRlcmFsKCk7XG4gICAgICAgICAgaWYgKHMzICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICBwZWckcmVwb3J0ZWRQb3MgPSBzMDtcbiAgICAgICAgICAgIHMxID0gcGVnJGM0NihzMyk7XG4gICAgICAgICAgICBzMCA9IHMxO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgfVxuICAgICAgaWYgKHMwID09PSBwZWckRkFJTEVEKSB7XG4gICAgICAgIHMwID0gcGVnJGN1cnJQb3M7XG4gICAgICAgIGlmIChpbnB1dC5zdWJzdHIocGVnJGN1cnJQb3MsIDIpID09PSBwZWckYzQ3KSB7XG4gICAgICAgICAgczEgPSBwZWckYzQ3O1xuICAgICAgICAgIHBlZyRjdXJyUG9zICs9IDI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgczEgPSBwZWckRkFJTEVEO1xuICAgICAgICAgIGlmIChwZWckc2lsZW50RmFpbHMgPT09IDApIHsgcGVnJGZhaWwocGVnJGM0OCk7IH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoczEgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICBzMiA9IFtdO1xuICAgICAgICAgIHMzID0gcGVnJHBhcnNld3MoKTtcbiAgICAgICAgICBpZiAoczMgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgIHdoaWxlIChzMyAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgICBzMi5wdXNoKHMzKTtcbiAgICAgICAgICAgICAgczMgPSBwZWckcGFyc2V3cygpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBzMiA9IHBlZyRjMTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKHMyICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICBzMyA9IHBlZyRwYXJzZVN0cmluZ0xpdGVyYWwoKTtcbiAgICAgICAgICAgIGlmIChzMyAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgICBwZWckcmVwb3J0ZWRQb3MgPSBzMDtcbiAgICAgICAgICAgICAgczEgPSBwZWckYzQ5KHMzKTtcbiAgICAgICAgICAgICAgczAgPSBzMTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHMwID09PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgczAgPSBwZWckY3VyclBvcztcbiAgICAgICAgICBpZiAoaW5wdXQuc3Vic3RyKHBlZyRjdXJyUG9zLCAyKSA9PT0gcGVnJGM1MCkge1xuICAgICAgICAgICAgczEgPSBwZWckYzUwO1xuICAgICAgICAgICAgcGVnJGN1cnJQb3MgKz0gMjtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgczEgPSBwZWckRkFJTEVEO1xuICAgICAgICAgICAgaWYgKHBlZyRzaWxlbnRGYWlscyA9PT0gMCkgeyBwZWckZmFpbChwZWckYzUxKTsgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoczEgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgIHMyID0gW107XG4gICAgICAgICAgICBzMyA9IHBlZyRwYXJzZXdzKCk7XG4gICAgICAgICAgICBpZiAoczMgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgICAgd2hpbGUgKHMzICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgczIucHVzaChzMyk7XG4gICAgICAgICAgICAgICAgczMgPSBwZWckcGFyc2V3cygpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBzMiA9IHBlZyRjMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChzMiAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgICBzMyA9IHBlZyRwYXJzZVN0cmluZ0xpdGVyYWwoKTtcbiAgICAgICAgICAgICAgaWYgKHMzICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgcGVnJHJlcG9ydGVkUG9zID0gczA7XG4gICAgICAgICAgICAgICAgczEgPSBwZWckYzUyKHMzKTtcbiAgICAgICAgICAgICAgICBzMCA9IHMxO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChzMCA9PT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgczAgPSBwZWckY3VyclBvcztcbiAgICAgICAgICAgIGlmIChpbnB1dC5zdWJzdHIocGVnJGN1cnJQb3MsIDMpID09PSBwZWckYzUzKSB7XG4gICAgICAgICAgICAgIHMxID0gcGVnJGM1MztcbiAgICAgICAgICAgICAgcGVnJGN1cnJQb3MgKz0gMztcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHMxID0gcGVnJEZBSUxFRDtcbiAgICAgICAgICAgICAgaWYgKHBlZyRzaWxlbnRGYWlscyA9PT0gMCkgeyBwZWckZmFpbChwZWckYzU0KTsgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHMxICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgIHMyID0gW107XG4gICAgICAgICAgICAgIHMzID0gcGVnJHBhcnNld3MoKTtcbiAgICAgICAgICAgICAgaWYgKHMzICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgd2hpbGUgKHMzICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgICBzMi5wdXNoKHMzKTtcbiAgICAgICAgICAgICAgICAgIHMzID0gcGVnJHBhcnNld3MoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgczIgPSBwZWckYzE7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgaWYgKHMyICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgczMgPSBwZWckcGFyc2VTdHJpbmdMaXRlcmFsKCk7XG4gICAgICAgICAgICAgICAgaWYgKHMzICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgICBwZWckcmVwb3J0ZWRQb3MgPSBzMDtcbiAgICAgICAgICAgICAgICAgIHMxID0gcGVnJGM1NShzMyk7XG4gICAgICAgICAgICAgICAgICBzMCA9IHMxO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICAgICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHMwID09PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgIHMwID0gcGVnJGN1cnJQb3M7XG4gICAgICAgICAgICAgIGlmIChpbnB1dC5zdWJzdHIocGVnJGN1cnJQb3MsIDMpID09PSBwZWckYzU2KSB7XG4gICAgICAgICAgICAgICAgczEgPSBwZWckYzU2O1xuICAgICAgICAgICAgICAgIHBlZyRjdXJyUG9zICs9IDM7XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgczEgPSBwZWckRkFJTEVEO1xuICAgICAgICAgICAgICAgIGlmIChwZWckc2lsZW50RmFpbHMgPT09IDApIHsgcGVnJGZhaWwocGVnJGM1Nyk7IH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBpZiAoczEgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgICAgICBzMiA9IFtdO1xuICAgICAgICAgICAgICAgIHMzID0gcGVnJHBhcnNld3MoKTtcbiAgICAgICAgICAgICAgICBpZiAoczMgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgICAgICAgIHdoaWxlIChzMyAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgICAgICAgICBzMi5wdXNoKHMzKTtcbiAgICAgICAgICAgICAgICAgICAgczMgPSBwZWckcGFyc2V3cygpO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICBzMiA9IHBlZyRjMTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKHMyICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgICBzMyA9IHBlZyRwYXJzZVN0cmluZ0xpdGVyYWwoKTtcbiAgICAgICAgICAgICAgICAgIGlmIChzMyAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgICAgICAgICBwZWckcmVwb3J0ZWRQb3MgPSBzMDtcbiAgICAgICAgICAgICAgICAgICAgczEgPSBwZWckYzU4KHMzKTtcbiAgICAgICAgICAgICAgICAgICAgczAgPSBzMTtcbiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICAgICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICAgICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgaWYgKHMwID09PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgczAgPSBwZWckY3VyclBvcztcbiAgICAgICAgICAgICAgICBpZiAoaW5wdXQuc3Vic3RyKHBlZyRjdXJyUG9zLCAyKSA9PT0gcGVnJGM1OSkge1xuICAgICAgICAgICAgICAgICAgczEgPSBwZWckYzU5O1xuICAgICAgICAgICAgICAgICAgcGVnJGN1cnJQb3MgKz0gMjtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgczEgPSBwZWckRkFJTEVEO1xuICAgICAgICAgICAgICAgICAgaWYgKHBlZyRzaWxlbnRGYWlscyA9PT0gMCkgeyBwZWckZmFpbChwZWckYzYwKTsgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoczEgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgICAgICAgIHMyID0gW107XG4gICAgICAgICAgICAgICAgICBzMyA9IHBlZyRwYXJzZXdzKCk7XG4gICAgICAgICAgICAgICAgICBpZiAoczMgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgICAgICAgICAgd2hpbGUgKHMzICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgICAgICAgczIucHVzaChzMyk7XG4gICAgICAgICAgICAgICAgICAgICAgczMgPSBwZWckcGFyc2V3cygpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBzMiA9IHBlZyRjMTtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIGlmIChzMiAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgICAgICAgICBzMyA9IHBlZyRwYXJzZVN0cmluZ0xpdGVyYWwoKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHMzICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgICAgICAgcGVnJHJlcG9ydGVkUG9zID0gczA7XG4gICAgICAgICAgICAgICAgICAgICAgczEgPSBwZWckYzYxKHMzKTtcbiAgICAgICAgICAgICAgICAgICAgICBzMCA9IHMxO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICAgICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICAgICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICAgICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChzMCA9PT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgICAgICAgczAgPSBwZWckY3VyclBvcztcbiAgICAgICAgICAgICAgICAgIGlmIChpbnB1dC5zdWJzdHIocGVnJGN1cnJQb3MsIDIpID09PSBwZWckYzYyKSB7XG4gICAgICAgICAgICAgICAgICAgIHMxID0gcGVnJGM2MjtcbiAgICAgICAgICAgICAgICAgICAgcGVnJGN1cnJQb3MgKz0gMjtcbiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHMxID0gcGVnJEZBSUxFRDtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHBlZyRzaWxlbnRGYWlscyA9PT0gMCkgeyBwZWckZmFpbChwZWckYzYzKTsgfVxuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgaWYgKHMxICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgICAgIHMyID0gW107XG4gICAgICAgICAgICAgICAgICAgIHMzID0gcGVnJHBhcnNld3MoKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHMzICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgICAgICAgd2hpbGUgKHMzICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzMi5wdXNoKHMzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHMzID0gcGVnJHBhcnNld3MoKTtcbiAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgczIgPSBwZWckYzE7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKHMyICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgICAgICAgczMgPSBwZWckcGFyc2VTdHJpbmdMaXRlcmFsKCk7XG4gICAgICAgICAgICAgICAgICAgICAgaWYgKHMzICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBwZWckcmVwb3J0ZWRQb3MgPSBzMDtcbiAgICAgICAgICAgICAgICAgICAgICAgIHMxID0gcGVnJGM2NChzMyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBzMCA9IHMxO1xuICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICAgICAgICAgICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICAgICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICAgICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgaWYgKHMwID09PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgICAgIHMwID0gcGVnJGN1cnJQb3M7XG4gICAgICAgICAgICAgICAgICAgIGlmIChpbnB1dC5zdWJzdHIocGVnJGN1cnJQb3MsIDMpID09PSBwZWckYzY1KSB7XG4gICAgICAgICAgICAgICAgICAgICAgczEgPSBwZWckYzY1O1xuICAgICAgICAgICAgICAgICAgICAgIHBlZyRjdXJyUG9zICs9IDM7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgczEgPSBwZWckRkFJTEVEO1xuICAgICAgICAgICAgICAgICAgICAgIGlmIChwZWckc2lsZW50RmFpbHMgPT09IDApIHsgcGVnJGZhaWwocGVnJGM2Nik7IH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBpZiAoczEgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgICAgICAgICAgICBzMiA9IFtdO1xuICAgICAgICAgICAgICAgICAgICAgIHMzID0gcGVnJHBhcnNld3MoKTtcbiAgICAgICAgICAgICAgICAgICAgICBpZiAoczMgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHdoaWxlIChzMyAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBzMi5wdXNoKHMzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgczMgPSBwZWckcGFyc2V3cygpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzMiA9IHBlZyRjMTtcbiAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgaWYgKHMyICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzMyA9IHBlZyRwYXJzZVN0cmluZ0xpdGVyYWwoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzMyAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBwZWckcmVwb3J0ZWRQb3MgPSBzMDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgczEgPSBwZWckYzY3KHMzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgczAgPSBzMTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICAgICAgICAgICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICAgICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKHMwID09PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgICAgICAgczAgPSBwZWckY3VyclBvcztcbiAgICAgICAgICAgICAgICAgICAgICBpZiAoaW5wdXQuc3Vic3RyKHBlZyRjdXJyUG9zLCAzKSA9PT0gcGVnJGM2OCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgczEgPSBwZWckYzY4O1xuICAgICAgICAgICAgICAgICAgICAgICAgcGVnJGN1cnJQb3MgKz0gMztcbiAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgczEgPSBwZWckRkFJTEVEO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBlZyRzaWxlbnRGYWlscyA9PT0gMCkgeyBwZWckZmFpbChwZWckYzY5KTsgfVxuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICBpZiAoczEgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHMyID0gW107XG4gICAgICAgICAgICAgICAgICAgICAgICBzMyA9IHBlZyRwYXJzZXdzKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoczMgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpbGUgKHMzICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgczIucHVzaChzMyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgczMgPSBwZWckcGFyc2V3cygpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBzMiA9IHBlZyRjMTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzMiAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBzMyA9IHBlZyRwYXJzZVN0cmluZ0xpdGVyYWwoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHMzICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcGVnJHJlcG9ydGVkUG9zID0gczA7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgczEgPSBwZWckYzcwKHMzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzMCA9IHMxO1xuICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICAgICAgICAgICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgIGlmIChzMCA9PT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgczAgPSBwZWckY3VyclBvcztcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpbnB1dC5zdWJzdHIocGVnJGN1cnJQb3MsIDIpID09PSBwZWckYzcxKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHMxID0gcGVnJGM3MTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcGVnJGN1cnJQb3MgKz0gMjtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHMxID0gcGVnJEZBSUxFRDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBlZyRzaWxlbnRGYWlscyA9PT0gMCkgeyBwZWckZmFpbChwZWckYzcyKTsgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHMxICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHMyID0gW107XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHMzID0gcGVnJHBhcnNld3MoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHMzICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpbGUgKHMzICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzMi5wdXNoKHMzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHMzID0gcGVnJHBhcnNld3MoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgczIgPSBwZWckYzE7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHMyICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgczMgPSBwZWckcGFyc2VTdHJpbmdMaXRlcmFsKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHMzICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZWckcmVwb3J0ZWRQb3MgPSBzMDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHMxID0gcGVnJGM3MyhzMyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzMCA9IHMxO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHMwID09PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHMwID0gcGVnJGN1cnJQb3M7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHMxID0gcGVnJHBhcnNlU3RyaW5nTGl0ZXJhbCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoczEgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZWckcmVwb3J0ZWRQb3MgPSBzMDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzMSA9IHBlZyRjNzMoczEpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHMwID0gczE7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBzMDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBwZWckcGFyc2VJbnRlZ2VyTGl0ZXJhbCgpIHtcbiAgICAgIHZhciBzMCwgczEsIHMyLCBzMztcblxuICAgICAgcGVnJHNpbGVudEZhaWxzKys7XG4gICAgICBzMCA9IHBlZyRjdXJyUG9zO1xuICAgICAgaWYgKHBlZyRjNzYudGVzdChpbnB1dC5jaGFyQXQocGVnJGN1cnJQb3MpKSkge1xuICAgICAgICBzMSA9IGlucHV0LmNoYXJBdChwZWckY3VyclBvcyk7XG4gICAgICAgIHBlZyRjdXJyUG9zKys7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzMSA9IHBlZyRGQUlMRUQ7XG4gICAgICAgIGlmIChwZWckc2lsZW50RmFpbHMgPT09IDApIHsgcGVnJGZhaWwocGVnJGM3Nyk7IH1cbiAgICAgIH1cbiAgICAgIGlmIChzMSA9PT0gcGVnJEZBSUxFRCkge1xuICAgICAgICBzMSA9IHBlZyRjNzU7XG4gICAgICB9XG4gICAgICBpZiAoczEgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgczIgPSBbXTtcbiAgICAgICAgaWYgKHBlZyRjNzgudGVzdChpbnB1dC5jaGFyQXQocGVnJGN1cnJQb3MpKSkge1xuICAgICAgICAgIHMzID0gaW5wdXQuY2hhckF0KHBlZyRjdXJyUG9zKTtcbiAgICAgICAgICBwZWckY3VyclBvcysrO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHMzID0gcGVnJEZBSUxFRDtcbiAgICAgICAgICBpZiAocGVnJHNpbGVudEZhaWxzID09PSAwKSB7IHBlZyRmYWlsKHBlZyRjNzkpOyB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHMzICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgd2hpbGUgKHMzICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICBzMi5wdXNoKHMzKTtcbiAgICAgICAgICAgIGlmIChwZWckYzc4LnRlc3QoaW5wdXQuY2hhckF0KHBlZyRjdXJyUG9zKSkpIHtcbiAgICAgICAgICAgICAgczMgPSBpbnB1dC5jaGFyQXQocGVnJGN1cnJQb3MpO1xuICAgICAgICAgICAgICBwZWckY3VyclBvcysrO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgczMgPSBwZWckRkFJTEVEO1xuICAgICAgICAgICAgICBpZiAocGVnJHNpbGVudEZhaWxzID09PSAwKSB7IHBlZyRmYWlsKHBlZyRjNzkpOyB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHMyID0gcGVnJGMxO1xuICAgICAgICB9XG4gICAgICAgIGlmIChzMiAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgIGlmIChwZWckYzc2LnRlc3QoaW5wdXQuY2hhckF0KHBlZyRjdXJyUG9zKSkpIHtcbiAgICAgICAgICAgIHMzID0gaW5wdXQuY2hhckF0KHBlZyRjdXJyUG9zKTtcbiAgICAgICAgICAgIHBlZyRjdXJyUG9zKys7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHMzID0gcGVnJEZBSUxFRDtcbiAgICAgICAgICAgIGlmIChwZWckc2lsZW50RmFpbHMgPT09IDApIHsgcGVnJGZhaWwocGVnJGM3Nyk7IH1cbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKHMzID09PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICBzMyA9IHBlZyRjNzU7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChzMyAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgcGVnJHJlcG9ydGVkUG9zID0gczA7XG4gICAgICAgICAgICBzMSA9IHBlZyRjODAoczIpO1xuICAgICAgICAgICAgczAgPSBzMTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcGVnJGN1cnJQb3MgPSBzMDtcbiAgICAgICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICBzMCA9IHBlZyRjMTtcbiAgICAgIH1cbiAgICAgIHBlZyRzaWxlbnRGYWlscy0tO1xuICAgICAgaWYgKHMwID09PSBwZWckRkFJTEVEKSB7XG4gICAgICAgIHMxID0gcGVnJEZBSUxFRDtcbiAgICAgICAgaWYgKHBlZyRzaWxlbnRGYWlscyA9PT0gMCkgeyBwZWckZmFpbChwZWckYzc0KTsgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gczA7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcGVnJHBhcnNlU3RyaW5nTGl0ZXJhbCgpIHtcbiAgICAgIHZhciBzMCwgczEsIHMyLCBzMztcblxuICAgICAgcGVnJHNpbGVudEZhaWxzKys7XG4gICAgICBzMCA9IHBlZyRjdXJyUG9zO1xuICAgICAgaWYgKGlucHV0LmNoYXJDb2RlQXQocGVnJGN1cnJQb3MpID09PSAzNCkge1xuICAgICAgICBzMSA9IHBlZyRjODI7XG4gICAgICAgIHBlZyRjdXJyUG9zKys7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzMSA9IHBlZyRGQUlMRUQ7XG4gICAgICAgIGlmIChwZWckc2lsZW50RmFpbHMgPT09IDApIHsgcGVnJGZhaWwocGVnJGM4Myk7IH1cbiAgICAgIH1cbiAgICAgIGlmIChzMSAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICBzMiA9IFtdO1xuICAgICAgICBzMyA9IHBlZyRwYXJzZURvdWJsZVN0cmluZ0NoYXIoKTtcbiAgICAgICAgd2hpbGUgKHMzICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgczIucHVzaChzMyk7XG4gICAgICAgICAgczMgPSBwZWckcGFyc2VEb3VibGVTdHJpbmdDaGFyKCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHMyICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgaWYgKGlucHV0LmNoYXJDb2RlQXQocGVnJGN1cnJQb3MpID09PSAzNCkge1xuICAgICAgICAgICAgczMgPSBwZWckYzgyO1xuICAgICAgICAgICAgcGVnJGN1cnJQb3MrKztcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgczMgPSBwZWckRkFJTEVEO1xuICAgICAgICAgICAgaWYgKHBlZyRzaWxlbnRGYWlscyA9PT0gMCkgeyBwZWckZmFpbChwZWckYzgzKTsgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoczMgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgIHBlZyRyZXBvcnRlZFBvcyA9IHMwO1xuICAgICAgICAgICAgczEgPSBwZWckYzg0KHMyKTtcbiAgICAgICAgICAgIHMwID0gczE7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICBzMCA9IHBlZyRjMTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcGVnJGN1cnJQb3MgPSBzMDtcbiAgICAgICAgICBzMCA9IHBlZyRjMTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcGVnJGN1cnJQb3MgPSBzMDtcbiAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICB9XG4gICAgICBpZiAoczAgPT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgczAgPSBwZWckY3VyclBvcztcbiAgICAgICAgaWYgKGlucHV0LmNoYXJDb2RlQXQocGVnJGN1cnJQb3MpID09PSAzOSkge1xuICAgICAgICAgIHMxID0gcGVnJGM4NTtcbiAgICAgICAgICBwZWckY3VyclBvcysrO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHMxID0gcGVnJEZBSUxFRDtcbiAgICAgICAgICBpZiAocGVnJHNpbGVudEZhaWxzID09PSAwKSB7IHBlZyRmYWlsKHBlZyRjODYpOyB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHMxICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgczIgPSBbXTtcbiAgICAgICAgICBzMyA9IHBlZyRwYXJzZVNpbmdsZVN0cmluZ0NoYXIoKTtcbiAgICAgICAgICB3aGlsZSAoczMgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgIHMyLnB1c2goczMpO1xuICAgICAgICAgICAgczMgPSBwZWckcGFyc2VTaW5nbGVTdHJpbmdDaGFyKCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChzMiAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgaWYgKGlucHV0LmNoYXJDb2RlQXQocGVnJGN1cnJQb3MpID09PSAzOSkge1xuICAgICAgICAgICAgICBzMyA9IHBlZyRjODU7XG4gICAgICAgICAgICAgIHBlZyRjdXJyUG9zKys7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBzMyA9IHBlZyRGQUlMRUQ7XG4gICAgICAgICAgICAgIGlmIChwZWckc2lsZW50RmFpbHMgPT09IDApIHsgcGVnJGZhaWwocGVnJGM4Nik7IH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChzMyAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgICBwZWckcmVwb3J0ZWRQb3MgPSBzMDtcbiAgICAgICAgICAgICAgczEgPSBwZWckYzg0KHMyKTtcbiAgICAgICAgICAgICAgczAgPSBzMTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHMwID09PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgczAgPSBwZWckY3VyclBvcztcbiAgICAgICAgICBzMSA9IHBlZyRjdXJyUG9zO1xuICAgICAgICAgIHBlZyRzaWxlbnRGYWlscysrO1xuICAgICAgICAgIHMyID0gcGVnJHBhcnNlY2MoKTtcbiAgICAgICAgICBwZWckc2lsZW50RmFpbHMtLTtcbiAgICAgICAgICBpZiAoczIgPT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgIHMxID0gcGVnJGM4NztcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcGVnJGN1cnJQb3MgPSBzMTtcbiAgICAgICAgICAgIHMxID0gcGVnJGMxO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoczEgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgIHMyID0gW107XG4gICAgICAgICAgICBzMyA9IHBlZyRwYXJzZVVucXVvdGVkU3RyaW5nQ2hhcigpO1xuICAgICAgICAgICAgaWYgKHMzICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgIHdoaWxlIChzMyAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgICAgIHMyLnB1c2goczMpO1xuICAgICAgICAgICAgICAgIHMzID0gcGVnJHBhcnNlVW5xdW90ZWRTdHJpbmdDaGFyKCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHMyID0gcGVnJGMxO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHMyICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgICAgIHBlZyRyZXBvcnRlZFBvcyA9IHMwO1xuICAgICAgICAgICAgICBzMSA9IHBlZyRjODQoczIpO1xuICAgICAgICAgICAgICBzMCA9IHMxO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgcGVnJGN1cnJQb3MgPSBzMDtcbiAgICAgICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICBzMCA9IHBlZyRjMTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHBlZyRzaWxlbnRGYWlscy0tO1xuICAgICAgaWYgKHMwID09PSBwZWckRkFJTEVEKSB7XG4gICAgICAgIHMxID0gcGVnJEZBSUxFRDtcbiAgICAgICAgaWYgKHBlZyRzaWxlbnRGYWlscyA9PT0gMCkgeyBwZWckZmFpbChwZWckYzgxKTsgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gczA7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcGVnJHBhcnNlRG91YmxlU3RyaW5nQ2hhcigpIHtcbiAgICAgIHZhciBzMCwgczEsIHMyO1xuXG4gICAgICBzMCA9IHBlZyRjdXJyUG9zO1xuICAgICAgczEgPSBwZWckY3VyclBvcztcbiAgICAgIHBlZyRzaWxlbnRGYWlscysrO1xuICAgICAgaWYgKHBlZyRjODgudGVzdChpbnB1dC5jaGFyQXQocGVnJGN1cnJQb3MpKSkge1xuICAgICAgICBzMiA9IGlucHV0LmNoYXJBdChwZWckY3VyclBvcyk7XG4gICAgICAgIHBlZyRjdXJyUG9zKys7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzMiA9IHBlZyRGQUlMRUQ7XG4gICAgICAgIGlmIChwZWckc2lsZW50RmFpbHMgPT09IDApIHsgcGVnJGZhaWwocGVnJGM4OSk7IH1cbiAgICAgIH1cbiAgICAgIHBlZyRzaWxlbnRGYWlscy0tO1xuICAgICAgaWYgKHMyID09PSBwZWckRkFJTEVEKSB7XG4gICAgICAgIHMxID0gcGVnJGM4NztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHBlZyRjdXJyUG9zID0gczE7XG4gICAgICAgIHMxID0gcGVnJGMxO1xuICAgICAgfVxuICAgICAgaWYgKHMxICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgIGlmIChpbnB1dC5sZW5ndGggPiBwZWckY3VyclBvcykge1xuICAgICAgICAgIHMyID0gaW5wdXQuY2hhckF0KHBlZyRjdXJyUG9zKTtcbiAgICAgICAgICBwZWckY3VyclBvcysrO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHMyID0gcGVnJEZBSUxFRDtcbiAgICAgICAgICBpZiAocGVnJHNpbGVudEZhaWxzID09PSAwKSB7IHBlZyRmYWlsKHBlZyRjOTApOyB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHMyICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgcGVnJHJlcG9ydGVkUG9zID0gczA7XG4gICAgICAgICAgczEgPSBwZWckYzkxKHMyKTtcbiAgICAgICAgICBzMCA9IHMxO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgfVxuICAgICAgaWYgKHMwID09PSBwZWckRkFJTEVEKSB7XG4gICAgICAgIHMwID0gcGVnJGN1cnJQb3M7XG4gICAgICAgIGlmIChpbnB1dC5jaGFyQ29kZUF0KHBlZyRjdXJyUG9zKSA9PT0gOTIpIHtcbiAgICAgICAgICBzMSA9IHBlZyRjOTI7XG4gICAgICAgICAgcGVnJGN1cnJQb3MrKztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzMSA9IHBlZyRGQUlMRUQ7XG4gICAgICAgICAgaWYgKHBlZyRzaWxlbnRGYWlscyA9PT0gMCkgeyBwZWckZmFpbChwZWckYzkzKTsgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChzMSAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgIHMyID0gcGVnJHBhcnNlRXNjYXBlU2VxdWVuY2UoKTtcbiAgICAgICAgICBpZiAoczIgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgIHBlZyRyZXBvcnRlZFBvcyA9IHMwO1xuICAgICAgICAgICAgczEgPSBwZWckYzkxKHMyKTtcbiAgICAgICAgICAgIHMwID0gczE7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICBzMCA9IHBlZyRjMTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcGVnJGN1cnJQb3MgPSBzMDtcbiAgICAgICAgICBzMCA9IHBlZyRjMTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gczA7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcGVnJHBhcnNlU2luZ2xlU3RyaW5nQ2hhcigpIHtcbiAgICAgIHZhciBzMCwgczEsIHMyO1xuXG4gICAgICBzMCA9IHBlZyRjdXJyUG9zO1xuICAgICAgczEgPSBwZWckY3VyclBvcztcbiAgICAgIHBlZyRzaWxlbnRGYWlscysrO1xuICAgICAgaWYgKHBlZyRjOTQudGVzdChpbnB1dC5jaGFyQXQocGVnJGN1cnJQb3MpKSkge1xuICAgICAgICBzMiA9IGlucHV0LmNoYXJBdChwZWckY3VyclBvcyk7XG4gICAgICAgIHBlZyRjdXJyUG9zKys7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzMiA9IHBlZyRGQUlMRUQ7XG4gICAgICAgIGlmIChwZWckc2lsZW50RmFpbHMgPT09IDApIHsgcGVnJGZhaWwocGVnJGM5NSk7IH1cbiAgICAgIH1cbiAgICAgIHBlZyRzaWxlbnRGYWlscy0tO1xuICAgICAgaWYgKHMyID09PSBwZWckRkFJTEVEKSB7XG4gICAgICAgIHMxID0gcGVnJGM4NztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHBlZyRjdXJyUG9zID0gczE7XG4gICAgICAgIHMxID0gcGVnJGMxO1xuICAgICAgfVxuICAgICAgaWYgKHMxICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgIGlmIChpbnB1dC5sZW5ndGggPiBwZWckY3VyclBvcykge1xuICAgICAgICAgIHMyID0gaW5wdXQuY2hhckF0KHBlZyRjdXJyUG9zKTtcbiAgICAgICAgICBwZWckY3VyclBvcysrO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHMyID0gcGVnJEZBSUxFRDtcbiAgICAgICAgICBpZiAocGVnJHNpbGVudEZhaWxzID09PSAwKSB7IHBlZyRmYWlsKHBlZyRjOTApOyB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHMyICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgcGVnJHJlcG9ydGVkUG9zID0gczA7XG4gICAgICAgICAgczEgPSBwZWckYzkxKHMyKTtcbiAgICAgICAgICBzMCA9IHMxO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgczAgPSBwZWckYzE7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgfVxuICAgICAgaWYgKHMwID09PSBwZWckRkFJTEVEKSB7XG4gICAgICAgIHMwID0gcGVnJGN1cnJQb3M7XG4gICAgICAgIGlmIChpbnB1dC5jaGFyQ29kZUF0KHBlZyRjdXJyUG9zKSA9PT0gOTIpIHtcbiAgICAgICAgICBzMSA9IHBlZyRjOTI7XG4gICAgICAgICAgcGVnJGN1cnJQb3MrKztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzMSA9IHBlZyRGQUlMRUQ7XG4gICAgICAgICAgaWYgKHBlZyRzaWxlbnRGYWlscyA9PT0gMCkgeyBwZWckZmFpbChwZWckYzkzKTsgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChzMSAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgIHMyID0gcGVnJHBhcnNlRXNjYXBlU2VxdWVuY2UoKTtcbiAgICAgICAgICBpZiAoczIgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgIHBlZyRyZXBvcnRlZFBvcyA9IHMwO1xuICAgICAgICAgICAgczEgPSBwZWckYzkxKHMyKTtcbiAgICAgICAgICAgIHMwID0gczE7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHBlZyRjdXJyUG9zID0gczA7XG4gICAgICAgICAgICBzMCA9IHBlZyRjMTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcGVnJGN1cnJQb3MgPSBzMDtcbiAgICAgICAgICBzMCA9IHBlZyRjMTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gczA7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcGVnJHBhcnNlVW5xdW90ZWRTdHJpbmdDaGFyKCkge1xuICAgICAgdmFyIHMwLCBzMSwgczI7XG5cbiAgICAgIHMwID0gcGVnJGN1cnJQb3M7XG4gICAgICBzMSA9IHBlZyRjdXJyUG9zO1xuICAgICAgcGVnJHNpbGVudEZhaWxzKys7XG4gICAgICBzMiA9IHBlZyRwYXJzZXdzKCk7XG4gICAgICBwZWckc2lsZW50RmFpbHMtLTtcbiAgICAgIGlmIChzMiA9PT0gcGVnJEZBSUxFRCkge1xuICAgICAgICBzMSA9IHBlZyRjODc7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBwZWckY3VyclBvcyA9IHMxO1xuICAgICAgICBzMSA9IHBlZyRjMTtcbiAgICAgIH1cbiAgICAgIGlmIChzMSAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICBpZiAoaW5wdXQubGVuZ3RoID4gcGVnJGN1cnJQb3MpIHtcbiAgICAgICAgICBzMiA9IGlucHV0LmNoYXJBdChwZWckY3VyclBvcyk7XG4gICAgICAgICAgcGVnJGN1cnJQb3MrKztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzMiA9IHBlZyRGQUlMRUQ7XG4gICAgICAgICAgaWYgKHBlZyRzaWxlbnRGYWlscyA9PT0gMCkgeyBwZWckZmFpbChwZWckYzkwKTsgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChzMiAhPT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgIHBlZyRyZXBvcnRlZFBvcyA9IHMwO1xuICAgICAgICAgIHMxID0gcGVnJGM5MShzMik7XG4gICAgICAgICAgczAgPSBzMTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICAgIHMwID0gcGVnJGMxO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBwZWckY3VyclBvcyA9IHMwO1xuICAgICAgICBzMCA9IHBlZyRjMTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHMwO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHBlZyRwYXJzZUVzY2FwZVNlcXVlbmNlKCkge1xuICAgICAgdmFyIHMwLCBzMTtcblxuICAgICAgaWYgKHBlZyRjOTYudGVzdChpbnB1dC5jaGFyQXQocGVnJGN1cnJQb3MpKSkge1xuICAgICAgICBzMCA9IGlucHV0LmNoYXJBdChwZWckY3VyclBvcyk7XG4gICAgICAgIHBlZyRjdXJyUG9zKys7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzMCA9IHBlZyRGQUlMRUQ7XG4gICAgICAgIGlmIChwZWckc2lsZW50RmFpbHMgPT09IDApIHsgcGVnJGZhaWwocGVnJGM5Nyk7IH1cbiAgICAgIH1cbiAgICAgIGlmIChzMCA9PT0gcGVnJEZBSUxFRCkge1xuICAgICAgICBzMCA9IHBlZyRjdXJyUG9zO1xuICAgICAgICBpZiAoaW5wdXQuY2hhckNvZGVBdChwZWckY3VyclBvcykgPT09IDExMCkge1xuICAgICAgICAgIHMxID0gcGVnJGM5ODtcbiAgICAgICAgICBwZWckY3VyclBvcysrO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHMxID0gcGVnJEZBSUxFRDtcbiAgICAgICAgICBpZiAocGVnJHNpbGVudEZhaWxzID09PSAwKSB7IHBlZyRmYWlsKHBlZyRjOTkpOyB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHMxICE9PSBwZWckRkFJTEVEKSB7XG4gICAgICAgICAgcGVnJHJlcG9ydGVkUG9zID0gczA7XG4gICAgICAgICAgczEgPSBwZWckYzEwMCgpO1xuICAgICAgICB9XG4gICAgICAgIHMwID0gczE7XG4gICAgICAgIGlmIChzMCA9PT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgIHMwID0gcGVnJGN1cnJQb3M7XG4gICAgICAgICAgaWYgKGlucHV0LmNoYXJDb2RlQXQocGVnJGN1cnJQb3MpID09PSAxMTQpIHtcbiAgICAgICAgICAgIHMxID0gcGVnJGMxMDE7XG4gICAgICAgICAgICBwZWckY3VyclBvcysrO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBzMSA9IHBlZyRGQUlMRUQ7XG4gICAgICAgICAgICBpZiAocGVnJHNpbGVudEZhaWxzID09PSAwKSB7IHBlZyRmYWlsKHBlZyRjMTAyKTsgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoczEgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgIHBlZyRyZXBvcnRlZFBvcyA9IHMwO1xuICAgICAgICAgICAgczEgPSBwZWckYzEwMygpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBzMCA9IHMxO1xuICAgICAgICAgIGlmIChzMCA9PT0gcGVnJEZBSUxFRCkge1xuICAgICAgICAgICAgczAgPSBwZWckY3VyclBvcztcbiAgICAgICAgICAgIGlmIChpbnB1dC5jaGFyQ29kZUF0KHBlZyRjdXJyUG9zKSA9PT0gMTE2KSB7XG4gICAgICAgICAgICAgIHMxID0gcGVnJGMxMDQ7XG4gICAgICAgICAgICAgIHBlZyRjdXJyUG9zKys7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBzMSA9IHBlZyRGQUlMRUQ7XG4gICAgICAgICAgICAgIGlmIChwZWckc2lsZW50RmFpbHMgPT09IDApIHsgcGVnJGZhaWwocGVnJGMxMDUpOyB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoczEgIT09IHBlZyRGQUlMRUQpIHtcbiAgICAgICAgICAgICAgcGVnJHJlcG9ydGVkUG9zID0gczA7XG4gICAgICAgICAgICAgIHMxID0gcGVnJGMxMDYoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHMwID0gczE7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBzMDtcbiAgICB9XG5cblxuICAgIGZ1bmN0aW9uIG9yKGZpcnN0LCBzZWNvbmQpIHtcbiAgICAgICAgLy8gQWRkIGV4cGxpY2l0IGZ1bmN0aW9uIG5hbWVzIHRvIGVhc2UgZGVidWdnaW5nLlxuICAgICAgICBmdW5jdGlvbiBvckZpbHRlcigpIHtcbiAgICAgICAgICAgIHJldHVybiBmaXJzdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpIHx8IHNlY29uZC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICB9XG4gICAgICAgIG9yRmlsdGVyLmRlc2MgPSBmaXJzdC5kZXNjICsgXCIgb3IgXCIgKyBzZWNvbmQuZGVzYztcbiAgICAgICAgcmV0dXJuIG9yRmlsdGVyO1xuICAgIH1cbiAgICBmdW5jdGlvbiBhbmQoZmlyc3QsIHNlY29uZCkge1xuICAgICAgICBmdW5jdGlvbiBhbmRGaWx0ZXIoKSB7XG4gICAgICAgICAgICByZXR1cm4gZmlyc3QuYXBwbHkodGhpcywgYXJndW1lbnRzKSAmJiBzZWNvbmQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgfVxuICAgICAgICBhbmRGaWx0ZXIuZGVzYyA9IGZpcnN0LmRlc2MgKyBcIiBhbmQgXCIgKyBzZWNvbmQuZGVzYztcbiAgICAgICAgcmV0dXJuIGFuZEZpbHRlcjtcbiAgICB9XG4gICAgZnVuY3Rpb24gbm90KGV4cHIpIHtcbiAgICAgICAgZnVuY3Rpb24gbm90RmlsdGVyKCkge1xuICAgICAgICAgICAgcmV0dXJuICFleHByLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgIH1cbiAgICAgICAgbm90RmlsdGVyLmRlc2MgPSBcIm5vdCBcIiArIGV4cHIuZGVzYztcbiAgICAgICAgcmV0dXJuIG5vdEZpbHRlcjtcbiAgICB9XG4gICAgZnVuY3Rpb24gYmluZGluZyhleHByKSB7XG4gICAgICAgIGZ1bmN0aW9uIGJpbmRpbmdGaWx0ZXIoKSB7XG4gICAgICAgICAgICByZXR1cm4gZXhwci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICB9XG4gICAgICAgIGJpbmRpbmdGaWx0ZXIuZGVzYyA9IFwiKFwiICsgZXhwci5kZXNjICsgXCIpXCI7XG4gICAgICAgIHJldHVybiBiaW5kaW5nRmlsdGVyO1xuICAgIH1cbiAgICBmdW5jdGlvbiB0cnVlRmlsdGVyKGZsb3cpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHRydWVGaWx0ZXIuZGVzYyA9IFwidHJ1ZVwiO1xuICAgIGZ1bmN0aW9uIGZhbHNlRmlsdGVyKGZsb3cpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBmYWxzZUZpbHRlci5kZXNjID0gXCJmYWxzZVwiO1xuXG4gICAgdmFyIEFTU0VUX1RZUEVTID0gW1xuICAgICAgICBuZXcgUmVnRXhwKFwidGV4dC9qYXZhc2NyaXB0XCIpLFxuICAgICAgICBuZXcgUmVnRXhwKFwiYXBwbGljYXRpb24veC1qYXZhc2NyaXB0XCIpLFxuICAgICAgICBuZXcgUmVnRXhwKFwiYXBwbGljYXRpb24vamF2YXNjcmlwdFwiKSxcbiAgICAgICAgbmV3IFJlZ0V4cChcInRleHQvY3NzXCIpLFxuICAgICAgICBuZXcgUmVnRXhwKFwiaW1hZ2UvLipcIiksXG4gICAgICAgIG5ldyBSZWdFeHAoXCJhcHBsaWNhdGlvbi94LXNob2Nrd2F2ZS1mbGFzaFwiKVxuICAgIF07XG4gICAgZnVuY3Rpb24gYXNzZXRGaWx0ZXIoZmxvdykge1xuICAgICAgICBpZiAoZmxvdy5yZXNwb25zZSkge1xuICAgICAgICAgICAgdmFyIGN0ID0gUmVzcG9uc2VVdGlscy5nZXRDb250ZW50VHlwZShmbG93LnJlc3BvbnNlKTtcbiAgICAgICAgICAgIHZhciBpID0gQVNTRVRfVFlQRVMubGVuZ3RoO1xuICAgICAgICAgICAgd2hpbGUgKGktLSkge1xuICAgICAgICAgICAgICAgIGlmIChBU1NFVF9UWVBFU1tpXS50ZXN0KGN0KSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBhc3NldEZpbHRlci5kZXNjID0gXCJpcyBhc3NldFwiO1xuICAgIGZ1bmN0aW9uIHJlc3BvbnNlQ29kZShjb2RlKXtcbiAgICAgICAgZnVuY3Rpb24gcmVzcG9uc2VDb2RlRmlsdGVyKGZsb3cpe1xuICAgICAgICAgICAgcmV0dXJuIGZsb3cucmVzcG9uc2UgJiYgZmxvdy5yZXNwb25zZS5jb2RlID09PSBjb2RlO1xuICAgICAgICB9XG4gICAgICAgIHJlc3BvbnNlQ29kZUZpbHRlci5kZXNjID0gXCJyZXNwLiBjb2RlIGlzIFwiICsgY29kZTtcbiAgICAgICAgcmV0dXJuIHJlc3BvbnNlQ29kZUZpbHRlcjtcbiAgICB9XG4gICAgZnVuY3Rpb24gZG9tYWluKHJlZ2V4KXtcbiAgICAgICAgcmVnZXggPSBuZXcgUmVnRXhwKHJlZ2V4LCBcImlcIik7XG4gICAgICAgIGZ1bmN0aW9uIGRvbWFpbkZpbHRlcihmbG93KXtcbiAgICAgICAgICAgIHJldHVybiBmbG93LnJlcXVlc3QgJiYgcmVnZXgudGVzdChmbG93LnJlcXVlc3QuaG9zdCk7XG4gICAgICAgIH1cbiAgICAgICAgZG9tYWluRmlsdGVyLmRlc2MgPSBcImRvbWFpbiBtYXRjaGVzIFwiICsgcmVnZXg7XG4gICAgICAgIHJldHVybiBkb21haW5GaWx0ZXI7XG4gICAgfVxuICAgIGZ1bmN0aW9uIGVycm9yRmlsdGVyKGZsb3cpe1xuICAgICAgICByZXR1cm4gISFmbG93LmVycm9yO1xuICAgIH1cbiAgICBlcnJvckZpbHRlci5kZXNjID0gXCJoYXMgZXJyb3JcIjtcbiAgICBmdW5jdGlvbiBoZWFkZXIocmVnZXgpe1xuICAgICAgICByZWdleCA9IG5ldyBSZWdFeHAocmVnZXgsIFwiaVwiKTtcbiAgICAgICAgZnVuY3Rpb24gaGVhZGVyRmlsdGVyKGZsb3cpe1xuICAgICAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgICAgICAoZmxvdy5yZXF1ZXN0ICYmIFJlcXVlc3RVdGlscy5tYXRjaF9oZWFkZXIoZmxvdy5yZXF1ZXN0LCByZWdleCkpXG4gICAgICAgICAgICAgICAgfHxcbiAgICAgICAgICAgICAgICAoZmxvdy5yZXNwb25zZSAmJiBSZXNwb25zZVV0aWxzLm1hdGNoX2hlYWRlcihmbG93LnJlc3BvbnNlLCByZWdleCkpXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIGhlYWRlckZpbHRlci5kZXNjID0gXCJoZWFkZXIgbWF0Y2hlcyBcIiArIHJlZ2V4O1xuICAgICAgICByZXR1cm4gaGVhZGVyRmlsdGVyO1xuICAgIH1cbiAgICBmdW5jdGlvbiByZXF1ZXN0SGVhZGVyKHJlZ2V4KXtcbiAgICAgICAgcmVnZXggPSBuZXcgUmVnRXhwKHJlZ2V4LCBcImlcIik7XG4gICAgICAgIGZ1bmN0aW9uIHJlcXVlc3RIZWFkZXJGaWx0ZXIoZmxvdyl7XG4gICAgICAgICAgICByZXR1cm4gKGZsb3cucmVxdWVzdCAmJiBSZXF1ZXN0VXRpbHMubWF0Y2hfaGVhZGVyKGZsb3cucmVxdWVzdCwgcmVnZXgpKTtcbiAgICAgICAgfVxuICAgICAgICByZXF1ZXN0SGVhZGVyRmlsdGVyLmRlc2MgPSBcInJlcS4gaGVhZGVyIG1hdGNoZXMgXCIgKyByZWdleDtcbiAgICAgICAgcmV0dXJuIHJlcXVlc3RIZWFkZXJGaWx0ZXI7XG4gICAgfVxuICAgIGZ1bmN0aW9uIHJlc3BvbnNlSGVhZGVyKHJlZ2V4KXtcbiAgICAgICAgcmVnZXggPSBuZXcgUmVnRXhwKHJlZ2V4LCBcImlcIik7XG4gICAgICAgIGZ1bmN0aW9uIHJlc3BvbnNlSGVhZGVyRmlsdGVyKGZsb3cpe1xuICAgICAgICAgICAgcmV0dXJuIChmbG93LnJlc3BvbnNlICYmIFJlc3BvbnNlVXRpbHMubWF0Y2hfaGVhZGVyKGZsb3cucmVzcG9uc2UsIHJlZ2V4KSk7XG4gICAgICAgIH1cbiAgICAgICAgcmVzcG9uc2VIZWFkZXJGaWx0ZXIuZGVzYyA9IFwicmVzcC4gaGVhZGVyIG1hdGNoZXMgXCIgKyByZWdleDtcbiAgICAgICAgcmV0dXJuIHJlc3BvbnNlSGVhZGVyRmlsdGVyO1xuICAgIH1cbiAgICBmdW5jdGlvbiBtZXRob2QocmVnZXgpe1xuICAgICAgICByZWdleCA9IG5ldyBSZWdFeHAocmVnZXgsIFwiaVwiKTtcbiAgICAgICAgZnVuY3Rpb24gbWV0aG9kRmlsdGVyKGZsb3cpe1xuICAgICAgICAgICAgcmV0dXJuIGZsb3cucmVxdWVzdCAmJiByZWdleC50ZXN0KGZsb3cucmVxdWVzdC5tZXRob2QpO1xuICAgICAgICB9XG4gICAgICAgIG1ldGhvZEZpbHRlci5kZXNjID0gXCJtZXRob2QgbWF0Y2hlcyBcIiArIHJlZ2V4O1xuICAgICAgICByZXR1cm4gbWV0aG9kRmlsdGVyO1xuICAgIH1cbiAgICBmdW5jdGlvbiBub1Jlc3BvbnNlRmlsdGVyKGZsb3cpe1xuICAgICAgICByZXR1cm4gZmxvdy5yZXF1ZXN0ICYmICFmbG93LnJlc3BvbnNlO1xuICAgIH1cbiAgICBub1Jlc3BvbnNlRmlsdGVyLmRlc2MgPSBcImhhcyBubyByZXNwb25zZVwiO1xuICAgIGZ1bmN0aW9uIHJlc3BvbnNlRmlsdGVyKGZsb3cpe1xuICAgICAgICByZXR1cm4gISFmbG93LnJlc3BvbnNlO1xuICAgIH1cbiAgICByZXNwb25zZUZpbHRlci5kZXNjID0gXCJoYXMgcmVzcG9uc2VcIjtcblxuICAgIGZ1bmN0aW9uIGNvbnRlbnRUeXBlKHJlZ2V4KXtcbiAgICAgICAgcmVnZXggPSBuZXcgUmVnRXhwKHJlZ2V4LCBcImlcIik7XG4gICAgICAgIGZ1bmN0aW9uIGNvbnRlbnRUeXBlRmlsdGVyKGZsb3cpe1xuICAgICAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgICAgICAoZmxvdy5yZXF1ZXN0ICYmIHJlZ2V4LnRlc3QoUmVxdWVzdFV0aWxzLmdldENvbnRlbnRUeXBlKGZsb3cucmVxdWVzdCkpKVxuICAgICAgICAgICAgICAgIHx8XG4gICAgICAgICAgICAgICAgKGZsb3cucmVzcG9uc2UgJiYgcmVnZXgudGVzdChSZXNwb25zZVV0aWxzLmdldENvbnRlbnRUeXBlKGZsb3cucmVzcG9uc2UpKSlcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgY29udGVudFR5cGVGaWx0ZXIuZGVzYyA9IFwiY29udGVudCB0eXBlIG1hdGNoZXMgXCIgKyByZWdleDtcbiAgICAgICAgcmV0dXJuIGNvbnRlbnRUeXBlRmlsdGVyO1xuICAgIH1cbiAgICBmdW5jdGlvbiByZXF1ZXN0Q29udGVudFR5cGUocmVnZXgpe1xuICAgICAgICByZWdleCA9IG5ldyBSZWdFeHAocmVnZXgsIFwiaVwiKTtcbiAgICAgICAgZnVuY3Rpb24gcmVxdWVzdENvbnRlbnRUeXBlRmlsdGVyKGZsb3cpe1xuICAgICAgICAgICAgcmV0dXJuIGZsb3cucmVxdWVzdCAmJiByZWdleC50ZXN0KFJlcXVlc3RVdGlscy5nZXRDb250ZW50VHlwZShmbG93LnJlcXVlc3QpKTtcbiAgICAgICAgfVxuICAgICAgICByZXF1ZXN0Q29udGVudFR5cGVGaWx0ZXIuZGVzYyA9IFwicmVxLiBjb250ZW50IHR5cGUgbWF0Y2hlcyBcIiArIHJlZ2V4O1xuICAgICAgICByZXR1cm4gcmVxdWVzdENvbnRlbnRUeXBlRmlsdGVyO1xuICAgIH1cbiAgICBmdW5jdGlvbiByZXNwb25zZUNvbnRlbnRUeXBlKHJlZ2V4KXtcbiAgICAgICAgcmVnZXggPSBuZXcgUmVnRXhwKHJlZ2V4LCBcImlcIik7XG4gICAgICAgIGZ1bmN0aW9uIHJlc3BvbnNlQ29udGVudFR5cGVGaWx0ZXIoZmxvdyl7XG4gICAgICAgICAgICByZXR1cm4gZmxvdy5yZXNwb25zZSAmJiByZWdleC50ZXN0KFJlc3BvbnNlVXRpbHMuZ2V0Q29udGVudFR5cGUoZmxvdy5yZXNwb25zZSkpO1xuICAgICAgICB9XG4gICAgICAgIHJlc3BvbnNlQ29udGVudFR5cGVGaWx0ZXIuZGVzYyA9IFwicmVzcC4gY29udGVudCB0eXBlIG1hdGNoZXMgXCIgKyByZWdleDtcbiAgICAgICAgcmV0dXJuIHJlc3BvbnNlQ29udGVudFR5cGVGaWx0ZXI7XG4gICAgfVxuICAgIGZ1bmN0aW9uIHVybChyZWdleCl7XG4gICAgICAgIHJlZ2V4ID0gbmV3IFJlZ0V4cChyZWdleCwgXCJpXCIpO1xuICAgICAgICBmdW5jdGlvbiB1cmxGaWx0ZXIoZmxvdyl7XG4gICAgICAgICAgICByZXR1cm4gZmxvdy5yZXF1ZXN0ICYmIHJlZ2V4LnRlc3QoUmVxdWVzdFV0aWxzLnByZXR0eV91cmwoZmxvdy5yZXF1ZXN0KSk7XG4gICAgICAgIH1cbiAgICAgICAgdXJsRmlsdGVyLmRlc2MgPSBcInVybCBtYXRjaGVzIFwiICsgcmVnZXg7XG4gICAgICAgIHJldHVybiB1cmxGaWx0ZXI7XG4gICAgfVxuXG5cbiAgICBwZWckcmVzdWx0ID0gcGVnJHN0YXJ0UnVsZUZ1bmN0aW9uKCk7XG5cbiAgICBpZiAocGVnJHJlc3VsdCAhPT0gcGVnJEZBSUxFRCAmJiBwZWckY3VyclBvcyA9PT0gaW5wdXQubGVuZ3RoKSB7XG4gICAgICByZXR1cm4gcGVnJHJlc3VsdDtcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKHBlZyRyZXN1bHQgIT09IHBlZyRGQUlMRUQgJiYgcGVnJGN1cnJQb3MgPCBpbnB1dC5sZW5ndGgpIHtcbiAgICAgICAgcGVnJGZhaWwoeyB0eXBlOiBcImVuZFwiLCBkZXNjcmlwdGlvbjogXCJlbmQgb2YgaW5wdXRcIiB9KTtcbiAgICAgIH1cblxuICAgICAgdGhyb3cgcGVnJGJ1aWxkRXhjZXB0aW9uKG51bGwsIHBlZyRtYXhGYWlsRXhwZWN0ZWQsIHBlZyRtYXhGYWlsUG9zKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4ge1xuICAgIFN5bnRheEVycm9yOiBTeW50YXhFcnJvcixcbiAgICBwYXJzZTogICAgICAgcGFyc2VcbiAgfTtcbn0pKCk7XG4vKiBqc2hpbnQgaWdub3JlOmVuZCAqL1xuXG5tb2R1bGUuZXhwb3J0cyA9IEZpbHQ7XG4iLCJ2YXIgXyA9IHJlcXVpcmUoXCJsb2Rhc2hcIik7XG5cbnZhciBfTWVzc2FnZVV0aWxzID0ge1xuICAgIGdldENvbnRlbnRUeXBlOiBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRfZmlyc3RfaGVhZGVyKG1lc3NhZ2UsIC9eQ29udGVudC1UeXBlJC9pKTtcbiAgICB9LFxuICAgIGdldF9maXJzdF9oZWFkZXI6IGZ1bmN0aW9uIChtZXNzYWdlLCByZWdleCkge1xuICAgICAgICAvL0ZJWE1FOiBDYWNoZSBJbnZhbGlkYXRpb24uXG4gICAgICAgIGlmICghbWVzc2FnZS5faGVhZGVyTG9va3VwcylcbiAgICAgICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShtZXNzYWdlLCBcIl9oZWFkZXJMb29rdXBzXCIsIHtcbiAgICAgICAgICAgICAgICB2YWx1ZToge30sXG4gICAgICAgICAgICAgICAgY29uZmlndXJhYmxlOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgICAgICAgICAgICAgICB3cml0YWJsZTogZmFsc2VcbiAgICAgICAgICAgIH0pO1xuICAgICAgICBpZiAoIShyZWdleCBpbiBtZXNzYWdlLl9oZWFkZXJMb29rdXBzKSkge1xuICAgICAgICAgICAgdmFyIGhlYWRlcjtcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbWVzc2FnZS5oZWFkZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgaWYgKCEhbWVzc2FnZS5oZWFkZXJzW2ldWzBdLm1hdGNoKHJlZ2V4KSkge1xuICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBtZXNzYWdlLmhlYWRlcnNbaV07XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIG1lc3NhZ2UuX2hlYWRlckxvb2t1cHNbcmVnZXhdID0gaGVhZGVyID8gaGVhZGVyWzFdIDogdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBtZXNzYWdlLl9oZWFkZXJMb29rdXBzW3JlZ2V4XTtcbiAgICB9LFxuICAgIG1hdGNoX2hlYWRlcjogZnVuY3Rpb24gKG1lc3NhZ2UsIHJlZ2V4KSB7XG4gICAgICAgIHZhciBoZWFkZXJzID0gbWVzc2FnZS5oZWFkZXJzO1xuICAgICAgICB2YXIgaSA9IGhlYWRlcnMubGVuZ3RoO1xuICAgICAgICB3aGlsZSAoaS0tKSB7XG4gICAgICAgICAgICBpZiAocmVnZXgudGVzdChoZWFkZXJzW2ldLmpvaW4oXCIgXCIpKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBoZWFkZXJzW2ldO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG59O1xuXG52YXIgZGVmYXVsdFBvcnRzID0ge1xuICAgIFwiaHR0cFwiOiA4MCxcbiAgICBcImh0dHBzXCI6IDQ0M1xufTtcblxudmFyIFJlcXVlc3RVdGlscyA9IF8uZXh0ZW5kKF9NZXNzYWdlVXRpbHMsIHtcbiAgICBwcmV0dHlfaG9zdDogZnVuY3Rpb24gKHJlcXVlc3QpIHtcbiAgICAgICAgLy9GSVhNRTogQWRkIGhvc3RoZWFkZXJcbiAgICAgICAgcmV0dXJuIHJlcXVlc3QuaG9zdDtcbiAgICB9LFxuICAgIHByZXR0eV91cmw6IGZ1bmN0aW9uIChyZXF1ZXN0KSB7XG4gICAgICAgIHZhciBwb3J0ID0gXCJcIjtcbiAgICAgICAgaWYgKGRlZmF1bHRQb3J0c1tyZXF1ZXN0LnNjaGVtZV0gIT09IHJlcXVlc3QucG9ydCkge1xuICAgICAgICAgICAgcG9ydCA9IFwiOlwiICsgcmVxdWVzdC5wb3J0O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXF1ZXN0LnNjaGVtZSArIFwiOi8vXCIgKyB0aGlzLnByZXR0eV9ob3N0KHJlcXVlc3QpICsgcG9ydCArIHJlcXVlc3QucGF0aDtcbiAgICB9XG59KTtcblxudmFyIFJlc3BvbnNlVXRpbHMgPSBfLmV4dGVuZChfTWVzc2FnZVV0aWxzLCB7fSk7XG5cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgUmVzcG9uc2VVdGlsczogUmVzcG9uc2VVdGlsc1xufSIsIlxudmFyIF8gPSByZXF1aXJlKFwibG9kYXNoXCIpO1xudmFyICQgPSByZXF1aXJlKFwianF1ZXJ5XCIpO1xuXG52YXIgdXRpbHMgPSByZXF1aXJlKFwiLi4vdXRpbHMuanNcIik7XG52YXIgYWN0aW9ucyA9IHJlcXVpcmUoXCIuLi9hY3Rpb25zLmpzXCIpO1xudmFyIGRpc3BhdGNoZXIgPSByZXF1aXJlKFwiLi4vZGlzcGF0Y2hlci5qc1wiKTtcblxuXG5mdW5jdGlvbiBMaXN0U3RvcmUoKSB7XG4gICAgdXRpbHMuRXZlbnRFbWl0dGVyLmNhbGwodGhpcyk7XG4gICAgdGhpcy5yZXNldCgpO1xufVxuXy5leHRlbmQoTGlzdFN0b3JlLnByb3RvdHlwZSwgdXRpbHMuRXZlbnRFbWl0dGVyLnByb3RvdHlwZSwge1xuICAgIGFkZDogZnVuY3Rpb24gKGVsZW0pIHtcbiAgICAgICAgaWYgKGVsZW0uaWQgaW4gdGhpcy5fcG9zX21hcCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuX3Bvc19tYXBbZWxlbS5pZF0gPSB0aGlzLmxpc3QubGVuZ3RoO1xuICAgICAgICB0aGlzLmxpc3QucHVzaChlbGVtKTtcbiAgICAgICAgdGhpcy5lbWl0KFwiYWRkXCIsIGVsZW0pO1xuICAgIH0sXG4gICAgdXBkYXRlOiBmdW5jdGlvbiAoZWxlbSkge1xuICAgICAgICBpZiAoIShlbGVtLmlkIGluIHRoaXMuX3Bvc19tYXApKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5saXN0W3RoaXMuX3Bvc19tYXBbZWxlbS5pZF1dID0gZWxlbTtcbiAgICAgICAgdGhpcy5lbWl0KFwidXBkYXRlXCIsIGVsZW0pO1xuICAgIH0sXG4gICAgcmVtb3ZlOiBmdW5jdGlvbiAoZWxlbV9pZCkge1xuICAgICAgICBpZiAoIShlbGVtX2lkIGluIHRoaXMuX3Bvc19tYXApKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5saXN0LnNwbGljZSh0aGlzLl9wb3NfbWFwW2VsZW1faWRdLCAxKTtcbiAgICAgICAgdGhpcy5fYnVpbGRfbWFwKCk7XG4gICAgICAgIHRoaXMuZW1pdChcInJlbW92ZVwiLCBlbGVtX2lkKTtcbiAgICB9LFxuICAgIHJlc2V0OiBmdW5jdGlvbiAoZWxlbXMpIHtcbiAgICAgICAgdGhpcy5saXN0ID0gZWxlbXMgfHwgW107XG4gICAgICAgIHRoaXMuX2J1aWxkX21hcCgpO1xuICAgICAgICB0aGlzLmVtaXQoXCJyZWNhbGN1bGF0ZVwiKTtcbiAgICB9LFxuICAgIF9idWlsZF9tYXA6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5fcG9zX21hcCA9IHt9O1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMubGlzdC5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgdmFyIGVsZW0gPSB0aGlzLmxpc3RbaV07XG4gICAgICAgICAgICB0aGlzLl9wb3NfbWFwW2VsZW0uaWRdID0gaTtcbiAgICAgICAgfVxuICAgIH0sXG4gICAgZ2V0OiBmdW5jdGlvbiAoZWxlbV9pZCkge1xuICAgICAgICByZXR1cm4gdGhpcy5saXN0W3RoaXMuX3Bvc19tYXBbZWxlbV9pZF1dO1xuICAgIH0sXG4gICAgaW5kZXg6IGZ1bmN0aW9uIChlbGVtX2lkKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9wb3NfbWFwW2VsZW1faWRdO1xuICAgIH1cbn0pO1xuXG5cbmZ1bmN0aW9uIERpY3RTdG9yZSgpIHtcbiAgICB1dGlscy5FdmVudEVtaXR0ZXIuY2FsbCh0aGlzKTtcbiAgICB0aGlzLnJlc2V0KCk7XG59XG5fLmV4dGVuZChEaWN0U3RvcmUucHJvdG90eXBlLCB1dGlscy5FdmVudEVtaXR0ZXIucHJvdG90eXBlLCB7XG4gICAgdXBkYXRlOiBmdW5jdGlvbiAoZGljdCkge1xuICAgICAgICBfLm1lcmdlKHRoaXMuZGljdCwgZGljdCk7XG4gICAgICAgIHRoaXMuZW1pdChcInJlY2FsY3VsYXRlXCIpO1xuICAgIH0sXG4gICAgcmVzZXQ6IGZ1bmN0aW9uIChkaWN0KSB7XG4gICAgICAgIHRoaXMuZGljdCA9IGRpY3QgfHwge307XG4gICAgICAgIHRoaXMuZW1pdChcInJlY2FsY3VsYXRlXCIpO1xuICAgIH1cbn0pO1xuXG5mdW5jdGlvbiBMaXZlU3RvcmVNaXhpbih0eXBlKSB7XG4gICAgdGhpcy50eXBlID0gdHlwZTtcblxuICAgIHRoaXMuX3VwZGF0ZXNfYmVmb3JlX2ZldGNoID0gdW5kZWZpbmVkO1xuICAgIHRoaXMuX2ZldGNoeGhyID0gZmFsc2U7XG5cbiAgICB0aGlzLmhhbmRsZSA9IHRoaXMuaGFuZGxlLmJpbmQodGhpcyk7XG4gICAgZGlzcGF0Y2hlci5BcHBEaXNwYXRjaGVyLnJlZ2lzdGVyKHRoaXMuaGFuZGxlKTtcblxuICAgIC8vIEF2b2lkIGRvdWJsZS1mZXRjaCBvbiBzdGFydHVwLlxuICAgIGlmICghKHdpbmRvdy53cyAmJiB3aW5kb3cud3MucmVhZHlTdGF0ZSA9PT0gV2ViU29ja2V0LkNPTk5FQ1RJTkcpKSB7XG4gICAgICAgIHRoaXMuZmV0Y2goKTtcbiAgICB9XG59XG5fLmV4dGVuZChMaXZlU3RvcmVNaXhpbi5wcm90b3R5cGUsIHtcbiAgICBoYW5kbGU6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICBpZiAoZXZlbnQudHlwZSA9PT0gYWN0aW9ucy5BY3Rpb25UeXBlcy5DT05ORUNUSU9OX09QRU4pIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmZldGNoKCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGV2ZW50LnR5cGUgPT09IHRoaXMudHlwZSkge1xuICAgICAgICAgICAgaWYgKGV2ZW50LmNtZCA9PT0gU3RvcmVDbWRzLlJFU0VUKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5mZXRjaChldmVudC5kYXRhKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAodGhpcy5fdXBkYXRlc19iZWZvcmVfZmV0Y2gpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcImRlZmVyIHVwZGF0ZVwiLCBldmVudCk7XG4gICAgICAgICAgICAgICAgdGhpcy5fdXBkYXRlc19iZWZvcmVfZmV0Y2gucHVzaChldmVudCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXNbZXZlbnQuY21kXShldmVudC5kYXRhKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0sXG4gICAgY2xvc2U6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgZGlzcGF0Y2hlci5BcHBEaXNwYXRjaGVyLnVucmVnaXN0ZXIodGhpcy5oYW5kbGUpO1xuICAgIH0sXG4gICAgZmV0Y2g6IGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKFwiZmV0Y2ggXCIgKyB0aGlzLnR5cGUpO1xuICAgICAgICBpZiAodGhpcy5fZmV0Y2h4aHIpIHtcbiAgICAgICAgICAgIHRoaXMuX2ZldGNoeGhyLmFib3J0KCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5fdXBkYXRlc19iZWZvcmVfZmV0Y2ggPSBbXTsgLy8gKEpTOiBlbXB0eSBhcnJheSBpcyB0cnVlKVxuICAgICAgICBpZiAoZGF0YSkge1xuICAgICAgICAgICAgdGhpcy5oYW5kbGVfZmV0Y2goZGF0YSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLl9mZXRjaHhociA9ICQuZ2V0SlNPTihcIi9cIiArIHRoaXMudHlwZSlcbiAgICAgICAgICAgICAgICAuZG9uZShmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmhhbmRsZV9mZXRjaChtZXNzYWdlLmRhdGEpO1xuICAgICAgICAgICAgICAgIH0uYmluZCh0aGlzKSlcbiAgICAgICAgICAgICAgICAuZmFpbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIEV2ZW50TG9nQWN0aW9ucy5hZGRfZXZlbnQoXCJDb3VsZCBub3QgZmV0Y2ggXCIgKyB0aGlzLnR5cGUpO1xuICAgICAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIGhhbmRsZV9mZXRjaDogZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgICAgdGhpcy5fZmV0Y2h4aHIgPSBmYWxzZTtcbiAgICAgICAgY29uc29sZS5sb2codGhpcy50eXBlICsgXCIgZmV0Y2hlZC5cIiwgdGhpcy5fdXBkYXRlc19iZWZvcmVfZmV0Y2gpO1xuICAgICAgICB0aGlzLnJlc2V0KGRhdGEpO1xuICAgICAgICB2YXIgdXBkYXRlcyA9IHRoaXMuX3VwZGF0ZXNfYmVmb3JlX2ZldGNoO1xuICAgICAgICB0aGlzLl91cGRhdGVzX2JlZm9yZV9mZXRjaCA9IGZhbHNlO1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHVwZGF0ZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIHRoaXMuaGFuZGxlKHVwZGF0ZXNbaV0pO1xuICAgICAgICB9XG4gICAgfSxcbn0pO1xuXG5mdW5jdGlvbiBMaXZlTGlzdFN0b3JlKHR5cGUpIHtcbiAgICBMaXN0U3RvcmUuY2FsbCh0aGlzKTtcbiAgICBMaXZlU3RvcmVNaXhpbi5jYWxsKHRoaXMsIHR5cGUpO1xufVxuXy5leHRlbmQoTGl2ZUxpc3RTdG9yZS5wcm90b3R5cGUsIExpc3RTdG9yZS5wcm90b3R5cGUsIExpdmVTdG9yZU1peGluLnByb3RvdHlwZSk7XG5cbmZ1bmN0aW9uIExpdmVEaWN0U3RvcmUodHlwZSkge1xuICAgIERpY3RTdG9yZS5jYWxsKHRoaXMpO1xuICAgIExpdmVTdG9yZU1peGluLmNhbGwodGhpcywgdHlwZSk7XG59XG5fLmV4dGVuZChMaXZlRGljdFN0b3JlLnByb3RvdHlwZSwgRGljdFN0b3JlLnByb3RvdHlwZSwgTGl2ZVN0b3JlTWl4aW4ucHJvdG90eXBlKTtcblxuXG5mdW5jdGlvbiBGbG93U3RvcmUoKSB7XG4gICAgcmV0dXJuIG5ldyBMaXZlTGlzdFN0b3JlKGFjdGlvbnMuQWN0aW9uVHlwZXMuRkxPV19TVE9SRSk7XG59XG5cbmZ1bmN0aW9uIFNldHRpbmdzU3RvcmUoKSB7XG4gICAgcmV0dXJuIG5ldyBMaXZlRGljdFN0b3JlKGFjdGlvbnMuQWN0aW9uVHlwZXMuU0VUVElOR1NfU1RPUkUpO1xufVxuXG5mdW5jdGlvbiBFdmVudExvZ1N0b3JlKCkge1xuICAgIExpdmVMaXN0U3RvcmUuY2FsbCh0aGlzLCBhY3Rpb25zLkFjdGlvblR5cGVzLkVWRU5UX1NUT1JFKTtcbn1cbl8uZXh0ZW5kKEV2ZW50TG9nU3RvcmUucHJvdG90eXBlLCBMaXZlTGlzdFN0b3JlLnByb3RvdHlwZSwge1xuICAgIGZldGNoOiBmdW5jdGlvbigpe1xuICAgICAgICBMaXZlTGlzdFN0b3JlLnByb3RvdHlwZS5mZXRjaC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuXG4gICAgICAgIC8vIE1ha2Ugc3VyZSB0byBkaXNwbGF5IHVwZGF0ZXMgZXZlbiBpZiBmZXRjaGluZyBhbGwgZXZlbnRzIGZhaWxlZC5cbiAgICAgICAgLy8gVGhpcyB3YXksIHdlIGNhbiBzZW5kIFwiZmV0Y2ggZmFpbGVkXCIgbG9nIG1lc3NhZ2VzIHRvIHRoZSBsb2cuXG4gICAgICAgIGlmKHRoaXMuX2ZldGNoeGhyKXtcbiAgICAgICAgICAgIHRoaXMuX2ZldGNoeGhyLmZhaWwoZnVuY3Rpb24oKXtcbiAgICAgICAgICAgICAgICB0aGlzLmhhbmRsZV9mZXRjaChudWxsKTtcbiAgICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgICAgIH1cbiAgICB9XG59KTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBFdmVudExvZ1N0b3JlOiBFdmVudExvZ1N0b3JlLFxuICAgIFNldHRpbmdzU3RvcmU6IFNldHRpbmdzU3RvcmUsXG4gICAgRmxvd1N0b3JlOiBGbG93U3RvcmVcbn07IiwidmFyIF8gPSByZXF1aXJlKFwibG9kYXNoXCIpO1xuXG52YXIgdXRpbHMgPSByZXF1aXJlKFwiLi4vdXRpbHMuanNcIik7XG5cbmZ1bmN0aW9uIFNvcnRCeVN0b3JlT3JkZXIoZWxlbSkge1xuICAgIHJldHVybiB0aGlzLnN0b3JlLmluZGV4KGVsZW0uaWQpO1xufVxuXG52YXIgZGVmYXVsdF9zb3J0ID0gU29ydEJ5U3RvcmVPcmRlcjtcbnZhciBkZWZhdWx0X2ZpbHQgPSBmdW5jdGlvbihlbGVtKXtcbiAgICByZXR1cm4gdHJ1ZTtcbn07XG5cbmZ1bmN0aW9uIFN0b3JlVmlldyhzdG9yZSwgZmlsdCwgc29ydGZ1bikge1xuICAgIHV0aWxzLkV2ZW50RW1pdHRlci5jYWxsKHRoaXMpO1xuICAgIGZpbHQgPSBmaWx0IHx8IGRlZmF1bHRfZmlsdDtcbiAgICBzb3J0ZnVuID0gc29ydGZ1biB8fCBkZWZhdWx0X3NvcnQ7XG5cbiAgICB0aGlzLnN0b3JlID0gc3RvcmU7XG5cbiAgICB0aGlzLmFkZCA9IHRoaXMuYWRkLmJpbmQodGhpcyk7XG4gICAgdGhpcy51cGRhdGUgPSB0aGlzLnVwZGF0ZS5iaW5kKHRoaXMpO1xuICAgIHRoaXMucmVtb3ZlID0gdGhpcy5yZW1vdmUuYmluZCh0aGlzKTtcbiAgICB0aGlzLnJlY2FsY3VsYXRlID0gdGhpcy5yZWNhbGN1bGF0ZS5iaW5kKHRoaXMpO1xuICAgIHRoaXMuc3RvcmUuYWRkTGlzdGVuZXIoXCJhZGRcIiwgdGhpcy5hZGQpO1xuICAgIHRoaXMuc3RvcmUuYWRkTGlzdGVuZXIoXCJ1cGRhdGVcIiwgdGhpcy51cGRhdGUpO1xuICAgIHRoaXMuc3RvcmUuYWRkTGlzdGVuZXIoXCJyZW1vdmVcIiwgdGhpcy5yZW1vdmUpO1xuICAgIHRoaXMuc3RvcmUuYWRkTGlzdGVuZXIoXCJyZWNhbGN1bGF0ZVwiLCB0aGlzLnJlY2FsY3VsYXRlKTtcblxuICAgIHRoaXMucmVjYWxjdWxhdGUoZmlsdCwgc29ydGZ1bik7XG59XG5cbl8uZXh0ZW5kKFN0b3JlVmlldy5wcm90b3R5cGUsIHV0aWxzLkV2ZW50RW1pdHRlci5wcm90b3R5cGUsIHtcbiAgICBjbG9zZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLnN0b3JlLnJlbW92ZUxpc3RlbmVyKFwiYWRkXCIsIHRoaXMuYWRkKTtcbiAgICAgICAgdGhpcy5zdG9yZS5yZW1vdmVMaXN0ZW5lcihcInVwZGF0ZVwiLCB0aGlzLnVwZGF0ZSk7XG4gICAgICAgIHRoaXMuc3RvcmUucmVtb3ZlTGlzdGVuZXIoXCJyZW1vdmVcIiwgdGhpcy5yZW1vdmUpO1xuICAgICAgICB0aGlzLnN0b3JlLnJlbW92ZUxpc3RlbmVyKFwicmVjYWxjdWxhdGVcIiwgdGhpcy5yZWNhbGN1bGF0ZSk7XG4gICAgICAgIH0sXG4gICAgICAgIHJlY2FsY3VsYXRlOiBmdW5jdGlvbiAoZmlsdCwgc29ydGZ1bikge1xuICAgICAgICBpZiAoZmlsdCkge1xuICAgICAgICAgICAgdGhpcy5maWx0ID0gZmlsdC5iaW5kKHRoaXMpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChzb3J0ZnVuKSB7XG4gICAgICAgICAgICB0aGlzLnNvcnRmdW4gPSBzb3J0ZnVuLmJpbmQodGhpcyk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmxpc3QgPSB0aGlzLnN0b3JlLmxpc3QuZmlsdGVyKHRoaXMuZmlsdCk7XG4gICAgICAgIHRoaXMubGlzdC5zb3J0KGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5zb3J0ZnVuKGEpIC0gdGhpcy5zb3J0ZnVuKGIpO1xuICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgICAgICB0aGlzLmVtaXQoXCJyZWNhbGN1bGF0ZVwiKTtcbiAgICB9LFxuICAgIGluZGV4OiBmdW5jdGlvbiAoZWxlbSkge1xuICAgICAgICByZXR1cm4gXy5zb3J0ZWRJbmRleCh0aGlzLmxpc3QsIGVsZW0sIHRoaXMuc29ydGZ1bik7XG4gICAgfSxcbiAgICBhZGQ6IGZ1bmN0aW9uIChlbGVtKSB7XG4gICAgICAgIGlmICh0aGlzLmZpbHQoZWxlbSkpIHtcbiAgICAgICAgICAgIHZhciBpZHggPSB0aGlzLmluZGV4KGVsZW0pO1xuICAgICAgICAgICAgaWYgKGlkeCA9PT0gdGhpcy5saXN0Lmxlbmd0aCkgeyAvL2hhcHBlbnMgb2Z0ZW4sIC5wdXNoIGlzIHdheSBmYXN0ZXIuXG4gICAgICAgICAgICAgICAgdGhpcy5saXN0LnB1c2goZWxlbSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMubGlzdC5zcGxpY2UoaWR4LCAwLCBlbGVtKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuZW1pdChcImFkZFwiLCBlbGVtLCBpZHgpO1xuICAgICAgICB9XG4gICAgfSxcbiAgICB1cGRhdGU6IGZ1bmN0aW9uIChlbGVtKSB7XG4gICAgICAgIHZhciBpZHg7XG4gICAgICAgIHZhciBpID0gdGhpcy5saXN0Lmxlbmd0aDtcbiAgICAgICAgLy8gU2VhcmNoIGZyb20gdGhlIGJhY2ssIHdlIHVzdWFsbHkgdXBkYXRlIHRoZSBsYXRlc3QgZW50cmllcy5cbiAgICAgICAgd2hpbGUgKGktLSkge1xuICAgICAgICAgICAgaWYgKHRoaXMubGlzdFtpXS5pZCA9PT0gZWxlbS5pZCkge1xuICAgICAgICAgICAgICAgIGlkeCA9IGk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaWR4ID09PSAtMSkgeyAvL25vdCBjb250YWluZWQgaW4gbGlzdFxuICAgICAgICAgICAgdGhpcy5hZGQoZWxlbSk7XG4gICAgICAgIH0gZWxzZSBpZiAoIXRoaXMuZmlsdChlbGVtKSkge1xuICAgICAgICAgICAgdGhpcy5yZW1vdmUoZWxlbS5pZCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZiAodGhpcy5zb3J0ZnVuKHRoaXMubGlzdFtpZHhdKSAhPT0gdGhpcy5zb3J0ZnVuKGVsZW0pKSB7IC8vc29ydHBvcyBoYXMgY2hhbmdlZFxuICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKHRoaXMubGlzdFtpZHhdKTtcbiAgICAgICAgICAgICAgICB0aGlzLmFkZChlbGVtKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5saXN0W2lkeF0gPSBlbGVtO1xuICAgICAgICAgICAgICAgIHRoaXMuZW1pdChcInVwZGF0ZVwiLCBlbGVtLCBpZHgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfSxcbiAgICByZW1vdmU6IGZ1bmN0aW9uIChlbGVtX2lkKSB7XG4gICAgICAgIHZhciBpZHggPSB0aGlzLmxpc3QubGVuZ3RoO1xuICAgICAgICB3aGlsZSAoaWR4LS0pIHtcbiAgICAgICAgICAgIGlmICh0aGlzLmxpc3RbaWR4XS5pZCA9PT0gZWxlbV9pZCkge1xuICAgICAgICAgICAgICAgIHRoaXMubGlzdC5zcGxpY2UoaWR4LCAxKTtcbiAgICAgICAgICAgICAgICB0aGlzLmVtaXQoXCJyZW1vdmVcIiwgZWxlbV9pZCwgaWR4KTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBTdG9yZVZpZXc6IFN0b3JlVmlld1xufTsiLCJ2YXIgJCA9IHJlcXVpcmUoXCJqcXVlcnlcIik7XG5cblxudmFyIEtleSA9IHtcbiAgICBVUDogMzgsXG4gICAgRE9XTjogNDAsXG4gICAgUEFHRV9VUDogMzMsXG4gICAgUEFHRV9ET1dOOiAzNCxcbiAgICBIT01FOiAzNixcbiAgICBFTkQ6IDM1LFxuICAgIExFRlQ6IDM3LFxuICAgIFJJR0hUOiAzOSxcbiAgICBFTlRFUjogMTMsXG4gICAgRVNDOiAyNyxcbiAgICBUQUI6IDksXG4gICAgU1BBQ0U6IDMyLFxuICAgIEJBQ0tTUEFDRTogOCxcbn07XG4vLyBBZGQgQS1aXG5mb3IgKHZhciBpID0gNjU7IGkgPD0gOTA7IGkrKykge1xuICAgIEtleVtTdHJpbmcuZnJvbUNoYXJDb2RlKGkpXSA9IGk7XG59XG5cblxudmFyIGZvcm1hdFNpemUgPSBmdW5jdGlvbiAoYnl0ZXMpIHtcbiAgICB2YXIgc2l6ZSA9IGJ5dGVzO1xuICAgIHZhciBwcmVmaXggPSBbXCJCXCIsIFwiS0JcIiwgXCJNQlwiLCBcIkdCXCIsIFwiVEJcIl07XG4gICAgdmFyIGkgPSAwO1xuICAgIHdoaWxlIChNYXRoLmFicyhzaXplKSA+PSAxMDI0ICYmIGkgPCBwcmVmaXgubGVuZ3RoIC0gMSkge1xuICAgICAgICBpKys7XG4gICAgICAgIHNpemUgPSBzaXplIC8gMTAyNDtcbiAgICB9XG4gICAgcmV0dXJuIChNYXRoLmZsb29yKHNpemUgKiAxMDApIC8gMTAwLjApLnRvRml4ZWQoMikgKyBwcmVmaXhbaV07XG59O1xuXG5cbnZhciBmb3JtYXRUaW1lRGVsdGEgPSBmdW5jdGlvbiAobWlsbGlzZWNvbmRzKSB7XG4gICAgdmFyIHRpbWUgPSBtaWxsaXNlY29uZHM7XG4gICAgdmFyIHByZWZpeCA9IFtcIm1zXCIsIFwic1wiLCBcIm1pblwiLCBcImhcIl07XG4gICAgdmFyIGRpdiA9IFsxMDAwLCA2MCwgNjBdO1xuICAgIHZhciBpID0gMDtcbiAgICB3aGlsZSAoTWF0aC5hYnModGltZSkgPj0gZGl2W2ldICYmIGkgPCBkaXYubGVuZ3RoKSB7XG4gICAgICAgIHRpbWUgPSB0aW1lIC8gZGl2W2ldO1xuICAgICAgICBpKys7XG4gICAgfVxuICAgIHJldHVybiBNYXRoLnJvdW5kKHRpbWUpICsgcHJlZml4W2ldO1xufTtcblxuXG52YXIgZm9ybWF0VGltZVN0YW1wID0gZnVuY3Rpb24gKHNlY29uZHMpIHtcbiAgICB2YXIgdHMgPSAobmV3IERhdGUoc2Vjb25kcyAqIDEwMDApKS50b0lTT1N0cmluZygpO1xuICAgIHJldHVybiB0cy5yZXBsYWNlKFwiVFwiLCBcIiBcIikucmVwbGFjZShcIlpcIiwgXCJcIik7XG59O1xuXG5cbmZ1bmN0aW9uIEV2ZW50RW1pdHRlcigpIHtcbiAgICB0aGlzLmxpc3RlbmVycyA9IHt9O1xufVxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5lbWl0ID0gZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgaWYgKCEoZXZlbnQgaW4gdGhpcy5saXN0ZW5lcnMpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgIHRoaXMubGlzdGVuZXJzW2V2ZW50XS5mb3JFYWNoKGZ1bmN0aW9uIChsaXN0ZW5lcikge1xuICAgICAgICBsaXN0ZW5lci5hcHBseSh0aGlzLCBhcmdzKTtcbiAgICB9LmJpbmQodGhpcykpO1xufTtcbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuYWRkTGlzdGVuZXIgPSBmdW5jdGlvbiAoZXZlbnRzLCBmKSB7XG4gICAgZXZlbnRzLnNwbGl0KFwiIFwiKS5mb3JFYWNoKGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICB0aGlzLmxpc3RlbmVyc1tldmVudF0gPSB0aGlzLmxpc3RlbmVyc1tldmVudF0gfHwgW107XG4gICAgICAgIHRoaXMubGlzdGVuZXJzW2V2ZW50XS5wdXNoKGYpO1xuICAgIH0uYmluZCh0aGlzKSk7XG59O1xuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5yZW1vdmVMaXN0ZW5lciA9IGZ1bmN0aW9uIChldmVudHMsIGYpIHtcbiAgICBpZiAoIShldmVudHMgaW4gdGhpcy5saXN0ZW5lcnMpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgZXZlbnRzLnNwbGl0KFwiIFwiKS5mb3JFYWNoKGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICB2YXIgaW5kZXggPSB0aGlzLmxpc3RlbmVyc1tldmVudF0uaW5kZXhPZihmKTtcbiAgICAgICAgaWYgKGluZGV4ID49IDApIHtcbiAgICAgICAgICAgIHRoaXMubGlzdGVuZXJzW2V2ZW50XS5zcGxpY2UoaW5kZXgsIDEpO1xuICAgICAgICB9XG4gICAgfS5iaW5kKHRoaXMpKTtcbn07XG5cblxuZnVuY3Rpb24gZ2V0Q29va2llKG5hbWUpIHtcbiAgICB2YXIgciA9IGRvY3VtZW50LmNvb2tpZS5tYXRjaChcIlxcXFxiXCIgKyBuYW1lICsgXCI9KFteO10qKVxcXFxiXCIpO1xuICAgIHJldHVybiByID8gclsxXSA6IHVuZGVmaW5lZDtcbn1cbnZhciB4c3JmID0gJC5wYXJhbSh7X3hzcmY6IGdldENvb2tpZShcIl94c3JmXCIpfSk7XG5cbi8vVG9ybmFkbyBYU1JGIFByb3RlY3Rpb24uXG4kLmFqYXhQcmVmaWx0ZXIoZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICBpZiAoW1wicG9zdFwiLCBcInB1dFwiLCBcImRlbGV0ZVwiXS5pbmRleE9mKG9wdGlvbnMudHlwZS50b0xvd2VyQ2FzZSgpKSA+PSAwICYmIG9wdGlvbnMudXJsWzBdID09PSBcIi9cIikge1xuICAgICAgICBpZiAob3B0aW9ucy5kYXRhKSB7XG4gICAgICAgICAgICBvcHRpb25zLmRhdGEgKz0gKFwiJlwiICsgeHNyZik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBvcHRpb25zLmRhdGEgPSB4c3JmO1xuICAgICAgICB9XG4gICAgfVxufSk7XG4vLyBMb2cgQUpBWCBFcnJvcnNcbiQoZG9jdW1lbnQpLmFqYXhFcnJvcihmdW5jdGlvbiAoZXZlbnQsIGpxWEhSLCBhamF4U2V0dGluZ3MsIHRocm93bkVycm9yKSB7XG4gICAgdmFyIG1lc3NhZ2UgPSBqcVhIUi5yZXNwb25zZVRleHQ7XG4gICAgY29uc29sZS5lcnJvcihtZXNzYWdlLCBhcmd1bWVudHMpO1xuICAgIEV2ZW50TG9nQWN0aW9ucy5hZGRfZXZlbnQodGhyb3duRXJyb3IgKyBcIjogXCIgKyBtZXNzYWdlKTtcbiAgICB3aW5kb3cuYWxlcnQobWVzc2FnZSk7XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgRXZlbnRFbWl0dGVyOiBFdmVudEVtaXR0ZXIsXG4gICAgZm9ybWF0U2l6ZTogZm9ybWF0U2l6ZSxcbiAgICBmb3JtYXRUaW1lRGVsdGE6IGZvcm1hdFRpbWVEZWx0YSxcbiAgICBmb3JtYXRUaW1lU3RhbXA6IGZvcm1hdFRpbWVTdGFtcFxufTsiXX0=
diff --git a/libmproxy/web/static/js/app.js b/libmproxy/web/static/js/app.js
deleted file mode 100644
index c054baa2..00000000
--- a/libmproxy/web/static/js/app.js
+++ /dev/null
@@ -1,4153 +0,0 @@
-var Key = {
- UP: 38,
- DOWN: 40,
- PAGE_UP: 33,
- PAGE_DOWN: 34,
- HOME: 36,
- END: 35,
- LEFT: 37,
- RIGHT: 39,
- ENTER: 13,
- ESC: 27,
- TAB: 9,
- SPACE: 32,
- BACKSPACE: 8,
-};
-// Add A-Z
-for (var i = 65; i <= 90; i++) {
- Key[String.fromCharCode(i)] = i;
-}
-
-
-var formatSize = function (bytes) {
- var size = bytes;
- var prefix = ["B", "KB", "MB", "GB", "TB"];
- var i = 0;
- while (Math.abs(size) >= 1024 && i < prefix.length - 1) {
- i++;
- size = size / 1024;
- }
- return (Math.floor(size * 100) / 100.0).toFixed(2) + prefix[i];
-};
-
-
-var formatTimeDelta = function (milliseconds) {
- var time = milliseconds;
- var prefix = ["ms", "s", "min", "h"];
- var div = [1000, 60, 60];
- var i = 0;
- while (Math.abs(time) >= div[i] && i < div.length) {
- time = time / div[i];
- i++;
- }
- return Math.round(time) + prefix[i];
-};
-
-
-var formatTimeStamp = function (seconds) {
- var ts = (new Date(seconds * 1000)).toISOString();
- return ts.replace("T", " ").replace("Z", "");
-};
-
-
-function EventEmitter() {
- this.listeners = {};
-}
-EventEmitter.prototype.emit = function (event) {
- if (!(event in this.listeners)) {
- return;
- }
- var args = Array.prototype.slice.call(arguments, 1);
- this.listeners[event].forEach(function (listener) {
- listener.apply(this, args);
- }.bind(this));
-};
-EventEmitter.prototype.addListener = function (events, f) {
- events.split(" ").forEach(function (event) {
- this.listeners[event] = this.listeners[event] || [];
- this.listeners[event].push(f);
- }.bind(this));
-};
-EventEmitter.prototype.removeListener = function (events, f) {
- if (!(events in this.listeners)) {
- return false;
- }
- events.split(" ").forEach(function (event) {
- var index = this.listeners[event].indexOf(f);
- if (index >= 0) {
- this.listeners[event].splice(index, 1);
- }
- }.bind(this));
-};
-
-
-function getCookie(name) {
- var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
- return r ? r[1] : undefined;
-}
-var xsrf = $.param({_xsrf: getCookie("_xsrf")});
-
-//Tornado XSRF Protection.
-jQuery.ajaxPrefilter(function (options) {
- if (["post", "put", "delete"].indexOf(options.type.toLowerCase()) >= 0 && options.url[0] === "/") {
- if (options.data) {
- options.data += ("&" + xsrf);
- } else {
- options.data = xsrf;
- }
- }
-});
-// Log AJAX Errors
-$(document).ajaxError(function (event, jqXHR, ajaxSettings, thrownError) {
- var message = jqXHR.responseText;
- console.error(message, arguments);
- EventLogActions.add_event(thrownError + ": " + message);
- window.alert(message);
-});
-const PayloadSources = {
- VIEW: "view",
- SERVER: "server"
-};
-
-
-function Dispatcher() {
- this.callbacks = [];
-}
-Dispatcher.prototype.register = function (callback) {
- this.callbacks.push(callback);
-};
-Dispatcher.prototype.unregister = function (callback) {
- var index = this.callbacks.indexOf(callback);
- if (index >= 0) {
- this.callbacks.splice(index, 1);
- }
-};
-Dispatcher.prototype.dispatch = function (payload) {
- console.debug("dispatch", payload);
- for (var i = 0; i < this.callbacks.length; i++) {
- this.callbacks[i](payload);
- }
-};
-
-
-AppDispatcher = new Dispatcher();
-AppDispatcher.dispatchViewAction = function (action) {
- action.source = PayloadSources.VIEW;
- this.dispatch(action);
-};
-AppDispatcher.dispatchServerAction = function (action) {
- action.source = PayloadSources.SERVER;
- this.dispatch(action);
-};
-
-var ActionTypes = {
- // Connection
- CONNECTION_OPEN: "connection_open",
- CONNECTION_CLOSE: "connection_close",
- CONNECTION_ERROR: "connection_error",
-
- // Stores
- SETTINGS_STORE: "settings",
- EVENT_STORE: "events",
- FLOW_STORE: "flows",
-};
-
-var StoreCmds = {
- ADD: "add",
- UPDATE: "update",
- REMOVE: "remove",
- RESET: "reset"
-};
-
-var ConnectionActions = {
- open: function () {
- AppDispatcher.dispatchViewAction({
- type: ActionTypes.CONNECTION_OPEN
- });
- },
- close: function () {
- AppDispatcher.dispatchViewAction({
- type: ActionTypes.CONNECTION_CLOSE
- });
- },
- error: function () {
- AppDispatcher.dispatchViewAction({
- type: ActionTypes.CONNECTION_ERROR
- });
- }
-};
-
-var SettingsActions = {
- update: function (settings) {
-
- jQuery.ajax({
- type: "PUT",
- url: "/settings",
- data: settings
- });
-
- /*
- //Facebook Flux: We do an optimistic update on the client already.
- AppDispatcher.dispatchViewAction({
- type: ActionTypes.SETTINGS_STORE,
- cmd: StoreCmds.UPDATE,
- data: settings
- });
- */
- }
-};
-
-var EventLogActions_event_id = 0;
-var EventLogActions = {
- add_event: function (message) {
- AppDispatcher.dispatchViewAction({
- type: ActionTypes.EVENT_STORE,
- cmd: StoreCmds.ADD,
- data: {
- message: message,
- level: "web",
- id: "viewAction-" + EventLogActions_event_id++
- }
- });
- }
-};
-
-var FlowActions = {
- accept: function (flow) {
- jQuery.post("/flows/" + flow.id + "/accept");
- },
- accept_all: function(){
- jQuery.post("/flows/accept");
- },
- "delete": function(flow){
- jQuery.ajax({
- type:"DELETE",
- url: "/flows/" + flow.id
- });
- },
- duplicate: function(flow){
- jQuery.post("/flows/" + flow.id + "/duplicate");
- },
- replay: function(flow){
- jQuery.post("/flows/" + flow.id + "/replay");
- },
- revert: function(flow){
- jQuery.post("/flows/" + flow.id + "/revert");
- },
- update: function (flow) {
- AppDispatcher.dispatchViewAction({
- type: ActionTypes.FLOW_STORE,
- cmd: StoreCmds.UPDATE,
- data: flow
- });
- },
- clear: function(){
- jQuery.post("/clear");
- }
-};
-
-Query = {
- FILTER: "f",
- HIGHLIGHT: "h",
- SHOW_EVENTLOG: "e"
-};
-Filt = (function() {
- /*
- * Generated by PEG.js 0.8.0.
- *
- * http://pegjs.majda.cz/
- */
-
- function peg$subclass(child, parent) {
- function ctor() { this.constructor = child; }
- ctor.prototype = parent.prototype;
- child.prototype = new ctor();
- }
-
- function SyntaxError(message, expected, found, offset, line, column) {
- this.message = message;
- this.expected = expected;
- this.found = found;
- this.offset = offset;
- this.line = line;
- this.column = column;
-
- this.name = "SyntaxError";
- }
-
- peg$subclass(SyntaxError, Error);
-
- function parse(input) {
- var options = arguments.length > 1 ? arguments[1] : {},
-
- peg$FAILED = {},
-
- peg$startRuleFunctions = { start: peg$parsestart },
- peg$startRuleFunction = peg$parsestart,
-
- peg$c0 = { type: "other", description: "filter expression" },
- peg$c1 = peg$FAILED,
- peg$c2 = function(orExpr) { return orExpr; },
- peg$c3 = [],
- peg$c4 = function() {return trueFilter; },
- peg$c5 = { type: "other", description: "whitespace" },
- peg$c6 = /^[ \t\n\r]/,
- peg$c7 = { type: "class", value: "[ \\t\\n\\r]", description: "[ \\t\\n\\r]" },
- peg$c8 = { type: "other", description: "control character" },
- peg$c9 = /^[|&!()~"]/,
- peg$c10 = { type: "class", value: "[|&!()~\"]", description: "[|&!()~\"]" },
- peg$c11 = { type: "other", description: "optional whitespace" },
- peg$c12 = "|",
- peg$c13 = { type: "literal", value: "|", description: "\"|\"" },
- peg$c14 = function(first, second) { return or(first, second); },
- peg$c15 = "&",
- peg$c16 = { type: "literal", value: "&", description: "\"&\"" },
- peg$c17 = function(first, second) { return and(first, second); },
- peg$c18 = "!",
- peg$c19 = { type: "literal", value: "!", description: "\"!\"" },
- peg$c20 = function(expr) { return not(expr); },
- peg$c21 = "(",
- peg$c22 = { type: "literal", value: "(", description: "\"(\"" },
- peg$c23 = ")",
- peg$c24 = { type: "literal", value: ")", description: "\")\"" },
- peg$c25 = function(expr) { return binding(expr); },
- peg$c26 = "~a",
- peg$c27 = { type: "literal", value: "~a", description: "\"~a\"" },
- peg$c28 = function() { return assetFilter; },
- peg$c29 = "~e",
- peg$c30 = { type: "literal", value: "~e", description: "\"~e\"" },
- peg$c31 = function() { return errorFilter; },
- peg$c32 = "~q",
- peg$c33 = { type: "literal", value: "~q", description: "\"~q\"" },
- peg$c34 = function() { return noResponseFilter; },
- peg$c35 = "~s",
- peg$c36 = { type: "literal", value: "~s", description: "\"~s\"" },
- peg$c37 = function() { return responseFilter; },
- peg$c38 = "true",
- peg$c39 = { type: "literal", value: "true", description: "\"true\"" },
- peg$c40 = function() { return trueFilter; },
- peg$c41 = "false",
- peg$c42 = { type: "literal", value: "false", description: "\"false\"" },
- peg$c43 = function() { return falseFilter; },
- peg$c44 = "~c",
- peg$c45 = { type: "literal", value: "~c", description: "\"~c\"" },
- peg$c46 = function(s) { return responseCode(s); },
- peg$c47 = "~d",
- peg$c48 = { type: "literal", value: "~d", description: "\"~d\"" },
- peg$c49 = function(s) { return domain(s); },
- peg$c50 = "~h",
- peg$c51 = { type: "literal", value: "~h", description: "\"~h\"" },
- peg$c52 = function(s) { return header(s); },
- peg$c53 = "~hq",
- peg$c54 = { type: "literal", value: "~hq", description: "\"~hq\"" },
- peg$c55 = function(s) { return requestHeader(s); },
- peg$c56 = "~hs",
- peg$c57 = { type: "literal", value: "~hs", description: "\"~hs\"" },
- peg$c58 = function(s) { return responseHeader(s); },
- peg$c59 = "~m",
- peg$c60 = { type: "literal", value: "~m", description: "\"~m\"" },
- peg$c61 = function(s) { return method(s); },
- peg$c62 = "~t",
- peg$c63 = { type: "literal", value: "~t", description: "\"~t\"" },
- peg$c64 = function(s) { return contentType(s); },
- peg$c65 = "~tq",
- peg$c66 = { type: "literal", value: "~tq", description: "\"~tq\"" },
- peg$c67 = function(s) { return requestContentType(s); },
- peg$c68 = "~ts",
- peg$c69 = { type: "literal", value: "~ts", description: "\"~ts\"" },
- peg$c70 = function(s) { return responseContentType(s); },
- peg$c71 = "~u",
- peg$c72 = { type: "literal", value: "~u", description: "\"~u\"" },
- peg$c73 = function(s) { return url(s); },
- peg$c74 = { type: "other", description: "integer" },
- peg$c75 = null,
- peg$c76 = /^['"]/,
- peg$c77 = { type: "class", value: "['\"]", description: "['\"]" },
- peg$c78 = /^[0-9]/,
- peg$c79 = { type: "class", value: "[0-9]", description: "[0-9]" },
- peg$c80 = function(digits) { return parseInt(digits.join(""), 10); },
- peg$c81 = { type: "other", description: "string" },
- peg$c82 = "\"",
- peg$c83 = { type: "literal", value: "\"", description: "\"\\\"\"" },
- peg$c84 = function(chars) { return chars.join(""); },
- peg$c85 = "'",
- peg$c86 = { type: "literal", value: "'", description: "\"'\"" },
- peg$c87 = void 0,
- peg$c88 = /^["\\]/,
- peg$c89 = { type: "class", value: "[\"\\\\]", description: "[\"\\\\]" },
- peg$c90 = { type: "any", description: "any character" },
- peg$c91 = function(char) { return char; },
- peg$c92 = "\\",
- peg$c93 = { type: "literal", value: "\\", description: "\"\\\\\"" },
- peg$c94 = /^['\\]/,
- peg$c95 = { type: "class", value: "['\\\\]", description: "['\\\\]" },
- peg$c96 = /^['"\\]/,
- peg$c97 = { type: "class", value: "['\"\\\\]", description: "['\"\\\\]" },
- peg$c98 = "n",
- peg$c99 = { type: "literal", value: "n", description: "\"n\"" },
- peg$c100 = function() { return "\n"; },
- peg$c101 = "r",
- peg$c102 = { type: "literal", value: "r", description: "\"r\"" },
- peg$c103 = function() { return "\r"; },
- peg$c104 = "t",
- peg$c105 = { type: "literal", value: "t", description: "\"t\"" },
- peg$c106 = function() { return "\t"; },
-
- peg$currPos = 0,
- peg$reportedPos = 0,
- peg$cachedPos = 0,
- peg$cachedPosDetails = { line: 1, column: 1, seenCR: false },
- peg$maxFailPos = 0,
- peg$maxFailExpected = [],
- peg$silentFails = 0,
-
- peg$result;
-
- if ("startRule" in options) {
- if (!(options.startRule in peg$startRuleFunctions)) {
- throw new Error("Can't start parsing from rule \"" + options.startRule + "\".");
- }
-
- peg$startRuleFunction = peg$startRuleFunctions[options.startRule];
- }
-
- function text() {
- return input.substring(peg$reportedPos, peg$currPos);
- }
-
- function offset() {
- return peg$reportedPos;
- }
-
- function line() {
- return peg$computePosDetails(peg$reportedPos).line;
- }
-
- function column() {
- return peg$computePosDetails(peg$reportedPos).column;
- }
-
- function expected(description) {
- throw peg$buildException(
- null,
- [{ type: "other", description: description }],
- peg$reportedPos
- );
- }
-
- function error(message) {
- throw peg$buildException(message, null, peg$reportedPos);
- }
-
- function peg$computePosDetails(pos) {
- function advance(details, startPos, endPos) {
- var p, ch;
-
- for (p = startPos; p < endPos; p++) {
- ch = input.charAt(p);
- if (ch === "\n") {
- if (!details.seenCR) { details.line++; }
- details.column = 1;
- details.seenCR = false;
- } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") {
- details.line++;
- details.column = 1;
- details.seenCR = true;
- } else {
- details.column++;
- details.seenCR = false;
- }
- }
- }
-
- if (peg$cachedPos !== pos) {
- if (peg$cachedPos > pos) {
- peg$cachedPos = 0;
- peg$cachedPosDetails = { line: 1, column: 1, seenCR: false };
- }
- advance(peg$cachedPosDetails, peg$cachedPos, pos);
- peg$cachedPos = pos;
- }
-
- return peg$cachedPosDetails;
- }
-
- function peg$fail(expected) {
- if (peg$currPos < peg$maxFailPos) { return; }
-
- if (peg$currPos > peg$maxFailPos) {
- peg$maxFailPos = peg$currPos;
- peg$maxFailExpected = [];
- }
-
- peg$maxFailExpected.push(expected);
- }
-
- function peg$buildException(message, expected, pos) {
- function cleanupExpected(expected) {
- var i = 1;
-
- expected.sort(function(a, b) {
- if (a.description < b.description) {
- return -1;
- } else if (a.description > b.description) {
- return 1;
- } else {
- return 0;
- }
- });
-
- while (i < expected.length) {
- if (expected[i - 1] === expected[i]) {
- expected.splice(i, 1);
- } else {
- i++;
- }
- }
- }
-
- function buildMessage(expected, found) {
- function stringEscape(s) {
- function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); }
-
- return s
- .replace(/\\/g, '\\\\')
- .replace(/"/g, '\\"')
- .replace(/\x08/g, '\\b')
- .replace(/\t/g, '\\t')
- .replace(/\n/g, '\\n')
- .replace(/\f/g, '\\f')
- .replace(/\r/g, '\\r')
- .replace(/[\x00-\x07\x0B\x0E\x0F]/g, function(ch) { return '\\x0' + hex(ch); })
- .replace(/[\x10-\x1F\x80-\xFF]/g, function(ch) { return '\\x' + hex(ch); })
- .replace(/[\u0180-\u0FFF]/g, function(ch) { return '\\u0' + hex(ch); })
- .replace(/[\u1080-\uFFFF]/g, function(ch) { return '\\u' + hex(ch); });
- }
-
- var expectedDescs = new Array(expected.length),
- expectedDesc, foundDesc, i;
-
- for (i = 0; i < expected.length; i++) {
- expectedDescs[i] = expected[i].description;
- }
-
- expectedDesc = (expected.length > 1
- ? expectedDescs.slice(0, -1).join(", ")
- + " or "
- + expectedDescs[expected.length - 1]
- : expectedDescs[0]);
-
- foundDesc = found ? "\"" + stringEscape(found) + "\"" : "end of input";
-
- return "Expected " + expectedDesc + " but " + foundDesc + " found.";
- }
-
- var posDetails = peg$computePosDetails(pos),
- found = pos < input.length ? input.charAt(pos) : null;
-
- if (expected !== null) {
- cleanupExpected(expected);
- }
-
- return new SyntaxError(
- message !== null ? message : buildMessage(expected, found),
- expected,
- found,
- pos,
- posDetails.line,
- posDetails.column
- );
- }
-
- function peg$parsestart() {
- var s0, s1, s2, s3;
-
- peg$silentFails++;
- s0 = peg$currPos;
- s1 = peg$parse__();
- if (s1 !== peg$FAILED) {
- s2 = peg$parseOrExpr();
- if (s2 !== peg$FAILED) {
- s3 = peg$parse__();
- if (s3 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c2(s2);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- s1 = [];
- if (s1 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c4();
- }
- s0 = s1;
- }
- peg$silentFails--;
- if (s0 === peg$FAILED) {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c0); }
- }
-
- return s0;
- }
-
- function peg$parsews() {
- var s0, s1;
-
- peg$silentFails++;
- if (peg$c6.test(input.charAt(peg$currPos))) {
- s0 = input.charAt(peg$currPos);
- peg$currPos++;
- } else {
- s0 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c7); }
- }
- peg$silentFails--;
- if (s0 === peg$FAILED) {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c5); }
- }
-
- return s0;
- }
-
- function peg$parsecc() {
- var s0, s1;
-
- peg$silentFails++;
- if (peg$c9.test(input.charAt(peg$currPos))) {
- s0 = input.charAt(peg$currPos);
- peg$currPos++;
- } else {
- s0 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c10); }
- }
- peg$silentFails--;
- if (s0 === peg$FAILED) {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c8); }
- }
-
- return s0;
- }
-
- function peg$parse__() {
- var s0, s1;
-
- peg$silentFails++;
- s0 = [];
- s1 = peg$parsews();
- while (s1 !== peg$FAILED) {
- s0.push(s1);
- s1 = peg$parsews();
- }
- peg$silentFails--;
- if (s0 === peg$FAILED) {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c11); }
- }
-
- return s0;
- }
-
- function peg$parseOrExpr() {
- var s0, s1, s2, s3, s4, s5;
-
- s0 = peg$currPos;
- s1 = peg$parseAndExpr();
- if (s1 !== peg$FAILED) {
- s2 = peg$parse__();
- if (s2 !== peg$FAILED) {
- if (input.charCodeAt(peg$currPos) === 124) {
- s3 = peg$c12;
- peg$currPos++;
- } else {
- s3 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c13); }
- }
- if (s3 !== peg$FAILED) {
- s4 = peg$parse__();
- if (s4 !== peg$FAILED) {
- s5 = peg$parseOrExpr();
- if (s5 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c14(s1, s5);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- if (s0 === peg$FAILED) {
- s0 = peg$parseAndExpr();
- }
-
- return s0;
- }
-
- function peg$parseAndExpr() {
- var s0, s1, s2, s3, s4, s5;
-
- s0 = peg$currPos;
- s1 = peg$parseNotExpr();
- if (s1 !== peg$FAILED) {
- s2 = peg$parse__();
- if (s2 !== peg$FAILED) {
- if (input.charCodeAt(peg$currPos) === 38) {
- s3 = peg$c15;
- peg$currPos++;
- } else {
- s3 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c16); }
- }
- if (s3 !== peg$FAILED) {
- s4 = peg$parse__();
- if (s4 !== peg$FAILED) {
- s5 = peg$parseAndExpr();
- if (s5 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c17(s1, s5);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- s1 = peg$parseNotExpr();
- if (s1 !== peg$FAILED) {
- s2 = [];
- s3 = peg$parsews();
- if (s3 !== peg$FAILED) {
- while (s3 !== peg$FAILED) {
- s2.push(s3);
- s3 = peg$parsews();
- }
- } else {
- s2 = peg$c1;
- }
- if (s2 !== peg$FAILED) {
- s3 = peg$parseAndExpr();
- if (s3 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c17(s1, s3);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- if (s0 === peg$FAILED) {
- s0 = peg$parseNotExpr();
- }
- }
-
- return s0;
- }
-
- function peg$parseNotExpr() {
- var s0, s1, s2, s3;
-
- s0 = peg$currPos;
- if (input.charCodeAt(peg$currPos) === 33) {
- s1 = peg$c18;
- peg$currPos++;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c19); }
- }
- if (s1 !== peg$FAILED) {
- s2 = peg$parse__();
- if (s2 !== peg$FAILED) {
- s3 = peg$parseNotExpr();
- if (s3 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c20(s3);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- if (s0 === peg$FAILED) {
- s0 = peg$parseBindingExpr();
- }
-
- return s0;
- }
-
- function peg$parseBindingExpr() {
- var s0, s1, s2, s3, s4, s5;
-
- s0 = peg$currPos;
- if (input.charCodeAt(peg$currPos) === 40) {
- s1 = peg$c21;
- peg$currPos++;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c22); }
- }
- if (s1 !== peg$FAILED) {
- s2 = peg$parse__();
- if (s2 !== peg$FAILED) {
- s3 = peg$parseOrExpr();
- if (s3 !== peg$FAILED) {
- s4 = peg$parse__();
- if (s4 !== peg$FAILED) {
- if (input.charCodeAt(peg$currPos) === 41) {
- s5 = peg$c23;
- peg$currPos++;
- } else {
- s5 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c24); }
- }
- if (s5 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c25(s3);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- if (s0 === peg$FAILED) {
- s0 = peg$parseExpr();
- }
-
- return s0;
- }
-
- function peg$parseExpr() {
- var s0;
-
- s0 = peg$parseNullaryExpr();
- if (s0 === peg$FAILED) {
- s0 = peg$parseUnaryExpr();
- }
-
- return s0;
- }
-
- function peg$parseNullaryExpr() {
- var s0, s1;
-
- s0 = peg$parseBooleanLiteral();
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- if (input.substr(peg$currPos, 2) === peg$c26) {
- s1 = peg$c26;
- peg$currPos += 2;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c27); }
- }
- if (s1 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c28();
- }
- s0 = s1;
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- if (input.substr(peg$currPos, 2) === peg$c29) {
- s1 = peg$c29;
- peg$currPos += 2;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c30); }
- }
- if (s1 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c31();
- }
- s0 = s1;
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- if (input.substr(peg$currPos, 2) === peg$c32) {
- s1 = peg$c32;
- peg$currPos += 2;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c33); }
- }
- if (s1 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c34();
- }
- s0 = s1;
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- if (input.substr(peg$currPos, 2) === peg$c35) {
- s1 = peg$c35;
- peg$currPos += 2;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c36); }
- }
- if (s1 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c37();
- }
- s0 = s1;
- }
- }
- }
- }
-
- return s0;
- }
-
- function peg$parseBooleanLiteral() {
- var s0, s1;
-
- s0 = peg$currPos;
- if (input.substr(peg$currPos, 4) === peg$c38) {
- s1 = peg$c38;
- peg$currPos += 4;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c39); }
- }
- if (s1 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c40();
- }
- s0 = s1;
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- if (input.substr(peg$currPos, 5) === peg$c41) {
- s1 = peg$c41;
- peg$currPos += 5;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c42); }
- }
- if (s1 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c43();
- }
- s0 = s1;
- }
-
- return s0;
- }
-
- function peg$parseUnaryExpr() {
- var s0, s1, s2, s3;
-
- s0 = peg$currPos;
- if (input.substr(peg$currPos, 2) === peg$c44) {
- s1 = peg$c44;
- peg$currPos += 2;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c45); }
- }
- if (s1 !== peg$FAILED) {
- s2 = [];
- s3 = peg$parsews();
- if (s3 !== peg$FAILED) {
- while (s3 !== peg$FAILED) {
- s2.push(s3);
- s3 = peg$parsews();
- }
- } else {
- s2 = peg$c1;
- }
- if (s2 !== peg$FAILED) {
- s3 = peg$parseIntegerLiteral();
- if (s3 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c46(s3);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- if (input.substr(peg$currPos, 2) === peg$c47) {
- s1 = peg$c47;
- peg$currPos += 2;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c48); }
- }
- if (s1 !== peg$FAILED) {
- s2 = [];
- s3 = peg$parsews();
- if (s3 !== peg$FAILED) {
- while (s3 !== peg$FAILED) {
- s2.push(s3);
- s3 = peg$parsews();
- }
- } else {
- s2 = peg$c1;
- }
- if (s2 !== peg$FAILED) {
- s3 = peg$parseStringLiteral();
- if (s3 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c49(s3);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- if (input.substr(peg$currPos, 2) === peg$c50) {
- s1 = peg$c50;
- peg$currPos += 2;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c51); }
- }
- if (s1 !== peg$FAILED) {
- s2 = [];
- s3 = peg$parsews();
- if (s3 !== peg$FAILED) {
- while (s3 !== peg$FAILED) {
- s2.push(s3);
- s3 = peg$parsews();
- }
- } else {
- s2 = peg$c1;
- }
- if (s2 !== peg$FAILED) {
- s3 = peg$parseStringLiteral();
- if (s3 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c52(s3);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- if (input.substr(peg$currPos, 3) === peg$c53) {
- s1 = peg$c53;
- peg$currPos += 3;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c54); }
- }
- if (s1 !== peg$FAILED) {
- s2 = [];
- s3 = peg$parsews();
- if (s3 !== peg$FAILED) {
- while (s3 !== peg$FAILED) {
- s2.push(s3);
- s3 = peg$parsews();
- }
- } else {
- s2 = peg$c1;
- }
- if (s2 !== peg$FAILED) {
- s3 = peg$parseStringLiteral();
- if (s3 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c55(s3);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- if (input.substr(peg$currPos, 3) === peg$c56) {
- s1 = peg$c56;
- peg$currPos += 3;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c57); }
- }
- if (s1 !== peg$FAILED) {
- s2 = [];
- s3 = peg$parsews();
- if (s3 !== peg$FAILED) {
- while (s3 !== peg$FAILED) {
- s2.push(s3);
- s3 = peg$parsews();
- }
- } else {
- s2 = peg$c1;
- }
- if (s2 !== peg$FAILED) {
- s3 = peg$parseStringLiteral();
- if (s3 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c58(s3);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- if (input.substr(peg$currPos, 2) === peg$c59) {
- s1 = peg$c59;
- peg$currPos += 2;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c60); }
- }
- if (s1 !== peg$FAILED) {
- s2 = [];
- s3 = peg$parsews();
- if (s3 !== peg$FAILED) {
- while (s3 !== peg$FAILED) {
- s2.push(s3);
- s3 = peg$parsews();
- }
- } else {
- s2 = peg$c1;
- }
- if (s2 !== peg$FAILED) {
- s3 = peg$parseStringLiteral();
- if (s3 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c61(s3);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- if (input.substr(peg$currPos, 2) === peg$c62) {
- s1 = peg$c62;
- peg$currPos += 2;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c63); }
- }
- if (s1 !== peg$FAILED) {
- s2 = [];
- s3 = peg$parsews();
- if (s3 !== peg$FAILED) {
- while (s3 !== peg$FAILED) {
- s2.push(s3);
- s3 = peg$parsews();
- }
- } else {
- s2 = peg$c1;
- }
- if (s2 !== peg$FAILED) {
- s3 = peg$parseStringLiteral();
- if (s3 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c64(s3);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- if (input.substr(peg$currPos, 3) === peg$c65) {
- s1 = peg$c65;
- peg$currPos += 3;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c66); }
- }
- if (s1 !== peg$FAILED) {
- s2 = [];
- s3 = peg$parsews();
- if (s3 !== peg$FAILED) {
- while (s3 !== peg$FAILED) {
- s2.push(s3);
- s3 = peg$parsews();
- }
- } else {
- s2 = peg$c1;
- }
- if (s2 !== peg$FAILED) {
- s3 = peg$parseStringLiteral();
- if (s3 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c67(s3);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- if (input.substr(peg$currPos, 3) === peg$c68) {
- s1 = peg$c68;
- peg$currPos += 3;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c69); }
- }
- if (s1 !== peg$FAILED) {
- s2 = [];
- s3 = peg$parsews();
- if (s3 !== peg$FAILED) {
- while (s3 !== peg$FAILED) {
- s2.push(s3);
- s3 = peg$parsews();
- }
- } else {
- s2 = peg$c1;
- }
- if (s2 !== peg$FAILED) {
- s3 = peg$parseStringLiteral();
- if (s3 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c70(s3);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- if (input.substr(peg$currPos, 2) === peg$c71) {
- s1 = peg$c71;
- peg$currPos += 2;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c72); }
- }
- if (s1 !== peg$FAILED) {
- s2 = [];
- s3 = peg$parsews();
- if (s3 !== peg$FAILED) {
- while (s3 !== peg$FAILED) {
- s2.push(s3);
- s3 = peg$parsews();
- }
- } else {
- s2 = peg$c1;
- }
- if (s2 !== peg$FAILED) {
- s3 = peg$parseStringLiteral();
- if (s3 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c73(s3);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- s1 = peg$parseStringLiteral();
- if (s1 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c73(s1);
- }
- s0 = s1;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- return s0;
- }
-
- function peg$parseIntegerLiteral() {
- var s0, s1, s2, s3;
-
- peg$silentFails++;
- s0 = peg$currPos;
- if (peg$c76.test(input.charAt(peg$currPos))) {
- s1 = input.charAt(peg$currPos);
- peg$currPos++;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c77); }
- }
- if (s1 === peg$FAILED) {
- s1 = peg$c75;
- }
- if (s1 !== peg$FAILED) {
- s2 = [];
- if (peg$c78.test(input.charAt(peg$currPos))) {
- s3 = input.charAt(peg$currPos);
- peg$currPos++;
- } else {
- s3 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c79); }
- }
- if (s3 !== peg$FAILED) {
- while (s3 !== peg$FAILED) {
- s2.push(s3);
- if (peg$c78.test(input.charAt(peg$currPos))) {
- s3 = input.charAt(peg$currPos);
- peg$currPos++;
- } else {
- s3 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c79); }
- }
- }
- } else {
- s2 = peg$c1;
- }
- if (s2 !== peg$FAILED) {
- if (peg$c76.test(input.charAt(peg$currPos))) {
- s3 = input.charAt(peg$currPos);
- peg$currPos++;
- } else {
- s3 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c77); }
- }
- if (s3 === peg$FAILED) {
- s3 = peg$c75;
- }
- if (s3 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c80(s2);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- peg$silentFails--;
- if (s0 === peg$FAILED) {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c74); }
- }
-
- return s0;
- }
-
- function peg$parseStringLiteral() {
- var s0, s1, s2, s3;
-
- peg$silentFails++;
- s0 = peg$currPos;
- if (input.charCodeAt(peg$currPos) === 34) {
- s1 = peg$c82;
- peg$currPos++;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c83); }
- }
- if (s1 !== peg$FAILED) {
- s2 = [];
- s3 = peg$parseDoubleStringChar();
- while (s3 !== peg$FAILED) {
- s2.push(s3);
- s3 = peg$parseDoubleStringChar();
- }
- if (s2 !== peg$FAILED) {
- if (input.charCodeAt(peg$currPos) === 34) {
- s3 = peg$c82;
- peg$currPos++;
- } else {
- s3 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c83); }
- }
- if (s3 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c84(s2);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- if (input.charCodeAt(peg$currPos) === 39) {
- s1 = peg$c85;
- peg$currPos++;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c86); }
- }
- if (s1 !== peg$FAILED) {
- s2 = [];
- s3 = peg$parseSingleStringChar();
- while (s3 !== peg$FAILED) {
- s2.push(s3);
- s3 = peg$parseSingleStringChar();
- }
- if (s2 !== peg$FAILED) {
- if (input.charCodeAt(peg$currPos) === 39) {
- s3 = peg$c85;
- peg$currPos++;
- } else {
- s3 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c86); }
- }
- if (s3 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c84(s2);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- s1 = peg$currPos;
- peg$silentFails++;
- s2 = peg$parsecc();
- peg$silentFails--;
- if (s2 === peg$FAILED) {
- s1 = peg$c87;
- } else {
- peg$currPos = s1;
- s1 = peg$c1;
- }
- if (s1 !== peg$FAILED) {
- s2 = [];
- s3 = peg$parseUnquotedStringChar();
- if (s3 !== peg$FAILED) {
- while (s3 !== peg$FAILED) {
- s2.push(s3);
- s3 = peg$parseUnquotedStringChar();
- }
- } else {
- s2 = peg$c1;
- }
- if (s2 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c84(s2);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- }
- }
- peg$silentFails--;
- if (s0 === peg$FAILED) {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c81); }
- }
-
- return s0;
- }
-
- function peg$parseDoubleStringChar() {
- var s0, s1, s2;
-
- s0 = peg$currPos;
- s1 = peg$currPos;
- peg$silentFails++;
- if (peg$c88.test(input.charAt(peg$currPos))) {
- s2 = input.charAt(peg$currPos);
- peg$currPos++;
- } else {
- s2 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c89); }
- }
- peg$silentFails--;
- if (s2 === peg$FAILED) {
- s1 = peg$c87;
- } else {
- peg$currPos = s1;
- s1 = peg$c1;
- }
- if (s1 !== peg$FAILED) {
- if (input.length > peg$currPos) {
- s2 = input.charAt(peg$currPos);
- peg$currPos++;
- } else {
- s2 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c90); }
- }
- if (s2 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c91(s2);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- if (input.charCodeAt(peg$currPos) === 92) {
- s1 = peg$c92;
- peg$currPos++;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c93); }
- }
- if (s1 !== peg$FAILED) {
- s2 = peg$parseEscapeSequence();
- if (s2 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c91(s2);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- }
-
- return s0;
- }
-
- function peg$parseSingleStringChar() {
- var s0, s1, s2;
-
- s0 = peg$currPos;
- s1 = peg$currPos;
- peg$silentFails++;
- if (peg$c94.test(input.charAt(peg$currPos))) {
- s2 = input.charAt(peg$currPos);
- peg$currPos++;
- } else {
- s2 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c95); }
- }
- peg$silentFails--;
- if (s2 === peg$FAILED) {
- s1 = peg$c87;
- } else {
- peg$currPos = s1;
- s1 = peg$c1;
- }
- if (s1 !== peg$FAILED) {
- if (input.length > peg$currPos) {
- s2 = input.charAt(peg$currPos);
- peg$currPos++;
- } else {
- s2 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c90); }
- }
- if (s2 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c91(s2);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- if (input.charCodeAt(peg$currPos) === 92) {
- s1 = peg$c92;
- peg$currPos++;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c93); }
- }
- if (s1 !== peg$FAILED) {
- s2 = peg$parseEscapeSequence();
- if (s2 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c91(s2);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- }
-
- return s0;
- }
-
- function peg$parseUnquotedStringChar() {
- var s0, s1, s2;
-
- s0 = peg$currPos;
- s1 = peg$currPos;
- peg$silentFails++;
- s2 = peg$parsews();
- peg$silentFails--;
- if (s2 === peg$FAILED) {
- s1 = peg$c87;
- } else {
- peg$currPos = s1;
- s1 = peg$c1;
- }
- if (s1 !== peg$FAILED) {
- if (input.length > peg$currPos) {
- s2 = input.charAt(peg$currPos);
- peg$currPos++;
- } else {
- s2 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c90); }
- }
- if (s2 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c91(s2);
- s0 = s1;
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
- } else {
- peg$currPos = s0;
- s0 = peg$c1;
- }
-
- return s0;
- }
-
- function peg$parseEscapeSequence() {
- var s0, s1;
-
- if (peg$c96.test(input.charAt(peg$currPos))) {
- s0 = input.charAt(peg$currPos);
- peg$currPos++;
- } else {
- s0 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c97); }
- }
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- if (input.charCodeAt(peg$currPos) === 110) {
- s1 = peg$c98;
- peg$currPos++;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c99); }
- }
- if (s1 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c100();
- }
- s0 = s1;
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- if (input.charCodeAt(peg$currPos) === 114) {
- s1 = peg$c101;
- peg$currPos++;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c102); }
- }
- if (s1 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c103();
- }
- s0 = s1;
- if (s0 === peg$FAILED) {
- s0 = peg$currPos;
- if (input.charCodeAt(peg$currPos) === 116) {
- s1 = peg$c104;
- peg$currPos++;
- } else {
- s1 = peg$FAILED;
- if (peg$silentFails === 0) { peg$fail(peg$c105); }
- }
- if (s1 !== peg$FAILED) {
- peg$reportedPos = s0;
- s1 = peg$c106();
- }
- s0 = s1;
- }
- }
- }
-
- return s0;
- }
-
-
- function or(first, second) {
- // Add explicit function names to ease debugging.
- function orFilter() {
- return first.apply(this, arguments) || second.apply(this, arguments);
- }
- orFilter.desc = first.desc + " or " + second.desc;
- return orFilter;
- }
- function and(first, second) {
- function andFilter() {
- return first.apply(this, arguments) && second.apply(this, arguments);
- }
- andFilter.desc = first.desc + " and " + second.desc;
- return andFilter;
- }
- function not(expr) {
- function notFilter() {
- return !expr.apply(this, arguments);
- }
- notFilter.desc = "not " + expr.desc;
- return notFilter;
- }
- function binding(expr) {
- function bindingFilter() {
- return expr.apply(this, arguments);
- }
- bindingFilter.desc = "(" + expr.desc + ")";
- return bindingFilter;
- }
- function trueFilter(flow) {
- return true;
- }
- trueFilter.desc = "true";
- function falseFilter(flow) {
- return false;
- }
- falseFilter.desc = "false";
-
- var ASSET_TYPES = [
- new RegExp("text/javascript"),
- new RegExp("application/x-javascript"),
- new RegExp("application/javascript"),
- new RegExp("text/css"),
- new RegExp("image/.*"),
- new RegExp("application/x-shockwave-flash")
- ];
- function assetFilter(flow) {
- if (flow.response) {
- var ct = ResponseUtils.getContentType(flow.response);
- var i = ASSET_TYPES.length;
- while (i--) {
- if (ASSET_TYPES[i].test(ct)) {
- return true;
- }
- }
- }
- return false;
- }
- assetFilter.desc = "is asset";
- function responseCode(code){
- function responseCodeFilter(flow){
- return flow.response && flow.response.code === code;
- }
- responseCodeFilter.desc = "resp. code is " + code;
- return responseCodeFilter;
- }
- function domain(regex){
- regex = new RegExp(regex, "i");
- function domainFilter(flow){
- return flow.request && regex.test(flow.request.host);
- }
- domainFilter.desc = "domain matches " + regex;
- return domainFilter;
- }
- function errorFilter(flow){
- return !!flow.error;
- }
- errorFilter.desc = "has error";
- function header(regex){
- regex = new RegExp(regex, "i");
- function headerFilter(flow){
- return (
- (flow.request && RequestUtils.match_header(flow.request, regex))
- ||
- (flow.response && ResponseUtils.match_header(flow.response, regex))
- );
- }
- headerFilter.desc = "header matches " + regex;
- return headerFilter;
- }
- function requestHeader(regex){
- regex = new RegExp(regex, "i");
- function requestHeaderFilter(flow){
- return (flow.request && RequestUtils.match_header(flow.request, regex));
- }
- requestHeaderFilter.desc = "req. header matches " + regex;
- return requestHeaderFilter;
- }
- function responseHeader(regex){
- regex = new RegExp(regex, "i");
- function responseHeaderFilter(flow){
- return (flow.response && ResponseUtils.match_header(flow.response, regex));
- }
- responseHeaderFilter.desc = "resp. header matches " + regex;
- return responseHeaderFilter;
- }
- function method(regex){
- regex = new RegExp(regex, "i");
- function methodFilter(flow){
- return flow.request && regex.test(flow.request.method);
- }
- methodFilter.desc = "method matches " + regex;
- return methodFilter;
- }
- function noResponseFilter(flow){
- return flow.request && !flow.response;
- }
- noResponseFilter.desc = "has no response";
- function responseFilter(flow){
- return !!flow.response;
- }
- responseFilter.desc = "has response";
-
- function contentType(regex){
- regex = new RegExp(regex, "i");
- function contentTypeFilter(flow){
- return (
- (flow.request && regex.test(RequestUtils.getContentType(flow.request)))
- ||
- (flow.response && regex.test(ResponseUtils.getContentType(flow.response)))
- );
- }
- contentTypeFilter.desc = "content type matches " + regex;
- return contentTypeFilter;
- }
- function requestContentType(regex){
- regex = new RegExp(regex, "i");
- function requestContentTypeFilter(flow){
- return flow.request && regex.test(RequestUtils.getContentType(flow.request));
- }
- requestContentTypeFilter.desc = "req. content type matches " + regex;
- return requestContentTypeFilter;
- }
- function responseContentType(regex){
- regex = new RegExp(regex, "i");
- function responseContentTypeFilter(flow){
- return flow.response && regex.test(ResponseUtils.getContentType(flow.response));
- }
- responseContentTypeFilter.desc = "resp. content type matches " + regex;
- return responseContentTypeFilter;
- }
- function url(regex){
- regex = new RegExp(regex, "i");
- function urlFilter(flow){
- return flow.request && regex.test(RequestUtils.pretty_url(flow.request));
- }
- urlFilter.desc = "url matches " + regex;
- return urlFilter;
- }
-
-
- peg$result = peg$startRuleFunction();
-
- if (peg$result !== peg$FAILED && peg$currPos === input.length) {
- return peg$result;
- } else {
- if (peg$result !== peg$FAILED && peg$currPos < input.length) {
- peg$fail({ type: "end", description: "end of input" });
- }
-
- throw peg$buildException(null, peg$maxFailExpected, peg$maxFailPos);
- }
- }
-
- return {
- SyntaxError: SyntaxError,
- parse: parse
- };
-})();
-var _MessageUtils = {
- getContentType: function (message) {
- return this.get_first_header(message, /^Content-Type$/i);
- },
- get_first_header: function (message, regex) {
- //FIXME: Cache Invalidation.
- if (!message._headerLookups)
- Object.defineProperty(message, "_headerLookups", {
- value: {},
- configurable: false,
- enumerable: false,
- writable: false
- });
- if (!(regex in message._headerLookups)) {
- var header;
- for (var i = 0; i < message.headers.length; i++) {
- if (!!message.headers[i][0].match(regex)) {
- header = message.headers[i];
- break;
- }
- }
- message._headerLookups[regex] = header ? header[1] : undefined;
- }
- return message._headerLookups[regex];
- },
- match_header: function (message, regex) {
- var headers = message.headers;
- var i = headers.length;
- while (i--) {
- if (regex.test(headers[i].join(" "))) {
- return headers[i];
- }
- }
- return false;
- }
-};
-
-var defaultPorts = {
- "http": 80,
- "https": 443
-};
-
-var RequestUtils = _.extend(_MessageUtils, {
- pretty_host: function (request) {
- //FIXME: Add hostheader
- return request.host;
- },
- pretty_url: function (request) {
- var port = "";
- if (defaultPorts[request.scheme] !== request.port) {
- port = ":" + request.port;
- }
- return request.scheme + "://" + this.pretty_host(request) + port + request.path;
- }
-});
-
-var ResponseUtils = _.extend(_MessageUtils, {});
-function ListStore() {
- EventEmitter.call(this);
- this.reset();
-}
-_.extend(ListStore.prototype, EventEmitter.prototype, {
- add: function (elem) {
- if (elem.id in this._pos_map) {
- return;
- }
- this._pos_map[elem.id] = this.list.length;
- this.list.push(elem);
- this.emit("add", elem);
- },
- update: function (elem) {
- if (!(elem.id in this._pos_map)) {
- return;
- }
- this.list[this._pos_map[elem.id]] = elem;
- this.emit("update", elem);
- },
- remove: function (elem_id) {
- if (!(elem_id in this._pos_map)) {
- return;
- }
- this.list.splice(this._pos_map[elem_id], 1);
- this._build_map();
- this.emit("remove", elem_id);
- },
- reset: function (elems) {
- this.list = elems || [];
- this._build_map();
- this.emit("recalculate");
- },
- _build_map: function () {
- this._pos_map = {};
- for (var i = 0; i < this.list.length; i++) {
- var elem = this.list[i];
- this._pos_map[elem.id] = i;
- }
- },
- get: function (elem_id) {
- return this.list[this._pos_map[elem_id]];
- },
- index: function (elem_id) {
- return this._pos_map[elem_id];
- }
-});
-
-
-function DictStore() {
- EventEmitter.call(this);
- this.reset();
-}
-_.extend(DictStore.prototype, EventEmitter.prototype, {
- update: function (dict) {
- _.merge(this.dict, dict);
- this.emit("recalculate");
- },
- reset: function (dict) {
- this.dict = dict || {};
- this.emit("recalculate");
- }
-});
-
-function LiveStoreMixin(type) {
- this.type = type;
-
- this._updates_before_fetch = undefined;
- this._fetchxhr = false;
-
- this.handle = this.handle.bind(this);
- AppDispatcher.register(this.handle);
-
- // Avoid double-fetch on startup.
- if (!(window.ws && window.ws.readyState === WebSocket.CONNECTING)) {
- this.fetch();
- }
-}
-_.extend(LiveStoreMixin.prototype, {
- handle: function (event) {
- if (event.type === ActionTypes.CONNECTION_OPEN) {
- return this.fetch();
- }
- if (event.type === this.type) {
- if (event.cmd === StoreCmds.RESET) {
- this.fetch(event.data);
- } else if (this._updates_before_fetch) {
- console.log("defer update", event);
- this._updates_before_fetch.push(event);
- } else {
- this[event.cmd](event.data);
- }
- }
- },
- close: function () {
- AppDispatcher.unregister(this.handle);
- },
- fetch: function (data) {
- console.log("fetch " + this.type);
- if (this._fetchxhr) {
- this._fetchxhr.abort();
- }
- this._updates_before_fetch = []; // (JS: empty array is true)
- if (data) {
- this.handle_fetch(data);
- } else {
- this._fetchxhr = $.getJSON("/" + this.type)
- .done(function (message) {
- this.handle_fetch(message.data);
- }.bind(this))
- .fail(function () {
- EventLogActions.add_event("Could not fetch " + this.type);
- }.bind(this));
- }
- },
- handle_fetch: function (data) {
- this._fetchxhr = false;
- console.log(this.type + " fetched.", this._updates_before_fetch);
- this.reset(data);
- var updates = this._updates_before_fetch;
- this._updates_before_fetch = false;
- for (var i = 0; i < updates.length; i++) {
- this.handle(updates[i]);
- }
- },
-});
-
-function LiveListStore(type) {
- ListStore.call(this);
- LiveStoreMixin.call(this, type);
-}
-_.extend(LiveListStore.prototype, ListStore.prototype, LiveStoreMixin.prototype);
-
-function LiveDictStore(type) {
- DictStore.call(this);
- LiveStoreMixin.call(this, type);
-}
-_.extend(LiveDictStore.prototype, DictStore.prototype, LiveStoreMixin.prototype);
-
-
-function FlowStore() {
- return new LiveListStore(ActionTypes.FLOW_STORE);
-}
-
-function SettingsStore() {
- return new LiveDictStore(ActionTypes.SETTINGS_STORE);
-}
-
-function EventLogStore() {
- LiveListStore.call(this, ActionTypes.EVENT_STORE);
-}
-_.extend(EventLogStore.prototype, LiveListStore.prototype, {
- fetch: function(){
- LiveListStore.prototype.fetch.apply(this, arguments);
-
- // Make sure to display updates even if fetching all events failed.
- // This way, we can send "fetch failed" log messages to the log.
- if(this._fetchxhr){
- this._fetchxhr.fail(function(){
- this.handle_fetch(null);
- }.bind(this));
- }
- }
-});
-function SortByStoreOrder(elem) {
- return this.store.index(elem.id);
-}
-
-var default_sort = SortByStoreOrder;
-var default_filt = function(elem){
- return true;
-};
-
-function StoreView(store, filt, sortfun) {
- EventEmitter.call(this);
- filt = filt || default_filt;
- sortfun = sortfun || default_sort;
-
- this.store = store;
-
- this.add = this.add.bind(this);
- this.update = this.update.bind(this);
- this.remove = this.remove.bind(this);
- this.recalculate = this.recalculate.bind(this);
- this.store.addListener("add", this.add);
- this.store.addListener("update", this.update);
- this.store.addListener("remove", this.remove);
- this.store.addListener("recalculate", this.recalculate);
-
- this.recalculate(filt, sortfun);
-}
-
-_.extend(StoreView.prototype, EventEmitter.prototype, {
- close: function () {
- this.store.removeListener("add", this.add);
- this.store.removeListener("update", this.update);
- this.store.removeListener("remove", this.remove);
- this.store.removeListener("recalculate", this.recalculate);
- },
- recalculate: function (filt, sortfun) {
- if (filt) {
- this.filt = filt.bind(this);
- }
- if (sortfun) {
- this.sortfun = sortfun.bind(this);
- }
-
- this.list = this.store.list.filter(this.filt);
- this.list.sort(function (a, b) {
- return this.sortfun(a) - this.sortfun(b);
- }.bind(this));
- this.emit("recalculate");
- },
- index: function (elem) {
- return _.sortedIndex(this.list, elem, this.sortfun);
- },
- add: function (elem) {
- if (this.filt(elem)) {
- var idx = this.index(elem);
- if (idx === this.list.length) { //happens often, .push is way faster.
- this.list.push(elem);
- } else {
- this.list.splice(idx, 0, elem);
- }
- this.emit("add", elem, idx);
- }
- },
- update: function (elem) {
- var idx;
- var i = this.list.length;
- // Search from the back, we usually update the latest entries.
- while (i--) {
- if (this.list[i].id === elem.id) {
- idx = i;
- break;
- }
- }
-
- if (idx === -1) { //not contained in list
- this.add(elem);
- } else if (!this.filt(elem)) {
- this.remove(elem.id);
- } else {
- if (this.sortfun(this.list[idx]) !== this.sortfun(elem)) { //sortpos has changed
- this.remove(this.list[idx]);
- this.add(elem);
- } else {
- this.list[idx] = elem;
- this.emit("update", elem, idx);
- }
- }
- },
- remove: function (elem_id) {
- var idx = this.list.length;
- while (idx--) {
- if (this.list[idx].id === elem_id) {
- this.list.splice(idx, 1);
- this.emit("remove", elem_id, idx);
- break;
- }
- }
- }
-});
-function Connection(url) {
-
- if (url[0] === "/") {
- url = location.origin.replace("http", "ws") + url;
- }
-
- var ws = new WebSocket(url);
- ws.onopen = function () {
- ConnectionActions.open();
- };
- ws.onmessage = function (message) {
- var m = JSON.parse(message.data);
- AppDispatcher.dispatchServerAction(m);
- };
- ws.onerror = function () {
- ConnectionActions.error();
- EventLogActions.add_event("WebSocket connection error.");
- };
- ws.onclose = function () {
- ConnectionActions.close();
- EventLogActions.add_event("WebSocket connection closed.");
- };
- return ws;
-}
-//React utils. For other utilities, see ../utils.js
-
-// http://blog.vjeux.com/2013/javascript/scroll-position-with-react.html (also contains inverse example)
-var AutoScrollMixin = {
- componentWillUpdate: function () {
- var node = this.getDOMNode();
- this._shouldScrollBottom = (
- node.scrollTop !== 0 &&
- node.scrollTop + node.clientHeight === node.scrollHeight
- );
- },
- componentDidUpdate: function () {
- if (this._shouldScrollBottom) {
- var node = this.getDOMNode();
- node.scrollTop = node.scrollHeight;
- }
- },
-};
-
-
-var StickyHeadMixin = {
- adjustHead: function () {
- // Abusing CSS transforms to set the element
- // referenced as head into some kind of position:sticky.
- var head = this.refs.head.getDOMNode();
- head.style.transform = "translate(0," + this.getDOMNode().scrollTop + "px)";
- }
-};
-
-
-var Navigation = _.extend({}, ReactRouter.Navigation, {
- setQuery: function (dict) {
- var q = this.context.getCurrentQuery();
- for(var i in dict){
- if(dict.hasOwnProperty(i)){
- q[i] = dict[i] || undefined; //falsey values shall be removed.
- }
- }
- q._ = "_"; // workaround for https://github.com/rackt/react-router/pull/599
- this.replaceWith(this.context.getCurrentPath(), this.context.getCurrentParams(), q);
- },
- replaceWith: function(routeNameOrPath, params, query) {
- if(routeNameOrPath === undefined){
- routeNameOrPath = this.context.getCurrentPath();
- }
- if(params === undefined){
- params = this.context.getCurrentParams();
- }
- if(query === undefined){
- query = this.context.getCurrentQuery();
- }
- ReactRouter.Navigation.replaceWith.call(this, routeNameOrPath, params, query);
- }
-});
-_.extend(Navigation.contextTypes, ReactRouter.State.contextTypes);
-
-var State = _.extend({}, ReactRouter.State, {
- getInitialState: function () {
- this._query = this.context.getCurrentQuery();
- this._queryWatches = [];
- return null;
- },
- onQueryChange: function (key, callback) {
- this._queryWatches.push({
- key: key,
- callback: callback
- });
- },
- componentWillReceiveProps: function (nextProps, nextState) {
- var q = this.context.getCurrentQuery();
- for (var i = 0; i < this._queryWatches.length; i++) {
- var watch = this._queryWatches[i];
- if (this._query[watch.key] !== q[watch.key]) {
- watch.callback(this._query[watch.key], q[watch.key], watch.key);
- }
- }
- this._query = q;
- }
-});
-
-var Splitter = React.createClass({displayName: 'Splitter',
- getDefaultProps: function () {
- return {
- axis: "x"
- };
- },
- getInitialState: function () {
- return {
- applied: false,
- startX: false,
- startY: false
- };
- },
- onMouseDown: function (e) {
- this.setState({
- startX: e.pageX,
- startY: e.pageY
- });
- window.addEventListener("mousemove", this.onMouseMove);
- window.addEventListener("mouseup", this.onMouseUp);
- // Occasionally, only a dragEnd event is triggered, but no mouseUp.
- window.addEventListener("dragend", this.onDragEnd);
- },
- onDragEnd: function () {
- this.getDOMNode().style.transform = "";
- window.removeEventListener("dragend", this.onDragEnd);
- window.removeEventListener("mouseup", this.onMouseUp);
- window.removeEventListener("mousemove", this.onMouseMove);
- },
- onMouseUp: function (e) {
- this.onDragEnd();
-
- var node = this.getDOMNode();
- var prev = node.previousElementSibling;
- var next = node.nextElementSibling;
-
- var dX = e.pageX - this.state.startX;
- var dY = e.pageY - this.state.startY;
- var flexBasis;
- if (this.props.axis === "x") {
- flexBasis = prev.offsetWidth + dX;
- } else {
- flexBasis = prev.offsetHeight + dY;
- }
-
- prev.style.flex = "0 0 " + Math.max(0, flexBasis) + "px";
- next.style.flex = "1 1 auto";
-
- this.setState({
- applied: true
- });
- this.onResize();
- },
- onMouseMove: function (e) {
- var dX = 0, dY = 0;
- if (this.props.axis === "x") {
- dX = e.pageX - this.state.startX;
- } else {
- dY = e.pageY - this.state.startY;
- }
- this.getDOMNode().style.transform = "translate(" + dX + "px," + dY + "px)";
- },
- onResize: function () {
- // Trigger a global resize event. This notifies components that employ virtual scrolling
- // that their viewport may have changed.
- window.setTimeout(function () {
- window.dispatchEvent(new CustomEvent("resize"));
- }, 1);
- },
- reset: function (willUnmount) {
- if (!this.state.applied) {
- return;
- }
- var node = this.getDOMNode();
- var prev = node.previousElementSibling;
- var next = node.nextElementSibling;
-
- prev.style.flex = "";
- next.style.flex = "";
-
- if (!willUnmount) {
- this.setState({
- applied: false
- });
- }
- this.onResize();
- },
- componentWillUnmount: function () {
- this.reset(true);
- },
- render: function () {
- var className = "splitter";
- if (this.props.axis === "x") {
- className += " splitter-x";
- } else {
- className += " splitter-y";
- }
- return (
- React.createElement("div", {className: className},
- React.createElement("div", {onMouseDown: this.onMouseDown, draggable: "true"})
- )
- );
- }
-});
-var VirtualScrollMixin = {
- getInitialState: function () {
- return {
- start: 0,
- stop: 0
- };
- },
- componentWillMount: function () {
- if (!this.props.rowHeight) {
- console.warn("VirtualScrollMixin: No rowHeight specified", this);
- }
- },
- getPlaceholderTop: function (total) {
- var Tag = this.props.placeholderTagName || "tr";
- // When a large trunk of elements is removed from the button, start may be far off the viewport.
- // To make this issue less severe, limit the top placeholder to the total number of rows.
- var style = {
- height: Math.min(this.state.start, total) * this.props.rowHeight
- };
- var spacer = React.createElement(Tag, {key: "placeholder-top", style: style});
-
- if (this.state.start % 2 === 1) {
- // fix even/odd rows
- return [spacer, React.createElement(Tag, {key: "placeholder-top-2"})];
- } else {
- return spacer;
- }
- },
- getPlaceholderBottom: function (total) {
- var Tag = this.props.placeholderTagName || "tr";
- var style = {
- height: Math.max(0, total - this.state.stop) * this.props.rowHeight
- };
- return React.createElement(Tag, {key: "placeholder-bottom", style: style});
- },
- componentDidMount: function () {
- this.onScroll();
- window.addEventListener('resize', this.onScroll);
- },
- componentWillUnmount: function(){
- window.removeEventListener('resize', this.onScroll);
- },
- onScroll: function () {
- var viewport = this.getDOMNode();
- var top = viewport.scrollTop;
- var height = viewport.offsetHeight;
- var start = Math.floor(top / this.props.rowHeight);
- var stop = start + Math.ceil(height / (this.props.rowHeightMin || this.props.rowHeight));
-
- this.setState({
- start: start,
- stop: stop
- });
- },
- renderRows: function (elems) {
- var rows = [];
- var max = Math.min(elems.length, this.state.stop);
-
- for (var i = this.state.start; i < max; i++) {
- var elem = elems[i];
- rows.push(this.renderRow(elem));
- }
- return rows;
- },
- scrollRowIntoView: function (index, head_height) {
-
- var row_top = (index * this.props.rowHeight) + head_height;
- var row_bottom = row_top + this.props.rowHeight;
-
- var viewport = this.getDOMNode();
- var viewport_top = viewport.scrollTop;
- var viewport_bottom = viewport_top + viewport.offsetHeight;
-
- // Account for pinned thead
- if (row_top - head_height < viewport_top) {
- viewport.scrollTop = row_top - head_height;
- } else if (row_bottom > viewport_bottom) {
- viewport.scrollTop = row_bottom - viewport.offsetHeight;
- }
- },
-};
-var FilterDocs = React.createClass({displayName: 'FilterDocs',
- statics: {
- xhr: false,
- doc: false
- },
- componentWillMount: function () {
- if (!FilterDocs.doc) {
- FilterDocs.xhr = $.getJSON("/filter-help").done(function (doc) {
- FilterDocs.doc = doc;
- FilterDocs.xhr = false;
- });
- }
- if (FilterDocs.xhr) {
- FilterDocs.xhr.done(function () {
- this.forceUpdate();
- }.bind(this));
- }
- },
- render: function () {
- if (!FilterDocs.doc) {
- return React.createElement("i", {className: "fa fa-spinner fa-spin"});
- } else {
- var commands = FilterDocs.doc.commands.map(function (c) {
- return React.createElement("tr", null,
- React.createElement("td", null, c[0].replace(" ", '\u00a0')),
- React.createElement("td", null, c[1])
- );
- });
- commands.push(React.createElement("tr", null,
- React.createElement("td", {colSpan: "2"},
- React.createElement("a", {href: "https://mitmproxy.org/doc/features/filters.html",
- target: "_blank"},
- React.createElement("i", {className: "fa fa-external-link"}),
- "  mitmproxy docs")
- )
- ));
- return React.createElement("table", {className: "table table-condensed"},
- React.createElement("tbody", null, commands)
- );
- }
- }
-});
-var FilterInput = React.createClass({displayName: 'FilterInput',
- getInitialState: function () {
- // Consider both focus and mouseover for showing/hiding the tooltip,
- // because onBlur of the input is triggered before the click on the tooltip
- // finalized, hiding the tooltip just as the user clicks on it.
- return {
- value: this.props.value,
- focus: false,
- mousefocus: false
- };
- },
- componentWillReceiveProps: function (nextProps) {
- this.setState({value: nextProps.value});
- },
- onChange: function (e) {
- var nextValue = e.target.value;
- this.setState({
- value: nextValue
- });
- // Only propagate valid filters upwards.
- if (this.isValid(nextValue)) {
- this.props.onChange(nextValue);
- }
- },
- isValid: function (filt) {
- try {
- Filt.parse(filt || this.state.value);
- return true;
- } catch (e) {
- return false;
- }
- },
- getDesc: function () {
- var desc;
- try {
- desc = Filt.parse(this.state.value).desc;
- } catch (e) {
- desc = "" + e;
- }
- if (desc !== "true") {
- return desc;
- } else {
- return (
- React.createElement(FilterDocs, null)
- );
- }
- },
- onFocus: function () {
- this.setState({focus: true});
- },
- onBlur: function () {
- this.setState({focus: false});
- },
- onMouseEnter: function () {
- this.setState({mousefocus: true});
- },
- onMouseLeave: function () {
- this.setState({mousefocus: false});
- },
- onKeyDown: function (e) {
- if (e.keyCode === Key.ESC || e.keyCode === Key.ENTER) {
- this.blur();
- // If closed using ESC/ENTER, hide the tooltip.
- this.setState({mousefocus: false});
- }
- },
- blur: function () {
- this.refs.input.getDOMNode().blur();
- },
- focus: function () {
- this.refs.input.getDOMNode().select();
- },
- render: function () {
- var isValid = this.isValid();
- var icon = "fa fa-fw fa-" + this.props.type;
- var groupClassName = "filter-input input-group" + (isValid ? "" : " has-error");
-
- var popover;
- if (this.state.focus || this.state.mousefocus) {
- popover = (
- React.createElement("div", {className: "popover bottom", onMouseEnter: this.onMouseEnter, onMouseLeave: this.onMouseLeave},
- React.createElement("div", {className: "arrow"}),
- React.createElement("div", {className: "popover-content"},
- this.getDesc()
- )
- )
- );
- }
-
- return (
- React.createElement("div", {className: groupClassName},
- React.createElement("span", {className: "input-group-addon"},
- React.createElement("i", {className: icon, style: {color: this.props.color}})
- ),
- React.createElement("input", {type: "text", placeholder: this.props.placeholder, className: "form-control",
- ref: "input",
- onChange: this.onChange,
- onFocus: this.onFocus,
- onBlur: this.onBlur,
- onKeyDown: this.onKeyDown,
- value: this.state.value}),
- popover
- )
- );
- }
-});
-
-var MainMenu = React.createClass({displayName: 'MainMenu',
- mixins: [Navigation, State],
- statics: {
- title: "Start",
- route: "flows"
- },
- onFilterChange: function (val) {
- var d = {};
- d[Query.FILTER] = val;
- this.setQuery(d);
- },
- onHighlightChange: function (val) {
- var d = {};
- d[Query.HIGHLIGHT] = val;
- this.setQuery(d);
- },
- onInterceptChange: function (val) {
- SettingsActions.update({intercept: val});
- },
- render: function () {
- var filter = this.getQuery()[Query.FILTER] || "";
- var highlight = this.getQuery()[Query.HIGHLIGHT] || "";
- var intercept = this.props.settings.intercept || "";
-
- return (
- React.createElement("div", null,
- React.createElement("div", {className: "menu-row"},
- React.createElement(FilterInput, {
- placeholder: "Filter",
- type: "filter",
- color: "black",
- value: filter,
- onChange: this.onFilterChange}),
- React.createElement(FilterInput, {
- placeholder: "Highlight",
- type: "tag",
- color: "hsl(48, 100%, 50%)",
- value: highlight,
- onChange: this.onHighlightChange}),
- React.createElement(FilterInput, {
- placeholder: "Intercept",
- type: "pause",
- color: "hsl(208, 56%, 53%)",
- value: intercept,
- onChange: this.onInterceptChange})
- ),
- React.createElement("div", {className: "clearfix"})
- )
- );
- }
-});
-
-
-var ViewMenu = React.createClass({displayName: 'ViewMenu',
- statics: {
- title: "View",
- route: "flows"
- },
- mixins: [Navigation, State],
- toggleEventLog: function () {
- var d = {};
-
- if (this.getQuery()[Query.SHOW_EVENTLOG]) {
- d[Query.SHOW_EVENTLOG] = undefined;
- } else {
- d[Query.SHOW_EVENTLOG] = "t"; // any non-false value will do it, keep it short
- }
-
- this.setQuery(d);
- },
- render: function () {
- var showEventLog = this.getQuery()[Query.SHOW_EVENTLOG];
- return (
- React.createElement("div", null,
- React.createElement("button", {
- className: "btn " + (showEventLog ? "btn-primary" : "btn-default"),
- onClick: this.toggleEventLog},
- React.createElement("i", {className: "fa fa-database"}),
- " Show Eventlog"
- ),
- React.createElement("span", null, " ")
- )
- );
- }
-});
-
-
-var ReportsMenu = React.createClass({displayName: 'ReportsMenu',
- statics: {
- title: "Visualization",
- route: "reports"
- },
- render: function () {
- return React.createElement("div", null, "Reports Menu");
- }
-});
-
-var FileMenu = React.createClass({displayName: 'FileMenu',
- getInitialState: function () {
- return {
- showFileMenu: false
- };
- },
- handleFileClick: function (e) {
- e.preventDefault();
- if (!this.state.showFileMenu) {
- var close = function () {
- this.setState({showFileMenu: false});
- document.removeEventListener("click", close);
- }.bind(this);
- document.addEventListener("click", close);
-
- this.setState({
- showFileMenu: true
- });
- }
- },
- handleNewClick: function (e) {
- e.preventDefault();
- if (confirm("Delete all flows?")) {
- FlowActions.clear();
- }
- },
- handleOpenClick: function (e) {
- e.preventDefault();
- console.error("unimplemented: handleOpenClick");
- },
- handleSaveClick: function (e) {
- e.preventDefault();
- console.error("unimplemented: handleSaveClick");
- },
- handleShutdownClick: function (e) {
- e.preventDefault();
- console.error("unimplemented: handleShutdownClick");
- },
- render: function () {
- var fileMenuClass = "dropdown pull-left" + (this.state.showFileMenu ? " open" : "");
-
- return (
- React.createElement("div", {className: fileMenuClass},
- React.createElement("a", {href: "#", className: "special", onClick: this.handleFileClick}, " File "),
- React.createElement("ul", {className: "dropdown-menu", role: "menu"},
- React.createElement("li", null,
- React.createElement("a", {href: "#", onClick: this.handleNewClick},
- React.createElement("i", {className: "fa fa-fw fa-file"}),
- "New"
- )
- ),
- React.createElement("li", {role: "presentation", className: "divider"}),
- React.createElement("li", null,
- React.createElement("a", {href: "http://mitm.it/", target: "_blank"},
- React.createElement("i", {className: "fa fa-fw fa-external-link"}),
- "Install Certificates..."
- )
- )
- /*
- <li>
- <a href="#" onClick={this.handleOpenClick}>
- <i className="fa fa-fw fa-folder-open"></i>
- Open
- </a>
- </li>
- <li>
- <a href="#" onClick={this.handleSaveClick}>
- <i className="fa fa-fw fa-save"></i>
- Save
- </a>
- </li>
- <li role="presentation" className="divider"></li>
- <li>
- <a href="#" onClick={this.handleShutdownClick}>
- <i className="fa fa-fw fa-plug"></i>
- Shutdown
- </a>
- </li>
- */
- )
- )
- );
- }
-});
-
-
-var header_entries = [MainMenu, ViewMenu /*, ReportsMenu */];
-
-
-var Header = React.createClass({displayName: 'Header',
- mixins: [Navigation],
- getInitialState: function () {
- return {
- active: header_entries[0]
- };
- },
- handleClick: function (active, e) {
- e.preventDefault();
- this.replaceWith(active.route);
- this.setState({active: active});
- },
- render: function () {
- var header = header_entries.map(function (entry, i) {
- var classes = React.addons.classSet({
- active: entry == this.state.active
- });
- return (
- React.createElement("a", {key: i,
- href: "#",
- className: classes,
- onClick: this.handleClick.bind(this, entry)
- },
- entry.title
- )
- );
- }.bind(this));
-
- return (
- React.createElement("header", null,
- React.createElement("div", {className: "title-bar"},
- "mitmproxy ", this.props.settings.version
- ),
- React.createElement("nav", {className: "nav-tabs nav-tabs-lg"},
- React.createElement(FileMenu, null),
- header
- ),
- React.createElement("div", {className: "menu"},
- React.createElement(this.state.active, {settings: this.props.settings})
- )
- )
- );
- }
-});
-
-var TLSColumn = React.createClass({displayName: 'TLSColumn',
- statics: {
- renderTitle: function () {
- return React.createElement("th", {key: "tls", className: "col-tls"});
- }
- },
- render: function () {
- var flow = this.props.flow;
- var ssl = (flow.request.scheme == "https");
- var classes;
- if (ssl) {
- classes = "col-tls col-tls-https";
- } else {
- classes = "col-tls col-tls-http";
- }
- return React.createElement("td", {className: classes});
- }
-});
-
-
-var IconColumn = React.createClass({displayName: 'IconColumn',
- statics: {
- renderTitle: function () {
- return React.createElement("th", {key: "icon", className: "col-icon"});
- }
- },
- render: function () {
- var flow = this.props.flow;
-
- var icon;
- if (flow.response) {
- var contentType = ResponseUtils.getContentType(flow.response);
-
- //TODO: We should assign a type to the flow somewhere else.
- if (flow.response.code == 304) {
- icon = "resource-icon-not-modified";
- } else if (300 <= flow.response.code && flow.response.code < 400) {
- icon = "resource-icon-redirect";
- } else if (contentType && contentType.indexOf("image") >= 0) {
- icon = "resource-icon-image";
- } else if (contentType && contentType.indexOf("javascript") >= 0) {
- icon = "resource-icon-js";
- } else if (contentType && contentType.indexOf("css") >= 0) {
- icon = "resource-icon-css";
- } else if (contentType && contentType.indexOf("html") >= 0) {
- icon = "resource-icon-document";
- }
- }
- if (!icon) {
- icon = "resource-icon-plain";
- }
-
-
- icon += " resource-icon";
- return React.createElement("td", {className: "col-icon"},
- React.createElement("div", {className: icon})
- );
- }
-});
-
-var PathColumn = React.createClass({displayName: 'PathColumn',
- statics: {
- renderTitle: function () {
- return React.createElement("th", {key: "path", className: "col-path"}, "Path");
- }
- },
- render: function () {
- var flow = this.props.flow;
- return React.createElement("td", {className: "col-path"},
- flow.request.is_replay ? React.createElement("i", {className: "fa fa-fw fa-repeat pull-right"}) : null,
- flow.intercepted ? React.createElement("i", {className: "fa fa-fw fa-pause pull-right"}) : null,
- flow.request.scheme + "://" + flow.request.host + flow.request.path
- );
- }
-});
-
-
-var MethodColumn = React.createClass({displayName: 'MethodColumn',
- statics: {
- renderTitle: function () {
- return React.createElement("th", {key: "method", className: "col-method"}, "Method");
- }
- },
- render: function () {
- var flow = this.props.flow;
- return React.createElement("td", {className: "col-method"}, flow.request.method);
- }
-});
-
-
-var StatusColumn = React.createClass({displayName: 'StatusColumn',
- statics: {
- renderTitle: function () {
- return React.createElement("th", {key: "status", className: "col-status"}, "Status");
- }
- },
- render: function () {
- var flow = this.props.flow;
- var status;
- if (flow.response) {
- status = flow.response.code;
- } else {
- status = null;
- }
- return React.createElement("td", {className: "col-status"}, status);
- }
-});
-
-
-var SizeColumn = React.createClass({displayName: 'SizeColumn',
- statics: {
- renderTitle: function () {
- return React.createElement("th", {key: "size", className: "col-size"}, "Size");
- }
- },
- render: function () {
- var flow = this.props.flow;
-
- var total = flow.request.contentLength;
- if (flow.response) {
- total += flow.response.contentLength || 0;
- }
- var size = formatSize(total);
- return React.createElement("td", {className: "col-size"}, size);
- }
-});
-
-
-var TimeColumn = React.createClass({displayName: 'TimeColumn',
- statics: {
- renderTitle: function () {
- return React.createElement("th", {key: "time", className: "col-time"}, "Time");
- }
- },
- render: function () {
- var flow = this.props.flow;
- var time;
- if (flow.response) {
- time = formatTimeDelta(1000 * (flow.response.timestamp_end - flow.request.timestamp_start));
- } else {
- time = "...";
- }
- return React.createElement("td", {className: "col-time"}, time);
- }
-});
-
-
-var all_columns = [
- TLSColumn,
- IconColumn,
- PathColumn,
- MethodColumn,
- StatusColumn,
- SizeColumn,
- TimeColumn];
-
-
-var FlowRow = React.createClass({displayName: 'FlowRow',
- render: function () {
- var flow = this.props.flow;
- var columns = this.props.columns.map(function (Column) {
- return React.createElement(Column, {key: Column.displayName, flow: flow});
- }.bind(this));
- var className = "";
- if (this.props.selected) {
- className += " selected";
- }
- if (this.props.highlighted) {
- className += " highlighted";
- }
- if (flow.intercepted) {
- className += " intercepted";
- }
- if (flow.request) {
- className += " has-request";
- }
- if (flow.response) {
- className += " has-response";
- }
-
- return (
- React.createElement("tr", {className: className, onClick: this.props.selectFlow.bind(null, flow)},
- columns
- ));
- },
- shouldComponentUpdate: function (nextProps) {
- return true;
- // Further optimization could be done here
- // by calling forceUpdate on flow updates, selection changes and column changes.
- //return (
- //(this.props.columns.length !== nextProps.columns.length) ||
- //(this.props.selected !== nextProps.selected)
- //);
- }
-});
-
-var FlowTableHead = React.createClass({displayName: 'FlowTableHead',
- render: function () {
- var columns = this.props.columns.map(function (column) {
- return column.renderTitle();
- }.bind(this));
- return React.createElement("thead", null,
- React.createElement("tr", null, columns)
- );
- }
-});
-
-
-var ROW_HEIGHT = 32;
-
-var FlowTable = React.createClass({displayName: 'FlowTable',
- mixins: [StickyHeadMixin, AutoScrollMixin, VirtualScrollMixin],
- getInitialState: function () {
- return {
- columns: all_columns
- };
- },
- componentWillMount: function () {
- if (this.props.view) {
- this.props.view.addListener("add update remove recalculate", this.onChange);
- }
- },
- componentWillReceiveProps: function (nextProps) {
- if (nextProps.view !== this.props.view) {
- if (this.props.view) {
- this.props.view.removeListener("add update remove recalculate");
- }
- nextProps.view.addListener("add update remove recalculate", this.onChange);
- }
- },
- getDefaultProps: function () {
- return {
- rowHeight: ROW_HEIGHT
- };
- },
- onScrollFlowTable: function () {
- this.adjustHead();
- this.onScroll();
- },
- onChange: function () {
- this.forceUpdate();
- },
- scrollIntoView: function (flow) {
- this.scrollRowIntoView(
- this.props.view.index(flow),
- this.refs.body.getDOMNode().offsetTop
- );
- },
- renderRow: function (flow) {
- var selected = (flow === this.props.selected);
- var highlighted =
- (
- this.props.view._highlight &&
- this.props.view._highlight[flow.id]
- );
-
- return React.createElement(FlowRow, {key: flow.id,
- ref: flow.id,
- flow: flow,
- columns: this.state.columns,
- selected: selected,
- highlighted: highlighted,
- selectFlow: this.props.selectFlow}
- );
- },
- render: function () {
- //console.log("render flowtable", this.state.start, this.state.stop, this.props.selected);
- var flows = this.props.view ? this.props.view.list : [];
-
- var rows = this.renderRows(flows);
-
- return (
- React.createElement("div", {className: "flow-table", onScroll: this.onScrollFlowTable},
- React.createElement("table", null,
- React.createElement(FlowTableHead, {ref: "head",
- columns: this.state.columns}),
- React.createElement("tbody", {ref: "body"},
- this.getPlaceholderTop(flows.length),
- rows,
- this.getPlaceholderBottom(flows.length)
- )
- )
- )
- );
- }
-});
-
-var NavAction = React.createClass({displayName: 'NavAction',
- onClick: function (e) {
- e.preventDefault();
- this.props.onClick();
- },
- render: function () {
- return (
- React.createElement("a", {title: this.props.title,
- href: "#",
- className: "nav-action",
- onClick: this.onClick},
- React.createElement("i", {className: "fa fa-fw " + this.props.icon})
- )
- );
- }
-});
-
-var FlowDetailNav = React.createClass({displayName: 'FlowDetailNav',
- render: function () {
- var flow = this.props.flow;
-
- var tabs = this.props.tabs.map(function (e) {
- var str = e.charAt(0).toUpperCase() + e.slice(1);
- var className = this.props.active === e ? "active" : "";
- var onClick = function (event) {
- this.props.selectTab(e);
- event.preventDefault();
- }.bind(this);
- return React.createElement("a", {key: e,
- href: "#",
- className: className,
- onClick: onClick}, str);
- }.bind(this));
-
- var acceptButton = null;
- if(flow.intercepted){
- acceptButton = React.createElement(NavAction, {title: "[a]ccept intercepted flow", icon: "fa-play", onClick: FlowActions.accept.bind(null, flow)})
- }
- var revertButton = null;
- if(flow.modified){
- revertButton = React.createElement(NavAction, {title: "revert changes to flow [V]", icon: "fa-history", onClick: FlowActions.revert.bind(null, flow)})
- }
-
- return (
- React.createElement("nav", {ref: "head", className: "nav-tabs nav-tabs-sm"},
- tabs,
- React.createElement(NavAction, {title: "[d]elete flow", icon: "fa-trash", onClick: FlowActions.delete.bind(null, flow)}),
- React.createElement(NavAction, {title: "[D]uplicate flow", icon: "fa-copy", onClick: FlowActions.duplicate.bind(null, flow)}),
- React.createElement(NavAction, {disabled: true, title: "[r]eplay flow", icon: "fa-repeat", onClick: FlowActions.replay.bind(null, flow)}),
- acceptButton,
- revertButton
- )
- );
- }
-});
-
-var Headers = React.createClass({displayName: 'Headers',
- render: function () {
- var rows = this.props.message.headers.map(function (header, i) {
- return (
- React.createElement("tr", {key: i},
- React.createElement("td", {className: "header-name"}, header[0] + ":"),
- React.createElement("td", {className: "header-value"}, header[1])
- )
- );
- });
- return (
- React.createElement("table", {className: "header-table"},
- React.createElement("tbody", null,
- rows
- )
- )
- );
- }
-});
-
-var FlowDetailRequest = React.createClass({displayName: 'FlowDetailRequest',
- render: function () {
- var flow = this.props.flow;
- var first_line = [
- flow.request.method,
- RequestUtils.pretty_url(flow.request),
- "HTTP/" + flow.request.httpversion.join(".")
- ].join(" ");
- var content = null;
- if (flow.request.contentLength > 0) {
- content = "Request Content Size: " + formatSize(flow.request.contentLength);
- } else {
- content = React.createElement("div", {className: "alert alert-info"}, "No Content");
- }
-
- //TODO: Styling
-
- return (
- React.createElement("section", null,
- React.createElement("div", {className: "first-line"}, first_line ),
- React.createElement(Headers, {message: flow.request}),
- React.createElement("hr", null),
- content
- )
- );
- }
-});
-
-var FlowDetailResponse = React.createClass({displayName: 'FlowDetailResponse',
- render: function () {
- var flow = this.props.flow;
- var first_line = [
- "HTTP/" + flow.response.httpversion.join("."),
- flow.response.code,
- flow.response.msg
- ].join(" ");
- var content = null;
- if (flow.response.contentLength > 0) {
- content = "Response Content Size: " + formatSize(flow.response.contentLength);
- } else {
- content = React.createElement("div", {className: "alert alert-info"}, "No Content");
- }
-
- //TODO: Styling
-
- return (
- React.createElement("section", null,
- React.createElement("div", {className: "first-line"}, first_line ),
- React.createElement(Headers, {message: flow.response}),
- React.createElement("hr", null),
- content
- )
- );
- }
-});
-
-var FlowDetailError = React.createClass({displayName: 'FlowDetailError',
- render: function () {
- var flow = this.props.flow;
- return (
- React.createElement("section", null,
- React.createElement("div", {className: "alert alert-warning"},
- flow.error.msg,
- React.createElement("div", null,
- React.createElement("small", null, formatTimeStamp(flow.error.timestamp) )
- )
- )
- )
- );
- }
-});
-
-var TimeStamp = React.createClass({displayName: 'TimeStamp',
- render: function () {
-
- if (!this.props.t) {
- //should be return null, but that triggers a React bug.
- return React.createElement("tr", null);
- }
-
- var ts = formatTimeStamp(this.props.t);
-
- var delta;
- if (this.props.deltaTo) {
- delta = formatTimeDelta(1000 * (this.props.t - this.props.deltaTo));
- delta = React.createElement("span", {className: "text-muted"}, "(" + delta + ")");
- } else {
- delta = null;
- }
-
- return React.createElement("tr", null,
- React.createElement("td", null, this.props.title + ":"),
- React.createElement("td", null, ts, " ", delta)
- );
- }
-});
-
-var ConnectionInfo = React.createClass({displayName: 'ConnectionInfo',
-
- render: function () {
- var conn = this.props.conn;
- var address = conn.address.address.join(":");
-
- var sni = React.createElement("tr", {key: "sni"}); //should be null, but that triggers a React bug.
- if (conn.sni) {
- sni = React.createElement("tr", {key: "sni"},
- React.createElement("td", null,
- React.createElement("abbr", {title: "TLS Server Name Indication"}, "TLS SNI:")
- ),
- React.createElement("td", null, conn.sni)
- );
- }
- return (
- React.createElement("table", {className: "connection-table"},
- React.createElement("tbody", null,
- React.createElement("tr", {key: "address"},
- React.createElement("td", null, "Address:"),
- React.createElement("td", null, address)
- ),
- sni
- )
- )
- );
- }
-});
-
-var CertificateInfo = React.createClass({displayName: 'CertificateInfo',
- render: function () {
- //TODO: We should fetch human-readable certificate representation
- // from the server
- var flow = this.props.flow;
- var client_conn = flow.client_conn;
- var server_conn = flow.server_conn;
-
- var preStyle = {maxHeight: 100};
- return (
- React.createElement("div", null,
- client_conn.cert ? React.createElement("h4", null, "Client Certificate") : null,
- client_conn.cert ? React.createElement("pre", {style: preStyle}, client_conn.cert) : null,
-
- server_conn.cert ? React.createElement("h4", null, "Server Certificate") : null,
- server_conn.cert ? React.createElement("pre", {style: preStyle}, server_conn.cert) : null
- )
- );
- }
-});
-
-var Timing = React.createClass({displayName: 'Timing',
- render: function () {
- var flow = this.props.flow;
- var sc = flow.server_conn;
- var cc = flow.client_conn;
- var req = flow.request;
- var resp = flow.response;
-
- var timestamps = [
- {
- title: "Server conn. initiated",
- t: sc.timestamp_start,
- deltaTo: req.timestamp_start
- }, {
- title: "Server conn. TCP handshake",
- t: sc.timestamp_tcp_setup,
- deltaTo: req.timestamp_start
- }, {
- title: "Server conn. SSL handshake",
- t: sc.timestamp_ssl_setup,
- deltaTo: req.timestamp_start
- }, {
- title: "Client conn. established",
- t: cc.timestamp_start,
- deltaTo: req.timestamp_start
- }, {
- title: "Client conn. SSL handshake",
- t: cc.timestamp_ssl_setup,
- deltaTo: req.timestamp_start
- }, {
- title: "First request byte",
- t: req.timestamp_start,
- }, {
- title: "Request complete",
- t: req.timestamp_end,
- deltaTo: req.timestamp_start
- }
- ];
-
- if (flow.response) {
- timestamps.push(
- {
- title: "First response byte",
- t: resp.timestamp_start,
- deltaTo: req.timestamp_start
- }, {
- title: "Response complete",
- t: resp.timestamp_end,
- deltaTo: req.timestamp_start
- }
- );
- }
-
- //Add unique key for each row.
- timestamps.forEach(function (e) {
- e.key = e.title;
- });
-
- timestamps = _.sortBy(timestamps, 't');
-
- var rows = timestamps.map(function (e) {
- return React.createElement(TimeStamp, React.__spread({}, e));
- });
-
- return (
- React.createElement("div", null,
- React.createElement("h4", null, "Timing"),
- React.createElement("table", {className: "timing-table"},
- React.createElement("tbody", null,
- rows
- )
- )
- )
- );
- }
-});
-
-var FlowDetailConnectionInfo = React.createClass({displayName: 'FlowDetailConnectionInfo',
- render: function () {
- var flow = this.props.flow;
- var client_conn = flow.client_conn;
- var server_conn = flow.server_conn;
- return (
- React.createElement("section", null,
-
- React.createElement("h4", null, "Client Connection"),
- React.createElement(ConnectionInfo, {conn: client_conn}),
-
- React.createElement("h4", null, "Server Connection"),
- React.createElement(ConnectionInfo, {conn: server_conn}),
-
- React.createElement(CertificateInfo, {flow: flow}),
-
- React.createElement(Timing, {flow: flow})
-
- )
- );
- }
-});
-
-var allTabs = {
- request: FlowDetailRequest,
- response: FlowDetailResponse,
- error: FlowDetailError,
- details: FlowDetailConnectionInfo
-};
-
-var FlowDetail = React.createClass({displayName: 'FlowDetail',
- mixins: [StickyHeadMixin, Navigation, State],
- getTabs: function (flow) {
- var tabs = [];
- ["request", "response", "error"].forEach(function (e) {
- if (flow[e]) {
- tabs.push(e);
- }
- });
- tabs.push("details");
- return tabs;
- },
- nextTab: function (i) {
- var tabs = this.getTabs(this.props.flow);
- var currentIndex = tabs.indexOf(this.getParams().detailTab);
- // JS modulo operator doesn't correct negative numbers, make sure that we are positive.
- var nextIndex = (currentIndex + i + tabs.length) % tabs.length;
- this.selectTab(tabs[nextIndex]);
- },
- selectTab: function (panel) {
- this.replaceWith(
- "flow",
- {
- flowId: this.getParams().flowId,
- detailTab: panel
- }
- );
- },
- render: function () {
- var flow = this.props.flow;
- var tabs = this.getTabs(flow);
- var active = this.getParams().detailTab;
-
- if (!_.contains(tabs, active)) {
- if (active === "response" && flow.error) {
- active = "error";
- } else if (active === "error" && flow.response) {
- active = "response";
- } else {
- active = tabs[0];
- }
- this.selectTab(active);
- }
-
- var Tab = allTabs[active];
- return (
- React.createElement("div", {className: "flow-detail", onScroll: this.adjustHead},
- React.createElement(FlowDetailNav, {ref: "head",
- flow: flow,
- tabs: tabs,
- active: active,
- selectTab: this.selectTab}),
- React.createElement(Tab, {flow: flow})
- )
- );
- }
-});
-var MainView = React.createClass({displayName: 'MainView',
- mixins: [Navigation, State],
- getInitialState: function () {
- this.onQueryChange(Query.FILTER, function () {
- this.state.view.recalculate(this.getViewFilt(), this.getViewSort());
- }.bind(this));
- this.onQueryChange(Query.HIGHLIGHT, function () {
- this.state.view.recalculate(this.getViewFilt(), this.getViewSort());
- }.bind(this));
- return {
- flows: []
- };
- },
- getViewFilt: function () {
- try {
- var filt = Filt.parse(this.getQuery()[Query.FILTER] || "");
- var highlightStr = this.getQuery()[Query.HIGHLIGHT];
- var highlight = highlightStr ? Filt.parse(highlightStr) : false;
- } catch (e) {
- console.error("Error when processing filter: " + e);
- }
-
- return function filter_and_highlight(flow) {
- if (!this._highlight) {
- this._highlight = {};
- }
- this._highlight[flow.id] = highlight && highlight(flow);
- return filt(flow);
- };
- },
- getViewSort: function () {
- },
- componentWillReceiveProps: function (nextProps) {
- if (nextProps.flowStore !== this.props.flowStore) {
- this.closeView();
- this.openView(nextProps.flowStore);
- }
- },
- openView: function (store) {
- var view = new StoreView(store, this.getViewFilt(), this.getViewSort());
- this.setState({
- view: view
- });
-
- view.addListener("recalculate", this.onRecalculate);
- view.addListener("add update remove", this.onUpdate);
- view.addListener("remove", this.onRemove);
- },
- onRecalculate: function () {
- this.forceUpdate();
- var selected = this.getSelected();
- if (selected) {
- this.refs.flowTable.scrollIntoView(selected);
- }
- },
- onUpdate: function (flow) {
- if (flow.id === this.getParams().flowId) {
- this.forceUpdate();
- }
- },
- onRemove: function (flow_id, index) {
- if (flow_id === this.getParams().flowId) {
- var flow_to_select = this.state.view.list[Math.min(index, this.state.view.list.length -1)];
- this.selectFlow(flow_to_select);
- }
- },
- closeView: function () {
- this.state.view.close();
- },
- componentWillMount: function () {
- this.openView(this.props.flowStore);
- },
- componentWillUnmount: function () {
- this.closeView();
- },
- selectFlow: function (flow) {
- if (flow) {
- this.replaceWith(
- "flow",
- {
- flowId: flow.id,
- detailTab: this.getParams().detailTab || "request"
- }
- );
- this.refs.flowTable.scrollIntoView(flow);
- } else {
- this.replaceWith("flows", {});
- }
- },
- selectFlowRelative: function (shift) {
- var flows = this.state.view.list;
- var index;
- if (!this.getParams().flowId) {
- if (shift > 0) {
- index = flows.length - 1;
- } else {
- index = 0;
- }
- } else {
- var currFlowId = this.getParams().flowId;
- var i = flows.length;
- while (i--) {
- if (flows[i].id === currFlowId) {
- index = i;
- break;
- }
- }
- index = Math.min(
- Math.max(0, index + shift),
- flows.length - 1);
- }
- this.selectFlow(flows[index]);
- },
- onKeyDown: function (e) {
- var flow = this.getSelected();
- if (e.ctrlKey) {
- return;
- }
- switch (e.keyCode) {
- case Key.K:
- case Key.UP:
- this.selectFlowRelative(-1);
- break;
- case Key.J:
- case Key.DOWN:
- this.selectFlowRelative(+1);
- break;
- case Key.SPACE:
- case Key.PAGE_DOWN:
- this.selectFlowRelative(+10);
- break;
- case Key.PAGE_UP:
- this.selectFlowRelative(-10);
- break;
- case Key.END:
- this.selectFlowRelative(+1e10);
- break;
- case Key.HOME:
- this.selectFlowRelative(-1e10);
- break;
- case Key.ESC:
- this.selectFlow(null);
- break;
- case Key.H:
- case Key.LEFT:
- if (this.refs.flowDetails) {
- this.refs.flowDetails.nextTab(-1);
- }
- break;
- case Key.L:
- case Key.TAB:
- case Key.RIGHT:
- if (this.refs.flowDetails) {
- this.refs.flowDetails.nextTab(+1);
- }
- break;
- case Key.C:
- if (e.shiftKey) {
- FlowActions.clear();
- }
- break;
- case Key.D:
- if (flow) {
- if (e.shiftKey) {
- FlowActions.duplicate(flow);
- } else {
- FlowActions.delete(flow);
- }
- }
- break;
- case Key.A:
- if (e.shiftKey) {
- FlowActions.accept_all();
- } else if (flow && flow.intercepted) {
- FlowActions.accept(flow);
- }
- break;
- case Key.R:
- if (!e.shiftKey && flow) {
- FlowActions.replay(flow);
- }
- break;
- case Key.V:
- if(e.shiftKey && flow && flow.modified) {
- FlowActions.revert(flow);
- }
- break;
- default:
- console.debug("keydown", e.keyCode);
- return;
- }
- e.preventDefault();
- },
- getSelected: function () {
- return this.props.flowStore.get(this.getParams().flowId);
- },
- render: function () {
- var selected = this.getSelected();
-
- var details;
- if (selected) {
- details = [
- React.createElement(Splitter, {key: "splitter"}),
- React.createElement(FlowDetail, {key: "flowDetails", ref: "flowDetails", flow: selected})
- ];
- } else {
- details = null;
- }
-
- return (
- React.createElement("div", {className: "main-view", onKeyDown: this.onKeyDown, tabIndex: "0"},
- React.createElement(FlowTable, {ref: "flowTable",
- view: this.state.view,
- selectFlow: this.selectFlow,
- selected: selected}),
- details
- )
- );
- }
-});
-var LogMessage = React.createClass({displayName: 'LogMessage',
- render: function () {
- var entry = this.props.entry;
- var indicator;
- switch (entry.level) {
- case "web":
- indicator = React.createElement("i", {className: "fa fa-fw fa-html5"});
- break;
- case "debug":
- indicator = React.createElement("i", {className: "fa fa-fw fa-bug"});
- break;
- default:
- indicator = React.createElement("i", {className: "fa fa-fw fa-info"});
- }
- return (
- React.createElement("div", null,
- indicator, " ", entry.message
- )
- );
- },
- shouldComponentUpdate: function () {
- return false; // log entries are immutable.
- }
-});
-
-var EventLogContents = React.createClass({displayName: 'EventLogContents',
- mixins: [AutoScrollMixin, VirtualScrollMixin],
- getInitialState: function () {
- return {
- log: []
- };
- },
- componentWillMount: function () {
- this.openView(this.props.eventStore);
- },
- componentWillUnmount: function () {
- this.closeView();
- },
- openView: function (store) {
- var view = new StoreView(store, function (entry) {
- return this.props.filter[entry.level];
- }.bind(this));
- this.setState({
- view: view
- });
-
- view.addListener("add recalculate", this.onEventLogChange);
- },
- closeView: function () {
- this.state.view.close();
- },
- onEventLogChange: function () {
- this.setState({
- log: this.state.view.list
- });
- },
- componentWillReceiveProps: function (nextProps) {
- if (nextProps.filter !== this.props.filter) {
- this.props.filter = nextProps.filter; // Dirty: Make sure that view filter sees the update.
- this.state.view.recalculate();
- }
- if (nextProps.eventStore !== this.props.eventStore) {
- this.closeView();
- this.openView(nextProps.eventStore);
- }
- },
- getDefaultProps: function () {
- return {
- rowHeight: 45,
- rowHeightMin: 15,
- placeholderTagName: "div"
- };
- },
- renderRow: function (elem) {
- return React.createElement(LogMessage, {key: elem.id, entry: elem});
- },
- render: function () {
- var rows = this.renderRows(this.state.log);
-
- return React.createElement("pre", {onScroll: this.onScroll},
- this.getPlaceholderTop(this.state.log.length),
- rows,
- this.getPlaceholderBottom(this.state.log.length)
- );
- }
-});
-
-var ToggleFilter = React.createClass({displayName: 'ToggleFilter',
- toggle: function (e) {
- e.preventDefault();
- return this.props.toggleLevel(this.props.name);
- },
- render: function () {
- var className = "label ";
- if (this.props.active) {
- className += "label-primary";
- } else {
- className += "label-default";
- }
- return (
- React.createElement("a", {
- href: "#",
- className: className,
- onClick: this.toggle},
- this.props.name
- )
- );
- }
-});
-
-var EventLog = React.createClass({displayName: 'EventLog',
- getInitialState: function () {
- return {
- filter: {
- "debug": false,
- "info": true,
- "web": true
- }
- };
- },
- close: function () {
- var d = {};
- d[Query.SHOW_EVENTLOG] = undefined;
- this.setQuery(d);
- },
- toggleLevel: function (level) {
- var filter = _.extend({}, this.state.filter);
- filter[level] = !filter[level];
- this.setState({filter: filter});
- },
- render: function () {
- return (
- React.createElement("div", {className: "eventlog"},
- React.createElement("div", null,
- "Eventlog",
- React.createElement("div", {className: "pull-right"},
- React.createElement(ToggleFilter, {name: "debug", active: this.state.filter.debug, toggleLevel: this.toggleLevel}),
- React.createElement(ToggleFilter, {name: "info", active: this.state.filter.info, toggleLevel: this.toggleLevel}),
- React.createElement(ToggleFilter, {name: "web", active: this.state.filter.web, toggleLevel: this.toggleLevel}),
- React.createElement("i", {onClick: this.close, className: "fa fa-close"})
- )
-
- ),
- React.createElement(EventLogContents, {filter: this.state.filter, eventStore: this.props.eventStore})
- )
- );
- }
-});
-var Footer = React.createClass({displayName: 'Footer',
- render: function () {
- var mode = this.props.settings.mode;
- var intercept = this.props.settings.intercept;
- return (
- React.createElement("footer", null,
- mode != "regular" ? React.createElement("span", {className: "label label-success"}, mode, " mode") : null,
- " ",
- intercept ? React.createElement("span", {className: "label label-success"}, "Intercept: ", intercept) : null
- )
- );
- }
-});
-
-//TODO: Move out of here, just a stub.
-var Reports = React.createClass({displayName: 'Reports',
- render: function () {
- return React.createElement("div", null, "ReportEditor");
- }
-});
-
-
-var ProxyAppMain = React.createClass({displayName: 'ProxyAppMain',
- mixins: [State],
- getInitialState: function () {
- var eventStore = new EventLogStore();
- var flowStore = new FlowStore();
- var settings = new SettingsStore();
-
- // Default Settings before fetch
- _.extend(settings.dict,{
- });
- return {
- settings: settings,
- flowStore: flowStore,
- eventStore: eventStore
- };
- },
- componentDidMount: function () {
- this.state.settings.addListener("recalculate", this.onSettingsChange);
- window.app = this;
- },
- componentWillUnmount: function () {
- this.state.settings.removeListener("recalculate", this.onSettingsChange);
- },
- onSettingsChange: function(){
- this.setState({
- settings: this.state.settings
- });
- },
- render: function () {
-
- var eventlog;
- if (this.getQuery()[Query.SHOW_EVENTLOG]) {
- eventlog = [
- React.createElement(Splitter, {key: "splitter", axis: "y"}),
- React.createElement(EventLog, {key: "eventlog", eventStore: this.state.eventStore})
- ];
- } else {
- eventlog = null;
- }
-
- return (
- React.createElement("div", {id: "container"},
- React.createElement(Header, {settings: this.state.settings.dict}),
- React.createElement(RouteHandler, {settings: this.state.settings.dict, flowStore: this.state.flowStore}),
- eventlog,
- React.createElement(Footer, {settings: this.state.settings.dict})
- )
- );
- }
-});
-
-
-var Route = ReactRouter.Route;
-var RouteHandler = ReactRouter.RouteHandler;
-var Redirect = ReactRouter.Redirect;
-var DefaultRoute = ReactRouter.DefaultRoute;
-var NotFoundRoute = ReactRouter.NotFoundRoute;
-
-
-var routes = (
- React.createElement(Route, {path: "/", handler: ProxyAppMain},
- React.createElement(Route, {name: "flows", path: "flows", handler: MainView}),
- React.createElement(Route, {name: "flow", path: "flows/:flowId/:detailTab", handler: MainView}),
- React.createElement(Route, {name: "reports", handler: Reports}),
- React.createElement(Redirect, {path: "/", to: "flows"})
- )
-);
-$(function () {
- window.ws = new Connection("/updates");
-
- ReactRouter.run(routes, function (Handler) {
- React.render(React.createElement(Handler, null), document.body);
- });
-});
-//# sourceMappingURL=app.js.map \ No newline at end of file
diff --git a/libmproxy/web/static/js/vendor.js b/libmproxy/web/static/js/vendor.js
deleted file mode 100644
index 7d65bd88..00000000
--- a/libmproxy/web/static/js/vendor.js
+++ /dev/null
@@ -1,39553 +0,0 @@
-/*!
- * jQuery JavaScript Library v2.1.1
- * http://jquery.com/
- *
- * Includes Sizzle.js
- * http://sizzlejs.com/
- *
- * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors
- * Released under the MIT license
- * http://jquery.org/license
- *
- * Date: 2014-05-01T17:11Z
- */
-
-(function( global, factory ) {
-
- if ( typeof module === "object" && typeof module.exports === "object" ) {
- // For CommonJS and CommonJS-like environments where a proper window is present,
- // execute the factory and get jQuery
- // For environments that do not inherently posses a window with a document
- // (such as Node.js), expose a jQuery-making factory as module.exports
- // This accentuates the need for the creation of a real window
- // e.g. var jQuery = require("jquery")(window);
- // See ticket #14549 for more info
- module.exports = global.document ?
- factory( global, true ) :
- function( w ) {
- if ( !w.document ) {
- throw new Error( "jQuery requires a window with a document" );
- }
- return factory( w );
- };
- } else {
- factory( global );
- }
-
-// Pass this if window is not defined yet
-}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
-
-// Can't do this because several apps including ASP.NET trace
-// the stack via arguments.caller.callee and Firefox dies if
-// you try to trace through "use strict" call chains. (#13335)
-// Support: Firefox 18+
-//
-
-var arr = [];
-
-var slice = arr.slice;
-
-var concat = arr.concat;
-
-var push = arr.push;
-
-var indexOf = arr.indexOf;
-
-var class2type = {};
-
-var toString = class2type.toString;
-
-var hasOwn = class2type.hasOwnProperty;
-
-var support = {};
-
-
-
-var
- // Use the correct document accordingly with window argument (sandbox)
- document = window.document,
-
- version = "2.1.1",
-
- // Define a local copy of jQuery
- jQuery = function( selector, context ) {
- // The jQuery object is actually just the init constructor 'enhanced'
- // Need init if jQuery is called (just allow error to be thrown if not included)
- return new jQuery.fn.init( selector, context );
- },
-
- // Support: Android<4.1
- // Make sure we trim BOM and NBSP
- rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
-
- // Matches dashed string for camelizing
- rmsPrefix = /^-ms-/,
- rdashAlpha = /-([\da-z])/gi,
-
- // Used by jQuery.camelCase as callback to replace()
- fcamelCase = function( all, letter ) {
- return letter.toUpperCase();
- };
-
-jQuery.fn = jQuery.prototype = {
- // The current version of jQuery being used
- jquery: version,
-
- constructor: jQuery,
-
- // Start with an empty selector
- selector: "",
-
- // The default length of a jQuery object is 0
- length: 0,
-
- toArray: function() {
- return slice.call( this );
- },
-
- // Get the Nth element in the matched element set OR
- // Get the whole matched element set as a clean array
- get: function( num ) {
- return num != null ?
-
- // Return just the one element from the set
- ( num < 0 ? this[ num + this.length ] : this[ num ] ) :
-
- // Return all the elements in a clean array
- slice.call( this );
- },
-
- // Take an array of elements and push it onto the stack
- // (returning the new matched element set)
- pushStack: function( elems ) {
-
- // Build a new jQuery matched element set
- var ret = jQuery.merge( this.constructor(), elems );
-
- // Add the old object onto the stack (as a reference)
- ret.prevObject = this;
- ret.context = this.context;
-
- // Return the newly-formed element set
- return ret;
- },
-
- // Execute a callback for every element in the matched set.
- // (You can seed the arguments with an array of args, but this is
- // only used internally.)
- each: function( callback, args ) {
- return jQuery.each( this, callback, args );
- },
-
- map: function( callback ) {
- return this.pushStack( jQuery.map(this, function( elem, i ) {
- return callback.call( elem, i, elem );
- }));
- },
-
- slice: function() {
- return this.pushStack( slice.apply( this, arguments ) );
- },
-
- first: function() {
- return this.eq( 0 );
- },
-
- last: function() {
- return this.eq( -1 );
- },
-
- eq: function( i ) {
- var len = this.length,
- j = +i + ( i < 0 ? len : 0 );
- return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
- },
-
- end: function() {
- return this.prevObject || this.constructor(null);
- },
-
- // For internal use only.
- // Behaves like an Array's method, not like a jQuery method.
- push: push,
- sort: arr.sort,
- splice: arr.splice
-};
-
-jQuery.extend = jQuery.fn.extend = function() {
- var options, name, src, copy, copyIsArray, clone,
- target = arguments[0] || {},
- i = 1,
- length = arguments.length,
- deep = false;
-
- // Handle a deep copy situation
- if ( typeof target === "boolean" ) {
- deep = target;
-
- // skip the boolean and the target
- target = arguments[ i ] || {};
- i++;
- }
-
- // Handle case when target is a string or something (possible in deep copy)
- if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
- target = {};
- }
-
- // extend jQuery itself if only one argument is passed
- if ( i === length ) {
- target = this;
- i--;
- }
-
- for ( ; i < length; i++ ) {
- // Only deal with non-null/undefined values
- if ( (options = arguments[ i ]) != null ) {
- // Extend the base object
- for ( name in options ) {
- src = target[ name ];
- copy = options[ name ];
-
- // Prevent never-ending loop
- if ( target === copy ) {
- continue;
- }
-
- // Recurse if we're merging plain objects or arrays
- if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
- if ( copyIsArray ) {
- copyIsArray = false;
- clone = src && jQuery.isArray(src) ? src : [];
-
- } else {
- clone = src && jQuery.isPlainObject(src) ? src : {};
- }
-
- // Never move original objects, clone them
- target[ name ] = jQuery.extend( deep, clone, copy );
-
- // Don't bring in undefined values
- } else if ( copy !== undefined ) {
- target[ name ] = copy;
- }
- }
- }
- }
-
- // Return the modified object
- return target;
-};
-
-jQuery.extend({
- // Unique for each copy of jQuery on the page
- expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
-
- // Assume jQuery is ready without the ready module
- isReady: true,
-
- error: function( msg ) {
- throw new Error( msg );
- },
-
- noop: function() {},
-
- // See test/unit/core.js for details concerning isFunction.
- // Since version 1.3, DOM methods and functions like alert
- // aren't supported. They return false on IE (#2968).
- isFunction: function( obj ) {
- return jQuery.type(obj) === "function";
- },
-
- isArray: Array.isArray,
-
- isWindow: function( obj ) {
- return obj != null && obj === obj.window;
- },
-
- isNumeric: function( obj ) {
- // parseFloat NaNs numeric-cast false positives (null|true|false|"")
- // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
- // subtraction forces infinities to NaN
- return !jQuery.isArray( obj ) && obj - parseFloat( obj ) >= 0;
- },
-
- isPlainObject: function( obj ) {
- // Not plain objects:
- // - Any object or value whose internal [[Class]] property is not "[object Object]"
- // - DOM nodes
- // - window
- if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
- return false;
- }
-
- if ( obj.constructor &&
- !hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
- return false;
- }
-
- // If the function hasn't returned already, we're confident that
- // |obj| is a plain object, created by {} or constructed with new Object
- return true;
- },
-
- isEmptyObject: function( obj ) {
- var name;
- for ( name in obj ) {
- return false;
- }
- return true;
- },
-
- type: function( obj ) {
- if ( obj == null ) {
- return obj + "";
- }
- // Support: Android < 4.0, iOS < 6 (functionish RegExp)
- return typeof obj === "object" || typeof obj === "function" ?
- class2type[ toString.call(obj) ] || "object" :
- typeof obj;
- },
-
- // Evaluates a script in a global context
- globalEval: function( code ) {
- var script,
- indirect = eval;
-
- code = jQuery.trim( code );
-
- if ( code ) {
- // If the code includes a valid, prologue position
- // strict mode pragma, execute code by injecting a
- // script tag into the document.
- if ( code.indexOf("use strict") === 1 ) {
- script = document.createElement("script");
- script.text = code;
- document.head.appendChild( script ).parentNode.removeChild( script );
- } else {
- // Otherwise, avoid the DOM node creation, insertion
- // and removal by using an indirect global eval
- indirect( code );
- }
- }
- },
-
- // Convert dashed to camelCase; used by the css and data modules
- // Microsoft forgot to hump their vendor prefix (#9572)
- camelCase: function( string ) {
- return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
- },
-
- nodeName: function( elem, name ) {
- return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
- },
-
- // args is for internal usage only
- each: function( obj, callback, args ) {
- var value,
- i = 0,
- length = obj.length,
- isArray = isArraylike( obj );
-
- if ( args ) {
- if ( isArray ) {
- for ( ; i < length; i++ ) {
- value = callback.apply( obj[ i ], args );
-
- if ( value === false ) {
- break;
- }
- }
- } else {
- for ( i in obj ) {
- value = callback.apply( obj[ i ], args );
-
- if ( value === false ) {
- break;
- }
- }
- }
-
- // A special, fast, case for the most common use of each
- } else {
- if ( isArray ) {
- for ( ; i < length; i++ ) {
- value = callback.call( obj[ i ], i, obj[ i ] );
-
- if ( value === false ) {
- break;
- }
- }
- } else {
- for ( i in obj ) {
- value = callback.call( obj[ i ], i, obj[ i ] );
-
- if ( value === false ) {
- break;
- }
- }
- }
- }
-
- return obj;
- },
-
- // Support: Android<4.1
- trim: function( text ) {
- return text == null ?
- "" :
- ( text + "" ).replace( rtrim, "" );
- },
-
- // results is for internal usage only
- makeArray: function( arr, results ) {
- var ret = results || [];
-
- if ( arr != null ) {
- if ( isArraylike( Object(arr) ) ) {
- jQuery.merge( ret,
- typeof arr === "string" ?
- [ arr ] : arr
- );
- } else {
- push.call( ret, arr );
- }
- }
-
- return ret;
- },
-
- inArray: function( elem, arr, i ) {
- return arr == null ? -1 : indexOf.call( arr, elem, i );
- },
-
- merge: function( first, second ) {
- var len = +second.length,
- j = 0,
- i = first.length;
-
- for ( ; j < len; j++ ) {
- first[ i++ ] = second[ j ];
- }
-
- first.length = i;
-
- return first;
- },
-
- grep: function( elems, callback, invert ) {
- var callbackInverse,
- matches = [],
- i = 0,
- length = elems.length,
- callbackExpect = !invert;
-
- // Go through the array, only saving the items
- // that pass the validator function
- for ( ; i < length; i++ ) {
- callbackInverse = !callback( elems[ i ], i );
- if ( callbackInverse !== callbackExpect ) {
- matches.push( elems[ i ] );
- }
- }
-
- return matches;
- },
-
- // arg is for internal usage only
- map: function( elems, callback, arg ) {
- var value,
- i = 0,
- length = elems.length,
- isArray = isArraylike( elems ),
- ret = [];
-
- // Go through the array, translating each of the items to their new values
- if ( isArray ) {
- for ( ; i < length; i++ ) {
- value = callback( elems[ i ], i, arg );
-
- if ( value != null ) {
- ret.push( value );
- }
- }
-
- // Go through every key on the object,
- } else {
- for ( i in elems ) {
- value = callback( elems[ i ], i, arg );
-
- if ( value != null ) {
- ret.push( value );
- }
- }
- }
-
- // Flatten any nested arrays
- return concat.apply( [], ret );
- },
-
- // A global GUID counter for objects
- guid: 1,
-
- // Bind a function to a context, optionally partially applying any
- // arguments.
- proxy: function( fn, context ) {
- var tmp, args, proxy;
-
- if ( typeof context === "string" ) {
- tmp = fn[ context ];
- context = fn;
- fn = tmp;
- }
-
- // Quick check to determine if target is callable, in the spec
- // this throws a TypeError, but we will just return undefined.
- if ( !jQuery.isFunction( fn ) ) {
- return undefined;
- }
-
- // Simulated bind
- args = slice.call( arguments, 2 );
- proxy = function() {
- return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
- };
-
- // Set the guid of unique handler to the same of original handler, so it can be removed
- proxy.guid = fn.guid = fn.guid || jQuery.guid++;
-
- return proxy;
- },
-
- now: Date.now,
-
- // jQuery.support is not used in Core but other projects attach their
- // properties to it so it needs to exist.
- support: support
-});
-
-// Populate the class2type map
-jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
- class2type[ "[object " + name + "]" ] = name.toLowerCase();
-});
-
-function isArraylike( obj ) {
- var length = obj.length,
- type = jQuery.type( obj );
-
- if ( type === "function" || jQuery.isWindow( obj ) ) {
- return false;
- }
-
- if ( obj.nodeType === 1 && length ) {
- return true;
- }
-
- return type === "array" || length === 0 ||
- typeof length === "number" && length > 0 && ( length - 1 ) in obj;
-}
-var Sizzle =
-/*!
- * Sizzle CSS Selector Engine v1.10.19
- * http://sizzlejs.com/
- *
- * Copyright 2013 jQuery Foundation, Inc. and other contributors
- * Released under the MIT license
- * http://jquery.org/license
- *
- * Date: 2014-04-18
- */
-(function( window ) {
-
-var i,
- support,
- Expr,
- getText,
- isXML,
- tokenize,
- compile,
- select,
- outermostContext,
- sortInput,
- hasDuplicate,
-
- // Local document vars
- setDocument,
- document,
- docElem,
- documentIsHTML,
- rbuggyQSA,
- rbuggyMatches,
- matches,
- contains,
-
- // Instance-specific data
- expando = "sizzle" + -(new Date()),
- preferredDoc = window.document,
- dirruns = 0,
- done = 0,
- classCache = createCache(),
- tokenCache = createCache(),
- compilerCache = createCache(),
- sortOrder = function( a, b ) {
- if ( a === b ) {
- hasDuplicate = true;
- }
- return 0;
- },
-
- // General-purpose constants
- strundefined = typeof undefined,
- MAX_NEGATIVE = 1 << 31,
-
- // Instance methods
- hasOwn = ({}).hasOwnProperty,
- arr = [],
- pop = arr.pop,
- push_native = arr.push,
- push = arr.push,
- slice = arr.slice,
- // Use a stripped-down indexOf if we can't use a native one
- indexOf = arr.indexOf || function( elem ) {
- var i = 0,
- len = this.length;
- for ( ; i < len; i++ ) {
- if ( this[i] === elem ) {
- return i;
- }
- }
- return -1;
- },
-
- booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
-
- // Regular expressions
-
- // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
- whitespace = "[\\x20\\t\\r\\n\\f]",
- // http://www.w3.org/TR/css3-syntax/#characters
- characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
-
- // Loosely modeled on CSS identifier characters
- // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
- // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
- identifier = characterEncoding.replace( "w", "w#" ),
-
- // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
- attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace +
- // Operator (capture 2)
- "*([*^$|!~]?=)" + whitespace +
- // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
- "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
- "*\\]",
-
- pseudos = ":(" + characterEncoding + ")(?:\\((" +
- // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
- // 1. quoted (capture 3; capture 4 or capture 5)
- "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
- // 2. simple (capture 6)
- "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
- // 3. anything else (capture 2)
- ".*" +
- ")\\)|)",
-
- // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
- rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
-
- rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
- rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
-
- rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
-
- rpseudo = new RegExp( pseudos ),
- ridentifier = new RegExp( "^" + identifier + "$" ),
-
- matchExpr = {
- "ID": new RegExp( "^#(" + characterEncoding + ")" ),
- "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
- "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
- "ATTR": new RegExp( "^" + attributes ),
- "PSEUDO": new RegExp( "^" + pseudos ),
- "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
- "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
- "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
- "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
- // For use in libraries implementing .is()
- // We use this for POS matching in `select`
- "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
- whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
- },
-
- rinputs = /^(?:input|select|textarea|button)$/i,
- rheader = /^h\d$/i,
-
- rnative = /^[^{]+\{\s*\[native \w/,
-
- // Easily-parseable/retrievable ID or TAG or CLASS selectors
- rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
-
- rsibling = /[+~]/,
- rescape = /'|\\/g,
-
- // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
- runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
- funescape = function( _, escaped, escapedWhitespace ) {
- var high = "0x" + escaped - 0x10000;
- // NaN means non-codepoint
- // Support: Firefox<24
- // Workaround erroneous numeric interpretation of +"0x"
- return high !== high || escapedWhitespace ?
- escaped :
- high < 0 ?
- // BMP codepoint
- String.fromCharCode( high + 0x10000 ) :
- // Supplemental Plane codepoint (surrogate pair)
- String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
- };
-
-// Optimize for push.apply( _, NodeList )
-try {
- push.apply(
- (arr = slice.call( preferredDoc.childNodes )),
- preferredDoc.childNodes
- );
- // Support: Android<4.0
- // Detect silently failing push.apply
- arr[ preferredDoc.childNodes.length ].nodeType;
-} catch ( e ) {
- push = { apply: arr.length ?
-
- // Leverage slice if possible
- function( target, els ) {
- push_native.apply( target, slice.call(els) );
- } :
-
- // Support: IE<9
- // Otherwise append directly
- function( target, els ) {
- var j = target.length,
- i = 0;
- // Can't trust NodeList.length
- while ( (target[j++] = els[i++]) ) {}
- target.length = j - 1;
- }
- };
-}
-
-function Sizzle( selector, context, results, seed ) {
- var match, elem, m, nodeType,
- // QSA vars
- i, groups, old, nid, newContext, newSelector;
-
- if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
- setDocument( context );
- }
-
- context = context || document;
- results = results || [];
-
- if ( !selector || typeof selector !== "string" ) {
- return results;
- }
-
- if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
- return [];
- }
-
- if ( documentIsHTML && !seed ) {
-
- // Shortcuts
- if ( (match = rquickExpr.exec( selector )) ) {
- // Speed-up: Sizzle("#ID")
- if ( (m = match[1]) ) {
- if ( nodeType === 9 ) {
- elem = context.getElementById( m );
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document (jQuery #6963)
- if ( elem && elem.parentNode ) {
- // Handle the case where IE, Opera, and Webkit return items
- // by name instead of ID
- if ( elem.id === m ) {
- results.push( elem );
- return results;
- }
- } else {
- return results;
- }
- } else {
- // Context is not a document
- if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
- contains( context, elem ) && elem.id === m ) {
- results.push( elem );
- return results;
- }
- }
-
- // Speed-up: Sizzle("TAG")
- } else if ( match[2] ) {
- push.apply( results, context.getElementsByTagName( selector ) );
- return results;
-
- // Speed-up: Sizzle(".CLASS")
- } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
- push.apply( results, context.getElementsByClassName( m ) );
- return results;
- }
- }
-
- // QSA path
- if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
- nid = old = expando;
- newContext = context;
- newSelector = nodeType === 9 && selector;
-
- // qSA works strangely on Element-rooted queries
- // We can work around this by specifying an extra ID on the root
- // and working up from there (Thanks to Andrew Dupont for the technique)
- // IE 8 doesn't work on object elements
- if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
- groups = tokenize( selector );
-
- if ( (old = context.getAttribute("id")) ) {
- nid = old.replace( rescape, "\\$&" );
- } else {
- context.setAttribute( "id", nid );
- }
- nid = "[id='" + nid + "'] ";
-
- i = groups.length;
- while ( i-- ) {
- groups[i] = nid + toSelector( groups[i] );
- }
- newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
- newSelector = groups.join(",");
- }
-
- if ( newSelector ) {
- try {
- push.apply( results,
- newContext.querySelectorAll( newSelector )
- );
- return results;
- } catch(qsaError) {
- } finally {
- if ( !old ) {
- context.removeAttribute("id");
- }
- }
- }
- }
- }
-
- // All others
- return select( selector.replace( rtrim, "$1" ), context, results, seed );
-}
-
-/**
- * Create key-value caches of limited size
- * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
- * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
- * deleting the oldest entry
- */
-function createCache() {
- var keys = [];
-
- function cache( key, value ) {
- // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
- if ( keys.push( key + " " ) > Expr.cacheLength ) {
- // Only keep the most recent entries
- delete cache[ keys.shift() ];
- }
- return (cache[ key + " " ] = value);
- }
- return cache;
-}
-
-/**
- * Mark a function for special use by Sizzle
- * @param {Function} fn The function to mark
- */
-function markFunction( fn ) {
- fn[ expando ] = true;
- return fn;
-}
-
-/**
- * Support testing using an element
- * @param {Function} fn Passed the created div and expects a boolean result
- */
-function assert( fn ) {
- var div = document.createElement("div");
-
- try {
- return !!fn( div );
- } catch (e) {
- return false;
- } finally {
- // Remove from its parent by default
- if ( div.parentNode ) {
- div.parentNode.removeChild( div );
- }
- // release memory in IE
- div = null;
- }
-}
-
-/**
- * Adds the same handler for all of the specified attrs
- * @param {String} attrs Pipe-separated list of attributes
- * @param {Function} handler The method that will be applied
- */
-function addHandle( attrs, handler ) {
- var arr = attrs.split("|"),
- i = attrs.length;
-
- while ( i-- ) {
- Expr.attrHandle[ arr[i] ] = handler;
- }
-}
-
-/**
- * Checks document order of two siblings
- * @param {Element} a
- * @param {Element} b
- * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
- */
-function siblingCheck( a, b ) {
- var cur = b && a,
- diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
- ( ~b.sourceIndex || MAX_NEGATIVE ) -
- ( ~a.sourceIndex || MAX_NEGATIVE );
-
- // Use IE sourceIndex if available on both nodes
- if ( diff ) {
- return diff;
- }
-
- // Check if b follows a
- if ( cur ) {
- while ( (cur = cur.nextSibling) ) {
- if ( cur === b ) {
- return -1;
- }
- }
- }
-
- return a ? 1 : -1;
-}
-
-/**
- * Returns a function to use in pseudos for input types
- * @param {String} type
- */
-function createInputPseudo( type ) {
- return function( elem ) {
- var name = elem.nodeName.toLowerCase();
- return name === "input" && elem.type === type;
- };
-}
-
-/**
- * Returns a function to use in pseudos for buttons
- * @param {String} type
- */
-function createButtonPseudo( type ) {
- return function( elem ) {
- var name = elem.nodeName.toLowerCase();
- return (name === "input" || name === "button") && elem.type === type;
- };
-}
-
-/**
- * Returns a function to use in pseudos for positionals
- * @param {Function} fn
- */
-function createPositionalPseudo( fn ) {
- return markFunction(function( argument ) {
- argument = +argument;
- return markFunction(function( seed, matches ) {
- var j,
- matchIndexes = fn( [], seed.length, argument ),
- i = matchIndexes.length;
-
- // Match elements found at the specified indexes
- while ( i-- ) {
- if ( seed[ (j = matchIndexes[i]) ] ) {
- seed[j] = !(matches[j] = seed[j]);
- }
- }
- });
- });
-}
-
-/**
- * Checks a node for validity as a Sizzle context
- * @param {Element|Object=} context
- * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
- */
-function testContext( context ) {
- return context && typeof context.getElementsByTagName !== strundefined && context;
-}
-
-// Expose support vars for convenience
-support = Sizzle.support = {};
-
-/**
- * Detects XML nodes
- * @param {Element|Object} elem An element or a document
- * @returns {Boolean} True iff elem is a non-HTML XML node
- */
-isXML = Sizzle.isXML = function( elem ) {
- // documentElement is verified for cases where it doesn't yet exist
- // (such as loading iframes in IE - #4833)
- var documentElement = elem && (elem.ownerDocument || elem).documentElement;
- return documentElement ? documentElement.nodeName !== "HTML" : false;
-};
-
-/**
- * Sets document-related variables once based on the current document
- * @param {Element|Object} [doc] An element or document object to use to set the document
- * @returns {Object} Returns the current document
- */
-setDocument = Sizzle.setDocument = function( node ) {
- var hasCompare,
- doc = node ? node.ownerDocument || node : preferredDoc,
- parent = doc.defaultView;
-
- // If no document and documentElement is available, return
- if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
- return document;
- }
-
- // Set our document
- document = doc;
- docElem = doc.documentElement;
-
- // Support tests
- documentIsHTML = !isXML( doc );
-
- // Support: IE>8
- // If iframe document is assigned to "document" variable and if iframe has been reloaded,
- // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
- // IE6-8 do not support the defaultView property so parent will be undefined
- if ( parent && parent !== parent.top ) {
- // IE11 does not have attachEvent, so all must suffer
- if ( parent.addEventListener ) {
- parent.addEventListener( "unload", function() {
- setDocument();
- }, false );
- } else if ( parent.attachEvent ) {
- parent.attachEvent( "onunload", function() {
- setDocument();
- });
- }
- }
-
- /* Attributes
- ---------------------------------------------------------------------- */
-
- // Support: IE<8
- // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
- support.attributes = assert(function( div ) {
- div.className = "i";
- return !div.getAttribute("className");
- });
-
- /* getElement(s)By*
- ---------------------------------------------------------------------- */
-
- // Check if getElementsByTagName("*") returns only elements
- support.getElementsByTagName = assert(function( div ) {
- div.appendChild( doc.createComment("") );
- return !div.getElementsByTagName("*").length;
- });
-
- // Check if getElementsByClassName can be trusted
- support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {
- div.innerHTML = "<div class='a'></div><div class='a i'></div>";
-
- // Support: Safari<4
- // Catch class over-caching
- div.firstChild.className = "i";
- // Support: Opera<10
- // Catch gEBCN failure to find non-leading classes
- return div.getElementsByClassName("i").length === 2;
- });
-
- // Support: IE<10
- // Check if getElementById returns elements by name
- // The broken getElementById methods don't pick up programatically-set names,
- // so use a roundabout getElementsByName test
- support.getById = assert(function( div ) {
- docElem.appendChild( div ).id = expando;
- return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
- });
-
- // ID find and filter
- if ( support.getById ) {
- Expr.find["ID"] = function( id, context ) {
- if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
- var m = context.getElementById( id );
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #6963
- return m && m.parentNode ? [ m ] : [];
- }
- };
- Expr.filter["ID"] = function( id ) {
- var attrId = id.replace( runescape, funescape );
- return function( elem ) {
- return elem.getAttribute("id") === attrId;
- };
- };
- } else {
- // Support: IE6/7
- // getElementById is not reliable as a find shortcut
- delete Expr.find["ID"];
-
- Expr.filter["ID"] = function( id ) {
- var attrId = id.replace( runescape, funescape );
- return function( elem ) {
- var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
- return node && node.value === attrId;
- };
- };
- }
-
- // Tag
- Expr.find["TAG"] = support.getElementsByTagName ?
- function( tag, context ) {
- if ( typeof context.getElementsByTagName !== strundefined ) {
- return context.getElementsByTagName( tag );
- }
- } :
- function( tag, context ) {
- var elem,
- tmp = [],
- i = 0,
- results = context.getElementsByTagName( tag );
-
- // Filter out possible comments
- if ( tag === "*" ) {
- while ( (elem = results[i++]) ) {
- if ( elem.nodeType === 1 ) {
- tmp.push( elem );
- }
- }
-
- return tmp;
- }
- return results;
- };
-
- // Class
- Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
- if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
- return context.getElementsByClassName( className );
- }
- };
-
- /* QSA/matchesSelector
- ---------------------------------------------------------------------- */
-
- // QSA and matchesSelector support
-
- // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
- rbuggyMatches = [];
-
- // qSa(:focus) reports false when true (Chrome 21)
- // We allow this because of a bug in IE8/9 that throws an error
- // whenever `document.activeElement` is accessed on an iframe
- // So, we allow :focus to pass through QSA all the time to avoid the IE error
- // See http://bugs.jquery.com/ticket/13378
- rbuggyQSA = [];
-
- if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
- // Build QSA regex
- // Regex strategy adopted from Diego Perini
- assert(function( div ) {
- // Select is set to empty string on purpose
- // This is to test IE's treatment of not explicitly
- // setting a boolean content attribute,
- // since its presence should be enough
- // http://bugs.jquery.com/ticket/12359
- div.innerHTML = "<select msallowclip=''><option selected=''></option></select>";
-
- // Support: IE8, Opera 11-12.16
- // Nothing should be selected when empty strings follow ^= or $= or *=
- // The test attribute must be unknown in Opera but "safe" for WinRT
- // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
- if ( div.querySelectorAll("[msallowclip^='']").length ) {
- rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
- }
-
- // Support: IE8
- // Boolean attributes and "value" are not treated correctly
- if ( !div.querySelectorAll("[selected]").length ) {
- rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
- }
-
- // Webkit/Opera - :checked should return selected option elements
- // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
- // IE8 throws error here and will not see later tests
- if ( !div.querySelectorAll(":checked").length ) {
- rbuggyQSA.push(":checked");
- }
- });
-
- assert(function( div ) {
- // Support: Windows 8 Native Apps
- // The type and name attributes are restricted during .innerHTML assignment
- var input = doc.createElement("input");
- input.setAttribute( "type", "hidden" );
- div.appendChild( input ).setAttribute( "name", "D" );
-
- // Support: IE8
- // Enforce case-sensitivity of name attribute
- if ( div.querySelectorAll("[name=d]").length ) {
- rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
- }
-
- // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
- // IE8 throws error here and will not see later tests
- if ( !div.querySelectorAll(":enabled").length ) {
- rbuggyQSA.push( ":enabled", ":disabled" );
- }
-
- // Opera 10-11 does not throw on post-comma invalid pseudos
- div.querySelectorAll("*,:x");
- rbuggyQSA.push(",.*:");
- });
- }
-
- if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
- docElem.webkitMatchesSelector ||
- docElem.mozMatchesSelector ||
- docElem.oMatchesSelector ||
- docElem.msMatchesSelector) )) ) {
-
- assert(function( div ) {
- // Check to see if it's possible to do matchesSelector
- // on a disconnected node (IE 9)
- support.disconnectedMatch = matches.call( div, "div" );
-
- // This should fail with an exception
- // Gecko does not error, returns false instead
- matches.call( div, "[s!='']:x" );
- rbuggyMatches.push( "!=", pseudos );
- });
- }
-
- rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
- rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
-
- /* Contains
- ---------------------------------------------------------------------- */
- hasCompare = rnative.test( docElem.compareDocumentPosition );
-
- // Element contains another
- // Purposefully does not implement inclusive descendent
- // As in, an element does not contain itself
- contains = hasCompare || rnative.test( docElem.contains ) ?
- function( a, b ) {
- var adown = a.nodeType === 9 ? a.documentElement : a,
- bup = b && b.parentNode;
- return a === bup || !!( bup && bup.nodeType === 1 && (
- adown.contains ?
- adown.contains( bup ) :
- a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
- ));
- } :
- function( a, b ) {
- if ( b ) {
- while ( (b = b.parentNode) ) {
- if ( b === a ) {
- return true;
- }
- }
- }
- return false;
- };
-
- /* Sorting
- ---------------------------------------------------------------------- */
-
- // Document order sorting
- sortOrder = hasCompare ?
- function( a, b ) {
-
- // Flag for duplicate removal
- if ( a === b ) {
- hasDuplicate = true;
- return 0;
- }
-
- // Sort on method existence if only one input has compareDocumentPosition
- var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
- if ( compare ) {
- return compare;
- }
-
- // Calculate position if both inputs belong to the same document
- compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
- a.compareDocumentPosition( b ) :
-
- // Otherwise we know they are disconnected
- 1;
-
- // Disconnected nodes
- if ( compare & 1 ||
- (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
-
- // Choose the first element that is related to our preferred document
- if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
- return -1;
- }
- if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
- return 1;
- }
-
- // Maintain original order
- return sortInput ?
- ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
- 0;
- }
-
- return compare & 4 ? -1 : 1;
- } :
- function( a, b ) {
- // Exit early if the nodes are identical
- if ( a === b ) {
- hasDuplicate = true;
- return 0;
- }
-
- var cur,
- i = 0,
- aup = a.parentNode,
- bup = b.parentNode,
- ap = [ a ],
- bp = [ b ];
-
- // Parentless nodes are either documents or disconnected
- if ( !aup || !bup ) {
- return a === doc ? -1 :
- b === doc ? 1 :
- aup ? -1 :
- bup ? 1 :
- sortInput ?
- ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
- 0;
-
- // If the nodes are siblings, we can do a quick check
- } else if ( aup === bup ) {
- return siblingCheck( a, b );
- }
-
- // Otherwise we need full lists of their ancestors for comparison
- cur = a;
- while ( (cur = cur.parentNode) ) {
- ap.unshift( cur );
- }
- cur = b;
- while ( (cur = cur.parentNode) ) {
- bp.unshift( cur );
- }
-
- // Walk down the tree looking for a discrepancy
- while ( ap[i] === bp[i] ) {
- i++;
- }
-
- return i ?
- // Do a sibling check if the nodes have a common ancestor
- siblingCheck( ap[i], bp[i] ) :
-
- // Otherwise nodes in our document sort first
- ap[i] === preferredDoc ? -1 :
- bp[i] === preferredDoc ? 1 :
- 0;
- };
-
- return doc;
-};
-
-Sizzle.matches = function( expr, elements ) {
- return Sizzle( expr, null, null, elements );
-};
-
-Sizzle.matchesSelector = function( elem, expr ) {
- // Set document vars if needed
- if ( ( elem.ownerDocument || elem ) !== document ) {
- setDocument( elem );
- }
-
- // Make sure that attribute selectors are quoted
- expr = expr.replace( rattributeQuotes, "='$1']" );
-
- if ( support.matchesSelector && documentIsHTML &&
- ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
- ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
-
- try {
- var ret = matches.call( elem, expr );
-
- // IE 9's matchesSelector returns false on disconnected nodes
- if ( ret || support.disconnectedMatch ||
- // As well, disconnected nodes are said to be in a document
- // fragment in IE 9
- elem.document && elem.document.nodeType !== 11 ) {
- return ret;
- }
- } catch(e) {}
- }
-
- return Sizzle( expr, document, null, [ elem ] ).length > 0;
-};
-
-Sizzle.contains = function( context, elem ) {
- // Set document vars if needed
- if ( ( context.ownerDocument || context ) !== document ) {
- setDocument( context );
- }
- return contains( context, elem );
-};
-
-Sizzle.attr = function( elem, name ) {
- // Set document vars if needed
- if ( ( elem.ownerDocument || elem ) !== document ) {
- setDocument( elem );
- }
-
- var fn = Expr.attrHandle[ name.toLowerCase() ],
- // Don't get fooled by Object.prototype properties (jQuery #13807)
- val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
- fn( elem, name, !documentIsHTML ) :
- undefined;
-
- return val !== undefined ?
- val :
- support.attributes || !documentIsHTML ?
- elem.getAttribute( name ) :
- (val = elem.getAttributeNode(name)) && val.specified ?
- val.value :
- null;
-};
-
-Sizzle.error = function( msg ) {
- throw new Error( "Syntax error, unrecognized expression: " + msg );
-};
-
-/**
- * Document sorting and removing duplicates
- * @param {ArrayLike} results
- */
-Sizzle.uniqueSort = function( results ) {
- var elem,
- duplicates = [],
- j = 0,
- i = 0;
-
- // Unless we *know* we can detect duplicates, assume their presence
- hasDuplicate = !support.detectDuplicates;
- sortInput = !support.sortStable && results.slice( 0 );
- results.sort( sortOrder );
-
- if ( hasDuplicate ) {
- while ( (elem = results[i++]) ) {
- if ( elem === results[ i ] ) {
- j = duplicates.push( i );
- }
- }
- while ( j-- ) {
- results.splice( duplicates[ j ], 1 );
- }
- }
-
- // Clear input after sorting to release objects
- // See https://github.com/jquery/sizzle/pull/225
- sortInput = null;
-
- return results;
-};
-
-/**
- * Utility function for retrieving the text value of an array of DOM nodes
- * @param {Array|Element} elem
- */
-getText = Sizzle.getText = function( elem ) {
- var node,
- ret = "",
- i = 0,
- nodeType = elem.nodeType;
-
- if ( !nodeType ) {
- // If no nodeType, this is expected to be an array
- while ( (node = elem[i++]) ) {
- // Do not traverse comment nodes
- ret += getText( node );
- }
- } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
- // Use textContent for elements
- // innerText usage removed for consistency of new lines (jQuery #11153)
- if ( typeof elem.textContent === "string" ) {
- return elem.textContent;
- } else {
- // Traverse its children
- for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
- ret += getText( elem );
- }
- }
- } else if ( nodeType === 3 || nodeType === 4 ) {
- return elem.nodeValue;
- }
- // Do not include comment or processing instruction nodes
-
- return ret;
-};
-
-Expr = Sizzle.selectors = {
-
- // Can be adjusted by the user
- cacheLength: 50,
-
- createPseudo: markFunction,
-
- match: matchExpr,
-
- attrHandle: {},
-
- find: {},
-
- relative: {
- ">": { dir: "parentNode", first: true },
- " ": { dir: "parentNode" },
- "+": { dir: "previousSibling", first: true },
- "~": { dir: "previousSibling" }
- },
-
- preFilter: {
- "ATTR": function( match ) {
- match[1] = match[1].replace( runescape, funescape );
-
- // Move the given value to match[3] whether quoted or unquoted
- match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
-
- if ( match[2] === "~=" ) {
- match[3] = " " + match[3] + " ";
- }
-
- return match.slice( 0, 4 );
- },
-
- "CHILD": function( match ) {
- /* matches from matchExpr["CHILD"]
- 1 type (only|nth|...)
- 2 what (child|of-type)
- 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
- 4 xn-component of xn+y argument ([+-]?\d*n|)
- 5 sign of xn-component
- 6 x of xn-component
- 7 sign of y-component
- 8 y of y-component
- */
- match[1] = match[1].toLowerCase();
-
- if ( match[1].slice( 0, 3 ) === "nth" ) {
- // nth-* requires argument
- if ( !match[3] ) {
- Sizzle.error( match[0] );
- }
-
- // numeric x and y parameters for Expr.filter.CHILD
- // remember that false/true cast respectively to 0/1
- match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
- match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
-
- // other types prohibit arguments
- } else if ( match[3] ) {
- Sizzle.error( match[0] );
- }
-
- return match;
- },
-
- "PSEUDO": function( match ) {
- var excess,
- unquoted = !match[6] && match[2];
-
- if ( matchExpr["CHILD"].test( match[0] ) ) {
- return null;
- }
-
- // Accept quoted arguments as-is
- if ( match[3] ) {
- match[2] = match[4] || match[5] || "";
-
- // Strip excess characters from unquoted arguments
- } else if ( unquoted && rpseudo.test( unquoted ) &&
- // Get excess from tokenize (recursively)
- (excess = tokenize( unquoted, true )) &&
- // advance to the next closing parenthesis
- (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
-
- // excess is a negative index
- match[0] = match[0].slice( 0, excess );
- match[2] = unquoted.slice( 0, excess );
- }
-
- // Return only captures needed by the pseudo filter method (type and argument)
- return match.slice( 0, 3 );
- }
- },
-
- filter: {
-
- "TAG": function( nodeNameSelector ) {
- var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
- return nodeNameSelector === "*" ?
- function() { return true; } :
- function( elem ) {
- return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
- };
- },
-
- "CLASS": function( className ) {
- var pattern = classCache[ className + " " ];
-
- return pattern ||
- (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
- classCache( className, function( elem ) {
- return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
- });
- },
-
- "ATTR": function( name, operator, check ) {
- return function( elem ) {
- var result = Sizzle.attr( elem, name );
-
- if ( result == null ) {
- return operator === "!=";
- }
- if ( !operator ) {
- return true;
- }
-
- result += "";
-
- return operator === "=" ? result === check :
- operator === "!=" ? result !== check :
- operator === "^=" ? check && result.indexOf( check ) === 0 :
- operator === "*=" ? check && result.indexOf( check ) > -1 :
- operator === "$=" ? check && result.slice( -check.length ) === check :
- operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
- operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
- false;
- };
- },
-
- "CHILD": function( type, what, argument, first, last ) {
- var simple = type.slice( 0, 3 ) !== "nth",
- forward = type.slice( -4 ) !== "last",
- ofType = what === "of-type";
-
- return first === 1 && last === 0 ?
-
- // Shortcut for :nth-*(n)
- function( elem ) {
- return !!elem.parentNode;
- } :
-
- function( elem, context, xml ) {
- var cache, outerCache, node, diff, nodeIndex, start,
- dir = simple !== forward ? "nextSibling" : "previousSibling",
- parent = elem.parentNode,
- name = ofType && elem.nodeName.toLowerCase(),
- useCache = !xml && !ofType;
-
- if ( parent ) {
-
- // :(first|last|only)-(child|of-type)
- if ( simple ) {
- while ( dir ) {
- node = elem;
- while ( (node = node[ dir ]) ) {
- if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
- return false;
- }
- }
- // Reverse direction for :only-* (if we haven't yet done so)
- start = dir = type === "only" && !start && "nextSibling";
- }
- return true;
- }
-
- start = [ forward ? parent.firstChild : parent.lastChild ];
-
- // non-xml :nth-child(...) stores cache data on `parent`
- if ( forward && useCache ) {
- // Seek `elem` from a previously-cached index
- outerCache = parent[ expando ] || (parent[ expando ] = {});
- cache = outerCache[ type ] || [];
- nodeIndex = cache[0] === dirruns && cache[1];
- diff = cache[0] === dirruns && cache[2];
- node = nodeIndex && parent.childNodes[ nodeIndex ];
-
- while ( (node = ++nodeIndex && node && node[ dir ] ||
-
- // Fallback to seeking `elem` from the start
- (diff = nodeIndex = 0) || start.pop()) ) {
-
- // When found, cache indexes on `parent` and break
- if ( node.nodeType === 1 && ++diff && node === elem ) {
- outerCache[ type ] = [ dirruns, nodeIndex, diff ];
- break;
- }
- }
-
- // Use previously-cached element index if available
- } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
- diff = cache[1];
-
- // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
- } else {
- // Use the same loop as above to seek `elem` from the start
- while ( (node = ++nodeIndex && node && node[ dir ] ||
- (diff = nodeIndex = 0) || start.pop()) ) {
-
- if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
- // Cache the index of each encountered element
- if ( useCache ) {
- (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
- }
-
- if ( node === elem ) {
- break;
- }
- }
- }
- }
-
- // Incorporate the offset, then check against cycle size
- diff -= last;
- return diff === first || ( diff % first === 0 && diff / first >= 0 );
- }
- };
- },
-
- "PSEUDO": function( pseudo, argument ) {
- // pseudo-class names are case-insensitive
- // http://www.w3.org/TR/selectors/#pseudo-classes
- // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
- // Remember that setFilters inherits from pseudos
- var args,
- fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
- Sizzle.error( "unsupported pseudo: " + pseudo );
-
- // The user may use createPseudo to indicate that
- // arguments are needed to create the filter function
- // just as Sizzle does
- if ( fn[ expando ] ) {
- return fn( argument );
- }
-
- // But maintain support for old signatures
- if ( fn.length > 1 ) {
- args = [ pseudo, pseudo, "", argument ];
- return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
- markFunction(function( seed, matches ) {
- var idx,
- matched = fn( seed, argument ),
- i = matched.length;
- while ( i-- ) {
- idx = indexOf.call( seed, matched[i] );
- seed[ idx ] = !( matches[ idx ] = matched[i] );
- }
- }) :
- function( elem ) {
- return fn( elem, 0, args );
- };
- }
-
- return fn;
- }
- },
-
- pseudos: {
- // Potentially complex pseudos
- "not": markFunction(function( selector ) {
- // Trim the selector passed to compile
- // to avoid treating leading and trailing
- // spaces as combinators
- var input = [],
- results = [],
- matcher = compile( selector.replace( rtrim, "$1" ) );
-
- return matcher[ expando ] ?
- markFunction(function( seed, matches, context, xml ) {
- var elem,
- unmatched = matcher( seed, null, xml, [] ),
- i = seed.length;
-
- // Match elements unmatched by `matcher`
- while ( i-- ) {
- if ( (elem = unmatched[i]) ) {
- seed[i] = !(matches[i] = elem);
- }
- }
- }) :
- function( elem, context, xml ) {
- input[0] = elem;
- matcher( input, null, xml, results );
- return !results.pop();
- };
- }),
-
- "has": markFunction(function( selector ) {
- return function( elem ) {
- return Sizzle( selector, elem ).length > 0;
- };
- }),
-
- "contains": markFunction(function( text ) {
- return function( elem ) {
- return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
- };
- }),
-
- // "Whether an element is represented by a :lang() selector
- // is based solely on the element's language value
- // being equal to the identifier C,
- // or beginning with the identifier C immediately followed by "-".
- // The matching of C against the element's language value is performed case-insensitively.
- // The identifier C does not have to be a valid language name."
- // http://www.w3.org/TR/selectors/#lang-pseudo
- "lang": markFunction( function( lang ) {
- // lang value must be a valid identifier
- if ( !ridentifier.test(lang || "") ) {
- Sizzle.error( "unsupported lang: " + lang );
- }
- lang = lang.replace( runescape, funescape ).toLowerCase();
- return function( elem ) {
- var elemLang;
- do {
- if ( (elemLang = documentIsHTML ?
- elem.lang :
- elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
-
- elemLang = elemLang.toLowerCase();
- return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
- }
- } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
- return false;
- };
- }),
-
- // Miscellaneous
- "target": function( elem ) {
- var hash = window.location && window.location.hash;
- return hash && hash.slice( 1 ) === elem.id;
- },
-
- "root": function( elem ) {
- return elem === docElem;
- },
-
- "focus": function( elem ) {
- return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
- },
-
- // Boolean properties
- "enabled": function( elem ) {
- return elem.disabled === false;
- },
-
- "disabled": function( elem ) {
- return elem.disabled === true;
- },
-
- "checked": function( elem ) {
- // In CSS3, :checked should return both checked and selected elements
- // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
- var nodeName = elem.nodeName.toLowerCase();
- return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
- },
-
- "selected": function( elem ) {
- // Accessing this property makes selected-by-default
- // options in Safari work properly
- if ( elem.parentNode ) {
- elem.parentNode.selectedIndex;
- }
-
- return elem.selected === true;
- },
-
- // Contents
- "empty": function( elem ) {
- // http://www.w3.org/TR/selectors/#empty-pseudo
- // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
- // but not by others (comment: 8; processing instruction: 7; etc.)
- // nodeType < 6 works because attributes (2) do not appear as children
- for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
- if ( elem.nodeType < 6 ) {
- return false;
- }
- }
- return true;
- },
-
- "parent": function( elem ) {
- return !Expr.pseudos["empty"]( elem );
- },
-
- // Element/input types
- "header": function( elem ) {
- return rheader.test( elem.nodeName );
- },
-
- "input": function( elem ) {
- return rinputs.test( elem.nodeName );
- },
-
- "button": function( elem ) {
- var name = elem.nodeName.toLowerCase();
- return name === "input" && elem.type === "button" || name === "button";
- },
-
- "text": function( elem ) {
- var attr;
- return elem.nodeName.toLowerCase() === "input" &&
- elem.type === "text" &&
-
- // Support: IE<8
- // New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
- ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
- },
-
- // Position-in-collection
- "first": createPositionalPseudo(function() {
- return [ 0 ];
- }),
-
- "last": createPositionalPseudo(function( matchIndexes, length ) {
- return [ length - 1 ];
- }),
-
- "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
- return [ argument < 0 ? argument + length : argument ];
- }),
-
- "even": createPositionalPseudo(function( matchIndexes, length ) {
- var i = 0;
- for ( ; i < length; i += 2 ) {
- matchIndexes.push( i );
- }
- return matchIndexes;
- }),
-
- "odd": createPositionalPseudo(function( matchIndexes, length ) {
- var i = 1;
- for ( ; i < length; i += 2 ) {
- matchIndexes.push( i );
- }
- return matchIndexes;
- }),
-
- "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
- var i = argument < 0 ? argument + length : argument;
- for ( ; --i >= 0; ) {
- matchIndexes.push( i );
- }
- return matchIndexes;
- }),
-
- "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
- var i = argument < 0 ? argument + length : argument;
- for ( ; ++i < length; ) {
- matchIndexes.push( i );
- }
- return matchIndexes;
- })
- }
-};
-
-Expr.pseudos["nth"] = Expr.pseudos["eq"];
-
-// Add button/input type pseudos
-for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
- Expr.pseudos[ i ] = createInputPseudo( i );
-}
-for ( i in { submit: true, reset: true } ) {
- Expr.pseudos[ i ] = createButtonPseudo( i );
-}
-
-// Easy API for creating new setFilters
-function setFilters() {}
-setFilters.prototype = Expr.filters = Expr.pseudos;
-Expr.setFilters = new setFilters();
-
-tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
- var matched, match, tokens, type,
- soFar, groups, preFilters,
- cached = tokenCache[ selector + " " ];
-
- if ( cached ) {
- return parseOnly ? 0 : cached.slice( 0 );
- }
-
- soFar = selector;
- groups = [];
- preFilters = Expr.preFilter;
-
- while ( soFar ) {
-
- // Comma and first run
- if ( !matched || (match = rcomma.exec( soFar )) ) {
- if ( match ) {
- // Don't consume trailing commas as valid
- soFar = soFar.slice( match[0].length ) || soFar;
- }
- groups.push( (tokens = []) );
- }
-
- matched = false;
-
- // Combinators
- if ( (match = rcombinators.exec( soFar )) ) {
- matched = match.shift();
- tokens.push({
- value: matched,
- // Cast descendant combinators to space
- type: match[0].replace( rtrim, " " )
- });
- soFar = soFar.slice( matched.length );
- }
-
- // Filters
- for ( type in Expr.filter ) {
- if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
- (match = preFilters[ type ]( match ))) ) {
- matched = match.shift();
- tokens.push({
- value: matched,
- type: type,
- matches: match
- });
- soFar = soFar.slice( matched.length );
- }
- }
-
- if ( !matched ) {
- break;
- }
- }
-
- // Return the length of the invalid excess
- // if we're just parsing
- // Otherwise, throw an error or return tokens
- return parseOnly ?
- soFar.length :
- soFar ?
- Sizzle.error( selector ) :
- // Cache the tokens
- tokenCache( selector, groups ).slice( 0 );
-};
-
-function toSelector( tokens ) {
- var i = 0,
- len = tokens.length,
- selector = "";
- for ( ; i < len; i++ ) {
- selector += tokens[i].value;
- }
- return selector;
-}
-
-function addCombinator( matcher, combinator, base ) {
- var dir = combinator.dir,
- checkNonElements = base && dir === "parentNode",
- doneName = done++;
-
- return combinator.first ?
- // Check against closest ancestor/preceding element
- function( elem, context, xml ) {
- while ( (elem = elem[ dir ]) ) {
- if ( elem.nodeType === 1 || checkNonElements ) {
- return matcher( elem, context, xml );
- }
- }
- } :
-
- // Check against all ancestor/preceding elements
- function( elem, context, xml ) {
- var oldCache, outerCache,
- newCache = [ dirruns, doneName ];
-
- // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
- if ( xml ) {
- while ( (elem = elem[ dir ]) ) {
- if ( elem.nodeType === 1 || checkNonElements ) {
- if ( matcher( elem, context, xml ) ) {
- return true;
- }
- }
- }
- } else {
- while ( (elem = elem[ dir ]) ) {
- if ( elem.nodeType === 1 || checkNonElements ) {
- outerCache = elem[ expando ] || (elem[ expando ] = {});
- if ( (oldCache = outerCache[ dir ]) &&
- oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
-
- // Assign to newCache so results back-propagate to previous elements
- return (newCache[ 2 ] = oldCache[ 2 ]);
- } else {
- // Reuse newcache so results back-propagate to previous elements
- outerCache[ dir ] = newCache;
-
- // A match means we're done; a fail means we have to keep checking
- if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
- return true;
- }
- }
- }
- }
- }
- };
-}
-
-function elementMatcher( matchers ) {
- return matchers.length > 1 ?
- function( elem, context, xml ) {
- var i = matchers.length;
- while ( i-- ) {
- if ( !matchers[i]( elem, context, xml ) ) {
- return false;
- }
- }
- return true;
- } :
- matchers[0];
-}
-
-function multipleContexts( selector, contexts, results ) {
- var i = 0,
- len = contexts.length;
- for ( ; i < len; i++ ) {
- Sizzle( selector, contexts[i], results );
- }
- return results;
-}
-
-function condense( unmatched, map, filter, context, xml ) {
- var elem,
- newUnmatched = [],
- i = 0,
- len = unmatched.length,
- mapped = map != null;
-
- for ( ; i < len; i++ ) {
- if ( (elem = unmatched[i]) ) {
- if ( !filter || filter( elem, context, xml ) ) {
- newUnmatched.push( elem );
- if ( mapped ) {
- map.push( i );
- }
- }
- }
- }
-
- return newUnmatched;
-}
-
-function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
- if ( postFilter && !postFilter[ expando ] ) {
- postFilter = setMatcher( postFilter );
- }
- if ( postFinder && !postFinder[ expando ] ) {
- postFinder = setMatcher( postFinder, postSelector );
- }
- return markFunction(function( seed, results, context, xml ) {
- var temp, i, elem,
- preMap = [],
- postMap = [],
- preexisting = results.length,
-
- // Get initial elements from seed or context
- elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
-
- // Prefilter to get matcher input, preserving a map for seed-results synchronization
- matcherIn = preFilter && ( seed || !selector ) ?
- condense( elems, preMap, preFilter, context, xml ) :
- elems,
-
- matcherOut = matcher ?
- // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
- postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
-
- // ...intermediate processing is necessary
- [] :
-
- // ...otherwise use results directly
- results :
- matcherIn;
-
- // Find primary matches
- if ( matcher ) {
- matcher( matcherIn, matcherOut, context, xml );
- }
-
- // Apply postFilter
- if ( postFilter ) {
- temp = condense( matcherOut, postMap );
- postFilter( temp, [], context, xml );
-
- // Un-match failing elements by moving them back to matcherIn
- i = temp.length;
- while ( i-- ) {
- if ( (elem = temp[i]) ) {
- matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
- }
- }
- }
-
- if ( seed ) {
- if ( postFinder || preFilter ) {
- if ( postFinder ) {
- // Get the final matcherOut by condensing this intermediate into postFinder contexts
- temp = [];
- i = matcherOut.length;
- while ( i-- ) {
- if ( (elem = matcherOut[i]) ) {
- // Restore matcherIn since elem is not yet a final match
- temp.push( (matcherIn[i] = elem) );
- }
- }
- postFinder( null, (matcherOut = []), temp, xml );
- }
-
- // Move matched elements from seed to results to keep them synchronized
- i = matcherOut.length;
- while ( i-- ) {
- if ( (elem = matcherOut[i]) &&
- (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
-
- seed[temp] = !(results[temp] = elem);
- }
- }
- }
-
- // Add elements to results, through postFinder if defined
- } else {
- matcherOut = condense(
- matcherOut === results ?
- matcherOut.splice( preexisting, matcherOut.length ) :
- matcherOut
- );
- if ( postFinder ) {
- postFinder( null, results, matcherOut, xml );
- } else {
- push.apply( results, matcherOut );
- }
- }
- });
-}
-
-function matcherFromTokens( tokens ) {
- var checkContext, matcher, j,
- len = tokens.length,
- leadingRelative = Expr.relative[ tokens[0].type ],
- implicitRelative = leadingRelative || Expr.relative[" "],
- i = leadingRelative ? 1 : 0,
-
- // The foundational matcher ensures that elements are reachable from top-level context(s)
- matchContext = addCombinator( function( elem ) {
- return elem === checkContext;
- }, implicitRelative, true ),
- matchAnyContext = addCombinator( function( elem ) {
- return indexOf.call( checkContext, elem ) > -1;
- }, implicitRelative, true ),
- matchers = [ function( elem, context, xml ) {
- return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
- (checkContext = context).nodeType ?
- matchContext( elem, context, xml ) :
- matchAnyContext( elem, context, xml ) );
- } ];
-
- for ( ; i < len; i++ ) {
- if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
- matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
- } else {
- matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
-
- // Return special upon seeing a positional matcher
- if ( matcher[ expando ] ) {
- // Find the next relative operator (if any) for proper handling
- j = ++i;
- for ( ; j < len; j++ ) {
- if ( Expr.relative[ tokens[j].type ] ) {
- break;
- }
- }
- return setMatcher(
- i > 1 && elementMatcher( matchers ),
- i > 1 && toSelector(
- // If the preceding token was a descendant combinator, insert an implicit any-element `*`
- tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
- ).replace( rtrim, "$1" ),
- matcher,
- i < j && matcherFromTokens( tokens.slice( i, j ) ),
- j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
- j < len && toSelector( tokens )
- );
- }
- matchers.push( matcher );
- }
- }
-
- return elementMatcher( matchers );
-}
-
-function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
- var bySet = setMatchers.length > 0,
- byElement = elementMatchers.length > 0,
- superMatcher = function( seed, context, xml, results, outermost ) {
- var elem, j, matcher,
- matchedCount = 0,
- i = "0",
- unmatched = seed && [],
- setMatched = [],
- contextBackup = outermostContext,
- // We must always have either seed elements or outermost context
- elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
- // Use integer dirruns iff this is the outermost matcher
- dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
- len = elems.length;
-
- if ( outermost ) {
- outermostContext = context !== document && context;
- }
-
- // Add elements passing elementMatchers directly to results
- // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
- // Support: IE<9, Safari
- // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
- for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
- if ( byElement && elem ) {
- j = 0;
- while ( (matcher = elementMatchers[j++]) ) {
- if ( matcher( elem, context, xml ) ) {
- results.push( elem );
- break;
- }
- }
- if ( outermost ) {
- dirruns = dirrunsUnique;
- }
- }
-
- // Track unmatched elements for set filters
- if ( bySet ) {
- // They will have gone through all possible matchers
- if ( (elem = !matcher && elem) ) {
- matchedCount--;
- }
-
- // Lengthen the array for every element, matched or not
- if ( seed ) {
- unmatched.push( elem );
- }
- }
- }
-
- // Apply set filters to unmatched elements
- matchedCount += i;
- if ( bySet && i !== matchedCount ) {
- j = 0;
- while ( (matcher = setMatchers[j++]) ) {
- matcher( unmatched, setMatched, context, xml );
- }
-
- if ( seed ) {
- // Reintegrate element matches to eliminate the need for sorting
- if ( matchedCount > 0 ) {
- while ( i-- ) {
- if ( !(unmatched[i] || setMatched[i]) ) {
- setMatched[i] = pop.call( results );
- }
- }
- }
-
- // Discard index placeholder values to get only actual matches
- setMatched = condense( setMatched );
- }
-
- // Add matches to results
- push.apply( results, setMatched );
-
- // Seedless set matches succeeding multiple successful matchers stipulate sorting
- if ( outermost && !seed && setMatched.length > 0 &&
- ( matchedCount + setMatchers.length ) > 1 ) {
-
- Sizzle.uniqueSort( results );
- }
- }
-
- // Override manipulation of globals by nested matchers
- if ( outermost ) {
- dirruns = dirrunsUnique;
- outermostContext = contextBackup;
- }
-
- return unmatched;
- };
-
- return bySet ?
- markFunction( superMatcher ) :
- superMatcher;
-}
-
-compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
- var i,
- setMatchers = [],
- elementMatchers = [],
- cached = compilerCache[ selector + " " ];
-
- if ( !cached ) {
- // Generate a function of recursive functions that can be used to check each element
- if ( !match ) {
- match = tokenize( selector );
- }
- i = match.length;
- while ( i-- ) {
- cached = matcherFromTokens( match[i] );
- if ( cached[ expando ] ) {
- setMatchers.push( cached );
- } else {
- elementMatchers.push( cached );
- }
- }
-
- // Cache the compiled function
- cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
-
- // Save selector and tokenization
- cached.selector = selector;
- }
- return cached;
-};
-
-/**
- * A low-level selection function that works with Sizzle's compiled
- * selector functions
- * @param {String|Function} selector A selector or a pre-compiled
- * selector function built with Sizzle.compile
- * @param {Element} context
- * @param {Array} [results]
- * @param {Array} [seed] A set of elements to match against
- */
-select = Sizzle.select = function( selector, context, results, seed ) {
- var i, tokens, token, type, find,
- compiled = typeof selector === "function" && selector,
- match = !seed && tokenize( (selector = compiled.selector || selector) );
-
- results = results || [];
-
- // Try to minimize operations if there is no seed and only one group
- if ( match.length === 1 ) {
-
- // Take a shortcut and set the context if the root selector is an ID
- tokens = match[0] = match[0].slice( 0 );
- if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
- support.getById && context.nodeType === 9 && documentIsHTML &&
- Expr.relative[ tokens[1].type ] ) {
-
- context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
- if ( !context ) {
- return results;
-
- // Precompiled matchers will still verify ancestry, so step up a level
- } else if ( compiled ) {
- context = context.parentNode;
- }
-
- selector = selector.slice( tokens.shift().value.length );
- }
-
- // Fetch a seed set for right-to-left matching
- i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
- while ( i-- ) {
- token = tokens[i];
-
- // Abort if we hit a combinator
- if ( Expr.relative[ (type = token.type) ] ) {
- break;
- }
- if ( (find = Expr.find[ type ]) ) {
- // Search, expanding context for leading sibling combinators
- if ( (seed = find(
- token.matches[0].replace( runescape, funescape ),
- rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
- )) ) {
-
- // If seed is empty or no tokens remain, we can return early
- tokens.splice( i, 1 );
- selector = seed.length && toSelector( tokens );
- if ( !selector ) {
- push.apply( results, seed );
- return results;
- }
-
- break;
- }
- }
- }
- }
-
- // Compile and execute a filtering function if one is not provided
- // Provide `match` to avoid retokenization if we modified the selector above
- ( compiled || compile( selector, match ) )(
- seed,
- context,
- !documentIsHTML,
- results,
- rsibling.test( selector ) && testContext( context.parentNode ) || context
- );
- return results;
-};
-
-// One-time assignments
-
-// Sort stability
-support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
-
-// Support: Chrome<14
-// Always assume duplicates if they aren't passed to the comparison function
-support.detectDuplicates = !!hasDuplicate;
-
-// Initialize against the default document
-setDocument();
-
-// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
-// Detached nodes confoundingly follow *each other*
-support.sortDetached = assert(function( div1 ) {
- // Should return 1, but returns 4 (following)
- return div1.compareDocumentPosition( document.createElement("div") ) & 1;
-});
-
-// Support: IE<8
-// Prevent attribute/property "interpolation"
-// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
-if ( !assert(function( div ) {
- div.innerHTML = "<a href='#'></a>";
- return div.firstChild.getAttribute("href") === "#" ;
-}) ) {
- addHandle( "type|href|height|width", function( elem, name, isXML ) {
- if ( !isXML ) {
- return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
- }
- });
-}
-
-// Support: IE<9
-// Use defaultValue in place of getAttribute("value")
-if ( !support.attributes || !assert(function( div ) {
- div.innerHTML = "<input/>";
- div.firstChild.setAttribute( "value", "" );
- return div.firstChild.getAttribute( "value" ) === "";
-}) ) {
- addHandle( "value", function( elem, name, isXML ) {
- if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
- return elem.defaultValue;
- }
- });
-}
-
-// Support: IE<9
-// Use getAttributeNode to fetch booleans when getAttribute lies
-if ( !assert(function( div ) {
- return div.getAttribute("disabled") == null;
-}) ) {
- addHandle( booleans, function( elem, name, isXML ) {
- var val;
- if ( !isXML ) {
- return elem[ name ] === true ? name.toLowerCase() :
- (val = elem.getAttributeNode( name )) && val.specified ?
- val.value :
- null;
- }
- });
-}
-
-return Sizzle;
-
-})( window );
-
-
-
-jQuery.find = Sizzle;
-jQuery.expr = Sizzle.selectors;
-jQuery.expr[":"] = jQuery.expr.pseudos;
-jQuery.unique = Sizzle.uniqueSort;
-jQuery.text = Sizzle.getText;
-jQuery.isXMLDoc = Sizzle.isXML;
-jQuery.contains = Sizzle.contains;
-
-
-
-var rneedsContext = jQuery.expr.match.needsContext;
-
-var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/);
-
-
-
-var risSimple = /^.[^:#\[\.,]*$/;
-
-// Implement the identical functionality for filter and not
-function winnow( elements, qualifier, not ) {
- if ( jQuery.isFunction( qualifier ) ) {
- return jQuery.grep( elements, function( elem, i ) {
- /* jshint -W018 */
- return !!qualifier.call( elem, i, elem ) !== not;
- });
-
- }
-
- if ( qualifier.nodeType ) {
- return jQuery.grep( elements, function( elem ) {
- return ( elem === qualifier ) !== not;
- });
-
- }
-
- if ( typeof qualifier === "string" ) {
- if ( risSimple.test( qualifier ) ) {
- return jQuery.filter( qualifier, elements, not );
- }
-
- qualifier = jQuery.filter( qualifier, elements );
- }
-
- return jQuery.grep( elements, function( elem ) {
- return ( indexOf.call( qualifier, elem ) >= 0 ) !== not;
- });
-}
-
-jQuery.filter = function( expr, elems, not ) {
- var elem = elems[ 0 ];
-
- if ( not ) {
- expr = ":not(" + expr + ")";
- }
-
- return elems.length === 1 && elem.nodeType === 1 ?
- jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
- jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
- return elem.nodeType === 1;
- }));
-};
-
-jQuery.fn.extend({
- find: function( selector ) {
- var i,
- len = this.length,
- ret = [],
- self = this;
-
- if ( typeof selector !== "string" ) {
- return this.pushStack( jQuery( selector ).filter(function() {
- for ( i = 0; i < len; i++ ) {
- if ( jQuery.contains( self[ i ], this ) ) {
- return true;
- }
- }
- }) );
- }
-
- for ( i = 0; i < len; i++ ) {
- jQuery.find( selector, self[ i ], ret );
- }
-
- // Needed because $( selector, context ) becomes $( context ).find( selector )
- ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
- ret.selector = this.selector ? this.selector + " " + selector : selector;
- return ret;
- },
- filter: function( selector ) {
- return this.pushStack( winnow(this, selector || [], false) );
- },
- not: function( selector ) {
- return this.pushStack( winnow(this, selector || [], true) );
- },
- is: function( selector ) {
- return !!winnow(
- this,
-
- // If this is a positional/relative selector, check membership in the returned set
- // so $("p:first").is("p:last") won't return true for a doc with two "p".
- typeof selector === "string" && rneedsContext.test( selector ) ?
- jQuery( selector ) :
- selector || [],
- false
- ).length;
- }
-});
-
-
-// Initialize a jQuery object
-
-
-// A central reference to the root jQuery(document)
-var rootjQuery,
-
- // A simple way to check for HTML strings
- // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
- // Strict HTML recognition (#11290: must start with <)
- rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
-
- init = jQuery.fn.init = function( selector, context ) {
- var match, elem;
-
- // HANDLE: $(""), $(null), $(undefined), $(false)
- if ( !selector ) {
- return this;
- }
-
- // Handle HTML strings
- if ( typeof selector === "string" ) {
- if ( selector[0] === "<" && selector[ selector.length - 1 ] === ">" && selector.length >= 3 ) {
- // Assume that strings that start and end with <> are HTML and skip the regex check
- match = [ null, selector, null ];
-
- } else {
- match = rquickExpr.exec( selector );
- }
-
- // Match html or make sure no context is specified for #id
- if ( match && (match[1] || !context) ) {
-
- // HANDLE: $(html) -> $(array)
- if ( match[1] ) {
- context = context instanceof jQuery ? context[0] : context;
-
- // scripts is true for back-compat
- // Intentionally let the error be thrown if parseHTML is not present
- jQuery.merge( this, jQuery.parseHTML(
- match[1],
- context && context.nodeType ? context.ownerDocument || context : document,
- true
- ) );
-
- // HANDLE: $(html, props)
- if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
- for ( match in context ) {
- // Properties of context are called as methods if possible
- if ( jQuery.isFunction( this[ match ] ) ) {
- this[ match ]( context[ match ] );
-
- // ...and otherwise set as attributes
- } else {
- this.attr( match, context[ match ] );
- }
- }
- }
-
- return this;
-
- // HANDLE: $(#id)
- } else {
- elem = document.getElementById( match[2] );
-
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #6963
- if ( elem && elem.parentNode ) {
- // Inject the element directly into the jQuery object
- this.length = 1;
- this[0] = elem;
- }
-
- this.context = document;
- this.selector = selector;
- return this;
- }
-
- // HANDLE: $(expr, $(...))
- } else if ( !context || context.jquery ) {
- return ( context || rootjQuery ).find( selector );
-
- // HANDLE: $(expr, context)
- // (which is just equivalent to: $(context).find(expr)
- } else {
- return this.constructor( context ).find( selector );
- }
-
- // HANDLE: $(DOMElement)
- } else if ( selector.nodeType ) {
- this.context = this[0] = selector;
- this.length = 1;
- return this;
-
- // HANDLE: $(function)
- // Shortcut for document ready
- } else if ( jQuery.isFunction( selector ) ) {
- return typeof rootjQuery.ready !== "undefined" ?
- rootjQuery.ready( selector ) :
- // Execute immediately if ready is not present
- selector( jQuery );
- }
-
- if ( selector.selector !== undefined ) {
- this.selector = selector.selector;
- this.context = selector.context;
- }
-
- return jQuery.makeArray( selector, this );
- };
-
-// Give the init function the jQuery prototype for later instantiation
-init.prototype = jQuery.fn;
-
-// Initialize central reference
-rootjQuery = jQuery( document );
-
-
-var rparentsprev = /^(?:parents|prev(?:Until|All))/,
- // methods guaranteed to produce a unique set when starting from a unique set
- guaranteedUnique = {
- children: true,
- contents: true,
- next: true,
- prev: true
- };
-
-jQuery.extend({
- dir: function( elem, dir, until ) {
- var matched = [],
- truncate = until !== undefined;
-
- while ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) {
- if ( elem.nodeType === 1 ) {
- if ( truncate && jQuery( elem ).is( until ) ) {
- break;
- }
- matched.push( elem );
- }
- }
- return matched;
- },
-
- sibling: function( n, elem ) {
- var matched = [];
-
- for ( ; n; n = n.nextSibling ) {
- if ( n.nodeType === 1 && n !== elem ) {
- matched.push( n );
- }
- }
-
- return matched;
- }
-});
-
-jQuery.fn.extend({
- has: function( target ) {
- var targets = jQuery( target, this ),
- l = targets.length;
-
- return this.filter(function() {
- var i = 0;
- for ( ; i < l; i++ ) {
- if ( jQuery.contains( this, targets[i] ) ) {
- return true;
- }
- }
- });
- },
-
- closest: function( selectors, context ) {
- var cur,
- i = 0,
- l = this.length,
- matched = [],
- pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
- jQuery( selectors, context || this.context ) :
- 0;
-
- for ( ; i < l; i++ ) {
- for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
- // Always skip document fragments
- if ( cur.nodeType < 11 && (pos ?
- pos.index(cur) > -1 :
-
- // Don't pass non-elements to Sizzle
- cur.nodeType === 1 &&
- jQuery.find.matchesSelector(cur, selectors)) ) {
-
- matched.push( cur );
- break;
- }
- }
- }
-
- return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
- },
-
- // Determine the position of an element within
- // the matched set of elements
- index: function( elem ) {
-
- // No argument, return index in parent
- if ( !elem ) {
- return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
- }
-
- // index in selector
- if ( typeof elem === "string" ) {
- return indexOf.call( jQuery( elem ), this[ 0 ] );
- }
-
- // Locate the position of the desired element
- return indexOf.call( this,
-
- // If it receives a jQuery object, the first element is used
- elem.jquery ? elem[ 0 ] : elem
- );
- },
-
- add: function( selector, context ) {
- return this.pushStack(
- jQuery.unique(
- jQuery.merge( this.get(), jQuery( selector, context ) )
- )
- );
- },
-
- addBack: function( selector ) {
- return this.add( selector == null ?
- this.prevObject : this.prevObject.filter(selector)
- );
- }
-});
-
-function sibling( cur, dir ) {
- while ( (cur = cur[dir]) && cur.nodeType !== 1 ) {}
- return cur;
-}
-
-jQuery.each({
- parent: function( elem ) {
- var parent = elem.parentNode;
- return parent && parent.nodeType !== 11 ? parent : null;
- },
- parents: function( elem ) {
- return jQuery.dir( elem, "parentNode" );
- },
- parentsUntil: function( elem, i, until ) {
- return jQuery.dir( elem, "parentNode", until );
- },
- next: function( elem ) {
- return sibling( elem, "nextSibling" );
- },
- prev: function( elem ) {
- return sibling( elem, "previousSibling" );
- },
- nextAll: function( elem ) {
- return jQuery.dir( elem, "nextSibling" );
- },
- prevAll: function( elem ) {
- return jQuery.dir( elem, "previousSibling" );
- },
- nextUntil: function( elem, i, until ) {
- return jQuery.dir( elem, "nextSibling", until );
- },
- prevUntil: function( elem, i, until ) {
- return jQuery.dir( elem, "previousSibling", until );
- },
- siblings: function( elem ) {
- return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
- },
- children: function( elem ) {
- return jQuery.sibling( elem.firstChild );
- },
- contents: function( elem ) {
- return elem.contentDocument || jQuery.merge( [], elem.childNodes );
- }
-}, function( name, fn ) {
- jQuery.fn[ name ] = function( until, selector ) {
- var matched = jQuery.map( this, fn, until );
-
- if ( name.slice( -5 ) !== "Until" ) {
- selector = until;
- }
-
- if ( selector && typeof selector === "string" ) {
- matched = jQuery.filter( selector, matched );
- }
-
- if ( this.length > 1 ) {
- // Remove duplicates
- if ( !guaranteedUnique[ name ] ) {
- jQuery.unique( matched );
- }
-
- // Reverse order for parents* and prev-derivatives
- if ( rparentsprev.test( name ) ) {
- matched.reverse();
- }
- }
-
- return this.pushStack( matched );
- };
-});
-var rnotwhite = (/\S+/g);
-
-
-
-// String to Object options format cache
-var optionsCache = {};
-
-// Convert String-formatted options into Object-formatted ones and store in cache
-function createOptions( options ) {
- var object = optionsCache[ options ] = {};
- jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
- object[ flag ] = true;
- });
- return object;
-}
-
-/*
- * Create a callback list using the following parameters:
- *
- * options: an optional list of space-separated options that will change how
- * the callback list behaves or a more traditional option object
- *
- * By default a callback list will act like an event callback list and can be
- * "fired" multiple times.
- *
- * Possible options:
- *
- * once: will ensure the callback list can only be fired once (like a Deferred)
- *
- * memory: will keep track of previous values and will call any callback added
- * after the list has been fired right away with the latest "memorized"
- * values (like a Deferred)
- *
- * unique: will ensure a callback can only be added once (no duplicate in the list)
- *
- * stopOnFalse: interrupt callings when a callback returns false
- *
- */
-jQuery.Callbacks = function( options ) {
-
- // Convert options from String-formatted to Object-formatted if needed
- // (we check in cache first)
- options = typeof options === "string" ?
- ( optionsCache[ options ] || createOptions( options ) ) :
- jQuery.extend( {}, options );
-
- var // Last fire value (for non-forgettable lists)
- memory,
- // Flag to know if list was already fired
- fired,
- // Flag to know if list is currently firing
- firing,
- // First callback to fire (used internally by add and fireWith)
- firingStart,
- // End of the loop when firing
- firingLength,
- // Index of currently firing callback (modified by remove if needed)
- firingIndex,
- // Actual callback list
- list = [],
- // Stack of fire calls for repeatable lists
- stack = !options.once && [],
- // Fire callbacks
- fire = function( data ) {
- memory = options.memory && data;
- fired = true;
- firingIndex = firingStart || 0;
- firingStart = 0;
- firingLength = list.length;
- firing = true;
- for ( ; list && firingIndex < firingLength; firingIndex++ ) {
- if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
- memory = false; // To prevent further calls using add
- break;
- }
- }
- firing = false;
- if ( list ) {
- if ( stack ) {
- if ( stack.length ) {
- fire( stack.shift() );
- }
- } else if ( memory ) {
- list = [];
- } else {
- self.disable();
- }
- }
- },
- // Actual Callbacks object
- self = {
- // Add a callback or a collection of callbacks to the list
- add: function() {
- if ( list ) {
- // First, we save the current length
- var start = list.length;
- (function add( args ) {
- jQuery.each( args, function( _, arg ) {
- var type = jQuery.type( arg );
- if ( type === "function" ) {
- if ( !options.unique || !self.has( arg ) ) {
- list.push( arg );
- }
- } else if ( arg && arg.length && type !== "string" ) {
- // Inspect recursively
- add( arg );
- }
- });
- })( arguments );
- // Do we need to add the callbacks to the
- // current firing batch?
- if ( firing ) {
- firingLength = list.length;
- // With memory, if we're not firing then
- // we should call right away
- } else if ( memory ) {
- firingStart = start;
- fire( memory );
- }
- }
- return this;
- },
- // Remove a callback from the list
- remove: function() {
- if ( list ) {
- jQuery.each( arguments, function( _, arg ) {
- var index;
- while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
- list.splice( index, 1 );
- // Handle firing indexes
- if ( firing ) {
- if ( index <= firingLength ) {
- firingLength--;
- }
- if ( index <= firingIndex ) {
- firingIndex--;
- }
- }
- }
- });
- }
- return this;
- },
- // Check if a given callback is in the list.
- // If no argument is given, return whether or not list has callbacks attached.
- has: function( fn ) {
- return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
- },
- // Remove all callbacks from the list
- empty: function() {
- list = [];
- firingLength = 0;
- return this;
- },
- // Have the list do nothing anymore
- disable: function() {
- list = stack = memory = undefined;
- return this;
- },
- // Is it disabled?
- disabled: function() {
- return !list;
- },
- // Lock the list in its current state
- lock: function() {
- stack = undefined;
- if ( !memory ) {
- self.disable();
- }
- return this;
- },
- // Is it locked?
- locked: function() {
- return !stack;
- },
- // Call all callbacks with the given context and arguments
- fireWith: function( context, args ) {
- if ( list && ( !fired || stack ) ) {
- args = args || [];
- args = [ context, args.slice ? args.slice() : args ];
- if ( firing ) {
- stack.push( args );
- } else {
- fire( args );
- }
- }
- return this;
- },
- // Call all the callbacks with the given arguments
- fire: function() {
- self.fireWith( this, arguments );
- return this;
- },
- // To know if the callbacks have already been called at least once
- fired: function() {
- return !!fired;
- }
- };
-
- return self;
-};
-
-
-jQuery.extend({
-
- Deferred: function( func ) {
- var tuples = [
- // action, add listener, listener list, final state
- [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
- [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
- [ "notify", "progress", jQuery.Callbacks("memory") ]
- ],
- state = "pending",
- promise = {
- state: function() {
- return state;
- },
- always: function() {
- deferred.done( arguments ).fail( arguments );
- return this;
- },
- then: function( /* fnDone, fnFail, fnProgress */ ) {
- var fns = arguments;
- return jQuery.Deferred(function( newDefer ) {
- jQuery.each( tuples, function( i, tuple ) {
- var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
- // deferred[ done | fail | progress ] for forwarding actions to newDefer
- deferred[ tuple[1] ](function() {
- var returned = fn && fn.apply( this, arguments );
- if ( returned && jQuery.isFunction( returned.promise ) ) {
- returned.promise()
- .done( newDefer.resolve )
- .fail( newDefer.reject )
- .progress( newDefer.notify );
- } else {
- newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
- }
- });
- });
- fns = null;
- }).promise();
- },
- // Get a promise for this deferred
- // If obj is provided, the promise aspect is added to the object
- promise: function( obj ) {
- return obj != null ? jQuery.extend( obj, promise ) : promise;
- }
- },
- deferred = {};
-
- // Keep pipe for back-compat
- promise.pipe = promise.then;
-
- // Add list-specific methods
- jQuery.each( tuples, function( i, tuple ) {
- var list = tuple[ 2 ],
- stateString = tuple[ 3 ];
-
- // promise[ done | fail | progress ] = list.add
- promise[ tuple[1] ] = list.add;
-
- // Handle state
- if ( stateString ) {
- list.add(function() {
- // state = [ resolved | rejected ]
- state = stateString;
-
- // [ reject_list | resolve_list ].disable; progress_list.lock
- }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
- }
-
- // deferred[ resolve | reject | notify ]
- deferred[ tuple[0] ] = function() {
- deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
- return this;
- };
- deferred[ tuple[0] + "With" ] = list.fireWith;
- });
-
- // Make the deferred a promise
- promise.promise( deferred );
-
- // Call given func if any
- if ( func ) {
- func.call( deferred, deferred );
- }
-
- // All done!
- return deferred;
- },
-
- // Deferred helper
- when: function( subordinate /* , ..., subordinateN */ ) {
- var i = 0,
- resolveValues = slice.call( arguments ),
- length = resolveValues.length,
-
- // the count of uncompleted subordinates
- remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
-
- // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
- deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
-
- // Update function for both resolve and progress values
- updateFunc = function( i, contexts, values ) {
- return function( value ) {
- contexts[ i ] = this;
- values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
- if ( values === progressValues ) {
- deferred.notifyWith( contexts, values );
- } else if ( !( --remaining ) ) {
- deferred.resolveWith( contexts, values );
- }
- };
- },
-
- progressValues, progressContexts, resolveContexts;
-
- // add listeners to Deferred subordinates; treat others as resolved
- if ( length > 1 ) {
- progressValues = new Array( length );
- progressContexts = new Array( length );
- resolveContexts = new Array( length );
- for ( ; i < length; i++ ) {
- if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
- resolveValues[ i ].promise()
- .done( updateFunc( i, resolveContexts, resolveValues ) )
- .fail( deferred.reject )
- .progress( updateFunc( i, progressContexts, progressValues ) );
- } else {
- --remaining;
- }
- }
- }
-
- // if we're not waiting on anything, resolve the master
- if ( !remaining ) {
- deferred.resolveWith( resolveContexts, resolveValues );
- }
-
- return deferred.promise();
- }
-});
-
-
-// The deferred used on DOM ready
-var readyList;
-
-jQuery.fn.ready = function( fn ) {
- // Add the callback
- jQuery.ready.promise().done( fn );
-
- return this;
-};
-
-jQuery.extend({
- // Is the DOM ready to be used? Set to true once it occurs.
- isReady: false,
-
- // A counter to track how many items to wait for before
- // the ready event fires. See #6781
- readyWait: 1,
-
- // Hold (or release) the ready event
- holdReady: function( hold ) {
- if ( hold ) {
- jQuery.readyWait++;
- } else {
- jQuery.ready( true );
- }
- },
-
- // Handle when the DOM is ready
- ready: function( wait ) {
-
- // Abort if there are pending holds or we're already ready
- if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
- return;
- }
-
- // Remember that the DOM is ready
- jQuery.isReady = true;
-
- // If a normal DOM Ready event fired, decrement, and wait if need be
- if ( wait !== true && --jQuery.readyWait > 0 ) {
- return;
- }
-
- // If there are functions bound, to execute
- readyList.resolveWith( document, [ jQuery ] );
-
- // Trigger any bound ready events
- if ( jQuery.fn.triggerHandler ) {
- jQuery( document ).triggerHandler( "ready" );
- jQuery( document ).off( "ready" );
- }
- }
-});
-
-/**
- * The ready event handler and self cleanup method
- */
-function completed() {
- document.removeEventListener( "DOMContentLoaded", completed, false );
- window.removeEventListener( "load", completed, false );
- jQuery.ready();
-}
-
-jQuery.ready.promise = function( obj ) {
- if ( !readyList ) {
-
- readyList = jQuery.Deferred();
-
- // Catch cases where $(document).ready() is called after the browser event has already occurred.
- // we once tried to use readyState "interactive" here, but it caused issues like the one
- // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
- if ( document.readyState === "complete" ) {
- // Handle it asynchronously to allow scripts the opportunity to delay ready
- setTimeout( jQuery.ready );
-
- } else {
-
- // Use the handy event callback
- document.addEventListener( "DOMContentLoaded", completed, false );
-
- // A fallback to window.onload, that will always work
- window.addEventListener( "load", completed, false );
- }
- }
- return readyList.promise( obj );
-};
-
-// Kick off the DOM ready check even if the user does not
-jQuery.ready.promise();
-
-
-
-
-// Multifunctional method to get and set values of a collection
-// The value/s can optionally be executed if it's a function
-var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
- var i = 0,
- len = elems.length,
- bulk = key == null;
-
- // Sets many values
- if ( jQuery.type( key ) === "object" ) {
- chainable = true;
- for ( i in key ) {
- jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
- }
-
- // Sets one value
- } else if ( value !== undefined ) {
- chainable = true;
-
- if ( !jQuery.isFunction( value ) ) {
- raw = true;
- }
-
- if ( bulk ) {
- // Bulk operations run against the entire set
- if ( raw ) {
- fn.call( elems, value );
- fn = null;
-
- // ...except when executing function values
- } else {
- bulk = fn;
- fn = function( elem, key, value ) {
- return bulk.call( jQuery( elem ), value );
- };
- }
- }
-
- if ( fn ) {
- for ( ; i < len; i++ ) {
- fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
- }
- }
- }
-
- return chainable ?
- elems :
-
- // Gets
- bulk ?
- fn.call( elems ) :
- len ? fn( elems[0], key ) : emptyGet;
-};
-
-
-/**
- * Determines whether an object can have data
- */
-jQuery.acceptData = function( owner ) {
- // Accepts only:
- // - Node
- // - Node.ELEMENT_NODE
- // - Node.DOCUMENT_NODE
- // - Object
- // - Any
- /* jshint -W018 */
- return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
-};
-
-
-function Data() {
- // Support: Android < 4,
- // Old WebKit does not have Object.preventExtensions/freeze method,
- // return new empty object instead with no [[set]] accessor
- Object.defineProperty( this.cache = {}, 0, {
- get: function() {
- return {};
- }
- });
-
- this.expando = jQuery.expando + Math.random();
-}
-
-Data.uid = 1;
-Data.accepts = jQuery.acceptData;
-
-Data.prototype = {
- key: function( owner ) {
- // We can accept data for non-element nodes in modern browsers,
- // but we should not, see #8335.
- // Always return the key for a frozen object.
- if ( !Data.accepts( owner ) ) {
- return 0;
- }
-
- var descriptor = {},
- // Check if the owner object already has a cache key
- unlock = owner[ this.expando ];
-
- // If not, create one
- if ( !unlock ) {
- unlock = Data.uid++;
-
- // Secure it in a non-enumerable, non-writable property
- try {
- descriptor[ this.expando ] = { value: unlock };
- Object.defineProperties( owner, descriptor );
-
- // Support: Android < 4
- // Fallback to a less secure definition
- } catch ( e ) {
- descriptor[ this.expando ] = unlock;
- jQuery.extend( owner, descriptor );
- }
- }
-
- // Ensure the cache object
- if ( !this.cache[ unlock ] ) {
- this.cache[ unlock ] = {};
- }
-
- return unlock;
- },
- set: function( owner, data, value ) {
- var prop,
- // There may be an unlock assigned to this node,
- // if there is no entry for this "owner", create one inline
- // and set the unlock as though an owner entry had always existed
- unlock = this.key( owner ),
- cache = this.cache[ unlock ];
-
- // Handle: [ owner, key, value ] args
- if ( typeof data === "string" ) {
- cache[ data ] = value;
-
- // Handle: [ owner, { properties } ] args
- } else {
- // Fresh assignments by object are shallow copied
- if ( jQuery.isEmptyObject( cache ) ) {
- jQuery.extend( this.cache[ unlock ], data );
- // Otherwise, copy the properties one-by-one to the cache object
- } else {
- for ( prop in data ) {
- cache[ prop ] = data[ prop ];
- }
- }
- }
- return cache;
- },
- get: function( owner, key ) {
- // Either a valid cache is found, or will be created.
- // New caches will be created and the unlock returned,
- // allowing direct access to the newly created
- // empty data object. A valid owner object must be provided.
- var cache = this.cache[ this.key( owner ) ];
-
- return key === undefined ?
- cache : cache[ key ];
- },
- access: function( owner, key, value ) {
- var stored;
- // In cases where either:
- //
- // 1. No key was specified
- // 2. A string key was specified, but no value provided
- //
- // Take the "read" path and allow the get method to determine
- // which value to return, respectively either:
- //
- // 1. The entire cache object
- // 2. The data stored at the key
- //
- if ( key === undefined ||
- ((key && typeof key === "string") && value === undefined) ) {
-
- stored = this.get( owner, key );
-
- return stored !== undefined ?
- stored : this.get( owner, jQuery.camelCase(key) );
- }
-
- // [*]When the key is not a string, or both a key and value
- // are specified, set or extend (existing objects) with either:
- //
- // 1. An object of properties
- // 2. A key and value
- //
- this.set( owner, key, value );
-
- // Since the "set" path can have two possible entry points
- // return the expected data based on which path was taken[*]
- return value !== undefined ? value : key;
- },
- remove: function( owner, key ) {
- var i, name, camel,
- unlock = this.key( owner ),
- cache = this.cache[ unlock ];
-
- if ( key === undefined ) {
- this.cache[ unlock ] = {};
-
- } else {
- // Support array or space separated string of keys
- if ( jQuery.isArray( key ) ) {
- // If "name" is an array of keys...
- // When data is initially created, via ("key", "val") signature,
- // keys will be converted to camelCase.
- // Since there is no way to tell _how_ a key was added, remove
- // both plain key and camelCase key. #12786
- // This will only penalize the array argument path.
- name = key.concat( key.map( jQuery.camelCase ) );
- } else {
- camel = jQuery.camelCase( key );
- // Try the string as a key before any manipulation
- if ( key in cache ) {
- name = [ key, camel ];
- } else {
- // If a key with the spaces exists, use it.
- // Otherwise, create an array by matching non-whitespace
- name = camel;
- name = name in cache ?
- [ name ] : ( name.match( rnotwhite ) || [] );
- }
- }
-
- i = name.length;
- while ( i-- ) {
- delete cache[ name[ i ] ];
- }
- }
- },
- hasData: function( owner ) {
- return !jQuery.isEmptyObject(
- this.cache[ owner[ this.expando ] ] || {}
- );
- },
- discard: function( owner ) {
- if ( owner[ this.expando ] ) {
- delete this.cache[ owner[ this.expando ] ];
- }
- }
-};
-var data_priv = new Data();
-
-var data_user = new Data();
-
-
-
-/*
- Implementation Summary
-
- 1. Enforce API surface and semantic compatibility with 1.9.x branch
- 2. Improve the module's maintainability by reducing the storage
- paths to a single mechanism.
- 3. Use the same single mechanism to support "private" and "user" data.
- 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
- 5. Avoid exposing implementation details on user objects (eg. expando properties)
- 6. Provide a clear path for implementation upgrade to WeakMap in 2014
-*/
-var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
- rmultiDash = /([A-Z])/g;
-
-function dataAttr( elem, key, data ) {
- var name;
-
- // If nothing was found internally, try to fetch any
- // data from the HTML5 data-* attribute
- if ( data === undefined && elem.nodeType === 1 ) {
- name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
- data = elem.getAttribute( name );
-
- if ( typeof data === "string" ) {
- try {
- data = data === "true" ? true :
- data === "false" ? false :
- data === "null" ? null :
- // Only convert to a number if it doesn't change the string
- +data + "" === data ? +data :
- rbrace.test( data ) ? jQuery.parseJSON( data ) :
- data;
- } catch( e ) {}
-
- // Make sure we set the data so it isn't changed later
- data_user.set( elem, key, data );
- } else {
- data = undefined;
- }
- }
- return data;
-}
-
-jQuery.extend({
- hasData: function( elem ) {
- return data_user.hasData( elem ) || data_priv.hasData( elem );
- },
-
- data: function( elem, name, data ) {
- return data_user.access( elem, name, data );
- },
-
- removeData: function( elem, name ) {
- data_user.remove( elem, name );
- },
-
- // TODO: Now that all calls to _data and _removeData have been replaced
- // with direct calls to data_priv methods, these can be deprecated.
- _data: function( elem, name, data ) {
- return data_priv.access( elem, name, data );
- },
-
- _removeData: function( elem, name ) {
- data_priv.remove( elem, name );
- }
-});
-
-jQuery.fn.extend({
- data: function( key, value ) {
- var i, name, data,
- elem = this[ 0 ],
- attrs = elem && elem.attributes;
-
- // Gets all values
- if ( key === undefined ) {
- if ( this.length ) {
- data = data_user.get( elem );
-
- if ( elem.nodeType === 1 && !data_priv.get( elem, "hasDataAttrs" ) ) {
- i = attrs.length;
- while ( i-- ) {
-
- // Support: IE11+
- // The attrs elements can be null (#14894)
- if ( attrs[ i ] ) {
- name = attrs[ i ].name;
- if ( name.indexOf( "data-" ) === 0 ) {
- name = jQuery.camelCase( name.slice(5) );
- dataAttr( elem, name, data[ name ] );
- }
- }
- }
- data_priv.set( elem, "hasDataAttrs", true );
- }
- }
-
- return data;
- }
-
- // Sets multiple values
- if ( typeof key === "object" ) {
- return this.each(function() {
- data_user.set( this, key );
- });
- }
-
- return access( this, function( value ) {
- var data,
- camelKey = jQuery.camelCase( key );
-
- // The calling jQuery object (element matches) is not empty
- // (and therefore has an element appears at this[ 0 ]) and the
- // `value` parameter was not undefined. An empty jQuery object
- // will result in `undefined` for elem = this[ 0 ] which will
- // throw an exception if an attempt to read a data cache is made.
- if ( elem && value === undefined ) {
- // Attempt to get data from the cache
- // with the key as-is
- data = data_user.get( elem, key );
- if ( data !== undefined ) {
- return data;
- }
-
- // Attempt to get data from the cache
- // with the key camelized
- data = data_user.get( elem, camelKey );
- if ( data !== undefined ) {
- return data;
- }
-
- // Attempt to "discover" the data in
- // HTML5 custom data-* attrs
- data = dataAttr( elem, camelKey, undefined );
- if ( data !== undefined ) {
- return data;
- }
-
- // We tried really hard, but the data doesn't exist.
- return;
- }
-
- // Set the data...
- this.each(function() {
- // First, attempt to store a copy or reference of any
- // data that might've been store with a camelCased key.
- var data = data_user.get( this, camelKey );
-
- // For HTML5 data-* attribute interop, we have to
- // store property names with dashes in a camelCase form.
- // This might not apply to all properties...*
- data_user.set( this, camelKey, value );
-
- // *... In the case of properties that might _actually_
- // have dashes, we need to also store a copy of that
- // unchanged property.
- if ( key.indexOf("-") !== -1 && data !== undefined ) {
- data_user.set( this, key, value );
- }
- });
- }, null, value, arguments.length > 1, null, true );
- },
-
- removeData: function( key ) {
- return this.each(function() {
- data_user.remove( this, key );
- });
- }
-});
-
-
-jQuery.extend({
- queue: function( elem, type, data ) {
- var queue;
-
- if ( elem ) {
- type = ( type || "fx" ) + "queue";
- queue = data_priv.get( elem, type );
-
- // Speed up dequeue by getting out quickly if this is just a lookup
- if ( data ) {
- if ( !queue || jQuery.isArray( data ) ) {
- queue = data_priv.access( elem, type, jQuery.makeArray(data) );
- } else {
- queue.push( data );
- }
- }
- return queue || [];
- }
- },
-
- dequeue: function( elem, type ) {
- type = type || "fx";
-
- var queue = jQuery.queue( elem, type ),
- startLength = queue.length,
- fn = queue.shift(),
- hooks = jQuery._queueHooks( elem, type ),
- next = function() {
- jQuery.dequeue( elem, type );
- };
-
- // If the fx queue is dequeued, always remove the progress sentinel
- if ( fn === "inprogress" ) {
- fn = queue.shift();
- startLength--;
- }
-
- if ( fn ) {
-
- // Add a progress sentinel to prevent the fx queue from being
- // automatically dequeued
- if ( type === "fx" ) {
- queue.unshift( "inprogress" );
- }
-
- // clear up the last queue stop function
- delete hooks.stop;
- fn.call( elem, next, hooks );
- }
-
- if ( !startLength && hooks ) {
- hooks.empty.fire();
- }
- },
-
- // not intended for public consumption - generates a queueHooks object, or returns the current one
- _queueHooks: function( elem, type ) {
- var key = type + "queueHooks";
- return data_priv.get( elem, key ) || data_priv.access( elem, key, {
- empty: jQuery.Callbacks("once memory").add(function() {
- data_priv.remove( elem, [ type + "queue", key ] );
- })
- });
- }
-});
-
-jQuery.fn.extend({
- queue: function( type, data ) {
- var setter = 2;
-
- if ( typeof type !== "string" ) {
- data = type;
- type = "fx";
- setter--;
- }
-
- if ( arguments.length < setter ) {
- return jQuery.queue( this[0], type );
- }
-
- return data === undefined ?
- this :
- this.each(function() {
- var queue = jQuery.queue( this, type, data );
-
- // ensure a hooks for this queue
- jQuery._queueHooks( this, type );
-
- if ( type === "fx" && queue[0] !== "inprogress" ) {
- jQuery.dequeue( this, type );
- }
- });
- },
- dequeue: function( type ) {
- return this.each(function() {
- jQuery.dequeue( this, type );
- });
- },
- clearQueue: function( type ) {
- return this.queue( type || "fx", [] );
- },
- // Get a promise resolved when queues of a certain type
- // are emptied (fx is the type by default)
- promise: function( type, obj ) {
- var tmp,
- count = 1,
- defer = jQuery.Deferred(),
- elements = this,
- i = this.length,
- resolve = function() {
- if ( !( --count ) ) {
- defer.resolveWith( elements, [ elements ] );
- }
- };
-
- if ( typeof type !== "string" ) {
- obj = type;
- type = undefined;
- }
- type = type || "fx";
-
- while ( i-- ) {
- tmp = data_priv.get( elements[ i ], type + "queueHooks" );
- if ( tmp && tmp.empty ) {
- count++;
- tmp.empty.add( resolve );
- }
- }
- resolve();
- return defer.promise( obj );
- }
-});
-var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source;
-
-var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
-
-var isHidden = function( elem, el ) {
- // isHidden might be called from jQuery#filter function;
- // in that case, element will be second argument
- elem = el || elem;
- return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
- };
-
-var rcheckableType = (/^(?:checkbox|radio)$/i);
-
-
-
-(function() {
- var fragment = document.createDocumentFragment(),
- div = fragment.appendChild( document.createElement( "div" ) ),
- input = document.createElement( "input" );
-
- // #11217 - WebKit loses check when the name is after the checked attribute
- // Support: Windows Web Apps (WWA)
- // `name` and `type` need .setAttribute for WWA
- input.setAttribute( "type", "radio" );
- input.setAttribute( "checked", "checked" );
- input.setAttribute( "name", "t" );
-
- div.appendChild( input );
-
- // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
- // old WebKit doesn't clone checked state correctly in fragments
- support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
-
- // Make sure textarea (and checkbox) defaultValue is properly cloned
- // Support: IE9-IE11+
- div.innerHTML = "<textarea>x</textarea>";
- support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
-})();
-var strundefined = typeof undefined;
-
-
-
-support.focusinBubbles = "onfocusin" in window;
-
-
-var
- rkeyEvent = /^key/,
- rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/,
- rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
- rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
-
-function returnTrue() {
- return true;
-}
-
-function returnFalse() {
- return false;
-}
-
-function safeActiveElement() {
- try {
- return document.activeElement;
- } catch ( err ) { }
-}
-
-/*
- * Helper functions for managing events -- not part of the public interface.
- * Props to Dean Edwards' addEvent library for many of the ideas.
- */
-jQuery.event = {
-
- global: {},
-
- add: function( elem, types, handler, data, selector ) {
-
- var handleObjIn, eventHandle, tmp,
- events, t, handleObj,
- special, handlers, type, namespaces, origType,
- elemData = data_priv.get( elem );
-
- // Don't attach events to noData or text/comment nodes (but allow plain objects)
- if ( !elemData ) {
- return;
- }
-
- // Caller can pass in an object of custom data in lieu of the handler
- if ( handler.handler ) {
- handleObjIn = handler;
- handler = handleObjIn.handler;
- selector = handleObjIn.selector;
- }
-
- // Make sure that the handler has a unique ID, used to find/remove it later
- if ( !handler.guid ) {
- handler.guid = jQuery.guid++;
- }
-
- // Init the element's event structure and main handler, if this is the first
- if ( !(events = elemData.events) ) {
- events = elemData.events = {};
- }
- if ( !(eventHandle = elemData.handle) ) {
- eventHandle = elemData.handle = function( e ) {
- // Discard the second event of a jQuery.event.trigger() and
- // when an event is called after a page has unloaded
- return typeof jQuery !== strundefined && jQuery.event.triggered !== e.type ?
- jQuery.event.dispatch.apply( elem, arguments ) : undefined;
- };
- }
-
- // Handle multiple events separated by a space
- types = ( types || "" ).match( rnotwhite ) || [ "" ];
- t = types.length;
- while ( t-- ) {
- tmp = rtypenamespace.exec( types[t] ) || [];
- type = origType = tmp[1];
- namespaces = ( tmp[2] || "" ).split( "." ).sort();
-
- // There *must* be a type, no attaching namespace-only handlers
- if ( !type ) {
- continue;
- }
-
- // If event changes its type, use the special event handlers for the changed type
- special = jQuery.event.special[ type ] || {};
-
- // If selector defined, determine special event api type, otherwise given type
- type = ( selector ? special.delegateType : special.bindType ) || type;
-
- // Update special based on newly reset type
- special = jQuery.event.special[ type ] || {};
-
- // handleObj is passed to all event handlers
- handleObj = jQuery.extend({
- type: type,
- origType: origType,
- data: data,
- handler: handler,
- guid: handler.guid,
- selector: selector,
- needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
- namespace: namespaces.join(".")
- }, handleObjIn );
-
- // Init the event handler queue if we're the first
- if ( !(handlers = events[ type ]) ) {
- handlers = events[ type ] = [];
- handlers.delegateCount = 0;
-
- // Only use addEventListener if the special events handler returns false
- if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
- if ( elem.addEventListener ) {
- elem.addEventListener( type, eventHandle, false );
- }
- }
- }
-
- if ( special.add ) {
- special.add.call( elem, handleObj );
-
- if ( !handleObj.handler.guid ) {
- handleObj.handler.guid = handler.guid;
- }
- }
-
- // Add to the element's handler list, delegates in front
- if ( selector ) {
- handlers.splice( handlers.delegateCount++, 0, handleObj );
- } else {
- handlers.push( handleObj );
- }
-
- // Keep track of which events have ever been used, for event optimization
- jQuery.event.global[ type ] = true;
- }
-
- },
-
- // Detach an event or set of events from an element
- remove: function( elem, types, handler, selector, mappedTypes ) {
-
- var j, origCount, tmp,
- events, t, handleObj,
- special, handlers, type, namespaces, origType,
- elemData = data_priv.hasData( elem ) && data_priv.get( elem );
-
- if ( !elemData || !(events = elemData.events) ) {
- return;
- }
-
- // Once for each type.namespace in types; type may be omitted
- types = ( types || "" ).match( rnotwhite ) || [ "" ];
- t = types.length;
- while ( t-- ) {
- tmp = rtypenamespace.exec( types[t] ) || [];
- type = origType = tmp[1];
- namespaces = ( tmp[2] || "" ).split( "." ).sort();
-
- // Unbind all events (on this namespace, if provided) for the element
- if ( !type ) {
- for ( type in events ) {
- jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
- }
- continue;
- }
-
- special = jQuery.event.special[ type ] || {};
- type = ( selector ? special.delegateType : special.bindType ) || type;
- handlers = events[ type ] || [];
- tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
-
- // Remove matching events
- origCount = j = handlers.length;
- while ( j-- ) {
- handleObj = handlers[ j ];
-
- if ( ( mappedTypes || origType === handleObj.origType ) &&
- ( !handler || handler.guid === handleObj.guid ) &&
- ( !tmp || tmp.test( handleObj.namespace ) ) &&
- ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
- handlers.splice( j, 1 );
-
- if ( handleObj.selector ) {
- handlers.delegateCount--;
- }
- if ( special.remove ) {
- special.remove.call( elem, handleObj );
- }
- }
- }
-
- // Remove generic event handler if we removed something and no more handlers exist
- // (avoids potential for endless recursion during removal of special event handlers)
- if ( origCount && !handlers.length ) {
- if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
- jQuery.removeEvent( elem, type, elemData.handle );
- }
-
- delete events[ type ];
- }
- }
-
- // Remove the expando if it's no longer used
- if ( jQuery.isEmptyObject( events ) ) {
- delete elemData.handle;
- data_priv.remove( elem, "events" );
- }
- },
-
- trigger: function( event, data, elem, onlyHandlers ) {
-
- var i, cur, tmp, bubbleType, ontype, handle, special,
- eventPath = [ elem || document ],
- type = hasOwn.call( event, "type" ) ? event.type : event,
- namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
-
- cur = tmp = elem = elem || document;
-
- // Don't do events on text and comment nodes
- if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
- return;
- }
-
- // focus/blur morphs to focusin/out; ensure we're not firing them right now
- if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
- return;
- }
-
- if ( type.indexOf(".") >= 0 ) {
- // Namespaced trigger; create a regexp to match event type in handle()
- namespaces = type.split(".");
- type = namespaces.shift();
- namespaces.sort();
- }
- ontype = type.indexOf(":") < 0 && "on" + type;
-
- // Caller can pass in a jQuery.Event object, Object, or just an event type string
- event = event[ jQuery.expando ] ?
- event :
- new jQuery.Event( type, typeof event === "object" && event );
-
- // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
- event.isTrigger = onlyHandlers ? 2 : 3;
- event.namespace = namespaces.join(".");
- event.namespace_re = event.namespace ?
- new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
- null;
-
- // Clean up the event in case it is being reused
- event.result = undefined;
- if ( !event.target ) {
- event.target = elem;
- }
-
- // Clone any incoming data and prepend the event, creating the handler arg list
- data = data == null ?
- [ event ] :
- jQuery.makeArray( data, [ event ] );
-
- // Allow special events to draw outside the lines
- special = jQuery.event.special[ type ] || {};
- if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
- return;
- }
-
- // Determine event propagation path in advance, per W3C events spec (#9951)
- // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
- if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
-
- bubbleType = special.delegateType || type;
- if ( !rfocusMorph.test( bubbleType + type ) ) {
- cur = cur.parentNode;
- }
- for ( ; cur; cur = cur.parentNode ) {
- eventPath.push( cur );
- tmp = cur;
- }
-
- // Only add window if we got to document (e.g., not plain obj or detached DOM)
- if ( tmp === (elem.ownerDocument || document) ) {
- eventPath.push( tmp.defaultView || tmp.parentWindow || window );
- }
- }
-
- // Fire handlers on the event path
- i = 0;
- while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
-
- event.type = i > 1 ?
- bubbleType :
- special.bindType || type;
-
- // jQuery handler
- handle = ( data_priv.get( cur, "events" ) || {} )[ event.type ] && data_priv.get( cur, "handle" );
- if ( handle ) {
- handle.apply( cur, data );
- }
-
- // Native handler
- handle = ontype && cur[ ontype ];
- if ( handle && handle.apply && jQuery.acceptData( cur ) ) {
- event.result = handle.apply( cur, data );
- if ( event.result === false ) {
- event.preventDefault();
- }
- }
- }
- event.type = type;
-
- // If nobody prevented the default action, do it now
- if ( !onlyHandlers && !event.isDefaultPrevented() ) {
-
- if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
- jQuery.acceptData( elem ) ) {
-
- // Call a native DOM method on the target with the same name name as the event.
- // Don't do default actions on window, that's where global variables be (#6170)
- if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {
-
- // Don't re-trigger an onFOO event when we call its FOO() method
- tmp = elem[ ontype ];
-
- if ( tmp ) {
- elem[ ontype ] = null;
- }
-
- // Prevent re-triggering of the same event, since we already bubbled it above
- jQuery.event.triggered = type;
- elem[ type ]();
- jQuery.event.triggered = undefined;
-
- if ( tmp ) {
- elem[ ontype ] = tmp;
- }
- }
- }
- }
-
- return event.result;
- },
-
- dispatch: function( event ) {
-
- // Make a writable jQuery.Event from the native event object
- event = jQuery.event.fix( event );
-
- var i, j, ret, matched, handleObj,
- handlerQueue = [],
- args = slice.call( arguments ),
- handlers = ( data_priv.get( this, "events" ) || {} )[ event.type ] || [],
- special = jQuery.event.special[ event.type ] || {};
-
- // Use the fix-ed jQuery.Event rather than the (read-only) native event
- args[0] = event;
- event.delegateTarget = this;
-
- // Call the preDispatch hook for the mapped type, and let it bail if desired
- if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
- return;
- }
-
- // Determine handlers
- handlerQueue = jQuery.event.handlers.call( this, event, handlers );
-
- // Run delegates first; they may want to stop propagation beneath us
- i = 0;
- while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
- event.currentTarget = matched.elem;
-
- j = 0;
- while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
-
- // Triggered event must either 1) have no namespace, or
- // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
- if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
-
- event.handleObj = handleObj;
- event.data = handleObj.data;
-
- ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
- .apply( matched.elem, args );
-
- if ( ret !== undefined ) {
- if ( (event.result = ret) === false ) {
- event.preventDefault();
- event.stopPropagation();
- }
- }
- }
- }
- }
-
- // Call the postDispatch hook for the mapped type
- if ( special.postDispatch ) {
- special.postDispatch.call( this, event );
- }
-
- return event.result;
- },
-
- handlers: function( event, handlers ) {
- var i, matches, sel, handleObj,
- handlerQueue = [],
- delegateCount = handlers.delegateCount,
- cur = event.target;
-
- // Find delegate handlers
- // Black-hole SVG <use> instance trees (#13180)
- // Avoid non-left-click bubbling in Firefox (#3861)
- if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
-
- for ( ; cur !== this; cur = cur.parentNode || this ) {
-
- // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
- if ( cur.disabled !== true || event.type !== "click" ) {
- matches = [];
- for ( i = 0; i < delegateCount; i++ ) {
- handleObj = handlers[ i ];
-
- // Don't conflict with Object.prototype properties (#13203)
- sel = handleObj.selector + " ";
-
- if ( matches[ sel ] === undefined ) {
- matches[ sel ] = handleObj.needsContext ?
- jQuery( sel, this ).index( cur ) >= 0 :
- jQuery.find( sel, this, null, [ cur ] ).length;
- }
- if ( matches[ sel ] ) {
- matches.push( handleObj );
- }
- }
- if ( matches.length ) {
- handlerQueue.push({ elem: cur, handlers: matches });
- }
- }
- }
- }
-
- // Add the remaining (directly-bound) handlers
- if ( delegateCount < handlers.length ) {
- handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
- }
-
- return handlerQueue;
- },
-
- // Includes some event props shared by KeyEvent and MouseEvent
- props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
-
- fixHooks: {},
-
- keyHooks: {
- props: "char charCode key keyCode".split(" "),
- filter: function( event, original ) {
-
- // Add which for key events
- if ( event.which == null ) {
- event.which = original.charCode != null ? original.charCode : original.keyCode;
- }
-
- return event;
- }
- },
-
- mouseHooks: {
- props: "button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
- filter: function( event, original ) {
- var eventDoc, doc, body,
- button = original.button;
-
- // Calculate pageX/Y if missing and clientX/Y available
- if ( event.pageX == null && original.clientX != null ) {
- eventDoc = event.target.ownerDocument || document;
- doc = eventDoc.documentElement;
- body = eventDoc.body;
-
- event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
- event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
- }
-
- // Add which for click: 1 === left; 2 === middle; 3 === right
- // Note: button is not normalized, so don't use it
- if ( !event.which && button !== undefined ) {
- event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
- }
-
- return event;
- }
- },
-
- fix: function( event ) {
- if ( event[ jQuery.expando ] ) {
- return event;
- }
-
- // Create a writable copy of the event object and normalize some properties
- var i, prop, copy,
- type = event.type,
- originalEvent = event,
- fixHook = this.fixHooks[ type ];
-
- if ( !fixHook ) {
- this.fixHooks[ type ] = fixHook =
- rmouseEvent.test( type ) ? this.mouseHooks :
- rkeyEvent.test( type ) ? this.keyHooks :
- {};
- }
- copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
-
- event = new jQuery.Event( originalEvent );
-
- i = copy.length;
- while ( i-- ) {
- prop = copy[ i ];
- event[ prop ] = originalEvent[ prop ];
- }
-
- // Support: Cordova 2.5 (WebKit) (#13255)
- // All events should have a target; Cordova deviceready doesn't
- if ( !event.target ) {
- event.target = document;
- }
-
- // Support: Safari 6.0+, Chrome < 28
- // Target should not be a text node (#504, #13143)
- if ( event.target.nodeType === 3 ) {
- event.target = event.target.parentNode;
- }
-
- return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
- },
-
- special: {
- load: {
- // Prevent triggered image.load events from bubbling to window.load
- noBubble: true
- },
- focus: {
- // Fire native event if possible so blur/focus sequence is correct
- trigger: function() {
- if ( this !== safeActiveElement() && this.focus ) {
- this.focus();
- return false;
- }
- },
- delegateType: "focusin"
- },
- blur: {
- trigger: function() {
- if ( this === safeActiveElement() && this.blur ) {
- this.blur();
- return false;
- }
- },
- delegateType: "focusout"
- },
- click: {
- // For checkbox, fire native event so checked state will be right
- trigger: function() {
- if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) {
- this.click();
- return false;
- }
- },
-
- // For cross-browser consistency, don't fire native .click() on links
- _default: function( event ) {
- return jQuery.nodeName( event.target, "a" );
- }
- },
-
- beforeunload: {
- postDispatch: function( event ) {
-
- // Support: Firefox 20+
- // Firefox doesn't alert if the returnValue field is not set.
- if ( event.result !== undefined && event.originalEvent ) {
- event.originalEvent.returnValue = event.result;
- }
- }
- }
- },
-
- simulate: function( type, elem, event, bubble ) {
- // Piggyback on a donor event to simulate a different one.
- // Fake originalEvent to avoid donor's stopPropagation, but if the
- // simulated event prevents default then we do the same on the donor.
- var e = jQuery.extend(
- new jQuery.Event(),
- event,
- {
- type: type,
- isSimulated: true,
- originalEvent: {}
- }
- );
- if ( bubble ) {
- jQuery.event.trigger( e, null, elem );
- } else {
- jQuery.event.dispatch.call( elem, e );
- }
- if ( e.isDefaultPrevented() ) {
- event.preventDefault();
- }
- }
-};
-
-jQuery.removeEvent = function( elem, type, handle ) {
- if ( elem.removeEventListener ) {
- elem.removeEventListener( type, handle, false );
- }
-};
-
-jQuery.Event = function( src, props ) {
- // Allow instantiation without the 'new' keyword
- if ( !(this instanceof jQuery.Event) ) {
- return new jQuery.Event( src, props );
- }
-
- // Event object
- if ( src && src.type ) {
- this.originalEvent = src;
- this.type = src.type;
-
- // Events bubbling up the document may have been marked as prevented
- // by a handler lower down the tree; reflect the correct value.
- this.isDefaultPrevented = src.defaultPrevented ||
- src.defaultPrevented === undefined &&
- // Support: Android < 4.0
- src.returnValue === false ?
- returnTrue :
- returnFalse;
-
- // Event type
- } else {
- this.type = src;
- }
-
- // Put explicitly provided properties onto the event object
- if ( props ) {
- jQuery.extend( this, props );
- }
-
- // Create a timestamp if incoming event doesn't have one
- this.timeStamp = src && src.timeStamp || jQuery.now();
-
- // Mark it as fixed
- this[ jQuery.expando ] = true;
-};
-
-// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
-// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
-jQuery.Event.prototype = {
- isDefaultPrevented: returnFalse,
- isPropagationStopped: returnFalse,
- isImmediatePropagationStopped: returnFalse,
-
- preventDefault: function() {
- var e = this.originalEvent;
-
- this.isDefaultPrevented = returnTrue;
-
- if ( e && e.preventDefault ) {
- e.preventDefault();
- }
- },
- stopPropagation: function() {
- var e = this.originalEvent;
-
- this.isPropagationStopped = returnTrue;
-
- if ( e && e.stopPropagation ) {
- e.stopPropagation();
- }
- },
- stopImmediatePropagation: function() {
- var e = this.originalEvent;
-
- this.isImmediatePropagationStopped = returnTrue;
-
- if ( e && e.stopImmediatePropagation ) {
- e.stopImmediatePropagation();
- }
-
- this.stopPropagation();
- }
-};
-
-// Create mouseenter/leave events using mouseover/out and event-time checks
-// Support: Chrome 15+
-jQuery.each({
- mouseenter: "mouseover",
- mouseleave: "mouseout",
- pointerenter: "pointerover",
- pointerleave: "pointerout"
-}, function( orig, fix ) {
- jQuery.event.special[ orig ] = {
- delegateType: fix,
- bindType: fix,
-
- handle: function( event ) {
- var ret,
- target = this,
- related = event.relatedTarget,
- handleObj = event.handleObj;
-
- // For mousenter/leave call the handler if related is outside the target.
- // NB: No relatedTarget if the mouse left/entered the browser window
- if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
- event.type = handleObj.origType;
- ret = handleObj.handler.apply( this, arguments );
- event.type = fix;
- }
- return ret;
- }
- };
-});
-
-// Create "bubbling" focus and blur events
-// Support: Firefox, Chrome, Safari
-if ( !support.focusinBubbles ) {
- jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
-
- // Attach a single capturing handler on the document while someone wants focusin/focusout
- var handler = function( event ) {
- jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
- };
-
- jQuery.event.special[ fix ] = {
- setup: function() {
- var doc = this.ownerDocument || this,
- attaches = data_priv.access( doc, fix );
-
- if ( !attaches ) {
- doc.addEventListener( orig, handler, true );
- }
- data_priv.access( doc, fix, ( attaches || 0 ) + 1 );
- },
- teardown: function() {
- var doc = this.ownerDocument || this,
- attaches = data_priv.access( doc, fix ) - 1;
-
- if ( !attaches ) {
- doc.removeEventListener( orig, handler, true );
- data_priv.remove( doc, fix );
-
- } else {
- data_priv.access( doc, fix, attaches );
- }
- }
- };
- });
-}
-
-jQuery.fn.extend({
-
- on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
- var origFn, type;
-
- // Types can be a map of types/handlers
- if ( typeof types === "object" ) {
- // ( types-Object, selector, data )
- if ( typeof selector !== "string" ) {
- // ( types-Object, data )
- data = data || selector;
- selector = undefined;
- }
- for ( type in types ) {
- this.on( type, selector, data, types[ type ], one );
- }
- return this;
- }
-
- if ( data == null && fn == null ) {
- // ( types, fn )
- fn = selector;
- data = selector = undefined;
- } else if ( fn == null ) {
- if ( typeof selector === "string" ) {
- // ( types, selector, fn )
- fn = data;
- data = undefined;
- } else {
- // ( types, data, fn )
- fn = data;
- data = selector;
- selector = undefined;
- }
- }
- if ( fn === false ) {
- fn = returnFalse;
- } else if ( !fn ) {
- return this;
- }
-
- if ( one === 1 ) {
- origFn = fn;
- fn = function( event ) {
- // Can use an empty set, since event contains the info
- jQuery().off( event );
- return origFn.apply( this, arguments );
- };
- // Use same guid so caller can remove using origFn
- fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
- }
- return this.each( function() {
- jQuery.event.add( this, types, fn, data, selector );
- });
- },
- one: function( types, selector, data, fn ) {
- return this.on( types, selector, data, fn, 1 );
- },
- off: function( types, selector, fn ) {
- var handleObj, type;
- if ( types && types.preventDefault && types.handleObj ) {
- // ( event ) dispatched jQuery.Event
- handleObj = types.handleObj;
- jQuery( types.delegateTarget ).off(
- handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
- handleObj.selector,
- handleObj.handler
- );
- return this;
- }
- if ( typeof types === "object" ) {
- // ( types-object [, selector] )
- for ( type in types ) {
- this.off( type, selector, types[ type ] );
- }
- return this;
- }
- if ( selector === false || typeof selector === "function" ) {
- // ( types [, fn] )
- fn = selector;
- selector = undefined;
- }
- if ( fn === false ) {
- fn = returnFalse;
- }
- return this.each(function() {
- jQuery.event.remove( this, types, fn, selector );
- });
- },
-
- trigger: function( type, data ) {
- return this.each(function() {
- jQuery.event.trigger( type, data, this );
- });
- },
- triggerHandler: function( type, data ) {
- var elem = this[0];
- if ( elem ) {
- return jQuery.event.trigger( type, data, elem, true );
- }
- }
-});
-
-
-var
- rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
- rtagName = /<([\w:]+)/,
- rhtml = /<|&#?\w+;/,
- rnoInnerhtml = /<(?:script|style|link)/i,
- // checked="checked" or checked
- rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
- rscriptType = /^$|\/(?:java|ecma)script/i,
- rscriptTypeMasked = /^true\/(.*)/,
- rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
-
- // We have to close these tags to support XHTML (#13200)
- wrapMap = {
-
- // Support: IE 9
- option: [ 1, "<select multiple='multiple'>", "</select>" ],
-
- thead: [ 1, "<table>", "</table>" ],
- col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
- tr: [ 2, "<table><tbody>", "</tbody></table>" ],
- td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
-
- _default: [ 0, "", "" ]
- };
-
-// Support: IE 9
-wrapMap.optgroup = wrapMap.option;
-
-wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
-wrapMap.th = wrapMap.td;
-
-// Support: 1.x compatibility
-// Manipulating tables requires a tbody
-function manipulationTarget( elem, content ) {
- return jQuery.nodeName( elem, "table" ) &&
- jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ?
-
- elem.getElementsByTagName("tbody")[0] ||
- elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
- elem;
-}
-
-// Replace/restore the type attribute of script elements for safe DOM manipulation
-function disableScript( elem ) {
- elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type;
- return elem;
-}
-function restoreScript( elem ) {
- var match = rscriptTypeMasked.exec( elem.type );
-
- if ( match ) {
- elem.type = match[ 1 ];
- } else {
- elem.removeAttribute("type");
- }
-
- return elem;
-}
-
-// Mark scripts as having already been evaluated
-function setGlobalEval( elems, refElements ) {
- var i = 0,
- l = elems.length;
-
- for ( ; i < l; i++ ) {
- data_priv.set(
- elems[ i ], "globalEval", !refElements || data_priv.get( refElements[ i ], "globalEval" )
- );
- }
-}
-
-function cloneCopyEvent( src, dest ) {
- var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
-
- if ( dest.nodeType !== 1 ) {
- return;
- }
-
- // 1. Copy private data: events, handlers, etc.
- if ( data_priv.hasData( src ) ) {
- pdataOld = data_priv.access( src );
- pdataCur = data_priv.set( dest, pdataOld );
- events = pdataOld.events;
-
- if ( events ) {
- delete pdataCur.handle;
- pdataCur.events = {};
-
- for ( type in events ) {
- for ( i = 0, l = events[ type ].length; i < l; i++ ) {
- jQuery.event.add( dest, type, events[ type ][ i ] );
- }
- }
- }
- }
-
- // 2. Copy user data
- if ( data_user.hasData( src ) ) {
- udataOld = data_user.access( src );
- udataCur = jQuery.extend( {}, udataOld );
-
- data_user.set( dest, udataCur );
- }
-}
-
-function getAll( context, tag ) {
- var ret = context.getElementsByTagName ? context.getElementsByTagName( tag || "*" ) :
- context.querySelectorAll ? context.querySelectorAll( tag || "*" ) :
- [];
-
- return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
- jQuery.merge( [ context ], ret ) :
- ret;
-}
-
-// Support: IE >= 9
-function fixInput( src, dest ) {
- var nodeName = dest.nodeName.toLowerCase();
-
- // Fails to persist the checked state of a cloned checkbox or radio button.
- if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
- dest.checked = src.checked;
-
- // Fails to return the selected option to the default selected state when cloning options
- } else if ( nodeName === "input" || nodeName === "textarea" ) {
- dest.defaultValue = src.defaultValue;
- }
-}
-
-jQuery.extend({
- clone: function( elem, dataAndEvents, deepDataAndEvents ) {
- var i, l, srcElements, destElements,
- clone = elem.cloneNode( true ),
- inPage = jQuery.contains( elem.ownerDocument, elem );
-
- // Support: IE >= 9
- // Fix Cloning issues
- if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
- !jQuery.isXMLDoc( elem ) ) {
-
- // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
- destElements = getAll( clone );
- srcElements = getAll( elem );
-
- for ( i = 0, l = srcElements.length; i < l; i++ ) {
- fixInput( srcElements[ i ], destElements[ i ] );
- }
- }
-
- // Copy the events from the original to the clone
- if ( dataAndEvents ) {
- if ( deepDataAndEvents ) {
- srcElements = srcElements || getAll( elem );
- destElements = destElements || getAll( clone );
-
- for ( i = 0, l = srcElements.length; i < l; i++ ) {
- cloneCopyEvent( srcElements[ i ], destElements[ i ] );
- }
- } else {
- cloneCopyEvent( elem, clone );
- }
- }
-
- // Preserve script evaluation history
- destElements = getAll( clone, "script" );
- if ( destElements.length > 0 ) {
- setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
- }
-
- // Return the cloned set
- return clone;
- },
-
- buildFragment: function( elems, context, scripts, selection ) {
- var elem, tmp, tag, wrap, contains, j,
- fragment = context.createDocumentFragment(),
- nodes = [],
- i = 0,
- l = elems.length;
-
- for ( ; i < l; i++ ) {
- elem = elems[ i ];
-
- if ( elem || elem === 0 ) {
-
- // Add nodes directly
- if ( jQuery.type( elem ) === "object" ) {
- // Support: QtWebKit
- // jQuery.merge because push.apply(_, arraylike) throws
- jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
-
- // Convert non-html into a text node
- } else if ( !rhtml.test( elem ) ) {
- nodes.push( context.createTextNode( elem ) );
-
- // Convert html into DOM nodes
- } else {
- tmp = tmp || fragment.appendChild( context.createElement("div") );
-
- // Deserialize a standard representation
- tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
- wrap = wrapMap[ tag ] || wrapMap._default;
- tmp.innerHTML = wrap[ 1 ] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[ 2 ];
-
- // Descend through wrappers to the right content
- j = wrap[ 0 ];
- while ( j-- ) {
- tmp = tmp.lastChild;
- }
-
- // Support: QtWebKit
- // jQuery.merge because push.apply(_, arraylike) throws
- jQuery.merge( nodes, tmp.childNodes );
-
- // Remember the top-level container
- tmp = fragment.firstChild;
-
- // Fixes #12346
- // Support: Webkit, IE
- tmp.textContent = "";
- }
- }
- }
-
- // Remove wrapper from fragment
- fragment.textContent = "";
-
- i = 0;
- while ( (elem = nodes[ i++ ]) ) {
-
- // #4087 - If origin and destination elements are the same, and this is
- // that element, do not do anything
- if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
- continue;
- }
-
- contains = jQuery.contains( elem.ownerDocument, elem );
-
- // Append to fragment
- tmp = getAll( fragment.appendChild( elem ), "script" );
-
- // Preserve script evaluation history
- if ( contains ) {
- setGlobalEval( tmp );
- }
-
- // Capture executables
- if ( scripts ) {
- j = 0;
- while ( (elem = tmp[ j++ ]) ) {
- if ( rscriptType.test( elem.type || "" ) ) {
- scripts.push( elem );
- }
- }
- }
- }
-
- return fragment;
- },
-
- cleanData: function( elems ) {
- var data, elem, type, key,
- special = jQuery.event.special,
- i = 0;
-
- for ( ; (elem = elems[ i ]) !== undefined; i++ ) {
- if ( jQuery.acceptData( elem ) ) {
- key = elem[ data_priv.expando ];
-
- if ( key && (data = data_priv.cache[ key ]) ) {
- if ( data.events ) {
- for ( type in data.events ) {
- if ( special[ type ] ) {
- jQuery.event.remove( elem, type );
-
- // This is a shortcut to avoid jQuery.event.remove's overhead
- } else {
- jQuery.removeEvent( elem, type, data.handle );
- }
- }
- }
- if ( data_priv.cache[ key ] ) {
- // Discard any remaining `private` data
- delete data_priv.cache[ key ];
- }
- }
- }
- // Discard any remaining `user` data
- delete data_user.cache[ elem[ data_user.expando ] ];
- }
- }
-});
-
-jQuery.fn.extend({
- text: function( value ) {
- return access( this, function( value ) {
- return value === undefined ?
- jQuery.text( this ) :
- this.empty().each(function() {
- if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
- this.textContent = value;
- }
- });
- }, null, value, arguments.length );
- },
-
- append: function() {
- return this.domManip( arguments, function( elem ) {
- if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
- var target = manipulationTarget( this, elem );
- target.appendChild( elem );
- }
- });
- },
-
- prepend: function() {
- return this.domManip( arguments, function( elem ) {
- if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
- var target = manipulationTarget( this, elem );
- target.insertBefore( elem, target.firstChild );
- }
- });
- },
-
- before: function() {
- return this.domManip( arguments, function( elem ) {
- if ( this.parentNode ) {
- this.parentNode.insertBefore( elem, this );
- }
- });
- },
-
- after: function() {
- return this.domManip( arguments, function( elem ) {
- if ( this.parentNode ) {
- this.parentNode.insertBefore( elem, this.nextSibling );
- }
- });
- },
-
- remove: function( selector, keepData /* Internal Use Only */ ) {
- var elem,
- elems = selector ? jQuery.filter( selector, this ) : this,
- i = 0;
-
- for ( ; (elem = elems[i]) != null; i++ ) {
- if ( !keepData && elem.nodeType === 1 ) {
- jQuery.cleanData( getAll( elem ) );
- }
-
- if ( elem.parentNode ) {
- if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
- setGlobalEval( getAll( elem, "script" ) );
- }
- elem.parentNode.removeChild( elem );
- }
- }
-
- return this;
- },
-
- empty: function() {
- var elem,
- i = 0;
-
- for ( ; (elem = this[i]) != null; i++ ) {
- if ( elem.nodeType === 1 ) {
-
- // Prevent memory leaks
- jQuery.cleanData( getAll( elem, false ) );
-
- // Remove any remaining nodes
- elem.textContent = "";
- }
- }
-
- return this;
- },
-
- clone: function( dataAndEvents, deepDataAndEvents ) {
- dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
- deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
-
- return this.map(function() {
- return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
- });
- },
-
- html: function( value ) {
- return access( this, function( value ) {
- var elem = this[ 0 ] || {},
- i = 0,
- l = this.length;
-
- if ( value === undefined && elem.nodeType === 1 ) {
- return elem.innerHTML;
- }
-
- // See if we can take a shortcut and just use innerHTML
- if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
- !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
-
- value = value.replace( rxhtmlTag, "<$1></$2>" );
-
- try {
- for ( ; i < l; i++ ) {
- elem = this[ i ] || {};
-
- // Remove element nodes and prevent memory leaks
- if ( elem.nodeType === 1 ) {
- jQuery.cleanData( getAll( elem, false ) );
- elem.innerHTML = value;
- }
- }
-
- elem = 0;
-
- // If using innerHTML throws an exception, use the fallback method
- } catch( e ) {}
- }
-
- if ( elem ) {
- this.empty().append( value );
- }
- }, null, value, arguments.length );
- },
-
- replaceWith: function() {
- var arg = arguments[ 0 ];
-
- // Make the changes, replacing each context element with the new content
- this.domManip( arguments, function( elem ) {
- arg = this.parentNode;
-
- jQuery.cleanData( getAll( this ) );
-
- if ( arg ) {
- arg.replaceChild( elem, this );
- }
- });
-
- // Force removal if there was no new content (e.g., from empty arguments)
- return arg && (arg.length || arg.nodeType) ? this : this.remove();
- },
-
- detach: function( selector ) {
- return this.remove( selector, true );
- },
-
- domManip: function( args, callback ) {
-
- // Flatten any nested arrays
- args = concat.apply( [], args );
-
- var fragment, first, scripts, hasScripts, node, doc,
- i = 0,
- l = this.length,
- set = this,
- iNoClone = l - 1,
- value = args[ 0 ],
- isFunction = jQuery.isFunction( value );
-
- // We can't cloneNode fragments that contain checked, in WebKit
- if ( isFunction ||
- ( l > 1 && typeof value === "string" &&
- !support.checkClone && rchecked.test( value ) ) ) {
- return this.each(function( index ) {
- var self = set.eq( index );
- if ( isFunction ) {
- args[ 0 ] = value.call( this, index, self.html() );
- }
- self.domManip( args, callback );
- });
- }
-
- if ( l ) {
- fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
- first = fragment.firstChild;
-
- if ( fragment.childNodes.length === 1 ) {
- fragment = first;
- }
-
- if ( first ) {
- scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
- hasScripts = scripts.length;
-
- // Use the original fragment for the last item instead of the first because it can end up
- // being emptied incorrectly in certain situations (#8070).
- for ( ; i < l; i++ ) {
- node = fragment;
-
- if ( i !== iNoClone ) {
- node = jQuery.clone( node, true, true );
-
- // Keep references to cloned scripts for later restoration
- if ( hasScripts ) {
- // Support: QtWebKit
- // jQuery.merge because push.apply(_, arraylike) throws
- jQuery.merge( scripts, getAll( node, "script" ) );
- }
- }
-
- callback.call( this[ i ], node, i );
- }
-
- if ( hasScripts ) {
- doc = scripts[ scripts.length - 1 ].ownerDocument;
-
- // Reenable scripts
- jQuery.map( scripts, restoreScript );
-
- // Evaluate executable scripts on first document insertion
- for ( i = 0; i < hasScripts; i++ ) {
- node = scripts[ i ];
- if ( rscriptType.test( node.type || "" ) &&
- !data_priv.access( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
-
- if ( node.src ) {
- // Optional AJAX dependency, but won't run scripts if not present
- if ( jQuery._evalUrl ) {
- jQuery._evalUrl( node.src );
- }
- } else {
- jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) );
- }
- }
- }
- }
- }
- }
-
- return this;
- }
-});
-
-jQuery.each({
- appendTo: "append",
- prependTo: "prepend",
- insertBefore: "before",
- insertAfter: "after",
- replaceAll: "replaceWith"
-}, function( name, original ) {
- jQuery.fn[ name ] = function( selector ) {
- var elems,
- ret = [],
- insert = jQuery( selector ),
- last = insert.length - 1,
- i = 0;
-
- for ( ; i <= last; i++ ) {
- elems = i === last ? this : this.clone( true );
- jQuery( insert[ i ] )[ original ]( elems );
-
- // Support: QtWebKit
- // .get() because push.apply(_, arraylike) throws
- push.apply( ret, elems.get() );
- }
-
- return this.pushStack( ret );
- };
-});
-
-
-var iframe,
- elemdisplay = {};
-
-/**
- * Retrieve the actual display of a element
- * @param {String} name nodeName of the element
- * @param {Object} doc Document object
- */
-// Called only from within defaultDisplay
-function actualDisplay( name, doc ) {
- var style,
- elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
-
- // getDefaultComputedStyle might be reliably used only on attached element
- display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ?
-
- // Use of this method is a temporary fix (more like optmization) until something better comes along,
- // since it was removed from specification and supported only in FF
- style.display : jQuery.css( elem[ 0 ], "display" );
-
- // We don't have any data stored on the element,
- // so use "detach" method as fast way to get rid of the element
- elem.detach();
-
- return display;
-}
-
-/**
- * Try to determine the default display value of an element
- * @param {String} nodeName
- */
-function defaultDisplay( nodeName ) {
- var doc = document,
- display = elemdisplay[ nodeName ];
-
- if ( !display ) {
- display = actualDisplay( nodeName, doc );
-
- // If the simple way fails, read from inside an iframe
- if ( display === "none" || !display ) {
-
- // Use the already-created iframe if possible
- iframe = (iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" )).appendTo( doc.documentElement );
-
- // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
- doc = iframe[ 0 ].contentDocument;
-
- // Support: IE
- doc.write();
- doc.close();
-
- display = actualDisplay( nodeName, doc );
- iframe.detach();
- }
-
- // Store the correct default display
- elemdisplay[ nodeName ] = display;
- }
-
- return display;
-}
-var rmargin = (/^margin/);
-
-var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
-
-var getStyles = function( elem ) {
- return elem.ownerDocument.defaultView.getComputedStyle( elem, null );
- };
-
-
-
-function curCSS( elem, name, computed ) {
- var width, minWidth, maxWidth, ret,
- style = elem.style;
-
- computed = computed || getStyles( elem );
-
- // Support: IE9
- // getPropertyValue is only needed for .css('filter') in IE9, see #12537
- if ( computed ) {
- ret = computed.getPropertyValue( name ) || computed[ name ];
- }
-
- if ( computed ) {
-
- if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
- ret = jQuery.style( elem, name );
- }
-
- // Support: iOS < 6
- // A tribute to the "awesome hack by Dean Edwards"
- // iOS < 6 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
- // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
- if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
-
- // Remember the original values
- width = style.width;
- minWidth = style.minWidth;
- maxWidth = style.maxWidth;
-
- // Put in the new values to get a computed value out
- style.minWidth = style.maxWidth = style.width = ret;
- ret = computed.width;
-
- // Revert the changed values
- style.width = width;
- style.minWidth = minWidth;
- style.maxWidth = maxWidth;
- }
- }
-
- return ret !== undefined ?
- // Support: IE
- // IE returns zIndex value as an integer.
- ret + "" :
- ret;
-}
-
-
-function addGetHookIf( conditionFn, hookFn ) {
- // Define the hook, we'll check on the first run if it's really needed.
- return {
- get: function() {
- if ( conditionFn() ) {
- // Hook not needed (or it's not possible to use it due to missing dependency),
- // remove it.
- // Since there are no other hooks for marginRight, remove the whole object.
- delete this.get;
- return;
- }
-
- // Hook needed; redefine it so that the support test is not executed again.
-
- return (this.get = hookFn).apply( this, arguments );
- }
- };
-}
-
-
-(function() {
- var pixelPositionVal, boxSizingReliableVal,
- docElem = document.documentElement,
- container = document.createElement( "div" ),
- div = document.createElement( "div" );
-
- if ( !div.style ) {
- return;
- }
-
- div.style.backgroundClip = "content-box";
- div.cloneNode( true ).style.backgroundClip = "";
- support.clearCloneStyle = div.style.backgroundClip === "content-box";
-
- container.style.cssText = "border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;" +
- "position:absolute";
- container.appendChild( div );
-
- // Executing both pixelPosition & boxSizingReliable tests require only one layout
- // so they're executed at the same time to save the second computation.
- function computePixelPositionAndBoxSizingReliable() {
- div.style.cssText =
- // Support: Firefox<29, Android 2.3
- // Vendor-prefix box-sizing
- "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;" +
- "box-sizing:border-box;display:block;margin-top:1%;top:1%;" +
- "border:1px;padding:1px;width:4px;position:absolute";
- div.innerHTML = "";
- docElem.appendChild( container );
-
- var divStyle = window.getComputedStyle( div, null );
- pixelPositionVal = divStyle.top !== "1%";
- boxSizingReliableVal = divStyle.width === "4px";
-
- docElem.removeChild( container );
- }
-
- // Support: node.js jsdom
- // Don't assume that getComputedStyle is a property of the global object
- if ( window.getComputedStyle ) {
- jQuery.extend( support, {
- pixelPosition: function() {
- // This test is executed only once but we still do memoizing
- // since we can use the boxSizingReliable pre-computing.
- // No need to check if the test was already performed, though.
- computePixelPositionAndBoxSizingReliable();
- return pixelPositionVal;
- },
- boxSizingReliable: function() {
- if ( boxSizingReliableVal == null ) {
- computePixelPositionAndBoxSizingReliable();
- }
- return boxSizingReliableVal;
- },
- reliableMarginRight: function() {
- // Support: Android 2.3
- // Check if div with explicit width and no margin-right incorrectly
- // gets computed margin-right based on width of container. (#3333)
- // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
- // This support function is only executed once so no memoizing is needed.
- var ret,
- marginDiv = div.appendChild( document.createElement( "div" ) );
-
- // Reset CSS: box-sizing; display; margin; border; padding
- marginDiv.style.cssText = div.style.cssText =
- // Support: Firefox<29, Android 2.3
- // Vendor-prefix box-sizing
- "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
- "box-sizing:content-box;display:block;margin:0;border:0;padding:0";
- marginDiv.style.marginRight = marginDiv.style.width = "0";
- div.style.width = "1px";
- docElem.appendChild( container );
-
- ret = !parseFloat( window.getComputedStyle( marginDiv, null ).marginRight );
-
- docElem.removeChild( container );
-
- return ret;
- }
- });
- }
-})();
-
-
-// A method for quickly swapping in/out CSS properties to get correct calculations.
-jQuery.swap = function( elem, options, callback, args ) {
- var ret, name,
- old = {};
-
- // Remember the old values, and insert the new ones
- for ( name in options ) {
- old[ name ] = elem.style[ name ];
- elem.style[ name ] = options[ name ];
- }
-
- ret = callback.apply( elem, args || [] );
-
- // Revert the old values
- for ( name in options ) {
- elem.style[ name ] = old[ name ];
- }
-
- return ret;
-};
-
-
-var
- // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
- // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
- rdisplayswap = /^(none|table(?!-c[ea]).+)/,
- rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ),
- rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ),
-
- cssShow = { position: "absolute", visibility: "hidden", display: "block" },
- cssNormalTransform = {
- letterSpacing: "0",
- fontWeight: "400"
- },
-
- cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
-
-// return a css property mapped to a potentially vendor prefixed property
-function vendorPropName( style, name ) {
-
- // shortcut for names that are not vendor prefixed
- if ( name in style ) {
- return name;
- }
-
- // check for vendor prefixed names
- var capName = name[0].toUpperCase() + name.slice(1),
- origName = name,
- i = cssPrefixes.length;
-
- while ( i-- ) {
- name = cssPrefixes[ i ] + capName;
- if ( name in style ) {
- return name;
- }
- }
-
- return origName;
-}
-
-function setPositiveNumber( elem, value, subtract ) {
- var matches = rnumsplit.exec( value );
- return matches ?
- // Guard against undefined "subtract", e.g., when used as in cssHooks
- Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
- value;
-}
-
-function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
- var i = extra === ( isBorderBox ? "border" : "content" ) ?
- // If we already have the right measurement, avoid augmentation
- 4 :
- // Otherwise initialize for horizontal or vertical properties
- name === "width" ? 1 : 0,
-
- val = 0;
-
- for ( ; i < 4; i += 2 ) {
- // both box models exclude margin, so add it if we want it
- if ( extra === "margin" ) {
- val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
- }
-
- if ( isBorderBox ) {
- // border-box includes padding, so remove it if we want content
- if ( extra === "content" ) {
- val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
- }
-
- // at this point, extra isn't border nor margin, so remove border
- if ( extra !== "margin" ) {
- val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
- }
- } else {
- // at this point, extra isn't content, so add padding
- val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
-
- // at this point, extra isn't content nor padding, so add border
- if ( extra !== "padding" ) {
- val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
- }
- }
- }
-
- return val;
-}
-
-function getWidthOrHeight( elem, name, extra ) {
-
- // Start with offset property, which is equivalent to the border-box value
- var valueIsBorderBox = true,
- val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
- styles = getStyles( elem ),
- isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
-
- // some non-html elements return undefined for offsetWidth, so check for null/undefined
- // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
- // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
- if ( val <= 0 || val == null ) {
- // Fall back to computed then uncomputed css if necessary
- val = curCSS( elem, name, styles );
- if ( val < 0 || val == null ) {
- val = elem.style[ name ];
- }
-
- // Computed unit is not pixels. Stop here and return.
- if ( rnumnonpx.test(val) ) {
- return val;
- }
-
- // we need the check for style in case a browser which returns unreliable values
- // for getComputedStyle silently falls back to the reliable elem.style
- valueIsBorderBox = isBorderBox &&
- ( support.boxSizingReliable() || val === elem.style[ name ] );
-
- // Normalize "", auto, and prepare for extra
- val = parseFloat( val ) || 0;
- }
-
- // use the active box-sizing model to add/subtract irrelevant styles
- return ( val +
- augmentWidthOrHeight(
- elem,
- name,
- extra || ( isBorderBox ? "border" : "content" ),
- valueIsBorderBox,
- styles
- )
- ) + "px";
-}
-
-function showHide( elements, show ) {
- var display, elem, hidden,
- values = [],
- index = 0,
- length = elements.length;
-
- for ( ; index < length; index++ ) {
- elem = elements[ index ];
- if ( !elem.style ) {
- continue;
- }
-
- values[ index ] = data_priv.get( elem, "olddisplay" );
- display = elem.style.display;
- if ( show ) {
- // Reset the inline display of this element to learn if it is
- // being hidden by cascaded rules or not
- if ( !values[ index ] && display === "none" ) {
- elem.style.display = "";
- }
-
- // Set elements which have been overridden with display: none
- // in a stylesheet to whatever the default browser style is
- // for such an element
- if ( elem.style.display === "" && isHidden( elem ) ) {
- values[ index ] = data_priv.access( elem, "olddisplay", defaultDisplay(elem.nodeName) );
- }
- } else {
- hidden = isHidden( elem );
-
- if ( display !== "none" || !hidden ) {
- data_priv.set( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
- }
- }
- }
-
- // Set the display of most of the elements in a second loop
- // to avoid the constant reflow
- for ( index = 0; index < length; index++ ) {
- elem = elements[ index ];
- if ( !elem.style ) {
- continue;
- }
- if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
- elem.style.display = show ? values[ index ] || "" : "none";
- }
- }
-
- return elements;
-}
-
-jQuery.extend({
- // Add in style property hooks for overriding the default
- // behavior of getting and setting a style property
- cssHooks: {
- opacity: {
- get: function( elem, computed ) {
- if ( computed ) {
- // We should always get a number back from opacity
- var ret = curCSS( elem, "opacity" );
- return ret === "" ? "1" : ret;
- }
- }
- }
- },
-
- // Don't automatically add "px" to these possibly-unitless properties
- cssNumber: {
- "columnCount": true,
- "fillOpacity": true,
- "flexGrow": true,
- "flexShrink": true,
- "fontWeight": true,
- "lineHeight": true,
- "opacity": true,
- "order": true,
- "orphans": true,
- "widows": true,
- "zIndex": true,
- "zoom": true
- },
-
- // Add in properties whose names you wish to fix before
- // setting or getting the value
- cssProps: {
- // normalize float css property
- "float": "cssFloat"
- },
-
- // Get and set the style property on a DOM Node
- style: function( elem, name, value, extra ) {
- // Don't set styles on text and comment nodes
- if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
- return;
- }
-
- // Make sure that we're working with the right name
- var ret, type, hooks,
- origName = jQuery.camelCase( name ),
- style = elem.style;
-
- name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
-
- // gets hook for the prefixed version
- // followed by the unprefixed version
- hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
-
- // Check if we're setting a value
- if ( value !== undefined ) {
- type = typeof value;
-
- // convert relative number strings (+= or -=) to relative numbers. #7345
- if ( type === "string" && (ret = rrelNum.exec( value )) ) {
- value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
- // Fixes bug #9237
- type = "number";
- }
-
- // Make sure that null and NaN values aren't set. See: #7116
- if ( value == null || value !== value ) {
- return;
- }
-
- // If a number was passed in, add 'px' to the (except for certain CSS properties)
- if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
- value += "px";
- }
-
- // Fixes #8908, it can be done more correctly by specifying setters in cssHooks,
- // but it would mean to define eight (for every problematic property) identical functions
- if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
- style[ name ] = "inherit";
- }
-
- // If a hook was provided, use that value, otherwise just set the specified value
- if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
- style[ name ] = value;
- }
-
- } else {
- // If a hook was provided get the non-computed value from there
- if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
- return ret;
- }
-
- // Otherwise just get the value from the style object
- return style[ name ];
- }
- },
-
- css: function( elem, name, extra, styles ) {
- var val, num, hooks,
- origName = jQuery.camelCase( name );
-
- // Make sure that we're working with the right name
- name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
-
- // gets hook for the prefixed version
- // followed by the unprefixed version
- hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
-
- // If a hook was provided get the computed value from there
- if ( hooks && "get" in hooks ) {
- val = hooks.get( elem, true, extra );
- }
-
- // Otherwise, if a way to get the computed value exists, use that
- if ( val === undefined ) {
- val = curCSS( elem, name, styles );
- }
-
- //convert "normal" to computed value
- if ( val === "normal" && name in cssNormalTransform ) {
- val = cssNormalTransform[ name ];
- }
-
- // Return, converting to number if forced or a qualifier was provided and val looks numeric
- if ( extra === "" || extra ) {
- num = parseFloat( val );
- return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
- }
- return val;
- }
-});
-
-jQuery.each([ "height", "width" ], function( i, name ) {
- jQuery.cssHooks[ name ] = {
- get: function( elem, computed, extra ) {
- if ( computed ) {
- // certain elements can have dimension info if we invisibly show them
- // however, it must have a current display style that would benefit from this
- return rdisplayswap.test( jQuery.css( elem, "display" ) ) && elem.offsetWidth === 0 ?
- jQuery.swap( elem, cssShow, function() {
- return getWidthOrHeight( elem, name, extra );
- }) :
- getWidthOrHeight( elem, name, extra );
- }
- },
-
- set: function( elem, value, extra ) {
- var styles = extra && getStyles( elem );
- return setPositiveNumber( elem, value, extra ?
- augmentWidthOrHeight(
- elem,
- name,
- extra,
- jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
- styles
- ) : 0
- );
- }
- };
-});
-
-// Support: Android 2.3
-jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
- function( elem, computed ) {
- if ( computed ) {
- // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
- // Work around by temporarily setting element display to inline-block
- return jQuery.swap( elem, { "display": "inline-block" },
- curCSS, [ elem, "marginRight" ] );
- }
- }
-);
-
-// These hooks are used by animate to expand properties
-jQuery.each({
- margin: "",
- padding: "",
- border: "Width"
-}, function( prefix, suffix ) {
- jQuery.cssHooks[ prefix + suffix ] = {
- expand: function( value ) {
- var i = 0,
- expanded = {},
-
- // assumes a single number if not a string
- parts = typeof value === "string" ? value.split(" ") : [ value ];
-
- for ( ; i < 4; i++ ) {
- expanded[ prefix + cssExpand[ i ] + suffix ] =
- parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
- }
-
- return expanded;
- }
- };
-
- if ( !rmargin.test( prefix ) ) {
- jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
- }
-});
-
-jQuery.fn.extend({
- css: function( name, value ) {
- return access( this, function( elem, name, value ) {
- var styles, len,
- map = {},
- i = 0;
-
- if ( jQuery.isArray( name ) ) {
- styles = getStyles( elem );
- len = name.length;
-
- for ( ; i < len; i++ ) {
- map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
- }
-
- return map;
- }
-
- return value !== undefined ?
- jQuery.style( elem, name, value ) :
- jQuery.css( elem, name );
- }, name, value, arguments.length > 1 );
- },
- show: function() {
- return showHide( this, true );
- },
- hide: function() {
- return showHide( this );
- },
- toggle: function( state ) {
- if ( typeof state === "boolean" ) {
- return state ? this.show() : this.hide();
- }
-
- return this.each(function() {
- if ( isHidden( this ) ) {
- jQuery( this ).show();
- } else {
- jQuery( this ).hide();
- }
- });
- }
-});
-
-
-function Tween( elem, options, prop, end, easing ) {
- return new Tween.prototype.init( elem, options, prop, end, easing );
-}
-jQuery.Tween = Tween;
-
-Tween.prototype = {
- constructor: Tween,
- init: function( elem, options, prop, end, easing, unit ) {
- this.elem = elem;
- this.prop = prop;
- this.easing = easing || "swing";
- this.options = options;
- this.start = this.now = this.cur();
- this.end = end;
- this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
- },
- cur: function() {
- var hooks = Tween.propHooks[ this.prop ];
-
- return hooks && hooks.get ?
- hooks.get( this ) :
- Tween.propHooks._default.get( this );
- },
- run: function( percent ) {
- var eased,
- hooks = Tween.propHooks[ this.prop ];
-
- if ( this.options.duration ) {
- this.pos = eased = jQuery.easing[ this.easing ](
- percent, this.options.duration * percent, 0, 1, this.options.duration
- );
- } else {
- this.pos = eased = percent;
- }
- this.now = ( this.end - this.start ) * eased + this.start;
-
- if ( this.options.step ) {
- this.options.step.call( this.elem, this.now, this );
- }
-
- if ( hooks && hooks.set ) {
- hooks.set( this );
- } else {
- Tween.propHooks._default.set( this );
- }
- return this;
- }
-};
-
-Tween.prototype.init.prototype = Tween.prototype;
-
-Tween.propHooks = {
- _default: {
- get: function( tween ) {
- var result;
-
- if ( tween.elem[ tween.prop ] != null &&
- (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
- return tween.elem[ tween.prop ];
- }
-
- // passing an empty string as a 3rd parameter to .css will automatically
- // attempt a parseFloat and fallback to a string if the parse fails
- // so, simple values such as "10px" are parsed to Float.
- // complex values such as "rotate(1rad)" are returned as is.
- result = jQuery.css( tween.elem, tween.prop, "" );
- // Empty strings, null, undefined and "auto" are converted to 0.
- return !result || result === "auto" ? 0 : result;
- },
- set: function( tween ) {
- // use step hook for back compat - use cssHook if its there - use .style if its
- // available and use plain properties where available
- if ( jQuery.fx.step[ tween.prop ] ) {
- jQuery.fx.step[ tween.prop ]( tween );
- } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
- jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
- } else {
- tween.elem[ tween.prop ] = tween.now;
- }
- }
- }
-};
-
-// Support: IE9
-// Panic based approach to setting things on disconnected nodes
-
-Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
- set: function( tween ) {
- if ( tween.elem.nodeType && tween.elem.parentNode ) {
- tween.elem[ tween.prop ] = tween.now;
- }
- }
-};
-
-jQuery.easing = {
- linear: function( p ) {
- return p;
- },
- swing: function( p ) {
- return 0.5 - Math.cos( p * Math.PI ) / 2;
- }
-};
-
-jQuery.fx = Tween.prototype.init;
-
-// Back Compat <1.8 extension point
-jQuery.fx.step = {};
-
-
-
-
-var
- fxNow, timerId,
- rfxtypes = /^(?:toggle|show|hide)$/,
- rfxnum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ),
- rrun = /queueHooks$/,
- animationPrefilters = [ defaultPrefilter ],
- tweeners = {
- "*": [ function( prop, value ) {
- var tween = this.createTween( prop, value ),
- target = tween.cur(),
- parts = rfxnum.exec( value ),
- unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
-
- // Starting value computation is required for potential unit mismatches
- start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
- rfxnum.exec( jQuery.css( tween.elem, prop ) ),
- scale = 1,
- maxIterations = 20;
-
- if ( start && start[ 3 ] !== unit ) {
- // Trust units reported by jQuery.css
- unit = unit || start[ 3 ];
-
- // Make sure we update the tween properties later on
- parts = parts || [];
-
- // Iteratively approximate from a nonzero starting point
- start = +target || 1;
-
- do {
- // If previous iteration zeroed out, double until we get *something*
- // Use a string for doubling factor so we don't accidentally see scale as unchanged below
- scale = scale || ".5";
-
- // Adjust and apply
- start = start / scale;
- jQuery.style( tween.elem, prop, start + unit );
-
- // Update scale, tolerating zero or NaN from tween.cur()
- // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
- } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
- }
-
- // Update tween properties
- if ( parts ) {
- start = tween.start = +start || +target || 0;
- tween.unit = unit;
- // If a +=/-= token was provided, we're doing a relative animation
- tween.end = parts[ 1 ] ?
- start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
- +parts[ 2 ];
- }
-
- return tween;
- } ]
- };
-
-// Animations created synchronously will run synchronously
-function createFxNow() {
- setTimeout(function() {
- fxNow = undefined;
- });
- return ( fxNow = jQuery.now() );
-}
-
-// Generate parameters to create a standard animation
-function genFx( type, includeWidth ) {
- var which,
- i = 0,
- attrs = { height: type };
-
- // if we include width, step value is 1 to do all cssExpand values,
- // if we don't include width, step value is 2 to skip over Left and Right
- includeWidth = includeWidth ? 1 : 0;
- for ( ; i < 4 ; i += 2 - includeWidth ) {
- which = cssExpand[ i ];
- attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
- }
-
- if ( includeWidth ) {
- attrs.opacity = attrs.width = type;
- }
-
- return attrs;
-}
-
-function createTween( value, prop, animation ) {
- var tween,
- collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
- index = 0,
- length = collection.length;
- for ( ; index < length; index++ ) {
- if ( (tween = collection[ index ].call( animation, prop, value )) ) {
-
- // we're done with this property
- return tween;
- }
- }
-}
-
-function defaultPrefilter( elem, props, opts ) {
- /* jshint validthis: true */
- var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
- anim = this,
- orig = {},
- style = elem.style,
- hidden = elem.nodeType && isHidden( elem ),
- dataShow = data_priv.get( elem, "fxshow" );
-
- // handle queue: false promises
- if ( !opts.queue ) {
- hooks = jQuery._queueHooks( elem, "fx" );
- if ( hooks.unqueued == null ) {
- hooks.unqueued = 0;
- oldfire = hooks.empty.fire;
- hooks.empty.fire = function() {
- if ( !hooks.unqueued ) {
- oldfire();
- }
- };
- }
- hooks.unqueued++;
-
- anim.always(function() {
- // doing this makes sure that the complete handler will be called
- // before this completes
- anim.always(function() {
- hooks.unqueued--;
- if ( !jQuery.queue( elem, "fx" ).length ) {
- hooks.empty.fire();
- }
- });
- });
- }
-
- // height/width overflow pass
- if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
- // Make sure that nothing sneaks out
- // Record all 3 overflow attributes because IE9-10 do not
- // change the overflow attribute when overflowX and
- // overflowY are set to the same value
- opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
-
- // Set display property to inline-block for height/width
- // animations on inline elements that are having width/height animated
- display = jQuery.css( elem, "display" );
-
- // Test default display if display is currently "none"
- checkDisplay = display === "none" ?
- data_priv.get( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;
-
- if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) {
- style.display = "inline-block";
- }
- }
-
- if ( opts.overflow ) {
- style.overflow = "hidden";
- anim.always(function() {
- style.overflow = opts.overflow[ 0 ];
- style.overflowX = opts.overflow[ 1 ];
- style.overflowY = opts.overflow[ 2 ];
- });
- }
-
- // show/hide pass
- for ( prop in props ) {
- value = props[ prop ];
- if ( rfxtypes.exec( value ) ) {
- delete props[ prop ];
- toggle = toggle || value === "toggle";
- if ( value === ( hidden ? "hide" : "show" ) ) {
-
- // If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden
- if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
- hidden = true;
- } else {
- continue;
- }
- }
- orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
-
- // Any non-fx value stops us from restoring the original display value
- } else {
- display = undefined;
- }
- }
-
- if ( !jQuery.isEmptyObject( orig ) ) {
- if ( dataShow ) {
- if ( "hidden" in dataShow ) {
- hidden = dataShow.hidden;
- }
- } else {
- dataShow = data_priv.access( elem, "fxshow", {} );
- }
-
- // store state if its toggle - enables .stop().toggle() to "reverse"
- if ( toggle ) {
- dataShow.hidden = !hidden;
- }
- if ( hidden ) {
- jQuery( elem ).show();
- } else {
- anim.done(function() {
- jQuery( elem ).hide();
- });
- }
- anim.done(function() {
- var prop;
-
- data_priv.remove( elem, "fxshow" );
- for ( prop in orig ) {
- jQuery.style( elem, prop, orig[ prop ] );
- }
- });
- for ( prop in orig ) {
- tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
-
- if ( !( prop in dataShow ) ) {
- dataShow[ prop ] = tween.start;
- if ( hidden ) {
- tween.end = tween.start;
- tween.start = prop === "width" || prop === "height" ? 1 : 0;
- }
- }
- }
-
- // If this is a noop like .hide().hide(), restore an overwritten display value
- } else if ( (display === "none" ? defaultDisplay( elem.nodeName ) : display) === "inline" ) {
- style.display = display;
- }
-}
-
-function propFilter( props, specialEasing ) {
- var index, name, easing, value, hooks;
-
- // camelCase, specialEasing and expand cssHook pass
- for ( index in props ) {
- name = jQuery.camelCase( index );
- easing = specialEasing[ name ];
- value = props[ index ];
- if ( jQuery.isArray( value ) ) {
- easing = value[ 1 ];
- value = props[ index ] = value[ 0 ];
- }
-
- if ( index !== name ) {
- props[ name ] = value;
- delete props[ index ];
- }
-
- hooks = jQuery.cssHooks[ name ];
- if ( hooks && "expand" in hooks ) {
- value = hooks.expand( value );
- delete props[ name ];
-
- // not quite $.extend, this wont overwrite keys already present.
- // also - reusing 'index' from above because we have the correct "name"
- for ( index in value ) {
- if ( !( index in props ) ) {
- props[ index ] = value[ index ];
- specialEasing[ index ] = easing;
- }
- }
- } else {
- specialEasing[ name ] = easing;
- }
- }
-}
-
-function Animation( elem, properties, options ) {
- var result,
- stopped,
- index = 0,
- length = animationPrefilters.length,
- deferred = jQuery.Deferred().always( function() {
- // don't match elem in the :animated selector
- delete tick.elem;
- }),
- tick = function() {
- if ( stopped ) {
- return false;
- }
- var currentTime = fxNow || createFxNow(),
- remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
- // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
- temp = remaining / animation.duration || 0,
- percent = 1 - temp,
- index = 0,
- length = animation.tweens.length;
-
- for ( ; index < length ; index++ ) {
- animation.tweens[ index ].run( percent );
- }
-
- deferred.notifyWith( elem, [ animation, percent, remaining ]);
-
- if ( percent < 1 && length ) {
- return remaining;
- } else {
- deferred.resolveWith( elem, [ animation ] );
- return false;
- }
- },
- animation = deferred.promise({
- elem: elem,
- props: jQuery.extend( {}, properties ),
- opts: jQuery.extend( true, { specialEasing: {} }, options ),
- originalProperties: properties,
- originalOptions: options,
- startTime: fxNow || createFxNow(),
- duration: options.duration,
- tweens: [],
- createTween: function( prop, end ) {
- var tween = jQuery.Tween( elem, animation.opts, prop, end,
- animation.opts.specialEasing[ prop ] || animation.opts.easing );
- animation.tweens.push( tween );
- return tween;
- },
- stop: function( gotoEnd ) {
- var index = 0,
- // if we are going to the end, we want to run all the tweens
- // otherwise we skip this part
- length = gotoEnd ? animation.tweens.length : 0;
- if ( stopped ) {
- return this;
- }
- stopped = true;
- for ( ; index < length ; index++ ) {
- animation.tweens[ index ].run( 1 );
- }
-
- // resolve when we played the last frame
- // otherwise, reject
- if ( gotoEnd ) {
- deferred.resolveWith( elem, [ animation, gotoEnd ] );
- } else {
- deferred.rejectWith( elem, [ animation, gotoEnd ] );
- }
- return this;
- }
- }),
- props = animation.props;
-
- propFilter( props, animation.opts.specialEasing );
-
- for ( ; index < length ; index++ ) {
- result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
- if ( result ) {
- return result;
- }
- }
-
- jQuery.map( props, createTween, animation );
-
- if ( jQuery.isFunction( animation.opts.start ) ) {
- animation.opts.start.call( elem, animation );
- }
-
- jQuery.fx.timer(
- jQuery.extend( tick, {
- elem: elem,
- anim: animation,
- queue: animation.opts.queue
- })
- );
-
- // attach callbacks from options
- return animation.progress( animation.opts.progress )
- .done( animation.opts.done, animation.opts.complete )
- .fail( animation.opts.fail )
- .always( animation.opts.always );
-}
-
-jQuery.Animation = jQuery.extend( Animation, {
-
- tweener: function( props, callback ) {
- if ( jQuery.isFunction( props ) ) {
- callback = props;
- props = [ "*" ];
- } else {
- props = props.split(" ");
- }
-
- var prop,
- index = 0,
- length = props.length;
-
- for ( ; index < length ; index++ ) {
- prop = props[ index ];
- tweeners[ prop ] = tweeners[ prop ] || [];
- tweeners[ prop ].unshift( callback );
- }
- },
-
- prefilter: function( callback, prepend ) {
- if ( prepend ) {
- animationPrefilters.unshift( callback );
- } else {
- animationPrefilters.push( callback );
- }
- }
-});
-
-jQuery.speed = function( speed, easing, fn ) {
- var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
- complete: fn || !fn && easing ||
- jQuery.isFunction( speed ) && speed,
- duration: speed,
- easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
- };
-
- opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
- opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
-
- // normalize opt.queue - true/undefined/null -> "fx"
- if ( opt.queue == null || opt.queue === true ) {
- opt.queue = "fx";
- }
-
- // Queueing
- opt.old = opt.complete;
-
- opt.complete = function() {
- if ( jQuery.isFunction( opt.old ) ) {
- opt.old.call( this );
- }
-
- if ( opt.queue ) {
- jQuery.dequeue( this, opt.queue );
- }
- };
-
- return opt;
-};
-
-jQuery.fn.extend({
- fadeTo: function( speed, to, easing, callback ) {
-
- // show any hidden elements after setting opacity to 0
- return this.filter( isHidden ).css( "opacity", 0 ).show()
-
- // animate to the value specified
- .end().animate({ opacity: to }, speed, easing, callback );
- },
- animate: function( prop, speed, easing, callback ) {
- var empty = jQuery.isEmptyObject( prop ),
- optall = jQuery.speed( speed, easing, callback ),
- doAnimation = function() {
- // Operate on a copy of prop so per-property easing won't be lost
- var anim = Animation( this, jQuery.extend( {}, prop ), optall );
-
- // Empty animations, or finishing resolves immediately
- if ( empty || data_priv.get( this, "finish" ) ) {
- anim.stop( true );
- }
- };
- doAnimation.finish = doAnimation;
-
- return empty || optall.queue === false ?
- this.each( doAnimation ) :
- this.queue( optall.queue, doAnimation );
- },
- stop: function( type, clearQueue, gotoEnd ) {
- var stopQueue = function( hooks ) {
- var stop = hooks.stop;
- delete hooks.stop;
- stop( gotoEnd );
- };
-
- if ( typeof type !== "string" ) {
- gotoEnd = clearQueue;
- clearQueue = type;
- type = undefined;
- }
- if ( clearQueue && type !== false ) {
- this.queue( type || "fx", [] );
- }
-
- return this.each(function() {
- var dequeue = true,
- index = type != null && type + "queueHooks",
- timers = jQuery.timers,
- data = data_priv.get( this );
-
- if ( index ) {
- if ( data[ index ] && data[ index ].stop ) {
- stopQueue( data[ index ] );
- }
- } else {
- for ( index in data ) {
- if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
- stopQueue( data[ index ] );
- }
- }
- }
-
- for ( index = timers.length; index--; ) {
- if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
- timers[ index ].anim.stop( gotoEnd );
- dequeue = false;
- timers.splice( index, 1 );
- }
- }
-
- // start the next in the queue if the last step wasn't forced
- // timers currently will call their complete callbacks, which will dequeue
- // but only if they were gotoEnd
- if ( dequeue || !gotoEnd ) {
- jQuery.dequeue( this, type );
- }
- });
- },
- finish: function( type ) {
- if ( type !== false ) {
- type = type || "fx";
- }
- return this.each(function() {
- var index,
- data = data_priv.get( this ),
- queue = data[ type + "queue" ],
- hooks = data[ type + "queueHooks" ],
- timers = jQuery.timers,
- length = queue ? queue.length : 0;
-
- // enable finishing flag on private data
- data.finish = true;
-
- // empty the queue first
- jQuery.queue( this, type, [] );
-
- if ( hooks && hooks.stop ) {
- hooks.stop.call( this, true );
- }
-
- // look for any active animations, and finish them
- for ( index = timers.length; index--; ) {
- if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
- timers[ index ].anim.stop( true );
- timers.splice( index, 1 );
- }
- }
-
- // look for any animations in the old queue and finish them
- for ( index = 0; index < length; index++ ) {
- if ( queue[ index ] && queue[ index ].finish ) {
- queue[ index ].finish.call( this );
- }
- }
-
- // turn off finishing flag
- delete data.finish;
- });
- }
-});
-
-jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
- var cssFn = jQuery.fn[ name ];
- jQuery.fn[ name ] = function( speed, easing, callback ) {
- return speed == null || typeof speed === "boolean" ?
- cssFn.apply( this, arguments ) :
- this.animate( genFx( name, true ), speed, easing, callback );
- };
-});
-
-// Generate shortcuts for custom animations
-jQuery.each({
- slideDown: genFx("show"),
- slideUp: genFx("hide"),
- slideToggle: genFx("toggle"),
- fadeIn: { opacity: "show" },
- fadeOut: { opacity: "hide" },
- fadeToggle: { opacity: "toggle" }
-}, function( name, props ) {
- jQuery.fn[ name ] = function( speed, easing, callback ) {
- return this.animate( props, speed, easing, callback );
- };
-});
-
-jQuery.timers = [];
-jQuery.fx.tick = function() {
- var timer,
- i = 0,
- timers = jQuery.timers;
-
- fxNow = jQuery.now();
-
- for ( ; i < timers.length; i++ ) {
- timer = timers[ i ];
- // Checks the timer has not already been removed
- if ( !timer() && timers[ i ] === timer ) {
- timers.splice( i--, 1 );
- }
- }
-
- if ( !timers.length ) {
- jQuery.fx.stop();
- }
- fxNow = undefined;
-};
-
-jQuery.fx.timer = function( timer ) {
- jQuery.timers.push( timer );
- if ( timer() ) {
- jQuery.fx.start();
- } else {
- jQuery.timers.pop();
- }
-};
-
-jQuery.fx.interval = 13;
-
-jQuery.fx.start = function() {
- if ( !timerId ) {
- timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
- }
-};
-
-jQuery.fx.stop = function() {
- clearInterval( timerId );
- timerId = null;
-};
-
-jQuery.fx.speeds = {
- slow: 600,
- fast: 200,
- // Default speed
- _default: 400
-};
-
-
-// Based off of the plugin by Clint Helfers, with permission.
-// http://blindsignals.com/index.php/2009/07/jquery-delay/
-jQuery.fn.delay = function( time, type ) {
- time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
- type = type || "fx";
-
- return this.queue( type, function( next, hooks ) {
- var timeout = setTimeout( next, time );
- hooks.stop = function() {
- clearTimeout( timeout );
- };
- });
-};
-
-
-(function() {
- var input = document.createElement( "input" ),
- select = document.createElement( "select" ),
- opt = select.appendChild( document.createElement( "option" ) );
-
- input.type = "checkbox";
-
- // Support: iOS 5.1, Android 4.x, Android 2.3
- // Check the default checkbox/radio value ("" on old WebKit; "on" elsewhere)
- support.checkOn = input.value !== "";
-
- // Must access the parent to make an option select properly
- // Support: IE9, IE10
- support.optSelected = opt.selected;
-
- // Make sure that the options inside disabled selects aren't marked as disabled
- // (WebKit marks them as disabled)
- select.disabled = true;
- support.optDisabled = !opt.disabled;
-
- // Check if an input maintains its value after becoming a radio
- // Support: IE9, IE10
- input = document.createElement( "input" );
- input.value = "t";
- input.type = "radio";
- support.radioValue = input.value === "t";
-})();
-
-
-var nodeHook, boolHook,
- attrHandle = jQuery.expr.attrHandle;
-
-jQuery.fn.extend({
- attr: function( name, value ) {
- return access( this, jQuery.attr, name, value, arguments.length > 1 );
- },
-
- removeAttr: function( name ) {
- return this.each(function() {
- jQuery.removeAttr( this, name );
- });
- }
-});
-
-jQuery.extend({
- attr: function( elem, name, value ) {
- var hooks, ret,
- nType = elem.nodeType;
-
- // don't get/set attributes on text, comment and attribute nodes
- if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
- return;
- }
-
- // Fallback to prop when attributes are not supported
- if ( typeof elem.getAttribute === strundefined ) {
- return jQuery.prop( elem, name, value );
- }
-
- // All attributes are lowercase
- // Grab necessary hook if one is defined
- if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
- name = name.toLowerCase();
- hooks = jQuery.attrHooks[ name ] ||
- ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
- }
-
- if ( value !== undefined ) {
-
- if ( value === null ) {
- jQuery.removeAttr( elem, name );
-
- } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
- return ret;
-
- } else {
- elem.setAttribute( name, value + "" );
- return value;
- }
-
- } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
- return ret;
-
- } else {
- ret = jQuery.find.attr( elem, name );
-
- // Non-existent attributes return null, we normalize to undefined
- return ret == null ?
- undefined :
- ret;
- }
- },
-
- removeAttr: function( elem, value ) {
- var name, propName,
- i = 0,
- attrNames = value && value.match( rnotwhite );
-
- if ( attrNames && elem.nodeType === 1 ) {
- while ( (name = attrNames[i++]) ) {
- propName = jQuery.propFix[ name ] || name;
-
- // Boolean attributes get special treatment (#10870)
- if ( jQuery.expr.match.bool.test( name ) ) {
- // Set corresponding property to false
- elem[ propName ] = false;
- }
-
- elem.removeAttribute( name );
- }
- }
- },
-
- attrHooks: {
- type: {
- set: function( elem, value ) {
- if ( !support.radioValue && value === "radio" &&
- jQuery.nodeName( elem, "input" ) ) {
- // Setting the type on a radio button after the value resets the value in IE6-9
- // Reset value to default in case type is set after value during creation
- var val = elem.value;
- elem.setAttribute( "type", value );
- if ( val ) {
- elem.value = val;
- }
- return value;
- }
- }
- }
- }
-});
-
-// Hooks for boolean attributes
-boolHook = {
- set: function( elem, value, name ) {
- if ( value === false ) {
- // Remove boolean attributes when set to false
- jQuery.removeAttr( elem, name );
- } else {
- elem.setAttribute( name, name );
- }
- return name;
- }
-};
-jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
- var getter = attrHandle[ name ] || jQuery.find.attr;
-
- attrHandle[ name ] = function( elem, name, isXML ) {
- var ret, handle;
- if ( !isXML ) {
- // Avoid an infinite loop by temporarily removing this function from the getter
- handle = attrHandle[ name ];
- attrHandle[ name ] = ret;
- ret = getter( elem, name, isXML ) != null ?
- name.toLowerCase() :
- null;
- attrHandle[ name ] = handle;
- }
- return ret;
- };
-});
-
-
-
-
-var rfocusable = /^(?:input|select|textarea|button)$/i;
-
-jQuery.fn.extend({
- prop: function( name, value ) {
- return access( this, jQuery.prop, name, value, arguments.length > 1 );
- },
-
- removeProp: function( name ) {
- return this.each(function() {
- delete this[ jQuery.propFix[ name ] || name ];
- });
- }
-});
-
-jQuery.extend({
- propFix: {
- "for": "htmlFor",
- "class": "className"
- },
-
- prop: function( elem, name, value ) {
- var ret, hooks, notxml,
- nType = elem.nodeType;
-
- // don't get/set properties on text, comment and attribute nodes
- if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
- return;
- }
-
- notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
-
- if ( notxml ) {
- // Fix name and attach hooks
- name = jQuery.propFix[ name ] || name;
- hooks = jQuery.propHooks[ name ];
- }
-
- if ( value !== undefined ) {
- return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
- ret :
- ( elem[ name ] = value );
-
- } else {
- return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
- ret :
- elem[ name ];
- }
- },
-
- propHooks: {
- tabIndex: {
- get: function( elem ) {
- return elem.hasAttribute( "tabindex" ) || rfocusable.test( elem.nodeName ) || elem.href ?
- elem.tabIndex :
- -1;
- }
- }
- }
-});
-
-// Support: IE9+
-// Selectedness for an option in an optgroup can be inaccurate
-if ( !support.optSelected ) {
- jQuery.propHooks.selected = {
- get: function( elem ) {
- var parent = elem.parentNode;
- if ( parent && parent.parentNode ) {
- parent.parentNode.selectedIndex;
- }
- return null;
- }
- };
-}
-
-jQuery.each([
- "tabIndex",
- "readOnly",
- "maxLength",
- "cellSpacing",
- "cellPadding",
- "rowSpan",
- "colSpan",
- "useMap",
- "frameBorder",
- "contentEditable"
-], function() {
- jQuery.propFix[ this.toLowerCase() ] = this;
-});
-
-
-
-
-var rclass = /[\t\r\n\f]/g;
-
-jQuery.fn.extend({
- addClass: function( value ) {
- var classes, elem, cur, clazz, j, finalValue,
- proceed = typeof value === "string" && value,
- i = 0,
- len = this.length;
-
- if ( jQuery.isFunction( value ) ) {
- return this.each(function( j ) {
- jQuery( this ).addClass( value.call( this, j, this.className ) );
- });
- }
-
- if ( proceed ) {
- // The disjunction here is for better compressibility (see removeClass)
- classes = ( value || "" ).match( rnotwhite ) || [];
-
- for ( ; i < len; i++ ) {
- elem = this[ i ];
- cur = elem.nodeType === 1 && ( elem.className ?
- ( " " + elem.className + " " ).replace( rclass, " " ) :
- " "
- );
-
- if ( cur ) {
- j = 0;
- while ( (clazz = classes[j++]) ) {
- if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
- cur += clazz + " ";
- }
- }
-
- // only assign if different to avoid unneeded rendering.
- finalValue = jQuery.trim( cur );
- if ( elem.className !== finalValue ) {
- elem.className = finalValue;
- }
- }
- }
- }
-
- return this;
- },
-
- removeClass: function( value ) {
- var classes, elem, cur, clazz, j, finalValue,
- proceed = arguments.length === 0 || typeof value === "string" && value,
- i = 0,
- len = this.length;
-
- if ( jQuery.isFunction( value ) ) {
- return this.each(function( j ) {
- jQuery( this ).removeClass( value.call( this, j, this.className ) );
- });
- }
- if ( proceed ) {
- classes = ( value || "" ).match( rnotwhite ) || [];
-
- for ( ; i < len; i++ ) {
- elem = this[ i ];
- // This expression is here for better compressibility (see addClass)
- cur = elem.nodeType === 1 && ( elem.className ?
- ( " " + elem.className + " " ).replace( rclass, " " ) :
- ""
- );
-
- if ( cur ) {
- j = 0;
- while ( (clazz = classes[j++]) ) {
- // Remove *all* instances
- while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
- cur = cur.replace( " " + clazz + " ", " " );
- }
- }
-
- // only assign if different to avoid unneeded rendering.
- finalValue = value ? jQuery.trim( cur ) : "";
- if ( elem.className !== finalValue ) {
- elem.className = finalValue;
- }
- }
- }
- }
-
- return this;
- },
-
- toggleClass: function( value, stateVal ) {
- var type = typeof value;
-
- if ( typeof stateVal === "boolean" && type === "string" ) {
- return stateVal ? this.addClass( value ) : this.removeClass( value );
- }
-
- if ( jQuery.isFunction( value ) ) {
- return this.each(function( i ) {
- jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
- });
- }
-
- return this.each(function() {
- if ( type === "string" ) {
- // toggle individual class names
- var className,
- i = 0,
- self = jQuery( this ),
- classNames = value.match( rnotwhite ) || [];
-
- while ( (className = classNames[ i++ ]) ) {
- // check each className given, space separated list
- if ( self.hasClass( className ) ) {
- self.removeClass( className );
- } else {
- self.addClass( className );
- }
- }
-
- // Toggle whole class name
- } else if ( type === strundefined || type === "boolean" ) {
- if ( this.className ) {
- // store className if set
- data_priv.set( this, "__className__", this.className );
- }
-
- // If the element has a class name or if we're passed "false",
- // then remove the whole classname (if there was one, the above saved it).
- // Otherwise bring back whatever was previously saved (if anything),
- // falling back to the empty string if nothing was stored.
- this.className = this.className || value === false ? "" : data_priv.get( this, "__className__" ) || "";
- }
- });
- },
-
- hasClass: function( selector ) {
- var className = " " + selector + " ",
- i = 0,
- l = this.length;
- for ( ; i < l; i++ ) {
- if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
- return true;
- }
- }
-
- return false;
- }
-});
-
-
-
-
-var rreturn = /\r/g;
-
-jQuery.fn.extend({
- val: function( value ) {
- var hooks, ret, isFunction,
- elem = this[0];
-
- if ( !arguments.length ) {
- if ( elem ) {
- hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
-
- if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
- return ret;
- }
-
- ret = elem.value;
-
- return typeof ret === "string" ?
- // handle most common string cases
- ret.replace(rreturn, "") :
- // handle cases where value is null/undef or number
- ret == null ? "" : ret;
- }
-
- return;
- }
-
- isFunction = jQuery.isFunction( value );
-
- return this.each(function( i ) {
- var val;
-
- if ( this.nodeType !== 1 ) {
- return;
- }
-
- if ( isFunction ) {
- val = value.call( this, i, jQuery( this ).val() );
- } else {
- val = value;
- }
-
- // Treat null/undefined as ""; convert numbers to string
- if ( val == null ) {
- val = "";
-
- } else if ( typeof val === "number" ) {
- val += "";
-
- } else if ( jQuery.isArray( val ) ) {
- val = jQuery.map( val, function( value ) {
- return value == null ? "" : value + "";
- });
- }
-
- hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
-
- // If set returns undefined, fall back to normal setting
- if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
- this.value = val;
- }
- });
- }
-});
-
-jQuery.extend({
- valHooks: {
- option: {
- get: function( elem ) {
- var val = jQuery.find.attr( elem, "value" );
- return val != null ?
- val :
- // Support: IE10-11+
- // option.text throws exceptions (#14686, #14858)
- jQuery.trim( jQuery.text( elem ) );
- }
- },
- select: {
- get: function( elem ) {
- var value, option,
- options = elem.options,
- index = elem.selectedIndex,
- one = elem.type === "select-one" || index < 0,
- values = one ? null : [],
- max = one ? index + 1 : options.length,
- i = index < 0 ?
- max :
- one ? index : 0;
-
- // Loop through all the selected options
- for ( ; i < max; i++ ) {
- option = options[ i ];
-
- // IE6-9 doesn't update selected after form reset (#2551)
- if ( ( option.selected || i === index ) &&
- // Don't return options that are disabled or in a disabled optgroup
- ( support.optDisabled ? !option.disabled : option.getAttribute( "disabled" ) === null ) &&
- ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
-
- // Get the specific value for the option
- value = jQuery( option ).val();
-
- // We don't need an array for one selects
- if ( one ) {
- return value;
- }
-
- // Multi-Selects return an array
- values.push( value );
- }
- }
-
- return values;
- },
-
- set: function( elem, value ) {
- var optionSet, option,
- options = elem.options,
- values = jQuery.makeArray( value ),
- i = options.length;
-
- while ( i-- ) {
- option = options[ i ];
- if ( (option.selected = jQuery.inArray( option.value, values ) >= 0) ) {
- optionSet = true;
- }
- }
-
- // force browsers to behave consistently when non-matching value is set
- if ( !optionSet ) {
- elem.selectedIndex = -1;
- }
- return values;
- }
- }
- }
-});
-
-// Radios and checkboxes getter/setter
-jQuery.each([ "radio", "checkbox" ], function() {
- jQuery.valHooks[ this ] = {
- set: function( elem, value ) {
- if ( jQuery.isArray( value ) ) {
- return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
- }
- }
- };
- if ( !support.checkOn ) {
- jQuery.valHooks[ this ].get = function( elem ) {
- // Support: Webkit
- // "" is returned instead of "on" if a value isn't specified
- return elem.getAttribute("value") === null ? "on" : elem.value;
- };
- }
-});
-
-
-
-
-// Return jQuery for attributes-only inclusion
-
-
-jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
- "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
- "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
-
- // Handle event binding
- jQuery.fn[ name ] = function( data, fn ) {
- return arguments.length > 0 ?
- this.on( name, null, data, fn ) :
- this.trigger( name );
- };
-});
-
-jQuery.fn.extend({
- hover: function( fnOver, fnOut ) {
- return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
- },
-
- bind: function( types, data, fn ) {
- return this.on( types, null, data, fn );
- },
- unbind: function( types, fn ) {
- return this.off( types, null, fn );
- },
-
- delegate: function( selector, types, data, fn ) {
- return this.on( types, selector, data, fn );
- },
- undelegate: function( selector, types, fn ) {
- // ( namespace ) or ( selector, types [, fn] )
- return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
- }
-});
-
-
-var nonce = jQuery.now();
-
-var rquery = (/\?/);
-
-
-
-// Support: Android 2.3
-// Workaround failure to string-cast null input
-jQuery.parseJSON = function( data ) {
- return JSON.parse( data + "" );
-};
-
-
-// Cross-browser xml parsing
-jQuery.parseXML = function( data ) {
- var xml, tmp;
- if ( !data || typeof data !== "string" ) {
- return null;
- }
-
- // Support: IE9
- try {
- tmp = new DOMParser();
- xml = tmp.parseFromString( data, "text/xml" );
- } catch ( e ) {
- xml = undefined;
- }
-
- if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
- jQuery.error( "Invalid XML: " + data );
- }
- return xml;
-};
-
-
-var
- // Document location
- ajaxLocParts,
- ajaxLocation,
-
- rhash = /#.*$/,
- rts = /([?&])_=[^&]*/,
- rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
- // #7653, #8125, #8152: local protocol detection
- rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
- rnoContent = /^(?:GET|HEAD)$/,
- rprotocol = /^\/\//,
- rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,
-
- /* Prefilters
- * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
- * 2) These are called:
- * - BEFORE asking for a transport
- * - AFTER param serialization (s.data is a string if s.processData is true)
- * 3) key is the dataType
- * 4) the catchall symbol "*" can be used
- * 5) execution will start with transport dataType and THEN continue down to "*" if needed
- */
- prefilters = {},
-
- /* Transports bindings
- * 1) key is the dataType
- * 2) the catchall symbol "*" can be used
- * 3) selection will start with transport dataType and THEN go to "*" if needed
- */
- transports = {},
-
- // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
- allTypes = "*/".concat("*");
-
-// #8138, IE may throw an exception when accessing
-// a field from window.location if document.domain has been set
-try {
- ajaxLocation = location.href;
-} catch( e ) {
- // Use the href attribute of an A element
- // since IE will modify it given document.location
- ajaxLocation = document.createElement( "a" );
- ajaxLocation.href = "";
- ajaxLocation = ajaxLocation.href;
-}
-
-// Segment location into parts
-ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
-
-// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
-function addToPrefiltersOrTransports( structure ) {
-
- // dataTypeExpression is optional and defaults to "*"
- return function( dataTypeExpression, func ) {
-
- if ( typeof dataTypeExpression !== "string" ) {
- func = dataTypeExpression;
- dataTypeExpression = "*";
- }
-
- var dataType,
- i = 0,
- dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];
-
- if ( jQuery.isFunction( func ) ) {
- // For each dataType in the dataTypeExpression
- while ( (dataType = dataTypes[i++]) ) {
- // Prepend if requested
- if ( dataType[0] === "+" ) {
- dataType = dataType.slice( 1 ) || "*";
- (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
-
- // Otherwise append
- } else {
- (structure[ dataType ] = structure[ dataType ] || []).push( func );
- }
- }
- }
- };
-}
-
-// Base inspection function for prefilters and transports
-function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
-
- var inspected = {},
- seekingTransport = ( structure === transports );
-
- function inspect( dataType ) {
- var selected;
- inspected[ dataType ] = true;
- jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
- var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
- if ( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
- options.dataTypes.unshift( dataTypeOrTransport );
- inspect( dataTypeOrTransport );
- return false;
- } else if ( seekingTransport ) {
- return !( selected = dataTypeOrTransport );
- }
- });
- return selected;
- }
-
- return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
-}
-
-// A special extend for ajax options
-// that takes "flat" options (not to be deep extended)
-// Fixes #9887
-function ajaxExtend( target, src ) {
- var key, deep,
- flatOptions = jQuery.ajaxSettings.flatOptions || {};
-
- for ( key in src ) {
- if ( src[ key ] !== undefined ) {
- ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
- }
- }
- if ( deep ) {
- jQuery.extend( true, target, deep );
- }
-
- return target;
-}
-
-/* Handles responses to an ajax request:
- * - finds the right dataType (mediates between content-type and expected dataType)
- * - returns the corresponding response
- */
-function ajaxHandleResponses( s, jqXHR, responses ) {
-
- var ct, type, finalDataType, firstDataType,
- contents = s.contents,
- dataTypes = s.dataTypes;
-
- // Remove auto dataType and get content-type in the process
- while ( dataTypes[ 0 ] === "*" ) {
- dataTypes.shift();
- if ( ct === undefined ) {
- ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
- }
- }
-
- // Check if we're dealing with a known content-type
- if ( ct ) {
- for ( type in contents ) {
- if ( contents[ type ] && contents[ type ].test( ct ) ) {
- dataTypes.unshift( type );
- break;
- }
- }
- }
-
- // Check to see if we have a response for the expected dataType
- if ( dataTypes[ 0 ] in responses ) {
- finalDataType = dataTypes[ 0 ];
- } else {
- // Try convertible dataTypes
- for ( type in responses ) {
- if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
- finalDataType = type;
- break;
- }
- if ( !firstDataType ) {
- firstDataType = type;
- }
- }
- // Or just use first one
- finalDataType = finalDataType || firstDataType;
- }
-
- // If we found a dataType
- // We add the dataType to the list if needed
- // and return the corresponding response
- if ( finalDataType ) {
- if ( finalDataType !== dataTypes[ 0 ] ) {
- dataTypes.unshift( finalDataType );
- }
- return responses[ finalDataType ];
- }
-}
-
-/* Chain conversions given the request and the original response
- * Also sets the responseXXX fields on the jqXHR instance
- */
-function ajaxConvert( s, response, jqXHR, isSuccess ) {
- var conv2, current, conv, tmp, prev,
- converters = {},
- // Work with a copy of dataTypes in case we need to modify it for conversion
- dataTypes = s.dataTypes.slice();
-
- // Create converters map with lowercased keys
- if ( dataTypes[ 1 ] ) {
- for ( conv in s.converters ) {
- converters[ conv.toLowerCase() ] = s.converters[ conv ];
- }
- }
-
- current = dataTypes.shift();
-
- // Convert to each sequential dataType
- while ( current ) {
-
- if ( s.responseFields[ current ] ) {
- jqXHR[ s.responseFields[ current ] ] = response;
- }
-
- // Apply the dataFilter if provided
- if ( !prev && isSuccess && s.dataFilter ) {
- response = s.dataFilter( response, s.dataType );
- }
-
- prev = current;
- current = dataTypes.shift();
-
- if ( current ) {
-
- // There's only work to do if current dataType is non-auto
- if ( current === "*" ) {
-
- current = prev;
-
- // Convert response if prev dataType is non-auto and differs from current
- } else if ( prev !== "*" && prev !== current ) {
-
- // Seek a direct converter
- conv = converters[ prev + " " + current ] || converters[ "* " + current ];
-
- // If none found, seek a pair
- if ( !conv ) {
- for ( conv2 in converters ) {
-
- // If conv2 outputs current
- tmp = conv2.split( " " );
- if ( tmp[ 1 ] === current ) {
-
- // If prev can be converted to accepted input
- conv = converters[ prev + " " + tmp[ 0 ] ] ||
- converters[ "* " + tmp[ 0 ] ];
- if ( conv ) {
- // Condense equivalence converters
- if ( conv === true ) {
- conv = converters[ conv2 ];
-
- // Otherwise, insert the intermediate dataType
- } else if ( converters[ conv2 ] !== true ) {
- current = tmp[ 0 ];
- dataTypes.unshift( tmp[ 1 ] );
- }
- break;
- }
- }
- }
- }
-
- // Apply converter (if not an equivalence)
- if ( conv !== true ) {
-
- // Unless errors are allowed to bubble, catch and return them
- if ( conv && s[ "throws" ] ) {
- response = conv( response );
- } else {
- try {
- response = conv( response );
- } catch ( e ) {
- return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
- }
- }
- }
- }
- }
- }
-
- return { state: "success", data: response };
-}
-
-jQuery.extend({
-
- // Counter for holding the number of active queries
- active: 0,
-
- // Last-Modified header cache for next request
- lastModified: {},
- etag: {},
-
- ajaxSettings: {
- url: ajaxLocation,
- type: "GET",
- isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
- global: true,
- processData: true,
- async: true,
- contentType: "application/x-www-form-urlencoded; charset=UTF-8",
- /*
- timeout: 0,
- data: null,
- dataType: null,
- username: null,
- password: null,
- cache: null,
- throws: false,
- traditional: false,
- headers: {},
- */
-
- accepts: {
- "*": allTypes,
- text: "text/plain",
- html: "text/html",
- xml: "application/xml, text/xml",
- json: "application/json, text/javascript"
- },
-
- contents: {
- xml: /xml/,
- html: /html/,
- json: /json/
- },
-
- responseFields: {
- xml: "responseXML",
- text: "responseText",
- json: "responseJSON"
- },
-
- // Data converters
- // Keys separate source (or catchall "*") and destination types with a single space
- converters: {
-
- // Convert anything to text
- "* text": String,
-
- // Text to html (true = no transformation)
- "text html": true,
-
- // Evaluate text as a json expression
- "text json": jQuery.parseJSON,
-
- // Parse text as xml
- "text xml": jQuery.parseXML
- },
-
- // For options that shouldn't be deep extended:
- // you can add your own custom options here if
- // and when you create one that shouldn't be
- // deep extended (see ajaxExtend)
- flatOptions: {
- url: true,
- context: true
- }
- },
-
- // Creates a full fledged settings object into target
- // with both ajaxSettings and settings fields.
- // If target is omitted, writes into ajaxSettings.
- ajaxSetup: function( target, settings ) {
- return settings ?
-
- // Building a settings object
- ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
-
- // Extending ajaxSettings
- ajaxExtend( jQuery.ajaxSettings, target );
- },
-
- ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
- ajaxTransport: addToPrefiltersOrTransports( transports ),
-
- // Main method
- ajax: function( url, options ) {
-
- // If url is an object, simulate pre-1.5 signature
- if ( typeof url === "object" ) {
- options = url;
- url = undefined;
- }
-
- // Force options to be an object
- options = options || {};
-
- var transport,
- // URL without anti-cache param
- cacheURL,
- // Response headers
- responseHeadersString,
- responseHeaders,
- // timeout handle
- timeoutTimer,
- // Cross-domain detection vars
- parts,
- // To know if global events are to be dispatched
- fireGlobals,
- // Loop variable
- i,
- // Create the final options object
- s = jQuery.ajaxSetup( {}, options ),
- // Callbacks context
- callbackContext = s.context || s,
- // Context for global events is callbackContext if it is a DOM node or jQuery collection
- globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
- jQuery( callbackContext ) :
- jQuery.event,
- // Deferreds
- deferred = jQuery.Deferred(),
- completeDeferred = jQuery.Callbacks("once memory"),
- // Status-dependent callbacks
- statusCode = s.statusCode || {},
- // Headers (they are sent all at once)
- requestHeaders = {},
- requestHeadersNames = {},
- // The jqXHR state
- state = 0,
- // Default abort message
- strAbort = "canceled",
- // Fake xhr
- jqXHR = {
- readyState: 0,
-
- // Builds headers hashtable if needed
- getResponseHeader: function( key ) {
- var match;
- if ( state === 2 ) {
- if ( !responseHeaders ) {
- responseHeaders = {};
- while ( (match = rheaders.exec( responseHeadersString )) ) {
- responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
- }
- }
- match = responseHeaders[ key.toLowerCase() ];
- }
- return match == null ? null : match;
- },
-
- // Raw string
- getAllResponseHeaders: function() {
- return state === 2 ? responseHeadersString : null;
- },
-
- // Caches the header
- setRequestHeader: function( name, value ) {
- var lname = name.toLowerCase();
- if ( !state ) {
- name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
- requestHeaders[ name ] = value;
- }
- return this;
- },
-
- // Overrides response content-type header
- overrideMimeType: function( type ) {
- if ( !state ) {
- s.mimeType = type;
- }
- return this;
- },
-
- // Status-dependent callbacks
- statusCode: function( map ) {
- var code;
- if ( map ) {
- if ( state < 2 ) {
- for ( code in map ) {
- // Lazy-add the new callback in a way that preserves old ones
- statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
- }
- } else {
- // Execute the appropriate callbacks
- jqXHR.always( map[ jqXHR.status ] );
- }
- }
- return this;
- },
-
- // Cancel the request
- abort: function( statusText ) {
- var finalText = statusText || strAbort;
- if ( transport ) {
- transport.abort( finalText );
- }
- done( 0, finalText );
- return this;
- }
- };
-
- // Attach deferreds
- deferred.promise( jqXHR ).complete = completeDeferred.add;
- jqXHR.success = jqXHR.done;
- jqXHR.error = jqXHR.fail;
-
- // Remove hash character (#7531: and string promotion)
- // Add protocol if not provided (prefilters might expect it)
- // Handle falsy url in the settings object (#10093: consistency with old signature)
- // We also use the url parameter if available
- s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" )
- .replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
-
- // Alias method option to type as per ticket #12004
- s.type = options.method || options.type || s.method || s.type;
-
- // Extract dataTypes list
- s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];
-
- // A cross-domain request is in order when we have a protocol:host:port mismatch
- if ( s.crossDomain == null ) {
- parts = rurl.exec( s.url.toLowerCase() );
- s.crossDomain = !!( parts &&
- ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
- ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
- ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
- );
- }
-
- // Convert data if not already a string
- if ( s.data && s.processData && typeof s.data !== "string" ) {
- s.data = jQuery.param( s.data, s.traditional );
- }
-
- // Apply prefilters
- inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
-
- // If request was aborted inside a prefilter, stop there
- if ( state === 2 ) {
- return jqXHR;
- }
-
- // We can fire global events as of now if asked to
- fireGlobals = s.global;
-
- // Watch for a new set of requests
- if ( fireGlobals && jQuery.active++ === 0 ) {
- jQuery.event.trigger("ajaxStart");
- }
-
- // Uppercase the type
- s.type = s.type.toUpperCase();
-
- // Determine if request has content
- s.hasContent = !rnoContent.test( s.type );
-
- // Save the URL in case we're toying with the If-Modified-Since
- // and/or If-None-Match header later on
- cacheURL = s.url;
-
- // More options handling for requests with no content
- if ( !s.hasContent ) {
-
- // If data is available, append data to url
- if ( s.data ) {
- cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
- // #9682: remove data so that it's not used in an eventual retry
- delete s.data;
- }
-
- // Add anti-cache in url if needed
- if ( s.cache === false ) {
- s.url = rts.test( cacheURL ) ?
-
- // If there is already a '_' parameter, set its value
- cacheURL.replace( rts, "$1_=" + nonce++ ) :
-
- // Otherwise add one to the end
- cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++;
- }
- }
-
- // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
- if ( s.ifModified ) {
- if ( jQuery.lastModified[ cacheURL ] ) {
- jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
- }
- if ( jQuery.etag[ cacheURL ] ) {
- jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
- }
- }
-
- // Set the correct header, if data is being sent
- if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
- jqXHR.setRequestHeader( "Content-Type", s.contentType );
- }
-
- // Set the Accepts header for the server, depending on the dataType
- jqXHR.setRequestHeader(
- "Accept",
- s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
- s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
- s.accepts[ "*" ]
- );
-
- // Check for headers option
- for ( i in s.headers ) {
- jqXHR.setRequestHeader( i, s.headers[ i ] );
- }
-
- // Allow custom headers/mimetypes and early abort
- if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
- // Abort if not done already and return
- return jqXHR.abort();
- }
-
- // aborting is no longer a cancellation
- strAbort = "abort";
-
- // Install callbacks on deferreds
- for ( i in { success: 1, error: 1, complete: 1 } ) {
- jqXHR[ i ]( s[ i ] );
- }
-
- // Get transport
- transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
-
- // If no transport, we auto-abort
- if ( !transport ) {
- done( -1, "No Transport" );
- } else {
- jqXHR.readyState = 1;
-
- // Send global event
- if ( fireGlobals ) {
- globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
- }
- // Timeout
- if ( s.async && s.timeout > 0 ) {
- timeoutTimer = setTimeout(function() {
- jqXHR.abort("timeout");
- }, s.timeout );
- }
-
- try {
- state = 1;
- transport.send( requestHeaders, done );
- } catch ( e ) {
- // Propagate exception as error if not done
- if ( state < 2 ) {
- done( -1, e );
- // Simply rethrow otherwise
- } else {
- throw e;
- }
- }
- }
-
- // Callback for when everything is done
- function done( status, nativeStatusText, responses, headers ) {
- var isSuccess, success, error, response, modified,
- statusText = nativeStatusText;
-
- // Called once
- if ( state === 2 ) {
- return;
- }
-
- // State is "done" now
- state = 2;
-
- // Clear timeout if it exists
- if ( timeoutTimer ) {
- clearTimeout( timeoutTimer );
- }
-
- // Dereference transport for early garbage collection
- // (no matter how long the jqXHR object will be used)
- transport = undefined;
-
- // Cache response headers
- responseHeadersString = headers || "";
-
- // Set readyState
- jqXHR.readyState = status > 0 ? 4 : 0;
-
- // Determine if successful
- isSuccess = status >= 200 && status < 300 || status === 304;
-
- // Get response data
- if ( responses ) {
- response = ajaxHandleResponses( s, jqXHR, responses );
- }
-
- // Convert no matter what (that way responseXXX fields are always set)
- response = ajaxConvert( s, response, jqXHR, isSuccess );
-
- // If successful, handle type chaining
- if ( isSuccess ) {
-
- // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
- if ( s.ifModified ) {
- modified = jqXHR.getResponseHeader("Last-Modified");
- if ( modified ) {
- jQuery.lastModified[ cacheURL ] = modified;
- }
- modified = jqXHR.getResponseHeader("etag");
- if ( modified ) {
- jQuery.etag[ cacheURL ] = modified;
- }
- }
-
- // if no content
- if ( status === 204 || s.type === "HEAD" ) {
- statusText = "nocontent";
-
- // if not modified
- } else if ( status === 304 ) {
- statusText = "notmodified";
-
- // If we have data, let's convert it
- } else {
- statusText = response.state;
- success = response.data;
- error = response.error;
- isSuccess = !error;
- }
- } else {
- // We extract error from statusText
- // then normalize statusText and status for non-aborts
- error = statusText;
- if ( status || !statusText ) {
- statusText = "error";
- if ( status < 0 ) {
- status = 0;
- }
- }
- }
-
- // Set data for the fake xhr object
- jqXHR.status = status;
- jqXHR.statusText = ( nativeStatusText || statusText ) + "";
-
- // Success/Error
- if ( isSuccess ) {
- deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
- } else {
- deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
- }
-
- // Status-dependent callbacks
- jqXHR.statusCode( statusCode );
- statusCode = undefined;
-
- if ( fireGlobals ) {
- globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
- [ jqXHR, s, isSuccess ? success : error ] );
- }
-
- // Complete
- completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
-
- if ( fireGlobals ) {
- globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
- // Handle the global AJAX counter
- if ( !( --jQuery.active ) ) {
- jQuery.event.trigger("ajaxStop");
- }
- }
- }
-
- return jqXHR;
- },
-
- getJSON: function( url, data, callback ) {
- return jQuery.get( url, data, callback, "json" );
- },
-
- getScript: function( url, callback ) {
- return jQuery.get( url, undefined, callback, "script" );
- }
-});
-
-jQuery.each( [ "get", "post" ], function( i, method ) {
- jQuery[ method ] = function( url, data, callback, type ) {
- // shift arguments if data argument was omitted
- if ( jQuery.isFunction( data ) ) {
- type = type || callback;
- callback = data;
- data = undefined;
- }
-
- return jQuery.ajax({
- url: url,
- type: method,
- dataType: type,
- data: data,
- success: callback
- });
- };
-});
-
-// Attach a bunch of functions for handling common AJAX events
-jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) {
- jQuery.fn[ type ] = function( fn ) {
- return this.on( type, fn );
- };
-});
-
-
-jQuery._evalUrl = function( url ) {
- return jQuery.ajax({
- url: url,
- type: "GET",
- dataType: "script",
- async: false,
- global: false,
- "throws": true
- });
-};
-
-
-jQuery.fn.extend({
- wrapAll: function( html ) {
- var wrap;
-
- if ( jQuery.isFunction( html ) ) {
- return this.each(function( i ) {
- jQuery( this ).wrapAll( html.call(this, i) );
- });
- }
-
- if ( this[ 0 ] ) {
-
- // The elements to wrap the target around
- wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
-
- if ( this[ 0 ].parentNode ) {
- wrap.insertBefore( this[ 0 ] );
- }
-
- wrap.map(function() {
- var elem = this;
-
- while ( elem.firstElementChild ) {
- elem = elem.firstElementChild;
- }
-
- return elem;
- }).append( this );
- }
-
- return this;
- },
-
- wrapInner: function( html ) {
- if ( jQuery.isFunction( html ) ) {
- return this.each(function( i ) {
- jQuery( this ).wrapInner( html.call(this, i) );
- });
- }
-
- return this.each(function() {
- var self = jQuery( this ),
- contents = self.contents();
-
- if ( contents.length ) {
- contents.wrapAll( html );
-
- } else {
- self.append( html );
- }
- });
- },
-
- wrap: function( html ) {
- var isFunction = jQuery.isFunction( html );
-
- return this.each(function( i ) {
- jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
- });
- },
-
- unwrap: function() {
- return this.parent().each(function() {
- if ( !jQuery.nodeName( this, "body" ) ) {
- jQuery( this ).replaceWith( this.childNodes );
- }
- }).end();
- }
-});
-
-
-jQuery.expr.filters.hidden = function( elem ) {
- // Support: Opera <= 12.12
- // Opera reports offsetWidths and offsetHeights less than zero on some elements
- return elem.offsetWidth <= 0 && elem.offsetHeight <= 0;
-};
-jQuery.expr.filters.visible = function( elem ) {
- return !jQuery.expr.filters.hidden( elem );
-};
-
-
-
-
-var r20 = /%20/g,
- rbracket = /\[\]$/,
- rCRLF = /\r?\n/g,
- rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
- rsubmittable = /^(?:input|select|textarea|keygen)/i;
-
-function buildParams( prefix, obj, traditional, add ) {
- var name;
-
- if ( jQuery.isArray( obj ) ) {
- // Serialize array item.
- jQuery.each( obj, function( i, v ) {
- if ( traditional || rbracket.test( prefix ) ) {
- // Treat each array item as a scalar.
- add( prefix, v );
-
- } else {
- // Item is non-scalar (array or object), encode its numeric index.
- buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
- }
- });
-
- } else if ( !traditional && jQuery.type( obj ) === "object" ) {
- // Serialize object item.
- for ( name in obj ) {
- buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
- }
-
- } else {
- // Serialize scalar item.
- add( prefix, obj );
- }
-}
-
-// Serialize an array of form elements or a set of
-// key/values into a query string
-jQuery.param = function( a, traditional ) {
- var prefix,
- s = [],
- add = function( key, value ) {
- // If value is a function, invoke it and return its value
- value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
- s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
- };
-
- // Set traditional to true for jQuery <= 1.3.2 behavior.
- if ( traditional === undefined ) {
- traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
- }
-
- // If an array was passed in, assume that it is an array of form elements.
- if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
- // Serialize the form elements
- jQuery.each( a, function() {
- add( this.name, this.value );
- });
-
- } else {
- // If traditional, encode the "old" way (the way 1.3.2 or older
- // did it), otherwise encode params recursively.
- for ( prefix in a ) {
- buildParams( prefix, a[ prefix ], traditional, add );
- }
- }
-
- // Return the resulting serialization
- return s.join( "&" ).replace( r20, "+" );
-};
-
-jQuery.fn.extend({
- serialize: function() {
- return jQuery.param( this.serializeArray() );
- },
- serializeArray: function() {
- return this.map(function() {
- // Can add propHook for "elements" to filter or add form elements
- var elements = jQuery.prop( this, "elements" );
- return elements ? jQuery.makeArray( elements ) : this;
- })
- .filter(function() {
- var type = this.type;
-
- // Use .is( ":disabled" ) so that fieldset[disabled] works
- return this.name && !jQuery( this ).is( ":disabled" ) &&
- rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
- ( this.checked || !rcheckableType.test( type ) );
- })
- .map(function( i, elem ) {
- var val = jQuery( this ).val();
-
- return val == null ?
- null :
- jQuery.isArray( val ) ?
- jQuery.map( val, function( val ) {
- return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
- }) :
- { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
- }).get();
- }
-});
-
-
-jQuery.ajaxSettings.xhr = function() {
- try {
- return new XMLHttpRequest();
- } catch( e ) {}
-};
-
-var xhrId = 0,
- xhrCallbacks = {},
- xhrSuccessStatus = {
- // file protocol always yields status code 0, assume 200
- 0: 200,
- // Support: IE9
- // #1450: sometimes IE returns 1223 when it should be 204
- 1223: 204
- },
- xhrSupported = jQuery.ajaxSettings.xhr();
-
-// Support: IE9
-// Open requests must be manually aborted on unload (#5280)
-if ( window.ActiveXObject ) {
- jQuery( window ).on( "unload", function() {
- for ( var key in xhrCallbacks ) {
- xhrCallbacks[ key ]();
- }
- });
-}
-
-support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
-support.ajax = xhrSupported = !!xhrSupported;
-
-jQuery.ajaxTransport(function( options ) {
- var callback;
-
- // Cross domain only allowed if supported through XMLHttpRequest
- if ( support.cors || xhrSupported && !options.crossDomain ) {
- return {
- send: function( headers, complete ) {
- var i,
- xhr = options.xhr(),
- id = ++xhrId;
-
- xhr.open( options.type, options.url, options.async, options.username, options.password );
-
- // Apply custom fields if provided
- if ( options.xhrFields ) {
- for ( i in options.xhrFields ) {
- xhr[ i ] = options.xhrFields[ i ];
- }
- }
-
- // Override mime type if needed
- if ( options.mimeType && xhr.overrideMimeType ) {
- xhr.overrideMimeType( options.mimeType );
- }
-
- // X-Requested-With header
- // For cross-domain requests, seeing as conditions for a preflight are
- // akin to a jigsaw puzzle, we simply never set it to be sure.
- // (it can always be set on a per-request basis or even using ajaxSetup)
- // For same-domain requests, won't change header if already provided.
- if ( !options.crossDomain && !headers["X-Requested-With"] ) {
- headers["X-Requested-With"] = "XMLHttpRequest";
- }
-
- // Set headers
- for ( i in headers ) {
- xhr.setRequestHeader( i, headers[ i ] );
- }
-
- // Callback
- callback = function( type ) {
- return function() {
- if ( callback ) {
- delete xhrCallbacks[ id ];
- callback = xhr.onload = xhr.onerror = null;
-
- if ( type === "abort" ) {
- xhr.abort();
- } else if ( type === "error" ) {
- complete(
- // file: protocol always yields status 0; see #8605, #14207
- xhr.status,
- xhr.statusText
- );
- } else {
- complete(
- xhrSuccessStatus[ xhr.status ] || xhr.status,
- xhr.statusText,
- // Support: IE9
- // Accessing binary-data responseText throws an exception
- // (#11426)
- typeof xhr.responseText === "string" ? {
- text: xhr.responseText
- } : undefined,
- xhr.getAllResponseHeaders()
- );
- }
- }
- };
- };
-
- // Listen to events
- xhr.onload = callback();
- xhr.onerror = callback("error");
-
- // Create the abort callback
- callback = xhrCallbacks[ id ] = callback("abort");
-
- try {
- // Do send the request (this may raise an exception)
- xhr.send( options.hasContent && options.data || null );
- } catch ( e ) {
- // #14683: Only rethrow if this hasn't been notified as an error yet
- if ( callback ) {
- throw e;
- }
- }
- },
-
- abort: function() {
- if ( callback ) {
- callback();
- }
- }
- };
- }
-});
-
-
-
-
-// Install script dataType
-jQuery.ajaxSetup({
- accepts: {
- script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
- },
- contents: {
- script: /(?:java|ecma)script/
- },
- converters: {
- "text script": function( text ) {
- jQuery.globalEval( text );
- return text;
- }
- }
-});
-
-// Handle cache's special case and crossDomain
-jQuery.ajaxPrefilter( "script", function( s ) {
- if ( s.cache === undefined ) {
- s.cache = false;
- }
- if ( s.crossDomain ) {
- s.type = "GET";
- }
-});
-
-// Bind script tag hack transport
-jQuery.ajaxTransport( "script", function( s ) {
- // This transport only deals with cross domain requests
- if ( s.crossDomain ) {
- var script, callback;
- return {
- send: function( _, complete ) {
- script = jQuery("<script>").prop({
- async: true,
- charset: s.scriptCharset,
- src: s.url
- }).on(
- "load error",
- callback = function( evt ) {
- script.remove();
- callback = null;
- if ( evt ) {
- complete( evt.type === "error" ? 404 : 200, evt.type );
- }
- }
- );
- document.head.appendChild( script[ 0 ] );
- },
- abort: function() {
- if ( callback ) {
- callback();
- }
- }
- };
- }
-});
-
-
-
-
-var oldCallbacks = [],
- rjsonp = /(=)\?(?=&|$)|\?\?/;
-
-// Default jsonp settings
-jQuery.ajaxSetup({
- jsonp: "callback",
- jsonpCallback: function() {
- var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
- this[ callback ] = true;
- return callback;
- }
-});
-
-// Detect, normalize options and install callbacks for jsonp requests
-jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
-
- var callbackName, overwritten, responseContainer,
- jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
- "url" :
- typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
- );
-
- // Handle iff the expected data type is "jsonp" or we have a parameter to set
- if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
-
- // Get callback name, remembering preexisting value associated with it
- callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
- s.jsonpCallback() :
- s.jsonpCallback;
-
- // Insert callback into url or form data
- if ( jsonProp ) {
- s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
- } else if ( s.jsonp !== false ) {
- s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
- }
-
- // Use data converter to retrieve json after script execution
- s.converters["script json"] = function() {
- if ( !responseContainer ) {
- jQuery.error( callbackName + " was not called" );
- }
- return responseContainer[ 0 ];
- };
-
- // force json dataType
- s.dataTypes[ 0 ] = "json";
-
- // Install callback
- overwritten = window[ callbackName ];
- window[ callbackName ] = function() {
- responseContainer = arguments;
- };
-
- // Clean-up function (fires after converters)
- jqXHR.always(function() {
- // Restore preexisting value
- window[ callbackName ] = overwritten;
-
- // Save back as free
- if ( s[ callbackName ] ) {
- // make sure that re-using the options doesn't screw things around
- s.jsonpCallback = originalSettings.jsonpCallback;
-
- // save the callback name for future use
- oldCallbacks.push( callbackName );
- }
-
- // Call if it was a function and we have a response
- if ( responseContainer && jQuery.isFunction( overwritten ) ) {
- overwritten( responseContainer[ 0 ] );
- }
-
- responseContainer = overwritten = undefined;
- });
-
- // Delegate to script
- return "script";
- }
-});
-
-
-
-
-// data: string of html
-// context (optional): If specified, the fragment will be created in this context, defaults to document
-// keepScripts (optional): If true, will include scripts passed in the html string
-jQuery.parseHTML = function( data, context, keepScripts ) {
- if ( !data || typeof data !== "string" ) {
- return null;
- }
- if ( typeof context === "boolean" ) {
- keepScripts = context;
- context = false;
- }
- context = context || document;
-
- var parsed = rsingleTag.exec( data ),
- scripts = !keepScripts && [];
-
- // Single tag
- if ( parsed ) {
- return [ context.createElement( parsed[1] ) ];
- }
-
- parsed = jQuery.buildFragment( [ data ], context, scripts );
-
- if ( scripts && scripts.length ) {
- jQuery( scripts ).remove();
- }
-
- return jQuery.merge( [], parsed.childNodes );
-};
-
-
-// Keep a copy of the old load method
-var _load = jQuery.fn.load;
-
-/**
- * Load a url into a page
- */
-jQuery.fn.load = function( url, params, callback ) {
- if ( typeof url !== "string" && _load ) {
- return _load.apply( this, arguments );
- }
-
- var selector, type, response,
- self = this,
- off = url.indexOf(" ");
-
- if ( off >= 0 ) {
- selector = jQuery.trim( url.slice( off ) );
- url = url.slice( 0, off );
- }
-
- // If it's a function
- if ( jQuery.isFunction( params ) ) {
-
- // We assume that it's the callback
- callback = params;
- params = undefined;
-
- // Otherwise, build a param string
- } else if ( params && typeof params === "object" ) {
- type = "POST";
- }
-
- // If we have elements to modify, make the request
- if ( self.length > 0 ) {
- jQuery.ajax({
- url: url,
-
- // if "type" variable is undefined, then "GET" method will be used
- type: type,
- dataType: "html",
- data: params
- }).done(function( responseText ) {
-
- // Save response for use in complete callback
- response = arguments;
-
- self.html( selector ?
-
- // If a selector was specified, locate the right elements in a dummy div
- // Exclude scripts to avoid IE 'Permission Denied' errors
- jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
-
- // Otherwise use the full result
- responseText );
-
- }).complete( callback && function( jqXHR, status ) {
- self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
- });
- }
-
- return this;
-};
-
-
-
-
-jQuery.expr.filters.animated = function( elem ) {
- return jQuery.grep(jQuery.timers, function( fn ) {
- return elem === fn.elem;
- }).length;
-};
-
-
-
-
-var docElem = window.document.documentElement;
-
-/**
- * Gets a window from an element
- */
-function getWindow( elem ) {
- return jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;
-}
-
-jQuery.offset = {
- setOffset: function( elem, options, i ) {
- var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
- position = jQuery.css( elem, "position" ),
- curElem = jQuery( elem ),
- props = {};
-
- // Set position first, in-case top/left are set even on static elem
- if ( position === "static" ) {
- elem.style.position = "relative";
- }
-
- curOffset = curElem.offset();
- curCSSTop = jQuery.css( elem, "top" );
- curCSSLeft = jQuery.css( elem, "left" );
- calculatePosition = ( position === "absolute" || position === "fixed" ) &&
- ( curCSSTop + curCSSLeft ).indexOf("auto") > -1;
-
- // Need to be able to calculate position if either top or left is auto and position is either absolute or fixed
- if ( calculatePosition ) {
- curPosition = curElem.position();
- curTop = curPosition.top;
- curLeft = curPosition.left;
-
- } else {
- curTop = parseFloat( curCSSTop ) || 0;
- curLeft = parseFloat( curCSSLeft ) || 0;
- }
-
- if ( jQuery.isFunction( options ) ) {
- options = options.call( elem, i, curOffset );
- }
-
- if ( options.top != null ) {
- props.top = ( options.top - curOffset.top ) + curTop;
- }
- if ( options.left != null ) {
- props.left = ( options.left - curOffset.left ) + curLeft;
- }
-
- if ( "using" in options ) {
- options.using.call( elem, props );
-
- } else {
- curElem.css( props );
- }
- }
-};
-
-jQuery.fn.extend({
- offset: function( options ) {
- if ( arguments.length ) {
- return options === undefined ?
- this :
- this.each(function( i ) {
- jQuery.offset.setOffset( this, options, i );
- });
- }
-
- var docElem, win,
- elem = this[ 0 ],
- box = { top: 0, left: 0 },
- doc = elem && elem.ownerDocument;
-
- if ( !doc ) {
- return;
- }
-
- docElem = doc.documentElement;
-
- // Make sure it's not a disconnected DOM node
- if ( !jQuery.contains( docElem, elem ) ) {
- return box;
- }
-
- // If we don't have gBCR, just use 0,0 rather than error
- // BlackBerry 5, iOS 3 (original iPhone)
- if ( typeof elem.getBoundingClientRect !== strundefined ) {
- box = elem.getBoundingClientRect();
- }
- win = getWindow( doc );
- return {
- top: box.top + win.pageYOffset - docElem.clientTop,
- left: box.left + win.pageXOffset - docElem.clientLeft
- };
- },
-
- position: function() {
- if ( !this[ 0 ] ) {
- return;
- }
-
- var offsetParent, offset,
- elem = this[ 0 ],
- parentOffset = { top: 0, left: 0 };
-
- // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent
- if ( jQuery.css( elem, "position" ) === "fixed" ) {
- // We assume that getBoundingClientRect is available when computed position is fixed
- offset = elem.getBoundingClientRect();
-
- } else {
- // Get *real* offsetParent
- offsetParent = this.offsetParent();
-
- // Get correct offsets
- offset = this.offset();
- if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
- parentOffset = offsetParent.offset();
- }
-
- // Add offsetParent borders
- parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
- parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
- }
-
- // Subtract parent offsets and element margins
- return {
- top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
- left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
- };
- },
-
- offsetParent: function() {
- return this.map(function() {
- var offsetParent = this.offsetParent || docElem;
-
- while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position" ) === "static" ) ) {
- offsetParent = offsetParent.offsetParent;
- }
-
- return offsetParent || docElem;
- });
- }
-});
-
-// Create scrollLeft and scrollTop methods
-jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
- var top = "pageYOffset" === prop;
-
- jQuery.fn[ method ] = function( val ) {
- return access( this, function( elem, method, val ) {
- var win = getWindow( elem );
-
- if ( val === undefined ) {
- return win ? win[ prop ] : elem[ method ];
- }
-
- if ( win ) {
- win.scrollTo(
- !top ? val : window.pageXOffset,
- top ? val : window.pageYOffset
- );
-
- } else {
- elem[ method ] = val;
- }
- }, method, val, arguments.length, null );
- };
-});
-
-// Add the top/left cssHooks using jQuery.fn.position
-// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
-// getComputedStyle returns percent when specified for top/left/bottom/right
-// rather than make the css module depend on the offset module, we just check for it here
-jQuery.each( [ "top", "left" ], function( i, prop ) {
- jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
- function( elem, computed ) {
- if ( computed ) {
- computed = curCSS( elem, prop );
- // if curCSS returns percentage, fallback to offset
- return rnumnonpx.test( computed ) ?
- jQuery( elem ).position()[ prop ] + "px" :
- computed;
- }
- }
- );
-});
-
-
-// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
-jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
- jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
- // margin is only for outerHeight, outerWidth
- jQuery.fn[ funcName ] = function( margin, value ) {
- var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
- extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
-
- return access( this, function( elem, type, value ) {
- var doc;
-
- if ( jQuery.isWindow( elem ) ) {
- // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
- // isn't a whole lot we can do. See pull request at this URL for discussion:
- // https://github.com/jquery/jquery/pull/764
- return elem.document.documentElement[ "client" + name ];
- }
-
- // Get document width or height
- if ( elem.nodeType === 9 ) {
- doc = elem.documentElement;
-
- // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
- // whichever is greatest
- return Math.max(
- elem.body[ "scroll" + name ], doc[ "scroll" + name ],
- elem.body[ "offset" + name ], doc[ "offset" + name ],
- doc[ "client" + name ]
- );
- }
-
- return value === undefined ?
- // Get width or height on the element, requesting but not forcing parseFloat
- jQuery.css( elem, type, extra ) :
-
- // Set width or height on the element
- jQuery.style( elem, type, value, extra );
- }, type, chainable ? margin : undefined, chainable, null );
- };
- });
-});
-
-
-// The number of elements contained in the matched element set
-jQuery.fn.size = function() {
- return this.length;
-};
-
-jQuery.fn.andSelf = jQuery.fn.addBack;
-
-
-
-
-// Register as a named AMD module, since jQuery can be concatenated with other
-// files that may use define, but not via a proper concatenation script that
-// understands anonymous AMD modules. A named AMD is safest and most robust
-// way to register. Lowercase jquery is used because AMD module names are
-// derived from file names, and jQuery is normally delivered in a lowercase
-// file name. Do this after creating the global so that if an AMD module wants
-// to call noConflict to hide this version of jQuery, it will work.
-
-// Note that for maximum portability, libraries that are not jQuery should
-// declare themselves as anonymous modules, and avoid setting a global if an
-// AMD loader is present. jQuery is a special case. For more information, see
-// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
-
-if ( typeof define === "function" && define.amd ) {
- define( "jquery", [], function() {
- return jQuery;
- });
-}
-
-
-
-
-var
- // Map over jQuery in case of overwrite
- _jQuery = window.jQuery,
-
- // Map over the $ in case of overwrite
- _$ = window.$;
-
-jQuery.noConflict = function( deep ) {
- if ( window.$ === jQuery ) {
- window.$ = _$;
- }
-
- if ( deep && window.jQuery === jQuery ) {
- window.jQuery = _jQuery;
- }
-
- return jQuery;
-};
-
-// Expose jQuery and $ identifiers, even in
-// AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
-// and CommonJS for browser emulators (#13566)
-if ( typeof noGlobal === strundefined ) {
- window.jQuery = window.$ = jQuery;
-}
-
-
-
-
-return jQuery;
-
-}));
-
-/**
- * @license
- * Lo-Dash 2.4.1 (Custom Build) <http://lodash.com/>
- * Build: `lodash modern -o ./dist/lodash.js`
- * Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.5.2 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <http://lodash.com/license>
- */
-;(function() {
-
- /** Used as a safe reference for `undefined` in pre ES5 environments */
- var undefined;
-
- /** Used to pool arrays and objects used internally */
- var arrayPool = [],
- objectPool = [];
-
- /** Used to generate unique IDs */
- var idCounter = 0;
-
- /** Used to prefix keys to avoid issues with `__proto__` and properties on `Object.prototype` */
- var keyPrefix = +new Date + '';
-
- /** Used as the size when optimizations are enabled for large arrays */
- var largeArraySize = 75;
-
- /** Used as the max size of the `arrayPool` and `objectPool` */
- var maxPoolSize = 40;
-
- /** Used to detect and test whitespace */
- var whitespace = (
- // whitespace
- ' \t\x0B\f\xA0\ufeff' +
-
- // line terminators
- '\n\r\u2028\u2029' +
-
- // unicode category "Zs" space separators
- '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'
- );
-
- /** Used to match empty string literals in compiled template source */
- var reEmptyStringLeading = /\b__p \+= '';/g,
- reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
- reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
-
- /**
- * Used to match ES6 template delimiters
- * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-literals-string-literals
- */
- var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
-
- /** Used to match regexp flags from their coerced string values */
- var reFlags = /\w*$/;
-
- /** Used to detected named functions */
- var reFuncName = /^\s*function[ \n\r\t]+\w/;
-
- /** Used to match "interpolate" template delimiters */
- var reInterpolate = /<%=([\s\S]+?)%>/g;
-
- /** Used to match leading whitespace and zeros to be removed */
- var reLeadingSpacesAndZeros = RegExp('^[' + whitespace + ']*0+(?=.$)');
-
- /** Used to ensure capturing order of template delimiters */
- var reNoMatch = /($^)/;
-
- /** Used to detect functions containing a `this` reference */
- var reThis = /\bthis\b/;
-
- /** Used to match unescaped characters in compiled string literals */
- var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g;
-
- /** Used to assign default `context` object properties */
- var contextProps = [
- 'Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object',
- 'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN',
- 'parseInt', 'setTimeout'
- ];
-
- /** Used to make template sourceURLs easier to identify */
- var templateCounter = 0;
-
- /** `Object#toString` result shortcuts */
- var argsClass = '[object Arguments]',
- arrayClass = '[object Array]',
- boolClass = '[object Boolean]',
- dateClass = '[object Date]',
- funcClass = '[object Function]',
- numberClass = '[object Number]',
- objectClass = '[object Object]',
- regexpClass = '[object RegExp]',
- stringClass = '[object String]';
-
- /** Used to identify object classifications that `_.clone` supports */
- var cloneableClasses = {};
- cloneableClasses[funcClass] = false;
- cloneableClasses[argsClass] = cloneableClasses[arrayClass] =
- cloneableClasses[boolClass] = cloneableClasses[dateClass] =
- cloneableClasses[numberClass] = cloneableClasses[objectClass] =
- cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true;
-
- /** Used as an internal `_.debounce` options object */
- var debounceOptions = {
- 'leading': false,
- 'maxWait': 0,
- 'trailing': false
- };
-
- /** Used as the property descriptor for `__bindData__` */
- var descriptor = {
- 'configurable': false,
- 'enumerable': false,
- 'value': null,
- 'writable': false
- };
-
- /** Used to determine if values are of the language type Object */
- var objectTypes = {
- 'boolean': false,
- 'function': true,
- 'object': true,
- 'number': false,
- 'string': false,
- 'undefined': false
- };
-
- /** Used to escape characters for inclusion in compiled string literals */
- var stringEscapes = {
- '\\': '\\',
- "'": "'",
- '\n': 'n',
- '\r': 'r',
- '\t': 't',
- '\u2028': 'u2028',
- '\u2029': 'u2029'
- };
-
- /** Used as a reference to the global object */
- var root = (objectTypes[typeof window] && window) || this;
-
- /** Detect free variable `exports` */
- var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
-
- /** Detect free variable `module` */
- var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
-
- /** Detect the popular CommonJS extension `module.exports` */
- var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
-
- /** Detect free variable `global` from Node.js or Browserified code and use it as `root` */
- var freeGlobal = objectTypes[typeof global] && global;
- if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) {
- root = freeGlobal;
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * The base implementation of `_.indexOf` without support for binary searches
- * or `fromIndex` constraints.
- *
- * @private
- * @param {Array} array The array to search.
- * @param {*} value The value to search for.
- * @param {number} [fromIndex=0] The index to search from.
- * @returns {number} Returns the index of the matched value or `-1`.
- */
- function baseIndexOf(array, value, fromIndex) {
- var index = (fromIndex || 0) - 1,
- length = array ? array.length : 0;
-
- while (++index < length) {
- if (array[index] === value) {
- return index;
- }
- }
- return -1;
- }
-
- /**
- * An implementation of `_.contains` for cache objects that mimics the return
- * signature of `_.indexOf` by returning `0` if the value is found, else `-1`.
- *
- * @private
- * @param {Object} cache The cache object to inspect.
- * @param {*} value The value to search for.
- * @returns {number} Returns `0` if `value` is found, else `-1`.
- */
- function cacheIndexOf(cache, value) {
- var type = typeof value;
- cache = cache.cache;
-
- if (type == 'boolean' || value == null) {
- return cache[value] ? 0 : -1;
- }
- if (type != 'number' && type != 'string') {
- type = 'object';
- }
- var key = type == 'number' ? value : keyPrefix + value;
- cache = (cache = cache[type]) && cache[key];
-
- return type == 'object'
- ? (cache && baseIndexOf(cache, value) > -1 ? 0 : -1)
- : (cache ? 0 : -1);
- }
-
- /**
- * Adds a given value to the corresponding cache object.
- *
- * @private
- * @param {*} value The value to add to the cache.
- */
- function cachePush(value) {
- var cache = this.cache,
- type = typeof value;
-
- if (type == 'boolean' || value == null) {
- cache[value] = true;
- } else {
- if (type != 'number' && type != 'string') {
- type = 'object';
- }
- var key = type == 'number' ? value : keyPrefix + value,
- typeCache = cache[type] || (cache[type] = {});
-
- if (type == 'object') {
- (typeCache[key] || (typeCache[key] = [])).push(value);
- } else {
- typeCache[key] = true;
- }
- }
- }
-
- /**
- * Used by `_.max` and `_.min` as the default callback when a given
- * collection is a string value.
- *
- * @private
- * @param {string} value The character to inspect.
- * @returns {number} Returns the code unit of given character.
- */
- function charAtCallback(value) {
- return value.charCodeAt(0);
- }
-
- /**
- * Used by `sortBy` to compare transformed `collection` elements, stable sorting
- * them in ascending order.
- *
- * @private
- * @param {Object} a The object to compare to `b`.
- * @param {Object} b The object to compare to `a`.
- * @returns {number} Returns the sort order indicator of `1` or `-1`.
- */
- function compareAscending(a, b) {
- var ac = a.criteria,
- bc = b.criteria,
- index = -1,
- length = ac.length;
-
- while (++index < length) {
- var value = ac[index],
- other = bc[index];
-
- if (value !== other) {
- if (value > other || typeof value == 'undefined') {
- return 1;
- }
- if (value < other || typeof other == 'undefined') {
- return -1;
- }
- }
- }
- // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
- // that causes it, under certain circumstances, to return the same value for
- // `a` and `b`. See https://github.com/jashkenas/underscore/pull/1247
- //
- // This also ensures a stable sort in V8 and other engines.
- // See http://code.google.com/p/v8/issues/detail?id=90
- return a.index - b.index;
- }
-
- /**
- * Creates a cache object to optimize linear searches of large arrays.
- *
- * @private
- * @param {Array} [array=[]] The array to search.
- * @returns {null|Object} Returns the cache object or `null` if caching should not be used.
- */
- function createCache(array) {
- var index = -1,
- length = array.length,
- first = array[0],
- mid = array[(length / 2) | 0],
- last = array[length - 1];
-
- if (first && typeof first == 'object' &&
- mid && typeof mid == 'object' && last && typeof last == 'object') {
- return false;
- }
- var cache = getObject();
- cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false;
-
- var result = getObject();
- result.array = array;
- result.cache = cache;
- result.push = cachePush;
-
- while (++index < length) {
- result.push(array[index]);
- }
- return result;
- }
-
- /**
- * Used by `template` to escape characters for inclusion in compiled
- * string literals.
- *
- * @private
- * @param {string} match The matched character to escape.
- * @returns {string} Returns the escaped character.
- */
- function escapeStringChar(match) {
- return '\\' + stringEscapes[match];
- }
-
- /**
- * Gets an array from the array pool or creates a new one if the pool is empty.
- *
- * @private
- * @returns {Array} The array from the pool.
- */
- function getArray() {
- return arrayPool.pop() || [];
- }
-
- /**
- * Gets an object from the object pool or creates a new one if the pool is empty.
- *
- * @private
- * @returns {Object} The object from the pool.
- */
- function getObject() {
- return objectPool.pop() || {
- 'array': null,
- 'cache': null,
- 'criteria': null,
- 'false': false,
- 'index': 0,
- 'null': false,
- 'number': null,
- 'object': null,
- 'push': null,
- 'string': null,
- 'true': false,
- 'undefined': false,
- 'value': null
- };
- }
-
- /**
- * Releases the given array back to the array pool.
- *
- * @private
- * @param {Array} [array] The array to release.
- */
- function releaseArray(array) {
- array.length = 0;
- if (arrayPool.length < maxPoolSize) {
- arrayPool.push(array);
- }
- }
-
- /**
- * Releases the given object back to the object pool.
- *
- * @private
- * @param {Object} [object] The object to release.
- */
- function releaseObject(object) {
- var cache = object.cache;
- if (cache) {
- releaseObject(cache);
- }
- object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null;
- if (objectPool.length < maxPoolSize) {
- objectPool.push(object);
- }
- }
-
- /**
- * Slices the `collection` from the `start` index up to, but not including,
- * the `end` index.
- *
- * Note: This function is used instead of `Array#slice` to support node lists
- * in IE < 9 and to ensure dense arrays are returned.
- *
- * @private
- * @param {Array|Object|string} collection The collection to slice.
- * @param {number} start The start index.
- * @param {number} end The end index.
- * @returns {Array} Returns the new array.
- */
- function slice(array, start, end) {
- start || (start = 0);
- if (typeof end == 'undefined') {
- end = array ? array.length : 0;
- }
- var index = -1,
- length = end - start || 0,
- result = Array(length < 0 ? 0 : length);
-
- while (++index < length) {
- result[index] = array[start + index];
- }
- return result;
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Create a new `lodash` function using the given context object.
- *
- * @static
- * @memberOf _
- * @category Utilities
- * @param {Object} [context=root] The context object.
- * @returns {Function} Returns the `lodash` function.
- */
- function runInContext(context) {
- // Avoid issues with some ES3 environments that attempt to use values, named
- // after built-in constructors like `Object`, for the creation of literals.
- // ES5 clears this up by stating that literals must use built-in constructors.
- // See http://es5.github.io/#x11.1.5.
- context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root;
-
- /** Native constructor references */
- var Array = context.Array,
- Boolean = context.Boolean,
- Date = context.Date,
- Function = context.Function,
- Math = context.Math,
- Number = context.Number,
- Object = context.Object,
- RegExp = context.RegExp,
- String = context.String,
- TypeError = context.TypeError;
-
- /**
- * Used for `Array` method references.
- *
- * Normally `Array.prototype` would suffice, however, using an array literal
- * avoids issues in Narwhal.
- */
- var arrayRef = [];
-
- /** Used for native method references */
- var objectProto = Object.prototype;
-
- /** Used to restore the original `_` reference in `noConflict` */
- var oldDash = context._;
-
- /** Used to resolve the internal [[Class]] of values */
- var toString = objectProto.toString;
-
- /** Used to detect if a method is native */
- var reNative = RegExp('^' +
- String(toString)
- .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
- .replace(/toString| for [^\]]+/g, '.*?') + '$'
- );
-
- /** Native method shortcuts */
- var ceil = Math.ceil,
- clearTimeout = context.clearTimeout,
- floor = Math.floor,
- fnToString = Function.prototype.toString,
- getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
- hasOwnProperty = objectProto.hasOwnProperty,
- push = arrayRef.push,
- setTimeout = context.setTimeout,
- splice = arrayRef.splice,
- unshift = arrayRef.unshift;
-
- /** Used to set meta data on functions */
- var defineProperty = (function() {
- // IE 8 only accepts DOM elements
- try {
- var o = {},
- func = isNative(func = Object.defineProperty) && func,
- result = func(o, o, o) && func;
- } catch(e) { }
- return result;
- }());
-
- /* Native method shortcuts for methods with the same name as other `lodash` methods */
- var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate,
- nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray,
- nativeIsFinite = context.isFinite,
- nativeIsNaN = context.isNaN,
- nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys,
- nativeMax = Math.max,
- nativeMin = Math.min,
- nativeParseInt = context.parseInt,
- nativeRandom = Math.random;
-
- /** Used to lookup a built-in constructor by [[Class]] */
- var ctorByClass = {};
- ctorByClass[arrayClass] = Array;
- ctorByClass[boolClass] = Boolean;
- ctorByClass[dateClass] = Date;
- ctorByClass[funcClass] = Function;
- ctorByClass[objectClass] = Object;
- ctorByClass[numberClass] = Number;
- ctorByClass[regexpClass] = RegExp;
- ctorByClass[stringClass] = String;
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Creates a `lodash` object which wraps the given value to enable intuitive
- * method chaining.
- *
- * In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
- * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
- * and `unshift`
- *
- * Chaining is supported in custom builds as long as the `value` method is
- * implicitly or explicitly included in the build.
- *
- * The chainable wrapper functions are:
- * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`,
- * `compose`, `concat`, `countBy`, `create`, `createCallback`, `curry`,
- * `debounce`, `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`,
- * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`,
- * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`,
- * `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`,
- * `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `pull`, `push`,
- * `range`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`,
- * `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`, `transform`,
- * `union`, `uniq`, `unshift`, `unzip`, `values`, `where`, `without`, `wrap`,
- * and `zip`
- *
- * The non-chainable wrapper functions are:
- * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `findIndex`,
- * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `has`, `identity`,
- * `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`,
- * `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`,
- * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`,
- * `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, `pop`, `random`, `reduce`,
- * `reduceRight`, `result`, `shift`, `size`, `some`, `sortedIndex`, `runInContext`,
- * `template`, `unescape`, `uniqueId`, and `value`
- *
- * The wrapper functions `first` and `last` return wrapped values when `n` is
- * provided, otherwise they return unwrapped values.
- *
- * Explicit chaining can be enabled by using the `_.chain` method.
- *
- * @name _
- * @constructor
- * @category Chaining
- * @param {*} value The value to wrap in a `lodash` instance.
- * @returns {Object} Returns a `lodash` instance.
- * @example
- *
- * var wrapped = _([1, 2, 3]);
- *
- * // returns an unwrapped value
- * wrapped.reduce(function(sum, num) {
- * return sum + num;
- * });
- * // => 6
- *
- * // returns a wrapped value
- * var squares = wrapped.map(function(num) {
- * return num * num;
- * });
- *
- * _.isArray(squares);
- * // => false
- *
- * _.isArray(squares.value());
- * // => true
- */
- function lodash(value) {
- // don't wrap if already wrapped, even if wrapped by a different `lodash` constructor
- return (value && typeof value == 'object' && !isArray(value) && hasOwnProperty.call(value, '__wrapped__'))
- ? value
- : new lodashWrapper(value);
- }
-
- /**
- * A fast path for creating `lodash` wrapper objects.
- *
- * @private
- * @param {*} value The value to wrap in a `lodash` instance.
- * @param {boolean} chainAll A flag to enable chaining for all methods
- * @returns {Object} Returns a `lodash` instance.
- */
- function lodashWrapper(value, chainAll) {
- this.__chain__ = !!chainAll;
- this.__wrapped__ = value;
- }
- // ensure `new lodashWrapper` is an instance of `lodash`
- lodashWrapper.prototype = lodash.prototype;
-
- /**
- * An object used to flag environments features.
- *
- * @static
- * @memberOf _
- * @type Object
- */
- var support = lodash.support = {};
-
- /**
- * Detect if functions can be decompiled by `Function#toString`
- * (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps).
- *
- * @memberOf _.support
- * @type boolean
- */
- support.funcDecomp = !isNative(context.WinRTError) && reThis.test(runInContext);
-
- /**
- * Detect if `Function#name` is supported (all but IE).
- *
- * @memberOf _.support
- * @type boolean
- */
- support.funcNames = typeof Function.name == 'string';
-
- /**
- * By default, the template delimiters used by Lo-Dash are similar to those in
- * embedded Ruby (ERB). Change the following template settings to use alternative
- * delimiters.
- *
- * @static
- * @memberOf _
- * @type Object
- */
- lodash.templateSettings = {
-
- /**
- * Used to detect `data` property values to be HTML-escaped.
- *
- * @memberOf _.templateSettings
- * @type RegExp
- */
- 'escape': /<%-([\s\S]+?)%>/g,
-
- /**
- * Used to detect code to be evaluated.
- *
- * @memberOf _.templateSettings
- * @type RegExp
- */
- 'evaluate': /<%([\s\S]+?)%>/g,
-
- /**
- * Used to detect `data` property values to inject.
- *
- * @memberOf _.templateSettings
- * @type RegExp
- */
- 'interpolate': reInterpolate,
-
- /**
- * Used to reference the data object in the template text.
- *
- * @memberOf _.templateSettings
- * @type string
- */
- 'variable': '',
-
- /**
- * Used to import variables into the compiled template.
- *
- * @memberOf _.templateSettings
- * @type Object
- */
- 'imports': {
-
- /**
- * A reference to the `lodash` function.
- *
- * @memberOf _.templateSettings.imports
- * @type Function
- */
- '_': lodash
- }
- };
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * The base implementation of `_.bind` that creates the bound function and
- * sets its meta data.
- *
- * @private
- * @param {Array} bindData The bind data array.
- * @returns {Function} Returns the new bound function.
- */
- function baseBind(bindData) {
- var func = bindData[0],
- partialArgs = bindData[2],
- thisArg = bindData[4];
-
- function bound() {
- // `Function#bind` spec
- // http://es5.github.io/#x15.3.4.5
- if (partialArgs) {
- // avoid `arguments` object deoptimizations by using `slice` instead
- // of `Array.prototype.slice.call` and not assigning `arguments` to a
- // variable as a ternary expression
- var args = slice(partialArgs);
- push.apply(args, arguments);
- }
- // mimic the constructor's `return` behavior
- // http://es5.github.io/#x13.2.2
- if (this instanceof bound) {
- // ensure `new bound` is an instance of `func`
- var thisBinding = baseCreate(func.prototype),
- result = func.apply(thisBinding, args || arguments);
- return isObject(result) ? result : thisBinding;
- }
- return func.apply(thisArg, args || arguments);
- }
- setBindData(bound, bindData);
- return bound;
- }
-
- /**
- * The base implementation of `_.clone` without argument juggling or support
- * for `thisArg` binding.
- *
- * @private
- * @param {*} value The value to clone.
- * @param {boolean} [isDeep=false] Specify a deep clone.
- * @param {Function} [callback] The function to customize cloning values.
- * @param {Array} [stackA=[]] Tracks traversed source objects.
- * @param {Array} [stackB=[]] Associates clones with source counterparts.
- * @returns {*} Returns the cloned value.
- */
- function baseClone(value, isDeep, callback, stackA, stackB) {
- if (callback) {
- var result = callback(value);
- if (typeof result != 'undefined') {
- return result;
- }
- }
- // inspect [[Class]]
- var isObj = isObject(value);
- if (isObj) {
- var className = toString.call(value);
- if (!cloneableClasses[className]) {
- return value;
- }
- var ctor = ctorByClass[className];
- switch (className) {
- case boolClass:
- case dateClass:
- return new ctor(+value);
-
- case numberClass:
- case stringClass:
- return new ctor(value);
-
- case regexpClass:
- result = ctor(value.source, reFlags.exec(value));
- result.lastIndex = value.lastIndex;
- return result;
- }
- } else {
- return value;
- }
- var isArr = isArray(value);
- if (isDeep) {
- // check for circular references and return corresponding clone
- var initedStack = !stackA;
- stackA || (stackA = getArray());
- stackB || (stackB = getArray());
-
- var length = stackA.length;
- while (length--) {
- if (stackA[length] == value) {
- return stackB[length];
- }
- }
- result = isArr ? ctor(value.length) : {};
- }
- else {
- result = isArr ? slice(value) : assign({}, value);
- }
- // add array properties assigned by `RegExp#exec`
- if (isArr) {
- if (hasOwnProperty.call(value, 'index')) {
- result.index = value.index;
- }
- if (hasOwnProperty.call(value, 'input')) {
- result.input = value.input;
- }
- }
- // exit for shallow clone
- if (!isDeep) {
- return result;
- }
- // add the source value to the stack of traversed objects
- // and associate it with its clone
- stackA.push(value);
- stackB.push(result);
-
- // recursively populate clone (susceptible to call stack limits)
- (isArr ? forEach : forOwn)(value, function(objValue, key) {
- result[key] = baseClone(objValue, isDeep, callback, stackA, stackB);
- });
-
- if (initedStack) {
- releaseArray(stackA);
- releaseArray(stackB);
- }
- return result;
- }
-
- /**
- * The base implementation of `_.create` without support for assigning
- * properties to the created object.
- *
- * @private
- * @param {Object} prototype The object to inherit from.
- * @returns {Object} Returns the new object.
- */
- function baseCreate(prototype, properties) {
- return isObject(prototype) ? nativeCreate(prototype) : {};
- }
- // fallback for browsers without `Object.create`
- if (!nativeCreate) {
- baseCreate = (function() {
- function Object() {}
- return function(prototype) {
- if (isObject(prototype)) {
- Object.prototype = prototype;
- var result = new Object;
- Object.prototype = null;
- }
- return result || context.Object();
- };
- }());
- }
-
- /**
- * The base implementation of `_.createCallback` without support for creating
- * "_.pluck" or "_.where" style callbacks.
- *
- * @private
- * @param {*} [func=identity] The value to convert to a callback.
- * @param {*} [thisArg] The `this` binding of the created callback.
- * @param {number} [argCount] The number of arguments the callback accepts.
- * @returns {Function} Returns a callback function.
- */
- function baseCreateCallback(func, thisArg, argCount) {
- if (typeof func != 'function') {
- return identity;
- }
- // exit early for no `thisArg` or already bound by `Function#bind`
- if (typeof thisArg == 'undefined' || !('prototype' in func)) {
- return func;
- }
- var bindData = func.__bindData__;
- if (typeof bindData == 'undefined') {
- if (support.funcNames) {
- bindData = !func.name;
- }
- bindData = bindData || !support.funcDecomp;
- if (!bindData) {
- var source = fnToString.call(func);
- if (!support.funcNames) {
- bindData = !reFuncName.test(source);
- }
- if (!bindData) {
- // checks if `func` references the `this` keyword and stores the result
- bindData = reThis.test(source);
- setBindData(func, bindData);
- }
- }
- }
- // exit early if there are no `this` references or `func` is bound
- if (bindData === false || (bindData !== true && bindData[1] & 1)) {
- return func;
- }
- switch (argCount) {
- case 1: return function(value) {
- return func.call(thisArg, value);
- };
- case 2: return function(a, b) {
- return func.call(thisArg, a, b);
- };
- case 3: return function(value, index, collection) {
- return func.call(thisArg, value, index, collection);
- };
- case 4: return function(accumulator, value, index, collection) {
- return func.call(thisArg, accumulator, value, index, collection);
- };
- }
- return bind(func, thisArg);
- }
-
- /**
- * The base implementation of `createWrapper` that creates the wrapper and
- * sets its meta data.
- *
- * @private
- * @param {Array} bindData The bind data array.
- * @returns {Function} Returns the new function.
- */
- function baseCreateWrapper(bindData) {
- var func = bindData[0],
- bitmask = bindData[1],
- partialArgs = bindData[2],
- partialRightArgs = bindData[3],
- thisArg = bindData[4],
- arity = bindData[5];
-
- var isBind = bitmask & 1,
- isBindKey = bitmask & 2,
- isCurry = bitmask & 4,
- isCurryBound = bitmask & 8,
- key = func;
-
- function bound() {
- var thisBinding = isBind ? thisArg : this;
- if (partialArgs) {
- var args = slice(partialArgs);
- push.apply(args, arguments);
- }
- if (partialRightArgs || isCurry) {
- args || (args = slice(arguments));
- if (partialRightArgs) {
- push.apply(args, partialRightArgs);
- }
- if (isCurry && args.length < arity) {
- bitmask |= 16 & ~32;
- return baseCreateWrapper([func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity]);
- }
- }
- args || (args = arguments);
- if (isBindKey) {
- func = thisBinding[key];
- }
- if (this instanceof bound) {
- thisBinding = baseCreate(func.prototype);
- var result = func.apply(thisBinding, args);
- return isObject(result) ? result : thisBinding;
- }
- return func.apply(thisBinding, args);
- }
- setBindData(bound, bindData);
- return bound;
- }
-
- /**
- * The base implementation of `_.difference` that accepts a single array
- * of values to exclude.
- *
- * @private
- * @param {Array} array The array to process.
- * @param {Array} [values] The array of values to exclude.
- * @returns {Array} Returns a new array of filtered values.
- */
- function baseDifference(array, values) {
- var index = -1,
- indexOf = getIndexOf(),
- length = array ? array.length : 0,
- isLarge = length >= largeArraySize && indexOf === baseIndexOf,
- result = [];
-
- if (isLarge) {
- var cache = createCache(values);
- if (cache) {
- indexOf = cacheIndexOf;
- values = cache;
- } else {
- isLarge = false;
- }
- }
- while (++index < length) {
- var value = array[index];
- if (indexOf(values, value) < 0) {
- result.push(value);
- }
- }
- if (isLarge) {
- releaseObject(values);
- }
- return result;
- }
-
- /**
- * The base implementation of `_.flatten` without support for callback
- * shorthands or `thisArg` binding.
- *
- * @private
- * @param {Array} array The array to flatten.
- * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
- * @param {boolean} [isStrict=false] A flag to restrict flattening to arrays and `arguments` objects.
- * @param {number} [fromIndex=0] The index to start from.
- * @returns {Array} Returns a new flattened array.
- */
- function baseFlatten(array, isShallow, isStrict, fromIndex) {
- var index = (fromIndex || 0) - 1,
- length = array ? array.length : 0,
- result = [];
-
- while (++index < length) {
- var value = array[index];
-
- if (value && typeof value == 'object' && typeof value.length == 'number'
- && (isArray(value) || isArguments(value))) {
- // recursively flatten arrays (susceptible to call stack limits)
- if (!isShallow) {
- value = baseFlatten(value, isShallow, isStrict);
- }
- var valIndex = -1,
- valLength = value.length,
- resIndex = result.length;
-
- result.length += valLength;
- while (++valIndex < valLength) {
- result[resIndex++] = value[valIndex];
- }
- } else if (!isStrict) {
- result.push(value);
- }
- }
- return result;
- }
-
- /**
- * The base implementation of `_.isEqual`, without support for `thisArg` binding,
- * that allows partial "_.where" style comparisons.
- *
- * @private
- * @param {*} a The value to compare.
- * @param {*} b The other value to compare.
- * @param {Function} [callback] The function to customize comparing values.
- * @param {Function} [isWhere=false] A flag to indicate performing partial comparisons.
- * @param {Array} [stackA=[]] Tracks traversed `a` objects.
- * @param {Array} [stackB=[]] Tracks traversed `b` objects.
- * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
- */
- function baseIsEqual(a, b, callback, isWhere, stackA, stackB) {
- // used to indicate that when comparing objects, `a` has at least the properties of `b`
- if (callback) {
- var result = callback(a, b);
- if (typeof result != 'undefined') {
- return !!result;
- }
- }
- // exit early for identical values
- if (a === b) {
- // treat `+0` vs. `-0` as not equal
- return a !== 0 || (1 / a == 1 / b);
- }
- var type = typeof a,
- otherType = typeof b;
-
- // exit early for unlike primitive values
- if (a === a &&
- !(a && objectTypes[type]) &&
- !(b && objectTypes[otherType])) {
- return false;
- }
- // exit early for `null` and `undefined` avoiding ES3's Function#call behavior
- // http://es5.github.io/#x15.3.4.4
- if (a == null || b == null) {
- return a === b;
- }
- // compare [[Class]] names
- var className = toString.call(a),
- otherClass = toString.call(b);
-
- if (className == argsClass) {
- className = objectClass;
- }
- if (otherClass == argsClass) {
- otherClass = objectClass;
- }
- if (className != otherClass) {
- return false;
- }
- switch (className) {
- case boolClass:
- case dateClass:
- // coerce dates and booleans to numbers, dates to milliseconds and booleans
- // to `1` or `0` treating invalid dates coerced to `NaN` as not equal
- return +a == +b;
-
- case numberClass:
- // treat `NaN` vs. `NaN` as equal
- return (a != +a)
- ? b != +b
- // but treat `+0` vs. `-0` as not equal
- : (a == 0 ? (1 / a == 1 / b) : a == +b);
-
- case regexpClass:
- case stringClass:
- // coerce regexes to strings (http://es5.github.io/#x15.10.6.4)
- // treat string primitives and their corresponding object instances as equal
- return a == String(b);
- }
- var isArr = className == arrayClass;
- if (!isArr) {
- // unwrap any `lodash` wrapped values
- var aWrapped = hasOwnProperty.call(a, '__wrapped__'),
- bWrapped = hasOwnProperty.call(b, '__wrapped__');
-
- if (aWrapped || bWrapped) {
- return baseIsEqual(aWrapped ? a.__wrapped__ : a, bWrapped ? b.__wrapped__ : b, callback, isWhere, stackA, stackB);
- }
- // exit for functions and DOM nodes
- if (className != objectClass) {
- return false;
- }
- // in older versions of Opera, `arguments` objects have `Array` constructors
- var ctorA = a.constructor,
- ctorB = b.constructor;
-
- // non `Object` object instances with different constructors are not equal
- if (ctorA != ctorB &&
- !(isFunction(ctorA) && ctorA instanceof ctorA && isFunction(ctorB) && ctorB instanceof ctorB) &&
- ('constructor' in a && 'constructor' in b)
- ) {
- return false;
- }
- }
- // assume cyclic structures are equal
- // the algorithm for detecting cyclic structures is adapted from ES 5.1
- // section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3)
- var initedStack = !stackA;
- stackA || (stackA = getArray());
- stackB || (stackB = getArray());
-
- var length = stackA.length;
- while (length--) {
- if (stackA[length] == a) {
- return stackB[length] == b;
- }
- }
- var size = 0;
- result = true;
-
- // add `a` and `b` to the stack of traversed objects
- stackA.push(a);
- stackB.push(b);
-
- // recursively compare objects and arrays (susceptible to call stack limits)
- if (isArr) {
- // compare lengths to determine if a deep comparison is necessary
- length = a.length;
- size = b.length;
- result = size == length;
-
- if (result || isWhere) {
- // deep compare the contents, ignoring non-numeric properties
- while (size--) {
- var index = length,
- value = b[size];
-
- if (isWhere) {
- while (index--) {
- if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) {
- break;
- }
- }
- } else if (!(result = baseIsEqual(a[size], value, callback, isWhere, stackA, stackB))) {
- break;
- }
- }
- }
- }
- else {
- // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys`
- // which, in this case, is more costly
- forIn(b, function(value, key, b) {
- if (hasOwnProperty.call(b, key)) {
- // count the number of properties.
- size++;
- // deep compare each property value.
- return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB));
- }
- });
-
- if (result && !isWhere) {
- // ensure both objects have the same number of properties
- forIn(a, function(value, key, a) {
- if (hasOwnProperty.call(a, key)) {
- // `size` will be `-1` if `a` has more properties than `b`
- return (result = --size > -1);
- }
- });
- }
- }
- stackA.pop();
- stackB.pop();
-
- if (initedStack) {
- releaseArray(stackA);
- releaseArray(stackB);
- }
- return result;
- }
-
- /**
- * The base implementation of `_.merge` without argument juggling or support
- * for `thisArg` binding.
- *
- * @private
- * @param {Object} object The destination object.
- * @param {Object} source The source object.
- * @param {Function} [callback] The function to customize merging properties.
- * @param {Array} [stackA=[]] Tracks traversed source objects.
- * @param {Array} [stackB=[]] Associates values with source counterparts.
- */
- function baseMerge(object, source, callback, stackA, stackB) {
- (isArray(source) ? forEach : forOwn)(source, function(source, key) {
- var found,
- isArr,
- result = source,
- value = object[key];
-
- if (source && ((isArr = isArray(source)) || isPlainObject(source))) {
- // avoid merging previously merged cyclic sources
- var stackLength = stackA.length;
- while (stackLength--) {
- if ((found = stackA[stackLength] == source)) {
- value = stackB[stackLength];
- break;
- }
- }
- if (!found) {
- var isShallow;
- if (callback) {
- result = callback(value, source);
- if ((isShallow = typeof result != 'undefined')) {
- value = result;
- }
- }
- if (!isShallow) {
- value = isArr
- ? (isArray(value) ? value : [])
- : (isPlainObject(value) ? value : {});
- }
- // add `source` and associated `value` to the stack of traversed objects
- stackA.push(source);
- stackB.push(value);
-
- // recursively merge objects and arrays (susceptible to call stack limits)
- if (!isShallow) {
- baseMerge(value, source, callback, stackA, stackB);
- }
- }
- }
- else {
- if (callback) {
- result = callback(value, source);
- if (typeof result == 'undefined') {
- result = source;
- }
- }
- if (typeof result != 'undefined') {
- value = result;
- }
- }
- object[key] = value;
- });
- }
-
- /**
- * The base implementation of `_.random` without argument juggling or support
- * for returning floating-point numbers.
- *
- * @private
- * @param {number} min The minimum possible value.
- * @param {number} max The maximum possible value.
- * @returns {number} Returns a random number.
- */
- function baseRandom(min, max) {
- return min + floor(nativeRandom() * (max - min + 1));
- }
-
- /**
- * The base implementation of `_.uniq` without support for callback shorthands
- * or `thisArg` binding.
- *
- * @private
- * @param {Array} array The array to process.
- * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
- * @param {Function} [callback] The function called per iteration.
- * @returns {Array} Returns a duplicate-value-free array.
- */
- function baseUniq(array, isSorted, callback) {
- var index = -1,
- indexOf = getIndexOf(),
- length = array ? array.length : 0,
- result = [];
-
- var isLarge = !isSorted && length >= largeArraySize && indexOf === baseIndexOf,
- seen = (callback || isLarge) ? getArray() : result;
-
- if (isLarge) {
- var cache = createCache(seen);
- indexOf = cacheIndexOf;
- seen = cache;
- }
- while (++index < length) {
- var value = array[index],
- computed = callback ? callback(value, index, array) : value;
-
- if (isSorted
- ? !index || seen[seen.length - 1] !== computed
- : indexOf(seen, computed) < 0
- ) {
- if (callback || isLarge) {
- seen.push(computed);
- }
- result.push(value);
- }
- }
- if (isLarge) {
- releaseArray(seen.array);
- releaseObject(seen);
- } else if (callback) {
- releaseArray(seen);
- }
- return result;
- }
-
- /**
- * Creates a function that aggregates a collection, creating an object composed
- * of keys generated from the results of running each element of the collection
- * through a callback. The given `setter` function sets the keys and values
- * of the composed object.
- *
- * @private
- * @param {Function} setter The setter function.
- * @returns {Function} Returns the new aggregator function.
- */
- function createAggregator(setter) {
- return function(collection, callback, thisArg) {
- var result = {};
- callback = lodash.createCallback(callback, thisArg, 3);
-
- var index = -1,
- length = collection ? collection.length : 0;
-
- if (typeof length == 'number') {
- while (++index < length) {
- var value = collection[index];
- setter(result, value, callback(value, index, collection), collection);
- }
- } else {
- forOwn(collection, function(value, key, collection) {
- setter(result, value, callback(value, key, collection), collection);
- });
- }
- return result;
- };
- }
-
- /**
- * Creates a function that, when called, either curries or invokes `func`
- * with an optional `this` binding and partially applied arguments.
- *
- * @private
- * @param {Function|string} func The function or method name to reference.
- * @param {number} bitmask The bitmask of method flags to compose.
- * The bitmask may be composed of the following flags:
- * 1 - `_.bind`
- * 2 - `_.bindKey`
- * 4 - `_.curry`
- * 8 - `_.curry` (bound)
- * 16 - `_.partial`
- * 32 - `_.partialRight`
- * @param {Array} [partialArgs] An array of arguments to prepend to those
- * provided to the new function.
- * @param {Array} [partialRightArgs] An array of arguments to append to those
- * provided to the new function.
- * @param {*} [thisArg] The `this` binding of `func`.
- * @param {number} [arity] The arity of `func`.
- * @returns {Function} Returns the new function.
- */
- function createWrapper(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) {
- var isBind = bitmask & 1,
- isBindKey = bitmask & 2,
- isCurry = bitmask & 4,
- isCurryBound = bitmask & 8,
- isPartial = bitmask & 16,
- isPartialRight = bitmask & 32;
-
- if (!isBindKey && !isFunction(func)) {
- throw new TypeError;
- }
- if (isPartial && !partialArgs.length) {
- bitmask &= ~16;
- isPartial = partialArgs = false;
- }
- if (isPartialRight && !partialRightArgs.length) {
- bitmask &= ~32;
- isPartialRight = partialRightArgs = false;
- }
- var bindData = func && func.__bindData__;
- if (bindData && bindData !== true) {
- // clone `bindData`
- bindData = slice(bindData);
- if (bindData[2]) {
- bindData[2] = slice(bindData[2]);
- }
- if (bindData[3]) {
- bindData[3] = slice(bindData[3]);
- }
- // set `thisBinding` is not previously bound
- if (isBind && !(bindData[1] & 1)) {
- bindData[4] = thisArg;
- }
- // set if previously bound but not currently (subsequent curried functions)
- if (!isBind && bindData[1] & 1) {
- bitmask |= 8;
- }
- // set curried arity if not yet set
- if (isCurry && !(bindData[1] & 4)) {
- bindData[5] = arity;
- }
- // append partial left arguments
- if (isPartial) {
- push.apply(bindData[2] || (bindData[2] = []), partialArgs);
- }
- // append partial right arguments
- if (isPartialRight) {
- unshift.apply(bindData[3] || (bindData[3] = []), partialRightArgs);
- }
- // merge flags
- bindData[1] |= bitmask;
- return createWrapper.apply(null, bindData);
- }
- // fast path for `_.bind`
- var creater = (bitmask == 1 || bitmask === 17) ? baseBind : baseCreateWrapper;
- return creater([func, bitmask, partialArgs, partialRightArgs, thisArg, arity]);
- }
-
- /**
- * Used by `escape` to convert characters to HTML entities.
- *
- * @private
- * @param {string} match The matched character to escape.
- * @returns {string} Returns the escaped character.
- */
- function escapeHtmlChar(match) {
- return htmlEscapes[match];
- }
-
- /**
- * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
- * customized, this method returns the custom method, otherwise it returns
- * the `baseIndexOf` function.
- *
- * @private
- * @returns {Function} Returns the "indexOf" function.
- */
- function getIndexOf() {
- var result = (result = lodash.indexOf) === indexOf ? baseIndexOf : result;
- return result;
- }
-
- /**
- * Checks if `value` is a native function.
- *
- * @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is a native function, else `false`.
- */
- function isNative(value) {
- return typeof value == 'function' && reNative.test(value);
- }
-
- /**
- * Sets `this` binding data on a given function.
- *
- * @private
- * @param {Function} func The function to set data on.
- * @param {Array} value The data array to set.
- */
- var setBindData = !defineProperty ? noop : function(func, value) {
- descriptor.value = value;
- defineProperty(func, '__bindData__', descriptor);
- };
-
- /**
- * A fallback implementation of `isPlainObject` which checks if a given value
- * is an object created by the `Object` constructor, assuming objects created
- * by the `Object` constructor have no inherited enumerable properties and that
- * there are no `Object.prototype` extensions.
- *
- * @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
- */
- function shimIsPlainObject(value) {
- var ctor,
- result;
-
- // avoid non Object objects, `arguments` objects, and DOM elements
- if (!(value && toString.call(value) == objectClass) ||
- (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor))) {
- return false;
- }
- // In most environments an object's own properties are iterated before
- // its inherited properties. If the last iterated property is an object's
- // own property then there are no inherited enumerable properties.
- forIn(value, function(value, key) {
- result = key;
- });
- return typeof result == 'undefined' || hasOwnProperty.call(value, result);
- }
-
- /**
- * Used by `unescape` to convert HTML entities to characters.
- *
- * @private
- * @param {string} match The matched character to unescape.
- * @returns {string} Returns the unescaped character.
- */
- function unescapeHtmlChar(match) {
- return htmlUnescapes[match];
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Checks if `value` is an `arguments` object.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is an `arguments` object, else `false`.
- * @example
- *
- * (function() { return _.isArguments(arguments); })(1, 2, 3);
- * // => true
- *
- * _.isArguments([1, 2, 3]);
- * // => false
- */
- function isArguments(value) {
- return value && typeof value == 'object' && typeof value.length == 'number' &&
- toString.call(value) == argsClass || false;
- }
-
- /**
- * Checks if `value` is an array.
- *
- * @static
- * @memberOf _
- * @type Function
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is an array, else `false`.
- * @example
- *
- * (function() { return _.isArray(arguments); })();
- * // => false
- *
- * _.isArray([1, 2, 3]);
- * // => true
- */
- var isArray = nativeIsArray || function(value) {
- return value && typeof value == 'object' && typeof value.length == 'number' &&
- toString.call(value) == arrayClass || false;
- };
-
- /**
- * A fallback implementation of `Object.keys` which produces an array of the
- * given object's own enumerable property names.
- *
- * @private
- * @type Function
- * @param {Object} object The object to inspect.
- * @returns {Array} Returns an array of property names.
- */
- var shimKeys = function(object) {
- var index, iterable = object, result = [];
- if (!iterable) return result;
- if (!(objectTypes[typeof object])) return result;
- for (index in iterable) {
- if (hasOwnProperty.call(iterable, index)) {
- result.push(index);
- }
- }
- return result
- };
-
- /**
- * Creates an array composed of the own enumerable property names of an object.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {Object} object The object to inspect.
- * @returns {Array} Returns an array of property names.
- * @example
- *
- * _.keys({ 'one': 1, 'two': 2, 'three': 3 });
- * // => ['one', 'two', 'three'] (property order is not guaranteed across environments)
- */
- var keys = !nativeKeys ? shimKeys : function(object) {
- if (!isObject(object)) {
- return [];
- }
- return nativeKeys(object);
- };
-
- /**
- * Used to convert characters to HTML entities:
- *
- * Though the `>` character is escaped for symmetry, characters like `>` and `/`
- * don't require escaping in HTML and have no special meaning unless they're part
- * of a tag or an unquoted attribute value.
- * http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact")
- */
- var htmlEscapes = {
- '&': '&amp;',
- '<': '&lt;',
- '>': '&gt;',
- '"': '&quot;',
- "'": '&#39;'
- };
-
- /** Used to convert HTML entities to characters */
- var htmlUnescapes = invert(htmlEscapes);
-
- /** Used to match HTML entities and HTML characters */
- var reEscapedHtml = RegExp('(' + keys(htmlUnescapes).join('|') + ')', 'g'),
- reUnescapedHtml = RegExp('[' + keys(htmlEscapes).join('') + ']', 'g');
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Assigns own enumerable properties of source object(s) to the destination
- * object. Subsequent sources will overwrite property assignments of previous
- * sources. If a callback is provided it will be executed to produce the
- * assigned values. The callback is bound to `thisArg` and invoked with two
- * arguments; (objectValue, sourceValue).
- *
- * @static
- * @memberOf _
- * @type Function
- * @alias extend
- * @category Objects
- * @param {Object} object The destination object.
- * @param {...Object} [source] The source objects.
- * @param {Function} [callback] The function to customize assigning values.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Object} Returns the destination object.
- * @example
- *
- * _.assign({ 'name': 'fred' }, { 'employer': 'slate' });
- * // => { 'name': 'fred', 'employer': 'slate' }
- *
- * var defaults = _.partialRight(_.assign, function(a, b) {
- * return typeof a == 'undefined' ? b : a;
- * });
- *
- * var object = { 'name': 'barney' };
- * defaults(object, { 'name': 'fred', 'employer': 'slate' });
- * // => { 'name': 'barney', 'employer': 'slate' }
- */
- var assign = function(object, source, guard) {
- var index, iterable = object, result = iterable;
- if (!iterable) return result;
- var args = arguments,
- argsIndex = 0,
- argsLength = typeof guard == 'number' ? 2 : args.length;
- if (argsLength > 3 && typeof args[argsLength - 2] == 'function') {
- var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2);
- } else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {
- callback = args[--argsLength];
- }
- while (++argsIndex < argsLength) {
- iterable = args[argsIndex];
- if (iterable && objectTypes[typeof iterable]) {
- var ownIndex = -1,
- ownProps = objectTypes[typeof iterable] && keys(iterable),
- length = ownProps ? ownProps.length : 0;
-
- while (++ownIndex < length) {
- index = ownProps[ownIndex];
- result[index] = callback ? callback(result[index], iterable[index]) : iterable[index];
- }
- }
- }
- return result
- };
-
- /**
- * Creates a clone of `value`. If `isDeep` is `true` nested objects will also
- * be cloned, otherwise they will be assigned by reference. If a callback
- * is provided it will be executed to produce the cloned values. If the
- * callback returns `undefined` cloning will be handled by the method instead.
- * The callback is bound to `thisArg` and invoked with one argument; (value).
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {*} value The value to clone.
- * @param {boolean} [isDeep=false] Specify a deep clone.
- * @param {Function} [callback] The function to customize cloning values.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {*} Returns the cloned value.
- * @example
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36 },
- * { 'name': 'fred', 'age': 40 }
- * ];
- *
- * var shallow = _.clone(characters);
- * shallow[0] === characters[0];
- * // => true
- *
- * var deep = _.clone(characters, true);
- * deep[0] === characters[0];
- * // => false
- *
- * _.mixin({
- * 'clone': _.partialRight(_.clone, function(value) {
- * return _.isElement(value) ? value.cloneNode(false) : undefined;
- * })
- * });
- *
- * var clone = _.clone(document.body);
- * clone.childNodes.length;
- * // => 0
- */
- function clone(value, isDeep, callback, thisArg) {
- // allows working with "Collections" methods without using their `index`
- // and `collection` arguments for `isDeep` and `callback`
- if (typeof isDeep != 'boolean' && isDeep != null) {
- thisArg = callback;
- callback = isDeep;
- isDeep = false;
- }
- return baseClone(value, isDeep, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
- }
-
- /**
- * Creates a deep clone of `value`. If a callback is provided it will be
- * executed to produce the cloned values. If the callback returns `undefined`
- * cloning will be handled by the method instead. The callback is bound to
- * `thisArg` and invoked with one argument; (value).
- *
- * Note: This method is loosely based on the structured clone algorithm. Functions
- * and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and
- * objects created by constructors other than `Object` are cloned to plain `Object` objects.
- * See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {*} value The value to deep clone.
- * @param {Function} [callback] The function to customize cloning values.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {*} Returns the deep cloned value.
- * @example
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36 },
- * { 'name': 'fred', 'age': 40 }
- * ];
- *
- * var deep = _.cloneDeep(characters);
- * deep[0] === characters[0];
- * // => false
- *
- * var view = {
- * 'label': 'docs',
- * 'node': element
- * };
- *
- * var clone = _.cloneDeep(view, function(value) {
- * return _.isElement(value) ? value.cloneNode(true) : undefined;
- * });
- *
- * clone.node == view.node;
- * // => false
- */
- function cloneDeep(value, callback, thisArg) {
- return baseClone(value, true, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
- }
-
- /**
- * Creates an object that inherits from the given `prototype` object. If a
- * `properties` object is provided its own enumerable properties are assigned
- * to the created object.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {Object} prototype The object to inherit from.
- * @param {Object} [properties] The properties to assign to the object.
- * @returns {Object} Returns the new object.
- * @example
- *
- * function Shape() {
- * this.x = 0;
- * this.y = 0;
- * }
- *
- * function Circle() {
- * Shape.call(this);
- * }
- *
- * Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle });
- *
- * var circle = new Circle;
- * circle instanceof Circle;
- * // => true
- *
- * circle instanceof Shape;
- * // => true
- */
- function create(prototype, properties) {
- var result = baseCreate(prototype);
- return properties ? assign(result, properties) : result;
- }
-
- /**
- * Assigns own enumerable properties of source object(s) to the destination
- * object for all destination properties that resolve to `undefined`. Once a
- * property is set, additional defaults of the same property will be ignored.
- *
- * @static
- * @memberOf _
- * @type Function
- * @category Objects
- * @param {Object} object The destination object.
- * @param {...Object} [source] The source objects.
- * @param- {Object} [guard] Allows working with `_.reduce` without using its
- * `key` and `object` arguments as sources.
- * @returns {Object} Returns the destination object.
- * @example
- *
- * var object = { 'name': 'barney' };
- * _.defaults(object, { 'name': 'fred', 'employer': 'slate' });
- * // => { 'name': 'barney', 'employer': 'slate' }
- */
- var defaults = function(object, source, guard) {
- var index, iterable = object, result = iterable;
- if (!iterable) return result;
- var args = arguments,
- argsIndex = 0,
- argsLength = typeof guard == 'number' ? 2 : args.length;
- while (++argsIndex < argsLength) {
- iterable = args[argsIndex];
- if (iterable && objectTypes[typeof iterable]) {
- var ownIndex = -1,
- ownProps = objectTypes[typeof iterable] && keys(iterable),
- length = ownProps ? ownProps.length : 0;
-
- while (++ownIndex < length) {
- index = ownProps[ownIndex];
- if (typeof result[index] == 'undefined') result[index] = iterable[index];
- }
- }
- }
- return result
- };
-
- /**
- * This method is like `_.findIndex` except that it returns the key of the
- * first element that passes the callback check, instead of the element itself.
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {Object} object The object to search.
- * @param {Function|Object|string} [callback=identity] The function called per
- * iteration. If a property name or object is provided it will be used to
- * create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {string|undefined} Returns the key of the found element, else `undefined`.
- * @example
- *
- * var characters = {
- * 'barney': { 'age': 36, 'blocked': false },
- * 'fred': { 'age': 40, 'blocked': true },
- * 'pebbles': { 'age': 1, 'blocked': false }
- * };
- *
- * _.findKey(characters, function(chr) {
- * return chr.age < 40;
- * });
- * // => 'barney' (property order is not guaranteed across environments)
- *
- * // using "_.where" callback shorthand
- * _.findKey(characters, { 'age': 1 });
- * // => 'pebbles'
- *
- * // using "_.pluck" callback shorthand
- * _.findKey(characters, 'blocked');
- * // => 'fred'
- */
- function findKey(object, callback, thisArg) {
- var result;
- callback = lodash.createCallback(callback, thisArg, 3);
- forOwn(object, function(value, key, object) {
- if (callback(value, key, object)) {
- result = key;
- return false;
- }
- });
- return result;
- }
-
- /**
- * This method is like `_.findKey` except that it iterates over elements
- * of a `collection` in the opposite order.
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {Object} object The object to search.
- * @param {Function|Object|string} [callback=identity] The function called per
- * iteration. If a property name or object is provided it will be used to
- * create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {string|undefined} Returns the key of the found element, else `undefined`.
- * @example
- *
- * var characters = {
- * 'barney': { 'age': 36, 'blocked': true },
- * 'fred': { 'age': 40, 'blocked': false },
- * 'pebbles': { 'age': 1, 'blocked': true }
- * };
- *
- * _.findLastKey(characters, function(chr) {
- * return chr.age < 40;
- * });
- * // => returns `pebbles`, assuming `_.findKey` returns `barney`
- *
- * // using "_.where" callback shorthand
- * _.findLastKey(characters, { 'age': 40 });
- * // => 'fred'
- *
- * // using "_.pluck" callback shorthand
- * _.findLastKey(characters, 'blocked');
- * // => 'pebbles'
- */
- function findLastKey(object, callback, thisArg) {
- var result;
- callback = lodash.createCallback(callback, thisArg, 3);
- forOwnRight(object, function(value, key, object) {
- if (callback(value, key, object)) {
- result = key;
- return false;
- }
- });
- return result;
- }
-
- /**
- * Iterates over own and inherited enumerable properties of an object,
- * executing the callback for each property. The callback is bound to `thisArg`
- * and invoked with three arguments; (value, key, object). Callbacks may exit
- * iteration early by explicitly returning `false`.
- *
- * @static
- * @memberOf _
- * @type Function
- * @category Objects
- * @param {Object} object The object to iterate over.
- * @param {Function} [callback=identity] The function called per iteration.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Object} Returns `object`.
- * @example
- *
- * function Shape() {
- * this.x = 0;
- * this.y = 0;
- * }
- *
- * Shape.prototype.move = function(x, y) {
- * this.x += x;
- * this.y += y;
- * };
- *
- * _.forIn(new Shape, function(value, key) {
- * console.log(key);
- * });
- * // => logs 'x', 'y', and 'move' (property order is not guaranteed across environments)
- */
- var forIn = function(collection, callback, thisArg) {
- var index, iterable = collection, result = iterable;
- if (!iterable) return result;
- if (!objectTypes[typeof iterable]) return result;
- callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
- for (index in iterable) {
- if (callback(iterable[index], index, collection) === false) return result;
- }
- return result
- };
-
- /**
- * This method is like `_.forIn` except that it iterates over elements
- * of a `collection` in the opposite order.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {Object} object The object to iterate over.
- * @param {Function} [callback=identity] The function called per iteration.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Object} Returns `object`.
- * @example
- *
- * function Shape() {
- * this.x = 0;
- * this.y = 0;
- * }
- *
- * Shape.prototype.move = function(x, y) {
- * this.x += x;
- * this.y += y;
- * };
- *
- * _.forInRight(new Shape, function(value, key) {
- * console.log(key);
- * });
- * // => logs 'move', 'y', and 'x' assuming `_.forIn ` logs 'x', 'y', and 'move'
- */
- function forInRight(object, callback, thisArg) {
- var pairs = [];
-
- forIn(object, function(value, key) {
- pairs.push(key, value);
- });
-
- var length = pairs.length;
- callback = baseCreateCallback(callback, thisArg, 3);
- while (length--) {
- if (callback(pairs[length--], pairs[length], object) === false) {
- break;
- }
- }
- return object;
- }
-
- /**
- * Iterates over own enumerable properties of an object, executing the callback
- * for each property. The callback is bound to `thisArg` and invoked with three
- * arguments; (value, key, object). Callbacks may exit iteration early by
- * explicitly returning `false`.
- *
- * @static
- * @memberOf _
- * @type Function
- * @category Objects
- * @param {Object} object The object to iterate over.
- * @param {Function} [callback=identity] The function called per iteration.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Object} Returns `object`.
- * @example
- *
- * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
- * console.log(key);
- * });
- * // => logs '0', '1', and 'length' (property order is not guaranteed across environments)
- */
- var forOwn = function(collection, callback, thisArg) {
- var index, iterable = collection, result = iterable;
- if (!iterable) return result;
- if (!objectTypes[typeof iterable]) return result;
- callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
- var ownIndex = -1,
- ownProps = objectTypes[typeof iterable] && keys(iterable),
- length = ownProps ? ownProps.length : 0;
-
- while (++ownIndex < length) {
- index = ownProps[ownIndex];
- if (callback(iterable[index], index, collection) === false) return result;
- }
- return result
- };
-
- /**
- * This method is like `_.forOwn` except that it iterates over elements
- * of a `collection` in the opposite order.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {Object} object The object to iterate over.
- * @param {Function} [callback=identity] The function called per iteration.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Object} Returns `object`.
- * @example
- *
- * _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
- * console.log(key);
- * });
- * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length'
- */
- function forOwnRight(object, callback, thisArg) {
- var props = keys(object),
- length = props.length;
-
- callback = baseCreateCallback(callback, thisArg, 3);
- while (length--) {
- var key = props[length];
- if (callback(object[key], key, object) === false) {
- break;
- }
- }
- return object;
- }
-
- /**
- * Creates a sorted array of property names of all enumerable properties,
- * own and inherited, of `object` that have function values.
- *
- * @static
- * @memberOf _
- * @alias methods
- * @category Objects
- * @param {Object} object The object to inspect.
- * @returns {Array} Returns an array of property names that have function values.
- * @example
- *
- * _.functions(_);
- * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
- */
- function functions(object) {
- var result = [];
- forIn(object, function(value, key) {
- if (isFunction(value)) {
- result.push(key);
- }
- });
- return result.sort();
- }
-
- /**
- * Checks if the specified property name exists as a direct property of `object`,
- * instead of an inherited property.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {Object} object The object to inspect.
- * @param {string} key The name of the property to check.
- * @returns {boolean} Returns `true` if key is a direct property, else `false`.
- * @example
- *
- * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
- * // => true
- */
- function has(object, key) {
- return object ? hasOwnProperty.call(object, key) : false;
- }
-
- /**
- * Creates an object composed of the inverted keys and values of the given object.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {Object} object The object to invert.
- * @returns {Object} Returns the created inverted object.
- * @example
- *
- * _.invert({ 'first': 'fred', 'second': 'barney' });
- * // => { 'fred': 'first', 'barney': 'second' }
- */
- function invert(object) {
- var index = -1,
- props = keys(object),
- length = props.length,
- result = {};
-
- while (++index < length) {
- var key = props[index];
- result[object[key]] = key;
- }
- return result;
- }
-
- /**
- * Checks if `value` is a boolean value.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is a boolean value, else `false`.
- * @example
- *
- * _.isBoolean(null);
- * // => false
- */
- function isBoolean(value) {
- return value === true || value === false ||
- value && typeof value == 'object' && toString.call(value) == boolClass || false;
- }
-
- /**
- * Checks if `value` is a date.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is a date, else `false`.
- * @example
- *
- * _.isDate(new Date);
- * // => true
- */
- function isDate(value) {
- return value && typeof value == 'object' && toString.call(value) == dateClass || false;
- }
-
- /**
- * Checks if `value` is a DOM element.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is a DOM element, else `false`.
- * @example
- *
- * _.isElement(document.body);
- * // => true
- */
- function isElement(value) {
- return value && value.nodeType === 1 || false;
- }
-
- /**
- * Checks if `value` is empty. Arrays, strings, or `arguments` objects with a
- * length of `0` and objects with no own enumerable properties are considered
- * "empty".
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {Array|Object|string} value The value to inspect.
- * @returns {boolean} Returns `true` if the `value` is empty, else `false`.
- * @example
- *
- * _.isEmpty([1, 2, 3]);
- * // => false
- *
- * _.isEmpty({});
- * // => true
- *
- * _.isEmpty('');
- * // => true
- */
- function isEmpty(value) {
- var result = true;
- if (!value) {
- return result;
- }
- var className = toString.call(value),
- length = value.length;
-
- if ((className == arrayClass || className == stringClass || className == argsClass ) ||
- (className == objectClass && typeof length == 'number' && isFunction(value.splice))) {
- return !length;
- }
- forOwn(value, function() {
- return (result = false);
- });
- return result;
- }
-
- /**
- * Performs a deep comparison between two values to determine if they are
- * equivalent to each other. If a callback is provided it will be executed
- * to compare values. If the callback returns `undefined` comparisons will
- * be handled by the method instead. The callback is bound to `thisArg` and
- * invoked with two arguments; (a, b).
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {*} a The value to compare.
- * @param {*} b The other value to compare.
- * @param {Function} [callback] The function to customize comparing values.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
- * @example
- *
- * var object = { 'name': 'fred' };
- * var copy = { 'name': 'fred' };
- *
- * object == copy;
- * // => false
- *
- * _.isEqual(object, copy);
- * // => true
- *
- * var words = ['hello', 'goodbye'];
- * var otherWords = ['hi', 'goodbye'];
- *
- * _.isEqual(words, otherWords, function(a, b) {
- * var reGreet = /^(?:hello|hi)$/i,
- * aGreet = _.isString(a) && reGreet.test(a),
- * bGreet = _.isString(b) && reGreet.test(b);
- *
- * return (aGreet || bGreet) ? (aGreet == bGreet) : undefined;
- * });
- * // => true
- */
- function isEqual(a, b, callback, thisArg) {
- return baseIsEqual(a, b, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 2));
- }
-
- /**
- * Checks if `value` is, or can be coerced to, a finite number.
- *
- * Note: This is not the same as native `isFinite` which will return true for
- * booleans and empty strings. See http://es5.github.io/#x15.1.2.5.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is finite, else `false`.
- * @example
- *
- * _.isFinite(-101);
- * // => true
- *
- * _.isFinite('10');
- * // => true
- *
- * _.isFinite(true);
- * // => false
- *
- * _.isFinite('');
- * // => false
- *
- * _.isFinite(Infinity);
- * // => false
- */
- function isFinite(value) {
- return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value));
- }
-
- /**
- * Checks if `value` is a function.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is a function, else `false`.
- * @example
- *
- * _.isFunction(_);
- * // => true
- */
- function isFunction(value) {
- return typeof value == 'function';
- }
-
- /**
- * Checks if `value` is the language type of Object.
- * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is an object, else `false`.
- * @example
- *
- * _.isObject({});
- * // => true
- *
- * _.isObject([1, 2, 3]);
- * // => true
- *
- * _.isObject(1);
- * // => false
- */
- function isObject(value) {
- // check if the value is the ECMAScript language type of Object
- // http://es5.github.io/#x8
- // and avoid a V8 bug
- // http://code.google.com/p/v8/issues/detail?id=2291
- return !!(value && objectTypes[typeof value]);
- }
-
- /**
- * Checks if `value` is `NaN`.
- *
- * Note: This is not the same as native `isNaN` which will return `true` for
- * `undefined` and other non-numeric values. See http://es5.github.io/#x15.1.2.4.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is `NaN`, else `false`.
- * @example
- *
- * _.isNaN(NaN);
- * // => true
- *
- * _.isNaN(new Number(NaN));
- * // => true
- *
- * isNaN(undefined);
- * // => true
- *
- * _.isNaN(undefined);
- * // => false
- */
- function isNaN(value) {
- // `NaN` as a primitive is the only value that is not equal to itself
- // (perform the [[Class]] check first to avoid errors with some host objects in IE)
- return isNumber(value) && value != +value;
- }
-
- /**
- * Checks if `value` is `null`.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is `null`, else `false`.
- * @example
- *
- * _.isNull(null);
- * // => true
- *
- * _.isNull(undefined);
- * // => false
- */
- function isNull(value) {
- return value === null;
- }
-
- /**
- * Checks if `value` is a number.
- *
- * Note: `NaN` is considered a number. See http://es5.github.io/#x8.5.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is a number, else `false`.
- * @example
- *
- * _.isNumber(8.4 * 5);
- * // => true
- */
- function isNumber(value) {
- return typeof value == 'number' ||
- value && typeof value == 'object' && toString.call(value) == numberClass || false;
- }
-
- /**
- * Checks if `value` is an object created by the `Object` constructor.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
- * @example
- *
- * function Shape() {
- * this.x = 0;
- * this.y = 0;
- * }
- *
- * _.isPlainObject(new Shape);
- * // => false
- *
- * _.isPlainObject([1, 2, 3]);
- * // => false
- *
- * _.isPlainObject({ 'x': 0, 'y': 0 });
- * // => true
- */
- var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) {
- if (!(value && toString.call(value) == objectClass)) {
- return false;
- }
- var valueOf = value.valueOf,
- objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
-
- return objProto
- ? (value == objProto || getPrototypeOf(value) == objProto)
- : shimIsPlainObject(value);
- };
-
- /**
- * Checks if `value` is a regular expression.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is a regular expression, else `false`.
- * @example
- *
- * _.isRegExp(/fred/);
- * // => true
- */
- function isRegExp(value) {
- return value && typeof value == 'object' && toString.call(value) == regexpClass || false;
- }
-
- /**
- * Checks if `value` is a string.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is a string, else `false`.
- * @example
- *
- * _.isString('fred');
- * // => true
- */
- function isString(value) {
- return typeof value == 'string' ||
- value && typeof value == 'object' && toString.call(value) == stringClass || false;
- }
-
- /**
- * Checks if `value` is `undefined`.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is `undefined`, else `false`.
- * @example
- *
- * _.isUndefined(void 0);
- * // => true
- */
- function isUndefined(value) {
- return typeof value == 'undefined';
- }
-
- /**
- * Creates an object with the same keys as `object` and values generated by
- * running each own enumerable property of `object` through the callback.
- * The callback is bound to `thisArg` and invoked with three arguments;
- * (value, key, object).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {Object} object The object to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array} Returns a new object with values of the results of each `callback` execution.
- * @example
- *
- * _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; });
- * // => { 'a': 3, 'b': 6, 'c': 9 }
- *
- * var characters = {
- * 'fred': { 'name': 'fred', 'age': 40 },
- * 'pebbles': { 'name': 'pebbles', 'age': 1 }
- * };
- *
- * // using "_.pluck" callback shorthand
- * _.mapValues(characters, 'age');
- * // => { 'fred': 40, 'pebbles': 1 }
- */
- function mapValues(object, callback, thisArg) {
- var result = {};
- callback = lodash.createCallback(callback, thisArg, 3);
-
- forOwn(object, function(value, key, object) {
- result[key] = callback(value, key, object);
- });
- return result;
- }
-
- /**
- * Recursively merges own enumerable properties of the source object(s), that
- * don't resolve to `undefined` into the destination object. Subsequent sources
- * will overwrite property assignments of previous sources. If a callback is
- * provided it will be executed to produce the merged values of the destination
- * and source properties. If the callback returns `undefined` merging will
- * be handled by the method instead. The callback is bound to `thisArg` and
- * invoked with two arguments; (objectValue, sourceValue).
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {Object} object The destination object.
- * @param {...Object} [source] The source objects.
- * @param {Function} [callback] The function to customize merging properties.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Object} Returns the destination object.
- * @example
- *
- * var names = {
- * 'characters': [
- * { 'name': 'barney' },
- * { 'name': 'fred' }
- * ]
- * };
- *
- * var ages = {
- * 'characters': [
- * { 'age': 36 },
- * { 'age': 40 }
- * ]
- * };
- *
- * _.merge(names, ages);
- * // => { 'characters': [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] }
- *
- * var food = {
- * 'fruits': ['apple'],
- * 'vegetables': ['beet']
- * };
- *
- * var otherFood = {
- * 'fruits': ['banana'],
- * 'vegetables': ['carrot']
- * };
- *
- * _.merge(food, otherFood, function(a, b) {
- * return _.isArray(a) ? a.concat(b) : undefined;
- * });
- * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] }
- */
- function merge(object) {
- var args = arguments,
- length = 2;
-
- if (!isObject(object)) {
- return object;
- }
- // allows working with `_.reduce` and `_.reduceRight` without using
- // their `index` and `collection` arguments
- if (typeof args[2] != 'number') {
- length = args.length;
- }
- if (length > 3 && typeof args[length - 2] == 'function') {
- var callback = baseCreateCallback(args[--length - 1], args[length--], 2);
- } else if (length > 2 && typeof args[length - 1] == 'function') {
- callback = args[--length];
- }
- var sources = slice(arguments, 1, length),
- index = -1,
- stackA = getArray(),
- stackB = getArray();
-
- while (++index < length) {
- baseMerge(object, sources[index], callback, stackA, stackB);
- }
- releaseArray(stackA);
- releaseArray(stackB);
- return object;
- }
-
- /**
- * Creates a shallow clone of `object` excluding the specified properties.
- * Property names may be specified as individual arguments or as arrays of
- * property names. If a callback is provided it will be executed for each
- * property of `object` omitting the properties the callback returns truey
- * for. The callback is bound to `thisArg` and invoked with three arguments;
- * (value, key, object).
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {Object} object The source object.
- * @param {Function|...string|string[]} [callback] The properties to omit or the
- * function called per iteration.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Object} Returns an object without the omitted properties.
- * @example
- *
- * _.omit({ 'name': 'fred', 'age': 40 }, 'age');
- * // => { 'name': 'fred' }
- *
- * _.omit({ 'name': 'fred', 'age': 40 }, function(value) {
- * return typeof value == 'number';
- * });
- * // => { 'name': 'fred' }
- */
- function omit(object, callback, thisArg) {
- var result = {};
- if (typeof callback != 'function') {
- var props = [];
- forIn(object, function(value, key) {
- props.push(key);
- });
- props = baseDifference(props, baseFlatten(arguments, true, false, 1));
-
- var index = -1,
- length = props.length;
-
- while (++index < length) {
- var key = props[index];
- result[key] = object[key];
- }
- } else {
- callback = lodash.createCallback(callback, thisArg, 3);
- forIn(object, function(value, key, object) {
- if (!callback(value, key, object)) {
- result[key] = value;
- }
- });
- }
- return result;
- }
-
- /**
- * Creates a two dimensional array of an object's key-value pairs,
- * i.e. `[[key1, value1], [key2, value2]]`.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {Object} object The object to inspect.
- * @returns {Array} Returns new array of key-value pairs.
- * @example
- *
- * _.pairs({ 'barney': 36, 'fred': 40 });
- * // => [['barney', 36], ['fred', 40]] (property order is not guaranteed across environments)
- */
- function pairs(object) {
- var index = -1,
- props = keys(object),
- length = props.length,
- result = Array(length);
-
- while (++index < length) {
- var key = props[index];
- result[index] = [key, object[key]];
- }
- return result;
- }
-
- /**
- * Creates a shallow clone of `object` composed of the specified properties.
- * Property names may be specified as individual arguments or as arrays of
- * property names. If a callback is provided it will be executed for each
- * property of `object` picking the properties the callback returns truey
- * for. The callback is bound to `thisArg` and invoked with three arguments;
- * (value, key, object).
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {Object} object The source object.
- * @param {Function|...string|string[]} [callback] The function called per
- * iteration or property names to pick, specified as individual property
- * names or arrays of property names.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Object} Returns an object composed of the picked properties.
- * @example
- *
- * _.pick({ 'name': 'fred', '_userid': 'fred1' }, 'name');
- * // => { 'name': 'fred' }
- *
- * _.pick({ 'name': 'fred', '_userid': 'fred1' }, function(value, key) {
- * return key.charAt(0) != '_';
- * });
- * // => { 'name': 'fred' }
- */
- function pick(object, callback, thisArg) {
- var result = {};
- if (typeof callback != 'function') {
- var index = -1,
- props = baseFlatten(arguments, true, false, 1),
- length = isObject(object) ? props.length : 0;
-
- while (++index < length) {
- var key = props[index];
- if (key in object) {
- result[key] = object[key];
- }
- }
- } else {
- callback = lodash.createCallback(callback, thisArg, 3);
- forIn(object, function(value, key, object) {
- if (callback(value, key, object)) {
- result[key] = value;
- }
- });
- }
- return result;
- }
-
- /**
- * An alternative to `_.reduce` this method transforms `object` to a new
- * `accumulator` object which is the result of running each of its own
- * enumerable properties through a callback, with each callback execution
- * potentially mutating the `accumulator` object. The callback is bound to
- * `thisArg` and invoked with four arguments; (accumulator, value, key, object).
- * Callbacks may exit iteration early by explicitly returning `false`.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {Array|Object} object The object to iterate over.
- * @param {Function} [callback=identity] The function called per iteration.
- * @param {*} [accumulator] The custom accumulator value.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {*} Returns the accumulated value.
- * @example
- *
- * var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) {
- * num *= num;
- * if (num % 2) {
- * return result.push(num) < 3;
- * }
- * });
- * // => [1, 9, 25]
- *
- * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
- * result[key] = num * 3;
- * });
- * // => { 'a': 3, 'b': 6, 'c': 9 }
- */
- function transform(object, callback, accumulator, thisArg) {
- var isArr = isArray(object);
- if (accumulator == null) {
- if (isArr) {
- accumulator = [];
- } else {
- var ctor = object && object.constructor,
- proto = ctor && ctor.prototype;
-
- accumulator = baseCreate(proto);
- }
- }
- if (callback) {
- callback = lodash.createCallback(callback, thisArg, 4);
- (isArr ? forEach : forOwn)(object, function(value, index, object) {
- return callback(accumulator, value, index, object);
- });
- }
- return accumulator;
- }
-
- /**
- * Creates an array composed of the own enumerable property values of `object`.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {Object} object The object to inspect.
- * @returns {Array} Returns an array of property values.
- * @example
- *
- * _.values({ 'one': 1, 'two': 2, 'three': 3 });
- * // => [1, 2, 3] (property order is not guaranteed across environments)
- */
- function values(object) {
- var index = -1,
- props = keys(object),
- length = props.length,
- result = Array(length);
-
- while (++index < length) {
- result[index] = object[props[index]];
- }
- return result;
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Creates an array of elements from the specified indexes, or keys, of the
- * `collection`. Indexes may be specified as individual arguments or as arrays
- * of indexes.
- *
- * @static
- * @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {...(number|number[]|string|string[])} [index] The indexes of `collection`
- * to retrieve, specified as individual indexes or arrays of indexes.
- * @returns {Array} Returns a new array of elements corresponding to the
- * provided indexes.
- * @example
- *
- * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
- * // => ['a', 'c', 'e']
- *
- * _.at(['fred', 'barney', 'pebbles'], 0, 2);
- * // => ['fred', 'pebbles']
- */
- function at(collection) {
- var args = arguments,
- index = -1,
- props = baseFlatten(args, true, false, 1),
- length = (args[2] && args[2][args[1]] === collection) ? 1 : props.length,
- result = Array(length);
-
- while(++index < length) {
- result[index] = collection[props[index]];
- }
- return result;
- }
-
- /**
- * Checks if a given value is present in a collection using strict equality
- * for comparisons, i.e. `===`. If `fromIndex` is negative, it is used as the
- * offset from the end of the collection.
- *
- * @static
- * @memberOf _
- * @alias include
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {*} target The value to check for.
- * @param {number} [fromIndex=0] The index to search from.
- * @returns {boolean} Returns `true` if the `target` element is found, else `false`.
- * @example
- *
- * _.contains([1, 2, 3], 1);
- * // => true
- *
- * _.contains([1, 2, 3], 1, 2);
- * // => false
- *
- * _.contains({ 'name': 'fred', 'age': 40 }, 'fred');
- * // => true
- *
- * _.contains('pebbles', 'eb');
- * // => true
- */
- function contains(collection, target, fromIndex) {
- var index = -1,
- indexOf = getIndexOf(),
- length = collection ? collection.length : 0,
- result = false;
-
- fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0;
- if (isArray(collection)) {
- result = indexOf(collection, target, fromIndex) > -1;
- } else if (typeof length == 'number') {
- result = (isString(collection) ? collection.indexOf(target, fromIndex) : indexOf(collection, target, fromIndex)) > -1;
- } else {
- forOwn(collection, function(value) {
- if (++index >= fromIndex) {
- return !(result = value === target);
- }
- });
- }
- return result;
- }
-
- /**
- * Creates an object composed of keys generated from the results of running
- * each element of `collection` through the callback. The corresponding value
- * of each key is the number of times the key was returned by the callback.
- * The callback is bound to `thisArg` and invoked with three arguments;
- * (value, index|key, collection).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Object} Returns the composed aggregate object.
- * @example
- *
- * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); });
- * // => { '4': 1, '6': 2 }
- *
- * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
- * // => { '4': 1, '6': 2 }
- *
- * _.countBy(['one', 'two', 'three'], 'length');
- * // => { '3': 2, '5': 1 }
- */
- var countBy = createAggregator(function(result, value, key) {
- (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1);
- });
-
- /**
- * Checks if the given callback returns truey value for **all** elements of
- * a collection. The callback is bound to `thisArg` and invoked with three
- * arguments; (value, index|key, collection).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @alias all
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {boolean} Returns `true` if all elements passed the callback check,
- * else `false`.
- * @example
- *
- * _.every([true, 1, null, 'yes']);
- * // => false
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36 },
- * { 'name': 'fred', 'age': 40 }
- * ];
- *
- * // using "_.pluck" callback shorthand
- * _.every(characters, 'age');
- * // => true
- *
- * // using "_.where" callback shorthand
- * _.every(characters, { 'age': 36 });
- * // => false
- */
- function every(collection, callback, thisArg) {
- var result = true;
- callback = lodash.createCallback(callback, thisArg, 3);
-
- var index = -1,
- length = collection ? collection.length : 0;
-
- if (typeof length == 'number') {
- while (++index < length) {
- if (!(result = !!callback(collection[index], index, collection))) {
- break;
- }
- }
- } else {
- forOwn(collection, function(value, index, collection) {
- return (result = !!callback(value, index, collection));
- });
- }
- return result;
- }
-
- /**
- * Iterates over elements of a collection, returning an array of all elements
- * the callback returns truey for. The callback is bound to `thisArg` and
- * invoked with three arguments; (value, index|key, collection).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @alias select
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array} Returns a new array of elements that passed the callback check.
- * @example
- *
- * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
- * // => [2, 4, 6]
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36, 'blocked': false },
- * { 'name': 'fred', 'age': 40, 'blocked': true }
- * ];
- *
- * // using "_.pluck" callback shorthand
- * _.filter(characters, 'blocked');
- * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
- *
- * // using "_.where" callback shorthand
- * _.filter(characters, { 'age': 36 });
- * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
- */
- function filter(collection, callback, thisArg) {
- var result = [];
- callback = lodash.createCallback(callback, thisArg, 3);
-
- var index = -1,
- length = collection ? collection.length : 0;
-
- if (typeof length == 'number') {
- while (++index < length) {
- var value = collection[index];
- if (callback(value, index, collection)) {
- result.push(value);
- }
- }
- } else {
- forOwn(collection, function(value, index, collection) {
- if (callback(value, index, collection)) {
- result.push(value);
- }
- });
- }
- return result;
- }
-
- /**
- * Iterates over elements of a collection, returning the first element that
- * the callback returns truey for. The callback is bound to `thisArg` and
- * invoked with three arguments; (value, index|key, collection).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @alias detect, findWhere
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {*} Returns the found element, else `undefined`.
- * @example
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36, 'blocked': false },
- * { 'name': 'fred', 'age': 40, 'blocked': true },
- * { 'name': 'pebbles', 'age': 1, 'blocked': false }
- * ];
- *
- * _.find(characters, function(chr) {
- * return chr.age < 40;
- * });
- * // => { 'name': 'barney', 'age': 36, 'blocked': false }
- *
- * // using "_.where" callback shorthand
- * _.find(characters, { 'age': 1 });
- * // => { 'name': 'pebbles', 'age': 1, 'blocked': false }
- *
- * // using "_.pluck" callback shorthand
- * _.find(characters, 'blocked');
- * // => { 'name': 'fred', 'age': 40, 'blocked': true }
- */
- function find(collection, callback, thisArg) {
- callback = lodash.createCallback(callback, thisArg, 3);
-
- var index = -1,
- length = collection ? collection.length : 0;
-
- if (typeof length == 'number') {
- while (++index < length) {
- var value = collection[index];
- if (callback(value, index, collection)) {
- return value;
- }
- }
- } else {
- var result;
- forOwn(collection, function(value, index, collection) {
- if (callback(value, index, collection)) {
- result = value;
- return false;
- }
- });
- return result;
- }
- }
-
- /**
- * This method is like `_.find` except that it iterates over elements
- * of a `collection` from right to left.
- *
- * @static
- * @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {*} Returns the found element, else `undefined`.
- * @example
- *
- * _.findLast([1, 2, 3, 4], function(num) {
- * return num % 2 == 1;
- * });
- * // => 3
- */
- function findLast(collection, callback, thisArg) {
- var result;
- callback = lodash.createCallback(callback, thisArg, 3);
- forEachRight(collection, function(value, index, collection) {
- if (callback(value, index, collection)) {
- result = value;
- return false;
- }
- });
- return result;
- }
-
- /**
- * Iterates over elements of a collection, executing the callback for each
- * element. The callback is bound to `thisArg` and invoked with three arguments;
- * (value, index|key, collection). Callbacks may exit iteration early by
- * explicitly returning `false`.
- *
- * Note: As with other "Collections" methods, objects with a `length` property
- * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
- * may be used for object iteration.
- *
- * @static
- * @memberOf _
- * @alias each
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function} [callback=identity] The function called per iteration.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array|Object|string} Returns `collection`.
- * @example
- *
- * _([1, 2, 3]).forEach(function(num) { console.log(num); }).join(',');
- * // => logs each number and returns '1,2,3'
- *
- * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { console.log(num); });
- * // => logs each number and returns the object (property order is not guaranteed across environments)
- */
- function forEach(collection, callback, thisArg) {
- var index = -1,
- length = collection ? collection.length : 0;
-
- callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
- if (typeof length == 'number') {
- while (++index < length) {
- if (callback(collection[index], index, collection) === false) {
- break;
- }
- }
- } else {
- forOwn(collection, callback);
- }
- return collection;
- }
-
- /**
- * This method is like `_.forEach` except that it iterates over elements
- * of a `collection` from right to left.
- *
- * @static
- * @memberOf _
- * @alias eachRight
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function} [callback=identity] The function called per iteration.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array|Object|string} Returns `collection`.
- * @example
- *
- * _([1, 2, 3]).forEachRight(function(num) { console.log(num); }).join(',');
- * // => logs each number from right to left and returns '3,2,1'
- */
- function forEachRight(collection, callback, thisArg) {
- var length = collection ? collection.length : 0;
- callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
- if (typeof length == 'number') {
- while (length--) {
- if (callback(collection[length], length, collection) === false) {
- break;
- }
- }
- } else {
- var props = keys(collection);
- length = props.length;
- forOwn(collection, function(value, key, collection) {
- key = props ? props[--length] : --length;
- return callback(collection[key], key, collection);
- });
- }
- return collection;
- }
-
- /**
- * Creates an object composed of keys generated from the results of running
- * each element of a collection through the callback. The corresponding value
- * of each key is an array of the elements responsible for generating the key.
- * The callback is bound to `thisArg` and invoked with three arguments;
- * (value, index|key, collection).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`
- *
- * @static
- * @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Object} Returns the composed aggregate object.
- * @example
- *
- * _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); });
- * // => { '4': [4.2], '6': [6.1, 6.4] }
- *
- * _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
- * // => { '4': [4.2], '6': [6.1, 6.4] }
- *
- * // using "_.pluck" callback shorthand
- * _.groupBy(['one', 'two', 'three'], 'length');
- * // => { '3': ['one', 'two'], '5': ['three'] }
- */
- var groupBy = createAggregator(function(result, value, key) {
- (hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value);
- });
-
- /**
- * Creates an object composed of keys generated from the results of running
- * each element of the collection through the given callback. The corresponding
- * value of each key is the last element responsible for generating the key.
- * The callback is bound to `thisArg` and invoked with three arguments;
- * (value, index|key, collection).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Object} Returns the composed aggregate object.
- * @example
- *
- * var keys = [
- * { 'dir': 'left', 'code': 97 },
- * { 'dir': 'right', 'code': 100 }
- * ];
- *
- * _.indexBy(keys, 'dir');
- * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
- *
- * _.indexBy(keys, function(key) { return String.fromCharCode(key.code); });
- * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
- *
- * _.indexBy(characters, function(key) { this.fromCharCode(key.code); }, String);
- * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
- */
- var indexBy = createAggregator(function(result, value, key) {
- result[key] = value;
- });
-
- /**
- * Invokes the method named by `methodName` on each element in the `collection`
- * returning an array of the results of each invoked method. Additional arguments
- * will be provided to each invoked method. If `methodName` is a function it
- * will be invoked for, and `this` bound to, each element in the `collection`.
- *
- * @static
- * @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|string} methodName The name of the method to invoke or
- * the function invoked per iteration.
- * @param {...*} [arg] Arguments to invoke the method with.
- * @returns {Array} Returns a new array of the results of each invoked method.
- * @example
- *
- * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
- * // => [[1, 5, 7], [1, 2, 3]]
- *
- * _.invoke([123, 456], String.prototype.split, '');
- * // => [['1', '2', '3'], ['4', '5', '6']]
- */
- function invoke(collection, methodName) {
- var args = slice(arguments, 2),
- index = -1,
- isFunc = typeof methodName == 'function',
- length = collection ? collection.length : 0,
- result = Array(typeof length == 'number' ? length : 0);
-
- forEach(collection, function(value) {
- result[++index] = (isFunc ? methodName : value[methodName]).apply(value, args);
- });
- return result;
- }
-
- /**
- * Creates an array of values by running each element in the collection
- * through the callback. The callback is bound to `thisArg` and invoked with
- * three arguments; (value, index|key, collection).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @alias collect
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array} Returns a new array of the results of each `callback` execution.
- * @example
- *
- * _.map([1, 2, 3], function(num) { return num * 3; });
- * // => [3, 6, 9]
- *
- * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
- * // => [3, 6, 9] (property order is not guaranteed across environments)
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36 },
- * { 'name': 'fred', 'age': 40 }
- * ];
- *
- * // using "_.pluck" callback shorthand
- * _.map(characters, 'name');
- * // => ['barney', 'fred']
- */
- function map(collection, callback, thisArg) {
- var index = -1,
- length = collection ? collection.length : 0;
-
- callback = lodash.createCallback(callback, thisArg, 3);
- if (typeof length == 'number') {
- var result = Array(length);
- while (++index < length) {
- result[index] = callback(collection[index], index, collection);
- }
- } else {
- result = [];
- forOwn(collection, function(value, key, collection) {
- result[++index] = callback(value, key, collection);
- });
- }
- return result;
- }
-
- /**
- * Retrieves the maximum value of a collection. If the collection is empty or
- * falsey `-Infinity` is returned. If a callback is provided it will be executed
- * for each value in the collection to generate the criterion by which the value
- * is ranked. The callback is bound to `thisArg` and invoked with three
- * arguments; (value, index, collection).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {*} Returns the maximum value.
- * @example
- *
- * _.max([4, 2, 8, 6]);
- * // => 8
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36 },
- * { 'name': 'fred', 'age': 40 }
- * ];
- *
- * _.max(characters, function(chr) { return chr.age; });
- * // => { 'name': 'fred', 'age': 40 };
- *
- * // using "_.pluck" callback shorthand
- * _.max(characters, 'age');
- * // => { 'name': 'fred', 'age': 40 };
- */
- function max(collection, callback, thisArg) {
- var computed = -Infinity,
- result = computed;
-
- // allows working with functions like `_.map` without using
- // their `index` argument as a callback
- if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) {
- callback = null;
- }
- if (callback == null && isArray(collection)) {
- var index = -1,
- length = collection.length;
-
- while (++index < length) {
- var value = collection[index];
- if (value > result) {
- result = value;
- }
- }
- } else {
- callback = (callback == null && isString(collection))
- ? charAtCallback
- : lodash.createCallback(callback, thisArg, 3);
-
- forEach(collection, function(value, index, collection) {
- var current = callback(value, index, collection);
- if (current > computed) {
- computed = current;
- result = value;
- }
- });
- }
- return result;
- }
-
- /**
- * Retrieves the minimum value of a collection. If the collection is empty or
- * falsey `Infinity` is returned. If a callback is provided it will be executed
- * for each value in the collection to generate the criterion by which the value
- * is ranked. The callback is bound to `thisArg` and invoked with three
- * arguments; (value, index, collection).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {*} Returns the minimum value.
- * @example
- *
- * _.min([4, 2, 8, 6]);
- * // => 2
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36 },
- * { 'name': 'fred', 'age': 40 }
- * ];
- *
- * _.min(characters, function(chr) { return chr.age; });
- * // => { 'name': 'barney', 'age': 36 };
- *
- * // using "_.pluck" callback shorthand
- * _.min(characters, 'age');
- * // => { 'name': 'barney', 'age': 36 };
- */
- function min(collection, callback, thisArg) {
- var computed = Infinity,
- result = computed;
-
- // allows working with functions like `_.map` without using
- // their `index` argument as a callback
- if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) {
- callback = null;
- }
- if (callback == null && isArray(collection)) {
- var index = -1,
- length = collection.length;
-
- while (++index < length) {
- var value = collection[index];
- if (value < result) {
- result = value;
- }
- }
- } else {
- callback = (callback == null && isString(collection))
- ? charAtCallback
- : lodash.createCallback(callback, thisArg, 3);
-
- forEach(collection, function(value, index, collection) {
- var current = callback(value, index, collection);
- if (current < computed) {
- computed = current;
- result = value;
- }
- });
- }
- return result;
- }
-
- /**
- * Retrieves the value of a specified property from all elements in the collection.
- *
- * @static
- * @memberOf _
- * @type Function
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {string} property The name of the property to pluck.
- * @returns {Array} Returns a new array of property values.
- * @example
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36 },
- * { 'name': 'fred', 'age': 40 }
- * ];
- *
- * _.pluck(characters, 'name');
- * // => ['barney', 'fred']
- */
- var pluck = map;
-
- /**
- * Reduces a collection to a value which is the accumulated result of running
- * each element in the collection through the callback, where each successive
- * callback execution consumes the return value of the previous execution. If
- * `accumulator` is not provided the first element of the collection will be
- * used as the initial `accumulator` value. The callback is bound to `thisArg`
- * and invoked with four arguments; (accumulator, value, index|key, collection).
- *
- * @static
- * @memberOf _
- * @alias foldl, inject
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function} [callback=identity] The function called per iteration.
- * @param {*} [accumulator] Initial value of the accumulator.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {*} Returns the accumulated value.
- * @example
- *
- * var sum = _.reduce([1, 2, 3], function(sum, num) {
- * return sum + num;
- * });
- * // => 6
- *
- * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
- * result[key] = num * 3;
- * return result;
- * }, {});
- * // => { 'a': 3, 'b': 6, 'c': 9 }
- */
- function reduce(collection, callback, accumulator, thisArg) {
- if (!collection) return accumulator;
- var noaccum = arguments.length < 3;
- callback = lodash.createCallback(callback, thisArg, 4);
-
- var index = -1,
- length = collection.length;
-
- if (typeof length == 'number') {
- if (noaccum) {
- accumulator = collection[++index];
- }
- while (++index < length) {
- accumulator = callback(accumulator, collection[index], index, collection);
- }
- } else {
- forOwn(collection, function(value, index, collection) {
- accumulator = noaccum
- ? (noaccum = false, value)
- : callback(accumulator, value, index, collection)
- });
- }
- return accumulator;
- }
-
- /**
- * This method is like `_.reduce` except that it iterates over elements
- * of a `collection` from right to left.
- *
- * @static
- * @memberOf _
- * @alias foldr
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function} [callback=identity] The function called per iteration.
- * @param {*} [accumulator] Initial value of the accumulator.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {*} Returns the accumulated value.
- * @example
- *
- * var list = [[0, 1], [2, 3], [4, 5]];
- * var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
- * // => [4, 5, 2, 3, 0, 1]
- */
- function reduceRight(collection, callback, accumulator, thisArg) {
- var noaccum = arguments.length < 3;
- callback = lodash.createCallback(callback, thisArg, 4);
- forEachRight(collection, function(value, index, collection) {
- accumulator = noaccum
- ? (noaccum = false, value)
- : callback(accumulator, value, index, collection);
- });
- return accumulator;
- }
-
- /**
- * The opposite of `_.filter` this method returns the elements of a
- * collection that the callback does **not** return truey for.
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array} Returns a new array of elements that failed the callback check.
- * @example
- *
- * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
- * // => [1, 3, 5]
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36, 'blocked': false },
- * { 'name': 'fred', 'age': 40, 'blocked': true }
- * ];
- *
- * // using "_.pluck" callback shorthand
- * _.reject(characters, 'blocked');
- * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
- *
- * // using "_.where" callback shorthand
- * _.reject(characters, { 'age': 36 });
- * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
- */
- function reject(collection, callback, thisArg) {
- callback = lodash.createCallback(callback, thisArg, 3);
- return filter(collection, function(value, index, collection) {
- return !callback(value, index, collection);
- });
- }
-
- /**
- * Retrieves a random element or `n` random elements from a collection.
- *
- * @static
- * @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to sample.
- * @param {number} [n] The number of elements to sample.
- * @param- {Object} [guard] Allows working with functions like `_.map`
- * without using their `index` arguments as `n`.
- * @returns {Array} Returns the random sample(s) of `collection`.
- * @example
- *
- * _.sample([1, 2, 3, 4]);
- * // => 2
- *
- * _.sample([1, 2, 3, 4], 2);
- * // => [3, 1]
- */
- function sample(collection, n, guard) {
- if (collection && typeof collection.length != 'number') {
- collection = values(collection);
- }
- if (n == null || guard) {
- return collection ? collection[baseRandom(0, collection.length - 1)] : undefined;
- }
- var result = shuffle(collection);
- result.length = nativeMin(nativeMax(0, n), result.length);
- return result;
- }
-
- /**
- * Creates an array of shuffled values, using a version of the Fisher-Yates
- * shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
- *
- * @static
- * @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to shuffle.
- * @returns {Array} Returns a new shuffled collection.
- * @example
- *
- * _.shuffle([1, 2, 3, 4, 5, 6]);
- * // => [4, 1, 6, 3, 5, 2]
- */
- function shuffle(collection) {
- var index = -1,
- length = collection ? collection.length : 0,
- result = Array(typeof length == 'number' ? length : 0);
-
- forEach(collection, function(value) {
- var rand = baseRandom(0, ++index);
- result[index] = result[rand];
- result[rand] = value;
- });
- return result;
- }
-
- /**
- * Gets the size of the `collection` by returning `collection.length` for arrays
- * and array-like objects or the number of own enumerable properties for objects.
- *
- * @static
- * @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to inspect.
- * @returns {number} Returns `collection.length` or number of own enumerable properties.
- * @example
- *
- * _.size([1, 2]);
- * // => 2
- *
- * _.size({ 'one': 1, 'two': 2, 'three': 3 });
- * // => 3
- *
- * _.size('pebbles');
- * // => 7
- */
- function size(collection) {
- var length = collection ? collection.length : 0;
- return typeof length == 'number' ? length : keys(collection).length;
- }
-
- /**
- * Checks if the callback returns a truey value for **any** element of a
- * collection. The function returns as soon as it finds a passing value and
- * does not iterate over the entire collection. The callback is bound to
- * `thisArg` and invoked with three arguments; (value, index|key, collection).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @alias any
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {boolean} Returns `true` if any element passed the callback check,
- * else `false`.
- * @example
- *
- * _.some([null, 0, 'yes', false], Boolean);
- * // => true
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36, 'blocked': false },
- * { 'name': 'fred', 'age': 40, 'blocked': true }
- * ];
- *
- * // using "_.pluck" callback shorthand
- * _.some(characters, 'blocked');
- * // => true
- *
- * // using "_.where" callback shorthand
- * _.some(characters, { 'age': 1 });
- * // => false
- */
- function some(collection, callback, thisArg) {
- var result;
- callback = lodash.createCallback(callback, thisArg, 3);
-
- var index = -1,
- length = collection ? collection.length : 0;
-
- if (typeof length == 'number') {
- while (++index < length) {
- if ((result = callback(collection[index], index, collection))) {
- break;
- }
- }
- } else {
- forOwn(collection, function(value, index, collection) {
- return !(result = callback(value, index, collection));
- });
- }
- return !!result;
- }
-
- /**
- * Creates an array of elements, sorted in ascending order by the results of
- * running each element in a collection through the callback. This method
- * performs a stable sort, that is, it will preserve the original sort order
- * of equal elements. The callback is bound to `thisArg` and invoked with
- * three arguments; (value, index|key, collection).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an array of property names is provided for `callback` the collection
- * will be sorted by each property value.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Array|Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array} Returns a new array of sorted elements.
- * @example
- *
- * _.sortBy([1, 2, 3], function(num) { return Math.sin(num); });
- * // => [3, 1, 2]
- *
- * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math);
- * // => [3, 1, 2]
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36 },
- * { 'name': 'fred', 'age': 40 },
- * { 'name': 'barney', 'age': 26 },
- * { 'name': 'fred', 'age': 30 }
- * ];
- *
- * // using "_.pluck" callback shorthand
- * _.map(_.sortBy(characters, 'age'), _.values);
- * // => [['barney', 26], ['fred', 30], ['barney', 36], ['fred', 40]]
- *
- * // sorting by multiple properties
- * _.map(_.sortBy(characters, ['name', 'age']), _.values);
- * // = > [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]]
- */
- function sortBy(collection, callback, thisArg) {
- var index = -1,
- isArr = isArray(callback),
- length = collection ? collection.length : 0,
- result = Array(typeof length == 'number' ? length : 0);
-
- if (!isArr) {
- callback = lodash.createCallback(callback, thisArg, 3);
- }
- forEach(collection, function(value, key, collection) {
- var object = result[++index] = getObject();
- if (isArr) {
- object.criteria = map(callback, function(key) { return value[key]; });
- } else {
- (object.criteria = getArray())[0] = callback(value, key, collection);
- }
- object.index = index;
- object.value = value;
- });
-
- length = result.length;
- result.sort(compareAscending);
- while (length--) {
- var object = result[length];
- result[length] = object.value;
- if (!isArr) {
- releaseArray(object.criteria);
- }
- releaseObject(object);
- }
- return result;
- }
-
- /**
- * Converts the `collection` to an array.
- *
- * @static
- * @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to convert.
- * @returns {Array} Returns the new converted array.
- * @example
- *
- * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
- * // => [2, 3, 4]
- */
- function toArray(collection) {
- if (collection && typeof collection.length == 'number') {
- return slice(collection);
- }
- return values(collection);
- }
-
- /**
- * Performs a deep comparison of each element in a `collection` to the given
- * `properties` object, returning an array of all elements that have equivalent
- * property values.
- *
- * @static
- * @memberOf _
- * @type Function
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Object} props The object of property values to filter by.
- * @returns {Array} Returns a new array of elements that have the given properties.
- * @example
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36, 'pets': ['hoppy'] },
- * { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }
- * ];
- *
- * _.where(characters, { 'age': 36 });
- * // => [{ 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }]
- *
- * _.where(characters, { 'pets': ['dino'] });
- * // => [{ 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }]
- */
- var where = filter;
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Creates an array with all falsey values removed. The values `false`, `null`,
- * `0`, `""`, `undefined`, and `NaN` are all falsey.
- *
- * @static
- * @memberOf _
- * @category Arrays
- * @param {Array} array The array to compact.
- * @returns {Array} Returns a new array of filtered values.
- * @example
- *
- * _.compact([0, 1, false, 2, '', 3]);
- * // => [1, 2, 3]
- */
- function compact(array) {
- var index = -1,
- length = array ? array.length : 0,
- result = [];
-
- while (++index < length) {
- var value = array[index];
- if (value) {
- result.push(value);
- }
- }
- return result;
- }
-
- /**
- * Creates an array excluding all values of the provided arrays using strict
- * equality for comparisons, i.e. `===`.
- *
- * @static
- * @memberOf _
- * @category Arrays
- * @param {Array} array The array to process.
- * @param {...Array} [values] The arrays of values to exclude.
- * @returns {Array} Returns a new array of filtered values.
- * @example
- *
- * _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
- * // => [1, 3, 4]
- */
- function difference(array) {
- return baseDifference(array, baseFlatten(arguments, true, true, 1));
- }
-
- /**
- * This method is like `_.find` except that it returns the index of the first
- * element that passes the callback check, instead of the element itself.
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @category Arrays
- * @param {Array} array The array to search.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {number} Returns the index of the found element, else `-1`.
- * @example
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36, 'blocked': false },
- * { 'name': 'fred', 'age': 40, 'blocked': true },
- * { 'name': 'pebbles', 'age': 1, 'blocked': false }
- * ];
- *
- * _.findIndex(characters, function(chr) {
- * return chr.age < 20;
- * });
- * // => 2
- *
- * // using "_.where" callback shorthand
- * _.findIndex(characters, { 'age': 36 });
- * // => 0
- *
- * // using "_.pluck" callback shorthand
- * _.findIndex(characters, 'blocked');
- * // => 1
- */
- function findIndex(array, callback, thisArg) {
- var index = -1,
- length = array ? array.length : 0;
-
- callback = lodash.createCallback(callback, thisArg, 3);
- while (++index < length) {
- if (callback(array[index], index, array)) {
- return index;
- }
- }
- return -1;
- }
-
- /**
- * This method is like `_.findIndex` except that it iterates over elements
- * of a `collection` from right to left.
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @category Arrays
- * @param {Array} array The array to search.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {number} Returns the index of the found element, else `-1`.
- * @example
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36, 'blocked': true },
- * { 'name': 'fred', 'age': 40, 'blocked': false },
- * { 'name': 'pebbles', 'age': 1, 'blocked': true }
- * ];
- *
- * _.findLastIndex(characters, function(chr) {
- * return chr.age > 30;
- * });
- * // => 1
- *
- * // using "_.where" callback shorthand
- * _.findLastIndex(characters, { 'age': 36 });
- * // => 0
- *
- * // using "_.pluck" callback shorthand
- * _.findLastIndex(characters, 'blocked');
- * // => 2
- */
- function findLastIndex(array, callback, thisArg) {
- var length = array ? array.length : 0;
- callback = lodash.createCallback(callback, thisArg, 3);
- while (length--) {
- if (callback(array[length], length, array)) {
- return length;
- }
- }
- return -1;
- }
-
- /**
- * Gets the first element or first `n` elements of an array. If a callback
- * is provided elements at the beginning of the array are returned as long
- * as the callback returns truey. The callback is bound to `thisArg` and
- * invoked with three arguments; (value, index, array).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @alias head, take
- * @category Arrays
- * @param {Array} array The array to query.
- * @param {Function|Object|number|string} [callback] The function called
- * per element or the number of elements to return. If a property name or
- * object is provided it will be used to create a "_.pluck" or "_.where"
- * style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {*} Returns the first element(s) of `array`.
- * @example
- *
- * _.first([1, 2, 3]);
- * // => 1
- *
- * _.first([1, 2, 3], 2);
- * // => [1, 2]
- *
- * _.first([1, 2, 3], function(num) {
- * return num < 3;
- * });
- * // => [1, 2]
- *
- * var characters = [
- * { 'name': 'barney', 'blocked': true, 'employer': 'slate' },
- * { 'name': 'fred', 'blocked': false, 'employer': 'slate' },
- * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
- * ];
- *
- * // using "_.pluck" callback shorthand
- * _.first(characters, 'blocked');
- * // => [{ 'name': 'barney', 'blocked': true, 'employer': 'slate' }]
- *
- * // using "_.where" callback shorthand
- * _.pluck(_.first(characters, { 'employer': 'slate' }), 'name');
- * // => ['barney', 'fred']
- */
- function first(array, callback, thisArg) {
- var n = 0,
- length = array ? array.length : 0;
-
- if (typeof callback != 'number' && callback != null) {
- var index = -1;
- callback = lodash.createCallback(callback, thisArg, 3);
- while (++index < length && callback(array[index], index, array)) {
- n++;
- }
- } else {
- n = callback;
- if (n == null || thisArg) {
- return array ? array[0] : undefined;
- }
- }
- return slice(array, 0, nativeMin(nativeMax(0, n), length));
- }
-
- /**
- * Flattens a nested array (the nesting can be to any depth). If `isShallow`
- * is truey, the array will only be flattened a single level. If a callback
- * is provided each element of the array is passed through the callback before
- * flattening. The callback is bound to `thisArg` and invoked with three
- * arguments; (value, index, array).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @category Arrays
- * @param {Array} array The array to flatten.
- * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array} Returns a new flattened array.
- * @example
- *
- * _.flatten([1, [2], [3, [[4]]]]);
- * // => [1, 2, 3, 4];
- *
- * _.flatten([1, [2], [3, [[4]]]], true);
- * // => [1, 2, 3, [[4]]];
- *
- * var characters = [
- * { 'name': 'barney', 'age': 30, 'pets': ['hoppy'] },
- * { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }
- * ];
- *
- * // using "_.pluck" callback shorthand
- * _.flatten(characters, 'pets');
- * // => ['hoppy', 'baby puss', 'dino']
- */
- function flatten(array, isShallow, callback, thisArg) {
- // juggle arguments
- if (typeof isShallow != 'boolean' && isShallow != null) {
- thisArg = callback;
- callback = (typeof isShallow != 'function' && thisArg && thisArg[isShallow] === array) ? null : isShallow;
- isShallow = false;
- }
- if (callback != null) {
- array = map(array, callback, thisArg);
- }
- return baseFlatten(array, isShallow);
- }
-
- /**
- * Gets the index at which the first occurrence of `value` is found using
- * strict equality for comparisons, i.e. `===`. If the array is already sorted
- * providing `true` for `fromIndex` will run a faster binary search.
- *
- * @static
- * @memberOf _
- * @category Arrays
- * @param {Array} array The array to search.
- * @param {*} value The value to search for.
- * @param {boolean|number} [fromIndex=0] The index to search from or `true`
- * to perform a binary search on a sorted array.
- * @returns {number} Returns the index of the matched value or `-1`.
- * @example
- *
- * _.indexOf([1, 2, 3, 1, 2, 3], 2);
- * // => 1
- *
- * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
- * // => 4
- *
- * _.indexOf([1, 1, 2, 2, 3, 3], 2, true);
- * // => 2
- */
- function indexOf(array, value, fromIndex) {
- if (typeof fromIndex == 'number') {
- var length = array ? array.length : 0;
- fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0);
- } else if (fromIndex) {
- var index = sortedIndex(array, value);
- return array[index] === value ? index : -1;
- }
- return baseIndexOf(array, value, fromIndex);
- }
-
- /**
- * Gets all but the last element or last `n` elements of an array. If a
- * callback is provided elements at the end of the array are excluded from
- * the result as long as the callback returns truey. The callback is bound
- * to `thisArg` and invoked with three arguments; (value, index, array).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @category Arrays
- * @param {Array} array The array to query.
- * @param {Function|Object|number|string} [callback=1] The function called
- * per element or the number of elements to exclude. If a property name or
- * object is provided it will be used to create a "_.pluck" or "_.where"
- * style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array} Returns a slice of `array`.
- * @example
- *
- * _.initial([1, 2, 3]);
- * // => [1, 2]
- *
- * _.initial([1, 2, 3], 2);
- * // => [1]
- *
- * _.initial([1, 2, 3], function(num) {
- * return num > 1;
- * });
- * // => [1]
- *
- * var characters = [
- * { 'name': 'barney', 'blocked': false, 'employer': 'slate' },
- * { 'name': 'fred', 'blocked': true, 'employer': 'slate' },
- * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
- * ];
- *
- * // using "_.pluck" callback shorthand
- * _.initial(characters, 'blocked');
- * // => [{ 'name': 'barney', 'blocked': false, 'employer': 'slate' }]
- *
- * // using "_.where" callback shorthand
- * _.pluck(_.initial(characters, { 'employer': 'na' }), 'name');
- * // => ['barney', 'fred']
- */
- function initial(array, callback, thisArg) {
- var n = 0,
- length = array ? array.length : 0;
-
- if (typeof callback != 'number' && callback != null) {
- var index = length;
- callback = lodash.createCallback(callback, thisArg, 3);
- while (index-- && callback(array[index], index, array)) {
- n++;
- }
- } else {
- n = (callback == null || thisArg) ? 1 : callback || n;
- }
- return slice(array, 0, nativeMin(nativeMax(0, length - n), length));
- }
-
- /**
- * Creates an array of unique values present in all provided arrays using
- * strict equality for comparisons, i.e. `===`.
- *
- * @static
- * @memberOf _
- * @category Arrays
- * @param {...Array} [array] The arrays to inspect.
- * @returns {Array} Returns an array of shared values.
- * @example
- *
- * _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]);
- * // => [1, 2]
- */
- function intersection() {
- var args = [],
- argsIndex = -1,
- argsLength = arguments.length,
- caches = getArray(),
- indexOf = getIndexOf(),
- trustIndexOf = indexOf === baseIndexOf,
- seen = getArray();
-
- while (++argsIndex < argsLength) {
- var value = arguments[argsIndex];
- if (isArray(value) || isArguments(value)) {
- args.push(value);
- caches.push(trustIndexOf && value.length >= largeArraySize &&
- createCache(argsIndex ? args[argsIndex] : seen));
- }
- }
- var array = args[0],
- index = -1,
- length = array ? array.length : 0,
- result = [];
-
- outer:
- while (++index < length) {
- var cache = caches[0];
- value = array[index];
-
- if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) {
- argsIndex = argsLength;
- (cache || seen).push(value);
- while (--argsIndex) {
- cache = caches[argsIndex];
- if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) {
- continue outer;
- }
- }
- result.push(value);
- }
- }
- while (argsLength--) {
- cache = caches[argsLength];
- if (cache) {
- releaseObject(cache);
- }
- }
- releaseArray(caches);
- releaseArray(seen);
- return result;
- }
-
- /**
- * Gets the last element or last `n` elements of an array. If a callback is
- * provided elements at the end of the array are returned as long as the
- * callback returns truey. The callback is bound to `thisArg` and invoked
- * with three arguments; (value, index, array).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @category Arrays
- * @param {Array} array The array to query.
- * @param {Function|Object|number|string} [callback] The function called
- * per element or the number of elements to return. If a property name or
- * object is provided it will be used to create a "_.pluck" or "_.where"
- * style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {*} Returns the last element(s) of `array`.
- * @example
- *
- * _.last([1, 2, 3]);
- * // => 3
- *
- * _.last([1, 2, 3], 2);
- * // => [2, 3]
- *
- * _.last([1, 2, 3], function(num) {
- * return num > 1;
- * });
- * // => [2, 3]
- *
- * var characters = [
- * { 'name': 'barney', 'blocked': false, 'employer': 'slate' },
- * { 'name': 'fred', 'blocked': true, 'employer': 'slate' },
- * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
- * ];
- *
- * // using "_.pluck" callback shorthand
- * _.pluck(_.last(characters, 'blocked'), 'name');
- * // => ['fred', 'pebbles']
- *
- * // using "_.where" callback shorthand
- * _.last(characters, { 'employer': 'na' });
- * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
- */
- function last(array, callback, thisArg) {
- var n = 0,
- length = array ? array.length : 0;
-
- if (typeof callback != 'number' && callback != null) {
- var index = length;
- callback = lodash.createCallback(callback, thisArg, 3);
- while (index-- && callback(array[index], index, array)) {
- n++;
- }
- } else {
- n = callback;
- if (n == null || thisArg) {
- return array ? array[length - 1] : undefined;
- }
- }
- return slice(array, nativeMax(0, length - n));
- }
-
- /**
- * Gets the index at which the last occurrence of `value` is found using strict
- * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
- * as the offset from the end of the collection.
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @category Arrays
- * @param {Array} array The array to search.
- * @param {*} value The value to search for.
- * @param {number} [fromIndex=array.length-1] The index to search from.
- * @returns {number} Returns the index of the matched value or `-1`.
- * @example
- *
- * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
- * // => 4
- *
- * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
- * // => 1
- */
- function lastIndexOf(array, value, fromIndex) {
- var index = array ? array.length : 0;
- if (typeof fromIndex == 'number') {
- index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1;
- }
- while (index--) {
- if (array[index] === value) {
- return index;
- }
- }
- return -1;
- }
-
- /**
- * Removes all provided values from the given array using strict equality for
- * comparisons, i.e. `===`.
- *
- * @static
- * @memberOf _
- * @category Arrays
- * @param {Array} array The array to modify.
- * @param {...*} [value] The values to remove.
- * @returns {Array} Returns `array`.
- * @example
- *
- * var array = [1, 2, 3, 1, 2, 3];
- * _.pull(array, 2, 3);
- * console.log(array);
- * // => [1, 1]
- */
- function pull(array) {
- var args = arguments,
- argsIndex = 0,
- argsLength = args.length,
- length = array ? array.length : 0;
-
- while (++argsIndex < argsLength) {
- var index = -1,
- value = args[argsIndex];
- while (++index < length) {
- if (array[index] === value) {
- splice.call(array, index--, 1);
- length--;
- }
- }
- }
- return array;
- }
-
- /**
- * Creates an array of numbers (positive and/or negative) progressing from
- * `start` up to but not including `end`. If `start` is less than `stop` a
- * zero-length range is created unless a negative `step` is specified.
- *
- * @static
- * @memberOf _
- * @category Arrays
- * @param {number} [start=0] The start of the range.
- * @param {number} end The end of the range.
- * @param {number} [step=1] The value to increment or decrement by.
- * @returns {Array} Returns a new range array.
- * @example
- *
- * _.range(4);
- * // => [0, 1, 2, 3]
- *
- * _.range(1, 5);
- * // => [1, 2, 3, 4]
- *
- * _.range(0, 20, 5);
- * // => [0, 5, 10, 15]
- *
- * _.range(0, -4, -1);
- * // => [0, -1, -2, -3]
- *
- * _.range(1, 4, 0);
- * // => [1, 1, 1]
- *
- * _.range(0);
- * // => []
- */
- function range(start, end, step) {
- start = +start || 0;
- step = typeof step == 'number' ? step : (+step || 1);
-
- if (end == null) {
- end = start;
- start = 0;
- }
- // use `Array(length)` so engines like Chakra and V8 avoid slower modes
- // http://youtu.be/XAqIpGU8ZZk#t=17m25s
- var index = -1,
- length = nativeMax(0, ceil((end - start) / (step || 1))),
- result = Array(length);
-
- while (++index < length) {
- result[index] = start;
- start += step;
- }
- return result;
- }
-
- /**
- * Removes all elements from an array that the callback returns truey for
- * and returns an array of removed elements. The callback is bound to `thisArg`
- * and invoked with three arguments; (value, index, array).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @category Arrays
- * @param {Array} array The array to modify.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array} Returns a new array of removed elements.
- * @example
- *
- * var array = [1, 2, 3, 4, 5, 6];
- * var evens = _.remove(array, function(num) { return num % 2 == 0; });
- *
- * console.log(array);
- * // => [1, 3, 5]
- *
- * console.log(evens);
- * // => [2, 4, 6]
- */
- function remove(array, callback, thisArg) {
- var index = -1,
- length = array ? array.length : 0,
- result = [];
-
- callback = lodash.createCallback(callback, thisArg, 3);
- while (++index < length) {
- var value = array[index];
- if (callback(value, index, array)) {
- result.push(value);
- splice.call(array, index--, 1);
- length--;
- }
- }
- return result;
- }
-
- /**
- * The opposite of `_.initial` this method gets all but the first element or
- * first `n` elements of an array. If a callback function is provided elements
- * at the beginning of the array are excluded from the result as long as the
- * callback returns truey. The callback is bound to `thisArg` and invoked
- * with three arguments; (value, index, array).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @alias drop, tail
- * @category Arrays
- * @param {Array} array The array to query.
- * @param {Function|Object|number|string} [callback=1] The function called
- * per element or the number of elements to exclude. If a property name or
- * object is provided it will be used to create a "_.pluck" or "_.where"
- * style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array} Returns a slice of `array`.
- * @example
- *
- * _.rest([1, 2, 3]);
- * // => [2, 3]
- *
- * _.rest([1, 2, 3], 2);
- * // => [3]
- *
- * _.rest([1, 2, 3], function(num) {
- * return num < 3;
- * });
- * // => [3]
- *
- * var characters = [
- * { 'name': 'barney', 'blocked': true, 'employer': 'slate' },
- * { 'name': 'fred', 'blocked': false, 'employer': 'slate' },
- * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
- * ];
- *
- * // using "_.pluck" callback shorthand
- * _.pluck(_.rest(characters, 'blocked'), 'name');
- * // => ['fred', 'pebbles']
- *
- * // using "_.where" callback shorthand
- * _.rest(characters, { 'employer': 'slate' });
- * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
- */
- function rest(array, callback, thisArg) {
- if (typeof callback != 'number' && callback != null) {
- var n = 0,
- index = -1,
- length = array ? array.length : 0;
-
- callback = lodash.createCallback(callback, thisArg, 3);
- while (++index < length && callback(array[index], index, array)) {
- n++;
- }
- } else {
- n = (callback == null || thisArg) ? 1 : nativeMax(0, callback);
- }
- return slice(array, n);
- }
-
- /**
- * Uses a binary search to determine the smallest index at which a value
- * should be inserted into a given sorted array in order to maintain the sort
- * order of the array. If a callback is provided it will be executed for
- * `value` and each element of `array` to compute their sort ranking. The
- * callback is bound to `thisArg` and invoked with one argument; (value).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @category Arrays
- * @param {Array} array The array to inspect.
- * @param {*} value The value to evaluate.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {number} Returns the index at which `value` should be inserted
- * into `array`.
- * @example
- *
- * _.sortedIndex([20, 30, 50], 40);
- * // => 2
- *
- * // using "_.pluck" callback shorthand
- * _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
- * // => 2
- *
- * var dict = {
- * 'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 }
- * };
- *
- * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
- * return dict.wordToNumber[word];
- * });
- * // => 2
- *
- * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
- * return this.wordToNumber[word];
- * }, dict);
- * // => 2
- */
- function sortedIndex(array, value, callback, thisArg) {
- var low = 0,
- high = array ? array.length : low;
-
- // explicitly reference `identity` for better inlining in Firefox
- callback = callback ? lodash.createCallback(callback, thisArg, 1) : identity;
- value = callback(value);
-
- while (low < high) {
- var mid = (low + high) >>> 1;
- (callback(array[mid]) < value)
- ? low = mid + 1
- : high = mid;
- }
- return low;
- }
-
- /**
- * Creates an array of unique values, in order, of the provided arrays using
- * strict equality for comparisons, i.e. `===`.
- *
- * @static
- * @memberOf _
- * @category Arrays
- * @param {...Array} [array] The arrays to inspect.
- * @returns {Array} Returns an array of combined values.
- * @example
- *
- * _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]);
- * // => [1, 2, 3, 5, 4]
- */
- function union() {
- return baseUniq(baseFlatten(arguments, true, true));
- }
-
- /**
- * Creates a duplicate-value-free version of an array using strict equality
- * for comparisons, i.e. `===`. If the array is sorted, providing
- * `true` for `isSorted` will use a faster algorithm. If a callback is provided
- * each element of `array` is passed through the callback before uniqueness
- * is computed. The callback is bound to `thisArg` and invoked with three
- * arguments; (value, index, array).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @alias unique
- * @category Arrays
- * @param {Array} array The array to process.
- * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array} Returns a duplicate-value-free array.
- * @example
- *
- * _.uniq([1, 2, 1, 3, 1]);
- * // => [1, 2, 3]
- *
- * _.uniq([1, 1, 2, 2, 3], true);
- * // => [1, 2, 3]
- *
- * _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); });
- * // => ['A', 'b', 'C']
- *
- * _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math);
- * // => [1, 2.5, 3]
- *
- * // using "_.pluck" callback shorthand
- * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
- * // => [{ 'x': 1 }, { 'x': 2 }]
- */
- function uniq(array, isSorted, callback, thisArg) {
- // juggle arguments
- if (typeof isSorted != 'boolean' && isSorted != null) {
- thisArg = callback;
- callback = (typeof isSorted != 'function' && thisArg && thisArg[isSorted] === array) ? null : isSorted;
- isSorted = false;
- }
- if (callback != null) {
- callback = lodash.createCallback(callback, thisArg, 3);
- }
- return baseUniq(array, isSorted, callback);
- }
-
- /**
- * Creates an array excluding all provided values using strict equality for
- * comparisons, i.e. `===`.
- *
- * @static
- * @memberOf _
- * @category Arrays
- * @param {Array} array The array to filter.
- * @param {...*} [value] The values to exclude.
- * @returns {Array} Returns a new array of filtered values.
- * @example
- *
- * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
- * // => [2, 3, 4]
- */
- function without(array) {
- return baseDifference(array, slice(arguments, 1));
- }
-
- /**
- * Creates an array that is the symmetric difference of the provided arrays.
- * See http://en.wikipedia.org/wiki/Symmetric_difference.
- *
- * @static
- * @memberOf _
- * @category Arrays
- * @param {...Array} [array] The arrays to inspect.
- * @returns {Array} Returns an array of values.
- * @example
- *
- * _.xor([1, 2, 3], [5, 2, 1, 4]);
- * // => [3, 5, 4]
- *
- * _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]);
- * // => [1, 4, 5]
- */
- function xor() {
- var index = -1,
- length = arguments.length;
-
- while (++index < length) {
- var array = arguments[index];
- if (isArray(array) || isArguments(array)) {
- var result = result
- ? baseUniq(baseDifference(result, array).concat(baseDifference(array, result)))
- : array;
- }
- }
- return result || [];
- }
-
- /**
- * Creates an array of grouped elements, the first of which contains the first
- * elements of the given arrays, the second of which contains the second
- * elements of the given arrays, and so on.
- *
- * @static
- * @memberOf _
- * @alias unzip
- * @category Arrays
- * @param {...Array} [array] Arrays to process.
- * @returns {Array} Returns a new array of grouped elements.
- * @example
- *
- * _.zip(['fred', 'barney'], [30, 40], [true, false]);
- * // => [['fred', 30, true], ['barney', 40, false]]
- */
- function zip() {
- var array = arguments.length > 1 ? arguments : arguments[0],
- index = -1,
- length = array ? max(pluck(array, 'length')) : 0,
- result = Array(length < 0 ? 0 : length);
-
- while (++index < length) {
- result[index] = pluck(array, index);
- }
- return result;
- }
-
- /**
- * Creates an object composed from arrays of `keys` and `values`. Provide
- * either a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`
- * or two arrays, one of `keys` and one of corresponding `values`.
- *
- * @static
- * @memberOf _
- * @alias object
- * @category Arrays
- * @param {Array} keys The array of keys.
- * @param {Array} [values=[]] The array of values.
- * @returns {Object} Returns an object composed of the given keys and
- * corresponding values.
- * @example
- *
- * _.zipObject(['fred', 'barney'], [30, 40]);
- * // => { 'fred': 30, 'barney': 40 }
- */
- function zipObject(keys, values) {
- var index = -1,
- length = keys ? keys.length : 0,
- result = {};
-
- if (!values && length && !isArray(keys[0])) {
- values = [];
- }
- while (++index < length) {
- var key = keys[index];
- if (values) {
- result[key] = values[index];
- } else if (key) {
- result[key[0]] = key[1];
- }
- }
- return result;
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Creates a function that executes `func`, with the `this` binding and
- * arguments of the created function, only after being called `n` times.
- *
- * @static
- * @memberOf _
- * @category Functions
- * @param {number} n The number of times the function must be called before
- * `func` is executed.
- * @param {Function} func The function to restrict.
- * @returns {Function} Returns the new restricted function.
- * @example
- *
- * var saves = ['profile', 'settings'];
- *
- * var done = _.after(saves.length, function() {
- * console.log('Done saving!');
- * });
- *
- * _.forEach(saves, function(type) {
- * asyncSave({ 'type': type, 'complete': done });
- * });
- * // => logs 'Done saving!', after all saves have completed
- */
- function after(n, func) {
- if (!isFunction(func)) {
- throw new TypeError;
- }
- return function() {
- if (--n < 1) {
- return func.apply(this, arguments);
- }
- };
- }
-
- /**
- * Creates a function that, when called, invokes `func` with the `this`
- * binding of `thisArg` and prepends any additional `bind` arguments to those
- * provided to the bound function.
- *
- * @static
- * @memberOf _
- * @category Functions
- * @param {Function} func The function to bind.
- * @param {*} [thisArg] The `this` binding of `func`.
- * @param {...*} [arg] Arguments to be partially applied.
- * @returns {Function} Returns the new bound function.
- * @example
- *
- * var func = function(greeting) {
- * return greeting + ' ' + this.name;
- * };
- *
- * func = _.bind(func, { 'name': 'fred' }, 'hi');
- * func();
- * // => 'hi fred'
- */
- function bind(func, thisArg) {
- return arguments.length > 2
- ? createWrapper(func, 17, slice(arguments, 2), null, thisArg)
- : createWrapper(func, 1, null, null, thisArg);
- }
-
- /**
- * Binds methods of an object to the object itself, overwriting the existing
- * method. Method names may be specified as individual arguments or as arrays
- * of method names. If no method names are provided all the function properties
- * of `object` will be bound.
- *
- * @static
- * @memberOf _
- * @category Functions
- * @param {Object} object The object to bind and assign the bound methods to.
- * @param {...string} [methodName] The object method names to
- * bind, specified as individual method names or arrays of method names.
- * @returns {Object} Returns `object`.
- * @example
- *
- * var view = {
- * 'label': 'docs',
- * 'onClick': function() { console.log('clicked ' + this.label); }
- * };
- *
- * _.bindAll(view);
- * jQuery('#docs').on('click', view.onClick);
- * // => logs 'clicked docs', when the button is clicked
- */
- function bindAll(object) {
- var funcs = arguments.length > 1 ? baseFlatten(arguments, true, false, 1) : functions(object),
- index = -1,
- length = funcs.length;
-
- while (++index < length) {
- var key = funcs[index];
- object[key] = createWrapper(object[key], 1, null, null, object);
- }
- return object;
- }
-
- /**
- * Creates a function that, when called, invokes the method at `object[key]`
- * and prepends any additional `bindKey` arguments to those provided to the bound
- * function. This method differs from `_.bind` by allowing bound functions to
- * reference methods that will be redefined or don't yet exist.
- * See http://michaux.ca/articles/lazy-function-definition-pattern.
- *
- * @static
- * @memberOf _
- * @category Functions
- * @param {Object} object The object the method belongs to.
- * @param {string} key The key of the method.
- * @param {...*} [arg] Arguments to be partially applied.
- * @returns {Function} Returns the new bound function.
- * @example
- *
- * var object = {
- * 'name': 'fred',
- * 'greet': function(greeting) {
- * return greeting + ' ' + this.name;
- * }
- * };
- *
- * var func = _.bindKey(object, 'greet', 'hi');
- * func();
- * // => 'hi fred'
- *
- * object.greet = function(greeting) {
- * return greeting + 'ya ' + this.name + '!';
- * };
- *
- * func();
- * // => 'hiya fred!'
- */
- function bindKey(object, key) {
- return arguments.length > 2
- ? createWrapper(key, 19, slice(arguments, 2), null, object)
- : createWrapper(key, 3, null, null, object);
- }
-
- /**
- * Creates a function that is the composition of the provided functions,
- * where each function consumes the return value of the function that follows.
- * For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`.
- * Each function is executed with the `this` binding of the composed function.
- *
- * @static
- * @memberOf _
- * @category Functions
- * @param {...Function} [func] Functions to compose.
- * @returns {Function} Returns the new composed function.
- * @example
- *
- * var realNameMap = {
- * 'pebbles': 'penelope'
- * };
- *
- * var format = function(name) {
- * name = realNameMap[name.toLowerCase()] || name;
- * return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();
- * };
- *
- * var greet = function(formatted) {
- * return 'Hiya ' + formatted + '!';
- * };
- *
- * var welcome = _.compose(greet, format);
- * welcome('pebbles');
- * // => 'Hiya Penelope!'
- */
- function compose() {
- var funcs = arguments,
- length = funcs.length;
-
- while (length--) {
- if (!isFunction(funcs[length])) {
- throw new TypeError;
- }
- }
- return function() {
- var args = arguments,
- length = funcs.length;
-
- while (length--) {
- args = [funcs[length].apply(this, args)];
- }
- return args[0];
- };
- }
-
- /**
- * Creates a function which accepts one or more arguments of `func` that when
- * invoked either executes `func` returning its result, if all `func` arguments
- * have been provided, or returns a function that accepts one or more of the
- * remaining `func` arguments, and so on. The arity of `func` can be specified
- * if `func.length` is not sufficient.
- *
- * @static
- * @memberOf _
- * @category Functions
- * @param {Function} func The function to curry.
- * @param {number} [arity=func.length] The arity of `func`.
- * @returns {Function} Returns the new curried function.
- * @example
- *
- * var curried = _.curry(function(a, b, c) {
- * console.log(a + b + c);
- * });
- *
- * curried(1)(2)(3);
- * // => 6
- *
- * curried(1, 2)(3);
- * // => 6
- *
- * curried(1, 2, 3);
- * // => 6
- */
- function curry(func, arity) {
- arity = typeof arity == 'number' ? arity : (+arity || func.length);
- return createWrapper(func, 4, null, null, null, arity);
- }
-
- /**
- * Creates a function that will delay the execution of `func` until after
- * `wait` milliseconds have elapsed since the last time it was invoked.
- * Provide an options object to indicate that `func` should be invoked on
- * the leading and/or trailing edge of the `wait` timeout. Subsequent calls
- * to the debounced function will return the result of the last `func` call.
- *
- * Note: If `leading` and `trailing` options are `true` `func` will be called
- * on the trailing edge of the timeout only if the the debounced function is
- * invoked more than once during the `wait` timeout.
- *
- * @static
- * @memberOf _
- * @category Functions
- * @param {Function} func The function to debounce.
- * @param {number} wait The number of milliseconds to delay.
- * @param {Object} [options] The options object.
- * @param {boolean} [options.leading=false] Specify execution on the leading edge of the timeout.
- * @param {number} [options.maxWait] The maximum time `func` is allowed to be delayed before it's called.
- * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
- * @returns {Function} Returns the new debounced function.
- * @example
- *
- * // avoid costly calculations while the window size is in flux
- * var lazyLayout = _.debounce(calculateLayout, 150);
- * jQuery(window).on('resize', lazyLayout);
- *
- * // execute `sendMail` when the click event is fired, debouncing subsequent calls
- * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
- * 'leading': true,
- * 'trailing': false
- * });
- *
- * // ensure `batchLog` is executed once after 1 second of debounced calls
- * var source = new EventSource('/stream');
- * source.addEventListener('message', _.debounce(batchLog, 250, {
- * 'maxWait': 1000
- * }, false);
- */
- function debounce(func, wait, options) {
- var args,
- maxTimeoutId,
- result,
- stamp,
- thisArg,
- timeoutId,
- trailingCall,
- lastCalled = 0,
- maxWait = false,
- trailing = true;
-
- if (!isFunction(func)) {
- throw new TypeError;
- }
- wait = nativeMax(0, wait) || 0;
- if (options === true) {
- var leading = true;
- trailing = false;
- } else if (isObject(options)) {
- leading = options.leading;
- maxWait = 'maxWait' in options && (nativeMax(wait, options.maxWait) || 0);
- trailing = 'trailing' in options ? options.trailing : trailing;
- }
- var delayed = function() {
- var remaining = wait - (now() - stamp);
- if (remaining <= 0) {
- if (maxTimeoutId) {
- clearTimeout(maxTimeoutId);
- }
- var isCalled = trailingCall;
- maxTimeoutId = timeoutId = trailingCall = undefined;
- if (isCalled) {
- lastCalled = now();
- result = func.apply(thisArg, args);
- if (!timeoutId && !maxTimeoutId) {
- args = thisArg = null;
- }
- }
- } else {
- timeoutId = setTimeout(delayed, remaining);
- }
- };
-
- var maxDelayed = function() {
- if (timeoutId) {
- clearTimeout(timeoutId);
- }
- maxTimeoutId = timeoutId = trailingCall = undefined;
- if (trailing || (maxWait !== wait)) {
- lastCalled = now();
- result = func.apply(thisArg, args);
- if (!timeoutId && !maxTimeoutId) {
- args = thisArg = null;
- }
- }
- };
-
- return function() {
- args = arguments;
- stamp = now();
- thisArg = this;
- trailingCall = trailing && (timeoutId || !leading);
-
- if (maxWait === false) {
- var leadingCall = leading && !timeoutId;
- } else {
- if (!maxTimeoutId && !leading) {
- lastCalled = stamp;
- }
- var remaining = maxWait - (stamp - lastCalled),
- isCalled = remaining <= 0;
-
- if (isCalled) {
- if (maxTimeoutId) {
- maxTimeoutId = clearTimeout(maxTimeoutId);
- }
- lastCalled = stamp;
- result = func.apply(thisArg, args);
- }
- else if (!maxTimeoutId) {
- maxTimeoutId = setTimeout(maxDelayed, remaining);
- }
- }
- if (isCalled && timeoutId) {
- timeoutId = clearTimeout(timeoutId);
- }
- else if (!timeoutId && wait !== maxWait) {
- timeoutId = setTimeout(delayed, wait);
- }
- if (leadingCall) {
- isCalled = true;
- result = func.apply(thisArg, args);
- }
- if (isCalled && !timeoutId && !maxTimeoutId) {
- args = thisArg = null;
- }
- return result;
- };
- }
-
- /**
- * Defers executing the `func` function until the current call stack has cleared.
- * Additional arguments will be provided to `func` when it is invoked.
- *
- * @static
- * @memberOf _
- * @category Functions
- * @param {Function} func The function to defer.
- * @param {...*} [arg] Arguments to invoke the function with.
- * @returns {number} Returns the timer id.
- * @example
- *
- * _.defer(function(text) { console.log(text); }, 'deferred');
- * // logs 'deferred' after one or more milliseconds
- */
- function defer(func) {
- if (!isFunction(func)) {
- throw new TypeError;
- }
- var args = slice(arguments, 1);
- return setTimeout(function() { func.apply(undefined, args); }, 1);
- }
-
- /**
- * Executes the `func` function after `wait` milliseconds. Additional arguments
- * will be provided to `func` when it is invoked.
- *
- * @static
- * @memberOf _
- * @category Functions
- * @param {Function} func The function to delay.
- * @param {number} wait The number of milliseconds to delay execution.
- * @param {...*} [arg] Arguments to invoke the function with.
- * @returns {number} Returns the timer id.
- * @example
- *
- * _.delay(function(text) { console.log(text); }, 1000, 'later');
- * // => logs 'later' after one second
- */
- function delay(func, wait) {
- if (!isFunction(func)) {
- throw new TypeError;
- }
- var args = slice(arguments, 2);
- return setTimeout(function() { func.apply(undefined, args); }, wait);
- }
-
- /**
- * Creates a function that memoizes the result of `func`. If `resolver` is
- * provided it will be used to determine the cache key for storing the result
- * based on the arguments provided to the memoized function. By default, the
- * first argument provided to the memoized function is used as the cache key.
- * The `func` is executed with the `this` binding of the memoized function.
- * The result cache is exposed as the `cache` property on the memoized function.
- *
- * @static
- * @memberOf _
- * @category Functions
- * @param {Function} func The function to have its output memoized.
- * @param {Function} [resolver] A function used to resolve the cache key.
- * @returns {Function} Returns the new memoizing function.
- * @example
- *
- * var fibonacci = _.memoize(function(n) {
- * return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
- * });
- *
- * fibonacci(9)
- * // => 34
- *
- * var data = {
- * 'fred': { 'name': 'fred', 'age': 40 },
- * 'pebbles': { 'name': 'pebbles', 'age': 1 }
- * };
- *
- * // modifying the result cache
- * var get = _.memoize(function(name) { return data[name]; }, _.identity);
- * get('pebbles');
- * // => { 'name': 'pebbles', 'age': 1 }
- *
- * get.cache.pebbles.name = 'penelope';
- * get('pebbles');
- * // => { 'name': 'penelope', 'age': 1 }
- */
- function memoize(func, resolver) {
- if (!isFunction(func)) {
- throw new TypeError;
- }
- var memoized = function() {
- var cache = memoized.cache,
- key = resolver ? resolver.apply(this, arguments) : keyPrefix + arguments[0];
-
- return hasOwnProperty.call(cache, key)
- ? cache[key]
- : (cache[key] = func.apply(this, arguments));
- }
- memoized.cache = {};
- return memoized;
- }
-
- /**
- * Creates a function that is restricted to execute `func` once. Repeat calls to
- * the function will return the value of the first call. The `func` is executed
- * with the `this` binding of the created function.
- *
- * @static
- * @memberOf _
- * @category Functions
- * @param {Function} func The function to restrict.
- * @returns {Function} Returns the new restricted function.
- * @example
- *
- * var initialize = _.once(createApplication);
- * initialize();
- * initialize();
- * // `initialize` executes `createApplication` once
- */
- function once(func) {
- var ran,
- result;
-
- if (!isFunction(func)) {
- throw new TypeError;
- }
- return function() {
- if (ran) {
- return result;
- }
- ran = true;
- result = func.apply(this, arguments);
-
- // clear the `func` variable so the function may be garbage collected
- func = null;
- return result;
- };
- }
-
- /**
- * Creates a function that, when called, invokes `func` with any additional
- * `partial` arguments prepended to those provided to the new function. This
- * method is similar to `_.bind` except it does **not** alter the `this` binding.
- *
- * @static
- * @memberOf _
- * @category Functions
- * @param {Function} func The function to partially apply arguments to.
- * @param {...*} [arg] Arguments to be partially applied.
- * @returns {Function} Returns the new partially applied function.
- * @example
- *
- * var greet = function(greeting, name) { return greeting + ' ' + name; };
- * var hi = _.partial(greet, 'hi');
- * hi('fred');
- * // => 'hi fred'
- */
- function partial(func) {
- return createWrapper(func, 16, slice(arguments, 1));
- }
-
- /**
- * This method is like `_.partial` except that `partial` arguments are
- * appended to those provided to the new function.
- *
- * @static
- * @memberOf _
- * @category Functions
- * @param {Function} func The function to partially apply arguments to.
- * @param {...*} [arg] Arguments to be partially applied.
- * @returns {Function} Returns the new partially applied function.
- * @example
- *
- * var defaultsDeep = _.partialRight(_.merge, _.defaults);
- *
- * var options = {
- * 'variable': 'data',
- * 'imports': { 'jq': $ }
- * };
- *
- * defaultsDeep(options, _.templateSettings);
- *
- * options.variable
- * // => 'data'
- *
- * options.imports
- * // => { '_': _, 'jq': $ }
- */
- function partialRight(func) {
- return createWrapper(func, 32, null, slice(arguments, 1));
- }
-
- /**
- * Creates a function that, when executed, will only call the `func` function
- * at most once per every `wait` milliseconds. Provide an options object to
- * indicate that `func` should be invoked on the leading and/or trailing edge
- * of the `wait` timeout. Subsequent calls to the throttled function will
- * return the result of the last `func` call.
- *
- * Note: If `leading` and `trailing` options are `true` `func` will be called
- * on the trailing edge of the timeout only if the the throttled function is
- * invoked more than once during the `wait` timeout.
- *
- * @static
- * @memberOf _
- * @category Functions
- * @param {Function} func The function to throttle.
- * @param {number} wait The number of milliseconds to throttle executions to.
- * @param {Object} [options] The options object.
- * @param {boolean} [options.leading=true] Specify execution on the leading edge of the timeout.
- * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
- * @returns {Function} Returns the new throttled function.
- * @example
- *
- * // avoid excessively updating the position while scrolling
- * var throttled = _.throttle(updatePosition, 100);
- * jQuery(window).on('scroll', throttled);
- *
- * // execute `renewToken` when the click event is fired, but not more than once every 5 minutes
- * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, {
- * 'trailing': false
- * }));
- */
- function throttle(func, wait, options) {
- var leading = true,
- trailing = true;
-
- if (!isFunction(func)) {
- throw new TypeError;
- }
- if (options === false) {
- leading = false;
- } else if (isObject(options)) {
- leading = 'leading' in options ? options.leading : leading;
- trailing = 'trailing' in options ? options.trailing : trailing;
- }
- debounceOptions.leading = leading;
- debounceOptions.maxWait = wait;
- debounceOptions.trailing = trailing;
-
- return debounce(func, wait, debounceOptions);
- }
-
- /**
- * Creates a function that provides `value` to the wrapper function as its
- * first argument. Additional arguments provided to the function are appended
- * to those provided to the wrapper function. The wrapper is executed with
- * the `this` binding of the created function.
- *
- * @static
- * @memberOf _
- * @category Functions
- * @param {*} value The value to wrap.
- * @param {Function} wrapper The wrapper function.
- * @returns {Function} Returns the new function.
- * @example
- *
- * var p = _.wrap(_.escape, function(func, text) {
- * return '<p>' + func(text) + '</p>';
- * });
- *
- * p('Fred, Wilma, & Pebbles');
- * // => '<p>Fred, Wilma, &amp; Pebbles</p>'
- */
- function wrap(value, wrapper) {
- return createWrapper(wrapper, 16, [value]);
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Creates a function that returns `value`.
- *
- * @static
- * @memberOf _
- * @category Utilities
- * @param {*} value The value to return from the new function.
- * @returns {Function} Returns the new function.
- * @example
- *
- * var object = { 'name': 'fred' };
- * var getter = _.constant(object);
- * getter() === object;
- * // => true
- */
- function constant(value) {
- return function() {
- return value;
- };
- }
-
- /**
- * Produces a callback bound to an optional `thisArg`. If `func` is a property
- * name the created callback will return the property value for a given element.
- * If `func` is an object the created callback will return `true` for elements
- * that contain the equivalent object properties, otherwise it will return `false`.
- *
- * @static
- * @memberOf _
- * @category Utilities
- * @param {*} [func=identity] The value to convert to a callback.
- * @param {*} [thisArg] The `this` binding of the created callback.
- * @param {number} [argCount] The number of arguments the callback accepts.
- * @returns {Function} Returns a callback function.
- * @example
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36 },
- * { 'name': 'fred', 'age': 40 }
- * ];
- *
- * // wrap to create custom callback shorthands
- * _.createCallback = _.wrap(_.createCallback, function(func, callback, thisArg) {
- * var match = /^(.+?)__([gl]t)(.+)$/.exec(callback);
- * return !match ? func(callback, thisArg) : function(object) {
- * return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3];
- * };
- * });
- *
- * _.filter(characters, 'age__gt38');
- * // => [{ 'name': 'fred', 'age': 40 }]
- */
- function createCallback(func, thisArg, argCount) {
- var type = typeof func;
- if (func == null || type == 'function') {
- return baseCreateCallback(func, thisArg, argCount);
- }
- // handle "_.pluck" style callback shorthands
- if (type != 'object') {
- return property(func);
- }
- var props = keys(func),
- key = props[0],
- a = func[key];
-
- // handle "_.where" style callback shorthands
- if (props.length == 1 && a === a && !isObject(a)) {
- // fast path the common case of providing an object with a single
- // property containing a primitive value
- return function(object) {
- var b = object[key];
- return a === b && (a !== 0 || (1 / a == 1 / b));
- };
- }
- return function(object) {
- var length = props.length,
- result = false;
-
- while (length--) {
- if (!(result = baseIsEqual(object[props[length]], func[props[length]], null, true))) {
- break;
- }
- }
- return result;
- };
- }
-
- /**
- * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their
- * corresponding HTML entities.
- *
- * @static
- * @memberOf _
- * @category Utilities
- * @param {string} string The string to escape.
- * @returns {string} Returns the escaped string.
- * @example
- *
- * _.escape('Fred, Wilma, & Pebbles');
- * // => 'Fred, Wilma, &amp; Pebbles'
- */
- function escape(string) {
- return string == null ? '' : String(string).replace(reUnescapedHtml, escapeHtmlChar);
- }
-
- /**
- * This method returns the first argument provided to it.
- *
- * @static
- * @memberOf _
- * @category Utilities
- * @param {*} value Any value.
- * @returns {*} Returns `value`.
- * @example
- *
- * var object = { 'name': 'fred' };
- * _.identity(object) === object;
- * // => true
- */
- function identity(value) {
- return value;
- }
-
- /**
- * Adds function properties of a source object to the destination object.
- * If `object` is a function methods will be added to its prototype as well.
- *
- * @static
- * @memberOf _
- * @category Utilities
- * @param {Function|Object} [object=lodash] object The destination object.
- * @param {Object} source The object of functions to add.
- * @param {Object} [options] The options object.
- * @param {boolean} [options.chain=true] Specify whether the functions added are chainable.
- * @example
- *
- * function capitalize(string) {
- * return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
- * }
- *
- * _.mixin({ 'capitalize': capitalize });
- * _.capitalize('fred');
- * // => 'Fred'
- *
- * _('fred').capitalize().value();
- * // => 'Fred'
- *
- * _.mixin({ 'capitalize': capitalize }, { 'chain': false });
- * _('fred').capitalize();
- * // => 'Fred'
- */
- function mixin(object, source, options) {
- var chain = true,
- methodNames = source && functions(source);
-
- if (!source || (!options && !methodNames.length)) {
- if (options == null) {
- options = source;
- }
- ctor = lodashWrapper;
- source = object;
- object = lodash;
- methodNames = functions(source);
- }
- if (options === false) {
- chain = false;
- } else if (isObject(options) && 'chain' in options) {
- chain = options.chain;
- }
- var ctor = object,
- isFunc = isFunction(ctor);
-
- forEach(methodNames, function(methodName) {
- var func = object[methodName] = source[methodName];
- if (isFunc) {
- ctor.prototype[methodName] = function() {
- var chainAll = this.__chain__,
- value = this.__wrapped__,
- args = [value];
-
- push.apply(args, arguments);
- var result = func.apply(object, args);
- if (chain || chainAll) {
- if (value === result && isObject(result)) {
- return this;
- }
- result = new ctor(result);
- result.__chain__ = chainAll;
- }
- return result;
- };
- }
- });
- }
-
- /**
- * Reverts the '_' variable to its previous value and returns a reference to
- * the `lodash` function.
- *
- * @static
- * @memberOf _
- * @category Utilities
- * @returns {Function} Returns the `lodash` function.
- * @example
- *
- * var lodash = _.noConflict();
- */
- function noConflict() {
- context._ = oldDash;
- return this;
- }
-
- /**
- * A no-operation function.
- *
- * @static
- * @memberOf _
- * @category Utilities
- * @example
- *
- * var object = { 'name': 'fred' };
- * _.noop(object) === undefined;
- * // => true
- */
- function noop() {
- // no operation performed
- }
-
- /**
- * Gets the number of milliseconds that have elapsed since the Unix epoch
- * (1 January 1970 00:00:00 UTC).
- *
- * @static
- * @memberOf _
- * @category Utilities
- * @example
- *
- * var stamp = _.now();
- * _.defer(function() { console.log(_.now() - stamp); });
- * // => logs the number of milliseconds it took for the deferred function to be called
- */
- var now = isNative(now = Date.now) && now || function() {
- return new Date().getTime();
- };
-
- /**
- * Converts the given value into an integer of the specified radix.
- * If `radix` is `undefined` or `0` a `radix` of `10` is used unless the
- * `value` is a hexadecimal, in which case a `radix` of `16` is used.
- *
- * Note: This method avoids differences in native ES3 and ES5 `parseInt`
- * implementations. See http://es5.github.io/#E.
- *
- * @static
- * @memberOf _
- * @category Utilities
- * @param {string} value The value to parse.
- * @param {number} [radix] The radix used to interpret the value to parse.
- * @returns {number} Returns the new integer value.
- * @example
- *
- * _.parseInt('08');
- * // => 8
- */
- var parseInt = nativeParseInt(whitespace + '08') == 8 ? nativeParseInt : function(value, radix) {
- // Firefox < 21 and Opera < 15 follow the ES3 specified implementation of `parseInt`
- return nativeParseInt(isString(value) ? value.replace(reLeadingSpacesAndZeros, '') : value, radix || 0);
- };
-
- /**
- * Creates a "_.pluck" style function, which returns the `key` value of a
- * given object.
- *
- * @static
- * @memberOf _
- * @category Utilities
- * @param {string} key The name of the property to retrieve.
- * @returns {Function} Returns the new function.
- * @example
- *
- * var characters = [
- * { 'name': 'fred', 'age': 40 },
- * { 'name': 'barney', 'age': 36 }
- * ];
- *
- * var getName = _.property('name');
- *
- * _.map(characters, getName);
- * // => ['barney', 'fred']
- *
- * _.sortBy(characters, getName);
- * // => [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }]
- */
- function property(key) {
- return function(object) {
- return object[key];
- };
- }
-
- /**
- * Produces a random number between `min` and `max` (inclusive). If only one
- * argument is provided a number between `0` and the given number will be
- * returned. If `floating` is truey or either `min` or `max` are floats a
- * floating-point number will be returned instead of an integer.
- *
- * @static
- * @memberOf _
- * @category Utilities
- * @param {number} [min=0] The minimum possible value.
- * @param {number} [max=1] The maximum possible value.
- * @param {boolean} [floating=false] Specify returning a floating-point number.
- * @returns {number} Returns a random number.
- * @example
- *
- * _.random(0, 5);
- * // => an integer between 0 and 5
- *
- * _.random(5);
- * // => also an integer between 0 and 5
- *
- * _.random(5, true);
- * // => a floating-point number between 0 and 5
- *
- * _.random(1.2, 5.2);
- * // => a floating-point number between 1.2 and 5.2
- */
- function random(min, max, floating) {
- var noMin = min == null,
- noMax = max == null;
-
- if (floating == null) {
- if (typeof min == 'boolean' && noMax) {
- floating = min;
- min = 1;
- }
- else if (!noMax && typeof max == 'boolean') {
- floating = max;
- noMax = true;
- }
- }
- if (noMin && noMax) {
- max = 1;
- }
- min = +min || 0;
- if (noMax) {
- max = min;
- min = 0;
- } else {
- max = +max || 0;
- }
- if (floating || min % 1 || max % 1) {
- var rand = nativeRandom();
- return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1)))), max);
- }
- return baseRandom(min, max);
- }
-
- /**
- * Resolves the value of property `key` on `object`. If `key` is a function
- * it will be invoked with the `this` binding of `object` and its result returned,
- * else the property value is returned. If `object` is falsey then `undefined`
- * is returned.
- *
- * @static
- * @memberOf _
- * @category Utilities
- * @param {Object} object The object to inspect.
- * @param {string} key The name of the property to resolve.
- * @returns {*} Returns the resolved value.
- * @example
- *
- * var object = {
- * 'cheese': 'crumpets',
- * 'stuff': function() {
- * return 'nonsense';
- * }
- * };
- *
- * _.result(object, 'cheese');
- * // => 'crumpets'
- *
- * _.result(object, 'stuff');
- * // => 'nonsense'
- */
- function result(object, key) {
- if (object) {
- var value = object[key];
- return isFunction(value) ? object[key]() : value;
- }
- }
-
- /**
- * A micro-templating method that handles arbitrary delimiters, preserves
- * whitespace, and correctly escapes quotes within interpolated code.
- *
- * Note: In the development build, `_.template` utilizes sourceURLs for easier
- * debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
- *
- * For more information on precompiling templates see:
- * http://lodash.com/custom-builds
- *
- * For more information on Chrome extension sandboxes see:
- * http://developer.chrome.com/stable/extensions/sandboxingEval.html
- *
- * @static
- * @memberOf _
- * @category Utilities
- * @param {string} text The template text.
- * @param {Object} data The data object used to populate the text.
- * @param {Object} [options] The options object.
- * @param {RegExp} [options.escape] The "escape" delimiter.
- * @param {RegExp} [options.evaluate] The "evaluate" delimiter.
- * @param {Object} [options.imports] An object to import into the template as local variables.
- * @param {RegExp} [options.interpolate] The "interpolate" delimiter.
- * @param {string} [sourceURL] The sourceURL of the template's compiled source.
- * @param {string} [variable] The data object variable name.
- * @returns {Function|string} Returns a compiled function when no `data` object
- * is given, else it returns the interpolated text.
- * @example
- *
- * // using the "interpolate" delimiter to create a compiled template
- * var compiled = _.template('hello <%= name %>');
- * compiled({ 'name': 'fred' });
- * // => 'hello fred'
- *
- * // using the "escape" delimiter to escape HTML in data property values
- * _.template('<b><%- value %></b>', { 'value': '<script>' });
- * // => '<b>&lt;script&gt;</b>'
- *
- * // using the "evaluate" delimiter to generate HTML
- * var list = '<% _.forEach(people, function(name) { %><li><%- name %></li><% }); %>';
- * _.template(list, { 'people': ['fred', 'barney'] });
- * // => '<li>fred</li><li>barney</li>'
- *
- * // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
- * _.template('hello ${ name }', { 'name': 'pebbles' });
- * // => 'hello pebbles'
- *
- * // using the internal `print` function in "evaluate" delimiters
- * _.template('<% print("hello " + name); %>!', { 'name': 'barney' });
- * // => 'hello barney!'
- *
- * // using a custom template delimiters
- * _.templateSettings = {
- * 'interpolate': /{{([\s\S]+?)}}/g
- * };
- *
- * _.template('hello {{ name }}!', { 'name': 'mustache' });
- * // => 'hello mustache!'
- *
- * // using the `imports` option to import jQuery
- * var list = '<% jq.each(people, function(name) { %><li><%- name %></li><% }); %>';
- * _.template(list, { 'people': ['fred', 'barney'] }, { 'imports': { 'jq': jQuery } });
- * // => '<li>fred</li><li>barney</li>'
- *
- * // using the `sourceURL` option to specify a custom sourceURL for the template
- * var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' });
- * compiled(data);
- * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
- *
- * // using the `variable` option to ensure a with-statement isn't used in the compiled template
- * var compiled = _.template('hi <%= data.name %>!', null, { 'variable': 'data' });
- * compiled.source;
- * // => function(data) {
- * var __t, __p = '', __e = _.escape;
- * __p += 'hi ' + ((__t = ( data.name )) == null ? '' : __t) + '!';
- * return __p;
- * }
- *
- * // using the `source` property to inline compiled templates for meaningful
- * // line numbers in error messages and a stack trace
- * fs.writeFileSync(path.join(cwd, 'jst.js'), '\
- * var JST = {\
- * "main": ' + _.template(mainText).source + '\
- * };\
- * ');
- */
- function template(text, data, options) {
- // based on John Resig's `tmpl` implementation
- // http://ejohn.org/blog/javascript-micro-templating/
- // and Laura Doktorova's doT.js
- // https://github.com/olado/doT
- var settings = lodash.templateSettings;
- text = String(text || '');
-
- // avoid missing dependencies when `iteratorTemplate` is not defined
- options = defaults({}, options, settings);
-
- var imports = defaults({}, options.imports, settings.imports),
- importsKeys = keys(imports),
- importsValues = values(imports);
-
- var isEvaluating,
- index = 0,
- interpolate = options.interpolate || reNoMatch,
- source = "__p += '";
-
- // compile the regexp to match each delimiter
- var reDelimiters = RegExp(
- (options.escape || reNoMatch).source + '|' +
- interpolate.source + '|' +
- (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
- (options.evaluate || reNoMatch).source + '|$'
- , 'g');
-
- text.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
- interpolateValue || (interpolateValue = esTemplateValue);
-
- // escape characters that cannot be included in string literals
- source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar);
-
- // replace delimiters with snippets
- if (escapeValue) {
- source += "' +\n__e(" + escapeValue + ") +\n'";
- }
- if (evaluateValue) {
- isEvaluating = true;
- source += "';\n" + evaluateValue + ";\n__p += '";
- }
- if (interpolateValue) {
- source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
- }
- index = offset + match.length;
-
- // the JS engine embedded in Adobe products requires returning the `match`
- // string in order to produce the correct `offset` value
- return match;
- });
-
- source += "';\n";
-
- // if `variable` is not specified, wrap a with-statement around the generated
- // code to add the data object to the top of the scope chain
- var variable = options.variable,
- hasVariable = variable;
-
- if (!hasVariable) {
- variable = 'obj';
- source = 'with (' + variable + ') {\n' + source + '\n}\n';
- }
- // cleanup code by stripping empty strings
- source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
- .replace(reEmptyStringMiddle, '$1')
- .replace(reEmptyStringTrailing, '$1;');
-
- // frame code as the function body
- source = 'function(' + variable + ') {\n' +
- (hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') +
- "var __t, __p = '', __e = _.escape" +
- (isEvaluating
- ? ', __j = Array.prototype.join;\n' +
- "function print() { __p += __j.call(arguments, '') }\n"
- : ';\n'
- ) +
- source +
- 'return __p\n}';
-
- // Use a sourceURL for easier debugging.
- // http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
- var sourceURL = '\n/*\n//# sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']') + '\n*/';
-
- try {
- var result = Function(importsKeys, 'return ' + source + sourceURL).apply(undefined, importsValues);
- } catch(e) {
- e.source = source;
- throw e;
- }
- if (data) {
- return result(data);
- }
- // provide the compiled function's source by its `toString` method, in
- // supported environments, or the `source` property as a convenience for
- // inlining compiled templates during the build process
- result.source = source;
- return result;
- }
-
- /**
- * Executes the callback `n` times, returning an array of the results
- * of each callback execution. The callback is bound to `thisArg` and invoked
- * with one argument; (index).
- *
- * @static
- * @memberOf _
- * @category Utilities
- * @param {number} n The number of times to execute the callback.
- * @param {Function} callback The function called per iteration.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array} Returns an array of the results of each `callback` execution.
- * @example
- *
- * var diceRolls = _.times(3, _.partial(_.random, 1, 6));
- * // => [3, 6, 4]
- *
- * _.times(3, function(n) { mage.castSpell(n); });
- * // => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, and `2` respectively
- *
- * _.times(3, function(n) { this.cast(n); }, mage);
- * // => also calls `mage.castSpell(n)` three times
- */
- function times(n, callback, thisArg) {
- n = (n = +n) > -1 ? n : 0;
- var index = -1,
- result = Array(n);
-
- callback = baseCreateCallback(callback, thisArg, 1);
- while (++index < n) {
- result[index] = callback(index);
- }
- return result;
- }
-
- /**
- * The inverse of `_.escape` this method converts the HTML entities
- * `&amp;`, `&lt;`, `&gt;`, `&quot;`, and `&#39;` in `string` to their
- * corresponding characters.
- *
- * @static
- * @memberOf _
- * @category Utilities
- * @param {string} string The string to unescape.
- * @returns {string} Returns the unescaped string.
- * @example
- *
- * _.unescape('Fred, Barney &amp; Pebbles');
- * // => 'Fred, Barney & Pebbles'
- */
- function unescape(string) {
- return string == null ? '' : String(string).replace(reEscapedHtml, unescapeHtmlChar);
- }
-
- /**
- * Generates a unique ID. If `prefix` is provided the ID will be appended to it.
- *
- * @static
- * @memberOf _
- * @category Utilities
- * @param {string} [prefix] The value to prefix the ID with.
- * @returns {string} Returns the unique ID.
- * @example
- *
- * _.uniqueId('contact_');
- * // => 'contact_104'
- *
- * _.uniqueId();
- * // => '105'
- */
- function uniqueId(prefix) {
- var id = ++idCounter;
- return String(prefix == null ? '' : prefix) + id;
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Creates a `lodash` object that wraps the given value with explicit
- * method chaining enabled.
- *
- * @static
- * @memberOf _
- * @category Chaining
- * @param {*} value The value to wrap.
- * @returns {Object} Returns the wrapper object.
- * @example
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36 },
- * { 'name': 'fred', 'age': 40 },
- * { 'name': 'pebbles', 'age': 1 }
- * ];
- *
- * var youngest = _.chain(characters)
- * .sortBy('age')
- * .map(function(chr) { return chr.name + ' is ' + chr.age; })
- * .first()
- * .value();
- * // => 'pebbles is 1'
- */
- function chain(value) {
- value = new lodashWrapper(value);
- value.__chain__ = true;
- return value;
- }
-
- /**
- * Invokes `interceptor` with the `value` as the first argument and then
- * returns `value`. The purpose of this method is to "tap into" a method
- * chain in order to perform operations on intermediate results within
- * the chain.
- *
- * @static
- * @memberOf _
- * @category Chaining
- * @param {*} value The value to provide to `interceptor`.
- * @param {Function} interceptor The function to invoke.
- * @returns {*} Returns `value`.
- * @example
- *
- * _([1, 2, 3, 4])
- * .tap(function(array) { array.pop(); })
- * .reverse()
- * .value();
- * // => [3, 2, 1]
- */
- function tap(value, interceptor) {
- interceptor(value);
- return value;
- }
-
- /**
- * Enables explicit method chaining on the wrapper object.
- *
- * @name chain
- * @memberOf _
- * @category Chaining
- * @returns {*} Returns the wrapper object.
- * @example
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36 },
- * { 'name': 'fred', 'age': 40 }
- * ];
- *
- * // without explicit chaining
- * _(characters).first();
- * // => { 'name': 'barney', 'age': 36 }
- *
- * // with explicit chaining
- * _(characters).chain()
- * .first()
- * .pick('age')
- * .value();
- * // => { 'age': 36 }
- */
- function wrapperChain() {
- this.__chain__ = true;
- return this;
- }
-
- /**
- * Produces the `toString` result of the wrapped value.
- *
- * @name toString
- * @memberOf _
- * @category Chaining
- * @returns {string} Returns the string result.
- * @example
- *
- * _([1, 2, 3]).toString();
- * // => '1,2,3'
- */
- function wrapperToString() {
- return String(this.__wrapped__);
- }
-
- /**
- * Extracts the wrapped value.
- *
- * @name valueOf
- * @memberOf _
- * @alias value
- * @category Chaining
- * @returns {*} Returns the wrapped value.
- * @example
- *
- * _([1, 2, 3]).valueOf();
- * // => [1, 2, 3]
- */
- function wrapperValueOf() {
- return this.__wrapped__;
- }
-
- /*--------------------------------------------------------------------------*/
-
- // add functions that return wrapped values when chaining
- lodash.after = after;
- lodash.assign = assign;
- lodash.at = at;
- lodash.bind = bind;
- lodash.bindAll = bindAll;
- lodash.bindKey = bindKey;
- lodash.chain = chain;
- lodash.compact = compact;
- lodash.compose = compose;
- lodash.constant = constant;
- lodash.countBy = countBy;
- lodash.create = create;
- lodash.createCallback = createCallback;
- lodash.curry = curry;
- lodash.debounce = debounce;
- lodash.defaults = defaults;
- lodash.defer = defer;
- lodash.delay = delay;
- lodash.difference = difference;
- lodash.filter = filter;
- lodash.flatten = flatten;
- lodash.forEach = forEach;
- lodash.forEachRight = forEachRight;
- lodash.forIn = forIn;
- lodash.forInRight = forInRight;
- lodash.forOwn = forOwn;
- lodash.forOwnRight = forOwnRight;
- lodash.functions = functions;
- lodash.groupBy = groupBy;
- lodash.indexBy = indexBy;
- lodash.initial = initial;
- lodash.intersection = intersection;
- lodash.invert = invert;
- lodash.invoke = invoke;
- lodash.keys = keys;
- lodash.map = map;
- lodash.mapValues = mapValues;
- lodash.max = max;
- lodash.memoize = memoize;
- lodash.merge = merge;
- lodash.min = min;
- lodash.omit = omit;
- lodash.once = once;
- lodash.pairs = pairs;
- lodash.partial = partial;
- lodash.partialRight = partialRight;
- lodash.pick = pick;
- lodash.pluck = pluck;
- lodash.property = property;
- lodash.pull = pull;
- lodash.range = range;
- lodash.reject = reject;
- lodash.remove = remove;
- lodash.rest = rest;
- lodash.shuffle = shuffle;
- lodash.sortBy = sortBy;
- lodash.tap = tap;
- lodash.throttle = throttle;
- lodash.times = times;
- lodash.toArray = toArray;
- lodash.transform = transform;
- lodash.union = union;
- lodash.uniq = uniq;
- lodash.values = values;
- lodash.where = where;
- lodash.without = without;
- lodash.wrap = wrap;
- lodash.xor = xor;
- lodash.zip = zip;
- lodash.zipObject = zipObject;
-
- // add aliases
- lodash.collect = map;
- lodash.drop = rest;
- lodash.each = forEach;
- lodash.eachRight = forEachRight;
- lodash.extend = assign;
- lodash.methods = functions;
- lodash.object = zipObject;
- lodash.select = filter;
- lodash.tail = rest;
- lodash.unique = uniq;
- lodash.unzip = zip;
-
- // add functions to `lodash.prototype`
- mixin(lodash);
-
- /*--------------------------------------------------------------------------*/
-
- // add functions that return unwrapped values when chaining
- lodash.clone = clone;
- lodash.cloneDeep = cloneDeep;
- lodash.contains = contains;
- lodash.escape = escape;
- lodash.every = every;
- lodash.find = find;
- lodash.findIndex = findIndex;
- lodash.findKey = findKey;
- lodash.findLast = findLast;
- lodash.findLastIndex = findLastIndex;
- lodash.findLastKey = findLastKey;
- lodash.has = has;
- lodash.identity = identity;
- lodash.indexOf = indexOf;
- lodash.isArguments = isArguments;
- lodash.isArray = isArray;
- lodash.isBoolean = isBoolean;
- lodash.isDate = isDate;
- lodash.isElement = isElement;
- lodash.isEmpty = isEmpty;
- lodash.isEqual = isEqual;
- lodash.isFinite = isFinite;
- lodash.isFunction = isFunction;
- lodash.isNaN = isNaN;
- lodash.isNull = isNull;
- lodash.isNumber = isNumber;
- lodash.isObject = isObject;
- lodash.isPlainObject = isPlainObject;
- lodash.isRegExp = isRegExp;
- lodash.isString = isString;
- lodash.isUndefined = isUndefined;
- lodash.lastIndexOf = lastIndexOf;
- lodash.mixin = mixin;
- lodash.noConflict = noConflict;
- lodash.noop = noop;
- lodash.now = now;
- lodash.parseInt = parseInt;
- lodash.random = random;
- lodash.reduce = reduce;
- lodash.reduceRight = reduceRight;
- lodash.result = result;
- lodash.runInContext = runInContext;
- lodash.size = size;
- lodash.some = some;
- lodash.sortedIndex = sortedIndex;
- lodash.template = template;
- lodash.unescape = unescape;
- lodash.uniqueId = uniqueId;
-
- // add aliases
- lodash.all = every;
- lodash.any = some;
- lodash.detect = find;
- lodash.findWhere = find;
- lodash.foldl = reduce;
- lodash.foldr = reduceRight;
- lodash.include = contains;
- lodash.inject = reduce;
-
- mixin(function() {
- var source = {}
- forOwn(lodash, function(func, methodName) {
- if (!lodash.prototype[methodName]) {
- source[methodName] = func;
- }
- });
- return source;
- }(), false);
-
- /*--------------------------------------------------------------------------*/
-
- // add functions capable of returning wrapped and unwrapped values when chaining
- lodash.first = first;
- lodash.last = last;
- lodash.sample = sample;
-
- // add aliases
- lodash.take = first;
- lodash.head = first;
-
- forOwn(lodash, function(func, methodName) {
- var callbackable = methodName !== 'sample';
- if (!lodash.prototype[methodName]) {
- lodash.prototype[methodName]= function(n, guard) {
- var chainAll = this.__chain__,
- result = func(this.__wrapped__, n, guard);
-
- return !chainAll && (n == null || (guard && !(callbackable && typeof n == 'function')))
- ? result
- : new lodashWrapper(result, chainAll);
- };
- }
- });
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * The semantic version number.
- *
- * @static
- * @memberOf _
- * @type string
- */
- lodash.VERSION = '2.4.1';
-
- // add "Chaining" functions to the wrapper
- lodash.prototype.chain = wrapperChain;
- lodash.prototype.toString = wrapperToString;
- lodash.prototype.value = wrapperValueOf;
- lodash.prototype.valueOf = wrapperValueOf;
-
- // add `Array` functions that return unwrapped values
- forEach(['join', 'pop', 'shift'], function(methodName) {
- var func = arrayRef[methodName];
- lodash.prototype[methodName] = function() {
- var chainAll = this.__chain__,
- result = func.apply(this.__wrapped__, arguments);
-
- return chainAll
- ? new lodashWrapper(result, chainAll)
- : result;
- };
- });
-
- // add `Array` functions that return the existing wrapped value
- forEach(['push', 'reverse', 'sort', 'unshift'], function(methodName) {
- var func = arrayRef[methodName];
- lodash.prototype[methodName] = function() {
- func.apply(this.__wrapped__, arguments);
- return this;
- };
- });
-
- // add `Array` functions that return new wrapped values
- forEach(['concat', 'slice', 'splice'], function(methodName) {
- var func = arrayRef[methodName];
- lodash.prototype[methodName] = function() {
- return new lodashWrapper(func.apply(this.__wrapped__, arguments), this.__chain__);
- };
- });
-
- return lodash;
- }
-
- /*--------------------------------------------------------------------------*/
-
- // expose Lo-Dash
- var _ = runInContext();
-
- // some AMD build optimizers like r.js check for condition patterns like the following:
- if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
- // Expose Lo-Dash to the global object even when an AMD loader is present in
- // case Lo-Dash is loaded with a RequireJS shim config.
- // See http://requirejs.org/docs/api.html#config-shim
- root._ = _;
-
- // define as an anonymous module so, through path mapping, it can be
- // referenced as the "underscore" module
- define(function() {
- return _;
- });
- }
- // check for `exports` after `define` in case a build optimizer adds an `exports` object
- else if (freeExports && freeModule) {
- // in Node.js or RingoJS
- if (moduleExports) {
- (freeModule.exports = _)._ = _;
- }
- // in Narwhal or Rhino -require
- else {
- freeExports._ = _;
- }
- }
- else {
- // in a browser or Rhino
- root._ = _;
- }
-}.call(this));
-
-/**
- * React (with addons) v0.12.1
- */
-!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.React=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactWithAddons
- */
-
-/**
- * This module exists purely in the open source project, and is meant as a way
- * to create a separate standalone build of React. This build has "addons", or
- * functionality we've built and think might be useful but doesn't have a good
- * place to live inside React core.
- */
-
-"use strict";
-
-var LinkedStateMixin = _dereq_("./LinkedStateMixin");
-var React = _dereq_("./React");
-var ReactComponentWithPureRenderMixin =
- _dereq_("./ReactComponentWithPureRenderMixin");
-var ReactCSSTransitionGroup = _dereq_("./ReactCSSTransitionGroup");
-var ReactTransitionGroup = _dereq_("./ReactTransitionGroup");
-var ReactUpdates = _dereq_("./ReactUpdates");
-
-var cx = _dereq_("./cx");
-var cloneWithProps = _dereq_("./cloneWithProps");
-var update = _dereq_("./update");
-
-React.addons = {
- CSSTransitionGroup: ReactCSSTransitionGroup,
- LinkedStateMixin: LinkedStateMixin,
- PureRenderMixin: ReactComponentWithPureRenderMixin,
- TransitionGroup: ReactTransitionGroup,
-
- batchedUpdates: ReactUpdates.batchedUpdates,
- classSet: cx,
- cloneWithProps: cloneWithProps,
- update: update
-};
-
-if ("production" !== "development") {
- React.addons.Perf = _dereq_("./ReactDefaultPerf");
- React.addons.TestUtils = _dereq_("./ReactTestUtils");
-}
-
-module.exports = React;
-
-},{"./LinkedStateMixin":25,"./React":31,"./ReactCSSTransitionGroup":34,"./ReactComponentWithPureRenderMixin":39,"./ReactDefaultPerf":56,"./ReactTestUtils":86,"./ReactTransitionGroup":90,"./ReactUpdates":91,"./cloneWithProps":113,"./cx":118,"./update":159}],2:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule AutoFocusMixin
- * @typechecks static-only
- */
-
-"use strict";
-
-var focusNode = _dereq_("./focusNode");
-
-var AutoFocusMixin = {
- componentDidMount: function() {
- if (this.props.autoFocus) {
- focusNode(this.getDOMNode());
- }
- }
-};
-
-module.exports = AutoFocusMixin;
-
-},{"./focusNode":125}],3:[function(_dereq_,module,exports){
-/**
- * Copyright 2013 Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule BeforeInputEventPlugin
- * @typechecks static-only
- */
-
-"use strict";
-
-var EventConstants = _dereq_("./EventConstants");
-var EventPropagators = _dereq_("./EventPropagators");
-var ExecutionEnvironment = _dereq_("./ExecutionEnvironment");
-var SyntheticInputEvent = _dereq_("./SyntheticInputEvent");
-
-var keyOf = _dereq_("./keyOf");
-
-var canUseTextInputEvent = (
- ExecutionEnvironment.canUseDOM &&
- 'TextEvent' in window &&
- !('documentMode' in document || isPresto())
-);
-
-/**
- * Opera <= 12 includes TextEvent in window, but does not fire
- * text input events. Rely on keypress instead.
- */
-function isPresto() {
- var opera = window.opera;
- return (
- typeof opera === 'object' &&
- typeof opera.version === 'function' &&
- parseInt(opera.version(), 10) <= 12
- );
-}
-
-var SPACEBAR_CODE = 32;
-var SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE);
-
-var topLevelTypes = EventConstants.topLevelTypes;
-
-// Events and their corresponding property names.
-var eventTypes = {
- beforeInput: {
- phasedRegistrationNames: {
- bubbled: keyOf({onBeforeInput: null}),
- captured: keyOf({onBeforeInputCapture: null})
- },
- dependencies: [
- topLevelTypes.topCompositionEnd,
- topLevelTypes.topKeyPress,
- topLevelTypes.topTextInput,
- topLevelTypes.topPaste
- ]
- }
-};
-
-// Track characters inserted via keypress and composition events.
-var fallbackChars = null;
-
-// Track whether we've ever handled a keypress on the space key.
-var hasSpaceKeypress = false;
-
-/**
- * Return whether a native keypress event is assumed to be a command.
- * This is required because Firefox fires `keypress` events for key commands
- * (cut, copy, select-all, etc.) even though no character is inserted.
- */
-function isKeypressCommand(nativeEvent) {
- return (
- (nativeEvent.ctrlKey || nativeEvent.altKey || nativeEvent.metaKey) &&
- // ctrlKey && altKey is equivalent to AltGr, and is not a command.
- !(nativeEvent.ctrlKey && nativeEvent.altKey)
- );
-}
-
-/**
- * Create an `onBeforeInput` event to match
- * http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#events-inputevents.
- *
- * This event plugin is based on the native `textInput` event
- * available in Chrome, Safari, Opera, and IE. This event fires after
- * `onKeyPress` and `onCompositionEnd`, but before `onInput`.
- *
- * `beforeInput` is spec'd but not implemented in any browsers, and
- * the `input` event does not provide any useful information about what has
- * actually been added, contrary to the spec. Thus, `textInput` is the best
- * available event to identify the characters that have actually been inserted
- * into the target node.
- */
-var BeforeInputEventPlugin = {
-
- eventTypes: eventTypes,
-
- /**
- * @param {string} topLevelType Record from `EventConstants`.
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
- * @param {object} nativeEvent Native browser event.
- * @return {*} An accumulation of synthetic events.
- * @see {EventPluginHub.extractEvents}
- */
- extractEvents: function(
- topLevelType,
- topLevelTarget,
- topLevelTargetID,
- nativeEvent) {
-
- var chars;
-
- if (canUseTextInputEvent) {
- switch (topLevelType) {
- case topLevelTypes.topKeyPress:
- /**
- * If native `textInput` events are available, our goal is to make
- * use of them. However, there is a special case: the spacebar key.
- * In Webkit, preventing default on a spacebar `textInput` event
- * cancels character insertion, but it *also* causes the browser
- * to fall back to its default spacebar behavior of scrolling the
- * page.
- *
- * Tracking at:
- * https://code.google.com/p/chromium/issues/detail?id=355103
- *
- * To avoid this issue, use the keypress event as if no `textInput`
- * event is available.
- */
- var which = nativeEvent.which;
- if (which !== SPACEBAR_CODE) {
- return;
- }
-
- hasSpaceKeypress = true;
- chars = SPACEBAR_CHAR;
- break;
-
- case topLevelTypes.topTextInput:
- // Record the characters to be added to the DOM.
- chars = nativeEvent.data;
-
- // If it's a spacebar character, assume that we have already handled
- // it at the keypress level and bail immediately. Android Chrome
- // doesn't give us keycodes, so we need to blacklist it.
- if (chars === SPACEBAR_CHAR && hasSpaceKeypress) {
- return;
- }
-
- // Otherwise, carry on.
- break;
-
- default:
- // For other native event types, do nothing.
- return;
- }
- } else {
- switch (topLevelType) {
- case topLevelTypes.topPaste:
- // If a paste event occurs after a keypress, throw out the input
- // chars. Paste events should not lead to BeforeInput events.
- fallbackChars = null;
- break;
- case topLevelTypes.topKeyPress:
- /**
- * As of v27, Firefox may fire keypress events even when no character
- * will be inserted. A few possibilities:
- *
- * - `which` is `0`. Arrow keys, Esc key, etc.
- *
- * - `which` is the pressed key code, but no char is available.
- * Ex: 'AltGr + d` in Polish. There is no modified character for
- * this key combination and no character is inserted into the
- * document, but FF fires the keypress for char code `100` anyway.
- * No `input` event will occur.
- *
- * - `which` is the pressed key code, but a command combination is
- * being used. Ex: `Cmd+C`. No character is inserted, and no
- * `input` event will occur.
- */
- if (nativeEvent.which && !isKeypressCommand(nativeEvent)) {
- fallbackChars = String.fromCharCode(nativeEvent.which);
- }
- break;
- case topLevelTypes.topCompositionEnd:
- fallbackChars = nativeEvent.data;
- break;
- }
-
- // If no changes have occurred to the fallback string, no relevant
- // event has fired and we're done.
- if (fallbackChars === null) {
- return;
- }
-
- chars = fallbackChars;
- }
-
- // If no characters are being inserted, no BeforeInput event should
- // be fired.
- if (!chars) {
- return;
- }
-
- var event = SyntheticInputEvent.getPooled(
- eventTypes.beforeInput,
- topLevelTargetID,
- nativeEvent
- );
-
- event.data = chars;
- fallbackChars = null;
- EventPropagators.accumulateTwoPhaseDispatches(event);
- return event;
- }
-};
-
-module.exports = BeforeInputEventPlugin;
-
-},{"./EventConstants":17,"./EventPropagators":22,"./ExecutionEnvironment":23,"./SyntheticInputEvent":101,"./keyOf":147}],4:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule CSSCore
- * @typechecks
- */
-
-var invariant = _dereq_("./invariant");
-
-/**
- * The CSSCore module specifies the API (and implements most of the methods)
- * that should be used when dealing with the display of elements (via their
- * CSS classes and visibility on screen. It is an API focused on mutating the
- * display and not reading it as no logical state should be encoded in the
- * display of elements.
- */
-
-var CSSCore = {
-
- /**
- * Adds the class passed in to the element if it doesn't already have it.
- *
- * @param {DOMElement} element the element to set the class on
- * @param {string} className the CSS className
- * @return {DOMElement} the element passed in
- */
- addClass: function(element, className) {
- ("production" !== "development" ? invariant(
- !/\s/.test(className),
- 'CSSCore.addClass takes only a single class name. "%s" contains ' +
- 'multiple classes.', className
- ) : invariant(!/\s/.test(className)));
-
- if (className) {
- if (element.classList) {
- element.classList.add(className);
- } else if (!CSSCore.hasClass(element, className)) {
- element.className = element.className + ' ' + className;
- }
- }
- return element;
- },
-
- /**
- * Removes the class passed in from the element
- *
- * @param {DOMElement} element the element to set the class on
- * @param {string} className the CSS className
- * @return {DOMElement} the element passed in
- */
- removeClass: function(element, className) {
- ("production" !== "development" ? invariant(
- !/\s/.test(className),
- 'CSSCore.removeClass takes only a single class name. "%s" contains ' +
- 'multiple classes.', className
- ) : invariant(!/\s/.test(className)));
-
- if (className) {
- if (element.classList) {
- element.classList.remove(className);
- } else if (CSSCore.hasClass(element, className)) {
- element.className = element.className
- .replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)', 'g'), '$1')
- .replace(/\s+/g, ' ') // multiple spaces to one
- .replace(/^\s*|\s*$/g, ''); // trim the ends
- }
- }
- return element;
- },
-
- /**
- * Helper to add or remove a class from an element based on a condition.
- *
- * @param {DOMElement} element the element to set the class on
- * @param {string} className the CSS className
- * @param {*} bool condition to whether to add or remove the class
- * @return {DOMElement} the element passed in
- */
- conditionClass: function(element, className, bool) {
- return (bool ? CSSCore.addClass : CSSCore.removeClass)(element, className);
- },
-
- /**
- * Tests whether the element has the class specified.
- *
- * @param {DOMNode|DOMWindow} element the element to set the class on
- * @param {string} className the CSS className
- * @return {boolean} true if the element has the class, false if not
- */
- hasClass: function(element, className) {
- ("production" !== "development" ? invariant(
- !/\s/.test(className),
- 'CSS.hasClass takes only a single class name.'
- ) : invariant(!/\s/.test(className)));
- if (element.classList) {
- return !!className && element.classList.contains(className);
- }
- return (' ' + element.className + ' ').indexOf(' ' + className + ' ') > -1;
- }
-
-};
-
-module.exports = CSSCore;
-
-},{"./invariant":140}],5:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule CSSProperty
- */
-
-"use strict";
-
-/**
- * CSS properties which accept numbers but are not in units of "px".
- */
-var isUnitlessNumber = {
- columnCount: true,
- fillOpacity: true,
- flex: true,
- flexGrow: true,
- flexShrink: true,
- fontWeight: true,
- lineClamp: true,
- lineHeight: true,
- opacity: true,
- order: true,
- orphans: true,
- widows: true,
- zIndex: true,
- zoom: true
-};
-
-/**
- * @param {string} prefix vendor-specific prefix, eg: Webkit
- * @param {string} key style name, eg: transitionDuration
- * @return {string} style name prefixed with `prefix`, properly camelCased, eg:
- * WebkitTransitionDuration
- */
-function prefixKey(prefix, key) {
- return prefix + key.charAt(0).toUpperCase() + key.substring(1);
-}
-
-/**
- * Support style names that may come passed in prefixed by adding permutations
- * of vendor prefixes.
- */
-var prefixes = ['Webkit', 'ms', 'Moz', 'O'];
-
-// Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an
-// infinite loop, because it iterates over the newly added props too.
-Object.keys(isUnitlessNumber).forEach(function(prop) {
- prefixes.forEach(function(prefix) {
- isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop];
- });
-});
-
-/**
- * Most style properties can be unset by doing .style[prop] = '' but IE8
- * doesn't like doing that with shorthand properties so for the properties that
- * IE8 breaks on, which are listed here, we instead unset each of the
- * individual properties. See http://bugs.jquery.com/ticket/12385.
- * The 4-value 'clock' properties like margin, padding, border-width seem to
- * behave without any problems. Curiously, list-style works too without any
- * special prodding.
- */
-var shorthandPropertyExpansions = {
- background: {
- backgroundImage: true,
- backgroundPosition: true,
- backgroundRepeat: true,
- backgroundColor: true
- },
- border: {
- borderWidth: true,
- borderStyle: true,
- borderColor: true
- },
- borderBottom: {
- borderBottomWidth: true,
- borderBottomStyle: true,
- borderBottomColor: true
- },
- borderLeft: {
- borderLeftWidth: true,
- borderLeftStyle: true,
- borderLeftColor: true
- },
- borderRight: {
- borderRightWidth: true,
- borderRightStyle: true,
- borderRightColor: true
- },
- borderTop: {
- borderTopWidth: true,
- borderTopStyle: true,
- borderTopColor: true
- },
- font: {
- fontStyle: true,
- fontVariant: true,
- fontWeight: true,
- fontSize: true,
- lineHeight: true,
- fontFamily: true
- }
-};
-
-var CSSProperty = {
- isUnitlessNumber: isUnitlessNumber,
- shorthandPropertyExpansions: shorthandPropertyExpansions
-};
-
-module.exports = CSSProperty;
-
-},{}],6:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule CSSPropertyOperations
- * @typechecks static-only
- */
-
-"use strict";
-
-var CSSProperty = _dereq_("./CSSProperty");
-var ExecutionEnvironment = _dereq_("./ExecutionEnvironment");
-
-var camelizeStyleName = _dereq_("./camelizeStyleName");
-var dangerousStyleValue = _dereq_("./dangerousStyleValue");
-var hyphenateStyleName = _dereq_("./hyphenateStyleName");
-var memoizeStringOnly = _dereq_("./memoizeStringOnly");
-var warning = _dereq_("./warning");
-
-var processStyleName = memoizeStringOnly(function(styleName) {
- return hyphenateStyleName(styleName);
-});
-
-var styleFloatAccessor = 'cssFloat';
-if (ExecutionEnvironment.canUseDOM) {
- // IE8 only supports accessing cssFloat (standard) as styleFloat
- if (document.documentElement.style.cssFloat === undefined) {
- styleFloatAccessor = 'styleFloat';
- }
-}
-
-if ("production" !== "development") {
- var warnedStyleNames = {};
-
- var warnHyphenatedStyleName = function(name) {
- if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) {
- return;
- }
-
- warnedStyleNames[name] = true;
- ("production" !== "development" ? warning(
- false,
- 'Unsupported style property ' + name + '. Did you mean ' +
- camelizeStyleName(name) + '?'
- ) : null);
- };
-}
-
-/**
- * Operations for dealing with CSS properties.
- */
-var CSSPropertyOperations = {
-
- /**
- * Serializes a mapping of style properties for use as inline styles:
- *
- * > createMarkupForStyles({width: '200px', height: 0})
- * "width:200px;height:0;"
- *
- * Undefined values are ignored so that declarative programming is easier.
- * The result should be HTML-escaped before insertion into the DOM.
- *
- * @param {object} styles
- * @return {?string}
- */
- createMarkupForStyles: function(styles) {
- var serialized = '';
- for (var styleName in styles) {
- if (!styles.hasOwnProperty(styleName)) {
- continue;
- }
- if ("production" !== "development") {
- if (styleName.indexOf('-') > -1) {
- warnHyphenatedStyleName(styleName);
- }
- }
- var styleValue = styles[styleName];
- if (styleValue != null) {
- serialized += processStyleName(styleName) + ':';
- serialized += dangerousStyleValue(styleName, styleValue) + ';';
- }
- }
- return serialized || null;
- },
-
- /**
- * Sets the value for multiple styles on a node. If a value is specified as
- * '' (empty string), the corresponding style property will be unset.
- *
- * @param {DOMElement} node
- * @param {object} styles
- */
- setValueForStyles: function(node, styles) {
- var style = node.style;
- for (var styleName in styles) {
- if (!styles.hasOwnProperty(styleName)) {
- continue;
- }
- if ("production" !== "development") {
- if (styleName.indexOf('-') > -1) {
- warnHyphenatedStyleName(styleName);
- }
- }
- var styleValue = dangerousStyleValue(styleName, styles[styleName]);
- if (styleName === 'float') {
- styleName = styleFloatAccessor;
- }
- if (styleValue) {
- style[styleName] = styleValue;
- } else {
- var expansion = CSSProperty.shorthandPropertyExpansions[styleName];
- if (expansion) {
- // Shorthand property that IE8 won't like unsetting, so unset each
- // component to placate it
- for (var individualStyleName in expansion) {
- style[individualStyleName] = '';
- }
- } else {
- style[styleName] = '';
- }
- }
- }
- }
-
-};
-
-module.exports = CSSPropertyOperations;
-
-},{"./CSSProperty":5,"./ExecutionEnvironment":23,"./camelizeStyleName":112,"./dangerousStyleValue":119,"./hyphenateStyleName":138,"./memoizeStringOnly":149,"./warning":160}],7:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule CallbackQueue
- */
-
-"use strict";
-
-var PooledClass = _dereq_("./PooledClass");
-
-var assign = _dereq_("./Object.assign");
-var invariant = _dereq_("./invariant");
-
-/**
- * A specialized pseudo-event module to help keep track of components waiting to
- * be notified when their DOM representations are available for use.
- *
- * This implements `PooledClass`, so you should never need to instantiate this.
- * Instead, use `CallbackQueue.getPooled()`.
- *
- * @class ReactMountReady
- * @implements PooledClass
- * @internal
- */
-function CallbackQueue() {
- this._callbacks = null;
- this._contexts = null;
-}
-
-assign(CallbackQueue.prototype, {
-
- /**
- * Enqueues a callback to be invoked when `notifyAll` is invoked.
- *
- * @param {function} callback Invoked when `notifyAll` is invoked.
- * @param {?object} context Context to call `callback` with.
- * @internal
- */
- enqueue: function(callback, context) {
- this._callbacks = this._callbacks || [];
- this._contexts = this._contexts || [];
- this._callbacks.push(callback);
- this._contexts.push(context);
- },
-
- /**
- * Invokes all enqueued callbacks and clears the queue. This is invoked after
- * the DOM representation of a component has been created or updated.
- *
- * @internal
- */
- notifyAll: function() {
- var callbacks = this._callbacks;
- var contexts = this._contexts;
- if (callbacks) {
- ("production" !== "development" ? invariant(
- callbacks.length === contexts.length,
- "Mismatched list of contexts in callback queue"
- ) : invariant(callbacks.length === contexts.length));
- this._callbacks = null;
- this._contexts = null;
- for (var i = 0, l = callbacks.length; i < l; i++) {
- callbacks[i].call(contexts[i]);
- }
- callbacks.length = 0;
- contexts.length = 0;
- }
- },
-
- /**
- * Resets the internal queue.
- *
- * @internal
- */
- reset: function() {
- this._callbacks = null;
- this._contexts = null;
- },
-
- /**
- * `PooledClass` looks for this.
- */
- destructor: function() {
- this.reset();
- }
-
-});
-
-PooledClass.addPoolingTo(CallbackQueue);
-
-module.exports = CallbackQueue;
-
-},{"./Object.assign":29,"./PooledClass":30,"./invariant":140}],8:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ChangeEventPlugin
- */
-
-"use strict";
-
-var EventConstants = _dereq_("./EventConstants");
-var EventPluginHub = _dereq_("./EventPluginHub");
-var EventPropagators = _dereq_("./EventPropagators");
-var ExecutionEnvironment = _dereq_("./ExecutionEnvironment");
-var ReactUpdates = _dereq_("./ReactUpdates");
-var SyntheticEvent = _dereq_("./SyntheticEvent");
-
-var isEventSupported = _dereq_("./isEventSupported");
-var isTextInputElement = _dereq_("./isTextInputElement");
-var keyOf = _dereq_("./keyOf");
-
-var topLevelTypes = EventConstants.topLevelTypes;
-
-var eventTypes = {
- change: {
- phasedRegistrationNames: {
- bubbled: keyOf({onChange: null}),
- captured: keyOf({onChangeCapture: null})
- },
- dependencies: [
- topLevelTypes.topBlur,
- topLevelTypes.topChange,
- topLevelTypes.topClick,
- topLevelTypes.topFocus,
- topLevelTypes.topInput,
- topLevelTypes.topKeyDown,
- topLevelTypes.topKeyUp,
- topLevelTypes.topSelectionChange
- ]
- }
-};
-
-/**
- * For IE shims
- */
-var activeElement = null;
-var activeElementID = null;
-var activeElementValue = null;
-var activeElementValueProp = null;
-
-/**
- * SECTION: handle `change` event
- */
-function shouldUseChangeEvent(elem) {
- return (
- elem.nodeName === 'SELECT' ||
- (elem.nodeName === 'INPUT' && elem.type === 'file')
- );
-}
-
-var doesChangeEventBubble = false;
-if (ExecutionEnvironment.canUseDOM) {
- // See `handleChange` comment below
- doesChangeEventBubble = isEventSupported('change') && (
- !('documentMode' in document) || document.documentMode > 8
- );
-}
-
-function manualDispatchChangeEvent(nativeEvent) {
- var event = SyntheticEvent.getPooled(
- eventTypes.change,
- activeElementID,
- nativeEvent
- );
- EventPropagators.accumulateTwoPhaseDispatches(event);
-
- // If change and propertychange bubbled, we'd just bind to it like all the
- // other events and have it go through ReactBrowserEventEmitter. Since it
- // doesn't, we manually listen for the events and so we have to enqueue and
- // process the abstract event manually.
- //
- // Batching is necessary here in order to ensure that all event handlers run
- // before the next rerender (including event handlers attached to ancestor
- // elements instead of directly on the input). Without this, controlled
- // components don't work properly in conjunction with event bubbling because
- // the component is rerendered and the value reverted before all the event
- // handlers can run. See https://github.com/facebook/react/issues/708.
- ReactUpdates.batchedUpdates(runEventInBatch, event);
-}
-
-function runEventInBatch(event) {
- EventPluginHub.enqueueEvents(event);
- EventPluginHub.processEventQueue();
-}
-
-function startWatchingForChangeEventIE8(target, targetID) {
- activeElement = target;
- activeElementID = targetID;
- activeElement.attachEvent('onchange', manualDispatchChangeEvent);
-}
-
-function stopWatchingForChangeEventIE8() {
- if (!activeElement) {
- return;
- }
- activeElement.detachEvent('onchange', manualDispatchChangeEvent);
- activeElement = null;
- activeElementID = null;
-}
-
-function getTargetIDForChangeEvent(
- topLevelType,
- topLevelTarget,
- topLevelTargetID) {
- if (topLevelType === topLevelTypes.topChange) {
- return topLevelTargetID;
- }
-}
-function handleEventsForChangeEventIE8(
- topLevelType,
- topLevelTarget,
- topLevelTargetID) {
- if (topLevelType === topLevelTypes.topFocus) {
- // stopWatching() should be a noop here but we call it just in case we
- // missed a blur event somehow.
- stopWatchingForChangeEventIE8();
- startWatchingForChangeEventIE8(topLevelTarget, topLevelTargetID);
- } else if (topLevelType === topLevelTypes.topBlur) {
- stopWatchingForChangeEventIE8();
- }
-}
-
-
-/**
- * SECTION: handle `input` event
- */
-var isInputEventSupported = false;
-if (ExecutionEnvironment.canUseDOM) {
- // IE9 claims to support the input event but fails to trigger it when
- // deleting text, so we ignore its input events
- isInputEventSupported = isEventSupported('input') && (
- !('documentMode' in document) || document.documentMode > 9
- );
-}
-
-/**
- * (For old IE.) Replacement getter/setter for the `value` property that gets
- * set on the active element.
- */
-var newValueProp = {
- get: function() {
- return activeElementValueProp.get.call(this);
- },
- set: function(val) {
- // Cast to a string so we can do equality checks.
- activeElementValue = '' + val;
- activeElementValueProp.set.call(this, val);
- }
-};
-
-/**
- * (For old IE.) Starts tracking propertychange events on the passed-in element
- * and override the value property so that we can distinguish user events from
- * value changes in JS.
- */
-function startWatchingForValueChange(target, targetID) {
- activeElement = target;
- activeElementID = targetID;
- activeElementValue = target.value;
- activeElementValueProp = Object.getOwnPropertyDescriptor(
- target.constructor.prototype,
- 'value'
- );
-
- Object.defineProperty(activeElement, 'value', newValueProp);
- activeElement.attachEvent('onpropertychange', handlePropertyChange);
-}
-
-/**
- * (For old IE.) Removes the event listeners from the currently-tracked element,
- * if any exists.
- */
-function stopWatchingForValueChange() {
- if (!activeElement) {
- return;
- }
-
- // delete restores the original property definition
- delete activeElement.value;
- activeElement.detachEvent('onpropertychange', handlePropertyChange);
-
- activeElement = null;
- activeElementID = null;
- activeElementValue = null;
- activeElementValueProp = null;
-}
-
-/**
- * (For old IE.) Handles a propertychange event, sending a `change` event if
- * the value of the active element has changed.
- */
-function handlePropertyChange(nativeEvent) {
- if (nativeEvent.propertyName !== 'value') {
- return;
- }
- var value = nativeEvent.srcElement.value;
- if (value === activeElementValue) {
- return;
- }
- activeElementValue = value;
-
- manualDispatchChangeEvent(nativeEvent);
-}
-
-/**
- * If a `change` event should be fired, returns the target's ID.
- */
-function getTargetIDForInputEvent(
- topLevelType,
- topLevelTarget,
- topLevelTargetID) {
- if (topLevelType === topLevelTypes.topInput) {
- // In modern browsers (i.e., not IE8 or IE9), the input event is exactly
- // what we want so fall through here and trigger an abstract event
- return topLevelTargetID;
- }
-}
-
-// For IE8 and IE9.
-function handleEventsForInputEventIE(
- topLevelType,
- topLevelTarget,
- topLevelTargetID) {
- if (topLevelType === topLevelTypes.topFocus) {
- // In IE8, we can capture almost all .value changes by adding a
- // propertychange handler and looking for events with propertyName
- // equal to 'value'
- // In IE9, propertychange fires for most input events but is buggy and
- // doesn't fire when text is deleted, but conveniently, selectionchange
- // appears to fire in all of the remaining cases so we catch those and
- // forward the event if the value has changed
- // In either case, we don't want to call the event handler if the value
- // is changed from JS so we redefine a setter for `.value` that updates
- // our activeElementValue variable, allowing us to ignore those changes
- //
- // stopWatching() should be a noop here but we call it just in case we
- // missed a blur event somehow.
- stopWatchingForValueChange();
- startWatchingForValueChange(topLevelTarget, topLevelTargetID);
- } else if (topLevelType === topLevelTypes.topBlur) {
- stopWatchingForValueChange();
- }
-}
-
-// For IE8 and IE9.
-function getTargetIDForInputEventIE(
- topLevelType,
- topLevelTarget,
- topLevelTargetID) {
- if (topLevelType === topLevelTypes.topSelectionChange ||
- topLevelType === topLevelTypes.topKeyUp ||
- topLevelType === topLevelTypes.topKeyDown) {
- // On the selectionchange event, the target is just document which isn't
- // helpful for us so just check activeElement instead.
- //
- // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire
- // propertychange on the first input event after setting `value` from a
- // script and fires only keydown, keypress, keyup. Catching keyup usually
- // gets it and catching keydown lets us fire an event for the first
- // keystroke if user does a key repeat (it'll be a little delayed: right
- // before the second keystroke). Other input methods (e.g., paste) seem to
- // fire selectionchange normally.
- if (activeElement && activeElement.value !== activeElementValue) {
- activeElementValue = activeElement.value;
- return activeElementID;
- }
- }
-}
-
-
-/**
- * SECTION: handle `click` event
- */
-function shouldUseClickEvent(elem) {
- // Use the `click` event to detect changes to checkbox and radio inputs.
- // This approach works across all browsers, whereas `change` does not fire
- // until `blur` in IE8.
- return (
- elem.nodeName === 'INPUT' &&
- (elem.type === 'checkbox' || elem.type === 'radio')
- );
-}
-
-function getTargetIDForClickEvent(
- topLevelType,
- topLevelTarget,
- topLevelTargetID) {
- if (topLevelType === topLevelTypes.topClick) {
- return topLevelTargetID;
- }
-}
-
-/**
- * This plugin creates an `onChange` event that normalizes change events
- * across form elements. This event fires at a time when it's possible to
- * change the element's value without seeing a flicker.
- *
- * Supported elements are:
- * - input (see `isTextInputElement`)
- * - textarea
- * - select
- */
-var ChangeEventPlugin = {
-
- eventTypes: eventTypes,
-
- /**
- * @param {string} topLevelType Record from `EventConstants`.
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
- * @param {object} nativeEvent Native browser event.
- * @return {*} An accumulation of synthetic events.
- * @see {EventPluginHub.extractEvents}
- */
- extractEvents: function(
- topLevelType,
- topLevelTarget,
- topLevelTargetID,
- nativeEvent) {
-
- var getTargetIDFunc, handleEventFunc;
- if (shouldUseChangeEvent(topLevelTarget)) {
- if (doesChangeEventBubble) {
- getTargetIDFunc = getTargetIDForChangeEvent;
- } else {
- handleEventFunc = handleEventsForChangeEventIE8;
- }
- } else if (isTextInputElement(topLevelTarget)) {
- if (isInputEventSupported) {
- getTargetIDFunc = getTargetIDForInputEvent;
- } else {
- getTargetIDFunc = getTargetIDForInputEventIE;
- handleEventFunc = handleEventsForInputEventIE;
- }
- } else if (shouldUseClickEvent(topLevelTarget)) {
- getTargetIDFunc = getTargetIDForClickEvent;
- }
-
- if (getTargetIDFunc) {
- var targetID = getTargetIDFunc(
- topLevelType,
- topLevelTarget,
- topLevelTargetID
- );
- if (targetID) {
- var event = SyntheticEvent.getPooled(
- eventTypes.change,
- targetID,
- nativeEvent
- );
- EventPropagators.accumulateTwoPhaseDispatches(event);
- return event;
- }
- }
-
- if (handleEventFunc) {
- handleEventFunc(
- topLevelType,
- topLevelTarget,
- topLevelTargetID
- );
- }
- }
-
-};
-
-module.exports = ChangeEventPlugin;
-
-},{"./EventConstants":17,"./EventPluginHub":19,"./EventPropagators":22,"./ExecutionEnvironment":23,"./ReactUpdates":91,"./SyntheticEvent":99,"./isEventSupported":141,"./isTextInputElement":143,"./keyOf":147}],9:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ClientReactRootIndex
- * @typechecks
- */
-
-"use strict";
-
-var nextReactRootIndex = 0;
-
-var ClientReactRootIndex = {
- createReactRootIndex: function() {
- return nextReactRootIndex++;
- }
-};
-
-module.exports = ClientReactRootIndex;
-
-},{}],10:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule CompositionEventPlugin
- * @typechecks static-only
- */
-
-"use strict";
-
-var EventConstants = _dereq_("./EventConstants");
-var EventPropagators = _dereq_("./EventPropagators");
-var ExecutionEnvironment = _dereq_("./ExecutionEnvironment");
-var ReactInputSelection = _dereq_("./ReactInputSelection");
-var SyntheticCompositionEvent = _dereq_("./SyntheticCompositionEvent");
-
-var getTextContentAccessor = _dereq_("./getTextContentAccessor");
-var keyOf = _dereq_("./keyOf");
-
-var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space
-var START_KEYCODE = 229;
-
-var useCompositionEvent = (
- ExecutionEnvironment.canUseDOM &&
- 'CompositionEvent' in window
-);
-
-// In IE9+, we have access to composition events, but the data supplied
-// by the native compositionend event may be incorrect. In Korean, for example,
-// the compositionend event contains only one character regardless of
-// how many characters have been composed since compositionstart.
-// We therefore use the fallback data while still using the native
-// events as triggers.
-var useFallbackData = (
- !useCompositionEvent ||
- (
- 'documentMode' in document &&
- document.documentMode > 8 &&
- document.documentMode <= 11
- )
-);
-
-var topLevelTypes = EventConstants.topLevelTypes;
-var currentComposition = null;
-
-// Events and their corresponding property names.
-var eventTypes = {
- compositionEnd: {
- phasedRegistrationNames: {
- bubbled: keyOf({onCompositionEnd: null}),
- captured: keyOf({onCompositionEndCapture: null})
- },
- dependencies: [
- topLevelTypes.topBlur,
- topLevelTypes.topCompositionEnd,
- topLevelTypes.topKeyDown,
- topLevelTypes.topKeyPress,
- topLevelTypes.topKeyUp,
- topLevelTypes.topMouseDown
- ]
- },
- compositionStart: {
- phasedRegistrationNames: {
- bubbled: keyOf({onCompositionStart: null}),
- captured: keyOf({onCompositionStartCapture: null})
- },
- dependencies: [
- topLevelTypes.topBlur,
- topLevelTypes.topCompositionStart,
- topLevelTypes.topKeyDown,
- topLevelTypes.topKeyPress,
- topLevelTypes.topKeyUp,
- topLevelTypes.topMouseDown
- ]
- },
- compositionUpdate: {
- phasedRegistrationNames: {
- bubbled: keyOf({onCompositionUpdate: null}),
- captured: keyOf({onCompositionUpdateCapture: null})
- },
- dependencies: [
- topLevelTypes.topBlur,
- topLevelTypes.topCompositionUpdate,
- topLevelTypes.topKeyDown,
- topLevelTypes.topKeyPress,
- topLevelTypes.topKeyUp,
- topLevelTypes.topMouseDown
- ]
- }
-};
-
-/**
- * Translate native top level events into event types.
- *
- * @param {string} topLevelType
- * @return {object}
- */
-function getCompositionEventType(topLevelType) {
- switch (topLevelType) {
- case topLevelTypes.topCompositionStart:
- return eventTypes.compositionStart;
- case topLevelTypes.topCompositionEnd:
- return eventTypes.compositionEnd;
- case topLevelTypes.topCompositionUpdate:
- return eventTypes.compositionUpdate;
- }
-}
-
-/**
- * Does our fallback best-guess model think this event signifies that
- * composition has begun?
- *
- * @param {string} topLevelType
- * @param {object} nativeEvent
- * @return {boolean}
- */
-function isFallbackStart(topLevelType, nativeEvent) {
- return (
- topLevelType === topLevelTypes.topKeyDown &&
- nativeEvent.keyCode === START_KEYCODE
- );
-}
-
-/**
- * Does our fallback mode think that this event is the end of composition?
- *
- * @param {string} topLevelType
- * @param {object} nativeEvent
- * @return {boolean}
- */
-function isFallbackEnd(topLevelType, nativeEvent) {
- switch (topLevelType) {
- case topLevelTypes.topKeyUp:
- // Command keys insert or clear IME input.
- return (END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1);
- case topLevelTypes.topKeyDown:
- // Expect IME keyCode on each keydown. If we get any other
- // code we must have exited earlier.
- return (nativeEvent.keyCode !== START_KEYCODE);
- case topLevelTypes.topKeyPress:
- case topLevelTypes.topMouseDown:
- case topLevelTypes.topBlur:
- // Events are not possible without cancelling IME.
- return true;
- default:
- return false;
- }
-}
-
-/**
- * Helper class stores information about selection and document state
- * so we can figure out what changed at a later date.
- *
- * @param {DOMEventTarget} root
- */
-function FallbackCompositionState(root) {
- this.root = root;
- this.startSelection = ReactInputSelection.getSelection(root);
- this.startValue = this.getText();
-}
-
-/**
- * Get current text of input.
- *
- * @return {string}
- */
-FallbackCompositionState.prototype.getText = function() {
- return this.root.value || this.root[getTextContentAccessor()];
-};
-
-/**
- * Text that has changed since the start of composition.
- *
- * @return {string}
- */
-FallbackCompositionState.prototype.getData = function() {
- var endValue = this.getText();
- var prefixLength = this.startSelection.start;
- var suffixLength = this.startValue.length - this.startSelection.end;
-
- return endValue.substr(
- prefixLength,
- endValue.length - suffixLength - prefixLength
- );
-};
-
-/**
- * This plugin creates `onCompositionStart`, `onCompositionUpdate` and
- * `onCompositionEnd` events on inputs, textareas and contentEditable
- * nodes.
- */
-var CompositionEventPlugin = {
-
- eventTypes: eventTypes,
-
- /**
- * @param {string} topLevelType Record from `EventConstants`.
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
- * @param {object} nativeEvent Native browser event.
- * @return {*} An accumulation of synthetic events.
- * @see {EventPluginHub.extractEvents}
- */
- extractEvents: function(
- topLevelType,
- topLevelTarget,
- topLevelTargetID,
- nativeEvent) {
-
- var eventType;
- var data;
-
- if (useCompositionEvent) {
- eventType = getCompositionEventType(topLevelType);
- } else if (!currentComposition) {
- if (isFallbackStart(topLevelType, nativeEvent)) {
- eventType = eventTypes.compositionStart;
- }
- } else if (isFallbackEnd(topLevelType, nativeEvent)) {
- eventType = eventTypes.compositionEnd;
- }
-
- if (useFallbackData) {
- // The current composition is stored statically and must not be
- // overwritten while composition continues.
- if (!currentComposition && eventType === eventTypes.compositionStart) {
- currentComposition = new FallbackCompositionState(topLevelTarget);
- } else if (eventType === eventTypes.compositionEnd) {
- if (currentComposition) {
- data = currentComposition.getData();
- currentComposition = null;
- }
- }
- }
-
- if (eventType) {
- var event = SyntheticCompositionEvent.getPooled(
- eventType,
- topLevelTargetID,
- nativeEvent
- );
- if (data) {
- // Inject data generated from fallback path into the synthetic event.
- // This matches the property of native CompositionEventInterface.
- event.data = data;
- }
- EventPropagators.accumulateTwoPhaseDispatches(event);
- return event;
- }
- }
-};
-
-module.exports = CompositionEventPlugin;
-
-},{"./EventConstants":17,"./EventPropagators":22,"./ExecutionEnvironment":23,"./ReactInputSelection":65,"./SyntheticCompositionEvent":97,"./getTextContentAccessor":135,"./keyOf":147}],11:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule DOMChildrenOperations
- * @typechecks static-only
- */
-
-"use strict";
-
-var Danger = _dereq_("./Danger");
-var ReactMultiChildUpdateTypes = _dereq_("./ReactMultiChildUpdateTypes");
-
-var getTextContentAccessor = _dereq_("./getTextContentAccessor");
-var invariant = _dereq_("./invariant");
-
-/**
- * The DOM property to use when setting text content.
- *
- * @type {string}
- * @private
- */
-var textContentAccessor = getTextContentAccessor();
-
-/**
- * Inserts `childNode` as a child of `parentNode` at the `index`.
- *
- * @param {DOMElement} parentNode Parent node in which to insert.
- * @param {DOMElement} childNode Child node to insert.
- * @param {number} index Index at which to insert the child.
- * @internal
- */
-function insertChildAt(parentNode, childNode, index) {
- // By exploiting arrays returning `undefined` for an undefined index, we can
- // rely exclusively on `insertBefore(node, null)` instead of also using
- // `appendChild(node)`. However, using `undefined` is not allowed by all
- // browsers so we must replace it with `null`.
- parentNode.insertBefore(
- childNode,
- parentNode.childNodes[index] || null
- );
-}
-
-var updateTextContent;
-if (textContentAccessor === 'textContent') {
- /**
- * Sets the text content of `node` to `text`.
- *
- * @param {DOMElement} node Node to change
- * @param {string} text New text content
- */
- updateTextContent = function(node, text) {
- node.textContent = text;
- };
-} else {
- /**
- * Sets the text content of `node` to `text`.
- *
- * @param {DOMElement} node Node to change
- * @param {string} text New text content
- */
- updateTextContent = function(node, text) {
- // In order to preserve newlines correctly, we can't use .innerText to set
- // the contents (see #1080), so we empty the element then append a text node
- while (node.firstChild) {
- node.removeChild(node.firstChild);
- }
- if (text) {
- var doc = node.ownerDocument || document;
- node.appendChild(doc.createTextNode(text));
- }
- };
-}
-
-/**
- * Operations for updating with DOM children.
- */
-var DOMChildrenOperations = {
-
- dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup,
-
- updateTextContent: updateTextContent,
-
- /**
- * Updates a component's children by processing a series of updates. The
- * update configurations are each expected to have a `parentNode` property.
- *
- * @param {array<object>} updates List of update configurations.
- * @param {array<string>} markupList List of markup strings.
- * @internal
- */
- processUpdates: function(updates, markupList) {
- var update;
- // Mapping from parent IDs to initial child orderings.
- var initialChildren = null;
- // List of children that will be moved or removed.
- var updatedChildren = null;
-
- for (var i = 0; update = updates[i]; i++) {
- if (update.type === ReactMultiChildUpdateTypes.MOVE_EXISTING ||
- update.type === ReactMultiChildUpdateTypes.REMOVE_NODE) {
- var updatedIndex = update.fromIndex;
- var updatedChild = update.parentNode.childNodes[updatedIndex];
- var parentID = update.parentID;
-
- ("production" !== "development" ? invariant(
- updatedChild,
- 'processUpdates(): Unable to find child %s of element. This ' +
- 'probably means the DOM was unexpectedly mutated (e.g., by the ' +
- 'browser), usually due to forgetting a <tbody> when using tables, ' +
- 'nesting tags like <form>, <p>, or <a>, or using non-SVG elements '+
- 'in an <svg> parent. Try inspecting the child nodes of the element ' +
- 'with React ID `%s`.',
- updatedIndex,
- parentID
- ) : invariant(updatedChild));
-
- initialChildren = initialChildren || {};
- initialChildren[parentID] = initialChildren[parentID] || [];
- initialChildren[parentID][updatedIndex] = updatedChild;
-
- updatedChildren = updatedChildren || [];
- updatedChildren.push(updatedChild);
- }
- }
-
- var renderedMarkup = Danger.dangerouslyRenderMarkup(markupList);
-
- // Remove updated children first so that `toIndex` is consistent.
- if (updatedChildren) {
- for (var j = 0; j < updatedChildren.length; j++) {
- updatedChildren[j].parentNode.removeChild(updatedChildren[j]);
- }
- }
-
- for (var k = 0; update = updates[k]; k++) {
- switch (update.type) {
- case ReactMultiChildUpdateTypes.INSERT_MARKUP:
- insertChildAt(
- update.parentNode,
- renderedMarkup[update.markupIndex],
- update.toIndex
- );
- break;
- case ReactMultiChildUpdateTypes.MOVE_EXISTING:
- insertChildAt(
- update.parentNode,
- initialChildren[update.parentID][update.fromIndex],
- update.toIndex
- );
- break;
- case ReactMultiChildUpdateTypes.TEXT_CONTENT:
- updateTextContent(
- update.parentNode,
- update.textContent
- );
- break;
- case ReactMultiChildUpdateTypes.REMOVE_NODE:
- // Already removed by the for-loop above.
- break;
- }
- }
- }
-
-};
-
-module.exports = DOMChildrenOperations;
-
-},{"./Danger":14,"./ReactMultiChildUpdateTypes":72,"./getTextContentAccessor":135,"./invariant":140}],12:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule DOMProperty
- * @typechecks static-only
- */
-
-/*jslint bitwise: true */
-
-"use strict";
-
-var invariant = _dereq_("./invariant");
-
-function checkMask(value, bitmask) {
- return (value & bitmask) === bitmask;
-}
-
-var DOMPropertyInjection = {
- /**
- * Mapping from normalized, camelcased property names to a configuration that
- * specifies how the associated DOM property should be accessed or rendered.
- */
- MUST_USE_ATTRIBUTE: 0x1,
- MUST_USE_PROPERTY: 0x2,
- HAS_SIDE_EFFECTS: 0x4,
- HAS_BOOLEAN_VALUE: 0x8,
- HAS_NUMERIC_VALUE: 0x10,
- HAS_POSITIVE_NUMERIC_VALUE: 0x20 | 0x10,
- HAS_OVERLOADED_BOOLEAN_VALUE: 0x40,
-
- /**
- * Inject some specialized knowledge about the DOM. This takes a config object
- * with the following properties:
- *
- * isCustomAttribute: function that given an attribute name will return true
- * if it can be inserted into the DOM verbatim. Useful for data-* or aria-*
- * attributes where it's impossible to enumerate all of the possible
- * attribute names,
- *
- * Properties: object mapping DOM property name to one of the
- * DOMPropertyInjection constants or null. If your attribute isn't in here,
- * it won't get written to the DOM.
- *
- * DOMAttributeNames: object mapping React attribute name to the DOM
- * attribute name. Attribute names not specified use the **lowercase**
- * normalized name.
- *
- * DOMPropertyNames: similar to DOMAttributeNames but for DOM properties.
- * Property names not specified use the normalized name.
- *
- * DOMMutationMethods: Properties that require special mutation methods. If
- * `value` is undefined, the mutation method should unset the property.
- *
- * @param {object} domPropertyConfig the config as described above.
- */
- injectDOMPropertyConfig: function(domPropertyConfig) {
- var Properties = domPropertyConfig.Properties || {};
- var DOMAttributeNames = domPropertyConfig.DOMAttributeNames || {};
- var DOMPropertyNames = domPropertyConfig.DOMPropertyNames || {};
- var DOMMutationMethods = domPropertyConfig.DOMMutationMethods || {};
-
- if (domPropertyConfig.isCustomAttribute) {
- DOMProperty._isCustomAttributeFunctions.push(
- domPropertyConfig.isCustomAttribute
- );
- }
-
- for (var propName in Properties) {
- ("production" !== "development" ? invariant(
- !DOMProperty.isStandardName.hasOwnProperty(propName),
- 'injectDOMPropertyConfig(...): You\'re trying to inject DOM property ' +
- '\'%s\' which has already been injected. You may be accidentally ' +
- 'injecting the same DOM property config twice, or you may be ' +
- 'injecting two configs that have conflicting property names.',
- propName
- ) : invariant(!DOMProperty.isStandardName.hasOwnProperty(propName)));
-
- DOMProperty.isStandardName[propName] = true;
-
- var lowerCased = propName.toLowerCase();
- DOMProperty.getPossibleStandardName[lowerCased] = propName;
-
- if (DOMAttributeNames.hasOwnProperty(propName)) {
- var attributeName = DOMAttributeNames[propName];
- DOMProperty.getPossibleStandardName[attributeName] = propName;
- DOMProperty.getAttributeName[propName] = attributeName;
- } else {
- DOMProperty.getAttributeName[propName] = lowerCased;
- }
-
- DOMProperty.getPropertyName[propName] =
- DOMPropertyNames.hasOwnProperty(propName) ?
- DOMPropertyNames[propName] :
- propName;
-
- if (DOMMutationMethods.hasOwnProperty(propName)) {
- DOMProperty.getMutationMethod[propName] = DOMMutationMethods[propName];
- } else {
- DOMProperty.getMutationMethod[propName] = null;
- }
-
- var propConfig = Properties[propName];
- DOMProperty.mustUseAttribute[propName] =
- checkMask(propConfig, DOMPropertyInjection.MUST_USE_ATTRIBUTE);
- DOMProperty.mustUseProperty[propName] =
- checkMask(propConfig, DOMPropertyInjection.MUST_USE_PROPERTY);
- DOMProperty.hasSideEffects[propName] =
- checkMask(propConfig, DOMPropertyInjection.HAS_SIDE_EFFECTS);
- DOMProperty.hasBooleanValue[propName] =
- checkMask(propConfig, DOMPropertyInjection.HAS_BOOLEAN_VALUE);
- DOMProperty.hasNumericValue[propName] =
- checkMask(propConfig, DOMPropertyInjection.HAS_NUMERIC_VALUE);
- DOMProperty.hasPositiveNumericValue[propName] =
- checkMask(propConfig, DOMPropertyInjection.HAS_POSITIVE_NUMERIC_VALUE);
- DOMProperty.hasOverloadedBooleanValue[propName] =
- checkMask(propConfig, DOMPropertyInjection.HAS_OVERLOADED_BOOLEAN_VALUE);
-
- ("production" !== "development" ? invariant(
- !DOMProperty.mustUseAttribute[propName] ||
- !DOMProperty.mustUseProperty[propName],
- 'DOMProperty: Cannot require using both attribute and property: %s',
- propName
- ) : invariant(!DOMProperty.mustUseAttribute[propName] ||
- !DOMProperty.mustUseProperty[propName]));
- ("production" !== "development" ? invariant(
- DOMProperty.mustUseProperty[propName] ||
- !DOMProperty.hasSideEffects[propName],
- 'DOMProperty: Properties that have side effects must use property: %s',
- propName
- ) : invariant(DOMProperty.mustUseProperty[propName] ||
- !DOMProperty.hasSideEffects[propName]));
- ("production" !== "development" ? invariant(
- !!DOMProperty.hasBooleanValue[propName] +
- !!DOMProperty.hasNumericValue[propName] +
- !!DOMProperty.hasOverloadedBooleanValue[propName] <= 1,
- 'DOMProperty: Value can be one of boolean, overloaded boolean, or ' +
- 'numeric value, but not a combination: %s',
- propName
- ) : invariant(!!DOMProperty.hasBooleanValue[propName] +
- !!DOMProperty.hasNumericValue[propName] +
- !!DOMProperty.hasOverloadedBooleanValue[propName] <= 1));
- }
- }
-};
-var defaultValueCache = {};
-
-/**
- * DOMProperty exports lookup objects that can be used like functions:
- *
- * > DOMProperty.isValid['id']
- * true
- * > DOMProperty.isValid['foobar']
- * undefined
- *
- * Although this may be confusing, it performs better in general.
- *
- * @see http://jsperf.com/key-exists
- * @see http://jsperf.com/key-missing
- */
-var DOMProperty = {
-
- ID_ATTRIBUTE_NAME: 'data-reactid',
-
- /**
- * Checks whether a property name is a standard property.
- * @type {Object}
- */
- isStandardName: {},
-
- /**
- * Mapping from lowercase property names to the properly cased version, used
- * to warn in the case of missing properties.
- * @type {Object}
- */
- getPossibleStandardName: {},
-
- /**
- * Mapping from normalized names to attribute names that differ. Attribute
- * names are used when rendering markup or with `*Attribute()`.
- * @type {Object}
- */
- getAttributeName: {},
-
- /**
- * Mapping from normalized names to properties on DOM node instances.
- * (This includes properties that mutate due to external factors.)
- * @type {Object}
- */
- getPropertyName: {},
-
- /**
- * Mapping from normalized names to mutation methods. This will only exist if
- * mutation cannot be set simply by the property or `setAttribute()`.
- * @type {Object}
- */
- getMutationMethod: {},
-
- /**
- * Whether the property must be accessed and mutated as an object property.
- * @type {Object}
- */
- mustUseAttribute: {},
-
- /**
- * Whether the property must be accessed and mutated using `*Attribute()`.
- * (This includes anything that fails `<propName> in <element>`.)
- * @type {Object}
- */
- mustUseProperty: {},
-
- /**
- * Whether or not setting a value causes side effects such as triggering
- * resources to be loaded or text selection changes. We must ensure that
- * the value is only set if it has changed.
- * @type {Object}
- */
- hasSideEffects: {},
-
- /**
- * Whether the property should be removed when set to a falsey value.
- * @type {Object}
- */
- hasBooleanValue: {},
-
- /**
- * Whether the property must be numeric or parse as a
- * numeric and should be removed when set to a falsey value.
- * @type {Object}
- */
- hasNumericValue: {},
-
- /**
- * Whether the property must be positive numeric or parse as a positive
- * numeric and should be removed when set to a falsey value.
- * @type {Object}
- */
- hasPositiveNumericValue: {},
-
- /**
- * Whether the property can be used as a flag as well as with a value. Removed
- * when strictly equal to false; present without a value when strictly equal
- * to true; present with a value otherwise.
- * @type {Object}
- */
- hasOverloadedBooleanValue: {},
-
- /**
- * All of the isCustomAttribute() functions that have been injected.
- */
- _isCustomAttributeFunctions: [],
-
- /**
- * Checks whether a property name is a custom attribute.
- * @method
- */
- isCustomAttribute: function(attributeName) {
- for (var i = 0; i < DOMProperty._isCustomAttributeFunctions.length; i++) {
- var isCustomAttributeFn = DOMProperty._isCustomAttributeFunctions[i];
- if (isCustomAttributeFn(attributeName)) {
- return true;
- }
- }
- return false;
- },
-
- /**
- * Returns the default property value for a DOM property (i.e., not an
- * attribute). Most default values are '' or false, but not all. Worse yet,
- * some (in particular, `type`) vary depending on the type of element.
- *
- * TODO: Is it better to grab all the possible properties when creating an
- * element to avoid having to create the same element twice?
- */
- getDefaultValueForProperty: function(nodeName, prop) {
- var nodeDefaults = defaultValueCache[nodeName];
- var testElement;
- if (!nodeDefaults) {
- defaultValueCache[nodeName] = nodeDefaults = {};
- }
- if (!(prop in nodeDefaults)) {
- testElement = document.createElement(nodeName);
- nodeDefaults[prop] = testElement[prop];
- }
- return nodeDefaults[prop];
- },
-
- injection: DOMPropertyInjection
-};
-
-module.exports = DOMProperty;
-
-},{"./invariant":140}],13:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule DOMPropertyOperations
- * @typechecks static-only
- */
-
-"use strict";
-
-var DOMProperty = _dereq_("./DOMProperty");
-
-var escapeTextForBrowser = _dereq_("./escapeTextForBrowser");
-var memoizeStringOnly = _dereq_("./memoizeStringOnly");
-var warning = _dereq_("./warning");
-
-function shouldIgnoreValue(name, value) {
- return value == null ||
- (DOMProperty.hasBooleanValue[name] && !value) ||
- (DOMProperty.hasNumericValue[name] && isNaN(value)) ||
- (DOMProperty.hasPositiveNumericValue[name] && (value < 1)) ||
- (DOMProperty.hasOverloadedBooleanValue[name] && value === false);
-}
-
-var processAttributeNameAndPrefix = memoizeStringOnly(function(name) {
- return escapeTextForBrowser(name) + '="';
-});
-
-if ("production" !== "development") {
- var reactProps = {
- children: true,
- dangerouslySetInnerHTML: true,
- key: true,
- ref: true
- };
- var warnedProperties = {};
-
- var warnUnknownProperty = function(name) {
- if (reactProps.hasOwnProperty(name) && reactProps[name] ||
- warnedProperties.hasOwnProperty(name) && warnedProperties[name]) {
- return;
- }
-
- warnedProperties[name] = true;
- var lowerCasedName = name.toLowerCase();
-
- // data-* attributes should be lowercase; suggest the lowercase version
- var standardName = (
- DOMProperty.isCustomAttribute(lowerCasedName) ?
- lowerCasedName :
- DOMProperty.getPossibleStandardName.hasOwnProperty(lowerCasedName) ?
- DOMProperty.getPossibleStandardName[lowerCasedName] :
- null
- );
-
- // For now, only warn when we have a suggested correction. This prevents
- // logging too much when using transferPropsTo.
- ("production" !== "development" ? warning(
- standardName == null,
- 'Unknown DOM property ' + name + '. Did you mean ' + standardName + '?'
- ) : null);
-
- };
-}
-
-/**
- * Operations for dealing with DOM properties.
- */
-var DOMPropertyOperations = {
-
- /**
- * Creates markup for the ID property.
- *
- * @param {string} id Unescaped ID.
- * @return {string} Markup string.
- */
- createMarkupForID: function(id) {
- return processAttributeNameAndPrefix(DOMProperty.ID_ATTRIBUTE_NAME) +
- escapeTextForBrowser(id) + '"';
- },
-
- /**
- * Creates markup for a property.
- *
- * @param {string} name
- * @param {*} value
- * @return {?string} Markup string, or null if the property was invalid.
- */
- createMarkupForProperty: function(name, value) {
- if (DOMProperty.isStandardName.hasOwnProperty(name) &&
- DOMProperty.isStandardName[name]) {
- if (shouldIgnoreValue(name, value)) {
- return '';
- }
- var attributeName = DOMProperty.getAttributeName[name];
- if (DOMProperty.hasBooleanValue[name] ||
- (DOMProperty.hasOverloadedBooleanValue[name] && value === true)) {
- return escapeTextForBrowser(attributeName);
- }
- return processAttributeNameAndPrefix(attributeName) +
- escapeTextForBrowser(value) + '"';
- } else if (DOMProperty.isCustomAttribute(name)) {
- if (value == null) {
- return '';
- }
- return processAttributeNameAndPrefix(name) +
- escapeTextForBrowser(value) + '"';
- } else if ("production" !== "development") {
- warnUnknownProperty(name);
- }
- return null;
- },
-
- /**
- * Sets the value for a property on a node.
- *
- * @param {DOMElement} node
- * @param {string} name
- * @param {*} value
- */
- setValueForProperty: function(node, name, value) {
- if (DOMProperty.isStandardName.hasOwnProperty(name) &&
- DOMProperty.isStandardName[name]) {
- var mutationMethod = DOMProperty.getMutationMethod[name];
- if (mutationMethod) {
- mutationMethod(node, value);
- } else if (shouldIgnoreValue(name, value)) {
- this.deleteValueForProperty(node, name);
- } else if (DOMProperty.mustUseAttribute[name]) {
- // `setAttribute` with objects becomes only `[object]` in IE8/9,
- // ('' + value) makes it output the correct toString()-value.
- node.setAttribute(DOMProperty.getAttributeName[name], '' + value);
- } else {
- var propName = DOMProperty.getPropertyName[name];
- // Must explicitly cast values for HAS_SIDE_EFFECTS-properties to the
- // property type before comparing; only `value` does and is string.
- if (!DOMProperty.hasSideEffects[name] ||
- ('' + node[propName]) !== ('' + value)) {
- // Contrary to `setAttribute`, object properties are properly
- // `toString`ed by IE8/9.
- node[propName] = value;
- }
- }
- } else if (DOMProperty.isCustomAttribute(name)) {
- if (value == null) {
- node.removeAttribute(name);
- } else {
- node.setAttribute(name, '' + value);
- }
- } else if ("production" !== "development") {
- warnUnknownProperty(name);
- }
- },
-
- /**
- * Deletes the value for a property on a node.
- *
- * @param {DOMElement} node
- * @param {string} name
- */
- deleteValueForProperty: function(node, name) {
- if (DOMProperty.isStandardName.hasOwnProperty(name) &&
- DOMProperty.isStandardName[name]) {
- var mutationMethod = DOMProperty.getMutationMethod[name];
- if (mutationMethod) {
- mutationMethod(node, undefined);
- } else if (DOMProperty.mustUseAttribute[name]) {
- node.removeAttribute(DOMProperty.getAttributeName[name]);
- } else {
- var propName = DOMProperty.getPropertyName[name];
- var defaultValue = DOMProperty.getDefaultValueForProperty(
- node.nodeName,
- propName
- );
- if (!DOMProperty.hasSideEffects[name] ||
- ('' + node[propName]) !== defaultValue) {
- node[propName] = defaultValue;
- }
- }
- } else if (DOMProperty.isCustomAttribute(name)) {
- node.removeAttribute(name);
- } else if ("production" !== "development") {
- warnUnknownProperty(name);
- }
- }
-
-};
-
-module.exports = DOMPropertyOperations;
-
-},{"./DOMProperty":12,"./escapeTextForBrowser":123,"./memoizeStringOnly":149,"./warning":160}],14:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule Danger
- * @typechecks static-only
- */
-
-/*jslint evil: true, sub: true */
-
-"use strict";
-
-var ExecutionEnvironment = _dereq_("./ExecutionEnvironment");
-
-var createNodesFromMarkup = _dereq_("./createNodesFromMarkup");
-var emptyFunction = _dereq_("./emptyFunction");
-var getMarkupWrap = _dereq_("./getMarkupWrap");
-var invariant = _dereq_("./invariant");
-
-var OPEN_TAG_NAME_EXP = /^(<[^ \/>]+)/;
-var RESULT_INDEX_ATTR = 'data-danger-index';
-
-/**
- * Extracts the `nodeName` from a string of markup.
- *
- * NOTE: Extracting the `nodeName` does not require a regular expression match
- * because we make assumptions about React-generated markup (i.e. there are no
- * spaces surrounding the opening tag and there is at least one attribute).
- *
- * @param {string} markup String of markup.
- * @return {string} Node name of the supplied markup.
- * @see http://jsperf.com/extract-nodename
- */
-function getNodeName(markup) {
- return markup.substring(1, markup.indexOf(' '));
-}
-
-var Danger = {
-
- /**
- * Renders markup into an array of nodes. The markup is expected to render
- * into a list of root nodes. Also, the length of `resultList` and
- * `markupList` should be the same.
- *
- * @param {array<string>} markupList List of markup strings to render.
- * @return {array<DOMElement>} List of rendered nodes.
- * @internal
- */
- dangerouslyRenderMarkup: function(markupList) {
- ("production" !== "development" ? invariant(
- ExecutionEnvironment.canUseDOM,
- 'dangerouslyRenderMarkup(...): Cannot render markup in a worker ' +
- 'thread. Make sure `window` and `document` are available globally ' +
- 'before requiring React when unit testing or use ' +
- 'React.renderToString for server rendering.'
- ) : invariant(ExecutionEnvironment.canUseDOM));
- var nodeName;
- var markupByNodeName = {};
- // Group markup by `nodeName` if a wrap is necessary, else by '*'.
- for (var i = 0; i < markupList.length; i++) {
- ("production" !== "development" ? invariant(
- markupList[i],
- 'dangerouslyRenderMarkup(...): Missing markup.'
- ) : invariant(markupList[i]));
- nodeName = getNodeName(markupList[i]);
- nodeName = getMarkupWrap(nodeName) ? nodeName : '*';
- markupByNodeName[nodeName] = markupByNodeName[nodeName] || [];
- markupByNodeName[nodeName][i] = markupList[i];
- }
- var resultList = [];
- var resultListAssignmentCount = 0;
- for (nodeName in markupByNodeName) {
- if (!markupByNodeName.hasOwnProperty(nodeName)) {
- continue;
- }
- var markupListByNodeName = markupByNodeName[nodeName];
-
- // This for-in loop skips the holes of the sparse array. The order of
- // iteration should follow the order of assignment, which happens to match
- // numerical index order, but we don't rely on that.
- for (var resultIndex in markupListByNodeName) {
- if (markupListByNodeName.hasOwnProperty(resultIndex)) {
- var markup = markupListByNodeName[resultIndex];
-
- // Push the requested markup with an additional RESULT_INDEX_ATTR
- // attribute. If the markup does not start with a < character, it
- // will be discarded below (with an appropriate console.error).
- markupListByNodeName[resultIndex] = markup.replace(
- OPEN_TAG_NAME_EXP,
- // This index will be parsed back out below.
- '$1 ' + RESULT_INDEX_ATTR + '="' + resultIndex + '" '
- );
- }
- }
-
- // Render each group of markup with similar wrapping `nodeName`.
- var renderNodes = createNodesFromMarkup(
- markupListByNodeName.join(''),
- emptyFunction // Do nothing special with <script> tags.
- );
-
- for (i = 0; i < renderNodes.length; ++i) {
- var renderNode = renderNodes[i];
- if (renderNode.hasAttribute &&
- renderNode.hasAttribute(RESULT_INDEX_ATTR)) {
-
- resultIndex = +renderNode.getAttribute(RESULT_INDEX_ATTR);
- renderNode.removeAttribute(RESULT_INDEX_ATTR);
-
- ("production" !== "development" ? invariant(
- !resultList.hasOwnProperty(resultIndex),
- 'Danger: Assigning to an already-occupied result index.'
- ) : invariant(!resultList.hasOwnProperty(resultIndex)));
-
- resultList[resultIndex] = renderNode;
-
- // This should match resultList.length and markupList.length when
- // we're done.
- resultListAssignmentCount += 1;
-
- } else if ("production" !== "development") {
- console.error(
- "Danger: Discarding unexpected node:",
- renderNode
- );
- }
- }
- }
-
- // Although resultList was populated out of order, it should now be a dense
- // array.
- ("production" !== "development" ? invariant(
- resultListAssignmentCount === resultList.length,
- 'Danger: Did not assign to every index of resultList.'
- ) : invariant(resultListAssignmentCount === resultList.length));
-
- ("production" !== "development" ? invariant(
- resultList.length === markupList.length,
- 'Danger: Expected markup to render %s nodes, but rendered %s.',
- markupList.length,
- resultList.length
- ) : invariant(resultList.length === markupList.length));
-
- return resultList;
- },
-
- /**
- * Replaces a node with a string of markup at its current position within its
- * parent. The markup must render into a single root node.
- *
- * @param {DOMElement} oldChild Child node to replace.
- * @param {string} markup Markup to render in place of the child node.
- * @internal
- */
- dangerouslyReplaceNodeWithMarkup: function(oldChild, markup) {
- ("production" !== "development" ? invariant(
- ExecutionEnvironment.canUseDOM,
- 'dangerouslyReplaceNodeWithMarkup(...): Cannot render markup in a ' +
- 'worker thread. Make sure `window` and `document` are available ' +
- 'globally before requiring React when unit testing or use ' +
- 'React.renderToString for server rendering.'
- ) : invariant(ExecutionEnvironment.canUseDOM));
- ("production" !== "development" ? invariant(markup, 'dangerouslyReplaceNodeWithMarkup(...): Missing markup.') : invariant(markup));
- ("production" !== "development" ? invariant(
- oldChild.tagName.toLowerCase() !== 'html',
- 'dangerouslyReplaceNodeWithMarkup(...): Cannot replace markup of the ' +
- '<html> node. This is because browser quirks make this unreliable ' +
- 'and/or slow. If you want to render to the root you must use ' +
- 'server rendering. See renderComponentToString().'
- ) : invariant(oldChild.tagName.toLowerCase() !== 'html'));
-
- var newChild = createNodesFromMarkup(markup, emptyFunction)[0];
- oldChild.parentNode.replaceChild(newChild, oldChild);
- }
-
-};
-
-module.exports = Danger;
-
-},{"./ExecutionEnvironment":23,"./createNodesFromMarkup":117,"./emptyFunction":121,"./getMarkupWrap":132,"./invariant":140}],15:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule DefaultEventPluginOrder
- */
-
-"use strict";
-
- var keyOf = _dereq_("./keyOf");
-
-/**
- * Module that is injectable into `EventPluginHub`, that specifies a
- * deterministic ordering of `EventPlugin`s. A convenient way to reason about
- * plugins, without having to package every one of them. This is better than
- * having plugins be ordered in the same order that they are injected because
- * that ordering would be influenced by the packaging order.
- * `ResponderEventPlugin` must occur before `SimpleEventPlugin` so that
- * preventing default on events is convenient in `SimpleEventPlugin` handlers.
- */
-var DefaultEventPluginOrder = [
- keyOf({ResponderEventPlugin: null}),
- keyOf({SimpleEventPlugin: null}),
- keyOf({TapEventPlugin: null}),
- keyOf({EnterLeaveEventPlugin: null}),
- keyOf({ChangeEventPlugin: null}),
- keyOf({SelectEventPlugin: null}),
- keyOf({CompositionEventPlugin: null}),
- keyOf({BeforeInputEventPlugin: null}),
- keyOf({AnalyticsEventPlugin: null}),
- keyOf({MobileSafariClickEventPlugin: null})
-];
-
-module.exports = DefaultEventPluginOrder;
-
-},{"./keyOf":147}],16:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule EnterLeaveEventPlugin
- * @typechecks static-only
- */
-
-"use strict";
-
-var EventConstants = _dereq_("./EventConstants");
-var EventPropagators = _dereq_("./EventPropagators");
-var SyntheticMouseEvent = _dereq_("./SyntheticMouseEvent");
-
-var ReactMount = _dereq_("./ReactMount");
-var keyOf = _dereq_("./keyOf");
-
-var topLevelTypes = EventConstants.topLevelTypes;
-var getFirstReactDOM = ReactMount.getFirstReactDOM;
-
-var eventTypes = {
- mouseEnter: {
- registrationName: keyOf({onMouseEnter: null}),
- dependencies: [
- topLevelTypes.topMouseOut,
- topLevelTypes.topMouseOver
- ]
- },
- mouseLeave: {
- registrationName: keyOf({onMouseLeave: null}),
- dependencies: [
- topLevelTypes.topMouseOut,
- topLevelTypes.topMouseOver
- ]
- }
-};
-
-var extractedEvents = [null, null];
-
-var EnterLeaveEventPlugin = {
-
- eventTypes: eventTypes,
-
- /**
- * For almost every interaction we care about, there will be both a top-level
- * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that
- * we do not extract duplicate events. However, moving the mouse into the
- * browser from outside will not fire a `mouseout` event. In this case, we use
- * the `mouseover` top-level event.
- *
- * @param {string} topLevelType Record from `EventConstants`.
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
- * @param {object} nativeEvent Native browser event.
- * @return {*} An accumulation of synthetic events.
- * @see {EventPluginHub.extractEvents}
- */
- extractEvents: function(
- topLevelType,
- topLevelTarget,
- topLevelTargetID,
- nativeEvent) {
- if (topLevelType === topLevelTypes.topMouseOver &&
- (nativeEvent.relatedTarget || nativeEvent.fromElement)) {
- return null;
- }
- if (topLevelType !== topLevelTypes.topMouseOut &&
- topLevelType !== topLevelTypes.topMouseOver) {
- // Must not be a mouse in or mouse out - ignoring.
- return null;
- }
-
- var win;
- if (topLevelTarget.window === topLevelTarget) {
- // `topLevelTarget` is probably a window object.
- win = topLevelTarget;
- } else {
- // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.
- var doc = topLevelTarget.ownerDocument;
- if (doc) {
- win = doc.defaultView || doc.parentWindow;
- } else {
- win = window;
- }
- }
-
- var from, to;
- if (topLevelType === topLevelTypes.topMouseOut) {
- from = topLevelTarget;
- to =
- getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement) ||
- win;
- } else {
- from = win;
- to = topLevelTarget;
- }
-
- if (from === to) {
- // Nothing pertains to our managed components.
- return null;
- }
-
- var fromID = from ? ReactMount.getID(from) : '';
- var toID = to ? ReactMount.getID(to) : '';
-
- var leave = SyntheticMouseEvent.getPooled(
- eventTypes.mouseLeave,
- fromID,
- nativeEvent
- );
- leave.type = 'mouseleave';
- leave.target = from;
- leave.relatedTarget = to;
-
- var enter = SyntheticMouseEvent.getPooled(
- eventTypes.mouseEnter,
- toID,
- nativeEvent
- );
- enter.type = 'mouseenter';
- enter.target = to;
- enter.relatedTarget = from;
-
- EventPropagators.accumulateEnterLeaveDispatches(leave, enter, fromID, toID);
-
- extractedEvents[0] = leave;
- extractedEvents[1] = enter;
-
- return extractedEvents;
- }
-
-};
-
-module.exports = EnterLeaveEventPlugin;
-
-},{"./EventConstants":17,"./EventPropagators":22,"./ReactMount":70,"./SyntheticMouseEvent":103,"./keyOf":147}],17:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule EventConstants
- */
-
-"use strict";
-
-var keyMirror = _dereq_("./keyMirror");
-
-var PropagationPhases = keyMirror({bubbled: null, captured: null});
-
-/**
- * Types of raw signals from the browser caught at the top level.
- */
-var topLevelTypes = keyMirror({
- topBlur: null,
- topChange: null,
- topClick: null,
- topCompositionEnd: null,
- topCompositionStart: null,
- topCompositionUpdate: null,
- topContextMenu: null,
- topCopy: null,
- topCut: null,
- topDoubleClick: null,
- topDrag: null,
- topDragEnd: null,
- topDragEnter: null,
- topDragExit: null,
- topDragLeave: null,
- topDragOver: null,
- topDragStart: null,
- topDrop: null,
- topError: null,
- topFocus: null,
- topInput: null,
- topKeyDown: null,
- topKeyPress: null,
- topKeyUp: null,
- topLoad: null,
- topMouseDown: null,
- topMouseMove: null,
- topMouseOut: null,
- topMouseOver: null,
- topMouseUp: null,
- topPaste: null,
- topReset: null,
- topScroll: null,
- topSelectionChange: null,
- topSubmit: null,
- topTextInput: null,
- topTouchCancel: null,
- topTouchEnd: null,
- topTouchMove: null,
- topTouchStart: null,
- topWheel: null
-});
-
-var EventConstants = {
- topLevelTypes: topLevelTypes,
- PropagationPhases: PropagationPhases
-};
-
-module.exports = EventConstants;
-
-},{"./keyMirror":146}],18:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014 Facebook, 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.
- *
- * @providesModule EventListener
- * @typechecks
- */
-
-var emptyFunction = _dereq_("./emptyFunction");
-
-/**
- * Upstream version of event listener. Does not take into account specific
- * nature of platform.
- */
-var EventListener = {
- /**
- * Listen to DOM events during the bubble phase.
- *
- * @param {DOMEventTarget} target DOM element to register listener on.
- * @param {string} eventType Event type, e.g. 'click' or 'mouseover'.
- * @param {function} callback Callback function.
- * @return {object} Object with a `remove` method.
- */
- listen: function(target, eventType, callback) {
- if (target.addEventListener) {
- target.addEventListener(eventType, callback, false);
- return {
- remove: function() {
- target.removeEventListener(eventType, callback, false);
- }
- };
- } else if (target.attachEvent) {
- target.attachEvent('on' + eventType, callback);
- return {
- remove: function() {
- target.detachEvent('on' + eventType, callback);
- }
- };
- }
- },
-
- /**
- * Listen to DOM events during the capture phase.
- *
- * @param {DOMEventTarget} target DOM element to register listener on.
- * @param {string} eventType Event type, e.g. 'click' or 'mouseover'.
- * @param {function} callback Callback function.
- * @return {object} Object with a `remove` method.
- */
- capture: function(target, eventType, callback) {
- if (!target.addEventListener) {
- if ("production" !== "development") {
- console.error(
- 'Attempted to listen to events during the capture phase on a ' +
- 'browser that does not support the capture phase. Your application ' +
- 'will not receive some events.'
- );
- }
- return {
- remove: emptyFunction
- };
- } else {
- target.addEventListener(eventType, callback, true);
- return {
- remove: function() {
- target.removeEventListener(eventType, callback, true);
- }
- };
- }
- },
-
- registerDefault: function() {}
-};
-
-module.exports = EventListener;
-
-},{"./emptyFunction":121}],19:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule EventPluginHub
- */
-
-"use strict";
-
-var EventPluginRegistry = _dereq_("./EventPluginRegistry");
-var EventPluginUtils = _dereq_("./EventPluginUtils");
-
-var accumulateInto = _dereq_("./accumulateInto");
-var forEachAccumulated = _dereq_("./forEachAccumulated");
-var invariant = _dereq_("./invariant");
-
-/**
- * Internal store for event listeners
- */
-var listenerBank = {};
-
-/**
- * Internal queue of events that have accumulated their dispatches and are
- * waiting to have their dispatches executed.
- */
-var eventQueue = null;
-
-/**
- * Dispatches an event and releases it back into the pool, unless persistent.
- *
- * @param {?object} event Synthetic event to be dispatched.
- * @private
- */
-var executeDispatchesAndRelease = function(event) {
- if (event) {
- var executeDispatch = EventPluginUtils.executeDispatch;
- // Plugins can provide custom behavior when dispatching events.
- var PluginModule = EventPluginRegistry.getPluginModuleForEvent(event);
- if (PluginModule && PluginModule.executeDispatch) {
- executeDispatch = PluginModule.executeDispatch;
- }
- EventPluginUtils.executeDispatchesInOrder(event, executeDispatch);
-
- if (!event.isPersistent()) {
- event.constructor.release(event);
- }
- }
-};
-
-/**
- * - `InstanceHandle`: [required] Module that performs logical traversals of DOM
- * hierarchy given ids of the logical DOM elements involved.
- */
-var InstanceHandle = null;
-
-function validateInstanceHandle() {
- var invalid = !InstanceHandle||
- !InstanceHandle.traverseTwoPhase ||
- !InstanceHandle.traverseEnterLeave;
- if (invalid) {
- throw new Error('InstanceHandle not injected before use!');
- }
-}
-
-/**
- * This is a unified interface for event plugins to be installed and configured.
- *
- * Event plugins can implement the following properties:
- *
- * `extractEvents` {function(string, DOMEventTarget, string, object): *}
- * Required. When a top-level event is fired, this method is expected to
- * extract synthetic events that will in turn be queued and dispatched.
- *
- * `eventTypes` {object}
- * Optional, plugins that fire events must publish a mapping of registration
- * names that are used to register listeners. Values of this mapping must
- * be objects that contain `registrationName` or `phasedRegistrationNames`.
- *
- * `executeDispatch` {function(object, function, string)}
- * Optional, allows plugins to override how an event gets dispatched. By
- * default, the listener is simply invoked.
- *
- * Each plugin that is injected into `EventsPluginHub` is immediately operable.
- *
- * @public
- */
-var EventPluginHub = {
-
- /**
- * Methods for injecting dependencies.
- */
- injection: {
-
- /**
- * @param {object} InjectedMount
- * @public
- */
- injectMount: EventPluginUtils.injection.injectMount,
-
- /**
- * @param {object} InjectedInstanceHandle
- * @public
- */
- injectInstanceHandle: function(InjectedInstanceHandle) {
- InstanceHandle = InjectedInstanceHandle;
- if ("production" !== "development") {
- validateInstanceHandle();
- }
- },
-
- getInstanceHandle: function() {
- if ("production" !== "development") {
- validateInstanceHandle();
- }
- return InstanceHandle;
- },
-
- /**
- * @param {array} InjectedEventPluginOrder
- * @public
- */
- injectEventPluginOrder: EventPluginRegistry.injectEventPluginOrder,
-
- /**
- * @param {object} injectedNamesToPlugins Map from names to plugin modules.
- */
- injectEventPluginsByName: EventPluginRegistry.injectEventPluginsByName
-
- },
-
- eventNameDispatchConfigs: EventPluginRegistry.eventNameDispatchConfigs,
-
- registrationNameModules: EventPluginRegistry.registrationNameModules,
-
- /**
- * Stores `listener` at `listenerBank[registrationName][id]`. Is idempotent.
- *
- * @param {string} id ID of the DOM element.
- * @param {string} registrationName Name of listener (e.g. `onClick`).
- * @param {?function} listener The callback to store.
- */
- putListener: function(id, registrationName, listener) {
- ("production" !== "development" ? invariant(
- !listener || typeof listener === 'function',
- 'Expected %s listener to be a function, instead got type %s',
- registrationName, typeof listener
- ) : invariant(!listener || typeof listener === 'function'));
-
- var bankForRegistrationName =
- listenerBank[registrationName] || (listenerBank[registrationName] = {});
- bankForRegistrationName[id] = listener;
- },
-
- /**
- * @param {string} id ID of the DOM element.
- * @param {string} registrationName Name of listener (e.g. `onClick`).
- * @return {?function} The stored callback.
- */
- getListener: function(id, registrationName) {
- var bankForRegistrationName = listenerBank[registrationName];
- return bankForRegistrationName && bankForRegistrationName[id];
- },
-
- /**
- * Deletes a listener from the registration bank.
- *
- * @param {string} id ID of the DOM element.
- * @param {string} registrationName Name of listener (e.g. `onClick`).
- */
- deleteListener: function(id, registrationName) {
- var bankForRegistrationName = listenerBank[registrationName];
- if (bankForRegistrationName) {
- delete bankForRegistrationName[id];
- }
- },
-
- /**
- * Deletes all listeners for the DOM element with the supplied ID.
- *
- * @param {string} id ID of the DOM element.
- */
- deleteAllListeners: function(id) {
- for (var registrationName in listenerBank) {
- delete listenerBank[registrationName][id];
- }
- },
-
- /**
- * Allows registered plugins an opportunity to extract events from top-level
- * native browser events.
- *
- * @param {string} topLevelType Record from `EventConstants`.
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
- * @param {object} nativeEvent Native browser event.
- * @return {*} An accumulation of synthetic events.
- * @internal
- */
- extractEvents: function(
- topLevelType,
- topLevelTarget,
- topLevelTargetID,
- nativeEvent) {
- var events;
- var plugins = EventPluginRegistry.plugins;
- for (var i = 0, l = plugins.length; i < l; i++) {
- // Not every plugin in the ordering may be loaded at runtime.
- var possiblePlugin = plugins[i];
- if (possiblePlugin) {
- var extractedEvents = possiblePlugin.extractEvents(
- topLevelType,
- topLevelTarget,
- topLevelTargetID,
- nativeEvent
- );
- if (extractedEvents) {
- events = accumulateInto(events, extractedEvents);
- }
- }
- }
- return events;
- },
-
- /**
- * Enqueues a synthetic event that should be dispatched when
- * `processEventQueue` is invoked.
- *
- * @param {*} events An accumulation of synthetic events.
- * @internal
- */
- enqueueEvents: function(events) {
- if (events) {
- eventQueue = accumulateInto(eventQueue, events);
- }
- },
-
- /**
- * Dispatches all synthetic events on the event queue.
- *
- * @internal
- */
- processEventQueue: function() {
- // Set `eventQueue` to null before processing it so that we can tell if more
- // events get enqueued while processing.
- var processingEventQueue = eventQueue;
- eventQueue = null;
- forEachAccumulated(processingEventQueue, executeDispatchesAndRelease);
- ("production" !== "development" ? invariant(
- !eventQueue,
- 'processEventQueue(): Additional events were enqueued while processing ' +
- 'an event queue. Support for this has not yet been implemented.'
- ) : invariant(!eventQueue));
- },
-
- /**
- * These are needed for tests only. Do not use!
- */
- __purge: function() {
- listenerBank = {};
- },
-
- __getListenerBank: function() {
- return listenerBank;
- }
-
-};
-
-module.exports = EventPluginHub;
-
-},{"./EventPluginRegistry":20,"./EventPluginUtils":21,"./accumulateInto":109,"./forEachAccumulated":126,"./invariant":140}],20:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule EventPluginRegistry
- * @typechecks static-only
- */
-
-"use strict";
-
-var invariant = _dereq_("./invariant");
-
-/**
- * Injectable ordering of event plugins.
- */
-var EventPluginOrder = null;
-
-/**
- * Injectable mapping from names to event plugin modules.
- */
-var namesToPlugins = {};
-
-/**
- * Recomputes the plugin list using the injected plugins and plugin ordering.
- *
- * @private
- */
-function recomputePluginOrdering() {
- if (!EventPluginOrder) {
- // Wait until an `EventPluginOrder` is injected.
- return;
- }
- for (var pluginName in namesToPlugins) {
- var PluginModule = namesToPlugins[pluginName];
- var pluginIndex = EventPluginOrder.indexOf(pluginName);
- ("production" !== "development" ? invariant(
- pluginIndex > -1,
- 'EventPluginRegistry: Cannot inject event plugins that do not exist in ' +
- 'the plugin ordering, `%s`.',
- pluginName
- ) : invariant(pluginIndex > -1));
- if (EventPluginRegistry.plugins[pluginIndex]) {
- continue;
- }
- ("production" !== "development" ? invariant(
- PluginModule.extractEvents,
- 'EventPluginRegistry: Event plugins must implement an `extractEvents` ' +
- 'method, but `%s` does not.',
- pluginName
- ) : invariant(PluginModule.extractEvents));
- EventPluginRegistry.plugins[pluginIndex] = PluginModule;
- var publishedEvents = PluginModule.eventTypes;
- for (var eventName in publishedEvents) {
- ("production" !== "development" ? invariant(
- publishEventForPlugin(
- publishedEvents[eventName],
- PluginModule,
- eventName
- ),
- 'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.',
- eventName,
- pluginName
- ) : invariant(publishEventForPlugin(
- publishedEvents[eventName],
- PluginModule,
- eventName
- )));
- }
- }
-}
-
-/**
- * Publishes an event so that it can be dispatched by the supplied plugin.
- *
- * @param {object} dispatchConfig Dispatch configuration for the event.
- * @param {object} PluginModule Plugin publishing the event.
- * @return {boolean} True if the event was successfully published.
- * @private
- */
-function publishEventForPlugin(dispatchConfig, PluginModule, eventName) {
- ("production" !== "development" ? invariant(
- !EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName),
- 'EventPluginHub: More than one plugin attempted to publish the same ' +
- 'event name, `%s`.',
- eventName
- ) : invariant(!EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName)));
- EventPluginRegistry.eventNameDispatchConfigs[eventName] = dispatchConfig;
-
- var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames;
- if (phasedRegistrationNames) {
- for (var phaseName in phasedRegistrationNames) {
- if (phasedRegistrationNames.hasOwnProperty(phaseName)) {
- var phasedRegistrationName = phasedRegistrationNames[phaseName];
- publishRegistrationName(
- phasedRegistrationName,
- PluginModule,
- eventName
- );
- }
- }
- return true;
- } else if (dispatchConfig.registrationName) {
- publishRegistrationName(
- dispatchConfig.registrationName,
- PluginModule,
- eventName
- );
- return true;
- }
- return false;
-}
-
-/**
- * Publishes a registration name that is used to identify dispatched events and
- * can be used with `EventPluginHub.putListener` to register listeners.
- *
- * @param {string} registrationName Registration name to add.
- * @param {object} PluginModule Plugin publishing the event.
- * @private
- */
-function publishRegistrationName(registrationName, PluginModule, eventName) {
- ("production" !== "development" ? invariant(
- !EventPluginRegistry.registrationNameModules[registrationName],
- 'EventPluginHub: More than one plugin attempted to publish the same ' +
- 'registration name, `%s`.',
- registrationName
- ) : invariant(!EventPluginRegistry.registrationNameModules[registrationName]));
- EventPluginRegistry.registrationNameModules[registrationName] = PluginModule;
- EventPluginRegistry.registrationNameDependencies[registrationName] =
- PluginModule.eventTypes[eventName].dependencies;
-}
-
-/**
- * Registers plugins so that they can extract and dispatch events.
- *
- * @see {EventPluginHub}
- */
-var EventPluginRegistry = {
-
- /**
- * Ordered list of injected plugins.
- */
- plugins: [],
-
- /**
- * Mapping from event name to dispatch config
- */
- eventNameDispatchConfigs: {},
-
- /**
- * Mapping from registration name to plugin module
- */
- registrationNameModules: {},
-
- /**
- * Mapping from registration name to event name
- */
- registrationNameDependencies: {},
-
- /**
- * Injects an ordering of plugins (by plugin name). This allows the ordering
- * to be decoupled from injection of the actual plugins so that ordering is
- * always deterministic regardless of packaging, on-the-fly injection, etc.
- *
- * @param {array} InjectedEventPluginOrder
- * @internal
- * @see {EventPluginHub.injection.injectEventPluginOrder}
- */
- injectEventPluginOrder: function(InjectedEventPluginOrder) {
- ("production" !== "development" ? invariant(
- !EventPluginOrder,
- 'EventPluginRegistry: Cannot inject event plugin ordering more than ' +
- 'once. You are likely trying to load more than one copy of React.'
- ) : invariant(!EventPluginOrder));
- // Clone the ordering so it cannot be dynamically mutated.
- EventPluginOrder = Array.prototype.slice.call(InjectedEventPluginOrder);
- recomputePluginOrdering();
- },
-
- /**
- * Injects plugins to be used by `EventPluginHub`. The plugin names must be
- * in the ordering injected by `injectEventPluginOrder`.
- *
- * Plugins can be injected as part of page initialization or on-the-fly.
- *
- * @param {object} injectedNamesToPlugins Map from names to plugin modules.
- * @internal
- * @see {EventPluginHub.injection.injectEventPluginsByName}
- */
- injectEventPluginsByName: function(injectedNamesToPlugins) {
- var isOrderingDirty = false;
- for (var pluginName in injectedNamesToPlugins) {
- if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) {
- continue;
- }
- var PluginModule = injectedNamesToPlugins[pluginName];
- if (!namesToPlugins.hasOwnProperty(pluginName) ||
- namesToPlugins[pluginName] !== PluginModule) {
- ("production" !== "development" ? invariant(
- !namesToPlugins[pluginName],
- 'EventPluginRegistry: Cannot inject two different event plugins ' +
- 'using the same name, `%s`.',
- pluginName
- ) : invariant(!namesToPlugins[pluginName]));
- namesToPlugins[pluginName] = PluginModule;
- isOrderingDirty = true;
- }
- }
- if (isOrderingDirty) {
- recomputePluginOrdering();
- }
- },
-
- /**
- * Looks up the plugin for the supplied event.
- *
- * @param {object} event A synthetic event.
- * @return {?object} The plugin that created the supplied event.
- * @internal
- */
- getPluginModuleForEvent: function(event) {
- var dispatchConfig = event.dispatchConfig;
- if (dispatchConfig.registrationName) {
- return EventPluginRegistry.registrationNameModules[
- dispatchConfig.registrationName
- ] || null;
- }
- for (var phase in dispatchConfig.phasedRegistrationNames) {
- if (!dispatchConfig.phasedRegistrationNames.hasOwnProperty(phase)) {
- continue;
- }
- var PluginModule = EventPluginRegistry.registrationNameModules[
- dispatchConfig.phasedRegistrationNames[phase]
- ];
- if (PluginModule) {
- return PluginModule;
- }
- }
- return null;
- },
-
- /**
- * Exposed for unit testing.
- * @private
- */
- _resetEventPlugins: function() {
- EventPluginOrder = null;
- for (var pluginName in namesToPlugins) {
- if (namesToPlugins.hasOwnProperty(pluginName)) {
- delete namesToPlugins[pluginName];
- }
- }
- EventPluginRegistry.plugins.length = 0;
-
- var eventNameDispatchConfigs = EventPluginRegistry.eventNameDispatchConfigs;
- for (var eventName in eventNameDispatchConfigs) {
- if (eventNameDispatchConfigs.hasOwnProperty(eventName)) {
- delete eventNameDispatchConfigs[eventName];
- }
- }
-
- var registrationNameModules = EventPluginRegistry.registrationNameModules;
- for (var registrationName in registrationNameModules) {
- if (registrationNameModules.hasOwnProperty(registrationName)) {
- delete registrationNameModules[registrationName];
- }
- }
- }
-
-};
-
-module.exports = EventPluginRegistry;
-
-},{"./invariant":140}],21:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule EventPluginUtils
- */
-
-"use strict";
-
-var EventConstants = _dereq_("./EventConstants");
-
-var invariant = _dereq_("./invariant");
-
-/**
- * Injected dependencies:
- */
-
-/**
- * - `Mount`: [required] Module that can convert between React dom IDs and
- * actual node references.
- */
-var injection = {
- Mount: null,
- injectMount: function(InjectedMount) {
- injection.Mount = InjectedMount;
- if ("production" !== "development") {
- ("production" !== "development" ? invariant(
- InjectedMount && InjectedMount.getNode,
- 'EventPluginUtils.injection.injectMount(...): Injected Mount module ' +
- 'is missing getNode.'
- ) : invariant(InjectedMount && InjectedMount.getNode));
- }
- }
-};
-
-var topLevelTypes = EventConstants.topLevelTypes;
-
-function isEndish(topLevelType) {
- return topLevelType === topLevelTypes.topMouseUp ||
- topLevelType === topLevelTypes.topTouchEnd ||
- topLevelType === topLevelTypes.topTouchCancel;
-}
-
-function isMoveish(topLevelType) {
- return topLevelType === topLevelTypes.topMouseMove ||
- topLevelType === topLevelTypes.topTouchMove;
-}
-function isStartish(topLevelType) {
- return topLevelType === topLevelTypes.topMouseDown ||
- topLevelType === topLevelTypes.topTouchStart;
-}
-
-
-var validateEventDispatches;
-if ("production" !== "development") {
- validateEventDispatches = function(event) {
- var dispatchListeners = event._dispatchListeners;
- var dispatchIDs = event._dispatchIDs;
-
- var listenersIsArr = Array.isArray(dispatchListeners);
- var idsIsArr = Array.isArray(dispatchIDs);
- var IDsLen = idsIsArr ? dispatchIDs.length : dispatchIDs ? 1 : 0;
- var listenersLen = listenersIsArr ?
- dispatchListeners.length :
- dispatchListeners ? 1 : 0;
-
- ("production" !== "development" ? invariant(
- idsIsArr === listenersIsArr && IDsLen === listenersLen,
- 'EventPluginUtils: Invalid `event`.'
- ) : invariant(idsIsArr === listenersIsArr && IDsLen === listenersLen));
- };
-}
-
-/**
- * Invokes `cb(event, listener, id)`. Avoids using call if no scope is
- * provided. The `(listener,id)` pair effectively forms the "dispatch" but are
- * kept separate to conserve memory.
- */
-function forEachEventDispatch(event, cb) {
- var dispatchListeners = event._dispatchListeners;
- var dispatchIDs = event._dispatchIDs;
- if ("production" !== "development") {
- validateEventDispatches(event);
- }
- if (Array.isArray(dispatchListeners)) {
- for (var i = 0; i < dispatchListeners.length; i++) {
- if (event.isPropagationStopped()) {
- break;
- }
- // Listeners and IDs are two parallel arrays that are always in sync.
- cb(event, dispatchListeners[i], dispatchIDs[i]);
- }
- } else if (dispatchListeners) {
- cb(event, dispatchListeners, dispatchIDs);
- }
-}
-
-/**
- * Default implementation of PluginModule.executeDispatch().
- * @param {SyntheticEvent} SyntheticEvent to handle
- * @param {function} Application-level callback
- * @param {string} domID DOM id to pass to the callback.
- */
-function executeDispatch(event, listener, domID) {
- event.currentTarget = injection.Mount.getNode(domID);
- var returnValue = listener(event, domID);
- event.currentTarget = null;
- return returnValue;
-}
-
-/**
- * Standard/simple iteration through an event's collected dispatches.
- */
-function executeDispatchesInOrder(event, executeDispatch) {
- forEachEventDispatch(event, executeDispatch);
- event._dispatchListeners = null;
- event._dispatchIDs = null;
-}
-
-/**
- * Standard/simple iteration through an event's collected dispatches, but stops
- * at the first dispatch execution returning true, and returns that id.
- *
- * @return id of the first dispatch execution who's listener returns true, or
- * null if no listener returned true.
- */
-function executeDispatchesInOrderStopAtTrueImpl(event) {
- var dispatchListeners = event._dispatchListeners;
- var dispatchIDs = event._dispatchIDs;
- if ("production" !== "development") {
- validateEventDispatches(event);
- }
- if (Array.isArray(dispatchListeners)) {
- for (var i = 0; i < dispatchListeners.length; i++) {
- if (event.isPropagationStopped()) {
- break;
- }
- // Listeners and IDs are two parallel arrays that are always in sync.
- if (dispatchListeners[i](event, dispatchIDs[i])) {
- return dispatchIDs[i];
- }
- }
- } else if (dispatchListeners) {
- if (dispatchListeners(event, dispatchIDs)) {
- return dispatchIDs;
- }
- }
- return null;
-}
-
-/**
- * @see executeDispatchesInOrderStopAtTrueImpl
- */
-function executeDispatchesInOrderStopAtTrue(event) {
- var ret = executeDispatchesInOrderStopAtTrueImpl(event);
- event._dispatchIDs = null;
- event._dispatchListeners = null;
- return ret;
-}
-
-/**
- * Execution of a "direct" dispatch - there must be at most one dispatch
- * accumulated on the event or it is considered an error. It doesn't really make
- * sense for an event with multiple dispatches (bubbled) to keep track of the
- * return values at each dispatch execution, but it does tend to make sense when
- * dealing with "direct" dispatches.
- *
- * @return The return value of executing the single dispatch.
- */
-function executeDirectDispatch(event) {
- if ("production" !== "development") {
- validateEventDispatches(event);
- }
- var dispatchListener = event._dispatchListeners;
- var dispatchID = event._dispatchIDs;
- ("production" !== "development" ? invariant(
- !Array.isArray(dispatchListener),
- 'executeDirectDispatch(...): Invalid `event`.'
- ) : invariant(!Array.isArray(dispatchListener)));
- var res = dispatchListener ?
- dispatchListener(event, dispatchID) :
- null;
- event._dispatchListeners = null;
- event._dispatchIDs = null;
- return res;
-}
-
-/**
- * @param {SyntheticEvent} event
- * @return {bool} True iff number of dispatches accumulated is greater than 0.
- */
-function hasDispatches(event) {
- return !!event._dispatchListeners;
-}
-
-/**
- * General utilities that are useful in creating custom Event Plugins.
- */
-var EventPluginUtils = {
- isEndish: isEndish,
- isMoveish: isMoveish,
- isStartish: isStartish,
-
- executeDirectDispatch: executeDirectDispatch,
- executeDispatch: executeDispatch,
- executeDispatchesInOrder: executeDispatchesInOrder,
- executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue,
- hasDispatches: hasDispatches,
- injection: injection,
- useTouchEvents: false
-};
-
-module.exports = EventPluginUtils;
-
-},{"./EventConstants":17,"./invariant":140}],22:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule EventPropagators
- */
-
-"use strict";
-
-var EventConstants = _dereq_("./EventConstants");
-var EventPluginHub = _dereq_("./EventPluginHub");
-
-var accumulateInto = _dereq_("./accumulateInto");
-var forEachAccumulated = _dereq_("./forEachAccumulated");
-
-var PropagationPhases = EventConstants.PropagationPhases;
-var getListener = EventPluginHub.getListener;
-
-/**
- * Some event types have a notion of different registration names for different
- * "phases" of propagation. This finds listeners by a given phase.
- */
-function listenerAtPhase(id, event, propagationPhase) {
- var registrationName =
- event.dispatchConfig.phasedRegistrationNames[propagationPhase];
- return getListener(id, registrationName);
-}
-
-/**
- * Tags a `SyntheticEvent` with dispatched listeners. Creating this function
- * here, allows us to not have to bind or create functions for each event.
- * Mutating the event's members allows us to not have to create a wrapping
- * "dispatch" object that pairs the event with the listener.
- */
-function accumulateDirectionalDispatches(domID, upwards, event) {
- if ("production" !== "development") {
- if (!domID) {
- throw new Error('Dispatching id must not be null');
- }
- }
- var phase = upwards ? PropagationPhases.bubbled : PropagationPhases.captured;
- var listener = listenerAtPhase(domID, event, phase);
- if (listener) {
- event._dispatchListeners =
- accumulateInto(event._dispatchListeners, listener);
- event._dispatchIDs = accumulateInto(event._dispatchIDs, domID);
- }
-}
-
-/**
- * Collect dispatches (must be entirely collected before dispatching - see unit
- * tests). Lazily allocate the array to conserve memory. We must loop through
- * each event and perform the traversal for each one. We can not perform a
- * single traversal for the entire collection of events because each event may
- * have a different target.
- */
-function accumulateTwoPhaseDispatchesSingle(event) {
- if (event && event.dispatchConfig.phasedRegistrationNames) {
- EventPluginHub.injection.getInstanceHandle().traverseTwoPhase(
- event.dispatchMarker,
- accumulateDirectionalDispatches,
- event
- );
- }
-}
-
-
-/**
- * Accumulates without regard to direction, does not look for phased
- * registration names. Same as `accumulateDirectDispatchesSingle` but without
- * requiring that the `dispatchMarker` be the same as the dispatched ID.
- */
-function accumulateDispatches(id, ignoredDirection, event) {
- if (event && event.dispatchConfig.registrationName) {
- var registrationName = event.dispatchConfig.registrationName;
- var listener = getListener(id, registrationName);
- if (listener) {
- event._dispatchListeners =
- accumulateInto(event._dispatchListeners, listener);
- event._dispatchIDs = accumulateInto(event._dispatchIDs, id);
- }
- }
-}
-
-/**
- * Accumulates dispatches on an `SyntheticEvent`, but only for the
- * `dispatchMarker`.
- * @param {SyntheticEvent} event
- */
-function accumulateDirectDispatchesSingle(event) {
- if (event && event.dispatchConfig.registrationName) {
- accumulateDispatches(event.dispatchMarker, null, event);
- }
-}
-
-function accumulateTwoPhaseDispatches(events) {
- forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle);
-}
-
-function accumulateEnterLeaveDispatches(leave, enter, fromID, toID) {
- EventPluginHub.injection.getInstanceHandle().traverseEnterLeave(
- fromID,
- toID,
- accumulateDispatches,
- leave,
- enter
- );
-}
-
-
-function accumulateDirectDispatches(events) {
- forEachAccumulated(events, accumulateDirectDispatchesSingle);
-}
-
-
-
-/**
- * A small set of propagation patterns, each of which will accept a small amount
- * of information, and generate a set of "dispatch ready event objects" - which
- * are sets of events that have already been annotated with a set of dispatched
- * listener functions/ids. The API is designed this way to discourage these
- * propagation strategies from actually executing the dispatches, since we
- * always want to collect the entire set of dispatches before executing event a
- * single one.
- *
- * @constructor EventPropagators
- */
-var EventPropagators = {
- accumulateTwoPhaseDispatches: accumulateTwoPhaseDispatches,
- accumulateDirectDispatches: accumulateDirectDispatches,
- accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches
-};
-
-module.exports = EventPropagators;
-
-},{"./EventConstants":17,"./EventPluginHub":19,"./accumulateInto":109,"./forEachAccumulated":126}],23:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ExecutionEnvironment
- */
-
-/*jslint evil: true */
-
-"use strict";
-
-var canUseDOM = !!(
- typeof window !== 'undefined' &&
- window.document &&
- window.document.createElement
-);
-
-/**
- * Simple, lightweight module assisting with the detection and context of
- * Worker. Helps avoid circular dependencies and allows code to reason about
- * whether or not they are in a Worker, even if they never include the main
- * `ReactWorker` dependency.
- */
-var ExecutionEnvironment = {
-
- canUseDOM: canUseDOM,
-
- canUseWorkers: typeof Worker !== 'undefined',
-
- canUseEventListeners:
- canUseDOM && !!(window.addEventListener || window.attachEvent),
-
- canUseViewport: canUseDOM && !!window.screen,
-
- isInWorker: !canUseDOM // For now, this is true - might change in the future.
-
-};
-
-module.exports = ExecutionEnvironment;
-
-},{}],24:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule HTMLDOMPropertyConfig
- */
-
-/*jslint bitwise: true*/
-
-"use strict";
-
-var DOMProperty = _dereq_("./DOMProperty");
-var ExecutionEnvironment = _dereq_("./ExecutionEnvironment");
-
-var MUST_USE_ATTRIBUTE = DOMProperty.injection.MUST_USE_ATTRIBUTE;
-var MUST_USE_PROPERTY = DOMProperty.injection.MUST_USE_PROPERTY;
-var HAS_BOOLEAN_VALUE = DOMProperty.injection.HAS_BOOLEAN_VALUE;
-var HAS_SIDE_EFFECTS = DOMProperty.injection.HAS_SIDE_EFFECTS;
-var HAS_NUMERIC_VALUE = DOMProperty.injection.HAS_NUMERIC_VALUE;
-var HAS_POSITIVE_NUMERIC_VALUE =
- DOMProperty.injection.HAS_POSITIVE_NUMERIC_VALUE;
-var HAS_OVERLOADED_BOOLEAN_VALUE =
- DOMProperty.injection.HAS_OVERLOADED_BOOLEAN_VALUE;
-
-var hasSVG;
-if (ExecutionEnvironment.canUseDOM) {
- var implementation = document.implementation;
- hasSVG = (
- implementation &&
- implementation.hasFeature &&
- implementation.hasFeature(
- 'http://www.w3.org/TR/SVG11/feature#BasicStructure',
- '1.1'
- )
- );
-}
-
-
-var HTMLDOMPropertyConfig = {
- isCustomAttribute: RegExp.prototype.test.bind(
- /^(data|aria)-[a-z_][a-z\d_.\-]*$/
- ),
- Properties: {
- /**
- * Standard Properties
- */
- accept: null,
- acceptCharset: null,
- accessKey: null,
- action: null,
- allowFullScreen: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
- allowTransparency: MUST_USE_ATTRIBUTE,
- alt: null,
- async: HAS_BOOLEAN_VALUE,
- autoComplete: null,
- // autoFocus is polyfilled/normalized by AutoFocusMixin
- // autoFocus: HAS_BOOLEAN_VALUE,
- autoPlay: HAS_BOOLEAN_VALUE,
- cellPadding: null,
- cellSpacing: null,
- charSet: MUST_USE_ATTRIBUTE,
- checked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
- classID: MUST_USE_ATTRIBUTE,
- // To set className on SVG elements, it's necessary to use .setAttribute;
- // this works on HTML elements too in all browsers except IE8. Conveniently,
- // IE8 doesn't support SVG and so we can simply use the attribute in
- // browsers that support SVG and the property in browsers that don't,
- // regardless of whether the element is HTML or SVG.
- className: hasSVG ? MUST_USE_ATTRIBUTE : MUST_USE_PROPERTY,
- cols: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE,
- colSpan: null,
- content: null,
- contentEditable: null,
- contextMenu: MUST_USE_ATTRIBUTE,
- controls: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
- coords: null,
- crossOrigin: null,
- data: null, // For `<object />` acts as `src`.
- dateTime: MUST_USE_ATTRIBUTE,
- defer: HAS_BOOLEAN_VALUE,
- dir: null,
- disabled: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
- download: HAS_OVERLOADED_BOOLEAN_VALUE,
- draggable: null,
- encType: null,
- form: MUST_USE_ATTRIBUTE,
- formNoValidate: HAS_BOOLEAN_VALUE,
- frameBorder: MUST_USE_ATTRIBUTE,
- height: MUST_USE_ATTRIBUTE,
- hidden: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
- href: null,
- hrefLang: null,
- htmlFor: null,
- httpEquiv: null,
- icon: null,
- id: MUST_USE_PROPERTY,
- label: null,
- lang: null,
- list: MUST_USE_ATTRIBUTE,
- loop: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
- manifest: MUST_USE_ATTRIBUTE,
- max: null,
- maxLength: MUST_USE_ATTRIBUTE,
- media: MUST_USE_ATTRIBUTE,
- mediaGroup: null,
- method: null,
- min: null,
- multiple: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
- muted: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
- name: null,
- noValidate: HAS_BOOLEAN_VALUE,
- open: null,
- pattern: null,
- placeholder: null,
- poster: null,
- preload: null,
- radioGroup: null,
- readOnly: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
- rel: null,
- required: HAS_BOOLEAN_VALUE,
- role: MUST_USE_ATTRIBUTE,
- rows: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE,
- rowSpan: null,
- sandbox: null,
- scope: null,
- scrolling: null,
- seamless: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
- selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
- shape: null,
- size: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE,
- sizes: MUST_USE_ATTRIBUTE,
- span: HAS_POSITIVE_NUMERIC_VALUE,
- spellCheck: null,
- src: null,
- srcDoc: MUST_USE_PROPERTY,
- srcSet: MUST_USE_ATTRIBUTE,
- start: HAS_NUMERIC_VALUE,
- step: null,
- style: null,
- tabIndex: null,
- target: null,
- title: null,
- type: null,
- useMap: null,
- value: MUST_USE_PROPERTY | HAS_SIDE_EFFECTS,
- width: MUST_USE_ATTRIBUTE,
- wmode: MUST_USE_ATTRIBUTE,
-
- /**
- * Non-standard Properties
- */
- autoCapitalize: null, // Supported in Mobile Safari for keyboard hints
- autoCorrect: null, // Supported in Mobile Safari for keyboard hints
- itemProp: MUST_USE_ATTRIBUTE, // Microdata: http://schema.org/docs/gs.html
- itemScope: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, // Microdata: http://schema.org/docs/gs.html
- itemType: MUST_USE_ATTRIBUTE, // Microdata: http://schema.org/docs/gs.html
- property: null // Supports OG in meta tags
- },
- DOMAttributeNames: {
- acceptCharset: 'accept-charset',
- className: 'class',
- htmlFor: 'for',
- httpEquiv: 'http-equiv'
- },
- DOMPropertyNames: {
- autoCapitalize: 'autocapitalize',
- autoComplete: 'autocomplete',
- autoCorrect: 'autocorrect',
- autoFocus: 'autofocus',
- autoPlay: 'autoplay',
- encType: 'enctype',
- hrefLang: 'hreflang',
- radioGroup: 'radiogroup',
- spellCheck: 'spellcheck',
- srcDoc: 'srcdoc',
- srcSet: 'srcset'
- }
-};
-
-module.exports = HTMLDOMPropertyConfig;
-
-},{"./DOMProperty":12,"./ExecutionEnvironment":23}],25:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule LinkedStateMixin
- * @typechecks static-only
- */
-
-"use strict";
-
-var ReactLink = _dereq_("./ReactLink");
-var ReactStateSetters = _dereq_("./ReactStateSetters");
-
-/**
- * A simple mixin around ReactLink.forState().
- */
-var LinkedStateMixin = {
- /**
- * Create a ReactLink that's linked to part of this component's state. The
- * ReactLink will have the current value of this.state[key] and will call
- * setState() when a change is requested.
- *
- * @param {string} key state key to update. Note: you may want to use keyOf()
- * if you're using Google Closure Compiler advanced mode.
- * @return {ReactLink} ReactLink instance linking to the state.
- */
- linkState: function(key) {
- return new ReactLink(
- this.state[key],
- ReactStateSetters.createStateKeySetter(this, key)
- );
- }
-};
-
-module.exports = LinkedStateMixin;
-
-},{"./ReactLink":68,"./ReactStateSetters":85}],26:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule LinkedValueUtils
- * @typechecks static-only
- */
-
-"use strict";
-
-var ReactPropTypes = _dereq_("./ReactPropTypes");
-
-var invariant = _dereq_("./invariant");
-
-var hasReadOnlyValue = {
- 'button': true,
- 'checkbox': true,
- 'image': true,
- 'hidden': true,
- 'radio': true,
- 'reset': true,
- 'submit': true
-};
-
-function _assertSingleLink(input) {
- ("production" !== "development" ? invariant(
- input.props.checkedLink == null || input.props.valueLink == null,
- 'Cannot provide a checkedLink and a valueLink. If you want to use ' +
- 'checkedLink, you probably don\'t want to use valueLink and vice versa.'
- ) : invariant(input.props.checkedLink == null || input.props.valueLink == null));
-}
-function _assertValueLink(input) {
- _assertSingleLink(input);
- ("production" !== "development" ? invariant(
- input.props.value == null && input.props.onChange == null,
- 'Cannot provide a valueLink and a value or onChange event. If you want ' +
- 'to use value or onChange, you probably don\'t want to use valueLink.'
- ) : invariant(input.props.value == null && input.props.onChange == null));
-}
-
-function _assertCheckedLink(input) {
- _assertSingleLink(input);
- ("production" !== "development" ? invariant(
- input.props.checked == null && input.props.onChange == null,
- 'Cannot provide a checkedLink and a checked property or onChange event. ' +
- 'If you want to use checked or onChange, you probably don\'t want to ' +
- 'use checkedLink'
- ) : invariant(input.props.checked == null && input.props.onChange == null));
-}
-
-/**
- * @param {SyntheticEvent} e change event to handle
- */
-function _handleLinkedValueChange(e) {
- /*jshint validthis:true */
- this.props.valueLink.requestChange(e.target.value);
-}
-
-/**
- * @param {SyntheticEvent} e change event to handle
- */
-function _handleLinkedCheckChange(e) {
- /*jshint validthis:true */
- this.props.checkedLink.requestChange(e.target.checked);
-}
-
-/**
- * Provide a linked `value` attribute for controlled forms. You should not use
- * this outside of the ReactDOM controlled form components.
- */
-var LinkedValueUtils = {
- Mixin: {
- propTypes: {
- value: function(props, propName, componentName) {
- if (!props[propName] ||
- hasReadOnlyValue[props.type] ||
- props.onChange ||
- props.readOnly ||
- props.disabled) {
- return;
- }
- return new Error(
- 'You provided a `value` prop to a form field without an ' +
- '`onChange` handler. This will render a read-only field. If ' +
- 'the field should be mutable use `defaultValue`. Otherwise, ' +
- 'set either `onChange` or `readOnly`.'
- );
- },
- checked: function(props, propName, componentName) {
- if (!props[propName] ||
- props.onChange ||
- props.readOnly ||
- props.disabled) {
- return;
- }
- return new Error(
- 'You provided a `checked` prop to a form field without an ' +
- '`onChange` handler. This will render a read-only field. If ' +
- 'the field should be mutable use `defaultChecked`. Otherwise, ' +
- 'set either `onChange` or `readOnly`.'
- );
- },
- onChange: ReactPropTypes.func
- }
- },
-
- /**
- * @param {ReactComponent} input Form component
- * @return {*} current value of the input either from value prop or link.
- */
- getValue: function(input) {
- if (input.props.valueLink) {
- _assertValueLink(input);
- return input.props.valueLink.value;
- }
- return input.props.value;
- },
-
- /**
- * @param {ReactComponent} input Form component
- * @return {*} current checked status of the input either from checked prop
- * or link.
- */
- getChecked: function(input) {
- if (input.props.checkedLink) {
- _assertCheckedLink(input);
- return input.props.checkedLink.value;
- }
- return input.props.checked;
- },
-
- /**
- * @param {ReactComponent} input Form component
- * @return {function} change callback either from onChange prop or link.
- */
- getOnChange: function(input) {
- if (input.props.valueLink) {
- _assertValueLink(input);
- return _handleLinkedValueChange;
- } else if (input.props.checkedLink) {
- _assertCheckedLink(input);
- return _handleLinkedCheckChange;
- }
- return input.props.onChange;
- }
-};
-
-module.exports = LinkedValueUtils;
-
-},{"./ReactPropTypes":79,"./invariant":140}],27:[function(_dereq_,module,exports){
-/**
- * Copyright 2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule LocalEventTrapMixin
- */
-
-"use strict";
-
-var ReactBrowserEventEmitter = _dereq_("./ReactBrowserEventEmitter");
-
-var accumulateInto = _dereq_("./accumulateInto");
-var forEachAccumulated = _dereq_("./forEachAccumulated");
-var invariant = _dereq_("./invariant");
-
-function remove(event) {
- event.remove();
-}
-
-var LocalEventTrapMixin = {
- trapBubbledEvent:function(topLevelType, handlerBaseName) {
- ("production" !== "development" ? invariant(this.isMounted(), 'Must be mounted to trap events') : invariant(this.isMounted()));
- var listener = ReactBrowserEventEmitter.trapBubbledEvent(
- topLevelType,
- handlerBaseName,
- this.getDOMNode()
- );
- this._localEventListeners =
- accumulateInto(this._localEventListeners, listener);
- },
-
- // trapCapturedEvent would look nearly identical. We don't implement that
- // method because it isn't currently needed.
-
- componentWillUnmount:function() {
- if (this._localEventListeners) {
- forEachAccumulated(this._localEventListeners, remove);
- }
- }
-};
-
-module.exports = LocalEventTrapMixin;
-
-},{"./ReactBrowserEventEmitter":33,"./accumulateInto":109,"./forEachAccumulated":126,"./invariant":140}],28:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule MobileSafariClickEventPlugin
- * @typechecks static-only
- */
-
-"use strict";
-
-var EventConstants = _dereq_("./EventConstants");
-
-var emptyFunction = _dereq_("./emptyFunction");
-
-var topLevelTypes = EventConstants.topLevelTypes;
-
-/**
- * Mobile Safari does not fire properly bubble click events on non-interactive
- * elements, which means delegated click listeners do not fire. The workaround
- * for this bug involves attaching an empty click listener on the target node.
- *
- * This particular plugin works around the bug by attaching an empty click
- * listener on `touchstart` (which does fire on every element).
- */
-var MobileSafariClickEventPlugin = {
-
- eventTypes: null,
-
- /**
- * @param {string} topLevelType Record from `EventConstants`.
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
- * @param {object} nativeEvent Native browser event.
- * @return {*} An accumulation of synthetic events.
- * @see {EventPluginHub.extractEvents}
- */
- extractEvents: function(
- topLevelType,
- topLevelTarget,
- topLevelTargetID,
- nativeEvent) {
- if (topLevelType === topLevelTypes.topTouchStart) {
- var target = nativeEvent.target;
- if (target && !target.onclick) {
- target.onclick = emptyFunction;
- }
- }
- }
-
-};
-
-module.exports = MobileSafariClickEventPlugin;
-
-},{"./EventConstants":17,"./emptyFunction":121}],29:[function(_dereq_,module,exports){
-/**
- * Copyright 2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule Object.assign
- */
-
-// https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign
-
-function assign(target, sources) {
- if (target == null) {
- throw new TypeError('Object.assign target cannot be null or undefined');
- }
-
- var to = Object(target);
- var hasOwnProperty = Object.prototype.hasOwnProperty;
-
- for (var nextIndex = 1; nextIndex < arguments.length; nextIndex++) {
- var nextSource = arguments[nextIndex];
- if (nextSource == null) {
- continue;
- }
-
- var from = Object(nextSource);
-
- // We don't currently support accessors nor proxies. Therefore this
- // copy cannot throw. If we ever supported this then we must handle
- // exceptions and side-effects. We don't support symbols so they won't
- // be transferred.
-
- for (var key in from) {
- if (hasOwnProperty.call(from, key)) {
- to[key] = from[key];
- }
- }
- }
-
- return to;
-};
-
-module.exports = assign;
-
-},{}],30:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule PooledClass
- */
-
-"use strict";
-
-var invariant = _dereq_("./invariant");
-
-/**
- * Static poolers. Several custom versions for each potential number of
- * arguments. A completely generic pooler is easy to implement, but would
- * require accessing the `arguments` object. In each of these, `this` refers to
- * the Class itself, not an instance. If any others are needed, simply add them
- * here, or in their own files.
- */
-var oneArgumentPooler = function(copyFieldsFrom) {
- var Klass = this;
- if (Klass.instancePool.length) {
- var instance = Klass.instancePool.pop();
- Klass.call(instance, copyFieldsFrom);
- return instance;
- } else {
- return new Klass(copyFieldsFrom);
- }
-};
-
-var twoArgumentPooler = function(a1, a2) {
- var Klass = this;
- if (Klass.instancePool.length) {
- var instance = Klass.instancePool.pop();
- Klass.call(instance, a1, a2);
- return instance;
- } else {
- return new Klass(a1, a2);
- }
-};
-
-var threeArgumentPooler = function(a1, a2, a3) {
- var Klass = this;
- if (Klass.instancePool.length) {
- var instance = Klass.instancePool.pop();
- Klass.call(instance, a1, a2, a3);
- return instance;
- } else {
- return new Klass(a1, a2, a3);
- }
-};
-
-var fiveArgumentPooler = function(a1, a2, a3, a4, a5) {
- var Klass = this;
- if (Klass.instancePool.length) {
- var instance = Klass.instancePool.pop();
- Klass.call(instance, a1, a2, a3, a4, a5);
- return instance;
- } else {
- return new Klass(a1, a2, a3, a4, a5);
- }
-};
-
-var standardReleaser = function(instance) {
- var Klass = this;
- ("production" !== "development" ? invariant(
- instance instanceof Klass,
- 'Trying to release an instance into a pool of a different type.'
- ) : invariant(instance instanceof Klass));
- if (instance.destructor) {
- instance.destructor();
- }
- if (Klass.instancePool.length < Klass.poolSize) {
- Klass.instancePool.push(instance);
- }
-};
-
-var DEFAULT_POOL_SIZE = 10;
-var DEFAULT_POOLER = oneArgumentPooler;
-
-/**
- * Augments `CopyConstructor` to be a poolable class, augmenting only the class
- * itself (statically) not adding any prototypical fields. Any CopyConstructor
- * you give this may have a `poolSize` property, and will look for a
- * prototypical `destructor` on instances (optional).
- *
- * @param {Function} CopyConstructor Constructor that can be used to reset.
- * @param {Function} pooler Customizable pooler.
- */
-var addPoolingTo = function(CopyConstructor, pooler) {
- var NewKlass = CopyConstructor;
- NewKlass.instancePool = [];
- NewKlass.getPooled = pooler || DEFAULT_POOLER;
- if (!NewKlass.poolSize) {
- NewKlass.poolSize = DEFAULT_POOL_SIZE;
- }
- NewKlass.release = standardReleaser;
- return NewKlass;
-};
-
-var PooledClass = {
- addPoolingTo: addPoolingTo,
- oneArgumentPooler: oneArgumentPooler,
- twoArgumentPooler: twoArgumentPooler,
- threeArgumentPooler: threeArgumentPooler,
- fiveArgumentPooler: fiveArgumentPooler
-};
-
-module.exports = PooledClass;
-
-},{"./invariant":140}],31:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule React
- */
-
-"use strict";
-
-var DOMPropertyOperations = _dereq_("./DOMPropertyOperations");
-var EventPluginUtils = _dereq_("./EventPluginUtils");
-var ReactChildren = _dereq_("./ReactChildren");
-var ReactComponent = _dereq_("./ReactComponent");
-var ReactCompositeComponent = _dereq_("./ReactCompositeComponent");
-var ReactContext = _dereq_("./ReactContext");
-var ReactCurrentOwner = _dereq_("./ReactCurrentOwner");
-var ReactElement = _dereq_("./ReactElement");
-var ReactElementValidator = _dereq_("./ReactElementValidator");
-var ReactDOM = _dereq_("./ReactDOM");
-var ReactDOMComponent = _dereq_("./ReactDOMComponent");
-var ReactDefaultInjection = _dereq_("./ReactDefaultInjection");
-var ReactInstanceHandles = _dereq_("./ReactInstanceHandles");
-var ReactLegacyElement = _dereq_("./ReactLegacyElement");
-var ReactMount = _dereq_("./ReactMount");
-var ReactMultiChild = _dereq_("./ReactMultiChild");
-var ReactPerf = _dereq_("./ReactPerf");
-var ReactPropTypes = _dereq_("./ReactPropTypes");
-var ReactServerRendering = _dereq_("./ReactServerRendering");
-var ReactTextComponent = _dereq_("./ReactTextComponent");
-
-var assign = _dereq_("./Object.assign");
-var deprecated = _dereq_("./deprecated");
-var onlyChild = _dereq_("./onlyChild");
-
-ReactDefaultInjection.inject();
-
-var createElement = ReactElement.createElement;
-var createFactory = ReactElement.createFactory;
-
-if ("production" !== "development") {
- createElement = ReactElementValidator.createElement;
- createFactory = ReactElementValidator.createFactory;
-}
-
-// TODO: Drop legacy elements once classes no longer export these factories
-createElement = ReactLegacyElement.wrapCreateElement(
- createElement
-);
-createFactory = ReactLegacyElement.wrapCreateFactory(
- createFactory
-);
-
-var render = ReactPerf.measure('React', 'render', ReactMount.render);
-
-var React = {
- Children: {
- map: ReactChildren.map,
- forEach: ReactChildren.forEach,
- count: ReactChildren.count,
- only: onlyChild
- },
- DOM: ReactDOM,
- PropTypes: ReactPropTypes,
- initializeTouchEvents: function(shouldUseTouch) {
- EventPluginUtils.useTouchEvents = shouldUseTouch;
- },
- createClass: ReactCompositeComponent.createClass,
- createElement: createElement,
- createFactory: createFactory,
- constructAndRenderComponent: ReactMount.constructAndRenderComponent,
- constructAndRenderComponentByID: ReactMount.constructAndRenderComponentByID,
- render: render,
- renderToString: ReactServerRendering.renderToString,
- renderToStaticMarkup: ReactServerRendering.renderToStaticMarkup,
- unmountComponentAtNode: ReactMount.unmountComponentAtNode,
- isValidClass: ReactLegacyElement.isValidClass,
- isValidElement: ReactElement.isValidElement,
- withContext: ReactContext.withContext,
-
- // Hook for JSX spread, don't use this for anything else.
- __spread: assign,
-
- // Deprecations (remove for 0.13)
- renderComponent: deprecated(
- 'React',
- 'renderComponent',
- 'render',
- this,
- render
- ),
- renderComponentToString: deprecated(
- 'React',
- 'renderComponentToString',
- 'renderToString',
- this,
- ReactServerRendering.renderToString
- ),
- renderComponentToStaticMarkup: deprecated(
- 'React',
- 'renderComponentToStaticMarkup',
- 'renderToStaticMarkup',
- this,
- ReactServerRendering.renderToStaticMarkup
- ),
- isValidComponent: deprecated(
- 'React',
- 'isValidComponent',
- 'isValidElement',
- this,
- ReactElement.isValidElement
- )
-};
-
-// Inject the runtime into a devtools global hook regardless of browser.
-// Allows for debugging when the hook is injected on the page.
-if (
- typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' &&
- typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function') {
- __REACT_DEVTOOLS_GLOBAL_HOOK__.inject({
- Component: ReactComponent,
- CurrentOwner: ReactCurrentOwner,
- DOMComponent: ReactDOMComponent,
- DOMPropertyOperations: DOMPropertyOperations,
- InstanceHandles: ReactInstanceHandles,
- Mount: ReactMount,
- MultiChild: ReactMultiChild,
- TextComponent: ReactTextComponent
- });
-}
-
-if ("production" !== "development") {
- var ExecutionEnvironment = _dereq_("./ExecutionEnvironment");
- if (ExecutionEnvironment.canUseDOM && window.top === window.self) {
-
- // If we're in Chrome, look for the devtools marker and provide a download
- // link if not installed.
- if (navigator.userAgent.indexOf('Chrome') > -1) {
- if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') {
- console.debug(
- 'Download the React DevTools for a better development experience: ' +
- 'http://fb.me/react-devtools'
- );
- }
- }
-
- var expectedFeatures = [
- // shims
- Array.isArray,
- Array.prototype.every,
- Array.prototype.forEach,
- Array.prototype.indexOf,
- Array.prototype.map,
- Date.now,
- Function.prototype.bind,
- Object.keys,
- String.prototype.split,
- String.prototype.trim,
-
- // shams
- Object.create,
- Object.freeze
- ];
-
- for (var i = 0; i < expectedFeatures.length; i++) {
- if (!expectedFeatures[i]) {
- console.error(
- 'One or more ES5 shim/shams expected by React are not available: ' +
- 'http://fb.me/react-warning-polyfills'
- );
- break;
- }
- }
- }
-}
-
-// Version exists only in the open-source version of React, not in Facebook's
-// internal version.
-React.version = '0.12.1';
-
-module.exports = React;
-
-},{"./DOMPropertyOperations":13,"./EventPluginUtils":21,"./ExecutionEnvironment":23,"./Object.assign":29,"./ReactChildren":36,"./ReactComponent":37,"./ReactCompositeComponent":40,"./ReactContext":41,"./ReactCurrentOwner":42,"./ReactDOM":43,"./ReactDOMComponent":45,"./ReactDefaultInjection":55,"./ReactElement":58,"./ReactElementValidator":59,"./ReactInstanceHandles":66,"./ReactLegacyElement":67,"./ReactMount":70,"./ReactMultiChild":71,"./ReactPerf":75,"./ReactPropTypes":79,"./ReactServerRendering":83,"./ReactTextComponent":87,"./deprecated":120,"./onlyChild":151}],32:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactBrowserComponentMixin
- */
-
-"use strict";
-
-var ReactEmptyComponent = _dereq_("./ReactEmptyComponent");
-var ReactMount = _dereq_("./ReactMount");
-
-var invariant = _dereq_("./invariant");
-
-var ReactBrowserComponentMixin = {
- /**
- * Returns the DOM node rendered by this component.
- *
- * @return {DOMElement} The root node of this component.
- * @final
- * @protected
- */
- getDOMNode: function() {
- ("production" !== "development" ? invariant(
- this.isMounted(),
- 'getDOMNode(): A component must be mounted to have a DOM node.'
- ) : invariant(this.isMounted()));
- if (ReactEmptyComponent.isNullComponentID(this._rootNodeID)) {
- return null;
- }
- return ReactMount.getNode(this._rootNodeID);
- }
-};
-
-module.exports = ReactBrowserComponentMixin;
-
-},{"./ReactEmptyComponent":60,"./ReactMount":70,"./invariant":140}],33:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactBrowserEventEmitter
- * @typechecks static-only
- */
-
-"use strict";
-
-var EventConstants = _dereq_("./EventConstants");
-var EventPluginHub = _dereq_("./EventPluginHub");
-var EventPluginRegistry = _dereq_("./EventPluginRegistry");
-var ReactEventEmitterMixin = _dereq_("./ReactEventEmitterMixin");
-var ViewportMetrics = _dereq_("./ViewportMetrics");
-
-var assign = _dereq_("./Object.assign");
-var isEventSupported = _dereq_("./isEventSupported");
-
-/**
- * Summary of `ReactBrowserEventEmitter` event handling:
- *
- * - Top-level delegation is used to trap most native browser events. This
- * may only occur in the main thread and is the responsibility of
- * ReactEventListener, which is injected and can therefore support pluggable
- * event sources. This is the only work that occurs in the main thread.
- *
- * - We normalize and de-duplicate events to account for browser quirks. This
- * may be done in the worker thread.
- *
- * - Forward these native events (with the associated top-level type used to
- * trap it) to `EventPluginHub`, which in turn will ask plugins if they want
- * to extract any synthetic events.
- *
- * - The `EventPluginHub` will then process each event by annotating them with
- * "dispatches", a sequence of listeners and IDs that care about that event.
- *
- * - The `EventPluginHub` then dispatches the events.
- *
- * Overview of React and the event system:
- *
- * +------------+ .
- * | DOM | .
- * +------------+ .
- * | .
- * v .
- * +------------+ .
- * | ReactEvent | .
- * | Listener | .
- * +------------+ . +-----------+
- * | . +--------+|SimpleEvent|
- * | . | |Plugin |
- * +-----|------+ . v +-----------+
- * | | | . +--------------+ +------------+
- * | +-----------.--->|EventPluginHub| | Event |
- * | | . | | +-----------+ | Propagators|
- * | ReactEvent | . | | |TapEvent | |------------|
- * | Emitter | . | |<---+|Plugin | |other plugin|
- * | | . | | +-----------+ | utilities |
- * | +-----------.--->| | +------------+
- * | | | . +--------------+
- * +-----|------+ . ^ +-----------+
- * | . | |Enter/Leave|
- * + . +-------+|Plugin |
- * +-------------+ . +-----------+
- * | application | .
- * |-------------| .
- * | | .
- * | | .
- * +-------------+ .
- * .
- * React Core . General Purpose Event Plugin System
- */
-
-var alreadyListeningTo = {};
-var isMonitoringScrollValue = false;
-var reactTopListenersCounter = 0;
-
-// For events like 'submit' which don't consistently bubble (which we trap at a
-// lower node than `document`), binding at `document` would cause duplicate
-// events so we don't include them here
-var topEventMapping = {
- topBlur: 'blur',
- topChange: 'change',
- topClick: 'click',
- topCompositionEnd: 'compositionend',
- topCompositionStart: 'compositionstart',
- topCompositionUpdate: 'compositionupdate',
- topContextMenu: 'contextmenu',
- topCopy: 'copy',
- topCut: 'cut',
- topDoubleClick: 'dblclick',
- topDrag: 'drag',
- topDragEnd: 'dragend',
- topDragEnter: 'dragenter',
- topDragExit: 'dragexit',
- topDragLeave: 'dragleave',
- topDragOver: 'dragover',
- topDragStart: 'dragstart',
- topDrop: 'drop',
- topFocus: 'focus',
- topInput: 'input',
- topKeyDown: 'keydown',
- topKeyPress: 'keypress',
- topKeyUp: 'keyup',
- topMouseDown: 'mousedown',
- topMouseMove: 'mousemove',
- topMouseOut: 'mouseout',
- topMouseOver: 'mouseover',
- topMouseUp: 'mouseup',
- topPaste: 'paste',
- topScroll: 'scroll',
- topSelectionChange: 'selectionchange',
- topTextInput: 'textInput',
- topTouchCancel: 'touchcancel',
- topTouchEnd: 'touchend',
- topTouchMove: 'touchmove',
- topTouchStart: 'touchstart',
- topWheel: 'wheel'
-};
-
-/**
- * To ensure no conflicts with other potential React instances on the page
- */
-var topListenersIDKey = "_reactListenersID" + String(Math.random()).slice(2);
-
-function getListeningForDocument(mountAt) {
- // In IE8, `mountAt` is a host object and doesn't have `hasOwnProperty`
- // directly.
- if (!Object.prototype.hasOwnProperty.call(mountAt, topListenersIDKey)) {
- mountAt[topListenersIDKey] = reactTopListenersCounter++;
- alreadyListeningTo[mountAt[topListenersIDKey]] = {};
- }
- return alreadyListeningTo[mountAt[topListenersIDKey]];
-}
-
-/**
- * `ReactBrowserEventEmitter` is used to attach top-level event listeners. For
- * example:
- *
- * ReactBrowserEventEmitter.putListener('myID', 'onClick', myFunction);
- *
- * This would allocate a "registration" of `('onClick', myFunction)` on 'myID'.
- *
- * @internal
- */
-var ReactBrowserEventEmitter = assign({}, ReactEventEmitterMixin, {
-
- /**
- * Injectable event backend
- */
- ReactEventListener: null,
-
- injection: {
- /**
- * @param {object} ReactEventListener
- */
- injectReactEventListener: function(ReactEventListener) {
- ReactEventListener.setHandleTopLevel(
- ReactBrowserEventEmitter.handleTopLevel
- );
- ReactBrowserEventEmitter.ReactEventListener = ReactEventListener;
- }
- },
-
- /**
- * Sets whether or not any created callbacks should be enabled.
- *
- * @param {boolean} enabled True if callbacks should be enabled.
- */
- setEnabled: function(enabled) {
- if (ReactBrowserEventEmitter.ReactEventListener) {
- ReactBrowserEventEmitter.ReactEventListener.setEnabled(enabled);
- }
- },
-
- /**
- * @return {boolean} True if callbacks are enabled.
- */
- isEnabled: function() {
- return !!(
- ReactBrowserEventEmitter.ReactEventListener &&
- ReactBrowserEventEmitter.ReactEventListener.isEnabled()
- );
- },
-
- /**
- * We listen for bubbled touch events on the document object.
- *
- * Firefox v8.01 (and possibly others) exhibited strange behavior when
- * mounting `onmousemove` events at some node that was not the document
- * element. The symptoms were that if your mouse is not moving over something
- * contained within that mount point (for example on the background) the
- * top-level listeners for `onmousemove` won't be called. However, if you
- * register the `mousemove` on the document object, then it will of course
- * catch all `mousemove`s. This along with iOS quirks, justifies restricting
- * top-level listeners to the document object only, at least for these
- * movement types of events and possibly all events.
- *
- * @see http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html
- *
- * Also, `keyup`/`keypress`/`keydown` do not bubble to the window on IE, but
- * they bubble to document.
- *
- * @param {string} registrationName Name of listener (e.g. `onClick`).
- * @param {object} contentDocumentHandle Document which owns the container
- */
- listenTo: function(registrationName, contentDocumentHandle) {
- var mountAt = contentDocumentHandle;
- var isListening = getListeningForDocument(mountAt);
- var dependencies = EventPluginRegistry.
- registrationNameDependencies[registrationName];
-
- var topLevelTypes = EventConstants.topLevelTypes;
- for (var i = 0, l = dependencies.length; i < l; i++) {
- var dependency = dependencies[i];
- if (!(
- isListening.hasOwnProperty(dependency) &&
- isListening[dependency]
- )) {
- if (dependency === topLevelTypes.topWheel) {
- if (isEventSupported('wheel')) {
- ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
- topLevelTypes.topWheel,
- 'wheel',
- mountAt
- );
- } else if (isEventSupported('mousewheel')) {
- ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
- topLevelTypes.topWheel,
- 'mousewheel',
- mountAt
- );
- } else {
- // Firefox needs to capture a different mouse scroll event.
- // @see http://www.quirksmode.org/dom/events/tests/scroll.html
- ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
- topLevelTypes.topWheel,
- 'DOMMouseScroll',
- mountAt
- );
- }
- } else if (dependency === topLevelTypes.topScroll) {
-
- if (isEventSupported('scroll', true)) {
- ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
- topLevelTypes.topScroll,
- 'scroll',
- mountAt
- );
- } else {
- ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
- topLevelTypes.topScroll,
- 'scroll',
- ReactBrowserEventEmitter.ReactEventListener.WINDOW_HANDLE
- );
- }
- } else if (dependency === topLevelTypes.topFocus ||
- dependency === topLevelTypes.topBlur) {
-
- if (isEventSupported('focus', true)) {
- ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
- topLevelTypes.topFocus,
- 'focus',
- mountAt
- );
- ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
- topLevelTypes.topBlur,
- 'blur',
- mountAt
- );
- } else if (isEventSupported('focusin')) {
- // IE has `focusin` and `focusout` events which bubble.
- // @see http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
- ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
- topLevelTypes.topFocus,
- 'focusin',
- mountAt
- );
- ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
- topLevelTypes.topBlur,
- 'focusout',
- mountAt
- );
- }
-
- // to make sure blur and focus event listeners are only attached once
- isListening[topLevelTypes.topBlur] = true;
- isListening[topLevelTypes.topFocus] = true;
- } else if (topEventMapping.hasOwnProperty(dependency)) {
- ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
- dependency,
- topEventMapping[dependency],
- mountAt
- );
- }
-
- isListening[dependency] = true;
- }
- }
- },
-
- trapBubbledEvent: function(topLevelType, handlerBaseName, handle) {
- return ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
- topLevelType,
- handlerBaseName,
- handle
- );
- },
-
- trapCapturedEvent: function(topLevelType, handlerBaseName, handle) {
- return ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
- topLevelType,
- handlerBaseName,
- handle
- );
- },
-
- /**
- * Listens to window scroll and resize events. We cache scroll values so that
- * application code can access them without triggering reflows.
- *
- * NOTE: Scroll events do not bubble.
- *
- * @see http://www.quirksmode.org/dom/events/scroll.html
- */
- ensureScrollValueMonitoring: function(){
- if (!isMonitoringScrollValue) {
- var refresh = ViewportMetrics.refreshScrollValues;
- ReactBrowserEventEmitter.ReactEventListener.monitorScrollValue(refresh);
- isMonitoringScrollValue = true;
- }
- },
-
- eventNameDispatchConfigs: EventPluginHub.eventNameDispatchConfigs,
-
- registrationNameModules: EventPluginHub.registrationNameModules,
-
- putListener: EventPluginHub.putListener,
-
- getListener: EventPluginHub.getListener,
-
- deleteListener: EventPluginHub.deleteListener,
-
- deleteAllListeners: EventPluginHub.deleteAllListeners
-
-});
-
-module.exports = ReactBrowserEventEmitter;
-
-},{"./EventConstants":17,"./EventPluginHub":19,"./EventPluginRegistry":20,"./Object.assign":29,"./ReactEventEmitterMixin":62,"./ViewportMetrics":108,"./isEventSupported":141}],34:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @typechecks
- * @providesModule ReactCSSTransitionGroup
- */
-
-"use strict";
-
-var React = _dereq_("./React");
-
-var assign = _dereq_("./Object.assign");
-
-var ReactTransitionGroup = React.createFactory(
- _dereq_("./ReactTransitionGroup")
-);
-var ReactCSSTransitionGroupChild = React.createFactory(
- _dereq_("./ReactCSSTransitionGroupChild")
-);
-
-var ReactCSSTransitionGroup = React.createClass({
- displayName: 'ReactCSSTransitionGroup',
-
- propTypes: {
- transitionName: React.PropTypes.string.isRequired,
- transitionEnter: React.PropTypes.bool,
- transitionLeave: React.PropTypes.bool
- },
-
- getDefaultProps: function() {
- return {
- transitionEnter: true,
- transitionLeave: true
- };
- },
-
- _wrapChild: function(child) {
- // We need to provide this childFactory so that
- // ReactCSSTransitionGroupChild can receive updates to name, enter, and
- // leave while it is leaving.
- return ReactCSSTransitionGroupChild(
- {
- name: this.props.transitionName,
- enter: this.props.transitionEnter,
- leave: this.props.transitionLeave
- },
- child
- );
- },
-
- render: function() {
- return (
- ReactTransitionGroup(
- assign({}, this.props, {childFactory: this._wrapChild})
- )
- );
- }
-});
-
-module.exports = ReactCSSTransitionGroup;
-
-},{"./Object.assign":29,"./React":31,"./ReactCSSTransitionGroupChild":35,"./ReactTransitionGroup":90}],35:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @typechecks
- * @providesModule ReactCSSTransitionGroupChild
- */
-
-"use strict";
-
-var React = _dereq_("./React");
-
-var CSSCore = _dereq_("./CSSCore");
-var ReactTransitionEvents = _dereq_("./ReactTransitionEvents");
-
-var onlyChild = _dereq_("./onlyChild");
-
-// We don't remove the element from the DOM until we receive an animationend or
-// transitionend event. If the user screws up and forgets to add an animation
-// their node will be stuck in the DOM forever, so we detect if an animation
-// does not start and if it doesn't, we just call the end listener immediately.
-var TICK = 17;
-var NO_EVENT_TIMEOUT = 5000;
-
-var noEventListener = null;
-
-
-if ("production" !== "development") {
- noEventListener = function() {
- console.warn(
- 'transition(): tried to perform an animation without ' +
- 'an animationend or transitionend event after timeout (' +
- NO_EVENT_TIMEOUT + 'ms). You should either disable this ' +
- 'transition in JS or add a CSS animation/transition.'
- );
- };
-}
-
-var ReactCSSTransitionGroupChild = React.createClass({
- displayName: 'ReactCSSTransitionGroupChild',
-
- transition: function(animationType, finishCallback) {
- var node = this.getDOMNode();
- var className = this.props.name + '-' + animationType;
- var activeClassName = className + '-active';
- var noEventTimeout = null;
-
- var endListener = function(e) {
- if (e && e.target !== node) {
- return;
- }
- if ("production" !== "development") {
- clearTimeout(noEventTimeout);
- }
-
- CSSCore.removeClass(node, className);
- CSSCore.removeClass(node, activeClassName);
-
- ReactTransitionEvents.removeEndEventListener(node, endListener);
-
- // Usually this optional callback is used for informing an owner of
- // a leave animation and telling it to remove the child.
- finishCallback && finishCallback();
- };
-
- ReactTransitionEvents.addEndEventListener(node, endListener);
-
- CSSCore.addClass(node, className);
-
- // Need to do this to actually trigger a transition.
- this.queueClass(activeClassName);
-
- if ("production" !== "development") {
- noEventTimeout = setTimeout(noEventListener, NO_EVENT_TIMEOUT);
- }
- },
-
- queueClass: function(className) {
- this.classNameQueue.push(className);
-
- if (!this.timeout) {
- this.timeout = setTimeout(this.flushClassNameQueue, TICK);
- }
- },
-
- flushClassNameQueue: function() {
- if (this.isMounted()) {
- this.classNameQueue.forEach(
- CSSCore.addClass.bind(CSSCore, this.getDOMNode())
- );
- }
- this.classNameQueue.length = 0;
- this.timeout = null;
- },
-
- componentWillMount: function() {
- this.classNameQueue = [];
- },
-
- componentWillUnmount: function() {
- if (this.timeout) {
- clearTimeout(this.timeout);
- }
- },
-
- componentWillEnter: function(done) {
- if (this.props.enter) {
- this.transition('enter', done);
- } else {
- done();
- }
- },
-
- componentWillLeave: function(done) {
- if (this.props.leave) {
- this.transition('leave', done);
- } else {
- done();
- }
- },
-
- render: function() {
- return onlyChild(this.props.children);
- }
-});
-
-module.exports = ReactCSSTransitionGroupChild;
-
-},{"./CSSCore":4,"./React":31,"./ReactTransitionEvents":89,"./onlyChild":151}],36:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactChildren
- */
-
-"use strict";
-
-var PooledClass = _dereq_("./PooledClass");
-
-var traverseAllChildren = _dereq_("./traverseAllChildren");
-var warning = _dereq_("./warning");
-
-var twoArgumentPooler = PooledClass.twoArgumentPooler;
-var threeArgumentPooler = PooledClass.threeArgumentPooler;
-
-/**
- * PooledClass representing the bookkeeping associated with performing a child
- * traversal. Allows avoiding binding callbacks.
- *
- * @constructor ForEachBookKeeping
- * @param {!function} forEachFunction Function to perform traversal with.
- * @param {?*} forEachContext Context to perform context with.
- */
-function ForEachBookKeeping(forEachFunction, forEachContext) {
- this.forEachFunction = forEachFunction;
- this.forEachContext = forEachContext;
-}
-PooledClass.addPoolingTo(ForEachBookKeeping, twoArgumentPooler);
-
-function forEachSingleChild(traverseContext, child, name, i) {
- var forEachBookKeeping = traverseContext;
- forEachBookKeeping.forEachFunction.call(
- forEachBookKeeping.forEachContext, child, i);
-}
-
-/**
- * Iterates through children that are typically specified as `props.children`.
- *
- * The provided forEachFunc(child, index) will be called for each
- * leaf child.
- *
- * @param {?*} children Children tree container.
- * @param {function(*, int)} forEachFunc.
- * @param {*} forEachContext Context for forEachContext.
- */
-function forEachChildren(children, forEachFunc, forEachContext) {
- if (children == null) {
- return children;
- }
-
- var traverseContext =
- ForEachBookKeeping.getPooled(forEachFunc, forEachContext);
- traverseAllChildren(children, forEachSingleChild, traverseContext);
- ForEachBookKeeping.release(traverseContext);
-}
-
-/**
- * PooledClass representing the bookkeeping associated with performing a child
- * mapping. Allows avoiding binding callbacks.
- *
- * @constructor MapBookKeeping
- * @param {!*} mapResult Object containing the ordered map of results.
- * @param {!function} mapFunction Function to perform mapping with.
- * @param {?*} mapContext Context to perform mapping with.
- */
-function MapBookKeeping(mapResult, mapFunction, mapContext) {
- this.mapResult = mapResult;
- this.mapFunction = mapFunction;
- this.mapContext = mapContext;
-}
-PooledClass.addPoolingTo(MapBookKeeping, threeArgumentPooler);
-
-function mapSingleChildIntoContext(traverseContext, child, name, i) {
- var mapBookKeeping = traverseContext;
- var mapResult = mapBookKeeping.mapResult;
-
- var keyUnique = !mapResult.hasOwnProperty(name);
- ("production" !== "development" ? warning(
- keyUnique,
- 'ReactChildren.map(...): Encountered two children with the same key, ' +
- '`%s`. Child keys must be unique; when two children share a key, only ' +
- 'the first child will be used.',
- name
- ) : null);
-
- if (keyUnique) {
- var mappedChild =
- mapBookKeeping.mapFunction.call(mapBookKeeping.mapContext, child, i);
- mapResult[name] = mappedChild;
- }
-}
-
-/**
- * Maps children that are typically specified as `props.children`.
- *
- * The provided mapFunction(child, key, index) will be called for each
- * leaf child.
- *
- * TODO: This may likely break any calls to `ReactChildren.map` that were
- * previously relying on the fact that we guarded against null children.
- *
- * @param {?*} children Children tree container.
- * @param {function(*, int)} mapFunction.
- * @param {*} mapContext Context for mapFunction.
- * @return {object} Object containing the ordered map of results.
- */
-function mapChildren(children, func, context) {
- if (children == null) {
- return children;
- }
-
- var mapResult = {};
- var traverseContext = MapBookKeeping.getPooled(mapResult, func, context);
- traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);
- MapBookKeeping.release(traverseContext);
- return mapResult;
-}
-
-function forEachSingleChildDummy(traverseContext, child, name, i) {
- return null;
-}
-
-/**
- * Count the number of children that are typically specified as
- * `props.children`.
- *
- * @param {?*} children Children tree container.
- * @return {number} The number of children.
- */
-function countChildren(children, context) {
- return traverseAllChildren(children, forEachSingleChildDummy, null);
-}
-
-var ReactChildren = {
- forEach: forEachChildren,
- map: mapChildren,
- count: countChildren
-};
-
-module.exports = ReactChildren;
-
-},{"./PooledClass":30,"./traverseAllChildren":158,"./warning":160}],37:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactComponent
- */
-
-"use strict";
-
-var ReactElement = _dereq_("./ReactElement");
-var ReactOwner = _dereq_("./ReactOwner");
-var ReactUpdates = _dereq_("./ReactUpdates");
-
-var assign = _dereq_("./Object.assign");
-var invariant = _dereq_("./invariant");
-var keyMirror = _dereq_("./keyMirror");
-
-/**
- * Every React component is in one of these life cycles.
- */
-var ComponentLifeCycle = keyMirror({
- /**
- * Mounted components have a DOM node representation and are capable of
- * receiving new props.
- */
- MOUNTED: null,
- /**
- * Unmounted components are inactive and cannot receive new props.
- */
- UNMOUNTED: null
-});
-
-var injected = false;
-
-/**
- * Optionally injectable environment dependent cleanup hook. (server vs.
- * browser etc). Example: A browser system caches DOM nodes based on component
- * ID and must remove that cache entry when this instance is unmounted.
- *
- * @private
- */
-var unmountIDFromEnvironment = null;
-
-/**
- * The "image" of a component tree, is the platform specific (typically
- * serialized) data that represents a tree of lower level UI building blocks.
- * On the web, this "image" is HTML markup which describes a construction of
- * low level `div` and `span` nodes. Other platforms may have different
- * encoding of this "image". This must be injected.
- *
- * @private
- */
-var mountImageIntoNode = null;
-
-/**
- * Components are the basic units of composition in React.
- *
- * Every component accepts a set of keyed input parameters known as "props" that
- * are initialized by the constructor. Once a component is mounted, the props
- * can be mutated using `setProps` or `replaceProps`.
- *
- * Every component is capable of the following operations:
- *
- * `mountComponent`
- * Initializes the component, renders markup, and registers event listeners.
- *
- * `receiveComponent`
- * Updates the rendered DOM nodes to match the given component.
- *
- * `unmountComponent`
- * Releases any resources allocated by this component.
- *
- * Components can also be "owned" by other components. Being owned by another
- * component means being constructed by that component. This is different from
- * being the child of a component, which means having a DOM representation that
- * is a child of the DOM representation of that component.
- *
- * @class ReactComponent
- */
-var ReactComponent = {
-
- injection: {
- injectEnvironment: function(ReactComponentEnvironment) {
- ("production" !== "development" ? invariant(
- !injected,
- 'ReactComponent: injectEnvironment() can only be called once.'
- ) : invariant(!injected));
- mountImageIntoNode = ReactComponentEnvironment.mountImageIntoNode;
- unmountIDFromEnvironment =
- ReactComponentEnvironment.unmountIDFromEnvironment;
- ReactComponent.BackendIDOperations =
- ReactComponentEnvironment.BackendIDOperations;
- injected = true;
- }
- },
-
- /**
- * @internal
- */
- LifeCycle: ComponentLifeCycle,
-
- /**
- * Injected module that provides ability to mutate individual properties.
- * Injected into the base class because many different subclasses need access
- * to this.
- *
- * @internal
- */
- BackendIDOperations: null,
-
- /**
- * Base functionality for every ReactComponent constructor. Mixed into the
- * `ReactComponent` prototype, but exposed statically for easy access.
- *
- * @lends {ReactComponent.prototype}
- */
- Mixin: {
-
- /**
- * Checks whether or not this component is mounted.
- *
- * @return {boolean} True if mounted, false otherwise.
- * @final
- * @protected
- */
- isMounted: function() {
- return this._lifeCycleState === ComponentLifeCycle.MOUNTED;
- },
-
- /**
- * Sets a subset of the props.
- *
- * @param {object} partialProps Subset of the next props.
- * @param {?function} callback Called after props are updated.
- * @final
- * @public
- */
- setProps: function(partialProps, callback) {
- // Merge with the pending element if it exists, otherwise with existing
- // element props.
- var element = this._pendingElement || this._currentElement;
- this.replaceProps(
- assign({}, element.props, partialProps),
- callback
- );
- },
-
- /**
- * Replaces all of the props.
- *
- * @param {object} props New props.
- * @param {?function} callback Called after props are updated.
- * @final
- * @public
- */
- replaceProps: function(props, callback) {
- ("production" !== "development" ? invariant(
- this.isMounted(),
- 'replaceProps(...): Can only update a mounted component.'
- ) : invariant(this.isMounted()));
- ("production" !== "development" ? invariant(
- this._mountDepth === 0,
- 'replaceProps(...): You called `setProps` or `replaceProps` on a ' +
- 'component with a parent. This is an anti-pattern since props will ' +
- 'get reactively updated when rendered. Instead, change the owner\'s ' +
- '`render` method to pass the correct value as props to the component ' +
- 'where it is created.'
- ) : invariant(this._mountDepth === 0));
- // This is a deoptimized path. We optimize for always having a element.
- // This creates an extra internal element.
- this._pendingElement = ReactElement.cloneAndReplaceProps(
- this._pendingElement || this._currentElement,
- props
- );
- ReactUpdates.enqueueUpdate(this, callback);
- },
-
- /**
- * Schedule a partial update to the props. Only used for internal testing.
- *
- * @param {object} partialProps Subset of the next props.
- * @param {?function} callback Called after props are updated.
- * @final
- * @internal
- */
- _setPropsInternal: function(partialProps, callback) {
- // This is a deoptimized path. We optimize for always having a element.
- // This creates an extra internal element.
- var element = this._pendingElement || this._currentElement;
- this._pendingElement = ReactElement.cloneAndReplaceProps(
- element,
- assign({}, element.props, partialProps)
- );
- ReactUpdates.enqueueUpdate(this, callback);
- },
-
- /**
- * Base constructor for all React components.
- *
- * Subclasses that override this method should make sure to invoke
- * `ReactComponent.Mixin.construct.call(this, ...)`.
- *
- * @param {ReactElement} element
- * @internal
- */
- construct: function(element) {
- // This is the public exposed props object after it has been processed
- // with default props. The element's props represents the true internal
- // state of the props.
- this.props = element.props;
- // Record the component responsible for creating this component.
- // This is accessible through the element but we maintain an extra
- // field for compatibility with devtools and as a way to make an
- // incremental update. TODO: Consider deprecating this field.
- this._owner = element._owner;
-
- // All components start unmounted.
- this._lifeCycleState = ComponentLifeCycle.UNMOUNTED;
-
- // See ReactUpdates.
- this._pendingCallbacks = null;
-
- // We keep the old element and a reference to the pending element
- // to track updates.
- this._currentElement = element;
- this._pendingElement = null;
- },
-
- /**
- * Initializes the component, renders markup, and registers event listeners.
- *
- * NOTE: This does not insert any nodes into the DOM.
- *
- * Subclasses that override this method should make sure to invoke
- * `ReactComponent.Mixin.mountComponent.call(this, ...)`.
- *
- * @param {string} rootID DOM ID of the root node.
- * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
- * @param {number} mountDepth number of components in the owner hierarchy.
- * @return {?string} Rendered markup to be inserted into the DOM.
- * @internal
- */
- mountComponent: function(rootID, transaction, mountDepth) {
- ("production" !== "development" ? invariant(
- !this.isMounted(),
- 'mountComponent(%s, ...): Can only mount an unmounted component. ' +
- 'Make sure to avoid storing components between renders or reusing a ' +
- 'single component instance in multiple places.',
- rootID
- ) : invariant(!this.isMounted()));
- var ref = this._currentElement.ref;
- if (ref != null) {
- var owner = this._currentElement._owner;
- ReactOwner.addComponentAsRefTo(this, ref, owner);
- }
- this._rootNodeID = rootID;
- this._lifeCycleState = ComponentLifeCycle.MOUNTED;
- this._mountDepth = mountDepth;
- // Effectively: return '';
- },
-
- /**
- * Releases any resources allocated by `mountComponent`.
- *
- * NOTE: This does not remove any nodes from the DOM.
- *
- * Subclasses that override this method should make sure to invoke
- * `ReactComponent.Mixin.unmountComponent.call(this)`.
- *
- * @internal
- */
- unmountComponent: function() {
- ("production" !== "development" ? invariant(
- this.isMounted(),
- 'unmountComponent(): Can only unmount a mounted component.'
- ) : invariant(this.isMounted()));
- var ref = this._currentElement.ref;
- if (ref != null) {
- ReactOwner.removeComponentAsRefFrom(this, ref, this._owner);
- }
- unmountIDFromEnvironment(this._rootNodeID);
- this._rootNodeID = null;
- this._lifeCycleState = ComponentLifeCycle.UNMOUNTED;
- },
-
- /**
- * Given a new instance of this component, updates the rendered DOM nodes
- * as if that instance was rendered instead.
- *
- * Subclasses that override this method should make sure to invoke
- * `ReactComponent.Mixin.receiveComponent.call(this, ...)`.
- *
- * @param {object} nextComponent Next set of properties.
- * @param {ReactReconcileTransaction} transaction
- * @internal
- */
- receiveComponent: function(nextElement, transaction) {
- ("production" !== "development" ? invariant(
- this.isMounted(),
- 'receiveComponent(...): Can only update a mounted component.'
- ) : invariant(this.isMounted()));
- this._pendingElement = nextElement;
- this.performUpdateIfNecessary(transaction);
- },
-
- /**
- * If `_pendingElement` is set, update the component.
- *
- * @param {ReactReconcileTransaction} transaction
- * @internal
- */
- performUpdateIfNecessary: function(transaction) {
- if (this._pendingElement == null) {
- return;
- }
- var prevElement = this._currentElement;
- var nextElement = this._pendingElement;
- this._currentElement = nextElement;
- this.props = nextElement.props;
- this._owner = nextElement._owner;
- this._pendingElement = null;
- this.updateComponent(transaction, prevElement);
- },
-
- /**
- * Updates the component's currently mounted representation.
- *
- * @param {ReactReconcileTransaction} transaction
- * @param {object} prevElement
- * @internal
- */
- updateComponent: function(transaction, prevElement) {
- var nextElement = this._currentElement;
-
- // If either the owner or a `ref` has changed, make sure the newest owner
- // has stored a reference to `this`, and the previous owner (if different)
- // has forgotten the reference to `this`. We use the element instead
- // of the public this.props because the post processing cannot determine
- // a ref. The ref conceptually lives on the element.
-
- // TODO: Should this even be possible? The owner cannot change because
- // it's forbidden by shouldUpdateReactComponent. The ref can change
- // if you swap the keys of but not the refs. Reconsider where this check
- // is made. It probably belongs where the key checking and
- // instantiateReactComponent is done.
-
- if (nextElement._owner !== prevElement._owner ||
- nextElement.ref !== prevElement.ref) {
- if (prevElement.ref != null) {
- ReactOwner.removeComponentAsRefFrom(
- this, prevElement.ref, prevElement._owner
- );
- }
- // Correct, even if the owner is the same, and only the ref has changed.
- if (nextElement.ref != null) {
- ReactOwner.addComponentAsRefTo(
- this,
- nextElement.ref,
- nextElement._owner
- );
- }
- }
- },
-
- /**
- * Mounts this component and inserts it into the DOM.
- *
- * @param {string} rootID DOM ID of the root node.
- * @param {DOMElement} container DOM element to mount into.
- * @param {boolean} shouldReuseMarkup If true, do not insert markup
- * @final
- * @internal
- * @see {ReactMount.render}
- */
- mountComponentIntoNode: function(rootID, container, shouldReuseMarkup) {
- var transaction = ReactUpdates.ReactReconcileTransaction.getPooled();
- transaction.perform(
- this._mountComponentIntoNode,
- this,
- rootID,
- container,
- transaction,
- shouldReuseMarkup
- );
- ReactUpdates.ReactReconcileTransaction.release(transaction);
- },
-
- /**
- * @param {string} rootID DOM ID of the root node.
- * @param {DOMElement} container DOM element to mount into.
- * @param {ReactReconcileTransaction} transaction
- * @param {boolean} shouldReuseMarkup If true, do not insert markup
- * @final
- * @private
- */
- _mountComponentIntoNode: function(
- rootID,
- container,
- transaction,
- shouldReuseMarkup) {
- var markup = this.mountComponent(rootID, transaction, 0);
- mountImageIntoNode(markup, container, shouldReuseMarkup);
- },
-
- /**
- * Checks if this component is owned by the supplied `owner` component.
- *
- * @param {ReactComponent} owner Component to check.
- * @return {boolean} True if `owners` owns this component.
- * @final
- * @internal
- */
- isOwnedBy: function(owner) {
- return this._owner === owner;
- },
-
- /**
- * Gets another component, that shares the same owner as this one, by ref.
- *
- * @param {string} ref of a sibling Component.
- * @return {?ReactComponent} the actual sibling Component.
- * @final
- * @internal
- */
- getSiblingByRef: function(ref) {
- var owner = this._owner;
- if (!owner || !owner.refs) {
- return null;
- }
- return owner.refs[ref];
- }
- }
-};
-
-module.exports = ReactComponent;
-
-},{"./Object.assign":29,"./ReactElement":58,"./ReactOwner":74,"./ReactUpdates":91,"./invariant":140,"./keyMirror":146}],38:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactComponentBrowserEnvironment
- */
-
-/*jslint evil: true */
-
-"use strict";
-
-var ReactDOMIDOperations = _dereq_("./ReactDOMIDOperations");
-var ReactMarkupChecksum = _dereq_("./ReactMarkupChecksum");
-var ReactMount = _dereq_("./ReactMount");
-var ReactPerf = _dereq_("./ReactPerf");
-var ReactReconcileTransaction = _dereq_("./ReactReconcileTransaction");
-
-var getReactRootElementInContainer = _dereq_("./getReactRootElementInContainer");
-var invariant = _dereq_("./invariant");
-var setInnerHTML = _dereq_("./setInnerHTML");
-
-
-var ELEMENT_NODE_TYPE = 1;
-var DOC_NODE_TYPE = 9;
-
-
-/**
- * Abstracts away all functionality of `ReactComponent` requires knowledge of
- * the browser context.
- */
-var ReactComponentBrowserEnvironment = {
- ReactReconcileTransaction: ReactReconcileTransaction,
-
- BackendIDOperations: ReactDOMIDOperations,
-
- /**
- * If a particular environment requires that some resources be cleaned up,
- * specify this in the injected Mixin. In the DOM, we would likely want to
- * purge any cached node ID lookups.
- *
- * @private
- */
- unmountIDFromEnvironment: function(rootNodeID) {
- ReactMount.purgeID(rootNodeID);
- },
-
- /**
- * @param {string} markup Markup string to place into the DOM Element.
- * @param {DOMElement} container DOM Element to insert markup into.
- * @param {boolean} shouldReuseMarkup Should reuse the existing markup in the
- * container if possible.
- */
- mountImageIntoNode: ReactPerf.measure(
- 'ReactComponentBrowserEnvironment',
- 'mountImageIntoNode',
- function(markup, container, shouldReuseMarkup) {
- ("production" !== "development" ? invariant(
- container && (
- container.nodeType === ELEMENT_NODE_TYPE ||
- container.nodeType === DOC_NODE_TYPE
- ),
- 'mountComponentIntoNode(...): Target container is not valid.'
- ) : invariant(container && (
- container.nodeType === ELEMENT_NODE_TYPE ||
- container.nodeType === DOC_NODE_TYPE
- )));
-
- if (shouldReuseMarkup) {
- if (ReactMarkupChecksum.canReuseMarkup(
- markup,
- getReactRootElementInContainer(container))) {
- return;
- } else {
- ("production" !== "development" ? invariant(
- container.nodeType !== DOC_NODE_TYPE,
- 'You\'re trying to render a component to the document using ' +
- 'server rendering but the checksum was invalid. This usually ' +
- 'means you rendered a different component type or props on ' +
- 'the client from the one on the server, or your render() ' +
- 'methods are impure. React cannot handle this case due to ' +
- 'cross-browser quirks by rendering at the document root. You ' +
- 'should look for environment dependent code in your components ' +
- 'and ensure the props are the same client and server side.'
- ) : invariant(container.nodeType !== DOC_NODE_TYPE));
-
- if ("production" !== "development") {
- console.warn(
- 'React attempted to use reuse markup in a container but the ' +
- 'checksum was invalid. This generally means that you are ' +
- 'using server rendering and the markup generated on the ' +
- 'server was not what the client was expecting. React injected ' +
- 'new markup to compensate which works but you have lost many ' +
- 'of the benefits of server rendering. Instead, figure out ' +
- 'why the markup being generated is different on the client ' +
- 'or server.'
- );
- }
- }
- }
-
- ("production" !== "development" ? invariant(
- container.nodeType !== DOC_NODE_TYPE,
- 'You\'re trying to render a component to the document but ' +
- 'you didn\'t use server rendering. We can\'t do this ' +
- 'without using server rendering due to cross-browser quirks. ' +
- 'See renderComponentToString() for server rendering.'
- ) : invariant(container.nodeType !== DOC_NODE_TYPE));
-
- setInnerHTML(container, markup);
- }
- )
-};
-
-module.exports = ReactComponentBrowserEnvironment;
-
-},{"./ReactDOMIDOperations":47,"./ReactMarkupChecksum":69,"./ReactMount":70,"./ReactPerf":75,"./ReactReconcileTransaction":81,"./getReactRootElementInContainer":134,"./invariant":140,"./setInnerHTML":154}],39:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
-* @providesModule ReactComponentWithPureRenderMixin
-*/
-
-"use strict";
-
-var shallowEqual = _dereq_("./shallowEqual");
-
-/**
- * If your React component's render function is "pure", e.g. it will render the
- * same result given the same props and state, provide this Mixin for a
- * considerable performance boost.
- *
- * Most React components have pure render functions.
- *
- * Example:
- *
- * var ReactComponentWithPureRenderMixin =
- * require('ReactComponentWithPureRenderMixin');
- * React.createClass({
- * mixins: [ReactComponentWithPureRenderMixin],
- *
- * render: function() {
- * return <div className={this.props.className}>foo</div>;
- * }
- * });
- *
- * Note: This only checks shallow equality for props and state. If these contain
- * complex data structures this mixin may have false-negatives for deeper
- * differences. Only mixin to components which have simple props and state, or
- * use `forceUpdate()` when you know deep data structures have changed.
- */
-var ReactComponentWithPureRenderMixin = {
- shouldComponentUpdate: function(nextProps, nextState) {
- return !shallowEqual(this.props, nextProps) ||
- !shallowEqual(this.state, nextState);
- }
-};
-
-module.exports = ReactComponentWithPureRenderMixin;
-
-},{"./shallowEqual":155}],40:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactCompositeComponent
- */
-
-"use strict";
-
-var ReactComponent = _dereq_("./ReactComponent");
-var ReactContext = _dereq_("./ReactContext");
-var ReactCurrentOwner = _dereq_("./ReactCurrentOwner");
-var ReactElement = _dereq_("./ReactElement");
-var ReactElementValidator = _dereq_("./ReactElementValidator");
-var ReactEmptyComponent = _dereq_("./ReactEmptyComponent");
-var ReactErrorUtils = _dereq_("./ReactErrorUtils");
-var ReactLegacyElement = _dereq_("./ReactLegacyElement");
-var ReactOwner = _dereq_("./ReactOwner");
-var ReactPerf = _dereq_("./ReactPerf");
-var ReactPropTransferer = _dereq_("./ReactPropTransferer");
-var ReactPropTypeLocations = _dereq_("./ReactPropTypeLocations");
-var ReactPropTypeLocationNames = _dereq_("./ReactPropTypeLocationNames");
-var ReactUpdates = _dereq_("./ReactUpdates");
-
-var assign = _dereq_("./Object.assign");
-var instantiateReactComponent = _dereq_("./instantiateReactComponent");
-var invariant = _dereq_("./invariant");
-var keyMirror = _dereq_("./keyMirror");
-var keyOf = _dereq_("./keyOf");
-var monitorCodeUse = _dereq_("./monitorCodeUse");
-var mapObject = _dereq_("./mapObject");
-var shouldUpdateReactComponent = _dereq_("./shouldUpdateReactComponent");
-var warning = _dereq_("./warning");
-
-var MIXINS_KEY = keyOf({mixins: null});
-
-/**
- * Policies that describe methods in `ReactCompositeComponentInterface`.
- */
-var SpecPolicy = keyMirror({
- /**
- * These methods may be defined only once by the class specification or mixin.
- */
- DEFINE_ONCE: null,
- /**
- * These methods may be defined by both the class specification and mixins.
- * Subsequent definitions will be chained. These methods must return void.
- */
- DEFINE_MANY: null,
- /**
- * These methods are overriding the base ReactCompositeComponent class.
- */
- OVERRIDE_BASE: null,
- /**
- * These methods are similar to DEFINE_MANY, except we assume they return
- * objects. We try to merge the keys of the return values of all the mixed in
- * functions. If there is a key conflict we throw.
- */
- DEFINE_MANY_MERGED: null
-});
-
-
-var injectedMixins = [];
-
-/**
- * Composite components are higher-level components that compose other composite
- * or native components.
- *
- * To create a new type of `ReactCompositeComponent`, pass a specification of
- * your new class to `React.createClass`. The only requirement of your class
- * specification is that you implement a `render` method.
- *
- * var MyComponent = React.createClass({
- * render: function() {
- * return <div>Hello World</div>;
- * }
- * });
- *
- * The class specification supports a specific protocol of methods that have
- * special meaning (e.g. `render`). See `ReactCompositeComponentInterface` for
- * more the comprehensive protocol. Any other properties and methods in the
- * class specification will available on the prototype.
- *
- * @interface ReactCompositeComponentInterface
- * @internal
- */
-var ReactCompositeComponentInterface = {
-
- /**
- * An array of Mixin objects to include when defining your component.
- *
- * @type {array}
- * @optional
- */
- mixins: SpecPolicy.DEFINE_MANY,
-
- /**
- * An object containing properties and methods that should be defined on
- * the component's constructor instead of its prototype (static methods).
- *
- * @type {object}
- * @optional
- */
- statics: SpecPolicy.DEFINE_MANY,
-
- /**
- * Definition of prop types for this component.
- *
- * @type {object}
- * @optional
- */
- propTypes: SpecPolicy.DEFINE_MANY,
-
- /**
- * Definition of context types for this component.
- *
- * @type {object}
- * @optional
- */
- contextTypes: SpecPolicy.DEFINE_MANY,
-
- /**
- * Definition of context types this component sets for its children.
- *
- * @type {object}
- * @optional
- */
- childContextTypes: SpecPolicy.DEFINE_MANY,
-
- // ==== Definition methods ====
-
- /**
- * Invoked when the component is mounted. Values in the mapping will be set on
- * `this.props` if that prop is not specified (i.e. using an `in` check).
- *
- * This method is invoked before `getInitialState` and therefore cannot rely
- * on `this.state` or use `this.setState`.
- *
- * @return {object}
- * @optional
- */
- getDefaultProps: SpecPolicy.DEFINE_MANY_MERGED,
-
- /**
- * Invoked once before the component is mounted. The return value will be used
- * as the initial value of `this.state`.
- *
- * getInitialState: function() {
- * return {
- * isOn: false,
- * fooBaz: new BazFoo()
- * }
- * }
- *
- * @return {object}
- * @optional
- */
- getInitialState: SpecPolicy.DEFINE_MANY_MERGED,
-
- /**
- * @return {object}
- * @optional
- */
- getChildContext: SpecPolicy.DEFINE_MANY_MERGED,
-
- /**
- * Uses props from `this.props` and state from `this.state` to render the
- * structure of the component.
- *
- * No guarantees are made about when or how often this method is invoked, so
- * it must not have side effects.
- *
- * render: function() {
- * var name = this.props.name;
- * return <div>Hello, {name}!</div>;
- * }
- *
- * @return {ReactComponent}
- * @nosideeffects
- * @required
- */
- render: SpecPolicy.DEFINE_ONCE,
-
-
-
- // ==== Delegate methods ====
-
- /**
- * Invoked when the component is initially created and about to be mounted.
- * This may have side effects, but any external subscriptions or data created
- * by this method must be cleaned up in `componentWillUnmount`.
- *
- * @optional
- */
- componentWillMount: SpecPolicy.DEFINE_MANY,
-
- /**
- * Invoked when the component has been mounted and has a DOM representation.
- * However, there is no guarantee that the DOM node is in the document.
- *
- * Use this as an opportunity to operate on the DOM when the component has
- * been mounted (initialized and rendered) for the first time.
- *
- * @param {DOMElement} rootNode DOM element representing the component.
- * @optional
- */
- componentDidMount: SpecPolicy.DEFINE_MANY,
-
- /**
- * Invoked before the component receives new props.
- *
- * Use this as an opportunity to react to a prop transition by updating the
- * state using `this.setState`. Current props are accessed via `this.props`.
- *
- * componentWillReceiveProps: function(nextProps, nextContext) {
- * this.setState({
- * likesIncreasing: nextProps.likeCount > this.props.likeCount
- * });
- * }
- *
- * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop
- * transition may cause a state change, but the opposite is not true. If you
- * need it, you are probably looking for `componentWillUpdate`.
- *
- * @param {object} nextProps
- * @optional
- */
- componentWillReceiveProps: SpecPolicy.DEFINE_MANY,
-
- /**
- * Invoked while deciding if the component should be updated as a result of
- * receiving new props, state and/or context.
- *
- * Use this as an opportunity to `return false` when you're certain that the
- * transition to the new props/state/context will not require a component
- * update.
- *
- * shouldComponentUpdate: function(nextProps, nextState, nextContext) {
- * return !equal(nextProps, this.props) ||
- * !equal(nextState, this.state) ||
- * !equal(nextContext, this.context);
- * }
- *
- * @param {object} nextProps
- * @param {?object} nextState
- * @param {?object} nextContext
- * @return {boolean} True if the component should update.
- * @optional
- */
- shouldComponentUpdate: SpecPolicy.DEFINE_ONCE,
-
- /**
- * Invoked when the component is about to update due to a transition from
- * `this.props`, `this.state` and `this.context` to `nextProps`, `nextState`
- * and `nextContext`.
- *
- * Use this as an opportunity to perform preparation before an update occurs.
- *
- * NOTE: You **cannot** use `this.setState()` in this method.
- *
- * @param {object} nextProps
- * @param {?object} nextState
- * @param {?object} nextContext
- * @param {ReactReconcileTransaction} transaction
- * @optional
- */
- componentWillUpdate: SpecPolicy.DEFINE_MANY,
-
- /**
- * Invoked when the component's DOM representation has been updated.
- *
- * Use this as an opportunity to operate on the DOM when the component has
- * been updated.
- *
- * @param {object} prevProps
- * @param {?object} prevState
- * @param {?object} prevContext
- * @param {DOMElement} rootNode DOM element representing the component.
- * @optional
- */
- componentDidUpdate: SpecPolicy.DEFINE_MANY,
-
- /**
- * Invoked when the component is about to be removed from its parent and have
- * its DOM representation destroyed.
- *
- * Use this as an opportunity to deallocate any external resources.
- *
- * NOTE: There is no `componentDidUnmount` since your component will have been
- * destroyed by that point.
- *
- * @optional
- */
- componentWillUnmount: SpecPolicy.DEFINE_MANY,
-
-
-
- // ==== Advanced methods ====
-
- /**
- * Updates the component's currently mounted DOM representation.
- *
- * By default, this implements React's rendering and reconciliation algorithm.
- * Sophisticated clients may wish to override this.
- *
- * @param {ReactReconcileTransaction} transaction
- * @internal
- * @overridable
- */
- updateComponent: SpecPolicy.OVERRIDE_BASE
-
-};
-
-/**
- * Mapping from class specification keys to special processing functions.
- *
- * Although these are declared like instance properties in the specification
- * when defining classes using `React.createClass`, they are actually static
- * and are accessible on the constructor instead of the prototype. Despite
- * being static, they must be defined outside of the "statics" key under
- * which all other static methods are defined.
- */
-var RESERVED_SPEC_KEYS = {
- displayName: function(Constructor, displayName) {
- Constructor.displayName = displayName;
- },
- mixins: function(Constructor, mixins) {
- if (mixins) {
- for (var i = 0; i < mixins.length; i++) {
- mixSpecIntoComponent(Constructor, mixins[i]);
- }
- }
- },
- childContextTypes: function(Constructor, childContextTypes) {
- validateTypeDef(
- Constructor,
- childContextTypes,
- ReactPropTypeLocations.childContext
- );
- Constructor.childContextTypes = assign(
- {},
- Constructor.childContextTypes,
- childContextTypes
- );
- },
- contextTypes: function(Constructor, contextTypes) {
- validateTypeDef(
- Constructor,
- contextTypes,
- ReactPropTypeLocations.context
- );
- Constructor.contextTypes = assign(
- {},
- Constructor.contextTypes,
- contextTypes
- );
- },
- /**
- * Special case getDefaultProps which should move into statics but requires
- * automatic merging.
- */
- getDefaultProps: function(Constructor, getDefaultProps) {
- if (Constructor.getDefaultProps) {
- Constructor.getDefaultProps = createMergedResultFunction(
- Constructor.getDefaultProps,
- getDefaultProps
- );
- } else {
- Constructor.getDefaultProps = getDefaultProps;
- }
- },
- propTypes: function(Constructor, propTypes) {
- validateTypeDef(
- Constructor,
- propTypes,
- ReactPropTypeLocations.prop
- );
- Constructor.propTypes = assign(
- {},
- Constructor.propTypes,
- propTypes
- );
- },
- statics: function(Constructor, statics) {
- mixStaticSpecIntoComponent(Constructor, statics);
- }
-};
-
-function getDeclarationErrorAddendum(component) {
- var owner = component._owner || null;
- if (owner && owner.constructor && owner.constructor.displayName) {
- return ' Check the render method of `' + owner.constructor.displayName +
- '`.';
- }
- return '';
-}
-
-function validateTypeDef(Constructor, typeDef, location) {
- for (var propName in typeDef) {
- if (typeDef.hasOwnProperty(propName)) {
- ("production" !== "development" ? invariant(
- typeof typeDef[propName] == 'function',
- '%s: %s type `%s` is invalid; it must be a function, usually from ' +
- 'React.PropTypes.',
- Constructor.displayName || 'ReactCompositeComponent',
- ReactPropTypeLocationNames[location],
- propName
- ) : invariant(typeof typeDef[propName] == 'function'));
- }
- }
-}
-
-function validateMethodOverride(proto, name) {
- var specPolicy = ReactCompositeComponentInterface.hasOwnProperty(name) ?
- ReactCompositeComponentInterface[name] :
- null;
-
- // Disallow overriding of base class methods unless explicitly allowed.
- if (ReactCompositeComponentMixin.hasOwnProperty(name)) {
- ("production" !== "development" ? invariant(
- specPolicy === SpecPolicy.OVERRIDE_BASE,
- 'ReactCompositeComponentInterface: You are attempting to override ' +
- '`%s` from your class specification. Ensure that your method names ' +
- 'do not overlap with React methods.',
- name
- ) : invariant(specPolicy === SpecPolicy.OVERRIDE_BASE));
- }
-
- // Disallow defining methods more than once unless explicitly allowed.
- if (proto.hasOwnProperty(name)) {
- ("production" !== "development" ? invariant(
- specPolicy === SpecPolicy.DEFINE_MANY ||
- specPolicy === SpecPolicy.DEFINE_MANY_MERGED,
- 'ReactCompositeComponentInterface: You are attempting to define ' +
- '`%s` on your component more than once. This conflict may be due ' +
- 'to a mixin.',
- name
- ) : invariant(specPolicy === SpecPolicy.DEFINE_MANY ||
- specPolicy === SpecPolicy.DEFINE_MANY_MERGED));
- }
-}
-
-function validateLifeCycleOnReplaceState(instance) {
- var compositeLifeCycleState = instance._compositeLifeCycleState;
- ("production" !== "development" ? invariant(
- instance.isMounted() ||
- compositeLifeCycleState === CompositeLifeCycle.MOUNTING,
- 'replaceState(...): Can only update a mounted or mounting component.'
- ) : invariant(instance.isMounted() ||
- compositeLifeCycleState === CompositeLifeCycle.MOUNTING));
- ("production" !== "development" ? invariant(
- ReactCurrentOwner.current == null,
- 'replaceState(...): Cannot update during an existing state transition ' +
- '(such as within `render`). Render methods should be a pure function ' +
- 'of props and state.'
- ) : invariant(ReactCurrentOwner.current == null));
- ("production" !== "development" ? invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING,
- 'replaceState(...): Cannot update while unmounting component. This ' +
- 'usually means you called setState() on an unmounted component.'
- ) : invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING));
-}
-
-/**
- * Mixin helper which handles policy validation and reserved
- * specification keys when building `ReactCompositeComponent` classses.
- */
-function mixSpecIntoComponent(Constructor, spec) {
- if (!spec) {
- return;
- }
-
- ("production" !== "development" ? invariant(
- !ReactLegacyElement.isValidFactory(spec),
- 'ReactCompositeComponent: You\'re attempting to ' +
- 'use a component class as a mixin. Instead, just use a regular object.'
- ) : invariant(!ReactLegacyElement.isValidFactory(spec)));
- ("production" !== "development" ? invariant(
- !ReactElement.isValidElement(spec),
- 'ReactCompositeComponent: You\'re attempting to ' +
- 'use a component as a mixin. Instead, just use a regular object.'
- ) : invariant(!ReactElement.isValidElement(spec)));
-
- var proto = Constructor.prototype;
-
- // By handling mixins before any other properties, we ensure the same
- // chaining order is applied to methods with DEFINE_MANY policy, whether
- // mixins are listed before or after these methods in the spec.
- if (spec.hasOwnProperty(MIXINS_KEY)) {
- RESERVED_SPEC_KEYS.mixins(Constructor, spec.mixins);
- }
-
- for (var name in spec) {
- if (!spec.hasOwnProperty(name)) {
- continue;
- }
-
- if (name === MIXINS_KEY) {
- // We have already handled mixins in a special case above
- continue;
- }
-
- var property = spec[name];
- validateMethodOverride(proto, name);
-
- if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) {
- RESERVED_SPEC_KEYS[name](Constructor, property);
- } else {
- // Setup methods on prototype:
- // The following member methods should not be automatically bound:
- // 1. Expected ReactCompositeComponent methods (in the "interface").
- // 2. Overridden methods (that were mixed in).
- var isCompositeComponentMethod =
- ReactCompositeComponentInterface.hasOwnProperty(name);
- var isAlreadyDefined = proto.hasOwnProperty(name);
- var markedDontBind = property && property.__reactDontBind;
- var isFunction = typeof property === 'function';
- var shouldAutoBind =
- isFunction &&
- !isCompositeComponentMethod &&
- !isAlreadyDefined &&
- !markedDontBind;
-
- if (shouldAutoBind) {
- if (!proto.__reactAutoBindMap) {
- proto.__reactAutoBindMap = {};
- }
- proto.__reactAutoBindMap[name] = property;
- proto[name] = property;
- } else {
- if (isAlreadyDefined) {
- var specPolicy = ReactCompositeComponentInterface[name];
-
- // These cases should already be caught by validateMethodOverride
- ("production" !== "development" ? invariant(
- isCompositeComponentMethod && (
- specPolicy === SpecPolicy.DEFINE_MANY_MERGED ||
- specPolicy === SpecPolicy.DEFINE_MANY
- ),
- 'ReactCompositeComponent: Unexpected spec policy %s for key %s ' +
- 'when mixing in component specs.',
- specPolicy,
- name
- ) : invariant(isCompositeComponentMethod && (
- specPolicy === SpecPolicy.DEFINE_MANY_MERGED ||
- specPolicy === SpecPolicy.DEFINE_MANY
- )));
-
- // For methods which are defined more than once, call the existing
- // methods before calling the new property, merging if appropriate.
- if (specPolicy === SpecPolicy.DEFINE_MANY_MERGED) {
- proto[name] = createMergedResultFunction(proto[name], property);
- } else if (specPolicy === SpecPolicy.DEFINE_MANY) {
- proto[name] = createChainedFunction(proto[name], property);
- }
- } else {
- proto[name] = property;
- if ("production" !== "development") {
- // Add verbose displayName to the function, which helps when looking
- // at profiling tools.
- if (typeof property === 'function' && spec.displayName) {
- proto[name].displayName = spec.displayName + '_' + name;
- }
- }
- }
- }
- }
- }
-}
-
-function mixStaticSpecIntoComponent(Constructor, statics) {
- if (!statics) {
- return;
- }
- for (var name in statics) {
- var property = statics[name];
- if (!statics.hasOwnProperty(name)) {
- continue;
- }
-
- var isReserved = name in RESERVED_SPEC_KEYS;
- ("production" !== "development" ? invariant(
- !isReserved,
- 'ReactCompositeComponent: You are attempting to define a reserved ' +
- 'property, `%s`, that shouldn\'t be on the "statics" key. Define it ' +
- 'as an instance property instead; it will still be accessible on the ' +
- 'constructor.',
- name
- ) : invariant(!isReserved));
-
- var isInherited = name in Constructor;
- ("production" !== "development" ? invariant(
- !isInherited,
- 'ReactCompositeComponent: You are attempting to define ' +
- '`%s` on your component more than once. This conflict may be ' +
- 'due to a mixin.',
- name
- ) : invariant(!isInherited));
- Constructor[name] = property;
- }
-}
-
-/**
- * Merge two objects, but throw if both contain the same key.
- *
- * @param {object} one The first object, which is mutated.
- * @param {object} two The second object
- * @return {object} one after it has been mutated to contain everything in two.
- */
-function mergeObjectsWithNoDuplicateKeys(one, two) {
- ("production" !== "development" ? invariant(
- one && two && typeof one === 'object' && typeof two === 'object',
- 'mergeObjectsWithNoDuplicateKeys(): Cannot merge non-objects'
- ) : invariant(one && two && typeof one === 'object' && typeof two === 'object'));
-
- mapObject(two, function(value, key) {
- ("production" !== "development" ? invariant(
- one[key] === undefined,
- 'mergeObjectsWithNoDuplicateKeys(): ' +
- 'Tried to merge two objects with the same key: `%s`. This conflict ' +
- 'may be due to a mixin; in particular, this may be caused by two ' +
- 'getInitialState() or getDefaultProps() methods returning objects ' +
- 'with clashing keys.',
- key
- ) : invariant(one[key] === undefined));
- one[key] = value;
- });
- return one;
-}
-
-/**
- * Creates a function that invokes two functions and merges their return values.
- *
- * @param {function} one Function to invoke first.
- * @param {function} two Function to invoke second.
- * @return {function} Function that invokes the two argument functions.
- * @private
- */
-function createMergedResultFunction(one, two) {
- return function mergedResult() {
- var a = one.apply(this, arguments);
- var b = two.apply(this, arguments);
- if (a == null) {
- return b;
- } else if (b == null) {
- return a;
- }
- return mergeObjectsWithNoDuplicateKeys(a, b);
- };
-}
-
-/**
- * Creates a function that invokes two functions and ignores their return vales.
- *
- * @param {function} one Function to invoke first.
- * @param {function} two Function to invoke second.
- * @return {function} Function that invokes the two argument functions.
- * @private
- */
-function createChainedFunction(one, two) {
- return function chainedFunction() {
- one.apply(this, arguments);
- two.apply(this, arguments);
- };
-}
-
-/**
- * `ReactCompositeComponent` maintains an auxiliary life cycle state in
- * `this._compositeLifeCycleState` (which can be null).
- *
- * This is different from the life cycle state maintained by `ReactComponent` in
- * `this._lifeCycleState`. The following diagram shows how the states overlap in
- * time. There are times when the CompositeLifeCycle is null - at those times it
- * is only meaningful to look at ComponentLifeCycle alone.
- *
- * Top Row: ReactComponent.ComponentLifeCycle
- * Low Row: ReactComponent.CompositeLifeCycle
- *
- * +-------+---------------------------------+--------+
- * | UN | MOUNTED | UN |
- * |MOUNTED| | MOUNTED|
- * +-------+---------------------------------+--------+
- * | ^--------+ +-------+ +--------^ |
- * | | | | | | | |
- * | 0--|MOUNTING|-0-|RECEIVE|-0-| UN |--->0 |
- * | | | |PROPS | |MOUNTING| |
- * | | | | | | | |
- * | | | | | | | |
- * | +--------+ +-------+ +--------+ |
- * | | | |
- * +-------+---------------------------------+--------+
- */
-var CompositeLifeCycle = keyMirror({
- /**
- * Components in the process of being mounted respond to state changes
- * differently.
- */
- MOUNTING: null,
- /**
- * Components in the process of being unmounted are guarded against state
- * changes.
- */
- UNMOUNTING: null,
- /**
- * Components that are mounted and receiving new props respond to state
- * changes differently.
- */
- RECEIVING_PROPS: null
-});
-
-/**
- * @lends {ReactCompositeComponent.prototype}
- */
-var ReactCompositeComponentMixin = {
-
- /**
- * Base constructor for all composite component.
- *
- * @param {ReactElement} element
- * @final
- * @internal
- */
- construct: function(element) {
- // Children can be either an array or more than one argument
- ReactComponent.Mixin.construct.apply(this, arguments);
- ReactOwner.Mixin.construct.apply(this, arguments);
-
- this.state = null;
- this._pendingState = null;
-
- // This is the public post-processed context. The real context and pending
- // context lives on the element.
- this.context = null;
-
- this._compositeLifeCycleState = null;
- },
-
- /**
- * Checks whether or not this composite component is mounted.
- * @return {boolean} True if mounted, false otherwise.
- * @protected
- * @final
- */
- isMounted: function() {
- return ReactComponent.Mixin.isMounted.call(this) &&
- this._compositeLifeCycleState !== CompositeLifeCycle.MOUNTING;
- },
-
- /**
- * Initializes the component, renders markup, and registers event listeners.
- *
- * @param {string} rootID DOM ID of the root node.
- * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
- * @param {number} mountDepth number of components in the owner hierarchy
- * @return {?string} Rendered markup to be inserted into the DOM.
- * @final
- * @internal
- */
- mountComponent: ReactPerf.measure(
- 'ReactCompositeComponent',
- 'mountComponent',
- function(rootID, transaction, mountDepth) {
- ReactComponent.Mixin.mountComponent.call(
- this,
- rootID,
- transaction,
- mountDepth
- );
- this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING;
-
- if (this.__reactAutoBindMap) {
- this._bindAutoBindMethods();
- }
-
- this.context = this._processContext(this._currentElement._context);
- this.props = this._processProps(this.props);
-
- this.state = this.getInitialState ? this.getInitialState() : null;
- ("production" !== "development" ? invariant(
- typeof this.state === 'object' && !Array.isArray(this.state),
- '%s.getInitialState(): must return an object or null',
- this.constructor.displayName || 'ReactCompositeComponent'
- ) : invariant(typeof this.state === 'object' && !Array.isArray(this.state)));
-
- this._pendingState = null;
- this._pendingForceUpdate = false;
-
- if (this.componentWillMount) {
- this.componentWillMount();
- // When mounting, calls to `setState` by `componentWillMount` will set
- // `this._pendingState` without triggering a re-render.
- if (this._pendingState) {
- this.state = this._pendingState;
- this._pendingState = null;
- }
- }
-
- this._renderedComponent = instantiateReactComponent(
- this._renderValidatedComponent(),
- this._currentElement.type // The wrapping type
- );
-
- // Done with mounting, `setState` will now trigger UI changes.
- this._compositeLifeCycleState = null;
- var markup = this._renderedComponent.mountComponent(
- rootID,
- transaction,
- mountDepth + 1
- );
- if (this.componentDidMount) {
- transaction.getReactMountReady().enqueue(this.componentDidMount, this);
- }
- return markup;
- }
- ),
-
- /**
- * Releases any resources allocated by `mountComponent`.
- *
- * @final
- * @internal
- */
- unmountComponent: function() {
- this._compositeLifeCycleState = CompositeLifeCycle.UNMOUNTING;
- if (this.componentWillUnmount) {
- this.componentWillUnmount();
- }
- this._compositeLifeCycleState = null;
-
- this._renderedComponent.unmountComponent();
- this._renderedComponent = null;
-
- ReactComponent.Mixin.unmountComponent.call(this);
-
- // Some existing components rely on this.props even after they've been
- // destroyed (in event handlers).
- // TODO: this.props = null;
- // TODO: this.state = null;
- },
-
- /**
- * Sets a subset of the state. Always use this or `replaceState` to mutate
- * state. You should treat `this.state` as immutable.
- *
- * There is no guarantee that `this.state` will be immediately updated, so
- * accessing `this.state` after calling this method may return the old value.
- *
- * There is no guarantee that calls to `setState` will run synchronously,
- * as they may eventually be batched together. You can provide an optional
- * callback that will be executed when the call to setState is actually
- * completed.
- *
- * @param {object} partialState Next partial state to be merged with state.
- * @param {?function} callback Called after state is updated.
- * @final
- * @protected
- */
- setState: function(partialState, callback) {
- ("production" !== "development" ? invariant(
- typeof partialState === 'object' || partialState == null,
- 'setState(...): takes an object of state variables to update.'
- ) : invariant(typeof partialState === 'object' || partialState == null));
- if ("production" !== "development"){
- ("production" !== "development" ? warning(
- partialState != null,
- 'setState(...): You passed an undefined or null state object; ' +
- 'instead, use forceUpdate().'
- ) : null);
- }
- // Merge with `_pendingState` if it exists, otherwise with existing state.
- this.replaceState(
- assign({}, this._pendingState || this.state, partialState),
- callback
- );
- },
-
- /**
- * Replaces all of the state. Always use this or `setState` to mutate state.
- * You should treat `this.state` as immutable.
- *
- * There is no guarantee that `this.state` will be immediately updated, so
- * accessing `this.state` after calling this method may return the old value.
- *
- * @param {object} completeState Next state.
- * @param {?function} callback Called after state is updated.
- * @final
- * @protected
- */
- replaceState: function(completeState, callback) {
- validateLifeCycleOnReplaceState(this);
- this._pendingState = completeState;
- if (this._compositeLifeCycleState !== CompositeLifeCycle.MOUNTING) {
- // If we're in a componentWillMount handler, don't enqueue a rerender
- // because ReactUpdates assumes we're in a browser context (which is wrong
- // for server rendering) and we're about to do a render anyway.
- // TODO: The callback here is ignored when setState is called from
- // componentWillMount. Either fix it or disallow doing so completely in
- // favor of getInitialState.
- ReactUpdates.enqueueUpdate(this, callback);
- }
- },
-
- /**
- * Filters the context object to only contain keys specified in
- * `contextTypes`, and asserts that they are valid.
- *
- * @param {object} context
- * @return {?object}
- * @private
- */
- _processContext: function(context) {
- var maskedContext = null;
- var contextTypes = this.constructor.contextTypes;
- if (contextTypes) {
- maskedContext = {};
- for (var contextName in contextTypes) {
- maskedContext[contextName] = context[contextName];
- }
- if ("production" !== "development") {
- this._checkPropTypes(
- contextTypes,
- maskedContext,
- ReactPropTypeLocations.context
- );
- }
- }
- return maskedContext;
- },
-
- /**
- * @param {object} currentContext
- * @return {object}
- * @private
- */
- _processChildContext: function(currentContext) {
- var childContext = this.getChildContext && this.getChildContext();
- var displayName = this.constructor.displayName || 'ReactCompositeComponent';
- if (childContext) {
- ("production" !== "development" ? invariant(
- typeof this.constructor.childContextTypes === 'object',
- '%s.getChildContext(): childContextTypes must be defined in order to ' +
- 'use getChildContext().',
- displayName
- ) : invariant(typeof this.constructor.childContextTypes === 'object'));
- if ("production" !== "development") {
- this._checkPropTypes(
- this.constructor.childContextTypes,
- childContext,
- ReactPropTypeLocations.childContext
- );
- }
- for (var name in childContext) {
- ("production" !== "development" ? invariant(
- name in this.constructor.childContextTypes,
- '%s.getChildContext(): key "%s" is not defined in childContextTypes.',
- displayName,
- name
- ) : invariant(name in this.constructor.childContextTypes));
- }
- return assign({}, currentContext, childContext);
- }
- return currentContext;
- },
-
- /**
- * Processes props by setting default values for unspecified props and
- * asserting that the props are valid. Does not mutate its argument; returns
- * a new props object with defaults merged in.
- *
- * @param {object} newProps
- * @return {object}
- * @private
- */
- _processProps: function(newProps) {
- if ("production" !== "development") {
- var propTypes = this.constructor.propTypes;
- if (propTypes) {
- this._checkPropTypes(propTypes, newProps, ReactPropTypeLocations.prop);
- }
- }
- return newProps;
- },
-
- /**
- * Assert that the props are valid
- *
- * @param {object} propTypes Map of prop name to a ReactPropType
- * @param {object} props
- * @param {string} location e.g. "prop", "context", "child context"
- * @private
- */
- _checkPropTypes: function(propTypes, props, location) {
- // TODO: Stop validating prop types here and only use the element
- // validation.
- var componentName = this.constructor.displayName;
- for (var propName in propTypes) {
- if (propTypes.hasOwnProperty(propName)) {
- var error =
- propTypes[propName](props, propName, componentName, location);
- if (error instanceof Error) {
- // We may want to extend this logic for similar errors in
- // renderComponent calls, so I'm abstracting it away into
- // a function to minimize refactoring in the future
- var addendum = getDeclarationErrorAddendum(this);
- ("production" !== "development" ? warning(false, error.message + addendum) : null);
- }
- }
- }
- },
-
- /**
- * If any of `_pendingElement`, `_pendingState`, or `_pendingForceUpdate`
- * is set, update the component.
- *
- * @param {ReactReconcileTransaction} transaction
- * @internal
- */
- performUpdateIfNecessary: function(transaction) {
- var compositeLifeCycleState = this._compositeLifeCycleState;
- // Do not trigger a state transition if we are in the middle of mounting or
- // receiving props because both of those will already be doing this.
- if (compositeLifeCycleState === CompositeLifeCycle.MOUNTING ||
- compositeLifeCycleState === CompositeLifeCycle.RECEIVING_PROPS) {
- return;
- }
-
- if (this._pendingElement == null &&
- this._pendingState == null &&
- !this._pendingForceUpdate) {
- return;
- }
-
- var nextContext = this.context;
- var nextProps = this.props;
- var nextElement = this._currentElement;
- if (this._pendingElement != null) {
- nextElement = this._pendingElement;
- nextContext = this._processContext(nextElement._context);
- nextProps = this._processProps(nextElement.props);
- this._pendingElement = null;
-
- this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_PROPS;
- if (this.componentWillReceiveProps) {
- this.componentWillReceiveProps(nextProps, nextContext);
- }
- }
-
- this._compositeLifeCycleState = null;
-
- var nextState = this._pendingState || this.state;
- this._pendingState = null;
-
- var shouldUpdate =
- this._pendingForceUpdate ||
- !this.shouldComponentUpdate ||
- this.shouldComponentUpdate(nextProps, nextState, nextContext);
-
- if ("production" !== "development") {
- if (typeof shouldUpdate === "undefined") {
- console.warn(
- (this.constructor.displayName || 'ReactCompositeComponent') +
- '.shouldComponentUpdate(): Returned undefined instead of a ' +
- 'boolean value. Make sure to return true or false.'
- );
- }
- }
-
- if (shouldUpdate) {
- this._pendingForceUpdate = false;
- // Will set `this.props`, `this.state` and `this.context`.
- this._performComponentUpdate(
- nextElement,
- nextProps,
- nextState,
- nextContext,
- transaction
- );
- } else {
- // If it's determined that a component should not update, we still want
- // to set props and state.
- this._currentElement = nextElement;
- this.props = nextProps;
- this.state = nextState;
- this.context = nextContext;
-
- // Owner cannot change because shouldUpdateReactComponent doesn't allow
- // it. TODO: Remove this._owner completely.
- this._owner = nextElement._owner;
- }
- },
-
- /**
- * Merges new props and state, notifies delegate methods of update and
- * performs update.
- *
- * @param {ReactElement} nextElement Next element
- * @param {object} nextProps Next public object to set as properties.
- * @param {?object} nextState Next object to set as state.
- * @param {?object} nextContext Next public object to set as context.
- * @param {ReactReconcileTransaction} transaction
- * @private
- */
- _performComponentUpdate: function(
- nextElement,
- nextProps,
- nextState,
- nextContext,
- transaction
- ) {
- var prevElement = this._currentElement;
- var prevProps = this.props;
- var prevState = this.state;
- var prevContext = this.context;
-
- if (this.componentWillUpdate) {
- this.componentWillUpdate(nextProps, nextState, nextContext);
- }
-
- this._currentElement = nextElement;
- this.props = nextProps;
- this.state = nextState;
- this.context = nextContext;
-
- // Owner cannot change because shouldUpdateReactComponent doesn't allow
- // it. TODO: Remove this._owner completely.
- this._owner = nextElement._owner;
-
- this.updateComponent(
- transaction,
- prevElement
- );
-
- if (this.componentDidUpdate) {
- transaction.getReactMountReady().enqueue(
- this.componentDidUpdate.bind(this, prevProps, prevState, prevContext),
- this
- );
- }
- },
-
- receiveComponent: function(nextElement, transaction) {
- if (nextElement === this._currentElement &&
- nextElement._owner != null) {
- // Since elements are immutable after the owner is rendered,
- // we can do a cheap identity compare here to determine if this is a
- // superfluous reconcile. It's possible for state to be mutable but such
- // change should trigger an update of the owner which would recreate
- // the element. We explicitly check for the existence of an owner since
- // it's possible for a element created outside a composite to be
- // deeply mutated and reused.
- return;
- }
-
- ReactComponent.Mixin.receiveComponent.call(
- this,
- nextElement,
- transaction
- );
- },
-
- /**
- * Updates the component's currently mounted DOM representation.
- *
- * By default, this implements React's rendering and reconciliation algorithm.
- * Sophisticated clients may wish to override this.
- *
- * @param {ReactReconcileTransaction} transaction
- * @param {ReactElement} prevElement
- * @internal
- * @overridable
- */
- updateComponent: ReactPerf.measure(
- 'ReactCompositeComponent',
- 'updateComponent',
- function(transaction, prevParentElement) {
- ReactComponent.Mixin.updateComponent.call(
- this,
- transaction,
- prevParentElement
- );
-
- var prevComponentInstance = this._renderedComponent;
- var prevElement = prevComponentInstance._currentElement;
- var nextElement = this._renderValidatedComponent();
- if (shouldUpdateReactComponent(prevElement, nextElement)) {
- prevComponentInstance.receiveComponent(nextElement, transaction);
- } else {
- // These two IDs are actually the same! But nothing should rely on that.
- var thisID = this._rootNodeID;
- var prevComponentID = prevComponentInstance._rootNodeID;
- prevComponentInstance.unmountComponent();
- this._renderedComponent = instantiateReactComponent(
- nextElement,
- this._currentElement.type
- );
- var nextMarkup = this._renderedComponent.mountComponent(
- thisID,
- transaction,
- this._mountDepth + 1
- );
- ReactComponent.BackendIDOperations.dangerouslyReplaceNodeWithMarkupByID(
- prevComponentID,
- nextMarkup
- );
- }
- }
- ),
-
- /**
- * Forces an update. This should only be invoked when it is known with
- * certainty that we are **not** in a DOM transaction.
- *
- * You may want to call this when you know that some deeper aspect of the
- * component's state has changed but `setState` was not called.
- *
- * This will not invoke `shouldUpdateComponent`, but it will invoke
- * `componentWillUpdate` and `componentDidUpdate`.
- *
- * @param {?function} callback Called after update is complete.
- * @final
- * @protected
- */
- forceUpdate: function(callback) {
- var compositeLifeCycleState = this._compositeLifeCycleState;
- ("production" !== "development" ? invariant(
- this.isMounted() ||
- compositeLifeCycleState === CompositeLifeCycle.MOUNTING,
- 'forceUpdate(...): Can only force an update on mounted or mounting ' +
- 'components.'
- ) : invariant(this.isMounted() ||
- compositeLifeCycleState === CompositeLifeCycle.MOUNTING));
- ("production" !== "development" ? invariant(
- compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING &&
- ReactCurrentOwner.current == null,
- 'forceUpdate(...): Cannot force an update while unmounting component ' +
- 'or within a `render` function.'
- ) : invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING &&
- ReactCurrentOwner.current == null));
- this._pendingForceUpdate = true;
- ReactUpdates.enqueueUpdate(this, callback);
- },
-
- /**
- * @private
- */
- _renderValidatedComponent: ReactPerf.measure(
- 'ReactCompositeComponent',
- '_renderValidatedComponent',
- function() {
- var renderedComponent;
- var previousContext = ReactContext.current;
- ReactContext.current = this._processChildContext(
- this._currentElement._context
- );
- ReactCurrentOwner.current = this;
- try {
- renderedComponent = this.render();
- if (renderedComponent === null || renderedComponent === false) {
- renderedComponent = ReactEmptyComponent.getEmptyComponent();
- ReactEmptyComponent.registerNullComponentID(this._rootNodeID);
- } else {
- ReactEmptyComponent.deregisterNullComponentID(this._rootNodeID);
- }
- } finally {
- ReactContext.current = previousContext;
- ReactCurrentOwner.current = null;
- }
- ("production" !== "development" ? invariant(
- ReactElement.isValidElement(renderedComponent),
- '%s.render(): A valid ReactComponent must be returned. You may have ' +
- 'returned undefined, an array or some other invalid object.',
- this.constructor.displayName || 'ReactCompositeComponent'
- ) : invariant(ReactElement.isValidElement(renderedComponent)));
- return renderedComponent;
- }
- ),
-
- /**
- * @private
- */
- _bindAutoBindMethods: function() {
- for (var autoBindKey in this.__reactAutoBindMap) {
- if (!this.__reactAutoBindMap.hasOwnProperty(autoBindKey)) {
- continue;
- }
- var method = this.__reactAutoBindMap[autoBindKey];
- this[autoBindKey] = this._bindAutoBindMethod(ReactErrorUtils.guard(
- method,
- this.constructor.displayName + '.' + autoBindKey
- ));
- }
- },
-
- /**
- * Binds a method to the component.
- *
- * @param {function} method Method to be bound.
- * @private
- */
- _bindAutoBindMethod: function(method) {
- var component = this;
- var boundMethod = method.bind(component);
- if ("production" !== "development") {
- boundMethod.__reactBoundContext = component;
- boundMethod.__reactBoundMethod = method;
- boundMethod.__reactBoundArguments = null;
- var componentName = component.constructor.displayName;
- var _bind = boundMethod.bind;
- boundMethod.bind = function(newThis ) {for (var args=[],$__0=1,$__1=arguments.length;$__0<$__1;$__0++) args.push(arguments[$__0]);
- // User is trying to bind() an autobound method; we effectively will
- // ignore the value of "this" that the user is trying to use, so
- // let's warn.
- if (newThis !== component && newThis !== null) {
- monitorCodeUse('react_bind_warning', { component: componentName });
- console.warn(
- 'bind(): React component methods may only be bound to the ' +
- 'component instance. See ' + componentName
- );
- } else if (!args.length) {
- monitorCodeUse('react_bind_warning', { component: componentName });
- console.warn(
- 'bind(): You are binding a component method to the component. ' +
- 'React does this for you automatically in a high-performance ' +
- 'way, so you can safely remove this call. See ' + componentName
- );
- return boundMethod;
- }
- var reboundMethod = _bind.apply(boundMethod, arguments);
- reboundMethod.__reactBoundContext = component;
- reboundMethod.__reactBoundMethod = method;
- reboundMethod.__reactBoundArguments = args;
- return reboundMethod;
- };
- }
- return boundMethod;
- }
-};
-
-var ReactCompositeComponentBase = function() {};
-assign(
- ReactCompositeComponentBase.prototype,
- ReactComponent.Mixin,
- ReactOwner.Mixin,
- ReactPropTransferer.Mixin,
- ReactCompositeComponentMixin
-);
-
-/**
- * Module for creating composite components.
- *
- * @class ReactCompositeComponent
- * @extends ReactComponent
- * @extends ReactOwner
- * @extends ReactPropTransferer
- */
-var ReactCompositeComponent = {
-
- LifeCycle: CompositeLifeCycle,
-
- Base: ReactCompositeComponentBase,
-
- /**
- * Creates a composite component class given a class specification.
- *
- * @param {object} spec Class specification (which must define `render`).
- * @return {function} Component constructor function.
- * @public
- */
- createClass: function(spec) {
- var Constructor = function(props) {
- // This constructor is overridden by mocks. The argument is used
- // by mocks to assert on what gets mounted. This will later be used
- // by the stand-alone class implementation.
- };
- Constructor.prototype = new ReactCompositeComponentBase();
- Constructor.prototype.constructor = Constructor;
-
- injectedMixins.forEach(
- mixSpecIntoComponent.bind(null, Constructor)
- );
-
- mixSpecIntoComponent(Constructor, spec);
-
- // Initialize the defaultProps property after all mixins have been merged
- if (Constructor.getDefaultProps) {
- Constructor.defaultProps = Constructor.getDefaultProps();
- }
-
- ("production" !== "development" ? invariant(
- Constructor.prototype.render,
- 'createClass(...): Class specification must implement a `render` method.'
- ) : invariant(Constructor.prototype.render));
-
- if ("production" !== "development") {
- if (Constructor.prototype.componentShouldUpdate) {
- monitorCodeUse(
- 'react_component_should_update_warning',
- { component: spec.displayName }
- );
- console.warn(
- (spec.displayName || 'A component') + ' has a method called ' +
- 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
- 'The name is phrased as a question because the function is ' +
- 'expected to return a value.'
- );
- }
- }
-
- // Reduce time spent doing lookups by setting these on the prototype.
- for (var methodName in ReactCompositeComponentInterface) {
- if (!Constructor.prototype[methodName]) {
- Constructor.prototype[methodName] = null;
- }
- }
-
- if ("production" !== "development") {
- return ReactLegacyElement.wrapFactory(
- ReactElementValidator.createFactory(Constructor)
- );
- }
- return ReactLegacyElement.wrapFactory(
- ReactElement.createFactory(Constructor)
- );
- },
-
- injection: {
- injectMixin: function(mixin) {
- injectedMixins.push(mixin);
- }
- }
-};
-
-module.exports = ReactCompositeComponent;
-
-},{"./Object.assign":29,"./ReactComponent":37,"./ReactContext":41,"./ReactCurrentOwner":42,"./ReactElement":58,"./ReactElementValidator":59,"./ReactEmptyComponent":60,"./ReactErrorUtils":61,"./ReactLegacyElement":67,"./ReactOwner":74,"./ReactPerf":75,"./ReactPropTransferer":76,"./ReactPropTypeLocationNames":77,"./ReactPropTypeLocations":78,"./ReactUpdates":91,"./instantiateReactComponent":139,"./invariant":140,"./keyMirror":146,"./keyOf":147,"./mapObject":148,"./monitorCodeUse":150,"./shouldUpdateReactComponent":156,"./warning":160}],41:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactContext
- */
-
-"use strict";
-
-var assign = _dereq_("./Object.assign");
-
-/**
- * Keeps track of the current context.
- *
- * The context is automatically passed down the component ownership hierarchy
- * and is accessible via `this.context` on ReactCompositeComponents.
- */
-var ReactContext = {
-
- /**
- * @internal
- * @type {object}
- */
- current: {},
-
- /**
- * Temporarily extends the current context while executing scopedCallback.
- *
- * A typical use case might look like
- *
- * render: function() {
- * var children = ReactContext.withContext({foo: 'foo'}, () => (
- *
- * ));
- * return <div>{children}</div>;
- * }
- *
- * @param {object} newContext New context to merge into the existing context
- * @param {function} scopedCallback Callback to run with the new context
- * @return {ReactComponent|array<ReactComponent>}
- */
- withContext: function(newContext, scopedCallback) {
- var result;
- var previousContext = ReactContext.current;
- ReactContext.current = assign({}, previousContext, newContext);
- try {
- result = scopedCallback();
- } finally {
- ReactContext.current = previousContext;
- }
- return result;
- }
-
-};
-
-module.exports = ReactContext;
-
-},{"./Object.assign":29}],42:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactCurrentOwner
- */
-
-"use strict";
-
-/**
- * Keeps track of the current owner.
- *
- * The current owner is the component who should own any components that are
- * currently being constructed.
- *
- * The depth indicate how many composite components are above this render level.
- */
-var ReactCurrentOwner = {
-
- /**
- * @internal
- * @type {ReactComponent}
- */
- current: null
-
-};
-
-module.exports = ReactCurrentOwner;
-
-},{}],43:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOM
- * @typechecks static-only
- */
-
-"use strict";
-
-var ReactElement = _dereq_("./ReactElement");
-var ReactElementValidator = _dereq_("./ReactElementValidator");
-var ReactLegacyElement = _dereq_("./ReactLegacyElement");
-
-var mapObject = _dereq_("./mapObject");
-
-/**
- * Create a factory that creates HTML tag elements.
- *
- * @param {string} tag Tag name (e.g. `div`).
- * @private
- */
-function createDOMFactory(tag) {
- if ("production" !== "development") {
- return ReactLegacyElement.markNonLegacyFactory(
- ReactElementValidator.createFactory(tag)
- );
- }
- return ReactLegacyElement.markNonLegacyFactory(
- ReactElement.createFactory(tag)
- );
-}
-
-/**
- * Creates a mapping from supported HTML tags to `ReactDOMComponent` classes.
- * This is also accessible via `React.DOM`.
- *
- * @public
- */
-var ReactDOM = mapObject({
- a: 'a',
- abbr: 'abbr',
- address: 'address',
- area: 'area',
- article: 'article',
- aside: 'aside',
- audio: 'audio',
- b: 'b',
- base: 'base',
- bdi: 'bdi',
- bdo: 'bdo',
- big: 'big',
- blockquote: 'blockquote',
- body: 'body',
- br: 'br',
- button: 'button',
- canvas: 'canvas',
- caption: 'caption',
- cite: 'cite',
- code: 'code',
- col: 'col',
- colgroup: 'colgroup',
- data: 'data',
- datalist: 'datalist',
- dd: 'dd',
- del: 'del',
- details: 'details',
- dfn: 'dfn',
- dialog: 'dialog',
- div: 'div',
- dl: 'dl',
- dt: 'dt',
- em: 'em',
- embed: 'embed',
- fieldset: 'fieldset',
- figcaption: 'figcaption',
- figure: 'figure',
- footer: 'footer',
- form: 'form',
- h1: 'h1',
- h2: 'h2',
- h3: 'h3',
- h4: 'h4',
- h5: 'h5',
- h6: 'h6',
- head: 'head',
- header: 'header',
- hr: 'hr',
- html: 'html',
- i: 'i',
- iframe: 'iframe',
- img: 'img',
- input: 'input',
- ins: 'ins',
- kbd: 'kbd',
- keygen: 'keygen',
- label: 'label',
- legend: 'legend',
- li: 'li',
- link: 'link',
- main: 'main',
- map: 'map',
- mark: 'mark',
- menu: 'menu',
- menuitem: 'menuitem',
- meta: 'meta',
- meter: 'meter',
- nav: 'nav',
- noscript: 'noscript',
- object: 'object',
- ol: 'ol',
- optgroup: 'optgroup',
- option: 'option',
- output: 'output',
- p: 'p',
- param: 'param',
- picture: 'picture',
- pre: 'pre',
- progress: 'progress',
- q: 'q',
- rp: 'rp',
- rt: 'rt',
- ruby: 'ruby',
- s: 's',
- samp: 'samp',
- script: 'script',
- section: 'section',
- select: 'select',
- small: 'small',
- source: 'source',
- span: 'span',
- strong: 'strong',
- style: 'style',
- sub: 'sub',
- summary: 'summary',
- sup: 'sup',
- table: 'table',
- tbody: 'tbody',
- td: 'td',
- textarea: 'textarea',
- tfoot: 'tfoot',
- th: 'th',
- thead: 'thead',
- time: 'time',
- title: 'title',
- tr: 'tr',
- track: 'track',
- u: 'u',
- ul: 'ul',
- 'var': 'var',
- video: 'video',
- wbr: 'wbr',
-
- // SVG
- circle: 'circle',
- defs: 'defs',
- ellipse: 'ellipse',
- g: 'g',
- line: 'line',
- linearGradient: 'linearGradient',
- mask: 'mask',
- path: 'path',
- pattern: 'pattern',
- polygon: 'polygon',
- polyline: 'polyline',
- radialGradient: 'radialGradient',
- rect: 'rect',
- stop: 'stop',
- svg: 'svg',
- text: 'text',
- tspan: 'tspan'
-
-}, createDOMFactory);
-
-module.exports = ReactDOM;
-
-},{"./ReactElement":58,"./ReactElementValidator":59,"./ReactLegacyElement":67,"./mapObject":148}],44:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOMButton
- */
-
-"use strict";
-
-var AutoFocusMixin = _dereq_("./AutoFocusMixin");
-var ReactBrowserComponentMixin = _dereq_("./ReactBrowserComponentMixin");
-var ReactCompositeComponent = _dereq_("./ReactCompositeComponent");
-var ReactElement = _dereq_("./ReactElement");
-var ReactDOM = _dereq_("./ReactDOM");
-
-var keyMirror = _dereq_("./keyMirror");
-
-// Store a reference to the <button> `ReactDOMComponent`. TODO: use string
-var button = ReactElement.createFactory(ReactDOM.button.type);
-
-var mouseListenerNames = keyMirror({
- onClick: true,
- onDoubleClick: true,
- onMouseDown: true,
- onMouseMove: true,
- onMouseUp: true,
- onClickCapture: true,
- onDoubleClickCapture: true,
- onMouseDownCapture: true,
- onMouseMoveCapture: true,
- onMouseUpCapture: true
-});
-
-/**
- * Implements a <button> native component that does not receive mouse events
- * when `disabled` is set.
- */
-var ReactDOMButton = ReactCompositeComponent.createClass({
- displayName: 'ReactDOMButton',
-
- mixins: [AutoFocusMixin, ReactBrowserComponentMixin],
-
- render: function() {
- var props = {};
-
- // Copy the props; except the mouse listeners if we're disabled
- for (var key in this.props) {
- if (this.props.hasOwnProperty(key) &&
- (!this.props.disabled || !mouseListenerNames[key])) {
- props[key] = this.props[key];
- }
- }
-
- return button(props, this.props.children);
- }
-
-});
-
-module.exports = ReactDOMButton;
-
-},{"./AutoFocusMixin":2,"./ReactBrowserComponentMixin":32,"./ReactCompositeComponent":40,"./ReactDOM":43,"./ReactElement":58,"./keyMirror":146}],45:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOMComponent
- * @typechecks static-only
- */
-
-"use strict";
-
-var CSSPropertyOperations = _dereq_("./CSSPropertyOperations");
-var DOMProperty = _dereq_("./DOMProperty");
-var DOMPropertyOperations = _dereq_("./DOMPropertyOperations");
-var ReactBrowserComponentMixin = _dereq_("./ReactBrowserComponentMixin");
-var ReactComponent = _dereq_("./ReactComponent");
-var ReactBrowserEventEmitter = _dereq_("./ReactBrowserEventEmitter");
-var ReactMount = _dereq_("./ReactMount");
-var ReactMultiChild = _dereq_("./ReactMultiChild");
-var ReactPerf = _dereq_("./ReactPerf");
-
-var assign = _dereq_("./Object.assign");
-var escapeTextForBrowser = _dereq_("./escapeTextForBrowser");
-var invariant = _dereq_("./invariant");
-var isEventSupported = _dereq_("./isEventSupported");
-var keyOf = _dereq_("./keyOf");
-var monitorCodeUse = _dereq_("./monitorCodeUse");
-
-var deleteListener = ReactBrowserEventEmitter.deleteListener;
-var listenTo = ReactBrowserEventEmitter.listenTo;
-var registrationNameModules = ReactBrowserEventEmitter.registrationNameModules;
-
-// For quickly matching children type, to test if can be treated as content.
-var CONTENT_TYPES = {'string': true, 'number': true};
-
-var STYLE = keyOf({style: null});
-
-var ELEMENT_NODE_TYPE = 1;
-
-/**
- * @param {?object} props
- */
-function assertValidProps(props) {
- if (!props) {
- return;
- }
- // Note the use of `==` which checks for null or undefined.
- ("production" !== "development" ? invariant(
- props.children == null || props.dangerouslySetInnerHTML == null,
- 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.'
- ) : invariant(props.children == null || props.dangerouslySetInnerHTML == null));
- if ("production" !== "development") {
- if (props.contentEditable && props.children != null) {
- console.warn(
- 'A component is `contentEditable` and contains `children` managed by ' +
- 'React. It is now your responsibility to guarantee that none of those '+
- 'nodes are unexpectedly modified or duplicated. This is probably not ' +
- 'intentional.'
- );
- }
- }
- ("production" !== "development" ? invariant(
- props.style == null || typeof props.style === 'object',
- 'The `style` prop expects a mapping from style properties to values, ' +
- 'not a string.'
- ) : invariant(props.style == null || typeof props.style === 'object'));
-}
-
-function putListener(id, registrationName, listener, transaction) {
- if ("production" !== "development") {
- // IE8 has no API for event capturing and the `onScroll` event doesn't
- // bubble.
- if (registrationName === 'onScroll' &&
- !isEventSupported('scroll', true)) {
- monitorCodeUse('react_no_scroll_event');
- console.warn('This browser doesn\'t support the `onScroll` event');
- }
- }
- var container = ReactMount.findReactContainerForID(id);
- if (container) {
- var doc = container.nodeType === ELEMENT_NODE_TYPE ?
- container.ownerDocument :
- container;
- listenTo(registrationName, doc);
- }
- transaction.getPutListenerQueue().enqueuePutListener(
- id,
- registrationName,
- listener
- );
-}
-
-// For HTML, certain tags should omit their close tag. We keep a whitelist for
-// those special cased tags.
-
-var omittedCloseTags = {
- 'area': true,
- 'base': true,
- 'br': true,
- 'col': true,
- 'embed': true,
- 'hr': true,
- 'img': true,
- 'input': true,
- 'keygen': true,
- 'link': true,
- 'meta': true,
- 'param': true,
- 'source': true,
- 'track': true,
- 'wbr': true
- // NOTE: menuitem's close tag should be omitted, but that causes problems.
-};
-
-// We accept any tag to be rendered but since this gets injected into abitrary
-// HTML, we want to make sure that it's a safe tag.
-// http://www.w3.org/TR/REC-xml/#NT-Name
-
-var VALID_TAG_REGEX = /^[a-zA-Z][a-zA-Z:_\.\-\d]*$/; // Simplified subset
-var validatedTagCache = {};
-var hasOwnProperty = {}.hasOwnProperty;
-
-function validateDangerousTag(tag) {
- if (!hasOwnProperty.call(validatedTagCache, tag)) {
- ("production" !== "development" ? invariant(VALID_TAG_REGEX.test(tag), 'Invalid tag: %s', tag) : invariant(VALID_TAG_REGEX.test(tag)));
- validatedTagCache[tag] = true;
- }
-}
-
-/**
- * Creates a new React class that is idempotent and capable of containing other
- * React components. It accepts event listeners and DOM properties that are
- * valid according to `DOMProperty`.
- *
- * - Event listeners: `onClick`, `onMouseDown`, etc.
- * - DOM properties: `className`, `name`, `title`, etc.
- *
- * The `style` property functions differently from the DOM API. It accepts an
- * object mapping of style properties to values.
- *
- * @constructor ReactDOMComponent
- * @extends ReactComponent
- * @extends ReactMultiChild
- */
-function ReactDOMComponent(tag) {
- validateDangerousTag(tag);
- this._tag = tag;
- this.tagName = tag.toUpperCase();
-}
-
-ReactDOMComponent.displayName = 'ReactDOMComponent';
-
-ReactDOMComponent.Mixin = {
-
- /**
- * Generates root tag markup then recurses. This method has side effects and
- * is not idempotent.
- *
- * @internal
- * @param {string} rootID The root DOM ID for this node.
- * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
- * @param {number} mountDepth number of components in the owner hierarchy
- * @return {string} The computed markup.
- */
- mountComponent: ReactPerf.measure(
- 'ReactDOMComponent',
- 'mountComponent',
- function(rootID, transaction, mountDepth) {
- ReactComponent.Mixin.mountComponent.call(
- this,
- rootID,
- transaction,
- mountDepth
- );
- assertValidProps(this.props);
- var closeTag = omittedCloseTags[this._tag] ? '' : '</' + this._tag + '>';
- return (
- this._createOpenTagMarkupAndPutListeners(transaction) +
- this._createContentMarkup(transaction) +
- closeTag
- );
- }
- ),
-
- /**
- * Creates markup for the open tag and all attributes.
- *
- * This method has side effects because events get registered.
- *
- * Iterating over object properties is faster than iterating over arrays.
- * @see http://jsperf.com/obj-vs-arr-iteration
- *
- * @private
- * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
- * @return {string} Markup of opening tag.
- */
- _createOpenTagMarkupAndPutListeners: function(transaction) {
- var props = this.props;
- var ret = '<' + this._tag;
-
- for (var propKey in props) {
- if (!props.hasOwnProperty(propKey)) {
- continue;
- }
- var propValue = props[propKey];
- if (propValue == null) {
- continue;
- }
- if (registrationNameModules.hasOwnProperty(propKey)) {
- putListener(this._rootNodeID, propKey, propValue, transaction);
- } else {
- if (propKey === STYLE) {
- if (propValue) {
- propValue = props.style = assign({}, props.style);
- }
- propValue = CSSPropertyOperations.createMarkupForStyles(propValue);
- }
- var markup =
- DOMPropertyOperations.createMarkupForProperty(propKey, propValue);
- if (markup) {
- ret += ' ' + markup;
- }
- }
- }
-
- // For static pages, no need to put React ID and checksum. Saves lots of
- // bytes.
- if (transaction.renderToStaticMarkup) {
- return ret + '>';
- }
-
- var markupForID = DOMPropertyOperations.createMarkupForID(this._rootNodeID);
- return ret + ' ' + markupForID + '>';
- },
-
- /**
- * Creates markup for the content between the tags.
- *
- * @private
- * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
- * @return {string} Content markup.
- */
- _createContentMarkup: function(transaction) {
- // Intentional use of != to avoid catching zero/false.
- var innerHTML = this.props.dangerouslySetInnerHTML;
- if (innerHTML != null) {
- if (innerHTML.__html != null) {
- return innerHTML.__html;
- }
- } else {
- var contentToUse =
- CONTENT_TYPES[typeof this.props.children] ? this.props.children : null;
- var childrenToUse = contentToUse != null ? null : this.props.children;
- if (contentToUse != null) {
- return escapeTextForBrowser(contentToUse);
- } else if (childrenToUse != null) {
- var mountImages = this.mountChildren(
- childrenToUse,
- transaction
- );
- return mountImages.join('');
- }
- }
- return '';
- },
-
- receiveComponent: function(nextElement, transaction) {
- if (nextElement === this._currentElement &&
- nextElement._owner != null) {
- // Since elements are immutable after the owner is rendered,
- // we can do a cheap identity compare here to determine if this is a
- // superfluous reconcile. It's possible for state to be mutable but such
- // change should trigger an update of the owner which would recreate
- // the element. We explicitly check for the existence of an owner since
- // it's possible for a element created outside a composite to be
- // deeply mutated and reused.
- return;
- }
-
- ReactComponent.Mixin.receiveComponent.call(
- this,
- nextElement,
- transaction
- );
- },
-
- /**
- * Updates a native DOM component after it has already been allocated and
- * attached to the DOM. Reconciles the root DOM node, then recurses.
- *
- * @param {ReactReconcileTransaction} transaction
- * @param {ReactElement} prevElement
- * @internal
- * @overridable
- */
- updateComponent: ReactPerf.measure(
- 'ReactDOMComponent',
- 'updateComponent',
- function(transaction, prevElement) {
- assertValidProps(this._currentElement.props);
- ReactComponent.Mixin.updateComponent.call(
- this,
- transaction,
- prevElement
- );
- this._updateDOMProperties(prevElement.props, transaction);
- this._updateDOMChildren(prevElement.props, transaction);
- }
- ),
-
- /**
- * Reconciles the properties by detecting differences in property values and
- * updating the DOM as necessary. This function is probably the single most
- * critical path for performance optimization.
- *
- * TODO: Benchmark whether checking for changed values in memory actually
- * improves performance (especially statically positioned elements).
- * TODO: Benchmark the effects of putting this at the top since 99% of props
- * do not change for a given reconciliation.
- * TODO: Benchmark areas that can be improved with caching.
- *
- * @private
- * @param {object} lastProps
- * @param {ReactReconcileTransaction} transaction
- */
- _updateDOMProperties: function(lastProps, transaction) {
- var nextProps = this.props;
- var propKey;
- var styleName;
- var styleUpdates;
- for (propKey in lastProps) {
- if (nextProps.hasOwnProperty(propKey) ||
- !lastProps.hasOwnProperty(propKey)) {
- continue;
- }
- if (propKey === STYLE) {
- var lastStyle = lastProps[propKey];
- for (styleName in lastStyle) {
- if (lastStyle.hasOwnProperty(styleName)) {
- styleUpdates = styleUpdates || {};
- styleUpdates[styleName] = '';
- }
- }
- } else if (registrationNameModules.hasOwnProperty(propKey)) {
- deleteListener(this._rootNodeID, propKey);
- } else if (
- DOMProperty.isStandardName[propKey] ||
- DOMProperty.isCustomAttribute(propKey)) {
- ReactComponent.BackendIDOperations.deletePropertyByID(
- this._rootNodeID,
- propKey
- );
- }
- }
- for (propKey in nextProps) {
- var nextProp = nextProps[propKey];
- var lastProp = lastProps[propKey];
- if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp) {
- continue;
- }
- if (propKey === STYLE) {
- if (nextProp) {
- nextProp = nextProps.style = assign({}, nextProp);
- }
- if (lastProp) {
- // Unset styles on `lastProp` but not on `nextProp`.
- for (styleName in lastProp) {
- if (lastProp.hasOwnProperty(styleName) &&
- (!nextProp || !nextProp.hasOwnProperty(styleName))) {
- styleUpdates = styleUpdates || {};
- styleUpdates[styleName] = '';
- }
- }
- // Update styles that changed since `lastProp`.
- for (styleName in nextProp) {
- if (nextProp.hasOwnProperty(styleName) &&
- lastProp[styleName] !== nextProp[styleName]) {
- styleUpdates = styleUpdates || {};
- styleUpdates[styleName] = nextProp[styleName];
- }
- }
- } else {
- // Relies on `updateStylesByID` not mutating `styleUpdates`.
- styleUpdates = nextProp;
- }
- } else if (registrationNameModules.hasOwnProperty(propKey)) {
- putListener(this._rootNodeID, propKey, nextProp, transaction);
- } else if (
- DOMProperty.isStandardName[propKey] ||
- DOMProperty.isCustomAttribute(propKey)) {
- ReactComponent.BackendIDOperations.updatePropertyByID(
- this._rootNodeID,
- propKey,
- nextProp
- );
- }
- }
- if (styleUpdates) {
- ReactComponent.BackendIDOperations.updateStylesByID(
- this._rootNodeID,
- styleUpdates
- );
- }
- },
-
- /**
- * Reconciles the children with the various properties that affect the
- * children content.
- *
- * @param {object} lastProps
- * @param {ReactReconcileTransaction} transaction
- */
- _updateDOMChildren: function(lastProps, transaction) {
- var nextProps = this.props;
-
- var lastContent =
- CONTENT_TYPES[typeof lastProps.children] ? lastProps.children : null;
- var nextContent =
- CONTENT_TYPES[typeof nextProps.children] ? nextProps.children : null;
-
- var lastHtml =
- lastProps.dangerouslySetInnerHTML &&
- lastProps.dangerouslySetInnerHTML.__html;
- var nextHtml =
- nextProps.dangerouslySetInnerHTML &&
- nextProps.dangerouslySetInnerHTML.__html;
-
- // Note the use of `!=` which checks for null or undefined.
- var lastChildren = lastContent != null ? null : lastProps.children;
- var nextChildren = nextContent != null ? null : nextProps.children;
-
- // If we're switching from children to content/html or vice versa, remove
- // the old content
- var lastHasContentOrHtml = lastContent != null || lastHtml != null;
- var nextHasContentOrHtml = nextContent != null || nextHtml != null;
- if (lastChildren != null && nextChildren == null) {
- this.updateChildren(null, transaction);
- } else if (lastHasContentOrHtml && !nextHasContentOrHtml) {
- this.updateTextContent('');
- }
-
- if (nextContent != null) {
- if (lastContent !== nextContent) {
- this.updateTextContent('' + nextContent);
- }
- } else if (nextHtml != null) {
- if (lastHtml !== nextHtml) {
- ReactComponent.BackendIDOperations.updateInnerHTMLByID(
- this._rootNodeID,
- nextHtml
- );
- }
- } else if (nextChildren != null) {
- this.updateChildren(nextChildren, transaction);
- }
- },
-
- /**
- * Destroys all event registrations for this instance. Does not remove from
- * the DOM. That must be done by the parent.
- *
- * @internal
- */
- unmountComponent: function() {
- this.unmountChildren();
- ReactBrowserEventEmitter.deleteAllListeners(this._rootNodeID);
- ReactComponent.Mixin.unmountComponent.call(this);
- }
-
-};
-
-assign(
- ReactDOMComponent.prototype,
- ReactComponent.Mixin,
- ReactDOMComponent.Mixin,
- ReactMultiChild.Mixin,
- ReactBrowserComponentMixin
-);
-
-module.exports = ReactDOMComponent;
-
-},{"./CSSPropertyOperations":6,"./DOMProperty":12,"./DOMPropertyOperations":13,"./Object.assign":29,"./ReactBrowserComponentMixin":32,"./ReactBrowserEventEmitter":33,"./ReactComponent":37,"./ReactMount":70,"./ReactMultiChild":71,"./ReactPerf":75,"./escapeTextForBrowser":123,"./invariant":140,"./isEventSupported":141,"./keyOf":147,"./monitorCodeUse":150}],46:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOMForm
- */
-
-"use strict";
-
-var EventConstants = _dereq_("./EventConstants");
-var LocalEventTrapMixin = _dereq_("./LocalEventTrapMixin");
-var ReactBrowserComponentMixin = _dereq_("./ReactBrowserComponentMixin");
-var ReactCompositeComponent = _dereq_("./ReactCompositeComponent");
-var ReactElement = _dereq_("./ReactElement");
-var ReactDOM = _dereq_("./ReactDOM");
-
-// Store a reference to the <form> `ReactDOMComponent`. TODO: use string
-var form = ReactElement.createFactory(ReactDOM.form.type);
-
-/**
- * Since onSubmit doesn't bubble OR capture on the top level in IE8, we need
- * to capture it on the <form> element itself. There are lots of hacks we could
- * do to accomplish this, but the most reliable is to make <form> a
- * composite component and use `componentDidMount` to attach the event handlers.
- */
-var ReactDOMForm = ReactCompositeComponent.createClass({
- displayName: 'ReactDOMForm',
-
- mixins: [ReactBrowserComponentMixin, LocalEventTrapMixin],
-
- render: function() {
- // TODO: Instead of using `ReactDOM` directly, we should use JSX. However,
- // `jshint` fails to parse JSX so in order for linting to work in the open
- // source repo, we need to just use `ReactDOM.form`.
- return form(this.props);
- },
-
- componentDidMount: function() {
- this.trapBubbledEvent(EventConstants.topLevelTypes.topReset, 'reset');
- this.trapBubbledEvent(EventConstants.topLevelTypes.topSubmit, 'submit');
- }
-});
-
-module.exports = ReactDOMForm;
-
-},{"./EventConstants":17,"./LocalEventTrapMixin":27,"./ReactBrowserComponentMixin":32,"./ReactCompositeComponent":40,"./ReactDOM":43,"./ReactElement":58}],47:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOMIDOperations
- * @typechecks static-only
- */
-
-/*jslint evil: true */
-
-"use strict";
-
-var CSSPropertyOperations = _dereq_("./CSSPropertyOperations");
-var DOMChildrenOperations = _dereq_("./DOMChildrenOperations");
-var DOMPropertyOperations = _dereq_("./DOMPropertyOperations");
-var ReactMount = _dereq_("./ReactMount");
-var ReactPerf = _dereq_("./ReactPerf");
-
-var invariant = _dereq_("./invariant");
-var setInnerHTML = _dereq_("./setInnerHTML");
-
-/**
- * Errors for properties that should not be updated with `updatePropertyById()`.
- *
- * @type {object}
- * @private
- */
-var INVALID_PROPERTY_ERRORS = {
- dangerouslySetInnerHTML:
- '`dangerouslySetInnerHTML` must be set using `updateInnerHTMLByID()`.',
- style: '`style` must be set using `updateStylesByID()`.'
-};
-
-/**
- * Operations used to process updates to DOM nodes. This is made injectable via
- * `ReactComponent.BackendIDOperations`.
- */
-var ReactDOMIDOperations = {
-
- /**
- * Updates a DOM node with new property values. This should only be used to
- * update DOM properties in `DOMProperty`.
- *
- * @param {string} id ID of the node to update.
- * @param {string} name A valid property name, see `DOMProperty`.
- * @param {*} value New value of the property.
- * @internal
- */
- updatePropertyByID: ReactPerf.measure(
- 'ReactDOMIDOperations',
- 'updatePropertyByID',
- function(id, name, value) {
- var node = ReactMount.getNode(id);
- ("production" !== "development" ? invariant(
- !INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
- 'updatePropertyByID(...): %s',
- INVALID_PROPERTY_ERRORS[name]
- ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name)));
-
- // If we're updating to null or undefined, we should remove the property
- // from the DOM node instead of inadvertantly setting to a string. This
- // brings us in line with the same behavior we have on initial render.
- if (value != null) {
- DOMPropertyOperations.setValueForProperty(node, name, value);
- } else {
- DOMPropertyOperations.deleteValueForProperty(node, name);
- }
- }
- ),
-
- /**
- * Updates a DOM node to remove a property. This should only be used to remove
- * DOM properties in `DOMProperty`.
- *
- * @param {string} id ID of the node to update.
- * @param {string} name A property name to remove, see `DOMProperty`.
- * @internal
- */
- deletePropertyByID: ReactPerf.measure(
- 'ReactDOMIDOperations',
- 'deletePropertyByID',
- function(id, name, value) {
- var node = ReactMount.getNode(id);
- ("production" !== "development" ? invariant(
- !INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
- 'updatePropertyByID(...): %s',
- INVALID_PROPERTY_ERRORS[name]
- ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name)));
- DOMPropertyOperations.deleteValueForProperty(node, name, value);
- }
- ),
-
- /**
- * Updates a DOM node with new style values. If a value is specified as '',
- * the corresponding style property will be unset.
- *
- * @param {string} id ID of the node to update.
- * @param {object} styles Mapping from styles to values.
- * @internal
- */
- updateStylesByID: ReactPerf.measure(
- 'ReactDOMIDOperations',
- 'updateStylesByID',
- function(id, styles) {
- var node = ReactMount.getNode(id);
- CSSPropertyOperations.setValueForStyles(node, styles);
- }
- ),
-
- /**
- * Updates a DOM node's innerHTML.
- *
- * @param {string} id ID of the node to update.
- * @param {string} html An HTML string.
- * @internal
- */
- updateInnerHTMLByID: ReactPerf.measure(
- 'ReactDOMIDOperations',
- 'updateInnerHTMLByID',
- function(id, html) {
- var node = ReactMount.getNode(id);
- setInnerHTML(node, html);
- }
- ),
-
- /**
- * Updates a DOM node's text content set by `props.content`.
- *
- * @param {string} id ID of the node to update.
- * @param {string} content Text content.
- * @internal
- */
- updateTextContentByID: ReactPerf.measure(
- 'ReactDOMIDOperations',
- 'updateTextContentByID',
- function(id, content) {
- var node = ReactMount.getNode(id);
- DOMChildrenOperations.updateTextContent(node, content);
- }
- ),
-
- /**
- * Replaces a DOM node that exists in the document with markup.
- *
- * @param {string} id ID of child to be replaced.
- * @param {string} markup Dangerous markup to inject in place of child.
- * @internal
- * @see {Danger.dangerouslyReplaceNodeWithMarkup}
- */
- dangerouslyReplaceNodeWithMarkupByID: ReactPerf.measure(
- 'ReactDOMIDOperations',
- 'dangerouslyReplaceNodeWithMarkupByID',
- function(id, markup) {
- var node = ReactMount.getNode(id);
- DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup);
- }
- ),
-
- /**
- * Updates a component's children by processing a series of updates.
- *
- * @param {array<object>} updates List of update configurations.
- * @param {array<string>} markup List of markup strings.
- * @internal
- */
- dangerouslyProcessChildrenUpdates: ReactPerf.measure(
- 'ReactDOMIDOperations',
- 'dangerouslyProcessChildrenUpdates',
- function(updates, markup) {
- for (var i = 0; i < updates.length; i++) {
- updates[i].parentNode = ReactMount.getNode(updates[i].parentID);
- }
- DOMChildrenOperations.processUpdates(updates, markup);
- }
- )
-};
-
-module.exports = ReactDOMIDOperations;
-
-},{"./CSSPropertyOperations":6,"./DOMChildrenOperations":11,"./DOMPropertyOperations":13,"./ReactMount":70,"./ReactPerf":75,"./invariant":140,"./setInnerHTML":154}],48:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOMImg
- */
-
-"use strict";
-
-var EventConstants = _dereq_("./EventConstants");
-var LocalEventTrapMixin = _dereq_("./LocalEventTrapMixin");
-var ReactBrowserComponentMixin = _dereq_("./ReactBrowserComponentMixin");
-var ReactCompositeComponent = _dereq_("./ReactCompositeComponent");
-var ReactElement = _dereq_("./ReactElement");
-var ReactDOM = _dereq_("./ReactDOM");
-
-// Store a reference to the <img> `ReactDOMComponent`. TODO: use string
-var img = ReactElement.createFactory(ReactDOM.img.type);
-
-/**
- * Since onLoad doesn't bubble OR capture on the top level in IE8, we need to
- * capture it on the <img> element itself. There are lots of hacks we could do
- * to accomplish this, but the most reliable is to make <img> a composite
- * component and use `componentDidMount` to attach the event handlers.
- */
-var ReactDOMImg = ReactCompositeComponent.createClass({
- displayName: 'ReactDOMImg',
- tagName: 'IMG',
-
- mixins: [ReactBrowserComponentMixin, LocalEventTrapMixin],
-
- render: function() {
- return img(this.props);
- },
-
- componentDidMount: function() {
- this.trapBubbledEvent(EventConstants.topLevelTypes.topLoad, 'load');
- this.trapBubbledEvent(EventConstants.topLevelTypes.topError, 'error');
- }
-});
-
-module.exports = ReactDOMImg;
-
-},{"./EventConstants":17,"./LocalEventTrapMixin":27,"./ReactBrowserComponentMixin":32,"./ReactCompositeComponent":40,"./ReactDOM":43,"./ReactElement":58}],49:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOMInput
- */
-
-"use strict";
-
-var AutoFocusMixin = _dereq_("./AutoFocusMixin");
-var DOMPropertyOperations = _dereq_("./DOMPropertyOperations");
-var LinkedValueUtils = _dereq_("./LinkedValueUtils");
-var ReactBrowserComponentMixin = _dereq_("./ReactBrowserComponentMixin");
-var ReactCompositeComponent = _dereq_("./ReactCompositeComponent");
-var ReactElement = _dereq_("./ReactElement");
-var ReactDOM = _dereq_("./ReactDOM");
-var ReactMount = _dereq_("./ReactMount");
-var ReactUpdates = _dereq_("./ReactUpdates");
-
-var assign = _dereq_("./Object.assign");
-var invariant = _dereq_("./invariant");
-
-// Store a reference to the <input> `ReactDOMComponent`. TODO: use string
-var input = ReactElement.createFactory(ReactDOM.input.type);
-
-var instancesByReactID = {};
-
-function forceUpdateIfMounted() {
- /*jshint validthis:true */
- if (this.isMounted()) {
- this.forceUpdate();
- }
-}
-
-/**
- * Implements an <input> native component that allows setting these optional
- * props: `checked`, `value`, `defaultChecked`, and `defaultValue`.
- *
- * If `checked` or `value` are not supplied (or null/undefined), user actions
- * that affect the checked state or value will trigger updates to the element.
- *
- * If they are supplied (and not null/undefined), the rendered element will not
- * trigger updates to the element. Instead, the props must change in order for
- * the rendered element to be updated.
- *
- * The rendered element will be initialized as unchecked (or `defaultChecked`)
- * with an empty value (or `defaultValue`).
- *
- * @see http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html
- */
-var ReactDOMInput = ReactCompositeComponent.createClass({
- displayName: 'ReactDOMInput',
-
- mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
-
- getInitialState: function() {
- var defaultValue = this.props.defaultValue;
- return {
- initialChecked: this.props.defaultChecked || false,
- initialValue: defaultValue != null ? defaultValue : null
- };
- },
-
- render: function() {
- // Clone `this.props` so we don't mutate the input.
- var props = assign({}, this.props);
-
- props.defaultChecked = null;
- props.defaultValue = null;
-
- var value = LinkedValueUtils.getValue(this);
- props.value = value != null ? value : this.state.initialValue;
-
- var checked = LinkedValueUtils.getChecked(this);
- props.checked = checked != null ? checked : this.state.initialChecked;
-
- props.onChange = this._handleChange;
-
- return input(props, this.props.children);
- },
-
- componentDidMount: function() {
- var id = ReactMount.getID(this.getDOMNode());
- instancesByReactID[id] = this;
- },
-
- componentWillUnmount: function() {
- var rootNode = this.getDOMNode();
- var id = ReactMount.getID(rootNode);
- delete instancesByReactID[id];
- },
-
- componentDidUpdate: function(prevProps, prevState, prevContext) {
- var rootNode = this.getDOMNode();
- if (this.props.checked != null) {
- DOMPropertyOperations.setValueForProperty(
- rootNode,
- 'checked',
- this.props.checked || false
- );
- }
-
- var value = LinkedValueUtils.getValue(this);
- if (value != null) {
- // Cast `value` to a string to ensure the value is set correctly. While
- // browsers typically do this as necessary, jsdom doesn't.
- DOMPropertyOperations.setValueForProperty(rootNode, 'value', '' + value);
- }
- },
-
- _handleChange: function(event) {
- var returnValue;
- var onChange = LinkedValueUtils.getOnChange(this);
- if (onChange) {
- returnValue = onChange.call(this, event);
- }
- // Here we use asap to wait until all updates have propagated, which
- // is important when using controlled components within layers:
- // https://github.com/facebook/react/issues/1698
- ReactUpdates.asap(forceUpdateIfMounted, this);
-
- var name = this.props.name;
- if (this.props.type === 'radio' && name != null) {
- var rootNode = this.getDOMNode();
- var queryRoot = rootNode;
-
- while (queryRoot.parentNode) {
- queryRoot = queryRoot.parentNode;
- }
-
- // If `rootNode.form` was non-null, then we could try `form.elements`,
- // but that sometimes behaves strangely in IE8. We could also try using
- // `form.getElementsByName`, but that will only return direct children
- // and won't include inputs that use the HTML5 `form=` attribute. Since
- // the input might not even be in a form, let's just use the global
- // `querySelectorAll` to ensure we don't miss anything.
- var group = queryRoot.querySelectorAll(
- 'input[name=' + JSON.stringify('' + name) + '][type="radio"]');
-
- for (var i = 0, groupLen = group.length; i < groupLen; i++) {
- var otherNode = group[i];
- if (otherNode === rootNode ||
- otherNode.form !== rootNode.form) {
- continue;
- }
- var otherID = ReactMount.getID(otherNode);
- ("production" !== "development" ? invariant(
- otherID,
- 'ReactDOMInput: Mixing React and non-React radio inputs with the ' +
- 'same `name` is not supported.'
- ) : invariant(otherID));
- var otherInstance = instancesByReactID[otherID];
- ("production" !== "development" ? invariant(
- otherInstance,
- 'ReactDOMInput: Unknown radio button ID %s.',
- otherID
- ) : invariant(otherInstance));
- // If this is a controlled radio button group, forcing the input that
- // was previously checked to update will cause it to be come re-checked
- // as appropriate.
- ReactUpdates.asap(forceUpdateIfMounted, otherInstance);
- }
- }
-
- return returnValue;
- }
-
-});
-
-module.exports = ReactDOMInput;
-
-},{"./AutoFocusMixin":2,"./DOMPropertyOperations":13,"./LinkedValueUtils":26,"./Object.assign":29,"./ReactBrowserComponentMixin":32,"./ReactCompositeComponent":40,"./ReactDOM":43,"./ReactElement":58,"./ReactMount":70,"./ReactUpdates":91,"./invariant":140}],50:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOMOption
- */
-
-"use strict";
-
-var ReactBrowserComponentMixin = _dereq_("./ReactBrowserComponentMixin");
-var ReactCompositeComponent = _dereq_("./ReactCompositeComponent");
-var ReactElement = _dereq_("./ReactElement");
-var ReactDOM = _dereq_("./ReactDOM");
-
-var warning = _dereq_("./warning");
-
-// Store a reference to the <option> `ReactDOMComponent`. TODO: use string
-var option = ReactElement.createFactory(ReactDOM.option.type);
-
-/**
- * Implements an <option> native component that warns when `selected` is set.
- */
-var ReactDOMOption = ReactCompositeComponent.createClass({
- displayName: 'ReactDOMOption',
-
- mixins: [ReactBrowserComponentMixin],
-
- componentWillMount: function() {
- // TODO (yungsters): Remove support for `selected` in <option>.
- if ("production" !== "development") {
- ("production" !== "development" ? warning(
- this.props.selected == null,
- 'Use the `defaultValue` or `value` props on <select> instead of ' +
- 'setting `selected` on <option>.'
- ) : null);
- }
- },
-
- render: function() {
- return option(this.props, this.props.children);
- }
-
-});
-
-module.exports = ReactDOMOption;
-
-},{"./ReactBrowserComponentMixin":32,"./ReactCompositeComponent":40,"./ReactDOM":43,"./ReactElement":58,"./warning":160}],51:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOMSelect
- */
-
-"use strict";
-
-var AutoFocusMixin = _dereq_("./AutoFocusMixin");
-var LinkedValueUtils = _dereq_("./LinkedValueUtils");
-var ReactBrowserComponentMixin = _dereq_("./ReactBrowserComponentMixin");
-var ReactCompositeComponent = _dereq_("./ReactCompositeComponent");
-var ReactElement = _dereq_("./ReactElement");
-var ReactDOM = _dereq_("./ReactDOM");
-var ReactUpdates = _dereq_("./ReactUpdates");
-
-var assign = _dereq_("./Object.assign");
-
-// Store a reference to the <select> `ReactDOMComponent`. TODO: use string
-var select = ReactElement.createFactory(ReactDOM.select.type);
-
-function updateWithPendingValueIfMounted() {
- /*jshint validthis:true */
- if (this.isMounted()) {
- this.setState({value: this._pendingValue});
- this._pendingValue = 0;
- }
-}
-
-/**
- * Validation function for `value` and `defaultValue`.
- * @private
- */
-function selectValueType(props, propName, componentName) {
- if (props[propName] == null) {
- return;
- }
- if (props.multiple) {
- if (!Array.isArray(props[propName])) {
- return new Error(
- ("The `" + propName + "` prop supplied to <select> must be an array if ") +
- ("`multiple` is true.")
- );
- }
- } else {
- if (Array.isArray(props[propName])) {
- return new Error(
- ("The `" + propName + "` prop supplied to <select> must be a scalar ") +
- ("value if `multiple` is false.")
- );
- }
- }
-}
-
-/**
- * If `value` is supplied, updates <option> elements on mount and update.
- * @param {ReactComponent} component Instance of ReactDOMSelect
- * @param {?*} propValue For uncontrolled components, null/undefined. For
- * controlled components, a string (or with `multiple`, a list of strings).
- * @private
- */
-function updateOptions(component, propValue) {
- var multiple = component.props.multiple;
- var value = propValue != null ? propValue : component.state.value;
- var options = component.getDOMNode().options;
- var selectedValue, i, l;
- if (multiple) {
- selectedValue = {};
- for (i = 0, l = value.length; i < l; ++i) {
- selectedValue['' + value[i]] = true;
- }
- } else {
- selectedValue = '' + value;
- }
- for (i = 0, l = options.length; i < l; i++) {
- var selected = multiple ?
- selectedValue.hasOwnProperty(options[i].value) :
- options[i].value === selectedValue;
-
- if (selected !== options[i].selected) {
- options[i].selected = selected;
- }
- }
-}
-
-/**
- * Implements a <select> native component that allows optionally setting the
- * props `value` and `defaultValue`. If `multiple` is false, the prop must be a
- * string. If `multiple` is true, the prop must be an array of strings.
- *
- * If `value` is not supplied (or null/undefined), user actions that change the
- * selected option will trigger updates to the rendered options.
- *
- * If it is supplied (and not null/undefined), the rendered options will not
- * update in response to user actions. Instead, the `value` prop must change in
- * order for the rendered options to update.
- *
- * If `defaultValue` is provided, any options with the supplied values will be
- * selected.
- */
-var ReactDOMSelect = ReactCompositeComponent.createClass({
- displayName: 'ReactDOMSelect',
-
- mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
-
- propTypes: {
- defaultValue: selectValueType,
- value: selectValueType
- },
-
- getInitialState: function() {
- return {value: this.props.defaultValue || (this.props.multiple ? [] : '')};
- },
-
- componentWillMount: function() {
- this._pendingValue = null;
- },
-
- componentWillReceiveProps: function(nextProps) {
- if (!this.props.multiple && nextProps.multiple) {
- this.setState({value: [this.state.value]});
- } else if (this.props.multiple && !nextProps.multiple) {
- this.setState({value: this.state.value[0]});
- }
- },
-
- render: function() {
- // Clone `this.props` so we don't mutate the input.
- var props = assign({}, this.props);
-
- props.onChange = this._handleChange;
- props.value = null;
-
- return select(props, this.props.children);
- },
-
- componentDidMount: function() {
- updateOptions(this, LinkedValueUtils.getValue(this));
- },
-
- componentDidUpdate: function(prevProps) {
- var value = LinkedValueUtils.getValue(this);
- var prevMultiple = !!prevProps.multiple;
- var multiple = !!this.props.multiple;
- if (value != null || prevMultiple !== multiple) {
- updateOptions(this, value);
- }
- },
-
- _handleChange: function(event) {
- var returnValue;
- var onChange = LinkedValueUtils.getOnChange(this);
- if (onChange) {
- returnValue = onChange.call(this, event);
- }
-
- var selectedValue;
- if (this.props.multiple) {
- selectedValue = [];
- var options = event.target.options;
- for (var i = 0, l = options.length; i < l; i++) {
- if (options[i].selected) {
- selectedValue.push(options[i].value);
- }
- }
- } else {
- selectedValue = event.target.value;
- }
-
- this._pendingValue = selectedValue;
- ReactUpdates.asap(updateWithPendingValueIfMounted, this);
- return returnValue;
- }
-
-});
-
-module.exports = ReactDOMSelect;
-
-},{"./AutoFocusMixin":2,"./LinkedValueUtils":26,"./Object.assign":29,"./ReactBrowserComponentMixin":32,"./ReactCompositeComponent":40,"./ReactDOM":43,"./ReactElement":58,"./ReactUpdates":91}],52:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOMSelection
- */
-
-"use strict";
-
-var ExecutionEnvironment = _dereq_("./ExecutionEnvironment");
-
-var getNodeForCharacterOffset = _dereq_("./getNodeForCharacterOffset");
-var getTextContentAccessor = _dereq_("./getTextContentAccessor");
-
-/**
- * While `isCollapsed` is available on the Selection object and `collapsed`
- * is available on the Range object, IE11 sometimes gets them wrong.
- * If the anchor/focus nodes and offsets are the same, the range is collapsed.
- */
-function isCollapsed(anchorNode, anchorOffset, focusNode, focusOffset) {
- return anchorNode === focusNode && anchorOffset === focusOffset;
-}
-
-/**
- * Get the appropriate anchor and focus node/offset pairs for IE.
- *
- * The catch here is that IE's selection API doesn't provide information
- * about whether the selection is forward or backward, so we have to
- * behave as though it's always forward.
- *
- * IE text differs from modern selection in that it behaves as though
- * block elements end with a new line. This means character offsets will
- * differ between the two APIs.
- *
- * @param {DOMElement} node
- * @return {object}
- */
-function getIEOffsets(node) {
- var selection = document.selection;
- var selectedRange = selection.createRange();
- var selectedLength = selectedRange.text.length;
-
- // Duplicate selection so we can move range without breaking user selection.
- var fromStart = selectedRange.duplicate();
- fromStart.moveToElementText(node);
- fromStart.setEndPoint('EndToStart', selectedRange);
-
- var startOffset = fromStart.text.length;
- var endOffset = startOffset + selectedLength;
-
- return {
- start: startOffset,
- end: endOffset
- };
-}
-
-/**
- * @param {DOMElement} node
- * @return {?object}
- */
-function getModernOffsets(node) {
- var selection = window.getSelection && window.getSelection();
-
- if (!selection || selection.rangeCount === 0) {
- return null;
- }
-
- var anchorNode = selection.anchorNode;
- var anchorOffset = selection.anchorOffset;
- var focusNode = selection.focusNode;
- var focusOffset = selection.focusOffset;
-
- var currentRange = selection.getRangeAt(0);
-
- // If the node and offset values are the same, the selection is collapsed.
- // `Selection.isCollapsed` is available natively, but IE sometimes gets
- // this value wrong.
- var isSelectionCollapsed = isCollapsed(
- selection.anchorNode,
- selection.anchorOffset,
- selection.focusNode,
- selection.focusOffset
- );
-
- var rangeLength = isSelectionCollapsed ? 0 : currentRange.toString().length;
-
- var tempRange = currentRange.cloneRange();
- tempRange.selectNodeContents(node);
- tempRange.setEnd(currentRange.startContainer, currentRange.startOffset);
-
- var isTempRangeCollapsed = isCollapsed(
- tempRange.startContainer,
- tempRange.startOffset,
- tempRange.endContainer,
- tempRange.endOffset
- );
-
- var start = isTempRangeCollapsed ? 0 : tempRange.toString().length;
- var end = start + rangeLength;
-
- // Detect whether the selection is backward.
- var detectionRange = document.createRange();
- detectionRange.setStart(anchorNode, anchorOffset);
- detectionRange.setEnd(focusNode, focusOffset);
- var isBackward = detectionRange.collapsed;
-
- return {
- start: isBackward ? end : start,
- end: isBackward ? start : end
- };
-}
-
-/**
- * @param {DOMElement|DOMTextNode} node
- * @param {object} offsets
- */
-function setIEOffsets(node, offsets) {
- var range = document.selection.createRange().duplicate();
- var start, end;
-
- if (typeof offsets.end === 'undefined') {
- start = offsets.start;
- end = start;
- } else if (offsets.start > offsets.end) {
- start = offsets.end;
- end = offsets.start;
- } else {
- start = offsets.start;
- end = offsets.end;
- }
-
- range.moveToElementText(node);
- range.moveStart('character', start);
- range.setEndPoint('EndToStart', range);
- range.moveEnd('character', end - start);
- range.select();
-}
-
-/**
- * In modern non-IE browsers, we can support both forward and backward
- * selections.
- *
- * Note: IE10+ supports the Selection object, but it does not support
- * the `extend` method, which means that even in modern IE, it's not possible
- * to programatically create a backward selection. Thus, for all IE
- * versions, we use the old IE API to create our selections.
- *
- * @param {DOMElement|DOMTextNode} node
- * @param {object} offsets
- */
-function setModernOffsets(node, offsets) {
- if (!window.getSelection) {
- return;
- }
-
- var selection = window.getSelection();
- var length = node[getTextContentAccessor()].length;
- var start = Math.min(offsets.start, length);
- var end = typeof offsets.end === 'undefined' ?
- start : Math.min(offsets.end, length);
-
- // IE 11 uses modern selection, but doesn't support the extend method.
- // Flip backward selections, so we can set with a single range.
- if (!selection.extend && start > end) {
- var temp = end;
- end = start;
- start = temp;
- }
-
- var startMarker = getNodeForCharacterOffset(node, start);
- var endMarker = getNodeForCharacterOffset(node, end);
-
- if (startMarker && endMarker) {
- var range = document.createRange();
- range.setStart(startMarker.node, startMarker.offset);
- selection.removeAllRanges();
-
- if (start > end) {
- selection.addRange(range);
- selection.extend(endMarker.node, endMarker.offset);
- } else {
- range.setEnd(endMarker.node, endMarker.offset);
- selection.addRange(range);
- }
- }
-}
-
-var useIEOffsets = ExecutionEnvironment.canUseDOM && document.selection;
-
-var ReactDOMSelection = {
- /**
- * @param {DOMElement} node
- */
- getOffsets: useIEOffsets ? getIEOffsets : getModernOffsets,
-
- /**
- * @param {DOMElement|DOMTextNode} node
- * @param {object} offsets
- */
- setOffsets: useIEOffsets ? setIEOffsets : setModernOffsets
-};
-
-module.exports = ReactDOMSelection;
-
-},{"./ExecutionEnvironment":23,"./getNodeForCharacterOffset":133,"./getTextContentAccessor":135}],53:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOMTextarea
- */
-
-"use strict";
-
-var AutoFocusMixin = _dereq_("./AutoFocusMixin");
-var DOMPropertyOperations = _dereq_("./DOMPropertyOperations");
-var LinkedValueUtils = _dereq_("./LinkedValueUtils");
-var ReactBrowserComponentMixin = _dereq_("./ReactBrowserComponentMixin");
-var ReactCompositeComponent = _dereq_("./ReactCompositeComponent");
-var ReactElement = _dereq_("./ReactElement");
-var ReactDOM = _dereq_("./ReactDOM");
-var ReactUpdates = _dereq_("./ReactUpdates");
-
-var assign = _dereq_("./Object.assign");
-var invariant = _dereq_("./invariant");
-
-var warning = _dereq_("./warning");
-
-// Store a reference to the <textarea> `ReactDOMComponent`. TODO: use string
-var textarea = ReactElement.createFactory(ReactDOM.textarea.type);
-
-function forceUpdateIfMounted() {
- /*jshint validthis:true */
- if (this.isMounted()) {
- this.forceUpdate();
- }
-}
-
-/**
- * Implements a <textarea> native component that allows setting `value`, and
- * `defaultValue`. This differs from the traditional DOM API because value is
- * usually set as PCDATA children.
- *
- * If `value` is not supplied (or null/undefined), user actions that affect the
- * value will trigger updates to the element.
- *
- * If `value` is supplied (and not null/undefined), the rendered element will
- * not trigger updates to the element. Instead, the `value` prop must change in
- * order for the rendered element to be updated.
- *
- * The rendered element will be initialized with an empty value, the prop
- * `defaultValue` if specified, or the children content (deprecated).
- */
-var ReactDOMTextarea = ReactCompositeComponent.createClass({
- displayName: 'ReactDOMTextarea',
-
- mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
-
- getInitialState: function() {
- var defaultValue = this.props.defaultValue;
- // TODO (yungsters): Remove support for children content in <textarea>.
- var children = this.props.children;
- if (children != null) {
- if ("production" !== "development") {
- ("production" !== "development" ? warning(
- false,
- 'Use the `defaultValue` or `value` props instead of setting ' +
- 'children on <textarea>.'
- ) : null);
- }
- ("production" !== "development" ? invariant(
- defaultValue == null,
- 'If you supply `defaultValue` on a <textarea>, do not pass children.'
- ) : invariant(defaultValue == null));
- if (Array.isArray(children)) {
- ("production" !== "development" ? invariant(
- children.length <= 1,
- '<textarea> can only have at most one child.'
- ) : invariant(children.length <= 1));
- children = children[0];
- }
-
- defaultValue = '' + children;
- }
- if (defaultValue == null) {
- defaultValue = '';
- }
- var value = LinkedValueUtils.getValue(this);
- return {
- // We save the initial value so that `ReactDOMComponent` doesn't update
- // `textContent` (unnecessary since we update value).
- // The initial value can be a boolean or object so that's why it's
- // forced to be a string.
- initialValue: '' + (value != null ? value : defaultValue)
- };
- },
-
- render: function() {
- // Clone `this.props` so we don't mutate the input.
- var props = assign({}, this.props);
-
- ("production" !== "development" ? invariant(
- props.dangerouslySetInnerHTML == null,
- '`dangerouslySetInnerHTML` does not make sense on <textarea>.'
- ) : invariant(props.dangerouslySetInnerHTML == null));
-
- props.defaultValue = null;
- props.value = null;
- props.onChange = this._handleChange;
-
- // Always set children to the same thing. In IE9, the selection range will
- // get reset if `textContent` is mutated.
- return textarea(props, this.state.initialValue);
- },
-
- componentDidUpdate: function(prevProps, prevState, prevContext) {
- var value = LinkedValueUtils.getValue(this);
- if (value != null) {
- var rootNode = this.getDOMNode();
- // Cast `value` to a string to ensure the value is set correctly. While
- // browsers typically do this as necessary, jsdom doesn't.
- DOMPropertyOperations.setValueForProperty(rootNode, 'value', '' + value);
- }
- },
-
- _handleChange: function(event) {
- var returnValue;
- var onChange = LinkedValueUtils.getOnChange(this);
- if (onChange) {
- returnValue = onChange.call(this, event);
- }
- ReactUpdates.asap(forceUpdateIfMounted, this);
- return returnValue;
- }
-
-});
-
-module.exports = ReactDOMTextarea;
-
-},{"./AutoFocusMixin":2,"./DOMPropertyOperations":13,"./LinkedValueUtils":26,"./Object.assign":29,"./ReactBrowserComponentMixin":32,"./ReactCompositeComponent":40,"./ReactDOM":43,"./ReactElement":58,"./ReactUpdates":91,"./invariant":140,"./warning":160}],54:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDefaultBatchingStrategy
- */
-
-"use strict";
-
-var ReactUpdates = _dereq_("./ReactUpdates");
-var Transaction = _dereq_("./Transaction");
-
-var assign = _dereq_("./Object.assign");
-var emptyFunction = _dereq_("./emptyFunction");
-
-var RESET_BATCHED_UPDATES = {
- initialize: emptyFunction,
- close: function() {
- ReactDefaultBatchingStrategy.isBatchingUpdates = false;
- }
-};
-
-var FLUSH_BATCHED_UPDATES = {
- initialize: emptyFunction,
- close: ReactUpdates.flushBatchedUpdates.bind(ReactUpdates)
-};
-
-var TRANSACTION_WRAPPERS = [FLUSH_BATCHED_UPDATES, RESET_BATCHED_UPDATES];
-
-function ReactDefaultBatchingStrategyTransaction() {
- this.reinitializeTransaction();
-}
-
-assign(
- ReactDefaultBatchingStrategyTransaction.prototype,
- Transaction.Mixin,
- {
- getTransactionWrappers: function() {
- return TRANSACTION_WRAPPERS;
- }
- }
-);
-
-var transaction = new ReactDefaultBatchingStrategyTransaction();
-
-var ReactDefaultBatchingStrategy = {
- isBatchingUpdates: false,
-
- /**
- * Call the provided function in a context within which calls to `setState`
- * and friends are batched such that components aren't updated unnecessarily.
- */
- batchedUpdates: function(callback, a, b) {
- var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;
-
- ReactDefaultBatchingStrategy.isBatchingUpdates = true;
-
- // The code is written this way to avoid extra allocations
- if (alreadyBatchingUpdates) {
- callback(a, b);
- } else {
- transaction.perform(callback, null, a, b);
- }
- }
-};
-
-module.exports = ReactDefaultBatchingStrategy;
-
-},{"./Object.assign":29,"./ReactUpdates":91,"./Transaction":107,"./emptyFunction":121}],55:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDefaultInjection
- */
-
-"use strict";
-
-var BeforeInputEventPlugin = _dereq_("./BeforeInputEventPlugin");
-var ChangeEventPlugin = _dereq_("./ChangeEventPlugin");
-var ClientReactRootIndex = _dereq_("./ClientReactRootIndex");
-var CompositionEventPlugin = _dereq_("./CompositionEventPlugin");
-var DefaultEventPluginOrder = _dereq_("./DefaultEventPluginOrder");
-var EnterLeaveEventPlugin = _dereq_("./EnterLeaveEventPlugin");
-var ExecutionEnvironment = _dereq_("./ExecutionEnvironment");
-var HTMLDOMPropertyConfig = _dereq_("./HTMLDOMPropertyConfig");
-var MobileSafariClickEventPlugin = _dereq_("./MobileSafariClickEventPlugin");
-var ReactBrowserComponentMixin = _dereq_("./ReactBrowserComponentMixin");
-var ReactComponentBrowserEnvironment =
- _dereq_("./ReactComponentBrowserEnvironment");
-var ReactDefaultBatchingStrategy = _dereq_("./ReactDefaultBatchingStrategy");
-var ReactDOMComponent = _dereq_("./ReactDOMComponent");
-var ReactDOMButton = _dereq_("./ReactDOMButton");
-var ReactDOMForm = _dereq_("./ReactDOMForm");
-var ReactDOMImg = _dereq_("./ReactDOMImg");
-var ReactDOMInput = _dereq_("./ReactDOMInput");
-var ReactDOMOption = _dereq_("./ReactDOMOption");
-var ReactDOMSelect = _dereq_("./ReactDOMSelect");
-var ReactDOMTextarea = _dereq_("./ReactDOMTextarea");
-var ReactEventListener = _dereq_("./ReactEventListener");
-var ReactInjection = _dereq_("./ReactInjection");
-var ReactInstanceHandles = _dereq_("./ReactInstanceHandles");
-var ReactMount = _dereq_("./ReactMount");
-var SelectEventPlugin = _dereq_("./SelectEventPlugin");
-var ServerReactRootIndex = _dereq_("./ServerReactRootIndex");
-var SimpleEventPlugin = _dereq_("./SimpleEventPlugin");
-var SVGDOMPropertyConfig = _dereq_("./SVGDOMPropertyConfig");
-
-var createFullPageComponent = _dereq_("./createFullPageComponent");
-
-function inject() {
- ReactInjection.EventEmitter.injectReactEventListener(
- ReactEventListener
- );
-
- /**
- * Inject modules for resolving DOM hierarchy and plugin ordering.
- */
- ReactInjection.EventPluginHub.injectEventPluginOrder(DefaultEventPluginOrder);
- ReactInjection.EventPluginHub.injectInstanceHandle(ReactInstanceHandles);
- ReactInjection.EventPluginHub.injectMount(ReactMount);
-
- /**
- * Some important event plugins included by default (without having to require
- * them).
- */
- ReactInjection.EventPluginHub.injectEventPluginsByName({
- SimpleEventPlugin: SimpleEventPlugin,
- EnterLeaveEventPlugin: EnterLeaveEventPlugin,
- ChangeEventPlugin: ChangeEventPlugin,
- CompositionEventPlugin: CompositionEventPlugin,
- MobileSafariClickEventPlugin: MobileSafariClickEventPlugin,
- SelectEventPlugin: SelectEventPlugin,
- BeforeInputEventPlugin: BeforeInputEventPlugin
- });
-
- ReactInjection.NativeComponent.injectGenericComponentClass(
- ReactDOMComponent
- );
-
- ReactInjection.NativeComponent.injectComponentClasses({
- 'button': ReactDOMButton,
- 'form': ReactDOMForm,
- 'img': ReactDOMImg,
- 'input': ReactDOMInput,
- 'option': ReactDOMOption,
- 'select': ReactDOMSelect,
- 'textarea': ReactDOMTextarea,
-
- 'html': createFullPageComponent('html'),
- 'head': createFullPageComponent('head'),
- 'body': createFullPageComponent('body')
- });
-
- // This needs to happen after createFullPageComponent() otherwise the mixin
- // gets double injected.
- ReactInjection.CompositeComponent.injectMixin(ReactBrowserComponentMixin);
-
- ReactInjection.DOMProperty.injectDOMPropertyConfig(HTMLDOMPropertyConfig);
- ReactInjection.DOMProperty.injectDOMPropertyConfig(SVGDOMPropertyConfig);
-
- ReactInjection.EmptyComponent.injectEmptyComponent('noscript');
-
- ReactInjection.Updates.injectReconcileTransaction(
- ReactComponentBrowserEnvironment.ReactReconcileTransaction
- );
- ReactInjection.Updates.injectBatchingStrategy(
- ReactDefaultBatchingStrategy
- );
-
- ReactInjection.RootIndex.injectCreateReactRootIndex(
- ExecutionEnvironment.canUseDOM ?
- ClientReactRootIndex.createReactRootIndex :
- ServerReactRootIndex.createReactRootIndex
- );
-
- ReactInjection.Component.injectEnvironment(ReactComponentBrowserEnvironment);
-
- if ("production" !== "development") {
- var url = (ExecutionEnvironment.canUseDOM && window.location.href) || '';
- if ((/[?&]react_perf\b/).test(url)) {
- var ReactDefaultPerf = _dereq_("./ReactDefaultPerf");
- ReactDefaultPerf.start();
- }
- }
-}
-
-module.exports = {
- inject: inject
-};
-
-},{"./BeforeInputEventPlugin":3,"./ChangeEventPlugin":8,"./ClientReactRootIndex":9,"./CompositionEventPlugin":10,"./DefaultEventPluginOrder":15,"./EnterLeaveEventPlugin":16,"./ExecutionEnvironment":23,"./HTMLDOMPropertyConfig":24,"./MobileSafariClickEventPlugin":28,"./ReactBrowserComponentMixin":32,"./ReactComponentBrowserEnvironment":38,"./ReactDOMButton":44,"./ReactDOMComponent":45,"./ReactDOMForm":46,"./ReactDOMImg":48,"./ReactDOMInput":49,"./ReactDOMOption":50,"./ReactDOMSelect":51,"./ReactDOMTextarea":53,"./ReactDefaultBatchingStrategy":54,"./ReactDefaultPerf":56,"./ReactEventListener":63,"./ReactInjection":64,"./ReactInstanceHandles":66,"./ReactMount":70,"./SVGDOMPropertyConfig":92,"./SelectEventPlugin":93,"./ServerReactRootIndex":94,"./SimpleEventPlugin":95,"./createFullPageComponent":116}],56:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDefaultPerf
- * @typechecks static-only
- */
-
-"use strict";
-
-var DOMProperty = _dereq_("./DOMProperty");
-var ReactDefaultPerfAnalysis = _dereq_("./ReactDefaultPerfAnalysis");
-var ReactMount = _dereq_("./ReactMount");
-var ReactPerf = _dereq_("./ReactPerf");
-
-var performanceNow = _dereq_("./performanceNow");
-
-function roundFloat(val) {
- return Math.floor(val * 100) / 100;
-}
-
-function addValue(obj, key, val) {
- obj[key] = (obj[key] || 0) + val;
-}
-
-var ReactDefaultPerf = {
- _allMeasurements: [], // last item in the list is the current one
- _mountStack: [0],
- _injected: false,
-
- start: function() {
- if (!ReactDefaultPerf._injected) {
- ReactPerf.injection.injectMeasure(ReactDefaultPerf.measure);
- }
-
- ReactDefaultPerf._allMeasurements.length = 0;
- ReactPerf.enableMeasure = true;
- },
-
- stop: function() {
- ReactPerf.enableMeasure = false;
- },
-
- getLastMeasurements: function() {
- return ReactDefaultPerf._allMeasurements;
- },
-
- printExclusive: function(measurements) {
- measurements = measurements || ReactDefaultPerf._allMeasurements;
- var summary = ReactDefaultPerfAnalysis.getExclusiveSummary(measurements);
- console.table(summary.map(function(item) {
- return {
- 'Component class name': item.componentName,
- 'Total inclusive time (ms)': roundFloat(item.inclusive),
- 'Exclusive mount time (ms)': roundFloat(item.exclusive),
- 'Exclusive render time (ms)': roundFloat(item.render),
- 'Mount time per instance (ms)': roundFloat(item.exclusive / item.count),
- 'Render time per instance (ms)': roundFloat(item.render / item.count),
- 'Instances': item.count
- };
- }));
- // TODO: ReactDefaultPerfAnalysis.getTotalTime() does not return the correct
- // number.
- },
-
- printInclusive: function(measurements) {
- measurements = measurements || ReactDefaultPerf._allMeasurements;
- var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(measurements);
- console.table(summary.map(function(item) {
- return {
- 'Owner > component': item.componentName,
- 'Inclusive time (ms)': roundFloat(item.time),
- 'Instances': item.count
- };
- }));
- console.log(
- 'Total time:',
- ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
- );
- },
-
- getMeasurementsSummaryMap: function(measurements) {
- var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(
- measurements,
- true
- );
- return summary.map(function(item) {
- return {
- 'Owner > component': item.componentName,
- 'Wasted time (ms)': item.time,
- 'Instances': item.count
- };
- });
- },
-
- printWasted: function(measurements) {
- measurements = measurements || ReactDefaultPerf._allMeasurements;
- console.table(ReactDefaultPerf.getMeasurementsSummaryMap(measurements));
- console.log(
- 'Total time:',
- ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
- );
- },
-
- printDOM: function(measurements) {
- measurements = measurements || ReactDefaultPerf._allMeasurements;
- var summary = ReactDefaultPerfAnalysis.getDOMSummary(measurements);
- console.table(summary.map(function(item) {
- var result = {};
- result[DOMProperty.ID_ATTRIBUTE_NAME] = item.id;
- result['type'] = item.type;
- result['args'] = JSON.stringify(item.args);
- return result;
- }));
- console.log(
- 'Total time:',
- ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
- );
- },
-
- _recordWrite: function(id, fnName, totalTime, args) {
- // TODO: totalTime isn't that useful since it doesn't count paints/reflows
- var writes =
- ReactDefaultPerf
- ._allMeasurements[ReactDefaultPerf._allMeasurements.length - 1]
- .writes;
- writes[id] = writes[id] || [];
- writes[id].push({
- type: fnName,
- time: totalTime,
- args: args
- });
- },
-
- measure: function(moduleName, fnName, func) {
- return function() {for (var args=[],$__0=0,$__1=arguments.length;$__0<$__1;$__0++) args.push(arguments[$__0]);
- var totalTime;
- var rv;
- var start;
-
- if (fnName === '_renderNewRootComponent' ||
- fnName === 'flushBatchedUpdates') {
- // A "measurement" is a set of metrics recorded for each flush. We want
- // to group the metrics for a given flush together so we can look at the
- // components that rendered and the DOM operations that actually
- // happened to determine the amount of "wasted work" performed.
- ReactDefaultPerf._allMeasurements.push({
- exclusive: {},
- inclusive: {},
- render: {},
- counts: {},
- writes: {},
- displayNames: {},
- totalTime: 0
- });
- start = performanceNow();
- rv = func.apply(this, args);
- ReactDefaultPerf._allMeasurements[
- ReactDefaultPerf._allMeasurements.length - 1
- ].totalTime = performanceNow() - start;
- return rv;
- } else if (moduleName === 'ReactDOMIDOperations' ||
- moduleName === 'ReactComponentBrowserEnvironment') {
- start = performanceNow();
- rv = func.apply(this, args);
- totalTime = performanceNow() - start;
-
- if (fnName === 'mountImageIntoNode') {
- var mountID = ReactMount.getID(args[1]);
- ReactDefaultPerf._recordWrite(mountID, fnName, totalTime, args[0]);
- } else if (fnName === 'dangerouslyProcessChildrenUpdates') {
- // special format
- args[0].forEach(function(update) {
- var writeArgs = {};
- if (update.fromIndex !== null) {
- writeArgs.fromIndex = update.fromIndex;
- }
- if (update.toIndex !== null) {
- writeArgs.toIndex = update.toIndex;
- }
- if (update.textContent !== null) {
- writeArgs.textContent = update.textContent;
- }
- if (update.markupIndex !== null) {
- writeArgs.markup = args[1][update.markupIndex];
- }
- ReactDefaultPerf._recordWrite(
- update.parentID,
- update.type,
- totalTime,
- writeArgs
- );
- });
- } else {
- // basic format
- ReactDefaultPerf._recordWrite(
- args[0],
- fnName,
- totalTime,
- Array.prototype.slice.call(args, 1)
- );
- }
- return rv;
- } else if (moduleName === 'ReactCompositeComponent' && (
- fnName === 'mountComponent' ||
- fnName === 'updateComponent' || // TODO: receiveComponent()?
- fnName === '_renderValidatedComponent')) {
-
- var rootNodeID = fnName === 'mountComponent' ?
- args[0] :
- this._rootNodeID;
- var isRender = fnName === '_renderValidatedComponent';
- var isMount = fnName === 'mountComponent';
-
- var mountStack = ReactDefaultPerf._mountStack;
- var entry = ReactDefaultPerf._allMeasurements[
- ReactDefaultPerf._allMeasurements.length - 1
- ];
-
- if (isRender) {
- addValue(entry.counts, rootNodeID, 1);
- } else if (isMount) {
- mountStack.push(0);
- }
-
- start = performanceNow();
- rv = func.apply(this, args);
- totalTime = performanceNow() - start;
-
- if (isRender) {
- addValue(entry.render, rootNodeID, totalTime);
- } else if (isMount) {
- var subMountTime = mountStack.pop();
- mountStack[mountStack.length - 1] += totalTime;
- addValue(entry.exclusive, rootNodeID, totalTime - subMountTime);
- addValue(entry.inclusive, rootNodeID, totalTime);
- } else {
- addValue(entry.inclusive, rootNodeID, totalTime);
- }
-
- entry.displayNames[rootNodeID] = {
- current: this.constructor.displayName,
- owner: this._owner ? this._owner.constructor.displayName : '<root>'
- };
-
- return rv;
- } else {
- return func.apply(this, args);
- }
- };
- }
-};
-
-module.exports = ReactDefaultPerf;
-
-},{"./DOMProperty":12,"./ReactDefaultPerfAnalysis":57,"./ReactMount":70,"./ReactPerf":75,"./performanceNow":153}],57:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDefaultPerfAnalysis
- */
-
-var assign = _dereq_("./Object.assign");
-
-// Don't try to save users less than 1.2ms (a number I made up)
-var DONT_CARE_THRESHOLD = 1.2;
-var DOM_OPERATION_TYPES = {
- 'mountImageIntoNode': 'set innerHTML',
- INSERT_MARKUP: 'set innerHTML',
- MOVE_EXISTING: 'move',
- REMOVE_NODE: 'remove',
- TEXT_CONTENT: 'set textContent',
- 'updatePropertyByID': 'update attribute',
- 'deletePropertyByID': 'delete attribute',
- 'updateStylesByID': 'update styles',
- 'updateInnerHTMLByID': 'set innerHTML',
- 'dangerouslyReplaceNodeWithMarkupByID': 'replace'
-};
-
-function getTotalTime(measurements) {
- // TODO: return number of DOM ops? could be misleading.
- // TODO: measure dropped frames after reconcile?
- // TODO: log total time of each reconcile and the top-level component
- // class that triggered it.
- var totalTime = 0;
- for (var i = 0; i < measurements.length; i++) {
- var measurement = measurements[i];
- totalTime += measurement.totalTime;
- }
- return totalTime;
-}
-
-function getDOMSummary(measurements) {
- var items = [];
- for (var i = 0; i < measurements.length; i++) {
- var measurement = measurements[i];
- var id;
-
- for (id in measurement.writes) {
- measurement.writes[id].forEach(function(write) {
- items.push({
- id: id,
- type: DOM_OPERATION_TYPES[write.type] || write.type,
- args: write.args
- });
- });
- }
- }
- return items;
-}
-
-function getExclusiveSummary(measurements) {
- var candidates = {};
- var displayName;
-
- for (var i = 0; i < measurements.length; i++) {
- var measurement = measurements[i];
- var allIDs = assign(
- {},
- measurement.exclusive,
- measurement.inclusive
- );
-
- for (var id in allIDs) {
- displayName = measurement.displayNames[id].current;
-
- candidates[displayName] = candidates[displayName] || {
- componentName: displayName,
- inclusive: 0,
- exclusive: 0,
- render: 0,
- count: 0
- };
- if (measurement.render[id]) {
- candidates[displayName].render += measurement.render[id];
- }
- if (measurement.exclusive[id]) {
- candidates[displayName].exclusive += measurement.exclusive[id];
- }
- if (measurement.inclusive[id]) {
- candidates[displayName].inclusive += measurement.inclusive[id];
- }
- if (measurement.counts[id]) {
- candidates[displayName].count += measurement.counts[id];
- }
- }
- }
-
- // Now make a sorted array with the results.
- var arr = [];
- for (displayName in candidates) {
- if (candidates[displayName].exclusive >= DONT_CARE_THRESHOLD) {
- arr.push(candidates[displayName]);
- }
- }
-
- arr.sort(function(a, b) {
- return b.exclusive - a.exclusive;
- });
-
- return arr;
-}
-
-function getInclusiveSummary(measurements, onlyClean) {
- var candidates = {};
- var inclusiveKey;
-
- for (var i = 0; i < measurements.length; i++) {
- var measurement = measurements[i];
- var allIDs = assign(
- {},
- measurement.exclusive,
- measurement.inclusive
- );
- var cleanComponents;
-
- if (onlyClean) {
- cleanComponents = getUnchangedComponents(measurement);
- }
-
- for (var id in allIDs) {
- if (onlyClean && !cleanComponents[id]) {
- continue;
- }
-
- var displayName = measurement.displayNames[id];
-
- // Inclusive time is not useful for many components without knowing where
- // they are instantiated. So we aggregate inclusive time with both the
- // owner and current displayName as the key.
- inclusiveKey = displayName.owner + ' > ' + displayName.current;
-
- candidates[inclusiveKey] = candidates[inclusiveKey] || {
- componentName: inclusiveKey,
- time: 0,
- count: 0
- };
-
- if (measurement.inclusive[id]) {
- candidates[inclusiveKey].time += measurement.inclusive[id];
- }
- if (measurement.counts[id]) {
- candidates[inclusiveKey].count += measurement.counts[id];
- }
- }
- }
-
- // Now make a sorted array with the results.
- var arr = [];
- for (inclusiveKey in candidates) {
- if (candidates[inclusiveKey].time >= DONT_CARE_THRESHOLD) {
- arr.push(candidates[inclusiveKey]);
- }
- }
-
- arr.sort(function(a, b) {
- return b.time - a.time;
- });
-
- return arr;
-}
-
-function getUnchangedComponents(measurement) {
- // For a given reconcile, look at which components did not actually
- // render anything to the DOM and return a mapping of their ID to
- // the amount of time it took to render the entire subtree.
- var cleanComponents = {};
- var dirtyLeafIDs = Object.keys(measurement.writes);
- var allIDs = assign({}, measurement.exclusive, measurement.inclusive);
-
- for (var id in allIDs) {
- var isDirty = false;
- // For each component that rendered, see if a component that triggered
- // a DOM op is in its subtree.
- for (var i = 0; i < dirtyLeafIDs.length; i++) {
- if (dirtyLeafIDs[i].indexOf(id) === 0) {
- isDirty = true;
- break;
- }
- }
- if (!isDirty && measurement.counts[id] > 0) {
- cleanComponents[id] = true;
- }
- }
- return cleanComponents;
-}
-
-var ReactDefaultPerfAnalysis = {
- getExclusiveSummary: getExclusiveSummary,
- getInclusiveSummary: getInclusiveSummary,
- getDOMSummary: getDOMSummary,
- getTotalTime: getTotalTime
-};
-
-module.exports = ReactDefaultPerfAnalysis;
-
-},{"./Object.assign":29}],58:[function(_dereq_,module,exports){
-/**
- * Copyright 2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactElement
- */
-
-"use strict";
-
-var ReactContext = _dereq_("./ReactContext");
-var ReactCurrentOwner = _dereq_("./ReactCurrentOwner");
-
-var warning = _dereq_("./warning");
-
-var RESERVED_PROPS = {
- key: true,
- ref: true
-};
-
-/**
- * Warn for mutations.
- *
- * @internal
- * @param {object} object
- * @param {string} key
- */
-function defineWarningProperty(object, key) {
- Object.defineProperty(object, key, {
-
- configurable: false,
- enumerable: true,
-
- get: function() {
- if (!this._store) {
- return null;
- }
- return this._store[key];
- },
-
- set: function(value) {
- ("production" !== "development" ? warning(
- false,
- 'Don\'t set the ' + key + ' property of the component. ' +
- 'Mutate the existing props object instead.'
- ) : null);
- this._store[key] = value;
- }
-
- });
-}
-
-/**
- * This is updated to true if the membrane is successfully created.
- */
-var useMutationMembrane = false;
-
-/**
- * Warn for mutations.
- *
- * @internal
- * @param {object} element
- */
-function defineMutationMembrane(prototype) {
- try {
- var pseudoFrozenProperties = {
- props: true
- };
- for (var key in pseudoFrozenProperties) {
- defineWarningProperty(prototype, key);
- }
- useMutationMembrane = true;
- } catch (x) {
- // IE will fail on defineProperty
- }
-}
-
-/**
- * Base constructor for all React elements. This is only used to make this
- * work with a dynamic instanceof check. Nothing should live on this prototype.
- *
- * @param {*} type
- * @param {string|object} ref
- * @param {*} key
- * @param {*} props
- * @internal
- */
-var ReactElement = function(type, key, ref, owner, context, props) {
- // Built-in properties that belong on the element
- this.type = type;
- this.key = key;
- this.ref = ref;
-
- // Record the component responsible for creating this element.
- this._owner = owner;
-
- // TODO: Deprecate withContext, and then the context becomes accessible
- // through the owner.
- this._context = context;
-
- if ("production" !== "development") {
- // The validation flag and props are currently mutative. We put them on
- // an external backing store so that we can freeze the whole object.
- // This can be replaced with a WeakMap once they are implemented in
- // commonly used development environments.
- this._store = { validated: false, props: props };
-
- // We're not allowed to set props directly on the object so we early
- // return and rely on the prototype membrane to forward to the backing
- // store.
- if (useMutationMembrane) {
- Object.freeze(this);
- return;
- }
- }
-
- this.props = props;
-};
-
-// We intentionally don't expose the function on the constructor property.
-// ReactElement should be indistinguishable from a plain object.
-ReactElement.prototype = {
- _isReactElement: true
-};
-
-if ("production" !== "development") {
- defineMutationMembrane(ReactElement.prototype);
-}
-
-ReactElement.createElement = function(type, config, children) {
- var propName;
-
- // Reserved names are extracted
- var props = {};
-
- var key = null;
- var ref = null;
-
- if (config != null) {
- ref = config.ref === undefined ? null : config.ref;
- if ("production" !== "development") {
- ("production" !== "development" ? warning(
- config.key !== null,
- 'createElement(...): Encountered component with a `key` of null. In ' +
- 'a future version, this will be treated as equivalent to the string ' +
- '\'null\'; instead, provide an explicit key or use undefined.'
- ) : null);
- }
- // TODO: Change this back to `config.key === undefined`
- key = config.key == null ? null : '' + config.key;
- // Remaining properties are added to a new props object
- for (propName in config) {
- if (config.hasOwnProperty(propName) &&
- !RESERVED_PROPS.hasOwnProperty(propName)) {
- props[propName] = config[propName];
- }
- }
- }
-
- // Children can be more than one argument, and those are transferred onto
- // the newly allocated props object.
- var childrenLength = arguments.length - 2;
- if (childrenLength === 1) {
- props.children = children;
- } else if (childrenLength > 1) {
- var childArray = Array(childrenLength);
- for (var i = 0; i < childrenLength; i++) {
- childArray[i] = arguments[i + 2];
- }
- props.children = childArray;
- }
-
- // Resolve default props
- if (type.defaultProps) {
- var defaultProps = type.defaultProps;
- for (propName in defaultProps) {
- if (typeof props[propName] === 'undefined') {
- props[propName] = defaultProps[propName];
- }
- }
- }
-
- return new ReactElement(
- type,
- key,
- ref,
- ReactCurrentOwner.current,
- ReactContext.current,
- props
- );
-};
-
-ReactElement.createFactory = function(type) {
- var factory = ReactElement.createElement.bind(null, type);
- // Expose the type on the factory and the prototype so that it can be
- // easily accessed on elements. E.g. <Foo />.type === Foo.type.
- // This should not be named `constructor` since this may not be the function
- // that created the element, and it may not even be a constructor.
- factory.type = type;
- return factory;
-};
-
-ReactElement.cloneAndReplaceProps = function(oldElement, newProps) {
- var newElement = new ReactElement(
- oldElement.type,
- oldElement.key,
- oldElement.ref,
- oldElement._owner,
- oldElement._context,
- newProps
- );
-
- if ("production" !== "development") {
- // If the key on the original is valid, then the clone is valid
- newElement._store.validated = oldElement._store.validated;
- }
- return newElement;
-};
-
-/**
- * @param {?object} object
- * @return {boolean} True if `object` is a valid component.
- * @final
- */
-ReactElement.isValidElement = function(object) {
- // ReactTestUtils is often used outside of beforeEach where as React is
- // within it. This leads to two different instances of React on the same
- // page. To identify a element from a different React instance we use
- // a flag instead of an instanceof check.
- var isElement = !!(object && object._isReactElement);
- // if (isElement && !(object instanceof ReactElement)) {
- // This is an indicator that you're using multiple versions of React at the
- // same time. This will screw with ownership and stuff. Fix it, please.
- // TODO: We could possibly warn here.
- // }
- return isElement;
-};
-
-module.exports = ReactElement;
-
-},{"./ReactContext":41,"./ReactCurrentOwner":42,"./warning":160}],59:[function(_dereq_,module,exports){
-/**
- * Copyright 2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactElementValidator
- */
-
-/**
- * ReactElementValidator provides a wrapper around a element factory
- * which validates the props passed to the element. This is intended to be
- * used only in DEV and could be replaced by a static type checker for languages
- * that support it.
- */
-
-"use strict";
-
-var ReactElement = _dereq_("./ReactElement");
-var ReactPropTypeLocations = _dereq_("./ReactPropTypeLocations");
-var ReactCurrentOwner = _dereq_("./ReactCurrentOwner");
-
-var monitorCodeUse = _dereq_("./monitorCodeUse");
-
-/**
- * Warn if there's no key explicitly set on dynamic arrays of children or
- * object keys are not valid. This allows us to keep track of children between
- * updates.
- */
-var ownerHasKeyUseWarning = {
- 'react_key_warning': {},
- 'react_numeric_key_warning': {}
-};
-var ownerHasMonitoredObjectMap = {};
-
-var loggedTypeFailures = {};
-
-var NUMERIC_PROPERTY_REGEX = /^\d+$/;
-
-/**
- * Gets the current owner's displayName for use in warnings.
- *
- * @internal
- * @return {?string} Display name or undefined
- */
-function getCurrentOwnerDisplayName() {
- var current = ReactCurrentOwner.current;
- return current && current.constructor.displayName || undefined;
-}
-
-/**
- * Warn if the component doesn't have an explicit key assigned to it.
- * This component is in an array. The array could grow and shrink or be
- * reordered. All children that haven't already been validated are required to
- * have a "key" property assigned to it.
- *
- * @internal
- * @param {ReactComponent} component Component that requires a key.
- * @param {*} parentType component's parent's type.
- */
-function validateExplicitKey(component, parentType) {
- if (component._store.validated || component.key != null) {
- return;
- }
- component._store.validated = true;
-
- warnAndMonitorForKeyUse(
- 'react_key_warning',
- 'Each child in an array should have a unique "key" prop.',
- component,
- parentType
- );
-}
-
-/**
- * Warn if the key is being defined as an object property but has an incorrect
- * value.
- *
- * @internal
- * @param {string} name Property name of the key.
- * @param {ReactComponent} component Component that requires a key.
- * @param {*} parentType component's parent's type.
- */
-function validatePropertyKey(name, component, parentType) {
- if (!NUMERIC_PROPERTY_REGEX.test(name)) {
- return;
- }
- warnAndMonitorForKeyUse(
- 'react_numeric_key_warning',
- 'Child objects should have non-numeric keys so ordering is preserved.',
- component,
- parentType
- );
-}
-
-/**
- * Shared warning and monitoring code for the key warnings.
- *
- * @internal
- * @param {string} warningID The id used when logging.
- * @param {string} message The base warning that gets output.
- * @param {ReactComponent} component Component that requires a key.
- * @param {*} parentType component's parent's type.
- */
-function warnAndMonitorForKeyUse(warningID, message, component, parentType) {
- var ownerName = getCurrentOwnerDisplayName();
- var parentName = parentType.displayName;
-
- var useName = ownerName || parentName;
- var memoizer = ownerHasKeyUseWarning[warningID];
- if (memoizer.hasOwnProperty(useName)) {
- return;
- }
- memoizer[useName] = true;
-
- message += ownerName ?
- (" Check the render method of " + ownerName + ".") :
- (" Check the renderComponent call using <" + parentName + ">.");
-
- // Usually the current owner is the offender, but if it accepts children as a
- // property, it may be the creator of the child that's responsible for
- // assigning it a key.
- var childOwnerName = null;
- if (component._owner && component._owner !== ReactCurrentOwner.current) {
- // Name of the component that originally created this child.
- childOwnerName = component._owner.constructor.displayName;
-
- message += (" It was passed a child from " + childOwnerName + ".");
- }
-
- message += ' See http://fb.me/react-warning-keys for more information.';
- monitorCodeUse(warningID, {
- component: useName,
- componentOwner: childOwnerName
- });
- console.warn(message);
-}
-
-/**
- * Log that we're using an object map. We're considering deprecating this
- * feature and replace it with proper Map and ImmutableMap data structures.
- *
- * @internal
- */
-function monitorUseOfObjectMap() {
- var currentName = getCurrentOwnerDisplayName() || '';
- if (ownerHasMonitoredObjectMap.hasOwnProperty(currentName)) {
- return;
- }
- ownerHasMonitoredObjectMap[currentName] = true;
- monitorCodeUse('react_object_map_children');
-}
-
-/**
- * Ensure that every component either is passed in a static location, in an
- * array with an explicit keys property defined, or in an object literal
- * with valid key property.
- *
- * @internal
- * @param {*} component Statically passed child of any type.
- * @param {*} parentType component's parent's type.
- * @return {boolean}
- */
-function validateChildKeys(component, parentType) {
- if (Array.isArray(component)) {
- for (var i = 0; i < component.length; i++) {
- var child = component[i];
- if (ReactElement.isValidElement(child)) {
- validateExplicitKey(child, parentType);
- }
- }
- } else if (ReactElement.isValidElement(component)) {
- // This component was passed in a valid location.
- component._store.validated = true;
- } else if (component && typeof component === 'object') {
- monitorUseOfObjectMap();
- for (var name in component) {
- validatePropertyKey(name, component[name], parentType);
- }
- }
-}
-
-/**
- * Assert that the props are valid
- *
- * @param {string} componentName Name of the component for error messages.
- * @param {object} propTypes Map of prop name to a ReactPropType
- * @param {object} props
- * @param {string} location e.g. "prop", "context", "child context"
- * @private
- */
-function checkPropTypes(componentName, propTypes, props, location) {
- for (var propName in propTypes) {
- if (propTypes.hasOwnProperty(propName)) {
- var error;
- // Prop type validation may throw. In case they do, we don't want to
- // fail the render phase where it didn't fail before. So we log it.
- // After these have been cleaned up, we'll let them throw.
- try {
- error = propTypes[propName](props, propName, componentName, location);
- } catch (ex) {
- error = ex;
- }
- if (error instanceof Error && !(error.message in loggedTypeFailures)) {
- // Only monitor this failure once because there tends to be a lot of the
- // same error.
- loggedTypeFailures[error.message] = true;
- // This will soon use the warning module
- monitorCodeUse(
- 'react_failed_descriptor_type_check',
- { message: error.message }
- );
- }
- }
- }
-}
-
-var ReactElementValidator = {
-
- createElement: function(type, props, children) {
- var element = ReactElement.createElement.apply(this, arguments);
-
- // The result can be nullish if a mock or a custom function is used.
- // TODO: Drop this when these are no longer allowed as the type argument.
- if (element == null) {
- return element;
- }
-
- for (var i = 2; i < arguments.length; i++) {
- validateChildKeys(arguments[i], type);
- }
-
- var name = type.displayName;
- if (type.propTypes) {
- checkPropTypes(
- name,
- type.propTypes,
- element.props,
- ReactPropTypeLocations.prop
- );
- }
- if (type.contextTypes) {
- checkPropTypes(
- name,
- type.contextTypes,
- element._context,
- ReactPropTypeLocations.context
- );
- }
- return element;
- },
-
- createFactory: function(type) {
- var validatedFactory = ReactElementValidator.createElement.bind(
- null,
- type
- );
- validatedFactory.type = type;
- return validatedFactory;
- }
-
-};
-
-module.exports = ReactElementValidator;
-
-},{"./ReactCurrentOwner":42,"./ReactElement":58,"./ReactPropTypeLocations":78,"./monitorCodeUse":150}],60:[function(_dereq_,module,exports){
-/**
- * Copyright 2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactEmptyComponent
- */
-
-"use strict";
-
-var ReactElement = _dereq_("./ReactElement");
-
-var invariant = _dereq_("./invariant");
-
-var component;
-// This registry keeps track of the React IDs of the components that rendered to
-// `null` (in reality a placeholder such as `noscript`)
-var nullComponentIdsRegistry = {};
-
-var ReactEmptyComponentInjection = {
- injectEmptyComponent: function(emptyComponent) {
- component = ReactElement.createFactory(emptyComponent);
- }
-};
-
-/**
- * @return {ReactComponent} component The injected empty component.
- */
-function getEmptyComponent() {
- ("production" !== "development" ? invariant(
- component,
- 'Trying to return null from a render, but no null placeholder component ' +
- 'was injected.'
- ) : invariant(component));
- return component();
-}
-
-/**
- * Mark the component as having rendered to null.
- * @param {string} id Component's `_rootNodeID`.
- */
-function registerNullComponentID(id) {
- nullComponentIdsRegistry[id] = true;
-}
-
-/**
- * Unmark the component as having rendered to null: it renders to something now.
- * @param {string} id Component's `_rootNodeID`.
- */
-function deregisterNullComponentID(id) {
- delete nullComponentIdsRegistry[id];
-}
-
-/**
- * @param {string} id Component's `_rootNodeID`.
- * @return {boolean} True if the component is rendered to null.
- */
-function isNullComponentID(id) {
- return nullComponentIdsRegistry[id];
-}
-
-var ReactEmptyComponent = {
- deregisterNullComponentID: deregisterNullComponentID,
- getEmptyComponent: getEmptyComponent,
- injection: ReactEmptyComponentInjection,
- isNullComponentID: isNullComponentID,
- registerNullComponentID: registerNullComponentID
-};
-
-module.exports = ReactEmptyComponent;
-
-},{"./ReactElement":58,"./invariant":140}],61:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactErrorUtils
- * @typechecks
- */
-
-"use strict";
-
-var ReactErrorUtils = {
- /**
- * Creates a guarded version of a function. This is supposed to make debugging
- * of event handlers easier. To aid debugging with the browser's debugger,
- * this currently simply returns the original function.
- *
- * @param {function} func Function to be executed
- * @param {string} name The name of the guard
- * @return {function}
- */
- guard: function(func, name) {
- return func;
- }
-};
-
-module.exports = ReactErrorUtils;
-
-},{}],62:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactEventEmitterMixin
- */
-
-"use strict";
-
-var EventPluginHub = _dereq_("./EventPluginHub");
-
-function runEventQueueInBatch(events) {
- EventPluginHub.enqueueEvents(events);
- EventPluginHub.processEventQueue();
-}
-
-var ReactEventEmitterMixin = {
-
- /**
- * Streams a fired top-level event to `EventPluginHub` where plugins have the
- * opportunity to create `ReactEvent`s to be dispatched.
- *
- * @param {string} topLevelType Record from `EventConstants`.
- * @param {object} topLevelTarget The listening component root node.
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
- * @param {object} nativeEvent Native environment event.
- */
- handleTopLevel: function(
- topLevelType,
- topLevelTarget,
- topLevelTargetID,
- nativeEvent) {
- var events = EventPluginHub.extractEvents(
- topLevelType,
- topLevelTarget,
- topLevelTargetID,
- nativeEvent
- );
-
- runEventQueueInBatch(events);
- }
-};
-
-module.exports = ReactEventEmitterMixin;
-
-},{"./EventPluginHub":19}],63:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactEventListener
- * @typechecks static-only
- */
-
-"use strict";
-
-var EventListener = _dereq_("./EventListener");
-var ExecutionEnvironment = _dereq_("./ExecutionEnvironment");
-var PooledClass = _dereq_("./PooledClass");
-var ReactInstanceHandles = _dereq_("./ReactInstanceHandles");
-var ReactMount = _dereq_("./ReactMount");
-var ReactUpdates = _dereq_("./ReactUpdates");
-
-var assign = _dereq_("./Object.assign");
-var getEventTarget = _dereq_("./getEventTarget");
-var getUnboundedScrollPosition = _dereq_("./getUnboundedScrollPosition");
-
-/**
- * Finds the parent React component of `node`.
- *
- * @param {*} node
- * @return {?DOMEventTarget} Parent container, or `null` if the specified node
- * is not nested.
- */
-function findParent(node) {
- // TODO: It may be a good idea to cache this to prevent unnecessary DOM
- // traversal, but caching is difficult to do correctly without using a
- // mutation observer to listen for all DOM changes.
- var nodeID = ReactMount.getID(node);
- var rootID = ReactInstanceHandles.getReactRootIDFromNodeID(nodeID);
- var container = ReactMount.findReactContainerForID(rootID);
- var parent = ReactMount.getFirstReactDOM(container);
- return parent;
-}
-
-// Used to store ancestor hierarchy in top level callback
-function TopLevelCallbackBookKeeping(topLevelType, nativeEvent) {
- this.topLevelType = topLevelType;
- this.nativeEvent = nativeEvent;
- this.ancestors = [];
-}
-assign(TopLevelCallbackBookKeeping.prototype, {
- destructor: function() {
- this.topLevelType = null;
- this.nativeEvent = null;
- this.ancestors.length = 0;
- }
-});
-PooledClass.addPoolingTo(
- TopLevelCallbackBookKeeping,
- PooledClass.twoArgumentPooler
-);
-
-function handleTopLevelImpl(bookKeeping) {
- var topLevelTarget = ReactMount.getFirstReactDOM(
- getEventTarget(bookKeeping.nativeEvent)
- ) || window;
-
- // Loop through the hierarchy, in case there's any nested components.
- // It's important that we build the array of ancestors before calling any
- // event handlers, because event handlers can modify the DOM, leading to
- // inconsistencies with ReactMount's node cache. See #1105.
- var ancestor = topLevelTarget;
- while (ancestor) {
- bookKeeping.ancestors.push(ancestor);
- ancestor = findParent(ancestor);
- }
-
- for (var i = 0, l = bookKeeping.ancestors.length; i < l; i++) {
- topLevelTarget = bookKeeping.ancestors[i];
- var topLevelTargetID = ReactMount.getID(topLevelTarget) || '';
- ReactEventListener._handleTopLevel(
- bookKeeping.topLevelType,
- topLevelTarget,
- topLevelTargetID,
- bookKeeping.nativeEvent
- );
- }
-}
-
-function scrollValueMonitor(cb) {
- var scrollPosition = getUnboundedScrollPosition(window);
- cb(scrollPosition);
-}
-
-var ReactEventListener = {
- _enabled: true,
- _handleTopLevel: null,
-
- WINDOW_HANDLE: ExecutionEnvironment.canUseDOM ? window : null,
-
- setHandleTopLevel: function(handleTopLevel) {
- ReactEventListener._handleTopLevel = handleTopLevel;
- },
-
- setEnabled: function(enabled) {
- ReactEventListener._enabled = !!enabled;
- },
-
- isEnabled: function() {
- return ReactEventListener._enabled;
- },
-
-
- /**
- * Traps top-level events by using event bubbling.
- *
- * @param {string} topLevelType Record from `EventConstants`.
- * @param {string} handlerBaseName Event name (e.g. "click").
- * @param {object} handle Element on which to attach listener.
- * @return {object} An object with a remove function which will forcefully
- * remove the listener.
- * @internal
- */
- trapBubbledEvent: function(topLevelType, handlerBaseName, handle) {
- var element = handle;
- if (!element) {
- return;
- }
- return EventListener.listen(
- element,
- handlerBaseName,
- ReactEventListener.dispatchEvent.bind(null, topLevelType)
- );
- },
-
- /**
- * Traps a top-level event by using event capturing.
- *
- * @param {string} topLevelType Record from `EventConstants`.
- * @param {string} handlerBaseName Event name (e.g. "click").
- * @param {object} handle Element on which to attach listener.
- * @return {object} An object with a remove function which will forcefully
- * remove the listener.
- * @internal
- */
- trapCapturedEvent: function(topLevelType, handlerBaseName, handle) {
- var element = handle;
- if (!element) {
- return;
- }
- return EventListener.capture(
- element,
- handlerBaseName,
- ReactEventListener.dispatchEvent.bind(null, topLevelType)
- );
- },
-
- monitorScrollValue: function(refresh) {
- var callback = scrollValueMonitor.bind(null, refresh);
- EventListener.listen(window, 'scroll', callback);
- EventListener.listen(window, 'resize', callback);
- },
-
- dispatchEvent: function(topLevelType, nativeEvent) {
- if (!ReactEventListener._enabled) {
- return;
- }
-
- var bookKeeping = TopLevelCallbackBookKeeping.getPooled(
- topLevelType,
- nativeEvent
- );
- try {
- // Event queue being processed in the same cycle allows
- // `preventDefault`.
- ReactUpdates.batchedUpdates(handleTopLevelImpl, bookKeeping);
- } finally {
- TopLevelCallbackBookKeeping.release(bookKeeping);
- }
- }
-};
-
-module.exports = ReactEventListener;
-
-},{"./EventListener":18,"./ExecutionEnvironment":23,"./Object.assign":29,"./PooledClass":30,"./ReactInstanceHandles":66,"./ReactMount":70,"./ReactUpdates":91,"./getEventTarget":131,"./getUnboundedScrollPosition":136}],64:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactInjection
- */
-
-"use strict";
-
-var DOMProperty = _dereq_("./DOMProperty");
-var EventPluginHub = _dereq_("./EventPluginHub");
-var ReactComponent = _dereq_("./ReactComponent");
-var ReactCompositeComponent = _dereq_("./ReactCompositeComponent");
-var ReactEmptyComponent = _dereq_("./ReactEmptyComponent");
-var ReactBrowserEventEmitter = _dereq_("./ReactBrowserEventEmitter");
-var ReactNativeComponent = _dereq_("./ReactNativeComponent");
-var ReactPerf = _dereq_("./ReactPerf");
-var ReactRootIndex = _dereq_("./ReactRootIndex");
-var ReactUpdates = _dereq_("./ReactUpdates");
-
-var ReactInjection = {
- Component: ReactComponent.injection,
- CompositeComponent: ReactCompositeComponent.injection,
- DOMProperty: DOMProperty.injection,
- EmptyComponent: ReactEmptyComponent.injection,
- EventPluginHub: EventPluginHub.injection,
- EventEmitter: ReactBrowserEventEmitter.injection,
- NativeComponent: ReactNativeComponent.injection,
- Perf: ReactPerf.injection,
- RootIndex: ReactRootIndex.injection,
- Updates: ReactUpdates.injection
-};
-
-module.exports = ReactInjection;
-
-},{"./DOMProperty":12,"./EventPluginHub":19,"./ReactBrowserEventEmitter":33,"./ReactComponent":37,"./ReactCompositeComponent":40,"./ReactEmptyComponent":60,"./ReactNativeComponent":73,"./ReactPerf":75,"./ReactRootIndex":82,"./ReactUpdates":91}],65:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactInputSelection
- */
-
-"use strict";
-
-var ReactDOMSelection = _dereq_("./ReactDOMSelection");
-
-var containsNode = _dereq_("./containsNode");
-var focusNode = _dereq_("./focusNode");
-var getActiveElement = _dereq_("./getActiveElement");
-
-function isInDocument(node) {
- return containsNode(document.documentElement, node);
-}
-
-/**
- * @ReactInputSelection: React input selection module. Based on Selection.js,
- * but modified to be suitable for react and has a couple of bug fixes (doesn't
- * assume buttons have range selections allowed).
- * Input selection module for React.
- */
-var ReactInputSelection = {
-
- hasSelectionCapabilities: function(elem) {
- return elem && (
- (elem.nodeName === 'INPUT' && elem.type === 'text') ||
- elem.nodeName === 'TEXTAREA' ||
- elem.contentEditable === 'true'
- );
- },
-
- getSelectionInformation: function() {
- var focusedElem = getActiveElement();
- return {
- focusedElem: focusedElem,
- selectionRange:
- ReactInputSelection.hasSelectionCapabilities(focusedElem) ?
- ReactInputSelection.getSelection(focusedElem) :
- null
- };
- },
-
- /**
- * @restoreSelection: If any selection information was potentially lost,
- * restore it. This is useful when performing operations that could remove dom
- * nodes and place them back in, resulting in focus being lost.
- */
- restoreSelection: function(priorSelectionInformation) {
- var curFocusedElem = getActiveElement();
- var priorFocusedElem = priorSelectionInformation.focusedElem;
- var priorSelectionRange = priorSelectionInformation.selectionRange;
- if (curFocusedElem !== priorFocusedElem &&
- isInDocument(priorFocusedElem)) {
- if (ReactInputSelection.hasSelectionCapabilities(priorFocusedElem)) {
- ReactInputSelection.setSelection(
- priorFocusedElem,
- priorSelectionRange
- );
- }
- focusNode(priorFocusedElem);
- }
- },
-
- /**
- * @getSelection: Gets the selection bounds of a focused textarea, input or
- * contentEditable node.
- * -@input: Look up selection bounds of this input
- * -@return {start: selectionStart, end: selectionEnd}
- */
- getSelection: function(input) {
- var selection;
-
- if ('selectionStart' in input) {
- // Modern browser with input or textarea.
- selection = {
- start: input.selectionStart,
- end: input.selectionEnd
- };
- } else if (document.selection && input.nodeName === 'INPUT') {
- // IE8 input.
- var range = document.selection.createRange();
- // There can only be one selection per document in IE, so it must
- // be in our element.
- if (range.parentElement() === input) {
- selection = {
- start: -range.moveStart('character', -input.value.length),
- end: -range.moveEnd('character', -input.value.length)
- };
- }
- } else {
- // Content editable or old IE textarea.
- selection = ReactDOMSelection.getOffsets(input);
- }
-
- return selection || {start: 0, end: 0};
- },
-
- /**
- * @setSelection: Sets the selection bounds of a textarea or input and focuses
- * the input.
- * -@input Set selection bounds of this input or textarea
- * -@offsets Object of same form that is returned from get*
- */
- setSelection: function(input, offsets) {
- var start = offsets.start;
- var end = offsets.end;
- if (typeof end === 'undefined') {
- end = start;
- }
-
- if ('selectionStart' in input) {
- input.selectionStart = start;
- input.selectionEnd = Math.min(end, input.value.length);
- } else if (document.selection && input.nodeName === 'INPUT') {
- var range = input.createTextRange();
- range.collapse(true);
- range.moveStart('character', start);
- range.moveEnd('character', end - start);
- range.select();
- } else {
- ReactDOMSelection.setOffsets(input, offsets);
- }
- }
-};
-
-module.exports = ReactInputSelection;
-
-},{"./ReactDOMSelection":52,"./containsNode":114,"./focusNode":125,"./getActiveElement":127}],66:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactInstanceHandles
- * @typechecks static-only
- */
-
-"use strict";
-
-var ReactRootIndex = _dereq_("./ReactRootIndex");
-
-var invariant = _dereq_("./invariant");
-
-var SEPARATOR = '.';
-var SEPARATOR_LENGTH = SEPARATOR.length;
-
-/**
- * Maximum depth of traversals before we consider the possibility of a bad ID.
- */
-var MAX_TREE_DEPTH = 100;
-
-/**
- * Creates a DOM ID prefix to use when mounting React components.
- *
- * @param {number} index A unique integer
- * @return {string} React root ID.
- * @internal
- */
-function getReactRootIDString(index) {
- return SEPARATOR + index.toString(36);
-}
-
-/**
- * Checks if a character in the supplied ID is a separator or the end.
- *
- * @param {string} id A React DOM ID.
- * @param {number} index Index of the character to check.
- * @return {boolean} True if the character is a separator or end of the ID.
- * @private
- */
-function isBoundary(id, index) {
- return id.charAt(index) === SEPARATOR || index === id.length;
-}
-
-/**
- * Checks if the supplied string is a valid React DOM ID.
- *
- * @param {string} id A React DOM ID, maybe.
- * @return {boolean} True if the string is a valid React DOM ID.
- * @private
- */
-function isValidID(id) {
- return id === '' || (
- id.charAt(0) === SEPARATOR && id.charAt(id.length - 1) !== SEPARATOR
- );
-}
-
-/**
- * Checks if the first ID is an ancestor of or equal to the second ID.
- *
- * @param {string} ancestorID
- * @param {string} descendantID
- * @return {boolean} True if `ancestorID` is an ancestor of `descendantID`.
- * @internal
- */
-function isAncestorIDOf(ancestorID, descendantID) {
- return (
- descendantID.indexOf(ancestorID) === 0 &&
- isBoundary(descendantID, ancestorID.length)
- );
-}
-
-/**
- * Gets the parent ID of the supplied React DOM ID, `id`.
- *
- * @param {string} id ID of a component.
- * @return {string} ID of the parent, or an empty string.
- * @private
- */
-function getParentID(id) {
- return id ? id.substr(0, id.lastIndexOf(SEPARATOR)) : '';
-}
-
-/**
- * Gets the next DOM ID on the tree path from the supplied `ancestorID` to the
- * supplied `destinationID`. If they are equal, the ID is returned.
- *
- * @param {string} ancestorID ID of an ancestor node of `destinationID`.
- * @param {string} destinationID ID of the destination node.
- * @return {string} Next ID on the path from `ancestorID` to `destinationID`.
- * @private
- */
-function getNextDescendantID(ancestorID, destinationID) {
- ("production" !== "development" ? invariant(
- isValidID(ancestorID) && isValidID(destinationID),
- 'getNextDescendantID(%s, %s): Received an invalid React DOM ID.',
- ancestorID,
- destinationID
- ) : invariant(isValidID(ancestorID) && isValidID(destinationID)));
- ("production" !== "development" ? invariant(
- isAncestorIDOf(ancestorID, destinationID),
- 'getNextDescendantID(...): React has made an invalid assumption about ' +
- 'the DOM hierarchy. Expected `%s` to be an ancestor of `%s`.',
- ancestorID,
- destinationID
- ) : invariant(isAncestorIDOf(ancestorID, destinationID)));
- if (ancestorID === destinationID) {
- return ancestorID;
- }
- // Skip over the ancestor and the immediate separator. Traverse until we hit
- // another separator or we reach the end of `destinationID`.
- var start = ancestorID.length + SEPARATOR_LENGTH;
- for (var i = start; i < destinationID.length; i++) {
- if (isBoundary(destinationID, i)) {
- break;
- }
- }
- return destinationID.substr(0, i);
-}
-
-/**
- * Gets the nearest common ancestor ID of two IDs.
- *
- * Using this ID scheme, the nearest common ancestor ID is the longest common
- * prefix of the two IDs that immediately preceded a "marker" in both strings.
- *
- * @param {string} oneID
- * @param {string} twoID
- * @return {string} Nearest common ancestor ID, or the empty string if none.
- * @private
- */
-function getFirstCommonAncestorID(oneID, twoID) {
- var minLength = Math.min(oneID.length, twoID.length);
- if (minLength === 0) {
- return '';
- }
- var lastCommonMarkerIndex = 0;
- // Use `<=` to traverse until the "EOL" of the shorter string.
- for (var i = 0; i <= minLength; i++) {
- if (isBoundary(oneID, i) && isBoundary(twoID, i)) {
- lastCommonMarkerIndex = i;
- } else if (oneID.charAt(i) !== twoID.charAt(i)) {
- break;
- }
- }
- var longestCommonID = oneID.substr(0, lastCommonMarkerIndex);
- ("production" !== "development" ? invariant(
- isValidID(longestCommonID),
- 'getFirstCommonAncestorID(%s, %s): Expected a valid React DOM ID: %s',
- oneID,
- twoID,
- longestCommonID
- ) : invariant(isValidID(longestCommonID)));
- return longestCommonID;
-}
-
-/**
- * Traverses the parent path between two IDs (either up or down). The IDs must
- * not be the same, and there must exist a parent path between them. If the
- * callback returns `false`, traversal is stopped.
- *
- * @param {?string} start ID at which to start traversal.
- * @param {?string} stop ID at which to end traversal.
- * @param {function} cb Callback to invoke each ID with.
- * @param {?boolean} skipFirst Whether or not to skip the first node.
- * @param {?boolean} skipLast Whether or not to skip the last node.
- * @private
- */
-function traverseParentPath(start, stop, cb, arg, skipFirst, skipLast) {
- start = start || '';
- stop = stop || '';
- ("production" !== "development" ? invariant(
- start !== stop,
- 'traverseParentPath(...): Cannot traverse from and to the same ID, `%s`.',
- start
- ) : invariant(start !== stop));
- var traverseUp = isAncestorIDOf(stop, start);
- ("production" !== "development" ? invariant(
- traverseUp || isAncestorIDOf(start, stop),
- 'traverseParentPath(%s, %s, ...): Cannot traverse from two IDs that do ' +
- 'not have a parent path.',
- start,
- stop
- ) : invariant(traverseUp || isAncestorIDOf(start, stop)));
- // Traverse from `start` to `stop` one depth at a time.
- var depth = 0;
- var traverse = traverseUp ? getParentID : getNextDescendantID;
- for (var id = start; /* until break */; id = traverse(id, stop)) {
- var ret;
- if ((!skipFirst || id !== start) && (!skipLast || id !== stop)) {
- ret = cb(id, traverseUp, arg);
- }
- if (ret === false || id === stop) {
- // Only break //after// visiting `stop`.
- break;
- }
- ("production" !== "development" ? invariant(
- depth++ < MAX_TREE_DEPTH,
- 'traverseParentPath(%s, %s, ...): Detected an infinite loop while ' +
- 'traversing the React DOM ID tree. This may be due to malformed IDs: %s',
- start, stop
- ) : invariant(depth++ < MAX_TREE_DEPTH));
- }
-}
-
-/**
- * Manages the IDs assigned to DOM representations of React components. This
- * uses a specific scheme in order to traverse the DOM efficiently (e.g. in
- * order to simulate events).
- *
- * @internal
- */
-var ReactInstanceHandles = {
-
- /**
- * Constructs a React root ID
- * @return {string} A React root ID.
- */
- createReactRootID: function() {
- return getReactRootIDString(ReactRootIndex.createReactRootIndex());
- },
-
- /**
- * Constructs a React ID by joining a root ID with a name.
- *
- * @param {string} rootID Root ID of a parent component.
- * @param {string} name A component's name (as flattened children).
- * @return {string} A React ID.
- * @internal
- */
- createReactID: function(rootID, name) {
- return rootID + name;
- },
-
- /**
- * Gets the DOM ID of the React component that is the root of the tree that
- * contains the React component with the supplied DOM ID.
- *
- * @param {string} id DOM ID of a React component.
- * @return {?string} DOM ID of the React component that is the root.
- * @internal
- */
- getReactRootIDFromNodeID: function(id) {
- if (id && id.charAt(0) === SEPARATOR && id.length > 1) {
- var index = id.indexOf(SEPARATOR, 1);
- return index > -1 ? id.substr(0, index) : id;
- }
- return null;
- },
-
- /**
- * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that
- * should would receive a `mouseEnter` or `mouseLeave` event.
- *
- * NOTE: Does not invoke the callback on the nearest common ancestor because
- * nothing "entered" or "left" that element.
- *
- * @param {string} leaveID ID being left.
- * @param {string} enterID ID being entered.
- * @param {function} cb Callback to invoke on each entered/left ID.
- * @param {*} upArg Argument to invoke the callback with on left IDs.
- * @param {*} downArg Argument to invoke the callback with on entered IDs.
- * @internal
- */
- traverseEnterLeave: function(leaveID, enterID, cb, upArg, downArg) {
- var ancestorID = getFirstCommonAncestorID(leaveID, enterID);
- if (ancestorID !== leaveID) {
- traverseParentPath(leaveID, ancestorID, cb, upArg, false, true);
- }
- if (ancestorID !== enterID) {
- traverseParentPath(ancestorID, enterID, cb, downArg, true, false);
- }
- },
-
- /**
- * Simulates the traversal of a two-phase, capture/bubble event dispatch.
- *
- * NOTE: This traversal happens on IDs without touching the DOM.
- *
- * @param {string} targetID ID of the target node.
- * @param {function} cb Callback to invoke.
- * @param {*} arg Argument to invoke the callback with.
- * @internal
- */
- traverseTwoPhase: function(targetID, cb, arg) {
- if (targetID) {
- traverseParentPath('', targetID, cb, arg, true, false);
- traverseParentPath(targetID, '', cb, arg, false, true);
- }
- },
-
- /**
- * Traverse a node ID, calling the supplied `cb` for each ancestor ID. For
- * example, passing `.0.$row-0.1` would result in `cb` getting called
- * with `.0`, `.0.$row-0`, and `.0.$row-0.1`.
- *
- * NOTE: This traversal happens on IDs without touching the DOM.
- *
- * @param {string} targetID ID of the target node.
- * @param {function} cb Callback to invoke.
- * @param {*} arg Argument to invoke the callback with.
- * @internal
- */
- traverseAncestors: function(targetID, cb, arg) {
- traverseParentPath('', targetID, cb, arg, true, false);
- },
-
- /**
- * Exposed for unit testing.
- * @private
- */
- _getFirstCommonAncestorID: getFirstCommonAncestorID,
-
- /**
- * Exposed for unit testing.
- * @private
- */
- _getNextDescendantID: getNextDescendantID,
-
- isAncestorIDOf: isAncestorIDOf,
-
- SEPARATOR: SEPARATOR
-
-};
-
-module.exports = ReactInstanceHandles;
-
-},{"./ReactRootIndex":82,"./invariant":140}],67:[function(_dereq_,module,exports){
-/**
- * Copyright 2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactLegacyElement
- */
-
-"use strict";
-
-var ReactCurrentOwner = _dereq_("./ReactCurrentOwner");
-
-var invariant = _dereq_("./invariant");
-var monitorCodeUse = _dereq_("./monitorCodeUse");
-var warning = _dereq_("./warning");
-
-var legacyFactoryLogs = {};
-function warnForLegacyFactoryCall() {
- if (!ReactLegacyElementFactory._isLegacyCallWarningEnabled) {
- return;
- }
- var owner = ReactCurrentOwner.current;
- var name = owner && owner.constructor ? owner.constructor.displayName : '';
- if (!name) {
- name = 'Something';
- }
- if (legacyFactoryLogs.hasOwnProperty(name)) {
- return;
- }
- legacyFactoryLogs[name] = true;
- ("production" !== "development" ? warning(
- false,
- name + ' is calling a React component directly. ' +
- 'Use a factory or JSX instead. See: http://fb.me/react-legacyfactory'
- ) : null);
- monitorCodeUse('react_legacy_factory_call', { version: 3, name: name });
-}
-
-function warnForPlainFunctionType(type) {
- var isReactClass =
- type.prototype &&
- typeof type.prototype.mountComponent === 'function' &&
- typeof type.prototype.receiveComponent === 'function';
- if (isReactClass) {
- ("production" !== "development" ? warning(
- false,
- 'Did not expect to get a React class here. Use `Component` instead ' +
- 'of `Component.type` or `this.constructor`.'
- ) : null);
- } else {
- if (!type._reactWarnedForThisType) {
- try {
- type._reactWarnedForThisType = true;
- } catch (x) {
- // just incase this is a frozen object or some special object
- }
- monitorCodeUse(
- 'react_non_component_in_jsx',
- { version: 3, name: type.name }
- );
- }
- ("production" !== "development" ? warning(
- false,
- 'This JSX uses a plain function. Only React components are ' +
- 'valid in React\'s JSX transform.'
- ) : null);
- }
-}
-
-function warnForNonLegacyFactory(type) {
- ("production" !== "development" ? warning(
- false,
- 'Do not pass React.DOM.' + type.type + ' to JSX or createFactory. ' +
- 'Use the string "' + type.type + '" instead.'
- ) : null);
-}
-
-/**
- * Transfer static properties from the source to the target. Functions are
- * rebound to have this reflect the original source.
- */
-function proxyStaticMethods(target, source) {
- if (typeof source !== 'function') {
- return;
- }
- for (var key in source) {
- if (source.hasOwnProperty(key)) {
- var value = source[key];
- if (typeof value === 'function') {
- var bound = value.bind(source);
- // Copy any properties defined on the function, such as `isRequired` on
- // a PropTypes validator.
- for (var k in value) {
- if (value.hasOwnProperty(k)) {
- bound[k] = value[k];
- }
- }
- target[key] = bound;
- } else {
- target[key] = value;
- }
- }
- }
-}
-
-// We use an object instead of a boolean because booleans are ignored by our
-// mocking libraries when these factories gets mocked.
-var LEGACY_MARKER = {};
-var NON_LEGACY_MARKER = {};
-
-var ReactLegacyElementFactory = {};
-
-ReactLegacyElementFactory.wrapCreateFactory = function(createFactory) {
- var legacyCreateFactory = function(type) {
- if (typeof type !== 'function') {
- // Non-function types cannot be legacy factories
- return createFactory(type);
- }
-
- if (type.isReactNonLegacyFactory) {
- // This is probably a factory created by ReactDOM we unwrap it to get to
- // the underlying string type. It shouldn't have been passed here so we
- // warn.
- if ("production" !== "development") {
- warnForNonLegacyFactory(type);
- }
- return createFactory(type.type);
- }
-
- if (type.isReactLegacyFactory) {
- // This is probably a legacy factory created by ReactCompositeComponent.
- // We unwrap it to get to the underlying class.
- return createFactory(type.type);
- }
-
- if ("production" !== "development") {
- warnForPlainFunctionType(type);
- }
-
- // Unless it's a legacy factory, then this is probably a plain function,
- // that is expecting to be invoked by JSX. We can just return it as is.
- return type;
- };
- return legacyCreateFactory;
-};
-
-ReactLegacyElementFactory.wrapCreateElement = function(createElement) {
- var legacyCreateElement = function(type, props, children) {
- if (typeof type !== 'function') {
- // Non-function types cannot be legacy factories
- return createElement.apply(this, arguments);
- }
-
- var args;
-
- if (type.isReactNonLegacyFactory) {
- // This is probably a factory created by ReactDOM we unwrap it to get to
- // the underlying string type. It shouldn't have been passed here so we
- // warn.
- if ("production" !== "development") {
- warnForNonLegacyFactory(type);
- }
- args = Array.prototype.slice.call(arguments, 0);
- args[0] = type.type;
- return createElement.apply(this, args);
- }
-
- if (type.isReactLegacyFactory) {
- // This is probably a legacy factory created by ReactCompositeComponent.
- // We unwrap it to get to the underlying class.
- if (type._isMockFunction) {
- // If this is a mock function, people will expect it to be called. We
- // will actually call the original mock factory function instead. This
- // future proofs unit testing that assume that these are classes.
- type.type._mockedReactClassConstructor = type;
- }
- args = Array.prototype.slice.call(arguments, 0);
- args[0] = type.type;
- return createElement.apply(this, args);
- }
-
- if ("production" !== "development") {
- warnForPlainFunctionType(type);
- }
-
- // This is being called with a plain function we should invoke it
- // immediately as if this was used with legacy JSX.
- return type.apply(null, Array.prototype.slice.call(arguments, 1));
- };
- return legacyCreateElement;
-};
-
-ReactLegacyElementFactory.wrapFactory = function(factory) {
- ("production" !== "development" ? invariant(
- typeof factory === 'function',
- 'This is suppose to accept a element factory'
- ) : invariant(typeof factory === 'function'));
- var legacyElementFactory = function(config, children) {
- // This factory should not be called when JSX is used. Use JSX instead.
- if ("production" !== "development") {
- warnForLegacyFactoryCall();
- }
- return factory.apply(this, arguments);
- };
- proxyStaticMethods(legacyElementFactory, factory.type);
- legacyElementFactory.isReactLegacyFactory = LEGACY_MARKER;
- legacyElementFactory.type = factory.type;
- return legacyElementFactory;
-};
-
-// This is used to mark a factory that will remain. E.g. we're allowed to call
-// it as a function. However, you're not suppose to pass it to createElement
-// or createFactory, so it will warn you if you do.
-ReactLegacyElementFactory.markNonLegacyFactory = function(factory) {
- factory.isReactNonLegacyFactory = NON_LEGACY_MARKER;
- return factory;
-};
-
-// Checks if a factory function is actually a legacy factory pretending to
-// be a class.
-ReactLegacyElementFactory.isValidFactory = function(factory) {
- // TODO: This will be removed and moved into a class validator or something.
- return typeof factory === 'function' &&
- factory.isReactLegacyFactory === LEGACY_MARKER;
-};
-
-ReactLegacyElementFactory.isValidClass = function(factory) {
- if ("production" !== "development") {
- ("production" !== "development" ? warning(
- false,
- 'isValidClass is deprecated and will be removed in a future release. ' +
- 'Use a more specific validator instead.'
- ) : null);
- }
- return ReactLegacyElementFactory.isValidFactory(factory);
-};
-
-ReactLegacyElementFactory._isLegacyCallWarningEnabled = true;
-
-module.exports = ReactLegacyElementFactory;
-
-},{"./ReactCurrentOwner":42,"./invariant":140,"./monitorCodeUse":150,"./warning":160}],68:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactLink
- * @typechecks static-only
- */
-
-"use strict";
-
-/**
- * ReactLink encapsulates a common pattern in which a component wants to modify
- * a prop received from its parent. ReactLink allows the parent to pass down a
- * value coupled with a callback that, when invoked, expresses an intent to
- * modify that value. For example:
- *
- * React.createClass({
- * getInitialState: function() {
- * return {value: ''};
- * },
- * render: function() {
- * var valueLink = new ReactLink(this.state.value, this._handleValueChange);
- * return <input valueLink={valueLink} />;
- * },
- * this._handleValueChange: function(newValue) {
- * this.setState({value: newValue});
- * }
- * });
- *
- * We have provided some sugary mixins to make the creation and
- * consumption of ReactLink easier; see LinkedValueUtils and LinkedStateMixin.
- */
-
-var React = _dereq_("./React");
-
-/**
- * @param {*} value current value of the link
- * @param {function} requestChange callback to request a change
- */
-function ReactLink(value, requestChange) {
- this.value = value;
- this.requestChange = requestChange;
-}
-
-/**
- * Creates a PropType that enforces the ReactLink API and optionally checks the
- * type of the value being passed inside the link. Example:
- *
- * MyComponent.propTypes = {
- * tabIndexLink: ReactLink.PropTypes.link(React.PropTypes.number)
- * }
- */
-function createLinkTypeChecker(linkType) {
- var shapes = {
- value: typeof linkType === 'undefined' ?
- React.PropTypes.any.isRequired :
- linkType.isRequired,
- requestChange: React.PropTypes.func.isRequired
- };
- return React.PropTypes.shape(shapes);
-}
-
-ReactLink.PropTypes = {
- link: createLinkTypeChecker
-};
-
-module.exports = ReactLink;
-
-},{"./React":31}],69:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactMarkupChecksum
- */
-
-"use strict";
-
-var adler32 = _dereq_("./adler32");
-
-var ReactMarkupChecksum = {
- CHECKSUM_ATTR_NAME: 'data-react-checksum',
-
- /**
- * @param {string} markup Markup string
- * @return {string} Markup string with checksum attribute attached
- */
- addChecksumToMarkup: function(markup) {
- var checksum = adler32(markup);
- return markup.replace(
- '>',
- ' ' + ReactMarkupChecksum.CHECKSUM_ATTR_NAME + '="' + checksum + '">'
- );
- },
-
- /**
- * @param {string} markup to use
- * @param {DOMElement} element root React element
- * @returns {boolean} whether or not the markup is the same
- */
- canReuseMarkup: function(markup, element) {
- var existingChecksum = element.getAttribute(
- ReactMarkupChecksum.CHECKSUM_ATTR_NAME
- );
- existingChecksum = existingChecksum && parseInt(existingChecksum, 10);
- var markupChecksum = adler32(markup);
- return markupChecksum === existingChecksum;
- }
-};
-
-module.exports = ReactMarkupChecksum;
-
-},{"./adler32":110}],70:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactMount
- */
-
-"use strict";
-
-var DOMProperty = _dereq_("./DOMProperty");
-var ReactBrowserEventEmitter = _dereq_("./ReactBrowserEventEmitter");
-var ReactCurrentOwner = _dereq_("./ReactCurrentOwner");
-var ReactElement = _dereq_("./ReactElement");
-var ReactLegacyElement = _dereq_("./ReactLegacyElement");
-var ReactInstanceHandles = _dereq_("./ReactInstanceHandles");
-var ReactPerf = _dereq_("./ReactPerf");
-
-var containsNode = _dereq_("./containsNode");
-var deprecated = _dereq_("./deprecated");
-var getReactRootElementInContainer = _dereq_("./getReactRootElementInContainer");
-var instantiateReactComponent = _dereq_("./instantiateReactComponent");
-var invariant = _dereq_("./invariant");
-var shouldUpdateReactComponent = _dereq_("./shouldUpdateReactComponent");
-var warning = _dereq_("./warning");
-
-var createElement = ReactLegacyElement.wrapCreateElement(
- ReactElement.createElement
-);
-
-var SEPARATOR = ReactInstanceHandles.SEPARATOR;
-
-var ATTR_NAME = DOMProperty.ID_ATTRIBUTE_NAME;
-var nodeCache = {};
-
-var ELEMENT_NODE_TYPE = 1;
-var DOC_NODE_TYPE = 9;
-
-/** Mapping from reactRootID to React component instance. */
-var instancesByReactRootID = {};
-
-/** Mapping from reactRootID to `container` nodes. */
-var containersByReactRootID = {};
-
-if ("production" !== "development") {
- /** __DEV__-only mapping from reactRootID to root elements. */
- var rootElementsByReactRootID = {};
-}
-
-// Used to store breadth-first search state in findComponentRoot.
-var findComponentRootReusableArray = [];
-
-/**
- * @param {DOMElement} container DOM element that may contain a React component.
- * @return {?string} A "reactRoot" ID, if a React component is rendered.
- */
-function getReactRootID(container) {
- var rootElement = getReactRootElementInContainer(container);
- return rootElement && ReactMount.getID(rootElement);
-}
-
-/**
- * Accessing node[ATTR_NAME] or calling getAttribute(ATTR_NAME) on a form
- * element can return its control whose name or ID equals ATTR_NAME. All
- * DOM nodes support `getAttributeNode` but this can also get called on
- * other objects so just return '' if we're given something other than a
- * DOM node (such as window).
- *
- * @param {?DOMElement|DOMWindow|DOMDocument|DOMTextNode} node DOM node.
- * @return {string} ID of the supplied `domNode`.
- */
-function getID(node) {
- var id = internalGetID(node);
- if (id) {
- if (nodeCache.hasOwnProperty(id)) {
- var cached = nodeCache[id];
- if (cached !== node) {
- ("production" !== "development" ? invariant(
- !isValid(cached, id),
- 'ReactMount: Two valid but unequal nodes with the same `%s`: %s',
- ATTR_NAME, id
- ) : invariant(!isValid(cached, id)));
-
- nodeCache[id] = node;
- }
- } else {
- nodeCache[id] = node;
- }
- }
-
- return id;
-}
-
-function internalGetID(node) {
- // If node is something like a window, document, or text node, none of
- // which support attributes or a .getAttribute method, gracefully return
- // the empty string, as if the attribute were missing.
- return node && node.getAttribute && node.getAttribute(ATTR_NAME) || '';
-}
-
-/**
- * Sets the React-specific ID of the given node.
- *
- * @param {DOMElement} node The DOM node whose ID will be set.
- * @param {string} id The value of the ID attribute.
- */
-function setID(node, id) {
- var oldID = internalGetID(node);
- if (oldID !== id) {
- delete nodeCache[oldID];
- }
- node.setAttribute(ATTR_NAME, id);
- nodeCache[id] = node;
-}
-
-/**
- * Finds the node with the supplied React-generated DOM ID.
- *
- * @param {string} id A React-generated DOM ID.
- * @return {DOMElement} DOM node with the suppled `id`.
- * @internal
- */
-function getNode(id) {
- if (!nodeCache.hasOwnProperty(id) || !isValid(nodeCache[id], id)) {
- nodeCache[id] = ReactMount.findReactNodeByID(id);
- }
- return nodeCache[id];
-}
-
-/**
- * A node is "valid" if it is contained by a currently mounted container.
- *
- * This means that the node does not have to be contained by a document in
- * order to be considered valid.
- *
- * @param {?DOMElement} node The candidate DOM node.
- * @param {string} id The expected ID of the node.
- * @return {boolean} Whether the node is contained by a mounted container.
- */
-function isValid(node, id) {
- if (node) {
- ("production" !== "development" ? invariant(
- internalGetID(node) === id,
- 'ReactMount: Unexpected modification of `%s`',
- ATTR_NAME
- ) : invariant(internalGetID(node) === id));
-
- var container = ReactMount.findReactContainerForID(id);
- if (container && containsNode(container, node)) {
- return true;
- }
- }
-
- return false;
-}
-
-/**
- * Causes the cache to forget about one React-specific ID.
- *
- * @param {string} id The ID to forget.
- */
-function purgeID(id) {
- delete nodeCache[id];
-}
-
-var deepestNodeSoFar = null;
-function findDeepestCachedAncestorImpl(ancestorID) {
- var ancestor = nodeCache[ancestorID];
- if (ancestor && isValid(ancestor, ancestorID)) {
- deepestNodeSoFar = ancestor;
- } else {
- // This node isn't populated in the cache, so presumably none of its
- // descendants are. Break out of the loop.
- return false;
- }
-}
-
-/**
- * Return the deepest cached node whose ID is a prefix of `targetID`.
- */
-function findDeepestCachedAncestor(targetID) {
- deepestNodeSoFar = null;
- ReactInstanceHandles.traverseAncestors(
- targetID,
- findDeepestCachedAncestorImpl
- );
-
- var foundNode = deepestNodeSoFar;
- deepestNodeSoFar = null;
- return foundNode;
-}
-
-/**
- * Mounting is the process of initializing a React component by creatings its
- * representative DOM elements and inserting them into a supplied `container`.
- * Any prior content inside `container` is destroyed in the process.
- *
- * ReactMount.render(
- * component,
- * document.getElementById('container')
- * );
- *
- * <div id="container"> <-- Supplied `container`.
- * <div data-reactid=".3"> <-- Rendered reactRoot of React
- * // ... component.
- * </div>
- * </div>
- *
- * Inside of `container`, the first element rendered is the "reactRoot".
- */
-var ReactMount = {
- /** Exposed for debugging purposes **/
- _instancesByReactRootID: instancesByReactRootID,
-
- /**
- * This is a hook provided to support rendering React components while
- * ensuring that the apparent scroll position of its `container` does not
- * change.
- *
- * @param {DOMElement} container The `container` being rendered into.
- * @param {function} renderCallback This must be called once to do the render.
- */
- scrollMonitor: function(container, renderCallback) {
- renderCallback();
- },
-
- /**
- * Take a component that's already mounted into the DOM and replace its props
- * @param {ReactComponent} prevComponent component instance already in the DOM
- * @param {ReactComponent} nextComponent component instance to render
- * @param {DOMElement} container container to render into
- * @param {?function} callback function triggered on completion
- */
- _updateRootComponent: function(
- prevComponent,
- nextComponent,
- container,
- callback) {
- var nextProps = nextComponent.props;
- ReactMount.scrollMonitor(container, function() {
- prevComponent.replaceProps(nextProps, callback);
- });
-
- if ("production" !== "development") {
- // Record the root element in case it later gets transplanted.
- rootElementsByReactRootID[getReactRootID(container)] =
- getReactRootElementInContainer(container);
- }
-
- return prevComponent;
- },
-
- /**
- * Register a component into the instance map and starts scroll value
- * monitoring
- * @param {ReactComponent} nextComponent component instance to render
- * @param {DOMElement} container container to render into
- * @return {string} reactRoot ID prefix
- */
- _registerComponent: function(nextComponent, container) {
- ("production" !== "development" ? invariant(
- container && (
- container.nodeType === ELEMENT_NODE_TYPE ||
- container.nodeType === DOC_NODE_TYPE
- ),
- '_registerComponent(...): Target container is not a DOM element.'
- ) : invariant(container && (
- container.nodeType === ELEMENT_NODE_TYPE ||
- container.nodeType === DOC_NODE_TYPE
- )));
-
- ReactBrowserEventEmitter.ensureScrollValueMonitoring();
-
- var reactRootID = ReactMount.registerContainer(container);
- instancesByReactRootID[reactRootID] = nextComponent;
- return reactRootID;
- },
-
- /**
- * Render a new component into the DOM.
- * @param {ReactComponent} nextComponent component instance to render
- * @param {DOMElement} container container to render into
- * @param {boolean} shouldReuseMarkup if we should skip the markup insertion
- * @return {ReactComponent} nextComponent
- */
- _renderNewRootComponent: ReactPerf.measure(
- 'ReactMount',
- '_renderNewRootComponent',
- function(
- nextComponent,
- container,
- shouldReuseMarkup) {
- // Various parts of our code (such as ReactCompositeComponent's
- // _renderValidatedComponent) assume that calls to render aren't nested;
- // verify that that's the case.
- ("production" !== "development" ? warning(
- ReactCurrentOwner.current == null,
- '_renderNewRootComponent(): Render methods should be a pure function ' +
- 'of props and state; triggering nested component updates from ' +
- 'render is not allowed. If necessary, trigger nested updates in ' +
- 'componentDidUpdate.'
- ) : null);
-
- var componentInstance = instantiateReactComponent(nextComponent, null);
- var reactRootID = ReactMount._registerComponent(
- componentInstance,
- container
- );
- componentInstance.mountComponentIntoNode(
- reactRootID,
- container,
- shouldReuseMarkup
- );
-
- if ("production" !== "development") {
- // Record the root element in case it later gets transplanted.
- rootElementsByReactRootID[reactRootID] =
- getReactRootElementInContainer(container);
- }
-
- return componentInstance;
- }
- ),
-
- /**
- * Renders a React component into the DOM in the supplied `container`.
- *
- * If the React component was previously rendered into `container`, this will
- * perform an update on it and only mutate the DOM as necessary to reflect the
- * latest React component.
- *
- * @param {ReactElement} nextElement Component element to render.
- * @param {DOMElement} container DOM element to render into.
- * @param {?function} callback function triggered on completion
- * @return {ReactComponent} Component instance rendered in `container`.
- */
- render: function(nextElement, container, callback) {
- ("production" !== "development" ? invariant(
- ReactElement.isValidElement(nextElement),
- 'renderComponent(): Invalid component element.%s',
- (
- typeof nextElement === 'string' ?
- ' Instead of passing an element string, make sure to instantiate ' +
- 'it by passing it to React.createElement.' :
- ReactLegacyElement.isValidFactory(nextElement) ?
- ' Instead of passing a component class, make sure to instantiate ' +
- 'it by passing it to React.createElement.' :
- // Check if it quacks like a element
- typeof nextElement.props !== "undefined" ?
- ' This may be caused by unintentionally loading two independent ' +
- 'copies of React.' :
- ''
- )
- ) : invariant(ReactElement.isValidElement(nextElement)));
-
- var prevComponent = instancesByReactRootID[getReactRootID(container)];
-
- if (prevComponent) {
- var prevElement = prevComponent._currentElement;
- if (shouldUpdateReactComponent(prevElement, nextElement)) {
- return ReactMount._updateRootComponent(
- prevComponent,
- nextElement,
- container,
- callback
- );
- } else {
- ReactMount.unmountComponentAtNode(container);
- }
- }
-
- var reactRootElement = getReactRootElementInContainer(container);
- var containerHasReactMarkup =
- reactRootElement && ReactMount.isRenderedByReact(reactRootElement);
-
- var shouldReuseMarkup = containerHasReactMarkup && !prevComponent;
-
- var component = ReactMount._renderNewRootComponent(
- nextElement,
- container,
- shouldReuseMarkup
- );
- callback && callback.call(component);
- return component;
- },
-
- /**
- * Constructs a component instance of `constructor` with `initialProps` and
- * renders it into the supplied `container`.
- *
- * @param {function} constructor React component constructor.
- * @param {?object} props Initial props of the component instance.
- * @param {DOMElement} container DOM element to render into.
- * @return {ReactComponent} Component instance rendered in `container`.
- */
- constructAndRenderComponent: function(constructor, props, container) {
- var element = createElement(constructor, props);
- return ReactMount.render(element, container);
- },
-
- /**
- * Constructs a component instance of `constructor` with `initialProps` and
- * renders it into a container node identified by supplied `id`.
- *
- * @param {function} componentConstructor React component constructor
- * @param {?object} props Initial props of the component instance.
- * @param {string} id ID of the DOM element to render into.
- * @return {ReactComponent} Component instance rendered in the container node.
- */
- constructAndRenderComponentByID: function(constructor, props, id) {
- var domNode = document.getElementById(id);
- ("production" !== "development" ? invariant(
- domNode,
- 'Tried to get element with id of "%s" but it is not present on the page.',
- id
- ) : invariant(domNode));
- return ReactMount.constructAndRenderComponent(constructor, props, domNode);
- },
-
- /**
- * Registers a container node into which React components will be rendered.
- * This also creates the "reactRoot" ID that will be assigned to the element
- * rendered within.
- *
- * @param {DOMElement} container DOM element to register as a container.
- * @return {string} The "reactRoot" ID of elements rendered within.
- */
- registerContainer: function(container) {
- var reactRootID = getReactRootID(container);
- if (reactRootID) {
- // If one exists, make sure it is a valid "reactRoot" ID.
- reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(reactRootID);
- }
- if (!reactRootID) {
- // No valid "reactRoot" ID found, create one.
- reactRootID = ReactInstanceHandles.createReactRootID();
- }
- containersByReactRootID[reactRootID] = container;
- return reactRootID;
- },
-
- /**
- * Unmounts and destroys the React component rendered in the `container`.
- *
- * @param {DOMElement} container DOM element containing a React component.
- * @return {boolean} True if a component was found in and unmounted from
- * `container`
- */
- unmountComponentAtNode: function(container) {
- // Various parts of our code (such as ReactCompositeComponent's
- // _renderValidatedComponent) assume that calls to render aren't nested;
- // verify that that's the case. (Strictly speaking, unmounting won't cause a
- // render but we still don't expect to be in a render call here.)
- ("production" !== "development" ? warning(
- ReactCurrentOwner.current == null,
- 'unmountComponentAtNode(): Render methods should be a pure function of ' +
- 'props and state; triggering nested component updates from render is ' +
- 'not allowed. If necessary, trigger nested updates in ' +
- 'componentDidUpdate.'
- ) : null);
-
- var reactRootID = getReactRootID(container);
- var component = instancesByReactRootID[reactRootID];
- if (!component) {
- return false;
- }
- ReactMount.unmountComponentFromNode(component, container);
- delete instancesByReactRootID[reactRootID];
- delete containersByReactRootID[reactRootID];
- if ("production" !== "development") {
- delete rootElementsByReactRootID[reactRootID];
- }
- return true;
- },
-
- /**
- * Unmounts a component and removes it from the DOM.
- *
- * @param {ReactComponent} instance React component instance.
- * @param {DOMElement} container DOM element to unmount from.
- * @final
- * @internal
- * @see {ReactMount.unmountComponentAtNode}
- */
- unmountComponentFromNode: function(instance, container) {
- instance.unmountComponent();
-
- if (container.nodeType === DOC_NODE_TYPE) {
- container = container.documentElement;
- }
-
- // http://jsperf.com/emptying-a-node
- while (container.lastChild) {
- container.removeChild(container.lastChild);
- }
- },
-
- /**
- * Finds the container DOM element that contains React component to which the
- * supplied DOM `id` belongs.
- *
- * @param {string} id The ID of an element rendered by a React component.
- * @return {?DOMElement} DOM element that contains the `id`.
- */
- findReactContainerForID: function(id) {
- var reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(id);
- var container = containersByReactRootID[reactRootID];
-
- if ("production" !== "development") {
- var rootElement = rootElementsByReactRootID[reactRootID];
- if (rootElement && rootElement.parentNode !== container) {
- ("production" !== "development" ? invariant(
- // Call internalGetID here because getID calls isValid which calls
- // findReactContainerForID (this function).
- internalGetID(rootElement) === reactRootID,
- 'ReactMount: Root element ID differed from reactRootID.'
- ) : invariant(// Call internalGetID here because getID calls isValid which calls
- // findReactContainerForID (this function).
- internalGetID(rootElement) === reactRootID));
-
- var containerChild = container.firstChild;
- if (containerChild &&
- reactRootID === internalGetID(containerChild)) {
- // If the container has a new child with the same ID as the old
- // root element, then rootElementsByReactRootID[reactRootID] is
- // just stale and needs to be updated. The case that deserves a
- // warning is when the container is empty.
- rootElementsByReactRootID[reactRootID] = containerChild;
- } else {
- console.warn(
- 'ReactMount: Root element has been removed from its original ' +
- 'container. New container:', rootElement.parentNode
- );
- }
- }
- }
-
- return container;
- },
-
- /**
- * Finds an element rendered by React with the supplied ID.
- *
- * @param {string} id ID of a DOM node in the React component.
- * @return {DOMElement} Root DOM node of the React component.
- */
- findReactNodeByID: function(id) {
- var reactRoot = ReactMount.findReactContainerForID(id);
- return ReactMount.findComponentRoot(reactRoot, id);
- },
-
- /**
- * True if the supplied `node` is rendered by React.
- *
- * @param {*} node DOM Element to check.
- * @return {boolean} True if the DOM Element appears to be rendered by React.
- * @internal
- */
- isRenderedByReact: function(node) {
- if (node.nodeType !== 1) {
- // Not a DOMElement, therefore not a React component
- return false;
- }
- var id = ReactMount.getID(node);
- return id ? id.charAt(0) === SEPARATOR : false;
- },
-
- /**
- * Traverses up the ancestors of the supplied node to find a node that is a
- * DOM representation of a React component.
- *
- * @param {*} node
- * @return {?DOMEventTarget}
- * @internal
- */
- getFirstReactDOM: function(node) {
- var current = node;
- while (current && current.parentNode !== current) {
- if (ReactMount.isRenderedByReact(current)) {
- return current;
- }
- current = current.parentNode;
- }
- return null;
- },
-
- /**
- * Finds a node with the supplied `targetID` inside of the supplied
- * `ancestorNode`. Exploits the ID naming scheme to perform the search
- * quickly.
- *
- * @param {DOMEventTarget} ancestorNode Search from this root.
- * @pararm {string} targetID ID of the DOM representation of the component.
- * @return {DOMEventTarget} DOM node with the supplied `targetID`.
- * @internal
- */
- findComponentRoot: function(ancestorNode, targetID) {
- var firstChildren = findComponentRootReusableArray;
- var childIndex = 0;
-
- var deepestAncestor = findDeepestCachedAncestor(targetID) || ancestorNode;
-
- firstChildren[0] = deepestAncestor.firstChild;
- firstChildren.length = 1;
-
- while (childIndex < firstChildren.length) {
- var child = firstChildren[childIndex++];
- var targetChild;
-
- while (child) {
- var childID = ReactMount.getID(child);
- if (childID) {
- // Even if we find the node we're looking for, we finish looping
- // through its siblings to ensure they're cached so that we don't have
- // to revisit this node again. Otherwise, we make n^2 calls to getID
- // when visiting the many children of a single node in order.
-
- if (targetID === childID) {
- targetChild = child;
- } else if (ReactInstanceHandles.isAncestorIDOf(childID, targetID)) {
- // If we find a child whose ID is an ancestor of the given ID,
- // then we can be sure that we only want to search the subtree
- // rooted at this child, so we can throw out the rest of the
- // search state.
- firstChildren.length = childIndex = 0;
- firstChildren.push(child.firstChild);
- }
-
- } else {
- // If this child had no ID, then there's a chance that it was
- // injected automatically by the browser, as when a `<table>`
- // element sprouts an extra `<tbody>` child as a side effect of
- // `.innerHTML` parsing. Optimistically continue down this
- // branch, but not before examining the other siblings.
- firstChildren.push(child.firstChild);
- }
-
- child = child.nextSibling;
- }
-
- if (targetChild) {
- // Emptying firstChildren/findComponentRootReusableArray is
- // not necessary for correctness, but it helps the GC reclaim
- // any nodes that were left at the end of the search.
- firstChildren.length = 0;
-
- return targetChild;
- }
- }
-
- firstChildren.length = 0;
-
- ("production" !== "development" ? invariant(
- false,
- 'findComponentRoot(..., %s): Unable to find element. This probably ' +
- 'means the DOM was unexpectedly mutated (e.g., by the browser), ' +
- 'usually due to forgetting a <tbody> when using tables, nesting tags ' +
- 'like <form>, <p>, or <a>, or using non-SVG elements in an <svg> ' +
- 'parent. ' +
- 'Try inspecting the child nodes of the element with React ID `%s`.',
- targetID,
- ReactMount.getID(ancestorNode)
- ) : invariant(false));
- },
-
-
- /**
- * React ID utilities.
- */
-
- getReactRootID: getReactRootID,
-
- getID: getID,
-
- setID: setID,
-
- getNode: getNode,
-
- purgeID: purgeID
-};
-
-// Deprecations (remove for 0.13)
-ReactMount.renderComponent = deprecated(
- 'ReactMount',
- 'renderComponent',
- 'render',
- this,
- ReactMount.render
-);
-
-module.exports = ReactMount;
-
-},{"./DOMProperty":12,"./ReactBrowserEventEmitter":33,"./ReactCurrentOwner":42,"./ReactElement":58,"./ReactInstanceHandles":66,"./ReactLegacyElement":67,"./ReactPerf":75,"./containsNode":114,"./deprecated":120,"./getReactRootElementInContainer":134,"./instantiateReactComponent":139,"./invariant":140,"./shouldUpdateReactComponent":156,"./warning":160}],71:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactMultiChild
- * @typechecks static-only
- */
-
-"use strict";
-
-var ReactComponent = _dereq_("./ReactComponent");
-var ReactMultiChildUpdateTypes = _dereq_("./ReactMultiChildUpdateTypes");
-
-var flattenChildren = _dereq_("./flattenChildren");
-var instantiateReactComponent = _dereq_("./instantiateReactComponent");
-var shouldUpdateReactComponent = _dereq_("./shouldUpdateReactComponent");
-
-/**
- * Updating children of a component may trigger recursive updates. The depth is
- * used to batch recursive updates to render markup more efficiently.
- *
- * @type {number}
- * @private
- */
-var updateDepth = 0;
-
-/**
- * Queue of update configuration objects.
- *
- * Each object has a `type` property that is in `ReactMultiChildUpdateTypes`.
- *
- * @type {array<object>}
- * @private
- */
-var updateQueue = [];
-
-/**
- * Queue of markup to be rendered.
- *
- * @type {array<string>}
- * @private
- */
-var markupQueue = [];
-
-/**
- * Enqueues markup to be rendered and inserted at a supplied index.
- *
- * @param {string} parentID ID of the parent component.
- * @param {string} markup Markup that renders into an element.
- * @param {number} toIndex Destination index.
- * @private
- */
-function enqueueMarkup(parentID, markup, toIndex) {
- // NOTE: Null values reduce hidden classes.
- updateQueue.push({
- parentID: parentID,
- parentNode: null,
- type: ReactMultiChildUpdateTypes.INSERT_MARKUP,
- markupIndex: markupQueue.push(markup) - 1,
- textContent: null,
- fromIndex: null,
- toIndex: toIndex
- });
-}
-
-/**
- * Enqueues moving an existing element to another index.
- *
- * @param {string} parentID ID of the parent component.
- * @param {number} fromIndex Source index of the existing element.
- * @param {number} toIndex Destination index of the element.
- * @private
- */
-function enqueueMove(parentID, fromIndex, toIndex) {
- // NOTE: Null values reduce hidden classes.
- updateQueue.push({
- parentID: parentID,
- parentNode: null,
- type: ReactMultiChildUpdateTypes.MOVE_EXISTING,
- markupIndex: null,
- textContent: null,
- fromIndex: fromIndex,
- toIndex: toIndex
- });
-}
-
-/**
- * Enqueues removing an element at an index.
- *
- * @param {string} parentID ID of the parent component.
- * @param {number} fromIndex Index of the element to remove.
- * @private
- */
-function enqueueRemove(parentID, fromIndex) {
- // NOTE: Null values reduce hidden classes.
- updateQueue.push({
- parentID: parentID,
- parentNode: null,
- type: ReactMultiChildUpdateTypes.REMOVE_NODE,
- markupIndex: null,
- textContent: null,
- fromIndex: fromIndex,
- toIndex: null
- });
-}
-
-/**
- * Enqueues setting the text content.
- *
- * @param {string} parentID ID of the parent component.
- * @param {string} textContent Text content to set.
- * @private
- */
-function enqueueTextContent(parentID, textContent) {
- // NOTE: Null values reduce hidden classes.
- updateQueue.push({
- parentID: parentID,
- parentNode: null,
- type: ReactMultiChildUpdateTypes.TEXT_CONTENT,
- markupIndex: null,
- textContent: textContent,
- fromIndex: null,
- toIndex: null
- });
-}
-
-/**
- * Processes any enqueued updates.
- *
- * @private
- */
-function processQueue() {
- if (updateQueue.length) {
- ReactComponent.BackendIDOperations.dangerouslyProcessChildrenUpdates(
- updateQueue,
- markupQueue
- );
- clearQueue();
- }
-}
-
-/**
- * Clears any enqueued updates.
- *
- * @private
- */
-function clearQueue() {
- updateQueue.length = 0;
- markupQueue.length = 0;
-}
-
-/**
- * ReactMultiChild are capable of reconciling multiple children.
- *
- * @class ReactMultiChild
- * @internal
- */
-var ReactMultiChild = {
-
- /**
- * Provides common functionality for components that must reconcile multiple
- * children. This is used by `ReactDOMComponent` to mount, update, and
- * unmount child components.
- *
- * @lends {ReactMultiChild.prototype}
- */
- Mixin: {
-
- /**
- * Generates a "mount image" for each of the supplied children. In the case
- * of `ReactDOMComponent`, a mount image is a string of markup.
- *
- * @param {?object} nestedChildren Nested child maps.
- * @return {array} An array of mounted representations.
- * @internal
- */
- mountChildren: function(nestedChildren, transaction) {
- var children = flattenChildren(nestedChildren);
- var mountImages = [];
- var index = 0;
- this._renderedChildren = children;
- for (var name in children) {
- var child = children[name];
- if (children.hasOwnProperty(name)) {
- // The rendered children must be turned into instances as they're
- // mounted.
- var childInstance = instantiateReactComponent(child, null);
- children[name] = childInstance;
- // Inlined for performance, see `ReactInstanceHandles.createReactID`.
- var rootID = this._rootNodeID + name;
- var mountImage = childInstance.mountComponent(
- rootID,
- transaction,
- this._mountDepth + 1
- );
- childInstance._mountIndex = index;
- mountImages.push(mountImage);
- index++;
- }
- }
- return mountImages;
- },
-
- /**
- * Replaces any rendered children with a text content string.
- *
- * @param {string} nextContent String of content.
- * @internal
- */
- updateTextContent: function(nextContent) {
- updateDepth++;
- var errorThrown = true;
- try {
- var prevChildren = this._renderedChildren;
- // Remove any rendered children.
- for (var name in prevChildren) {
- if (prevChildren.hasOwnProperty(name)) {
- this._unmountChildByName(prevChildren[name], name);
- }
- }
- // Set new text content.
- this.setTextContent(nextContent);
- errorThrown = false;
- } finally {
- updateDepth--;
- if (!updateDepth) {
- errorThrown ? clearQueue() : processQueue();
- }
- }
- },
-
- /**
- * Updates the rendered children with new children.
- *
- * @param {?object} nextNestedChildren Nested child maps.
- * @param {ReactReconcileTransaction} transaction
- * @internal
- */
- updateChildren: function(nextNestedChildren, transaction) {
- updateDepth++;
- var errorThrown = true;
- try {
- this._updateChildren(nextNestedChildren, transaction);
- errorThrown = false;
- } finally {
- updateDepth--;
- if (!updateDepth) {
- errorThrown ? clearQueue() : processQueue();
- }
- }
- },
-
- /**
- * Improve performance by isolating this hot code path from the try/catch
- * block in `updateChildren`.
- *
- * @param {?object} nextNestedChildren Nested child maps.
- * @param {ReactReconcileTransaction} transaction
- * @final
- * @protected
- */
- _updateChildren: function(nextNestedChildren, transaction) {
- var nextChildren = flattenChildren(nextNestedChildren);
- var prevChildren = this._renderedChildren;
- if (!nextChildren && !prevChildren) {
- return;
- }
- var name;
- // `nextIndex` will increment for each child in `nextChildren`, but
- // `lastIndex` will be the last index visited in `prevChildren`.
- var lastIndex = 0;
- var nextIndex = 0;
- for (name in nextChildren) {
- if (!nextChildren.hasOwnProperty(name)) {
- continue;
- }
- var prevChild = prevChildren && prevChildren[name];
- var prevElement = prevChild && prevChild._currentElement;
- var nextElement = nextChildren[name];
- if (shouldUpdateReactComponent(prevElement, nextElement)) {
- this.moveChild(prevChild, nextIndex, lastIndex);
- lastIndex = Math.max(prevChild._mountIndex, lastIndex);
- prevChild.receiveComponent(nextElement, transaction);
- prevChild._mountIndex = nextIndex;
- } else {
- if (prevChild) {
- // Update `lastIndex` before `_mountIndex` gets unset by unmounting.
- lastIndex = Math.max(prevChild._mountIndex, lastIndex);
- this._unmountChildByName(prevChild, name);
- }
- // The child must be instantiated before it's mounted.
- var nextChildInstance = instantiateReactComponent(
- nextElement,
- null
- );
- this._mountChildByNameAtIndex(
- nextChildInstance, name, nextIndex, transaction
- );
- }
- nextIndex++;
- }
- // Remove children that are no longer present.
- for (name in prevChildren) {
- if (prevChildren.hasOwnProperty(name) &&
- !(nextChildren && nextChildren[name])) {
- this._unmountChildByName(prevChildren[name], name);
- }
- }
- },
-
- /**
- * Unmounts all rendered children. This should be used to clean up children
- * when this component is unmounted.
- *
- * @internal
- */
- unmountChildren: function() {
- var renderedChildren = this._renderedChildren;
- for (var name in renderedChildren) {
- var renderedChild = renderedChildren[name];
- // TODO: When is this not true?
- if (renderedChild.unmountComponent) {
- renderedChild.unmountComponent();
- }
- }
- this._renderedChildren = null;
- },
-
- /**
- * Moves a child component to the supplied index.
- *
- * @param {ReactComponent} child Component to move.
- * @param {number} toIndex Destination index of the element.
- * @param {number} lastIndex Last index visited of the siblings of `child`.
- * @protected
- */
- moveChild: function(child, toIndex, lastIndex) {
- // If the index of `child` is less than `lastIndex`, then it needs to
- // be moved. Otherwise, we do not need to move it because a child will be
- // inserted or moved before `child`.
- if (child._mountIndex < lastIndex) {
- enqueueMove(this._rootNodeID, child._mountIndex, toIndex);
- }
- },
-
- /**
- * Creates a child component.
- *
- * @param {ReactComponent} child Component to create.
- * @param {string} mountImage Markup to insert.
- * @protected
- */
- createChild: function(child, mountImage) {
- enqueueMarkup(this._rootNodeID, mountImage, child._mountIndex);
- },
-
- /**
- * Removes a child component.
- *
- * @param {ReactComponent} child Child to remove.
- * @protected
- */
- removeChild: function(child) {
- enqueueRemove(this._rootNodeID, child._mountIndex);
- },
-
- /**
- * Sets this text content string.
- *
- * @param {string} textContent Text content to set.
- * @protected
- */
- setTextContent: function(textContent) {
- enqueueTextContent(this._rootNodeID, textContent);
- },
-
- /**
- * Mounts a child with the supplied name.
- *
- * NOTE: This is part of `updateChildren` and is here for readability.
- *
- * @param {ReactComponent} child Component to mount.
- * @param {string} name Name of the child.
- * @param {number} index Index at which to insert the child.
- * @param {ReactReconcileTransaction} transaction
- * @private
- */
- _mountChildByNameAtIndex: function(child, name, index, transaction) {
- // Inlined for performance, see `ReactInstanceHandles.createReactID`.
- var rootID = this._rootNodeID + name;
- var mountImage = child.mountComponent(
- rootID,
- transaction,
- this._mountDepth + 1
- );
- child._mountIndex = index;
- this.createChild(child, mountImage);
- this._renderedChildren = this._renderedChildren || {};
- this._renderedChildren[name] = child;
- },
-
- /**
- * Unmounts a rendered child by name.
- *
- * NOTE: This is part of `updateChildren` and is here for readability.
- *
- * @param {ReactComponent} child Component to unmount.
- * @param {string} name Name of the child in `this._renderedChildren`.
- * @private
- */
- _unmountChildByName: function(child, name) {
- this.removeChild(child);
- child._mountIndex = null;
- child.unmountComponent();
- delete this._renderedChildren[name];
- }
-
- }
-
-};
-
-module.exports = ReactMultiChild;
-
-},{"./ReactComponent":37,"./ReactMultiChildUpdateTypes":72,"./flattenChildren":124,"./instantiateReactComponent":139,"./shouldUpdateReactComponent":156}],72:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactMultiChildUpdateTypes
- */
-
-"use strict";
-
-var keyMirror = _dereq_("./keyMirror");
-
-/**
- * When a component's children are updated, a series of update configuration
- * objects are created in order to batch and serialize the required changes.
- *
- * Enumerates all the possible types of update configurations.
- *
- * @internal
- */
-var ReactMultiChildUpdateTypes = keyMirror({
- INSERT_MARKUP: null,
- MOVE_EXISTING: null,
- REMOVE_NODE: null,
- TEXT_CONTENT: null
-});
-
-module.exports = ReactMultiChildUpdateTypes;
-
-},{"./keyMirror":146}],73:[function(_dereq_,module,exports){
-/**
- * Copyright 2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactNativeComponent
- */
-
-"use strict";
-
-var assign = _dereq_("./Object.assign");
-var invariant = _dereq_("./invariant");
-
-var genericComponentClass = null;
-// This registry keeps track of wrapper classes around native tags
-var tagToComponentClass = {};
-
-var ReactNativeComponentInjection = {
- // This accepts a class that receives the tag string. This is a catch all
- // that can render any kind of tag.
- injectGenericComponentClass: function(componentClass) {
- genericComponentClass = componentClass;
- },
- // This accepts a keyed object with classes as values. Each key represents a
- // tag. That particular tag will use this class instead of the generic one.
- injectComponentClasses: function(componentClasses) {
- assign(tagToComponentClass, componentClasses);
- }
-};
-
-/**
- * Create an internal class for a specific tag.
- *
- * @param {string} tag The tag for which to create an internal instance.
- * @param {any} props The props passed to the instance constructor.
- * @return {ReactComponent} component The injected empty component.
- */
-function createInstanceForTag(tag, props, parentType) {
- var componentClass = tagToComponentClass[tag];
- if (componentClass == null) {
- ("production" !== "development" ? invariant(
- genericComponentClass,
- 'There is no registered component for the tag %s',
- tag
- ) : invariant(genericComponentClass));
- return new genericComponentClass(tag, props);
- }
- if (parentType === tag) {
- // Avoid recursion
- ("production" !== "development" ? invariant(
- genericComponentClass,
- 'There is no registered component for the tag %s',
- tag
- ) : invariant(genericComponentClass));
- return new genericComponentClass(tag, props);
- }
- // Unwrap legacy factories
- return new componentClass.type(props);
-}
-
-var ReactNativeComponent = {
- createInstanceForTag: createInstanceForTag,
- injection: ReactNativeComponentInjection
-};
-
-module.exports = ReactNativeComponent;
-
-},{"./Object.assign":29,"./invariant":140}],74:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactOwner
- */
-
-"use strict";
-
-var emptyObject = _dereq_("./emptyObject");
-var invariant = _dereq_("./invariant");
-
-/**
- * ReactOwners are capable of storing references to owned components.
- *
- * All components are capable of //being// referenced by owner components, but
- * only ReactOwner components are capable of //referencing// owned components.
- * The named reference is known as a "ref".
- *
- * Refs are available when mounted and updated during reconciliation.
- *
- * var MyComponent = React.createClass({
- * render: function() {
- * return (
- * <div onClick={this.handleClick}>
- * <CustomComponent ref="custom" />
- * </div>
- * );
- * },
- * handleClick: function() {
- * this.refs.custom.handleClick();
- * },
- * componentDidMount: function() {
- * this.refs.custom.initialize();
- * }
- * });
- *
- * Refs should rarely be used. When refs are used, they should only be done to
- * control data that is not handled by React's data flow.
- *
- * @class ReactOwner
- */
-var ReactOwner = {
-
- /**
- * @param {?object} object
- * @return {boolean} True if `object` is a valid owner.
- * @final
- */
- isValidOwner: function(object) {
- return !!(
- object &&
- typeof object.attachRef === 'function' &&
- typeof object.detachRef === 'function'
- );
- },
-
- /**
- * Adds a component by ref to an owner component.
- *
- * @param {ReactComponent} component Component to reference.
- * @param {string} ref Name by which to refer to the component.
- * @param {ReactOwner} owner Component on which to record the ref.
- * @final
- * @internal
- */
- addComponentAsRefTo: function(component, ref, owner) {
- ("production" !== "development" ? invariant(
- ReactOwner.isValidOwner(owner),
- 'addComponentAsRefTo(...): Only a ReactOwner can have refs. This ' +
- 'usually means that you\'re trying to add a ref to a component that ' +
- 'doesn\'t have an owner (that is, was not created inside of another ' +
- 'component\'s `render` method). Try rendering this component inside of ' +
- 'a new top-level component which will hold the ref.'
- ) : invariant(ReactOwner.isValidOwner(owner)));
- owner.attachRef(ref, component);
- },
-
- /**
- * Removes a component by ref from an owner component.
- *
- * @param {ReactComponent} component Component to dereference.
- * @param {string} ref Name of the ref to remove.
- * @param {ReactOwner} owner Component on which the ref is recorded.
- * @final
- * @internal
- */
- removeComponentAsRefFrom: function(component, ref, owner) {
- ("production" !== "development" ? invariant(
- ReactOwner.isValidOwner(owner),
- 'removeComponentAsRefFrom(...): Only a ReactOwner can have refs. This ' +
- 'usually means that you\'re trying to remove a ref to a component that ' +
- 'doesn\'t have an owner (that is, was not created inside of another ' +
- 'component\'s `render` method). Try rendering this component inside of ' +
- 'a new top-level component which will hold the ref.'
- ) : invariant(ReactOwner.isValidOwner(owner)));
- // Check that `component` is still the current ref because we do not want to
- // detach the ref if another component stole it.
- if (owner.refs[ref] === component) {
- owner.detachRef(ref);
- }
- },
-
- /**
- * A ReactComponent must mix this in to have refs.
- *
- * @lends {ReactOwner.prototype}
- */
- Mixin: {
-
- construct: function() {
- this.refs = emptyObject;
- },
-
- /**
- * Lazily allocates the refs object and stores `component` as `ref`.
- *
- * @param {string} ref Reference name.
- * @param {component} component Component to store as `ref`.
- * @final
- * @private
- */
- attachRef: function(ref, component) {
- ("production" !== "development" ? invariant(
- component.isOwnedBy(this),
- 'attachRef(%s, ...): Only a component\'s owner can store a ref to it.',
- ref
- ) : invariant(component.isOwnedBy(this)));
- var refs = this.refs === emptyObject ? (this.refs = {}) : this.refs;
- refs[ref] = component;
- },
-
- /**
- * Detaches a reference name.
- *
- * @param {string} ref Name to dereference.
- * @final
- * @private
- */
- detachRef: function(ref) {
- delete this.refs[ref];
- }
-
- }
-
-};
-
-module.exports = ReactOwner;
-
-},{"./emptyObject":122,"./invariant":140}],75:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactPerf
- * @typechecks static-only
- */
-
-"use strict";
-
-/**
- * ReactPerf is a general AOP system designed to measure performance. This
- * module only has the hooks: see ReactDefaultPerf for the analysis tool.
- */
-var ReactPerf = {
- /**
- * Boolean to enable/disable measurement. Set to false by default to prevent
- * accidental logging and perf loss.
- */
- enableMeasure: false,
-
- /**
- * Holds onto the measure function in use. By default, don't measure
- * anything, but we'll override this if we inject a measure function.
- */
- storedMeasure: _noMeasure,
-
- /**
- * Use this to wrap methods you want to measure. Zero overhead in production.
- *
- * @param {string} objName
- * @param {string} fnName
- * @param {function} func
- * @return {function}
- */
- measure: function(objName, fnName, func) {
- if ("production" !== "development") {
- var measuredFunc = null;
- var wrapper = function() {
- if (ReactPerf.enableMeasure) {
- if (!measuredFunc) {
- measuredFunc = ReactPerf.storedMeasure(objName, fnName, func);
- }
- return measuredFunc.apply(this, arguments);
- }
- return func.apply(this, arguments);
- };
- wrapper.displayName = objName + '_' + fnName;
- return wrapper;
- }
- return func;
- },
-
- injection: {
- /**
- * @param {function} measure
- */
- injectMeasure: function(measure) {
- ReactPerf.storedMeasure = measure;
- }
- }
-};
-
-/**
- * Simply passes through the measured function, without measuring it.
- *
- * @param {string} objName
- * @param {string} fnName
- * @param {function} func
- * @return {function}
- */
-function _noMeasure(objName, fnName, func) {
- return func;
-}
-
-module.exports = ReactPerf;
-
-},{}],76:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactPropTransferer
- */
-
-"use strict";
-
-var assign = _dereq_("./Object.assign");
-var emptyFunction = _dereq_("./emptyFunction");
-var invariant = _dereq_("./invariant");
-var joinClasses = _dereq_("./joinClasses");
-var warning = _dereq_("./warning");
-
-var didWarn = false;
-
-/**
- * Creates a transfer strategy that will merge prop values using the supplied
- * `mergeStrategy`. If a prop was previously unset, this just sets it.
- *
- * @param {function} mergeStrategy
- * @return {function}
- */
-function createTransferStrategy(mergeStrategy) {
- return function(props, key, value) {
- if (!props.hasOwnProperty(key)) {
- props[key] = value;
- } else {
- props[key] = mergeStrategy(props[key], value);
- }
- };
-}
-
-var transferStrategyMerge = createTransferStrategy(function(a, b) {
- // `merge` overrides the first object's (`props[key]` above) keys using the
- // second object's (`value`) keys. An object's style's existing `propA` would
- // get overridden. Flip the order here.
- return assign({}, b, a);
-});
-
-/**
- * Transfer strategies dictate how props are transferred by `transferPropsTo`.
- * NOTE: if you add any more exceptions to this list you should be sure to
- * update `cloneWithProps()` accordingly.
- */
-var TransferStrategies = {
- /**
- * Never transfer `children`.
- */
- children: emptyFunction,
- /**
- * Transfer the `className` prop by merging them.
- */
- className: createTransferStrategy(joinClasses),
- /**
- * Transfer the `style` prop (which is an object) by merging them.
- */
- style: transferStrategyMerge
-};
-
-/**
- * Mutates the first argument by transferring the properties from the second
- * argument.
- *
- * @param {object} props
- * @param {object} newProps
- * @return {object}
- */
-function transferInto(props, newProps) {
- for (var thisKey in newProps) {
- if (!newProps.hasOwnProperty(thisKey)) {
- continue;
- }
-
- var transferStrategy = TransferStrategies[thisKey];
-
- if (transferStrategy && TransferStrategies.hasOwnProperty(thisKey)) {
- transferStrategy(props, thisKey, newProps[thisKey]);
- } else if (!props.hasOwnProperty(thisKey)) {
- props[thisKey] = newProps[thisKey];
- }
- }
- return props;
-}
-
-/**
- * ReactPropTransferer are capable of transferring props to another component
- * using a `transferPropsTo` method.
- *
- * @class ReactPropTransferer
- */
-var ReactPropTransferer = {
-
- TransferStrategies: TransferStrategies,
-
- /**
- * Merge two props objects using TransferStrategies.
- *
- * @param {object} oldProps original props (they take precedence)
- * @param {object} newProps new props to merge in
- * @return {object} a new object containing both sets of props merged.
- */
- mergeProps: function(oldProps, newProps) {
- return transferInto(assign({}, oldProps), newProps);
- },
-
- /**
- * @lends {ReactPropTransferer.prototype}
- */
- Mixin: {
-
- /**
- * Transfer props from this component to a target component.
- *
- * Props that do not have an explicit transfer strategy will be transferred
- * only if the target component does not already have the prop set.
- *
- * This is usually used to pass down props to a returned root component.
- *
- * @param {ReactElement} element Component receiving the properties.
- * @return {ReactElement} The supplied `component`.
- * @final
- * @protected
- */
- transferPropsTo: function(element) {
- ("production" !== "development" ? invariant(
- element._owner === this,
- '%s: You can\'t call transferPropsTo() on a component that you ' +
- 'don\'t own, %s. This usually means you are calling ' +
- 'transferPropsTo() on a component passed in as props or children.',
- this.constructor.displayName,
- typeof element.type === 'string' ?
- element.type :
- element.type.displayName
- ) : invariant(element._owner === this));
-
- if ("production" !== "development") {
- if (!didWarn) {
- didWarn = true;
- ("production" !== "development" ? warning(
- false,
- 'transferPropsTo is deprecated. ' +
- 'See http://fb.me/react-transferpropsto for more information.'
- ) : null);
- }
- }
-
- // Because elements are immutable we have to merge into the existing
- // props object rather than clone it.
- transferInto(element.props, this.props);
-
- return element;
- }
-
- }
-};
-
-module.exports = ReactPropTransferer;
-
-},{"./Object.assign":29,"./emptyFunction":121,"./invariant":140,"./joinClasses":145,"./warning":160}],77:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactPropTypeLocationNames
- */
-
-"use strict";
-
-var ReactPropTypeLocationNames = {};
-
-if ("production" !== "development") {
- ReactPropTypeLocationNames = {
- prop: 'prop',
- context: 'context',
- childContext: 'child context'
- };
-}
-
-module.exports = ReactPropTypeLocationNames;
-
-},{}],78:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactPropTypeLocations
- */
-
-"use strict";
-
-var keyMirror = _dereq_("./keyMirror");
-
-var ReactPropTypeLocations = keyMirror({
- prop: null,
- context: null,
- childContext: null
-});
-
-module.exports = ReactPropTypeLocations;
-
-},{"./keyMirror":146}],79:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactPropTypes
- */
-
-"use strict";
-
-var ReactElement = _dereq_("./ReactElement");
-var ReactPropTypeLocationNames = _dereq_("./ReactPropTypeLocationNames");
-
-var deprecated = _dereq_("./deprecated");
-var emptyFunction = _dereq_("./emptyFunction");
-
-/**
- * Collection of methods that allow declaration and validation of props that are
- * supplied to React components. Example usage:
- *
- * var Props = require('ReactPropTypes');
- * var MyArticle = React.createClass({
- * propTypes: {
- * // An optional string prop named "description".
- * description: Props.string,
- *
- * // A required enum prop named "category".
- * category: Props.oneOf(['News','Photos']).isRequired,
- *
- * // A prop named "dialog" that requires an instance of Dialog.
- * dialog: Props.instanceOf(Dialog).isRequired
- * },
- * render: function() { ... }
- * });
- *
- * A more formal specification of how these methods are used:
- *
- * type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...)
- * decl := ReactPropTypes.{type}(.isRequired)?
- *
- * Each and every declaration produces a function with the same signature. This
- * allows the creation of custom validation functions. For example:
- *
- * var MyLink = React.createClass({
- * propTypes: {
- * // An optional string or URI prop named "href".
- * href: function(props, propName, componentName) {
- * var propValue = props[propName];
- * if (propValue != null && typeof propValue !== 'string' &&
- * !(propValue instanceof URI)) {
- * return new Error(
- * 'Expected a string or an URI for ' + propName + ' in ' +
- * componentName
- * );
- * }
- * }
- * },
- * render: function() {...}
- * });
- *
- * @internal
- */
-
-var ANONYMOUS = '<<anonymous>>';
-
-var elementTypeChecker = createElementTypeChecker();
-var nodeTypeChecker = createNodeChecker();
-
-var ReactPropTypes = {
- array: createPrimitiveTypeChecker('array'),
- bool: createPrimitiveTypeChecker('boolean'),
- func: createPrimitiveTypeChecker('function'),
- number: createPrimitiveTypeChecker('number'),
- object: createPrimitiveTypeChecker('object'),
- string: createPrimitiveTypeChecker('string'),
-
- any: createAnyTypeChecker(),
- arrayOf: createArrayOfTypeChecker,
- element: elementTypeChecker,
- instanceOf: createInstanceTypeChecker,
- node: nodeTypeChecker,
- objectOf: createObjectOfTypeChecker,
- oneOf: createEnumTypeChecker,
- oneOfType: createUnionTypeChecker,
- shape: createShapeTypeChecker,
-
- component: deprecated(
- 'React.PropTypes',
- 'component',
- 'element',
- this,
- elementTypeChecker
- ),
- renderable: deprecated(
- 'React.PropTypes',
- 'renderable',
- 'node',
- this,
- nodeTypeChecker
- )
-};
-
-function createChainableTypeChecker(validate) {
- function checkType(isRequired, props, propName, componentName, location) {
- componentName = componentName || ANONYMOUS;
- if (props[propName] == null) {
- var locationName = ReactPropTypeLocationNames[location];
- if (isRequired) {
- return new Error(
- ("Required " + locationName + " `" + propName + "` was not specified in ")+
- ("`" + componentName + "`.")
- );
- }
- } else {
- return validate(props, propName, componentName, location);
- }
- }
-
- var chainedCheckType = checkType.bind(null, false);
- chainedCheckType.isRequired = checkType.bind(null, true);
-
- return chainedCheckType;
-}
-
-function createPrimitiveTypeChecker(expectedType) {
- function validate(props, propName, componentName, location) {
- var propValue = props[propName];
- var propType = getPropType(propValue);
- if (propType !== expectedType) {
- var locationName = ReactPropTypeLocationNames[location];
- // `propValue` being instance of, say, date/regexp, pass the 'object'
- // check, but we can offer a more precise error message here rather than
- // 'of type `object`'.
- var preciseType = getPreciseType(propValue);
-
- return new Error(
- ("Invalid " + locationName + " `" + propName + "` of type `" + preciseType + "` ") +
- ("supplied to `" + componentName + "`, expected `" + expectedType + "`.")
- );
- }
- }
- return createChainableTypeChecker(validate);
-}
-
-function createAnyTypeChecker() {
- return createChainableTypeChecker(emptyFunction.thatReturns());
-}
-
-function createArrayOfTypeChecker(typeChecker) {
- function validate(props, propName, componentName, location) {
- var propValue = props[propName];
- if (!Array.isArray(propValue)) {
- var locationName = ReactPropTypeLocationNames[location];
- var propType = getPropType(propValue);
- return new Error(
- ("Invalid " + locationName + " `" + propName + "` of type ") +
- ("`" + propType + "` supplied to `" + componentName + "`, expected an array.")
- );
- }
- for (var i = 0; i < propValue.length; i++) {
- var error = typeChecker(propValue, i, componentName, location);
- if (error instanceof Error) {
- return error;
- }
- }
- }
- return createChainableTypeChecker(validate);
-}
-
-function createElementTypeChecker() {
- function validate(props, propName, componentName, location) {
- if (!ReactElement.isValidElement(props[propName])) {
- var locationName = ReactPropTypeLocationNames[location];
- return new Error(
- ("Invalid " + locationName + " `" + propName + "` supplied to ") +
- ("`" + componentName + "`, expected a ReactElement.")
- );
- }
- }
- return createChainableTypeChecker(validate);
-}
-
-function createInstanceTypeChecker(expectedClass) {
- function validate(props, propName, componentName, location) {
- if (!(props[propName] instanceof expectedClass)) {
- var locationName = ReactPropTypeLocationNames[location];
- var expectedClassName = expectedClass.name || ANONYMOUS;
- return new Error(
- ("Invalid " + locationName + " `" + propName + "` supplied to ") +
- ("`" + componentName + "`, expected instance of `" + expectedClassName + "`.")
- );
- }
- }
- return createChainableTypeChecker(validate);
-}
-
-function createEnumTypeChecker(expectedValues) {
- function validate(props, propName, componentName, location) {
- var propValue = props[propName];
- for (var i = 0; i < expectedValues.length; i++) {
- if (propValue === expectedValues[i]) {
- return;
- }
- }
-
- var locationName = ReactPropTypeLocationNames[location];
- var valuesString = JSON.stringify(expectedValues);
- return new Error(
- ("Invalid " + locationName + " `" + propName + "` of value `" + propValue + "` ") +
- ("supplied to `" + componentName + "`, expected one of " + valuesString + ".")
- );
- }
- return createChainableTypeChecker(validate);
-}
-
-function createObjectOfTypeChecker(typeChecker) {
- function validate(props, propName, componentName, location) {
- var propValue = props[propName];
- var propType = getPropType(propValue);
- if (propType !== 'object') {
- var locationName = ReactPropTypeLocationNames[location];
- return new Error(
- ("Invalid " + locationName + " `" + propName + "` of type ") +
- ("`" + propType + "` supplied to `" + componentName + "`, expected an object.")
- );
- }
- for (var key in propValue) {
- if (propValue.hasOwnProperty(key)) {
- var error = typeChecker(propValue, key, componentName, location);
- if (error instanceof Error) {
- return error;
- }
- }
- }
- }
- return createChainableTypeChecker(validate);
-}
-
-function createUnionTypeChecker(arrayOfTypeCheckers) {
- function validate(props, propName, componentName, location) {
- for (var i = 0; i < arrayOfTypeCheckers.length; i++) {
- var checker = arrayOfTypeCheckers[i];
- if (checker(props, propName, componentName, location) == null) {
- return;
- }
- }
-
- var locationName = ReactPropTypeLocationNames[location];
- return new Error(
- ("Invalid " + locationName + " `" + propName + "` supplied to ") +
- ("`" + componentName + "`.")
- );
- }
- return createChainableTypeChecker(validate);
-}
-
-function createNodeChecker() {
- function validate(props, propName, componentName, location) {
- if (!isNode(props[propName])) {
- var locationName = ReactPropTypeLocationNames[location];
- return new Error(
- ("Invalid " + locationName + " `" + propName + "` supplied to ") +
- ("`" + componentName + "`, expected a ReactNode.")
- );
- }
- }
- return createChainableTypeChecker(validate);
-}
-
-function createShapeTypeChecker(shapeTypes) {
- function validate(props, propName, componentName, location) {
- var propValue = props[propName];
- var propType = getPropType(propValue);
- if (propType !== 'object') {
- var locationName = ReactPropTypeLocationNames[location];
- return new Error(
- ("Invalid " + locationName + " `" + propName + "` of type `" + propType + "` ") +
- ("supplied to `" + componentName + "`, expected `object`.")
- );
- }
- for (var key in shapeTypes) {
- var checker = shapeTypes[key];
- if (!checker) {
- continue;
- }
- var error = checker(propValue, key, componentName, location);
- if (error) {
- return error;
- }
- }
- }
- return createChainableTypeChecker(validate, 'expected `object`');
-}
-
-function isNode(propValue) {
- switch(typeof propValue) {
- case 'number':
- case 'string':
- return true;
- case 'boolean':
- return !propValue;
- case 'object':
- if (Array.isArray(propValue)) {
- return propValue.every(isNode);
- }
- if (ReactElement.isValidElement(propValue)) {
- return true;
- }
- for (var k in propValue) {
- if (!isNode(propValue[k])) {
- return false;
- }
- }
- return true;
- default:
- return false;
- }
-}
-
-// Equivalent of `typeof` but with special handling for array and regexp.
-function getPropType(propValue) {
- var propType = typeof propValue;
- if (Array.isArray(propValue)) {
- return 'array';
- }
- if (propValue instanceof RegExp) {
- // Old webkits (at least until Android 4.0) return 'function' rather than
- // 'object' for typeof a RegExp. We'll normalize this here so that /bla/
- // passes PropTypes.object.
- return 'object';
- }
- return propType;
-}
-
-// This handles more types than `getPropType`. Only used for error messages.
-// See `createPrimitiveTypeChecker`.
-function getPreciseType(propValue) {
- var propType = getPropType(propValue);
- if (propType === 'object') {
- if (propValue instanceof Date) {
- return 'date';
- } else if (propValue instanceof RegExp) {
- return 'regexp';
- }
- }
- return propType;
-}
-
-module.exports = ReactPropTypes;
-
-},{"./ReactElement":58,"./ReactPropTypeLocationNames":77,"./deprecated":120,"./emptyFunction":121}],80:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactPutListenerQueue
- */
-
-"use strict";
-
-var PooledClass = _dereq_("./PooledClass");
-var ReactBrowserEventEmitter = _dereq_("./ReactBrowserEventEmitter");
-
-var assign = _dereq_("./Object.assign");
-
-function ReactPutListenerQueue() {
- this.listenersToPut = [];
-}
-
-assign(ReactPutListenerQueue.prototype, {
- enqueuePutListener: function(rootNodeID, propKey, propValue) {
- this.listenersToPut.push({
- rootNodeID: rootNodeID,
- propKey: propKey,
- propValue: propValue
- });
- },
-
- putListeners: function() {
- for (var i = 0; i < this.listenersToPut.length; i++) {
- var listenerToPut = this.listenersToPut[i];
- ReactBrowserEventEmitter.putListener(
- listenerToPut.rootNodeID,
- listenerToPut.propKey,
- listenerToPut.propValue
- );
- }
- },
-
- reset: function() {
- this.listenersToPut.length = 0;
- },
-
- destructor: function() {
- this.reset();
- }
-});
-
-PooledClass.addPoolingTo(ReactPutListenerQueue);
-
-module.exports = ReactPutListenerQueue;
-
-},{"./Object.assign":29,"./PooledClass":30,"./ReactBrowserEventEmitter":33}],81:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactReconcileTransaction
- * @typechecks static-only
- */
-
-"use strict";
-
-var CallbackQueue = _dereq_("./CallbackQueue");
-var PooledClass = _dereq_("./PooledClass");
-var ReactBrowserEventEmitter = _dereq_("./ReactBrowserEventEmitter");
-var ReactInputSelection = _dereq_("./ReactInputSelection");
-var ReactPutListenerQueue = _dereq_("./ReactPutListenerQueue");
-var Transaction = _dereq_("./Transaction");
-
-var assign = _dereq_("./Object.assign");
-
-/**
- * Ensures that, when possible, the selection range (currently selected text
- * input) is not disturbed by performing the transaction.
- */
-var SELECTION_RESTORATION = {
- /**
- * @return {Selection} Selection information.
- */
- initialize: ReactInputSelection.getSelectionInformation,
- /**
- * @param {Selection} sel Selection information returned from `initialize`.
- */
- close: ReactInputSelection.restoreSelection
-};
-
-/**
- * Suppresses events (blur/focus) that could be inadvertently dispatched due to
- * high level DOM manipulations (like temporarily removing a text input from the
- * DOM).
- */
-var EVENT_SUPPRESSION = {
- /**
- * @return {boolean} The enabled status of `ReactBrowserEventEmitter` before
- * the reconciliation.
- */
- initialize: function() {
- var currentlyEnabled = ReactBrowserEventEmitter.isEnabled();
- ReactBrowserEventEmitter.setEnabled(false);
- return currentlyEnabled;
- },
-
- /**
- * @param {boolean} previouslyEnabled Enabled status of
- * `ReactBrowserEventEmitter` before the reconciliation occured. `close`
- * restores the previous value.
- */
- close: function(previouslyEnabled) {
- ReactBrowserEventEmitter.setEnabled(previouslyEnabled);
- }
-};
-
-/**
- * Provides a queue for collecting `componentDidMount` and
- * `componentDidUpdate` callbacks during the the transaction.
- */
-var ON_DOM_READY_QUEUEING = {
- /**
- * Initializes the internal `onDOMReady` queue.
- */
- initialize: function() {
- this.reactMountReady.reset();
- },
-
- /**
- * After DOM is flushed, invoke all registered `onDOMReady` callbacks.
- */
- close: function() {
- this.reactMountReady.notifyAll();
- }
-};
-
-var PUT_LISTENER_QUEUEING = {
- initialize: function() {
- this.putListenerQueue.reset();
- },
-
- close: function() {
- this.putListenerQueue.putListeners();
- }
-};
-
-/**
- * Executed within the scope of the `Transaction` instance. Consider these as
- * being member methods, but with an implied ordering while being isolated from
- * each other.
- */
-var TRANSACTION_WRAPPERS = [
- PUT_LISTENER_QUEUEING,
- SELECTION_RESTORATION,
- EVENT_SUPPRESSION,
- ON_DOM_READY_QUEUEING
-];
-
-/**
- * Currently:
- * - The order that these are listed in the transaction is critical:
- * - Suppresses events.
- * - Restores selection range.
- *
- * Future:
- * - Restore document/overflow scroll positions that were unintentionally
- * modified via DOM insertions above the top viewport boundary.
- * - Implement/integrate with customized constraint based layout system and keep
- * track of which dimensions must be remeasured.
- *
- * @class ReactReconcileTransaction
- */
-function ReactReconcileTransaction() {
- this.reinitializeTransaction();
- // Only server-side rendering really needs this option (see
- // `ReactServerRendering`), but server-side uses
- // `ReactServerRenderingTransaction` instead. This option is here so that it's
- // accessible and defaults to false when `ReactDOMComponent` and
- // `ReactTextComponent` checks it in `mountComponent`.`
- this.renderToStaticMarkup = false;
- this.reactMountReady = CallbackQueue.getPooled(null);
- this.putListenerQueue = ReactPutListenerQueue.getPooled();
-}
-
-var Mixin = {
- /**
- * @see Transaction
- * @abstract
- * @final
- * @return {array<object>} List of operation wrap proceedures.
- * TODO: convert to array<TransactionWrapper>
- */
- getTransactionWrappers: function() {
- return TRANSACTION_WRAPPERS;
- },
-
- /**
- * @return {object} The queue to collect `onDOMReady` callbacks with.
- */
- getReactMountReady: function() {
- return this.reactMountReady;
- },
-
- getPutListenerQueue: function() {
- return this.putListenerQueue;
- },
-
- /**
- * `PooledClass` looks for this, and will invoke this before allowing this
- * instance to be resused.
- */
- destructor: function() {
- CallbackQueue.release(this.reactMountReady);
- this.reactMountReady = null;
-
- ReactPutListenerQueue.release(this.putListenerQueue);
- this.putListenerQueue = null;
- }
-};
-
-
-assign(ReactReconcileTransaction.prototype, Transaction.Mixin, Mixin);
-
-PooledClass.addPoolingTo(ReactReconcileTransaction);
-
-module.exports = ReactReconcileTransaction;
-
-},{"./CallbackQueue":7,"./Object.assign":29,"./PooledClass":30,"./ReactBrowserEventEmitter":33,"./ReactInputSelection":65,"./ReactPutListenerQueue":80,"./Transaction":107}],82:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactRootIndex
- * @typechecks
- */
-
-"use strict";
-
-var ReactRootIndexInjection = {
- /**
- * @param {function} _createReactRootIndex
- */
- injectCreateReactRootIndex: function(_createReactRootIndex) {
- ReactRootIndex.createReactRootIndex = _createReactRootIndex;
- }
-};
-
-var ReactRootIndex = {
- createReactRootIndex: null,
- injection: ReactRootIndexInjection
-};
-
-module.exports = ReactRootIndex;
-
-},{}],83:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @typechecks static-only
- * @providesModule ReactServerRendering
- */
-"use strict";
-
-var ReactElement = _dereq_("./ReactElement");
-var ReactInstanceHandles = _dereq_("./ReactInstanceHandles");
-var ReactMarkupChecksum = _dereq_("./ReactMarkupChecksum");
-var ReactServerRenderingTransaction =
- _dereq_("./ReactServerRenderingTransaction");
-
-var instantiateReactComponent = _dereq_("./instantiateReactComponent");
-var invariant = _dereq_("./invariant");
-
-/**
- * @param {ReactElement} element
- * @return {string} the HTML markup
- */
-function renderToString(element) {
- ("production" !== "development" ? invariant(
- ReactElement.isValidElement(element),
- 'renderToString(): You must pass a valid ReactElement.'
- ) : invariant(ReactElement.isValidElement(element)));
-
- var transaction;
- try {
- var id = ReactInstanceHandles.createReactRootID();
- transaction = ReactServerRenderingTransaction.getPooled(false);
-
- return transaction.perform(function() {
- var componentInstance = instantiateReactComponent(element, null);
- var markup = componentInstance.mountComponent(id, transaction, 0);
- return ReactMarkupChecksum.addChecksumToMarkup(markup);
- }, null);
- } finally {
- ReactServerRenderingTransaction.release(transaction);
- }
-}
-
-/**
- * @param {ReactElement} element
- * @return {string} the HTML markup, without the extra React ID and checksum
- * (for generating static pages)
- */
-function renderToStaticMarkup(element) {
- ("production" !== "development" ? invariant(
- ReactElement.isValidElement(element),
- 'renderToStaticMarkup(): You must pass a valid ReactElement.'
- ) : invariant(ReactElement.isValidElement(element)));
-
- var transaction;
- try {
- var id = ReactInstanceHandles.createReactRootID();
- transaction = ReactServerRenderingTransaction.getPooled(true);
-
- return transaction.perform(function() {
- var componentInstance = instantiateReactComponent(element, null);
- return componentInstance.mountComponent(id, transaction, 0);
- }, null);
- } finally {
- ReactServerRenderingTransaction.release(transaction);
- }
-}
-
-module.exports = {
- renderToString: renderToString,
- renderToStaticMarkup: renderToStaticMarkup
-};
-
-},{"./ReactElement":58,"./ReactInstanceHandles":66,"./ReactMarkupChecksum":69,"./ReactServerRenderingTransaction":84,"./instantiateReactComponent":139,"./invariant":140}],84:[function(_dereq_,module,exports){
-/**
- * Copyright 2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactServerRenderingTransaction
- * @typechecks
- */
-
-"use strict";
-
-var PooledClass = _dereq_("./PooledClass");
-var CallbackQueue = _dereq_("./CallbackQueue");
-var ReactPutListenerQueue = _dereq_("./ReactPutListenerQueue");
-var Transaction = _dereq_("./Transaction");
-
-var assign = _dereq_("./Object.assign");
-var emptyFunction = _dereq_("./emptyFunction");
-
-/**
- * Provides a `CallbackQueue` queue for collecting `onDOMReady` callbacks
- * during the performing of the transaction.
- */
-var ON_DOM_READY_QUEUEING = {
- /**
- * Initializes the internal `onDOMReady` queue.
- */
- initialize: function() {
- this.reactMountReady.reset();
- },
-
- close: emptyFunction
-};
-
-var PUT_LISTENER_QUEUEING = {
- initialize: function() {
- this.putListenerQueue.reset();
- },
-
- close: emptyFunction
-};
-
-/**
- * Executed within the scope of the `Transaction` instance. Consider these as
- * being member methods, but with an implied ordering while being isolated from
- * each other.
- */
-var TRANSACTION_WRAPPERS = [
- PUT_LISTENER_QUEUEING,
- ON_DOM_READY_QUEUEING
-];
-
-/**
- * @class ReactServerRenderingTransaction
- * @param {boolean} renderToStaticMarkup
- */
-function ReactServerRenderingTransaction(renderToStaticMarkup) {
- this.reinitializeTransaction();
- this.renderToStaticMarkup = renderToStaticMarkup;
- this.reactMountReady = CallbackQueue.getPooled(null);
- this.putListenerQueue = ReactPutListenerQueue.getPooled();
-}
-
-var Mixin = {
- /**
- * @see Transaction
- * @abstract
- * @final
- * @return {array} Empty list of operation wrap proceedures.
- */
- getTransactionWrappers: function() {
- return TRANSACTION_WRAPPERS;
- },
-
- /**
- * @return {object} The queue to collect `onDOMReady` callbacks with.
- */
- getReactMountReady: function() {
- return this.reactMountReady;
- },
-
- getPutListenerQueue: function() {
- return this.putListenerQueue;
- },
-
- /**
- * `PooledClass` looks for this, and will invoke this before allowing this
- * instance to be resused.
- */
- destructor: function() {
- CallbackQueue.release(this.reactMountReady);
- this.reactMountReady = null;
-
- ReactPutListenerQueue.release(this.putListenerQueue);
- this.putListenerQueue = null;
- }
-};
-
-
-assign(
- ReactServerRenderingTransaction.prototype,
- Transaction.Mixin,
- Mixin
-);
-
-PooledClass.addPoolingTo(ReactServerRenderingTransaction);
-
-module.exports = ReactServerRenderingTransaction;
-
-},{"./CallbackQueue":7,"./Object.assign":29,"./PooledClass":30,"./ReactPutListenerQueue":80,"./Transaction":107,"./emptyFunction":121}],85:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactStateSetters
- */
-
-"use strict";
-
-var ReactStateSetters = {
- /**
- * Returns a function that calls the provided function, and uses the result
- * of that to set the component's state.
- *
- * @param {ReactCompositeComponent} component
- * @param {function} funcReturningState Returned callback uses this to
- * determine how to update state.
- * @return {function} callback that when invoked uses funcReturningState to
- * determined the object literal to setState.
- */
- createStateSetter: function(component, funcReturningState) {
- return function(a, b, c, d, e, f) {
- var partialState = funcReturningState.call(component, a, b, c, d, e, f);
- if (partialState) {
- component.setState(partialState);
- }
- };
- },
-
- /**
- * Returns a single-argument callback that can be used to update a single
- * key in the component's state.
- *
- * Note: this is memoized function, which makes it inexpensive to call.
- *
- * @param {ReactCompositeComponent} component
- * @param {string} key The key in the state that you should update.
- * @return {function} callback of 1 argument which calls setState() with
- * the provided keyName and callback argument.
- */
- createStateKeySetter: function(component, key) {
- // Memoize the setters.
- var cache = component.__keySetters || (component.__keySetters = {});
- return cache[key] || (cache[key] = createStateKeySetter(component, key));
- }
-};
-
-function createStateKeySetter(component, key) {
- // Partial state is allocated outside of the function closure so it can be
- // reused with every call, avoiding memory allocation when this function
- // is called.
- var partialState = {};
- return function stateKeySetter(value) {
- partialState[key] = value;
- component.setState(partialState);
- };
-}
-
-ReactStateSetters.Mixin = {
- /**
- * Returns a function that calls the provided function, and uses the result
- * of that to set the component's state.
- *
- * For example, these statements are equivalent:
- *
- * this.setState({x: 1});
- * this.createStateSetter(function(xValue) {
- * return {x: xValue};
- * })(1);
- *
- * @param {function} funcReturningState Returned callback uses this to
- * determine how to update state.
- * @return {function} callback that when invoked uses funcReturningState to
- * determined the object literal to setState.
- */
- createStateSetter: function(funcReturningState) {
- return ReactStateSetters.createStateSetter(this, funcReturningState);
- },
-
- /**
- * Returns a single-argument callback that can be used to update a single
- * key in the component's state.
- *
- * For example, these statements are equivalent:
- *
- * this.setState({x: 1});
- * this.createStateKeySetter('x')(1);
- *
- * Note: this is memoized function, which makes it inexpensive to call.
- *
- * @param {string} key The key in the state that you should update.
- * @return {function} callback of 1 argument which calls setState() with
- * the provided keyName and callback argument.
- */
- createStateKeySetter: function(key) {
- return ReactStateSetters.createStateKeySetter(this, key);
- }
-};
-
-module.exports = ReactStateSetters;
-
-},{}],86:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactTestUtils
- */
-
-"use strict";
-
-var EventConstants = _dereq_("./EventConstants");
-var EventPluginHub = _dereq_("./EventPluginHub");
-var EventPropagators = _dereq_("./EventPropagators");
-var React = _dereq_("./React");
-var ReactElement = _dereq_("./ReactElement");
-var ReactBrowserEventEmitter = _dereq_("./ReactBrowserEventEmitter");
-var ReactMount = _dereq_("./ReactMount");
-var ReactTextComponent = _dereq_("./ReactTextComponent");
-var ReactUpdates = _dereq_("./ReactUpdates");
-var SyntheticEvent = _dereq_("./SyntheticEvent");
-
-var assign = _dereq_("./Object.assign");
-
-var topLevelTypes = EventConstants.topLevelTypes;
-
-function Event(suffix) {}
-
-/**
- * @class ReactTestUtils
- */
-
-/**
- * Todo: Support the entire DOM.scry query syntax. For now, these simple
- * utilities will suffice for testing purposes.
- * @lends ReactTestUtils
- */
-var ReactTestUtils = {
- renderIntoDocument: function(instance) {
- var div = document.createElement('div');
- // None of our tests actually require attaching the container to the
- // DOM, and doing so creates a mess that we rely on test isolation to
- // clean up, so we're going to stop honoring the name of this method
- // (and probably rename it eventually) if no problems arise.
- // document.documentElement.appendChild(div);
- return React.render(instance, div);
- },
-
- isElement: function(element) {
- return ReactElement.isValidElement(element);
- },
-
- isElementOfType: function(inst, convenienceConstructor) {
- return (
- ReactElement.isValidElement(inst) &&
- inst.type === convenienceConstructor.type
- );
- },
-
- isDOMComponent: function(inst) {
- return !!(inst && inst.mountComponent && inst.tagName);
- },
-
- isDOMComponentElement: function(inst) {
- return !!(inst &&
- ReactElement.isValidElement(inst) &&
- !!inst.tagName);
- },
-
- isCompositeComponent: function(inst) {
- return typeof inst.render === 'function' &&
- typeof inst.setState === 'function';
- },
-
- isCompositeComponentWithType: function(inst, type) {
- return !!(ReactTestUtils.isCompositeComponent(inst) &&
- (inst.constructor === type.type));
- },
-
- isCompositeComponentElement: function(inst) {
- if (!ReactElement.isValidElement(inst)) {
- return false;
- }
- // We check the prototype of the type that will get mounted, not the
- // instance itself. This is a future proof way of duck typing.
- var prototype = inst.type.prototype;
- return (
- typeof prototype.render === 'function' &&
- typeof prototype.setState === 'function'
- );
- },
-
- isCompositeComponentElementWithType: function(inst, type) {
- return !!(ReactTestUtils.isCompositeComponentElement(inst) &&
- (inst.constructor === type));
- },
-
- isTextComponent: function(inst) {
- return inst instanceof ReactTextComponent.type;
- },
-
- findAllInRenderedTree: function(inst, test) {
- if (!inst) {
- return [];
- }
- var ret = test(inst) ? [inst] : [];
- if (ReactTestUtils.isDOMComponent(inst)) {
- var renderedChildren = inst._renderedChildren;
- var key;
- for (key in renderedChildren) {
- if (!renderedChildren.hasOwnProperty(key)) {
- continue;
- }
- ret = ret.concat(
- ReactTestUtils.findAllInRenderedTree(renderedChildren[key], test)
- );
- }
- } else if (ReactTestUtils.isCompositeComponent(inst)) {
- ret = ret.concat(
- ReactTestUtils.findAllInRenderedTree(inst._renderedComponent, test)
- );
- }
- return ret;
- },
-
- /**
- * Finds all instance of components in the rendered tree that are DOM
- * components with the class name matching `className`.
- * @return an array of all the matches.
- */
- scryRenderedDOMComponentsWithClass: function(root, className) {
- return ReactTestUtils.findAllInRenderedTree(root, function(inst) {
- var instClassName = inst.props.className;
- return ReactTestUtils.isDOMComponent(inst) && (
- instClassName &&
- (' ' + instClassName + ' ').indexOf(' ' + className + ' ') !== -1
- );
- });
- },
-
- /**
- * Like scryRenderedDOMComponentsWithClass but expects there to be one result,
- * and returns that one result, or throws exception if there is any other
- * number of matches besides one.
- * @return {!ReactDOMComponent} The one match.
- */
- findRenderedDOMComponentWithClass: function(root, className) {
- var all =
- ReactTestUtils.scryRenderedDOMComponentsWithClass(root, className);
- if (all.length !== 1) {
- throw new Error('Did not find exactly one match for class:' + className);
- }
- return all[0];
- },
-
-
- /**
- * Finds all instance of components in the rendered tree that are DOM
- * components with the tag name matching `tagName`.
- * @return an array of all the matches.
- */
- scryRenderedDOMComponentsWithTag: function(root, tagName) {
- return ReactTestUtils.findAllInRenderedTree(root, function(inst) {
- return ReactTestUtils.isDOMComponent(inst) &&
- inst.tagName === tagName.toUpperCase();
- });
- },
-
- /**
- * Like scryRenderedDOMComponentsWithTag but expects there to be one result,
- * and returns that one result, or throws exception if there is any other
- * number of matches besides one.
- * @return {!ReactDOMComponent} The one match.
- */
- findRenderedDOMComponentWithTag: function(root, tagName) {
- var all = ReactTestUtils.scryRenderedDOMComponentsWithTag(root, tagName);
- if (all.length !== 1) {
- throw new Error('Did not find exactly one match for tag:' + tagName);
- }
- return all[0];
- },
-
-
- /**
- * Finds all instances of components with type equal to `componentType`.
- * @return an array of all the matches.
- */
- scryRenderedComponentsWithType: function(root, componentType) {
- return ReactTestUtils.findAllInRenderedTree(root, function(inst) {
- return ReactTestUtils.isCompositeComponentWithType(
- inst,
- componentType
- );
- });
- },
-
- /**
- * Same as `scryRenderedComponentsWithType` but expects there to be one result
- * and returns that one result, or throws exception if there is any other
- * number of matches besides one.
- * @return {!ReactComponent} The one match.
- */
- findRenderedComponentWithType: function(root, componentType) {
- var all = ReactTestUtils.scryRenderedComponentsWithType(
- root,
- componentType
- );
- if (all.length !== 1) {
- throw new Error(
- 'Did not find exactly one match for componentType:' + componentType
- );
- }
- return all[0];
- },
-
- /**
- * Pass a mocked component module to this method to augment it with
- * useful methods that allow it to be used as a dummy React component.
- * Instead of rendering as usual, the component will become a simple
- * <div> containing any provided children.
- *
- * @param {object} module the mock function object exported from a
- * module that defines the component to be mocked
- * @param {?string} mockTagName optional dummy root tag name to return
- * from render method (overrides
- * module.mockTagName if provided)
- * @return {object} the ReactTestUtils object (for chaining)
- */
- mockComponent: function(module, mockTagName) {
- mockTagName = mockTagName || module.mockTagName || "div";
-
- var ConvenienceConstructor = React.createClass({displayName: 'ConvenienceConstructor',
- render: function() {
- return React.createElement(
- mockTagName,
- null,
- this.props.children
- );
- }
- });
-
- module.mockImplementation(ConvenienceConstructor);
-
- module.type = ConvenienceConstructor.type;
- module.isReactLegacyFactory = true;
-
- return this;
- },
-
- /**
- * Simulates a top level event being dispatched from a raw event that occured
- * on an `Element` node.
- * @param topLevelType {Object} A type from `EventConstants.topLevelTypes`
- * @param {!Element} node The dom to simulate an event occurring on.
- * @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.
- */
- simulateNativeEventOnNode: function(topLevelType, node, fakeNativeEvent) {
- fakeNativeEvent.target = node;
- ReactBrowserEventEmitter.ReactEventListener.dispatchEvent(
- topLevelType,
- fakeNativeEvent
- );
- },
-
- /**
- * Simulates a top level event being dispatched from a raw event that occured
- * on the `ReactDOMComponent` `comp`.
- * @param topLevelType {Object} A type from `EventConstants.topLevelTypes`.
- * @param comp {!ReactDOMComponent}
- * @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.
- */
- simulateNativeEventOnDOMComponent: function(
- topLevelType,
- comp,
- fakeNativeEvent) {
- ReactTestUtils.simulateNativeEventOnNode(
- topLevelType,
- comp.getDOMNode(),
- fakeNativeEvent
- );
- },
-
- nativeTouchData: function(x, y) {
- return {
- touches: [
- {pageX: x, pageY: y}
- ]
- };
- },
-
- Simulate: null,
- SimulateNative: {}
-};
-
-/**
- * Exports:
- *
- * - `ReactTestUtils.Simulate.click(Element/ReactDOMComponent)`
- * - `ReactTestUtils.Simulate.mouseMove(Element/ReactDOMComponent)`
- * - `ReactTestUtils.Simulate.change(Element/ReactDOMComponent)`
- * - ... (All keys from event plugin `eventTypes` objects)
- */
-function makeSimulator(eventType) {
- return function(domComponentOrNode, eventData) {
- var node;
- if (ReactTestUtils.isDOMComponent(domComponentOrNode)) {
- node = domComponentOrNode.getDOMNode();
- } else if (domComponentOrNode.tagName) {
- node = domComponentOrNode;
- }
-
- var fakeNativeEvent = new Event();
- fakeNativeEvent.target = node;
- // We don't use SyntheticEvent.getPooled in order to not have to worry about
- // properly destroying any properties assigned from `eventData` upon release
- var event = new SyntheticEvent(
- ReactBrowserEventEmitter.eventNameDispatchConfigs[eventType],
- ReactMount.getID(node),
- fakeNativeEvent
- );
- assign(event, eventData);
- EventPropagators.accumulateTwoPhaseDispatches(event);
-
- ReactUpdates.batchedUpdates(function() {
- EventPluginHub.enqueueEvents(event);
- EventPluginHub.processEventQueue();
- });
- };
-}
-
-function buildSimulators() {
- ReactTestUtils.Simulate = {};
-
- var eventType;
- for (eventType in ReactBrowserEventEmitter.eventNameDispatchConfigs) {
- /**
- * @param {!Element || ReactDOMComponent} domComponentOrNode
- * @param {?object} eventData Fake event data to use in SyntheticEvent.
- */
- ReactTestUtils.Simulate[eventType] = makeSimulator(eventType);
- }
-}
-
-// Rebuild ReactTestUtils.Simulate whenever event plugins are injected
-var oldInjectEventPluginOrder = EventPluginHub.injection.injectEventPluginOrder;
-EventPluginHub.injection.injectEventPluginOrder = function() {
- oldInjectEventPluginOrder.apply(this, arguments);
- buildSimulators();
-};
-var oldInjectEventPlugins = EventPluginHub.injection.injectEventPluginsByName;
-EventPluginHub.injection.injectEventPluginsByName = function() {
- oldInjectEventPlugins.apply(this, arguments);
- buildSimulators();
-};
-
-buildSimulators();
-
-/**
- * Exports:
- *
- * - `ReactTestUtils.SimulateNative.click(Element/ReactDOMComponent)`
- * - `ReactTestUtils.SimulateNative.mouseMove(Element/ReactDOMComponent)`
- * - `ReactTestUtils.SimulateNative.mouseIn/ReactDOMComponent)`
- * - `ReactTestUtils.SimulateNative.mouseOut(Element/ReactDOMComponent)`
- * - ... (All keys from `EventConstants.topLevelTypes`)
- *
- * Note: Top level event types are a subset of the entire set of handler types
- * (which include a broader set of "synthetic" events). For example, onDragDone
- * is a synthetic event. Except when testing an event plugin or React's event
- * handling code specifically, you probably want to use ReactTestUtils.Simulate
- * to dispatch synthetic events.
- */
-
-function makeNativeSimulator(eventType) {
- return function(domComponentOrNode, nativeEventData) {
- var fakeNativeEvent = new Event(eventType);
- assign(fakeNativeEvent, nativeEventData);
- if (ReactTestUtils.isDOMComponent(domComponentOrNode)) {
- ReactTestUtils.simulateNativeEventOnDOMComponent(
- eventType,
- domComponentOrNode,
- fakeNativeEvent
- );
- } else if (!!domComponentOrNode.tagName) {
- // Will allow on actual dom nodes.
- ReactTestUtils.simulateNativeEventOnNode(
- eventType,
- domComponentOrNode,
- fakeNativeEvent
- );
- }
- };
-}
-
-var eventType;
-for (eventType in topLevelTypes) {
- // Event type is stored as 'topClick' - we transform that to 'click'
- var convenienceName = eventType.indexOf('top') === 0 ?
- eventType.charAt(3).toLowerCase() + eventType.substr(4) : eventType;
- /**
- * @param {!Element || ReactDOMComponent} domComponentOrNode
- * @param {?Event} nativeEventData Fake native event to use in SyntheticEvent.
- */
- ReactTestUtils.SimulateNative[convenienceName] =
- makeNativeSimulator(eventType);
-}
-
-module.exports = ReactTestUtils;
-
-},{"./EventConstants":17,"./EventPluginHub":19,"./EventPropagators":22,"./Object.assign":29,"./React":31,"./ReactBrowserEventEmitter":33,"./ReactElement":58,"./ReactMount":70,"./ReactTextComponent":87,"./ReactUpdates":91,"./SyntheticEvent":99}],87:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactTextComponent
- * @typechecks static-only
- */
-
-"use strict";
-
-var DOMPropertyOperations = _dereq_("./DOMPropertyOperations");
-var ReactComponent = _dereq_("./ReactComponent");
-var ReactElement = _dereq_("./ReactElement");
-
-var assign = _dereq_("./Object.assign");
-var escapeTextForBrowser = _dereq_("./escapeTextForBrowser");
-
-/**
- * Text nodes violate a couple assumptions that React makes about components:
- *
- * - When mounting text into the DOM, adjacent text nodes are merged.
- * - Text nodes cannot be assigned a React root ID.
- *
- * This component is used to wrap strings in elements so that they can undergo
- * the same reconciliation that is applied to elements.
- *
- * TODO: Investigate representing React components in the DOM with text nodes.
- *
- * @class ReactTextComponent
- * @extends ReactComponent
- * @internal
- */
-var ReactTextComponent = function(props) {
- // This constructor and it's argument is currently used by mocks.
-};
-
-assign(ReactTextComponent.prototype, ReactComponent.Mixin, {
-
- /**
- * Creates the markup for this text node. This node is not intended to have
- * any features besides containing text content.
- *
- * @param {string} rootID DOM ID of the root node.
- * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
- * @param {number} mountDepth number of components in the owner hierarchy
- * @return {string} Markup for this text node.
- * @internal
- */
- mountComponent: function(rootID, transaction, mountDepth) {
- ReactComponent.Mixin.mountComponent.call(
- this,
- rootID,
- transaction,
- mountDepth
- );
-
- var escapedText = escapeTextForBrowser(this.props);
-
- if (transaction.renderToStaticMarkup) {
- // Normally we'd wrap this in a `span` for the reasons stated above, but
- // since this is a situation where React won't take over (static pages),
- // we can simply return the text as it is.
- return escapedText;
- }
-
- return (
- '<span ' + DOMPropertyOperations.createMarkupForID(rootID) + '>' +
- escapedText +
- '</span>'
- );
- },
-
- /**
- * Updates this component by updating the text content.
- *
- * @param {object} nextComponent Contains the next text content.
- * @param {ReactReconcileTransaction} transaction
- * @internal
- */
- receiveComponent: function(nextComponent, transaction) {
- var nextProps = nextComponent.props;
- if (nextProps !== this.props) {
- this.props = nextProps;
- ReactComponent.BackendIDOperations.updateTextContentByID(
- this._rootNodeID,
- nextProps
- );
- }
- }
-
-});
-
-var ReactTextComponentFactory = function(text) {
- // Bypass validation and configuration
- return new ReactElement(ReactTextComponent, null, null, null, null, text);
-};
-
-ReactTextComponentFactory.type = ReactTextComponent;
-
-module.exports = ReactTextComponentFactory;
-
-},{"./DOMPropertyOperations":13,"./Object.assign":29,"./ReactComponent":37,"./ReactElement":58,"./escapeTextForBrowser":123}],88:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @typechecks static-only
- * @providesModule ReactTransitionChildMapping
- */
-
-"use strict";
-
-var ReactChildren = _dereq_("./ReactChildren");
-
-var ReactTransitionChildMapping = {
- /**
- * Given `this.props.children`, return an object mapping key to child. Just
- * simple syntactic sugar around ReactChildren.map().
- *
- * @param {*} children `this.props.children`
- * @return {object} Mapping of key to child
- */
- getChildMapping: function(children) {
- return ReactChildren.map(children, function(child) {
- return child;
- });
- },
-
- /**
- * When you're adding or removing children some may be added or removed in the
- * same render pass. We want to show *both* since we want to simultaneously
- * animate elements in and out. This function takes a previous set of keys
- * and a new set of keys and merges them with its best guess of the correct
- * ordering. In the future we may expose some of the utilities in
- * ReactMultiChild to make this easy, but for now React itself does not
- * directly have this concept of the union of prevChildren and nextChildren
- * so we implement it here.
- *
- * @param {object} prev prev children as returned from
- * `ReactTransitionChildMapping.getChildMapping()`.
- * @param {object} next next children as returned from
- * `ReactTransitionChildMapping.getChildMapping()`.
- * @return {object} a key set that contains all keys in `prev` and all keys
- * in `next` in a reasonable order.
- */
- mergeChildMappings: function(prev, next) {
- prev = prev || {};
- next = next || {};
-
- function getValueForKey(key) {
- if (next.hasOwnProperty(key)) {
- return next[key];
- } else {
- return prev[key];
- }
- }
-
- // For each key of `next`, the list of keys to insert before that key in
- // the combined list
- var nextKeysPending = {};
-
- var pendingKeys = [];
- for (var prevKey in prev) {
- if (next.hasOwnProperty(prevKey)) {
- if (pendingKeys.length) {
- nextKeysPending[prevKey] = pendingKeys;
- pendingKeys = [];
- }
- } else {
- pendingKeys.push(prevKey);
- }
- }
-
- var i;
- var childMapping = {};
- for (var nextKey in next) {
- if (nextKeysPending.hasOwnProperty(nextKey)) {
- for (i = 0; i < nextKeysPending[nextKey].length; i++) {
- var pendingNextKey = nextKeysPending[nextKey][i];
- childMapping[nextKeysPending[nextKey][i]] = getValueForKey(
- pendingNextKey
- );
- }
- }
- childMapping[nextKey] = getValueForKey(nextKey);
- }
-
- // Finally, add the keys which didn't appear before any key in `next`
- for (i = 0; i < pendingKeys.length; i++) {
- childMapping[pendingKeys[i]] = getValueForKey(pendingKeys[i]);
- }
-
- return childMapping;
- }
-};
-
-module.exports = ReactTransitionChildMapping;
-
-},{"./ReactChildren":36}],89:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactTransitionEvents
- */
-
-"use strict";
-
-var ExecutionEnvironment = _dereq_("./ExecutionEnvironment");
-
-/**
- * EVENT_NAME_MAP is used to determine which event fired when a
- * transition/animation ends, based on the style property used to
- * define that event.
- */
-var EVENT_NAME_MAP = {
- transitionend: {
- 'transition': 'transitionend',
- 'WebkitTransition': 'webkitTransitionEnd',
- 'MozTransition': 'mozTransitionEnd',
- 'OTransition': 'oTransitionEnd',
- 'msTransition': 'MSTransitionEnd'
- },
-
- animationend: {
- 'animation': 'animationend',
- 'WebkitAnimation': 'webkitAnimationEnd',
- 'MozAnimation': 'mozAnimationEnd',
- 'OAnimation': 'oAnimationEnd',
- 'msAnimation': 'MSAnimationEnd'
- }
-};
-
-var endEvents = [];
-
-function detectEvents() {
- var testEl = document.createElement('div');
- var style = testEl.style;
-
- // On some platforms, in particular some releases of Android 4.x,
- // the un-prefixed "animation" and "transition" properties are defined on the
- // style object but the events that fire will still be prefixed, so we need
- // to check if the un-prefixed events are useable, and if not remove them
- // from the map
- if (!('AnimationEvent' in window)) {
- delete EVENT_NAME_MAP.animationend.animation;
- }
-
- if (!('TransitionEvent' in window)) {
- delete EVENT_NAME_MAP.transitionend.transition;
- }
-
- for (var baseEventName in EVENT_NAME_MAP) {
- var baseEvents = EVENT_NAME_MAP[baseEventName];
- for (var styleName in baseEvents) {
- if (styleName in style) {
- endEvents.push(baseEvents[styleName]);
- break;
- }
- }
- }
-}
-
-if (ExecutionEnvironment.canUseDOM) {
- detectEvents();
-}
-
-// We use the raw {add|remove}EventListener() call because EventListener
-// does not know how to remove event listeners and we really should
-// clean up. Also, these events are not triggered in older browsers
-// so we should be A-OK here.
-
-function addEventListener(node, eventName, eventListener) {
- node.addEventListener(eventName, eventListener, false);
-}
-
-function removeEventListener(node, eventName, eventListener) {
- node.removeEventListener(eventName, eventListener, false);
-}
-
-var ReactTransitionEvents = {
- addEndEventListener: function(node, eventListener) {
- if (endEvents.length === 0) {
- // If CSS transitions are not supported, trigger an "end animation"
- // event immediately.
- window.setTimeout(eventListener, 0);
- return;
- }
- endEvents.forEach(function(endEvent) {
- addEventListener(node, endEvent, eventListener);
- });
- },
-
- removeEndEventListener: function(node, eventListener) {
- if (endEvents.length === 0) {
- return;
- }
- endEvents.forEach(function(endEvent) {
- removeEventListener(node, endEvent, eventListener);
- });
- }
-};
-
-module.exports = ReactTransitionEvents;
-
-},{"./ExecutionEnvironment":23}],90:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactTransitionGroup
- */
-
-"use strict";
-
-var React = _dereq_("./React");
-var ReactTransitionChildMapping = _dereq_("./ReactTransitionChildMapping");
-
-var assign = _dereq_("./Object.assign");
-var cloneWithProps = _dereq_("./cloneWithProps");
-var emptyFunction = _dereq_("./emptyFunction");
-
-var ReactTransitionGroup = React.createClass({
- displayName: 'ReactTransitionGroup',
-
- propTypes: {
- component: React.PropTypes.any,
- childFactory: React.PropTypes.func
- },
-
- getDefaultProps: function() {
- return {
- component: 'span',
- childFactory: emptyFunction.thatReturnsArgument
- };
- },
-
- getInitialState: function() {
- return {
- children: ReactTransitionChildMapping.getChildMapping(this.props.children)
- };
- },
-
- componentWillReceiveProps: function(nextProps) {
- var nextChildMapping = ReactTransitionChildMapping.getChildMapping(
- nextProps.children
- );
- var prevChildMapping = this.state.children;
-
- this.setState({
- children: ReactTransitionChildMapping.mergeChildMappings(
- prevChildMapping,
- nextChildMapping
- )
- });
-
- var key;
-
- for (key in nextChildMapping) {
- var hasPrev = prevChildMapping && prevChildMapping.hasOwnProperty(key);
- if (nextChildMapping[key] && !hasPrev &&
- !this.currentlyTransitioningKeys[key]) {
- this.keysToEnter.push(key);
- }
- }
-
- for (key in prevChildMapping) {
- var hasNext = nextChildMapping && nextChildMapping.hasOwnProperty(key);
- if (prevChildMapping[key] && !hasNext &&
- !this.currentlyTransitioningKeys[key]) {
- this.keysToLeave.push(key);
- }
- }
-
- // If we want to someday check for reordering, we could do it here.
- },
-
- componentWillMount: function() {
- this.currentlyTransitioningKeys = {};
- this.keysToEnter = [];
- this.keysToLeave = [];
- },
-
- componentDidUpdate: function() {
- var keysToEnter = this.keysToEnter;
- this.keysToEnter = [];
- keysToEnter.forEach(this.performEnter);
-
- var keysToLeave = this.keysToLeave;
- this.keysToLeave = [];
- keysToLeave.forEach(this.performLeave);
- },
-
- performEnter: function(key) {
- this.currentlyTransitioningKeys[key] = true;
-
- var component = this.refs[key];
-
- if (component.componentWillEnter) {
- component.componentWillEnter(
- this._handleDoneEntering.bind(this, key)
- );
- } else {
- this._handleDoneEntering(key);
- }
- },
-
- _handleDoneEntering: function(key) {
- var component = this.refs[key];
- if (component.componentDidEnter) {
- component.componentDidEnter();
- }
-
- delete this.currentlyTransitioningKeys[key];
-
- var currentChildMapping = ReactTransitionChildMapping.getChildMapping(
- this.props.children
- );
-
- if (!currentChildMapping || !currentChildMapping.hasOwnProperty(key)) {
- // This was removed before it had fully entered. Remove it.
- this.performLeave(key);
- }
- },
-
- performLeave: function(key) {
- this.currentlyTransitioningKeys[key] = true;
-
- var component = this.refs[key];
- if (component.componentWillLeave) {
- component.componentWillLeave(this._handleDoneLeaving.bind(this, key));
- } else {
- // Note that this is somewhat dangerous b/c it calls setState()
- // again, effectively mutating the component before all the work
- // is done.
- this._handleDoneLeaving(key);
- }
- },
-
- _handleDoneLeaving: function(key) {
- var component = this.refs[key];
-
- if (component.componentDidLeave) {
- component.componentDidLeave();
- }
-
- delete this.currentlyTransitioningKeys[key];
-
- var currentChildMapping = ReactTransitionChildMapping.getChildMapping(
- this.props.children
- );
-
- if (currentChildMapping && currentChildMapping.hasOwnProperty(key)) {
- // This entered again before it fully left. Add it again.
- this.performEnter(key);
- } else {
- var newChildren = assign({}, this.state.children);
- delete newChildren[key];
- this.setState({children: newChildren});
- }
- },
-
- render: function() {
- // TODO: we could get rid of the need for the wrapper node
- // by cloning a single child
- var childrenToRender = {};
- for (var key in this.state.children) {
- var child = this.state.children[key];
- if (child) {
- // You may need to apply reactive updates to a child as it is leaving.
- // The normal React way to do it won't work since the child will have
- // already been removed. In case you need this behavior you can provide
- // a childFactory function to wrap every child, even the ones that are
- // leaving.
- childrenToRender[key] = cloneWithProps(
- this.props.childFactory(child),
- {ref: key}
- );
- }
- }
- return React.createElement(
- this.props.component,
- this.props,
- childrenToRender
- );
- }
-});
-
-module.exports = ReactTransitionGroup;
-
-},{"./Object.assign":29,"./React":31,"./ReactTransitionChildMapping":88,"./cloneWithProps":113,"./emptyFunction":121}],91:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactUpdates
- */
-
-"use strict";
-
-var CallbackQueue = _dereq_("./CallbackQueue");
-var PooledClass = _dereq_("./PooledClass");
-var ReactCurrentOwner = _dereq_("./ReactCurrentOwner");
-var ReactPerf = _dereq_("./ReactPerf");
-var Transaction = _dereq_("./Transaction");
-
-var assign = _dereq_("./Object.assign");
-var invariant = _dereq_("./invariant");
-var warning = _dereq_("./warning");
-
-var dirtyComponents = [];
-var asapCallbackQueue = CallbackQueue.getPooled();
-var asapEnqueued = false;
-
-var batchingStrategy = null;
-
-function ensureInjected() {
- ("production" !== "development" ? invariant(
- ReactUpdates.ReactReconcileTransaction && batchingStrategy,
- 'ReactUpdates: must inject a reconcile transaction class and batching ' +
- 'strategy'
- ) : invariant(ReactUpdates.ReactReconcileTransaction && batchingStrategy));
-}
-
-var NESTED_UPDATES = {
- initialize: function() {
- this.dirtyComponentsLength = dirtyComponents.length;
- },
- close: function() {
- if (this.dirtyComponentsLength !== dirtyComponents.length) {
- // Additional updates were enqueued by componentDidUpdate handlers or
- // similar; before our own UPDATE_QUEUEING wrapper closes, we want to run
- // these new updates so that if A's componentDidUpdate calls setState on
- // B, B will update before the callback A's updater provided when calling
- // setState.
- dirtyComponents.splice(0, this.dirtyComponentsLength);
- flushBatchedUpdates();
- } else {
- dirtyComponents.length = 0;
- }
- }
-};
-
-var UPDATE_QUEUEING = {
- initialize: function() {
- this.callbackQueue.reset();
- },
- close: function() {
- this.callbackQueue.notifyAll();
- }
-};
-
-var TRANSACTION_WRAPPERS = [NESTED_UPDATES, UPDATE_QUEUEING];
-
-function ReactUpdatesFlushTransaction() {
- this.reinitializeTransaction();
- this.dirtyComponentsLength = null;
- this.callbackQueue = CallbackQueue.getPooled();
- this.reconcileTransaction =
- ReactUpdates.ReactReconcileTransaction.getPooled();
-}
-
-assign(
- ReactUpdatesFlushTransaction.prototype,
- Transaction.Mixin, {
- getTransactionWrappers: function() {
- return TRANSACTION_WRAPPERS;
- },
-
- destructor: function() {
- this.dirtyComponentsLength = null;
- CallbackQueue.release(this.callbackQueue);
- this.callbackQueue = null;
- ReactUpdates.ReactReconcileTransaction.release(this.reconcileTransaction);
- this.reconcileTransaction = null;
- },
-
- perform: function(method, scope, a) {
- // Essentially calls `this.reconcileTransaction.perform(method, scope, a)`
- // with this transaction's wrappers around it.
- return Transaction.Mixin.perform.call(
- this,
- this.reconcileTransaction.perform,
- this.reconcileTransaction,
- method,
- scope,
- a
- );
- }
-});
-
-PooledClass.addPoolingTo(ReactUpdatesFlushTransaction);
-
-function batchedUpdates(callback, a, b) {
- ensureInjected();
- batchingStrategy.batchedUpdates(callback, a, b);
-}
-
-/**
- * Array comparator for ReactComponents by owner depth
- *
- * @param {ReactComponent} c1 first component you're comparing
- * @param {ReactComponent} c2 second component you're comparing
- * @return {number} Return value usable by Array.prototype.sort().
- */
-function mountDepthComparator(c1, c2) {
- return c1._mountDepth - c2._mountDepth;
-}
-
-function runBatchedUpdates(transaction) {
- var len = transaction.dirtyComponentsLength;
- ("production" !== "development" ? invariant(
- len === dirtyComponents.length,
- 'Expected flush transaction\'s stored dirty-components length (%s) to ' +
- 'match dirty-components array length (%s).',
- len,
- dirtyComponents.length
- ) : invariant(len === dirtyComponents.length));
-
- // Since reconciling a component higher in the owner hierarchy usually (not
- // always -- see shouldComponentUpdate()) will reconcile children, reconcile
- // them before their children by sorting the array.
- dirtyComponents.sort(mountDepthComparator);
-
- for (var i = 0; i < len; i++) {
- // If a component is unmounted before pending changes apply, ignore them
- // TODO: Queue unmounts in the same list to avoid this happening at all
- var component = dirtyComponents[i];
- if (component.isMounted()) {
- // If performUpdateIfNecessary happens to enqueue any new updates, we
- // shouldn't execute the callbacks until the next render happens, so
- // stash the callbacks first
- var callbacks = component._pendingCallbacks;
- component._pendingCallbacks = null;
- component.performUpdateIfNecessary(transaction.reconcileTransaction);
-
- if (callbacks) {
- for (var j = 0; j < callbacks.length; j++) {
- transaction.callbackQueue.enqueue(
- callbacks[j],
- component
- );
- }
- }
- }
- }
-}
-
-var flushBatchedUpdates = ReactPerf.measure(
- 'ReactUpdates',
- 'flushBatchedUpdates',
- function() {
- // ReactUpdatesFlushTransaction's wrappers will clear the dirtyComponents
- // array and perform any updates enqueued by mount-ready handlers (i.e.,
- // componentDidUpdate) but we need to check here too in order to catch
- // updates enqueued by setState callbacks and asap calls.
- while (dirtyComponents.length || asapEnqueued) {
- if (dirtyComponents.length) {
- var transaction = ReactUpdatesFlushTransaction.getPooled();
- transaction.perform(runBatchedUpdates, null, transaction);
- ReactUpdatesFlushTransaction.release(transaction);
- }
-
- if (asapEnqueued) {
- asapEnqueued = false;
- var queue = asapCallbackQueue;
- asapCallbackQueue = CallbackQueue.getPooled();
- queue.notifyAll();
- CallbackQueue.release(queue);
- }
- }
- }
-);
-
-/**
- * Mark a component as needing a rerender, adding an optional callback to a
- * list of functions which will be executed once the rerender occurs.
- */
-function enqueueUpdate(component, callback) {
- ("production" !== "development" ? invariant(
- !callback || typeof callback === "function",
- 'enqueueUpdate(...): You called `setProps`, `replaceProps`, ' +
- '`setState`, `replaceState`, or `forceUpdate` with a callback that ' +
- 'isn\'t callable.'
- ) : invariant(!callback || typeof callback === "function"));
- ensureInjected();
-
- // Various parts of our code (such as ReactCompositeComponent's
- // _renderValidatedComponent) assume that calls to render aren't nested;
- // verify that that's the case. (This is called by each top-level update
- // function, like setProps, setState, forceUpdate, etc.; creation and
- // destruction of top-level components is guarded in ReactMount.)
- ("production" !== "development" ? warning(
- ReactCurrentOwner.current == null,
- 'enqueueUpdate(): Render methods should be a pure function of props ' +
- 'and state; triggering nested component updates from render is not ' +
- 'allowed. If necessary, trigger nested updates in ' +
- 'componentDidUpdate.'
- ) : null);
-
- if (!batchingStrategy.isBatchingUpdates) {
- batchingStrategy.batchedUpdates(enqueueUpdate, component, callback);
- return;
- }
-
- dirtyComponents.push(component);
-
- if (callback) {
- if (component._pendingCallbacks) {
- component._pendingCallbacks.push(callback);
- } else {
- component._pendingCallbacks = [callback];
- }
- }
-}
-
-/**
- * Enqueue a callback to be run at the end of the current batching cycle. Throws
- * if no updates are currently being performed.
- */
-function asap(callback, context) {
- ("production" !== "development" ? invariant(
- batchingStrategy.isBatchingUpdates,
- 'ReactUpdates.asap: Can\'t enqueue an asap callback in a context where' +
- 'updates are not being batched.'
- ) : invariant(batchingStrategy.isBatchingUpdates));
- asapCallbackQueue.enqueue(callback, context);
- asapEnqueued = true;
-}
-
-var ReactUpdatesInjection = {
- injectReconcileTransaction: function(ReconcileTransaction) {
- ("production" !== "development" ? invariant(
- ReconcileTransaction,
- 'ReactUpdates: must provide a reconcile transaction class'
- ) : invariant(ReconcileTransaction));
- ReactUpdates.ReactReconcileTransaction = ReconcileTransaction;
- },
-
- injectBatchingStrategy: function(_batchingStrategy) {
- ("production" !== "development" ? invariant(
- _batchingStrategy,
- 'ReactUpdates: must provide a batching strategy'
- ) : invariant(_batchingStrategy));
- ("production" !== "development" ? invariant(
- typeof _batchingStrategy.batchedUpdates === 'function',
- 'ReactUpdates: must provide a batchedUpdates() function'
- ) : invariant(typeof _batchingStrategy.batchedUpdates === 'function'));
- ("production" !== "development" ? invariant(
- typeof _batchingStrategy.isBatchingUpdates === 'boolean',
- 'ReactUpdates: must provide an isBatchingUpdates boolean attribute'
- ) : invariant(typeof _batchingStrategy.isBatchingUpdates === 'boolean'));
- batchingStrategy = _batchingStrategy;
- }
-};
-
-var ReactUpdates = {
- /**
- * React references `ReactReconcileTransaction` using this property in order
- * to allow dependency injection.
- *
- * @internal
- */
- ReactReconcileTransaction: null,
-
- batchedUpdates: batchedUpdates,
- enqueueUpdate: enqueueUpdate,
- flushBatchedUpdates: flushBatchedUpdates,
- injection: ReactUpdatesInjection,
- asap: asap
-};
-
-module.exports = ReactUpdates;
-
-},{"./CallbackQueue":7,"./Object.assign":29,"./PooledClass":30,"./ReactCurrentOwner":42,"./ReactPerf":75,"./Transaction":107,"./invariant":140,"./warning":160}],92:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SVGDOMPropertyConfig
- */
-
-/*jslint bitwise: true*/
-
-"use strict";
-
-var DOMProperty = _dereq_("./DOMProperty");
-
-var MUST_USE_ATTRIBUTE = DOMProperty.injection.MUST_USE_ATTRIBUTE;
-
-var SVGDOMPropertyConfig = {
- Properties: {
- cx: MUST_USE_ATTRIBUTE,
- cy: MUST_USE_ATTRIBUTE,
- d: MUST_USE_ATTRIBUTE,
- dx: MUST_USE_ATTRIBUTE,
- dy: MUST_USE_ATTRIBUTE,
- fill: MUST_USE_ATTRIBUTE,
- fillOpacity: MUST_USE_ATTRIBUTE,
- fontFamily: MUST_USE_ATTRIBUTE,
- fontSize: MUST_USE_ATTRIBUTE,
- fx: MUST_USE_ATTRIBUTE,
- fy: MUST_USE_ATTRIBUTE,
- gradientTransform: MUST_USE_ATTRIBUTE,
- gradientUnits: MUST_USE_ATTRIBUTE,
- markerEnd: MUST_USE_ATTRIBUTE,
- markerMid: MUST_USE_ATTRIBUTE,
- markerStart: MUST_USE_ATTRIBUTE,
- offset: MUST_USE_ATTRIBUTE,
- opacity: MUST_USE_ATTRIBUTE,
- patternContentUnits: MUST_USE_ATTRIBUTE,
- patternUnits: MUST_USE_ATTRIBUTE,
- points: MUST_USE_ATTRIBUTE,
- preserveAspectRatio: MUST_USE_ATTRIBUTE,
- r: MUST_USE_ATTRIBUTE,
- rx: MUST_USE_ATTRIBUTE,
- ry: MUST_USE_ATTRIBUTE,
- spreadMethod: MUST_USE_ATTRIBUTE,
- stopColor: MUST_USE_ATTRIBUTE,
- stopOpacity: MUST_USE_ATTRIBUTE,
- stroke: MUST_USE_ATTRIBUTE,
- strokeDasharray: MUST_USE_ATTRIBUTE,
- strokeLinecap: MUST_USE_ATTRIBUTE,
- strokeOpacity: MUST_USE_ATTRIBUTE,
- strokeWidth: MUST_USE_ATTRIBUTE,
- textAnchor: MUST_USE_ATTRIBUTE,
- transform: MUST_USE_ATTRIBUTE,
- version: MUST_USE_ATTRIBUTE,
- viewBox: MUST_USE_ATTRIBUTE,
- x1: MUST_USE_ATTRIBUTE,
- x2: MUST_USE_ATTRIBUTE,
- x: MUST_USE_ATTRIBUTE,
- y1: MUST_USE_ATTRIBUTE,
- y2: MUST_USE_ATTRIBUTE,
- y: MUST_USE_ATTRIBUTE
- },
- DOMAttributeNames: {
- fillOpacity: 'fill-opacity',
- fontFamily: 'font-family',
- fontSize: 'font-size',
- gradientTransform: 'gradientTransform',
- gradientUnits: 'gradientUnits',
- markerEnd: 'marker-end',
- markerMid: 'marker-mid',
- markerStart: 'marker-start',
- patternContentUnits: 'patternContentUnits',
- patternUnits: 'patternUnits',
- preserveAspectRatio: 'preserveAspectRatio',
- spreadMethod: 'spreadMethod',
- stopColor: 'stop-color',
- stopOpacity: 'stop-opacity',
- strokeDasharray: 'stroke-dasharray',
- strokeLinecap: 'stroke-linecap',
- strokeOpacity: 'stroke-opacity',
- strokeWidth: 'stroke-width',
- textAnchor: 'text-anchor',
- viewBox: 'viewBox'
- }
-};
-
-module.exports = SVGDOMPropertyConfig;
-
-},{"./DOMProperty":12}],93:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SelectEventPlugin
- */
-
-"use strict";
-
-var EventConstants = _dereq_("./EventConstants");
-var EventPropagators = _dereq_("./EventPropagators");
-var ReactInputSelection = _dereq_("./ReactInputSelection");
-var SyntheticEvent = _dereq_("./SyntheticEvent");
-
-var getActiveElement = _dereq_("./getActiveElement");
-var isTextInputElement = _dereq_("./isTextInputElement");
-var keyOf = _dereq_("./keyOf");
-var shallowEqual = _dereq_("./shallowEqual");
-
-var topLevelTypes = EventConstants.topLevelTypes;
-
-var eventTypes = {
- select: {
- phasedRegistrationNames: {
- bubbled: keyOf({onSelect: null}),
- captured: keyOf({onSelectCapture: null})
- },
- dependencies: [
- topLevelTypes.topBlur,
- topLevelTypes.topContextMenu,
- topLevelTypes.topFocus,
- topLevelTypes.topKeyDown,
- topLevelTypes.topMouseDown,
- topLevelTypes.topMouseUp,
- topLevelTypes.topSelectionChange
- ]
- }
-};
-
-var activeElement = null;
-var activeElementID = null;
-var lastSelection = null;
-var mouseDown = false;
-
-/**
- * Get an object which is a unique representation of the current selection.
- *
- * The return value will not be consistent across nodes or browsers, but
- * two identical selections on the same node will return identical objects.
- *
- * @param {DOMElement} node
- * @param {object}
- */
-function getSelection(node) {
- if ('selectionStart' in node &&
- ReactInputSelection.hasSelectionCapabilities(node)) {
- return {
- start: node.selectionStart,
- end: node.selectionEnd
- };
- } else if (window.getSelection) {
- var selection = window.getSelection();
- return {
- anchorNode: selection.anchorNode,
- anchorOffset: selection.anchorOffset,
- focusNode: selection.focusNode,
- focusOffset: selection.focusOffset
- };
- } else if (document.selection) {
- var range = document.selection.createRange();
- return {
- parentElement: range.parentElement(),
- text: range.text,
- top: range.boundingTop,
- left: range.boundingLeft
- };
- }
-}
-
-/**
- * Poll selection to see whether it's changed.
- *
- * @param {object} nativeEvent
- * @return {?SyntheticEvent}
- */
-function constructSelectEvent(nativeEvent) {
- // Ensure we have the right element, and that the user is not dragging a
- // selection (this matches native `select` event behavior). In HTML5, select
- // fires only on input and textarea thus if there's no focused element we
- // won't dispatch.
- if (mouseDown ||
- activeElement == null ||
- activeElement != getActiveElement()) {
- return;
- }
-
- // Only fire when selection has actually changed.
- var currentSelection = getSelection(activeElement);
- if (!lastSelection || !shallowEqual(lastSelection, currentSelection)) {
- lastSelection = currentSelection;
-
- var syntheticEvent = SyntheticEvent.getPooled(
- eventTypes.select,
- activeElementID,
- nativeEvent
- );
-
- syntheticEvent.type = 'select';
- syntheticEvent.target = activeElement;
-
- EventPropagators.accumulateTwoPhaseDispatches(syntheticEvent);
-
- return syntheticEvent;
- }
-}
-
-/**
- * This plugin creates an `onSelect` event that normalizes select events
- * across form elements.
- *
- * Supported elements are:
- * - input (see `isTextInputElement`)
- * - textarea
- * - contentEditable
- *
- * This differs from native browser implementations in the following ways:
- * - Fires on contentEditable fields as well as inputs.
- * - Fires for collapsed selection.
- * - Fires after user input.
- */
-var SelectEventPlugin = {
-
- eventTypes: eventTypes,
-
- /**
- * @param {string} topLevelType Record from `EventConstants`.
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
- * @param {object} nativeEvent Native browser event.
- * @return {*} An accumulation of synthetic events.
- * @see {EventPluginHub.extractEvents}
- */
- extractEvents: function(
- topLevelType,
- topLevelTarget,
- topLevelTargetID,
- nativeEvent) {
-
- switch (topLevelType) {
- // Track the input node that has focus.
- case topLevelTypes.topFocus:
- if (isTextInputElement(topLevelTarget) ||
- topLevelTarget.contentEditable === 'true') {
- activeElement = topLevelTarget;
- activeElementID = topLevelTargetID;
- lastSelection = null;
- }
- break;
- case topLevelTypes.topBlur:
- activeElement = null;
- activeElementID = null;
- lastSelection = null;
- break;
-
- // Don't fire the event while the user is dragging. This matches the
- // semantics of the native select event.
- case topLevelTypes.topMouseDown:
- mouseDown = true;
- break;
- case topLevelTypes.topContextMenu:
- case topLevelTypes.topMouseUp:
- mouseDown = false;
- return constructSelectEvent(nativeEvent);
-
- // Chrome and IE fire non-standard event when selection is changed (and
- // sometimes when it hasn't).
- // Firefox doesn't support selectionchange, so check selection status
- // after each key entry. The selection changes after keydown and before
- // keyup, but we check on keydown as well in the case of holding down a
- // key, when multiple keydown events are fired but only one keyup is.
- case topLevelTypes.topSelectionChange:
- case topLevelTypes.topKeyDown:
- case topLevelTypes.topKeyUp:
- return constructSelectEvent(nativeEvent);
- }
- }
-};
-
-module.exports = SelectEventPlugin;
-
-},{"./EventConstants":17,"./EventPropagators":22,"./ReactInputSelection":65,"./SyntheticEvent":99,"./getActiveElement":127,"./isTextInputElement":143,"./keyOf":147,"./shallowEqual":155}],94:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ServerReactRootIndex
- * @typechecks
- */
-
-"use strict";
-
-/**
- * Size of the reactRoot ID space. We generate random numbers for React root
- * IDs and if there's a collision the events and DOM update system will
- * get confused. In the future we need a way to generate GUIDs but for
- * now this will work on a smaller scale.
- */
-var GLOBAL_MOUNT_POINT_MAX = Math.pow(2, 53);
-
-var ServerReactRootIndex = {
- createReactRootIndex: function() {
- return Math.ceil(Math.random() * GLOBAL_MOUNT_POINT_MAX);
- }
-};
-
-module.exports = ServerReactRootIndex;
-
-},{}],95:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SimpleEventPlugin
- */
-
-"use strict";
-
-var EventConstants = _dereq_("./EventConstants");
-var EventPluginUtils = _dereq_("./EventPluginUtils");
-var EventPropagators = _dereq_("./EventPropagators");
-var SyntheticClipboardEvent = _dereq_("./SyntheticClipboardEvent");
-var SyntheticEvent = _dereq_("./SyntheticEvent");
-var SyntheticFocusEvent = _dereq_("./SyntheticFocusEvent");
-var SyntheticKeyboardEvent = _dereq_("./SyntheticKeyboardEvent");
-var SyntheticMouseEvent = _dereq_("./SyntheticMouseEvent");
-var SyntheticDragEvent = _dereq_("./SyntheticDragEvent");
-var SyntheticTouchEvent = _dereq_("./SyntheticTouchEvent");
-var SyntheticUIEvent = _dereq_("./SyntheticUIEvent");
-var SyntheticWheelEvent = _dereq_("./SyntheticWheelEvent");
-
-var getEventCharCode = _dereq_("./getEventCharCode");
-
-var invariant = _dereq_("./invariant");
-var keyOf = _dereq_("./keyOf");
-var warning = _dereq_("./warning");
-
-var topLevelTypes = EventConstants.topLevelTypes;
-
-var eventTypes = {
- blur: {
- phasedRegistrationNames: {
- bubbled: keyOf({onBlur: true}),
- captured: keyOf({onBlurCapture: true})
- }
- },
- click: {
- phasedRegistrationNames: {
- bubbled: keyOf({onClick: true}),
- captured: keyOf({onClickCapture: true})
- }
- },
- contextMenu: {
- phasedRegistrationNames: {
- bubbled: keyOf({onContextMenu: true}),
- captured: keyOf({onContextMenuCapture: true})
- }
- },
- copy: {
- phasedRegistrationNames: {
- bubbled: keyOf({onCopy: true}),
- captured: keyOf({onCopyCapture: true})
- }
- },
- cut: {
- phasedRegistrationNames: {
- bubbled: keyOf({onCut: true}),
- captured: keyOf({onCutCapture: true})
- }
- },
- doubleClick: {
- phasedRegistrationNames: {
- bubbled: keyOf({onDoubleClick: true}),
- captured: keyOf({onDoubleClickCapture: true})
- }
- },
- drag: {
- phasedRegistrationNames: {
- bubbled: keyOf({onDrag: true}),
- captured: keyOf({onDragCapture: true})
- }
- },
- dragEnd: {
- phasedRegistrationNames: {
- bubbled: keyOf({onDragEnd: true}),
- captured: keyOf({onDragEndCapture: true})
- }
- },
- dragEnter: {
- phasedRegistrationNames: {
- bubbled: keyOf({onDragEnter: true}),
- captured: keyOf({onDragEnterCapture: true})
- }
- },
- dragExit: {
- phasedRegistrationNames: {
- bubbled: keyOf({onDragExit: true}),
- captured: keyOf({onDragExitCapture: true})
- }
- },
- dragLeave: {
- phasedRegistrationNames: {
- bubbled: keyOf({onDragLeave: true}),
- captured: keyOf({onDragLeaveCapture: true})
- }
- },
- dragOver: {
- phasedRegistrationNames: {
- bubbled: keyOf({onDragOver: true}),
- captured: keyOf({onDragOverCapture: true})
- }
- },
- dragStart: {
- phasedRegistrationNames: {
- bubbled: keyOf({onDragStart: true}),
- captured: keyOf({onDragStartCapture: true})
- }
- },
- drop: {
- phasedRegistrationNames: {
- bubbled: keyOf({onDrop: true}),
- captured: keyOf({onDropCapture: true})
- }
- },
- focus: {
- phasedRegistrationNames: {
- bubbled: keyOf({onFocus: true}),
- captured: keyOf({onFocusCapture: true})
- }
- },
- input: {
- phasedRegistrationNames: {
- bubbled: keyOf({onInput: true}),
- captured: keyOf({onInputCapture: true})
- }
- },
- keyDown: {
- phasedRegistrationNames: {
- bubbled: keyOf({onKeyDown: true}),
- captured: keyOf({onKeyDownCapture: true})
- }
- },
- keyPress: {
- phasedRegistrationNames: {
- bubbled: keyOf({onKeyPress: true}),
- captured: keyOf({onKeyPressCapture: true})
- }
- },
- keyUp: {
- phasedRegistrationNames: {
- bubbled: keyOf({onKeyUp: true}),
- captured: keyOf({onKeyUpCapture: true})
- }
- },
- load: {
- phasedRegistrationNames: {
- bubbled: keyOf({onLoad: true}),
- captured: keyOf({onLoadCapture: true})
- }
- },
- error: {
- phasedRegistrationNames: {
- bubbled: keyOf({onError: true}),
- captured: keyOf({onErrorCapture: true})
- }
- },
- // Note: We do not allow listening to mouseOver events. Instead, use the
- // onMouseEnter/onMouseLeave created by `EnterLeaveEventPlugin`.
- mouseDown: {
- phasedRegistrationNames: {
- bubbled: keyOf({onMouseDown: true}),
- captured: keyOf({onMouseDownCapture: true})
- }
- },
- mouseMove: {
- phasedRegistrationNames: {
- bubbled: keyOf({onMouseMove: true}),
- captured: keyOf({onMouseMoveCapture: true})
- }
- },
- mouseOut: {
- phasedRegistrationNames: {
- bubbled: keyOf({onMouseOut: true}),
- captured: keyOf({onMouseOutCapture: true})
- }
- },
- mouseOver: {
- phasedRegistrationNames: {
- bubbled: keyOf({onMouseOver: true}),
- captured: keyOf({onMouseOverCapture: true})
- }
- },
- mouseUp: {
- phasedRegistrationNames: {
- bubbled: keyOf({onMouseUp: true}),
- captured: keyOf({onMouseUpCapture: true})
- }
- },
- paste: {
- phasedRegistrationNames: {
- bubbled: keyOf({onPaste: true}),
- captured: keyOf({onPasteCapture: true})
- }
- },
- reset: {
- phasedRegistrationNames: {
- bubbled: keyOf({onReset: true}),
- captured: keyOf({onResetCapture: true})
- }
- },
- scroll: {
- phasedRegistrationNames: {
- bubbled: keyOf({onScroll: true}),
- captured: keyOf({onScrollCapture: true})
- }
- },
- submit: {
- phasedRegistrationNames: {
- bubbled: keyOf({onSubmit: true}),
- captured: keyOf({onSubmitCapture: true})
- }
- },
- touchCancel: {
- phasedRegistrationNames: {
- bubbled: keyOf({onTouchCancel: true}),
- captured: keyOf({onTouchCancelCapture: true})
- }
- },
- touchEnd: {
- phasedRegistrationNames: {
- bubbled: keyOf({onTouchEnd: true}),
- captured: keyOf({onTouchEndCapture: true})
- }
- },
- touchMove: {
- phasedRegistrationNames: {
- bubbled: keyOf({onTouchMove: true}),
- captured: keyOf({onTouchMoveCapture: true})
- }
- },
- touchStart: {
- phasedRegistrationNames: {
- bubbled: keyOf({onTouchStart: true}),
- captured: keyOf({onTouchStartCapture: true})
- }
- },
- wheel: {
- phasedRegistrationNames: {
- bubbled: keyOf({onWheel: true}),
- captured: keyOf({onWheelCapture: true})
- }
- }
-};
-
-var topLevelEventsToDispatchConfig = {
- topBlur: eventTypes.blur,
- topClick: eventTypes.click,
- topContextMenu: eventTypes.contextMenu,
- topCopy: eventTypes.copy,
- topCut: eventTypes.cut,
- topDoubleClick: eventTypes.doubleClick,
- topDrag: eventTypes.drag,
- topDragEnd: eventTypes.dragEnd,
- topDragEnter: eventTypes.dragEnter,
- topDragExit: eventTypes.dragExit,
- topDragLeave: eventTypes.dragLeave,
- topDragOver: eventTypes.dragOver,
- topDragStart: eventTypes.dragStart,
- topDrop: eventTypes.drop,
- topError: eventTypes.error,
- topFocus: eventTypes.focus,
- topInput: eventTypes.input,
- topKeyDown: eventTypes.keyDown,
- topKeyPress: eventTypes.keyPress,
- topKeyUp: eventTypes.keyUp,
- topLoad: eventTypes.load,
- topMouseDown: eventTypes.mouseDown,
- topMouseMove: eventTypes.mouseMove,
- topMouseOut: eventTypes.mouseOut,
- topMouseOver: eventTypes.mouseOver,
- topMouseUp: eventTypes.mouseUp,
- topPaste: eventTypes.paste,
- topReset: eventTypes.reset,
- topScroll: eventTypes.scroll,
- topSubmit: eventTypes.submit,
- topTouchCancel: eventTypes.touchCancel,
- topTouchEnd: eventTypes.touchEnd,
- topTouchMove: eventTypes.touchMove,
- topTouchStart: eventTypes.touchStart,
- topWheel: eventTypes.wheel
-};
-
-for (var topLevelType in topLevelEventsToDispatchConfig) {
- topLevelEventsToDispatchConfig[topLevelType].dependencies = [topLevelType];
-}
-
-var SimpleEventPlugin = {
-
- eventTypes: eventTypes,
-
- /**
- * Same as the default implementation, except cancels the event when return
- * value is false. This behavior will be disabled in a future release.
- *
- * @param {object} Event to be dispatched.
- * @param {function} Application-level callback.
- * @param {string} domID DOM ID to pass to the callback.
- */
- executeDispatch: function(event, listener, domID) {
- var returnValue = EventPluginUtils.executeDispatch(event, listener, domID);
-
- ("production" !== "development" ? warning(
- typeof returnValue !== 'boolean',
- 'Returning `false` from an event handler is deprecated and will be ' +
- 'ignored in a future release. Instead, manually call ' +
- 'e.stopPropagation() or e.preventDefault(), as appropriate.'
- ) : null);
-
- if (returnValue === false) {
- event.stopPropagation();
- event.preventDefault();
- }
- },
-
- /**
- * @param {string} topLevelType Record from `EventConstants`.
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
- * @param {object} nativeEvent Native browser event.
- * @return {*} An accumulation of synthetic events.
- * @see {EventPluginHub.extractEvents}
- */
- extractEvents: function(
- topLevelType,
- topLevelTarget,
- topLevelTargetID,
- nativeEvent) {
- var dispatchConfig = topLevelEventsToDispatchConfig[topLevelType];
- if (!dispatchConfig) {
- return null;
- }
- var EventConstructor;
- switch (topLevelType) {
- case topLevelTypes.topInput:
- case topLevelTypes.topLoad:
- case topLevelTypes.topError:
- case topLevelTypes.topReset:
- case topLevelTypes.topSubmit:
- // HTML Events
- // @see http://www.w3.org/TR/html5/index.html#events-0
- EventConstructor = SyntheticEvent;
- break;
- case topLevelTypes.topKeyPress:
- // FireFox creates a keypress event for function keys too. This removes
- // the unwanted keypress events. Enter is however both printable and
- // non-printable. One would expect Tab to be as well (but it isn't).
- if (getEventCharCode(nativeEvent) === 0) {
- return null;
- }
- /* falls through */
- case topLevelTypes.topKeyDown:
- case topLevelTypes.topKeyUp:
- EventConstructor = SyntheticKeyboardEvent;
- break;
- case topLevelTypes.topBlur:
- case topLevelTypes.topFocus:
- EventConstructor = SyntheticFocusEvent;
- break;
- case topLevelTypes.topClick:
- // Firefox creates a click event on right mouse clicks. This removes the
- // unwanted click events.
- if (nativeEvent.button === 2) {
- return null;
- }
- /* falls through */
- case topLevelTypes.topContextMenu:
- case topLevelTypes.topDoubleClick:
- case topLevelTypes.topMouseDown:
- case topLevelTypes.topMouseMove:
- case topLevelTypes.topMouseOut:
- case topLevelTypes.topMouseOver:
- case topLevelTypes.topMouseUp:
- EventConstructor = SyntheticMouseEvent;
- break;
- case topLevelTypes.topDrag:
- case topLevelTypes.topDragEnd:
- case topLevelTypes.topDragEnter:
- case topLevelTypes.topDragExit:
- case topLevelTypes.topDragLeave:
- case topLevelTypes.topDragOver:
- case topLevelTypes.topDragStart:
- case topLevelTypes.topDrop:
- EventConstructor = SyntheticDragEvent;
- break;
- case topLevelTypes.topTouchCancel:
- case topLevelTypes.topTouchEnd:
- case topLevelTypes.topTouchMove:
- case topLevelTypes.topTouchStart:
- EventConstructor = SyntheticTouchEvent;
- break;
- case topLevelTypes.topScroll:
- EventConstructor = SyntheticUIEvent;
- break;
- case topLevelTypes.topWheel:
- EventConstructor = SyntheticWheelEvent;
- break;
- case topLevelTypes.topCopy:
- case topLevelTypes.topCut:
- case topLevelTypes.topPaste:
- EventConstructor = SyntheticClipboardEvent;
- break;
- }
- ("production" !== "development" ? invariant(
- EventConstructor,
- 'SimpleEventPlugin: Unhandled event type, `%s`.',
- topLevelType
- ) : invariant(EventConstructor));
- var event = EventConstructor.getPooled(
- dispatchConfig,
- topLevelTargetID,
- nativeEvent
- );
- EventPropagators.accumulateTwoPhaseDispatches(event);
- return event;
- }
-
-};
-
-module.exports = SimpleEventPlugin;
-
-},{"./EventConstants":17,"./EventPluginUtils":21,"./EventPropagators":22,"./SyntheticClipboardEvent":96,"./SyntheticDragEvent":98,"./SyntheticEvent":99,"./SyntheticFocusEvent":100,"./SyntheticKeyboardEvent":102,"./SyntheticMouseEvent":103,"./SyntheticTouchEvent":104,"./SyntheticUIEvent":105,"./SyntheticWheelEvent":106,"./getEventCharCode":128,"./invariant":140,"./keyOf":147,"./warning":160}],96:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SyntheticClipboardEvent
- * @typechecks static-only
- */
-
-"use strict";
-
-var SyntheticEvent = _dereq_("./SyntheticEvent");
-
-/**
- * @interface Event
- * @see http://www.w3.org/TR/clipboard-apis/
- */
-var ClipboardEventInterface = {
- clipboardData: function(event) {
- return (
- 'clipboardData' in event ?
- event.clipboardData :
- window.clipboardData
- );
- }
-};
-
-/**
- * @param {object} dispatchConfig Configuration used to dispatch this event.
- * @param {string} dispatchMarker Marker identifying the event target.
- * @param {object} nativeEvent Native browser event.
- * @extends {SyntheticUIEvent}
- */
-function SyntheticClipboardEvent(dispatchConfig, dispatchMarker, nativeEvent) {
- SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
-}
-
-SyntheticEvent.augmentClass(SyntheticClipboardEvent, ClipboardEventInterface);
-
-module.exports = SyntheticClipboardEvent;
-
-
-},{"./SyntheticEvent":99}],97:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SyntheticCompositionEvent
- * @typechecks static-only
- */
-
-"use strict";
-
-var SyntheticEvent = _dereq_("./SyntheticEvent");
-
-/**
- * @interface Event
- * @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents
- */
-var CompositionEventInterface = {
- data: null
-};
-
-/**
- * @param {object} dispatchConfig Configuration used to dispatch this event.
- * @param {string} dispatchMarker Marker identifying the event target.
- * @param {object} nativeEvent Native browser event.
- * @extends {SyntheticUIEvent}
- */
-function SyntheticCompositionEvent(
- dispatchConfig,
- dispatchMarker,
- nativeEvent) {
- SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
-}
-
-SyntheticEvent.augmentClass(
- SyntheticCompositionEvent,
- CompositionEventInterface
-);
-
-module.exports = SyntheticCompositionEvent;
-
-
-},{"./SyntheticEvent":99}],98:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SyntheticDragEvent
- * @typechecks static-only
- */
-
-"use strict";
-
-var SyntheticMouseEvent = _dereq_("./SyntheticMouseEvent");
-
-/**
- * @interface DragEvent
- * @see http://www.w3.org/TR/DOM-Level-3-Events/
- */
-var DragEventInterface = {
- dataTransfer: null
-};
-
-/**
- * @param {object} dispatchConfig Configuration used to dispatch this event.
- * @param {string} dispatchMarker Marker identifying the event target.
- * @param {object} nativeEvent Native browser event.
- * @extends {SyntheticUIEvent}
- */
-function SyntheticDragEvent(dispatchConfig, dispatchMarker, nativeEvent) {
- SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
-}
-
-SyntheticMouseEvent.augmentClass(SyntheticDragEvent, DragEventInterface);
-
-module.exports = SyntheticDragEvent;
-
-},{"./SyntheticMouseEvent":103}],99:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SyntheticEvent
- * @typechecks static-only
- */
-
-"use strict";
-
-var PooledClass = _dereq_("./PooledClass");
-
-var assign = _dereq_("./Object.assign");
-var emptyFunction = _dereq_("./emptyFunction");
-var getEventTarget = _dereq_("./getEventTarget");
-
-/**
- * @interface Event
- * @see http://www.w3.org/TR/DOM-Level-3-Events/
- */
-var EventInterface = {
- type: null,
- target: getEventTarget,
- // currentTarget is set when dispatching; no use in copying it here
- currentTarget: emptyFunction.thatReturnsNull,
- eventPhase: null,
- bubbles: null,
- cancelable: null,
- timeStamp: function(event) {
- return event.timeStamp || Date.now();
- },
- defaultPrevented: null,
- isTrusted: null
-};
-
-/**
- * Synthetic events are dispatched by event plugins, typically in response to a
- * top-level event delegation handler.
- *
- * These systems should generally use pooling to reduce the frequency of garbage
- * collection. The system should check `isPersistent` to determine whether the
- * event should be released into the pool after being dispatched. Users that
- * need a persisted event should invoke `persist`.
- *
- * Synthetic events (and subclasses) implement the DOM Level 3 Events API by
- * normalizing browser quirks. Subclasses do not necessarily have to implement a
- * DOM interface; custom application-specific events can also subclass this.
- *
- * @param {object} dispatchConfig Configuration used to dispatch this event.
- * @param {string} dispatchMarker Marker identifying the event target.
- * @param {object} nativeEvent Native browser event.
- */
-function SyntheticEvent(dispatchConfig, dispatchMarker, nativeEvent) {
- this.dispatchConfig = dispatchConfig;
- this.dispatchMarker = dispatchMarker;
- this.nativeEvent = nativeEvent;
-
- var Interface = this.constructor.Interface;
- for (var propName in Interface) {
- if (!Interface.hasOwnProperty(propName)) {
- continue;
- }
- var normalize = Interface[propName];
- if (normalize) {
- this[propName] = normalize(nativeEvent);
- } else {
- this[propName] = nativeEvent[propName];
- }
- }
-
- var defaultPrevented = nativeEvent.defaultPrevented != null ?
- nativeEvent.defaultPrevented :
- nativeEvent.returnValue === false;
- if (defaultPrevented) {
- this.isDefaultPrevented = emptyFunction.thatReturnsTrue;
- } else {
- this.isDefaultPrevented = emptyFunction.thatReturnsFalse;
- }
- this.isPropagationStopped = emptyFunction.thatReturnsFalse;
-}
-
-assign(SyntheticEvent.prototype, {
-
- preventDefault: function() {
- this.defaultPrevented = true;
- var event = this.nativeEvent;
- event.preventDefault ? event.preventDefault() : event.returnValue = false;
- this.isDefaultPrevented = emptyFunction.thatReturnsTrue;
- },
-
- stopPropagation: function() {
- var event = this.nativeEvent;
- event.stopPropagation ? event.stopPropagation() : event.cancelBubble = true;
- this.isPropagationStopped = emptyFunction.thatReturnsTrue;
- },
-
- /**
- * We release all dispatched `SyntheticEvent`s after each event loop, adding
- * them back into the pool. This allows a way to hold onto a reference that
- * won't be added back into the pool.
- */
- persist: function() {
- this.isPersistent = emptyFunction.thatReturnsTrue;
- },
-
- /**
- * Checks if this event should be released back into the pool.
- *
- * @return {boolean} True if this should not be released, false otherwise.
- */
- isPersistent: emptyFunction.thatReturnsFalse,
-
- /**
- * `PooledClass` looks for `destructor` on each instance it releases.
- */
- destructor: function() {
- var Interface = this.constructor.Interface;
- for (var propName in Interface) {
- this[propName] = null;
- }
- this.dispatchConfig = null;
- this.dispatchMarker = null;
- this.nativeEvent = null;
- }
-
-});
-
-SyntheticEvent.Interface = EventInterface;
-
-/**
- * Helper to reduce boilerplate when creating subclasses.
- *
- * @param {function} Class
- * @param {?object} Interface
- */
-SyntheticEvent.augmentClass = function(Class, Interface) {
- var Super = this;
-
- var prototype = Object.create(Super.prototype);
- assign(prototype, Class.prototype);
- Class.prototype = prototype;
- Class.prototype.constructor = Class;
-
- Class.Interface = assign({}, Super.Interface, Interface);
- Class.augmentClass = Super.augmentClass;
-
- PooledClass.addPoolingTo(Class, PooledClass.threeArgumentPooler);
-};
-
-PooledClass.addPoolingTo(SyntheticEvent, PooledClass.threeArgumentPooler);
-
-module.exports = SyntheticEvent;
-
-},{"./Object.assign":29,"./PooledClass":30,"./emptyFunction":121,"./getEventTarget":131}],100:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SyntheticFocusEvent
- * @typechecks static-only
- */
-
-"use strict";
-
-var SyntheticUIEvent = _dereq_("./SyntheticUIEvent");
-
-/**
- * @interface FocusEvent
- * @see http://www.w3.org/TR/DOM-Level-3-Events/
- */
-var FocusEventInterface = {
- relatedTarget: null
-};
-
-/**
- * @param {object} dispatchConfig Configuration used to dispatch this event.
- * @param {string} dispatchMarker Marker identifying the event target.
- * @param {object} nativeEvent Native browser event.
- * @extends {SyntheticUIEvent}
- */
-function SyntheticFocusEvent(dispatchConfig, dispatchMarker, nativeEvent) {
- SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
-}
-
-SyntheticUIEvent.augmentClass(SyntheticFocusEvent, FocusEventInterface);
-
-module.exports = SyntheticFocusEvent;
-
-},{"./SyntheticUIEvent":105}],101:[function(_dereq_,module,exports){
-/**
- * Copyright 2013 Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SyntheticInputEvent
- * @typechecks static-only
- */
-
-"use strict";
-
-var SyntheticEvent = _dereq_("./SyntheticEvent");
-
-/**
- * @interface Event
- * @see http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105
- * /#events-inputevents
- */
-var InputEventInterface = {
- data: null
-};
-
-/**
- * @param {object} dispatchConfig Configuration used to dispatch this event.
- * @param {string} dispatchMarker Marker identifying the event target.
- * @param {object} nativeEvent Native browser event.
- * @extends {SyntheticUIEvent}
- */
-function SyntheticInputEvent(
- dispatchConfig,
- dispatchMarker,
- nativeEvent) {
- SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
-}
-
-SyntheticEvent.augmentClass(
- SyntheticInputEvent,
- InputEventInterface
-);
-
-module.exports = SyntheticInputEvent;
-
-
-},{"./SyntheticEvent":99}],102:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SyntheticKeyboardEvent
- * @typechecks static-only
- */
-
-"use strict";
-
-var SyntheticUIEvent = _dereq_("./SyntheticUIEvent");
-
-var getEventCharCode = _dereq_("./getEventCharCode");
-var getEventKey = _dereq_("./getEventKey");
-var getEventModifierState = _dereq_("./getEventModifierState");
-
-/**
- * @interface KeyboardEvent
- * @see http://www.w3.org/TR/DOM-Level-3-Events/
- */
-var KeyboardEventInterface = {
- key: getEventKey,
- location: null,
- ctrlKey: null,
- shiftKey: null,
- altKey: null,
- metaKey: null,
- repeat: null,
- locale: null,
- getModifierState: getEventModifierState,
- // Legacy Interface
- charCode: function(event) {
- // `charCode` is the result of a KeyPress event and represents the value of
- // the actual printable character.
-
- // KeyPress is deprecated, but its replacement is not yet final and not
- // implemented in any major browser. Only KeyPress has charCode.
- if (event.type === 'keypress') {
- return getEventCharCode(event);
- }
- return 0;
- },
- keyCode: function(event) {
- // `keyCode` is the result of a KeyDown/Up event and represents the value of
- // physical keyboard key.
-
- // The actual meaning of the value depends on the users' keyboard layout
- // which cannot be detected. Assuming that it is a US keyboard layout
- // provides a surprisingly accurate mapping for US and European users.
- // Due to this, it is left to the user to implement at this time.
- if (event.type === 'keydown' || event.type === 'keyup') {
- return event.keyCode;
- }
- return 0;
- },
- which: function(event) {
- // `which` is an alias for either `keyCode` or `charCode` depending on the
- // type of the event.
- if (event.type === 'keypress') {
- return getEventCharCode(event);
- }
- if (event.type === 'keydown' || event.type === 'keyup') {
- return event.keyCode;
- }
- return 0;
- }
-};
-
-/**
- * @param {object} dispatchConfig Configuration used to dispatch this event.
- * @param {string} dispatchMarker Marker identifying the event target.
- * @param {object} nativeEvent Native browser event.
- * @extends {SyntheticUIEvent}
- */
-function SyntheticKeyboardEvent(dispatchConfig, dispatchMarker, nativeEvent) {
- SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
-}
-
-SyntheticUIEvent.augmentClass(SyntheticKeyboardEvent, KeyboardEventInterface);
-
-module.exports = SyntheticKeyboardEvent;
-
-},{"./SyntheticUIEvent":105,"./getEventCharCode":128,"./getEventKey":129,"./getEventModifierState":130}],103:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SyntheticMouseEvent
- * @typechecks static-only
- */
-
-"use strict";
-
-var SyntheticUIEvent = _dereq_("./SyntheticUIEvent");
-var ViewportMetrics = _dereq_("./ViewportMetrics");
-
-var getEventModifierState = _dereq_("./getEventModifierState");
-
-/**
- * @interface MouseEvent
- * @see http://www.w3.org/TR/DOM-Level-3-Events/
- */
-var MouseEventInterface = {
- screenX: null,
- screenY: null,
- clientX: null,
- clientY: null,
- ctrlKey: null,
- shiftKey: null,
- altKey: null,
- metaKey: null,
- getModifierState: getEventModifierState,
- button: function(event) {
- // Webkit, Firefox, IE9+
- // which: 1 2 3
- // button: 0 1 2 (standard)
- var button = event.button;
- if ('which' in event) {
- return button;
- }
- // IE<9
- // which: undefined
- // button: 0 0 0
- // button: 1 4 2 (onmouseup)
- return button === 2 ? 2 : button === 4 ? 1 : 0;
- },
- buttons: null,
- relatedTarget: function(event) {
- return event.relatedTarget || (
- event.fromElement === event.srcElement ?
- event.toElement :
- event.fromElement
- );
- },
- // "Proprietary" Interface.
- pageX: function(event) {
- return 'pageX' in event ?
- event.pageX :
- event.clientX + ViewportMetrics.currentScrollLeft;
- },
- pageY: function(event) {
- return 'pageY' in event ?
- event.pageY :
- event.clientY + ViewportMetrics.currentScrollTop;
- }
-};
-
-/**
- * @param {object} dispatchConfig Configuration used to dispatch this event.
- * @param {string} dispatchMarker Marker identifying the event target.
- * @param {object} nativeEvent Native browser event.
- * @extends {SyntheticUIEvent}
- */
-function SyntheticMouseEvent(dispatchConfig, dispatchMarker, nativeEvent) {
- SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
-}
-
-SyntheticUIEvent.augmentClass(SyntheticMouseEvent, MouseEventInterface);
-
-module.exports = SyntheticMouseEvent;
-
-},{"./SyntheticUIEvent":105,"./ViewportMetrics":108,"./getEventModifierState":130}],104:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SyntheticTouchEvent
- * @typechecks static-only
- */
-
-"use strict";
-
-var SyntheticUIEvent = _dereq_("./SyntheticUIEvent");
-
-var getEventModifierState = _dereq_("./getEventModifierState");
-
-/**
- * @interface TouchEvent
- * @see http://www.w3.org/TR/touch-events/
- */
-var TouchEventInterface = {
- touches: null,
- targetTouches: null,
- changedTouches: null,
- altKey: null,
- metaKey: null,
- ctrlKey: null,
- shiftKey: null,
- getModifierState: getEventModifierState
-};
-
-/**
- * @param {object} dispatchConfig Configuration used to dispatch this event.
- * @param {string} dispatchMarker Marker identifying the event target.
- * @param {object} nativeEvent Native browser event.
- * @extends {SyntheticUIEvent}
- */
-function SyntheticTouchEvent(dispatchConfig, dispatchMarker, nativeEvent) {
- SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
-}
-
-SyntheticUIEvent.augmentClass(SyntheticTouchEvent, TouchEventInterface);
-
-module.exports = SyntheticTouchEvent;
-
-},{"./SyntheticUIEvent":105,"./getEventModifierState":130}],105:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SyntheticUIEvent
- * @typechecks static-only
- */
-
-"use strict";
-
-var SyntheticEvent = _dereq_("./SyntheticEvent");
-
-var getEventTarget = _dereq_("./getEventTarget");
-
-/**
- * @interface UIEvent
- * @see http://www.w3.org/TR/DOM-Level-3-Events/
- */
-var UIEventInterface = {
- view: function(event) {
- if (event.view) {
- return event.view;
- }
-
- var target = getEventTarget(event);
- if (target != null && target.window === target) {
- // target is a window object
- return target;
- }
-
- var doc = target.ownerDocument;
- // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.
- if (doc) {
- return doc.defaultView || doc.parentWindow;
- } else {
- return window;
- }
- },
- detail: function(event) {
- return event.detail || 0;
- }
-};
-
-/**
- * @param {object} dispatchConfig Configuration used to dispatch this event.
- * @param {string} dispatchMarker Marker identifying the event target.
- * @param {object} nativeEvent Native browser event.
- * @extends {SyntheticEvent}
- */
-function SyntheticUIEvent(dispatchConfig, dispatchMarker, nativeEvent) {
- SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
-}
-
-SyntheticEvent.augmentClass(SyntheticUIEvent, UIEventInterface);
-
-module.exports = SyntheticUIEvent;
-
-},{"./SyntheticEvent":99,"./getEventTarget":131}],106:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SyntheticWheelEvent
- * @typechecks static-only
- */
-
-"use strict";
-
-var SyntheticMouseEvent = _dereq_("./SyntheticMouseEvent");
-
-/**
- * @interface WheelEvent
- * @see http://www.w3.org/TR/DOM-Level-3-Events/
- */
-var WheelEventInterface = {
- deltaX: function(event) {
- return (
- 'deltaX' in event ? event.deltaX :
- // Fallback to `wheelDeltaX` for Webkit and normalize (right is positive).
- 'wheelDeltaX' in event ? -event.wheelDeltaX : 0
- );
- },
- deltaY: function(event) {
- return (
- 'deltaY' in event ? event.deltaY :
- // Fallback to `wheelDeltaY` for Webkit and normalize (down is positive).
- 'wheelDeltaY' in event ? -event.wheelDeltaY :
- // Fallback to `wheelDelta` for IE<9 and normalize (down is positive).
- 'wheelDelta' in event ? -event.wheelDelta : 0
- );
- },
- deltaZ: null,
-
- // Browsers without "deltaMode" is reporting in raw wheel delta where one
- // notch on the scroll is always +/- 120, roughly equivalent to pixels.
- // A good approximation of DOM_DELTA_LINE (1) is 5% of viewport size or
- // ~40 pixels, for DOM_DELTA_SCREEN (2) it is 87.5% of viewport size.
- deltaMode: null
-};
-
-/**
- * @param {object} dispatchConfig Configuration used to dispatch this event.
- * @param {string} dispatchMarker Marker identifying the event target.
- * @param {object} nativeEvent Native browser event.
- * @extends {SyntheticMouseEvent}
- */
-function SyntheticWheelEvent(dispatchConfig, dispatchMarker, nativeEvent) {
- SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
-}
-
-SyntheticMouseEvent.augmentClass(SyntheticWheelEvent, WheelEventInterface);
-
-module.exports = SyntheticWheelEvent;
-
-},{"./SyntheticMouseEvent":103}],107:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule Transaction
- */
-
-"use strict";
-
-var invariant = _dereq_("./invariant");
-
-/**
- * `Transaction` creates a black box that is able to wrap any method such that
- * certain invariants are maintained before and after the method is invoked
- * (Even if an exception is thrown while invoking the wrapped method). Whoever
- * instantiates a transaction can provide enforcers of the invariants at
- * creation time. The `Transaction` class itself will supply one additional
- * automatic invariant for you - the invariant that any transaction instance
- * should not be run while it is already being run. You would typically create a
- * single instance of a `Transaction` for reuse multiple times, that potentially
- * is used to wrap several different methods. Wrappers are extremely simple -
- * they only require implementing two methods.
- *
- * <pre>
- * wrappers (injected at creation time)
- * + +
- * | |
- * +-----------------|--------|--------------+
- * | v | |
- * | +---------------+ | |
- * | +--| wrapper1 |---|----+ |
- * | | +---------------+ v | |
- * | | +-------------+ | |
- * | | +----| wrapper2 |--------+ |
- * | | | +-------------+ | | |
- * | | | | | |
- * | v v v v | wrapper
- * | +---+ +---+ +---------+ +---+ +---+ | invariants
- * perform(anyMethod) | | | | | | | | | | | | maintained
- * +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|-------->
- * | | | | | | | | | | | |
- * | | | | | | | | | | | |
- * | | | | | | | | | | | |
- * | +---+ +---+ +---------+ +---+ +---+ |
- * | initialize close |
- * +-----------------------------------------+
- * </pre>
- *
- * Use cases:
- * - Preserving the input selection ranges before/after reconciliation.
- * Restoring selection even in the event of an unexpected error.
- * - Deactivating events while rearranging the DOM, preventing blurs/focuses,
- * while guaranteeing that afterwards, the event system is reactivated.
- * - Flushing a queue of collected DOM mutations to the main UI thread after a
- * reconciliation takes place in a worker thread.
- * - Invoking any collected `componentDidUpdate` callbacks after rendering new
- * content.
- * - (Future use case): Wrapping particular flushes of the `ReactWorker` queue
- * to preserve the `scrollTop` (an automatic scroll aware DOM).
- * - (Future use case): Layout calculations before and after DOM upates.
- *
- * Transactional plugin API:
- * - A module that has an `initialize` method that returns any precomputation.
- * - and a `close` method that accepts the precomputation. `close` is invoked
- * when the wrapped process is completed, or has failed.
- *
- * @param {Array<TransactionalWrapper>} transactionWrapper Wrapper modules
- * that implement `initialize` and `close`.
- * @return {Transaction} Single transaction for reuse in thread.
- *
- * @class Transaction
- */
-var Mixin = {
- /**
- * Sets up this instance so that it is prepared for collecting metrics. Does
- * so such that this setup method may be used on an instance that is already
- * initialized, in a way that does not consume additional memory upon reuse.
- * That can be useful if you decide to make your subclass of this mixin a
- * "PooledClass".
- */
- reinitializeTransaction: function() {
- this.transactionWrappers = this.getTransactionWrappers();
- if (!this.wrapperInitData) {
- this.wrapperInitData = [];
- } else {
- this.wrapperInitData.length = 0;
- }
- this._isInTransaction = false;
- },
-
- _isInTransaction: false,
-
- /**
- * @abstract
- * @return {Array<TransactionWrapper>} Array of transaction wrappers.
- */
- getTransactionWrappers: null,
-
- isInTransaction: function() {
- return !!this._isInTransaction;
- },
-
- /**
- * Executes the function within a safety window. Use this for the top level
- * methods that result in large amounts of computation/mutations that would
- * need to be safety checked.
- *
- * @param {function} method Member of scope to call.
- * @param {Object} scope Scope to invoke from.
- * @param {Object?=} args... Arguments to pass to the method (optional).
- * Helps prevent need to bind in many cases.
- * @return Return value from `method`.
- */
- perform: function(method, scope, a, b, c, d, e, f) {
- ("production" !== "development" ? invariant(
- !this.isInTransaction(),
- 'Transaction.perform(...): Cannot initialize a transaction when there ' +
- 'is already an outstanding transaction.'
- ) : invariant(!this.isInTransaction()));
- var errorThrown;
- var ret;
- try {
- this._isInTransaction = true;
- // Catching errors makes debugging more difficult, so we start with
- // errorThrown set to true before setting it to false after calling
- // close -- if it's still set to true in the finally block, it means
- // one of these calls threw.
- errorThrown = true;
- this.initializeAll(0);
- ret = method.call(scope, a, b, c, d, e, f);
- errorThrown = false;
- } finally {
- try {
- if (errorThrown) {
- // If `method` throws, prefer to show that stack trace over any thrown
- // by invoking `closeAll`.
- try {
- this.closeAll(0);
- } catch (err) {
- }
- } else {
- // Since `method` didn't throw, we don't want to silence the exception
- // here.
- this.closeAll(0);
- }
- } finally {
- this._isInTransaction = false;
- }
- }
- return ret;
- },
-
- initializeAll: function(startIndex) {
- var transactionWrappers = this.transactionWrappers;
- for (var i = startIndex; i < transactionWrappers.length; i++) {
- var wrapper = transactionWrappers[i];
- try {
- // Catching errors makes debugging more difficult, so we start with the
- // OBSERVED_ERROR state before overwriting it with the real return value
- // of initialize -- if it's still set to OBSERVED_ERROR in the finally
- // block, it means wrapper.initialize threw.
- this.wrapperInitData[i] = Transaction.OBSERVED_ERROR;
- this.wrapperInitData[i] = wrapper.initialize ?
- wrapper.initialize.call(this) :
- null;
- } finally {
- if (this.wrapperInitData[i] === Transaction.OBSERVED_ERROR) {
- // The initializer for wrapper i threw an error; initialize the
- // remaining wrappers but silence any exceptions from them to ensure
- // that the first error is the one to bubble up.
- try {
- this.initializeAll(i + 1);
- } catch (err) {
- }
- }
- }
- }
- },
-
- /**
- * Invokes each of `this.transactionWrappers.close[i]` functions, passing into
- * them the respective return values of `this.transactionWrappers.init[i]`
- * (`close`rs that correspond to initializers that failed will not be
- * invoked).
- */
- closeAll: function(startIndex) {
- ("production" !== "development" ? invariant(
- this.isInTransaction(),
- 'Transaction.closeAll(): Cannot close transaction when none are open.'
- ) : invariant(this.isInTransaction()));
- var transactionWrappers = this.transactionWrappers;
- for (var i = startIndex; i < transactionWrappers.length; i++) {
- var wrapper = transactionWrappers[i];
- var initData = this.wrapperInitData[i];
- var errorThrown;
- try {
- // Catching errors makes debugging more difficult, so we start with
- // errorThrown set to true before setting it to false after calling
- // close -- if it's still set to true in the finally block, it means
- // wrapper.close threw.
- errorThrown = true;
- if (initData !== Transaction.OBSERVED_ERROR) {
- wrapper.close && wrapper.close.call(this, initData);
- }
- errorThrown = false;
- } finally {
- if (errorThrown) {
- // The closer for wrapper i threw an error; close the remaining
- // wrappers but silence any exceptions from them to ensure that the
- // first error is the one to bubble up.
- try {
- this.closeAll(i + 1);
- } catch (e) {
- }
- }
- }
- }
- this.wrapperInitData.length = 0;
- }
-};
-
-var Transaction = {
-
- Mixin: Mixin,
-
- /**
- * Token to look for to determine if an error occured.
- */
- OBSERVED_ERROR: {}
-
-};
-
-module.exports = Transaction;
-
-},{"./invariant":140}],108:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ViewportMetrics
- */
-
-"use strict";
-
-var getUnboundedScrollPosition = _dereq_("./getUnboundedScrollPosition");
-
-var ViewportMetrics = {
-
- currentScrollLeft: 0,
-
- currentScrollTop: 0,
-
- refreshScrollValues: function() {
- var scrollPosition = getUnboundedScrollPosition(window);
- ViewportMetrics.currentScrollLeft = scrollPosition.x;
- ViewportMetrics.currentScrollTop = scrollPosition.y;
- }
-
-};
-
-module.exports = ViewportMetrics;
-
-},{"./getUnboundedScrollPosition":136}],109:[function(_dereq_,module,exports){
-/**
- * Copyright 2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule accumulateInto
- */
-
-"use strict";
-
-var invariant = _dereq_("./invariant");
-
-/**
- *
- * Accumulates items that must not be null or undefined into the first one. This
- * is used to conserve memory by avoiding array allocations, and thus sacrifices
- * API cleanness. Since `current` can be null before being passed in and not
- * null after this function, make sure to assign it back to `current`:
- *
- * `a = accumulateInto(a, b);`
- *
- * This API should be sparingly used. Try `accumulate` for something cleaner.
- *
- * @return {*|array<*>} An accumulation of items.
- */
-
-function accumulateInto(current, next) {
- ("production" !== "development" ? invariant(
- next != null,
- 'accumulateInto(...): Accumulated items must not be null or undefined.'
- ) : invariant(next != null));
- if (current == null) {
- return next;
- }
-
- // Both are not empty. Warning: Never call x.concat(y) when you are not
- // certain that x is an Array (x could be a string with concat method).
- var currentIsArray = Array.isArray(current);
- var nextIsArray = Array.isArray(next);
-
- if (currentIsArray && nextIsArray) {
- current.push.apply(current, next);
- return current;
- }
-
- if (currentIsArray) {
- current.push(next);
- return current;
- }
-
- if (nextIsArray) {
- // A bit too dangerous to mutate `next`.
- return [current].concat(next);
- }
-
- return [current, next];
-}
-
-module.exports = accumulateInto;
-
-},{"./invariant":140}],110:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule adler32
- */
-
-/* jslint bitwise:true */
-
-"use strict";
-
-var MOD = 65521;
-
-// This is a clean-room implementation of adler32 designed for detecting
-// if markup is not what we expect it to be. It does not need to be
-// cryptographically strong, only reasonably good at detecting if markup
-// generated on the server is different than that on the client.
-function adler32(data) {
- var a = 1;
- var b = 0;
- for (var i = 0; i < data.length; i++) {
- a = (a + data.charCodeAt(i)) % MOD;
- b = (b + a) % MOD;
- }
- return a | (b << 16);
-}
-
-module.exports = adler32;
-
-},{}],111:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule camelize
- * @typechecks
- */
-
-var _hyphenPattern = /-(.)/g;
-
-/**
- * Camelcases a hyphenated string, for example:
- *
- * > camelize('background-color')
- * < "backgroundColor"
- *
- * @param {string} string
- * @return {string}
- */
-function camelize(string) {
- return string.replace(_hyphenPattern, function(_, character) {
- return character.toUpperCase();
- });
-}
-
-module.exports = camelize;
-
-},{}],112:[function(_dereq_,module,exports){
-/**
- * Copyright 2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule camelizeStyleName
- * @typechecks
- */
-
-"use strict";
-
-var camelize = _dereq_("./camelize");
-
-var msPattern = /^-ms-/;
-
-/**
- * Camelcases a hyphenated CSS property name, for example:
- *
- * > camelizeStyleName('background-color')
- * < "backgroundColor"
- * > camelizeStyleName('-moz-transition')
- * < "MozTransition"
- * > camelizeStyleName('-ms-transition')
- * < "msTransition"
- *
- * As Andi Smith suggests
- * (http://www.andismith.com/blog/2012/02/modernizr-prefixed/), an `-ms` prefix
- * is converted to lowercase `ms`.
- *
- * @param {string} string
- * @return {string}
- */
-function camelizeStyleName(string) {
- return camelize(string.replace(msPattern, 'ms-'));
-}
-
-module.exports = camelizeStyleName;
-
-},{"./camelize":111}],113:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @typechecks
- * @providesModule cloneWithProps
- */
-
-"use strict";
-
-var ReactElement = _dereq_("./ReactElement");
-var ReactPropTransferer = _dereq_("./ReactPropTransferer");
-
-var keyOf = _dereq_("./keyOf");
-var warning = _dereq_("./warning");
-
-var CHILDREN_PROP = keyOf({children: null});
-
-/**
- * Sometimes you want to change the props of a child passed to you. Usually
- * this is to add a CSS class.
- *
- * @param {object} child child component you'd like to clone
- * @param {object} props props you'd like to modify. They will be merged
- * as if you used `transferPropsTo()`.
- * @return {object} a clone of child with props merged in.
- */
-function cloneWithProps(child, props) {
- if ("production" !== "development") {
- ("production" !== "development" ? warning(
- !child.ref,
- 'You are calling cloneWithProps() on a child with a ref. This is ' +
- 'dangerous because you\'re creating a new child which will not be ' +
- 'added as a ref to its parent.'
- ) : null);
- }
-
- var newProps = ReactPropTransferer.mergeProps(props, child.props);
-
- // Use `child.props.children` if it is provided.
- if (!newProps.hasOwnProperty(CHILDREN_PROP) &&
- child.props.hasOwnProperty(CHILDREN_PROP)) {
- newProps.children = child.props.children;
- }
-
- // The current API doesn't retain _owner and _context, which is why this
- // doesn't use ReactElement.cloneAndReplaceProps.
- return ReactElement.createElement(child.type, newProps);
-}
-
-module.exports = cloneWithProps;
-
-},{"./ReactElement":58,"./ReactPropTransferer":76,"./keyOf":147,"./warning":160}],114:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule containsNode
- * @typechecks
- */
-
-var isTextNode = _dereq_("./isTextNode");
-
-/*jslint bitwise:true */
-
-/**
- * Checks if a given DOM node contains or is another DOM node.
- *
- * @param {?DOMNode} outerNode Outer DOM node.
- * @param {?DOMNode} innerNode Inner DOM node.
- * @return {boolean} True if `outerNode` contains or is `innerNode`.
- */
-function containsNode(outerNode, innerNode) {
- if (!outerNode || !innerNode) {
- return false;
- } else if (outerNode === innerNode) {
- return true;
- } else if (isTextNode(outerNode)) {
- return false;
- } else if (isTextNode(innerNode)) {
- return containsNode(outerNode, innerNode.parentNode);
- } else if (outerNode.contains) {
- return outerNode.contains(innerNode);
- } else if (outerNode.compareDocumentPosition) {
- return !!(outerNode.compareDocumentPosition(innerNode) & 16);
- } else {
- return false;
- }
-}
-
-module.exports = containsNode;
-
-},{"./isTextNode":144}],115:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule createArrayFrom
- * @typechecks
- */
-
-var toArray = _dereq_("./toArray");
-
-/**
- * Perform a heuristic test to determine if an object is "array-like".
- *
- * A monk asked Joshu, a Zen master, "Has a dog Buddha nature?"
- * Joshu replied: "Mu."
- *
- * This function determines if its argument has "array nature": it returns
- * true if the argument is an actual array, an `arguments' object, or an
- * HTMLCollection (e.g. node.childNodes or node.getElementsByTagName()).
- *
- * It will return false for other array-like objects like Filelist.
- *
- * @param {*} obj
- * @return {boolean}
- */
-function hasArrayNature(obj) {
- return (
- // not null/false
- !!obj &&
- // arrays are objects, NodeLists are functions in Safari
- (typeof obj == 'object' || typeof obj == 'function') &&
- // quacks like an array
- ('length' in obj) &&
- // not window
- !('setInterval' in obj) &&
- // no DOM node should be considered an array-like
- // a 'select' element has 'length' and 'item' properties on IE8
- (typeof obj.nodeType != 'number') &&
- (
- // a real array
- (// HTMLCollection/NodeList
- (Array.isArray(obj) ||
- // arguments
- ('callee' in obj) || 'item' in obj))
- )
- );
-}
-
-/**
- * Ensure that the argument is an array by wrapping it in an array if it is not.
- * Creates a copy of the argument if it is already an array.
- *
- * This is mostly useful idiomatically:
- *
- * var createArrayFrom = require('createArrayFrom');
- *
- * function takesOneOrMoreThings(things) {
- * things = createArrayFrom(things);
- * ...
- * }
- *
- * This allows you to treat `things' as an array, but accept scalars in the API.
- *
- * If you need to convert an array-like object, like `arguments`, into an array
- * use toArray instead.
- *
- * @param {*} obj
- * @return {array}
- */
-function createArrayFrom(obj) {
- if (!hasArrayNature(obj)) {
- return [obj];
- } else if (Array.isArray(obj)) {
- return obj.slice();
- } else {
- return toArray(obj);
- }
-}
-
-module.exports = createArrayFrom;
-
-},{"./toArray":157}],116:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule createFullPageComponent
- * @typechecks
- */
-
-"use strict";
-
-// Defeat circular references by requiring this directly.
-var ReactCompositeComponent = _dereq_("./ReactCompositeComponent");
-var ReactElement = _dereq_("./ReactElement");
-
-var invariant = _dereq_("./invariant");
-
-/**
- * Create a component that will throw an exception when unmounted.
- *
- * Components like <html> <head> and <body> can't be removed or added
- * easily in a cross-browser way, however it's valuable to be able to
- * take advantage of React's reconciliation for styling and <title>
- * management. So we just document it and throw in dangerous cases.
- *
- * @param {string} tag The tag to wrap
- * @return {function} convenience constructor of new component
- */
-function createFullPageComponent(tag) {
- var elementFactory = ReactElement.createFactory(tag);
-
- var FullPageComponent = ReactCompositeComponent.createClass({
- displayName: 'ReactFullPageComponent' + tag,
-
- componentWillUnmount: function() {
- ("production" !== "development" ? invariant(
- false,
- '%s tried to unmount. Because of cross-browser quirks it is ' +
- 'impossible to unmount some top-level components (eg <html>, <head>, ' +
- 'and <body>) reliably and efficiently. To fix this, have a single ' +
- 'top-level component that never unmounts render these elements.',
- this.constructor.displayName
- ) : invariant(false));
- },
-
- render: function() {
- return elementFactory(this.props);
- }
- });
-
- return FullPageComponent;
-}
-
-module.exports = createFullPageComponent;
-
-},{"./ReactCompositeComponent":40,"./ReactElement":58,"./invariant":140}],117:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule createNodesFromMarkup
- * @typechecks
- */
-
-/*jslint evil: true, sub: true */
-
-var ExecutionEnvironment = _dereq_("./ExecutionEnvironment");
-
-var createArrayFrom = _dereq_("./createArrayFrom");
-var getMarkupWrap = _dereq_("./getMarkupWrap");
-var invariant = _dereq_("./invariant");
-
-/**
- * Dummy container used to render all markup.
- */
-var dummyNode =
- ExecutionEnvironment.canUseDOM ? document.createElement('div') : null;
-
-/**
- * Pattern used by `getNodeName`.
- */
-var nodeNamePattern = /^\s*<(\w+)/;
-
-/**
- * Extracts the `nodeName` of the first element in a string of markup.
- *
- * @param {string} markup String of markup.
- * @return {?string} Node name of the supplied markup.
- */
-function getNodeName(markup) {
- var nodeNameMatch = markup.match(nodeNamePattern);
- return nodeNameMatch && nodeNameMatch[1].toLowerCase();
-}
-
-/**
- * Creates an array containing the nodes rendered from the supplied markup. The
- * optionally supplied `handleScript` function will be invoked once for each
- * <script> element that is rendered. If no `handleScript` function is supplied,
- * an exception is thrown if any <script> elements are rendered.
- *
- * @param {string} markup A string of valid HTML markup.
- * @param {?function} handleScript Invoked once for each rendered <script>.
- * @return {array<DOMElement|DOMTextNode>} An array of rendered nodes.
- */
-function createNodesFromMarkup(markup, handleScript) {
- var node = dummyNode;
- ("production" !== "development" ? invariant(!!dummyNode, 'createNodesFromMarkup dummy not initialized') : invariant(!!dummyNode));
- var nodeName = getNodeName(markup);
-
- var wrap = nodeName && getMarkupWrap(nodeName);
- if (wrap) {
- node.innerHTML = wrap[1] + markup + wrap[2];
-
- var wrapDepth = wrap[0];
- while (wrapDepth--) {
- node = node.lastChild;
- }
- } else {
- node.innerHTML = markup;
- }
-
- var scripts = node.getElementsByTagName('script');
- if (scripts.length) {
- ("production" !== "development" ? invariant(
- handleScript,
- 'createNodesFromMarkup(...): Unexpected <script> element rendered.'
- ) : invariant(handleScript));
- createArrayFrom(scripts).forEach(handleScript);
- }
-
- var nodes = createArrayFrom(node.childNodes);
- while (node.lastChild) {
- node.removeChild(node.lastChild);
- }
- return nodes;
-}
-
-module.exports = createNodesFromMarkup;
-
-},{"./ExecutionEnvironment":23,"./createArrayFrom":115,"./getMarkupWrap":132,"./invariant":140}],118:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule cx
- */
-
-/**
- * This function is used to mark string literals representing CSS class names
- * so that they can be transformed statically. This allows for modularization
- * and minification of CSS class names.
- *
- * In static_upstream, this function is actually implemented, but it should
- * eventually be replaced with something more descriptive, and the transform
- * that is used in the main stack should be ported for use elsewhere.
- *
- * @param string|object className to modularize, or an object of key/values.
- * In the object case, the values are conditions that
- * determine if the className keys should be included.
- * @param [string ...] Variable list of classNames in the string case.
- * @return string Renderable space-separated CSS className.
- */
-function cx(classNames) {
- if (typeof classNames == 'object') {
- return Object.keys(classNames).filter(function(className) {
- return classNames[className];
- }).join(' ');
- } else {
- return Array.prototype.join.call(arguments, ' ');
- }
-}
-
-module.exports = cx;
-
-},{}],119:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule dangerousStyleValue
- * @typechecks static-only
- */
-
-"use strict";
-
-var CSSProperty = _dereq_("./CSSProperty");
-
-var isUnitlessNumber = CSSProperty.isUnitlessNumber;
-
-/**
- * Convert a value into the proper css writable value. The style name `name`
- * should be logical (no hyphens), as specified
- * in `CSSProperty.isUnitlessNumber`.
- *
- * @param {string} name CSS property name such as `topMargin`.
- * @param {*} value CSS property value such as `10px`.
- * @return {string} Normalized style value with dimensions applied.
- */
-function dangerousStyleValue(name, value) {
- // Note that we've removed escapeTextForBrowser() calls here since the
- // whole string will be escaped when the attribute is injected into
- // the markup. If you provide unsafe user data here they can inject
- // arbitrary CSS which may be problematic (I couldn't repro this):
- // https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
- // http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/
- // This is not an XSS hole but instead a potential CSS injection issue
- // which has lead to a greater discussion about how we're going to
- // trust URLs moving forward. See #2115901
-
- var isEmpty = value == null || typeof value === 'boolean' || value === '';
- if (isEmpty) {
- return '';
- }
-
- var isNonNumeric = isNaN(value);
- if (isNonNumeric || value === 0 ||
- isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name]) {
- return '' + value; // cast to string
- }
-
- if (typeof value === 'string') {
- value = value.trim();
- }
- return value + 'px';
-}
-
-module.exports = dangerousStyleValue;
-
-},{"./CSSProperty":5}],120:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule deprecated
- */
-
-var assign = _dereq_("./Object.assign");
-var warning = _dereq_("./warning");
-
-/**
- * This will log a single deprecation notice per function and forward the call
- * on to the new API.
- *
- * @param {string} namespace The namespace of the call, eg 'React'
- * @param {string} oldName The old function name, eg 'renderComponent'
- * @param {string} newName The new function name, eg 'render'
- * @param {*} ctx The context this forwarded call should run in
- * @param {function} fn The function to forward on to
- * @return {*} Will be the value as returned from `fn`
- */
-function deprecated(namespace, oldName, newName, ctx, fn) {
- var warned = false;
- if ("production" !== "development") {
- var newFn = function() {
- ("production" !== "development" ? warning(
- warned,
- (namespace + "." + oldName + " will be deprecated in a future version. ") +
- ("Use " + namespace + "." + newName + " instead.")
- ) : null);
- warned = true;
- return fn.apply(ctx, arguments);
- };
- newFn.displayName = (namespace + "_" + oldName);
- // We need to make sure all properties of the original fn are copied over.
- // In particular, this is needed to support PropTypes
- return assign(newFn, fn);
- }
-
- return fn;
-}
-
-module.exports = deprecated;
-
-},{"./Object.assign":29,"./warning":160}],121:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule emptyFunction
- */
-
-function makeEmptyFunction(arg) {
- return function() {
- return arg;
- };
-}
-
-/**
- * This function accepts and discards inputs; it has no side effects. This is
- * primarily useful idiomatically for overridable function endpoints which
- * always need to be callable, since JS lacks a null-call idiom ala Cocoa.
- */
-function emptyFunction() {}
-
-emptyFunction.thatReturns = makeEmptyFunction;
-emptyFunction.thatReturnsFalse = makeEmptyFunction(false);
-emptyFunction.thatReturnsTrue = makeEmptyFunction(true);
-emptyFunction.thatReturnsNull = makeEmptyFunction(null);
-emptyFunction.thatReturnsThis = function() { return this; };
-emptyFunction.thatReturnsArgument = function(arg) { return arg; };
-
-module.exports = emptyFunction;
-
-},{}],122:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule emptyObject
- */
-
-"use strict";
-
-var emptyObject = {};
-
-if ("production" !== "development") {
- Object.freeze(emptyObject);
-}
-
-module.exports = emptyObject;
-
-},{}],123:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule escapeTextForBrowser
- * @typechecks static-only
- */
-
-"use strict";
-
-var ESCAPE_LOOKUP = {
- "&": "&amp;",
- ">": "&gt;",
- "<": "&lt;",
- "\"": "&quot;",
- "'": "&#x27;"
-};
-
-var ESCAPE_REGEX = /[&><"']/g;
-
-function escaper(match) {
- return ESCAPE_LOOKUP[match];
-}
-
-/**
- * Escapes text to prevent scripting attacks.
- *
- * @param {*} text Text value to escape.
- * @return {string} An escaped string.
- */
-function escapeTextForBrowser(text) {
- return ('' + text).replace(ESCAPE_REGEX, escaper);
-}
-
-module.exports = escapeTextForBrowser;
-
-},{}],124:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule flattenChildren
- */
-
-"use strict";
-
-var ReactTextComponent = _dereq_("./ReactTextComponent");
-
-var traverseAllChildren = _dereq_("./traverseAllChildren");
-var warning = _dereq_("./warning");
-
-/**
- * @param {function} traverseContext Context passed through traversal.
- * @param {?ReactComponent} child React child component.
- * @param {!string} name String name of key path to child.
- */
-function flattenSingleChildIntoContext(traverseContext, child, name) {
- // We found a component instance.
- var result = traverseContext;
- var keyUnique = !result.hasOwnProperty(name);
- ("production" !== "development" ? warning(
- keyUnique,
- 'flattenChildren(...): Encountered two children with the same key, ' +
- '`%s`. Child keys must be unique; when two children share a key, only ' +
- 'the first child will be used.',
- name
- ) : null);
- if (keyUnique && child != null) {
- var type = typeof child;
- var normalizedValue;
-
- if (type === 'string') {
- normalizedValue = ReactTextComponent(child);
- } else if (type === 'number') {
- normalizedValue = ReactTextComponent('' + child);
- } else {
- normalizedValue = child;
- }
-
- result[name] = normalizedValue;
- }
-}
-
-/**
- * Flattens children that are typically specified as `props.children`. Any null
- * children will not be included in the resulting object.
- * @return {!object} flattened children keyed by name.
- */
-function flattenChildren(children) {
- if (children == null) {
- return children;
- }
- var result = {};
- traverseAllChildren(children, flattenSingleChildIntoContext, result);
- return result;
-}
-
-module.exports = flattenChildren;
-
-},{"./ReactTextComponent":87,"./traverseAllChildren":158,"./warning":160}],125:[function(_dereq_,module,exports){
-/**
- * Copyright 2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule focusNode
- */
-
-"use strict";
-
-/**
- * @param {DOMElement} node input/textarea to focus
- */
-function focusNode(node) {
- // IE8 can throw "Can't move focus to the control because it is invisible,
- // not enabled, or of a type that does not accept the focus." for all kinds of
- // reasons that are too expensive and fragile to test.
- try {
- node.focus();
- } catch(e) {
- }
-}
-
-module.exports = focusNode;
-
-},{}],126:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule forEachAccumulated
- */
-
-"use strict";
-
-/**
- * @param {array} an "accumulation" of items which is either an Array or
- * a single item. Useful when paired with the `accumulate` module. This is a
- * simple utility that allows us to reason about a collection of items, but
- * handling the case when there is exactly one item (and we do not need to
- * allocate an array).
- */
-var forEachAccumulated = function(arr, cb, scope) {
- if (Array.isArray(arr)) {
- arr.forEach(cb, scope);
- } else if (arr) {
- cb.call(scope, arr);
- }
-};
-
-module.exports = forEachAccumulated;
-
-},{}],127:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule getActiveElement
- * @typechecks
- */
-
-/**
- * Same as document.activeElement but wraps in a try-catch block. In IE it is
- * not safe to call document.activeElement if there is nothing focused.
- *
- * The activeElement will be null only if the document body is not yet defined.
- */
-function getActiveElement() /*?DOMElement*/ {
- try {
- return document.activeElement || document.body;
- } catch (e) {
- return document.body;
- }
-}
-
-module.exports = getActiveElement;
-
-},{}],128:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule getEventCharCode
- * @typechecks static-only
- */
-
-"use strict";
-
-/**
- * `charCode` represents the actual "character code" and is safe to use with
- * `String.fromCharCode`. As such, only keys that correspond to printable
- * characters produce a valid `charCode`, the only exception to this is Enter.
- * The Tab-key is considered non-printable and does not have a `charCode`,
- * presumably because it does not produce a tab-character in browsers.
- *
- * @param {object} nativeEvent Native browser event.
- * @return {string} Normalized `charCode` property.
- */
-function getEventCharCode(nativeEvent) {
- var charCode;
- var keyCode = nativeEvent.keyCode;
-
- if ('charCode' in nativeEvent) {
- charCode = nativeEvent.charCode;
-
- // FF does not set `charCode` for the Enter-key, check against `keyCode`.
- if (charCode === 0 && keyCode === 13) {
- charCode = 13;
- }
- } else {
- // IE8 does not implement `charCode`, but `keyCode` has the correct value.
- charCode = keyCode;
- }
-
- // Some non-printable keys are reported in `charCode`/`keyCode`, discard them.
- // Must not discard the (non-)printable Enter-key.
- if (charCode >= 32 || charCode === 13) {
- return charCode;
- }
-
- return 0;
-}
-
-module.exports = getEventCharCode;
-
-},{}],129:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule getEventKey
- * @typechecks static-only
- */
-
-"use strict";
-
-var getEventCharCode = _dereq_("./getEventCharCode");
-
-/**
- * Normalization of deprecated HTML5 `key` values
- * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names
- */
-var normalizeKey = {
- 'Esc': 'Escape',
- 'Spacebar': ' ',
- 'Left': 'ArrowLeft',
- 'Up': 'ArrowUp',
- 'Right': 'ArrowRight',
- 'Down': 'ArrowDown',
- 'Del': 'Delete',
- 'Win': 'OS',
- 'Menu': 'ContextMenu',
- 'Apps': 'ContextMenu',
- 'Scroll': 'ScrollLock',
- 'MozPrintableKey': 'Unidentified'
-};
-
-/**
- * Translation from legacy `keyCode` to HTML5 `key`
- * Only special keys supported, all others depend on keyboard layout or browser
- * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names
- */
-var translateToKey = {
- 8: 'Backspace',
- 9: 'Tab',
- 12: 'Clear',
- 13: 'Enter',
- 16: 'Shift',
- 17: 'Control',
- 18: 'Alt',
- 19: 'Pause',
- 20: 'CapsLock',
- 27: 'Escape',
- 32: ' ',
- 33: 'PageUp',
- 34: 'PageDown',
- 35: 'End',
- 36: 'Home',
- 37: 'ArrowLeft',
- 38: 'ArrowUp',
- 39: 'ArrowRight',
- 40: 'ArrowDown',
- 45: 'Insert',
- 46: 'Delete',
- 112: 'F1', 113: 'F2', 114: 'F3', 115: 'F4', 116: 'F5', 117: 'F6',
- 118: 'F7', 119: 'F8', 120: 'F9', 121: 'F10', 122: 'F11', 123: 'F12',
- 144: 'NumLock',
- 145: 'ScrollLock',
- 224: 'Meta'
-};
-
-/**
- * @param {object} nativeEvent Native browser event.
- * @return {string} Normalized `key` property.
- */
-function getEventKey(nativeEvent) {
- if (nativeEvent.key) {
- // Normalize inconsistent values reported by browsers due to
- // implementations of a working draft specification.
-
- // FireFox implements `key` but returns `MozPrintableKey` for all
- // printable characters (normalized to `Unidentified`), ignore it.
- var key = normalizeKey[nativeEvent.key] || nativeEvent.key;
- if (key !== 'Unidentified') {
- return key;
- }
- }
-
- // Browser does not implement `key`, polyfill as much of it as we can.
- if (nativeEvent.type === 'keypress') {
- var charCode = getEventCharCode(nativeEvent);
-
- // The enter-key is technically both printable and non-printable and can
- // thus be captured by `keypress`, no other non-printable key should.
- return charCode === 13 ? 'Enter' : String.fromCharCode(charCode);
- }
- if (nativeEvent.type === 'keydown' || nativeEvent.type === 'keyup') {
- // While user keyboard layout determines the actual meaning of each
- // `keyCode` value, almost all function keys have a universal value.
- return translateToKey[nativeEvent.keyCode] || 'Unidentified';
- }
- return '';
-}
-
-module.exports = getEventKey;
-
-},{"./getEventCharCode":128}],130:[function(_dereq_,module,exports){
-/**
- * Copyright 2013 Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule getEventModifierState
- * @typechecks static-only
- */
-
-"use strict";
-
-/**
- * Translation from modifier key to the associated property in the event.
- * @see http://www.w3.org/TR/DOM-Level-3-Events/#keys-Modifiers
- */
-
-var modifierKeyToProp = {
- 'Alt': 'altKey',
- 'Control': 'ctrlKey',
- 'Meta': 'metaKey',
- 'Shift': 'shiftKey'
-};
-
-// IE8 does not implement getModifierState so we simply map it to the only
-// modifier keys exposed by the event itself, does not support Lock-keys.
-// Currently, all major browsers except Chrome seems to support Lock-keys.
-function modifierStateGetter(keyArg) {
- /*jshint validthis:true */
- var syntheticEvent = this;
- var nativeEvent = syntheticEvent.nativeEvent;
- if (nativeEvent.getModifierState) {
- return nativeEvent.getModifierState(keyArg);
- }
- var keyProp = modifierKeyToProp[keyArg];
- return keyProp ? !!nativeEvent[keyProp] : false;
-}
-
-function getEventModifierState(nativeEvent) {
- return modifierStateGetter;
-}
-
-module.exports = getEventModifierState;
-
-},{}],131:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule getEventTarget
- * @typechecks static-only
- */
-
-"use strict";
-
-/**
- * Gets the target node from a native browser event by accounting for
- * inconsistencies in browser DOM APIs.
- *
- * @param {object} nativeEvent Native browser event.
- * @return {DOMEventTarget} Target node.
- */
-function getEventTarget(nativeEvent) {
- var target = nativeEvent.target || nativeEvent.srcElement || window;
- // Safari may fire events on text nodes (Node.TEXT_NODE is 3).
- // @see http://www.quirksmode.org/js/events_properties.html
- return target.nodeType === 3 ? target.parentNode : target;
-}
-
-module.exports = getEventTarget;
-
-},{}],132:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule getMarkupWrap
- */
-
-var ExecutionEnvironment = _dereq_("./ExecutionEnvironment");
-
-var invariant = _dereq_("./invariant");
-
-/**
- * Dummy container used to detect which wraps are necessary.
- */
-var dummyNode =
- ExecutionEnvironment.canUseDOM ? document.createElement('div') : null;
-
-/**
- * Some browsers cannot use `innerHTML` to render certain elements standalone,
- * so we wrap them, render the wrapped nodes, then extract the desired node.
- *
- * In IE8, certain elements cannot render alone, so wrap all elements ('*').
- */
-var shouldWrap = {
- // Force wrapping for SVG elements because if they get created inside a <div>,
- // they will be initialized in the wrong namespace (and will not display).
- 'circle': true,
- 'defs': true,
- 'ellipse': true,
- 'g': true,
- 'line': true,
- 'linearGradient': true,
- 'path': true,
- 'polygon': true,
- 'polyline': true,
- 'radialGradient': true,
- 'rect': true,
- 'stop': true,
- 'text': true
-};
-
-var selectWrap = [1, '<select multiple="true">', '</select>'];
-var tableWrap = [1, '<table>', '</table>'];
-var trWrap = [3, '<table><tbody><tr>', '</tr></tbody></table>'];
-
-var svgWrap = [1, '<svg>', '</svg>'];
-
-var markupWrap = {
- '*': [1, '?<div>', '</div>'],
-
- 'area': [1, '<map>', '</map>'],
- 'col': [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
- 'legend': [1, '<fieldset>', '</fieldset>'],
- 'param': [1, '<object>', '</object>'],
- 'tr': [2, '<table><tbody>', '</tbody></table>'],
-
- 'optgroup': selectWrap,
- 'option': selectWrap,
-
- 'caption': tableWrap,
- 'colgroup': tableWrap,
- 'tbody': tableWrap,
- 'tfoot': tableWrap,
- 'thead': tableWrap,
-
- 'td': trWrap,
- 'th': trWrap,
-
- 'circle': svgWrap,
- 'defs': svgWrap,
- 'ellipse': svgWrap,
- 'g': svgWrap,
- 'line': svgWrap,
- 'linearGradient': svgWrap,
- 'path': svgWrap,
- 'polygon': svgWrap,
- 'polyline': svgWrap,
- 'radialGradient': svgWrap,
- 'rect': svgWrap,
- 'stop': svgWrap,
- 'text': svgWrap
-};
-
-/**
- * Gets the markup wrap configuration for the supplied `nodeName`.
- *
- * NOTE: This lazily detects which wraps are necessary for the current browser.
- *
- * @param {string} nodeName Lowercase `nodeName`.
- * @return {?array} Markup wrap configuration, if applicable.
- */
-function getMarkupWrap(nodeName) {
- ("production" !== "development" ? invariant(!!dummyNode, 'Markup wrapping node not initialized') : invariant(!!dummyNode));
- if (!markupWrap.hasOwnProperty(nodeName)) {
- nodeName = '*';
- }
- if (!shouldWrap.hasOwnProperty(nodeName)) {
- if (nodeName === '*') {
- dummyNode.innerHTML = '<link />';
- } else {
- dummyNode.innerHTML = '<' + nodeName + '></' + nodeName + '>';
- }
- shouldWrap[nodeName] = !dummyNode.firstChild;
- }
- return shouldWrap[nodeName] ? markupWrap[nodeName] : null;
-}
-
-
-module.exports = getMarkupWrap;
-
-},{"./ExecutionEnvironment":23,"./invariant":140}],133:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule getNodeForCharacterOffset
- */
-
-"use strict";
-
-/**
- * Given any node return the first leaf node without children.
- *
- * @param {DOMElement|DOMTextNode} node
- * @return {DOMElement|DOMTextNode}
- */
-function getLeafNode(node) {
- while (node && node.firstChild) {
- node = node.firstChild;
- }
- return node;
-}
-
-/**
- * Get the next sibling within a container. This will walk up the
- * DOM if a node's siblings have been exhausted.
- *
- * @param {DOMElement|DOMTextNode} node
- * @return {?DOMElement|DOMTextNode}
- */
-function getSiblingNode(node) {
- while (node) {
- if (node.nextSibling) {
- return node.nextSibling;
- }
- node = node.parentNode;
- }
-}
-
-/**
- * Get object describing the nodes which contain characters at offset.
- *
- * @param {DOMElement|DOMTextNode} root
- * @param {number} offset
- * @return {?object}
- */
-function getNodeForCharacterOffset(root, offset) {
- var node = getLeafNode(root);
- var nodeStart = 0;
- var nodeEnd = 0;
-
- while (node) {
- if (node.nodeType == 3) {
- nodeEnd = nodeStart + node.textContent.length;
-
- if (nodeStart <= offset && nodeEnd >= offset) {
- return {
- node: node,
- offset: offset - nodeStart
- };
- }
-
- nodeStart = nodeEnd;
- }
-
- node = getLeafNode(getSiblingNode(node));
- }
-}
-
-module.exports = getNodeForCharacterOffset;
-
-},{}],134:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule getReactRootElementInContainer
- */
-
-"use strict";
-
-var DOC_NODE_TYPE = 9;
-
-/**
- * @param {DOMElement|DOMDocument} container DOM element that may contain
- * a React component
- * @return {?*} DOM element that may have the reactRoot ID, or null.
- */
-function getReactRootElementInContainer(container) {
- if (!container) {
- return null;
- }
-
- if (container.nodeType === DOC_NODE_TYPE) {
- return container.documentElement;
- } else {
- return container.firstChild;
- }
-}
-
-module.exports = getReactRootElementInContainer;
-
-},{}],135:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule getTextContentAccessor
- */
-
-"use strict";
-
-var ExecutionEnvironment = _dereq_("./ExecutionEnvironment");
-
-var contentKey = null;
-
-/**
- * Gets the key used to access text content on a DOM node.
- *
- * @return {?string} Key used to access text content.
- * @internal
- */
-function getTextContentAccessor() {
- if (!contentKey && ExecutionEnvironment.canUseDOM) {
- // Prefer textContent to innerText because many browsers support both but
- // SVG <text> elements don't support innerText even when <div> does.
- contentKey = 'textContent' in document.documentElement ?
- 'textContent' :
- 'innerText';
- }
- return contentKey;
-}
-
-module.exports = getTextContentAccessor;
-
-},{"./ExecutionEnvironment":23}],136:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule getUnboundedScrollPosition
- * @typechecks
- */
-
-"use strict";
-
-/**
- * Gets the scroll position of the supplied element or window.
- *
- * The return values are unbounded, unlike `getScrollPosition`. This means they
- * may be negative or exceed the element boundaries (which is possible using
- * inertial scrolling).
- *
- * @param {DOMWindow|DOMElement} scrollable
- * @return {object} Map with `x` and `y` keys.
- */
-function getUnboundedScrollPosition(scrollable) {
- if (scrollable === window) {
- return {
- x: window.pageXOffset || document.documentElement.scrollLeft,
- y: window.pageYOffset || document.documentElement.scrollTop
- };
- }
- return {
- x: scrollable.scrollLeft,
- y: scrollable.scrollTop
- };
-}
-
-module.exports = getUnboundedScrollPosition;
-
-},{}],137:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule hyphenate
- * @typechecks
- */
-
-var _uppercasePattern = /([A-Z])/g;
-
-/**
- * Hyphenates a camelcased string, for example:
- *
- * > hyphenate('backgroundColor')
- * < "background-color"
- *
- * For CSS style names, use `hyphenateStyleName` instead which works properly
- * with all vendor prefixes, including `ms`.
- *
- * @param {string} string
- * @return {string}
- */
-function hyphenate(string) {
- return string.replace(_uppercasePattern, '-$1').toLowerCase();
-}
-
-module.exports = hyphenate;
-
-},{}],138:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule hyphenateStyleName
- * @typechecks
- */
-
-"use strict";
-
-var hyphenate = _dereq_("./hyphenate");
-
-var msPattern = /^ms-/;
-
-/**
- * Hyphenates a camelcased CSS property name, for example:
- *
- * > hyphenateStyleName('backgroundColor')
- * < "background-color"
- * > hyphenateStyleName('MozTransition')
- * < "-moz-transition"
- * > hyphenateStyleName('msTransition')
- * < "-ms-transition"
- *
- * As Modernizr suggests (http://modernizr.com/docs/#prefixed), an `ms` prefix
- * is converted to `-ms-`.
- *
- * @param {string} string
- * @return {string}
- */
-function hyphenateStyleName(string) {
- return hyphenate(string).replace(msPattern, '-ms-');
-}
-
-module.exports = hyphenateStyleName;
-
-},{"./hyphenate":137}],139:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule instantiateReactComponent
- * @typechecks static-only
- */
-
-"use strict";
-
-var warning = _dereq_("./warning");
-
-var ReactElement = _dereq_("./ReactElement");
-var ReactLegacyElement = _dereq_("./ReactLegacyElement");
-var ReactNativeComponent = _dereq_("./ReactNativeComponent");
-var ReactEmptyComponent = _dereq_("./ReactEmptyComponent");
-
-/**
- * Given an `element` create an instance that will actually be mounted.
- *
- * @param {object} element
- * @param {*} parentCompositeType The composite type that resolved this.
- * @return {object} A new instance of the element's constructor.
- * @protected
- */
-function instantiateReactComponent(element, parentCompositeType) {
- var instance;
-
- if ("production" !== "development") {
- ("production" !== "development" ? warning(
- element && (typeof element.type === 'function' ||
- typeof element.type === 'string'),
- 'Only functions or strings can be mounted as React components.'
- ) : null);
-
- // Resolve mock instances
- if (element.type._mockedReactClassConstructor) {
- // If this is a mocked class, we treat the legacy factory as if it was the
- // class constructor for future proofing unit tests. Because this might
- // be mocked as a legacy factory, we ignore any warnings triggerd by
- // this temporary hack.
- ReactLegacyElement._isLegacyCallWarningEnabled = false;
- try {
- instance = new element.type._mockedReactClassConstructor(
- element.props
- );
- } finally {
- ReactLegacyElement._isLegacyCallWarningEnabled = true;
- }
-
- // If the mock implementation was a legacy factory, then it returns a
- // element. We need to turn this into a real component instance.
- if (ReactElement.isValidElement(instance)) {
- instance = new instance.type(instance.props);
- }
-
- var render = instance.render;
- if (!render) {
- // For auto-mocked factories, the prototype isn't shimmed and therefore
- // there is no render function on the instance. We replace the whole
- // component with an empty component instance instead.
- element = ReactEmptyComponent.getEmptyComponent();
- } else {
- if (render._isMockFunction && !render._getMockImplementation()) {
- // Auto-mocked components may have a prototype with a mocked render
- // function. For those, we'll need to mock the result of the render
- // since we consider undefined to be invalid results from render.
- render.mockImplementation(
- ReactEmptyComponent.getEmptyComponent
- );
- }
- instance.construct(element);
- return instance;
- }
- }
- }
-
- // Special case string values
- if (typeof element.type === 'string') {
- instance = ReactNativeComponent.createInstanceForTag(
- element.type,
- element.props,
- parentCompositeType
- );
- } else {
- // Normal case for non-mocks and non-strings
- instance = new element.type(element.props);
- }
-
- if ("production" !== "development") {
- ("production" !== "development" ? warning(
- typeof instance.construct === 'function' &&
- typeof instance.mountComponent === 'function' &&
- typeof instance.receiveComponent === 'function',
- 'Only React Components can be mounted.'
- ) : null);
- }
-
- // This actually sets up the internal instance. This will become decoupled
- // from the public instance in a future diff.
- instance.construct(element);
-
- return instance;
-}
-
-module.exports = instantiateReactComponent;
-
-},{"./ReactElement":58,"./ReactEmptyComponent":60,"./ReactLegacyElement":67,"./ReactNativeComponent":73,"./warning":160}],140:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule invariant
- */
-
-"use strict";
-
-/**
- * Use invariant() to assert state which your program assumes to be true.
- *
- * Provide sprintf-style format (only %s is supported) and arguments
- * to provide information about what broke and what you were
- * expecting.
- *
- * The invariant message will be stripped in production, but the invariant
- * will remain to ensure logic does not differ in production.
- */
-
-var invariant = function(condition, format, a, b, c, d, e, f) {
- if ("production" !== "development") {
- if (format === undefined) {
- throw new Error('invariant requires an error message argument');
- }
- }
-
- if (!condition) {
- var error;
- if (format === undefined) {
- error = new Error(
- 'Minified exception occurred; use the non-minified dev environment ' +
- 'for the full error message and additional helpful warnings.'
- );
- } else {
- var args = [a, b, c, d, e, f];
- var argIndex = 0;
- error = new Error(
- 'Invariant Violation: ' +
- format.replace(/%s/g, function() { return args[argIndex++]; })
- );
- }
-
- error.framesToPop = 1; // we don't care about invariant's own frame
- throw error;
- }
-};
-
-module.exports = invariant;
-
-},{}],141:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule isEventSupported
- */
-
-"use strict";
-
-var ExecutionEnvironment = _dereq_("./ExecutionEnvironment");
-
-var useHasFeature;
-if (ExecutionEnvironment.canUseDOM) {
- useHasFeature =
- document.implementation &&
- document.implementation.hasFeature &&
- // always returns true in newer browsers as per the standard.
- // @see http://dom.spec.whatwg.org/#dom-domimplementation-hasfeature
- document.implementation.hasFeature('', '') !== true;
-}
-
-/**
- * Checks if an event is supported in the current execution environment.
- *
- * NOTE: This will not work correctly for non-generic events such as `change`,
- * `reset`, `load`, `error`, and `select`.
- *
- * Borrows from Modernizr.
- *
- * @param {string} eventNameSuffix Event name, e.g. "click".
- * @param {?boolean} capture Check if the capture phase is supported.
- * @return {boolean} True if the event is supported.
- * @internal
- * @license Modernizr 3.0.0pre (Custom Build) | MIT
- */
-function isEventSupported(eventNameSuffix, capture) {
- if (!ExecutionEnvironment.canUseDOM ||
- capture && !('addEventListener' in document)) {
- return false;
- }
-
- var eventName = 'on' + eventNameSuffix;
- var isSupported = eventName in document;
-
- if (!isSupported) {
- var element = document.createElement('div');
- element.setAttribute(eventName, 'return;');
- isSupported = typeof element[eventName] === 'function';
- }
-
- if (!isSupported && useHasFeature && eventNameSuffix === 'wheel') {
- // This is the only way to test support for the `wheel` event in IE9+.
- isSupported = document.implementation.hasFeature('Events.wheel', '3.0');
- }
-
- return isSupported;
-}
-
-module.exports = isEventSupported;
-
-},{"./ExecutionEnvironment":23}],142:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule isNode
- * @typechecks
- */
-
-/**
- * @param {*} object The object to check.
- * @return {boolean} Whether or not the object is a DOM node.
- */
-function isNode(object) {
- return !!(object && (
- typeof Node === 'function' ? object instanceof Node :
- typeof object === 'object' &&
- typeof object.nodeType === 'number' &&
- typeof object.nodeName === 'string'
- ));
-}
-
-module.exports = isNode;
-
-},{}],143:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule isTextInputElement
- */
-
-"use strict";
-
-/**
- * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary
- */
-var supportedInputTypes = {
- 'color': true,
- 'date': true,
- 'datetime': true,
- 'datetime-local': true,
- 'email': true,
- 'month': true,
- 'number': true,
- 'password': true,
- 'range': true,
- 'search': true,
- 'tel': true,
- 'text': true,
- 'time': true,
- 'url': true,
- 'week': true
-};
-
-function isTextInputElement(elem) {
- return elem && (
- (elem.nodeName === 'INPUT' && supportedInputTypes[elem.type]) ||
- elem.nodeName === 'TEXTAREA'
- );
-}
-
-module.exports = isTextInputElement;
-
-},{}],144:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule isTextNode
- * @typechecks
- */
-
-var isNode = _dereq_("./isNode");
-
-/**
- * @param {*} object The object to check.
- * @return {boolean} Whether or not the object is a DOM text node.
- */
-function isTextNode(object) {
- return isNode(object) && object.nodeType == 3;
-}
-
-module.exports = isTextNode;
-
-},{"./isNode":142}],145:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule joinClasses
- * @typechecks static-only
- */
-
-"use strict";
-
-/**
- * Combines multiple className strings into one.
- * http://jsperf.com/joinclasses-args-vs-array
- *
- * @param {...?string} classes
- * @return {string}
- */
-function joinClasses(className/*, ... */) {
- if (!className) {
- className = '';
- }
- var nextClass;
- var argLength = arguments.length;
- if (argLength > 1) {
- for (var ii = 1; ii < argLength; ii++) {
- nextClass = arguments[ii];
- if (nextClass) {
- className = (className ? className + ' ' : '') + nextClass;
- }
- }
- }
- return className;
-}
-
-module.exports = joinClasses;
-
-},{}],146:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule keyMirror
- * @typechecks static-only
- */
-
-"use strict";
-
-var invariant = _dereq_("./invariant");
-
-/**
- * Constructs an enumeration with keys equal to their value.
- *
- * For example:
- *
- * var COLORS = keyMirror({blue: null, red: null});
- * var myColor = COLORS.blue;
- * var isColorValid = !!COLORS[myColor];
- *
- * The last line could not be performed if the values of the generated enum were
- * not equal to their keys.
- *
- * Input: {key1: val1, key2: val2}
- * Output: {key1: key1, key2: key2}
- *
- * @param {object} obj
- * @return {object}
- */
-var keyMirror = function(obj) {
- var ret = {};
- var key;
- ("production" !== "development" ? invariant(
- obj instanceof Object && !Array.isArray(obj),
- 'keyMirror(...): Argument must be an object.'
- ) : invariant(obj instanceof Object && !Array.isArray(obj)));
- for (key in obj) {
- if (!obj.hasOwnProperty(key)) {
- continue;
- }
- ret[key] = key;
- }
- return ret;
-};
-
-module.exports = keyMirror;
-
-},{"./invariant":140}],147:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule keyOf
- */
-
-/**
- * Allows extraction of a minified key. Let's the build system minify keys
- * without loosing the ability to dynamically use key strings as values
- * themselves. Pass in an object with a single key/val pair and it will return
- * you the string key of that single record. Suppose you want to grab the
- * value for a key 'className' inside of an object. Key/val minification may
- * have aliased that key to be 'xa12'. keyOf({className: null}) will return
- * 'xa12' in that case. Resolve keys you want to use once at startup time, then
- * reuse those resolutions.
- */
-var keyOf = function(oneKeyObj) {
- var key;
- for (key in oneKeyObj) {
- if (!oneKeyObj.hasOwnProperty(key)) {
- continue;
- }
- return key;
- }
- return null;
-};
-
-
-module.exports = keyOf;
-
-},{}],148:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule mapObject
- */
-
-'use strict';
-
-var hasOwnProperty = Object.prototype.hasOwnProperty;
-
-/**
- * Executes the provided `callback` once for each enumerable own property in the
- * object and constructs a new object from the results. The `callback` is
- * invoked with three arguments:
- *
- * - the property value
- * - the property name
- * - the object being traversed
- *
- * Properties that are added after the call to `mapObject` will not be visited
- * by `callback`. If the values of existing properties are changed, the value
- * passed to `callback` will be the value at the time `mapObject` visits them.
- * Properties that are deleted before being visited are not visited.
- *
- * @grep function objectMap()
- * @grep function objMap()
- *
- * @param {?object} object
- * @param {function} callback
- * @param {*} context
- * @return {?object}
- */
-function mapObject(object, callback, context) {
- if (!object) {
- return null;
- }
- var result = {};
- for (var name in object) {
- if (hasOwnProperty.call(object, name)) {
- result[name] = callback.call(context, object[name], name, object);
- }
- }
- return result;
-}
-
-module.exports = mapObject;
-
-},{}],149:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule memoizeStringOnly
- * @typechecks static-only
- */
-
-"use strict";
-
-/**
- * Memoizes the return value of a function that accepts one string argument.
- *
- * @param {function} callback
- * @return {function}
- */
-function memoizeStringOnly(callback) {
- var cache = {};
- return function(string) {
- if (cache.hasOwnProperty(string)) {
- return cache[string];
- } else {
- return cache[string] = callback.call(this, string);
- }
- };
-}
-
-module.exports = memoizeStringOnly;
-
-},{}],150:[function(_dereq_,module,exports){
-/**
- * Copyright 2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule monitorCodeUse
- */
-
-"use strict";
-
-var invariant = _dereq_("./invariant");
-
-/**
- * Provides open-source compatible instrumentation for monitoring certain API
- * uses before we're ready to issue a warning or refactor. It accepts an event
- * name which may only contain the characters [a-z0-9_] and an optional data
- * object with further information.
- */
-
-function monitorCodeUse(eventName, data) {
- ("production" !== "development" ? invariant(
- eventName && !/[^a-z0-9_]/.test(eventName),
- 'You must provide an eventName using only the characters [a-z0-9_]'
- ) : invariant(eventName && !/[^a-z0-9_]/.test(eventName)));
-}
-
-module.exports = monitorCodeUse;
-
-},{"./invariant":140}],151:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule onlyChild
- */
-"use strict";
-
-var ReactElement = _dereq_("./ReactElement");
-
-var invariant = _dereq_("./invariant");
-
-/**
- * Returns the first child in a collection of children and verifies that there
- * is only one child in the collection. The current implementation of this
- * function assumes that a single child gets passed without a wrapper, but the
- * purpose of this helper function is to abstract away the particular structure
- * of children.
- *
- * @param {?object} children Child collection structure.
- * @return {ReactComponent} The first and only `ReactComponent` contained in the
- * structure.
- */
-function onlyChild(children) {
- ("production" !== "development" ? invariant(
- ReactElement.isValidElement(children),
- 'onlyChild must be passed a children with exactly one child.'
- ) : invariant(ReactElement.isValidElement(children)));
- return children;
-}
-
-module.exports = onlyChild;
-
-},{"./ReactElement":58,"./invariant":140}],152:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule performance
- * @typechecks
- */
-
-"use strict";
-
-var ExecutionEnvironment = _dereq_("./ExecutionEnvironment");
-
-var performance;
-
-if (ExecutionEnvironment.canUseDOM) {
- performance =
- window.performance ||
- window.msPerformance ||
- window.webkitPerformance;
-}
-
-module.exports = performance || {};
-
-},{"./ExecutionEnvironment":23}],153:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule performanceNow
- * @typechecks
- */
-
-var performance = _dereq_("./performance");
-
-/**
- * Detect if we can use `window.performance.now()` and gracefully fallback to
- * `Date.now()` if it doesn't exist. We need to support Firefox < 15 for now
- * because of Facebook's testing infrastructure.
- */
-if (!performance || !performance.now) {
- performance = Date;
-}
-
-var performanceNow = performance.now.bind(performance);
-
-module.exports = performanceNow;
-
-},{"./performance":152}],154:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule setInnerHTML
- */
-
-"use strict";
-
-var ExecutionEnvironment = _dereq_("./ExecutionEnvironment");
-
-var WHITESPACE_TEST = /^[ \r\n\t\f]/;
-var NONVISIBLE_TEST = /<(!--|link|noscript|meta|script|style)[ \r\n\t\f\/>]/;
-
-/**
- * Set the innerHTML property of a node, ensuring that whitespace is preserved
- * even in IE8.
- *
- * @param {DOMElement} node
- * @param {string} html
- * @internal
- */
-var setInnerHTML = function(node, html) {
- node.innerHTML = html;
-};
-
-if (ExecutionEnvironment.canUseDOM) {
- // IE8: When updating a just created node with innerHTML only leading
- // whitespace is removed. When updating an existing node with innerHTML
- // whitespace in root TextNodes is also collapsed.
- // @see quirksmode.org/bugreports/archives/2004/11/innerhtml_and_t.html
-
- // Feature detection; only IE8 is known to behave improperly like this.
- var testElement = document.createElement('div');
- testElement.innerHTML = ' ';
- if (testElement.innerHTML === '') {
- setInnerHTML = function(node, html) {
- // Magic theory: IE8 supposedly differentiates between added and updated
- // nodes when processing innerHTML, innerHTML on updated nodes suffers
- // from worse whitespace behavior. Re-adding a node like this triggers
- // the initial and more favorable whitespace behavior.
- // TODO: What to do on a detached node?
- if (node.parentNode) {
- node.parentNode.replaceChild(node, node);
- }
-
- // We also implement a workaround for non-visible tags disappearing into
- // thin air on IE8, this only happens if there is no visible text
- // in-front of the non-visible tags. Piggyback on the whitespace fix
- // and simply check if any non-visible tags appear in the source.
- if (WHITESPACE_TEST.test(html) ||
- html[0] === '<' && NONVISIBLE_TEST.test(html)) {
- // Recover leading whitespace by temporarily prepending any character.
- // \uFEFF has the potential advantage of being zero-width/invisible.
- node.innerHTML = '\uFEFF' + html;
-
- // deleteData leaves an empty `TextNode` which offsets the index of all
- // children. Definitely want to avoid this.
- var textNode = node.firstChild;
- if (textNode.data.length === 1) {
- node.removeChild(textNode);
- } else {
- textNode.deleteData(0, 1);
- }
- } else {
- node.innerHTML = html;
- }
- };
- }
-}
-
-module.exports = setInnerHTML;
-
-},{"./ExecutionEnvironment":23}],155:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule shallowEqual
- */
-
-"use strict";
-
-/**
- * Performs equality by iterating through keys on an object and returning
- * false when any key has values which are not strictly equal between
- * objA and objB. Returns true when the values of all keys are strictly equal.
- *
- * @return {boolean}
- */
-function shallowEqual(objA, objB) {
- if (objA === objB) {
- return true;
- }
- var key;
- // Test for A's keys different from B.
- for (key in objA) {
- if (objA.hasOwnProperty(key) &&
- (!objB.hasOwnProperty(key) || objA[key] !== objB[key])) {
- return false;
- }
- }
- // Test for B's keys missing from A.
- for (key in objB) {
- if (objB.hasOwnProperty(key) && !objA.hasOwnProperty(key)) {
- return false;
- }
- }
- return true;
-}
-
-module.exports = shallowEqual;
-
-},{}],156:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule shouldUpdateReactComponent
- * @typechecks static-only
- */
-
-"use strict";
-
-/**
- * Given a `prevElement` and `nextElement`, determines if the existing
- * instance should be updated as opposed to being destroyed or replaced by a new
- * instance. Both arguments are elements. This ensures that this logic can
- * operate on stateless trees without any backing instance.
- *
- * @param {?object} prevElement
- * @param {?object} nextElement
- * @return {boolean} True if the existing instance should be updated.
- * @protected
- */
-function shouldUpdateReactComponent(prevElement, nextElement) {
- if (prevElement && nextElement &&
- prevElement.type === nextElement.type &&
- prevElement.key === nextElement.key &&
- prevElement._owner === nextElement._owner) {
- return true;
- }
- return false;
-}
-
-module.exports = shouldUpdateReactComponent;
-
-},{}],157:[function(_dereq_,module,exports){
-/**
- * Copyright 2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule toArray
- * @typechecks
- */
-
-var invariant = _dereq_("./invariant");
-
-/**
- * Convert array-like objects to arrays.
- *
- * This API assumes the caller knows the contents of the data type. For less
- * well defined inputs use createArrayFrom.
- *
- * @param {object|function|filelist} obj
- * @return {array}
- */
-function toArray(obj) {
- var length = obj.length;
-
- // Some browse builtin objects can report typeof 'function' (e.g. NodeList in
- // old versions of Safari).
- ("production" !== "development" ? invariant(
- !Array.isArray(obj) &&
- (typeof obj === 'object' || typeof obj === 'function'),
- 'toArray: Array-like object expected'
- ) : invariant(!Array.isArray(obj) &&
- (typeof obj === 'object' || typeof obj === 'function')));
-
- ("production" !== "development" ? invariant(
- typeof length === 'number',
- 'toArray: Object needs a length property'
- ) : invariant(typeof length === 'number'));
-
- ("production" !== "development" ? invariant(
- length === 0 ||
- (length - 1) in obj,
- 'toArray: Object should have keys for indices'
- ) : invariant(length === 0 ||
- (length - 1) in obj));
-
- // Old IE doesn't give collections access to hasOwnProperty. Assume inputs
- // without method will throw during the slice call and skip straight to the
- // fallback.
- if (obj.hasOwnProperty) {
- try {
- return Array.prototype.slice.call(obj);
- } catch (e) {
- // IE < 9 does not support Array#slice on collections objects
- }
- }
-
- // Fall back to copying key by key. This assumes all keys have a value,
- // so will not preserve sparsely populated inputs.
- var ret = Array(length);
- for (var ii = 0; ii < length; ii++) {
- ret[ii] = obj[ii];
- }
- return ret;
-}
-
-module.exports = toArray;
-
-},{"./invariant":140}],158:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule traverseAllChildren
- */
-
-"use strict";
-
-var ReactElement = _dereq_("./ReactElement");
-var ReactInstanceHandles = _dereq_("./ReactInstanceHandles");
-
-var invariant = _dereq_("./invariant");
-
-var SEPARATOR = ReactInstanceHandles.SEPARATOR;
-var SUBSEPARATOR = ':';
-
-/**
- * TODO: Test that:
- * 1. `mapChildren` transforms strings and numbers into `ReactTextComponent`.
- * 2. it('should fail when supplied duplicate key', function() {
- * 3. That a single child and an array with one item have the same key pattern.
- * });
- */
-
-var userProvidedKeyEscaperLookup = {
- '=': '=0',
- '.': '=1',
- ':': '=2'
-};
-
-var userProvidedKeyEscapeRegex = /[=.:]/g;
-
-function userProvidedKeyEscaper(match) {
- return userProvidedKeyEscaperLookup[match];
-}
-
-/**
- * Generate a key string that identifies a component within a set.
- *
- * @param {*} component A component that could contain a manual key.
- * @param {number} index Index that is used if a manual key is not provided.
- * @return {string}
- */
-function getComponentKey(component, index) {
- if (component && component.key != null) {
- // Explicit key
- return wrapUserProvidedKey(component.key);
- }
- // Implicit key determined by the index in the set
- return index.toString(36);
-}
-
-/**
- * Escape a component key so that it is safe to use in a reactid.
- *
- * @param {*} key Component key to be escaped.
- * @return {string} An escaped string.
- */
-function escapeUserProvidedKey(text) {
- return ('' + text).replace(
- userProvidedKeyEscapeRegex,
- userProvidedKeyEscaper
- );
-}
-
-/**
- * Wrap a `key` value explicitly provided by the user to distinguish it from
- * implicitly-generated keys generated by a component's index in its parent.
- *
- * @param {string} key Value of a user-provided `key` attribute
- * @return {string}
- */
-function wrapUserProvidedKey(key) {
- return '$' + escapeUserProvidedKey(key);
-}
-
-/**
- * @param {?*} children Children tree container.
- * @param {!string} nameSoFar Name of the key path so far.
- * @param {!number} indexSoFar Number of children encountered until this point.
- * @param {!function} callback Callback to invoke with each child found.
- * @param {?*} traverseContext Used to pass information throughout the traversal
- * process.
- * @return {!number} The number of children in this subtree.
- */
-var traverseAllChildrenImpl =
- function(children, nameSoFar, indexSoFar, callback, traverseContext) {
- var nextName, nextIndex;
- var subtreeCount = 0; // Count of children found in the current subtree.
- if (Array.isArray(children)) {
- for (var i = 0; i < children.length; i++) {
- var child = children[i];
- nextName = (
- nameSoFar +
- (nameSoFar ? SUBSEPARATOR : SEPARATOR) +
- getComponentKey(child, i)
- );
- nextIndex = indexSoFar + subtreeCount;
- subtreeCount += traverseAllChildrenImpl(
- child,
- nextName,
- nextIndex,
- callback,
- traverseContext
- );
- }
- } else {
- var type = typeof children;
- var isOnlyChild = nameSoFar === '';
- // If it's the only child, treat the name as if it was wrapped in an array
- // so that it's consistent if the number of children grows
- var storageName =
- isOnlyChild ? SEPARATOR + getComponentKey(children, 0) : nameSoFar;
- if (children == null || type === 'boolean') {
- // All of the above are perceived as null.
- callback(traverseContext, null, storageName, indexSoFar);
- subtreeCount = 1;
- } else if (type === 'string' || type === 'number' ||
- ReactElement.isValidElement(children)) {
- callback(traverseContext, children, storageName, indexSoFar);
- subtreeCount = 1;
- } else if (type === 'object') {
- ("production" !== "development" ? invariant(
- !children || children.nodeType !== 1,
- 'traverseAllChildren(...): Encountered an invalid child; DOM ' +
- 'elements are not valid children of React components.'
- ) : invariant(!children || children.nodeType !== 1));
- for (var key in children) {
- if (children.hasOwnProperty(key)) {
- nextName = (
- nameSoFar + (nameSoFar ? SUBSEPARATOR : SEPARATOR) +
- wrapUserProvidedKey(key) + SUBSEPARATOR +
- getComponentKey(children[key], 0)
- );
- nextIndex = indexSoFar + subtreeCount;
- subtreeCount += traverseAllChildrenImpl(
- children[key],
- nextName,
- nextIndex,
- callback,
- traverseContext
- );
- }
- }
- }
- }
- return subtreeCount;
- };
-
-/**
- * Traverses children that are typically specified as `props.children`, but
- * might also be specified through attributes:
- *
- * - `traverseAllChildren(this.props.children, ...)`
- * - `traverseAllChildren(this.props.leftPanelChildren, ...)`
- *
- * The `traverseContext` is an optional argument that is passed through the
- * entire traversal. It can be used to store accumulations or anything else that
- * the callback might find relevant.
- *
- * @param {?*} children Children tree object.
- * @param {!function} callback To invoke upon traversing each child.
- * @param {?*} traverseContext Context for traversal.
- * @return {!number} The number of children in this subtree.
- */
-function traverseAllChildren(children, callback, traverseContext) {
- if (children == null) {
- return 0;
- }
-
- return traverseAllChildrenImpl(children, '', 0, callback, traverseContext);
-}
-
-module.exports = traverseAllChildren;
-
-},{"./ReactElement":58,"./ReactInstanceHandles":66,"./invariant":140}],159:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule update
- */
-
-"use strict";
-
-var assign = _dereq_("./Object.assign");
-var keyOf = _dereq_("./keyOf");
-var invariant = _dereq_("./invariant");
-
-function shallowCopy(x) {
- if (Array.isArray(x)) {
- return x.concat();
- } else if (x && typeof x === 'object') {
- return assign(new x.constructor(), x);
- } else {
- return x;
- }
-}
-
-var COMMAND_PUSH = keyOf({$push: null});
-var COMMAND_UNSHIFT = keyOf({$unshift: null});
-var COMMAND_SPLICE = keyOf({$splice: null});
-var COMMAND_SET = keyOf({$set: null});
-var COMMAND_MERGE = keyOf({$merge: null});
-var COMMAND_APPLY = keyOf({$apply: null});
-
-var ALL_COMMANDS_LIST = [
- COMMAND_PUSH,
- COMMAND_UNSHIFT,
- COMMAND_SPLICE,
- COMMAND_SET,
- COMMAND_MERGE,
- COMMAND_APPLY
-];
-
-var ALL_COMMANDS_SET = {};
-
-ALL_COMMANDS_LIST.forEach(function(command) {
- ALL_COMMANDS_SET[command] = true;
-});
-
-function invariantArrayCase(value, spec, command) {
- ("production" !== "development" ? invariant(
- Array.isArray(value),
- 'update(): expected target of %s to be an array; got %s.',
- command,
- value
- ) : invariant(Array.isArray(value)));
- var specValue = spec[command];
- ("production" !== "development" ? invariant(
- Array.isArray(specValue),
- 'update(): expected spec of %s to be an array; got %s. ' +
- 'Did you forget to wrap your parameter in an array?',
- command,
- specValue
- ) : invariant(Array.isArray(specValue)));
-}
-
-function update(value, spec) {
- ("production" !== "development" ? invariant(
- typeof spec === 'object',
- 'update(): You provided a key path to update() that did not contain one ' +
- 'of %s. Did you forget to include {%s: ...}?',
- ALL_COMMANDS_LIST.join(', '),
- COMMAND_SET
- ) : invariant(typeof spec === 'object'));
-
- if (spec.hasOwnProperty(COMMAND_SET)) {
- ("production" !== "development" ? invariant(
- Object.keys(spec).length === 1,
- 'Cannot have more than one key in an object with %s',
- COMMAND_SET
- ) : invariant(Object.keys(spec).length === 1));
-
- return spec[COMMAND_SET];
- }
-
- var nextValue = shallowCopy(value);
-
- if (spec.hasOwnProperty(COMMAND_MERGE)) {
- var mergeObj = spec[COMMAND_MERGE];
- ("production" !== "development" ? invariant(
- mergeObj && typeof mergeObj === 'object',
- 'update(): %s expects a spec of type \'object\'; got %s',
- COMMAND_MERGE,
- mergeObj
- ) : invariant(mergeObj && typeof mergeObj === 'object'));
- ("production" !== "development" ? invariant(
- nextValue && typeof nextValue === 'object',
- 'update(): %s expects a target of type \'object\'; got %s',
- COMMAND_MERGE,
- nextValue
- ) : invariant(nextValue && typeof nextValue === 'object'));
- assign(nextValue, spec[COMMAND_MERGE]);
- }
-
- if (spec.hasOwnProperty(COMMAND_PUSH)) {
- invariantArrayCase(value, spec, COMMAND_PUSH);
- spec[COMMAND_PUSH].forEach(function(item) {
- nextValue.push(item);
- });
- }
-
- if (spec.hasOwnProperty(COMMAND_UNSHIFT)) {
- invariantArrayCase(value, spec, COMMAND_UNSHIFT);
- spec[COMMAND_UNSHIFT].forEach(function(item) {
- nextValue.unshift(item);
- });
- }
-
- if (spec.hasOwnProperty(COMMAND_SPLICE)) {
- ("production" !== "development" ? invariant(
- Array.isArray(value),
- 'Expected %s target to be an array; got %s',
- COMMAND_SPLICE,
- value
- ) : invariant(Array.isArray(value)));
- ("production" !== "development" ? invariant(
- Array.isArray(spec[COMMAND_SPLICE]),
- 'update(): expected spec of %s to be an array of arrays; got %s. ' +
- 'Did you forget to wrap your parameters in an array?',
- COMMAND_SPLICE,
- spec[COMMAND_SPLICE]
- ) : invariant(Array.isArray(spec[COMMAND_SPLICE])));
- spec[COMMAND_SPLICE].forEach(function(args) {
- ("production" !== "development" ? invariant(
- Array.isArray(args),
- 'update(): expected spec of %s to be an array of arrays; got %s. ' +
- 'Did you forget to wrap your parameters in an array?',
- COMMAND_SPLICE,
- spec[COMMAND_SPLICE]
- ) : invariant(Array.isArray(args)));
- nextValue.splice.apply(nextValue, args);
- });
- }
-
- if (spec.hasOwnProperty(COMMAND_APPLY)) {
- ("production" !== "development" ? invariant(
- typeof spec[COMMAND_APPLY] === 'function',
- 'update(): expected spec of %s to be a function; got %s.',
- COMMAND_APPLY,
- spec[COMMAND_APPLY]
- ) : invariant(typeof spec[COMMAND_APPLY] === 'function'));
- nextValue = spec[COMMAND_APPLY](nextValue);
- }
-
- for (var k in spec) {
- if (!(ALL_COMMANDS_SET.hasOwnProperty(k) && ALL_COMMANDS_SET[k])) {
- nextValue[k] = update(value[k], spec[k]);
- }
- }
-
- return nextValue;
-}
-
-module.exports = update;
-
-},{"./Object.assign":29,"./invariant":140,"./keyOf":147}],160:[function(_dereq_,module,exports){
-/**
- * Copyright 2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule warning
- */
-
-"use strict";
-
-var emptyFunction = _dereq_("./emptyFunction");
-
-/**
- * Similar to invariant but only logs a warning if the condition is not met.
- * This can be used to log issues in development environments in critical
- * paths. Removing the logging code for production environments will keep the
- * same logic and follow the same code paths.
- */
-
-var warning = emptyFunction;
-
-if ("production" !== "development") {
- warning = function(condition, format ) {for (var args=[],$__0=2,$__1=arguments.length;$__0<$__1;$__0++) args.push(arguments[$__0]);
- if (format === undefined) {
- throw new Error(
- '`warning(condition, format, ...args)` requires a warning ' +
- 'message argument'
- );
- }
-
- if (!condition) {
- var argIndex = 0;
- console.warn('Warning: ' + format.replace(/%s/g, function() {return args[argIndex++];}));
- }
- };
-}
-
-module.exports = warning;
-
-},{"./emptyFunction":121}]},{},[1])(1)
-});
-!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.ReactRouter=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
-/**
- * Actions that modify the URL.
- */
-var LocationActions = {
-
- /**
- * Indicates a new location is being pushed to the history stack.
- */
- PUSH: 'push',
-
- /**
- * Indicates the current location should be replaced.
- */
- REPLACE: 'replace',
-
- /**
- * Indicates the most recent entry should be removed from the history stack.
- */
- POP: 'pop'
-
-};
-
-module.exports = LocationActions;
-
-},{}],2:[function(_dereq_,module,exports){
-var LocationActions = _dereq_('../actions/LocationActions');
-
-/**
- * A scroll behavior that attempts to imitate the default behavior
- * of modern browsers.
- */
-var ImitateBrowserBehavior = {
-
- updateScrollPosition: function (position, actionType) {
- switch (actionType) {
- case LocationActions.PUSH:
- case LocationActions.REPLACE:
- window.scrollTo(0, 0);
- break;
- case LocationActions.POP:
- if (position) {
- window.scrollTo(position.x, position.y);
- } else {
- window.scrollTo(0, 0);
- }
- break;
- }
- }
-
-};
-
-module.exports = ImitateBrowserBehavior;
-
-},{"../actions/LocationActions":1}],3:[function(_dereq_,module,exports){
-/**
- * A scroll behavior that always scrolls to the top of the page
- * after a transition.
- */
-var ScrollToTopBehavior = {
-
- updateScrollPosition: function () {
- window.scrollTo(0, 0);
- }
-
-};
-
-module.exports = ScrollToTopBehavior;
-
-},{}],4:[function(_dereq_,module,exports){
-var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
-var FakeNode = _dereq_('../mixins/FakeNode');
-var PropTypes = _dereq_('../utils/PropTypes');
-
-/**
- * A <DefaultRoute> component is a special kind of <Route> that
- * renders when its parent matches but none of its siblings do.
- * Only one such route may be used at any given level in the
- * route hierarchy.
- */
-var DefaultRoute = React.createClass({
-
- displayName: 'DefaultRoute',
-
- mixins: [ FakeNode ],
-
- propTypes: {
- name: React.PropTypes.string,
- path: PropTypes.falsy,
- handler: React.PropTypes.func.isRequired
- }
-
-});
-
-module.exports = DefaultRoute;
-
-},{"../mixins/FakeNode":14,"../utils/PropTypes":23}],5:[function(_dereq_,module,exports){
-var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
-var classSet = _dereq_('react/lib/cx');
-var assign = _dereq_('react/lib/Object.assign');
-var Navigation = _dereq_('../mixins/Navigation');
-var State = _dereq_('../mixins/State');
-
-function isLeftClickEvent(event) {
- return event.button === 0;
-}
-
-function isModifiedEvent(event) {
- return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
-}
-
-/**
- * <Link> components are used to create an <a> element that links to a route.
- * When that route is active, the link gets an "active" class name (or the
- * value of its `activeClassName` prop).
- *
- * For example, assuming you have the following route:
- *
- * <Route name="showPost" path="/posts/:postID" handler={Post}/>
- *
- * You could use the following component to link to that route:
- *
- * <Link to="showPost" params={{ postID: "123" }} />
- *
- * In addition to params, links may pass along query string parameters
- * using the `query` prop.
- *
- * <Link to="showPost" params={{ postID: "123" }} query={{ show:true }}/>
- */
-var Link = React.createClass({
-
- displayName: 'Link',
-
- mixins: [ Navigation, State ],
-
- propTypes: {
- activeClassName: React.PropTypes.string.isRequired,
- to: React.PropTypes.string.isRequired,
- params: React.PropTypes.object,
- query: React.PropTypes.object,
- onClick: React.PropTypes.func
- },
-
- getDefaultProps: function () {
- return {
- activeClassName: 'active'
- };
- },
-
- handleClick: function (event) {
- var allowTransition = true;
- var clickResult;
-
- if (this.props.onClick)
- clickResult = this.props.onClick(event);
-
- if (isModifiedEvent(event) || !isLeftClickEvent(event))
- return;
-
- if (clickResult === false || event.defaultPrevented === true)
- allowTransition = false;
-
- event.preventDefault();
-
- if (allowTransition)
- this.transitionTo(this.props.to, this.props.params, this.props.query);
- },
-
- /**
- * Returns the value of the "href" attribute to use on the DOM element.
- */
- getHref: function () {
- return this.makeHref(this.props.to, this.props.params, this.props.query);
- },
-
- /**
- * Returns the value of the "class" attribute to use on the DOM element, which contains
- * the value of the activeClassName property when this <Link> is active.
- */
- getClassName: function () {
- var classNames = {};
-
- if (this.props.className)
- classNames[this.props.className] = true;
-
- if (this.isActive(this.props.to, this.props.params, this.props.query))
- classNames[this.props.activeClassName] = true;
-
- return classSet(classNames);
- },
-
- render: function () {
- var props = assign({}, this.props, {
- href: this.getHref(),
- className: this.getClassName(),
- onClick: this.handleClick
- });
-
- return React.DOM.a(props, this.props.children);
- }
-
-});
-
-module.exports = Link;
-
-},{"../mixins/Navigation":15,"../mixins/State":18,"react/lib/Object.assign":38,"react/lib/cx":39}],6:[function(_dereq_,module,exports){
-var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
-var FakeNode = _dereq_('../mixins/FakeNode');
-var PropTypes = _dereq_('../utils/PropTypes');
-
-/**
- * A <NotFoundRoute> is a special kind of <Route> that
- * renders when the beginning of its parent's path matches
- * but none of its siblings do, including any <DefaultRoute>.
- * Only one such route may be used at any given level in the
- * route hierarchy.
- */
-var NotFoundRoute = React.createClass({
-
- displayName: 'NotFoundRoute',
-
- mixins: [ FakeNode ],
-
- propTypes: {
- name: React.PropTypes.string,
- path: PropTypes.falsy,
- handler: React.PropTypes.func.isRequired
- }
-
-});
-
-module.exports = NotFoundRoute;
-
-},{"../mixins/FakeNode":14,"../utils/PropTypes":23}],7:[function(_dereq_,module,exports){
-var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
-var FakeNode = _dereq_('../mixins/FakeNode');
-var PropTypes = _dereq_('../utils/PropTypes');
-
-/**
- * A <Redirect> component is a special kind of <Route> that always
- * redirects to another route when it matches.
- */
-var Redirect = React.createClass({
-
- displayName: 'Redirect',
-
- mixins: [ FakeNode ],
-
- propTypes: {
- path: React.PropTypes.string,
- from: React.PropTypes.string, // Alias for path.
- to: React.PropTypes.string,
- handler: PropTypes.falsy
- }
-
-});
-
-module.exports = Redirect;
-
-},{"../mixins/FakeNode":14,"../utils/PropTypes":23}],8:[function(_dereq_,module,exports){
-var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
-var FakeNode = _dereq_('../mixins/FakeNode');
-
-/**
- * <Route> components specify components that are rendered to the page when the
- * URL matches a given pattern.
- *
- * Routes are arranged in a nested tree structure. When a new URL is requested,
- * the tree is searched depth-first to find a route whose path matches the URL.
- * When one is found, all routes in the tree that lead to it are considered
- * "active" and their components are rendered into the DOM, nested in the same
- * order as they are in the tree.
- *
- * The preferred way to configure a router is using JSX. The XML-like syntax is
- * a great way to visualize how routes are laid out in an application.
- *
- * var routes = [
- * <Route handler={App}>
- * <Route name="login" handler={Login}/>
- * <Route name="logout" handler={Logout}/>
- * <Route name="about" handler={About}/>
- * </Route>
- * ];
- *
- * Router.run(routes, function (Handler) {
- * React.render(<Handler/>, document.body);
- * });
- *
- * Handlers for Route components that contain children can render their active
- * child route using a <RouteHandler> element.
- *
- * var App = React.createClass({
- * render: function () {
- * return (
- * <div class="application">
- * <RouteHandler/>
- * </div>
- * );
- * }
- * });
- */
-var Route = React.createClass({
-
- displayName: 'Route',
-
- mixins: [ FakeNode ],
-
- propTypes: {
- name: React.PropTypes.string,
- path: React.PropTypes.string,
- handler: React.PropTypes.func.isRequired,
- ignoreScrollBehavior: React.PropTypes.bool
- }
-
-});
-
-module.exports = Route;
-
-},{"../mixins/FakeNode":14}],9:[function(_dereq_,module,exports){
-var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
-
-/**
- * A <RouteHandler> component renders the active child route handler
- * when routes are nested.
- */
-var RouteHandler = React.createClass({
-
- displayName: 'RouteHandler',
-
- getDefaultProps: function () {
- return {
- ref: '__routeHandler__'
- };
- },
-
- contextTypes: {
- getRouteAtDepth: React.PropTypes.func.isRequired,
- getRouteComponents: React.PropTypes.func.isRequired,
- routeHandlers: React.PropTypes.array.isRequired
- },
-
- childContextTypes: {
- routeHandlers: React.PropTypes.array.isRequired
- },
-
- getChildContext: function () {
- return {
- routeHandlers: this.context.routeHandlers.concat([ this ])
- };
- },
-
- getRouteDepth: function () {
- return this.context.routeHandlers.length - 1;
- },
-
- componentDidMount: function () {
- this._updateRouteComponent();
- },
-
- componentDidUpdate: function () {
- this._updateRouteComponent();
- },
-
- _updateRouteComponent: function () {
- var depth = this.getRouteDepth();
- var components = this.context.getRouteComponents();
- components[depth] = this.refs[this.props.ref];
- },
-
- render: function () {
- var route = this.context.getRouteAtDepth(this.getRouteDepth());
- return route ? React.createElement(route.handler, this.props) : null;
- }
-
-});
-
-module.exports = RouteHandler;
-
-},{}],10:[function(_dereq_,module,exports){
-exports.DefaultRoute = _dereq_('./components/DefaultRoute');
-exports.Link = _dereq_('./components/Link');
-exports.NotFoundRoute = _dereq_('./components/NotFoundRoute');
-exports.Redirect = _dereq_('./components/Redirect');
-exports.Route = _dereq_('./components/Route');
-exports.RouteHandler = _dereq_('./components/RouteHandler');
-
-exports.HashLocation = _dereq_('./locations/HashLocation');
-exports.HistoryLocation = _dereq_('./locations/HistoryLocation');
-exports.RefreshLocation = _dereq_('./locations/RefreshLocation');
-
-exports.ImitateBrowserBehavior = _dereq_('./behaviors/ImitateBrowserBehavior');
-exports.ScrollToTopBehavior = _dereq_('./behaviors/ScrollToTopBehavior');
-
-exports.Navigation = _dereq_('./mixins/Navigation');
-exports.State = _dereq_('./mixins/State');
-
-exports.create = _dereq_('./utils/createRouter');
-exports.run = _dereq_('./utils/runRouter');
-
-},{"./behaviors/ImitateBrowserBehavior":2,"./behaviors/ScrollToTopBehavior":3,"./components/DefaultRoute":4,"./components/Link":5,"./components/NotFoundRoute":6,"./components/Redirect":7,"./components/Route":8,"./components/RouteHandler":9,"./locations/HashLocation":11,"./locations/HistoryLocation":12,"./locations/RefreshLocation":13,"./mixins/Navigation":15,"./mixins/State":18,"./utils/createRouter":26,"./utils/runRouter":30}],11:[function(_dereq_,module,exports){
-var invariant = _dereq_('react/lib/invariant');
-var canUseDOM = _dereq_('react/lib/ExecutionEnvironment').canUseDOM;
-var LocationActions = _dereq_('../actions/LocationActions');
-var Path = _dereq_('../utils/Path');
-
-/**
- * Returns the current URL path from `window.location.hash`, including query string
- */
-function getHashPath() {
- invariant(
- canUseDOM,
- 'getHashPath needs a DOM'
- );
-
- return Path.decode(
- window.location.hash.substr(1)
- );
-}
-
-var _actionType;
-
-function ensureSlash() {
- var path = getHashPath();
-
- if (path.charAt(0) === '/')
- return true;
-
- HashLocation.replace('/' + path);
-
- return false;
-}
-
-var _changeListeners = [];
-
-function notifyChange(type) {
- var change = {
- path: getHashPath(),
- type: type
- };
-
- _changeListeners.forEach(function (listener) {
- listener(change);
- });
-}
-
-var _isListening = false;
-
-function onHashChange() {
- if (ensureSlash()) {
- // If we don't have an _actionType then all we know is the hash
- // changed. It was probably caused by the user clicking the Back
- // button, but may have also been the Forward button or manual
- // manipulation. So just guess 'pop'.
- notifyChange(_actionType || LocationActions.POP);
- _actionType = null;
- }
-}
-
-/**
- * A Location that uses `window.location.hash`.
- */
-var HashLocation = {
-
- addChangeListener: function (listener) {
- _changeListeners.push(listener);
-
- // Do this BEFORE listening for hashchange.
- ensureSlash();
-
- if (_isListening)
- return;
-
- if (window.addEventListener) {
- window.addEventListener('hashchange', onHashChange, false);
- } else {
- window.attachEvent('onhashchange', onHashChange);
- }
-
- _isListening = true;
- },
-
- push: function (path) {
- _actionType = LocationActions.PUSH;
- window.location.hash = Path.encode(path);
- },
-
- replace: function (path) {
- _actionType = LocationActions.REPLACE;
- window.location.replace(window.location.pathname + '#' + Path.encode(path));
- },
-
- pop: function () {
- _actionType = LocationActions.POP;
- window.history.back();
- },
-
- getCurrentPath: getHashPath,
-
- toString: function () {
- return '<HashLocation>';
- }
-
-};
-
-module.exports = HashLocation;
-
-},{"../actions/LocationActions":1,"../utils/Path":21,"react/lib/ExecutionEnvironment":37,"react/lib/invariant":41}],12:[function(_dereq_,module,exports){
-var invariant = _dereq_('react/lib/invariant');
-var canUseDOM = _dereq_('react/lib/ExecutionEnvironment').canUseDOM;
-var LocationActions = _dereq_('../actions/LocationActions');
-var Path = _dereq_('../utils/Path');
-
-/**
- * Returns the current URL path from `window.location`, including query string
- */
-function getWindowPath() {
- invariant(
- canUseDOM,
- 'getWindowPath needs a DOM'
- );
-
- return Path.decode(
- window.location.pathname + window.location.search
- );
-}
-
-var _changeListeners = [];
-
-function notifyChange(type) {
- var change = {
- path: getWindowPath(),
- type: type
- };
-
- _changeListeners.forEach(function (listener) {
- listener(change);
- });
-}
-
-var _isListening = false;
-
-function onPopState() {
- notifyChange(LocationActions.POP);
-}
-
-/**
- * A Location that uses HTML5 history.
- */
-var HistoryLocation = {
-
- addChangeListener: function (listener) {
- _changeListeners.push(listener);
-
- if (_isListening)
- return;
-
- if (window.addEventListener) {
- window.addEventListener('popstate', onPopState, false);
- } else {
- window.attachEvent('popstate', onPopState);
- }
-
- _isListening = true;
- },
-
- push: function (path) {
- window.history.pushState({ path: path }, '', Path.encode(path));
- notifyChange(LocationActions.PUSH);
- },
-
- replace: function (path) {
- window.history.replaceState({ path: path }, '', Path.encode(path));
- notifyChange(LocationActions.REPLACE);
- },
-
- pop: function () {
- window.history.back();
- },
-
- getCurrentPath: getWindowPath,
-
- toString: function () {
- return '<HistoryLocation>';
- }
-
-};
-
-module.exports = HistoryLocation;
-
-},{"../actions/LocationActions":1,"../utils/Path":21,"react/lib/ExecutionEnvironment":37,"react/lib/invariant":41}],13:[function(_dereq_,module,exports){
-var HistoryLocation = _dereq_('./HistoryLocation');
-var Path = _dereq_('../utils/Path');
-
-/**
- * A Location that uses full page refreshes. This is used as
- * the fallback for HistoryLocation in browsers that do not
- * support the HTML5 history API.
- */
-var RefreshLocation = {
-
- push: function (path) {
- window.location = Path.encode(path);
- },
-
- replace: function (path) {
- window.location.replace(Path.encode(path));
- },
-
- pop: function () {
- window.history.back();
- },
-
- getCurrentPath: HistoryLocation.getCurrentPath,
-
- toString: function () {
- return '<RefreshLocation>';
- }
-
-};
-
-module.exports = RefreshLocation;
-
-},{"../utils/Path":21,"./HistoryLocation":12}],14:[function(_dereq_,module,exports){
-var invariant = _dereq_('react/lib/invariant');
-
-var FakeNode = {
-
- render: function () {
- invariant(
- false,
- '%s elements should not be rendered',
- this.constructor.displayName
- );
- }
-
-};
-
-module.exports = FakeNode;
-
-},{"react/lib/invariant":41}],15:[function(_dereq_,module,exports){
-var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
-
-/**
- * A mixin for components that modify the URL.
- *
- * Example:
- *
- * var MyLink = React.createClass({
- * mixins: [ Router.Navigation ],
- * handleClick: function (event) {
- * event.preventDefault();
- * this.transitionTo('aRoute', { the: 'params' }, { the: 'query' });
- * },
- * render: function () {
- * return (
- * <a onClick={this.handleClick}>Click me!</a>
- * );
- * }
- * });
- */
-var Navigation = {
-
- contextTypes: {
- makePath: React.PropTypes.func.isRequired,
- makeHref: React.PropTypes.func.isRequired,
- transitionTo: React.PropTypes.func.isRequired,
- replaceWith: React.PropTypes.func.isRequired,
- goBack: React.PropTypes.func.isRequired
- },
-
- /**
- * Returns an absolute URL path created from the given route
- * name, URL parameters, and query values.
- */
- makePath: function (to, params, query) {
- return this.context.makePath(to, params, query);
- },
-
- /**
- * Returns a string that may safely be used as the href of a
- * link to the route with the given name.
- */
- makeHref: function (to, params, query) {
- return this.context.makeHref(to, params, query);
- },
-
- /**
- * Transitions to the URL specified in the arguments by pushing
- * a new URL onto the history stack.
- */
- transitionTo: function (to, params, query) {
- this.context.transitionTo(to, params, query);
- },
-
- /**
- * Transitions to the URL specified in the arguments by replacing
- * the current URL in the history stack.
- */
- replaceWith: function (to, params, query) {
- this.context.replaceWith(to, params, query);
- },
-
- /**
- * Transitions to the previous URL.
- */
- goBack: function () {
- this.context.goBack();
- }
-
-};
-
-module.exports = Navigation;
-
-},{}],16:[function(_dereq_,module,exports){
-var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
-
-/**
- * Provides the router with context for Router.Navigation.
- */
-var NavigationContext = {
-
- childContextTypes: {
- makePath: React.PropTypes.func.isRequired,
- makeHref: React.PropTypes.func.isRequired,
- transitionTo: React.PropTypes.func.isRequired,
- replaceWith: React.PropTypes.func.isRequired,
- goBack: React.PropTypes.func.isRequired
- },
-
- getChildContext: function () {
- return {
- makePath: this.constructor.makePath,
- makeHref: this.constructor.makeHref,
- transitionTo: this.constructor.transitionTo,
- replaceWith: this.constructor.replaceWith,
- goBack: this.constructor.goBack
- };
- }
-
-};
-
-module.exports = NavigationContext;
-
-},{}],17:[function(_dereq_,module,exports){
-var invariant = _dereq_('react/lib/invariant');
-var canUseDOM = _dereq_('react/lib/ExecutionEnvironment').canUseDOM;
-var getWindowScrollPosition = _dereq_('../utils/getWindowScrollPosition');
-
-function shouldUpdateScroll(state, prevState) {
- if (!prevState)
- return true;
-
- // Don't update scroll position when only the query has changed.
- if (state.pathname === prevState.pathname)
- return false;
-
- var routes = state.routes;
- var prevRoutes = prevState.routes;
-
- var sharedAncestorRoutes = routes.filter(function (route) {
- return prevRoutes.indexOf(route) !== -1;
- });
-
- return !sharedAncestorRoutes.some(function (route) {
- return route.ignoreScrollBehavior;
- });
-}
-
-/**
- * Provides the router with the ability to manage window scroll position
- * according to its scroll behavior.
- */
-var Scrolling = {
-
- statics: {
- /**
- * Records curent scroll position as the last known position for the given URL path.
- */
- recordScrollPosition: function (path) {
- if (!this.scrollHistory)
- this.scrollHistory = {};
-
- this.scrollHistory[path] = getWindowScrollPosition();
- },
-
- /**
- * Returns the last known scroll position for the given URL path.
- */
- getScrollPosition: function (path) {
- if (!this.scrollHistory)
- this.scrollHistory = {};
-
- return this.scrollHistory[path] || null;
- }
- },
-
- componentWillMount: function () {
- invariant(
- this.getScrollBehavior() == null || canUseDOM,
- 'Cannot use scroll behavior without a DOM'
- );
- },
-
- componentDidMount: function () {
- this._updateScroll();
- },
-
- componentDidUpdate: function (prevProps, prevState) {
- this._updateScroll(prevState);
- },
-
- _updateScroll: function (prevState) {
- if (!shouldUpdateScroll(this.state, prevState))
- return;
-
- var scrollBehavior = this.getScrollBehavior();
-
- if (scrollBehavior)
- scrollBehavior.updateScrollPosition(
- this.constructor.getScrollPosition(this.state.path),
- this.state.action
- );
- }
-
-};
-
-module.exports = Scrolling;
-
-},{"../utils/getWindowScrollPosition":28,"react/lib/ExecutionEnvironment":37,"react/lib/invariant":41}],18:[function(_dereq_,module,exports){
-var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
-
-/**
- * A mixin for components that need to know the path, routes, URL
- * params and query that are currently active.
- *
- * Example:
- *
- * var AboutLink = React.createClass({
- * mixins: [ Router.State ],
- * render: function () {
- * var className = this.props.className;
- *
- * if (this.isActive('about'))
- * className += ' is-active';
- *
- * return React.DOM.a({ className: className }, this.props.children);
- * }
- * });
- */
-var State = {
-
- contextTypes: {
- getCurrentPath: React.PropTypes.func.isRequired,
- getCurrentRoutes: React.PropTypes.func.isRequired,
- getCurrentPathname: React.PropTypes.func.isRequired,
- getCurrentParams: React.PropTypes.func.isRequired,
- getCurrentQuery: React.PropTypes.func.isRequired,
- isActive: React.PropTypes.func.isRequired
- },
-
- /**
- * Returns the current URL path.
- */
- getPath: function () {
- return this.context.getCurrentPath();
- },
-
- /**
- * Returns an array of the routes that are currently active.
- */
- getRoutes: function () {
- return this.context.getCurrentRoutes();
- },
-
- /**
- * Returns the current URL path without the query string.
- */
- getPathname: function () {
- return this.context.getCurrentPathname();
- },
-
- /**
- * Returns an object of the URL params that are currently active.
- */
- getParams: function () {
- return this.context.getCurrentParams();
- },
-
- /**
- * Returns an object of the query params that are currently active.
- */
- getQuery: function () {
- return this.context.getCurrentQuery();
- },
-
- /**
- * A helper method to determine if a given route, params, and query
- * are active.
- */
- isActive: function (to, params, query) {
- return this.context.isActive(to, params, query);
- }
-
-};
-
-module.exports = State;
-
-},{}],19:[function(_dereq_,module,exports){
-var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
-var assign = _dereq_('react/lib/Object.assign');
-var Path = _dereq_('../utils/Path');
-
-function routeIsActive(activeRoutes, routeName) {
- return activeRoutes.some(function (route) {
- return route.name === routeName;
- });
-}
-
-function paramsAreActive(activeParams, params) {
- for (var property in params)
- if (String(activeParams[property]) !== String(params[property]))
- return false;
-
- return true;
-}
-
-function queryIsActive(activeQuery, query) {
- for (var property in query)
- if (String(activeQuery[property]) !== String(query[property]))
- return false;
-
- return true;
-}
-
-/**
- * Provides the router with context for Router.State.
- */
-var StateContext = {
-
- /**
- * Returns the current URL path + query string.
- */
- getCurrentPath: function () {
- return this.state.path;
- },
-
- /**
- * Returns a read-only array of the currently active routes.
- */
- getCurrentRoutes: function () {
- return this.state.routes.slice(0);
- },
-
- /**
- * Returns the current URL path without the query string.
- */
- getCurrentPathname: function () {
- return this.state.pathname;
- },
-
- /**
- * Returns a read-only object of the currently active URL parameters.
- */
- getCurrentParams: function () {
- return assign({}, this.state.params);
- },
-
- /**
- * Returns a read-only object of the currently active query parameters.
- */
- getCurrentQuery: function () {
- return assign({}, this.state.query);
- },
-
- /**
- * Returns true if the given route, params, and query are active.
- */
- isActive: function (to, params, query) {
- if (Path.isAbsolute(to))
- return to === this.state.path;
-
- return routeIsActive(this.state.routes, to) &&
- paramsAreActive(this.state.params, params) &&
- (query == null || queryIsActive(this.state.query, query));
- },
-
- childContextTypes: {
- getCurrentPath: React.PropTypes.func.isRequired,
- getCurrentRoutes: React.PropTypes.func.isRequired,
- getCurrentPathname: React.PropTypes.func.isRequired,
- getCurrentParams: React.PropTypes.func.isRequired,
- getCurrentQuery: React.PropTypes.func.isRequired,
- isActive: React.PropTypes.func.isRequired
- },
-
- getChildContext: function () {
- return {
- getCurrentPath: this.getCurrentPath,
- getCurrentRoutes: this.getCurrentRoutes,
- getCurrentPathname: this.getCurrentPathname,
- getCurrentParams: this.getCurrentParams,
- getCurrentQuery: this.getCurrentQuery,
- isActive: this.isActive
- };
- }
-
-};
-
-module.exports = StateContext;
-
-},{"../utils/Path":21,"react/lib/Object.assign":38}],20:[function(_dereq_,module,exports){
-/**
- * Represents a cancellation caused by navigating away
- * before the previous transition has fully resolved.
- */
-function Cancellation() { }
-
-module.exports = Cancellation;
-
-},{}],21:[function(_dereq_,module,exports){
-var invariant = _dereq_('react/lib/invariant');
-var merge = _dereq_('qs/lib/utils').merge;
-var qs = _dereq_('qs');
-
-var paramCompileMatcher = /:([a-zA-Z_$][a-zA-Z0-9_$]*)|[*.()\[\]\\+|{}^$]/g;
-var paramInjectMatcher = /:([a-zA-Z_$][a-zA-Z0-9_$?]*[?]?)|[*]/g;
-var paramInjectTrailingSlashMatcher = /\/\/\?|\/\?/g;
-var queryMatcher = /\?(.+)/;
-
-var _compiledPatterns = {};
-
-function compilePattern(pattern) {
- if (!(pattern in _compiledPatterns)) {
- var paramNames = [];
- var source = pattern.replace(paramCompileMatcher, function (match, paramName) {
- if (paramName) {
- paramNames.push(paramName);
- return '([^/?#]+)';
- } else if (match === '*') {
- paramNames.push('splat');
- return '(.*?)';
- } else {
- return '\\' + match;
- }
- });
-
- _compiledPatterns[pattern] = {
- matcher: new RegExp('^' + source + '$', 'i'),
- paramNames: paramNames
- };
- }
-
- return _compiledPatterns[pattern];
-}
-
-var Path = {
-
- /**
- * Safely decodes special characters in the given URL path.
- */
- decode: function (path) {
- return decodeURI(path.replace(/\+/g, ' '));
- },
-
- /**
- * Safely encodes special characters in the given URL path.
- */
- encode: function (path) {
- return encodeURI(path).replace(/%20/g, '+');
- },
-
- /**
- * Returns an array of the names of all parameters in the given pattern.
- */
- extractParamNames: function (pattern) {
- return compilePattern(pattern).paramNames;
- },
-
- /**
- * Extracts the portions of the given URL path that match the given pattern
- * and returns an object of param name => value pairs. Returns null if the
- * pattern does not match the given path.
- */
- extractParams: function (pattern, path) {
- var object = compilePattern(pattern);
- var match = path.match(object.matcher);
-
- if (!match)
- return null;
-
- var params = {};
-
- object.paramNames.forEach(function (paramName, index) {
- params[paramName] = match[index + 1];
- });
-
- return params;
- },
-
- /**
- * Returns a version of the given route path with params interpolated. Throws
- * if there is a dynamic segment of the route path for which there is no param.
- */
- injectParams: function (pattern, params) {
- params = params || {};
-
- var splatIndex = 0;
-
- return pattern.replace(paramInjectMatcher, function (match, paramName) {
- paramName = paramName || 'splat';
-
- // If param is optional don't check for existence
- if (paramName.slice(-1) !== '?') {
- invariant(
- params[paramName] != null,
- 'Missing "' + paramName + '" parameter for path "' + pattern + '"'
- );
- } else {
- paramName = paramName.slice(0, -1);
-
- if (params[paramName] == null)
- return '';
- }
-
- var segment;
- if (paramName === 'splat' && Array.isArray(params[paramName])) {
- segment = params[paramName][splatIndex++];
-
- invariant(
- segment != null,
- 'Missing splat # ' + splatIndex + ' for path "' + pattern + '"'
- );
- } else {
- segment = params[paramName];
- }
-
- return segment;
- }).replace(paramInjectTrailingSlashMatcher, '/');
- },
-
- /**
- * Returns an object that is the result of parsing any query string contained
- * in the given path, null if the path contains no query string.
- */
- extractQuery: function (path) {
- var match = path.match(queryMatcher);
- return match && qs.parse(match[1]);
- },
-
- /**
- * Returns a version of the given path without the query string.
- */
- withoutQuery: function (path) {
- return path.replace(queryMatcher, '');
- },
-
- /**
- * Returns a version of the given path with the parameters in the given
- * query merged into the query string.
- */
- withQuery: function (path, query) {
- var existingQuery = Path.extractQuery(path);
-
- if (existingQuery)
- query = query ? merge(existingQuery, query) : existingQuery;
-
- var queryString = query && qs.stringify(query);
-
- if (queryString)
- return Path.withoutQuery(path) + '?' + queryString;
-
- return path;
- },
-
- /**
- * Returns true if the given path is absolute.
- */
- isAbsolute: function (path) {
- return path.charAt(0) === '/';
- },
-
- /**
- * Returns a normalized version of the given path.
- */
- normalize: function (path, parentRoute) {
- return path.replace(/^\/*/, '/');
- },
-
- /**
- * Joins two URL paths together.
- */
- join: function (a, b) {
- return a.replace(/\/*$/, '/') + b;
- }
-
-};
-
-module.exports = Path;
-
-},{"qs":32,"qs/lib/utils":36,"react/lib/invariant":41}],22:[function(_dereq_,module,exports){
-var Promise = _dereq_('when/lib/Promise');
-
-// TODO: Use process.env.NODE_ENV check + envify to enable
-// when's promise monitor here when in dev.
-
-module.exports = Promise;
-
-},{"when/lib/Promise":43}],23:[function(_dereq_,module,exports){
-var PropTypes = {
-
- /**
- * Requires that the value of a prop be falsy.
- */
- falsy: function (props, propName, elementName) {
- if (props[propName])
- return new Error('<' + elementName + '> may not have a "' + propName + '" prop');
- }
-
-};
-
-module.exports = PropTypes;
-
-},{}],24:[function(_dereq_,module,exports){
-/**
- * Encapsulates a redirect to the given route.
- */
-function Redirect(to, params, query) {
- this.to = to;
- this.params = params;
- this.query = query;
-}
-
-module.exports = Redirect;
-
-},{}],25:[function(_dereq_,module,exports){
-var assign = _dereq_('react/lib/Object.assign');
-var reversedArray = _dereq_('./reversedArray');
-var Redirect = _dereq_('./Redirect');
-var Promise = _dereq_('./Promise');
-
-/**
- * Runs all hook functions serially and calls callback(error) when finished.
- * A hook may return a promise if it needs to execute asynchronously.
- */
-function runHooks(hooks, callback) {
- try {
- var promise = hooks.reduce(function (promise, hook) {
- // The first hook to use transition.wait makes the rest
- // of the transition async from that point forward.
- return promise ? promise.then(hook) : hook();
- }, null);
- } catch (error) {
- return callback(error); // Sync error.
- }
-
- if (promise) {
- // Use setTimeout to break the promise chain.
- promise.then(function () {
- setTimeout(callback);
- }, function (error) {
- setTimeout(function () {
- callback(error);
- });
- });
- } else {
- callback();
- }
-}
-
-/**
- * Calls the willTransitionFrom hook of all handlers in the given matches
- * serially in reverse with the transition object and the current instance of
- * the route's handler, so that the deepest nested handlers are called first.
- * Calls callback(error) when finished.
- */
-function runTransitionFromHooks(transition, routes, components, callback) {
- components = reversedArray(components);
-
- var hooks = reversedArray(routes).map(function (route, index) {
- return function () {
- var handler = route.handler;
-
- if (!transition.isAborted && handler.willTransitionFrom)
- return handler.willTransitionFrom(transition, components[index]);
-
- var promise = transition._promise;
- transition._promise = null;
-
- return promise;
- };
- });
-
- runHooks(hooks, callback);
-}
-
-/**
- * Calls the willTransitionTo hook of all handlers in the given matches
- * serially with the transition object and any params that apply to that
- * handler. Calls callback(error) when finished.
- */
-function runTransitionToHooks(transition, routes, params, query, callback) {
- var hooks = routes.map(function (route) {
- return function () {
- var handler = route.handler;
-
- if (!transition.isAborted && handler.willTransitionTo)
- handler.willTransitionTo(transition, params, query);
-
- var promise = transition._promise;
- transition._promise = null;
-
- return promise;
- };
- });
-
- runHooks(hooks, callback);
-}
-
-/**
- * Encapsulates a transition to a given path.
- *
- * The willTransitionTo and willTransitionFrom handlers receive
- * an instance of this class as their first argument.
- */
-function Transition(path, retry) {
- this.path = path;
- this.abortReason = null;
- this.isAborted = false;
- this.retry = retry.bind(this);
- this._promise = null;
-}
-
-assign(Transition.prototype, {
-
- abort: function (reason) {
- if (this.isAborted) {
- // First abort wins.
- return;
- }
-
- this.abortReason = reason;
- this.isAborted = true;
- },
-
- redirect: function (to, params, query) {
- this.abort(new Redirect(to, params, query));
- },
-
- wait: function (value) {
- this._promise = Promise.resolve(value);
- },
-
- from: function (routes, components, callback) {
- return runTransitionFromHooks(this, routes, components, callback);
- },
-
- to: function (routes, params, query, callback) {
- return runTransitionToHooks(this, routes, params, query, callback);
- }
-
-});
-
-module.exports = Transition;
-
-},{"./Promise":22,"./Redirect":24,"./reversedArray":29,"react/lib/Object.assign":38}],26:[function(_dereq_,module,exports){
-var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
-var warning = _dereq_('react/lib/warning');
-var invariant = _dereq_('react/lib/invariant');
-var canUseDOM = _dereq_('react/lib/ExecutionEnvironment').canUseDOM;
-var ImitateBrowserBehavior = _dereq_('../behaviors/ImitateBrowserBehavior');
-var RouteHandler = _dereq_('../components/RouteHandler');
-var LocationActions = _dereq_('../actions/LocationActions');
-var HashLocation = _dereq_('../locations/HashLocation');
-var HistoryLocation = _dereq_('../locations/HistoryLocation');
-var RefreshLocation = _dereq_('../locations/RefreshLocation');
-var NavigationContext = _dereq_('../mixins/NavigationContext');
-var StateContext = _dereq_('../mixins/StateContext');
-var Scrolling = _dereq_('../mixins/Scrolling');
-var createRoutesFromChildren = _dereq_('./createRoutesFromChildren');
-var supportsHistory = _dereq_('./supportsHistory');
-var Transition = _dereq_('./Transition');
-var PropTypes = _dereq_('./PropTypes');
-var Redirect = _dereq_('./Redirect');
-var Cancellation = _dereq_('./Cancellation');
-var Path = _dereq_('./Path');
-
-/**
- * The default location for new routers.
- */
-var DEFAULT_LOCATION = canUseDOM ? HashLocation : '/';
-
-/**
- * The default scroll behavior for new routers.
- */
-var DEFAULT_SCROLL_BEHAVIOR = canUseDOM ? ImitateBrowserBehavior : null;
-
-/**
- * The default error handler for new routers.
- */
-function defaultErrorHandler(error) {
- // Throw so we don't silently swallow async errors.
- throw error; // This error probably originated in a transition hook.
-}
-
-/**
- * The default aborted transition handler for new routers.
- */
-function defaultAbortHandler(abortReason, location) {
- if (typeof location === 'string')
- throw new Error('Unhandled aborted transition! Reason: ' + abortReason);
-
- if (abortReason instanceof Cancellation) {
- return;
- } else if (abortReason instanceof Redirect) {
- location.replace(this.makePath(abortReason.to, abortReason.params, abortReason.query));
- } else {
- location.pop();
- }
-}
-
-function findMatch(pathname, routes, defaultRoute, notFoundRoute) {
- var match, route, params;
-
- for (var i = 0, len = routes.length; i < len; ++i) {
- route = routes[i];
-
- // Check the subtree first to find the most deeply-nested match.
- match = findMatch(pathname, route.childRoutes, route.defaultRoute, route.notFoundRoute);
-
- if (match != null) {
- match.routes.unshift(route);
- return match;
- }
-
- // No routes in the subtree matched, so check this route.
- params = Path.extractParams(route.path, pathname);
-
- if (params)
- return createMatch(route, params);
- }
-
- // No routes matched, so try the default route if there is one.
- if (defaultRoute && (params = Path.extractParams(defaultRoute.path, pathname)))
- return createMatch(defaultRoute, params);
-
- // Last attempt: does the "not found" route match?
- if (notFoundRoute && (params = Path.extractParams(notFoundRoute.path, pathname)))
- return createMatch(notFoundRoute, params);
-
- return match;
-}
-
-function createMatch(route, params) {
- return { routes: [ route ], params: params };
-}
-
-function hasMatch(routes, route, prevParams, nextParams) {
- return routes.some(function (r) {
- if (r !== route)
- return false;
-
- var paramNames = route.paramNames;
- var paramName;
-
- for (var i = 0, len = paramNames.length; i < len; ++i) {
- paramName = paramNames[i];
-
- if (nextParams[paramName] !== prevParams[paramName])
- return false;
- }
-
- return true;
- });
-}
-
-/**
- * Creates and returns a new router using the given options. A router
- * is a ReactComponent class that knows how to react to changes in the
- * URL and keep the contents of the page in sync.
- *
- * Options may be any of the following:
- *
- * - routes (required) The route config
- * - location The location to use. Defaults to HashLocation when
- * the DOM is available, "/" otherwise
- * - scrollBehavior The scroll behavior to use. Defaults to ImitateBrowserBehavior
- * when the DOM is available, null otherwise
- * - onError A function that is used to handle errors
- * - onAbort A function that is used to handle aborted transitions
- *
- * When rendering in a server-side environment, the location should simply
- * be the URL path that was used in the request, including the query string.
- */
-function createRouter(options) {
- options = options || {};
-
- if (typeof options === 'function') {
- options = { routes: options }; // Router.create(<Route>)
- } else if (Array.isArray(options)) {
- options = { routes: options }; // Router.create([ <Route>, <Route> ])
- }
-
- var routes = [];
- var namedRoutes = {};
- var components = [];
- var location = options.location || DEFAULT_LOCATION;
- var scrollBehavior = options.scrollBehavior || DEFAULT_SCROLL_BEHAVIOR;
- var onError = options.onError || defaultErrorHandler;
- var onAbort = options.onAbort || defaultAbortHandler;
- var state = {};
- var nextState = {};
- var pendingTransition = null;
-
- function updateState() {
- state = nextState;
- nextState = {};
- }
-
- // Automatically fall back to full page refreshes in
- // browsers that don't support the HTML history API.
- if (location === HistoryLocation && !supportsHistory())
- location = RefreshLocation;
-
- var router = React.createClass({
-
- displayName: 'Router',
-
- mixins: [ NavigationContext, StateContext, Scrolling ],
-
- statics: {
-
- defaultRoute: null,
- notFoundRoute: null,
-
- /**
- * Adds routes to this router from the given children object (see ReactChildren).
- */
- addRoutes: function (children) {
- routes.push.apply(routes, createRoutesFromChildren(children, this, namedRoutes));
- },
-
- /**
- * Returns an absolute URL path created from the given route
- * name, URL parameters, and query.
- */
- makePath: function (to, params, query) {
- var path;
- if (Path.isAbsolute(to)) {
- path = Path.normalize(to);
- } else {
- var route = namedRoutes[to];
-
- invariant(
- route,
- 'Unable to find <Route name="%s">',
- to
- );
-
- path = route.path;
- }
-
- return Path.withQuery(Path.injectParams(path, params), query);
- },
-
- /**
- * Returns a string that may safely be used as the href of a link
- * to the route with the given name, URL parameters, and query.
- */
- makeHref: function (to, params, query) {
- var path = this.makePath(to, params, query);
- return (location === HashLocation) ? '#' + path : path;
- },
-
- /**
- * Transitions to the URL specified in the arguments by pushing
- * a new URL onto the history stack.
- */
- transitionTo: function (to, params, query) {
- invariant(
- typeof location !== 'string',
- 'You cannot use transitionTo with a static location'
- );
-
- var path = this.makePath(to, params, query);
-
- if (pendingTransition) {
- // Replace so pending location does not stay in history.
- location.replace(path);
- } else {
- location.push(path);
- }
- },
-
- /**
- * Transitions to the URL specified in the arguments by replacing
- * the current URL in the history stack.
- */
- replaceWith: function (to, params, query) {
- invariant(
- typeof location !== 'string',
- 'You cannot use replaceWith with a static location'
- );
-
- location.replace(this.makePath(to, params, query));
- },
-
- /**
- * Transitions to the previous URL.
- */
- goBack: function () {
- invariant(
- typeof location !== 'string',
- 'You cannot use goBack with a static location'
- );
-
- location.pop();
- },
-
- /**
- * Performs a match of the given pathname against this router and returns an object
- * with the { routes, params } that match. Returns null if no match can be made.
- */
- match: function (pathname) {
- return findMatch(pathname, routes, this.defaultRoute, this.notFoundRoute) || null;
- },
-
- /**
- * Performs a transition to the given path and calls callback(error, abortReason)
- * when the transition is finished. If both arguments are null the router's state
- * was updated. Otherwise the transition did not complete.
- *
- * In a transition, a router first determines which routes are involved by beginning
- * with the current route, up the route tree to the first parent route that is shared
- * with the destination route, and back down the tree to the destination route. The
- * willTransitionFrom hook is invoked on all route handlers we're transitioning away
- * from, in reverse nesting order. Likewise, the willTransitionTo hook is invoked on
- * all route handlers we're transitioning to.
- *
- * Both willTransitionFrom and willTransitionTo hooks may either abort or redirect the
- * transition. To resolve asynchronously, they may use transition.wait(promise). If no
- * hooks wait, the transition is fully synchronous.
- */
- dispatch: function (path, action, callback) {
- if (pendingTransition) {
- pendingTransition.abort(new Cancellation);
- pendingTransition = null;
- }
-
- var prevPath = state.path;
- if (prevPath === path)
- return; // Nothing to do!
-
- // Record the scroll position as early as possible to
- // get it before browsers try update it automatically.
- if (prevPath && action !== LocationActions.REPLACE)
- this.recordScrollPosition(prevPath);
-
- var pathname = Path.withoutQuery(path);
- var match = this.match(pathname);
-
- warning(
- match != null,
- 'No route matches path "%s". Make sure you have <Route path="%s"> somewhere in your routes',
- path, path
- );
-
- if (match == null)
- match = {};
-
- var prevRoutes = state.routes || [];
- var prevParams = state.params || {};
-
- var nextRoutes = match.routes || [];
- var nextParams = match.params || {};
- var nextQuery = Path.extractQuery(path) || {};
-
- var fromRoutes, toRoutes;
- if (prevRoutes.length) {
- fromRoutes = prevRoutes.filter(function (route) {
- return !hasMatch(nextRoutes, route, prevParams, nextParams);
- });
-
- toRoutes = nextRoutes.filter(function (route) {
- return !hasMatch(prevRoutes, route, prevParams, nextParams);
- });
- } else {
- fromRoutes = [];
- toRoutes = nextRoutes;
- }
-
- var transition = new Transition(path, this.replaceWith.bind(this, path));
- pendingTransition = transition;
-
- transition.from(fromRoutes, components, function (error) {
- if (error || transition.isAborted)
- return callback.call(router, error, transition);
-
- transition.to(toRoutes, nextParams, nextQuery, function (error) {
- if (error || transition.isAborted)
- return callback.call(router, error, transition);
-
- nextState.path = path;
- nextState.action = action;
- nextState.pathname = pathname;
- nextState.routes = nextRoutes;
- nextState.params = nextParams;
- nextState.query = nextQuery;
-
- callback.call(router, null, transition);
- });
- });
- },
-
- /**
- * Starts this router and calls callback(router, state) when the route changes.
- *
- * If the router's location is static (i.e. a URL path in a server environment)
- * the callback is called only once. Otherwise, the location should be one of the
- * Router.*Location objects (e.g. Router.HashLocation or Router.HistoryLocation).
- */
- run: function (callback) {
- function dispatchHandler(error, transition) {
- pendingTransition = null;
-
- if (error) {
- onError.call(router, error);
- } else if (transition.isAborted) {
- onAbort.call(router, transition.abortReason, location);
- } else {
- callback.call(router, router, nextState);
- }
- }
-
- if (typeof location === 'string') {
- warning(
- !canUseDOM || "production" === 'test',
- 'You should not use a static location in a DOM environment because ' +
- 'the router will not be kept in sync with the current URL'
- );
-
- // Dispatch the location.
- router.dispatch(location, null, dispatchHandler);
- } else {
- invariant(
- canUseDOM,
- 'You cannot use %s in a non-DOM environment',
- location
- );
-
- // Listen for changes to the location.
- function changeListener(change) {
- router.dispatch(change.path, change.type, dispatchHandler);
- }
-
- if (location.addChangeListener)
- location.addChangeListener(changeListener);
-
- // Bootstrap using the current path.
- router.dispatch(location.getCurrentPath(), null, dispatchHandler);
- }
- }
-
- },
-
- propTypes: {
- children: PropTypes.falsy
- },
-
- getLocation: function () {
- return location;
- },
-
- getScrollBehavior: function () {
- return scrollBehavior;
- },
-
- getRouteAtDepth: function (depth) {
- var routes = this.state.routes;
- return routes && routes[depth];
- },
-
- getRouteComponents: function () {
- return components;
- },
-
- getInitialState: function () {
- updateState();
- return state;
- },
-
- componentWillReceiveProps: function () {
- updateState();
- this.setState(state);
- },
-
- render: function () {
- return this.getRouteAtDepth(0) ? React.createElement(RouteHandler, this.props) : null;
- },
-
- childContextTypes: {
- getRouteAtDepth: React.PropTypes.func.isRequired,
- getRouteComponents: React.PropTypes.func.isRequired,
- routeHandlers: React.PropTypes.array.isRequired
- },
-
- getChildContext: function () {
- return {
- getRouteComponents: this.getRouteComponents,
- getRouteAtDepth: this.getRouteAtDepth,
- routeHandlers: [ this ]
- };
- }
-
- });
-
- if (options.routes)
- router.addRoutes(options.routes);
-
- return router;
-}
-
-module.exports = createRouter;
-
-},{"../actions/LocationActions":1,"../behaviors/ImitateBrowserBehavior":2,"../components/RouteHandler":9,"../locations/HashLocation":11,"../locations/HistoryLocation":12,"../locations/RefreshLocation":13,"../mixins/NavigationContext":16,"../mixins/Scrolling":17,"../mixins/StateContext":19,"./Cancellation":20,"./Path":21,"./PropTypes":23,"./Redirect":24,"./Transition":25,"./createRoutesFromChildren":27,"./supportsHistory":31,"react/lib/ExecutionEnvironment":37,"react/lib/invariant":41,"react/lib/warning":42}],27:[function(_dereq_,module,exports){
-var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
-var warning = _dereq_('react/lib/warning');
-var invariant = _dereq_('react/lib/invariant');
-var DefaultRoute = _dereq_('../components/DefaultRoute');
-var NotFoundRoute = _dereq_('../components/NotFoundRoute');
-var Redirect = _dereq_('../components/Redirect');
-var Route = _dereq_('../components/Route');
-var Path = _dereq_('./Path');
-
-var CONFIG_ELEMENT_TYPES = [
- DefaultRoute.type,
- NotFoundRoute.type,
- Redirect.type,
- Route.type
-];
-
-function createRedirectHandler(to, _params, _query) {
- return React.createClass({
- statics: {
- willTransitionTo: function (transition, params, query) {
- transition.redirect(to, _params || params, _query || query);
- }
- },
-
- render: function () {
- return null;
- }
- });
-}
-
-function checkPropTypes(componentName, propTypes, props) {
- for (var propName in propTypes) {
- if (propTypes.hasOwnProperty(propName)) {
- var error = propTypes[propName](props, propName, componentName);
-
- if (error instanceof Error)
- warning(false, error.message);
- }
- }
-}
-
-function createRoute(element, parentRoute, namedRoutes) {
- var type = element.type;
- var props = element.props;
- var componentName = (type && type.displayName) || 'UnknownComponent';
-
- invariant(
- CONFIG_ELEMENT_TYPES.indexOf(type) !== -1,
- 'Unrecognized route configuration element "<%s>"',
- componentName
- );
-
- if (type.propTypes)
- checkPropTypes(componentName, type.propTypes, props);
-
- var route = { name: props.name };
-
- if (props.ignoreScrollBehavior) {
- route.ignoreScrollBehavior = true;
- }
-
- if (type === Redirect.type) {
- route.handler = createRedirectHandler(props.to, props.params, props.query);
- props.path = props.path || props.from || '*';
- } else {
- route.handler = props.handler;
- }
-
- var parentPath = (parentRoute && parentRoute.path) || '/';
-
- if ((props.path || props.name) && type !== DefaultRoute.type && type !== NotFoundRoute.type) {
- var path = props.path || props.name;
-
- // Relative paths extend their parent.
- if (!Path.isAbsolute(path))
- path = Path.join(parentPath, path);
-
- route.path = Path.normalize(path);
- } else {
- route.path = parentPath;
-
- if (type === NotFoundRoute.type)
- route.path += '*';
- }
-
- route.paramNames = Path.extractParamNames(route.path);
-
- // Make sure the route's path has all params its parent needs.
- if (parentRoute && Array.isArray(parentRoute.paramNames)) {
- parentRoute.paramNames.forEach(function (paramName) {
- invariant(
- route.paramNames.indexOf(paramName) !== -1,
- 'The nested route path "%s" is missing the "%s" parameter of its parent path "%s"',
- route.path, paramName, parentRoute.path
- );
- });
- }
-
- // Make sure the route can be looked up by <Link>s.
- if (props.name) {
- invariant(
- namedRoutes[props.name] == null,
- 'You cannot use the name "%s" for more than one route',
- props.name
- );
-
- namedRoutes[props.name] = route;
- }
-
- // Handle <NotFoundRoute>.
- if (type === NotFoundRoute.type) {
- invariant(
- parentRoute,
- '<NotFoundRoute> must have a parent <Route>'
- );
-
- invariant(
- parentRoute.notFoundRoute == null,
- 'You may not have more than one <NotFoundRoute> per <Route>'
- );
-
- parentRoute.notFoundRoute = route;
-
- return null;
- }
-
- // Handle <DefaultRoute>.
- if (type === DefaultRoute.type) {
- invariant(
- parentRoute,
- '<DefaultRoute> must have a parent <Route>'
- );
-
- invariant(
- parentRoute.defaultRoute == null,
- 'You may not have more than one <DefaultRoute> per <Route>'
- );
-
- parentRoute.defaultRoute = route;
-
- return null;
- }
-
- route.childRoutes = createRoutesFromChildren(props.children, route, namedRoutes);
-
- return route;
-}
-
-/**
- * Creates and returns an array of route objects from the given ReactChildren.
- */
-function createRoutesFromChildren(children, parentRoute, namedRoutes) {
- var routes = [];
-
- React.Children.forEach(children, function (child) {
- // Exclude <DefaultRoute>s and <NotFoundRoute>s.
- if (child = createRoute(child, parentRoute, namedRoutes))
- routes.push(child);
- });
-
- return routes;
-}
-
-module.exports = createRoutesFromChildren;
-
-},{"../components/DefaultRoute":4,"../components/NotFoundRoute":6,"../components/Redirect":7,"../components/Route":8,"./Path":21,"react/lib/invariant":41,"react/lib/warning":42}],28:[function(_dereq_,module,exports){
-var invariant = _dereq_('react/lib/invariant');
-var canUseDOM = _dereq_('react/lib/ExecutionEnvironment').canUseDOM;
-
-/**
- * Returns the current scroll position of the window as { x, y }.
- */
-function getWindowScrollPosition() {
- invariant(
- canUseDOM,
- 'Cannot get current scroll position without a DOM'
- );
-
- return {
- x: window.scrollX,
- y: window.scrollY
- };
-}
-
-module.exports = getWindowScrollPosition;
-
-},{"react/lib/ExecutionEnvironment":37,"react/lib/invariant":41}],29:[function(_dereq_,module,exports){
-function reversedArray(array) {
- return array.slice(0).reverse();
-}
-
-module.exports = reversedArray;
-
-},{}],30:[function(_dereq_,module,exports){
-var createRouter = _dereq_('./createRouter');
-
-/**
- * A high-level convenience method that creates, configures, and
- * runs a router in one shot. The method signature is:
- *
- * Router.run(routes[, location ], callback);
- *
- * Using `window.location.hash` to manage the URL, you could do:
- *
- * Router.run(routes, function (Handler) {
- * React.render(<Handler/>, document.body);
- * });
- *
- * Using HTML5 history and a custom "cursor" prop:
- *
- * Router.run(routes, Router.HistoryLocation, function (Handler) {
- * React.render(<Handler cursor={cursor}/>, document.body);
- * });
- *
- * Returns the newly created router.
- *
- * Note: If you need to specify further options for your router such
- * as error/abort handling or custom scroll behavior, use Router.create
- * instead.
- *
- * var router = Router.create(options);
- * router.run(function (Handler) {
- * // ...
- * });
- */
-function runRouter(routes, location, callback) {
- if (typeof location === 'function') {
- callback = location;
- location = null;
- }
-
- var router = createRouter({
- routes: routes,
- location: location
- });
-
- router.run(callback);
-
- return router;
-}
-
-module.exports = runRouter;
-
-},{"./createRouter":26}],31:[function(_dereq_,module,exports){
-function supportsHistory() {
- /*! taken from modernizr
- * https://github.com/Modernizr/Modernizr/blob/master/LICENSE
- * https://github.com/Modernizr/Modernizr/blob/master/feature-detects/history.js
- */
- var ua = navigator.userAgent;
- if ((ua.indexOf('Android 2.') !== -1 ||
- (ua.indexOf('Android 4.0') !== -1)) &&
- ua.indexOf('Mobile Safari') !== -1 &&
- ua.indexOf('Chrome') === -1) {
- return false;
- }
- return (window.history && 'pushState' in window.history);
-}
-
-module.exports = supportsHistory;
-
-},{}],32:[function(_dereq_,module,exports){
-module.exports = _dereq_('./lib');
-
-},{"./lib":33}],33:[function(_dereq_,module,exports){
-// Load modules
-
-var Stringify = _dereq_('./stringify');
-var Parse = _dereq_('./parse');
-
-
-// Declare internals
-
-var internals = {};
-
-
-module.exports = {
- stringify: Stringify,
- parse: Parse
-};
-
-},{"./parse":34,"./stringify":35}],34:[function(_dereq_,module,exports){
-// Load modules
-
-var Utils = _dereq_('./utils');
-
-
-// Declare internals
-
-var internals = {
- delimiter: '&',
- depth: 5,
- arrayLimit: 20,
- parameterLimit: 1000
-};
-
-
-internals.parseValues = function (str, options) {
-
- var obj = {};
- var parts = str.split(options.delimiter, options.parameterLimit === Infinity ? undefined : options.parameterLimit);
-
- for (var i = 0, il = parts.length; i < il; ++i) {
- var part = parts[i];
- var pos = part.indexOf(']=') === -1 ? part.indexOf('=') : part.indexOf(']=') + 1;
-
- if (pos === -1) {
- obj[Utils.decode(part)] = '';
- }
- else {
- var key = Utils.decode(part.slice(0, pos));
- var val = Utils.decode(part.slice(pos + 1));
-
- if (!obj[key]) {
- obj[key] = val;
- }
- else {
- obj[key] = [].concat(obj[key]).concat(val);
- }
- }
- }
-
- return obj;
-};
-
-
-internals.parseObject = function (chain, val, options) {
-
- if (!chain.length) {
- return val;
- }
-
- var root = chain.shift();
-
- var obj = {};
- if (root === '[]') {
- obj = [];
- obj = obj.concat(internals.parseObject(chain, val, options));
- }
- else {
- var cleanRoot = root[0] === '[' && root[root.length - 1] === ']' ? root.slice(1, root.length - 1) : root;
- var index = parseInt(cleanRoot, 10);
- if (!isNaN(index) &&
- root !== cleanRoot &&
- index <= options.arrayLimit) {
-
- obj = [];
- obj[index] = internals.parseObject(chain, val, options);
- }
- else {
- obj[cleanRoot] = internals.parseObject(chain, val, options);
- }
- }
-
- return obj;
-};
-
-
-internals.parseKeys = function (key, val, options) {
-
- if (!key) {
- return;
- }
-
- // The regex chunks
-
- var parent = /^([^\[\]]*)/;
- var child = /(\[[^\[\]]*\])/g;
-
- // Get the parent
-
- var segment = parent.exec(key);
-
- // Don't allow them to overwrite object prototype properties
-
- if (Object.prototype.hasOwnProperty(segment[1])) {
- return;
- }
-
- // Stash the parent if it exists
-
- var keys = [];
- if (segment[1]) {
- keys.push(segment[1]);
- }
-
- // Loop through children appending to the array until we hit depth
-
- var i = 0;
- while ((segment = child.exec(key)) !== null && i < options.depth) {
-
- ++i;
- if (!Object.prototype.hasOwnProperty(segment[1].replace(/\[|\]/g, ''))) {
- keys.push(segment[1]);
- }
- }
-
- // If there's a remainder, just add whatever is left
-
- if (segment) {
- keys.push('[' + key.slice(segment.index) + ']');
- }
-
- return internals.parseObject(keys, val, options);
-};
-
-
-module.exports = function (str, options) {
-
- if (str === '' ||
- str === null ||
- typeof str === 'undefined') {
-
- return {};
- }
-
- options = options || {};
- options.delimiter = typeof options.delimiter === 'string' || Utils.isRegExp(options.delimiter) ? options.delimiter : internals.delimiter;
- options.depth = typeof options.depth === 'number' ? options.depth : internals.depth;
- options.arrayLimit = typeof options.arrayLimit === 'number' ? options.arrayLimit : internals.arrayLimit;
- options.parameterLimit = typeof options.parameterLimit === 'number' ? options.parameterLimit : internals.parameterLimit;
-
- var tempObj = typeof str === 'string' ? internals.parseValues(str, options) : str;
- var obj = {};
-
- // Iterate over the keys and setup the new object
-
- var keys = Object.keys(tempObj);
- for (var i = 0, il = keys.length; i < il; ++i) {
- var key = keys[i];
- var newObj = internals.parseKeys(key, tempObj[key], options);
- obj = Utils.merge(obj, newObj);
- }
-
- return Utils.compact(obj);
-};
-
-},{"./utils":36}],35:[function(_dereq_,module,exports){
-// Load modules
-
-var Utils = _dereq_('./utils');
-
-
-// Declare internals
-
-var internals = {
- delimiter: '&'
-};
-
-
-internals.stringify = function (obj, prefix) {
-
- if (Utils.isBuffer(obj)) {
- obj = obj.toString();
- }
- else if (obj instanceof Date) {
- obj = obj.toISOString();
- }
- else if (obj === null) {
- obj = '';
- }
-
- if (typeof obj === 'string' ||
- typeof obj === 'number' ||
- typeof obj === 'boolean') {
-
- return [encodeURIComponent(prefix) + '=' + encodeURIComponent(obj)];
- }
-
- var values = [];
-
- for (var key in obj) {
- if (obj.hasOwnProperty(key)) {
- values = values.concat(internals.stringify(obj[key], prefix + '[' + key + ']'));
- }
- }
-
- return values;
-};
-
-
-module.exports = function (obj, options) {
-
- options = options || {};
- var delimiter = typeof options.delimiter === 'undefined' ? internals.delimiter : options.delimiter;
-
- var keys = [];
-
- for (var key in obj) {
- if (obj.hasOwnProperty(key)) {
- keys = keys.concat(internals.stringify(obj[key], key));
- }
- }
-
- return keys.join(delimiter);
-};
-
-},{"./utils":36}],36:[function(_dereq_,module,exports){
-// Load modules
-
-
-// Declare internals
-
-var internals = {};
-
-
-exports.arrayToObject = function (source) {
-
- var obj = {};
- for (var i = 0, il = source.length; i < il; ++i) {
- if (typeof source[i] !== 'undefined') {
-
- obj[i] = source[i];
- }
- }
-
- return obj;
-};
-
-
-exports.merge = function (target, source) {
-
- if (!source) {
- return target;
- }
-
- if (Array.isArray(source)) {
- for (var i = 0, il = source.length; i < il; ++i) {
- if (typeof source[i] !== 'undefined') {
- if (typeof target[i] === 'object') {
- target[i] = exports.merge(target[i], source[i]);
- }
- else {
- target[i] = source[i];
- }
- }
- }
-
- return target;
- }
-
- if (Array.isArray(target)) {
- if (typeof source !== 'object') {
- target.push(source);
- return target;
- }
- else {
- target = exports.arrayToObject(target);
- }
- }
-
- var keys = Object.keys(source);
- for (var k = 0, kl = keys.length; k < kl; ++k) {
- var key = keys[k];
- var value = source[key];
-
- if (value &&
- typeof value === 'object') {
-
- if (!target[key]) {
- target[key] = value;
- }
- else {
- target[key] = exports.merge(target[key], value);
- }
- }
- else {
- target[key] = value;
- }
- }
-
- return target;
-};
-
-
-exports.decode = function (str) {
-
- try {
- return decodeURIComponent(str.replace(/\+/g, ' '));
- } catch (e) {
- return str;
- }
-};
-
-
-exports.compact = function (obj, refs) {
-
- if (typeof obj !== 'object' ||
- obj === null) {
-
- return obj;
- }
-
- refs = refs || [];
- var lookup = refs.indexOf(obj);
- if (lookup !== -1) {
- return refs[lookup];
- }
-
- refs.push(obj);
-
- if (Array.isArray(obj)) {
- var compacted = [];
-
- for (var i = 0, l = obj.length; i < l; ++i) {
- if (typeof obj[i] !== 'undefined') {
- compacted.push(obj[i]);
- }
- }
-
- return compacted;
- }
-
- var keys = Object.keys(obj);
- for (var i = 0, il = keys.length; i < il; ++i) {
- var key = keys[i];
- obj[key] = exports.compact(obj[key], refs);
- }
-
- return obj;
-};
-
-
-exports.isRegExp = function (obj) {
- return Object.prototype.toString.call(obj) === '[object RegExp]';
-};
-
-
-exports.isBuffer = function (obj) {
-
- if (typeof Buffer !== 'undefined') {
- return Buffer.isBuffer(obj);
- }
- else {
- return false;
- }
-};
-
-},{}],37:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ExecutionEnvironment
- */
-
-/*jslint evil: true */
-
-"use strict";
-
-var canUseDOM = !!(
- typeof window !== 'undefined' &&
- window.document &&
- window.document.createElement
-);
-
-/**
- * Simple, lightweight module assisting with the detection and context of
- * Worker. Helps avoid circular dependencies and allows code to reason about
- * whether or not they are in a Worker, even if they never include the main
- * `ReactWorker` dependency.
- */
-var ExecutionEnvironment = {
-
- canUseDOM: canUseDOM,
-
- canUseWorkers: typeof Worker !== 'undefined',
-
- canUseEventListeners:
- canUseDOM && !!(window.addEventListener || window.attachEvent),
-
- canUseViewport: canUseDOM && !!window.screen,
-
- isInWorker: !canUseDOM // For now, this is true - might change in the future.
-
-};
-
-module.exports = ExecutionEnvironment;
-
-},{}],38:[function(_dereq_,module,exports){
-/**
- * Copyright 2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule Object.assign
- */
-
-// https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign
-
-function assign(target, sources) {
- if (target == null) {
- throw new TypeError('Object.assign target cannot be null or undefined');
- }
-
- var to = Object(target);
- var hasOwnProperty = Object.prototype.hasOwnProperty;
-
- for (var nextIndex = 1; nextIndex < arguments.length; nextIndex++) {
- var nextSource = arguments[nextIndex];
- if (nextSource == null) {
- continue;
- }
-
- var from = Object(nextSource);
-
- // We don't currently support accessors nor proxies. Therefore this
- // copy cannot throw. If we ever supported this then we must handle
- // exceptions and side-effects. We don't support symbols so they won't
- // be transferred.
-
- for (var key in from) {
- if (hasOwnProperty.call(from, key)) {
- to[key] = from[key];
- }
- }
- }
-
- return to;
-};
-
-module.exports = assign;
-
-},{}],39:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule cx
- */
-
-/**
- * This function is used to mark string literals representing CSS class names
- * so that they can be transformed statically. This allows for modularization
- * and minification of CSS class names.
- *
- * In static_upstream, this function is actually implemented, but it should
- * eventually be replaced with something more descriptive, and the transform
- * that is used in the main stack should be ported for use elsewhere.
- *
- * @param string|object className to modularize, or an object of key/values.
- * In the object case, the values are conditions that
- * determine if the className keys should be included.
- * @param [string ...] Variable list of classNames in the string case.
- * @return string Renderable space-separated CSS className.
- */
-function cx(classNames) {
- if (typeof classNames == 'object') {
- return Object.keys(classNames).filter(function(className) {
- return classNames[className];
- }).join(' ');
- } else {
- return Array.prototype.join.call(arguments, ' ');
- }
-}
-
-module.exports = cx;
-
-},{}],40:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule emptyFunction
- */
-
-function makeEmptyFunction(arg) {
- return function() {
- return arg;
- };
-}
-
-/**
- * This function accepts and discards inputs; it has no side effects. This is
- * primarily useful idiomatically for overridable function endpoints which
- * always need to be callable, since JS lacks a null-call idiom ala Cocoa.
- */
-function emptyFunction() {}
-
-emptyFunction.thatReturns = makeEmptyFunction;
-emptyFunction.thatReturnsFalse = makeEmptyFunction(false);
-emptyFunction.thatReturnsTrue = makeEmptyFunction(true);
-emptyFunction.thatReturnsNull = makeEmptyFunction(null);
-emptyFunction.thatReturnsThis = function() { return this; };
-emptyFunction.thatReturnsArgument = function(arg) { return arg; };
-
-module.exports = emptyFunction;
-
-},{}],41:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule invariant
- */
-
-"use strict";
-
-/**
- * Use invariant() to assert state which your program assumes to be true.
- *
- * Provide sprintf-style format (only %s is supported) and arguments
- * to provide information about what broke and what you were
- * expecting.
- *
- * The invariant message will be stripped in production, but the invariant
- * will remain to ensure logic does not differ in production.
- */
-
-var invariant = function(condition, format, a, b, c, d, e, f) {
- if ("production" !== "production") {
- if (format === undefined) {
- throw new Error('invariant requires an error message argument');
- }
- }
-
- if (!condition) {
- var error;
- if (format === undefined) {
- error = new Error(
- 'Minified exception occurred; use the non-minified dev environment ' +
- 'for the full error message and additional helpful warnings.'
- );
- } else {
- var args = [a, b, c, d, e, f];
- var argIndex = 0;
- error = new Error(
- 'Invariant Violation: ' +
- format.replace(/%s/g, function() { return args[argIndex++]; })
- );
- }
-
- error.framesToPop = 1; // we don't care about invariant's own frame
- throw error;
- }
-};
-
-module.exports = invariant;
-
-},{}],42:[function(_dereq_,module,exports){
-/**
- * Copyright 2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule warning
- */
-
-"use strict";
-
-var emptyFunction = _dereq_("./emptyFunction");
-
-/**
- * Similar to invariant but only logs a warning if the condition is not met.
- * This can be used to log issues in development environments in critical
- * paths. Removing the logging code for production environments will keep the
- * same logic and follow the same code paths.
- */
-
-var warning = emptyFunction;
-
-if ("production" !== "production") {
- warning = function(condition, format ) {var args=Array.prototype.slice.call(arguments,2);
- if (format === undefined) {
- throw new Error(
- '`warning(condition, format, ...args)` requires a warning ' +
- 'message argument'
- );
- }
-
- if (!condition) {
- var argIndex = 0;
- console.warn('Warning: ' + format.replace(/%s/g, function() {return args[argIndex++];}));
- }
- };
-}
-
-module.exports = warning;
-
-},{"./emptyFunction":40}],43:[function(_dereq_,module,exports){
-/** @license MIT License (c) copyright 2010-2014 original author or authors */
-/** @author Brian Cavalier */
-/** @author John Hann */
-
-(function(define) { 'use strict';
-define(function (_dereq_) {
-
- var makePromise = _dereq_('./makePromise');
- var Scheduler = _dereq_('./Scheduler');
- var async = _dereq_('./async');
-
- return makePromise({
- scheduler: new Scheduler(async)
- });
-
-});
-})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(_dereq_); });
-
-},{"./Scheduler":45,"./async":46,"./makePromise":47}],44:[function(_dereq_,module,exports){
-/** @license MIT License (c) copyright 2010-2014 original author or authors */
-/** @author Brian Cavalier */
-/** @author John Hann */
-
-(function(define) { 'use strict';
-define(function() {
- /**
- * Circular queue
- * @param {number} capacityPow2 power of 2 to which this queue's capacity
- * will be set initially. eg when capacityPow2 == 3, queue capacity
- * will be 8.
- * @constructor
- */
- function Queue(capacityPow2) {
- this.head = this.tail = this.length = 0;
- this.buffer = new Array(1 << capacityPow2);
- }
-
- Queue.prototype.push = function(x) {
- if(this.length === this.buffer.length) {
- this._ensureCapacity(this.length * 2);
- }
-
- this.buffer[this.tail] = x;
- this.tail = (this.tail + 1) & (this.buffer.length - 1);
- ++this.length;
- return this.length;
- };
-
- Queue.prototype.shift = function() {
- var x = this.buffer[this.head];
- this.buffer[this.head] = void 0;
- this.head = (this.head + 1) & (this.buffer.length - 1);
- --this.length;
- return x;
- };
-
- Queue.prototype._ensureCapacity = function(capacity) {
- var head = this.head;
- var buffer = this.buffer;
- var newBuffer = new Array(capacity);
- var i = 0;
- var len;
-
- if(head === 0) {
- len = this.length;
- for(; i<len; ++i) {
- newBuffer[i] = buffer[i];
- }
- } else {
- capacity = buffer.length;
- len = this.tail;
- for(; head<capacity; ++i, ++head) {
- newBuffer[i] = buffer[head];
- }
-
- for(head=0; head<len; ++i, ++head) {
- newBuffer[i] = buffer[head];
- }
- }
-
- this.buffer = newBuffer;
- this.head = 0;
- this.tail = this.length;
- };
-
- return Queue;
-
-});
-}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
-
-},{}],45:[function(_dereq_,module,exports){
-/** @license MIT License (c) copyright 2010-2014 original author or authors */
-/** @author Brian Cavalier */
-/** @author John Hann */
-
-(function(define) { 'use strict';
-define(function(_dereq_) {
-
- var Queue = _dereq_('./Queue');
-
- // Credit to Twisol (https://github.com/Twisol) for suggesting
- // this type of extensible queue + trampoline approach for next-tick conflation.
-
- /**
- * Async task scheduler
- * @param {function} async function to schedule a single async function
- * @constructor
- */
- function Scheduler(async) {
- this._async = async;
- this._queue = new Queue(15);
- this._afterQueue = new Queue(5);
- this._running = false;
-
- var self = this;
- this.drain = function() {
- self._drain();
- };
- }
-
- /**
- * Enqueue a task
- * @param {{ run:function }} task
- */
- Scheduler.prototype.enqueue = function(task) {
- this._add(this._queue, task);
- };
-
- /**
- * Enqueue a task to run after the main task queue
- * @param {{ run:function }} task
- */
- Scheduler.prototype.afterQueue = function(task) {
- this._add(this._afterQueue, task);
- };
-
- /**
- * Drain the handler queue entirely, and then the after queue
- */
- Scheduler.prototype._drain = function() {
- runQueue(this._queue);
- this._running = false;
- runQueue(this._afterQueue);
- };
-
- /**
- * Add a task to the q, and schedule drain if not already scheduled
- * @param {Queue} queue
- * @param {{run:function}} task
- * @private
- */
- Scheduler.prototype._add = function(queue, task) {
- queue.push(task);
- if(!this._running) {
- this._running = true;
- this._async(this.drain);
- }
- };
-
- /**
- * Run all the tasks in the q
- * @param queue
- */
- function runQueue(queue) {
- while(queue.length > 0) {
- queue.shift().run();
- }
- }
-
- return Scheduler;
-
-});
-}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(_dereq_); }));
-
-},{"./Queue":44}],46:[function(_dereq_,module,exports){
-/** @license MIT License (c) copyright 2010-2014 original author or authors */
-/** @author Brian Cavalier */
-/** @author John Hann */
-
-(function(define) { 'use strict';
-define(function(_dereq_) {
-
- // Sniff "best" async scheduling option
- // Prefer process.nextTick or MutationObserver, then check for
- // vertx and finally fall back to setTimeout
-
- /*jshint maxcomplexity:6*/
- /*global process,document,setTimeout,MutationObserver,WebKitMutationObserver*/
- var nextTick, MutationObs;
-
- if (typeof process !== 'undefined' && process !== null &&
- typeof process.nextTick === 'function') {
- nextTick = function(f) {
- process.nextTick(f);
- };
-
- } else if (MutationObs =
- (typeof MutationObserver === 'function' && MutationObserver) ||
- (typeof WebKitMutationObserver === 'function' && WebKitMutationObserver)) {
- nextTick = (function (document, MutationObserver) {
- var scheduled;
- var el = document.createElement('div');
- var o = new MutationObserver(run);
- o.observe(el, { attributes: true });
-
- function run() {
- var f = scheduled;
- scheduled = void 0;
- f();
- }
-
- return function (f) {
- scheduled = f;
- el.setAttribute('class', 'x');
- };
- }(document, MutationObs));
-
- } else {
- nextTick = (function(cjsRequire) {
- var vertx;
- try {
- // vert.x 1.x || 2.x
- vertx = cjsRequire('vertx');
- } catch (ignore) {}
-
- if (vertx) {
- if (typeof vertx.runOnLoop === 'function') {
- return vertx.runOnLoop;
- }
- if (typeof vertx.runOnContext === 'function') {
- return vertx.runOnContext;
- }
- }
-
- // capture setTimeout to avoid being caught by fake timers
- // used in time based tests
- var capturedSetTimeout = setTimeout;
- return function (t) {
- capturedSetTimeout(t, 0);
- };
- }(_dereq_));
- }
-
- return nextTick;
-});
-}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(_dereq_); }));
-
-},{}],47:[function(_dereq_,module,exports){
-/** @license MIT License (c) copyright 2010-2014 original author or authors */
-/** @author Brian Cavalier */
-/** @author John Hann */
-
-(function(define) { 'use strict';
-define(function() {
-
- return function makePromise(environment) {
-
- var tasks = environment.scheduler;
-
- var objectCreate = Object.create ||
- function(proto) {
- function Child() {}
- Child.prototype = proto;
- return new Child();
- };
-
- /**
- * Create a promise whose fate is determined by resolver
- * @constructor
- * @returns {Promise} promise
- * @name Promise
- */
- function Promise(resolver, handler) {
- this._handler = resolver === Handler ? handler : init(resolver);
- }
-
- /**
- * Run the supplied resolver
- * @param resolver
- * @returns {Pending}
- */
- function init(resolver) {
- var handler = new Pending();
-
- try {
- resolver(promiseResolve, promiseReject, promiseNotify);
- } catch (e) {
- promiseReject(e);
- }
-
- return handler;
-
- /**
- * Transition from pre-resolution state to post-resolution state, notifying
- * all listeners of the ultimate fulfillment or rejection
- * @param {*} x resolution value
- */
- function promiseResolve (x) {
- handler.resolve(x);
- }
- /**
- * Reject this promise with reason, which will be used verbatim
- * @param {Error|*} reason rejection reason, strongly suggested
- * to be an Error type
- */
- function promiseReject (reason) {
- handler.reject(reason);
- }
-
- /**
- * Issue a progress event, notifying all progress listeners
- * @param {*} x progress event payload to pass to all listeners
- */
- function promiseNotify (x) {
- handler.notify(x);
- }
- }
-
- // Creation
-
- Promise.resolve = resolve;
- Promise.reject = reject;
- Promise.never = never;
-
- Promise._defer = defer;
- Promise._handler = getHandler;
-
- /**
- * Returns a trusted promise. If x is already a trusted promise, it is
- * returned, otherwise returns a new trusted Promise which follows x.
- * @param {*} x
- * @return {Promise} promise
- */
- function resolve(x) {
- return isPromise(x) ? x
- : new Promise(Handler, new Async(getHandler(x)));
- }
-
- /**
- * Return a reject promise with x as its reason (x is used verbatim)
- * @param {*} x
- * @returns {Promise} rejected promise
- */
- function reject(x) {
- return new Promise(Handler, new Async(new Rejected(x)));
- }
-
- /**
- * Return a promise that remains pending forever
- * @returns {Promise} forever-pending promise.
- */
- function never() {
- return foreverPendingPromise; // Should be frozen
- }
-
- /**
- * Creates an internal {promise, resolver} pair
- * @private
- * @returns {Promise}
- */
- function defer() {
- return new Promise(Handler, new Pending());
- }
-
- // Transformation and flow control
-
- /**
- * Transform this promise's fulfillment value, returning a new Promise
- * for the transformed result. If the promise cannot be fulfilled, onRejected
- * is called with the reason. onProgress *may* be called with updates toward
- * this promise's fulfillment.
- * @param {function=} onFulfilled fulfillment handler
- * @param {function=} onRejected rejection handler
- * @deprecated @param {function=} onProgress progress handler
- * @return {Promise} new promise
- */
- Promise.prototype.then = function(onFulfilled, onRejected) {
- var parent = this._handler;
- var state = parent.join().state();
-
- if ((typeof onFulfilled !== 'function' && state > 0) ||
- (typeof onRejected !== 'function' && state < 0)) {
- // Short circuit: value will not change, simply share handler
- return new this.constructor(Handler, parent);
- }
-
- var p = this._beget();
- var child = p._handler;
-
- parent.chain(child, parent.receiver, onFulfilled, onRejected,
- arguments.length > 2 ? arguments[2] : void 0);
-
- return p;
- };
-
- /**
- * If this promise cannot be fulfilled due to an error, call onRejected to
- * handle the error. Shortcut for .then(undefined, onRejected)
- * @param {function?} onRejected
- * @return {Promise}
- */
- Promise.prototype['catch'] = function(onRejected) {
- return this.then(void 0, onRejected);
- };
-
- /**
- * Creates a new, pending promise of the same type as this promise
- * @private
- * @returns {Promise}
- */
- Promise.prototype._beget = function() {
- var parent = this._handler;
- var child = new Pending(parent.receiver, parent.join().context);
- return new this.constructor(Handler, child);
- };
-
- // Array combinators
-
- Promise.all = all;
- Promise.race = race;
-
- /**
- * Return a promise that will fulfill when all promises in the
- * input array have fulfilled, or will reject when one of the
- * promises rejects.
- * @param {array} promises array of promises
- * @returns {Promise} promise for array of fulfillment values
- */
- function all(promises) {
- /*jshint maxcomplexity:8*/
- var resolver = new Pending();
- var pending = promises.length >>> 0;
- var results = new Array(pending);
-
- var i, h, x, s;
- for (i = 0; i < promises.length; ++i) {
- x = promises[i];
-
- if (x === void 0 && !(i in promises)) {
- --pending;
- continue;
- }
-
- if (maybeThenable(x)) {
- h = getHandlerMaybeThenable(x);
-
- s = h.state();
- if (s === 0) {
- h.fold(settleAt, i, results, resolver);
- } else if (s > 0) {
- results[i] = h.value;
- --pending;
- } else {
- unreportRemaining(promises, i+1, h);
- resolver.become(h);
- break;
- }
-
- } else {
- results[i] = x;
- --pending;
- }
- }
-
- if(pending === 0) {
- resolver.become(new Fulfilled(results));
- }
-
- return new Promise(Handler, resolver);
-
- function settleAt(i, x, resolver) {
- /*jshint validthis:true*/
- this[i] = x;
- if(--pending === 0) {
- resolver.become(new Fulfilled(this));
- }
- }
- }
-
- function unreportRemaining(promises, start, rejectedHandler) {
- var i, h, x;
- for(i=start; i<promises.length; ++i) {
- x = promises[i];
- if(maybeThenable(x)) {
- h = getHandlerMaybeThenable(x);
-
- if(h !== rejectedHandler) {
- h.visit(h, void 0, h._unreport);
- }
- }
- }
- }
-
- /**
- * Fulfill-reject competitive race. Return a promise that will settle
- * to the same state as the earliest input promise to settle.
- *
- * WARNING: The ES6 Promise spec requires that race()ing an empty array
- * must return a promise that is pending forever. This implementation
- * returns a singleton forever-pending promise, the same singleton that is
- * returned by Promise.never(), thus can be checked with ===
- *
- * @param {array} promises array of promises to race
- * @returns {Promise} if input is non-empty, a promise that will settle
- * to the same outcome as the earliest input promise to settle. if empty
- * is empty, returns a promise that will never settle.
- */
- function race(promises) {
- // Sigh, race([]) is untestable unless we return *something*
- // that is recognizable without calling .then() on it.
- if(Object(promises) === promises && promises.length === 0) {
- return never();
- }
-
- var h = new Pending();
- var i, x;
- for(i=0; i<promises.length; ++i) {
- x = promises[i];
- if (x !== void 0 && i in promises) {
- getHandler(x).visit(h, h.resolve, h.reject);
- }
- }
- return new Promise(Handler, h);
- }
-
- // Promise internals
- // Below this, everything is @private
-
- /**
- * Get an appropriate handler for x, without checking for cycles
- * @param {*} x
- * @returns {object} handler
- */
- function getHandler(x) {
- if(isPromise(x)) {
- return x._handler.join();
- }
- return maybeThenable(x) ? getHandlerUntrusted(x) : new Fulfilled(x);
- }
-
- /**
- * Get a handler for thenable x.
- * NOTE: You must only call this if maybeThenable(x) == true
- * @param {object|function|Promise} x
- * @returns {object} handler
- */
- function getHandlerMaybeThenable(x) {
- return isPromise(x) ? x._handler.join() : getHandlerUntrusted(x);
- }
-
- /**
- * Get a handler for potentially untrusted thenable x
- * @param {*} x
- * @returns {object} handler
- */
- function getHandlerUntrusted(x) {
- try {
- var untrustedThen = x.then;
- return typeof untrustedThen === 'function'
- ? new Thenable(untrustedThen, x)
- : new Fulfilled(x);
- } catch(e) {
- return new Rejected(e);
- }
- }
-
- /**
- * Handler for a promise that is pending forever
- * @constructor
- */
- function Handler() {}
-
- Handler.prototype.when
- = Handler.prototype.become
- = Handler.prototype.notify
- = Handler.prototype.fail
- = Handler.prototype._unreport
- = Handler.prototype._report
- = noop;
-
- Handler.prototype._state = 0;
-
- Handler.prototype.state = function() {
- return this._state;
- };
-
- /**
- * Recursively collapse handler chain to find the handler
- * nearest to the fully resolved value.
- * @returns {object} handler nearest the fully resolved value
- */
- Handler.prototype.join = function() {
- var h = this;
- while(h.handler !== void 0) {
- h = h.handler;
- }
- return h;
- };
-
- Handler.prototype.chain = function(to, receiver, fulfilled, rejected, progress) {
- this.when({
- resolver: to,
- receiver: receiver,
- fulfilled: fulfilled,
- rejected: rejected,
- progress: progress
- });
- };
-
- Handler.prototype.visit = function(receiver, fulfilled, rejected, progress) {
- this.chain(failIfRejected, receiver, fulfilled, rejected, progress);
- };
-
- Handler.prototype.fold = function(f, z, c, to) {
- this.visit(to, function(x) {
- f.call(c, z, x, this);
- }, to.reject, to.notify);
- };
-
- /**
- * Handler that invokes fail() on any handler it becomes
- * @constructor
- */
- function FailIfRejected() {}
-
- inherit(Handler, FailIfRejected);
-
- FailIfRejected.prototype.become = function(h) {
- h.fail();
- };
-
- var failIfRejected = new FailIfRejected();
-
- /**
- * Handler that manages a queue of consumers waiting on a pending promise
- * @constructor
- */
- function Pending(receiver, inheritedContext) {
- Promise.createContext(this, inheritedContext);
-
- this.consumers = void 0;
- this.receiver = receiver;
- this.handler = void 0;
- this.resolved = false;
- }
-
- inherit(Handler, Pending);
-
- Pending.prototype._state = 0;
-
- Pending.prototype.resolve = function(x) {
- this.become(getHandler(x));
- };
-
- Pending.prototype.reject = function(x) {
- if(this.resolved) {
- return;
- }
-
- this.become(new Rejected(x));
- };
-
- Pending.prototype.join = function() {
- if (!this.resolved) {
- return this;
- }
-
- var h = this;
-
- while (h.handler !== void 0) {
- h = h.handler;
- if (h === this) {
- return this.handler = cycle();
- }
- }
-
- return h;
- };
-
- Pending.prototype.run = function() {
- var q = this.consumers;
- var handler = this.join();
- this.consumers = void 0;
-
- for (var i = 0; i < q.length; ++i) {
- handler.when(q[i]);
- }
- };
-
- Pending.prototype.become = function(handler) {
- if(this.resolved) {
- return;
- }
-
- this.resolved = true;
- this.handler = handler;
- if(this.consumers !== void 0) {
- tasks.enqueue(this);
- }
-
- if(this.context !== void 0) {
- handler._report(this.context);
- }
- };
-
- Pending.prototype.when = function(continuation) {
- if(this.resolved) {
- tasks.enqueue(new ContinuationTask(continuation, this.handler));
- } else {
- if(this.consumers === void 0) {
- this.consumers = [continuation];
- } else {
- this.consumers.push(continuation);
- }
- }
- };
-
- Pending.prototype.notify = function(x) {
- if(!this.resolved) {
- tasks.enqueue(new ProgressTask(x, this));
- }
- };
-
- Pending.prototype.fail = function(context) {
- var c = typeof context === 'undefined' ? this.context : context;
- this.resolved && this.handler.join().fail(c);
- };
-
- Pending.prototype._report = function(context) {
- this.resolved && this.handler.join()._report(context);
- };
-
- Pending.prototype._unreport = function() {
- this.resolved && this.handler.join()._unreport();
- };
-
- /**
- * Wrap another handler and force it into a future stack
- * @param {object} handler
- * @constructor
- */
- function Async(handler) {
- this.handler = handler;
- }
-
- inherit(Handler, Async);
-
- Async.prototype.when = function(continuation) {
- tasks.enqueue(new ContinuationTask(continuation, this));
- };
-
- Async.prototype._report = function(context) {
- this.join()._report(context);
- };
-
- Async.prototype._unreport = function() {
- this.join()._unreport();
- };
-
- /**
- * Handler that wraps an untrusted thenable and assimilates it in a future stack
- * @param {function} then
- * @param {{then: function}} thenable
- * @constructor
- */
- function Thenable(then, thenable) {
- Pending.call(this);
- tasks.enqueue(new AssimilateTask(then, thenable, this));
- }
-
- inherit(Pending, Thenable);
-
- /**
- * Handler for a fulfilled promise
- * @param {*} x fulfillment value
- * @constructor
- */
- function Fulfilled(x) {
- Promise.createContext(this);
- this.value = x;
- }
-
- inherit(Handler, Fulfilled);
-
- Fulfilled.prototype._state = 1;
-
- Fulfilled.prototype.fold = function(f, z, c, to) {
- runContinuation3(f, z, this, c, to);
- };
-
- Fulfilled.prototype.when = function(cont) {
- runContinuation1(cont.fulfilled, this, cont.receiver, cont.resolver);
- };
-
- var errorId = 0;
-
- /**
- * Handler for a rejected promise
- * @param {*} x rejection reason
- * @constructor
- */
- function Rejected(x) {
- Promise.createContext(this);
-
- this.id = ++errorId;
- this.value = x;
- this.handled = false;
- this.reported = false;
-
- this._report();
- }
-
- inherit(Handler, Rejected);
-
- Rejected.prototype._state = -1;
-
- Rejected.prototype.fold = function(f, z, c, to) {
- to.become(this);
- };
-
- Rejected.prototype.when = function(cont) {
- if(typeof cont.rejected === 'function') {
- this._unreport();
- }
- runContinuation1(cont.rejected, this, cont.receiver, cont.resolver);
- };
-
- Rejected.prototype._report = function(context) {
- tasks.afterQueue(new ReportTask(this, context));
- };
-
- Rejected.prototype._unreport = function() {
- this.handled = true;
- tasks.afterQueue(new UnreportTask(this));
- };
-
- Rejected.prototype.fail = function(context) {
- Promise.onFatalRejection(this, context === void 0 ? this.context : context);
- };
-
- function ReportTask(rejection, context) {
- this.rejection = rejection;
- this.context = context;
- }
-
- ReportTask.prototype.run = function() {
- if(!this.rejection.handled) {
- this.rejection.reported = true;
- Promise.onPotentiallyUnhandledRejection(this.rejection, this.context);
- }
- };
-
- function UnreportTask(rejection) {
- this.rejection = rejection;
- }
-
- UnreportTask.prototype.run = function() {
- if(this.rejection.reported) {
- Promise.onPotentiallyUnhandledRejectionHandled(this.rejection);
- }
- };
-
- // Unhandled rejection hooks
- // By default, everything is a noop
-
- // TODO: Better names: "annotate"?
- Promise.createContext
- = Promise.enterContext
- = Promise.exitContext
- = Promise.onPotentiallyUnhandledRejection
- = Promise.onPotentiallyUnhandledRejectionHandled
- = Promise.onFatalRejection
- = noop;
-
- // Errors and singletons
-
- var foreverPendingHandler = new Handler();
- var foreverPendingPromise = new Promise(Handler, foreverPendingHandler);
-
- function cycle() {
- return new Rejected(new TypeError('Promise cycle'));
- }
-
- // Task runners
-
- /**
- * Run a single consumer
- * @constructor
- */
- function ContinuationTask(continuation, handler) {
- this.continuation = continuation;
- this.handler = handler;
- }
-
- ContinuationTask.prototype.run = function() {
- this.handler.join().when(this.continuation);
- };
-
- /**
- * Run a queue of progress handlers
- * @constructor
- */
- function ProgressTask(value, handler) {
- this.handler = handler;
- this.value = value;
- }
-
- ProgressTask.prototype.run = function() {
- var q = this.handler.consumers;
- if(q === void 0) {
- return;
- }
-
- for (var c, i = 0; i < q.length; ++i) {
- c = q[i];
- runNotify(c.progress, this.value, this.handler, c.receiver, c.resolver);
- }
- };
-
- /**
- * Assimilate a thenable, sending it's value to resolver
- * @param {function} then
- * @param {object|function} thenable
- * @param {object} resolver
- * @constructor
- */
- function AssimilateTask(then, thenable, resolver) {
- this._then = then;
- this.thenable = thenable;
- this.resolver = resolver;
- }
-
- AssimilateTask.prototype.run = function() {
- var h = this.resolver;
- tryAssimilate(this._then, this.thenable, _resolve, _reject, _notify);
-
- function _resolve(x) { h.resolve(x); }
- function _reject(x) { h.reject(x); }
- function _notify(x) { h.notify(x); }
- };
-
- function tryAssimilate(then, thenable, resolve, reject, notify) {
- try {
- then.call(thenable, resolve, reject, notify);
- } catch (e) {
- reject(e);
- }
- }
-
- // Other helpers
-
- /**
- * @param {*} x
- * @returns {boolean} true iff x is a trusted Promise
- */
- function isPromise(x) {
- return x instanceof Promise;
- }
-
- /**
- * Test just enough to rule out primitives, in order to take faster
- * paths in some code
- * @param {*} x
- * @returns {boolean} false iff x is guaranteed *not* to be a thenable
- */
- function maybeThenable(x) {
- return (typeof x === 'object' || typeof x === 'function') && x !== null;
- }
-
- function runContinuation1(f, h, receiver, next) {
- if(typeof f !== 'function') {
- return next.become(h);
- }
-
- Promise.enterContext(h);
- tryCatchReject(f, h.value, receiver, next);
- Promise.exitContext();
- }
-
- function runContinuation3(f, x, h, receiver, next) {
- if(typeof f !== 'function') {
- return next.become(h);
- }
-
- Promise.enterContext(h);
- tryCatchReject3(f, x, h.value, receiver, next);
- Promise.exitContext();
- }
-
- function runNotify(f, x, h, receiver, next) {
- if(typeof f !== 'function') {
- return next.notify(x);
- }
-
- Promise.enterContext(h);
- tryCatchReturn(f, x, receiver, next);
- Promise.exitContext();
- }
-
- /**
- * Return f.call(thisArg, x), or if it throws return a rejected promise for
- * the thrown exception
- */
- function tryCatchReject(f, x, thisArg, next) {
- try {
- next.become(getHandler(f.call(thisArg, x)));
- } catch(e) {
- next.become(new Rejected(e));
- }
- }
-
- /**
- * Same as above, but includes the extra argument parameter.
- */
- function tryCatchReject3(f, x, y, thisArg, next) {
- try {
- f.call(thisArg, x, y, next);
- } catch(e) {
- next.become(new Rejected(e));
- }
- }
-
- /**
- * Return f.call(thisArg, x), or if it throws, *return* the exception
- */
- function tryCatchReturn(f, x, thisArg, next) {
- try {
- next.notify(f.call(thisArg, x));
- } catch(e) {
- next.notify(e);
- }
- }
-
- function inherit(Parent, Child) {
- Child.prototype = objectCreate(Parent.prototype);
- Child.prototype.constructor = Child;
- }
-
- function noop() {}
-
- return Promise;
- };
-});
-}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
-
-},{}]},{},[10])
-(10)
-});
-//# sourceMappingURL=vendor.js.map \ No newline at end of file
diff --git a/libmproxy/web/static/css/vendor.css b/libmproxy/web/static/vendor.css
index aebf39b0..f10d2b38 100644
--- a/libmproxy/web/static/css/vendor.css
+++ b/libmproxy/web/static/vendor.css
@@ -8087,4 +8087,4 @@ button.close {
content: "\f20c";
}
-/*# sourceMappingURL=../css/vendor.css.map */ \ No newline at end of file
+/*# sourceMappingURL=vendor.css.map */ \ No newline at end of file
diff --git a/libmproxy/web/static/vendor.js b/libmproxy/web/static/vendor.js
new file mode 100644
index 00000000..95c9a02d
--- /dev/null
+++ b/libmproxy/web/static/vendor.js
@@ -0,0 +1,40961 @@
+require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+/*!
+ * The buffer module from node.js, for the browser.
+ *
+ * @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
+ * @license MIT
+ */
+
+var base64 = require('base64-js')
+var ieee754 = require('ieee754')
+var isArray = require('is-array')
+
+exports.Buffer = Buffer
+exports.SlowBuffer = Buffer
+exports.INSPECT_MAX_BYTES = 50
+Buffer.poolSize = 8192 // not used by this implementation
+
+var kMaxLength = 0x3fffffff
+
+/**
+ * If `Buffer.TYPED_ARRAY_SUPPORT`:
+ * === true Use Uint8Array implementation (fastest)
+ * === false Use Object implementation (most compatible, even IE6)
+ *
+ * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,
+ * Opera 11.6+, iOS 4.2+.
+ *
+ * Note:
+ *
+ * - Implementation must support adding new properties to `Uint8Array` instances.
+ * Firefox 4-29 lacked support, fixed in Firefox 30+.
+ * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.
+ *
+ * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.
+ *
+ * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of
+ * incorrect length in some situations.
+ *
+ * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they will
+ * get the Object implementation, which is slower but will work correctly.
+ */
+Buffer.TYPED_ARRAY_SUPPORT = (function () {
+ try {
+ var buf = new ArrayBuffer(0)
+ var arr = new Uint8Array(buf)
+ arr.foo = function () { return 42 }
+ return 42 === arr.foo() && // typed array instances can be augmented
+ typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`
+ new Uint8Array(1).subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`
+ } catch (e) {
+ return false
+ }
+})()
+
+/**
+ * Class: Buffer
+ * =============
+ *
+ * The Buffer constructor returns instances of `Uint8Array` that are augmented
+ * with function properties for all the node `Buffer` API functions. We use
+ * `Uint8Array` so that square bracket notation works as expected -- it returns
+ * a single octet.
+ *
+ * By augmenting the instances, we can avoid modifying the `Uint8Array`
+ * prototype.
+ */
+function Buffer (subject, encoding, noZero) {
+ if (!(this instanceof Buffer))
+ return new Buffer(subject, encoding, noZero)
+
+ var type = typeof subject
+
+ // Find the length
+ var length
+ if (type === 'number')
+ length = subject > 0 ? subject >>> 0 : 0
+ else if (type === 'string') {
+ if (encoding === 'base64')
+ subject = base64clean(subject)
+ length = Buffer.byteLength(subject, encoding)
+ } else if (type === 'object' && subject !== null) { // assume object is array-like
+ if (subject.type === 'Buffer' && isArray(subject.data))
+ subject = subject.data
+ length = +subject.length > 0 ? Math.floor(+subject.length) : 0
+ } else
+ throw new TypeError('must start with number, buffer, array or string')
+
+ if (this.length > kMaxLength)
+ throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
+ 'size: 0x' + kMaxLength.toString(16) + ' bytes')
+
+ var buf
+ if (Buffer.TYPED_ARRAY_SUPPORT) {
+ // Preferred: Return an augmented `Uint8Array` instance for best performance
+ buf = Buffer._augment(new Uint8Array(length))
+ } else {
+ // Fallback: Return THIS instance of Buffer (created by `new`)
+ buf = this
+ buf.length = length
+ buf._isBuffer = true
+ }
+
+ var i
+ if (Buffer.TYPED_ARRAY_SUPPORT && typeof subject.byteLength === 'number') {
+ // Speed optimization -- use set if we're copying from a typed array
+ buf._set(subject)
+ } else if (isArrayish(subject)) {
+ // Treat array-ish objects as a byte array
+ if (Buffer.isBuffer(subject)) {
+ for (i = 0; i < length; i++)
+ buf[i] = subject.readUInt8(i)
+ } else {
+ for (i = 0; i < length; i++)
+ buf[i] = ((subject[i] % 256) + 256) % 256
+ }
+ } else if (type === 'string') {
+ buf.write(subject, 0, encoding)
+ } else if (type === 'number' && !Buffer.TYPED_ARRAY_SUPPORT && !noZero) {
+ for (i = 0; i < length; i++) {
+ buf[i] = 0
+ }
+ }
+
+ return buf
+}
+
+Buffer.isBuffer = function (b) {
+ return !!(b != null && b._isBuffer)
+}
+
+Buffer.compare = function (a, b) {
+ if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b))
+ throw new TypeError('Arguments must be Buffers')
+
+ var x = a.length
+ var y = b.length
+ for (var i = 0, len = Math.min(x, y); i < len && a[i] === b[i]; i++) {}
+ if (i !== len) {
+ x = a[i]
+ y = b[i]
+ }
+ if (x < y) return -1
+ if (y < x) return 1
+ return 0
+}
+
+Buffer.isEncoding = function (encoding) {
+ switch (String(encoding).toLowerCase()) {
+ case 'hex':
+ case 'utf8':
+ case 'utf-8':
+ case 'ascii':
+ case 'binary':
+ case 'base64':
+ case 'raw':
+ case 'ucs2':
+ case 'ucs-2':
+ case 'utf16le':
+ case 'utf-16le':
+ return true
+ default:
+ return false
+ }
+}
+
+Buffer.concat = function (list, totalLength) {
+ if (!isArray(list)) throw new TypeError('Usage: Buffer.concat(list[, length])')
+
+ if (list.length === 0) {
+ return new Buffer(0)
+ } else if (list.length === 1) {
+ return list[0]
+ }
+
+ var i
+ if (totalLength === undefined) {
+ totalLength = 0
+ for (i = 0; i < list.length; i++) {
+ totalLength += list[i].length
+ }
+ }
+
+ var buf = new Buffer(totalLength)
+ var pos = 0
+ for (i = 0; i < list.length; i++) {
+ var item = list[i]
+ item.copy(buf, pos)
+ pos += item.length
+ }
+ return buf
+}
+
+Buffer.byteLength = function (str, encoding) {
+ var ret
+ str = str + ''
+ switch (encoding || 'utf8') {
+ case 'ascii':
+ case 'binary':
+ case 'raw':
+ ret = str.length
+ break
+ case 'ucs2':
+ case 'ucs-2':
+ case 'utf16le':
+ case 'utf-16le':
+ ret = str.length * 2
+ break
+ case 'hex':
+ ret = str.length >>> 1
+ break
+ case 'utf8':
+ case 'utf-8':
+ ret = utf8ToBytes(str).length
+ break
+ case 'base64':
+ ret = base64ToBytes(str).length
+ break
+ default:
+ ret = str.length
+ }
+ return ret
+}
+
+// pre-set for values that may exist in the future
+Buffer.prototype.length = undefined
+Buffer.prototype.parent = undefined
+
+// toString(encoding, start=0, end=buffer.length)
+Buffer.prototype.toString = function (encoding, start, end) {
+ var loweredCase = false
+
+ start = start >>> 0
+ end = end === undefined || end === Infinity ? this.length : end >>> 0
+
+ if (!encoding) encoding = 'utf8'
+ if (start < 0) start = 0
+ if (end > this.length) end = this.length
+ if (end <= start) return ''
+
+ while (true) {
+ switch (encoding) {
+ case 'hex':
+ return hexSlice(this, start, end)
+
+ case 'utf8':
+ case 'utf-8':
+ return utf8Slice(this, start, end)
+
+ case 'ascii':
+ return asciiSlice(this, start, end)
+
+ case 'binary':
+ return binarySlice(this, start, end)
+
+ case 'base64':
+ return base64Slice(this, start, end)
+
+ case 'ucs2':
+ case 'ucs-2':
+ case 'utf16le':
+ case 'utf-16le':
+ return utf16leSlice(this, start, end)
+
+ default:
+ if (loweredCase)
+ throw new TypeError('Unknown encoding: ' + encoding)
+ encoding = (encoding + '').toLowerCase()
+ loweredCase = true
+ }
+ }
+}
+
+Buffer.prototype.equals = function (b) {
+ if(!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')
+ return Buffer.compare(this, b) === 0
+}
+
+Buffer.prototype.inspect = function () {
+ var str = ''
+ var max = exports.INSPECT_MAX_BYTES
+ if (this.length > 0) {
+ str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')
+ if (this.length > max)
+ str += ' ... '
+ }
+ return '<Buffer ' + str + '>'
+}
+
+Buffer.prototype.compare = function (b) {
+ if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')
+ return Buffer.compare(this, b)
+}
+
+// `get` will be removed in Node 0.13+
+Buffer.prototype.get = function (offset) {
+ console.log('.get() is deprecated. Access using array indexes instead.')
+ return this.readUInt8(offset)
+}
+
+// `set` will be removed in Node 0.13+
+Buffer.prototype.set = function (v, offset) {
+ console.log('.set() is deprecated. Access using array indexes instead.')
+ return this.writeUInt8(v, offset)
+}
+
+function hexWrite (buf, string, offset, length) {
+ offset = Number(offset) || 0
+ var remaining = buf.length - offset
+ if (!length) {
+ length = remaining
+ } else {
+ length = Number(length)
+ if (length > remaining) {
+ length = remaining
+ }
+ }
+
+ // must be an even number of digits
+ var strLen = string.length
+ if (strLen % 2 !== 0) throw new Error('Invalid hex string')
+
+ if (length > strLen / 2) {
+ length = strLen / 2
+ }
+ for (var i = 0; i < length; i++) {
+ var byte = parseInt(string.substr(i * 2, 2), 16)
+ if (isNaN(byte)) throw new Error('Invalid hex string')
+ buf[offset + i] = byte
+ }
+ return i
+}
+
+function utf8Write (buf, string, offset, length) {
+ var charsWritten = blitBuffer(utf8ToBytes(string), buf, offset, length)
+ return charsWritten
+}
+
+function asciiWrite (buf, string, offset, length) {
+ var charsWritten = blitBuffer(asciiToBytes(string), buf, offset, length)
+ return charsWritten
+}
+
+function binaryWrite (buf, string, offset, length) {
+ return asciiWrite(buf, string, offset, length)
+}
+
+function base64Write (buf, string, offset, length) {
+ var charsWritten = blitBuffer(base64ToBytes(string), buf, offset, length)
+ return charsWritten
+}
+
+function utf16leWrite (buf, string, offset, length) {
+ var charsWritten = blitBuffer(utf16leToBytes(string), buf, offset, length, 2)
+ return charsWritten
+}
+
+Buffer.prototype.write = function (string, offset, length, encoding) {
+ // Support both (string, offset, length, encoding)
+ // and the legacy (string, encoding, offset, length)
+ if (isFinite(offset)) {
+ if (!isFinite(length)) {
+ encoding = length
+ length = undefined
+ }
+ } else { // legacy
+ var swap = encoding
+ encoding = offset
+ offset = length
+ length = swap
+ }
+
+ offset = Number(offset) || 0
+ var remaining = this.length - offset
+ if (!length) {
+ length = remaining
+ } else {
+ length = Number(length)
+ if (length > remaining) {
+ length = remaining
+ }
+ }
+ encoding = String(encoding || 'utf8').toLowerCase()
+
+ var ret
+ switch (encoding) {
+ case 'hex':
+ ret = hexWrite(this, string, offset, length)
+ break
+ case 'utf8':
+ case 'utf-8':
+ ret = utf8Write(this, string, offset, length)
+ break
+ case 'ascii':
+ ret = asciiWrite(this, string, offset, length)
+ break
+ case 'binary':
+ ret = binaryWrite(this, string, offset, length)
+ break
+ case 'base64':
+ ret = base64Write(this, string, offset, length)
+ break
+ case 'ucs2':
+ case 'ucs-2':
+ case 'utf16le':
+ case 'utf-16le':
+ ret = utf16leWrite(this, string, offset, length)
+ break
+ default:
+ throw new TypeError('Unknown encoding: ' + encoding)
+ }
+ return ret
+}
+
+Buffer.prototype.toJSON = function () {
+ return {
+ type: 'Buffer',
+ data: Array.prototype.slice.call(this._arr || this, 0)
+ }
+}
+
+function base64Slice (buf, start, end) {
+ if (start === 0 && end === buf.length) {
+ return base64.fromByteArray(buf)
+ } else {
+ return base64.fromByteArray(buf.slice(start, end))
+ }
+}
+
+function utf8Slice (buf, start, end) {
+ var res = ''
+ var tmp = ''
+ end = Math.min(buf.length, end)
+
+ for (var i = start; i < end; i++) {
+ if (buf[i] <= 0x7F) {
+ res += decodeUtf8Char(tmp) + String.fromCharCode(buf[i])
+ tmp = ''
+ } else {
+ tmp += '%' + buf[i].toString(16)
+ }
+ }
+
+ return res + decodeUtf8Char(tmp)
+}
+
+function asciiSlice (buf, start, end) {
+ var ret = ''
+ end = Math.min(buf.length, end)
+
+ for (var i = start; i < end; i++) {
+ ret += String.fromCharCode(buf[i])
+ }
+ return ret
+}
+
+function binarySlice (buf, start, end) {
+ return asciiSlice(buf, start, end)
+}
+
+function hexSlice (buf, start, end) {
+ var len = buf.length
+
+ if (!start || start < 0) start = 0
+ if (!end || end < 0 || end > len) end = len
+
+ var out = ''
+ for (var i = start; i < end; i++) {
+ out += toHex(buf[i])
+ }
+ return out
+}
+
+function utf16leSlice (buf, start, end) {
+ var bytes = buf.slice(start, end)
+ var res = ''
+ for (var i = 0; i < bytes.length; i += 2) {
+ res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)
+ }
+ return res
+}
+
+Buffer.prototype.slice = function (start, end) {
+ var len = this.length
+ start = ~~start
+ end = end === undefined ? len : ~~end
+
+ if (start < 0) {
+ start += len;
+ if (start < 0)
+ start = 0
+ } else if (start > len) {
+ start = len
+ }
+
+ if (end < 0) {
+ end += len
+ if (end < 0)
+ end = 0
+ } else if (end > len) {
+ end = len
+ }
+
+ if (end < start)
+ end = start
+
+ if (Buffer.TYPED_ARRAY_SUPPORT) {
+ return Buffer._augment(this.subarray(start, end))
+ } else {
+ var sliceLen = end - start
+ var newBuf = new Buffer(sliceLen, undefined, true)
+ for (var i = 0; i < sliceLen; i++) {
+ newBuf[i] = this[i + start]
+ }
+ return newBuf
+ }
+}
+
+/*
+ * Need to make sure that buffer isn't trying to write out of bounds.
+ */
+function checkOffset (offset, ext, length) {
+ if ((offset % 1) !== 0 || offset < 0)
+ throw new RangeError('offset is not uint')
+ if (offset + ext > length)
+ throw new RangeError('Trying to access beyond buffer length')
+}
+
+Buffer.prototype.readUInt8 = function (offset, noAssert) {
+ if (!noAssert)
+ checkOffset(offset, 1, this.length)
+ return this[offset]
+}
+
+Buffer.prototype.readUInt16LE = function (offset, noAssert) {
+ if (!noAssert)
+ checkOffset(offset, 2, this.length)
+ return this[offset] | (this[offset + 1] << 8)
+}
+
+Buffer.prototype.readUInt16BE = function (offset, noAssert) {
+ if (!noAssert)
+ checkOffset(offset, 2, this.length)
+ return (this[offset] << 8) | this[offset + 1]
+}
+
+Buffer.prototype.readUInt32LE = function (offset, noAssert) {
+ if (!noAssert)
+ checkOffset(offset, 4, this.length)
+
+ return ((this[offset]) |
+ (this[offset + 1] << 8) |
+ (this[offset + 2] << 16)) +
+ (this[offset + 3] * 0x1000000)
+}
+
+Buffer.prototype.readUInt32BE = function (offset, noAssert) {
+ if (!noAssert)
+ checkOffset(offset, 4, this.length)
+
+ return (this[offset] * 0x1000000) +
+ ((this[offset + 1] << 16) |
+ (this[offset + 2] << 8) |
+ this[offset + 3])
+}
+
+Buffer.prototype.readInt8 = function (offset, noAssert) {
+ if (!noAssert)
+ checkOffset(offset, 1, this.length)
+ if (!(this[offset] & 0x80))
+ return (this[offset])
+ return ((0xff - this[offset] + 1) * -1)
+}
+
+Buffer.prototype.readInt16LE = function (offset, noAssert) {
+ if (!noAssert)
+ checkOffset(offset, 2, this.length)
+ var val = this[offset] | (this[offset + 1] << 8)
+ return (val & 0x8000) ? val | 0xFFFF0000 : val
+}
+
+Buffer.prototype.readInt16BE = function (offset, noAssert) {
+ if (!noAssert)
+ checkOffset(offset, 2, this.length)
+ var val = this[offset + 1] | (this[offset] << 8)
+ return (val & 0x8000) ? val | 0xFFFF0000 : val
+}
+
+Buffer.prototype.readInt32LE = function (offset, noAssert) {
+ if (!noAssert)
+ checkOffset(offset, 4, this.length)
+
+ return (this[offset]) |
+ (this[offset + 1] << 8) |
+ (this[offset + 2] << 16) |
+ (this[offset + 3] << 24)
+}
+
+Buffer.prototype.readInt32BE = function (offset, noAssert) {
+ if (!noAssert)
+ checkOffset(offset, 4, this.length)
+
+ return (this[offset] << 24) |
+ (this[offset + 1] << 16) |
+ (this[offset + 2] << 8) |
+ (this[offset + 3])
+}
+
+Buffer.prototype.readFloatLE = function (offset, noAssert) {
+ if (!noAssert)
+ checkOffset(offset, 4, this.length)
+ return ieee754.read(this, offset, true, 23, 4)
+}
+
+Buffer.prototype.readFloatBE = function (offset, noAssert) {
+ if (!noAssert)
+ checkOffset(offset, 4, this.length)
+ return ieee754.read(this, offset, false, 23, 4)
+}
+
+Buffer.prototype.readDoubleLE = function (offset, noAssert) {
+ if (!noAssert)
+ checkOffset(offset, 8, this.length)
+ return ieee754.read(this, offset, true, 52, 8)
+}
+
+Buffer.prototype.readDoubleBE = function (offset, noAssert) {
+ if (!noAssert)
+ checkOffset(offset, 8, this.length)
+ return ieee754.read(this, offset, false, 52, 8)
+}
+
+function checkInt (buf, value, offset, ext, max, min) {
+ if (!Buffer.isBuffer(buf)) throw new TypeError('buffer must be a Buffer instance')
+ if (value > max || value < min) throw new TypeError('value is out of bounds')
+ if (offset + ext > buf.length) throw new TypeError('index out of range')
+}
+
+Buffer.prototype.writeUInt8 = function (value, offset, noAssert) {
+ value = +value
+ offset = offset >>> 0
+ if (!noAssert)
+ checkInt(this, value, offset, 1, 0xff, 0)
+ if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)
+ this[offset] = value
+ return offset + 1
+}
+
+function objectWriteUInt16 (buf, value, offset, littleEndian) {
+ if (value < 0) value = 0xffff + value + 1
+ for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) {
+ buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>
+ (littleEndian ? i : 1 - i) * 8
+ }
+}
+
+Buffer.prototype.writeUInt16LE = function (value, offset, noAssert) {
+ value = +value
+ offset = offset >>> 0
+ if (!noAssert)
+ checkInt(this, value, offset, 2, 0xffff, 0)
+ if (Buffer.TYPED_ARRAY_SUPPORT) {
+ this[offset] = value
+ this[offset + 1] = (value >>> 8)
+ } else objectWriteUInt16(this, value, offset, true)
+ return offset + 2
+}
+
+Buffer.prototype.writeUInt16BE = function (value, offset, noAssert) {
+ value = +value
+ offset = offset >>> 0
+ if (!noAssert)
+ checkInt(this, value, offset, 2, 0xffff, 0)
+ if (Buffer.TYPED_ARRAY_SUPPORT) {
+ this[offset] = (value >>> 8)
+ this[offset + 1] = value
+ } else objectWriteUInt16(this, value, offset, false)
+ return offset + 2
+}
+
+function objectWriteUInt32 (buf, value, offset, littleEndian) {
+ if (value < 0) value = 0xffffffff + value + 1
+ for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) {
+ buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff
+ }
+}
+
+Buffer.prototype.writeUInt32LE = function (value, offset, noAssert) {
+ value = +value
+ offset = offset >>> 0
+ if (!noAssert)
+ checkInt(this, value, offset, 4, 0xffffffff, 0)
+ if (Buffer.TYPED_ARRAY_SUPPORT) {
+ this[offset + 3] = (value >>> 24)
+ this[offset + 2] = (value >>> 16)
+ this[offset + 1] = (value >>> 8)
+ this[offset] = value
+ } else objectWriteUInt32(this, value, offset, true)
+ return offset + 4
+}
+
+Buffer.prototype.writeUInt32BE = function (value, offset, noAssert) {
+ value = +value
+ offset = offset >>> 0
+ if (!noAssert)
+ checkInt(this, value, offset, 4, 0xffffffff, 0)
+ if (Buffer.TYPED_ARRAY_SUPPORT) {
+ this[offset] = (value >>> 24)
+ this[offset + 1] = (value >>> 16)
+ this[offset + 2] = (value >>> 8)
+ this[offset + 3] = value
+ } else objectWriteUInt32(this, value, offset, false)
+ return offset + 4
+}
+
+Buffer.prototype.writeInt8 = function (value, offset, noAssert) {
+ value = +value
+ offset = offset >>> 0
+ if (!noAssert)
+ checkInt(this, value, offset, 1, 0x7f, -0x80)
+ if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)
+ if (value < 0) value = 0xff + value + 1
+ this[offset] = value
+ return offset + 1
+}
+
+Buffer.prototype.writeInt16LE = function (value, offset, noAssert) {
+ value = +value
+ offset = offset >>> 0
+ if (!noAssert)
+ checkInt(this, value, offset, 2, 0x7fff, -0x8000)
+ if (Buffer.TYPED_ARRAY_SUPPORT) {
+ this[offset] = value
+ this[offset + 1] = (value >>> 8)
+ } else objectWriteUInt16(this, value, offset, true)
+ return offset + 2
+}
+
+Buffer.prototype.writeInt16BE = function (value, offset, noAssert) {
+ value = +value
+ offset = offset >>> 0
+ if (!noAssert)
+ checkInt(this, value, offset, 2, 0x7fff, -0x8000)
+ if (Buffer.TYPED_ARRAY_SUPPORT) {
+ this[offset] = (value >>> 8)
+ this[offset + 1] = value
+ } else objectWriteUInt16(this, value, offset, false)
+ return offset + 2
+}
+
+Buffer.prototype.writeInt32LE = function (value, offset, noAssert) {
+ value = +value
+ offset = offset >>> 0
+ if (!noAssert)
+ checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
+ if (Buffer.TYPED_ARRAY_SUPPORT) {
+ this[offset] = value
+ this[offset + 1] = (value >>> 8)
+ this[offset + 2] = (value >>> 16)
+ this[offset + 3] = (value >>> 24)
+ } else objectWriteUInt32(this, value, offset, true)
+ return offset + 4
+}
+
+Buffer.prototype.writeInt32BE = function (value, offset, noAssert) {
+ value = +value
+ offset = offset >>> 0
+ if (!noAssert)
+ checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
+ if (value < 0) value = 0xffffffff + value + 1
+ if (Buffer.TYPED_ARRAY_SUPPORT) {
+ this[offset] = (value >>> 24)
+ this[offset + 1] = (value >>> 16)
+ this[offset + 2] = (value >>> 8)
+ this[offset + 3] = value
+ } else objectWriteUInt32(this, value, offset, false)
+ return offset + 4
+}
+
+function checkIEEE754 (buf, value, offset, ext, max, min) {
+ if (value > max || value < min) throw new TypeError('value is out of bounds')
+ if (offset + ext > buf.length) throw new TypeError('index out of range')
+}
+
+function writeFloat (buf, value, offset, littleEndian, noAssert) {
+ if (!noAssert)
+ checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)
+ ieee754.write(buf, value, offset, littleEndian, 23, 4)
+ return offset + 4
+}
+
+Buffer.prototype.writeFloatLE = function (value, offset, noAssert) {
+ return writeFloat(this, value, offset, true, noAssert)
+}
+
+Buffer.prototype.writeFloatBE = function (value, offset, noAssert) {
+ return writeFloat(this, value, offset, false, noAssert)
+}
+
+function writeDouble (buf, value, offset, littleEndian, noAssert) {
+ if (!noAssert)
+ checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)
+ ieee754.write(buf, value, offset, littleEndian, 52, 8)
+ return offset + 8
+}
+
+Buffer.prototype.writeDoubleLE = function (value, offset, noAssert) {
+ return writeDouble(this, value, offset, true, noAssert)
+}
+
+Buffer.prototype.writeDoubleBE = function (value, offset, noAssert) {
+ return writeDouble(this, value, offset, false, noAssert)
+}
+
+// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
+Buffer.prototype.copy = function (target, target_start, start, end) {
+ var source = this
+
+ if (!start) start = 0
+ if (!end && end !== 0) end = this.length
+ if (!target_start) target_start = 0
+
+ // Copy 0 bytes; we're done
+ if (end === start) return
+ if (target.length === 0 || source.length === 0) return
+
+ // Fatal error conditions
+ if (end < start) throw new TypeError('sourceEnd < sourceStart')
+ if (target_start < 0 || target_start >= target.length)
+ throw new TypeError('targetStart out of bounds')
+ if (start < 0 || start >= source.length) throw new TypeError('sourceStart out of bounds')
+ if (end < 0 || end > source.length) throw new TypeError('sourceEnd out of bounds')
+
+ // Are we oob?
+ if (end > this.length)
+ end = this.length
+ if (target.length - target_start < end - start)
+ end = target.length - target_start + start
+
+ var len = end - start
+
+ if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {
+ for (var i = 0; i < len; i++) {
+ target[i + target_start] = this[i + start]
+ }
+ } else {
+ target._set(this.subarray(start, start + len), target_start)
+ }
+}
+
+// fill(value, start=0, end=buffer.length)
+Buffer.prototype.fill = function (value, start, end) {
+ if (!value) value = 0
+ if (!start) start = 0
+ if (!end) end = this.length
+
+ if (end < start) throw new TypeError('end < start')
+
+ // Fill 0 bytes; we're done
+ if (end === start) return
+ if (this.length === 0) return
+
+ if (start < 0 || start >= this.length) throw new TypeError('start out of bounds')
+ if (end < 0 || end > this.length) throw new TypeError('end out of bounds')
+
+ var i
+ if (typeof value === 'number') {
+ for (i = start; i < end; i++) {
+ this[i] = value
+ }
+ } else {
+ var bytes = utf8ToBytes(value.toString())
+ var len = bytes.length
+ for (i = start; i < end; i++) {
+ this[i] = bytes[i % len]
+ }
+ }
+
+ return this
+}
+
+/**
+ * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance.
+ * Added in Node 0.12. Only available in browsers that support ArrayBuffer.
+ */
+Buffer.prototype.toArrayBuffer = function () {
+ if (typeof Uint8Array !== 'undefined') {
+ if (Buffer.TYPED_ARRAY_SUPPORT) {
+ return (new Buffer(this)).buffer
+ } else {
+ var buf = new Uint8Array(this.length)
+ for (var i = 0, len = buf.length; i < len; i += 1) {
+ buf[i] = this[i]
+ }
+ return buf.buffer
+ }
+ } else {
+ throw new TypeError('Buffer.toArrayBuffer not supported in this browser')
+ }
+}
+
+// HELPER FUNCTIONS
+// ================
+
+var BP = Buffer.prototype
+
+/**
+ * Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods
+ */
+Buffer._augment = function (arr) {
+ arr.constructor = Buffer
+ arr._isBuffer = true
+
+ // save reference to original Uint8Array get/set methods before overwriting
+ arr._get = arr.get
+ arr._set = arr.set
+
+ // deprecated, will be removed in node 0.13+
+ arr.get = BP.get
+ arr.set = BP.set
+
+ arr.write = BP.write
+ arr.toString = BP.toString
+ arr.toLocaleString = BP.toString
+ arr.toJSON = BP.toJSON
+ arr.equals = BP.equals
+ arr.compare = BP.compare
+ arr.copy = BP.copy
+ arr.slice = BP.slice
+ arr.readUInt8 = BP.readUInt8
+ arr.readUInt16LE = BP.readUInt16LE
+ arr.readUInt16BE = BP.readUInt16BE
+ arr.readUInt32LE = BP.readUInt32LE
+ arr.readUInt32BE = BP.readUInt32BE
+ arr.readInt8 = BP.readInt8
+ arr.readInt16LE = BP.readInt16LE
+ arr.readInt16BE = BP.readInt16BE
+ arr.readInt32LE = BP.readInt32LE
+ arr.readInt32BE = BP.readInt32BE
+ arr.readFloatLE = BP.readFloatLE
+ arr.readFloatBE = BP.readFloatBE
+ arr.readDoubleLE = BP.readDoubleLE
+ arr.readDoubleBE = BP.readDoubleBE
+ arr.writeUInt8 = BP.writeUInt8
+ arr.writeUInt16LE = BP.writeUInt16LE
+ arr.writeUInt16BE = BP.writeUInt16BE
+ arr.writeUInt32LE = BP.writeUInt32LE
+ arr.writeUInt32BE = BP.writeUInt32BE
+ arr.writeInt8 = BP.writeInt8
+ arr.writeInt16LE = BP.writeInt16LE
+ arr.writeInt16BE = BP.writeInt16BE
+ arr.writeInt32LE = BP.writeInt32LE
+ arr.writeInt32BE = BP.writeInt32BE
+ arr.writeFloatLE = BP.writeFloatLE
+ arr.writeFloatBE = BP.writeFloatBE
+ arr.writeDoubleLE = BP.writeDoubleLE
+ arr.writeDoubleBE = BP.writeDoubleBE
+ arr.fill = BP.fill
+ arr.inspect = BP.inspect
+ arr.toArrayBuffer = BP.toArrayBuffer
+
+ return arr
+}
+
+var INVALID_BASE64_RE = /[^+\/0-9A-z]/g
+
+function base64clean (str) {
+ // Node strips out invalid characters like \n and \t from the string, base64-js does not
+ str = stringtrim(str).replace(INVALID_BASE64_RE, '')
+ // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not
+ while (str.length % 4 !== 0) {
+ str = str + '='
+ }
+ return str
+}
+
+function stringtrim (str) {
+ if (str.trim) return str.trim()
+ return str.replace(/^\s+|\s+$/g, '')
+}
+
+function isArrayish (subject) {
+ return isArray(subject) || Buffer.isBuffer(subject) ||
+ subject && typeof subject === 'object' &&
+ typeof subject.length === 'number'
+}
+
+function toHex (n) {
+ if (n < 16) return '0' + n.toString(16)
+ return n.toString(16)
+}
+
+function utf8ToBytes (str) {
+ var byteArray = []
+ for (var i = 0; i < str.length; i++) {
+ var b = str.charCodeAt(i)
+ if (b <= 0x7F) {
+ byteArray.push(b)
+ } else {
+ var start = i
+ if (b >= 0xD800 && b <= 0xDFFF) i++
+ var h = encodeURIComponent(str.slice(start, i+1)).substr(1).split('%')
+ for (var j = 0; j < h.length; j++) {
+ byteArray.push(parseInt(h[j], 16))
+ }
+ }
+ }
+ return byteArray
+}
+
+function asciiToBytes (str) {
+ var byteArray = []
+ for (var i = 0; i < str.length; i++) {
+ // Node's code seems to be doing this and not & 0x7F..
+ byteArray.push(str.charCodeAt(i) & 0xFF)
+ }
+ return byteArray
+}
+
+function utf16leToBytes (str) {
+ var c, hi, lo
+ var byteArray = []
+ for (var i = 0; i < str.length; i++) {
+ c = str.charCodeAt(i)
+ hi = c >> 8
+ lo = c % 256
+ byteArray.push(lo)
+ byteArray.push(hi)
+ }
+
+ return byteArray
+}
+
+function base64ToBytes (str) {
+ return base64.toByteArray(str)
+}
+
+function blitBuffer (src, dst, offset, length, unitSize) {
+ if (unitSize) length -= length % unitSize;
+ for (var i = 0; i < length; i++) {
+ if ((i + offset >= dst.length) || (i >= src.length))
+ break
+ dst[i + offset] = src[i]
+ }
+ return i
+}
+
+function decodeUtf8Char (str) {
+ try {
+ return decodeURIComponent(str)
+ } catch (err) {
+ return String.fromCharCode(0xFFFD) // UTF 8 invalid char
+ }
+}
+
+},{"base64-js":2,"ieee754":3,"is-array":4}],2:[function(require,module,exports){
+var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+
+;(function (exports) {
+ 'use strict';
+
+ var Arr = (typeof Uint8Array !== 'undefined')
+ ? Uint8Array
+ : Array
+
+ var PLUS = '+'.charCodeAt(0)
+ var SLASH = '/'.charCodeAt(0)
+ var NUMBER = '0'.charCodeAt(0)
+ var LOWER = 'a'.charCodeAt(0)
+ var UPPER = 'A'.charCodeAt(0)
+
+ function decode (elt) {
+ var code = elt.charCodeAt(0)
+ if (code === PLUS)
+ return 62 // '+'
+ if (code === SLASH)
+ return 63 // '/'
+ if (code < NUMBER)
+ return -1 //no match
+ if (code < NUMBER + 10)
+ return code - NUMBER + 26 + 26
+ if (code < UPPER + 26)
+ return code - UPPER
+ if (code < LOWER + 26)
+ return code - LOWER + 26
+ }
+
+ function b64ToByteArray (b64) {
+ var i, j, l, tmp, placeHolders, arr
+
+ if (b64.length % 4 > 0) {
+ throw new Error('Invalid string. Length must be a multiple of 4')
+ }
+
+ // the number of equal signs (place holders)
+ // if there are two placeholders, than the two characters before it
+ // represent one byte
+ // if there is only one, then the three characters before it represent 2 bytes
+ // this is just a cheap hack to not do indexOf twice
+ var len = b64.length
+ placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0
+
+ // base64 is 4/3 + up to two characters of the original data
+ arr = new Arr(b64.length * 3 / 4 - placeHolders)
+
+ // if there are placeholders, only get up to the last complete 4 chars
+ l = placeHolders > 0 ? b64.length - 4 : b64.length
+
+ var L = 0
+
+ function push (v) {
+ arr[L++] = v
+ }
+
+ for (i = 0, j = 0; i < l; i += 4, j += 3) {
+ tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))
+ push((tmp & 0xFF0000) >> 16)
+ push((tmp & 0xFF00) >> 8)
+ push(tmp & 0xFF)
+ }
+
+ if (placeHolders === 2) {
+ tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)
+ push(tmp & 0xFF)
+ } else if (placeHolders === 1) {
+ tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)
+ push((tmp >> 8) & 0xFF)
+ push(tmp & 0xFF)
+ }
+
+ return arr
+ }
+
+ function uint8ToBase64 (uint8) {
+ var i,
+ extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes
+ output = "",
+ temp, length
+
+ function encode (num) {
+ return lookup.charAt(num)
+ }
+
+ function tripletToBase64 (num) {
+ return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)
+ }
+
+ // go through the array every three bytes, we'll deal with trailing stuff later
+ for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {
+ temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])
+ output += tripletToBase64(temp)
+ }
+
+ // pad the end with zeros, but make sure to not forget the extra bytes
+ switch (extraBytes) {
+ case 1:
+ temp = uint8[uint8.length - 1]
+ output += encode(temp >> 2)
+ output += encode((temp << 4) & 0x3F)
+ output += '=='
+ break
+ case 2:
+ temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])
+ output += encode(temp >> 10)
+ output += encode((temp >> 4) & 0x3F)
+ output += encode((temp << 2) & 0x3F)
+ output += '='
+ break
+ }
+
+ return output
+ }
+
+ exports.toByteArray = b64ToByteArray
+ exports.fromByteArray = uint8ToBase64
+}(typeof exports === 'undefined' ? (this.base64js = {}) : exports))
+
+},{}],3:[function(require,module,exports){
+exports.read = function(buffer, offset, isLE, mLen, nBytes) {
+ var e, m,
+ eLen = nBytes * 8 - mLen - 1,
+ eMax = (1 << eLen) - 1,
+ eBias = eMax >> 1,
+ nBits = -7,
+ i = isLE ? (nBytes - 1) : 0,
+ d = isLE ? -1 : 1,
+ s = buffer[offset + i];
+
+ i += d;
+
+ e = s & ((1 << (-nBits)) - 1);
+ s >>= (-nBits);
+ nBits += eLen;
+ for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8);
+
+ m = e & ((1 << (-nBits)) - 1);
+ e >>= (-nBits);
+ nBits += mLen;
+ for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8);
+
+ if (e === 0) {
+ e = 1 - eBias;
+ } else if (e === eMax) {
+ return m ? NaN : ((s ? -1 : 1) * Infinity);
+ } else {
+ m = m + Math.pow(2, mLen);
+ e = e - eBias;
+ }
+ return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
+};
+
+exports.write = function(buffer, value, offset, isLE, mLen, nBytes) {
+ var e, m, c,
+ eLen = nBytes * 8 - mLen - 1,
+ eMax = (1 << eLen) - 1,
+ eBias = eMax >> 1,
+ rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0),
+ i = isLE ? 0 : (nBytes - 1),
+ d = isLE ? 1 : -1,
+ s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0;
+
+ value = Math.abs(value);
+
+ if (isNaN(value) || value === Infinity) {
+ m = isNaN(value) ? 1 : 0;
+ e = eMax;
+ } else {
+ e = Math.floor(Math.log(value) / Math.LN2);
+ if (value * (c = Math.pow(2, -e)) < 1) {
+ e--;
+ c *= 2;
+ }
+ if (e + eBias >= 1) {
+ value += rt / c;
+ } else {
+ value += rt * Math.pow(2, 1 - eBias);
+ }
+ if (value * c >= 2) {
+ e++;
+ c /= 2;
+ }
+
+ if (e + eBias >= eMax) {
+ m = 0;
+ e = eMax;
+ } else if (e + eBias >= 1) {
+ m = (value * c - 1) * Math.pow(2, mLen);
+ e = e + eBias;
+ } else {
+ m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
+ e = 0;
+ }
+ }
+
+ for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8);
+
+ e = (e << mLen) | m;
+ eLen += mLen;
+ for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8);
+
+ buffer[offset + i - d] |= s * 128;
+};
+
+},{}],4:[function(require,module,exports){
+
+/**
+ * isArray
+ */
+
+var isArray = Array.isArray;
+
+/**
+ * toString
+ */
+
+var str = Object.prototype.toString;
+
+/**
+ * Whether or not the given `val`
+ * is an array.
+ *
+ * example:
+ *
+ * isArray([]);
+ * // > true
+ * isArray(arguments);
+ * // > false
+ * isArray('');
+ * // > false
+ *
+ * @param {mixed} val
+ * @return {bool}
+ */
+
+module.exports = isArray || function (val) {
+ return !! val && '[object Array]' == str.call(val);
+};
+
+},{}],5:[function(require,module,exports){
+// shim for using process in browser
+
+var process = module.exports = {};
+
+process.nextTick = (function () {
+ var canSetImmediate = typeof window !== 'undefined'
+ && window.setImmediate;
+ var canMutationObserver = typeof window !== 'undefined'
+ && window.MutationObserver;
+ var canPost = typeof window !== 'undefined'
+ && window.postMessage && window.addEventListener
+ ;
+
+ if (canSetImmediate) {
+ return function (f) { return window.setImmediate(f) };
+ }
+
+ var queue = [];
+
+ if (canMutationObserver) {
+ var hiddenDiv = document.createElement("div");
+ var observer = new MutationObserver(function () {
+ var queueList = queue.slice();
+ queue.length = 0;
+ queueList.forEach(function (fn) {
+ fn();
+ });
+ });
+
+ observer.observe(hiddenDiv, { attributes: true });
+
+ return function nextTick(fn) {
+ if (!queue.length) {
+ hiddenDiv.setAttribute('yes', 'no');
+ }
+ queue.push(fn);
+ };
+ }
+
+ if (canPost) {
+ window.addEventListener('message', function (ev) {
+ var source = ev.source;
+ if ((source === window || source === null) && ev.data === 'process-tick') {
+ ev.stopPropagation();
+ if (queue.length > 0) {
+ var fn = queue.shift();
+ fn();
+ }
+ }
+ }, true);
+
+ return function nextTick(fn) {
+ queue.push(fn);
+ window.postMessage('process-tick', '*');
+ };
+ }
+
+ return function nextTick(fn) {
+ setTimeout(fn, 0);
+ };
+})();
+
+process.title = 'browser';
+process.browser = true;
+process.env = {};
+process.argv = [];
+
+function noop() {}
+
+process.on = noop;
+process.addListener = noop;
+process.once = noop;
+process.off = noop;
+process.removeListener = noop;
+process.removeAllListeners = noop;
+process.emit = noop;
+
+process.binding = function (name) {
+ throw new Error('process.binding is not supported');
+};
+
+// TODO(shtylman)
+process.cwd = function () { return '/' };
+process.chdir = function (dir) {
+ throw new Error('process.chdir is not supported');
+};
+
+},{}],6:[function(require,module,exports){
+/**
+ * Actions that modify the URL.
+ */
+var LocationActions = {
+
+ /**
+ * Indicates a new location is being pushed to the history stack.
+ */
+ PUSH: 'push',
+
+ /**
+ * Indicates the current location should be replaced.
+ */
+ REPLACE: 'replace',
+
+ /**
+ * Indicates the most recent entry should be removed from the history stack.
+ */
+ POP: 'pop'
+
+};
+
+module.exports = LocationActions;
+
+},{}],7:[function(require,module,exports){
+var LocationActions = require('../actions/LocationActions');
+
+/**
+ * A scroll behavior that attempts to imitate the default behavior
+ * of modern browsers.
+ */
+var ImitateBrowserBehavior = {
+
+ updateScrollPosition: function (position, actionType) {
+ switch (actionType) {
+ case LocationActions.PUSH:
+ case LocationActions.REPLACE:
+ window.scrollTo(0, 0);
+ break;
+ case LocationActions.POP:
+ if (position) {
+ window.scrollTo(position.x, position.y);
+ } else {
+ window.scrollTo(0, 0);
+ }
+ break;
+ }
+ }
+
+};
+
+module.exports = ImitateBrowserBehavior;
+
+},{"../actions/LocationActions":6}],8:[function(require,module,exports){
+/**
+ * A scroll behavior that always scrolls to the top of the page
+ * after a transition.
+ */
+var ScrollToTopBehavior = {
+
+ updateScrollPosition: function () {
+ window.scrollTo(0, 0);
+ }
+
+};
+
+module.exports = ScrollToTopBehavior;
+
+},{}],9:[function(require,module,exports){
+var React = require('react');
+var FakeNode = require('../mixins/FakeNode');
+var PropTypes = require('../utils/PropTypes');
+
+/**
+ * A <DefaultRoute> component is a special kind of <Route> that
+ * renders when its parent matches but none of its siblings do.
+ * Only one such route may be used at any given level in the
+ * route hierarchy.
+ */
+var DefaultRoute = React.createClass({
+
+ displayName: 'DefaultRoute',
+
+ mixins: [ FakeNode ],
+
+ propTypes: {
+ name: React.PropTypes.string,
+ path: PropTypes.falsy,
+ handler: React.PropTypes.func.isRequired
+ }
+
+});
+
+module.exports = DefaultRoute;
+
+},{"../mixins/FakeNode":18,"../utils/PropTypes":29,"react":"react"}],10:[function(require,module,exports){
+var React = require('react');
+var classSet = require('react/lib/cx');
+var assign = require('react/lib/Object.assign');
+var Navigation = require('../mixins/Navigation');
+var State = require('../mixins/State');
+
+function isLeftClickEvent(event) {
+ return event.button === 0;
+}
+
+function isModifiedEvent(event) {
+ return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
+}
+
+/**
+ * <Link> components are used to create an <a> element that links to a route.
+ * When that route is active, the link gets an "active" class name (or the
+ * value of its `activeClassName` prop).
+ *
+ * For example, assuming you have the following route:
+ *
+ * <Route name="showPost" path="/posts/:postID" handler={Post}/>
+ *
+ * You could use the following component to link to that route:
+ *
+ * <Link to="showPost" params={{ postID: "123" }} />
+ *
+ * In addition to params, links may pass along query string parameters
+ * using the `query` prop.
+ *
+ * <Link to="showPost" params={{ postID: "123" }} query={{ show:true }}/>
+ */
+var Link = React.createClass({
+
+ displayName: 'Link',
+
+ mixins: [ Navigation, State ],
+
+ propTypes: {
+ activeClassName: React.PropTypes.string.isRequired,
+ to: React.PropTypes.string.isRequired,
+ params: React.PropTypes.object,
+ query: React.PropTypes.object,
+ onClick: React.PropTypes.func
+ },
+
+ getDefaultProps: function () {
+ return {
+ activeClassName: 'active'
+ };
+ },
+
+ handleClick: function (event) {
+ var allowTransition = true;
+ var clickResult;
+
+ if (this.props.onClick)
+ clickResult = this.props.onClick(event);
+
+ if (isModifiedEvent(event) || !isLeftClickEvent(event))
+ return;
+
+ if (clickResult === false || event.defaultPrevented === true)
+ allowTransition = false;
+
+ event.preventDefault();
+
+ if (allowTransition)
+ this.transitionTo(this.props.to, this.props.params, this.props.query);
+ },
+
+ /**
+ * Returns the value of the "href" attribute to use on the DOM element.
+ */
+ getHref: function () {
+ return this.makeHref(this.props.to, this.props.params, this.props.query);
+ },
+
+ /**
+ * Returns the value of the "class" attribute to use on the DOM element, which contains
+ * the value of the activeClassName property when this <Link> is active.
+ */
+ getClassName: function () {
+ var classNames = {};
+
+ if (this.props.className)
+ classNames[this.props.className] = true;
+
+ if (this.isActive(this.props.to, this.props.params, this.props.query))
+ classNames[this.props.activeClassName] = true;
+
+ return classSet(classNames);
+ },
+
+ render: function () {
+ var props = assign({}, this.props, {
+ href: this.getHref(),
+ className: this.getClassName(),
+ onClick: this.handleClick
+ });
+
+ return React.DOM.a(props, this.props.children);
+ }
+
+});
+
+module.exports = Link;
+
+},{"../mixins/Navigation":19,"../mixins/State":23,"react":"react","react/lib/Object.assign":75,"react/lib/cx":165}],11:[function(require,module,exports){
+var React = require('react');
+var FakeNode = require('../mixins/FakeNode');
+var PropTypes = require('../utils/PropTypes');
+
+/**
+ * A <NotFoundRoute> is a special kind of <Route> that
+ * renders when the beginning of its parent's path matches
+ * but none of its siblings do, including any <DefaultRoute>.
+ * Only one such route may be used at any given level in the
+ * route hierarchy.
+ */
+var NotFoundRoute = React.createClass({
+
+ displayName: 'NotFoundRoute',
+
+ mixins: [ FakeNode ],
+
+ propTypes: {
+ name: React.PropTypes.string,
+ path: PropTypes.falsy,
+ handler: React.PropTypes.func.isRequired
+ }
+
+});
+
+module.exports = NotFoundRoute;
+
+},{"../mixins/FakeNode":18,"../utils/PropTypes":29,"react":"react"}],12:[function(require,module,exports){
+var React = require('react');
+var FakeNode = require('../mixins/FakeNode');
+var PropTypes = require('../utils/PropTypes');
+
+/**
+ * A <Redirect> component is a special kind of <Route> that always
+ * redirects to another route when it matches.
+ */
+var Redirect = React.createClass({
+
+ displayName: 'Redirect',
+
+ mixins: [ FakeNode ],
+
+ propTypes: {
+ path: React.PropTypes.string,
+ from: React.PropTypes.string, // Alias for path.
+ to: React.PropTypes.string,
+ handler: PropTypes.falsy
+ }
+
+});
+
+module.exports = Redirect;
+
+},{"../mixins/FakeNode":18,"../utils/PropTypes":29,"react":"react"}],13:[function(require,module,exports){
+var React = require('react');
+var FakeNode = require('../mixins/FakeNode');
+
+/**
+ * <Route> components specify components that are rendered to the page when the
+ * URL matches a given pattern.
+ *
+ * Routes are arranged in a nested tree structure. When a new URL is requested,
+ * the tree is searched depth-first to find a route whose path matches the URL.
+ * When one is found, all routes in the tree that lead to it are considered
+ * "active" and their components are rendered into the DOM, nested in the same
+ * order as they are in the tree.
+ *
+ * The preferred way to configure a router is using JSX. The XML-like syntax is
+ * a great way to visualize how routes are laid out in an application.
+ *
+ * var routes = [
+ * <Route handler={App}>
+ * <Route name="login" handler={Login}/>
+ * <Route name="logout" handler={Logout}/>
+ * <Route name="about" handler={About}/>
+ * </Route>
+ * ];
+ *
+ * Router.run(routes, function (Handler) {
+ * React.render(<Handler/>, document.body);
+ * });
+ *
+ * Handlers for Route components that contain children can render their active
+ * child route using a <RouteHandler> element.
+ *
+ * var App = React.createClass({
+ * render: function () {
+ * return (
+ * <div class="application">
+ * <RouteHandler/>
+ * </div>
+ * );
+ * }
+ * });
+ */
+var Route = React.createClass({
+
+ displayName: 'Route',
+
+ mixins: [ FakeNode ],
+
+ propTypes: {
+ name: React.PropTypes.string,
+ path: React.PropTypes.string,
+ handler: React.PropTypes.func.isRequired,
+ ignoreScrollBehavior: React.PropTypes.bool
+ }
+
+});
+
+module.exports = Route;
+
+},{"../mixins/FakeNode":18,"react":"react"}],14:[function(require,module,exports){
+var React = require('react');
+var RouteHandlerMixin = require('../mixins/RouteHandler');
+
+/**
+ * A <RouteHandler> component renders the active child route handler
+ * when routes are nested.
+ */
+var RouteHandler = React.createClass({
+
+ displayName: 'RouteHandler',
+
+ mixins: [RouteHandlerMixin],
+
+ getDefaultProps: function () {
+ return {
+ ref: '__routeHandler__'
+ };
+ },
+
+ render: function () {
+ return this.getRouteHandler();
+ }
+
+});
+
+module.exports = RouteHandler;
+
+},{"../mixins/RouteHandler":21,"react":"react"}],15:[function(require,module,exports){
+var LocationActions = require('../actions/LocationActions');
+var History = require('../utils/History');
+var Path = require('../utils/Path');
+
+/**
+ * Returns the current URL path from the `hash` portion of the URL, including
+ * query string.
+ */
+function getHashPath() {
+ return Path.decode(
+ // We can't use window.location.hash here because it's not
+ // consistent across browsers - Firefox will pre-decode it!
+ window.location.href.split('#')[1] || ''
+ );
+}
+
+var _actionType;
+
+function ensureSlash() {
+ var path = getHashPath();
+
+ if (path.charAt(0) === '/')
+ return true;
+
+ HashLocation.replace('/' + path);
+
+ return false;
+}
+
+var _changeListeners = [];
+
+function notifyChange(type) {
+ if (type === LocationActions.PUSH)
+ History.length += 1;
+
+ var change = {
+ path: getHashPath(),
+ type: type
+ };
+
+ _changeListeners.forEach(function (listener) {
+ listener(change);
+ });
+}
+
+var _isListening = false;
+
+function onHashChange() {
+ if (ensureSlash()) {
+ // If we don't have an _actionType then all we know is the hash
+ // changed. It was probably caused by the user clicking the Back
+ // button, but may have also been the Forward button or manual
+ // manipulation. So just guess 'pop'.
+ notifyChange(_actionType || LocationActions.POP);
+ _actionType = null;
+ }
+}
+
+/**
+ * A Location that uses `window.location.hash`.
+ */
+var HashLocation = {
+
+ addChangeListener: function (listener) {
+ _changeListeners.push(listener);
+
+ // Do this BEFORE listening for hashchange.
+ ensureSlash();
+
+ if (_isListening)
+ return;
+
+ if (window.addEventListener) {
+ window.addEventListener('hashchange', onHashChange, false);
+ } else {
+ window.attachEvent('onhashchange', onHashChange);
+ }
+
+ _isListening = true;
+ },
+
+ removeChangeListener: function(listener) {
+ for (var i = 0, l = _changeListeners.length; i < l; i ++) {
+ if (_changeListeners[i] === listener) {
+ _changeListeners.splice(i, 1);
+ break;
+ }
+ }
+
+ if (window.removeEventListener) {
+ window.removeEventListener('hashchange', onHashChange, false);
+ } else {
+ window.removeEvent('onhashchange', onHashChange);
+ }
+
+ if (_changeListeners.length === 0)
+ _isListening = false;
+ },
+
+
+
+ push: function (path) {
+ _actionType = LocationActions.PUSH;
+ window.location.hash = Path.encode(path);
+ },
+
+ replace: function (path) {
+ _actionType = LocationActions.REPLACE;
+ window.location.replace(window.location.pathname + '#' + Path.encode(path));
+ },
+
+ pop: function () {
+ _actionType = LocationActions.POP;
+ History.back();
+ },
+
+ getCurrentPath: getHashPath,
+
+ toString: function () {
+ return '<HashLocation>';
+ }
+
+};
+
+module.exports = HashLocation;
+
+},{"../actions/LocationActions":6,"../utils/History":26,"../utils/Path":27}],16:[function(require,module,exports){
+var LocationActions = require('../actions/LocationActions');
+var History = require('../utils/History');
+var Path = require('../utils/Path');
+
+/**
+ * Returns the current URL path from `window.location`, including query string.
+ */
+function getWindowPath() {
+ return Path.decode(
+ window.location.pathname + window.location.search
+ );
+}
+
+var _changeListeners = [];
+
+function notifyChange(type) {
+ var change = {
+ path: getWindowPath(),
+ type: type
+ };
+
+ _changeListeners.forEach(function (listener) {
+ listener(change);
+ });
+}
+
+var _isListening = false;
+
+function onPopState() {
+ notifyChange(LocationActions.POP);
+}
+
+/**
+ * A Location that uses HTML5 history.
+ */
+var HistoryLocation = {
+
+ addChangeListener: function (listener) {
+ _changeListeners.push(listener);
+
+ if (_isListening)
+ return;
+
+ if (window.addEventListener) {
+ window.addEventListener('popstate', onPopState, false);
+ } else {
+ window.attachEvent('popstate', onPopState);
+ }
+
+ _isListening = true;
+ },
+
+ removeChangeListener: function(listener) {
+ for (var i = 0, l = _changeListeners.length; i < l; i ++) {
+ if (_changeListeners[i] === listener) {
+ _changeListeners.splice(i, 1);
+ break;
+ }
+ }
+
+ if (window.addEventListener) {
+ window.removeEventListener('popstate', onPopState);
+ } else {
+ window.removeEvent('popstate', onPopState);
+ }
+
+ if (_changeListeners.length === 0)
+ _isListening = false;
+ },
+
+
+
+ push: function (path) {
+ window.history.pushState({ path: path }, '', Path.encode(path));
+ History.length += 1;
+ notifyChange(LocationActions.PUSH);
+ },
+
+ replace: function (path) {
+ window.history.replaceState({ path: path }, '', Path.encode(path));
+ notifyChange(LocationActions.REPLACE);
+ },
+
+ pop: History.back,
+
+ getCurrentPath: getWindowPath,
+
+ toString: function () {
+ return '<HistoryLocation>';
+ }
+
+};
+
+module.exports = HistoryLocation;
+
+},{"../actions/LocationActions":6,"../utils/History":26,"../utils/Path":27}],17:[function(require,module,exports){
+var HistoryLocation = require('./HistoryLocation');
+var History = require('../utils/History');
+var Path = require('../utils/Path');
+
+/**
+ * A Location that uses full page refreshes. This is used as
+ * the fallback for HistoryLocation in browsers that do not
+ * support the HTML5 history API.
+ */
+var RefreshLocation = {
+
+ push: function (path) {
+ window.location = Path.encode(path);
+ },
+
+ replace: function (path) {
+ window.location.replace(Path.encode(path));
+ },
+
+ pop: History.back,
+
+ getCurrentPath: HistoryLocation.getCurrentPath,
+
+ toString: function () {
+ return '<RefreshLocation>';
+ }
+
+};
+
+module.exports = RefreshLocation;
+
+},{"../utils/History":26,"../utils/Path":27,"./HistoryLocation":16}],18:[function(require,module,exports){
+var invariant = require('react/lib/invariant');
+
+var FakeNode = {
+
+ render: function () {
+ invariant(
+ false,
+ '%s elements should not be rendered',
+ this.constructor.displayName
+ );
+ }
+
+};
+
+module.exports = FakeNode;
+
+},{"react/lib/invariant":187}],19:[function(require,module,exports){
+var React = require('react');
+
+/**
+ * A mixin for components that modify the URL.
+ *
+ * Example:
+ *
+ * var MyLink = React.createClass({
+ * mixins: [ Router.Navigation ],
+ * handleClick: function (event) {
+ * event.preventDefault();
+ * this.transitionTo('aRoute', { the: 'params' }, { the: 'query' });
+ * },
+ * render: function () {
+ * return (
+ * <a onClick={this.handleClick}>Click me!</a>
+ * );
+ * }
+ * });
+ */
+var Navigation = {
+
+ contextTypes: {
+ makePath: React.PropTypes.func.isRequired,
+ makeHref: React.PropTypes.func.isRequired,
+ transitionTo: React.PropTypes.func.isRequired,
+ replaceWith: React.PropTypes.func.isRequired,
+ goBack: React.PropTypes.func.isRequired
+ },
+
+ /**
+ * Returns an absolute URL path created from the given route
+ * name, URL parameters, and query values.
+ */
+ makePath: function (to, params, query) {
+ return this.context.makePath(to, params, query);
+ },
+
+ /**
+ * Returns a string that may safely be used as the href of a
+ * link to the route with the given name.
+ */
+ makeHref: function (to, params, query) {
+ return this.context.makeHref(to, params, query);
+ },
+
+ /**
+ * Transitions to the URL specified in the arguments by pushing
+ * a new URL onto the history stack.
+ */
+ transitionTo: function (to, params, query) {
+ this.context.transitionTo(to, params, query);
+ },
+
+ /**
+ * Transitions to the URL specified in the arguments by replacing
+ * the current URL in the history stack.
+ */
+ replaceWith: function (to, params, query) {
+ this.context.replaceWith(to, params, query);
+ },
+
+ /**
+ * Transitions to the previous URL.
+ */
+ goBack: function () {
+ this.context.goBack();
+ }
+
+};
+
+module.exports = Navigation;
+
+},{"react":"react"}],20:[function(require,module,exports){
+var React = require('react');
+
+/**
+ * Provides the router with context for Router.Navigation.
+ */
+var NavigationContext = {
+
+ childContextTypes: {
+ makePath: React.PropTypes.func.isRequired,
+ makeHref: React.PropTypes.func.isRequired,
+ transitionTo: React.PropTypes.func.isRequired,
+ replaceWith: React.PropTypes.func.isRequired,
+ goBack: React.PropTypes.func.isRequired
+ },
+
+ getChildContext: function () {
+ return {
+ makePath: this.constructor.makePath,
+ makeHref: this.constructor.makeHref,
+ transitionTo: this.constructor.transitionTo,
+ replaceWith: this.constructor.replaceWith,
+ goBack: this.constructor.goBack
+ };
+ }
+
+};
+
+module.exports = NavigationContext;
+
+},{"react":"react"}],21:[function(require,module,exports){
+var React = require('react');
+
+module.exports = {
+ contextTypes: {
+ getRouteAtDepth: React.PropTypes.func.isRequired,
+ getRouteComponents: React.PropTypes.func.isRequired,
+ routeHandlers: React.PropTypes.array.isRequired
+ },
+
+ childContextTypes: {
+ routeHandlers: React.PropTypes.array.isRequired
+ },
+
+ getChildContext: function () {
+ return {
+ routeHandlers: this.context.routeHandlers.concat([ this ])
+ };
+ },
+
+ getRouteDepth: function () {
+ return this.context.routeHandlers.length - 1;
+ },
+
+ componentDidMount: function () {
+ this._updateRouteComponent();
+ },
+
+ componentDidUpdate: function () {
+ this._updateRouteComponent();
+ },
+
+ _updateRouteComponent: function () {
+ var depth = this.getRouteDepth();
+ var components = this.context.getRouteComponents();
+ components[depth] = this.refs[this.props.ref || '__routeHandler__'];
+ },
+
+ getRouteHandler: function (props) {
+ var route = this.context.getRouteAtDepth(this.getRouteDepth());
+ return route ? React.createElement(route.handler, props || this.props) : null;
+ }
+};
+},{"react":"react"}],22:[function(require,module,exports){
+var invariant = require('react/lib/invariant');
+var canUseDOM = require('react/lib/ExecutionEnvironment').canUseDOM;
+var getWindowScrollPosition = require('../utils/getWindowScrollPosition');
+
+function shouldUpdateScroll(state, prevState) {
+ if (!prevState)
+ return true;
+
+ // Don't update scroll position when only the query has changed.
+ if (state.pathname === prevState.pathname)
+ return false;
+
+ var routes = state.routes;
+ var prevRoutes = prevState.routes;
+
+ var sharedAncestorRoutes = routes.filter(function (route) {
+ return prevRoutes.indexOf(route) !== -1;
+ });
+
+ return !sharedAncestorRoutes.some(function (route) {
+ return route.ignoreScrollBehavior;
+ });
+}
+
+/**
+ * Provides the router with the ability to manage window scroll position
+ * according to its scroll behavior.
+ */
+var Scrolling = {
+
+ statics: {
+ /**
+ * Records curent scroll position as the last known position for the given URL path.
+ */
+ recordScrollPosition: function (path) {
+ if (!this.scrollHistory)
+ this.scrollHistory = {};
+
+ this.scrollHistory[path] = getWindowScrollPosition();
+ },
+
+ /**
+ * Returns the last known scroll position for the given URL path.
+ */
+ getScrollPosition: function (path) {
+ if (!this.scrollHistory)
+ this.scrollHistory = {};
+
+ return this.scrollHistory[path] || null;
+ }
+ },
+
+ componentWillMount: function () {
+ invariant(
+ this.getScrollBehavior() == null || canUseDOM,
+ 'Cannot use scroll behavior without a DOM'
+ );
+ },
+
+ componentDidMount: function () {
+ this._updateScroll();
+ },
+
+ componentDidUpdate: function (prevProps, prevState) {
+ this._updateScroll(prevState);
+ },
+
+ _updateScroll: function (prevState) {
+ if (!shouldUpdateScroll(this.state, prevState))
+ return;
+
+ var scrollBehavior = this.getScrollBehavior();
+
+ if (scrollBehavior)
+ scrollBehavior.updateScrollPosition(
+ this.constructor.getScrollPosition(this.state.path),
+ this.state.action
+ );
+ }
+
+};
+
+module.exports = Scrolling;
+
+},{"../utils/getWindowScrollPosition":34,"react/lib/ExecutionEnvironment":69,"react/lib/invariant":187}],23:[function(require,module,exports){
+var React = require('react');
+
+/**
+ * A mixin for components that need to know the path, routes, URL
+ * params and query that are currently active.
+ *
+ * Example:
+ *
+ * var AboutLink = React.createClass({
+ * mixins: [ Router.State ],
+ * render: function () {
+ * var className = this.props.className;
+ *
+ * if (this.isActive('about'))
+ * className += ' is-active';
+ *
+ * return React.DOM.a({ className: className }, this.props.children);
+ * }
+ * });
+ */
+var State = {
+
+ contextTypes: {
+ getCurrentPath: React.PropTypes.func.isRequired,
+ getCurrentRoutes: React.PropTypes.func.isRequired,
+ getCurrentPathname: React.PropTypes.func.isRequired,
+ getCurrentParams: React.PropTypes.func.isRequired,
+ getCurrentQuery: React.PropTypes.func.isRequired,
+ isActive: React.PropTypes.func.isRequired
+ },
+
+ /**
+ * Returns the current URL path.
+ */
+ getPath: function () {
+ return this.context.getCurrentPath();
+ },
+
+ /**
+ * Returns an array of the routes that are currently active.
+ */
+ getRoutes: function () {
+ return this.context.getCurrentRoutes();
+ },
+
+ /**
+ * Returns the current URL path without the query string.
+ */
+ getPathname: function () {
+ return this.context.getCurrentPathname();
+ },
+
+ /**
+ * Returns an object of the URL params that are currently active.
+ */
+ getParams: function () {
+ return this.context.getCurrentParams();
+ },
+
+ /**
+ * Returns an object of the query params that are currently active.
+ */
+ getQuery: function () {
+ return this.context.getCurrentQuery();
+ },
+
+ /**
+ * A helper method to determine if a given route, params, and query
+ * are active.
+ */
+ isActive: function (to, params, query) {
+ return this.context.isActive(to, params, query);
+ }
+
+};
+
+module.exports = State;
+
+},{"react":"react"}],24:[function(require,module,exports){
+var React = require('react');
+var assign = require('react/lib/Object.assign');
+var Path = require('../utils/Path');
+
+function routeIsActive(activeRoutes, routeName) {
+ return activeRoutes.some(function (route) {
+ return route.name === routeName;
+ });
+}
+
+function paramsAreActive(activeParams, params) {
+ for (var property in params)
+ if (String(activeParams[property]) !== String(params[property]))
+ return false;
+
+ return true;
+}
+
+function queryIsActive(activeQuery, query) {
+ for (var property in query)
+ if (String(activeQuery[property]) !== String(query[property]))
+ return false;
+
+ return true;
+}
+
+/**
+ * Provides the router with context for Router.State.
+ */
+var StateContext = {
+
+ /**
+ * Returns the current URL path + query string.
+ */
+ getCurrentPath: function () {
+ return this.state.path;
+ },
+
+ /**
+ * Returns a read-only array of the currently active routes.
+ */
+ getCurrentRoutes: function () {
+ return this.state.routes.slice(0);
+ },
+
+ /**
+ * Returns the current URL path without the query string.
+ */
+ getCurrentPathname: function () {
+ return this.state.pathname;
+ },
+
+ /**
+ * Returns a read-only object of the currently active URL parameters.
+ */
+ getCurrentParams: function () {
+ return assign({}, this.state.params);
+ },
+
+ /**
+ * Returns a read-only object of the currently active query parameters.
+ */
+ getCurrentQuery: function () {
+ return assign({}, this.state.query);
+ },
+
+ /**
+ * Returns true if the given route, params, and query are active.
+ */
+ isActive: function (to, params, query) {
+ if (Path.isAbsolute(to))
+ return to === this.state.path;
+
+ return routeIsActive(this.state.routes, to) &&
+ paramsAreActive(this.state.params, params) &&
+ (query == null || queryIsActive(this.state.query, query));
+ },
+
+ childContextTypes: {
+ getCurrentPath: React.PropTypes.func.isRequired,
+ getCurrentRoutes: React.PropTypes.func.isRequired,
+ getCurrentPathname: React.PropTypes.func.isRequired,
+ getCurrentParams: React.PropTypes.func.isRequired,
+ getCurrentQuery: React.PropTypes.func.isRequired,
+ isActive: React.PropTypes.func.isRequired
+ },
+
+ getChildContext: function () {
+ return {
+ getCurrentPath: this.getCurrentPath,
+ getCurrentRoutes: this.getCurrentRoutes,
+ getCurrentPathname: this.getCurrentPathname,
+ getCurrentParams: this.getCurrentParams,
+ getCurrentQuery: this.getCurrentQuery,
+ isActive: this.isActive
+ };
+ }
+
+};
+
+module.exports = StateContext;
+
+},{"../utils/Path":27,"react":"react","react/lib/Object.assign":75}],25:[function(require,module,exports){
+/**
+ * Represents a cancellation caused by navigating away
+ * before the previous transition has fully resolved.
+ */
+function Cancellation() { }
+
+module.exports = Cancellation;
+
+},{}],26:[function(require,module,exports){
+var invariant = require('react/lib/invariant');
+var canUseDOM = require('react/lib/ExecutionEnvironment').canUseDOM;
+
+var History = {
+
+ /**
+ * Sends the browser back one entry in the history.
+ */
+ back: function () {
+ invariant(
+ canUseDOM,
+ 'Cannot use History.back without a DOM'
+ );
+
+ // Do this first so that History.length will
+ // be accurate in location change listeners.
+ History.length -= 1;
+
+ window.history.back();
+ },
+
+ /**
+ * The current number of entries in the history.
+ */
+ length: 1
+
+};
+
+module.exports = History;
+
+},{"react/lib/ExecutionEnvironment":69,"react/lib/invariant":187}],27:[function(require,module,exports){
+var invariant = require('react/lib/invariant');
+var merge = require('qs/lib/utils').merge;
+var qs = require('qs');
+
+var paramCompileMatcher = /:([a-zA-Z_$][a-zA-Z0-9_$]*)|[*.()\[\]\\+|{}^$]/g;
+var paramInjectMatcher = /:([a-zA-Z_$][a-zA-Z0-9_$?]*[?]?)|[*]/g;
+var paramInjectTrailingSlashMatcher = /\/\/\?|\/\?/g;
+var queryMatcher = /\?(.+)/;
+
+var _compiledPatterns = {};
+
+function compilePattern(pattern) {
+ if (!(pattern in _compiledPatterns)) {
+ var paramNames = [];
+ var source = pattern.replace(paramCompileMatcher, function (match, paramName) {
+ if (paramName) {
+ paramNames.push(paramName);
+ return '([^/?#]+)';
+ } else if (match === '*') {
+ paramNames.push('splat');
+ return '(.*?)';
+ } else {
+ return '\\' + match;
+ }
+ });
+
+ _compiledPatterns[pattern] = {
+ matcher: new RegExp('^' + source + '$', 'i'),
+ paramNames: paramNames
+ };
+ }
+
+ return _compiledPatterns[pattern];
+}
+
+var Path = {
+
+ /**
+ * Safely decodes special characters in the given URL path.
+ */
+ decode: function (path) {
+ return decodeURI(path.replace(/\+/g, ' '));
+ },
+
+ /**
+ * Safely encodes special characters in the given URL path.
+ */
+ encode: function (path) {
+ return encodeURI(path).replace(/%20/g, '+');
+ },
+
+ /**
+ * Returns an array of the names of all parameters in the given pattern.
+ */
+ extractParamNames: function (pattern) {
+ return compilePattern(pattern).paramNames;
+ },
+
+ /**
+ * Extracts the portions of the given URL path that match the given pattern
+ * and returns an object of param name => value pairs. Returns null if the
+ * pattern does not match the given path.
+ */
+ extractParams: function (pattern, path) {
+ var object = compilePattern(pattern);
+ var match = path.match(object.matcher);
+
+ if (!match)
+ return null;
+
+ var params = {};
+
+ object.paramNames.forEach(function (paramName, index) {
+ params[paramName] = match[index + 1];
+ });
+
+ return params;
+ },
+
+ /**
+ * Returns a version of the given route path with params interpolated. Throws
+ * if there is a dynamic segment of the route path for which there is no param.
+ */
+ injectParams: function (pattern, params) {
+ params = params || {};
+
+ var splatIndex = 0;
+
+ return pattern.replace(paramInjectMatcher, function (match, paramName) {
+ paramName = paramName || 'splat';
+
+ // If param is optional don't check for existence
+ if (paramName.slice(-1) !== '?') {
+ invariant(
+ params[paramName] != null,
+ 'Missing "' + paramName + '" parameter for path "' + pattern + '"'
+ );
+ } else {
+ paramName = paramName.slice(0, -1);
+
+ if (params[paramName] == null)
+ return '';
+ }
+
+ var segment;
+ if (paramName === 'splat' && Array.isArray(params[paramName])) {
+ segment = params[paramName][splatIndex++];
+
+ invariant(
+ segment != null,
+ 'Missing splat # ' + splatIndex + ' for path "' + pattern + '"'
+ );
+ } else {
+ segment = params[paramName];
+ }
+
+ return segment;
+ }).replace(paramInjectTrailingSlashMatcher, '/');
+ },
+
+ /**
+ * Returns an object that is the result of parsing any query string contained
+ * in the given path, null if the path contains no query string.
+ */
+ extractQuery: function (path) {
+ var match = path.match(queryMatcher);
+ return match && qs.parse(match[1]);
+ },
+
+ /**
+ * Returns a version of the given path without the query string.
+ */
+ withoutQuery: function (path) {
+ return path.replace(queryMatcher, '');
+ },
+
+ /**
+ * Returns a version of the given path with the parameters in the given
+ * query merged into the query string.
+ */
+ withQuery: function (path, query) {
+ var existingQuery = Path.extractQuery(path);
+
+ if (existingQuery)
+ query = query ? merge(existingQuery, query) : existingQuery;
+
+ var queryString = query && qs.stringify(query);
+
+ if (queryString)
+ return Path.withoutQuery(path) + '?' + queryString;
+
+ return path;
+ },
+
+ /**
+ * Returns true if the given path is absolute.
+ */
+ isAbsolute: function (path) {
+ return path.charAt(0) === '/';
+ },
+
+ /**
+ * Returns a normalized version of the given path.
+ */
+ normalize: function (path, parentRoute) {
+ return path.replace(/^\/*/, '/');
+ },
+
+ /**
+ * Joins two URL paths together.
+ */
+ join: function (a, b) {
+ return a.replace(/\/*$/, '/') + b;
+ }
+
+};
+
+module.exports = Path;
+
+},{"qs":38,"qs/lib/utils":42,"react/lib/invariant":187}],28:[function(require,module,exports){
+var Promise = require('when/lib/Promise');
+
+// TODO: Use process.env.NODE_ENV check + envify to enable
+// when's promise monitor here when in dev.
+
+module.exports = Promise;
+
+},{"when/lib/Promise":43}],29:[function(require,module,exports){
+var PropTypes = {
+
+ /**
+ * Requires that the value of a prop be falsy.
+ */
+ falsy: function (props, propName, componentName) {
+ if (props[propName])
+ return new Error('<' + componentName + '> may not have a "' + propName + '" prop');
+ }
+
+};
+
+module.exports = PropTypes;
+
+},{}],30:[function(require,module,exports){
+/**
+ * Encapsulates a redirect to the given route.
+ */
+function Redirect(to, params, query) {
+ this.to = to;
+ this.params = params;
+ this.query = query;
+}
+
+module.exports = Redirect;
+
+},{}],31:[function(require,module,exports){
+var assign = require('react/lib/Object.assign');
+var reversedArray = require('./reversedArray');
+var Redirect = require('./Redirect');
+var Promise = require('./Promise');
+
+/**
+ * Runs all hook functions serially and calls callback(error) when finished.
+ * A hook may return a promise if it needs to execute asynchronously.
+ */
+function runHooks(hooks, callback) {
+ var promise;
+ try {
+ promise = hooks.reduce(function (promise, hook) {
+ // The first hook to use transition.wait makes the rest
+ // of the transition async from that point forward.
+ return promise ? promise.then(hook) : hook();
+ }, null);
+ } catch (error) {
+ return callback(error); // Sync error.
+ }
+
+ if (promise) {
+ // Use setTimeout to break the promise chain.
+ promise.then(function () {
+ setTimeout(callback);
+ }, function (error) {
+ setTimeout(function () {
+ callback(error);
+ });
+ });
+ } else {
+ callback();
+ }
+}
+
+/**
+ * Calls the willTransitionFrom hook of all handlers in the given matches
+ * serially in reverse with the transition object and the current instance of
+ * the route's handler, so that the deepest nested handlers are called first.
+ * Calls callback(error) when finished.
+ */
+function runTransitionFromHooks(transition, routes, components, callback) {
+ components = reversedArray(components);
+
+ var hooks = reversedArray(routes).map(function (route, index) {
+ return function () {
+ var handler = route.handler;
+
+ if (!transition.isAborted && handler.willTransitionFrom)
+ return handler.willTransitionFrom(transition, components[index]);
+
+ var promise = transition._promise;
+ transition._promise = null;
+
+ return promise;
+ };
+ });
+
+ runHooks(hooks, callback);
+}
+
+/**
+ * Calls the willTransitionTo hook of all handlers in the given matches
+ * serially with the transition object and any params that apply to that
+ * handler. Calls callback(error) when finished.
+ */
+function runTransitionToHooks(transition, routes, params, query, callback) {
+ var hooks = routes.map(function (route) {
+ return function () {
+ var handler = route.handler;
+
+ if (!transition.isAborted && handler.willTransitionTo)
+ handler.willTransitionTo(transition, params, query);
+
+ var promise = transition._promise;
+ transition._promise = null;
+
+ return promise;
+ };
+ });
+
+ runHooks(hooks, callback);
+}
+
+/**
+ * Encapsulates a transition to a given path.
+ *
+ * The willTransitionTo and willTransitionFrom handlers receive
+ * an instance of this class as their first argument.
+ */
+function Transition(path, retry) {
+ this.path = path;
+ this.abortReason = null;
+ this.isAborted = false;
+ this.retry = retry.bind(this);
+ this._promise = null;
+}
+
+assign(Transition.prototype, {
+
+ abort: function (reason) {
+ if (this.isAborted) {
+ // First abort wins.
+ return;
+ }
+
+ this.abortReason = reason;
+ this.isAborted = true;
+ },
+
+ redirect: function (to, params, query) {
+ this.abort(new Redirect(to, params, query));
+ },
+
+ wait: function (value) {
+ this._promise = Promise.resolve(value);
+ },
+
+ from: function (routes, components, callback) {
+ return runTransitionFromHooks(this, routes, components, callback);
+ },
+
+ to: function (routes, params, query, callback) {
+ return runTransitionToHooks(this, routes, params, query, callback);
+ }
+
+});
+
+module.exports = Transition;
+
+},{"./Promise":28,"./Redirect":30,"./reversedArray":35,"react/lib/Object.assign":75}],32:[function(require,module,exports){
+(function (process){
+/* jshint -W058 */
+var React = require('react');
+var warning = require('react/lib/warning');
+var invariant = require('react/lib/invariant');
+var canUseDOM = require('react/lib/ExecutionEnvironment').canUseDOM;
+var ImitateBrowserBehavior = require('../behaviors/ImitateBrowserBehavior');
+var RouteHandler = require('../components/RouteHandler');
+var LocationActions = require('../actions/LocationActions');
+var HashLocation = require('../locations/HashLocation');
+var HistoryLocation = require('../locations/HistoryLocation');
+var RefreshLocation = require('../locations/RefreshLocation');
+var NavigationContext = require('../mixins/NavigationContext');
+var StateContext = require('../mixins/StateContext');
+var Scrolling = require('../mixins/Scrolling');
+var createRoutesFromChildren = require('./createRoutesFromChildren');
+var supportsHistory = require('./supportsHistory');
+var Transition = require('./Transition');
+var PropTypes = require('./PropTypes');
+var Redirect = require('./Redirect');
+var History = require('./History');
+var Cancellation = require('./Cancellation');
+var Path = require('./Path');
+
+/**
+ * The default location for new routers.
+ */
+var DEFAULT_LOCATION = canUseDOM ? HashLocation : '/';
+
+/**
+ * The default scroll behavior for new routers.
+ */
+var DEFAULT_SCROLL_BEHAVIOR = canUseDOM ? ImitateBrowserBehavior : null;
+
+/**
+ * The default error handler for new routers.
+ */
+function defaultErrorHandler(error) {
+ // Throw so we don't silently swallow async errors.
+ throw error; // This error probably originated in a transition hook.
+}
+
+/**
+ * The default aborted transition handler for new routers.
+ */
+function defaultAbortHandler(abortReason, location) {
+ if (typeof location === 'string')
+ throw new Error('Unhandled aborted transition! Reason: ' + abortReason);
+
+ if (abortReason instanceof Cancellation) {
+ return;
+ } else if (abortReason instanceof Redirect) {
+ location.replace(this.makePath(abortReason.to, abortReason.params, abortReason.query));
+ } else {
+ location.pop();
+ }
+}
+
+function findMatch(pathname, routes, defaultRoute, notFoundRoute) {
+ var match, route, params;
+
+ for (var i = 0, len = routes.length; i < len; ++i) {
+ route = routes[i];
+
+ // Check the subtree first to find the most deeply-nested match.
+ match = findMatch(pathname, route.childRoutes, route.defaultRoute, route.notFoundRoute);
+
+ if (match != null) {
+ match.routes.unshift(route);
+ return match;
+ }
+
+ // No routes in the subtree matched, so check this route.
+ params = Path.extractParams(route.path, pathname);
+
+ if (params)
+ return createMatch(route, params);
+ }
+
+ // No routes matched, so try the default route if there is one.
+ if (defaultRoute && (params = Path.extractParams(defaultRoute.path, pathname)))
+ return createMatch(defaultRoute, params);
+
+ // Last attempt: does the "not found" route match?
+ if (notFoundRoute && (params = Path.extractParams(notFoundRoute.path, pathname)))
+ return createMatch(notFoundRoute, params);
+
+ return match;
+}
+
+function createMatch(route, params) {
+ return { routes: [ route ], params: params };
+}
+
+function hasProperties(object, properties) {
+ for (var propertyName in properties)
+ if (properties.hasOwnProperty(propertyName) && object[propertyName] !== properties[propertyName])
+ return false;
+
+ return true;
+}
+
+function hasMatch(routes, route, prevParams, nextParams, prevQuery, nextQuery) {
+ return routes.some(function (r) {
+ if (r !== route)
+ return false;
+
+ var paramNames = route.paramNames;
+ var paramName;
+
+ // Ensure that all params the route cares about did not change.
+ for (var i = 0, len = paramNames.length; i < len; ++i) {
+ paramName = paramNames[i];
+
+ if (nextParams[paramName] !== prevParams[paramName])
+ return false;
+ }
+
+ // Ensure the query hasn't changed.
+ return hasProperties(prevQuery, nextQuery) && hasProperties(nextQuery, prevQuery);
+ });
+}
+
+/**
+ * Creates and returns a new router using the given options. A router
+ * is a ReactComponent class that knows how to react to changes in the
+ * URL and keep the contents of the page in sync.
+ *
+ * Options may be any of the following:
+ *
+ * - routes (required) The route config
+ * - location The location to use. Defaults to HashLocation when
+ * the DOM is available, "/" otherwise
+ * - scrollBehavior The scroll behavior to use. Defaults to ImitateBrowserBehavior
+ * when the DOM is available, null otherwise
+ * - onError A function that is used to handle errors
+ * - onAbort A function that is used to handle aborted transitions
+ *
+ * When rendering in a server-side environment, the location should simply
+ * be the URL path that was used in the request, including the query string.
+ */
+function createRouter(options) {
+ options = options || {};
+
+ if (typeof options === 'function') {
+ options = { routes: options }; // Router.create(<Route>)
+ } else if (Array.isArray(options)) {
+ options = { routes: options }; // Router.create([ <Route>, <Route> ])
+ }
+
+ var routes = [];
+ var namedRoutes = {};
+ var components = [];
+ var location = options.location || DEFAULT_LOCATION;
+ var scrollBehavior = options.scrollBehavior || DEFAULT_SCROLL_BEHAVIOR;
+ var onError = options.onError || defaultErrorHandler;
+ var onAbort = options.onAbort || defaultAbortHandler;
+ var state = {};
+ var nextState = {};
+ var pendingTransition = null;
+
+ function updateState() {
+ state = nextState;
+ nextState = {};
+ }
+
+ if (typeof location === 'string') {
+ warning(
+ !canUseDOM || process.env.NODE_ENV === 'test',
+ 'You should not use a static location in a DOM environment because ' +
+ 'the router will not be kept in sync with the current URL'
+ );
+ } else {
+ invariant(
+ canUseDOM,
+ 'You cannot use %s without a DOM',
+ location
+ );
+ }
+
+ // Automatically fall back to full page refreshes in
+ // browsers that don't support the HTML history API.
+ if (location === HistoryLocation && !supportsHistory())
+ location = RefreshLocation;
+
+ var router = React.createClass({
+
+ displayName: 'Router',
+
+ mixins: [ NavigationContext, StateContext, Scrolling ],
+
+ statics: {
+
+ defaultRoute: null,
+ notFoundRoute: null,
+
+ /**
+ * Adds routes to this router from the given children object (see ReactChildren).
+ */
+ addRoutes: function (children) {
+ routes.push.apply(routes, createRoutesFromChildren(children, this, namedRoutes));
+ },
+
+ /**
+ * Returns an absolute URL path created from the given route
+ * name, URL parameters, and query.
+ */
+ makePath: function (to, params, query) {
+ var path;
+ if (Path.isAbsolute(to)) {
+ path = Path.normalize(to);
+ } else {
+ var route = namedRoutes[to];
+
+ invariant(
+ route,
+ 'Unable to find <Route name="%s">',
+ to
+ );
+
+ path = route.path;
+ }
+
+ return Path.withQuery(Path.injectParams(path, params), query);
+ },
+
+ /**
+ * Returns a string that may safely be used as the href of a link
+ * to the route with the given name, URL parameters, and query.
+ */
+ makeHref: function (to, params, query) {
+ var path = this.makePath(to, params, query);
+ return (location === HashLocation) ? '#' + path : path;
+ },
+
+ /**
+ * Transitions to the URL specified in the arguments by pushing
+ * a new URL onto the history stack.
+ */
+ transitionTo: function (to, params, query) {
+ invariant(
+ typeof location !== 'string',
+ 'You cannot use transitionTo with a static location'
+ );
+
+ var path = this.makePath(to, params, query);
+
+ if (pendingTransition) {
+ // Replace so pending location does not stay in history.
+ location.replace(path);
+ } else {
+ location.push(path);
+ }
+ },
+
+ /**
+ * Transitions to the URL specified in the arguments by replacing
+ * the current URL in the history stack.
+ */
+ replaceWith: function (to, params, query) {
+ invariant(
+ typeof location !== 'string',
+ 'You cannot use replaceWith with a static location'
+ );
+
+ location.replace(this.makePath(to, params, query));
+ },
+
+ /**
+ * Transitions to the previous URL if one is available. Returns true if the
+ * router was able to go back, false otherwise.
+ *
+ * Note: The router only tracks history entries in your application, not the
+ * current browser session, so you can safely call this function without guarding
+ * against sending the user back to some other site. However, when using
+ * RefreshLocation (which is the fallback for HistoryLocation in browsers that
+ * don't support HTML5 history) this method will *always* send the client back
+ * because we cannot reliably track history length.
+ */
+ goBack: function () {
+ invariant(
+ typeof location !== 'string',
+ 'You cannot use goBack with a static location'
+ );
+
+ if (History.length > 1 || location === RefreshLocation) {
+ location.pop();
+ return true;
+ }
+
+ warning(false, 'goBack() was ignored because there is no router history');
+
+ return false;
+ },
+
+ /**
+ * Performs a match of the given pathname against this router and returns an object
+ * with the { routes, params } that match. Returns null if no match can be made.
+ */
+ match: function (pathname) {
+ return findMatch(pathname, routes, this.defaultRoute, this.notFoundRoute) || null;
+ },
+
+ /**
+ * Performs a transition to the given path and calls callback(error, abortReason)
+ * when the transition is finished. If both arguments are null the router's state
+ * was updated. Otherwise the transition did not complete.
+ *
+ * In a transition, a router first determines which routes are involved by beginning
+ * with the current route, up the route tree to the first parent route that is shared
+ * with the destination route, and back down the tree to the destination route. The
+ * willTransitionFrom hook is invoked on all route handlers we're transitioning away
+ * from, in reverse nesting order. Likewise, the willTransitionTo hook is invoked on
+ * all route handlers we're transitioning to.
+ *
+ * Both willTransitionFrom and willTransitionTo hooks may either abort or redirect the
+ * transition. To resolve asynchronously, they may use transition.wait(promise). If no
+ * hooks wait, the transition is fully synchronous.
+ */
+ dispatch: function (path, action, callback) {
+ if (pendingTransition) {
+ pendingTransition.abort(new Cancellation);
+ pendingTransition = null;
+ }
+
+ var prevPath = state.path;
+ if (prevPath === path)
+ return; // Nothing to do!
+
+ // Record the scroll position as early as possible to
+ // get it before browsers try update it automatically.
+ if (prevPath && action !== LocationActions.REPLACE)
+ this.recordScrollPosition(prevPath);
+
+ var pathname = Path.withoutQuery(path);
+ var match = this.match(pathname);
+
+ warning(
+ match != null,
+ 'No route matches path "%s". Make sure you have <Route path="%s"> somewhere in your routes',
+ path, path
+ );
+
+ if (match == null)
+ match = {};
+
+ var prevRoutes = state.routes || [];
+ var prevParams = state.params || {};
+ var prevQuery = state.query || {};
+
+ var nextRoutes = match.routes || [];
+ var nextParams = match.params || {};
+ var nextQuery = Path.extractQuery(path) || {};
+
+ var fromRoutes, toRoutes;
+ if (prevRoutes.length) {
+ fromRoutes = prevRoutes.filter(function (route) {
+ return !hasMatch(nextRoutes, route, prevParams, nextParams, prevQuery, nextQuery);
+ });
+
+ toRoutes = nextRoutes.filter(function (route) {
+ return !hasMatch(prevRoutes, route, prevParams, nextParams, prevQuery, nextQuery);
+ });
+ } else {
+ fromRoutes = [];
+ toRoutes = nextRoutes;
+ }
+
+ var transition = new Transition(path, this.replaceWith.bind(this, path));
+ pendingTransition = transition;
+
+ transition.from(fromRoutes, components, function (error) {
+ if (error || transition.isAborted)
+ return callback.call(router, error, transition);
+
+ transition.to(toRoutes, nextParams, nextQuery, function (error) {
+ if (error || transition.isAborted)
+ return callback.call(router, error, transition);
+
+ nextState.path = path;
+ nextState.action = action;
+ nextState.pathname = pathname;
+ nextState.routes = nextRoutes;
+ nextState.params = nextParams;
+ nextState.query = nextQuery;
+
+ callback.call(router, null, transition);
+ });
+ });
+ },
+
+ /**
+ * Starts this router and calls callback(router, state) when the route changes.
+ *
+ * If the router's location is static (i.e. a URL path in a server environment)
+ * the callback is called only once. Otherwise, the location should be one of the
+ * Router.*Location objects (e.g. Router.HashLocation or Router.HistoryLocation).
+ */
+ run: function (callback) {
+ var dispatchHandler = function (error, transition) {
+ pendingTransition = null;
+
+ if (error) {
+ onError.call(router, error);
+ } else if (transition.isAborted) {
+ onAbort.call(router, transition.abortReason, location);
+ } else {
+ callback.call(router, router, nextState);
+ }
+ };
+
+ if (typeof location === 'string') {
+ router.dispatch(location, null, dispatchHandler);
+ } else {
+ // Listen for changes to the location.
+ var changeListener = function (change) {
+ router.dispatch(change.path, change.type, dispatchHandler);
+ };
+
+ if (location.addChangeListener)
+ location.addChangeListener(changeListener);
+
+ // Bootstrap using the current path.
+ router.dispatch(location.getCurrentPath(), null, dispatchHandler);
+ }
+ },
+
+ teardown: function() {
+ location.removeChangeListener(this.changeListener);
+ }
+
+ },
+
+ propTypes: {
+ children: PropTypes.falsy
+ },
+
+ getLocation: function () {
+ return location;
+ },
+
+ getScrollBehavior: function () {
+ return scrollBehavior;
+ },
+
+ getRouteAtDepth: function (depth) {
+ var routes = this.state.routes;
+ return routes && routes[depth];
+ },
+
+ getRouteComponents: function () {
+ return components;
+ },
+
+ getInitialState: function () {
+ updateState();
+ return state;
+ },
+
+ componentWillReceiveProps: function () {
+ updateState();
+ this.setState(state);
+ },
+
+ componentWillUnmount: function() {
+ router.teardown();
+ },
+
+ render: function () {
+ return this.getRouteAtDepth(0) ? React.createElement(RouteHandler, this.props) : null;
+ },
+
+ childContextTypes: {
+ getRouteAtDepth: React.PropTypes.func.isRequired,
+ getRouteComponents: React.PropTypes.func.isRequired,
+ routeHandlers: React.PropTypes.array.isRequired
+ },
+
+ getChildContext: function () {
+ return {
+ getRouteComponents: this.getRouteComponents,
+ getRouteAtDepth: this.getRouteAtDepth,
+ routeHandlers: [ this ]
+ };
+ }
+
+ });
+
+ if (options.routes)
+ router.addRoutes(options.routes);
+
+ return router;
+}
+
+module.exports = createRouter;
+
+}).call(this,require('_process'))
+},{"../actions/LocationActions":6,"../behaviors/ImitateBrowserBehavior":7,"../components/RouteHandler":14,"../locations/HashLocation":15,"../locations/HistoryLocation":16,"../locations/RefreshLocation":17,"../mixins/NavigationContext":20,"../mixins/Scrolling":22,"../mixins/StateContext":24,"./Cancellation":25,"./History":26,"./Path":27,"./PropTypes":29,"./Redirect":30,"./Transition":31,"./createRoutesFromChildren":33,"./supportsHistory":37,"_process":5,"react":"react","react/lib/ExecutionEnvironment":69,"react/lib/invariant":187,"react/lib/warning":207}],33:[function(require,module,exports){
+/* jshint -W084 */
+var React = require('react');
+var warning = require('react/lib/warning');
+var invariant = require('react/lib/invariant');
+var DefaultRoute = require('../components/DefaultRoute');
+var NotFoundRoute = require('../components/NotFoundRoute');
+var Redirect = require('../components/Redirect');
+var Route = require('../components/Route');
+var Path = require('./Path');
+
+var CONFIG_ELEMENT_TYPES = [
+ DefaultRoute.type,
+ NotFoundRoute.type,
+ Redirect.type,
+ Route.type
+];
+
+function createRedirectHandler(to, _params, _query) {
+ return React.createClass({
+ statics: {
+ willTransitionTo: function (transition, params, query) {
+ transition.redirect(to, _params || params, _query || query);
+ }
+ },
+
+ render: function () {
+ return null;
+ }
+ });
+}
+
+function checkPropTypes(componentName, propTypes, props) {
+ for (var propName in propTypes) {
+ if (propTypes.hasOwnProperty(propName)) {
+ var error = propTypes[propName](props, propName, componentName);
+
+ if (error instanceof Error)
+ warning(false, error.message);
+ }
+ }
+}
+
+function createRoute(element, parentRoute, namedRoutes) {
+ var type = element.type;
+ var props = element.props;
+ var componentName = (type && type.displayName) || 'UnknownComponent';
+
+ invariant(
+ CONFIG_ELEMENT_TYPES.indexOf(type) !== -1,
+ 'Unrecognized route configuration element "<%s>"',
+ componentName
+ );
+
+ if (type.propTypes)
+ checkPropTypes(componentName, type.propTypes, props);
+
+ var route = { name: props.name };
+
+ if (props.ignoreScrollBehavior) {
+ route.ignoreScrollBehavior = true;
+ }
+
+ if (type === Redirect.type) {
+ route.handler = createRedirectHandler(props.to, props.params, props.query);
+ props.path = props.path || props.from || '*';
+ } else {
+ route.handler = props.handler;
+ }
+
+ var parentPath = (parentRoute && parentRoute.path) || '/';
+
+ if ((props.path || props.name) && type !== DefaultRoute.type && type !== NotFoundRoute.type) {
+ var path = props.path || props.name;
+
+ // Relative paths extend their parent.
+ if (!Path.isAbsolute(path))
+ path = Path.join(parentPath, path);
+
+ route.path = Path.normalize(path);
+ } else {
+ route.path = parentPath;
+
+ if (type === NotFoundRoute.type)
+ route.path += '*';
+ }
+
+ route.paramNames = Path.extractParamNames(route.path);
+
+ // Make sure the route's path has all params its parent needs.
+ if (parentRoute && Array.isArray(parentRoute.paramNames)) {
+ parentRoute.paramNames.forEach(function (paramName) {
+ invariant(
+ route.paramNames.indexOf(paramName) !== -1,
+ 'The nested route path "%s" is missing the "%s" parameter of its parent path "%s"',
+ route.path, paramName, parentRoute.path
+ );
+ });
+ }
+
+ // Make sure the route can be looked up by <Link>s.
+ if (props.name) {
+ invariant(
+ namedRoutes[props.name] == null,
+ 'You cannot use the name "%s" for more than one route',
+ props.name
+ );
+
+ namedRoutes[props.name] = route;
+ }
+
+ // Handle <NotFoundRoute>.
+ if (type === NotFoundRoute.type) {
+ invariant(
+ parentRoute,
+ '<NotFoundRoute> must have a parent <Route>'
+ );
+
+ invariant(
+ parentRoute.notFoundRoute == null,
+ 'You may not have more than one <NotFoundRoute> per <Route>'
+ );
+
+ parentRoute.notFoundRoute = route;
+
+ return null;
+ }
+
+ // Handle <DefaultRoute>.
+ if (type === DefaultRoute.type) {
+ invariant(
+ parentRoute,
+ '<DefaultRoute> must have a parent <Route>'
+ );
+
+ invariant(
+ parentRoute.defaultRoute == null,
+ 'You may not have more than one <DefaultRoute> per <Route>'
+ );
+
+ parentRoute.defaultRoute = route;
+
+ return null;
+ }
+
+ route.childRoutes = createRoutesFromChildren(props.children, route, namedRoutes);
+
+ return route;
+}
+
+/**
+ * Creates and returns an array of route objects from the given ReactChildren.
+ */
+function createRoutesFromChildren(children, parentRoute, namedRoutes) {
+ var routes = [];
+
+ React.Children.forEach(children, function (child) {
+ // Exclude <DefaultRoute>s and <NotFoundRoute>s.
+ if (child = createRoute(child, parentRoute, namedRoutes))
+ routes.push(child);
+ });
+
+ return routes;
+}
+
+module.exports = createRoutesFromChildren;
+
+},{"../components/DefaultRoute":9,"../components/NotFoundRoute":11,"../components/Redirect":12,"../components/Route":13,"./Path":27,"react":"react","react/lib/invariant":187,"react/lib/warning":207}],34:[function(require,module,exports){
+var invariant = require('react/lib/invariant');
+var canUseDOM = require('react/lib/ExecutionEnvironment').canUseDOM;
+
+/**
+ * Returns the current scroll position of the window as { x, y }.
+ */
+function getWindowScrollPosition() {
+ invariant(
+ canUseDOM,
+ 'Cannot get current scroll position without a DOM'
+ );
+
+ return {
+ x: window.pageXOffset || document.documentElement.scrollLeft,
+ y: window.pageYOffset || document.documentElement.scrollTop
+ };
+}
+
+module.exports = getWindowScrollPosition;
+
+},{"react/lib/ExecutionEnvironment":69,"react/lib/invariant":187}],35:[function(require,module,exports){
+function reversedArray(array) {
+ return array.slice(0).reverse();
+}
+
+module.exports = reversedArray;
+
+},{}],36:[function(require,module,exports){
+var createRouter = require('./createRouter');
+
+/**
+ * A high-level convenience method that creates, configures, and
+ * runs a router in one shot. The method signature is:
+ *
+ * Router.run(routes[, location ], callback);
+ *
+ * Using `window.location.hash` to manage the URL, you could do:
+ *
+ * Router.run(routes, function (Handler) {
+ * React.render(<Handler/>, document.body);
+ * });
+ *
+ * Using HTML5 history and a custom "cursor" prop:
+ *
+ * Router.run(routes, Router.HistoryLocation, function (Handler) {
+ * React.render(<Handler cursor={cursor}/>, document.body);
+ * });
+ *
+ * Returns the newly created router.
+ *
+ * Note: If you need to specify further options for your router such
+ * as error/abort handling or custom scroll behavior, use Router.create
+ * instead.
+ *
+ * var router = Router.create(options);
+ * router.run(function (Handler) {
+ * // ...
+ * });
+ */
+function runRouter(routes, location, callback) {
+ if (typeof location === 'function') {
+ callback = location;
+ location = null;
+ }
+
+ var router = createRouter({
+ routes: routes,
+ location: location
+ });
+
+ router.run(callback);
+
+ return router;
+}
+
+module.exports = runRouter;
+
+},{"./createRouter":32}],37:[function(require,module,exports){
+function supportsHistory() {
+ /*! taken from modernizr
+ * https://github.com/Modernizr/Modernizr/blob/master/LICENSE
+ * https://github.com/Modernizr/Modernizr/blob/master/feature-detects/history.js
+ * changed to avoid false negatives for Windows Phones: https://github.com/rackt/react-router/issues/586
+ */
+ var ua = navigator.userAgent;
+ if ((ua.indexOf('Android 2.') !== -1 ||
+ (ua.indexOf('Android 4.0') !== -1)) &&
+ ua.indexOf('Mobile Safari') !== -1 &&
+ ua.indexOf('Chrome') === -1 &&
+ ua.indexOf('Windows Phone') === -1) {
+ return false;
+ }
+ return (window.history && 'pushState' in window.history);
+}
+
+module.exports = supportsHistory;
+
+},{}],38:[function(require,module,exports){
+module.exports = require('./lib');
+
+},{"./lib":39}],39:[function(require,module,exports){
+// Load modules
+
+var Stringify = require('./stringify');
+var Parse = require('./parse');
+
+
+// Declare internals
+
+var internals = {};
+
+
+module.exports = {
+ stringify: Stringify,
+ parse: Parse
+};
+
+},{"./parse":40,"./stringify":41}],40:[function(require,module,exports){
+// Load modules
+
+var Utils = require('./utils');
+
+
+// Declare internals
+
+var internals = {
+ delimiter: '&',
+ depth: 5,
+ arrayLimit: 20,
+ parameterLimit: 1000
+};
+
+
+internals.parseValues = function (str, options) {
+
+ var obj = {};
+ var parts = str.split(options.delimiter, options.parameterLimit === Infinity ? undefined : options.parameterLimit);
+
+ for (var i = 0, il = parts.length; i < il; ++i) {
+ var part = parts[i];
+ var pos = part.indexOf(']=') === -1 ? part.indexOf('=') : part.indexOf(']=') + 1;
+
+ if (pos === -1) {
+ obj[Utils.decode(part)] = '';
+ }
+ else {
+ var key = Utils.decode(part.slice(0, pos));
+ var val = Utils.decode(part.slice(pos + 1));
+
+ if (!obj[key]) {
+ obj[key] = val;
+ }
+ else {
+ obj[key] = [].concat(obj[key]).concat(val);
+ }
+ }
+ }
+
+ return obj;
+};
+
+
+internals.parseObject = function (chain, val, options) {
+
+ if (!chain.length) {
+ return val;
+ }
+
+ var root = chain.shift();
+
+ var obj = {};
+ if (root === '[]') {
+ obj = [];
+ obj = obj.concat(internals.parseObject(chain, val, options));
+ }
+ else {
+ var cleanRoot = root[0] === '[' && root[root.length - 1] === ']' ? root.slice(1, root.length - 1) : root;
+ var index = parseInt(cleanRoot, 10);
+ if (!isNaN(index) &&
+ root !== cleanRoot &&
+ index <= options.arrayLimit) {
+
+ obj = [];
+ obj[index] = internals.parseObject(chain, val, options);
+ }
+ else {
+ obj[cleanRoot] = internals.parseObject(chain, val, options);
+ }
+ }
+
+ return obj;
+};
+
+
+internals.parseKeys = function (key, val, options) {
+
+ if (!key) {
+ return;
+ }
+
+ // The regex chunks
+
+ var parent = /^([^\[\]]*)/;
+ var child = /(\[[^\[\]]*\])/g;
+
+ // Get the parent
+
+ var segment = parent.exec(key);
+
+ // Don't allow them to overwrite object prototype properties
+
+ if (Object.prototype.hasOwnProperty(segment[1])) {
+ return;
+ }
+
+ // Stash the parent if it exists
+
+ var keys = [];
+ if (segment[1]) {
+ keys.push(segment[1]);
+ }
+
+ // Loop through children appending to the array until we hit depth
+
+ var i = 0;
+ while ((segment = child.exec(key)) !== null && i < options.depth) {
+
+ ++i;
+ if (!Object.prototype.hasOwnProperty(segment[1].replace(/\[|\]/g, ''))) {
+ keys.push(segment[1]);
+ }
+ }
+
+ // If there's a remainder, just add whatever is left
+
+ if (segment) {
+ keys.push('[' + key.slice(segment.index) + ']');
+ }
+
+ return internals.parseObject(keys, val, options);
+};
+
+
+module.exports = function (str, options) {
+
+ if (str === '' ||
+ str === null ||
+ typeof str === 'undefined') {
+
+ return {};
+ }
+
+ options = options || {};
+ options.delimiter = typeof options.delimiter === 'string' || Utils.isRegExp(options.delimiter) ? options.delimiter : internals.delimiter;
+ options.depth = typeof options.depth === 'number' ? options.depth : internals.depth;
+ options.arrayLimit = typeof options.arrayLimit === 'number' ? options.arrayLimit : internals.arrayLimit;
+ options.parameterLimit = typeof options.parameterLimit === 'number' ? options.parameterLimit : internals.parameterLimit;
+
+ var tempObj = typeof str === 'string' ? internals.parseValues(str, options) : str;
+ var obj = {};
+
+ // Iterate over the keys and setup the new object
+
+ var keys = Object.keys(tempObj);
+ for (var i = 0, il = keys.length; i < il; ++i) {
+ var key = keys[i];
+ var newObj = internals.parseKeys(key, tempObj[key], options);
+ obj = Utils.merge(obj, newObj);
+ }
+
+ return Utils.compact(obj);
+};
+
+},{"./utils":42}],41:[function(require,module,exports){
+// Load modules
+
+var Utils = require('./utils');
+
+
+// Declare internals
+
+var internals = {
+ delimiter: '&'
+};
+
+
+internals.stringify = function (obj, prefix) {
+
+ if (Utils.isBuffer(obj)) {
+ obj = obj.toString();
+ }
+ else if (obj instanceof Date) {
+ obj = obj.toISOString();
+ }
+ else if (obj === null) {
+ obj = '';
+ }
+
+ if (typeof obj === 'string' ||
+ typeof obj === 'number' ||
+ typeof obj === 'boolean') {
+
+ return [encodeURIComponent(prefix) + '=' + encodeURIComponent(obj)];
+ }
+
+ var values = [];
+
+ for (var key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ values = values.concat(internals.stringify(obj[key], prefix + '[' + key + ']'));
+ }
+ }
+
+ return values;
+};
+
+
+module.exports = function (obj, options) {
+
+ options = options || {};
+ var delimiter = typeof options.delimiter === 'undefined' ? internals.delimiter : options.delimiter;
+
+ var keys = [];
+
+ for (var key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ keys = keys.concat(internals.stringify(obj[key], key));
+ }
+ }
+
+ return keys.join(delimiter);
+};
+
+},{"./utils":42}],42:[function(require,module,exports){
+(function (Buffer){
+// Load modules
+
+
+// Declare internals
+
+var internals = {};
+
+
+exports.arrayToObject = function (source) {
+
+ var obj = {};
+ for (var i = 0, il = source.length; i < il; ++i) {
+ if (typeof source[i] !== 'undefined') {
+
+ obj[i] = source[i];
+ }
+ }
+
+ return obj;
+};
+
+
+exports.merge = function (target, source) {
+
+ if (!source) {
+ return target;
+ }
+
+ if (Array.isArray(source)) {
+ for (var i = 0, il = source.length; i < il; ++i) {
+ if (typeof source[i] !== 'undefined') {
+ if (typeof target[i] === 'object') {
+ target[i] = exports.merge(target[i], source[i]);
+ }
+ else {
+ target[i] = source[i];
+ }
+ }
+ }
+
+ return target;
+ }
+
+ if (Array.isArray(target)) {
+ if (typeof source !== 'object') {
+ target.push(source);
+ return target;
+ }
+ else {
+ target = exports.arrayToObject(target);
+ }
+ }
+
+ var keys = Object.keys(source);
+ for (var k = 0, kl = keys.length; k < kl; ++k) {
+ var key = keys[k];
+ var value = source[key];
+
+ if (value &&
+ typeof value === 'object') {
+
+ if (!target[key]) {
+ target[key] = value;
+ }
+ else {
+ target[key] = exports.merge(target[key], value);
+ }
+ }
+ else {
+ target[key] = value;
+ }
+ }
+
+ return target;
+};
+
+
+exports.decode = function (str) {
+
+ try {
+ return decodeURIComponent(str.replace(/\+/g, ' '));
+ } catch (e) {
+ return str;
+ }
+};
+
+
+exports.compact = function (obj, refs) {
+
+ if (typeof obj !== 'object' ||
+ obj === null) {
+
+ return obj;
+ }
+
+ refs = refs || [];
+ var lookup = refs.indexOf(obj);
+ if (lookup !== -1) {
+ return refs[lookup];
+ }
+
+ refs.push(obj);
+
+ if (Array.isArray(obj)) {
+ var compacted = [];
+
+ for (var i = 0, l = obj.length; i < l; ++i) {
+ if (typeof obj[i] !== 'undefined') {
+ compacted.push(obj[i]);
+ }
+ }
+
+ return compacted;
+ }
+
+ var keys = Object.keys(obj);
+ for (var i = 0, il = keys.length; i < il; ++i) {
+ var key = keys[i];
+ obj[key] = exports.compact(obj[key], refs);
+ }
+
+ return obj;
+};
+
+
+exports.isRegExp = function (obj) {
+ return Object.prototype.toString.call(obj) === '[object RegExp]';
+};
+
+
+exports.isBuffer = function (obj) {
+
+ if (typeof Buffer !== 'undefined') {
+ return Buffer.isBuffer(obj);
+ }
+ else {
+ return false;
+ }
+};
+
+}).call(this,require("buffer").Buffer)
+},{"buffer":1}],43:[function(require,module,exports){
+/** @license MIT License (c) copyright 2010-2014 original author or authors */
+/** @author Brian Cavalier */
+/** @author John Hann */
+
+(function(define) { 'use strict';
+define(function (require) {
+
+ var makePromise = require('./makePromise');
+ var Scheduler = require('./Scheduler');
+ var async = require('./async');
+
+ return makePromise({
+ scheduler: new Scheduler(async)
+ });
+
+});
+})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); });
+
+},{"./Scheduler":45,"./async":46,"./makePromise":47}],44:[function(require,module,exports){
+/** @license MIT License (c) copyright 2010-2014 original author or authors */
+/** @author Brian Cavalier */
+/** @author John Hann */
+
+(function(define) { 'use strict';
+define(function() {
+ /**
+ * Circular queue
+ * @param {number} capacityPow2 power of 2 to which this queue's capacity
+ * will be set initially. eg when capacityPow2 == 3, queue capacity
+ * will be 8.
+ * @constructor
+ */
+ function Queue(capacityPow2) {
+ this.head = this.tail = this.length = 0;
+ this.buffer = new Array(1 << capacityPow2);
+ }
+
+ Queue.prototype.push = function(x) {
+ if(this.length === this.buffer.length) {
+ this._ensureCapacity(this.length * 2);
+ }
+
+ this.buffer[this.tail] = x;
+ this.tail = (this.tail + 1) & (this.buffer.length - 1);
+ ++this.length;
+ return this.length;
+ };
+
+ Queue.prototype.shift = function() {
+ var x = this.buffer[this.head];
+ this.buffer[this.head] = void 0;
+ this.head = (this.head + 1) & (this.buffer.length - 1);
+ --this.length;
+ return x;
+ };
+
+ Queue.prototype._ensureCapacity = function(capacity) {
+ var head = this.head;
+ var buffer = this.buffer;
+ var newBuffer = new Array(capacity);
+ var i = 0;
+ var len;
+
+ if(head === 0) {
+ len = this.length;
+ for(; i<len; ++i) {
+ newBuffer[i] = buffer[i];
+ }
+ } else {
+ capacity = buffer.length;
+ len = this.tail;
+ for(; head<capacity; ++i, ++head) {
+ newBuffer[i] = buffer[head];
+ }
+
+ for(head=0; head<len; ++i, ++head) {
+ newBuffer[i] = buffer[head];
+ }
+ }
+
+ this.buffer = newBuffer;
+ this.head = 0;
+ this.tail = this.length;
+ };
+
+ return Queue;
+
+});
+}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
+
+},{}],45:[function(require,module,exports){
+/** @license MIT License (c) copyright 2010-2014 original author or authors */
+/** @author Brian Cavalier */
+/** @author John Hann */
+
+(function(define) { 'use strict';
+define(function(require) {
+
+ var Queue = require('./Queue');
+
+ // Credit to Twisol (https://github.com/Twisol) for suggesting
+ // this type of extensible queue + trampoline approach for next-tick conflation.
+
+ /**
+ * Async task scheduler
+ * @param {function} async function to schedule a single async function
+ * @constructor
+ */
+ function Scheduler(async) {
+ this._async = async;
+ this._queue = new Queue(15);
+ this._afterQueue = new Queue(5);
+ this._running = false;
+
+ var self = this;
+ this.drain = function() {
+ self._drain();
+ };
+ }
+
+ /**
+ * Enqueue a task
+ * @param {{ run:function }} task
+ */
+ Scheduler.prototype.enqueue = function(task) {
+ this._add(this._queue, task);
+ };
+
+ /**
+ * Enqueue a task to run after the main task queue
+ * @param {{ run:function }} task
+ */
+ Scheduler.prototype.afterQueue = function(task) {
+ this._add(this._afterQueue, task);
+ };
+
+ /**
+ * Drain the handler queue entirely, and then the after queue
+ */
+ Scheduler.prototype._drain = function() {
+ runQueue(this._queue);
+ this._running = false;
+ runQueue(this._afterQueue);
+ };
+
+ /**
+ * Add a task to the q, and schedule drain if not already scheduled
+ * @param {Queue} queue
+ * @param {{run:function}} task
+ * @private
+ */
+ Scheduler.prototype._add = function(queue, task) {
+ queue.push(task);
+ if(!this._running) {
+ this._running = true;
+ this._async(this.drain);
+ }
+ };
+
+ /**
+ * Run all the tasks in the q
+ * @param queue
+ */
+ function runQueue(queue) {
+ while(queue.length > 0) {
+ queue.shift().run();
+ }
+ }
+
+ return Scheduler;
+
+});
+}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
+
+},{"./Queue":44}],46:[function(require,module,exports){
+(function (process){
+/** @license MIT License (c) copyright 2010-2014 original author or authors */
+/** @author Brian Cavalier */
+/** @author John Hann */
+
+(function(define) { 'use strict';
+define(function(require) {
+
+ // Sniff "best" async scheduling option
+ // Prefer process.nextTick or MutationObserver, then check for
+ // vertx and finally fall back to setTimeout
+
+ /*jshint maxcomplexity:6*/
+ /*global process,document,setTimeout,MutationObserver,WebKitMutationObserver*/
+ var nextTick, MutationObs;
+
+ if (typeof process !== 'undefined' && process !== null &&
+ typeof process.nextTick === 'function') {
+ nextTick = function(f) {
+ process.nextTick(f);
+ };
+
+ } else if (MutationObs =
+ (typeof MutationObserver === 'function' && MutationObserver) ||
+ (typeof WebKitMutationObserver === 'function' && WebKitMutationObserver)) {
+ nextTick = (function (document, MutationObserver) {
+ var scheduled;
+ var el = document.createElement('div');
+ var o = new MutationObserver(run);
+ o.observe(el, { attributes: true });
+
+ function run() {
+ var f = scheduled;
+ scheduled = void 0;
+ f();
+ }
+
+ return function (f) {
+ scheduled = f;
+ el.setAttribute('class', 'x');
+ };
+ }(document, MutationObs));
+
+ } else {
+ nextTick = (function(cjsRequire) {
+ var vertx;
+ try {
+ // vert.x 1.x || 2.x
+ vertx = cjsRequire('vertx');
+ } catch (ignore) {}
+
+ if (vertx) {
+ if (typeof vertx.runOnLoop === 'function') {
+ return vertx.runOnLoop;
+ }
+ if (typeof vertx.runOnContext === 'function') {
+ return vertx.runOnContext;
+ }
+ }
+
+ // capture setTimeout to avoid being caught by fake timers
+ // used in time based tests
+ var capturedSetTimeout = setTimeout;
+ return function (t) {
+ capturedSetTimeout(t, 0);
+ };
+ }(require));
+ }
+
+ return nextTick;
+});
+}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
+
+}).call(this,require('_process'))
+},{"_process":5}],47:[function(require,module,exports){
+/** @license MIT License (c) copyright 2010-2014 original author or authors */
+/** @author Brian Cavalier */
+/** @author John Hann */
+
+(function(define) { 'use strict';
+define(function() {
+
+ return function makePromise(environment) {
+
+ var tasks = environment.scheduler;
+
+ var objectCreate = Object.create ||
+ function(proto) {
+ function Child() {}
+ Child.prototype = proto;
+ return new Child();
+ };
+
+ /**
+ * Create a promise whose fate is determined by resolver
+ * @constructor
+ * @returns {Promise} promise
+ * @name Promise
+ */
+ function Promise(resolver, handler) {
+ this._handler = resolver === Handler ? handler : init(resolver);
+ }
+
+ /**
+ * Run the supplied resolver
+ * @param resolver
+ * @returns {Pending}
+ */
+ function init(resolver) {
+ var handler = new Pending();
+
+ try {
+ resolver(promiseResolve, promiseReject, promiseNotify);
+ } catch (e) {
+ promiseReject(e);
+ }
+
+ return handler;
+
+ /**
+ * Transition from pre-resolution state to post-resolution state, notifying
+ * all listeners of the ultimate fulfillment or rejection
+ * @param {*} x resolution value
+ */
+ function promiseResolve (x) {
+ handler.resolve(x);
+ }
+ /**
+ * Reject this promise with reason, which will be used verbatim
+ * @param {Error|*} reason rejection reason, strongly suggested
+ * to be an Error type
+ */
+ function promiseReject (reason) {
+ handler.reject(reason);
+ }
+
+ /**
+ * Issue a progress event, notifying all progress listeners
+ * @param {*} x progress event payload to pass to all listeners
+ */
+ function promiseNotify (x) {
+ handler.notify(x);
+ }
+ }
+
+ // Creation
+
+ Promise.resolve = resolve;
+ Promise.reject = reject;
+ Promise.never = never;
+
+ Promise._defer = defer;
+ Promise._handler = getHandler;
+
+ /**
+ * Returns a trusted promise. If x is already a trusted promise, it is
+ * returned, otherwise returns a new trusted Promise which follows x.
+ * @param {*} x
+ * @return {Promise} promise
+ */
+ function resolve(x) {
+ return isPromise(x) ? x
+ : new Promise(Handler, new Async(getHandler(x)));
+ }
+
+ /**
+ * Return a reject promise with x as its reason (x is used verbatim)
+ * @param {*} x
+ * @returns {Promise} rejected promise
+ */
+ function reject(x) {
+ return new Promise(Handler, new Async(new Rejected(x)));
+ }
+
+ /**
+ * Return a promise that remains pending forever
+ * @returns {Promise} forever-pending promise.
+ */
+ function never() {
+ return foreverPendingPromise; // Should be frozen
+ }
+
+ /**
+ * Creates an internal {promise, resolver} pair
+ * @private
+ * @returns {Promise}
+ */
+ function defer() {
+ return new Promise(Handler, new Pending());
+ }
+
+ // Transformation and flow control
+
+ /**
+ * Transform this promise's fulfillment value, returning a new Promise
+ * for the transformed result. If the promise cannot be fulfilled, onRejected
+ * is called with the reason. onProgress *may* be called with updates toward
+ * this promise's fulfillment.
+ * @param {function=} onFulfilled fulfillment handler
+ * @param {function=} onRejected rejection handler
+ * @deprecated @param {function=} onProgress progress handler
+ * @return {Promise} new promise
+ */
+ Promise.prototype.then = function(onFulfilled, onRejected) {
+ var parent = this._handler;
+ var state = parent.join().state();
+
+ if ((typeof onFulfilled !== 'function' && state > 0) ||
+ (typeof onRejected !== 'function' && state < 0)) {
+ // Short circuit: value will not change, simply share handler
+ return new this.constructor(Handler, parent);
+ }
+
+ var p = this._beget();
+ var child = p._handler;
+
+ parent.chain(child, parent.receiver, onFulfilled, onRejected,
+ arguments.length > 2 ? arguments[2] : void 0);
+
+ return p;
+ };
+
+ /**
+ * If this promise cannot be fulfilled due to an error, call onRejected to
+ * handle the error. Shortcut for .then(undefined, onRejected)
+ * @param {function?} onRejected
+ * @return {Promise}
+ */
+ Promise.prototype['catch'] = function(onRejected) {
+ return this.then(void 0, onRejected);
+ };
+
+ /**
+ * Creates a new, pending promise of the same type as this promise
+ * @private
+ * @returns {Promise}
+ */
+ Promise.prototype._beget = function() {
+ var parent = this._handler;
+ var child = new Pending(parent.receiver, parent.join().context);
+ return new this.constructor(Handler, child);
+ };
+
+ // Array combinators
+
+ Promise.all = all;
+ Promise.race = race;
+
+ /**
+ * Return a promise that will fulfill when all promises in the
+ * input array have fulfilled, or will reject when one of the
+ * promises rejects.
+ * @param {array} promises array of promises
+ * @returns {Promise} promise for array of fulfillment values
+ */
+ function all(promises) {
+ /*jshint maxcomplexity:8*/
+ var resolver = new Pending();
+ var pending = promises.length >>> 0;
+ var results = new Array(pending);
+
+ var i, h, x, s;
+ for (i = 0; i < promises.length; ++i) {
+ x = promises[i];
+
+ if (x === void 0 && !(i in promises)) {
+ --pending;
+ continue;
+ }
+
+ if (maybeThenable(x)) {
+ h = getHandlerMaybeThenable(x);
+
+ s = h.state();
+ if (s === 0) {
+ h.fold(settleAt, i, results, resolver);
+ } else if (s > 0) {
+ results[i] = h.value;
+ --pending;
+ } else {
+ unreportRemaining(promises, i+1, h);
+ resolver.become(h);
+ break;
+ }
+
+ } else {
+ results[i] = x;
+ --pending;
+ }
+ }
+
+ if(pending === 0) {
+ resolver.become(new Fulfilled(results));
+ }
+
+ return new Promise(Handler, resolver);
+
+ function settleAt(i, x, resolver) {
+ /*jshint validthis:true*/
+ this[i] = x;
+ if(--pending === 0) {
+ resolver.become(new Fulfilled(this));
+ }
+ }
+ }
+
+ function unreportRemaining(promises, start, rejectedHandler) {
+ var i, h, x;
+ for(i=start; i<promises.length; ++i) {
+ x = promises[i];
+ if(maybeThenable(x)) {
+ h = getHandlerMaybeThenable(x);
+
+ if(h !== rejectedHandler) {
+ h.visit(h, void 0, h._unreport);
+ }
+ }
+ }
+ }
+
+ /**
+ * Fulfill-reject competitive race. Return a promise that will settle
+ * to the same state as the earliest input promise to settle.
+ *
+ * WARNING: The ES6 Promise spec requires that race()ing an empty array
+ * must return a promise that is pending forever. This implementation
+ * returns a singleton forever-pending promise, the same singleton that is
+ * returned by Promise.never(), thus can be checked with ===
+ *
+ * @param {array} promises array of promises to race
+ * @returns {Promise} if input is non-empty, a promise that will settle
+ * to the same outcome as the earliest input promise to settle. if empty
+ * is empty, returns a promise that will never settle.
+ */
+ function race(promises) {
+ // Sigh, race([]) is untestable unless we return *something*
+ // that is recognizable without calling .then() on it.
+ if(Object(promises) === promises && promises.length === 0) {
+ return never();
+ }
+
+ var h = new Pending();
+ var i, x;
+ for(i=0; i<promises.length; ++i) {
+ x = promises[i];
+ if (x !== void 0 && i in promises) {
+ getHandler(x).visit(h, h.resolve, h.reject);
+ }
+ }
+ return new Promise(Handler, h);
+ }
+
+ // Promise internals
+ // Below this, everything is @private
+
+ /**
+ * Get an appropriate handler for x, without checking for cycles
+ * @param {*} x
+ * @returns {object} handler
+ */
+ function getHandler(x) {
+ if(isPromise(x)) {
+ return x._handler.join();
+ }
+ return maybeThenable(x) ? getHandlerUntrusted(x) : new Fulfilled(x);
+ }
+
+ /**
+ * Get a handler for thenable x.
+ * NOTE: You must only call this if maybeThenable(x) == true
+ * @param {object|function|Promise} x
+ * @returns {object} handler
+ */
+ function getHandlerMaybeThenable(x) {
+ return isPromise(x) ? x._handler.join() : getHandlerUntrusted(x);
+ }
+
+ /**
+ * Get a handler for potentially untrusted thenable x
+ * @param {*} x
+ * @returns {object} handler
+ */
+ function getHandlerUntrusted(x) {
+ try {
+ var untrustedThen = x.then;
+ return typeof untrustedThen === 'function'
+ ? new Thenable(untrustedThen, x)
+ : new Fulfilled(x);
+ } catch(e) {
+ return new Rejected(e);
+ }
+ }
+
+ /**
+ * Handler for a promise that is pending forever
+ * @constructor
+ */
+ function Handler() {}
+
+ Handler.prototype.when
+ = Handler.prototype.become
+ = Handler.prototype.notify
+ = Handler.prototype.fail
+ = Handler.prototype._unreport
+ = Handler.prototype._report
+ = noop;
+
+ Handler.prototype._state = 0;
+
+ Handler.prototype.state = function() {
+ return this._state;
+ };
+
+ /**
+ * Recursively collapse handler chain to find the handler
+ * nearest to the fully resolved value.
+ * @returns {object} handler nearest the fully resolved value
+ */
+ Handler.prototype.join = function() {
+ var h = this;
+ while(h.handler !== void 0) {
+ h = h.handler;
+ }
+ return h;
+ };
+
+ Handler.prototype.chain = function(to, receiver, fulfilled, rejected, progress) {
+ this.when({
+ resolver: to,
+ receiver: receiver,
+ fulfilled: fulfilled,
+ rejected: rejected,
+ progress: progress
+ });
+ };
+
+ Handler.prototype.visit = function(receiver, fulfilled, rejected, progress) {
+ this.chain(failIfRejected, receiver, fulfilled, rejected, progress);
+ };
+
+ Handler.prototype.fold = function(f, z, c, to) {
+ this.visit(to, function(x) {
+ f.call(c, z, x, this);
+ }, to.reject, to.notify);
+ };
+
+ /**
+ * Handler that invokes fail() on any handler it becomes
+ * @constructor
+ */
+ function FailIfRejected() {}
+
+ inherit(Handler, FailIfRejected);
+
+ FailIfRejected.prototype.become = function(h) {
+ h.fail();
+ };
+
+ var failIfRejected = new FailIfRejected();
+
+ /**
+ * Handler that manages a queue of consumers waiting on a pending promise
+ * @constructor
+ */
+ function Pending(receiver, inheritedContext) {
+ Promise.createContext(this, inheritedContext);
+
+ this.consumers = void 0;
+ this.receiver = receiver;
+ this.handler = void 0;
+ this.resolved = false;
+ }
+
+ inherit(Handler, Pending);
+
+ Pending.prototype._state = 0;
+
+ Pending.prototype.resolve = function(x) {
+ this.become(getHandler(x));
+ };
+
+ Pending.prototype.reject = function(x) {
+ if(this.resolved) {
+ return;
+ }
+
+ this.become(new Rejected(x));
+ };
+
+ Pending.prototype.join = function() {
+ if (!this.resolved) {
+ return this;
+ }
+
+ var h = this;
+
+ while (h.handler !== void 0) {
+ h = h.handler;
+ if (h === this) {
+ return this.handler = cycle();
+ }
+ }
+
+ return h;
+ };
+
+ Pending.prototype.run = function() {
+ var q = this.consumers;
+ var handler = this.join();
+ this.consumers = void 0;
+
+ for (var i = 0; i < q.length; ++i) {
+ handler.when(q[i]);
+ }
+ };
+
+ Pending.prototype.become = function(handler) {
+ if(this.resolved) {
+ return;
+ }
+
+ this.resolved = true;
+ this.handler = handler;
+ if(this.consumers !== void 0) {
+ tasks.enqueue(this);
+ }
+
+ if(this.context !== void 0) {
+ handler._report(this.context);
+ }
+ };
+
+ Pending.prototype.when = function(continuation) {
+ if(this.resolved) {
+ tasks.enqueue(new ContinuationTask(continuation, this.handler));
+ } else {
+ if(this.consumers === void 0) {
+ this.consumers = [continuation];
+ } else {
+ this.consumers.push(continuation);
+ }
+ }
+ };
+
+ Pending.prototype.notify = function(x) {
+ if(!this.resolved) {
+ tasks.enqueue(new ProgressTask(x, this));
+ }
+ };
+
+ Pending.prototype.fail = function(context) {
+ var c = typeof context === 'undefined' ? this.context : context;
+ this.resolved && this.handler.join().fail(c);
+ };
+
+ Pending.prototype._report = function(context) {
+ this.resolved && this.handler.join()._report(context);
+ };
+
+ Pending.prototype._unreport = function() {
+ this.resolved && this.handler.join()._unreport();
+ };
+
+ /**
+ * Wrap another handler and force it into a future stack
+ * @param {object} handler
+ * @constructor
+ */
+ function Async(handler) {
+ this.handler = handler;
+ }
+
+ inherit(Handler, Async);
+
+ Async.prototype.when = function(continuation) {
+ tasks.enqueue(new ContinuationTask(continuation, this));
+ };
+
+ Async.prototype._report = function(context) {
+ this.join()._report(context);
+ };
+
+ Async.prototype._unreport = function() {
+ this.join()._unreport();
+ };
+
+ /**
+ * Handler that wraps an untrusted thenable and assimilates it in a future stack
+ * @param {function} then
+ * @param {{then: function}} thenable
+ * @constructor
+ */
+ function Thenable(then, thenable) {
+ Pending.call(this);
+ tasks.enqueue(new AssimilateTask(then, thenable, this));
+ }
+
+ inherit(Pending, Thenable);
+
+ /**
+ * Handler for a fulfilled promise
+ * @param {*} x fulfillment value
+ * @constructor
+ */
+ function Fulfilled(x) {
+ Promise.createContext(this);
+ this.value = x;
+ }
+
+ inherit(Handler, Fulfilled);
+
+ Fulfilled.prototype._state = 1;
+
+ Fulfilled.prototype.fold = function(f, z, c, to) {
+ runContinuation3(f, z, this, c, to);
+ };
+
+ Fulfilled.prototype.when = function(cont) {
+ runContinuation1(cont.fulfilled, this, cont.receiver, cont.resolver);
+ };
+
+ var errorId = 0;
+
+ /**
+ * Handler for a rejected promise
+ * @param {*} x rejection reason
+ * @constructor
+ */
+ function Rejected(x) {
+ Promise.createContext(this);
+
+ this.id = ++errorId;
+ this.value = x;
+ this.handled = false;
+ this.reported = false;
+
+ this._report();
+ }
+
+ inherit(Handler, Rejected);
+
+ Rejected.prototype._state = -1;
+
+ Rejected.prototype.fold = function(f, z, c, to) {
+ to.become(this);
+ };
+
+ Rejected.prototype.when = function(cont) {
+ if(typeof cont.rejected === 'function') {
+ this._unreport();
+ }
+ runContinuation1(cont.rejected, this, cont.receiver, cont.resolver);
+ };
+
+ Rejected.prototype._report = function(context) {
+ tasks.afterQueue(new ReportTask(this, context));
+ };
+
+ Rejected.prototype._unreport = function() {
+ this.handled = true;
+ tasks.afterQueue(new UnreportTask(this));
+ };
+
+ Rejected.prototype.fail = function(context) {
+ Promise.onFatalRejection(this, context === void 0 ? this.context : context);
+ };
+
+ function ReportTask(rejection, context) {
+ this.rejection = rejection;
+ this.context = context;
+ }
+
+ ReportTask.prototype.run = function() {
+ if(!this.rejection.handled) {
+ this.rejection.reported = true;
+ Promise.onPotentiallyUnhandledRejection(this.rejection, this.context);
+ }
+ };
+
+ function UnreportTask(rejection) {
+ this.rejection = rejection;
+ }
+
+ UnreportTask.prototype.run = function() {
+ if(this.rejection.reported) {
+ Promise.onPotentiallyUnhandledRejectionHandled(this.rejection);
+ }
+ };
+
+ // Unhandled rejection hooks
+ // By default, everything is a noop
+
+ // TODO: Better names: "annotate"?
+ Promise.createContext
+ = Promise.enterContext
+ = Promise.exitContext
+ = Promise.onPotentiallyUnhandledRejection
+ = Promise.onPotentiallyUnhandledRejectionHandled
+ = Promise.onFatalRejection
+ = noop;
+
+ // Errors and singletons
+
+ var foreverPendingHandler = new Handler();
+ var foreverPendingPromise = new Promise(Handler, foreverPendingHandler);
+
+ function cycle() {
+ return new Rejected(new TypeError('Promise cycle'));
+ }
+
+ // Task runners
+
+ /**
+ * Run a single consumer
+ * @constructor
+ */
+ function ContinuationTask(continuation, handler) {
+ this.continuation = continuation;
+ this.handler = handler;
+ }
+
+ ContinuationTask.prototype.run = function() {
+ this.handler.join().when(this.continuation);
+ };
+
+ /**
+ * Run a queue of progress handlers
+ * @constructor
+ */
+ function ProgressTask(value, handler) {
+ this.handler = handler;
+ this.value = value;
+ }
+
+ ProgressTask.prototype.run = function() {
+ var q = this.handler.consumers;
+ if(q === void 0) {
+ return;
+ }
+
+ for (var c, i = 0; i < q.length; ++i) {
+ c = q[i];
+ runNotify(c.progress, this.value, this.handler, c.receiver, c.resolver);
+ }
+ };
+
+ /**
+ * Assimilate a thenable, sending it's value to resolver
+ * @param {function} then
+ * @param {object|function} thenable
+ * @param {object} resolver
+ * @constructor
+ */
+ function AssimilateTask(then, thenable, resolver) {
+ this._then = then;
+ this.thenable = thenable;
+ this.resolver = resolver;
+ }
+
+ AssimilateTask.prototype.run = function() {
+ var h = this.resolver;
+ tryAssimilate(this._then, this.thenable, _resolve, _reject, _notify);
+
+ function _resolve(x) { h.resolve(x); }
+ function _reject(x) { h.reject(x); }
+ function _notify(x) { h.notify(x); }
+ };
+
+ function tryAssimilate(then, thenable, resolve, reject, notify) {
+ try {
+ then.call(thenable, resolve, reject, notify);
+ } catch (e) {
+ reject(e);
+ }
+ }
+
+ // Other helpers
+
+ /**
+ * @param {*} x
+ * @returns {boolean} true iff x is a trusted Promise
+ */
+ function isPromise(x) {
+ return x instanceof Promise;
+ }
+
+ /**
+ * Test just enough to rule out primitives, in order to take faster
+ * paths in some code
+ * @param {*} x
+ * @returns {boolean} false iff x is guaranteed *not* to be a thenable
+ */
+ function maybeThenable(x) {
+ return (typeof x === 'object' || typeof x === 'function') && x !== null;
+ }
+
+ function runContinuation1(f, h, receiver, next) {
+ if(typeof f !== 'function') {
+ return next.become(h);
+ }
+
+ Promise.enterContext(h);
+ tryCatchReject(f, h.value, receiver, next);
+ Promise.exitContext();
+ }
+
+ function runContinuation3(f, x, h, receiver, next) {
+ if(typeof f !== 'function') {
+ return next.become(h);
+ }
+
+ Promise.enterContext(h);
+ tryCatchReject3(f, x, h.value, receiver, next);
+ Promise.exitContext();
+ }
+
+ function runNotify(f, x, h, receiver, next) {
+ if(typeof f !== 'function') {
+ return next.notify(x);
+ }
+
+ Promise.enterContext(h);
+ tryCatchReturn(f, x, receiver, next);
+ Promise.exitContext();
+ }
+
+ /**
+ * Return f.call(thisArg, x), or if it throws return a rejected promise for
+ * the thrown exception
+ */
+ function tryCatchReject(f, x, thisArg, next) {
+ try {
+ next.become(getHandler(f.call(thisArg, x)));
+ } catch(e) {
+ next.become(new Rejected(e));
+ }
+ }
+
+ /**
+ * Same as above, but includes the extra argument parameter.
+ */
+ function tryCatchReject3(f, x, y, thisArg, next) {
+ try {
+ f.call(thisArg, x, y, next);
+ } catch(e) {
+ next.become(new Rejected(e));
+ }
+ }
+
+ /**
+ * Return f.call(thisArg, x), or if it throws, *return* the exception
+ */
+ function tryCatchReturn(f, x, thisArg, next) {
+ try {
+ next.notify(f.call(thisArg, x));
+ } catch(e) {
+ next.notify(e);
+ }
+ }
+
+ function inherit(Parent, Child) {
+ Child.prototype = objectCreate(Parent.prototype);
+ Child.prototype.constructor = Child;
+ }
+
+ function noop() {}
+
+ return Promise;
+ };
+});
+}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
+
+},{}],48:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule AutoFocusMixin
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var focusNode = require("./focusNode");
+
+var AutoFocusMixin = {
+ componentDidMount: function() {
+ if (this.props.autoFocus) {
+ focusNode(this.getDOMNode());
+ }
+ }
+};
+
+module.exports = AutoFocusMixin;
+
+},{"./focusNode":172}],49:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule BeforeInputEventPlugin
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var EventConstants = require("./EventConstants");
+var EventPropagators = require("./EventPropagators");
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+var SyntheticInputEvent = require("./SyntheticInputEvent");
+
+var keyOf = require("./keyOf");
+
+var canUseTextInputEvent = (
+ ExecutionEnvironment.canUseDOM &&
+ 'TextEvent' in window &&
+ !('documentMode' in document || isPresto())
+);
+
+/**
+ * Opera <= 12 includes TextEvent in window, but does not fire
+ * text input events. Rely on keypress instead.
+ */
+function isPresto() {
+ var opera = window.opera;
+ return (
+ typeof opera === 'object' &&
+ typeof opera.version === 'function' &&
+ parseInt(opera.version(), 10) <= 12
+ );
+}
+
+var SPACEBAR_CODE = 32;
+var SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE);
+
+var topLevelTypes = EventConstants.topLevelTypes;
+
+// Events and their corresponding property names.
+var eventTypes = {
+ beforeInput: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onBeforeInput: null}),
+ captured: keyOf({onBeforeInputCapture: null})
+ },
+ dependencies: [
+ topLevelTypes.topCompositionEnd,
+ topLevelTypes.topKeyPress,
+ topLevelTypes.topTextInput,
+ topLevelTypes.topPaste
+ ]
+ }
+};
+
+// Track characters inserted via keypress and composition events.
+var fallbackChars = null;
+
+// Track whether we've ever handled a keypress on the space key.
+var hasSpaceKeypress = false;
+
+/**
+ * Return whether a native keypress event is assumed to be a command.
+ * This is required because Firefox fires `keypress` events for key commands
+ * (cut, copy, select-all, etc.) even though no character is inserted.
+ */
+function isKeypressCommand(nativeEvent) {
+ return (
+ (nativeEvent.ctrlKey || nativeEvent.altKey || nativeEvent.metaKey) &&
+ // ctrlKey && altKey is equivalent to AltGr, and is not a command.
+ !(nativeEvent.ctrlKey && nativeEvent.altKey)
+ );
+}
+
+/**
+ * Create an `onBeforeInput` event to match
+ * http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#events-inputevents.
+ *
+ * This event plugin is based on the native `textInput` event
+ * available in Chrome, Safari, Opera, and IE. This event fires after
+ * `onKeyPress` and `onCompositionEnd`, but before `onInput`.
+ *
+ * `beforeInput` is spec'd but not implemented in any browsers, and
+ * the `input` event does not provide any useful information about what has
+ * actually been added, contrary to the spec. Thus, `textInput` is the best
+ * available event to identify the characters that have actually been inserted
+ * into the target node.
+ */
+var BeforeInputEventPlugin = {
+
+ eventTypes: eventTypes,
+
+ /**
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {DOMEventTarget} topLevelTarget The listening component root node.
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
+ * @param {object} nativeEvent Native browser event.
+ * @return {*} An accumulation of synthetic events.
+ * @see {EventPluginHub.extractEvents}
+ */
+ extractEvents: function(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID,
+ nativeEvent) {
+
+ var chars;
+
+ if (canUseTextInputEvent) {
+ switch (topLevelType) {
+ case topLevelTypes.topKeyPress:
+ /**
+ * If native `textInput` events are available, our goal is to make
+ * use of them. However, there is a special case: the spacebar key.
+ * In Webkit, preventing default on a spacebar `textInput` event
+ * cancels character insertion, but it *also* causes the browser
+ * to fall back to its default spacebar behavior of scrolling the
+ * page.
+ *
+ * Tracking at:
+ * https://code.google.com/p/chromium/issues/detail?id=355103
+ *
+ * To avoid this issue, use the keypress event as if no `textInput`
+ * event is available.
+ */
+ var which = nativeEvent.which;
+ if (which !== SPACEBAR_CODE) {
+ return;
+ }
+
+ hasSpaceKeypress = true;
+ chars = SPACEBAR_CHAR;
+ break;
+
+ case topLevelTypes.topTextInput:
+ // Record the characters to be added to the DOM.
+ chars = nativeEvent.data;
+
+ // If it's a spacebar character, assume that we have already handled
+ // it at the keypress level and bail immediately. Android Chrome
+ // doesn't give us keycodes, so we need to blacklist it.
+ if (chars === SPACEBAR_CHAR && hasSpaceKeypress) {
+ return;
+ }
+
+ // Otherwise, carry on.
+ break;
+
+ default:
+ // For other native event types, do nothing.
+ return;
+ }
+ } else {
+ switch (topLevelType) {
+ case topLevelTypes.topPaste:
+ // If a paste event occurs after a keypress, throw out the input
+ // chars. Paste events should not lead to BeforeInput events.
+ fallbackChars = null;
+ break;
+ case topLevelTypes.topKeyPress:
+ /**
+ * As of v27, Firefox may fire keypress events even when no character
+ * will be inserted. A few possibilities:
+ *
+ * - `which` is `0`. Arrow keys, Esc key, etc.
+ *
+ * - `which` is the pressed key code, but no char is available.
+ * Ex: 'AltGr + d` in Polish. There is no modified character for
+ * this key combination and no character is inserted into the
+ * document, but FF fires the keypress for char code `100` anyway.
+ * No `input` event will occur.
+ *
+ * - `which` is the pressed key code, but a command combination is
+ * being used. Ex: `Cmd+C`. No character is inserted, and no
+ * `input` event will occur.
+ */
+ if (nativeEvent.which && !isKeypressCommand(nativeEvent)) {
+ fallbackChars = String.fromCharCode(nativeEvent.which);
+ }
+ break;
+ case topLevelTypes.topCompositionEnd:
+ fallbackChars = nativeEvent.data;
+ break;
+ }
+
+ // If no changes have occurred to the fallback string, no relevant
+ // event has fired and we're done.
+ if (fallbackChars === null) {
+ return;
+ }
+
+ chars = fallbackChars;
+ }
+
+ // If no characters are being inserted, no BeforeInput event should
+ // be fired.
+ if (!chars) {
+ return;
+ }
+
+ var event = SyntheticInputEvent.getPooled(
+ eventTypes.beforeInput,
+ topLevelTargetID,
+ nativeEvent
+ );
+
+ event.data = chars;
+ fallbackChars = null;
+ EventPropagators.accumulateTwoPhaseDispatches(event);
+ return event;
+ }
+};
+
+module.exports = BeforeInputEventPlugin;
+
+},{"./EventConstants":63,"./EventPropagators":68,"./ExecutionEnvironment":69,"./SyntheticInputEvent":148,"./keyOf":194}],50:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule CSSCore
+ * @typechecks
+ */
+
+var invariant = require("./invariant");
+
+/**
+ * The CSSCore module specifies the API (and implements most of the methods)
+ * that should be used when dealing with the display of elements (via their
+ * CSS classes and visibility on screen. It is an API focused on mutating the
+ * display and not reading it as no logical state should be encoded in the
+ * display of elements.
+ */
+
+var CSSCore = {
+
+ /**
+ * Adds the class passed in to the element if it doesn't already have it.
+ *
+ * @param {DOMElement} element the element to set the class on
+ * @param {string} className the CSS className
+ * @return {DOMElement} the element passed in
+ */
+ addClass: function(element, className) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !/\s/.test(className),
+ 'CSSCore.addClass takes only a single class name. "%s" contains ' +
+ 'multiple classes.', className
+ ) : invariant(!/\s/.test(className)));
+
+ if (className) {
+ if (element.classList) {
+ element.classList.add(className);
+ } else if (!CSSCore.hasClass(element, className)) {
+ element.className = element.className + ' ' + className;
+ }
+ }
+ return element;
+ },
+
+ /**
+ * Removes the class passed in from the element
+ *
+ * @param {DOMElement} element the element to set the class on
+ * @param {string} className the CSS className
+ * @return {DOMElement} the element passed in
+ */
+ removeClass: function(element, className) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !/\s/.test(className),
+ 'CSSCore.removeClass takes only a single class name. "%s" contains ' +
+ 'multiple classes.', className
+ ) : invariant(!/\s/.test(className)));
+
+ if (className) {
+ if (element.classList) {
+ element.classList.remove(className);
+ } else if (CSSCore.hasClass(element, className)) {
+ element.className = element.className
+ .replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)', 'g'), '$1')
+ .replace(/\s+/g, ' ') // multiple spaces to one
+ .replace(/^\s*|\s*$/g, ''); // trim the ends
+ }
+ }
+ return element;
+ },
+
+ /**
+ * Helper to add or remove a class from an element based on a condition.
+ *
+ * @param {DOMElement} element the element to set the class on
+ * @param {string} className the CSS className
+ * @param {*} bool condition to whether to add or remove the class
+ * @return {DOMElement} the element passed in
+ */
+ conditionClass: function(element, className, bool) {
+ return (bool ? CSSCore.addClass : CSSCore.removeClass)(element, className);
+ },
+
+ /**
+ * Tests whether the element has the class specified.
+ *
+ * @param {DOMNode|DOMWindow} element the element to set the class on
+ * @param {string} className the CSS className
+ * @return {boolean} true if the element has the class, false if not
+ */
+ hasClass: function(element, className) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !/\s/.test(className),
+ 'CSS.hasClass takes only a single class name.'
+ ) : invariant(!/\s/.test(className)));
+ if (element.classList) {
+ return !!className && element.classList.contains(className);
+ }
+ return (' ' + element.className + ' ').indexOf(' ' + className + ' ') > -1;
+ }
+
+};
+
+module.exports = CSSCore;
+
+}).call(this,require('_process'))
+},{"./invariant":187,"_process":5}],51:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule CSSProperty
+ */
+
+"use strict";
+
+/**
+ * CSS properties which accept numbers but are not in units of "px".
+ */
+var isUnitlessNumber = {
+ columnCount: true,
+ flex: true,
+ flexGrow: true,
+ flexShrink: true,
+ fontWeight: true,
+ lineClamp: true,
+ lineHeight: true,
+ opacity: true,
+ order: true,
+ orphans: true,
+ widows: true,
+ zIndex: true,
+ zoom: true,
+
+ // SVG-related properties
+ fillOpacity: true,
+ strokeOpacity: true
+};
+
+/**
+ * @param {string} prefix vendor-specific prefix, eg: Webkit
+ * @param {string} key style name, eg: transitionDuration
+ * @return {string} style name prefixed with `prefix`, properly camelCased, eg:
+ * WebkitTransitionDuration
+ */
+function prefixKey(prefix, key) {
+ return prefix + key.charAt(0).toUpperCase() + key.substring(1);
+}
+
+/**
+ * Support style names that may come passed in prefixed by adding permutations
+ * of vendor prefixes.
+ */
+var prefixes = ['Webkit', 'ms', 'Moz', 'O'];
+
+// Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an
+// infinite loop, because it iterates over the newly added props too.
+Object.keys(isUnitlessNumber).forEach(function(prop) {
+ prefixes.forEach(function(prefix) {
+ isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop];
+ });
+});
+
+/**
+ * Most style properties can be unset by doing .style[prop] = '' but IE8
+ * doesn't like doing that with shorthand properties so for the properties that
+ * IE8 breaks on, which are listed here, we instead unset each of the
+ * individual properties. See http://bugs.jquery.com/ticket/12385.
+ * The 4-value 'clock' properties like margin, padding, border-width seem to
+ * behave without any problems. Curiously, list-style works too without any
+ * special prodding.
+ */
+var shorthandPropertyExpansions = {
+ background: {
+ backgroundImage: true,
+ backgroundPosition: true,
+ backgroundRepeat: true,
+ backgroundColor: true
+ },
+ border: {
+ borderWidth: true,
+ borderStyle: true,
+ borderColor: true
+ },
+ borderBottom: {
+ borderBottomWidth: true,
+ borderBottomStyle: true,
+ borderBottomColor: true
+ },
+ borderLeft: {
+ borderLeftWidth: true,
+ borderLeftStyle: true,
+ borderLeftColor: true
+ },
+ borderRight: {
+ borderRightWidth: true,
+ borderRightStyle: true,
+ borderRightColor: true
+ },
+ borderTop: {
+ borderTopWidth: true,
+ borderTopStyle: true,
+ borderTopColor: true
+ },
+ font: {
+ fontStyle: true,
+ fontVariant: true,
+ fontWeight: true,
+ fontSize: true,
+ lineHeight: true,
+ fontFamily: true
+ }
+};
+
+var CSSProperty = {
+ isUnitlessNumber: isUnitlessNumber,
+ shorthandPropertyExpansions: shorthandPropertyExpansions
+};
+
+module.exports = CSSProperty;
+
+},{}],52:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule CSSPropertyOperations
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var CSSProperty = require("./CSSProperty");
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+
+var camelizeStyleName = require("./camelizeStyleName");
+var dangerousStyleValue = require("./dangerousStyleValue");
+var hyphenateStyleName = require("./hyphenateStyleName");
+var memoizeStringOnly = require("./memoizeStringOnly");
+var warning = require("./warning");
+
+var processStyleName = memoizeStringOnly(function(styleName) {
+ return hyphenateStyleName(styleName);
+});
+
+var styleFloatAccessor = 'cssFloat';
+if (ExecutionEnvironment.canUseDOM) {
+ // IE8 only supports accessing cssFloat (standard) as styleFloat
+ if (document.documentElement.style.cssFloat === undefined) {
+ styleFloatAccessor = 'styleFloat';
+ }
+}
+
+if ("production" !== process.env.NODE_ENV) {
+ var warnedStyleNames = {};
+
+ var warnHyphenatedStyleName = function(name) {
+ if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) {
+ return;
+ }
+
+ warnedStyleNames[name] = true;
+ ("production" !== process.env.NODE_ENV ? warning(
+ false,
+ 'Unsupported style property ' + name + '. Did you mean ' +
+ camelizeStyleName(name) + '?'
+ ) : null);
+ };
+}
+
+/**
+ * Operations for dealing with CSS properties.
+ */
+var CSSPropertyOperations = {
+
+ /**
+ * Serializes a mapping of style properties for use as inline styles:
+ *
+ * > createMarkupForStyles({width: '200px', height: 0})
+ * "width:200px;height:0;"
+ *
+ * Undefined values are ignored so that declarative programming is easier.
+ * The result should be HTML-escaped before insertion into the DOM.
+ *
+ * @param {object} styles
+ * @return {?string}
+ */
+ createMarkupForStyles: function(styles) {
+ var serialized = '';
+ for (var styleName in styles) {
+ if (!styles.hasOwnProperty(styleName)) {
+ continue;
+ }
+ if ("production" !== process.env.NODE_ENV) {
+ if (styleName.indexOf('-') > -1) {
+ warnHyphenatedStyleName(styleName);
+ }
+ }
+ var styleValue = styles[styleName];
+ if (styleValue != null) {
+ serialized += processStyleName(styleName) + ':';
+ serialized += dangerousStyleValue(styleName, styleValue) + ';';
+ }
+ }
+ return serialized || null;
+ },
+
+ /**
+ * Sets the value for multiple styles on a node. If a value is specified as
+ * '' (empty string), the corresponding style property will be unset.
+ *
+ * @param {DOMElement} node
+ * @param {object} styles
+ */
+ setValueForStyles: function(node, styles) {
+ var style = node.style;
+ for (var styleName in styles) {
+ if (!styles.hasOwnProperty(styleName)) {
+ continue;
+ }
+ if ("production" !== process.env.NODE_ENV) {
+ if (styleName.indexOf('-') > -1) {
+ warnHyphenatedStyleName(styleName);
+ }
+ }
+ var styleValue = dangerousStyleValue(styleName, styles[styleName]);
+ if (styleName === 'float') {
+ styleName = styleFloatAccessor;
+ }
+ if (styleValue) {
+ style[styleName] = styleValue;
+ } else {
+ var expansion = CSSProperty.shorthandPropertyExpansions[styleName];
+ if (expansion) {
+ // Shorthand property that IE8 won't like unsetting, so unset each
+ // component to placate it
+ for (var individualStyleName in expansion) {
+ style[individualStyleName] = '';
+ }
+ } else {
+ style[styleName] = '';
+ }
+ }
+ }
+ }
+
+};
+
+module.exports = CSSPropertyOperations;
+
+}).call(this,require('_process'))
+},{"./CSSProperty":51,"./ExecutionEnvironment":69,"./camelizeStyleName":159,"./dangerousStyleValue":166,"./hyphenateStyleName":185,"./memoizeStringOnly":196,"./warning":207,"_process":5}],53:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule CallbackQueue
+ */
+
+"use strict";
+
+var PooledClass = require("./PooledClass");
+
+var assign = require("./Object.assign");
+var invariant = require("./invariant");
+
+/**
+ * A specialized pseudo-event module to help keep track of components waiting to
+ * be notified when their DOM representations are available for use.
+ *
+ * This implements `PooledClass`, so you should never need to instantiate this.
+ * Instead, use `CallbackQueue.getPooled()`.
+ *
+ * @class ReactMountReady
+ * @implements PooledClass
+ * @internal
+ */
+function CallbackQueue() {
+ this._callbacks = null;
+ this._contexts = null;
+}
+
+assign(CallbackQueue.prototype, {
+
+ /**
+ * Enqueues a callback to be invoked when `notifyAll` is invoked.
+ *
+ * @param {function} callback Invoked when `notifyAll` is invoked.
+ * @param {?object} context Context to call `callback` with.
+ * @internal
+ */
+ enqueue: function(callback, context) {
+ this._callbacks = this._callbacks || [];
+ this._contexts = this._contexts || [];
+ this._callbacks.push(callback);
+ this._contexts.push(context);
+ },
+
+ /**
+ * Invokes all enqueued callbacks and clears the queue. This is invoked after
+ * the DOM representation of a component has been created or updated.
+ *
+ * @internal
+ */
+ notifyAll: function() {
+ var callbacks = this._callbacks;
+ var contexts = this._contexts;
+ if (callbacks) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ callbacks.length === contexts.length,
+ "Mismatched list of contexts in callback queue"
+ ) : invariant(callbacks.length === contexts.length));
+ this._callbacks = null;
+ this._contexts = null;
+ for (var i = 0, l = callbacks.length; i < l; i++) {
+ callbacks[i].call(contexts[i]);
+ }
+ callbacks.length = 0;
+ contexts.length = 0;
+ }
+ },
+
+ /**
+ * Resets the internal queue.
+ *
+ * @internal
+ */
+ reset: function() {
+ this._callbacks = null;
+ this._contexts = null;
+ },
+
+ /**
+ * `PooledClass` looks for this.
+ */
+ destructor: function() {
+ this.reset();
+ }
+
+});
+
+PooledClass.addPoolingTo(CallbackQueue);
+
+module.exports = CallbackQueue;
+
+}).call(this,require('_process'))
+},{"./Object.assign":75,"./PooledClass":76,"./invariant":187,"_process":5}],54:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ChangeEventPlugin
+ */
+
+"use strict";
+
+var EventConstants = require("./EventConstants");
+var EventPluginHub = require("./EventPluginHub");
+var EventPropagators = require("./EventPropagators");
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+var ReactUpdates = require("./ReactUpdates");
+var SyntheticEvent = require("./SyntheticEvent");
+
+var isEventSupported = require("./isEventSupported");
+var isTextInputElement = require("./isTextInputElement");
+var keyOf = require("./keyOf");
+
+var topLevelTypes = EventConstants.topLevelTypes;
+
+var eventTypes = {
+ change: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onChange: null}),
+ captured: keyOf({onChangeCapture: null})
+ },
+ dependencies: [
+ topLevelTypes.topBlur,
+ topLevelTypes.topChange,
+ topLevelTypes.topClick,
+ topLevelTypes.topFocus,
+ topLevelTypes.topInput,
+ topLevelTypes.topKeyDown,
+ topLevelTypes.topKeyUp,
+ topLevelTypes.topSelectionChange
+ ]
+ }
+};
+
+/**
+ * For IE shims
+ */
+var activeElement = null;
+var activeElementID = null;
+var activeElementValue = null;
+var activeElementValueProp = null;
+
+/**
+ * SECTION: handle `change` event
+ */
+function shouldUseChangeEvent(elem) {
+ return (
+ elem.nodeName === 'SELECT' ||
+ (elem.nodeName === 'INPUT' && elem.type === 'file')
+ );
+}
+
+var doesChangeEventBubble = false;
+if (ExecutionEnvironment.canUseDOM) {
+ // See `handleChange` comment below
+ doesChangeEventBubble = isEventSupported('change') && (
+ !('documentMode' in document) || document.documentMode > 8
+ );
+}
+
+function manualDispatchChangeEvent(nativeEvent) {
+ var event = SyntheticEvent.getPooled(
+ eventTypes.change,
+ activeElementID,
+ nativeEvent
+ );
+ EventPropagators.accumulateTwoPhaseDispatches(event);
+
+ // If change and propertychange bubbled, we'd just bind to it like all the
+ // other events and have it go through ReactBrowserEventEmitter. Since it
+ // doesn't, we manually listen for the events and so we have to enqueue and
+ // process the abstract event manually.
+ //
+ // Batching is necessary here in order to ensure that all event handlers run
+ // before the next rerender (including event handlers attached to ancestor
+ // elements instead of directly on the input). Without this, controlled
+ // components don't work properly in conjunction with event bubbling because
+ // the component is rerendered and the value reverted before all the event
+ // handlers can run. See https://github.com/facebook/react/issues/708.
+ ReactUpdates.batchedUpdates(runEventInBatch, event);
+}
+
+function runEventInBatch(event) {
+ EventPluginHub.enqueueEvents(event);
+ EventPluginHub.processEventQueue();
+}
+
+function startWatchingForChangeEventIE8(target, targetID) {
+ activeElement = target;
+ activeElementID = targetID;
+ activeElement.attachEvent('onchange', manualDispatchChangeEvent);
+}
+
+function stopWatchingForChangeEventIE8() {
+ if (!activeElement) {
+ return;
+ }
+ activeElement.detachEvent('onchange', manualDispatchChangeEvent);
+ activeElement = null;
+ activeElementID = null;
+}
+
+function getTargetIDForChangeEvent(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID) {
+ if (topLevelType === topLevelTypes.topChange) {
+ return topLevelTargetID;
+ }
+}
+function handleEventsForChangeEventIE8(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID) {
+ if (topLevelType === topLevelTypes.topFocus) {
+ // stopWatching() should be a noop here but we call it just in case we
+ // missed a blur event somehow.
+ stopWatchingForChangeEventIE8();
+ startWatchingForChangeEventIE8(topLevelTarget, topLevelTargetID);
+ } else if (topLevelType === topLevelTypes.topBlur) {
+ stopWatchingForChangeEventIE8();
+ }
+}
+
+
+/**
+ * SECTION: handle `input` event
+ */
+var isInputEventSupported = false;
+if (ExecutionEnvironment.canUseDOM) {
+ // IE9 claims to support the input event but fails to trigger it when
+ // deleting text, so we ignore its input events
+ isInputEventSupported = isEventSupported('input') && (
+ !('documentMode' in document) || document.documentMode > 9
+ );
+}
+
+/**
+ * (For old IE.) Replacement getter/setter for the `value` property that gets
+ * set on the active element.
+ */
+var newValueProp = {
+ get: function() {
+ return activeElementValueProp.get.call(this);
+ },
+ set: function(val) {
+ // Cast to a string so we can do equality checks.
+ activeElementValue = '' + val;
+ activeElementValueProp.set.call(this, val);
+ }
+};
+
+/**
+ * (For old IE.) Starts tracking propertychange events on the passed-in element
+ * and override the value property so that we can distinguish user events from
+ * value changes in JS.
+ */
+function startWatchingForValueChange(target, targetID) {
+ activeElement = target;
+ activeElementID = targetID;
+ activeElementValue = target.value;
+ activeElementValueProp = Object.getOwnPropertyDescriptor(
+ target.constructor.prototype,
+ 'value'
+ );
+
+ Object.defineProperty(activeElement, 'value', newValueProp);
+ activeElement.attachEvent('onpropertychange', handlePropertyChange);
+}
+
+/**
+ * (For old IE.) Removes the event listeners from the currently-tracked element,
+ * if any exists.
+ */
+function stopWatchingForValueChange() {
+ if (!activeElement) {
+ return;
+ }
+
+ // delete restores the original property definition
+ delete activeElement.value;
+ activeElement.detachEvent('onpropertychange', handlePropertyChange);
+
+ activeElement = null;
+ activeElementID = null;
+ activeElementValue = null;
+ activeElementValueProp = null;
+}
+
+/**
+ * (For old IE.) Handles a propertychange event, sending a `change` event if
+ * the value of the active element has changed.
+ */
+function handlePropertyChange(nativeEvent) {
+ if (nativeEvent.propertyName !== 'value') {
+ return;
+ }
+ var value = nativeEvent.srcElement.value;
+ if (value === activeElementValue) {
+ return;
+ }
+ activeElementValue = value;
+
+ manualDispatchChangeEvent(nativeEvent);
+}
+
+/**
+ * If a `change` event should be fired, returns the target's ID.
+ */
+function getTargetIDForInputEvent(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID) {
+ if (topLevelType === topLevelTypes.topInput) {
+ // In modern browsers (i.e., not IE8 or IE9), the input event is exactly
+ // what we want so fall through here and trigger an abstract event
+ return topLevelTargetID;
+ }
+}
+
+// For IE8 and IE9.
+function handleEventsForInputEventIE(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID) {
+ if (topLevelType === topLevelTypes.topFocus) {
+ // In IE8, we can capture almost all .value changes by adding a
+ // propertychange handler and looking for events with propertyName
+ // equal to 'value'
+ // In IE9, propertychange fires for most input events but is buggy and
+ // doesn't fire when text is deleted, but conveniently, selectionchange
+ // appears to fire in all of the remaining cases so we catch those and
+ // forward the event if the value has changed
+ // In either case, we don't want to call the event handler if the value
+ // is changed from JS so we redefine a setter for `.value` that updates
+ // our activeElementValue variable, allowing us to ignore those changes
+ //
+ // stopWatching() should be a noop here but we call it just in case we
+ // missed a blur event somehow.
+ stopWatchingForValueChange();
+ startWatchingForValueChange(topLevelTarget, topLevelTargetID);
+ } else if (topLevelType === topLevelTypes.topBlur) {
+ stopWatchingForValueChange();
+ }
+}
+
+// For IE8 and IE9.
+function getTargetIDForInputEventIE(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID) {
+ if (topLevelType === topLevelTypes.topSelectionChange ||
+ topLevelType === topLevelTypes.topKeyUp ||
+ topLevelType === topLevelTypes.topKeyDown) {
+ // On the selectionchange event, the target is just document which isn't
+ // helpful for us so just check activeElement instead.
+ //
+ // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire
+ // propertychange on the first input event after setting `value` from a
+ // script and fires only keydown, keypress, keyup. Catching keyup usually
+ // gets it and catching keydown lets us fire an event for the first
+ // keystroke if user does a key repeat (it'll be a little delayed: right
+ // before the second keystroke). Other input methods (e.g., paste) seem to
+ // fire selectionchange normally.
+ if (activeElement && activeElement.value !== activeElementValue) {
+ activeElementValue = activeElement.value;
+ return activeElementID;
+ }
+ }
+}
+
+
+/**
+ * SECTION: handle `click` event
+ */
+function shouldUseClickEvent(elem) {
+ // Use the `click` event to detect changes to checkbox and radio inputs.
+ // This approach works across all browsers, whereas `change` does not fire
+ // until `blur` in IE8.
+ return (
+ elem.nodeName === 'INPUT' &&
+ (elem.type === 'checkbox' || elem.type === 'radio')
+ );
+}
+
+function getTargetIDForClickEvent(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID) {
+ if (topLevelType === topLevelTypes.topClick) {
+ return topLevelTargetID;
+ }
+}
+
+/**
+ * This plugin creates an `onChange` event that normalizes change events
+ * across form elements. This event fires at a time when it's possible to
+ * change the element's value without seeing a flicker.
+ *
+ * Supported elements are:
+ * - input (see `isTextInputElement`)
+ * - textarea
+ * - select
+ */
+var ChangeEventPlugin = {
+
+ eventTypes: eventTypes,
+
+ /**
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {DOMEventTarget} topLevelTarget The listening component root node.
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
+ * @param {object} nativeEvent Native browser event.
+ * @return {*} An accumulation of synthetic events.
+ * @see {EventPluginHub.extractEvents}
+ */
+ extractEvents: function(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID,
+ nativeEvent) {
+
+ var getTargetIDFunc, handleEventFunc;
+ if (shouldUseChangeEvent(topLevelTarget)) {
+ if (doesChangeEventBubble) {
+ getTargetIDFunc = getTargetIDForChangeEvent;
+ } else {
+ handleEventFunc = handleEventsForChangeEventIE8;
+ }
+ } else if (isTextInputElement(topLevelTarget)) {
+ if (isInputEventSupported) {
+ getTargetIDFunc = getTargetIDForInputEvent;
+ } else {
+ getTargetIDFunc = getTargetIDForInputEventIE;
+ handleEventFunc = handleEventsForInputEventIE;
+ }
+ } else if (shouldUseClickEvent(topLevelTarget)) {
+ getTargetIDFunc = getTargetIDForClickEvent;
+ }
+
+ if (getTargetIDFunc) {
+ var targetID = getTargetIDFunc(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID
+ );
+ if (targetID) {
+ var event = SyntheticEvent.getPooled(
+ eventTypes.change,
+ targetID,
+ nativeEvent
+ );
+ EventPropagators.accumulateTwoPhaseDispatches(event);
+ return event;
+ }
+ }
+
+ if (handleEventFunc) {
+ handleEventFunc(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID
+ );
+ }
+ }
+
+};
+
+module.exports = ChangeEventPlugin;
+
+},{"./EventConstants":63,"./EventPluginHub":65,"./EventPropagators":68,"./ExecutionEnvironment":69,"./ReactUpdates":137,"./SyntheticEvent":146,"./isEventSupported":188,"./isTextInputElement":190,"./keyOf":194}],55:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ClientReactRootIndex
+ * @typechecks
+ */
+
+"use strict";
+
+var nextReactRootIndex = 0;
+
+var ClientReactRootIndex = {
+ createReactRootIndex: function() {
+ return nextReactRootIndex++;
+ }
+};
+
+module.exports = ClientReactRootIndex;
+
+},{}],56:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule CompositionEventPlugin
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var EventConstants = require("./EventConstants");
+var EventPropagators = require("./EventPropagators");
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+var ReactInputSelection = require("./ReactInputSelection");
+var SyntheticCompositionEvent = require("./SyntheticCompositionEvent");
+
+var getTextContentAccessor = require("./getTextContentAccessor");
+var keyOf = require("./keyOf");
+
+var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space
+var START_KEYCODE = 229;
+
+var useCompositionEvent = (
+ ExecutionEnvironment.canUseDOM &&
+ 'CompositionEvent' in window
+);
+
+// In IE9+, we have access to composition events, but the data supplied
+// by the native compositionend event may be incorrect. In Korean, for example,
+// the compositionend event contains only one character regardless of
+// how many characters have been composed since compositionstart.
+// We therefore use the fallback data while still using the native
+// events as triggers.
+var useFallbackData = (
+ !useCompositionEvent ||
+ (
+ 'documentMode' in document &&
+ document.documentMode > 8 &&
+ document.documentMode <= 11
+ )
+);
+
+var topLevelTypes = EventConstants.topLevelTypes;
+var currentComposition = null;
+
+// Events and their corresponding property names.
+var eventTypes = {
+ compositionEnd: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onCompositionEnd: null}),
+ captured: keyOf({onCompositionEndCapture: null})
+ },
+ dependencies: [
+ topLevelTypes.topBlur,
+ topLevelTypes.topCompositionEnd,
+ topLevelTypes.topKeyDown,
+ topLevelTypes.topKeyPress,
+ topLevelTypes.topKeyUp,
+ topLevelTypes.topMouseDown
+ ]
+ },
+ compositionStart: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onCompositionStart: null}),
+ captured: keyOf({onCompositionStartCapture: null})
+ },
+ dependencies: [
+ topLevelTypes.topBlur,
+ topLevelTypes.topCompositionStart,
+ topLevelTypes.topKeyDown,
+ topLevelTypes.topKeyPress,
+ topLevelTypes.topKeyUp,
+ topLevelTypes.topMouseDown
+ ]
+ },
+ compositionUpdate: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onCompositionUpdate: null}),
+ captured: keyOf({onCompositionUpdateCapture: null})
+ },
+ dependencies: [
+ topLevelTypes.topBlur,
+ topLevelTypes.topCompositionUpdate,
+ topLevelTypes.topKeyDown,
+ topLevelTypes.topKeyPress,
+ topLevelTypes.topKeyUp,
+ topLevelTypes.topMouseDown
+ ]
+ }
+};
+
+/**
+ * Translate native top level events into event types.
+ *
+ * @param {string} topLevelType
+ * @return {object}
+ */
+function getCompositionEventType(topLevelType) {
+ switch (topLevelType) {
+ case topLevelTypes.topCompositionStart:
+ return eventTypes.compositionStart;
+ case topLevelTypes.topCompositionEnd:
+ return eventTypes.compositionEnd;
+ case topLevelTypes.topCompositionUpdate:
+ return eventTypes.compositionUpdate;
+ }
+}
+
+/**
+ * Does our fallback best-guess model think this event signifies that
+ * composition has begun?
+ *
+ * @param {string} topLevelType
+ * @param {object} nativeEvent
+ * @return {boolean}
+ */
+function isFallbackStart(topLevelType, nativeEvent) {
+ return (
+ topLevelType === topLevelTypes.topKeyDown &&
+ nativeEvent.keyCode === START_KEYCODE
+ );
+}
+
+/**
+ * Does our fallback mode think that this event is the end of composition?
+ *
+ * @param {string} topLevelType
+ * @param {object} nativeEvent
+ * @return {boolean}
+ */
+function isFallbackEnd(topLevelType, nativeEvent) {
+ switch (topLevelType) {
+ case topLevelTypes.topKeyUp:
+ // Command keys insert or clear IME input.
+ return (END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1);
+ case topLevelTypes.topKeyDown:
+ // Expect IME keyCode on each keydown. If we get any other
+ // code we must have exited earlier.
+ return (nativeEvent.keyCode !== START_KEYCODE);
+ case topLevelTypes.topKeyPress:
+ case topLevelTypes.topMouseDown:
+ case topLevelTypes.topBlur:
+ // Events are not possible without cancelling IME.
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * Helper class stores information about selection and document state
+ * so we can figure out what changed at a later date.
+ *
+ * @param {DOMEventTarget} root
+ */
+function FallbackCompositionState(root) {
+ this.root = root;
+ this.startSelection = ReactInputSelection.getSelection(root);
+ this.startValue = this.getText();
+}
+
+/**
+ * Get current text of input.
+ *
+ * @return {string}
+ */
+FallbackCompositionState.prototype.getText = function() {
+ return this.root.value || this.root[getTextContentAccessor()];
+};
+
+/**
+ * Text that has changed since the start of composition.
+ *
+ * @return {string}
+ */
+FallbackCompositionState.prototype.getData = function() {
+ var endValue = this.getText();
+ var prefixLength = this.startSelection.start;
+ var suffixLength = this.startValue.length - this.startSelection.end;
+
+ return endValue.substr(
+ prefixLength,
+ endValue.length - suffixLength - prefixLength
+ );
+};
+
+/**
+ * This plugin creates `onCompositionStart`, `onCompositionUpdate` and
+ * `onCompositionEnd` events on inputs, textareas and contentEditable
+ * nodes.
+ */
+var CompositionEventPlugin = {
+
+ eventTypes: eventTypes,
+
+ /**
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {DOMEventTarget} topLevelTarget The listening component root node.
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
+ * @param {object} nativeEvent Native browser event.
+ * @return {*} An accumulation of synthetic events.
+ * @see {EventPluginHub.extractEvents}
+ */
+ extractEvents: function(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID,
+ nativeEvent) {
+
+ var eventType;
+ var data;
+
+ if (useCompositionEvent) {
+ eventType = getCompositionEventType(topLevelType);
+ } else if (!currentComposition) {
+ if (isFallbackStart(topLevelType, nativeEvent)) {
+ eventType = eventTypes.compositionStart;
+ }
+ } else if (isFallbackEnd(topLevelType, nativeEvent)) {
+ eventType = eventTypes.compositionEnd;
+ }
+
+ if (useFallbackData) {
+ // The current composition is stored statically and must not be
+ // overwritten while composition continues.
+ if (!currentComposition && eventType === eventTypes.compositionStart) {
+ currentComposition = new FallbackCompositionState(topLevelTarget);
+ } else if (eventType === eventTypes.compositionEnd) {
+ if (currentComposition) {
+ data = currentComposition.getData();
+ currentComposition = null;
+ }
+ }
+ }
+
+ if (eventType) {
+ var event = SyntheticCompositionEvent.getPooled(
+ eventType,
+ topLevelTargetID,
+ nativeEvent
+ );
+ if (data) {
+ // Inject data generated from fallback path into the synthetic event.
+ // This matches the property of native CompositionEventInterface.
+ event.data = data;
+ }
+ EventPropagators.accumulateTwoPhaseDispatches(event);
+ return event;
+ }
+ }
+};
+
+module.exports = CompositionEventPlugin;
+
+},{"./EventConstants":63,"./EventPropagators":68,"./ExecutionEnvironment":69,"./ReactInputSelection":111,"./SyntheticCompositionEvent":144,"./getTextContentAccessor":182,"./keyOf":194}],57:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule DOMChildrenOperations
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var Danger = require("./Danger");
+var ReactMultiChildUpdateTypes = require("./ReactMultiChildUpdateTypes");
+
+var getTextContentAccessor = require("./getTextContentAccessor");
+var invariant = require("./invariant");
+
+/**
+ * The DOM property to use when setting text content.
+ *
+ * @type {string}
+ * @private
+ */
+var textContentAccessor = getTextContentAccessor();
+
+/**
+ * Inserts `childNode` as a child of `parentNode` at the `index`.
+ *
+ * @param {DOMElement} parentNode Parent node in which to insert.
+ * @param {DOMElement} childNode Child node to insert.
+ * @param {number} index Index at which to insert the child.
+ * @internal
+ */
+function insertChildAt(parentNode, childNode, index) {
+ // By exploiting arrays returning `undefined` for an undefined index, we can
+ // rely exclusively on `insertBefore(node, null)` instead of also using
+ // `appendChild(node)`. However, using `undefined` is not allowed by all
+ // browsers so we must replace it with `null`.
+ parentNode.insertBefore(
+ childNode,
+ parentNode.childNodes[index] || null
+ );
+}
+
+var updateTextContent;
+if (textContentAccessor === 'textContent') {
+ /**
+ * Sets the text content of `node` to `text`.
+ *
+ * @param {DOMElement} node Node to change
+ * @param {string} text New text content
+ */
+ updateTextContent = function(node, text) {
+ node.textContent = text;
+ };
+} else {
+ /**
+ * Sets the text content of `node` to `text`.
+ *
+ * @param {DOMElement} node Node to change
+ * @param {string} text New text content
+ */
+ updateTextContent = function(node, text) {
+ // In order to preserve newlines correctly, we can't use .innerText to set
+ // the contents (see #1080), so we empty the element then append a text node
+ while (node.firstChild) {
+ node.removeChild(node.firstChild);
+ }
+ if (text) {
+ var doc = node.ownerDocument || document;
+ node.appendChild(doc.createTextNode(text));
+ }
+ };
+}
+
+/**
+ * Operations for updating with DOM children.
+ */
+var DOMChildrenOperations = {
+
+ dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup,
+
+ updateTextContent: updateTextContent,
+
+ /**
+ * Updates a component's children by processing a series of updates. The
+ * update configurations are each expected to have a `parentNode` property.
+ *
+ * @param {array<object>} updates List of update configurations.
+ * @param {array<string>} markupList List of markup strings.
+ * @internal
+ */
+ processUpdates: function(updates, markupList) {
+ var update;
+ // Mapping from parent IDs to initial child orderings.
+ var initialChildren = null;
+ // List of children that will be moved or removed.
+ var updatedChildren = null;
+
+ for (var i = 0; update = updates[i]; i++) {
+ if (update.type === ReactMultiChildUpdateTypes.MOVE_EXISTING ||
+ update.type === ReactMultiChildUpdateTypes.REMOVE_NODE) {
+ var updatedIndex = update.fromIndex;
+ var updatedChild = update.parentNode.childNodes[updatedIndex];
+ var parentID = update.parentID;
+
+ ("production" !== process.env.NODE_ENV ? invariant(
+ updatedChild,
+ 'processUpdates(): Unable to find child %s of element. This ' +
+ 'probably means the DOM was unexpectedly mutated (e.g., by the ' +
+ 'browser), usually due to forgetting a <tbody> when using tables, ' +
+ 'nesting tags like <form>, <p>, or <a>, or using non-SVG elements '+
+ 'in an <svg> parent. Try inspecting the child nodes of the element ' +
+ 'with React ID `%s`.',
+ updatedIndex,
+ parentID
+ ) : invariant(updatedChild));
+
+ initialChildren = initialChildren || {};
+ initialChildren[parentID] = initialChildren[parentID] || [];
+ initialChildren[parentID][updatedIndex] = updatedChild;
+
+ updatedChildren = updatedChildren || [];
+ updatedChildren.push(updatedChild);
+ }
+ }
+
+ var renderedMarkup = Danger.dangerouslyRenderMarkup(markupList);
+
+ // Remove updated children first so that `toIndex` is consistent.
+ if (updatedChildren) {
+ for (var j = 0; j < updatedChildren.length; j++) {
+ updatedChildren[j].parentNode.removeChild(updatedChildren[j]);
+ }
+ }
+
+ for (var k = 0; update = updates[k]; k++) {
+ switch (update.type) {
+ case ReactMultiChildUpdateTypes.INSERT_MARKUP:
+ insertChildAt(
+ update.parentNode,
+ renderedMarkup[update.markupIndex],
+ update.toIndex
+ );
+ break;
+ case ReactMultiChildUpdateTypes.MOVE_EXISTING:
+ insertChildAt(
+ update.parentNode,
+ initialChildren[update.parentID][update.fromIndex],
+ update.toIndex
+ );
+ break;
+ case ReactMultiChildUpdateTypes.TEXT_CONTENT:
+ updateTextContent(
+ update.parentNode,
+ update.textContent
+ );
+ break;
+ case ReactMultiChildUpdateTypes.REMOVE_NODE:
+ // Already removed by the for-loop above.
+ break;
+ }
+ }
+ }
+
+};
+
+module.exports = DOMChildrenOperations;
+
+}).call(this,require('_process'))
+},{"./Danger":60,"./ReactMultiChildUpdateTypes":118,"./getTextContentAccessor":182,"./invariant":187,"_process":5}],58:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule DOMProperty
+ * @typechecks static-only
+ */
+
+/*jslint bitwise: true */
+
+"use strict";
+
+var invariant = require("./invariant");
+
+function checkMask(value, bitmask) {
+ return (value & bitmask) === bitmask;
+}
+
+var DOMPropertyInjection = {
+ /**
+ * Mapping from normalized, camelcased property names to a configuration that
+ * specifies how the associated DOM property should be accessed or rendered.
+ */
+ MUST_USE_ATTRIBUTE: 0x1,
+ MUST_USE_PROPERTY: 0x2,
+ HAS_SIDE_EFFECTS: 0x4,
+ HAS_BOOLEAN_VALUE: 0x8,
+ HAS_NUMERIC_VALUE: 0x10,
+ HAS_POSITIVE_NUMERIC_VALUE: 0x20 | 0x10,
+ HAS_OVERLOADED_BOOLEAN_VALUE: 0x40,
+
+ /**
+ * Inject some specialized knowledge about the DOM. This takes a config object
+ * with the following properties:
+ *
+ * isCustomAttribute: function that given an attribute name will return true
+ * if it can be inserted into the DOM verbatim. Useful for data-* or aria-*
+ * attributes where it's impossible to enumerate all of the possible
+ * attribute names,
+ *
+ * Properties: object mapping DOM property name to one of the
+ * DOMPropertyInjection constants or null. If your attribute isn't in here,
+ * it won't get written to the DOM.
+ *
+ * DOMAttributeNames: object mapping React attribute name to the DOM
+ * attribute name. Attribute names not specified use the **lowercase**
+ * normalized name.
+ *
+ * DOMPropertyNames: similar to DOMAttributeNames but for DOM properties.
+ * Property names not specified use the normalized name.
+ *
+ * DOMMutationMethods: Properties that require special mutation methods. If
+ * `value` is undefined, the mutation method should unset the property.
+ *
+ * @param {object} domPropertyConfig the config as described above.
+ */
+ injectDOMPropertyConfig: function(domPropertyConfig) {
+ var Properties = domPropertyConfig.Properties || {};
+ var DOMAttributeNames = domPropertyConfig.DOMAttributeNames || {};
+ var DOMPropertyNames = domPropertyConfig.DOMPropertyNames || {};
+ var DOMMutationMethods = domPropertyConfig.DOMMutationMethods || {};
+
+ if (domPropertyConfig.isCustomAttribute) {
+ DOMProperty._isCustomAttributeFunctions.push(
+ domPropertyConfig.isCustomAttribute
+ );
+ }
+
+ for (var propName in Properties) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !DOMProperty.isStandardName.hasOwnProperty(propName),
+ 'injectDOMPropertyConfig(...): You\'re trying to inject DOM property ' +
+ '\'%s\' which has already been injected. You may be accidentally ' +
+ 'injecting the same DOM property config twice, or you may be ' +
+ 'injecting two configs that have conflicting property names.',
+ propName
+ ) : invariant(!DOMProperty.isStandardName.hasOwnProperty(propName)));
+
+ DOMProperty.isStandardName[propName] = true;
+
+ var lowerCased = propName.toLowerCase();
+ DOMProperty.getPossibleStandardName[lowerCased] = propName;
+
+ if (DOMAttributeNames.hasOwnProperty(propName)) {
+ var attributeName = DOMAttributeNames[propName];
+ DOMProperty.getPossibleStandardName[attributeName] = propName;
+ DOMProperty.getAttributeName[propName] = attributeName;
+ } else {
+ DOMProperty.getAttributeName[propName] = lowerCased;
+ }
+
+ DOMProperty.getPropertyName[propName] =
+ DOMPropertyNames.hasOwnProperty(propName) ?
+ DOMPropertyNames[propName] :
+ propName;
+
+ if (DOMMutationMethods.hasOwnProperty(propName)) {
+ DOMProperty.getMutationMethod[propName] = DOMMutationMethods[propName];
+ } else {
+ DOMProperty.getMutationMethod[propName] = null;
+ }
+
+ var propConfig = Properties[propName];
+ DOMProperty.mustUseAttribute[propName] =
+ checkMask(propConfig, DOMPropertyInjection.MUST_USE_ATTRIBUTE);
+ DOMProperty.mustUseProperty[propName] =
+ checkMask(propConfig, DOMPropertyInjection.MUST_USE_PROPERTY);
+ DOMProperty.hasSideEffects[propName] =
+ checkMask(propConfig, DOMPropertyInjection.HAS_SIDE_EFFECTS);
+ DOMProperty.hasBooleanValue[propName] =
+ checkMask(propConfig, DOMPropertyInjection.HAS_BOOLEAN_VALUE);
+ DOMProperty.hasNumericValue[propName] =
+ checkMask(propConfig, DOMPropertyInjection.HAS_NUMERIC_VALUE);
+ DOMProperty.hasPositiveNumericValue[propName] =
+ checkMask(propConfig, DOMPropertyInjection.HAS_POSITIVE_NUMERIC_VALUE);
+ DOMProperty.hasOverloadedBooleanValue[propName] =
+ checkMask(propConfig, DOMPropertyInjection.HAS_OVERLOADED_BOOLEAN_VALUE);
+
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !DOMProperty.mustUseAttribute[propName] ||
+ !DOMProperty.mustUseProperty[propName],
+ 'DOMProperty: Cannot require using both attribute and property: %s',
+ propName
+ ) : invariant(!DOMProperty.mustUseAttribute[propName] ||
+ !DOMProperty.mustUseProperty[propName]));
+ ("production" !== process.env.NODE_ENV ? invariant(
+ DOMProperty.mustUseProperty[propName] ||
+ !DOMProperty.hasSideEffects[propName],
+ 'DOMProperty: Properties that have side effects must use property: %s',
+ propName
+ ) : invariant(DOMProperty.mustUseProperty[propName] ||
+ !DOMProperty.hasSideEffects[propName]));
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !!DOMProperty.hasBooleanValue[propName] +
+ !!DOMProperty.hasNumericValue[propName] +
+ !!DOMProperty.hasOverloadedBooleanValue[propName] <= 1,
+ 'DOMProperty: Value can be one of boolean, overloaded boolean, or ' +
+ 'numeric value, but not a combination: %s',
+ propName
+ ) : invariant(!!DOMProperty.hasBooleanValue[propName] +
+ !!DOMProperty.hasNumericValue[propName] +
+ !!DOMProperty.hasOverloadedBooleanValue[propName] <= 1));
+ }
+ }
+};
+var defaultValueCache = {};
+
+/**
+ * DOMProperty exports lookup objects that can be used like functions:
+ *
+ * > DOMProperty.isValid['id']
+ * true
+ * > DOMProperty.isValid['foobar']
+ * undefined
+ *
+ * Although this may be confusing, it performs better in general.
+ *
+ * @see http://jsperf.com/key-exists
+ * @see http://jsperf.com/key-missing
+ */
+var DOMProperty = {
+
+ ID_ATTRIBUTE_NAME: 'data-reactid',
+
+ /**
+ * Checks whether a property name is a standard property.
+ * @type {Object}
+ */
+ isStandardName: {},
+
+ /**
+ * Mapping from lowercase property names to the properly cased version, used
+ * to warn in the case of missing properties.
+ * @type {Object}
+ */
+ getPossibleStandardName: {},
+
+ /**
+ * Mapping from normalized names to attribute names that differ. Attribute
+ * names are used when rendering markup or with `*Attribute()`.
+ * @type {Object}
+ */
+ getAttributeName: {},
+
+ /**
+ * Mapping from normalized names to properties on DOM node instances.
+ * (This includes properties that mutate due to external factors.)
+ * @type {Object}
+ */
+ getPropertyName: {},
+
+ /**
+ * Mapping from normalized names to mutation methods. This will only exist if
+ * mutation cannot be set simply by the property or `setAttribute()`.
+ * @type {Object}
+ */
+ getMutationMethod: {},
+
+ /**
+ * Whether the property must be accessed and mutated as an object property.
+ * @type {Object}
+ */
+ mustUseAttribute: {},
+
+ /**
+ * Whether the property must be accessed and mutated using `*Attribute()`.
+ * (This includes anything that fails `<propName> in <element>`.)
+ * @type {Object}
+ */
+ mustUseProperty: {},
+
+ /**
+ * Whether or not setting a value causes side effects such as triggering
+ * resources to be loaded or text selection changes. We must ensure that
+ * the value is only set if it has changed.
+ * @type {Object}
+ */
+ hasSideEffects: {},
+
+ /**
+ * Whether the property should be removed when set to a falsey value.
+ * @type {Object}
+ */
+ hasBooleanValue: {},
+
+ /**
+ * Whether the property must be numeric or parse as a
+ * numeric and should be removed when set to a falsey value.
+ * @type {Object}
+ */
+ hasNumericValue: {},
+
+ /**
+ * Whether the property must be positive numeric or parse as a positive
+ * numeric and should be removed when set to a falsey value.
+ * @type {Object}
+ */
+ hasPositiveNumericValue: {},
+
+ /**
+ * Whether the property can be used as a flag as well as with a value. Removed
+ * when strictly equal to false; present without a value when strictly equal
+ * to true; present with a value otherwise.
+ * @type {Object}
+ */
+ hasOverloadedBooleanValue: {},
+
+ /**
+ * All of the isCustomAttribute() functions that have been injected.
+ */
+ _isCustomAttributeFunctions: [],
+
+ /**
+ * Checks whether a property name is a custom attribute.
+ * @method
+ */
+ isCustomAttribute: function(attributeName) {
+ for (var i = 0; i < DOMProperty._isCustomAttributeFunctions.length; i++) {
+ var isCustomAttributeFn = DOMProperty._isCustomAttributeFunctions[i];
+ if (isCustomAttributeFn(attributeName)) {
+ return true;
+ }
+ }
+ return false;
+ },
+
+ /**
+ * Returns the default property value for a DOM property (i.e., not an
+ * attribute). Most default values are '' or false, but not all. Worse yet,
+ * some (in particular, `type`) vary depending on the type of element.
+ *
+ * TODO: Is it better to grab all the possible properties when creating an
+ * element to avoid having to create the same element twice?
+ */
+ getDefaultValueForProperty: function(nodeName, prop) {
+ var nodeDefaults = defaultValueCache[nodeName];
+ var testElement;
+ if (!nodeDefaults) {
+ defaultValueCache[nodeName] = nodeDefaults = {};
+ }
+ if (!(prop in nodeDefaults)) {
+ testElement = document.createElement(nodeName);
+ nodeDefaults[prop] = testElement[prop];
+ }
+ return nodeDefaults[prop];
+ },
+
+ injection: DOMPropertyInjection
+};
+
+module.exports = DOMProperty;
+
+}).call(this,require('_process'))
+},{"./invariant":187,"_process":5}],59:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule DOMPropertyOperations
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var DOMProperty = require("./DOMProperty");
+
+var escapeTextForBrowser = require("./escapeTextForBrowser");
+var memoizeStringOnly = require("./memoizeStringOnly");
+var warning = require("./warning");
+
+function shouldIgnoreValue(name, value) {
+ return value == null ||
+ (DOMProperty.hasBooleanValue[name] && !value) ||
+ (DOMProperty.hasNumericValue[name] && isNaN(value)) ||
+ (DOMProperty.hasPositiveNumericValue[name] && (value < 1)) ||
+ (DOMProperty.hasOverloadedBooleanValue[name] && value === false);
+}
+
+var processAttributeNameAndPrefix = memoizeStringOnly(function(name) {
+ return escapeTextForBrowser(name) + '="';
+});
+
+if ("production" !== process.env.NODE_ENV) {
+ var reactProps = {
+ children: true,
+ dangerouslySetInnerHTML: true,
+ key: true,
+ ref: true
+ };
+ var warnedProperties = {};
+
+ var warnUnknownProperty = function(name) {
+ if (reactProps.hasOwnProperty(name) && reactProps[name] ||
+ warnedProperties.hasOwnProperty(name) && warnedProperties[name]) {
+ return;
+ }
+
+ warnedProperties[name] = true;
+ var lowerCasedName = name.toLowerCase();
+
+ // data-* attributes should be lowercase; suggest the lowercase version
+ var standardName = (
+ DOMProperty.isCustomAttribute(lowerCasedName) ?
+ lowerCasedName :
+ DOMProperty.getPossibleStandardName.hasOwnProperty(lowerCasedName) ?
+ DOMProperty.getPossibleStandardName[lowerCasedName] :
+ null
+ );
+
+ // For now, only warn when we have a suggested correction. This prevents
+ // logging too much when using transferPropsTo.
+ ("production" !== process.env.NODE_ENV ? warning(
+ standardName == null,
+ 'Unknown DOM property ' + name + '. Did you mean ' + standardName + '?'
+ ) : null);
+
+ };
+}
+
+/**
+ * Operations for dealing with DOM properties.
+ */
+var DOMPropertyOperations = {
+
+ /**
+ * Creates markup for the ID property.
+ *
+ * @param {string} id Unescaped ID.
+ * @return {string} Markup string.
+ */
+ createMarkupForID: function(id) {
+ return processAttributeNameAndPrefix(DOMProperty.ID_ATTRIBUTE_NAME) +
+ escapeTextForBrowser(id) + '"';
+ },
+
+ /**
+ * Creates markup for a property.
+ *
+ * @param {string} name
+ * @param {*} value
+ * @return {?string} Markup string, or null if the property was invalid.
+ */
+ createMarkupForProperty: function(name, value) {
+ if (DOMProperty.isStandardName.hasOwnProperty(name) &&
+ DOMProperty.isStandardName[name]) {
+ if (shouldIgnoreValue(name, value)) {
+ return '';
+ }
+ var attributeName = DOMProperty.getAttributeName[name];
+ if (DOMProperty.hasBooleanValue[name] ||
+ (DOMProperty.hasOverloadedBooleanValue[name] && value === true)) {
+ return escapeTextForBrowser(attributeName);
+ }
+ return processAttributeNameAndPrefix(attributeName) +
+ escapeTextForBrowser(value) + '"';
+ } else if (DOMProperty.isCustomAttribute(name)) {
+ if (value == null) {
+ return '';
+ }
+ return processAttributeNameAndPrefix(name) +
+ escapeTextForBrowser(value) + '"';
+ } else if ("production" !== process.env.NODE_ENV) {
+ warnUnknownProperty(name);
+ }
+ return null;
+ },
+
+ /**
+ * Sets the value for a property on a node.
+ *
+ * @param {DOMElement} node
+ * @param {string} name
+ * @param {*} value
+ */
+ setValueForProperty: function(node, name, value) {
+ if (DOMProperty.isStandardName.hasOwnProperty(name) &&
+ DOMProperty.isStandardName[name]) {
+ var mutationMethod = DOMProperty.getMutationMethod[name];
+ if (mutationMethod) {
+ mutationMethod(node, value);
+ } else if (shouldIgnoreValue(name, value)) {
+ this.deleteValueForProperty(node, name);
+ } else if (DOMProperty.mustUseAttribute[name]) {
+ // `setAttribute` with objects becomes only `[object]` in IE8/9,
+ // ('' + value) makes it output the correct toString()-value.
+ node.setAttribute(DOMProperty.getAttributeName[name], '' + value);
+ } else {
+ var propName = DOMProperty.getPropertyName[name];
+ // Must explicitly cast values for HAS_SIDE_EFFECTS-properties to the
+ // property type before comparing; only `value` does and is string.
+ if (!DOMProperty.hasSideEffects[name] ||
+ ('' + node[propName]) !== ('' + value)) {
+ // Contrary to `setAttribute`, object properties are properly
+ // `toString`ed by IE8/9.
+ node[propName] = value;
+ }
+ }
+ } else if (DOMProperty.isCustomAttribute(name)) {
+ if (value == null) {
+ node.removeAttribute(name);
+ } else {
+ node.setAttribute(name, '' + value);
+ }
+ } else if ("production" !== process.env.NODE_ENV) {
+ warnUnknownProperty(name);
+ }
+ },
+
+ /**
+ * Deletes the value for a property on a node.
+ *
+ * @param {DOMElement} node
+ * @param {string} name
+ */
+ deleteValueForProperty: function(node, name) {
+ if (DOMProperty.isStandardName.hasOwnProperty(name) &&
+ DOMProperty.isStandardName[name]) {
+ var mutationMethod = DOMProperty.getMutationMethod[name];
+ if (mutationMethod) {
+ mutationMethod(node, undefined);
+ } else if (DOMProperty.mustUseAttribute[name]) {
+ node.removeAttribute(DOMProperty.getAttributeName[name]);
+ } else {
+ var propName = DOMProperty.getPropertyName[name];
+ var defaultValue = DOMProperty.getDefaultValueForProperty(
+ node.nodeName,
+ propName
+ );
+ if (!DOMProperty.hasSideEffects[name] ||
+ ('' + node[propName]) !== defaultValue) {
+ node[propName] = defaultValue;
+ }
+ }
+ } else if (DOMProperty.isCustomAttribute(name)) {
+ node.removeAttribute(name);
+ } else if ("production" !== process.env.NODE_ENV) {
+ warnUnknownProperty(name);
+ }
+ }
+
+};
+
+module.exports = DOMPropertyOperations;
+
+}).call(this,require('_process'))
+},{"./DOMProperty":58,"./escapeTextForBrowser":170,"./memoizeStringOnly":196,"./warning":207,"_process":5}],60:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule Danger
+ * @typechecks static-only
+ */
+
+/*jslint evil: true, sub: true */
+
+"use strict";
+
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+
+var createNodesFromMarkup = require("./createNodesFromMarkup");
+var emptyFunction = require("./emptyFunction");
+var getMarkupWrap = require("./getMarkupWrap");
+var invariant = require("./invariant");
+
+var OPEN_TAG_NAME_EXP = /^(<[^ \/>]+)/;
+var RESULT_INDEX_ATTR = 'data-danger-index';
+
+/**
+ * Extracts the `nodeName` from a string of markup.
+ *
+ * NOTE: Extracting the `nodeName` does not require a regular expression match
+ * because we make assumptions about React-generated markup (i.e. there are no
+ * spaces surrounding the opening tag and there is at least one attribute).
+ *
+ * @param {string} markup String of markup.
+ * @return {string} Node name of the supplied markup.
+ * @see http://jsperf.com/extract-nodename
+ */
+function getNodeName(markup) {
+ return markup.substring(1, markup.indexOf(' '));
+}
+
+var Danger = {
+
+ /**
+ * Renders markup into an array of nodes. The markup is expected to render
+ * into a list of root nodes. Also, the length of `resultList` and
+ * `markupList` should be the same.
+ *
+ * @param {array<string>} markupList List of markup strings to render.
+ * @return {array<DOMElement>} List of rendered nodes.
+ * @internal
+ */
+ dangerouslyRenderMarkup: function(markupList) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ ExecutionEnvironment.canUseDOM,
+ 'dangerouslyRenderMarkup(...): Cannot render markup in a worker ' +
+ 'thread. Make sure `window` and `document` are available globally ' +
+ 'before requiring React when unit testing or use ' +
+ 'React.renderToString for server rendering.'
+ ) : invariant(ExecutionEnvironment.canUseDOM));
+ var nodeName;
+ var markupByNodeName = {};
+ // Group markup by `nodeName` if a wrap is necessary, else by '*'.
+ for (var i = 0; i < markupList.length; i++) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ markupList[i],
+ 'dangerouslyRenderMarkup(...): Missing markup.'
+ ) : invariant(markupList[i]));
+ nodeName = getNodeName(markupList[i]);
+ nodeName = getMarkupWrap(nodeName) ? nodeName : '*';
+ markupByNodeName[nodeName] = markupByNodeName[nodeName] || [];
+ markupByNodeName[nodeName][i] = markupList[i];
+ }
+ var resultList = [];
+ var resultListAssignmentCount = 0;
+ for (nodeName in markupByNodeName) {
+ if (!markupByNodeName.hasOwnProperty(nodeName)) {
+ continue;
+ }
+ var markupListByNodeName = markupByNodeName[nodeName];
+
+ // This for-in loop skips the holes of the sparse array. The order of
+ // iteration should follow the order of assignment, which happens to match
+ // numerical index order, but we don't rely on that.
+ for (var resultIndex in markupListByNodeName) {
+ if (markupListByNodeName.hasOwnProperty(resultIndex)) {
+ var markup = markupListByNodeName[resultIndex];
+
+ // Push the requested markup with an additional RESULT_INDEX_ATTR
+ // attribute. If the markup does not start with a < character, it
+ // will be discarded below (with an appropriate console.error).
+ markupListByNodeName[resultIndex] = markup.replace(
+ OPEN_TAG_NAME_EXP,
+ // This index will be parsed back out below.
+ '$1 ' + RESULT_INDEX_ATTR + '="' + resultIndex + '" '
+ );
+ }
+ }
+
+ // Render each group of markup with similar wrapping `nodeName`.
+ var renderNodes = createNodesFromMarkup(
+ markupListByNodeName.join(''),
+ emptyFunction // Do nothing special with <script> tags.
+ );
+
+ for (i = 0; i < renderNodes.length; ++i) {
+ var renderNode = renderNodes[i];
+ if (renderNode.hasAttribute &&
+ renderNode.hasAttribute(RESULT_INDEX_ATTR)) {
+
+ resultIndex = +renderNode.getAttribute(RESULT_INDEX_ATTR);
+ renderNode.removeAttribute(RESULT_INDEX_ATTR);
+
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !resultList.hasOwnProperty(resultIndex),
+ 'Danger: Assigning to an already-occupied result index.'
+ ) : invariant(!resultList.hasOwnProperty(resultIndex)));
+
+ resultList[resultIndex] = renderNode;
+
+ // This should match resultList.length and markupList.length when
+ // we're done.
+ resultListAssignmentCount += 1;
+
+ } else if ("production" !== process.env.NODE_ENV) {
+ console.error(
+ "Danger: Discarding unexpected node:",
+ renderNode
+ );
+ }
+ }
+ }
+
+ // Although resultList was populated out of order, it should now be a dense
+ // array.
+ ("production" !== process.env.NODE_ENV ? invariant(
+ resultListAssignmentCount === resultList.length,
+ 'Danger: Did not assign to every index of resultList.'
+ ) : invariant(resultListAssignmentCount === resultList.length));
+
+ ("production" !== process.env.NODE_ENV ? invariant(
+ resultList.length === markupList.length,
+ 'Danger: Expected markup to render %s nodes, but rendered %s.',
+ markupList.length,
+ resultList.length
+ ) : invariant(resultList.length === markupList.length));
+
+ return resultList;
+ },
+
+ /**
+ * Replaces a node with a string of markup at its current position within its
+ * parent. The markup must render into a single root node.
+ *
+ * @param {DOMElement} oldChild Child node to replace.
+ * @param {string} markup Markup to render in place of the child node.
+ * @internal
+ */
+ dangerouslyReplaceNodeWithMarkup: function(oldChild, markup) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ ExecutionEnvironment.canUseDOM,
+ 'dangerouslyReplaceNodeWithMarkup(...): Cannot render markup in a ' +
+ 'worker thread. Make sure `window` and `document` are available ' +
+ 'globally before requiring React when unit testing or use ' +
+ 'React.renderToString for server rendering.'
+ ) : invariant(ExecutionEnvironment.canUseDOM));
+ ("production" !== process.env.NODE_ENV ? invariant(markup, 'dangerouslyReplaceNodeWithMarkup(...): Missing markup.') : invariant(markup));
+ ("production" !== process.env.NODE_ENV ? invariant(
+ oldChild.tagName.toLowerCase() !== 'html',
+ 'dangerouslyReplaceNodeWithMarkup(...): Cannot replace markup of the ' +
+ '<html> node. This is because browser quirks make this unreliable ' +
+ 'and/or slow. If you want to render to the root you must use ' +
+ 'server rendering. See renderComponentToString().'
+ ) : invariant(oldChild.tagName.toLowerCase() !== 'html'));
+
+ var newChild = createNodesFromMarkup(markup, emptyFunction)[0];
+ oldChild.parentNode.replaceChild(newChild, oldChild);
+ }
+
+};
+
+module.exports = Danger;
+
+}).call(this,require('_process'))
+},{"./ExecutionEnvironment":69,"./createNodesFromMarkup":164,"./emptyFunction":168,"./getMarkupWrap":179,"./invariant":187,"_process":5}],61:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule DefaultEventPluginOrder
+ */
+
+"use strict";
+
+ var keyOf = require("./keyOf");
+
+/**
+ * Module that is injectable into `EventPluginHub`, that specifies a
+ * deterministic ordering of `EventPlugin`s. A convenient way to reason about
+ * plugins, without having to package every one of them. This is better than
+ * having plugins be ordered in the same order that they are injected because
+ * that ordering would be influenced by the packaging order.
+ * `ResponderEventPlugin` must occur before `SimpleEventPlugin` so that
+ * preventing default on events is convenient in `SimpleEventPlugin` handlers.
+ */
+var DefaultEventPluginOrder = [
+ keyOf({ResponderEventPlugin: null}),
+ keyOf({SimpleEventPlugin: null}),
+ keyOf({TapEventPlugin: null}),
+ keyOf({EnterLeaveEventPlugin: null}),
+ keyOf({ChangeEventPlugin: null}),
+ keyOf({SelectEventPlugin: null}),
+ keyOf({CompositionEventPlugin: null}),
+ keyOf({BeforeInputEventPlugin: null}),
+ keyOf({AnalyticsEventPlugin: null}),
+ keyOf({MobileSafariClickEventPlugin: null})
+];
+
+module.exports = DefaultEventPluginOrder;
+
+},{"./keyOf":194}],62:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule EnterLeaveEventPlugin
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var EventConstants = require("./EventConstants");
+var EventPropagators = require("./EventPropagators");
+var SyntheticMouseEvent = require("./SyntheticMouseEvent");
+
+var ReactMount = require("./ReactMount");
+var keyOf = require("./keyOf");
+
+var topLevelTypes = EventConstants.topLevelTypes;
+var getFirstReactDOM = ReactMount.getFirstReactDOM;
+
+var eventTypes = {
+ mouseEnter: {
+ registrationName: keyOf({onMouseEnter: null}),
+ dependencies: [
+ topLevelTypes.topMouseOut,
+ topLevelTypes.topMouseOver
+ ]
+ },
+ mouseLeave: {
+ registrationName: keyOf({onMouseLeave: null}),
+ dependencies: [
+ topLevelTypes.topMouseOut,
+ topLevelTypes.topMouseOver
+ ]
+ }
+};
+
+var extractedEvents = [null, null];
+
+var EnterLeaveEventPlugin = {
+
+ eventTypes: eventTypes,
+
+ /**
+ * For almost every interaction we care about, there will be both a top-level
+ * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that
+ * we do not extract duplicate events. However, moving the mouse into the
+ * browser from outside will not fire a `mouseout` event. In this case, we use
+ * the `mouseover` top-level event.
+ *
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {DOMEventTarget} topLevelTarget The listening component root node.
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
+ * @param {object} nativeEvent Native browser event.
+ * @return {*} An accumulation of synthetic events.
+ * @see {EventPluginHub.extractEvents}
+ */
+ extractEvents: function(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID,
+ nativeEvent) {
+ if (topLevelType === topLevelTypes.topMouseOver &&
+ (nativeEvent.relatedTarget || nativeEvent.fromElement)) {
+ return null;
+ }
+ if (topLevelType !== topLevelTypes.topMouseOut &&
+ topLevelType !== topLevelTypes.topMouseOver) {
+ // Must not be a mouse in or mouse out - ignoring.
+ return null;
+ }
+
+ var win;
+ if (topLevelTarget.window === topLevelTarget) {
+ // `topLevelTarget` is probably a window object.
+ win = topLevelTarget;
+ } else {
+ // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.
+ var doc = topLevelTarget.ownerDocument;
+ if (doc) {
+ win = doc.defaultView || doc.parentWindow;
+ } else {
+ win = window;
+ }
+ }
+
+ var from, to;
+ if (topLevelType === topLevelTypes.topMouseOut) {
+ from = topLevelTarget;
+ to =
+ getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement) ||
+ win;
+ } else {
+ from = win;
+ to = topLevelTarget;
+ }
+
+ if (from === to) {
+ // Nothing pertains to our managed components.
+ return null;
+ }
+
+ var fromID = from ? ReactMount.getID(from) : '';
+ var toID = to ? ReactMount.getID(to) : '';
+
+ var leave = SyntheticMouseEvent.getPooled(
+ eventTypes.mouseLeave,
+ fromID,
+ nativeEvent
+ );
+ leave.type = 'mouseleave';
+ leave.target = from;
+ leave.relatedTarget = to;
+
+ var enter = SyntheticMouseEvent.getPooled(
+ eventTypes.mouseEnter,
+ toID,
+ nativeEvent
+ );
+ enter.type = 'mouseenter';
+ enter.target = to;
+ enter.relatedTarget = from;
+
+ EventPropagators.accumulateEnterLeaveDispatches(leave, enter, fromID, toID);
+
+ extractedEvents[0] = leave;
+ extractedEvents[1] = enter;
+
+ return extractedEvents;
+ }
+
+};
+
+module.exports = EnterLeaveEventPlugin;
+
+},{"./EventConstants":63,"./EventPropagators":68,"./ReactMount":116,"./SyntheticMouseEvent":150,"./keyOf":194}],63:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule EventConstants
+ */
+
+"use strict";
+
+var keyMirror = require("./keyMirror");
+
+var PropagationPhases = keyMirror({bubbled: null, captured: null});
+
+/**
+ * Types of raw signals from the browser caught at the top level.
+ */
+var topLevelTypes = keyMirror({
+ topBlur: null,
+ topChange: null,
+ topClick: null,
+ topCompositionEnd: null,
+ topCompositionStart: null,
+ topCompositionUpdate: null,
+ topContextMenu: null,
+ topCopy: null,
+ topCut: null,
+ topDoubleClick: null,
+ topDrag: null,
+ topDragEnd: null,
+ topDragEnter: null,
+ topDragExit: null,
+ topDragLeave: null,
+ topDragOver: null,
+ topDragStart: null,
+ topDrop: null,
+ topError: null,
+ topFocus: null,
+ topInput: null,
+ topKeyDown: null,
+ topKeyPress: null,
+ topKeyUp: null,
+ topLoad: null,
+ topMouseDown: null,
+ topMouseMove: null,
+ topMouseOut: null,
+ topMouseOver: null,
+ topMouseUp: null,
+ topPaste: null,
+ topReset: null,
+ topScroll: null,
+ topSelectionChange: null,
+ topSubmit: null,
+ topTextInput: null,
+ topTouchCancel: null,
+ topTouchEnd: null,
+ topTouchMove: null,
+ topTouchStart: null,
+ topWheel: null
+});
+
+var EventConstants = {
+ topLevelTypes: topLevelTypes,
+ PropagationPhases: PropagationPhases
+};
+
+module.exports = EventConstants;
+
+},{"./keyMirror":193}],64:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014 Facebook, 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.
+ *
+ * @providesModule EventListener
+ * @typechecks
+ */
+
+var emptyFunction = require("./emptyFunction");
+
+/**
+ * Upstream version of event listener. Does not take into account specific
+ * nature of platform.
+ */
+var EventListener = {
+ /**
+ * Listen to DOM events during the bubble phase.
+ *
+ * @param {DOMEventTarget} target DOM element to register listener on.
+ * @param {string} eventType Event type, e.g. 'click' or 'mouseover'.
+ * @param {function} callback Callback function.
+ * @return {object} Object with a `remove` method.
+ */
+ listen: function(target, eventType, callback) {
+ if (target.addEventListener) {
+ target.addEventListener(eventType, callback, false);
+ return {
+ remove: function() {
+ target.removeEventListener(eventType, callback, false);
+ }
+ };
+ } else if (target.attachEvent) {
+ target.attachEvent('on' + eventType, callback);
+ return {
+ remove: function() {
+ target.detachEvent('on' + eventType, callback);
+ }
+ };
+ }
+ },
+
+ /**
+ * Listen to DOM events during the capture phase.
+ *
+ * @param {DOMEventTarget} target DOM element to register listener on.
+ * @param {string} eventType Event type, e.g. 'click' or 'mouseover'.
+ * @param {function} callback Callback function.
+ * @return {object} Object with a `remove` method.
+ */
+ capture: function(target, eventType, callback) {
+ if (!target.addEventListener) {
+ if ("production" !== process.env.NODE_ENV) {
+ console.error(
+ 'Attempted to listen to events during the capture phase on a ' +
+ 'browser that does not support the capture phase. Your application ' +
+ 'will not receive some events.'
+ );
+ }
+ return {
+ remove: emptyFunction
+ };
+ } else {
+ target.addEventListener(eventType, callback, true);
+ return {
+ remove: function() {
+ target.removeEventListener(eventType, callback, true);
+ }
+ };
+ }
+ },
+
+ registerDefault: function() {}
+};
+
+module.exports = EventListener;
+
+}).call(this,require('_process'))
+},{"./emptyFunction":168,"_process":5}],65:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule EventPluginHub
+ */
+
+"use strict";
+
+var EventPluginRegistry = require("./EventPluginRegistry");
+var EventPluginUtils = require("./EventPluginUtils");
+
+var accumulateInto = require("./accumulateInto");
+var forEachAccumulated = require("./forEachAccumulated");
+var invariant = require("./invariant");
+
+/**
+ * Internal store for event listeners
+ */
+var listenerBank = {};
+
+/**
+ * Internal queue of events that have accumulated their dispatches and are
+ * waiting to have their dispatches executed.
+ */
+var eventQueue = null;
+
+/**
+ * Dispatches an event and releases it back into the pool, unless persistent.
+ *
+ * @param {?object} event Synthetic event to be dispatched.
+ * @private
+ */
+var executeDispatchesAndRelease = function(event) {
+ if (event) {
+ var executeDispatch = EventPluginUtils.executeDispatch;
+ // Plugins can provide custom behavior when dispatching events.
+ var PluginModule = EventPluginRegistry.getPluginModuleForEvent(event);
+ if (PluginModule && PluginModule.executeDispatch) {
+ executeDispatch = PluginModule.executeDispatch;
+ }
+ EventPluginUtils.executeDispatchesInOrder(event, executeDispatch);
+
+ if (!event.isPersistent()) {
+ event.constructor.release(event);
+ }
+ }
+};
+
+/**
+ * - `InstanceHandle`: [required] Module that performs logical traversals of DOM
+ * hierarchy given ids of the logical DOM elements involved.
+ */
+var InstanceHandle = null;
+
+function validateInstanceHandle() {
+ var invalid = !InstanceHandle||
+ !InstanceHandle.traverseTwoPhase ||
+ !InstanceHandle.traverseEnterLeave;
+ if (invalid) {
+ throw new Error('InstanceHandle not injected before use!');
+ }
+}
+
+/**
+ * This is a unified interface for event plugins to be installed and configured.
+ *
+ * Event plugins can implement the following properties:
+ *
+ * `extractEvents` {function(string, DOMEventTarget, string, object): *}
+ * Required. When a top-level event is fired, this method is expected to
+ * extract synthetic events that will in turn be queued and dispatched.
+ *
+ * `eventTypes` {object}
+ * Optional, plugins that fire events must publish a mapping of registration
+ * names that are used to register listeners. Values of this mapping must
+ * be objects that contain `registrationName` or `phasedRegistrationNames`.
+ *
+ * `executeDispatch` {function(object, function, string)}
+ * Optional, allows plugins to override how an event gets dispatched. By
+ * default, the listener is simply invoked.
+ *
+ * Each plugin that is injected into `EventsPluginHub` is immediately operable.
+ *
+ * @public
+ */
+var EventPluginHub = {
+
+ /**
+ * Methods for injecting dependencies.
+ */
+ injection: {
+
+ /**
+ * @param {object} InjectedMount
+ * @public
+ */
+ injectMount: EventPluginUtils.injection.injectMount,
+
+ /**
+ * @param {object} InjectedInstanceHandle
+ * @public
+ */
+ injectInstanceHandle: function(InjectedInstanceHandle) {
+ InstanceHandle = InjectedInstanceHandle;
+ if ("production" !== process.env.NODE_ENV) {
+ validateInstanceHandle();
+ }
+ },
+
+ getInstanceHandle: function() {
+ if ("production" !== process.env.NODE_ENV) {
+ validateInstanceHandle();
+ }
+ return InstanceHandle;
+ },
+
+ /**
+ * @param {array} InjectedEventPluginOrder
+ * @public
+ */
+ injectEventPluginOrder: EventPluginRegistry.injectEventPluginOrder,
+
+ /**
+ * @param {object} injectedNamesToPlugins Map from names to plugin modules.
+ */
+ injectEventPluginsByName: EventPluginRegistry.injectEventPluginsByName
+
+ },
+
+ eventNameDispatchConfigs: EventPluginRegistry.eventNameDispatchConfigs,
+
+ registrationNameModules: EventPluginRegistry.registrationNameModules,
+
+ /**
+ * Stores `listener` at `listenerBank[registrationName][id]`. Is idempotent.
+ *
+ * @param {string} id ID of the DOM element.
+ * @param {string} registrationName Name of listener (e.g. `onClick`).
+ * @param {?function} listener The callback to store.
+ */
+ putListener: function(id, registrationName, listener) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !listener || typeof listener === 'function',
+ 'Expected %s listener to be a function, instead got type %s',
+ registrationName, typeof listener
+ ) : invariant(!listener || typeof listener === 'function'));
+
+ var bankForRegistrationName =
+ listenerBank[registrationName] || (listenerBank[registrationName] = {});
+ bankForRegistrationName[id] = listener;
+ },
+
+ /**
+ * @param {string} id ID of the DOM element.
+ * @param {string} registrationName Name of listener (e.g. `onClick`).
+ * @return {?function} The stored callback.
+ */
+ getListener: function(id, registrationName) {
+ var bankForRegistrationName = listenerBank[registrationName];
+ return bankForRegistrationName && bankForRegistrationName[id];
+ },
+
+ /**
+ * Deletes a listener from the registration bank.
+ *
+ * @param {string} id ID of the DOM element.
+ * @param {string} registrationName Name of listener (e.g. `onClick`).
+ */
+ deleteListener: function(id, registrationName) {
+ var bankForRegistrationName = listenerBank[registrationName];
+ if (bankForRegistrationName) {
+ delete bankForRegistrationName[id];
+ }
+ },
+
+ /**
+ * Deletes all listeners for the DOM element with the supplied ID.
+ *
+ * @param {string} id ID of the DOM element.
+ */
+ deleteAllListeners: function(id) {
+ for (var registrationName in listenerBank) {
+ delete listenerBank[registrationName][id];
+ }
+ },
+
+ /**
+ * Allows registered plugins an opportunity to extract events from top-level
+ * native browser events.
+ *
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {DOMEventTarget} topLevelTarget The listening component root node.
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
+ * @param {object} nativeEvent Native browser event.
+ * @return {*} An accumulation of synthetic events.
+ * @internal
+ */
+ extractEvents: function(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID,
+ nativeEvent) {
+ var events;
+ var plugins = EventPluginRegistry.plugins;
+ for (var i = 0, l = plugins.length; i < l; i++) {
+ // Not every plugin in the ordering may be loaded at runtime.
+ var possiblePlugin = plugins[i];
+ if (possiblePlugin) {
+ var extractedEvents = possiblePlugin.extractEvents(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID,
+ nativeEvent
+ );
+ if (extractedEvents) {
+ events = accumulateInto(events, extractedEvents);
+ }
+ }
+ }
+ return events;
+ },
+
+ /**
+ * Enqueues a synthetic event that should be dispatched when
+ * `processEventQueue` is invoked.
+ *
+ * @param {*} events An accumulation of synthetic events.
+ * @internal
+ */
+ enqueueEvents: function(events) {
+ if (events) {
+ eventQueue = accumulateInto(eventQueue, events);
+ }
+ },
+
+ /**
+ * Dispatches all synthetic events on the event queue.
+ *
+ * @internal
+ */
+ processEventQueue: function() {
+ // Set `eventQueue` to null before processing it so that we can tell if more
+ // events get enqueued while processing.
+ var processingEventQueue = eventQueue;
+ eventQueue = null;
+ forEachAccumulated(processingEventQueue, executeDispatchesAndRelease);
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !eventQueue,
+ 'processEventQueue(): Additional events were enqueued while processing ' +
+ 'an event queue. Support for this has not yet been implemented.'
+ ) : invariant(!eventQueue));
+ },
+
+ /**
+ * These are needed for tests only. Do not use!
+ */
+ __purge: function() {
+ listenerBank = {};
+ },
+
+ __getListenerBank: function() {
+ return listenerBank;
+ }
+
+};
+
+module.exports = EventPluginHub;
+
+}).call(this,require('_process'))
+},{"./EventPluginRegistry":66,"./EventPluginUtils":67,"./accumulateInto":156,"./forEachAccumulated":173,"./invariant":187,"_process":5}],66:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule EventPluginRegistry
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var invariant = require("./invariant");
+
+/**
+ * Injectable ordering of event plugins.
+ */
+var EventPluginOrder = null;
+
+/**
+ * Injectable mapping from names to event plugin modules.
+ */
+var namesToPlugins = {};
+
+/**
+ * Recomputes the plugin list using the injected plugins and plugin ordering.
+ *
+ * @private
+ */
+function recomputePluginOrdering() {
+ if (!EventPluginOrder) {
+ // Wait until an `EventPluginOrder` is injected.
+ return;
+ }
+ for (var pluginName in namesToPlugins) {
+ var PluginModule = namesToPlugins[pluginName];
+ var pluginIndex = EventPluginOrder.indexOf(pluginName);
+ ("production" !== process.env.NODE_ENV ? invariant(
+ pluginIndex > -1,
+ 'EventPluginRegistry: Cannot inject event plugins that do not exist in ' +
+ 'the plugin ordering, `%s`.',
+ pluginName
+ ) : invariant(pluginIndex > -1));
+ if (EventPluginRegistry.plugins[pluginIndex]) {
+ continue;
+ }
+ ("production" !== process.env.NODE_ENV ? invariant(
+ PluginModule.extractEvents,
+ 'EventPluginRegistry: Event plugins must implement an `extractEvents` ' +
+ 'method, but `%s` does not.',
+ pluginName
+ ) : invariant(PluginModule.extractEvents));
+ EventPluginRegistry.plugins[pluginIndex] = PluginModule;
+ var publishedEvents = PluginModule.eventTypes;
+ for (var eventName in publishedEvents) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ publishEventForPlugin(
+ publishedEvents[eventName],
+ PluginModule,
+ eventName
+ ),
+ 'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.',
+ eventName,
+ pluginName
+ ) : invariant(publishEventForPlugin(
+ publishedEvents[eventName],
+ PluginModule,
+ eventName
+ )));
+ }
+ }
+}
+
+/**
+ * Publishes an event so that it can be dispatched by the supplied plugin.
+ *
+ * @param {object} dispatchConfig Dispatch configuration for the event.
+ * @param {object} PluginModule Plugin publishing the event.
+ * @return {boolean} True if the event was successfully published.
+ * @private
+ */
+function publishEventForPlugin(dispatchConfig, PluginModule, eventName) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName),
+ 'EventPluginHub: More than one plugin attempted to publish the same ' +
+ 'event name, `%s`.',
+ eventName
+ ) : invariant(!EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName)));
+ EventPluginRegistry.eventNameDispatchConfigs[eventName] = dispatchConfig;
+
+ var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames;
+ if (phasedRegistrationNames) {
+ for (var phaseName in phasedRegistrationNames) {
+ if (phasedRegistrationNames.hasOwnProperty(phaseName)) {
+ var phasedRegistrationName = phasedRegistrationNames[phaseName];
+ publishRegistrationName(
+ phasedRegistrationName,
+ PluginModule,
+ eventName
+ );
+ }
+ }
+ return true;
+ } else if (dispatchConfig.registrationName) {
+ publishRegistrationName(
+ dispatchConfig.registrationName,
+ PluginModule,
+ eventName
+ );
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Publishes a registration name that is used to identify dispatched events and
+ * can be used with `EventPluginHub.putListener` to register listeners.
+ *
+ * @param {string} registrationName Registration name to add.
+ * @param {object} PluginModule Plugin publishing the event.
+ * @private
+ */
+function publishRegistrationName(registrationName, PluginModule, eventName) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !EventPluginRegistry.registrationNameModules[registrationName],
+ 'EventPluginHub: More than one plugin attempted to publish the same ' +
+ 'registration name, `%s`.',
+ registrationName
+ ) : invariant(!EventPluginRegistry.registrationNameModules[registrationName]));
+ EventPluginRegistry.registrationNameModules[registrationName] = PluginModule;
+ EventPluginRegistry.registrationNameDependencies[registrationName] =
+ PluginModule.eventTypes[eventName].dependencies;
+}
+
+/**
+ * Registers plugins so that they can extract and dispatch events.
+ *
+ * @see {EventPluginHub}
+ */
+var EventPluginRegistry = {
+
+ /**
+ * Ordered list of injected plugins.
+ */
+ plugins: [],
+
+ /**
+ * Mapping from event name to dispatch config
+ */
+ eventNameDispatchConfigs: {},
+
+ /**
+ * Mapping from registration name to plugin module
+ */
+ registrationNameModules: {},
+
+ /**
+ * Mapping from registration name to event name
+ */
+ registrationNameDependencies: {},
+
+ /**
+ * Injects an ordering of plugins (by plugin name). This allows the ordering
+ * to be decoupled from injection of the actual plugins so that ordering is
+ * always deterministic regardless of packaging, on-the-fly injection, etc.
+ *
+ * @param {array} InjectedEventPluginOrder
+ * @internal
+ * @see {EventPluginHub.injection.injectEventPluginOrder}
+ */
+ injectEventPluginOrder: function(InjectedEventPluginOrder) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !EventPluginOrder,
+ 'EventPluginRegistry: Cannot inject event plugin ordering more than ' +
+ 'once. You are likely trying to load more than one copy of React.'
+ ) : invariant(!EventPluginOrder));
+ // Clone the ordering so it cannot be dynamically mutated.
+ EventPluginOrder = Array.prototype.slice.call(InjectedEventPluginOrder);
+ recomputePluginOrdering();
+ },
+
+ /**
+ * Injects plugins to be used by `EventPluginHub`. The plugin names must be
+ * in the ordering injected by `injectEventPluginOrder`.
+ *
+ * Plugins can be injected as part of page initialization or on-the-fly.
+ *
+ * @param {object} injectedNamesToPlugins Map from names to plugin modules.
+ * @internal
+ * @see {EventPluginHub.injection.injectEventPluginsByName}
+ */
+ injectEventPluginsByName: function(injectedNamesToPlugins) {
+ var isOrderingDirty = false;
+ for (var pluginName in injectedNamesToPlugins) {
+ if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) {
+ continue;
+ }
+ var PluginModule = injectedNamesToPlugins[pluginName];
+ if (!namesToPlugins.hasOwnProperty(pluginName) ||
+ namesToPlugins[pluginName] !== PluginModule) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !namesToPlugins[pluginName],
+ 'EventPluginRegistry: Cannot inject two different event plugins ' +
+ 'using the same name, `%s`.',
+ pluginName
+ ) : invariant(!namesToPlugins[pluginName]));
+ namesToPlugins[pluginName] = PluginModule;
+ isOrderingDirty = true;
+ }
+ }
+ if (isOrderingDirty) {
+ recomputePluginOrdering();
+ }
+ },
+
+ /**
+ * Looks up the plugin for the supplied event.
+ *
+ * @param {object} event A synthetic event.
+ * @return {?object} The plugin that created the supplied event.
+ * @internal
+ */
+ getPluginModuleForEvent: function(event) {
+ var dispatchConfig = event.dispatchConfig;
+ if (dispatchConfig.registrationName) {
+ return EventPluginRegistry.registrationNameModules[
+ dispatchConfig.registrationName
+ ] || null;
+ }
+ for (var phase in dispatchConfig.phasedRegistrationNames) {
+ if (!dispatchConfig.phasedRegistrationNames.hasOwnProperty(phase)) {
+ continue;
+ }
+ var PluginModule = EventPluginRegistry.registrationNameModules[
+ dispatchConfig.phasedRegistrationNames[phase]
+ ];
+ if (PluginModule) {
+ return PluginModule;
+ }
+ }
+ return null;
+ },
+
+ /**
+ * Exposed for unit testing.
+ * @private
+ */
+ _resetEventPlugins: function() {
+ EventPluginOrder = null;
+ for (var pluginName in namesToPlugins) {
+ if (namesToPlugins.hasOwnProperty(pluginName)) {
+ delete namesToPlugins[pluginName];
+ }
+ }
+ EventPluginRegistry.plugins.length = 0;
+
+ var eventNameDispatchConfigs = EventPluginRegistry.eventNameDispatchConfigs;
+ for (var eventName in eventNameDispatchConfigs) {
+ if (eventNameDispatchConfigs.hasOwnProperty(eventName)) {
+ delete eventNameDispatchConfigs[eventName];
+ }
+ }
+
+ var registrationNameModules = EventPluginRegistry.registrationNameModules;
+ for (var registrationName in registrationNameModules) {
+ if (registrationNameModules.hasOwnProperty(registrationName)) {
+ delete registrationNameModules[registrationName];
+ }
+ }
+ }
+
+};
+
+module.exports = EventPluginRegistry;
+
+}).call(this,require('_process'))
+},{"./invariant":187,"_process":5}],67:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule EventPluginUtils
+ */
+
+"use strict";
+
+var EventConstants = require("./EventConstants");
+
+var invariant = require("./invariant");
+
+/**
+ * Injected dependencies:
+ */
+
+/**
+ * - `Mount`: [required] Module that can convert between React dom IDs and
+ * actual node references.
+ */
+var injection = {
+ Mount: null,
+ injectMount: function(InjectedMount) {
+ injection.Mount = InjectedMount;
+ if ("production" !== process.env.NODE_ENV) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ InjectedMount && InjectedMount.getNode,
+ 'EventPluginUtils.injection.injectMount(...): Injected Mount module ' +
+ 'is missing getNode.'
+ ) : invariant(InjectedMount && InjectedMount.getNode));
+ }
+ }
+};
+
+var topLevelTypes = EventConstants.topLevelTypes;
+
+function isEndish(topLevelType) {
+ return topLevelType === topLevelTypes.topMouseUp ||
+ topLevelType === topLevelTypes.topTouchEnd ||
+ topLevelType === topLevelTypes.topTouchCancel;
+}
+
+function isMoveish(topLevelType) {
+ return topLevelType === topLevelTypes.topMouseMove ||
+ topLevelType === topLevelTypes.topTouchMove;
+}
+function isStartish(topLevelType) {
+ return topLevelType === topLevelTypes.topMouseDown ||
+ topLevelType === topLevelTypes.topTouchStart;
+}
+
+
+var validateEventDispatches;
+if ("production" !== process.env.NODE_ENV) {
+ validateEventDispatches = function(event) {
+ var dispatchListeners = event._dispatchListeners;
+ var dispatchIDs = event._dispatchIDs;
+
+ var listenersIsArr = Array.isArray(dispatchListeners);
+ var idsIsArr = Array.isArray(dispatchIDs);
+ var IDsLen = idsIsArr ? dispatchIDs.length : dispatchIDs ? 1 : 0;
+ var listenersLen = listenersIsArr ?
+ dispatchListeners.length :
+ dispatchListeners ? 1 : 0;
+
+ ("production" !== process.env.NODE_ENV ? invariant(
+ idsIsArr === listenersIsArr && IDsLen === listenersLen,
+ 'EventPluginUtils: Invalid `event`.'
+ ) : invariant(idsIsArr === listenersIsArr && IDsLen === listenersLen));
+ };
+}
+
+/**
+ * Invokes `cb(event, listener, id)`. Avoids using call if no scope is
+ * provided. The `(listener,id)` pair effectively forms the "dispatch" but are
+ * kept separate to conserve memory.
+ */
+function forEachEventDispatch(event, cb) {
+ var dispatchListeners = event._dispatchListeners;
+ var dispatchIDs = event._dispatchIDs;
+ if ("production" !== process.env.NODE_ENV) {
+ validateEventDispatches(event);
+ }
+ if (Array.isArray(dispatchListeners)) {
+ for (var i = 0; i < dispatchListeners.length; i++) {
+ if (event.isPropagationStopped()) {
+ break;
+ }
+ // Listeners and IDs are two parallel arrays that are always in sync.
+ cb(event, dispatchListeners[i], dispatchIDs[i]);
+ }
+ } else if (dispatchListeners) {
+ cb(event, dispatchListeners, dispatchIDs);
+ }
+}
+
+/**
+ * Default implementation of PluginModule.executeDispatch().
+ * @param {SyntheticEvent} SyntheticEvent to handle
+ * @param {function} Application-level callback
+ * @param {string} domID DOM id to pass to the callback.
+ */
+function executeDispatch(event, listener, domID) {
+ event.currentTarget = injection.Mount.getNode(domID);
+ var returnValue = listener(event, domID);
+ event.currentTarget = null;
+ return returnValue;
+}
+
+/**
+ * Standard/simple iteration through an event's collected dispatches.
+ */
+function executeDispatchesInOrder(event, executeDispatch) {
+ forEachEventDispatch(event, executeDispatch);
+ event._dispatchListeners = null;
+ event._dispatchIDs = null;
+}
+
+/**
+ * Standard/simple iteration through an event's collected dispatches, but stops
+ * at the first dispatch execution returning true, and returns that id.
+ *
+ * @return id of the first dispatch execution who's listener returns true, or
+ * null if no listener returned true.
+ */
+function executeDispatchesInOrderStopAtTrueImpl(event) {
+ var dispatchListeners = event._dispatchListeners;
+ var dispatchIDs = event._dispatchIDs;
+ if ("production" !== process.env.NODE_ENV) {
+ validateEventDispatches(event);
+ }
+ if (Array.isArray(dispatchListeners)) {
+ for (var i = 0; i < dispatchListeners.length; i++) {
+ if (event.isPropagationStopped()) {
+ break;
+ }
+ // Listeners and IDs are two parallel arrays that are always in sync.
+ if (dispatchListeners[i](event, dispatchIDs[i])) {
+ return dispatchIDs[i];
+ }
+ }
+ } else if (dispatchListeners) {
+ if (dispatchListeners(event, dispatchIDs)) {
+ return dispatchIDs;
+ }
+ }
+ return null;
+}
+
+/**
+ * @see executeDispatchesInOrderStopAtTrueImpl
+ */
+function executeDispatchesInOrderStopAtTrue(event) {
+ var ret = executeDispatchesInOrderStopAtTrueImpl(event);
+ event._dispatchIDs = null;
+ event._dispatchListeners = null;
+ return ret;
+}
+
+/**
+ * Execution of a "direct" dispatch - there must be at most one dispatch
+ * accumulated on the event or it is considered an error. It doesn't really make
+ * sense for an event with multiple dispatches (bubbled) to keep track of the
+ * return values at each dispatch execution, but it does tend to make sense when
+ * dealing with "direct" dispatches.
+ *
+ * @return The return value of executing the single dispatch.
+ */
+function executeDirectDispatch(event) {
+ if ("production" !== process.env.NODE_ENV) {
+ validateEventDispatches(event);
+ }
+ var dispatchListener = event._dispatchListeners;
+ var dispatchID = event._dispatchIDs;
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !Array.isArray(dispatchListener),
+ 'executeDirectDispatch(...): Invalid `event`.'
+ ) : invariant(!Array.isArray(dispatchListener)));
+ var res = dispatchListener ?
+ dispatchListener(event, dispatchID) :
+ null;
+ event._dispatchListeners = null;
+ event._dispatchIDs = null;
+ return res;
+}
+
+/**
+ * @param {SyntheticEvent} event
+ * @return {bool} True iff number of dispatches accumulated is greater than 0.
+ */
+function hasDispatches(event) {
+ return !!event._dispatchListeners;
+}
+
+/**
+ * General utilities that are useful in creating custom Event Plugins.
+ */
+var EventPluginUtils = {
+ isEndish: isEndish,
+ isMoveish: isMoveish,
+ isStartish: isStartish,
+
+ executeDirectDispatch: executeDirectDispatch,
+ executeDispatch: executeDispatch,
+ executeDispatchesInOrder: executeDispatchesInOrder,
+ executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue,
+ hasDispatches: hasDispatches,
+ injection: injection,
+ useTouchEvents: false
+};
+
+module.exports = EventPluginUtils;
+
+}).call(this,require('_process'))
+},{"./EventConstants":63,"./invariant":187,"_process":5}],68:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule EventPropagators
+ */
+
+"use strict";
+
+var EventConstants = require("./EventConstants");
+var EventPluginHub = require("./EventPluginHub");
+
+var accumulateInto = require("./accumulateInto");
+var forEachAccumulated = require("./forEachAccumulated");
+
+var PropagationPhases = EventConstants.PropagationPhases;
+var getListener = EventPluginHub.getListener;
+
+/**
+ * Some event types have a notion of different registration names for different
+ * "phases" of propagation. This finds listeners by a given phase.
+ */
+function listenerAtPhase(id, event, propagationPhase) {
+ var registrationName =
+ event.dispatchConfig.phasedRegistrationNames[propagationPhase];
+ return getListener(id, registrationName);
+}
+
+/**
+ * Tags a `SyntheticEvent` with dispatched listeners. Creating this function
+ * here, allows us to not have to bind or create functions for each event.
+ * Mutating the event's members allows us to not have to create a wrapping
+ * "dispatch" object that pairs the event with the listener.
+ */
+function accumulateDirectionalDispatches(domID, upwards, event) {
+ if ("production" !== process.env.NODE_ENV) {
+ if (!domID) {
+ throw new Error('Dispatching id must not be null');
+ }
+ }
+ var phase = upwards ? PropagationPhases.bubbled : PropagationPhases.captured;
+ var listener = listenerAtPhase(domID, event, phase);
+ if (listener) {
+ event._dispatchListeners =
+ accumulateInto(event._dispatchListeners, listener);
+ event._dispatchIDs = accumulateInto(event._dispatchIDs, domID);
+ }
+}
+
+/**
+ * Collect dispatches (must be entirely collected before dispatching - see unit
+ * tests). Lazily allocate the array to conserve memory. We must loop through
+ * each event and perform the traversal for each one. We can not perform a
+ * single traversal for the entire collection of events because each event may
+ * have a different target.
+ */
+function accumulateTwoPhaseDispatchesSingle(event) {
+ if (event && event.dispatchConfig.phasedRegistrationNames) {
+ EventPluginHub.injection.getInstanceHandle().traverseTwoPhase(
+ event.dispatchMarker,
+ accumulateDirectionalDispatches,
+ event
+ );
+ }
+}
+
+
+/**
+ * Accumulates without regard to direction, does not look for phased
+ * registration names. Same as `accumulateDirectDispatchesSingle` but without
+ * requiring that the `dispatchMarker` be the same as the dispatched ID.
+ */
+function accumulateDispatches(id, ignoredDirection, event) {
+ if (event && event.dispatchConfig.registrationName) {
+ var registrationName = event.dispatchConfig.registrationName;
+ var listener = getListener(id, registrationName);
+ if (listener) {
+ event._dispatchListeners =
+ accumulateInto(event._dispatchListeners, listener);
+ event._dispatchIDs = accumulateInto(event._dispatchIDs, id);
+ }
+ }
+}
+
+/**
+ * Accumulates dispatches on an `SyntheticEvent`, but only for the
+ * `dispatchMarker`.
+ * @param {SyntheticEvent} event
+ */
+function accumulateDirectDispatchesSingle(event) {
+ if (event && event.dispatchConfig.registrationName) {
+ accumulateDispatches(event.dispatchMarker, null, event);
+ }
+}
+
+function accumulateTwoPhaseDispatches(events) {
+ forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle);
+}
+
+function accumulateEnterLeaveDispatches(leave, enter, fromID, toID) {
+ EventPluginHub.injection.getInstanceHandle().traverseEnterLeave(
+ fromID,
+ toID,
+ accumulateDispatches,
+ leave,
+ enter
+ );
+}
+
+
+function accumulateDirectDispatches(events) {
+ forEachAccumulated(events, accumulateDirectDispatchesSingle);
+}
+
+
+
+/**
+ * A small set of propagation patterns, each of which will accept a small amount
+ * of information, and generate a set of "dispatch ready event objects" - which
+ * are sets of events that have already been annotated with a set of dispatched
+ * listener functions/ids. The API is designed this way to discourage these
+ * propagation strategies from actually executing the dispatches, since we
+ * always want to collect the entire set of dispatches before executing event a
+ * single one.
+ *
+ * @constructor EventPropagators
+ */
+var EventPropagators = {
+ accumulateTwoPhaseDispatches: accumulateTwoPhaseDispatches,
+ accumulateDirectDispatches: accumulateDirectDispatches,
+ accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches
+};
+
+module.exports = EventPropagators;
+
+}).call(this,require('_process'))
+},{"./EventConstants":63,"./EventPluginHub":65,"./accumulateInto":156,"./forEachAccumulated":173,"_process":5}],69:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ExecutionEnvironment
+ */
+
+/*jslint evil: true */
+
+"use strict";
+
+var canUseDOM = !!(
+ typeof window !== 'undefined' &&
+ window.document &&
+ window.document.createElement
+);
+
+/**
+ * Simple, lightweight module assisting with the detection and context of
+ * Worker. Helps avoid circular dependencies and allows code to reason about
+ * whether or not they are in a Worker, even if they never include the main
+ * `ReactWorker` dependency.
+ */
+var ExecutionEnvironment = {
+
+ canUseDOM: canUseDOM,
+
+ canUseWorkers: typeof Worker !== 'undefined',
+
+ canUseEventListeners:
+ canUseDOM && !!(window.addEventListener || window.attachEvent),
+
+ canUseViewport: canUseDOM && !!window.screen,
+
+ isInWorker: !canUseDOM // For now, this is true - might change in the future.
+
+};
+
+module.exports = ExecutionEnvironment;
+
+},{}],70:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule HTMLDOMPropertyConfig
+ */
+
+/*jslint bitwise: true*/
+
+"use strict";
+
+var DOMProperty = require("./DOMProperty");
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+
+var MUST_USE_ATTRIBUTE = DOMProperty.injection.MUST_USE_ATTRIBUTE;
+var MUST_USE_PROPERTY = DOMProperty.injection.MUST_USE_PROPERTY;
+var HAS_BOOLEAN_VALUE = DOMProperty.injection.HAS_BOOLEAN_VALUE;
+var HAS_SIDE_EFFECTS = DOMProperty.injection.HAS_SIDE_EFFECTS;
+var HAS_NUMERIC_VALUE = DOMProperty.injection.HAS_NUMERIC_VALUE;
+var HAS_POSITIVE_NUMERIC_VALUE =
+ DOMProperty.injection.HAS_POSITIVE_NUMERIC_VALUE;
+var HAS_OVERLOADED_BOOLEAN_VALUE =
+ DOMProperty.injection.HAS_OVERLOADED_BOOLEAN_VALUE;
+
+var hasSVG;
+if (ExecutionEnvironment.canUseDOM) {
+ var implementation = document.implementation;
+ hasSVG = (
+ implementation &&
+ implementation.hasFeature &&
+ implementation.hasFeature(
+ 'http://www.w3.org/TR/SVG11/feature#BasicStructure',
+ '1.1'
+ )
+ );
+}
+
+
+var HTMLDOMPropertyConfig = {
+ isCustomAttribute: RegExp.prototype.test.bind(
+ /^(data|aria)-[a-z_][a-z\d_.\-]*$/
+ ),
+ Properties: {
+ /**
+ * Standard Properties
+ */
+ accept: null,
+ acceptCharset: null,
+ accessKey: null,
+ action: null,
+ allowFullScreen: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
+ allowTransparency: MUST_USE_ATTRIBUTE,
+ alt: null,
+ async: HAS_BOOLEAN_VALUE,
+ autoComplete: null,
+ // autoFocus is polyfilled/normalized by AutoFocusMixin
+ // autoFocus: HAS_BOOLEAN_VALUE,
+ autoPlay: HAS_BOOLEAN_VALUE,
+ cellPadding: null,
+ cellSpacing: null,
+ charSet: MUST_USE_ATTRIBUTE,
+ checked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+ classID: MUST_USE_ATTRIBUTE,
+ // To set className on SVG elements, it's necessary to use .setAttribute;
+ // this works on HTML elements too in all browsers except IE8. Conveniently,
+ // IE8 doesn't support SVG and so we can simply use the attribute in
+ // browsers that support SVG and the property in browsers that don't,
+ // regardless of whether the element is HTML or SVG.
+ className: hasSVG ? MUST_USE_ATTRIBUTE : MUST_USE_PROPERTY,
+ cols: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE,
+ colSpan: null,
+ content: null,
+ contentEditable: null,
+ contextMenu: MUST_USE_ATTRIBUTE,
+ controls: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+ coords: null,
+ crossOrigin: null,
+ data: null, // For `<object />` acts as `src`.
+ dateTime: MUST_USE_ATTRIBUTE,
+ defer: HAS_BOOLEAN_VALUE,
+ dir: null,
+ disabled: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
+ download: HAS_OVERLOADED_BOOLEAN_VALUE,
+ draggable: null,
+ encType: null,
+ form: MUST_USE_ATTRIBUTE,
+ formAction: MUST_USE_ATTRIBUTE,
+ formEncType: MUST_USE_ATTRIBUTE,
+ formMethod: MUST_USE_ATTRIBUTE,
+ formNoValidate: HAS_BOOLEAN_VALUE,
+ formTarget: MUST_USE_ATTRIBUTE,
+ frameBorder: MUST_USE_ATTRIBUTE,
+ height: MUST_USE_ATTRIBUTE,
+ hidden: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
+ href: null,
+ hrefLang: null,
+ htmlFor: null,
+ httpEquiv: null,
+ icon: null,
+ id: MUST_USE_PROPERTY,
+ label: null,
+ lang: null,
+ list: MUST_USE_ATTRIBUTE,
+ loop: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+ manifest: MUST_USE_ATTRIBUTE,
+ marginHeight: null,
+ marginWidth: null,
+ max: null,
+ maxLength: MUST_USE_ATTRIBUTE,
+ media: MUST_USE_ATTRIBUTE,
+ mediaGroup: null,
+ method: null,
+ min: null,
+ multiple: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+ muted: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+ name: null,
+ noValidate: HAS_BOOLEAN_VALUE,
+ open: null,
+ pattern: null,
+ placeholder: null,
+ poster: null,
+ preload: null,
+ radioGroup: null,
+ readOnly: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+ rel: null,
+ required: HAS_BOOLEAN_VALUE,
+ role: MUST_USE_ATTRIBUTE,
+ rows: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE,
+ rowSpan: null,
+ sandbox: null,
+ scope: null,
+ scrolling: null,
+ seamless: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
+ selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+ shape: null,
+ size: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE,
+ sizes: MUST_USE_ATTRIBUTE,
+ span: HAS_POSITIVE_NUMERIC_VALUE,
+ spellCheck: null,
+ src: null,
+ srcDoc: MUST_USE_PROPERTY,
+ srcSet: MUST_USE_ATTRIBUTE,
+ start: HAS_NUMERIC_VALUE,
+ step: null,
+ style: null,
+ tabIndex: null,
+ target: null,
+ title: null,
+ type: null,
+ useMap: null,
+ value: MUST_USE_PROPERTY | HAS_SIDE_EFFECTS,
+ width: MUST_USE_ATTRIBUTE,
+ wmode: MUST_USE_ATTRIBUTE,
+
+ /**
+ * Non-standard Properties
+ */
+ autoCapitalize: null, // Supported in Mobile Safari for keyboard hints
+ autoCorrect: null, // Supported in Mobile Safari for keyboard hints
+ itemProp: MUST_USE_ATTRIBUTE, // Microdata: http://schema.org/docs/gs.html
+ itemScope: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, // Microdata: http://schema.org/docs/gs.html
+ itemType: MUST_USE_ATTRIBUTE, // Microdata: http://schema.org/docs/gs.html
+ property: null // Supports OG in meta tags
+ },
+ DOMAttributeNames: {
+ acceptCharset: 'accept-charset',
+ className: 'class',
+ htmlFor: 'for',
+ httpEquiv: 'http-equiv'
+ },
+ DOMPropertyNames: {
+ autoCapitalize: 'autocapitalize',
+ autoComplete: 'autocomplete',
+ autoCorrect: 'autocorrect',
+ autoFocus: 'autofocus',
+ autoPlay: 'autoplay',
+ encType: 'enctype',
+ hrefLang: 'hreflang',
+ radioGroup: 'radiogroup',
+ spellCheck: 'spellcheck',
+ srcDoc: 'srcdoc',
+ srcSet: 'srcset'
+ }
+};
+
+module.exports = HTMLDOMPropertyConfig;
+
+},{"./DOMProperty":58,"./ExecutionEnvironment":69}],71:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule LinkedStateMixin
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var ReactLink = require("./ReactLink");
+var ReactStateSetters = require("./ReactStateSetters");
+
+/**
+ * A simple mixin around ReactLink.forState().
+ */
+var LinkedStateMixin = {
+ /**
+ * Create a ReactLink that's linked to part of this component's state. The
+ * ReactLink will have the current value of this.state[key] and will call
+ * setState() when a change is requested.
+ *
+ * @param {string} key state key to update. Note: you may want to use keyOf()
+ * if you're using Google Closure Compiler advanced mode.
+ * @return {ReactLink} ReactLink instance linking to the state.
+ */
+ linkState: function(key) {
+ return new ReactLink(
+ this.state[key],
+ ReactStateSetters.createStateKeySetter(this, key)
+ );
+ }
+};
+
+module.exports = LinkedStateMixin;
+
+},{"./ReactLink":114,"./ReactStateSetters":131}],72:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule LinkedValueUtils
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var ReactPropTypes = require("./ReactPropTypes");
+
+var invariant = require("./invariant");
+
+var hasReadOnlyValue = {
+ 'button': true,
+ 'checkbox': true,
+ 'image': true,
+ 'hidden': true,
+ 'radio': true,
+ 'reset': true,
+ 'submit': true
+};
+
+function _assertSingleLink(input) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ input.props.checkedLink == null || input.props.valueLink == null,
+ 'Cannot provide a checkedLink and a valueLink. If you want to use ' +
+ 'checkedLink, you probably don\'t want to use valueLink and vice versa.'
+ ) : invariant(input.props.checkedLink == null || input.props.valueLink == null));
+}
+function _assertValueLink(input) {
+ _assertSingleLink(input);
+ ("production" !== process.env.NODE_ENV ? invariant(
+ input.props.value == null && input.props.onChange == null,
+ 'Cannot provide a valueLink and a value or onChange event. If you want ' +
+ 'to use value or onChange, you probably don\'t want to use valueLink.'
+ ) : invariant(input.props.value == null && input.props.onChange == null));
+}
+
+function _assertCheckedLink(input) {
+ _assertSingleLink(input);
+ ("production" !== process.env.NODE_ENV ? invariant(
+ input.props.checked == null && input.props.onChange == null,
+ 'Cannot provide a checkedLink and a checked property or onChange event. ' +
+ 'If you want to use checked or onChange, you probably don\'t want to ' +
+ 'use checkedLink'
+ ) : invariant(input.props.checked == null && input.props.onChange == null));
+}
+
+/**
+ * @param {SyntheticEvent} e change event to handle
+ */
+function _handleLinkedValueChange(e) {
+ /*jshint validthis:true */
+ this.props.valueLink.requestChange(e.target.value);
+}
+
+/**
+ * @param {SyntheticEvent} e change event to handle
+ */
+function _handleLinkedCheckChange(e) {
+ /*jshint validthis:true */
+ this.props.checkedLink.requestChange(e.target.checked);
+}
+
+/**
+ * Provide a linked `value` attribute for controlled forms. You should not use
+ * this outside of the ReactDOM controlled form components.
+ */
+var LinkedValueUtils = {
+ Mixin: {
+ propTypes: {
+ value: function(props, propName, componentName) {
+ if (!props[propName] ||
+ hasReadOnlyValue[props.type] ||
+ props.onChange ||
+ props.readOnly ||
+ props.disabled) {
+ return;
+ }
+ return new Error(
+ 'You provided a `value` prop to a form field without an ' +
+ '`onChange` handler. This will render a read-only field. If ' +
+ 'the field should be mutable use `defaultValue`. Otherwise, ' +
+ 'set either `onChange` or `readOnly`.'
+ );
+ },
+ checked: function(props, propName, componentName) {
+ if (!props[propName] ||
+ props.onChange ||
+ props.readOnly ||
+ props.disabled) {
+ return;
+ }
+ return new Error(
+ 'You provided a `checked` prop to a form field without an ' +
+ '`onChange` handler. This will render a read-only field. If ' +
+ 'the field should be mutable use `defaultChecked`. Otherwise, ' +
+ 'set either `onChange` or `readOnly`.'
+ );
+ },
+ onChange: ReactPropTypes.func
+ }
+ },
+
+ /**
+ * @param {ReactComponent} input Form component
+ * @return {*} current value of the input either from value prop or link.
+ */
+ getValue: function(input) {
+ if (input.props.valueLink) {
+ _assertValueLink(input);
+ return input.props.valueLink.value;
+ }
+ return input.props.value;
+ },
+
+ /**
+ * @param {ReactComponent} input Form component
+ * @return {*} current checked status of the input either from checked prop
+ * or link.
+ */
+ getChecked: function(input) {
+ if (input.props.checkedLink) {
+ _assertCheckedLink(input);
+ return input.props.checkedLink.value;
+ }
+ return input.props.checked;
+ },
+
+ /**
+ * @param {ReactComponent} input Form component
+ * @return {function} change callback either from onChange prop or link.
+ */
+ getOnChange: function(input) {
+ if (input.props.valueLink) {
+ _assertValueLink(input);
+ return _handleLinkedValueChange;
+ } else if (input.props.checkedLink) {
+ _assertCheckedLink(input);
+ return _handleLinkedCheckChange;
+ }
+ return input.props.onChange;
+ }
+};
+
+module.exports = LinkedValueUtils;
+
+}).call(this,require('_process'))
+},{"./ReactPropTypes":125,"./invariant":187,"_process":5}],73:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule LocalEventTrapMixin
+ */
+
+"use strict";
+
+var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");
+
+var accumulateInto = require("./accumulateInto");
+var forEachAccumulated = require("./forEachAccumulated");
+var invariant = require("./invariant");
+
+function remove(event) {
+ event.remove();
+}
+
+var LocalEventTrapMixin = {
+ trapBubbledEvent:function(topLevelType, handlerBaseName) {
+ ("production" !== process.env.NODE_ENV ? invariant(this.isMounted(), 'Must be mounted to trap events') : invariant(this.isMounted()));
+ var listener = ReactBrowserEventEmitter.trapBubbledEvent(
+ topLevelType,
+ handlerBaseName,
+ this.getDOMNode()
+ );
+ this._localEventListeners =
+ accumulateInto(this._localEventListeners, listener);
+ },
+
+ // trapCapturedEvent would look nearly identical. We don't implement that
+ // method because it isn't currently needed.
+
+ componentWillUnmount:function() {
+ if (this._localEventListeners) {
+ forEachAccumulated(this._localEventListeners, remove);
+ }
+ }
+};
+
+module.exports = LocalEventTrapMixin;
+
+}).call(this,require('_process'))
+},{"./ReactBrowserEventEmitter":79,"./accumulateInto":156,"./forEachAccumulated":173,"./invariant":187,"_process":5}],74:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule MobileSafariClickEventPlugin
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var EventConstants = require("./EventConstants");
+
+var emptyFunction = require("./emptyFunction");
+
+var topLevelTypes = EventConstants.topLevelTypes;
+
+/**
+ * Mobile Safari does not fire properly bubble click events on non-interactive
+ * elements, which means delegated click listeners do not fire. The workaround
+ * for this bug involves attaching an empty click listener on the target node.
+ *
+ * This particular plugin works around the bug by attaching an empty click
+ * listener on `touchstart` (which does fire on every element).
+ */
+var MobileSafariClickEventPlugin = {
+
+ eventTypes: null,
+
+ /**
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {DOMEventTarget} topLevelTarget The listening component root node.
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
+ * @param {object} nativeEvent Native browser event.
+ * @return {*} An accumulation of synthetic events.
+ * @see {EventPluginHub.extractEvents}
+ */
+ extractEvents: function(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID,
+ nativeEvent) {
+ if (topLevelType === topLevelTypes.topTouchStart) {
+ var target = nativeEvent.target;
+ if (target && !target.onclick) {
+ target.onclick = emptyFunction;
+ }
+ }
+ }
+
+};
+
+module.exports = MobileSafariClickEventPlugin;
+
+},{"./EventConstants":63,"./emptyFunction":168}],75:[function(require,module,exports){
+/**
+ * Copyright 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule Object.assign
+ */
+
+// https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign
+
+function assign(target, sources) {
+ if (target == null) {
+ throw new TypeError('Object.assign target cannot be null or undefined');
+ }
+
+ var to = Object(target);
+ var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+ for (var nextIndex = 1; nextIndex < arguments.length; nextIndex++) {
+ var nextSource = arguments[nextIndex];
+ if (nextSource == null) {
+ continue;
+ }
+
+ var from = Object(nextSource);
+
+ // We don't currently support accessors nor proxies. Therefore this
+ // copy cannot throw. If we ever supported this then we must handle
+ // exceptions and side-effects. We don't support symbols so they won't
+ // be transferred.
+
+ for (var key in from) {
+ if (hasOwnProperty.call(from, key)) {
+ to[key] = from[key];
+ }
+ }
+ }
+
+ return to;
+};
+
+module.exports = assign;
+
+},{}],76:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule PooledClass
+ */
+
+"use strict";
+
+var invariant = require("./invariant");
+
+/**
+ * Static poolers. Several custom versions for each potential number of
+ * arguments. A completely generic pooler is easy to implement, but would
+ * require accessing the `arguments` object. In each of these, `this` refers to
+ * the Class itself, not an instance. If any others are needed, simply add them
+ * here, or in their own files.
+ */
+var oneArgumentPooler = function(copyFieldsFrom) {
+ var Klass = this;
+ if (Klass.instancePool.length) {
+ var instance = Klass.instancePool.pop();
+ Klass.call(instance, copyFieldsFrom);
+ return instance;
+ } else {
+ return new Klass(copyFieldsFrom);
+ }
+};
+
+var twoArgumentPooler = function(a1, a2) {
+ var Klass = this;
+ if (Klass.instancePool.length) {
+ var instance = Klass.instancePool.pop();
+ Klass.call(instance, a1, a2);
+ return instance;
+ } else {
+ return new Klass(a1, a2);
+ }
+};
+
+var threeArgumentPooler = function(a1, a2, a3) {
+ var Klass = this;
+ if (Klass.instancePool.length) {
+ var instance = Klass.instancePool.pop();
+ Klass.call(instance, a1, a2, a3);
+ return instance;
+ } else {
+ return new Klass(a1, a2, a3);
+ }
+};
+
+var fiveArgumentPooler = function(a1, a2, a3, a4, a5) {
+ var Klass = this;
+ if (Klass.instancePool.length) {
+ var instance = Klass.instancePool.pop();
+ Klass.call(instance, a1, a2, a3, a4, a5);
+ return instance;
+ } else {
+ return new Klass(a1, a2, a3, a4, a5);
+ }
+};
+
+var standardReleaser = function(instance) {
+ var Klass = this;
+ ("production" !== process.env.NODE_ENV ? invariant(
+ instance instanceof Klass,
+ 'Trying to release an instance into a pool of a different type.'
+ ) : invariant(instance instanceof Klass));
+ if (instance.destructor) {
+ instance.destructor();
+ }
+ if (Klass.instancePool.length < Klass.poolSize) {
+ Klass.instancePool.push(instance);
+ }
+};
+
+var DEFAULT_POOL_SIZE = 10;
+var DEFAULT_POOLER = oneArgumentPooler;
+
+/**
+ * Augments `CopyConstructor` to be a poolable class, augmenting only the class
+ * itself (statically) not adding any prototypical fields. Any CopyConstructor
+ * you give this may have a `poolSize` property, and will look for a
+ * prototypical `destructor` on instances (optional).
+ *
+ * @param {Function} CopyConstructor Constructor that can be used to reset.
+ * @param {Function} pooler Customizable pooler.
+ */
+var addPoolingTo = function(CopyConstructor, pooler) {
+ var NewKlass = CopyConstructor;
+ NewKlass.instancePool = [];
+ NewKlass.getPooled = pooler || DEFAULT_POOLER;
+ if (!NewKlass.poolSize) {
+ NewKlass.poolSize = DEFAULT_POOL_SIZE;
+ }
+ NewKlass.release = standardReleaser;
+ return NewKlass;
+};
+
+var PooledClass = {
+ addPoolingTo: addPoolingTo,
+ oneArgumentPooler: oneArgumentPooler,
+ twoArgumentPooler: twoArgumentPooler,
+ threeArgumentPooler: threeArgumentPooler,
+ fiveArgumentPooler: fiveArgumentPooler
+};
+
+module.exports = PooledClass;
+
+}).call(this,require('_process'))
+},{"./invariant":187,"_process":5}],77:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule React
+ */
+
+"use strict";
+
+var DOMPropertyOperations = require("./DOMPropertyOperations");
+var EventPluginUtils = require("./EventPluginUtils");
+var ReactChildren = require("./ReactChildren");
+var ReactComponent = require("./ReactComponent");
+var ReactCompositeComponent = require("./ReactCompositeComponent");
+var ReactContext = require("./ReactContext");
+var ReactCurrentOwner = require("./ReactCurrentOwner");
+var ReactElement = require("./ReactElement");
+var ReactElementValidator = require("./ReactElementValidator");
+var ReactDOM = require("./ReactDOM");
+var ReactDOMComponent = require("./ReactDOMComponent");
+var ReactDefaultInjection = require("./ReactDefaultInjection");
+var ReactInstanceHandles = require("./ReactInstanceHandles");
+var ReactLegacyElement = require("./ReactLegacyElement");
+var ReactMount = require("./ReactMount");
+var ReactMultiChild = require("./ReactMultiChild");
+var ReactPerf = require("./ReactPerf");
+var ReactPropTypes = require("./ReactPropTypes");
+var ReactServerRendering = require("./ReactServerRendering");
+var ReactTextComponent = require("./ReactTextComponent");
+
+var assign = require("./Object.assign");
+var deprecated = require("./deprecated");
+var onlyChild = require("./onlyChild");
+
+ReactDefaultInjection.inject();
+
+var createElement = ReactElement.createElement;
+var createFactory = ReactElement.createFactory;
+
+if ("production" !== process.env.NODE_ENV) {
+ createElement = ReactElementValidator.createElement;
+ createFactory = ReactElementValidator.createFactory;
+}
+
+// TODO: Drop legacy elements once classes no longer export these factories
+createElement = ReactLegacyElement.wrapCreateElement(
+ createElement
+);
+createFactory = ReactLegacyElement.wrapCreateFactory(
+ createFactory
+);
+
+var render = ReactPerf.measure('React', 'render', ReactMount.render);
+
+var React = {
+ Children: {
+ map: ReactChildren.map,
+ forEach: ReactChildren.forEach,
+ count: ReactChildren.count,
+ only: onlyChild
+ },
+ DOM: ReactDOM,
+ PropTypes: ReactPropTypes,
+ initializeTouchEvents: function(shouldUseTouch) {
+ EventPluginUtils.useTouchEvents = shouldUseTouch;
+ },
+ createClass: ReactCompositeComponent.createClass,
+ createElement: createElement,
+ createFactory: createFactory,
+ constructAndRenderComponent: ReactMount.constructAndRenderComponent,
+ constructAndRenderComponentByID: ReactMount.constructAndRenderComponentByID,
+ render: render,
+ renderToString: ReactServerRendering.renderToString,
+ renderToStaticMarkup: ReactServerRendering.renderToStaticMarkup,
+ unmountComponentAtNode: ReactMount.unmountComponentAtNode,
+ isValidClass: ReactLegacyElement.isValidClass,
+ isValidElement: ReactElement.isValidElement,
+ withContext: ReactContext.withContext,
+
+ // Hook for JSX spread, don't use this for anything else.
+ __spread: assign,
+
+ // Deprecations (remove for 0.13)
+ renderComponent: deprecated(
+ 'React',
+ 'renderComponent',
+ 'render',
+ this,
+ render
+ ),
+ renderComponentToString: deprecated(
+ 'React',
+ 'renderComponentToString',
+ 'renderToString',
+ this,
+ ReactServerRendering.renderToString
+ ),
+ renderComponentToStaticMarkup: deprecated(
+ 'React',
+ 'renderComponentToStaticMarkup',
+ 'renderToStaticMarkup',
+ this,
+ ReactServerRendering.renderToStaticMarkup
+ ),
+ isValidComponent: deprecated(
+ 'React',
+ 'isValidComponent',
+ 'isValidElement',
+ this,
+ ReactElement.isValidElement
+ )
+};
+
+// Inject the runtime into a devtools global hook regardless of browser.
+// Allows for debugging when the hook is injected on the page.
+if (
+ typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' &&
+ typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function') {
+ __REACT_DEVTOOLS_GLOBAL_HOOK__.inject({
+ Component: ReactComponent,
+ CurrentOwner: ReactCurrentOwner,
+ DOMComponent: ReactDOMComponent,
+ DOMPropertyOperations: DOMPropertyOperations,
+ InstanceHandles: ReactInstanceHandles,
+ Mount: ReactMount,
+ MultiChild: ReactMultiChild,
+ TextComponent: ReactTextComponent
+ });
+}
+
+if ("production" !== process.env.NODE_ENV) {
+ var ExecutionEnvironment = require("./ExecutionEnvironment");
+ if (ExecutionEnvironment.canUseDOM && window.top === window.self) {
+
+ // If we're in Chrome, look for the devtools marker and provide a download
+ // link if not installed.
+ if (navigator.userAgent.indexOf('Chrome') > -1) {
+ if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') {
+ console.debug(
+ 'Download the React DevTools for a better development experience: ' +
+ 'http://fb.me/react-devtools'
+ );
+ }
+ }
+
+ var expectedFeatures = [
+ // shims
+ Array.isArray,
+ Array.prototype.every,
+ Array.prototype.forEach,
+ Array.prototype.indexOf,
+ Array.prototype.map,
+ Date.now,
+ Function.prototype.bind,
+ Object.keys,
+ String.prototype.split,
+ String.prototype.trim,
+
+ // shams
+ Object.create,
+ Object.freeze
+ ];
+
+ for (var i = 0; i < expectedFeatures.length; i++) {
+ if (!expectedFeatures[i]) {
+ console.error(
+ 'One or more ES5 shim/shams expected by React are not available: ' +
+ 'http://fb.me/react-warning-polyfills'
+ );
+ break;
+ }
+ }
+ }
+}
+
+// Version exists only in the open-source version of React, not in Facebook's
+// internal version.
+React.version = '0.12.2';
+
+module.exports = React;
+
+}).call(this,require('_process'))
+},{"./DOMPropertyOperations":59,"./EventPluginUtils":67,"./ExecutionEnvironment":69,"./Object.assign":75,"./ReactChildren":82,"./ReactComponent":83,"./ReactCompositeComponent":86,"./ReactContext":87,"./ReactCurrentOwner":88,"./ReactDOM":89,"./ReactDOMComponent":91,"./ReactDefaultInjection":101,"./ReactElement":104,"./ReactElementValidator":105,"./ReactInstanceHandles":112,"./ReactLegacyElement":113,"./ReactMount":116,"./ReactMultiChild":117,"./ReactPerf":121,"./ReactPropTypes":125,"./ReactServerRendering":129,"./ReactTextComponent":133,"./deprecated":167,"./onlyChild":198,"_process":5}],78:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactBrowserComponentMixin
+ */
+
+"use strict";
+
+var ReactEmptyComponent = require("./ReactEmptyComponent");
+var ReactMount = require("./ReactMount");
+
+var invariant = require("./invariant");
+
+var ReactBrowserComponentMixin = {
+ /**
+ * Returns the DOM node rendered by this component.
+ *
+ * @return {DOMElement} The root node of this component.
+ * @final
+ * @protected
+ */
+ getDOMNode: function() {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ this.isMounted(),
+ 'getDOMNode(): A component must be mounted to have a DOM node.'
+ ) : invariant(this.isMounted()));
+ if (ReactEmptyComponent.isNullComponentID(this._rootNodeID)) {
+ return null;
+ }
+ return ReactMount.getNode(this._rootNodeID);
+ }
+};
+
+module.exports = ReactBrowserComponentMixin;
+
+}).call(this,require('_process'))
+},{"./ReactEmptyComponent":106,"./ReactMount":116,"./invariant":187,"_process":5}],79:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactBrowserEventEmitter
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var EventConstants = require("./EventConstants");
+var EventPluginHub = require("./EventPluginHub");
+var EventPluginRegistry = require("./EventPluginRegistry");
+var ReactEventEmitterMixin = require("./ReactEventEmitterMixin");
+var ViewportMetrics = require("./ViewportMetrics");
+
+var assign = require("./Object.assign");
+var isEventSupported = require("./isEventSupported");
+
+/**
+ * Summary of `ReactBrowserEventEmitter` event handling:
+ *
+ * - Top-level delegation is used to trap most native browser events. This
+ * may only occur in the main thread and is the responsibility of
+ * ReactEventListener, which is injected and can therefore support pluggable
+ * event sources. This is the only work that occurs in the main thread.
+ *
+ * - We normalize and de-duplicate events to account for browser quirks. This
+ * may be done in the worker thread.
+ *
+ * - Forward these native events (with the associated top-level type used to
+ * trap it) to `EventPluginHub`, which in turn will ask plugins if they want
+ * to extract any synthetic events.
+ *
+ * - The `EventPluginHub` will then process each event by annotating them with
+ * "dispatches", a sequence of listeners and IDs that care about that event.
+ *
+ * - The `EventPluginHub` then dispatches the events.
+ *
+ * Overview of React and the event system:
+ *
+ * +------------+ .
+ * | DOM | .
+ * +------------+ .
+ * | .
+ * v .
+ * +------------+ .
+ * | ReactEvent | .
+ * | Listener | .
+ * +------------+ . +-----------+
+ * | . +--------+|SimpleEvent|
+ * | . | |Plugin |
+ * +-----|------+ . v +-----------+
+ * | | | . +--------------+ +------------+
+ * | +-----------.--->|EventPluginHub| | Event |
+ * | | . | | +-----------+ | Propagators|
+ * | ReactEvent | . | | |TapEvent | |------------|
+ * | Emitter | . | |<---+|Plugin | |other plugin|
+ * | | . | | +-----------+ | utilities |
+ * | +-----------.--->| | +------------+
+ * | | | . +--------------+
+ * +-----|------+ . ^ +-----------+
+ * | . | |Enter/Leave|
+ * + . +-------+|Plugin |
+ * +-------------+ . +-----------+
+ * | application | .
+ * |-------------| .
+ * | | .
+ * | | .
+ * +-------------+ .
+ * .
+ * React Core . General Purpose Event Plugin System
+ */
+
+var alreadyListeningTo = {};
+var isMonitoringScrollValue = false;
+var reactTopListenersCounter = 0;
+
+// For events like 'submit' which don't consistently bubble (which we trap at a
+// lower node than `document`), binding at `document` would cause duplicate
+// events so we don't include them here
+var topEventMapping = {
+ topBlur: 'blur',
+ topChange: 'change',
+ topClick: 'click',
+ topCompositionEnd: 'compositionend',
+ topCompositionStart: 'compositionstart',
+ topCompositionUpdate: 'compositionupdate',
+ topContextMenu: 'contextmenu',
+ topCopy: 'copy',
+ topCut: 'cut',
+ topDoubleClick: 'dblclick',
+ topDrag: 'drag',
+ topDragEnd: 'dragend',
+ topDragEnter: 'dragenter',
+ topDragExit: 'dragexit',
+ topDragLeave: 'dragleave',
+ topDragOver: 'dragover',
+ topDragStart: 'dragstart',
+ topDrop: 'drop',
+ topFocus: 'focus',
+ topInput: 'input',
+ topKeyDown: 'keydown',
+ topKeyPress: 'keypress',
+ topKeyUp: 'keyup',
+ topMouseDown: 'mousedown',
+ topMouseMove: 'mousemove',
+ topMouseOut: 'mouseout',
+ topMouseOver: 'mouseover',
+ topMouseUp: 'mouseup',
+ topPaste: 'paste',
+ topScroll: 'scroll',
+ topSelectionChange: 'selectionchange',
+ topTextInput: 'textInput',
+ topTouchCancel: 'touchcancel',
+ topTouchEnd: 'touchend',
+ topTouchMove: 'touchmove',
+ topTouchStart: 'touchstart',
+ topWheel: 'wheel'
+};
+
+/**
+ * To ensure no conflicts with other potential React instances on the page
+ */
+var topListenersIDKey = "_reactListenersID" + String(Math.random()).slice(2);
+
+function getListeningForDocument(mountAt) {
+ // In IE8, `mountAt` is a host object and doesn't have `hasOwnProperty`
+ // directly.
+ if (!Object.prototype.hasOwnProperty.call(mountAt, topListenersIDKey)) {
+ mountAt[topListenersIDKey] = reactTopListenersCounter++;
+ alreadyListeningTo[mountAt[topListenersIDKey]] = {};
+ }
+ return alreadyListeningTo[mountAt[topListenersIDKey]];
+}
+
+/**
+ * `ReactBrowserEventEmitter` is used to attach top-level event listeners. For
+ * example:
+ *
+ * ReactBrowserEventEmitter.putListener('myID', 'onClick', myFunction);
+ *
+ * This would allocate a "registration" of `('onClick', myFunction)` on 'myID'.
+ *
+ * @internal
+ */
+var ReactBrowserEventEmitter = assign({}, ReactEventEmitterMixin, {
+
+ /**
+ * Injectable event backend
+ */
+ ReactEventListener: null,
+
+ injection: {
+ /**
+ * @param {object} ReactEventListener
+ */
+ injectReactEventListener: function(ReactEventListener) {
+ ReactEventListener.setHandleTopLevel(
+ ReactBrowserEventEmitter.handleTopLevel
+ );
+ ReactBrowserEventEmitter.ReactEventListener = ReactEventListener;
+ }
+ },
+
+ /**
+ * Sets whether or not any created callbacks should be enabled.
+ *
+ * @param {boolean} enabled True if callbacks should be enabled.
+ */
+ setEnabled: function(enabled) {
+ if (ReactBrowserEventEmitter.ReactEventListener) {
+ ReactBrowserEventEmitter.ReactEventListener.setEnabled(enabled);
+ }
+ },
+
+ /**
+ * @return {boolean} True if callbacks are enabled.
+ */
+ isEnabled: function() {
+ return !!(
+ ReactBrowserEventEmitter.ReactEventListener &&
+ ReactBrowserEventEmitter.ReactEventListener.isEnabled()
+ );
+ },
+
+ /**
+ * We listen for bubbled touch events on the document object.
+ *
+ * Firefox v8.01 (and possibly others) exhibited strange behavior when
+ * mounting `onmousemove` events at some node that was not the document
+ * element. The symptoms were that if your mouse is not moving over something
+ * contained within that mount point (for example on the background) the
+ * top-level listeners for `onmousemove` won't be called. However, if you
+ * register the `mousemove` on the document object, then it will of course
+ * catch all `mousemove`s. This along with iOS quirks, justifies restricting
+ * top-level listeners to the document object only, at least for these
+ * movement types of events and possibly all events.
+ *
+ * @see http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html
+ *
+ * Also, `keyup`/`keypress`/`keydown` do not bubble to the window on IE, but
+ * they bubble to document.
+ *
+ * @param {string} registrationName Name of listener (e.g. `onClick`).
+ * @param {object} contentDocumentHandle Document which owns the container
+ */
+ listenTo: function(registrationName, contentDocumentHandle) {
+ var mountAt = contentDocumentHandle;
+ var isListening = getListeningForDocument(mountAt);
+ var dependencies = EventPluginRegistry.
+ registrationNameDependencies[registrationName];
+
+ var topLevelTypes = EventConstants.topLevelTypes;
+ for (var i = 0, l = dependencies.length; i < l; i++) {
+ var dependency = dependencies[i];
+ if (!(
+ isListening.hasOwnProperty(dependency) &&
+ isListening[dependency]
+ )) {
+ if (dependency === topLevelTypes.topWheel) {
+ if (isEventSupported('wheel')) {
+ ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+ topLevelTypes.topWheel,
+ 'wheel',
+ mountAt
+ );
+ } else if (isEventSupported('mousewheel')) {
+ ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+ topLevelTypes.topWheel,
+ 'mousewheel',
+ mountAt
+ );
+ } else {
+ // Firefox needs to capture a different mouse scroll event.
+ // @see http://www.quirksmode.org/dom/events/tests/scroll.html
+ ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+ topLevelTypes.topWheel,
+ 'DOMMouseScroll',
+ mountAt
+ );
+ }
+ } else if (dependency === topLevelTypes.topScroll) {
+
+ if (isEventSupported('scroll', true)) {
+ ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
+ topLevelTypes.topScroll,
+ 'scroll',
+ mountAt
+ );
+ } else {
+ ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+ topLevelTypes.topScroll,
+ 'scroll',
+ ReactBrowserEventEmitter.ReactEventListener.WINDOW_HANDLE
+ );
+ }
+ } else if (dependency === topLevelTypes.topFocus ||
+ dependency === topLevelTypes.topBlur) {
+
+ if (isEventSupported('focus', true)) {
+ ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
+ topLevelTypes.topFocus,
+ 'focus',
+ mountAt
+ );
+ ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
+ topLevelTypes.topBlur,
+ 'blur',
+ mountAt
+ );
+ } else if (isEventSupported('focusin')) {
+ // IE has `focusin` and `focusout` events which bubble.
+ // @see http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
+ ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+ topLevelTypes.topFocus,
+ 'focusin',
+ mountAt
+ );
+ ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+ topLevelTypes.topBlur,
+ 'focusout',
+ mountAt
+ );
+ }
+
+ // to make sure blur and focus event listeners are only attached once
+ isListening[topLevelTypes.topBlur] = true;
+ isListening[topLevelTypes.topFocus] = true;
+ } else if (topEventMapping.hasOwnProperty(dependency)) {
+ ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+ dependency,
+ topEventMapping[dependency],
+ mountAt
+ );
+ }
+
+ isListening[dependency] = true;
+ }
+ }
+ },
+
+ trapBubbledEvent: function(topLevelType, handlerBaseName, handle) {
+ return ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+ topLevelType,
+ handlerBaseName,
+ handle
+ );
+ },
+
+ trapCapturedEvent: function(topLevelType, handlerBaseName, handle) {
+ return ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
+ topLevelType,
+ handlerBaseName,
+ handle
+ );
+ },
+
+ /**
+ * Listens to window scroll and resize events. We cache scroll values so that
+ * application code can access them without triggering reflows.
+ *
+ * NOTE: Scroll events do not bubble.
+ *
+ * @see http://www.quirksmode.org/dom/events/scroll.html
+ */
+ ensureScrollValueMonitoring: function(){
+ if (!isMonitoringScrollValue) {
+ var refresh = ViewportMetrics.refreshScrollValues;
+ ReactBrowserEventEmitter.ReactEventListener.monitorScrollValue(refresh);
+ isMonitoringScrollValue = true;
+ }
+ },
+
+ eventNameDispatchConfigs: EventPluginHub.eventNameDispatchConfigs,
+
+ registrationNameModules: EventPluginHub.registrationNameModules,
+
+ putListener: EventPluginHub.putListener,
+
+ getListener: EventPluginHub.getListener,
+
+ deleteListener: EventPluginHub.deleteListener,
+
+ deleteAllListeners: EventPluginHub.deleteAllListeners
+
+});
+
+module.exports = ReactBrowserEventEmitter;
+
+},{"./EventConstants":63,"./EventPluginHub":65,"./EventPluginRegistry":66,"./Object.assign":75,"./ReactEventEmitterMixin":108,"./ViewportMetrics":155,"./isEventSupported":188}],80:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @typechecks
+ * @providesModule ReactCSSTransitionGroup
+ */
+
+"use strict";
+
+var React = require("./React");
+
+var assign = require("./Object.assign");
+
+var ReactTransitionGroup = React.createFactory(
+ require("./ReactTransitionGroup")
+);
+var ReactCSSTransitionGroupChild = React.createFactory(
+ require("./ReactCSSTransitionGroupChild")
+);
+
+var ReactCSSTransitionGroup = React.createClass({
+ displayName: 'ReactCSSTransitionGroup',
+
+ propTypes: {
+ transitionName: React.PropTypes.string.isRequired,
+ transitionEnter: React.PropTypes.bool,
+ transitionLeave: React.PropTypes.bool
+ },
+
+ getDefaultProps: function() {
+ return {
+ transitionEnter: true,
+ transitionLeave: true
+ };
+ },
+
+ _wrapChild: function(child) {
+ // We need to provide this childFactory so that
+ // ReactCSSTransitionGroupChild can receive updates to name, enter, and
+ // leave while it is leaving.
+ return ReactCSSTransitionGroupChild(
+ {
+ name: this.props.transitionName,
+ enter: this.props.transitionEnter,
+ leave: this.props.transitionLeave
+ },
+ child
+ );
+ },
+
+ render: function() {
+ return (
+ ReactTransitionGroup(
+ assign({}, this.props, {childFactory: this._wrapChild})
+ )
+ );
+ }
+});
+
+module.exports = ReactCSSTransitionGroup;
+
+},{"./Object.assign":75,"./React":77,"./ReactCSSTransitionGroupChild":81,"./ReactTransitionGroup":136}],81:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @typechecks
+ * @providesModule ReactCSSTransitionGroupChild
+ */
+
+"use strict";
+
+var React = require("./React");
+
+var CSSCore = require("./CSSCore");
+var ReactTransitionEvents = require("./ReactTransitionEvents");
+
+var onlyChild = require("./onlyChild");
+
+// We don't remove the element from the DOM until we receive an animationend or
+// transitionend event. If the user screws up and forgets to add an animation
+// their node will be stuck in the DOM forever, so we detect if an animation
+// does not start and if it doesn't, we just call the end listener immediately.
+var TICK = 17;
+var NO_EVENT_TIMEOUT = 5000;
+
+var noEventListener = null;
+
+
+if ("production" !== process.env.NODE_ENV) {
+ noEventListener = function() {
+ console.warn(
+ 'transition(): tried to perform an animation without ' +
+ 'an animationend or transitionend event after timeout (' +
+ NO_EVENT_TIMEOUT + 'ms). You should either disable this ' +
+ 'transition in JS or add a CSS animation/transition.'
+ );
+ };
+}
+
+var ReactCSSTransitionGroupChild = React.createClass({
+ displayName: 'ReactCSSTransitionGroupChild',
+
+ transition: function(animationType, finishCallback) {
+ var node = this.getDOMNode();
+ var className = this.props.name + '-' + animationType;
+ var activeClassName = className + '-active';
+ var noEventTimeout = null;
+
+ var endListener = function(e) {
+ if (e && e.target !== node) {
+ return;
+ }
+ if ("production" !== process.env.NODE_ENV) {
+ clearTimeout(noEventTimeout);
+ }
+
+ CSSCore.removeClass(node, className);
+ CSSCore.removeClass(node, activeClassName);
+
+ ReactTransitionEvents.removeEndEventListener(node, endListener);
+
+ // Usually this optional callback is used for informing an owner of
+ // a leave animation and telling it to remove the child.
+ finishCallback && finishCallback();
+ };
+
+ ReactTransitionEvents.addEndEventListener(node, endListener);
+
+ CSSCore.addClass(node, className);
+
+ // Need to do this to actually trigger a transition.
+ this.queueClass(activeClassName);
+
+ if ("production" !== process.env.NODE_ENV) {
+ noEventTimeout = setTimeout(noEventListener, NO_EVENT_TIMEOUT);
+ }
+ },
+
+ queueClass: function(className) {
+ this.classNameQueue.push(className);
+
+ if (!this.timeout) {
+ this.timeout = setTimeout(this.flushClassNameQueue, TICK);
+ }
+ },
+
+ flushClassNameQueue: function() {
+ if (this.isMounted()) {
+ this.classNameQueue.forEach(
+ CSSCore.addClass.bind(CSSCore, this.getDOMNode())
+ );
+ }
+ this.classNameQueue.length = 0;
+ this.timeout = null;
+ },
+
+ componentWillMount: function() {
+ this.classNameQueue = [];
+ },
+
+ componentWillUnmount: function() {
+ if (this.timeout) {
+ clearTimeout(this.timeout);
+ }
+ },
+
+ componentWillEnter: function(done) {
+ if (this.props.enter) {
+ this.transition('enter', done);
+ } else {
+ done();
+ }
+ },
+
+ componentWillLeave: function(done) {
+ if (this.props.leave) {
+ this.transition('leave', done);
+ } else {
+ done();
+ }
+ },
+
+ render: function() {
+ return onlyChild(this.props.children);
+ }
+});
+
+module.exports = ReactCSSTransitionGroupChild;
+
+}).call(this,require('_process'))
+},{"./CSSCore":50,"./React":77,"./ReactTransitionEvents":135,"./onlyChild":198,"_process":5}],82:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactChildren
+ */
+
+"use strict";
+
+var PooledClass = require("./PooledClass");
+
+var traverseAllChildren = require("./traverseAllChildren");
+var warning = require("./warning");
+
+var twoArgumentPooler = PooledClass.twoArgumentPooler;
+var threeArgumentPooler = PooledClass.threeArgumentPooler;
+
+/**
+ * PooledClass representing the bookkeeping associated with performing a child
+ * traversal. Allows avoiding binding callbacks.
+ *
+ * @constructor ForEachBookKeeping
+ * @param {!function} forEachFunction Function to perform traversal with.
+ * @param {?*} forEachContext Context to perform context with.
+ */
+function ForEachBookKeeping(forEachFunction, forEachContext) {
+ this.forEachFunction = forEachFunction;
+ this.forEachContext = forEachContext;
+}
+PooledClass.addPoolingTo(ForEachBookKeeping, twoArgumentPooler);
+
+function forEachSingleChild(traverseContext, child, name, i) {
+ var forEachBookKeeping = traverseContext;
+ forEachBookKeeping.forEachFunction.call(
+ forEachBookKeeping.forEachContext, child, i);
+}
+
+/**
+ * Iterates through children that are typically specified as `props.children`.
+ *
+ * The provided forEachFunc(child, index) will be called for each
+ * leaf child.
+ *
+ * @param {?*} children Children tree container.
+ * @param {function(*, int)} forEachFunc.
+ * @param {*} forEachContext Context for forEachContext.
+ */
+function forEachChildren(children, forEachFunc, forEachContext) {
+ if (children == null) {
+ return children;
+ }
+
+ var traverseContext =
+ ForEachBookKeeping.getPooled(forEachFunc, forEachContext);
+ traverseAllChildren(children, forEachSingleChild, traverseContext);
+ ForEachBookKeeping.release(traverseContext);
+}
+
+/**
+ * PooledClass representing the bookkeeping associated with performing a child
+ * mapping. Allows avoiding binding callbacks.
+ *
+ * @constructor MapBookKeeping
+ * @param {!*} mapResult Object containing the ordered map of results.
+ * @param {!function} mapFunction Function to perform mapping with.
+ * @param {?*} mapContext Context to perform mapping with.
+ */
+function MapBookKeeping(mapResult, mapFunction, mapContext) {
+ this.mapResult = mapResult;
+ this.mapFunction = mapFunction;
+ this.mapContext = mapContext;
+}
+PooledClass.addPoolingTo(MapBookKeeping, threeArgumentPooler);
+
+function mapSingleChildIntoContext(traverseContext, child, name, i) {
+ var mapBookKeeping = traverseContext;
+ var mapResult = mapBookKeeping.mapResult;
+
+ var keyUnique = !mapResult.hasOwnProperty(name);
+ ("production" !== process.env.NODE_ENV ? warning(
+ keyUnique,
+ 'ReactChildren.map(...): Encountered two children with the same key, ' +
+ '`%s`. Child keys must be unique; when two children share a key, only ' +
+ 'the first child will be used.',
+ name
+ ) : null);
+
+ if (keyUnique) {
+ var mappedChild =
+ mapBookKeeping.mapFunction.call(mapBookKeeping.mapContext, child, i);
+ mapResult[name] = mappedChild;
+ }
+}
+
+/**
+ * Maps children that are typically specified as `props.children`.
+ *
+ * The provided mapFunction(child, key, index) will be called for each
+ * leaf child.
+ *
+ * TODO: This may likely break any calls to `ReactChildren.map` that were
+ * previously relying on the fact that we guarded against null children.
+ *
+ * @param {?*} children Children tree container.
+ * @param {function(*, int)} mapFunction.
+ * @param {*} mapContext Context for mapFunction.
+ * @return {object} Object containing the ordered map of results.
+ */
+function mapChildren(children, func, context) {
+ if (children == null) {
+ return children;
+ }
+
+ var mapResult = {};
+ var traverseContext = MapBookKeeping.getPooled(mapResult, func, context);
+ traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);
+ MapBookKeeping.release(traverseContext);
+ return mapResult;
+}
+
+function forEachSingleChildDummy(traverseContext, child, name, i) {
+ return null;
+}
+
+/**
+ * Count the number of children that are typically specified as
+ * `props.children`.
+ *
+ * @param {?*} children Children tree container.
+ * @return {number} The number of children.
+ */
+function countChildren(children, context) {
+ return traverseAllChildren(children, forEachSingleChildDummy, null);
+}
+
+var ReactChildren = {
+ forEach: forEachChildren,
+ map: mapChildren,
+ count: countChildren
+};
+
+module.exports = ReactChildren;
+
+}).call(this,require('_process'))
+},{"./PooledClass":76,"./traverseAllChildren":205,"./warning":207,"_process":5}],83:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactComponent
+ */
+
+"use strict";
+
+var ReactElement = require("./ReactElement");
+var ReactOwner = require("./ReactOwner");
+var ReactUpdates = require("./ReactUpdates");
+
+var assign = require("./Object.assign");
+var invariant = require("./invariant");
+var keyMirror = require("./keyMirror");
+
+/**
+ * Every React component is in one of these life cycles.
+ */
+var ComponentLifeCycle = keyMirror({
+ /**
+ * Mounted components have a DOM node representation and are capable of
+ * receiving new props.
+ */
+ MOUNTED: null,
+ /**
+ * Unmounted components are inactive and cannot receive new props.
+ */
+ UNMOUNTED: null
+});
+
+var injected = false;
+
+/**
+ * Optionally injectable environment dependent cleanup hook. (server vs.
+ * browser etc). Example: A browser system caches DOM nodes based on component
+ * ID and must remove that cache entry when this instance is unmounted.
+ *
+ * @private
+ */
+var unmountIDFromEnvironment = null;
+
+/**
+ * The "image" of a component tree, is the platform specific (typically
+ * serialized) data that represents a tree of lower level UI building blocks.
+ * On the web, this "image" is HTML markup which describes a construction of
+ * low level `div` and `span` nodes. Other platforms may have different
+ * encoding of this "image". This must be injected.
+ *
+ * @private
+ */
+var mountImageIntoNode = null;
+
+/**
+ * Components are the basic units of composition in React.
+ *
+ * Every component accepts a set of keyed input parameters known as "props" that
+ * are initialized by the constructor. Once a component is mounted, the props
+ * can be mutated using `setProps` or `replaceProps`.
+ *
+ * Every component is capable of the following operations:
+ *
+ * `mountComponent`
+ * Initializes the component, renders markup, and registers event listeners.
+ *
+ * `receiveComponent`
+ * Updates the rendered DOM nodes to match the given component.
+ *
+ * `unmountComponent`
+ * Releases any resources allocated by this component.
+ *
+ * Components can also be "owned" by other components. Being owned by another
+ * component means being constructed by that component. This is different from
+ * being the child of a component, which means having a DOM representation that
+ * is a child of the DOM representation of that component.
+ *
+ * @class ReactComponent
+ */
+var ReactComponent = {
+
+ injection: {
+ injectEnvironment: function(ReactComponentEnvironment) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !injected,
+ 'ReactComponent: injectEnvironment() can only be called once.'
+ ) : invariant(!injected));
+ mountImageIntoNode = ReactComponentEnvironment.mountImageIntoNode;
+ unmountIDFromEnvironment =
+ ReactComponentEnvironment.unmountIDFromEnvironment;
+ ReactComponent.BackendIDOperations =
+ ReactComponentEnvironment.BackendIDOperations;
+ injected = true;
+ }
+ },
+
+ /**
+ * @internal
+ */
+ LifeCycle: ComponentLifeCycle,
+
+ /**
+ * Injected module that provides ability to mutate individual properties.
+ * Injected into the base class because many different subclasses need access
+ * to this.
+ *
+ * @internal
+ */
+ BackendIDOperations: null,
+
+ /**
+ * Base functionality for every ReactComponent constructor. Mixed into the
+ * `ReactComponent` prototype, but exposed statically for easy access.
+ *
+ * @lends {ReactComponent.prototype}
+ */
+ Mixin: {
+
+ /**
+ * Checks whether or not this component is mounted.
+ *
+ * @return {boolean} True if mounted, false otherwise.
+ * @final
+ * @protected
+ */
+ isMounted: function() {
+ return this._lifeCycleState === ComponentLifeCycle.MOUNTED;
+ },
+
+ /**
+ * Sets a subset of the props.
+ *
+ * @param {object} partialProps Subset of the next props.
+ * @param {?function} callback Called after props are updated.
+ * @final
+ * @public
+ */
+ setProps: function(partialProps, callback) {
+ // Merge with the pending element if it exists, otherwise with existing
+ // element props.
+ var element = this._pendingElement || this._currentElement;
+ this.replaceProps(
+ assign({}, element.props, partialProps),
+ callback
+ );
+ },
+
+ /**
+ * Replaces all of the props.
+ *
+ * @param {object} props New props.
+ * @param {?function} callback Called after props are updated.
+ * @final
+ * @public
+ */
+ replaceProps: function(props, callback) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ this.isMounted(),
+ 'replaceProps(...): Can only update a mounted component.'
+ ) : invariant(this.isMounted()));
+ ("production" !== process.env.NODE_ENV ? invariant(
+ this._mountDepth === 0,
+ 'replaceProps(...): You called `setProps` or `replaceProps` on a ' +
+ 'component with a parent. This is an anti-pattern since props will ' +
+ 'get reactively updated when rendered. Instead, change the owner\'s ' +
+ '`render` method to pass the correct value as props to the component ' +
+ 'where it is created.'
+ ) : invariant(this._mountDepth === 0));
+ // This is a deoptimized path. We optimize for always having a element.
+ // This creates an extra internal element.
+ this._pendingElement = ReactElement.cloneAndReplaceProps(
+ this._pendingElement || this._currentElement,
+ props
+ );
+ ReactUpdates.enqueueUpdate(this, callback);
+ },
+
+ /**
+ * Schedule a partial update to the props. Only used for internal testing.
+ *
+ * @param {object} partialProps Subset of the next props.
+ * @param {?function} callback Called after props are updated.
+ * @final
+ * @internal
+ */
+ _setPropsInternal: function(partialProps, callback) {
+ // This is a deoptimized path. We optimize for always having a element.
+ // This creates an extra internal element.
+ var element = this._pendingElement || this._currentElement;
+ this._pendingElement = ReactElement.cloneAndReplaceProps(
+ element,
+ assign({}, element.props, partialProps)
+ );
+ ReactUpdates.enqueueUpdate(this, callback);
+ },
+
+ /**
+ * Base constructor for all React components.
+ *
+ * Subclasses that override this method should make sure to invoke
+ * `ReactComponent.Mixin.construct.call(this, ...)`.
+ *
+ * @param {ReactElement} element
+ * @internal
+ */
+ construct: function(element) {
+ // This is the public exposed props object after it has been processed
+ // with default props. The element's props represents the true internal
+ // state of the props.
+ this.props = element.props;
+ // Record the component responsible for creating this component.
+ // This is accessible through the element but we maintain an extra
+ // field for compatibility with devtools and as a way to make an
+ // incremental update. TODO: Consider deprecating this field.
+ this._owner = element._owner;
+
+ // All components start unmounted.
+ this._lifeCycleState = ComponentLifeCycle.UNMOUNTED;
+
+ // See ReactUpdates.
+ this._pendingCallbacks = null;
+
+ // We keep the old element and a reference to the pending element
+ // to track updates.
+ this._currentElement = element;
+ this._pendingElement = null;
+ },
+
+ /**
+ * Initializes the component, renders markup, and registers event listeners.
+ *
+ * NOTE: This does not insert any nodes into the DOM.
+ *
+ * Subclasses that override this method should make sure to invoke
+ * `ReactComponent.Mixin.mountComponent.call(this, ...)`.
+ *
+ * @param {string} rootID DOM ID of the root node.
+ * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
+ * @param {number} mountDepth number of components in the owner hierarchy.
+ * @return {?string} Rendered markup to be inserted into the DOM.
+ * @internal
+ */
+ mountComponent: function(rootID, transaction, mountDepth) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !this.isMounted(),
+ 'mountComponent(%s, ...): Can only mount an unmounted component. ' +
+ 'Make sure to avoid storing components between renders or reusing a ' +
+ 'single component instance in multiple places.',
+ rootID
+ ) : invariant(!this.isMounted()));
+ var ref = this._currentElement.ref;
+ if (ref != null) {
+ var owner = this._currentElement._owner;
+ ReactOwner.addComponentAsRefTo(this, ref, owner);
+ }
+ this._rootNodeID = rootID;
+ this._lifeCycleState = ComponentLifeCycle.MOUNTED;
+ this._mountDepth = mountDepth;
+ // Effectively: return '';
+ },
+
+ /**
+ * Releases any resources allocated by `mountComponent`.
+ *
+ * NOTE: This does not remove any nodes from the DOM.
+ *
+ * Subclasses that override this method should make sure to invoke
+ * `ReactComponent.Mixin.unmountComponent.call(this)`.
+ *
+ * @internal
+ */
+ unmountComponent: function() {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ this.isMounted(),
+ 'unmountComponent(): Can only unmount a mounted component.'
+ ) : invariant(this.isMounted()));
+ var ref = this._currentElement.ref;
+ if (ref != null) {
+ ReactOwner.removeComponentAsRefFrom(this, ref, this._owner);
+ }
+ unmountIDFromEnvironment(this._rootNodeID);
+ this._rootNodeID = null;
+ this._lifeCycleState = ComponentLifeCycle.UNMOUNTED;
+ },
+
+ /**
+ * Given a new instance of this component, updates the rendered DOM nodes
+ * as if that instance was rendered instead.
+ *
+ * Subclasses that override this method should make sure to invoke
+ * `ReactComponent.Mixin.receiveComponent.call(this, ...)`.
+ *
+ * @param {object} nextComponent Next set of properties.
+ * @param {ReactReconcileTransaction} transaction
+ * @internal
+ */
+ receiveComponent: function(nextElement, transaction) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ this.isMounted(),
+ 'receiveComponent(...): Can only update a mounted component.'
+ ) : invariant(this.isMounted()));
+ this._pendingElement = nextElement;
+ this.performUpdateIfNecessary(transaction);
+ },
+
+ /**
+ * If `_pendingElement` is set, update the component.
+ *
+ * @param {ReactReconcileTransaction} transaction
+ * @internal
+ */
+ performUpdateIfNecessary: function(transaction) {
+ if (this._pendingElement == null) {
+ return;
+ }
+ var prevElement = this._currentElement;
+ var nextElement = this._pendingElement;
+ this._currentElement = nextElement;
+ this.props = nextElement.props;
+ this._owner = nextElement._owner;
+ this._pendingElement = null;
+ this.updateComponent(transaction, prevElement);
+ },
+
+ /**
+ * Updates the component's currently mounted representation.
+ *
+ * @param {ReactReconcileTransaction} transaction
+ * @param {object} prevElement
+ * @internal
+ */
+ updateComponent: function(transaction, prevElement) {
+ var nextElement = this._currentElement;
+
+ // If either the owner or a `ref` has changed, make sure the newest owner
+ // has stored a reference to `this`, and the previous owner (if different)
+ // has forgotten the reference to `this`. We use the element instead
+ // of the public this.props because the post processing cannot determine
+ // a ref. The ref conceptually lives on the element.
+
+ // TODO: Should this even be possible? The owner cannot change because
+ // it's forbidden by shouldUpdateReactComponent. The ref can change
+ // if you swap the keys of but not the refs. Reconsider where this check
+ // is made. It probably belongs where the key checking and
+ // instantiateReactComponent is done.
+
+ if (nextElement._owner !== prevElement._owner ||
+ nextElement.ref !== prevElement.ref) {
+ if (prevElement.ref != null) {
+ ReactOwner.removeComponentAsRefFrom(
+ this, prevElement.ref, prevElement._owner
+ );
+ }
+ // Correct, even if the owner is the same, and only the ref has changed.
+ if (nextElement.ref != null) {
+ ReactOwner.addComponentAsRefTo(
+ this,
+ nextElement.ref,
+ nextElement._owner
+ );
+ }
+ }
+ },
+
+ /**
+ * Mounts this component and inserts it into the DOM.
+ *
+ * @param {string} rootID DOM ID of the root node.
+ * @param {DOMElement} container DOM element to mount into.
+ * @param {boolean} shouldReuseMarkup If true, do not insert markup
+ * @final
+ * @internal
+ * @see {ReactMount.render}
+ */
+ mountComponentIntoNode: function(rootID, container, shouldReuseMarkup) {
+ var transaction = ReactUpdates.ReactReconcileTransaction.getPooled();
+ transaction.perform(
+ this._mountComponentIntoNode,
+ this,
+ rootID,
+ container,
+ transaction,
+ shouldReuseMarkup
+ );
+ ReactUpdates.ReactReconcileTransaction.release(transaction);
+ },
+
+ /**
+ * @param {string} rootID DOM ID of the root node.
+ * @param {DOMElement} container DOM element to mount into.
+ * @param {ReactReconcileTransaction} transaction
+ * @param {boolean} shouldReuseMarkup If true, do not insert markup
+ * @final
+ * @private
+ */
+ _mountComponentIntoNode: function(
+ rootID,
+ container,
+ transaction,
+ shouldReuseMarkup) {
+ var markup = this.mountComponent(rootID, transaction, 0);
+ mountImageIntoNode(markup, container, shouldReuseMarkup);
+ },
+
+ /**
+ * Checks if this component is owned by the supplied `owner` component.
+ *
+ * @param {ReactComponent} owner Component to check.
+ * @return {boolean} True if `owners` owns this component.
+ * @final
+ * @internal
+ */
+ isOwnedBy: function(owner) {
+ return this._owner === owner;
+ },
+
+ /**
+ * Gets another component, that shares the same owner as this one, by ref.
+ *
+ * @param {string} ref of a sibling Component.
+ * @return {?ReactComponent} the actual sibling Component.
+ * @final
+ * @internal
+ */
+ getSiblingByRef: function(ref) {
+ var owner = this._owner;
+ if (!owner || !owner.refs) {
+ return null;
+ }
+ return owner.refs[ref];
+ }
+ }
+};
+
+module.exports = ReactComponent;
+
+}).call(this,require('_process'))
+},{"./Object.assign":75,"./ReactElement":104,"./ReactOwner":120,"./ReactUpdates":137,"./invariant":187,"./keyMirror":193,"_process":5}],84:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactComponentBrowserEnvironment
+ */
+
+/*jslint evil: true */
+
+"use strict";
+
+var ReactDOMIDOperations = require("./ReactDOMIDOperations");
+var ReactMarkupChecksum = require("./ReactMarkupChecksum");
+var ReactMount = require("./ReactMount");
+var ReactPerf = require("./ReactPerf");
+var ReactReconcileTransaction = require("./ReactReconcileTransaction");
+
+var getReactRootElementInContainer = require("./getReactRootElementInContainer");
+var invariant = require("./invariant");
+var setInnerHTML = require("./setInnerHTML");
+
+
+var ELEMENT_NODE_TYPE = 1;
+var DOC_NODE_TYPE = 9;
+
+
+/**
+ * Abstracts away all functionality of `ReactComponent` requires knowledge of
+ * the browser context.
+ */
+var ReactComponentBrowserEnvironment = {
+ ReactReconcileTransaction: ReactReconcileTransaction,
+
+ BackendIDOperations: ReactDOMIDOperations,
+
+ /**
+ * If a particular environment requires that some resources be cleaned up,
+ * specify this in the injected Mixin. In the DOM, we would likely want to
+ * purge any cached node ID lookups.
+ *
+ * @private
+ */
+ unmountIDFromEnvironment: function(rootNodeID) {
+ ReactMount.purgeID(rootNodeID);
+ },
+
+ /**
+ * @param {string} markup Markup string to place into the DOM Element.
+ * @param {DOMElement} container DOM Element to insert markup into.
+ * @param {boolean} shouldReuseMarkup Should reuse the existing markup in the
+ * container if possible.
+ */
+ mountImageIntoNode: ReactPerf.measure(
+ 'ReactComponentBrowserEnvironment',
+ 'mountImageIntoNode',
+ function(markup, container, shouldReuseMarkup) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ container && (
+ container.nodeType === ELEMENT_NODE_TYPE ||
+ container.nodeType === DOC_NODE_TYPE
+ ),
+ 'mountComponentIntoNode(...): Target container is not valid.'
+ ) : invariant(container && (
+ container.nodeType === ELEMENT_NODE_TYPE ||
+ container.nodeType === DOC_NODE_TYPE
+ )));
+
+ if (shouldReuseMarkup) {
+ if (ReactMarkupChecksum.canReuseMarkup(
+ markup,
+ getReactRootElementInContainer(container))) {
+ return;
+ } else {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ container.nodeType !== DOC_NODE_TYPE,
+ 'You\'re trying to render a component to the document using ' +
+ 'server rendering but the checksum was invalid. This usually ' +
+ 'means you rendered a different component type or props on ' +
+ 'the client from the one on the server, or your render() ' +
+ 'methods are impure. React cannot handle this case due to ' +
+ 'cross-browser quirks by rendering at the document root. You ' +
+ 'should look for environment dependent code in your components ' +
+ 'and ensure the props are the same client and server side.'
+ ) : invariant(container.nodeType !== DOC_NODE_TYPE));
+
+ if ("production" !== process.env.NODE_ENV) {
+ console.warn(
+ 'React attempted to use reuse markup in a container but the ' +
+ 'checksum was invalid. This generally means that you are ' +
+ 'using server rendering and the markup generated on the ' +
+ 'server was not what the client was expecting. React injected ' +
+ 'new markup to compensate which works but you have lost many ' +
+ 'of the benefits of server rendering. Instead, figure out ' +
+ 'why the markup being generated is different on the client ' +
+ 'or server.'
+ );
+ }
+ }
+ }
+
+ ("production" !== process.env.NODE_ENV ? invariant(
+ container.nodeType !== DOC_NODE_TYPE,
+ 'You\'re trying to render a component to the document but ' +
+ 'you didn\'t use server rendering. We can\'t do this ' +
+ 'without using server rendering due to cross-browser quirks. ' +
+ 'See renderComponentToString() for server rendering.'
+ ) : invariant(container.nodeType !== DOC_NODE_TYPE));
+
+ setInnerHTML(container, markup);
+ }
+ )
+};
+
+module.exports = ReactComponentBrowserEnvironment;
+
+}).call(this,require('_process'))
+},{"./ReactDOMIDOperations":93,"./ReactMarkupChecksum":115,"./ReactMount":116,"./ReactPerf":121,"./ReactReconcileTransaction":127,"./getReactRootElementInContainer":181,"./invariant":187,"./setInnerHTML":201,"_process":5}],85:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+* @providesModule ReactComponentWithPureRenderMixin
+*/
+
+"use strict";
+
+var shallowEqual = require("./shallowEqual");
+
+/**
+ * If your React component's render function is "pure", e.g. it will render the
+ * same result given the same props and state, provide this Mixin for a
+ * considerable performance boost.
+ *
+ * Most React components have pure render functions.
+ *
+ * Example:
+ *
+ * var ReactComponentWithPureRenderMixin =
+ * require('ReactComponentWithPureRenderMixin');
+ * React.createClass({
+ * mixins: [ReactComponentWithPureRenderMixin],
+ *
+ * render: function() {
+ * return <div className={this.props.className}>foo</div>;
+ * }
+ * });
+ *
+ * Note: This only checks shallow equality for props and state. If these contain
+ * complex data structures this mixin may have false-negatives for deeper
+ * differences. Only mixin to components which have simple props and state, or
+ * use `forceUpdate()` when you know deep data structures have changed.
+ */
+var ReactComponentWithPureRenderMixin = {
+ shouldComponentUpdate: function(nextProps, nextState) {
+ return !shallowEqual(this.props, nextProps) ||
+ !shallowEqual(this.state, nextState);
+ }
+};
+
+module.exports = ReactComponentWithPureRenderMixin;
+
+},{"./shallowEqual":202}],86:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactCompositeComponent
+ */
+
+"use strict";
+
+var ReactComponent = require("./ReactComponent");
+var ReactContext = require("./ReactContext");
+var ReactCurrentOwner = require("./ReactCurrentOwner");
+var ReactElement = require("./ReactElement");
+var ReactElementValidator = require("./ReactElementValidator");
+var ReactEmptyComponent = require("./ReactEmptyComponent");
+var ReactErrorUtils = require("./ReactErrorUtils");
+var ReactLegacyElement = require("./ReactLegacyElement");
+var ReactOwner = require("./ReactOwner");
+var ReactPerf = require("./ReactPerf");
+var ReactPropTransferer = require("./ReactPropTransferer");
+var ReactPropTypeLocations = require("./ReactPropTypeLocations");
+var ReactPropTypeLocationNames = require("./ReactPropTypeLocationNames");
+var ReactUpdates = require("./ReactUpdates");
+
+var assign = require("./Object.assign");
+var instantiateReactComponent = require("./instantiateReactComponent");
+var invariant = require("./invariant");
+var keyMirror = require("./keyMirror");
+var keyOf = require("./keyOf");
+var monitorCodeUse = require("./monitorCodeUse");
+var mapObject = require("./mapObject");
+var shouldUpdateReactComponent = require("./shouldUpdateReactComponent");
+var warning = require("./warning");
+
+var MIXINS_KEY = keyOf({mixins: null});
+
+/**
+ * Policies that describe methods in `ReactCompositeComponentInterface`.
+ */
+var SpecPolicy = keyMirror({
+ /**
+ * These methods may be defined only once by the class specification or mixin.
+ */
+ DEFINE_ONCE: null,
+ /**
+ * These methods may be defined by both the class specification and mixins.
+ * Subsequent definitions will be chained. These methods must return void.
+ */
+ DEFINE_MANY: null,
+ /**
+ * These methods are overriding the base ReactCompositeComponent class.
+ */
+ OVERRIDE_BASE: null,
+ /**
+ * These methods are similar to DEFINE_MANY, except we assume they return
+ * objects. We try to merge the keys of the return values of all the mixed in
+ * functions. If there is a key conflict we throw.
+ */
+ DEFINE_MANY_MERGED: null
+});
+
+
+var injectedMixins = [];
+
+/**
+ * Composite components are higher-level components that compose other composite
+ * or native components.
+ *
+ * To create a new type of `ReactCompositeComponent`, pass a specification of
+ * your new class to `React.createClass`. The only requirement of your class
+ * specification is that you implement a `render` method.
+ *
+ * var MyComponent = React.createClass({
+ * render: function() {
+ * return <div>Hello World</div>;
+ * }
+ * });
+ *
+ * The class specification supports a specific protocol of methods that have
+ * special meaning (e.g. `render`). See `ReactCompositeComponentInterface` for
+ * more the comprehensive protocol. Any other properties and methods in the
+ * class specification will available on the prototype.
+ *
+ * @interface ReactCompositeComponentInterface
+ * @internal
+ */
+var ReactCompositeComponentInterface = {
+
+ /**
+ * An array of Mixin objects to include when defining your component.
+ *
+ * @type {array}
+ * @optional
+ */
+ mixins: SpecPolicy.DEFINE_MANY,
+
+ /**
+ * An object containing properties and methods that should be defined on
+ * the component's constructor instead of its prototype (static methods).
+ *
+ * @type {object}
+ * @optional
+ */
+ statics: SpecPolicy.DEFINE_MANY,
+
+ /**
+ * Definition of prop types for this component.
+ *
+ * @type {object}
+ * @optional
+ */
+ propTypes: SpecPolicy.DEFINE_MANY,
+
+ /**
+ * Definition of context types for this component.
+ *
+ * @type {object}
+ * @optional
+ */
+ contextTypes: SpecPolicy.DEFINE_MANY,
+
+ /**
+ * Definition of context types this component sets for its children.
+ *
+ * @type {object}
+ * @optional
+ */
+ childContextTypes: SpecPolicy.DEFINE_MANY,
+
+ // ==== Definition methods ====
+
+ /**
+ * Invoked when the component is mounted. Values in the mapping will be set on
+ * `this.props` if that prop is not specified (i.e. using an `in` check).
+ *
+ * This method is invoked before `getInitialState` and therefore cannot rely
+ * on `this.state` or use `this.setState`.
+ *
+ * @return {object}
+ * @optional
+ */
+ getDefaultProps: SpecPolicy.DEFINE_MANY_MERGED,
+
+ /**
+ * Invoked once before the component is mounted. The return value will be used
+ * as the initial value of `this.state`.
+ *
+ * getInitialState: function() {
+ * return {
+ * isOn: false,
+ * fooBaz: new BazFoo()
+ * }
+ * }
+ *
+ * @return {object}
+ * @optional
+ */
+ getInitialState: SpecPolicy.DEFINE_MANY_MERGED,
+
+ /**
+ * @return {object}
+ * @optional
+ */
+ getChildContext: SpecPolicy.DEFINE_MANY_MERGED,
+
+ /**
+ * Uses props from `this.props` and state from `this.state` to render the
+ * structure of the component.
+ *
+ * No guarantees are made about when or how often this method is invoked, so
+ * it must not have side effects.
+ *
+ * render: function() {
+ * var name = this.props.name;
+ * return <div>Hello, {name}!</div>;
+ * }
+ *
+ * @return {ReactComponent}
+ * @nosideeffects
+ * @required
+ */
+ render: SpecPolicy.DEFINE_ONCE,
+
+
+
+ // ==== Delegate methods ====
+
+ /**
+ * Invoked when the component is initially created and about to be mounted.
+ * This may have side effects, but any external subscriptions or data created
+ * by this method must be cleaned up in `componentWillUnmount`.
+ *
+ * @optional
+ */
+ componentWillMount: SpecPolicy.DEFINE_MANY,
+
+ /**
+ * Invoked when the component has been mounted and has a DOM representation.
+ * However, there is no guarantee that the DOM node is in the document.
+ *
+ * Use this as an opportunity to operate on the DOM when the component has
+ * been mounted (initialized and rendered) for the first time.
+ *
+ * @param {DOMElement} rootNode DOM element representing the component.
+ * @optional
+ */
+ componentDidMount: SpecPolicy.DEFINE_MANY,
+
+ /**
+ * Invoked before the component receives new props.
+ *
+ * Use this as an opportunity to react to a prop transition by updating the
+ * state using `this.setState`. Current props are accessed via `this.props`.
+ *
+ * componentWillReceiveProps: function(nextProps, nextContext) {
+ * this.setState({
+ * likesIncreasing: nextProps.likeCount > this.props.likeCount
+ * });
+ * }
+ *
+ * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop
+ * transition may cause a state change, but the opposite is not true. If you
+ * need it, you are probably looking for `componentWillUpdate`.
+ *
+ * @param {object} nextProps
+ * @optional
+ */
+ componentWillReceiveProps: SpecPolicy.DEFINE_MANY,
+
+ /**
+ * Invoked while deciding if the component should be updated as a result of
+ * receiving new props, state and/or context.
+ *
+ * Use this as an opportunity to `return false` when you're certain that the
+ * transition to the new props/state/context will not require a component
+ * update.
+ *
+ * shouldComponentUpdate: function(nextProps, nextState, nextContext) {
+ * return !equal(nextProps, this.props) ||
+ * !equal(nextState, this.state) ||
+ * !equal(nextContext, this.context);
+ * }
+ *
+ * @param {object} nextProps
+ * @param {?object} nextState
+ * @param {?object} nextContext
+ * @return {boolean} True if the component should update.
+ * @optional
+ */
+ shouldComponentUpdate: SpecPolicy.DEFINE_ONCE,
+
+ /**
+ * Invoked when the component is about to update due to a transition from
+ * `this.props`, `this.state` and `this.context` to `nextProps`, `nextState`
+ * and `nextContext`.
+ *
+ * Use this as an opportunity to perform preparation before an update occurs.
+ *
+ * NOTE: You **cannot** use `this.setState()` in this method.
+ *
+ * @param {object} nextProps
+ * @param {?object} nextState
+ * @param {?object} nextContext
+ * @param {ReactReconcileTransaction} transaction
+ * @optional
+ */
+ componentWillUpdate: SpecPolicy.DEFINE_MANY,
+
+ /**
+ * Invoked when the component's DOM representation has been updated.
+ *
+ * Use this as an opportunity to operate on the DOM when the component has
+ * been updated.
+ *
+ * @param {object} prevProps
+ * @param {?object} prevState
+ * @param {?object} prevContext
+ * @param {DOMElement} rootNode DOM element representing the component.
+ * @optional
+ */
+ componentDidUpdate: SpecPolicy.DEFINE_MANY,
+
+ /**
+ * Invoked when the component is about to be removed from its parent and have
+ * its DOM representation destroyed.
+ *
+ * Use this as an opportunity to deallocate any external resources.
+ *
+ * NOTE: There is no `componentDidUnmount` since your component will have been
+ * destroyed by that point.
+ *
+ * @optional
+ */
+ componentWillUnmount: SpecPolicy.DEFINE_MANY,
+
+
+
+ // ==== Advanced methods ====
+
+ /**
+ * Updates the component's currently mounted DOM representation.
+ *
+ * By default, this implements React's rendering and reconciliation algorithm.
+ * Sophisticated clients may wish to override this.
+ *
+ * @param {ReactReconcileTransaction} transaction
+ * @internal
+ * @overridable
+ */
+ updateComponent: SpecPolicy.OVERRIDE_BASE
+
+};
+
+/**
+ * Mapping from class specification keys to special processing functions.
+ *
+ * Although these are declared like instance properties in the specification
+ * when defining classes using `React.createClass`, they are actually static
+ * and are accessible on the constructor instead of the prototype. Despite
+ * being static, they must be defined outside of the "statics" key under
+ * which all other static methods are defined.
+ */
+var RESERVED_SPEC_KEYS = {
+ displayName: function(Constructor, displayName) {
+ Constructor.displayName = displayName;
+ },
+ mixins: function(Constructor, mixins) {
+ if (mixins) {
+ for (var i = 0; i < mixins.length; i++) {
+ mixSpecIntoComponent(Constructor, mixins[i]);
+ }
+ }
+ },
+ childContextTypes: function(Constructor, childContextTypes) {
+ validateTypeDef(
+ Constructor,
+ childContextTypes,
+ ReactPropTypeLocations.childContext
+ );
+ Constructor.childContextTypes = assign(
+ {},
+ Constructor.childContextTypes,
+ childContextTypes
+ );
+ },
+ contextTypes: function(Constructor, contextTypes) {
+ validateTypeDef(
+ Constructor,
+ contextTypes,
+ ReactPropTypeLocations.context
+ );
+ Constructor.contextTypes = assign(
+ {},
+ Constructor.contextTypes,
+ contextTypes
+ );
+ },
+ /**
+ * Special case getDefaultProps which should move into statics but requires
+ * automatic merging.
+ */
+ getDefaultProps: function(Constructor, getDefaultProps) {
+ if (Constructor.getDefaultProps) {
+ Constructor.getDefaultProps = createMergedResultFunction(
+ Constructor.getDefaultProps,
+ getDefaultProps
+ );
+ } else {
+ Constructor.getDefaultProps = getDefaultProps;
+ }
+ },
+ propTypes: function(Constructor, propTypes) {
+ validateTypeDef(
+ Constructor,
+ propTypes,
+ ReactPropTypeLocations.prop
+ );
+ Constructor.propTypes = assign(
+ {},
+ Constructor.propTypes,
+ propTypes
+ );
+ },
+ statics: function(Constructor, statics) {
+ mixStaticSpecIntoComponent(Constructor, statics);
+ }
+};
+
+function getDeclarationErrorAddendum(component) {
+ var owner = component._owner || null;
+ if (owner && owner.constructor && owner.constructor.displayName) {
+ return ' Check the render method of `' + owner.constructor.displayName +
+ '`.';
+ }
+ return '';
+}
+
+function validateTypeDef(Constructor, typeDef, location) {
+ for (var propName in typeDef) {
+ if (typeDef.hasOwnProperty(propName)) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ typeof typeDef[propName] == 'function',
+ '%s: %s type `%s` is invalid; it must be a function, usually from ' +
+ 'React.PropTypes.',
+ Constructor.displayName || 'ReactCompositeComponent',
+ ReactPropTypeLocationNames[location],
+ propName
+ ) : invariant(typeof typeDef[propName] == 'function'));
+ }
+ }
+}
+
+function validateMethodOverride(proto, name) {
+ var specPolicy = ReactCompositeComponentInterface.hasOwnProperty(name) ?
+ ReactCompositeComponentInterface[name] :
+ null;
+
+ // Disallow overriding of base class methods unless explicitly allowed.
+ if (ReactCompositeComponentMixin.hasOwnProperty(name)) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ specPolicy === SpecPolicy.OVERRIDE_BASE,
+ 'ReactCompositeComponentInterface: You are attempting to override ' +
+ '`%s` from your class specification. Ensure that your method names ' +
+ 'do not overlap with React methods.',
+ name
+ ) : invariant(specPolicy === SpecPolicy.OVERRIDE_BASE));
+ }
+
+ // Disallow defining methods more than once unless explicitly allowed.
+ if (proto.hasOwnProperty(name)) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ specPolicy === SpecPolicy.DEFINE_MANY ||
+ specPolicy === SpecPolicy.DEFINE_MANY_MERGED,
+ 'ReactCompositeComponentInterface: You are attempting to define ' +
+ '`%s` on your component more than once. This conflict may be due ' +
+ 'to a mixin.',
+ name
+ ) : invariant(specPolicy === SpecPolicy.DEFINE_MANY ||
+ specPolicy === SpecPolicy.DEFINE_MANY_MERGED));
+ }
+}
+
+function validateLifeCycleOnReplaceState(instance) {
+ var compositeLifeCycleState = instance._compositeLifeCycleState;
+ ("production" !== process.env.NODE_ENV ? invariant(
+ instance.isMounted() ||
+ compositeLifeCycleState === CompositeLifeCycle.MOUNTING,
+ 'replaceState(...): Can only update a mounted or mounting component.'
+ ) : invariant(instance.isMounted() ||
+ compositeLifeCycleState === CompositeLifeCycle.MOUNTING));
+ ("production" !== process.env.NODE_ENV ? invariant(
+ ReactCurrentOwner.current == null,
+ 'replaceState(...): Cannot update during an existing state transition ' +
+ '(such as within `render`). Render methods should be a pure function ' +
+ 'of props and state.'
+ ) : invariant(ReactCurrentOwner.current == null));
+ ("production" !== process.env.NODE_ENV ? invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING,
+ 'replaceState(...): Cannot update while unmounting component. This ' +
+ 'usually means you called setState() on an unmounted component.'
+ ) : invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING));
+}
+
+/**
+ * Mixin helper which handles policy validation and reserved
+ * specification keys when building `ReactCompositeComponent` classses.
+ */
+function mixSpecIntoComponent(Constructor, spec) {
+ if (!spec) {
+ return;
+ }
+
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !ReactLegacyElement.isValidFactory(spec),
+ 'ReactCompositeComponent: You\'re attempting to ' +
+ 'use a component class as a mixin. Instead, just use a regular object.'
+ ) : invariant(!ReactLegacyElement.isValidFactory(spec)));
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !ReactElement.isValidElement(spec),
+ 'ReactCompositeComponent: You\'re attempting to ' +
+ 'use a component as a mixin. Instead, just use a regular object.'
+ ) : invariant(!ReactElement.isValidElement(spec)));
+
+ var proto = Constructor.prototype;
+
+ // By handling mixins before any other properties, we ensure the same
+ // chaining order is applied to methods with DEFINE_MANY policy, whether
+ // mixins are listed before or after these methods in the spec.
+ if (spec.hasOwnProperty(MIXINS_KEY)) {
+ RESERVED_SPEC_KEYS.mixins(Constructor, spec.mixins);
+ }
+
+ for (var name in spec) {
+ if (!spec.hasOwnProperty(name)) {
+ continue;
+ }
+
+ if (name === MIXINS_KEY) {
+ // We have already handled mixins in a special case above
+ continue;
+ }
+
+ var property = spec[name];
+ validateMethodOverride(proto, name);
+
+ if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) {
+ RESERVED_SPEC_KEYS[name](Constructor, property);
+ } else {
+ // Setup methods on prototype:
+ // The following member methods should not be automatically bound:
+ // 1. Expected ReactCompositeComponent methods (in the "interface").
+ // 2. Overridden methods (that were mixed in).
+ var isCompositeComponentMethod =
+ ReactCompositeComponentInterface.hasOwnProperty(name);
+ var isAlreadyDefined = proto.hasOwnProperty(name);
+ var markedDontBind = property && property.__reactDontBind;
+ var isFunction = typeof property === 'function';
+ var shouldAutoBind =
+ isFunction &&
+ !isCompositeComponentMethod &&
+ !isAlreadyDefined &&
+ !markedDontBind;
+
+ if (shouldAutoBind) {
+ if (!proto.__reactAutoBindMap) {
+ proto.__reactAutoBindMap = {};
+ }
+ proto.__reactAutoBindMap[name] = property;
+ proto[name] = property;
+ } else {
+ if (isAlreadyDefined) {
+ var specPolicy = ReactCompositeComponentInterface[name];
+
+ // These cases should already be caught by validateMethodOverride
+ ("production" !== process.env.NODE_ENV ? invariant(
+ isCompositeComponentMethod && (
+ specPolicy === SpecPolicy.DEFINE_MANY_MERGED ||
+ specPolicy === SpecPolicy.DEFINE_MANY
+ ),
+ 'ReactCompositeComponent: Unexpected spec policy %s for key %s ' +
+ 'when mixing in component specs.',
+ specPolicy,
+ name
+ ) : invariant(isCompositeComponentMethod && (
+ specPolicy === SpecPolicy.DEFINE_MANY_MERGED ||
+ specPolicy === SpecPolicy.DEFINE_MANY
+ )));
+
+ // For methods which are defined more than once, call the existing
+ // methods before calling the new property, merging if appropriate.
+ if (specPolicy === SpecPolicy.DEFINE_MANY_MERGED) {
+ proto[name] = createMergedResultFunction(proto[name], property);
+ } else if (specPolicy === SpecPolicy.DEFINE_MANY) {
+ proto[name] = createChainedFunction(proto[name], property);
+ }
+ } else {
+ proto[name] = property;
+ if ("production" !== process.env.NODE_ENV) {
+ // Add verbose displayName to the function, which helps when looking
+ // at profiling tools.
+ if (typeof property === 'function' && spec.displayName) {
+ proto[name].displayName = spec.displayName + '_' + name;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+function mixStaticSpecIntoComponent(Constructor, statics) {
+ if (!statics) {
+ return;
+ }
+ for (var name in statics) {
+ var property = statics[name];
+ if (!statics.hasOwnProperty(name)) {
+ continue;
+ }
+
+ var isReserved = name in RESERVED_SPEC_KEYS;
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !isReserved,
+ 'ReactCompositeComponent: You are attempting to define a reserved ' +
+ 'property, `%s`, that shouldn\'t be on the "statics" key. Define it ' +
+ 'as an instance property instead; it will still be accessible on the ' +
+ 'constructor.',
+ name
+ ) : invariant(!isReserved));
+
+ var isInherited = name in Constructor;
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !isInherited,
+ 'ReactCompositeComponent: You are attempting to define ' +
+ '`%s` on your component more than once. This conflict may be ' +
+ 'due to a mixin.',
+ name
+ ) : invariant(!isInherited));
+ Constructor[name] = property;
+ }
+}
+
+/**
+ * Merge two objects, but throw if both contain the same key.
+ *
+ * @param {object} one The first object, which is mutated.
+ * @param {object} two The second object
+ * @return {object} one after it has been mutated to contain everything in two.
+ */
+function mergeObjectsWithNoDuplicateKeys(one, two) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ one && two && typeof one === 'object' && typeof two === 'object',
+ 'mergeObjectsWithNoDuplicateKeys(): Cannot merge non-objects'
+ ) : invariant(one && two && typeof one === 'object' && typeof two === 'object'));
+
+ mapObject(two, function(value, key) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ one[key] === undefined,
+ 'mergeObjectsWithNoDuplicateKeys(): ' +
+ 'Tried to merge two objects with the same key: `%s`. This conflict ' +
+ 'may be due to a mixin; in particular, this may be caused by two ' +
+ 'getInitialState() or getDefaultProps() methods returning objects ' +
+ 'with clashing keys.',
+ key
+ ) : invariant(one[key] === undefined));
+ one[key] = value;
+ });
+ return one;
+}
+
+/**
+ * Creates a function that invokes two functions and merges their return values.
+ *
+ * @param {function} one Function to invoke first.
+ * @param {function} two Function to invoke second.
+ * @return {function} Function that invokes the two argument functions.
+ * @private
+ */
+function createMergedResultFunction(one, two) {
+ return function mergedResult() {
+ var a = one.apply(this, arguments);
+ var b = two.apply(this, arguments);
+ if (a == null) {
+ return b;
+ } else if (b == null) {
+ return a;
+ }
+ return mergeObjectsWithNoDuplicateKeys(a, b);
+ };
+}
+
+/**
+ * Creates a function that invokes two functions and ignores their return vales.
+ *
+ * @param {function} one Function to invoke first.
+ * @param {function} two Function to invoke second.
+ * @return {function} Function that invokes the two argument functions.
+ * @private
+ */
+function createChainedFunction(one, two) {
+ return function chainedFunction() {
+ one.apply(this, arguments);
+ two.apply(this, arguments);
+ };
+}
+
+/**
+ * `ReactCompositeComponent` maintains an auxiliary life cycle state in
+ * `this._compositeLifeCycleState` (which can be null).
+ *
+ * This is different from the life cycle state maintained by `ReactComponent` in
+ * `this._lifeCycleState`. The following diagram shows how the states overlap in
+ * time. There are times when the CompositeLifeCycle is null - at those times it
+ * is only meaningful to look at ComponentLifeCycle alone.
+ *
+ * Top Row: ReactComponent.ComponentLifeCycle
+ * Low Row: ReactComponent.CompositeLifeCycle
+ *
+ * +-------+---------------------------------+--------+
+ * | UN | MOUNTED | UN |
+ * |MOUNTED| | MOUNTED|
+ * +-------+---------------------------------+--------+
+ * | ^--------+ +-------+ +--------^ |
+ * | | | | | | | |
+ * | 0--|MOUNTING|-0-|RECEIVE|-0-| UN |--->0 |
+ * | | | |PROPS | |MOUNTING| |
+ * | | | | | | | |
+ * | | | | | | | |
+ * | +--------+ +-------+ +--------+ |
+ * | | | |
+ * +-------+---------------------------------+--------+
+ */
+var CompositeLifeCycle = keyMirror({
+ /**
+ * Components in the process of being mounted respond to state changes
+ * differently.
+ */
+ MOUNTING: null,
+ /**
+ * Components in the process of being unmounted are guarded against state
+ * changes.
+ */
+ UNMOUNTING: null,
+ /**
+ * Components that are mounted and receiving new props respond to state
+ * changes differently.
+ */
+ RECEIVING_PROPS: null
+});
+
+/**
+ * @lends {ReactCompositeComponent.prototype}
+ */
+var ReactCompositeComponentMixin = {
+
+ /**
+ * Base constructor for all composite component.
+ *
+ * @param {ReactElement} element
+ * @final
+ * @internal
+ */
+ construct: function(element) {
+ // Children can be either an array or more than one argument
+ ReactComponent.Mixin.construct.apply(this, arguments);
+ ReactOwner.Mixin.construct.apply(this, arguments);
+
+ this.state = null;
+ this._pendingState = null;
+
+ // This is the public post-processed context. The real context and pending
+ // context lives on the element.
+ this.context = null;
+
+ this._compositeLifeCycleState = null;
+ },
+
+ /**
+ * Checks whether or not this composite component is mounted.
+ * @return {boolean} True if mounted, false otherwise.
+ * @protected
+ * @final
+ */
+ isMounted: function() {
+ return ReactComponent.Mixin.isMounted.call(this) &&
+ this._compositeLifeCycleState !== CompositeLifeCycle.MOUNTING;
+ },
+
+ /**
+ * Initializes the component, renders markup, and registers event listeners.
+ *
+ * @param {string} rootID DOM ID of the root node.
+ * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
+ * @param {number} mountDepth number of components in the owner hierarchy
+ * @return {?string} Rendered markup to be inserted into the DOM.
+ * @final
+ * @internal
+ */
+ mountComponent: ReactPerf.measure(
+ 'ReactCompositeComponent',
+ 'mountComponent',
+ function(rootID, transaction, mountDepth) {
+ ReactComponent.Mixin.mountComponent.call(
+ this,
+ rootID,
+ transaction,
+ mountDepth
+ );
+ this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING;
+
+ if (this.__reactAutoBindMap) {
+ this._bindAutoBindMethods();
+ }
+
+ this.context = this._processContext(this._currentElement._context);
+ this.props = this._processProps(this.props);
+
+ this.state = this.getInitialState ? this.getInitialState() : null;
+ ("production" !== process.env.NODE_ENV ? invariant(
+ typeof this.state === 'object' && !Array.isArray(this.state),
+ '%s.getInitialState(): must return an object or null',
+ this.constructor.displayName || 'ReactCompositeComponent'
+ ) : invariant(typeof this.state === 'object' && !Array.isArray(this.state)));
+
+ this._pendingState = null;
+ this._pendingForceUpdate = false;
+
+ if (this.componentWillMount) {
+ this.componentWillMount();
+ // When mounting, calls to `setState` by `componentWillMount` will set
+ // `this._pendingState` without triggering a re-render.
+ if (this._pendingState) {
+ this.state = this._pendingState;
+ this._pendingState = null;
+ }
+ }
+
+ this._renderedComponent = instantiateReactComponent(
+ this._renderValidatedComponent(),
+ this._currentElement.type // The wrapping type
+ );
+
+ // Done with mounting, `setState` will now trigger UI changes.
+ this._compositeLifeCycleState = null;
+ var markup = this._renderedComponent.mountComponent(
+ rootID,
+ transaction,
+ mountDepth + 1
+ );
+ if (this.componentDidMount) {
+ transaction.getReactMountReady().enqueue(this.componentDidMount, this);
+ }
+ return markup;
+ }
+ ),
+
+ /**
+ * Releases any resources allocated by `mountComponent`.
+ *
+ * @final
+ * @internal
+ */
+ unmountComponent: function() {
+ this._compositeLifeCycleState = CompositeLifeCycle.UNMOUNTING;
+ if (this.componentWillUnmount) {
+ this.componentWillUnmount();
+ }
+ this._compositeLifeCycleState = null;
+
+ this._renderedComponent.unmountComponent();
+ this._renderedComponent = null;
+
+ ReactComponent.Mixin.unmountComponent.call(this);
+
+ // Some existing components rely on this.props even after they've been
+ // destroyed (in event handlers).
+ // TODO: this.props = null;
+ // TODO: this.state = null;
+ },
+
+ /**
+ * Sets a subset of the state. Always use this or `replaceState` to mutate
+ * state. You should treat `this.state` as immutable.
+ *
+ * There is no guarantee that `this.state` will be immediately updated, so
+ * accessing `this.state` after calling this method may return the old value.
+ *
+ * There is no guarantee that calls to `setState` will run synchronously,
+ * as they may eventually be batched together. You can provide an optional
+ * callback that will be executed when the call to setState is actually
+ * completed.
+ *
+ * @param {object} partialState Next partial state to be merged with state.
+ * @param {?function} callback Called after state is updated.
+ * @final
+ * @protected
+ */
+ setState: function(partialState, callback) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ typeof partialState === 'object' || partialState == null,
+ 'setState(...): takes an object of state variables to update.'
+ ) : invariant(typeof partialState === 'object' || partialState == null));
+ if ("production" !== process.env.NODE_ENV){
+ ("production" !== process.env.NODE_ENV ? warning(
+ partialState != null,
+ 'setState(...): You passed an undefined or null state object; ' +
+ 'instead, use forceUpdate().'
+ ) : null);
+ }
+ // Merge with `_pendingState` if it exists, otherwise with existing state.
+ this.replaceState(
+ assign({}, this._pendingState || this.state, partialState),
+ callback
+ );
+ },
+
+ /**
+ * Replaces all of the state. Always use this or `setState` to mutate state.
+ * You should treat `this.state` as immutable.
+ *
+ * There is no guarantee that `this.state` will be immediately updated, so
+ * accessing `this.state` after calling this method may return the old value.
+ *
+ * @param {object} completeState Next state.
+ * @param {?function} callback Called after state is updated.
+ * @final
+ * @protected
+ */
+ replaceState: function(completeState, callback) {
+ validateLifeCycleOnReplaceState(this);
+ this._pendingState = completeState;
+ if (this._compositeLifeCycleState !== CompositeLifeCycle.MOUNTING) {
+ // If we're in a componentWillMount handler, don't enqueue a rerender
+ // because ReactUpdates assumes we're in a browser context (which is wrong
+ // for server rendering) and we're about to do a render anyway.
+ // TODO: The callback here is ignored when setState is called from
+ // componentWillMount. Either fix it or disallow doing so completely in
+ // favor of getInitialState.
+ ReactUpdates.enqueueUpdate(this, callback);
+ }
+ },
+
+ /**
+ * Filters the context object to only contain keys specified in
+ * `contextTypes`, and asserts that they are valid.
+ *
+ * @param {object} context
+ * @return {?object}
+ * @private
+ */
+ _processContext: function(context) {
+ var maskedContext = null;
+ var contextTypes = this.constructor.contextTypes;
+ if (contextTypes) {
+ maskedContext = {};
+ for (var contextName in contextTypes) {
+ maskedContext[contextName] = context[contextName];
+ }
+ if ("production" !== process.env.NODE_ENV) {
+ this._checkPropTypes(
+ contextTypes,
+ maskedContext,
+ ReactPropTypeLocations.context
+ );
+ }
+ }
+ return maskedContext;
+ },
+
+ /**
+ * @param {object} currentContext
+ * @return {object}
+ * @private
+ */
+ _processChildContext: function(currentContext) {
+ var childContext = this.getChildContext && this.getChildContext();
+ var displayName = this.constructor.displayName || 'ReactCompositeComponent';
+ if (childContext) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ typeof this.constructor.childContextTypes === 'object',
+ '%s.getChildContext(): childContextTypes must be defined in order to ' +
+ 'use getChildContext().',
+ displayName
+ ) : invariant(typeof this.constructor.childContextTypes === 'object'));
+ if ("production" !== process.env.NODE_ENV) {
+ this._checkPropTypes(
+ this.constructor.childContextTypes,
+ childContext,
+ ReactPropTypeLocations.childContext
+ );
+ }
+ for (var name in childContext) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ name in this.constructor.childContextTypes,
+ '%s.getChildContext(): key "%s" is not defined in childContextTypes.',
+ displayName,
+ name
+ ) : invariant(name in this.constructor.childContextTypes));
+ }
+ return assign({}, currentContext, childContext);
+ }
+ return currentContext;
+ },
+
+ /**
+ * Processes props by setting default values for unspecified props and
+ * asserting that the props are valid. Does not mutate its argument; returns
+ * a new props object with defaults merged in.
+ *
+ * @param {object} newProps
+ * @return {object}
+ * @private
+ */
+ _processProps: function(newProps) {
+ if ("production" !== process.env.NODE_ENV) {
+ var propTypes = this.constructor.propTypes;
+ if (propTypes) {
+ this._checkPropTypes(propTypes, newProps, ReactPropTypeLocations.prop);
+ }
+ }
+ return newProps;
+ },
+
+ /**
+ * Assert that the props are valid
+ *
+ * @param {object} propTypes Map of prop name to a ReactPropType
+ * @param {object} props
+ * @param {string} location e.g. "prop", "context", "child context"
+ * @private
+ */
+ _checkPropTypes: function(propTypes, props, location) {
+ // TODO: Stop validating prop types here and only use the element
+ // validation.
+ var componentName = this.constructor.displayName;
+ for (var propName in propTypes) {
+ if (propTypes.hasOwnProperty(propName)) {
+ var error =
+ propTypes[propName](props, propName, componentName, location);
+ if (error instanceof Error) {
+ // We may want to extend this logic for similar errors in
+ // renderComponent calls, so I'm abstracting it away into
+ // a function to minimize refactoring in the future
+ var addendum = getDeclarationErrorAddendum(this);
+ ("production" !== process.env.NODE_ENV ? warning(false, error.message + addendum) : null);
+ }
+ }
+ }
+ },
+
+ /**
+ * If any of `_pendingElement`, `_pendingState`, or `_pendingForceUpdate`
+ * is set, update the component.
+ *
+ * @param {ReactReconcileTransaction} transaction
+ * @internal
+ */
+ performUpdateIfNecessary: function(transaction) {
+ var compositeLifeCycleState = this._compositeLifeCycleState;
+ // Do not trigger a state transition if we are in the middle of mounting or
+ // receiving props because both of those will already be doing this.
+ if (compositeLifeCycleState === CompositeLifeCycle.MOUNTING ||
+ compositeLifeCycleState === CompositeLifeCycle.RECEIVING_PROPS) {
+ return;
+ }
+
+ if (this._pendingElement == null &&
+ this._pendingState == null &&
+ !this._pendingForceUpdate) {
+ return;
+ }
+
+ var nextContext = this.context;
+ var nextProps = this.props;
+ var nextElement = this._currentElement;
+ if (this._pendingElement != null) {
+ nextElement = this._pendingElement;
+ nextContext = this._processContext(nextElement._context);
+ nextProps = this._processProps(nextElement.props);
+ this._pendingElement = null;
+
+ this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_PROPS;
+ if (this.componentWillReceiveProps) {
+ this.componentWillReceiveProps(nextProps, nextContext);
+ }
+ }
+
+ this._compositeLifeCycleState = null;
+
+ var nextState = this._pendingState || this.state;
+ this._pendingState = null;
+
+ var shouldUpdate =
+ this._pendingForceUpdate ||
+ !this.shouldComponentUpdate ||
+ this.shouldComponentUpdate(nextProps, nextState, nextContext);
+
+ if ("production" !== process.env.NODE_ENV) {
+ if (typeof shouldUpdate === "undefined") {
+ console.warn(
+ (this.constructor.displayName || 'ReactCompositeComponent') +
+ '.shouldComponentUpdate(): Returned undefined instead of a ' +
+ 'boolean value. Make sure to return true or false.'
+ );
+ }
+ }
+
+ if (shouldUpdate) {
+ this._pendingForceUpdate = false;
+ // Will set `this.props`, `this.state` and `this.context`.
+ this._performComponentUpdate(
+ nextElement,
+ nextProps,
+ nextState,
+ nextContext,
+ transaction
+ );
+ } else {
+ // If it's determined that a component should not update, we still want
+ // to set props and state.
+ this._currentElement = nextElement;
+ this.props = nextProps;
+ this.state = nextState;
+ this.context = nextContext;
+
+ // Owner cannot change because shouldUpdateReactComponent doesn't allow
+ // it. TODO: Remove this._owner completely.
+ this._owner = nextElement._owner;
+ }
+ },
+
+ /**
+ * Merges new props and state, notifies delegate methods of update and
+ * performs update.
+ *
+ * @param {ReactElement} nextElement Next element
+ * @param {object} nextProps Next public object to set as properties.
+ * @param {?object} nextState Next object to set as state.
+ * @param {?object} nextContext Next public object to set as context.
+ * @param {ReactReconcileTransaction} transaction
+ * @private
+ */
+ _performComponentUpdate: function(
+ nextElement,
+ nextProps,
+ nextState,
+ nextContext,
+ transaction
+ ) {
+ var prevElement = this._currentElement;
+ var prevProps = this.props;
+ var prevState = this.state;
+ var prevContext = this.context;
+
+ if (this.componentWillUpdate) {
+ this.componentWillUpdate(nextProps, nextState, nextContext);
+ }
+
+ this._currentElement = nextElement;
+ this.props = nextProps;
+ this.state = nextState;
+ this.context = nextContext;
+
+ // Owner cannot change because shouldUpdateReactComponent doesn't allow
+ // it. TODO: Remove this._owner completely.
+ this._owner = nextElement._owner;
+
+ this.updateComponent(
+ transaction,
+ prevElement
+ );
+
+ if (this.componentDidUpdate) {
+ transaction.getReactMountReady().enqueue(
+ this.componentDidUpdate.bind(this, prevProps, prevState, prevContext),
+ this
+ );
+ }
+ },
+
+ receiveComponent: function(nextElement, transaction) {
+ if (nextElement === this._currentElement &&
+ nextElement._owner != null) {
+ // Since elements are immutable after the owner is rendered,
+ // we can do a cheap identity compare here to determine if this is a
+ // superfluous reconcile. It's possible for state to be mutable but such
+ // change should trigger an update of the owner which would recreate
+ // the element. We explicitly check for the existence of an owner since
+ // it's possible for a element created outside a composite to be
+ // deeply mutated and reused.
+ return;
+ }
+
+ ReactComponent.Mixin.receiveComponent.call(
+ this,
+ nextElement,
+ transaction
+ );
+ },
+
+ /**
+ * Updates the component's currently mounted DOM representation.
+ *
+ * By default, this implements React's rendering and reconciliation algorithm.
+ * Sophisticated clients may wish to override this.
+ *
+ * @param {ReactReconcileTransaction} transaction
+ * @param {ReactElement} prevElement
+ * @internal
+ * @overridable
+ */
+ updateComponent: ReactPerf.measure(
+ 'ReactCompositeComponent',
+ 'updateComponent',
+ function(transaction, prevParentElement) {
+ ReactComponent.Mixin.updateComponent.call(
+ this,
+ transaction,
+ prevParentElement
+ );
+
+ var prevComponentInstance = this._renderedComponent;
+ var prevElement = prevComponentInstance._currentElement;
+ var nextElement = this._renderValidatedComponent();
+ if (shouldUpdateReactComponent(prevElement, nextElement)) {
+ prevComponentInstance.receiveComponent(nextElement, transaction);
+ } else {
+ // These two IDs are actually the same! But nothing should rely on that.
+ var thisID = this._rootNodeID;
+ var prevComponentID = prevComponentInstance._rootNodeID;
+ prevComponentInstance.unmountComponent();
+ this._renderedComponent = instantiateReactComponent(
+ nextElement,
+ this._currentElement.type
+ );
+ var nextMarkup = this._renderedComponent.mountComponent(
+ thisID,
+ transaction,
+ this._mountDepth + 1
+ );
+ ReactComponent.BackendIDOperations.dangerouslyReplaceNodeWithMarkupByID(
+ prevComponentID,
+ nextMarkup
+ );
+ }
+ }
+ ),
+
+ /**
+ * Forces an update. This should only be invoked when it is known with
+ * certainty that we are **not** in a DOM transaction.
+ *
+ * You may want to call this when you know that some deeper aspect of the
+ * component's state has changed but `setState` was not called.
+ *
+ * This will not invoke `shouldUpdateComponent`, but it will invoke
+ * `componentWillUpdate` and `componentDidUpdate`.
+ *
+ * @param {?function} callback Called after update is complete.
+ * @final
+ * @protected
+ */
+ forceUpdate: function(callback) {
+ var compositeLifeCycleState = this._compositeLifeCycleState;
+ ("production" !== process.env.NODE_ENV ? invariant(
+ this.isMounted() ||
+ compositeLifeCycleState === CompositeLifeCycle.MOUNTING,
+ 'forceUpdate(...): Can only force an update on mounted or mounting ' +
+ 'components.'
+ ) : invariant(this.isMounted() ||
+ compositeLifeCycleState === CompositeLifeCycle.MOUNTING));
+ ("production" !== process.env.NODE_ENV ? invariant(
+ compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING &&
+ ReactCurrentOwner.current == null,
+ 'forceUpdate(...): Cannot force an update while unmounting component ' +
+ 'or within a `render` function.'
+ ) : invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING &&
+ ReactCurrentOwner.current == null));
+ this._pendingForceUpdate = true;
+ ReactUpdates.enqueueUpdate(this, callback);
+ },
+
+ /**
+ * @private
+ */
+ _renderValidatedComponent: ReactPerf.measure(
+ 'ReactCompositeComponent',
+ '_renderValidatedComponent',
+ function() {
+ var renderedComponent;
+ var previousContext = ReactContext.current;
+ ReactContext.current = this._processChildContext(
+ this._currentElement._context
+ );
+ ReactCurrentOwner.current = this;
+ try {
+ renderedComponent = this.render();
+ if (renderedComponent === null || renderedComponent === false) {
+ renderedComponent = ReactEmptyComponent.getEmptyComponent();
+ ReactEmptyComponent.registerNullComponentID(this._rootNodeID);
+ } else {
+ ReactEmptyComponent.deregisterNullComponentID(this._rootNodeID);
+ }
+ } finally {
+ ReactContext.current = previousContext;
+ ReactCurrentOwner.current = null;
+ }
+ ("production" !== process.env.NODE_ENV ? invariant(
+ ReactElement.isValidElement(renderedComponent),
+ '%s.render(): A valid ReactComponent must be returned. You may have ' +
+ 'returned undefined, an array or some other invalid object.',
+ this.constructor.displayName || 'ReactCompositeComponent'
+ ) : invariant(ReactElement.isValidElement(renderedComponent)));
+ return renderedComponent;
+ }
+ ),
+
+ /**
+ * @private
+ */
+ _bindAutoBindMethods: function() {
+ for (var autoBindKey in this.__reactAutoBindMap) {
+ if (!this.__reactAutoBindMap.hasOwnProperty(autoBindKey)) {
+ continue;
+ }
+ var method = this.__reactAutoBindMap[autoBindKey];
+ this[autoBindKey] = this._bindAutoBindMethod(ReactErrorUtils.guard(
+ method,
+ this.constructor.displayName + '.' + autoBindKey
+ ));
+ }
+ },
+
+ /**
+ * Binds a method to the component.
+ *
+ * @param {function} method Method to be bound.
+ * @private
+ */
+ _bindAutoBindMethod: function(method) {
+ var component = this;
+ var boundMethod = method.bind(component);
+ if ("production" !== process.env.NODE_ENV) {
+ boundMethod.__reactBoundContext = component;
+ boundMethod.__reactBoundMethod = method;
+ boundMethod.__reactBoundArguments = null;
+ var componentName = component.constructor.displayName;
+ var _bind = boundMethod.bind;
+ boundMethod.bind = function(newThis ) {for (var args=[],$__0=1,$__1=arguments.length;$__0<$__1;$__0++) args.push(arguments[$__0]);
+ // User is trying to bind() an autobound method; we effectively will
+ // ignore the value of "this" that the user is trying to use, so
+ // let's warn.
+ if (newThis !== component && newThis !== null) {
+ monitorCodeUse('react_bind_warning', { component: componentName });
+ console.warn(
+ 'bind(): React component methods may only be bound to the ' +
+ 'component instance. See ' + componentName
+ );
+ } else if (!args.length) {
+ monitorCodeUse('react_bind_warning', { component: componentName });
+ console.warn(
+ 'bind(): You are binding a component method to the component. ' +
+ 'React does this for you automatically in a high-performance ' +
+ 'way, so you can safely remove this call. See ' + componentName
+ );
+ return boundMethod;
+ }
+ var reboundMethod = _bind.apply(boundMethod, arguments);
+ reboundMethod.__reactBoundContext = component;
+ reboundMethod.__reactBoundMethod = method;
+ reboundMethod.__reactBoundArguments = args;
+ return reboundMethod;
+ };
+ }
+ return boundMethod;
+ }
+};
+
+var ReactCompositeComponentBase = function() {};
+assign(
+ ReactCompositeComponentBase.prototype,
+ ReactComponent.Mixin,
+ ReactOwner.Mixin,
+ ReactPropTransferer.Mixin,
+ ReactCompositeComponentMixin
+);
+
+/**
+ * Module for creating composite components.
+ *
+ * @class ReactCompositeComponent
+ * @extends ReactComponent
+ * @extends ReactOwner
+ * @extends ReactPropTransferer
+ */
+var ReactCompositeComponent = {
+
+ LifeCycle: CompositeLifeCycle,
+
+ Base: ReactCompositeComponentBase,
+
+ /**
+ * Creates a composite component class given a class specification.
+ *
+ * @param {object} spec Class specification (which must define `render`).
+ * @return {function} Component constructor function.
+ * @public
+ */
+ createClass: function(spec) {
+ var Constructor = function(props) {
+ // This constructor is overridden by mocks. The argument is used
+ // by mocks to assert on what gets mounted. This will later be used
+ // by the stand-alone class implementation.
+ };
+ Constructor.prototype = new ReactCompositeComponentBase();
+ Constructor.prototype.constructor = Constructor;
+
+ injectedMixins.forEach(
+ mixSpecIntoComponent.bind(null, Constructor)
+ );
+
+ mixSpecIntoComponent(Constructor, spec);
+
+ // Initialize the defaultProps property after all mixins have been merged
+ if (Constructor.getDefaultProps) {
+ Constructor.defaultProps = Constructor.getDefaultProps();
+ }
+
+ ("production" !== process.env.NODE_ENV ? invariant(
+ Constructor.prototype.render,
+ 'createClass(...): Class specification must implement a `render` method.'
+ ) : invariant(Constructor.prototype.render));
+
+ if ("production" !== process.env.NODE_ENV) {
+ if (Constructor.prototype.componentShouldUpdate) {
+ monitorCodeUse(
+ 'react_component_should_update_warning',
+ { component: spec.displayName }
+ );
+ console.warn(
+ (spec.displayName || 'A component') + ' has a method called ' +
+ 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
+ 'The name is phrased as a question because the function is ' +
+ 'expected to return a value.'
+ );
+ }
+ }
+
+ // Reduce time spent doing lookups by setting these on the prototype.
+ for (var methodName in ReactCompositeComponentInterface) {
+ if (!Constructor.prototype[methodName]) {
+ Constructor.prototype[methodName] = null;
+ }
+ }
+
+ if ("production" !== process.env.NODE_ENV) {
+ return ReactLegacyElement.wrapFactory(
+ ReactElementValidator.createFactory(Constructor)
+ );
+ }
+ return ReactLegacyElement.wrapFactory(
+ ReactElement.createFactory(Constructor)
+ );
+ },
+
+ injection: {
+ injectMixin: function(mixin) {
+ injectedMixins.push(mixin);
+ }
+ }
+};
+
+module.exports = ReactCompositeComponent;
+
+}).call(this,require('_process'))
+},{"./Object.assign":75,"./ReactComponent":83,"./ReactContext":87,"./ReactCurrentOwner":88,"./ReactElement":104,"./ReactElementValidator":105,"./ReactEmptyComponent":106,"./ReactErrorUtils":107,"./ReactLegacyElement":113,"./ReactOwner":120,"./ReactPerf":121,"./ReactPropTransferer":122,"./ReactPropTypeLocationNames":123,"./ReactPropTypeLocations":124,"./ReactUpdates":137,"./instantiateReactComponent":186,"./invariant":187,"./keyMirror":193,"./keyOf":194,"./mapObject":195,"./monitorCodeUse":197,"./shouldUpdateReactComponent":203,"./warning":207,"_process":5}],87:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactContext
+ */
+
+"use strict";
+
+var assign = require("./Object.assign");
+
+/**
+ * Keeps track of the current context.
+ *
+ * The context is automatically passed down the component ownership hierarchy
+ * and is accessible via `this.context` on ReactCompositeComponents.
+ */
+var ReactContext = {
+
+ /**
+ * @internal
+ * @type {object}
+ */
+ current: {},
+
+ /**
+ * Temporarily extends the current context while executing scopedCallback.
+ *
+ * A typical use case might look like
+ *
+ * render: function() {
+ * var children = ReactContext.withContext({foo: 'foo'}, () => (
+ *
+ * ));
+ * return <div>{children}</div>;
+ * }
+ *
+ * @param {object} newContext New context to merge into the existing context
+ * @param {function} scopedCallback Callback to run with the new context
+ * @return {ReactComponent|array<ReactComponent>}
+ */
+ withContext: function(newContext, scopedCallback) {
+ var result;
+ var previousContext = ReactContext.current;
+ ReactContext.current = assign({}, previousContext, newContext);
+ try {
+ result = scopedCallback();
+ } finally {
+ ReactContext.current = previousContext;
+ }
+ return result;
+ }
+
+};
+
+module.exports = ReactContext;
+
+},{"./Object.assign":75}],88:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactCurrentOwner
+ */
+
+"use strict";
+
+/**
+ * Keeps track of the current owner.
+ *
+ * The current owner is the component who should own any components that are
+ * currently being constructed.
+ *
+ * The depth indicate how many composite components are above this render level.
+ */
+var ReactCurrentOwner = {
+
+ /**
+ * @internal
+ * @type {ReactComponent}
+ */
+ current: null
+
+};
+
+module.exports = ReactCurrentOwner;
+
+},{}],89:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOM
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var ReactElement = require("./ReactElement");
+var ReactElementValidator = require("./ReactElementValidator");
+var ReactLegacyElement = require("./ReactLegacyElement");
+
+var mapObject = require("./mapObject");
+
+/**
+ * Create a factory that creates HTML tag elements.
+ *
+ * @param {string} tag Tag name (e.g. `div`).
+ * @private
+ */
+function createDOMFactory(tag) {
+ if ("production" !== process.env.NODE_ENV) {
+ return ReactLegacyElement.markNonLegacyFactory(
+ ReactElementValidator.createFactory(tag)
+ );
+ }
+ return ReactLegacyElement.markNonLegacyFactory(
+ ReactElement.createFactory(tag)
+ );
+}
+
+/**
+ * Creates a mapping from supported HTML tags to `ReactDOMComponent` classes.
+ * This is also accessible via `React.DOM`.
+ *
+ * @public
+ */
+var ReactDOM = mapObject({
+ a: 'a',
+ abbr: 'abbr',
+ address: 'address',
+ area: 'area',
+ article: 'article',
+ aside: 'aside',
+ audio: 'audio',
+ b: 'b',
+ base: 'base',
+ bdi: 'bdi',
+ bdo: 'bdo',
+ big: 'big',
+ blockquote: 'blockquote',
+ body: 'body',
+ br: 'br',
+ button: 'button',
+ canvas: 'canvas',
+ caption: 'caption',
+ cite: 'cite',
+ code: 'code',
+ col: 'col',
+ colgroup: 'colgroup',
+ data: 'data',
+ datalist: 'datalist',
+ dd: 'dd',
+ del: 'del',
+ details: 'details',
+ dfn: 'dfn',
+ dialog: 'dialog',
+ div: 'div',
+ dl: 'dl',
+ dt: 'dt',
+ em: 'em',
+ embed: 'embed',
+ fieldset: 'fieldset',
+ figcaption: 'figcaption',
+ figure: 'figure',
+ footer: 'footer',
+ form: 'form',
+ h1: 'h1',
+ h2: 'h2',
+ h3: 'h3',
+ h4: 'h4',
+ h5: 'h5',
+ h6: 'h6',
+ head: 'head',
+ header: 'header',
+ hr: 'hr',
+ html: 'html',
+ i: 'i',
+ iframe: 'iframe',
+ img: 'img',
+ input: 'input',
+ ins: 'ins',
+ kbd: 'kbd',
+ keygen: 'keygen',
+ label: 'label',
+ legend: 'legend',
+ li: 'li',
+ link: 'link',
+ main: 'main',
+ map: 'map',
+ mark: 'mark',
+ menu: 'menu',
+ menuitem: 'menuitem',
+ meta: 'meta',
+ meter: 'meter',
+ nav: 'nav',
+ noscript: 'noscript',
+ object: 'object',
+ ol: 'ol',
+ optgroup: 'optgroup',
+ option: 'option',
+ output: 'output',
+ p: 'p',
+ param: 'param',
+ picture: 'picture',
+ pre: 'pre',
+ progress: 'progress',
+ q: 'q',
+ rp: 'rp',
+ rt: 'rt',
+ ruby: 'ruby',
+ s: 's',
+ samp: 'samp',
+ script: 'script',
+ section: 'section',
+ select: 'select',
+ small: 'small',
+ source: 'source',
+ span: 'span',
+ strong: 'strong',
+ style: 'style',
+ sub: 'sub',
+ summary: 'summary',
+ sup: 'sup',
+ table: 'table',
+ tbody: 'tbody',
+ td: 'td',
+ textarea: 'textarea',
+ tfoot: 'tfoot',
+ th: 'th',
+ thead: 'thead',
+ time: 'time',
+ title: 'title',
+ tr: 'tr',
+ track: 'track',
+ u: 'u',
+ ul: 'ul',
+ 'var': 'var',
+ video: 'video',
+ wbr: 'wbr',
+
+ // SVG
+ circle: 'circle',
+ defs: 'defs',
+ ellipse: 'ellipse',
+ g: 'g',
+ line: 'line',
+ linearGradient: 'linearGradient',
+ mask: 'mask',
+ path: 'path',
+ pattern: 'pattern',
+ polygon: 'polygon',
+ polyline: 'polyline',
+ radialGradient: 'radialGradient',
+ rect: 'rect',
+ stop: 'stop',
+ svg: 'svg',
+ text: 'text',
+ tspan: 'tspan'
+
+}, createDOMFactory);
+
+module.exports = ReactDOM;
+
+}).call(this,require('_process'))
+},{"./ReactElement":104,"./ReactElementValidator":105,"./ReactLegacyElement":113,"./mapObject":195,"_process":5}],90:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMButton
+ */
+
+"use strict";
+
+var AutoFocusMixin = require("./AutoFocusMixin");
+var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
+var ReactCompositeComponent = require("./ReactCompositeComponent");
+var ReactElement = require("./ReactElement");
+var ReactDOM = require("./ReactDOM");
+
+var keyMirror = require("./keyMirror");
+
+// Store a reference to the <button> `ReactDOMComponent`. TODO: use string
+var button = ReactElement.createFactory(ReactDOM.button.type);
+
+var mouseListenerNames = keyMirror({
+ onClick: true,
+ onDoubleClick: true,
+ onMouseDown: true,
+ onMouseMove: true,
+ onMouseUp: true,
+ onClickCapture: true,
+ onDoubleClickCapture: true,
+ onMouseDownCapture: true,
+ onMouseMoveCapture: true,
+ onMouseUpCapture: true
+});
+
+/**
+ * Implements a <button> native component that does not receive mouse events
+ * when `disabled` is set.
+ */
+var ReactDOMButton = ReactCompositeComponent.createClass({
+ displayName: 'ReactDOMButton',
+
+ mixins: [AutoFocusMixin, ReactBrowserComponentMixin],
+
+ render: function() {
+ var props = {};
+
+ // Copy the props; except the mouse listeners if we're disabled
+ for (var key in this.props) {
+ if (this.props.hasOwnProperty(key) &&
+ (!this.props.disabled || !mouseListenerNames[key])) {
+ props[key] = this.props[key];
+ }
+ }
+
+ return button(props, this.props.children);
+ }
+
+});
+
+module.exports = ReactDOMButton;
+
+},{"./AutoFocusMixin":48,"./ReactBrowserComponentMixin":78,"./ReactCompositeComponent":86,"./ReactDOM":89,"./ReactElement":104,"./keyMirror":193}],91:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMComponent
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var CSSPropertyOperations = require("./CSSPropertyOperations");
+var DOMProperty = require("./DOMProperty");
+var DOMPropertyOperations = require("./DOMPropertyOperations");
+var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
+var ReactComponent = require("./ReactComponent");
+var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");
+var ReactMount = require("./ReactMount");
+var ReactMultiChild = require("./ReactMultiChild");
+var ReactPerf = require("./ReactPerf");
+
+var assign = require("./Object.assign");
+var escapeTextForBrowser = require("./escapeTextForBrowser");
+var invariant = require("./invariant");
+var isEventSupported = require("./isEventSupported");
+var keyOf = require("./keyOf");
+var monitorCodeUse = require("./monitorCodeUse");
+
+var deleteListener = ReactBrowserEventEmitter.deleteListener;
+var listenTo = ReactBrowserEventEmitter.listenTo;
+var registrationNameModules = ReactBrowserEventEmitter.registrationNameModules;
+
+// For quickly matching children type, to test if can be treated as content.
+var CONTENT_TYPES = {'string': true, 'number': true};
+
+var STYLE = keyOf({style: null});
+
+var ELEMENT_NODE_TYPE = 1;
+
+/**
+ * @param {?object} props
+ */
+function assertValidProps(props) {
+ if (!props) {
+ return;
+ }
+ // Note the use of `==` which checks for null or undefined.
+ ("production" !== process.env.NODE_ENV ? invariant(
+ props.children == null || props.dangerouslySetInnerHTML == null,
+ 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.'
+ ) : invariant(props.children == null || props.dangerouslySetInnerHTML == null));
+ if ("production" !== process.env.NODE_ENV) {
+ if (props.contentEditable && props.children != null) {
+ console.warn(
+ 'A component is `contentEditable` and contains `children` managed by ' +
+ 'React. It is now your responsibility to guarantee that none of those '+
+ 'nodes are unexpectedly modified or duplicated. This is probably not ' +
+ 'intentional.'
+ );
+ }
+ }
+ ("production" !== process.env.NODE_ENV ? invariant(
+ props.style == null || typeof props.style === 'object',
+ 'The `style` prop expects a mapping from style properties to values, ' +
+ 'not a string.'
+ ) : invariant(props.style == null || typeof props.style === 'object'));
+}
+
+function putListener(id, registrationName, listener, transaction) {
+ if ("production" !== process.env.NODE_ENV) {
+ // IE8 has no API for event capturing and the `onScroll` event doesn't
+ // bubble.
+ if (registrationName === 'onScroll' &&
+ !isEventSupported('scroll', true)) {
+ monitorCodeUse('react_no_scroll_event');
+ console.warn('This browser doesn\'t support the `onScroll` event');
+ }
+ }
+ var container = ReactMount.findReactContainerForID(id);
+ if (container) {
+ var doc = container.nodeType === ELEMENT_NODE_TYPE ?
+ container.ownerDocument :
+ container;
+ listenTo(registrationName, doc);
+ }
+ transaction.getPutListenerQueue().enqueuePutListener(
+ id,
+ registrationName,
+ listener
+ );
+}
+
+// For HTML, certain tags should omit their close tag. We keep a whitelist for
+// those special cased tags.
+
+var omittedCloseTags = {
+ 'area': true,
+ 'base': true,
+ 'br': true,
+ 'col': true,
+ 'embed': true,
+ 'hr': true,
+ 'img': true,
+ 'input': true,
+ 'keygen': true,
+ 'link': true,
+ 'meta': true,
+ 'param': true,
+ 'source': true,
+ 'track': true,
+ 'wbr': true
+ // NOTE: menuitem's close tag should be omitted, but that causes problems.
+};
+
+// We accept any tag to be rendered but since this gets injected into abitrary
+// HTML, we want to make sure that it's a safe tag.
+// http://www.w3.org/TR/REC-xml/#NT-Name
+
+var VALID_TAG_REGEX = /^[a-zA-Z][a-zA-Z:_\.\-\d]*$/; // Simplified subset
+var validatedTagCache = {};
+var hasOwnProperty = {}.hasOwnProperty;
+
+function validateDangerousTag(tag) {
+ if (!hasOwnProperty.call(validatedTagCache, tag)) {
+ ("production" !== process.env.NODE_ENV ? invariant(VALID_TAG_REGEX.test(tag), 'Invalid tag: %s', tag) : invariant(VALID_TAG_REGEX.test(tag)));
+ validatedTagCache[tag] = true;
+ }
+}
+
+/**
+ * Creates a new React class that is idempotent and capable of containing other
+ * React components. It accepts event listeners and DOM properties that are
+ * valid according to `DOMProperty`.
+ *
+ * - Event listeners: `onClick`, `onMouseDown`, etc.
+ * - DOM properties: `className`, `name`, `title`, etc.
+ *
+ * The `style` property functions differently from the DOM API. It accepts an
+ * object mapping of style properties to values.
+ *
+ * @constructor ReactDOMComponent
+ * @extends ReactComponent
+ * @extends ReactMultiChild
+ */
+function ReactDOMComponent(tag) {
+ validateDangerousTag(tag);
+ this._tag = tag;
+ this.tagName = tag.toUpperCase();
+}
+
+ReactDOMComponent.displayName = 'ReactDOMComponent';
+
+ReactDOMComponent.Mixin = {
+
+ /**
+ * Generates root tag markup then recurses. This method has side effects and
+ * is not idempotent.
+ *
+ * @internal
+ * @param {string} rootID The root DOM ID for this node.
+ * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
+ * @param {number} mountDepth number of components in the owner hierarchy
+ * @return {string} The computed markup.
+ */
+ mountComponent: ReactPerf.measure(
+ 'ReactDOMComponent',
+ 'mountComponent',
+ function(rootID, transaction, mountDepth) {
+ ReactComponent.Mixin.mountComponent.call(
+ this,
+ rootID,
+ transaction,
+ mountDepth
+ );
+ assertValidProps(this.props);
+ var closeTag = omittedCloseTags[this._tag] ? '' : '</' + this._tag + '>';
+ return (
+ this._createOpenTagMarkupAndPutListeners(transaction) +
+ this._createContentMarkup(transaction) +
+ closeTag
+ );
+ }
+ ),
+
+ /**
+ * Creates markup for the open tag and all attributes.
+ *
+ * This method has side effects because events get registered.
+ *
+ * Iterating over object properties is faster than iterating over arrays.
+ * @see http://jsperf.com/obj-vs-arr-iteration
+ *
+ * @private
+ * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
+ * @return {string} Markup of opening tag.
+ */
+ _createOpenTagMarkupAndPutListeners: function(transaction) {
+ var props = this.props;
+ var ret = '<' + this._tag;
+
+ for (var propKey in props) {
+ if (!props.hasOwnProperty(propKey)) {
+ continue;
+ }
+ var propValue = props[propKey];
+ if (propValue == null) {
+ continue;
+ }
+ if (registrationNameModules.hasOwnProperty(propKey)) {
+ putListener(this._rootNodeID, propKey, propValue, transaction);
+ } else {
+ if (propKey === STYLE) {
+ if (propValue) {
+ propValue = props.style = assign({}, props.style);
+ }
+ propValue = CSSPropertyOperations.createMarkupForStyles(propValue);
+ }
+ var markup =
+ DOMPropertyOperations.createMarkupForProperty(propKey, propValue);
+ if (markup) {
+ ret += ' ' + markup;
+ }
+ }
+ }
+
+ // For static pages, no need to put React ID and checksum. Saves lots of
+ // bytes.
+ if (transaction.renderToStaticMarkup) {
+ return ret + '>';
+ }
+
+ var markupForID = DOMPropertyOperations.createMarkupForID(this._rootNodeID);
+ return ret + ' ' + markupForID + '>';
+ },
+
+ /**
+ * Creates markup for the content between the tags.
+ *
+ * @private
+ * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
+ * @return {string} Content markup.
+ */
+ _createContentMarkup: function(transaction) {
+ // Intentional use of != to avoid catching zero/false.
+ var innerHTML = this.props.dangerouslySetInnerHTML;
+ if (innerHTML != null) {
+ if (innerHTML.__html != null) {
+ return innerHTML.__html;
+ }
+ } else {
+ var contentToUse =
+ CONTENT_TYPES[typeof this.props.children] ? this.props.children : null;
+ var childrenToUse = contentToUse != null ? null : this.props.children;
+ if (contentToUse != null) {
+ return escapeTextForBrowser(contentToUse);
+ } else if (childrenToUse != null) {
+ var mountImages = this.mountChildren(
+ childrenToUse,
+ transaction
+ );
+ return mountImages.join('');
+ }
+ }
+ return '';
+ },
+
+ receiveComponent: function(nextElement, transaction) {
+ if (nextElement === this._currentElement &&
+ nextElement._owner != null) {
+ // Since elements are immutable after the owner is rendered,
+ // we can do a cheap identity compare here to determine if this is a
+ // superfluous reconcile. It's possible for state to be mutable but such
+ // change should trigger an update of the owner which would recreate
+ // the element. We explicitly check for the existence of an owner since
+ // it's possible for a element created outside a composite to be
+ // deeply mutated and reused.
+ return;
+ }
+
+ ReactComponent.Mixin.receiveComponent.call(
+ this,
+ nextElement,
+ transaction
+ );
+ },
+
+ /**
+ * Updates a native DOM component after it has already been allocated and
+ * attached to the DOM. Reconciles the root DOM node, then recurses.
+ *
+ * @param {ReactReconcileTransaction} transaction
+ * @param {ReactElement} prevElement
+ * @internal
+ * @overridable
+ */
+ updateComponent: ReactPerf.measure(
+ 'ReactDOMComponent',
+ 'updateComponent',
+ function(transaction, prevElement) {
+ assertValidProps(this._currentElement.props);
+ ReactComponent.Mixin.updateComponent.call(
+ this,
+ transaction,
+ prevElement
+ );
+ this._updateDOMProperties(prevElement.props, transaction);
+ this._updateDOMChildren(prevElement.props, transaction);
+ }
+ ),
+
+ /**
+ * Reconciles the properties by detecting differences in property values and
+ * updating the DOM as necessary. This function is probably the single most
+ * critical path for performance optimization.
+ *
+ * TODO: Benchmark whether checking for changed values in memory actually
+ * improves performance (especially statically positioned elements).
+ * TODO: Benchmark the effects of putting this at the top since 99% of props
+ * do not change for a given reconciliation.
+ * TODO: Benchmark areas that can be improved with caching.
+ *
+ * @private
+ * @param {object} lastProps
+ * @param {ReactReconcileTransaction} transaction
+ */
+ _updateDOMProperties: function(lastProps, transaction) {
+ var nextProps = this.props;
+ var propKey;
+ var styleName;
+ var styleUpdates;
+ for (propKey in lastProps) {
+ if (nextProps.hasOwnProperty(propKey) ||
+ !lastProps.hasOwnProperty(propKey)) {
+ continue;
+ }
+ if (propKey === STYLE) {
+ var lastStyle = lastProps[propKey];
+ for (styleName in lastStyle) {
+ if (lastStyle.hasOwnProperty(styleName)) {
+ styleUpdates = styleUpdates || {};
+ styleUpdates[styleName] = '';
+ }
+ }
+ } else if (registrationNameModules.hasOwnProperty(propKey)) {
+ deleteListener(this._rootNodeID, propKey);
+ } else if (
+ DOMProperty.isStandardName[propKey] ||
+ DOMProperty.isCustomAttribute(propKey)) {
+ ReactComponent.BackendIDOperations.deletePropertyByID(
+ this._rootNodeID,
+ propKey
+ );
+ }
+ }
+ for (propKey in nextProps) {
+ var nextProp = nextProps[propKey];
+ var lastProp = lastProps[propKey];
+ if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp) {
+ continue;
+ }
+ if (propKey === STYLE) {
+ if (nextProp) {
+ nextProp = nextProps.style = assign({}, nextProp);
+ }
+ if (lastProp) {
+ // Unset styles on `lastProp` but not on `nextProp`.
+ for (styleName in lastProp) {
+ if (lastProp.hasOwnProperty(styleName) &&
+ (!nextProp || !nextProp.hasOwnProperty(styleName))) {
+ styleUpdates = styleUpdates || {};
+ styleUpdates[styleName] = '';
+ }
+ }
+ // Update styles that changed since `lastProp`.
+ for (styleName in nextProp) {
+ if (nextProp.hasOwnProperty(styleName) &&
+ lastProp[styleName] !== nextProp[styleName]) {
+ styleUpdates = styleUpdates || {};
+ styleUpdates[styleName] = nextProp[styleName];
+ }
+ }
+ } else {
+ // Relies on `updateStylesByID` not mutating `styleUpdates`.
+ styleUpdates = nextProp;
+ }
+ } else if (registrationNameModules.hasOwnProperty(propKey)) {
+ putListener(this._rootNodeID, propKey, nextProp, transaction);
+ } else if (
+ DOMProperty.isStandardName[propKey] ||
+ DOMProperty.isCustomAttribute(propKey)) {
+ ReactComponent.BackendIDOperations.updatePropertyByID(
+ this._rootNodeID,
+ propKey,
+ nextProp
+ );
+ }
+ }
+ if (styleUpdates) {
+ ReactComponent.BackendIDOperations.updateStylesByID(
+ this._rootNodeID,
+ styleUpdates
+ );
+ }
+ },
+
+ /**
+ * Reconciles the children with the various properties that affect the
+ * children content.
+ *
+ * @param {object} lastProps
+ * @param {ReactReconcileTransaction} transaction
+ */
+ _updateDOMChildren: function(lastProps, transaction) {
+ var nextProps = this.props;
+
+ var lastContent =
+ CONTENT_TYPES[typeof lastProps.children] ? lastProps.children : null;
+ var nextContent =
+ CONTENT_TYPES[typeof nextProps.children] ? nextProps.children : null;
+
+ var lastHtml =
+ lastProps.dangerouslySetInnerHTML &&
+ lastProps.dangerouslySetInnerHTML.__html;
+ var nextHtml =
+ nextProps.dangerouslySetInnerHTML &&
+ nextProps.dangerouslySetInnerHTML.__html;
+
+ // Note the use of `!=` which checks for null or undefined.
+ var lastChildren = lastContent != null ? null : lastProps.children;
+ var nextChildren = nextContent != null ? null : nextProps.children;
+
+ // If we're switching from children to content/html or vice versa, remove
+ // the old content
+ var lastHasContentOrHtml = lastContent != null || lastHtml != null;
+ var nextHasContentOrHtml = nextContent != null || nextHtml != null;
+ if (lastChildren != null && nextChildren == null) {
+ this.updateChildren(null, transaction);
+ } else if (lastHasContentOrHtml && !nextHasContentOrHtml) {
+ this.updateTextContent('');
+ }
+
+ if (nextContent != null) {
+ if (lastContent !== nextContent) {
+ this.updateTextContent('' + nextContent);
+ }
+ } else if (nextHtml != null) {
+ if (lastHtml !== nextHtml) {
+ ReactComponent.BackendIDOperations.updateInnerHTMLByID(
+ this._rootNodeID,
+ nextHtml
+ );
+ }
+ } else if (nextChildren != null) {
+ this.updateChildren(nextChildren, transaction);
+ }
+ },
+
+ /**
+ * Destroys all event registrations for this instance. Does not remove from
+ * the DOM. That must be done by the parent.
+ *
+ * @internal
+ */
+ unmountComponent: function() {
+ this.unmountChildren();
+ ReactBrowserEventEmitter.deleteAllListeners(this._rootNodeID);
+ ReactComponent.Mixin.unmountComponent.call(this);
+ }
+
+};
+
+assign(
+ ReactDOMComponent.prototype,
+ ReactComponent.Mixin,
+ ReactDOMComponent.Mixin,
+ ReactMultiChild.Mixin,
+ ReactBrowserComponentMixin
+);
+
+module.exports = ReactDOMComponent;
+
+}).call(this,require('_process'))
+},{"./CSSPropertyOperations":52,"./DOMProperty":58,"./DOMPropertyOperations":59,"./Object.assign":75,"./ReactBrowserComponentMixin":78,"./ReactBrowserEventEmitter":79,"./ReactComponent":83,"./ReactMount":116,"./ReactMultiChild":117,"./ReactPerf":121,"./escapeTextForBrowser":170,"./invariant":187,"./isEventSupported":188,"./keyOf":194,"./monitorCodeUse":197,"_process":5}],92:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMForm
+ */
+
+"use strict";
+
+var EventConstants = require("./EventConstants");
+var LocalEventTrapMixin = require("./LocalEventTrapMixin");
+var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
+var ReactCompositeComponent = require("./ReactCompositeComponent");
+var ReactElement = require("./ReactElement");
+var ReactDOM = require("./ReactDOM");
+
+// Store a reference to the <form> `ReactDOMComponent`. TODO: use string
+var form = ReactElement.createFactory(ReactDOM.form.type);
+
+/**
+ * Since onSubmit doesn't bubble OR capture on the top level in IE8, we need
+ * to capture it on the <form> element itself. There are lots of hacks we could
+ * do to accomplish this, but the most reliable is to make <form> a
+ * composite component and use `componentDidMount` to attach the event handlers.
+ */
+var ReactDOMForm = ReactCompositeComponent.createClass({
+ displayName: 'ReactDOMForm',
+
+ mixins: [ReactBrowserComponentMixin, LocalEventTrapMixin],
+
+ render: function() {
+ // TODO: Instead of using `ReactDOM` directly, we should use JSX. However,
+ // `jshint` fails to parse JSX so in order for linting to work in the open
+ // source repo, we need to just use `ReactDOM.form`.
+ return form(this.props);
+ },
+
+ componentDidMount: function() {
+ this.trapBubbledEvent(EventConstants.topLevelTypes.topReset, 'reset');
+ this.trapBubbledEvent(EventConstants.topLevelTypes.topSubmit, 'submit');
+ }
+});
+
+module.exports = ReactDOMForm;
+
+},{"./EventConstants":63,"./LocalEventTrapMixin":73,"./ReactBrowserComponentMixin":78,"./ReactCompositeComponent":86,"./ReactDOM":89,"./ReactElement":104}],93:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMIDOperations
+ * @typechecks static-only
+ */
+
+/*jslint evil: true */
+
+"use strict";
+
+var CSSPropertyOperations = require("./CSSPropertyOperations");
+var DOMChildrenOperations = require("./DOMChildrenOperations");
+var DOMPropertyOperations = require("./DOMPropertyOperations");
+var ReactMount = require("./ReactMount");
+var ReactPerf = require("./ReactPerf");
+
+var invariant = require("./invariant");
+var setInnerHTML = require("./setInnerHTML");
+
+/**
+ * Errors for properties that should not be updated with `updatePropertyById()`.
+ *
+ * @type {object}
+ * @private
+ */
+var INVALID_PROPERTY_ERRORS = {
+ dangerouslySetInnerHTML:
+ '`dangerouslySetInnerHTML` must be set using `updateInnerHTMLByID()`.',
+ style: '`style` must be set using `updateStylesByID()`.'
+};
+
+/**
+ * Operations used to process updates to DOM nodes. This is made injectable via
+ * `ReactComponent.BackendIDOperations`.
+ */
+var ReactDOMIDOperations = {
+
+ /**
+ * Updates a DOM node with new property values. This should only be used to
+ * update DOM properties in `DOMProperty`.
+ *
+ * @param {string} id ID of the node to update.
+ * @param {string} name A valid property name, see `DOMProperty`.
+ * @param {*} value New value of the property.
+ * @internal
+ */
+ updatePropertyByID: ReactPerf.measure(
+ 'ReactDOMIDOperations',
+ 'updatePropertyByID',
+ function(id, name, value) {
+ var node = ReactMount.getNode(id);
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
+ 'updatePropertyByID(...): %s',
+ INVALID_PROPERTY_ERRORS[name]
+ ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name)));
+
+ // If we're updating to null or undefined, we should remove the property
+ // from the DOM node instead of inadvertantly setting to a string. This
+ // brings us in line with the same behavior we have on initial render.
+ if (value != null) {
+ DOMPropertyOperations.setValueForProperty(node, name, value);
+ } else {
+ DOMPropertyOperations.deleteValueForProperty(node, name);
+ }
+ }
+ ),
+
+ /**
+ * Updates a DOM node to remove a property. This should only be used to remove
+ * DOM properties in `DOMProperty`.
+ *
+ * @param {string} id ID of the node to update.
+ * @param {string} name A property name to remove, see `DOMProperty`.
+ * @internal
+ */
+ deletePropertyByID: ReactPerf.measure(
+ 'ReactDOMIDOperations',
+ 'deletePropertyByID',
+ function(id, name, value) {
+ var node = ReactMount.getNode(id);
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
+ 'updatePropertyByID(...): %s',
+ INVALID_PROPERTY_ERRORS[name]
+ ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name)));
+ DOMPropertyOperations.deleteValueForProperty(node, name, value);
+ }
+ ),
+
+ /**
+ * Updates a DOM node with new style values. If a value is specified as '',
+ * the corresponding style property will be unset.
+ *
+ * @param {string} id ID of the node to update.
+ * @param {object} styles Mapping from styles to values.
+ * @internal
+ */
+ updateStylesByID: ReactPerf.measure(
+ 'ReactDOMIDOperations',
+ 'updateStylesByID',
+ function(id, styles) {
+ var node = ReactMount.getNode(id);
+ CSSPropertyOperations.setValueForStyles(node, styles);
+ }
+ ),
+
+ /**
+ * Updates a DOM node's innerHTML.
+ *
+ * @param {string} id ID of the node to update.
+ * @param {string} html An HTML string.
+ * @internal
+ */
+ updateInnerHTMLByID: ReactPerf.measure(
+ 'ReactDOMIDOperations',
+ 'updateInnerHTMLByID',
+ function(id, html) {
+ var node = ReactMount.getNode(id);
+ setInnerHTML(node, html);
+ }
+ ),
+
+ /**
+ * Updates a DOM node's text content set by `props.content`.
+ *
+ * @param {string} id ID of the node to update.
+ * @param {string} content Text content.
+ * @internal
+ */
+ updateTextContentByID: ReactPerf.measure(
+ 'ReactDOMIDOperations',
+ 'updateTextContentByID',
+ function(id, content) {
+ var node = ReactMount.getNode(id);
+ DOMChildrenOperations.updateTextContent(node, content);
+ }
+ ),
+
+ /**
+ * Replaces a DOM node that exists in the document with markup.
+ *
+ * @param {string} id ID of child to be replaced.
+ * @param {string} markup Dangerous markup to inject in place of child.
+ * @internal
+ * @see {Danger.dangerouslyReplaceNodeWithMarkup}
+ */
+ dangerouslyReplaceNodeWithMarkupByID: ReactPerf.measure(
+ 'ReactDOMIDOperations',
+ 'dangerouslyReplaceNodeWithMarkupByID',
+ function(id, markup) {
+ var node = ReactMount.getNode(id);
+ DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup);
+ }
+ ),
+
+ /**
+ * Updates a component's children by processing a series of updates.
+ *
+ * @param {array<object>} updates List of update configurations.
+ * @param {array<string>} markup List of markup strings.
+ * @internal
+ */
+ dangerouslyProcessChildrenUpdates: ReactPerf.measure(
+ 'ReactDOMIDOperations',
+ 'dangerouslyProcessChildrenUpdates',
+ function(updates, markup) {
+ for (var i = 0; i < updates.length; i++) {
+ updates[i].parentNode = ReactMount.getNode(updates[i].parentID);
+ }
+ DOMChildrenOperations.processUpdates(updates, markup);
+ }
+ )
+};
+
+module.exports = ReactDOMIDOperations;
+
+}).call(this,require('_process'))
+},{"./CSSPropertyOperations":52,"./DOMChildrenOperations":57,"./DOMPropertyOperations":59,"./ReactMount":116,"./ReactPerf":121,"./invariant":187,"./setInnerHTML":201,"_process":5}],94:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMImg
+ */
+
+"use strict";
+
+var EventConstants = require("./EventConstants");
+var LocalEventTrapMixin = require("./LocalEventTrapMixin");
+var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
+var ReactCompositeComponent = require("./ReactCompositeComponent");
+var ReactElement = require("./ReactElement");
+var ReactDOM = require("./ReactDOM");
+
+// Store a reference to the <img> `ReactDOMComponent`. TODO: use string
+var img = ReactElement.createFactory(ReactDOM.img.type);
+
+/**
+ * Since onLoad doesn't bubble OR capture on the top level in IE8, we need to
+ * capture it on the <img> element itself. There are lots of hacks we could do
+ * to accomplish this, but the most reliable is to make <img> a composite
+ * component and use `componentDidMount` to attach the event handlers.
+ */
+var ReactDOMImg = ReactCompositeComponent.createClass({
+ displayName: 'ReactDOMImg',
+ tagName: 'IMG',
+
+ mixins: [ReactBrowserComponentMixin, LocalEventTrapMixin],
+
+ render: function() {
+ return img(this.props);
+ },
+
+ componentDidMount: function() {
+ this.trapBubbledEvent(EventConstants.topLevelTypes.topLoad, 'load');
+ this.trapBubbledEvent(EventConstants.topLevelTypes.topError, 'error');
+ }
+});
+
+module.exports = ReactDOMImg;
+
+},{"./EventConstants":63,"./LocalEventTrapMixin":73,"./ReactBrowserComponentMixin":78,"./ReactCompositeComponent":86,"./ReactDOM":89,"./ReactElement":104}],95:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMInput
+ */
+
+"use strict";
+
+var AutoFocusMixin = require("./AutoFocusMixin");
+var DOMPropertyOperations = require("./DOMPropertyOperations");
+var LinkedValueUtils = require("./LinkedValueUtils");
+var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
+var ReactCompositeComponent = require("./ReactCompositeComponent");
+var ReactElement = require("./ReactElement");
+var ReactDOM = require("./ReactDOM");
+var ReactMount = require("./ReactMount");
+var ReactUpdates = require("./ReactUpdates");
+
+var assign = require("./Object.assign");
+var invariant = require("./invariant");
+
+// Store a reference to the <input> `ReactDOMComponent`. TODO: use string
+var input = ReactElement.createFactory(ReactDOM.input.type);
+
+var instancesByReactID = {};
+
+function forceUpdateIfMounted() {
+ /*jshint validthis:true */
+ if (this.isMounted()) {
+ this.forceUpdate();
+ }
+}
+
+/**
+ * Implements an <input> native component that allows setting these optional
+ * props: `checked`, `value`, `defaultChecked`, and `defaultValue`.
+ *
+ * If `checked` or `value` are not supplied (or null/undefined), user actions
+ * that affect the checked state or value will trigger updates to the element.
+ *
+ * If they are supplied (and not null/undefined), the rendered element will not
+ * trigger updates to the element. Instead, the props must change in order for
+ * the rendered element to be updated.
+ *
+ * The rendered element will be initialized as unchecked (or `defaultChecked`)
+ * with an empty value (or `defaultValue`).
+ *
+ * @see http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html
+ */
+var ReactDOMInput = ReactCompositeComponent.createClass({
+ displayName: 'ReactDOMInput',
+
+ mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
+
+ getInitialState: function() {
+ var defaultValue = this.props.defaultValue;
+ return {
+ initialChecked: this.props.defaultChecked || false,
+ initialValue: defaultValue != null ? defaultValue : null
+ };
+ },
+
+ render: function() {
+ // Clone `this.props` so we don't mutate the input.
+ var props = assign({}, this.props);
+
+ props.defaultChecked = null;
+ props.defaultValue = null;
+
+ var value = LinkedValueUtils.getValue(this);
+ props.value = value != null ? value : this.state.initialValue;
+
+ var checked = LinkedValueUtils.getChecked(this);
+ props.checked = checked != null ? checked : this.state.initialChecked;
+
+ props.onChange = this._handleChange;
+
+ return input(props, this.props.children);
+ },
+
+ componentDidMount: function() {
+ var id = ReactMount.getID(this.getDOMNode());
+ instancesByReactID[id] = this;
+ },
+
+ componentWillUnmount: function() {
+ var rootNode = this.getDOMNode();
+ var id = ReactMount.getID(rootNode);
+ delete instancesByReactID[id];
+ },
+
+ componentDidUpdate: function(prevProps, prevState, prevContext) {
+ var rootNode = this.getDOMNode();
+ if (this.props.checked != null) {
+ DOMPropertyOperations.setValueForProperty(
+ rootNode,
+ 'checked',
+ this.props.checked || false
+ );
+ }
+
+ var value = LinkedValueUtils.getValue(this);
+ if (value != null) {
+ // Cast `value` to a string to ensure the value is set correctly. While
+ // browsers typically do this as necessary, jsdom doesn't.
+ DOMPropertyOperations.setValueForProperty(rootNode, 'value', '' + value);
+ }
+ },
+
+ _handleChange: function(event) {
+ var returnValue;
+ var onChange = LinkedValueUtils.getOnChange(this);
+ if (onChange) {
+ returnValue = onChange.call(this, event);
+ }
+ // Here we use asap to wait until all updates have propagated, which
+ // is important when using controlled components within layers:
+ // https://github.com/facebook/react/issues/1698
+ ReactUpdates.asap(forceUpdateIfMounted, this);
+
+ var name = this.props.name;
+ if (this.props.type === 'radio' && name != null) {
+ var rootNode = this.getDOMNode();
+ var queryRoot = rootNode;
+
+ while (queryRoot.parentNode) {
+ queryRoot = queryRoot.parentNode;
+ }
+
+ // If `rootNode.form` was non-null, then we could try `form.elements`,
+ // but that sometimes behaves strangely in IE8. We could also try using
+ // `form.getElementsByName`, but that will only return direct children
+ // and won't include inputs that use the HTML5 `form=` attribute. Since
+ // the input might not even be in a form, let's just use the global
+ // `querySelectorAll` to ensure we don't miss anything.
+ var group = queryRoot.querySelectorAll(
+ 'input[name=' + JSON.stringify('' + name) + '][type="radio"]');
+
+ for (var i = 0, groupLen = group.length; i < groupLen; i++) {
+ var otherNode = group[i];
+ if (otherNode === rootNode ||
+ otherNode.form !== rootNode.form) {
+ continue;
+ }
+ var otherID = ReactMount.getID(otherNode);
+ ("production" !== process.env.NODE_ENV ? invariant(
+ otherID,
+ 'ReactDOMInput: Mixing React and non-React radio inputs with the ' +
+ 'same `name` is not supported.'
+ ) : invariant(otherID));
+ var otherInstance = instancesByReactID[otherID];
+ ("production" !== process.env.NODE_ENV ? invariant(
+ otherInstance,
+ 'ReactDOMInput: Unknown radio button ID %s.',
+ otherID
+ ) : invariant(otherInstance));
+ // If this is a controlled radio button group, forcing the input that
+ // was previously checked to update will cause it to be come re-checked
+ // as appropriate.
+ ReactUpdates.asap(forceUpdateIfMounted, otherInstance);
+ }
+ }
+
+ return returnValue;
+ }
+
+});
+
+module.exports = ReactDOMInput;
+
+}).call(this,require('_process'))
+},{"./AutoFocusMixin":48,"./DOMPropertyOperations":59,"./LinkedValueUtils":72,"./Object.assign":75,"./ReactBrowserComponentMixin":78,"./ReactCompositeComponent":86,"./ReactDOM":89,"./ReactElement":104,"./ReactMount":116,"./ReactUpdates":137,"./invariant":187,"_process":5}],96:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMOption
+ */
+
+"use strict";
+
+var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
+var ReactCompositeComponent = require("./ReactCompositeComponent");
+var ReactElement = require("./ReactElement");
+var ReactDOM = require("./ReactDOM");
+
+var warning = require("./warning");
+
+// Store a reference to the <option> `ReactDOMComponent`. TODO: use string
+var option = ReactElement.createFactory(ReactDOM.option.type);
+
+/**
+ * Implements an <option> native component that warns when `selected` is set.
+ */
+var ReactDOMOption = ReactCompositeComponent.createClass({
+ displayName: 'ReactDOMOption',
+
+ mixins: [ReactBrowserComponentMixin],
+
+ componentWillMount: function() {
+ // TODO (yungsters): Remove support for `selected` in <option>.
+ if ("production" !== process.env.NODE_ENV) {
+ ("production" !== process.env.NODE_ENV ? warning(
+ this.props.selected == null,
+ 'Use the `defaultValue` or `value` props on <select> instead of ' +
+ 'setting `selected` on <option>.'
+ ) : null);
+ }
+ },
+
+ render: function() {
+ return option(this.props, this.props.children);
+ }
+
+});
+
+module.exports = ReactDOMOption;
+
+}).call(this,require('_process'))
+},{"./ReactBrowserComponentMixin":78,"./ReactCompositeComponent":86,"./ReactDOM":89,"./ReactElement":104,"./warning":207,"_process":5}],97:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMSelect
+ */
+
+"use strict";
+
+var AutoFocusMixin = require("./AutoFocusMixin");
+var LinkedValueUtils = require("./LinkedValueUtils");
+var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
+var ReactCompositeComponent = require("./ReactCompositeComponent");
+var ReactElement = require("./ReactElement");
+var ReactDOM = require("./ReactDOM");
+var ReactUpdates = require("./ReactUpdates");
+
+var assign = require("./Object.assign");
+
+// Store a reference to the <select> `ReactDOMComponent`. TODO: use string
+var select = ReactElement.createFactory(ReactDOM.select.type);
+
+function updateWithPendingValueIfMounted() {
+ /*jshint validthis:true */
+ if (this.isMounted()) {
+ this.setState({value: this._pendingValue});
+ this._pendingValue = 0;
+ }
+}
+
+/**
+ * Validation function for `value` and `defaultValue`.
+ * @private
+ */
+function selectValueType(props, propName, componentName) {
+ if (props[propName] == null) {
+ return;
+ }
+ if (props.multiple) {
+ if (!Array.isArray(props[propName])) {
+ return new Error(
+ ("The `" + propName + "` prop supplied to <select> must be an array if ") +
+ ("`multiple` is true.")
+ );
+ }
+ } else {
+ if (Array.isArray(props[propName])) {
+ return new Error(
+ ("The `" + propName + "` prop supplied to <select> must be a scalar ") +
+ ("value if `multiple` is false.")
+ );
+ }
+ }
+}
+
+/**
+ * If `value` is supplied, updates <option> elements on mount and update.
+ * @param {ReactComponent} component Instance of ReactDOMSelect
+ * @param {?*} propValue For uncontrolled components, null/undefined. For
+ * controlled components, a string (or with `multiple`, a list of strings).
+ * @private
+ */
+function updateOptions(component, propValue) {
+ var multiple = component.props.multiple;
+ var value = propValue != null ? propValue : component.state.value;
+ var options = component.getDOMNode().options;
+ var selectedValue, i, l;
+ if (multiple) {
+ selectedValue = {};
+ for (i = 0, l = value.length; i < l; ++i) {
+ selectedValue['' + value[i]] = true;
+ }
+ } else {
+ selectedValue = '' + value;
+ }
+ for (i = 0, l = options.length; i < l; i++) {
+ var selected = multiple ?
+ selectedValue.hasOwnProperty(options[i].value) :
+ options[i].value === selectedValue;
+
+ if (selected !== options[i].selected) {
+ options[i].selected = selected;
+ }
+ }
+}
+
+/**
+ * Implements a <select> native component that allows optionally setting the
+ * props `value` and `defaultValue`. If `multiple` is false, the prop must be a
+ * string. If `multiple` is true, the prop must be an array of strings.
+ *
+ * If `value` is not supplied (or null/undefined), user actions that change the
+ * selected option will trigger updates to the rendered options.
+ *
+ * If it is supplied (and not null/undefined), the rendered options will not
+ * update in response to user actions. Instead, the `value` prop must change in
+ * order for the rendered options to update.
+ *
+ * If `defaultValue` is provided, any options with the supplied values will be
+ * selected.
+ */
+var ReactDOMSelect = ReactCompositeComponent.createClass({
+ displayName: 'ReactDOMSelect',
+
+ mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
+
+ propTypes: {
+ defaultValue: selectValueType,
+ value: selectValueType
+ },
+
+ getInitialState: function() {
+ return {value: this.props.defaultValue || (this.props.multiple ? [] : '')};
+ },
+
+ componentWillMount: function() {
+ this._pendingValue = null;
+ },
+
+ componentWillReceiveProps: function(nextProps) {
+ if (!this.props.multiple && nextProps.multiple) {
+ this.setState({value: [this.state.value]});
+ } else if (this.props.multiple && !nextProps.multiple) {
+ this.setState({value: this.state.value[0]});
+ }
+ },
+
+ render: function() {
+ // Clone `this.props` so we don't mutate the input.
+ var props = assign({}, this.props);
+
+ props.onChange = this._handleChange;
+ props.value = null;
+
+ return select(props, this.props.children);
+ },
+
+ componentDidMount: function() {
+ updateOptions(this, LinkedValueUtils.getValue(this));
+ },
+
+ componentDidUpdate: function(prevProps) {
+ var value = LinkedValueUtils.getValue(this);
+ var prevMultiple = !!prevProps.multiple;
+ var multiple = !!this.props.multiple;
+ if (value != null || prevMultiple !== multiple) {
+ updateOptions(this, value);
+ }
+ },
+
+ _handleChange: function(event) {
+ var returnValue;
+ var onChange = LinkedValueUtils.getOnChange(this);
+ if (onChange) {
+ returnValue = onChange.call(this, event);
+ }
+
+ var selectedValue;
+ if (this.props.multiple) {
+ selectedValue = [];
+ var options = event.target.options;
+ for (var i = 0, l = options.length; i < l; i++) {
+ if (options[i].selected) {
+ selectedValue.push(options[i].value);
+ }
+ }
+ } else {
+ selectedValue = event.target.value;
+ }
+
+ this._pendingValue = selectedValue;
+ ReactUpdates.asap(updateWithPendingValueIfMounted, this);
+ return returnValue;
+ }
+
+});
+
+module.exports = ReactDOMSelect;
+
+},{"./AutoFocusMixin":48,"./LinkedValueUtils":72,"./Object.assign":75,"./ReactBrowserComponentMixin":78,"./ReactCompositeComponent":86,"./ReactDOM":89,"./ReactElement":104,"./ReactUpdates":137}],98:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMSelection
+ */
+
+"use strict";
+
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+
+var getNodeForCharacterOffset = require("./getNodeForCharacterOffset");
+var getTextContentAccessor = require("./getTextContentAccessor");
+
+/**
+ * While `isCollapsed` is available on the Selection object and `collapsed`
+ * is available on the Range object, IE11 sometimes gets them wrong.
+ * If the anchor/focus nodes and offsets are the same, the range is collapsed.
+ */
+function isCollapsed(anchorNode, anchorOffset, focusNode, focusOffset) {
+ return anchorNode === focusNode && anchorOffset === focusOffset;
+}
+
+/**
+ * Get the appropriate anchor and focus node/offset pairs for IE.
+ *
+ * The catch here is that IE's selection API doesn't provide information
+ * about whether the selection is forward or backward, so we have to
+ * behave as though it's always forward.
+ *
+ * IE text differs from modern selection in that it behaves as though
+ * block elements end with a new line. This means character offsets will
+ * differ between the two APIs.
+ *
+ * @param {DOMElement} node
+ * @return {object}
+ */
+function getIEOffsets(node) {
+ var selection = document.selection;
+ var selectedRange = selection.createRange();
+ var selectedLength = selectedRange.text.length;
+
+ // Duplicate selection so we can move range without breaking user selection.
+ var fromStart = selectedRange.duplicate();
+ fromStart.moveToElementText(node);
+ fromStart.setEndPoint('EndToStart', selectedRange);
+
+ var startOffset = fromStart.text.length;
+ var endOffset = startOffset + selectedLength;
+
+ return {
+ start: startOffset,
+ end: endOffset
+ };
+}
+
+/**
+ * @param {DOMElement} node
+ * @return {?object}
+ */
+function getModernOffsets(node) {
+ var selection = window.getSelection && window.getSelection();
+
+ if (!selection || selection.rangeCount === 0) {
+ return null;
+ }
+
+ var anchorNode = selection.anchorNode;
+ var anchorOffset = selection.anchorOffset;
+ var focusNode = selection.focusNode;
+ var focusOffset = selection.focusOffset;
+
+ var currentRange = selection.getRangeAt(0);
+
+ // If the node and offset values are the same, the selection is collapsed.
+ // `Selection.isCollapsed` is available natively, but IE sometimes gets
+ // this value wrong.
+ var isSelectionCollapsed = isCollapsed(
+ selection.anchorNode,
+ selection.anchorOffset,
+ selection.focusNode,
+ selection.focusOffset
+ );
+
+ var rangeLength = isSelectionCollapsed ? 0 : currentRange.toString().length;
+
+ var tempRange = currentRange.cloneRange();
+ tempRange.selectNodeContents(node);
+ tempRange.setEnd(currentRange.startContainer, currentRange.startOffset);
+
+ var isTempRangeCollapsed = isCollapsed(
+ tempRange.startContainer,
+ tempRange.startOffset,
+ tempRange.endContainer,
+ tempRange.endOffset
+ );
+
+ var start = isTempRangeCollapsed ? 0 : tempRange.toString().length;
+ var end = start + rangeLength;
+
+ // Detect whether the selection is backward.
+ var detectionRange = document.createRange();
+ detectionRange.setStart(anchorNode, anchorOffset);
+ detectionRange.setEnd(focusNode, focusOffset);
+ var isBackward = detectionRange.collapsed;
+
+ return {
+ start: isBackward ? end : start,
+ end: isBackward ? start : end
+ };
+}
+
+/**
+ * @param {DOMElement|DOMTextNode} node
+ * @param {object} offsets
+ */
+function setIEOffsets(node, offsets) {
+ var range = document.selection.createRange().duplicate();
+ var start, end;
+
+ if (typeof offsets.end === 'undefined') {
+ start = offsets.start;
+ end = start;
+ } else if (offsets.start > offsets.end) {
+ start = offsets.end;
+ end = offsets.start;
+ } else {
+ start = offsets.start;
+ end = offsets.end;
+ }
+
+ range.moveToElementText(node);
+ range.moveStart('character', start);
+ range.setEndPoint('EndToStart', range);
+ range.moveEnd('character', end - start);
+ range.select();
+}
+
+/**
+ * In modern non-IE browsers, we can support both forward and backward
+ * selections.
+ *
+ * Note: IE10+ supports the Selection object, but it does not support
+ * the `extend` method, which means that even in modern IE, it's not possible
+ * to programatically create a backward selection. Thus, for all IE
+ * versions, we use the old IE API to create our selections.
+ *
+ * @param {DOMElement|DOMTextNode} node
+ * @param {object} offsets
+ */
+function setModernOffsets(node, offsets) {
+ if (!window.getSelection) {
+ return;
+ }
+
+ var selection = window.getSelection();
+ var length = node[getTextContentAccessor()].length;
+ var start = Math.min(offsets.start, length);
+ var end = typeof offsets.end === 'undefined' ?
+ start : Math.min(offsets.end, length);
+
+ // IE 11 uses modern selection, but doesn't support the extend method.
+ // Flip backward selections, so we can set with a single range.
+ if (!selection.extend && start > end) {
+ var temp = end;
+ end = start;
+ start = temp;
+ }
+
+ var startMarker = getNodeForCharacterOffset(node, start);
+ var endMarker = getNodeForCharacterOffset(node, end);
+
+ if (startMarker && endMarker) {
+ var range = document.createRange();
+ range.setStart(startMarker.node, startMarker.offset);
+ selection.removeAllRanges();
+
+ if (start > end) {
+ selection.addRange(range);
+ selection.extend(endMarker.node, endMarker.offset);
+ } else {
+ range.setEnd(endMarker.node, endMarker.offset);
+ selection.addRange(range);
+ }
+ }
+}
+
+var useIEOffsets = ExecutionEnvironment.canUseDOM && document.selection;
+
+var ReactDOMSelection = {
+ /**
+ * @param {DOMElement} node
+ */
+ getOffsets: useIEOffsets ? getIEOffsets : getModernOffsets,
+
+ /**
+ * @param {DOMElement|DOMTextNode} node
+ * @param {object} offsets
+ */
+ setOffsets: useIEOffsets ? setIEOffsets : setModernOffsets
+};
+
+module.exports = ReactDOMSelection;
+
+},{"./ExecutionEnvironment":69,"./getNodeForCharacterOffset":180,"./getTextContentAccessor":182}],99:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMTextarea
+ */
+
+"use strict";
+
+var AutoFocusMixin = require("./AutoFocusMixin");
+var DOMPropertyOperations = require("./DOMPropertyOperations");
+var LinkedValueUtils = require("./LinkedValueUtils");
+var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
+var ReactCompositeComponent = require("./ReactCompositeComponent");
+var ReactElement = require("./ReactElement");
+var ReactDOM = require("./ReactDOM");
+var ReactUpdates = require("./ReactUpdates");
+
+var assign = require("./Object.assign");
+var invariant = require("./invariant");
+
+var warning = require("./warning");
+
+// Store a reference to the <textarea> `ReactDOMComponent`. TODO: use string
+var textarea = ReactElement.createFactory(ReactDOM.textarea.type);
+
+function forceUpdateIfMounted() {
+ /*jshint validthis:true */
+ if (this.isMounted()) {
+ this.forceUpdate();
+ }
+}
+
+/**
+ * Implements a <textarea> native component that allows setting `value`, and
+ * `defaultValue`. This differs from the traditional DOM API because value is
+ * usually set as PCDATA children.
+ *
+ * If `value` is not supplied (or null/undefined), user actions that affect the
+ * value will trigger updates to the element.
+ *
+ * If `value` is supplied (and not null/undefined), the rendered element will
+ * not trigger updates to the element. Instead, the `value` prop must change in
+ * order for the rendered element to be updated.
+ *
+ * The rendered element will be initialized with an empty value, the prop
+ * `defaultValue` if specified, or the children content (deprecated).
+ */
+var ReactDOMTextarea = ReactCompositeComponent.createClass({
+ displayName: 'ReactDOMTextarea',
+
+ mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
+
+ getInitialState: function() {
+ var defaultValue = this.props.defaultValue;
+ // TODO (yungsters): Remove support for children content in <textarea>.
+ var children = this.props.children;
+ if (children != null) {
+ if ("production" !== process.env.NODE_ENV) {
+ ("production" !== process.env.NODE_ENV ? warning(
+ false,
+ 'Use the `defaultValue` or `value` props instead of setting ' +
+ 'children on <textarea>.'
+ ) : null);
+ }
+ ("production" !== process.env.NODE_ENV ? invariant(
+ defaultValue == null,
+ 'If you supply `defaultValue` on a <textarea>, do not pass children.'
+ ) : invariant(defaultValue == null));
+ if (Array.isArray(children)) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ children.length <= 1,
+ '<textarea> can only have at most one child.'
+ ) : invariant(children.length <= 1));
+ children = children[0];
+ }
+
+ defaultValue = '' + children;
+ }
+ if (defaultValue == null) {
+ defaultValue = '';
+ }
+ var value = LinkedValueUtils.getValue(this);
+ return {
+ // We save the initial value so that `ReactDOMComponent` doesn't update
+ // `textContent` (unnecessary since we update value).
+ // The initial value can be a boolean or object so that's why it's
+ // forced to be a string.
+ initialValue: '' + (value != null ? value : defaultValue)
+ };
+ },
+
+ render: function() {
+ // Clone `this.props` so we don't mutate the input.
+ var props = assign({}, this.props);
+
+ ("production" !== process.env.NODE_ENV ? invariant(
+ props.dangerouslySetInnerHTML == null,
+ '`dangerouslySetInnerHTML` does not make sense on <textarea>.'
+ ) : invariant(props.dangerouslySetInnerHTML == null));
+
+ props.defaultValue = null;
+ props.value = null;
+ props.onChange = this._handleChange;
+
+ // Always set children to the same thing. In IE9, the selection range will
+ // get reset if `textContent` is mutated.
+ return textarea(props, this.state.initialValue);
+ },
+
+ componentDidUpdate: function(prevProps, prevState, prevContext) {
+ var value = LinkedValueUtils.getValue(this);
+ if (value != null) {
+ var rootNode = this.getDOMNode();
+ // Cast `value` to a string to ensure the value is set correctly. While
+ // browsers typically do this as necessary, jsdom doesn't.
+ DOMPropertyOperations.setValueForProperty(rootNode, 'value', '' + value);
+ }
+ },
+
+ _handleChange: function(event) {
+ var returnValue;
+ var onChange = LinkedValueUtils.getOnChange(this);
+ if (onChange) {
+ returnValue = onChange.call(this, event);
+ }
+ ReactUpdates.asap(forceUpdateIfMounted, this);
+ return returnValue;
+ }
+
+});
+
+module.exports = ReactDOMTextarea;
+
+}).call(this,require('_process'))
+},{"./AutoFocusMixin":48,"./DOMPropertyOperations":59,"./LinkedValueUtils":72,"./Object.assign":75,"./ReactBrowserComponentMixin":78,"./ReactCompositeComponent":86,"./ReactDOM":89,"./ReactElement":104,"./ReactUpdates":137,"./invariant":187,"./warning":207,"_process":5}],100:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDefaultBatchingStrategy
+ */
+
+"use strict";
+
+var ReactUpdates = require("./ReactUpdates");
+var Transaction = require("./Transaction");
+
+var assign = require("./Object.assign");
+var emptyFunction = require("./emptyFunction");
+
+var RESET_BATCHED_UPDATES = {
+ initialize: emptyFunction,
+ close: function() {
+ ReactDefaultBatchingStrategy.isBatchingUpdates = false;
+ }
+};
+
+var FLUSH_BATCHED_UPDATES = {
+ initialize: emptyFunction,
+ close: ReactUpdates.flushBatchedUpdates.bind(ReactUpdates)
+};
+
+var TRANSACTION_WRAPPERS = [FLUSH_BATCHED_UPDATES, RESET_BATCHED_UPDATES];
+
+function ReactDefaultBatchingStrategyTransaction() {
+ this.reinitializeTransaction();
+}
+
+assign(
+ ReactDefaultBatchingStrategyTransaction.prototype,
+ Transaction.Mixin,
+ {
+ getTransactionWrappers: function() {
+ return TRANSACTION_WRAPPERS;
+ }
+ }
+);
+
+var transaction = new ReactDefaultBatchingStrategyTransaction();
+
+var ReactDefaultBatchingStrategy = {
+ isBatchingUpdates: false,
+
+ /**
+ * Call the provided function in a context within which calls to `setState`
+ * and friends are batched such that components aren't updated unnecessarily.
+ */
+ batchedUpdates: function(callback, a, b) {
+ var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;
+
+ ReactDefaultBatchingStrategy.isBatchingUpdates = true;
+
+ // The code is written this way to avoid extra allocations
+ if (alreadyBatchingUpdates) {
+ callback(a, b);
+ } else {
+ transaction.perform(callback, null, a, b);
+ }
+ }
+};
+
+module.exports = ReactDefaultBatchingStrategy;
+
+},{"./Object.assign":75,"./ReactUpdates":137,"./Transaction":154,"./emptyFunction":168}],101:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDefaultInjection
+ */
+
+"use strict";
+
+var BeforeInputEventPlugin = require("./BeforeInputEventPlugin");
+var ChangeEventPlugin = require("./ChangeEventPlugin");
+var ClientReactRootIndex = require("./ClientReactRootIndex");
+var CompositionEventPlugin = require("./CompositionEventPlugin");
+var DefaultEventPluginOrder = require("./DefaultEventPluginOrder");
+var EnterLeaveEventPlugin = require("./EnterLeaveEventPlugin");
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+var HTMLDOMPropertyConfig = require("./HTMLDOMPropertyConfig");
+var MobileSafariClickEventPlugin = require("./MobileSafariClickEventPlugin");
+var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
+var ReactComponentBrowserEnvironment =
+ require("./ReactComponentBrowserEnvironment");
+var ReactDefaultBatchingStrategy = require("./ReactDefaultBatchingStrategy");
+var ReactDOMComponent = require("./ReactDOMComponent");
+var ReactDOMButton = require("./ReactDOMButton");
+var ReactDOMForm = require("./ReactDOMForm");
+var ReactDOMImg = require("./ReactDOMImg");
+var ReactDOMInput = require("./ReactDOMInput");
+var ReactDOMOption = require("./ReactDOMOption");
+var ReactDOMSelect = require("./ReactDOMSelect");
+var ReactDOMTextarea = require("./ReactDOMTextarea");
+var ReactEventListener = require("./ReactEventListener");
+var ReactInjection = require("./ReactInjection");
+var ReactInstanceHandles = require("./ReactInstanceHandles");
+var ReactMount = require("./ReactMount");
+var SelectEventPlugin = require("./SelectEventPlugin");
+var ServerReactRootIndex = require("./ServerReactRootIndex");
+var SimpleEventPlugin = require("./SimpleEventPlugin");
+var SVGDOMPropertyConfig = require("./SVGDOMPropertyConfig");
+
+var createFullPageComponent = require("./createFullPageComponent");
+
+function inject() {
+ ReactInjection.EventEmitter.injectReactEventListener(
+ ReactEventListener
+ );
+
+ /**
+ * Inject modules for resolving DOM hierarchy and plugin ordering.
+ */
+ ReactInjection.EventPluginHub.injectEventPluginOrder(DefaultEventPluginOrder);
+ ReactInjection.EventPluginHub.injectInstanceHandle(ReactInstanceHandles);
+ ReactInjection.EventPluginHub.injectMount(ReactMount);
+
+ /**
+ * Some important event plugins included by default (without having to require
+ * them).
+ */
+ ReactInjection.EventPluginHub.injectEventPluginsByName({
+ SimpleEventPlugin: SimpleEventPlugin,
+ EnterLeaveEventPlugin: EnterLeaveEventPlugin,
+ ChangeEventPlugin: ChangeEventPlugin,
+ CompositionEventPlugin: CompositionEventPlugin,
+ MobileSafariClickEventPlugin: MobileSafariClickEventPlugin,
+ SelectEventPlugin: SelectEventPlugin,
+ BeforeInputEventPlugin: BeforeInputEventPlugin
+ });
+
+ ReactInjection.NativeComponent.injectGenericComponentClass(
+ ReactDOMComponent
+ );
+
+ ReactInjection.NativeComponent.injectComponentClasses({
+ 'button': ReactDOMButton,
+ 'form': ReactDOMForm,
+ 'img': ReactDOMImg,
+ 'input': ReactDOMInput,
+ 'option': ReactDOMOption,
+ 'select': ReactDOMSelect,
+ 'textarea': ReactDOMTextarea,
+
+ 'html': createFullPageComponent('html'),
+ 'head': createFullPageComponent('head'),
+ 'body': createFullPageComponent('body')
+ });
+
+ // This needs to happen after createFullPageComponent() otherwise the mixin
+ // gets double injected.
+ ReactInjection.CompositeComponent.injectMixin(ReactBrowserComponentMixin);
+
+ ReactInjection.DOMProperty.injectDOMPropertyConfig(HTMLDOMPropertyConfig);
+ ReactInjection.DOMProperty.injectDOMPropertyConfig(SVGDOMPropertyConfig);
+
+ ReactInjection.EmptyComponent.injectEmptyComponent('noscript');
+
+ ReactInjection.Updates.injectReconcileTransaction(
+ ReactComponentBrowserEnvironment.ReactReconcileTransaction
+ );
+ ReactInjection.Updates.injectBatchingStrategy(
+ ReactDefaultBatchingStrategy
+ );
+
+ ReactInjection.RootIndex.injectCreateReactRootIndex(
+ ExecutionEnvironment.canUseDOM ?
+ ClientReactRootIndex.createReactRootIndex :
+ ServerReactRootIndex.createReactRootIndex
+ );
+
+ ReactInjection.Component.injectEnvironment(ReactComponentBrowserEnvironment);
+
+ if ("production" !== process.env.NODE_ENV) {
+ var url = (ExecutionEnvironment.canUseDOM && window.location.href) || '';
+ if ((/[?&]react_perf\b/).test(url)) {
+ var ReactDefaultPerf = require("./ReactDefaultPerf");
+ ReactDefaultPerf.start();
+ }
+ }
+}
+
+module.exports = {
+ inject: inject
+};
+
+}).call(this,require('_process'))
+},{"./BeforeInputEventPlugin":49,"./ChangeEventPlugin":54,"./ClientReactRootIndex":55,"./CompositionEventPlugin":56,"./DefaultEventPluginOrder":61,"./EnterLeaveEventPlugin":62,"./ExecutionEnvironment":69,"./HTMLDOMPropertyConfig":70,"./MobileSafariClickEventPlugin":74,"./ReactBrowserComponentMixin":78,"./ReactComponentBrowserEnvironment":84,"./ReactDOMButton":90,"./ReactDOMComponent":91,"./ReactDOMForm":92,"./ReactDOMImg":94,"./ReactDOMInput":95,"./ReactDOMOption":96,"./ReactDOMSelect":97,"./ReactDOMTextarea":99,"./ReactDefaultBatchingStrategy":100,"./ReactDefaultPerf":102,"./ReactEventListener":109,"./ReactInjection":110,"./ReactInstanceHandles":112,"./ReactMount":116,"./SVGDOMPropertyConfig":139,"./SelectEventPlugin":140,"./ServerReactRootIndex":141,"./SimpleEventPlugin":142,"./createFullPageComponent":163,"_process":5}],102:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDefaultPerf
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var DOMProperty = require("./DOMProperty");
+var ReactDefaultPerfAnalysis = require("./ReactDefaultPerfAnalysis");
+var ReactMount = require("./ReactMount");
+var ReactPerf = require("./ReactPerf");
+
+var performanceNow = require("./performanceNow");
+
+function roundFloat(val) {
+ return Math.floor(val * 100) / 100;
+}
+
+function addValue(obj, key, val) {
+ obj[key] = (obj[key] || 0) + val;
+}
+
+var ReactDefaultPerf = {
+ _allMeasurements: [], // last item in the list is the current one
+ _mountStack: [0],
+ _injected: false,
+
+ start: function() {
+ if (!ReactDefaultPerf._injected) {
+ ReactPerf.injection.injectMeasure(ReactDefaultPerf.measure);
+ }
+
+ ReactDefaultPerf._allMeasurements.length = 0;
+ ReactPerf.enableMeasure = true;
+ },
+
+ stop: function() {
+ ReactPerf.enableMeasure = false;
+ },
+
+ getLastMeasurements: function() {
+ return ReactDefaultPerf._allMeasurements;
+ },
+
+ printExclusive: function(measurements) {
+ measurements = measurements || ReactDefaultPerf._allMeasurements;
+ var summary = ReactDefaultPerfAnalysis.getExclusiveSummary(measurements);
+ console.table(summary.map(function(item) {
+ return {
+ 'Component class name': item.componentName,
+ 'Total inclusive time (ms)': roundFloat(item.inclusive),
+ 'Exclusive mount time (ms)': roundFloat(item.exclusive),
+ 'Exclusive render time (ms)': roundFloat(item.render),
+ 'Mount time per instance (ms)': roundFloat(item.exclusive / item.count),
+ 'Render time per instance (ms)': roundFloat(item.render / item.count),
+ 'Instances': item.count
+ };
+ }));
+ // TODO: ReactDefaultPerfAnalysis.getTotalTime() does not return the correct
+ // number.
+ },
+
+ printInclusive: function(measurements) {
+ measurements = measurements || ReactDefaultPerf._allMeasurements;
+ var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(measurements);
+ console.table(summary.map(function(item) {
+ return {
+ 'Owner > component': item.componentName,
+ 'Inclusive time (ms)': roundFloat(item.time),
+ 'Instances': item.count
+ };
+ }));
+ console.log(
+ 'Total time:',
+ ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
+ );
+ },
+
+ getMeasurementsSummaryMap: function(measurements) {
+ var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(
+ measurements,
+ true
+ );
+ return summary.map(function(item) {
+ return {
+ 'Owner > component': item.componentName,
+ 'Wasted time (ms)': item.time,
+ 'Instances': item.count
+ };
+ });
+ },
+
+ printWasted: function(measurements) {
+ measurements = measurements || ReactDefaultPerf._allMeasurements;
+ console.table(ReactDefaultPerf.getMeasurementsSummaryMap(measurements));
+ console.log(
+ 'Total time:',
+ ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
+ );
+ },
+
+ printDOM: function(measurements) {
+ measurements = measurements || ReactDefaultPerf._allMeasurements;
+ var summary = ReactDefaultPerfAnalysis.getDOMSummary(measurements);
+ console.table(summary.map(function(item) {
+ var result = {};
+ result[DOMProperty.ID_ATTRIBUTE_NAME] = item.id;
+ result['type'] = item.type;
+ result['args'] = JSON.stringify(item.args);
+ return result;
+ }));
+ console.log(
+ 'Total time:',
+ ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
+ );
+ },
+
+ _recordWrite: function(id, fnName, totalTime, args) {
+ // TODO: totalTime isn't that useful since it doesn't count paints/reflows
+ var writes =
+ ReactDefaultPerf
+ ._allMeasurements[ReactDefaultPerf._allMeasurements.length - 1]
+ .writes;
+ writes[id] = writes[id] || [];
+ writes[id].push({
+ type: fnName,
+ time: totalTime,
+ args: args
+ });
+ },
+
+ measure: function(moduleName, fnName, func) {
+ return function() {for (var args=[],$__0=0,$__1=arguments.length;$__0<$__1;$__0++) args.push(arguments[$__0]);
+ var totalTime;
+ var rv;
+ var start;
+
+ if (fnName === '_renderNewRootComponent' ||
+ fnName === 'flushBatchedUpdates') {
+ // A "measurement" is a set of metrics recorded for each flush. We want
+ // to group the metrics for a given flush together so we can look at the
+ // components that rendered and the DOM operations that actually
+ // happened to determine the amount of "wasted work" performed.
+ ReactDefaultPerf._allMeasurements.push({
+ exclusive: {},
+ inclusive: {},
+ render: {},
+ counts: {},
+ writes: {},
+ displayNames: {},
+ totalTime: 0
+ });
+ start = performanceNow();
+ rv = func.apply(this, args);
+ ReactDefaultPerf._allMeasurements[
+ ReactDefaultPerf._allMeasurements.length - 1
+ ].totalTime = performanceNow() - start;
+ return rv;
+ } else if (moduleName === 'ReactDOMIDOperations' ||
+ moduleName === 'ReactComponentBrowserEnvironment') {
+ start = performanceNow();
+ rv = func.apply(this, args);
+ totalTime = performanceNow() - start;
+
+ if (fnName === 'mountImageIntoNode') {
+ var mountID = ReactMount.getID(args[1]);
+ ReactDefaultPerf._recordWrite(mountID, fnName, totalTime, args[0]);
+ } else if (fnName === 'dangerouslyProcessChildrenUpdates') {
+ // special format
+ args[0].forEach(function(update) {
+ var writeArgs = {};
+ if (update.fromIndex !== null) {
+ writeArgs.fromIndex = update.fromIndex;
+ }
+ if (update.toIndex !== null) {
+ writeArgs.toIndex = update.toIndex;
+ }
+ if (update.textContent !== null) {
+ writeArgs.textContent = update.textContent;
+ }
+ if (update.markupIndex !== null) {
+ writeArgs.markup = args[1][update.markupIndex];
+ }
+ ReactDefaultPerf._recordWrite(
+ update.parentID,
+ update.type,
+ totalTime,
+ writeArgs
+ );
+ });
+ } else {
+ // basic format
+ ReactDefaultPerf._recordWrite(
+ args[0],
+ fnName,
+ totalTime,
+ Array.prototype.slice.call(args, 1)
+ );
+ }
+ return rv;
+ } else if (moduleName === 'ReactCompositeComponent' && (
+ fnName === 'mountComponent' ||
+ fnName === 'updateComponent' || // TODO: receiveComponent()?
+ fnName === '_renderValidatedComponent')) {
+
+ var rootNodeID = fnName === 'mountComponent' ?
+ args[0] :
+ this._rootNodeID;
+ var isRender = fnName === '_renderValidatedComponent';
+ var isMount = fnName === 'mountComponent';
+
+ var mountStack = ReactDefaultPerf._mountStack;
+ var entry = ReactDefaultPerf._allMeasurements[
+ ReactDefaultPerf._allMeasurements.length - 1
+ ];
+
+ if (isRender) {
+ addValue(entry.counts, rootNodeID, 1);
+ } else if (isMount) {
+ mountStack.push(0);
+ }
+
+ start = performanceNow();
+ rv = func.apply(this, args);
+ totalTime = performanceNow() - start;
+
+ if (isRender) {
+ addValue(entry.render, rootNodeID, totalTime);
+ } else if (isMount) {
+ var subMountTime = mountStack.pop();
+ mountStack[mountStack.length - 1] += totalTime;
+ addValue(entry.exclusive, rootNodeID, totalTime - subMountTime);
+ addValue(entry.inclusive, rootNodeID, totalTime);
+ } else {
+ addValue(entry.inclusive, rootNodeID, totalTime);
+ }
+
+ entry.displayNames[rootNodeID] = {
+ current: this.constructor.displayName,
+ owner: this._owner ? this._owner.constructor.displayName : '<root>'
+ };
+
+ return rv;
+ } else {
+ return func.apply(this, args);
+ }
+ };
+ }
+};
+
+module.exports = ReactDefaultPerf;
+
+},{"./DOMProperty":58,"./ReactDefaultPerfAnalysis":103,"./ReactMount":116,"./ReactPerf":121,"./performanceNow":200}],103:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDefaultPerfAnalysis
+ */
+
+var assign = require("./Object.assign");
+
+// Don't try to save users less than 1.2ms (a number I made up)
+var DONT_CARE_THRESHOLD = 1.2;
+var DOM_OPERATION_TYPES = {
+ 'mountImageIntoNode': 'set innerHTML',
+ INSERT_MARKUP: 'set innerHTML',
+ MOVE_EXISTING: 'move',
+ REMOVE_NODE: 'remove',
+ TEXT_CONTENT: 'set textContent',
+ 'updatePropertyByID': 'update attribute',
+ 'deletePropertyByID': 'delete attribute',
+ 'updateStylesByID': 'update styles',
+ 'updateInnerHTMLByID': 'set innerHTML',
+ 'dangerouslyReplaceNodeWithMarkupByID': 'replace'
+};
+
+function getTotalTime(measurements) {
+ // TODO: return number of DOM ops? could be misleading.
+ // TODO: measure dropped frames after reconcile?
+ // TODO: log total time of each reconcile and the top-level component
+ // class that triggered it.
+ var totalTime = 0;
+ for (var i = 0; i < measurements.length; i++) {
+ var measurement = measurements[i];
+ totalTime += measurement.totalTime;
+ }
+ return totalTime;
+}
+
+function getDOMSummary(measurements) {
+ var items = [];
+ for (var i = 0; i < measurements.length; i++) {
+ var measurement = measurements[i];
+ var id;
+
+ for (id in measurement.writes) {
+ measurement.writes[id].forEach(function(write) {
+ items.push({
+ id: id,
+ type: DOM_OPERATION_TYPES[write.type] || write.type,
+ args: write.args
+ });
+ });
+ }
+ }
+ return items;
+}
+
+function getExclusiveSummary(measurements) {
+ var candidates = {};
+ var displayName;
+
+ for (var i = 0; i < measurements.length; i++) {
+ var measurement = measurements[i];
+ var allIDs = assign(
+ {},
+ measurement.exclusive,
+ measurement.inclusive
+ );
+
+ for (var id in allIDs) {
+ displayName = measurement.displayNames[id].current;
+
+ candidates[displayName] = candidates[displayName] || {
+ componentName: displayName,
+ inclusive: 0,
+ exclusive: 0,
+ render: 0,
+ count: 0
+ };
+ if (measurement.render[id]) {
+ candidates[displayName].render += measurement.render[id];
+ }
+ if (measurement.exclusive[id]) {
+ candidates[displayName].exclusive += measurement.exclusive[id];
+ }
+ if (measurement.inclusive[id]) {
+ candidates[displayName].inclusive += measurement.inclusive[id];
+ }
+ if (measurement.counts[id]) {
+ candidates[displayName].count += measurement.counts[id];
+ }
+ }
+ }
+
+ // Now make a sorted array with the results.
+ var arr = [];
+ for (displayName in candidates) {
+ if (candidates[displayName].exclusive >= DONT_CARE_THRESHOLD) {
+ arr.push(candidates[displayName]);
+ }
+ }
+
+ arr.sort(function(a, b) {
+ return b.exclusive - a.exclusive;
+ });
+
+ return arr;
+}
+
+function getInclusiveSummary(measurements, onlyClean) {
+ var candidates = {};
+ var inclusiveKey;
+
+ for (var i = 0; i < measurements.length; i++) {
+ var measurement = measurements[i];
+ var allIDs = assign(
+ {},
+ measurement.exclusive,
+ measurement.inclusive
+ );
+ var cleanComponents;
+
+ if (onlyClean) {
+ cleanComponents = getUnchangedComponents(measurement);
+ }
+
+ for (var id in allIDs) {
+ if (onlyClean && !cleanComponents[id]) {
+ continue;
+ }
+
+ var displayName = measurement.displayNames[id];
+
+ // Inclusive time is not useful for many components without knowing where
+ // they are instantiated. So we aggregate inclusive time with both the
+ // owner and current displayName as the key.
+ inclusiveKey = displayName.owner + ' > ' + displayName.current;
+
+ candidates[inclusiveKey] = candidates[inclusiveKey] || {
+ componentName: inclusiveKey,
+ time: 0,
+ count: 0
+ };
+
+ if (measurement.inclusive[id]) {
+ candidates[inclusiveKey].time += measurement.inclusive[id];
+ }
+ if (measurement.counts[id]) {
+ candidates[inclusiveKey].count += measurement.counts[id];
+ }
+ }
+ }
+
+ // Now make a sorted array with the results.
+ var arr = [];
+ for (inclusiveKey in candidates) {
+ if (candidates[inclusiveKey].time >= DONT_CARE_THRESHOLD) {
+ arr.push(candidates[inclusiveKey]);
+ }
+ }
+
+ arr.sort(function(a, b) {
+ return b.time - a.time;
+ });
+
+ return arr;
+}
+
+function getUnchangedComponents(measurement) {
+ // For a given reconcile, look at which components did not actually
+ // render anything to the DOM and return a mapping of their ID to
+ // the amount of time it took to render the entire subtree.
+ var cleanComponents = {};
+ var dirtyLeafIDs = Object.keys(measurement.writes);
+ var allIDs = assign({}, measurement.exclusive, measurement.inclusive);
+
+ for (var id in allIDs) {
+ var isDirty = false;
+ // For each component that rendered, see if a component that triggered
+ // a DOM op is in its subtree.
+ for (var i = 0; i < dirtyLeafIDs.length; i++) {
+ if (dirtyLeafIDs[i].indexOf(id) === 0) {
+ isDirty = true;
+ break;
+ }
+ }
+ if (!isDirty && measurement.counts[id] > 0) {
+ cleanComponents[id] = true;
+ }
+ }
+ return cleanComponents;
+}
+
+var ReactDefaultPerfAnalysis = {
+ getExclusiveSummary: getExclusiveSummary,
+ getInclusiveSummary: getInclusiveSummary,
+ getDOMSummary: getDOMSummary,
+ getTotalTime: getTotalTime
+};
+
+module.exports = ReactDefaultPerfAnalysis;
+
+},{"./Object.assign":75}],104:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactElement
+ */
+
+"use strict";
+
+var ReactContext = require("./ReactContext");
+var ReactCurrentOwner = require("./ReactCurrentOwner");
+
+var warning = require("./warning");
+
+var RESERVED_PROPS = {
+ key: true,
+ ref: true
+};
+
+/**
+ * Warn for mutations.
+ *
+ * @internal
+ * @param {object} object
+ * @param {string} key
+ */
+function defineWarningProperty(object, key) {
+ Object.defineProperty(object, key, {
+
+ configurable: false,
+ enumerable: true,
+
+ get: function() {
+ if (!this._store) {
+ return null;
+ }
+ return this._store[key];
+ },
+
+ set: function(value) {
+ ("production" !== process.env.NODE_ENV ? warning(
+ false,
+ 'Don\'t set the ' + key + ' property of the component. ' +
+ 'Mutate the existing props object instead.'
+ ) : null);
+ this._store[key] = value;
+ }
+
+ });
+}
+
+/**
+ * This is updated to true if the membrane is successfully created.
+ */
+var useMutationMembrane = false;
+
+/**
+ * Warn for mutations.
+ *
+ * @internal
+ * @param {object} element
+ */
+function defineMutationMembrane(prototype) {
+ try {
+ var pseudoFrozenProperties = {
+ props: true
+ };
+ for (var key in pseudoFrozenProperties) {
+ defineWarningProperty(prototype, key);
+ }
+ useMutationMembrane = true;
+ } catch (x) {
+ // IE will fail on defineProperty
+ }
+}
+
+/**
+ * Base constructor for all React elements. This is only used to make this
+ * work with a dynamic instanceof check. Nothing should live on this prototype.
+ *
+ * @param {*} type
+ * @param {string|object} ref
+ * @param {*} key
+ * @param {*} props
+ * @internal
+ */
+var ReactElement = function(type, key, ref, owner, context, props) {
+ // Built-in properties that belong on the element
+ this.type = type;
+ this.key = key;
+ this.ref = ref;
+
+ // Record the component responsible for creating this element.
+ this._owner = owner;
+
+ // TODO: Deprecate withContext, and then the context becomes accessible
+ // through the owner.
+ this._context = context;
+
+ if ("production" !== process.env.NODE_ENV) {
+ // The validation flag and props are currently mutative. We put them on
+ // an external backing store so that we can freeze the whole object.
+ // This can be replaced with a WeakMap once they are implemented in
+ // commonly used development environments.
+ this._store = { validated: false, props: props };
+
+ // We're not allowed to set props directly on the object so we early
+ // return and rely on the prototype membrane to forward to the backing
+ // store.
+ if (useMutationMembrane) {
+ Object.freeze(this);
+ return;
+ }
+ }
+
+ this.props = props;
+};
+
+// We intentionally don't expose the function on the constructor property.
+// ReactElement should be indistinguishable from a plain object.
+ReactElement.prototype = {
+ _isReactElement: true
+};
+
+if ("production" !== process.env.NODE_ENV) {
+ defineMutationMembrane(ReactElement.prototype);
+}
+
+ReactElement.createElement = function(type, config, children) {
+ var propName;
+
+ // Reserved names are extracted
+ var props = {};
+
+ var key = null;
+ var ref = null;
+
+ if (config != null) {
+ ref = config.ref === undefined ? null : config.ref;
+ if ("production" !== process.env.NODE_ENV) {
+ ("production" !== process.env.NODE_ENV ? warning(
+ config.key !== null,
+ 'createElement(...): Encountered component with a `key` of null. In ' +
+ 'a future version, this will be treated as equivalent to the string ' +
+ '\'null\'; instead, provide an explicit key or use undefined.'
+ ) : null);
+ }
+ // TODO: Change this back to `config.key === undefined`
+ key = config.key == null ? null : '' + config.key;
+ // Remaining properties are added to a new props object
+ for (propName in config) {
+ if (config.hasOwnProperty(propName) &&
+ !RESERVED_PROPS.hasOwnProperty(propName)) {
+ props[propName] = config[propName];
+ }
+ }
+ }
+
+ // Children can be more than one argument, and those are transferred onto
+ // the newly allocated props object.
+ var childrenLength = arguments.length - 2;
+ if (childrenLength === 1) {
+ props.children = children;
+ } else if (childrenLength > 1) {
+ var childArray = Array(childrenLength);
+ for (var i = 0; i < childrenLength; i++) {
+ childArray[i] = arguments[i + 2];
+ }
+ props.children = childArray;
+ }
+
+ // Resolve default props
+ if (type && type.defaultProps) {
+ var defaultProps = type.defaultProps;
+ for (propName in defaultProps) {
+ if (typeof props[propName] === 'undefined') {
+ props[propName] = defaultProps[propName];
+ }
+ }
+ }
+
+ return new ReactElement(
+ type,
+ key,
+ ref,
+ ReactCurrentOwner.current,
+ ReactContext.current,
+ props
+ );
+};
+
+ReactElement.createFactory = function(type) {
+ var factory = ReactElement.createElement.bind(null, type);
+ // Expose the type on the factory and the prototype so that it can be
+ // easily accessed on elements. E.g. <Foo />.type === Foo.type.
+ // This should not be named `constructor` since this may not be the function
+ // that created the element, and it may not even be a constructor.
+ factory.type = type;
+ return factory;
+};
+
+ReactElement.cloneAndReplaceProps = function(oldElement, newProps) {
+ var newElement = new ReactElement(
+ oldElement.type,
+ oldElement.key,
+ oldElement.ref,
+ oldElement._owner,
+ oldElement._context,
+ newProps
+ );
+
+ if ("production" !== process.env.NODE_ENV) {
+ // If the key on the original is valid, then the clone is valid
+ newElement._store.validated = oldElement._store.validated;
+ }
+ return newElement;
+};
+
+/**
+ * @param {?object} object
+ * @return {boolean} True if `object` is a valid component.
+ * @final
+ */
+ReactElement.isValidElement = function(object) {
+ // ReactTestUtils is often used outside of beforeEach where as React is
+ // within it. This leads to two different instances of React on the same
+ // page. To identify a element from a different React instance we use
+ // a flag instead of an instanceof check.
+ var isElement = !!(object && object._isReactElement);
+ // if (isElement && !(object instanceof ReactElement)) {
+ // This is an indicator that you're using multiple versions of React at the
+ // same time. This will screw with ownership and stuff. Fix it, please.
+ // TODO: We could possibly warn here.
+ // }
+ return isElement;
+};
+
+module.exports = ReactElement;
+
+}).call(this,require('_process'))
+},{"./ReactContext":87,"./ReactCurrentOwner":88,"./warning":207,"_process":5}],105:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactElementValidator
+ */
+
+/**
+ * ReactElementValidator provides a wrapper around a element factory
+ * which validates the props passed to the element. This is intended to be
+ * used only in DEV and could be replaced by a static type checker for languages
+ * that support it.
+ */
+
+"use strict";
+
+var ReactElement = require("./ReactElement");
+var ReactPropTypeLocations = require("./ReactPropTypeLocations");
+var ReactCurrentOwner = require("./ReactCurrentOwner");
+
+var monitorCodeUse = require("./monitorCodeUse");
+var warning = require("./warning");
+
+/**
+ * Warn if there's no key explicitly set on dynamic arrays of children or
+ * object keys are not valid. This allows us to keep track of children between
+ * updates.
+ */
+var ownerHasKeyUseWarning = {
+ 'react_key_warning': {},
+ 'react_numeric_key_warning': {}
+};
+var ownerHasMonitoredObjectMap = {};
+
+var loggedTypeFailures = {};
+
+var NUMERIC_PROPERTY_REGEX = /^\d+$/;
+
+/**
+ * Gets the current owner's displayName for use in warnings.
+ *
+ * @internal
+ * @return {?string} Display name or undefined
+ */
+function getCurrentOwnerDisplayName() {
+ var current = ReactCurrentOwner.current;
+ return current && current.constructor.displayName || undefined;
+}
+
+/**
+ * Warn if the component doesn't have an explicit key assigned to it.
+ * This component is in an array. The array could grow and shrink or be
+ * reordered. All children that haven't already been validated are required to
+ * have a "key" property assigned to it.
+ *
+ * @internal
+ * @param {ReactComponent} component Component that requires a key.
+ * @param {*} parentType component's parent's type.
+ */
+function validateExplicitKey(component, parentType) {
+ if (component._store.validated || component.key != null) {
+ return;
+ }
+ component._store.validated = true;
+
+ warnAndMonitorForKeyUse(
+ 'react_key_warning',
+ 'Each child in an array should have a unique "key" prop.',
+ component,
+ parentType
+ );
+}
+
+/**
+ * Warn if the key is being defined as an object property but has an incorrect
+ * value.
+ *
+ * @internal
+ * @param {string} name Property name of the key.
+ * @param {ReactComponent} component Component that requires a key.
+ * @param {*} parentType component's parent's type.
+ */
+function validatePropertyKey(name, component, parentType) {
+ if (!NUMERIC_PROPERTY_REGEX.test(name)) {
+ return;
+ }
+ warnAndMonitorForKeyUse(
+ 'react_numeric_key_warning',
+ 'Child objects should have non-numeric keys so ordering is preserved.',
+ component,
+ parentType
+ );
+}
+
+/**
+ * Shared warning and monitoring code for the key warnings.
+ *
+ * @internal
+ * @param {string} warningID The id used when logging.
+ * @param {string} message The base warning that gets output.
+ * @param {ReactComponent} component Component that requires a key.
+ * @param {*} parentType component's parent's type.
+ */
+function warnAndMonitorForKeyUse(warningID, message, component, parentType) {
+ var ownerName = getCurrentOwnerDisplayName();
+ var parentName = parentType.displayName;
+
+ var useName = ownerName || parentName;
+ var memoizer = ownerHasKeyUseWarning[warningID];
+ if (memoizer.hasOwnProperty(useName)) {
+ return;
+ }
+ memoizer[useName] = true;
+
+ message += ownerName ?
+ (" Check the render method of " + ownerName + ".") :
+ (" Check the renderComponent call using <" + parentName + ">.");
+
+ // Usually the current owner is the offender, but if it accepts children as a
+ // property, it may be the creator of the child that's responsible for
+ // assigning it a key.
+ var childOwnerName = null;
+ if (component._owner && component._owner !== ReactCurrentOwner.current) {
+ // Name of the component that originally created this child.
+ childOwnerName = component._owner.constructor.displayName;
+
+ message += (" It was passed a child from " + childOwnerName + ".");
+ }
+
+ message += ' See http://fb.me/react-warning-keys for more information.';
+ monitorCodeUse(warningID, {
+ component: useName,
+ componentOwner: childOwnerName
+ });
+ console.warn(message);
+}
+
+/**
+ * Log that we're using an object map. We're considering deprecating this
+ * feature and replace it with proper Map and ImmutableMap data structures.
+ *
+ * @internal
+ */
+function monitorUseOfObjectMap() {
+ var currentName = getCurrentOwnerDisplayName() || '';
+ if (ownerHasMonitoredObjectMap.hasOwnProperty(currentName)) {
+ return;
+ }
+ ownerHasMonitoredObjectMap[currentName] = true;
+ monitorCodeUse('react_object_map_children');
+}
+
+/**
+ * Ensure that every component either is passed in a static location, in an
+ * array with an explicit keys property defined, or in an object literal
+ * with valid key property.
+ *
+ * @internal
+ * @param {*} component Statically passed child of any type.
+ * @param {*} parentType component's parent's type.
+ * @return {boolean}
+ */
+function validateChildKeys(component, parentType) {
+ if (Array.isArray(component)) {
+ for (var i = 0; i < component.length; i++) {
+ var child = component[i];
+ if (ReactElement.isValidElement(child)) {
+ validateExplicitKey(child, parentType);
+ }
+ }
+ } else if (ReactElement.isValidElement(component)) {
+ // This component was passed in a valid location.
+ component._store.validated = true;
+ } else if (component && typeof component === 'object') {
+ monitorUseOfObjectMap();
+ for (var name in component) {
+ validatePropertyKey(name, component[name], parentType);
+ }
+ }
+}
+
+/**
+ * Assert that the props are valid
+ *
+ * @param {string} componentName Name of the component for error messages.
+ * @param {object} propTypes Map of prop name to a ReactPropType
+ * @param {object} props
+ * @param {string} location e.g. "prop", "context", "child context"
+ * @private
+ */
+function checkPropTypes(componentName, propTypes, props, location) {
+ for (var propName in propTypes) {
+ if (propTypes.hasOwnProperty(propName)) {
+ var error;
+ // Prop type validation may throw. In case they do, we don't want to
+ // fail the render phase where it didn't fail before. So we log it.
+ // After these have been cleaned up, we'll let them throw.
+ try {
+ error = propTypes[propName](props, propName, componentName, location);
+ } catch (ex) {
+ error = ex;
+ }
+ if (error instanceof Error && !(error.message in loggedTypeFailures)) {
+ // Only monitor this failure once because there tends to be a lot of the
+ // same error.
+ loggedTypeFailures[error.message] = true;
+ // This will soon use the warning module
+ monitorCodeUse(
+ 'react_failed_descriptor_type_check',
+ { message: error.message }
+ );
+ }
+ }
+ }
+}
+
+var ReactElementValidator = {
+
+ createElement: function(type, props, children) {
+ // We warn in this case but don't throw. We expect the element creation to
+ // succeed and there will likely be errors in render.
+ ("production" !== process.env.NODE_ENV ? warning(
+ type != null,
+ 'React.createElement: type should not be null or undefined. It should ' +
+ 'be a string (for DOM elements) or a ReactClass (for composite ' +
+ 'components).'
+ ) : null);
+
+ var element = ReactElement.createElement.apply(this, arguments);
+
+ // The result can be nullish if a mock or a custom function is used.
+ // TODO: Drop this when these are no longer allowed as the type argument.
+ if (element == null) {
+ return element;
+ }
+
+ for (var i = 2; i < arguments.length; i++) {
+ validateChildKeys(arguments[i], type);
+ }
+
+ if (type) {
+ var name = type.displayName;
+ if (type.propTypes) {
+ checkPropTypes(
+ name,
+ type.propTypes,
+ element.props,
+ ReactPropTypeLocations.prop
+ );
+ }
+ if (type.contextTypes) {
+ checkPropTypes(
+ name,
+ type.contextTypes,
+ element._context,
+ ReactPropTypeLocations.context
+ );
+ }
+ }
+ return element;
+ },
+
+ createFactory: function(type) {
+ var validatedFactory = ReactElementValidator.createElement.bind(
+ null,
+ type
+ );
+ validatedFactory.type = type;
+ return validatedFactory;
+ }
+
+};
+
+module.exports = ReactElementValidator;
+
+}).call(this,require('_process'))
+},{"./ReactCurrentOwner":88,"./ReactElement":104,"./ReactPropTypeLocations":124,"./monitorCodeUse":197,"./warning":207,"_process":5}],106:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactEmptyComponent
+ */
+
+"use strict";
+
+var ReactElement = require("./ReactElement");
+
+var invariant = require("./invariant");
+
+var component;
+// This registry keeps track of the React IDs of the components that rendered to
+// `null` (in reality a placeholder such as `noscript`)
+var nullComponentIdsRegistry = {};
+
+var ReactEmptyComponentInjection = {
+ injectEmptyComponent: function(emptyComponent) {
+ component = ReactElement.createFactory(emptyComponent);
+ }
+};
+
+/**
+ * @return {ReactComponent} component The injected empty component.
+ */
+function getEmptyComponent() {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ component,
+ 'Trying to return null from a render, but no null placeholder component ' +
+ 'was injected.'
+ ) : invariant(component));
+ return component();
+}
+
+/**
+ * Mark the component as having rendered to null.
+ * @param {string} id Component's `_rootNodeID`.
+ */
+function registerNullComponentID(id) {
+ nullComponentIdsRegistry[id] = true;
+}
+
+/**
+ * Unmark the component as having rendered to null: it renders to something now.
+ * @param {string} id Component's `_rootNodeID`.
+ */
+function deregisterNullComponentID(id) {
+ delete nullComponentIdsRegistry[id];
+}
+
+/**
+ * @param {string} id Component's `_rootNodeID`.
+ * @return {boolean} True if the component is rendered to null.
+ */
+function isNullComponentID(id) {
+ return nullComponentIdsRegistry[id];
+}
+
+var ReactEmptyComponent = {
+ deregisterNullComponentID: deregisterNullComponentID,
+ getEmptyComponent: getEmptyComponent,
+ injection: ReactEmptyComponentInjection,
+ isNullComponentID: isNullComponentID,
+ registerNullComponentID: registerNullComponentID
+};
+
+module.exports = ReactEmptyComponent;
+
+}).call(this,require('_process'))
+},{"./ReactElement":104,"./invariant":187,"_process":5}],107:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactErrorUtils
+ * @typechecks
+ */
+
+"use strict";
+
+var ReactErrorUtils = {
+ /**
+ * Creates a guarded version of a function. This is supposed to make debugging
+ * of event handlers easier. To aid debugging with the browser's debugger,
+ * this currently simply returns the original function.
+ *
+ * @param {function} func Function to be executed
+ * @param {string} name The name of the guard
+ * @return {function}
+ */
+ guard: function(func, name) {
+ return func;
+ }
+};
+
+module.exports = ReactErrorUtils;
+
+},{}],108:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactEventEmitterMixin
+ */
+
+"use strict";
+
+var EventPluginHub = require("./EventPluginHub");
+
+function runEventQueueInBatch(events) {
+ EventPluginHub.enqueueEvents(events);
+ EventPluginHub.processEventQueue();
+}
+
+var ReactEventEmitterMixin = {
+
+ /**
+ * Streams a fired top-level event to `EventPluginHub` where plugins have the
+ * opportunity to create `ReactEvent`s to be dispatched.
+ *
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {object} topLevelTarget The listening component root node.
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
+ * @param {object} nativeEvent Native environment event.
+ */
+ handleTopLevel: function(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID,
+ nativeEvent) {
+ var events = EventPluginHub.extractEvents(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID,
+ nativeEvent
+ );
+
+ runEventQueueInBatch(events);
+ }
+};
+
+module.exports = ReactEventEmitterMixin;
+
+},{"./EventPluginHub":65}],109:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactEventListener
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var EventListener = require("./EventListener");
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+var PooledClass = require("./PooledClass");
+var ReactInstanceHandles = require("./ReactInstanceHandles");
+var ReactMount = require("./ReactMount");
+var ReactUpdates = require("./ReactUpdates");
+
+var assign = require("./Object.assign");
+var getEventTarget = require("./getEventTarget");
+var getUnboundedScrollPosition = require("./getUnboundedScrollPosition");
+
+/**
+ * Finds the parent React component of `node`.
+ *
+ * @param {*} node
+ * @return {?DOMEventTarget} Parent container, or `null` if the specified node
+ * is not nested.
+ */
+function findParent(node) {
+ // TODO: It may be a good idea to cache this to prevent unnecessary DOM
+ // traversal, but caching is difficult to do correctly without using a
+ // mutation observer to listen for all DOM changes.
+ var nodeID = ReactMount.getID(node);
+ var rootID = ReactInstanceHandles.getReactRootIDFromNodeID(nodeID);
+ var container = ReactMount.findReactContainerForID(rootID);
+ var parent = ReactMount.getFirstReactDOM(container);
+ return parent;
+}
+
+// Used to store ancestor hierarchy in top level callback
+function TopLevelCallbackBookKeeping(topLevelType, nativeEvent) {
+ this.topLevelType = topLevelType;
+ this.nativeEvent = nativeEvent;
+ this.ancestors = [];
+}
+assign(TopLevelCallbackBookKeeping.prototype, {
+ destructor: function() {
+ this.topLevelType = null;
+ this.nativeEvent = null;
+ this.ancestors.length = 0;
+ }
+});
+PooledClass.addPoolingTo(
+ TopLevelCallbackBookKeeping,
+ PooledClass.twoArgumentPooler
+);
+
+function handleTopLevelImpl(bookKeeping) {
+ var topLevelTarget = ReactMount.getFirstReactDOM(
+ getEventTarget(bookKeeping.nativeEvent)
+ ) || window;
+
+ // Loop through the hierarchy, in case there's any nested components.
+ // It's important that we build the array of ancestors before calling any
+ // event handlers, because event handlers can modify the DOM, leading to
+ // inconsistencies with ReactMount's node cache. See #1105.
+ var ancestor = topLevelTarget;
+ while (ancestor) {
+ bookKeeping.ancestors.push(ancestor);
+ ancestor = findParent(ancestor);
+ }
+
+ for (var i = 0, l = bookKeeping.ancestors.length; i < l; i++) {
+ topLevelTarget = bookKeeping.ancestors[i];
+ var topLevelTargetID = ReactMount.getID(topLevelTarget) || '';
+ ReactEventListener._handleTopLevel(
+ bookKeeping.topLevelType,
+ topLevelTarget,
+ topLevelTargetID,
+ bookKeeping.nativeEvent
+ );
+ }
+}
+
+function scrollValueMonitor(cb) {
+ var scrollPosition = getUnboundedScrollPosition(window);
+ cb(scrollPosition);
+}
+
+var ReactEventListener = {
+ _enabled: true,
+ _handleTopLevel: null,
+
+ WINDOW_HANDLE: ExecutionEnvironment.canUseDOM ? window : null,
+
+ setHandleTopLevel: function(handleTopLevel) {
+ ReactEventListener._handleTopLevel = handleTopLevel;
+ },
+
+ setEnabled: function(enabled) {
+ ReactEventListener._enabled = !!enabled;
+ },
+
+ isEnabled: function() {
+ return ReactEventListener._enabled;
+ },
+
+
+ /**
+ * Traps top-level events by using event bubbling.
+ *
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {string} handlerBaseName Event name (e.g. "click").
+ * @param {object} handle Element on which to attach listener.
+ * @return {object} An object with a remove function which will forcefully
+ * remove the listener.
+ * @internal
+ */
+ trapBubbledEvent: function(topLevelType, handlerBaseName, handle) {
+ var element = handle;
+ if (!element) {
+ return;
+ }
+ return EventListener.listen(
+ element,
+ handlerBaseName,
+ ReactEventListener.dispatchEvent.bind(null, topLevelType)
+ );
+ },
+
+ /**
+ * Traps a top-level event by using event capturing.
+ *
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {string} handlerBaseName Event name (e.g. "click").
+ * @param {object} handle Element on which to attach listener.
+ * @return {object} An object with a remove function which will forcefully
+ * remove the listener.
+ * @internal
+ */
+ trapCapturedEvent: function(topLevelType, handlerBaseName, handle) {
+ var element = handle;
+ if (!element) {
+ return;
+ }
+ return EventListener.capture(
+ element,
+ handlerBaseName,
+ ReactEventListener.dispatchEvent.bind(null, topLevelType)
+ );
+ },
+
+ monitorScrollValue: function(refresh) {
+ var callback = scrollValueMonitor.bind(null, refresh);
+ EventListener.listen(window, 'scroll', callback);
+ EventListener.listen(window, 'resize', callback);
+ },
+
+ dispatchEvent: function(topLevelType, nativeEvent) {
+ if (!ReactEventListener._enabled) {
+ return;
+ }
+
+ var bookKeeping = TopLevelCallbackBookKeeping.getPooled(
+ topLevelType,
+ nativeEvent
+ );
+ try {
+ // Event queue being processed in the same cycle allows
+ // `preventDefault`.
+ ReactUpdates.batchedUpdates(handleTopLevelImpl, bookKeeping);
+ } finally {
+ TopLevelCallbackBookKeeping.release(bookKeeping);
+ }
+ }
+};
+
+module.exports = ReactEventListener;
+
+},{"./EventListener":64,"./ExecutionEnvironment":69,"./Object.assign":75,"./PooledClass":76,"./ReactInstanceHandles":112,"./ReactMount":116,"./ReactUpdates":137,"./getEventTarget":178,"./getUnboundedScrollPosition":183}],110:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactInjection
+ */
+
+"use strict";
+
+var DOMProperty = require("./DOMProperty");
+var EventPluginHub = require("./EventPluginHub");
+var ReactComponent = require("./ReactComponent");
+var ReactCompositeComponent = require("./ReactCompositeComponent");
+var ReactEmptyComponent = require("./ReactEmptyComponent");
+var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");
+var ReactNativeComponent = require("./ReactNativeComponent");
+var ReactPerf = require("./ReactPerf");
+var ReactRootIndex = require("./ReactRootIndex");
+var ReactUpdates = require("./ReactUpdates");
+
+var ReactInjection = {
+ Component: ReactComponent.injection,
+ CompositeComponent: ReactCompositeComponent.injection,
+ DOMProperty: DOMProperty.injection,
+ EmptyComponent: ReactEmptyComponent.injection,
+ EventPluginHub: EventPluginHub.injection,
+ EventEmitter: ReactBrowserEventEmitter.injection,
+ NativeComponent: ReactNativeComponent.injection,
+ Perf: ReactPerf.injection,
+ RootIndex: ReactRootIndex.injection,
+ Updates: ReactUpdates.injection
+};
+
+module.exports = ReactInjection;
+
+},{"./DOMProperty":58,"./EventPluginHub":65,"./ReactBrowserEventEmitter":79,"./ReactComponent":83,"./ReactCompositeComponent":86,"./ReactEmptyComponent":106,"./ReactNativeComponent":119,"./ReactPerf":121,"./ReactRootIndex":128,"./ReactUpdates":137}],111:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactInputSelection
+ */
+
+"use strict";
+
+var ReactDOMSelection = require("./ReactDOMSelection");
+
+var containsNode = require("./containsNode");
+var focusNode = require("./focusNode");
+var getActiveElement = require("./getActiveElement");
+
+function isInDocument(node) {
+ return containsNode(document.documentElement, node);
+}
+
+/**
+ * @ReactInputSelection: React input selection module. Based on Selection.js,
+ * but modified to be suitable for react and has a couple of bug fixes (doesn't
+ * assume buttons have range selections allowed).
+ * Input selection module for React.
+ */
+var ReactInputSelection = {
+
+ hasSelectionCapabilities: function(elem) {
+ return elem && (
+ (elem.nodeName === 'INPUT' && elem.type === 'text') ||
+ elem.nodeName === 'TEXTAREA' ||
+ elem.contentEditable === 'true'
+ );
+ },
+
+ getSelectionInformation: function() {
+ var focusedElem = getActiveElement();
+ return {
+ focusedElem: focusedElem,
+ selectionRange:
+ ReactInputSelection.hasSelectionCapabilities(focusedElem) ?
+ ReactInputSelection.getSelection(focusedElem) :
+ null
+ };
+ },
+
+ /**
+ * @restoreSelection: If any selection information was potentially lost,
+ * restore it. This is useful when performing operations that could remove dom
+ * nodes and place them back in, resulting in focus being lost.
+ */
+ restoreSelection: function(priorSelectionInformation) {
+ var curFocusedElem = getActiveElement();
+ var priorFocusedElem = priorSelectionInformation.focusedElem;
+ var priorSelectionRange = priorSelectionInformation.selectionRange;
+ if (curFocusedElem !== priorFocusedElem &&
+ isInDocument(priorFocusedElem)) {
+ if (ReactInputSelection.hasSelectionCapabilities(priorFocusedElem)) {
+ ReactInputSelection.setSelection(
+ priorFocusedElem,
+ priorSelectionRange
+ );
+ }
+ focusNode(priorFocusedElem);
+ }
+ },
+
+ /**
+ * @getSelection: Gets the selection bounds of a focused textarea, input or
+ * contentEditable node.
+ * -@input: Look up selection bounds of this input
+ * -@return {start: selectionStart, end: selectionEnd}
+ */
+ getSelection: function(input) {
+ var selection;
+
+ if ('selectionStart' in input) {
+ // Modern browser with input or textarea.
+ selection = {
+ start: input.selectionStart,
+ end: input.selectionEnd
+ };
+ } else if (document.selection && input.nodeName === 'INPUT') {
+ // IE8 input.
+ var range = document.selection.createRange();
+ // There can only be one selection per document in IE, so it must
+ // be in our element.
+ if (range.parentElement() === input) {
+ selection = {
+ start: -range.moveStart('character', -input.value.length),
+ end: -range.moveEnd('character', -input.value.length)
+ };
+ }
+ } else {
+ // Content editable or old IE textarea.
+ selection = ReactDOMSelection.getOffsets(input);
+ }
+
+ return selection || {start: 0, end: 0};
+ },
+
+ /**
+ * @setSelection: Sets the selection bounds of a textarea or input and focuses
+ * the input.
+ * -@input Set selection bounds of this input or textarea
+ * -@offsets Object of same form that is returned from get*
+ */
+ setSelection: function(input, offsets) {
+ var start = offsets.start;
+ var end = offsets.end;
+ if (typeof end === 'undefined') {
+ end = start;
+ }
+
+ if ('selectionStart' in input) {
+ input.selectionStart = start;
+ input.selectionEnd = Math.min(end, input.value.length);
+ } else if (document.selection && input.nodeName === 'INPUT') {
+ var range = input.createTextRange();
+ range.collapse(true);
+ range.moveStart('character', start);
+ range.moveEnd('character', end - start);
+ range.select();
+ } else {
+ ReactDOMSelection.setOffsets(input, offsets);
+ }
+ }
+};
+
+module.exports = ReactInputSelection;
+
+},{"./ReactDOMSelection":98,"./containsNode":161,"./focusNode":172,"./getActiveElement":174}],112:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactInstanceHandles
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var ReactRootIndex = require("./ReactRootIndex");
+
+var invariant = require("./invariant");
+
+var SEPARATOR = '.';
+var SEPARATOR_LENGTH = SEPARATOR.length;
+
+/**
+ * Maximum depth of traversals before we consider the possibility of a bad ID.
+ */
+var MAX_TREE_DEPTH = 100;
+
+/**
+ * Creates a DOM ID prefix to use when mounting React components.
+ *
+ * @param {number} index A unique integer
+ * @return {string} React root ID.
+ * @internal
+ */
+function getReactRootIDString(index) {
+ return SEPARATOR + index.toString(36);
+}
+
+/**
+ * Checks if a character in the supplied ID is a separator or the end.
+ *
+ * @param {string} id A React DOM ID.
+ * @param {number} index Index of the character to check.
+ * @return {boolean} True if the character is a separator or end of the ID.
+ * @private
+ */
+function isBoundary(id, index) {
+ return id.charAt(index) === SEPARATOR || index === id.length;
+}
+
+/**
+ * Checks if the supplied string is a valid React DOM ID.
+ *
+ * @param {string} id A React DOM ID, maybe.
+ * @return {boolean} True if the string is a valid React DOM ID.
+ * @private
+ */
+function isValidID(id) {
+ return id === '' || (
+ id.charAt(0) === SEPARATOR && id.charAt(id.length - 1) !== SEPARATOR
+ );
+}
+
+/**
+ * Checks if the first ID is an ancestor of or equal to the second ID.
+ *
+ * @param {string} ancestorID
+ * @param {string} descendantID
+ * @return {boolean} True if `ancestorID` is an ancestor of `descendantID`.
+ * @internal
+ */
+function isAncestorIDOf(ancestorID, descendantID) {
+ return (
+ descendantID.indexOf(ancestorID) === 0 &&
+ isBoundary(descendantID, ancestorID.length)
+ );
+}
+
+/**
+ * Gets the parent ID of the supplied React DOM ID, `id`.
+ *
+ * @param {string} id ID of a component.
+ * @return {string} ID of the parent, or an empty string.
+ * @private
+ */
+function getParentID(id) {
+ return id ? id.substr(0, id.lastIndexOf(SEPARATOR)) : '';
+}
+
+/**
+ * Gets the next DOM ID on the tree path from the supplied `ancestorID` to the
+ * supplied `destinationID`. If they are equal, the ID is returned.
+ *
+ * @param {string} ancestorID ID of an ancestor node of `destinationID`.
+ * @param {string} destinationID ID of the destination node.
+ * @return {string} Next ID on the path from `ancestorID` to `destinationID`.
+ * @private
+ */
+function getNextDescendantID(ancestorID, destinationID) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ isValidID(ancestorID) && isValidID(destinationID),
+ 'getNextDescendantID(%s, %s): Received an invalid React DOM ID.',
+ ancestorID,
+ destinationID
+ ) : invariant(isValidID(ancestorID) && isValidID(destinationID)));
+ ("production" !== process.env.NODE_ENV ? invariant(
+ isAncestorIDOf(ancestorID, destinationID),
+ 'getNextDescendantID(...): React has made an invalid assumption about ' +
+ 'the DOM hierarchy. Expected `%s` to be an ancestor of `%s`.',
+ ancestorID,
+ destinationID
+ ) : invariant(isAncestorIDOf(ancestorID, destinationID)));
+ if (ancestorID === destinationID) {
+ return ancestorID;
+ }
+ // Skip over the ancestor and the immediate separator. Traverse until we hit
+ // another separator or we reach the end of `destinationID`.
+ var start = ancestorID.length + SEPARATOR_LENGTH;
+ for (var i = start; i < destinationID.length; i++) {
+ if (isBoundary(destinationID, i)) {
+ break;
+ }
+ }
+ return destinationID.substr(0, i);
+}
+
+/**
+ * Gets the nearest common ancestor ID of two IDs.
+ *
+ * Using this ID scheme, the nearest common ancestor ID is the longest common
+ * prefix of the two IDs that immediately preceded a "marker" in both strings.
+ *
+ * @param {string} oneID
+ * @param {string} twoID
+ * @return {string} Nearest common ancestor ID, or the empty string if none.
+ * @private
+ */
+function getFirstCommonAncestorID(oneID, twoID) {
+ var minLength = Math.min(oneID.length, twoID.length);
+ if (minLength === 0) {
+ return '';
+ }
+ var lastCommonMarkerIndex = 0;
+ // Use `<=` to traverse until the "EOL" of the shorter string.
+ for (var i = 0; i <= minLength; i++) {
+ if (isBoundary(oneID, i) && isBoundary(twoID, i)) {
+ lastCommonMarkerIndex = i;
+ } else if (oneID.charAt(i) !== twoID.charAt(i)) {
+ break;
+ }
+ }
+ var longestCommonID = oneID.substr(0, lastCommonMarkerIndex);
+ ("production" !== process.env.NODE_ENV ? invariant(
+ isValidID(longestCommonID),
+ 'getFirstCommonAncestorID(%s, %s): Expected a valid React DOM ID: %s',
+ oneID,
+ twoID,
+ longestCommonID
+ ) : invariant(isValidID(longestCommonID)));
+ return longestCommonID;
+}
+
+/**
+ * Traverses the parent path between two IDs (either up or down). The IDs must
+ * not be the same, and there must exist a parent path between them. If the
+ * callback returns `false`, traversal is stopped.
+ *
+ * @param {?string} start ID at which to start traversal.
+ * @param {?string} stop ID at which to end traversal.
+ * @param {function} cb Callback to invoke each ID with.
+ * @param {?boolean} skipFirst Whether or not to skip the first node.
+ * @param {?boolean} skipLast Whether or not to skip the last node.
+ * @private
+ */
+function traverseParentPath(start, stop, cb, arg, skipFirst, skipLast) {
+ start = start || '';
+ stop = stop || '';
+ ("production" !== process.env.NODE_ENV ? invariant(
+ start !== stop,
+ 'traverseParentPath(...): Cannot traverse from and to the same ID, `%s`.',
+ start
+ ) : invariant(start !== stop));
+ var traverseUp = isAncestorIDOf(stop, start);
+ ("production" !== process.env.NODE_ENV ? invariant(
+ traverseUp || isAncestorIDOf(start, stop),
+ 'traverseParentPath(%s, %s, ...): Cannot traverse from two IDs that do ' +
+ 'not have a parent path.',
+ start,
+ stop
+ ) : invariant(traverseUp || isAncestorIDOf(start, stop)));
+ // Traverse from `start` to `stop` one depth at a time.
+ var depth = 0;
+ var traverse = traverseUp ? getParentID : getNextDescendantID;
+ for (var id = start; /* until break */; id = traverse(id, stop)) {
+ var ret;
+ if ((!skipFirst || id !== start) && (!skipLast || id !== stop)) {
+ ret = cb(id, traverseUp, arg);
+ }
+ if (ret === false || id === stop) {
+ // Only break //after// visiting `stop`.
+ break;
+ }
+ ("production" !== process.env.NODE_ENV ? invariant(
+ depth++ < MAX_TREE_DEPTH,
+ 'traverseParentPath(%s, %s, ...): Detected an infinite loop while ' +
+ 'traversing the React DOM ID tree. This may be due to malformed IDs: %s',
+ start, stop
+ ) : invariant(depth++ < MAX_TREE_DEPTH));
+ }
+}
+
+/**
+ * Manages the IDs assigned to DOM representations of React components. This
+ * uses a specific scheme in order to traverse the DOM efficiently (e.g. in
+ * order to simulate events).
+ *
+ * @internal
+ */
+var ReactInstanceHandles = {
+
+ /**
+ * Constructs a React root ID
+ * @return {string} A React root ID.
+ */
+ createReactRootID: function() {
+ return getReactRootIDString(ReactRootIndex.createReactRootIndex());
+ },
+
+ /**
+ * Constructs a React ID by joining a root ID with a name.
+ *
+ * @param {string} rootID Root ID of a parent component.
+ * @param {string} name A component's name (as flattened children).
+ * @return {string} A React ID.
+ * @internal
+ */
+ createReactID: function(rootID, name) {
+ return rootID + name;
+ },
+
+ /**
+ * Gets the DOM ID of the React component that is the root of the tree that
+ * contains the React component with the supplied DOM ID.
+ *
+ * @param {string} id DOM ID of a React component.
+ * @return {?string} DOM ID of the React component that is the root.
+ * @internal
+ */
+ getReactRootIDFromNodeID: function(id) {
+ if (id && id.charAt(0) === SEPARATOR && id.length > 1) {
+ var index = id.indexOf(SEPARATOR, 1);
+ return index > -1 ? id.substr(0, index) : id;
+ }
+ return null;
+ },
+
+ /**
+ * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that
+ * should would receive a `mouseEnter` or `mouseLeave` event.
+ *
+ * NOTE: Does not invoke the callback on the nearest common ancestor because
+ * nothing "entered" or "left" that element.
+ *
+ * @param {string} leaveID ID being left.
+ * @param {string} enterID ID being entered.
+ * @param {function} cb Callback to invoke on each entered/left ID.
+ * @param {*} upArg Argument to invoke the callback with on left IDs.
+ * @param {*} downArg Argument to invoke the callback with on entered IDs.
+ * @internal
+ */
+ traverseEnterLeave: function(leaveID, enterID, cb, upArg, downArg) {
+ var ancestorID = getFirstCommonAncestorID(leaveID, enterID);
+ if (ancestorID !== leaveID) {
+ traverseParentPath(leaveID, ancestorID, cb, upArg, false, true);
+ }
+ if (ancestorID !== enterID) {
+ traverseParentPath(ancestorID, enterID, cb, downArg, true, false);
+ }
+ },
+
+ /**
+ * Simulates the traversal of a two-phase, capture/bubble event dispatch.
+ *
+ * NOTE: This traversal happens on IDs without touching the DOM.
+ *
+ * @param {string} targetID ID of the target node.
+ * @param {function} cb Callback to invoke.
+ * @param {*} arg Argument to invoke the callback with.
+ * @internal
+ */
+ traverseTwoPhase: function(targetID, cb, arg) {
+ if (targetID) {
+ traverseParentPath('', targetID, cb, arg, true, false);
+ traverseParentPath(targetID, '', cb, arg, false, true);
+ }
+ },
+
+ /**
+ * Traverse a node ID, calling the supplied `cb` for each ancestor ID. For
+ * example, passing `.0.$row-0.1` would result in `cb` getting called
+ * with `.0`, `.0.$row-0`, and `.0.$row-0.1`.
+ *
+ * NOTE: This traversal happens on IDs without touching the DOM.
+ *
+ * @param {string} targetID ID of the target node.
+ * @param {function} cb Callback to invoke.
+ * @param {*} arg Argument to invoke the callback with.
+ * @internal
+ */
+ traverseAncestors: function(targetID, cb, arg) {
+ traverseParentPath('', targetID, cb, arg, true, false);
+ },
+
+ /**
+ * Exposed for unit testing.
+ * @private
+ */
+ _getFirstCommonAncestorID: getFirstCommonAncestorID,
+
+ /**
+ * Exposed for unit testing.
+ * @private
+ */
+ _getNextDescendantID: getNextDescendantID,
+
+ isAncestorIDOf: isAncestorIDOf,
+
+ SEPARATOR: SEPARATOR
+
+};
+
+module.exports = ReactInstanceHandles;
+
+}).call(this,require('_process'))
+},{"./ReactRootIndex":128,"./invariant":187,"_process":5}],113:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactLegacyElement
+ */
+
+"use strict";
+
+var ReactCurrentOwner = require("./ReactCurrentOwner");
+
+var invariant = require("./invariant");
+var monitorCodeUse = require("./monitorCodeUse");
+var warning = require("./warning");
+
+var legacyFactoryLogs = {};
+function warnForLegacyFactoryCall() {
+ if (!ReactLegacyElementFactory._isLegacyCallWarningEnabled) {
+ return;
+ }
+ var owner = ReactCurrentOwner.current;
+ var name = owner && owner.constructor ? owner.constructor.displayName : '';
+ if (!name) {
+ name = 'Something';
+ }
+ if (legacyFactoryLogs.hasOwnProperty(name)) {
+ return;
+ }
+ legacyFactoryLogs[name] = true;
+ ("production" !== process.env.NODE_ENV ? warning(
+ false,
+ name + ' is calling a React component directly. ' +
+ 'Use a factory or JSX instead. See: http://fb.me/react-legacyfactory'
+ ) : null);
+ monitorCodeUse('react_legacy_factory_call', { version: 3, name: name });
+}
+
+function warnForPlainFunctionType(type) {
+ var isReactClass =
+ type.prototype &&
+ typeof type.prototype.mountComponent === 'function' &&
+ typeof type.prototype.receiveComponent === 'function';
+ if (isReactClass) {
+ ("production" !== process.env.NODE_ENV ? warning(
+ false,
+ 'Did not expect to get a React class here. Use `Component` instead ' +
+ 'of `Component.type` or `this.constructor`.'
+ ) : null);
+ } else {
+ if (!type._reactWarnedForThisType) {
+ try {
+ type._reactWarnedForThisType = true;
+ } catch (x) {
+ // just incase this is a frozen object or some special object
+ }
+ monitorCodeUse(
+ 'react_non_component_in_jsx',
+ { version: 3, name: type.name }
+ );
+ }
+ ("production" !== process.env.NODE_ENV ? warning(
+ false,
+ 'This JSX uses a plain function. Only React components are ' +
+ 'valid in React\'s JSX transform.'
+ ) : null);
+ }
+}
+
+function warnForNonLegacyFactory(type) {
+ ("production" !== process.env.NODE_ENV ? warning(
+ false,
+ 'Do not pass React.DOM.' + type.type + ' to JSX or createFactory. ' +
+ 'Use the string "' + type.type + '" instead.'
+ ) : null);
+}
+
+/**
+ * Transfer static properties from the source to the target. Functions are
+ * rebound to have this reflect the original source.
+ */
+function proxyStaticMethods(target, source) {
+ if (typeof source !== 'function') {
+ return;
+ }
+ for (var key in source) {
+ if (source.hasOwnProperty(key)) {
+ var value = source[key];
+ if (typeof value === 'function') {
+ var bound = value.bind(source);
+ // Copy any properties defined on the function, such as `isRequired` on
+ // a PropTypes validator.
+ for (var k in value) {
+ if (value.hasOwnProperty(k)) {
+ bound[k] = value[k];
+ }
+ }
+ target[key] = bound;
+ } else {
+ target[key] = value;
+ }
+ }
+ }
+}
+
+// We use an object instead of a boolean because booleans are ignored by our
+// mocking libraries when these factories gets mocked.
+var LEGACY_MARKER = {};
+var NON_LEGACY_MARKER = {};
+
+var ReactLegacyElementFactory = {};
+
+ReactLegacyElementFactory.wrapCreateFactory = function(createFactory) {
+ var legacyCreateFactory = function(type) {
+ if (typeof type !== 'function') {
+ // Non-function types cannot be legacy factories
+ return createFactory(type);
+ }
+
+ if (type.isReactNonLegacyFactory) {
+ // This is probably a factory created by ReactDOM we unwrap it to get to
+ // the underlying string type. It shouldn't have been passed here so we
+ // warn.
+ if ("production" !== process.env.NODE_ENV) {
+ warnForNonLegacyFactory(type);
+ }
+ return createFactory(type.type);
+ }
+
+ if (type.isReactLegacyFactory) {
+ // This is probably a legacy factory created by ReactCompositeComponent.
+ // We unwrap it to get to the underlying class.
+ return createFactory(type.type);
+ }
+
+ if ("production" !== process.env.NODE_ENV) {
+ warnForPlainFunctionType(type);
+ }
+
+ // Unless it's a legacy factory, then this is probably a plain function,
+ // that is expecting to be invoked by JSX. We can just return it as is.
+ return type;
+ };
+ return legacyCreateFactory;
+};
+
+ReactLegacyElementFactory.wrapCreateElement = function(createElement) {
+ var legacyCreateElement = function(type, props, children) {
+ if (typeof type !== 'function') {
+ // Non-function types cannot be legacy factories
+ return createElement.apply(this, arguments);
+ }
+
+ var args;
+
+ if (type.isReactNonLegacyFactory) {
+ // This is probably a factory created by ReactDOM we unwrap it to get to
+ // the underlying string type. It shouldn't have been passed here so we
+ // warn.
+ if ("production" !== process.env.NODE_ENV) {
+ warnForNonLegacyFactory(type);
+ }
+ args = Array.prototype.slice.call(arguments, 0);
+ args[0] = type.type;
+ return createElement.apply(this, args);
+ }
+
+ if (type.isReactLegacyFactory) {
+ // This is probably a legacy factory created by ReactCompositeComponent.
+ // We unwrap it to get to the underlying class.
+ if (type._isMockFunction) {
+ // If this is a mock function, people will expect it to be called. We
+ // will actually call the original mock factory function instead. This
+ // future proofs unit testing that assume that these are classes.
+ type.type._mockedReactClassConstructor = type;
+ }
+ args = Array.prototype.slice.call(arguments, 0);
+ args[0] = type.type;
+ return createElement.apply(this, args);
+ }
+
+ if ("production" !== process.env.NODE_ENV) {
+ warnForPlainFunctionType(type);
+ }
+
+ // This is being called with a plain function we should invoke it
+ // immediately as if this was used with legacy JSX.
+ return type.apply(null, Array.prototype.slice.call(arguments, 1));
+ };
+ return legacyCreateElement;
+};
+
+ReactLegacyElementFactory.wrapFactory = function(factory) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ typeof factory === 'function',
+ 'This is suppose to accept a element factory'
+ ) : invariant(typeof factory === 'function'));
+ var legacyElementFactory = function(config, children) {
+ // This factory should not be called when JSX is used. Use JSX instead.
+ if ("production" !== process.env.NODE_ENV) {
+ warnForLegacyFactoryCall();
+ }
+ return factory.apply(this, arguments);
+ };
+ proxyStaticMethods(legacyElementFactory, factory.type);
+ legacyElementFactory.isReactLegacyFactory = LEGACY_MARKER;
+ legacyElementFactory.type = factory.type;
+ return legacyElementFactory;
+};
+
+// This is used to mark a factory that will remain. E.g. we're allowed to call
+// it as a function. However, you're not suppose to pass it to createElement
+// or createFactory, so it will warn you if you do.
+ReactLegacyElementFactory.markNonLegacyFactory = function(factory) {
+ factory.isReactNonLegacyFactory = NON_LEGACY_MARKER;
+ return factory;
+};
+
+// Checks if a factory function is actually a legacy factory pretending to
+// be a class.
+ReactLegacyElementFactory.isValidFactory = function(factory) {
+ // TODO: This will be removed and moved into a class validator or something.
+ return typeof factory === 'function' &&
+ factory.isReactLegacyFactory === LEGACY_MARKER;
+};
+
+ReactLegacyElementFactory.isValidClass = function(factory) {
+ if ("production" !== process.env.NODE_ENV) {
+ ("production" !== process.env.NODE_ENV ? warning(
+ false,
+ 'isValidClass is deprecated and will be removed in a future release. ' +
+ 'Use a more specific validator instead.'
+ ) : null);
+ }
+ return ReactLegacyElementFactory.isValidFactory(factory);
+};
+
+ReactLegacyElementFactory._isLegacyCallWarningEnabled = true;
+
+module.exports = ReactLegacyElementFactory;
+
+}).call(this,require('_process'))
+},{"./ReactCurrentOwner":88,"./invariant":187,"./monitorCodeUse":197,"./warning":207,"_process":5}],114:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactLink
+ * @typechecks static-only
+ */
+
+"use strict";
+
+/**
+ * ReactLink encapsulates a common pattern in which a component wants to modify
+ * a prop received from its parent. ReactLink allows the parent to pass down a
+ * value coupled with a callback that, when invoked, expresses an intent to
+ * modify that value. For example:
+ *
+ * React.createClass({
+ * getInitialState: function() {
+ * return {value: ''};
+ * },
+ * render: function() {
+ * var valueLink = new ReactLink(this.state.value, this._handleValueChange);
+ * return <input valueLink={valueLink} />;
+ * },
+ * this._handleValueChange: function(newValue) {
+ * this.setState({value: newValue});
+ * }
+ * });
+ *
+ * We have provided some sugary mixins to make the creation and
+ * consumption of ReactLink easier; see LinkedValueUtils and LinkedStateMixin.
+ */
+
+var React = require("./React");
+
+/**
+ * @param {*} value current value of the link
+ * @param {function} requestChange callback to request a change
+ */
+function ReactLink(value, requestChange) {
+ this.value = value;
+ this.requestChange = requestChange;
+}
+
+/**
+ * Creates a PropType that enforces the ReactLink API and optionally checks the
+ * type of the value being passed inside the link. Example:
+ *
+ * MyComponent.propTypes = {
+ * tabIndexLink: ReactLink.PropTypes.link(React.PropTypes.number)
+ * }
+ */
+function createLinkTypeChecker(linkType) {
+ var shapes = {
+ value: typeof linkType === 'undefined' ?
+ React.PropTypes.any.isRequired :
+ linkType.isRequired,
+ requestChange: React.PropTypes.func.isRequired
+ };
+ return React.PropTypes.shape(shapes);
+}
+
+ReactLink.PropTypes = {
+ link: createLinkTypeChecker
+};
+
+module.exports = ReactLink;
+
+},{"./React":77}],115:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactMarkupChecksum
+ */
+
+"use strict";
+
+var adler32 = require("./adler32");
+
+var ReactMarkupChecksum = {
+ CHECKSUM_ATTR_NAME: 'data-react-checksum',
+
+ /**
+ * @param {string} markup Markup string
+ * @return {string} Markup string with checksum attribute attached
+ */
+ addChecksumToMarkup: function(markup) {
+ var checksum = adler32(markup);
+ return markup.replace(
+ '>',
+ ' ' + ReactMarkupChecksum.CHECKSUM_ATTR_NAME + '="' + checksum + '">'
+ );
+ },
+
+ /**
+ * @param {string} markup to use
+ * @param {DOMElement} element root React element
+ * @returns {boolean} whether or not the markup is the same
+ */
+ canReuseMarkup: function(markup, element) {
+ var existingChecksum = element.getAttribute(
+ ReactMarkupChecksum.CHECKSUM_ATTR_NAME
+ );
+ existingChecksum = existingChecksum && parseInt(existingChecksum, 10);
+ var markupChecksum = adler32(markup);
+ return markupChecksum === existingChecksum;
+ }
+};
+
+module.exports = ReactMarkupChecksum;
+
+},{"./adler32":157}],116:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactMount
+ */
+
+"use strict";
+
+var DOMProperty = require("./DOMProperty");
+var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");
+var ReactCurrentOwner = require("./ReactCurrentOwner");
+var ReactElement = require("./ReactElement");
+var ReactLegacyElement = require("./ReactLegacyElement");
+var ReactInstanceHandles = require("./ReactInstanceHandles");
+var ReactPerf = require("./ReactPerf");
+
+var containsNode = require("./containsNode");
+var deprecated = require("./deprecated");
+var getReactRootElementInContainer = require("./getReactRootElementInContainer");
+var instantiateReactComponent = require("./instantiateReactComponent");
+var invariant = require("./invariant");
+var shouldUpdateReactComponent = require("./shouldUpdateReactComponent");
+var warning = require("./warning");
+
+var createElement = ReactLegacyElement.wrapCreateElement(
+ ReactElement.createElement
+);
+
+var SEPARATOR = ReactInstanceHandles.SEPARATOR;
+
+var ATTR_NAME = DOMProperty.ID_ATTRIBUTE_NAME;
+var nodeCache = {};
+
+var ELEMENT_NODE_TYPE = 1;
+var DOC_NODE_TYPE = 9;
+
+/** Mapping from reactRootID to React component instance. */
+var instancesByReactRootID = {};
+
+/** Mapping from reactRootID to `container` nodes. */
+var containersByReactRootID = {};
+
+if ("production" !== process.env.NODE_ENV) {
+ /** __DEV__-only mapping from reactRootID to root elements. */
+ var rootElementsByReactRootID = {};
+}
+
+// Used to store breadth-first search state in findComponentRoot.
+var findComponentRootReusableArray = [];
+
+/**
+ * @param {DOMElement} container DOM element that may contain a React component.
+ * @return {?string} A "reactRoot" ID, if a React component is rendered.
+ */
+function getReactRootID(container) {
+ var rootElement = getReactRootElementInContainer(container);
+ return rootElement && ReactMount.getID(rootElement);
+}
+
+/**
+ * Accessing node[ATTR_NAME] or calling getAttribute(ATTR_NAME) on a form
+ * element can return its control whose name or ID equals ATTR_NAME. All
+ * DOM nodes support `getAttributeNode` but this can also get called on
+ * other objects so just return '' if we're given something other than a
+ * DOM node (such as window).
+ *
+ * @param {?DOMElement|DOMWindow|DOMDocument|DOMTextNode} node DOM node.
+ * @return {string} ID of the supplied `domNode`.
+ */
+function getID(node) {
+ var id = internalGetID(node);
+ if (id) {
+ if (nodeCache.hasOwnProperty(id)) {
+ var cached = nodeCache[id];
+ if (cached !== node) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !isValid(cached, id),
+ 'ReactMount: Two valid but unequal nodes with the same `%s`: %s',
+ ATTR_NAME, id
+ ) : invariant(!isValid(cached, id)));
+
+ nodeCache[id] = node;
+ }
+ } else {
+ nodeCache[id] = node;
+ }
+ }
+
+ return id;
+}
+
+function internalGetID(node) {
+ // If node is something like a window, document, or text node, none of
+ // which support attributes or a .getAttribute method, gracefully return
+ // the empty string, as if the attribute were missing.
+ return node && node.getAttribute && node.getAttribute(ATTR_NAME) || '';
+}
+
+/**
+ * Sets the React-specific ID of the given node.
+ *
+ * @param {DOMElement} node The DOM node whose ID will be set.
+ * @param {string} id The value of the ID attribute.
+ */
+function setID(node, id) {
+ var oldID = internalGetID(node);
+ if (oldID !== id) {
+ delete nodeCache[oldID];
+ }
+ node.setAttribute(ATTR_NAME, id);
+ nodeCache[id] = node;
+}
+
+/**
+ * Finds the node with the supplied React-generated DOM ID.
+ *
+ * @param {string} id A React-generated DOM ID.
+ * @return {DOMElement} DOM node with the suppled `id`.
+ * @internal
+ */
+function getNode(id) {
+ if (!nodeCache.hasOwnProperty(id) || !isValid(nodeCache[id], id)) {
+ nodeCache[id] = ReactMount.findReactNodeByID(id);
+ }
+ return nodeCache[id];
+}
+
+/**
+ * A node is "valid" if it is contained by a currently mounted container.
+ *
+ * This means that the node does not have to be contained by a document in
+ * order to be considered valid.
+ *
+ * @param {?DOMElement} node The candidate DOM node.
+ * @param {string} id The expected ID of the node.
+ * @return {boolean} Whether the node is contained by a mounted container.
+ */
+function isValid(node, id) {
+ if (node) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ internalGetID(node) === id,
+ 'ReactMount: Unexpected modification of `%s`',
+ ATTR_NAME
+ ) : invariant(internalGetID(node) === id));
+
+ var container = ReactMount.findReactContainerForID(id);
+ if (container && containsNode(container, node)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Causes the cache to forget about one React-specific ID.
+ *
+ * @param {string} id The ID to forget.
+ */
+function purgeID(id) {
+ delete nodeCache[id];
+}
+
+var deepestNodeSoFar = null;
+function findDeepestCachedAncestorImpl(ancestorID) {
+ var ancestor = nodeCache[ancestorID];
+ if (ancestor && isValid(ancestor, ancestorID)) {
+ deepestNodeSoFar = ancestor;
+ } else {
+ // This node isn't populated in the cache, so presumably none of its
+ // descendants are. Break out of the loop.
+ return false;
+ }
+}
+
+/**
+ * Return the deepest cached node whose ID is a prefix of `targetID`.
+ */
+function findDeepestCachedAncestor(targetID) {
+ deepestNodeSoFar = null;
+ ReactInstanceHandles.traverseAncestors(
+ targetID,
+ findDeepestCachedAncestorImpl
+ );
+
+ var foundNode = deepestNodeSoFar;
+ deepestNodeSoFar = null;
+ return foundNode;
+}
+
+/**
+ * Mounting is the process of initializing a React component by creatings its
+ * representative DOM elements and inserting them into a supplied `container`.
+ * Any prior content inside `container` is destroyed in the process.
+ *
+ * ReactMount.render(
+ * component,
+ * document.getElementById('container')
+ * );
+ *
+ * <div id="container"> <-- Supplied `container`.
+ * <div data-reactid=".3"> <-- Rendered reactRoot of React
+ * // ... component.
+ * </div>
+ * </div>
+ *
+ * Inside of `container`, the first element rendered is the "reactRoot".
+ */
+var ReactMount = {
+ /** Exposed for debugging purposes **/
+ _instancesByReactRootID: instancesByReactRootID,
+
+ /**
+ * This is a hook provided to support rendering React components while
+ * ensuring that the apparent scroll position of its `container` does not
+ * change.
+ *
+ * @param {DOMElement} container The `container` being rendered into.
+ * @param {function} renderCallback This must be called once to do the render.
+ */
+ scrollMonitor: function(container, renderCallback) {
+ renderCallback();
+ },
+
+ /**
+ * Take a component that's already mounted into the DOM and replace its props
+ * @param {ReactComponent} prevComponent component instance already in the DOM
+ * @param {ReactComponent} nextComponent component instance to render
+ * @param {DOMElement} container container to render into
+ * @param {?function} callback function triggered on completion
+ */
+ _updateRootComponent: function(
+ prevComponent,
+ nextComponent,
+ container,
+ callback) {
+ var nextProps = nextComponent.props;
+ ReactMount.scrollMonitor(container, function() {
+ prevComponent.replaceProps(nextProps, callback);
+ });
+
+ if ("production" !== process.env.NODE_ENV) {
+ // Record the root element in case it later gets transplanted.
+ rootElementsByReactRootID[getReactRootID(container)] =
+ getReactRootElementInContainer(container);
+ }
+
+ return prevComponent;
+ },
+
+ /**
+ * Register a component into the instance map and starts scroll value
+ * monitoring
+ * @param {ReactComponent} nextComponent component instance to render
+ * @param {DOMElement} container container to render into
+ * @return {string} reactRoot ID prefix
+ */
+ _registerComponent: function(nextComponent, container) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ container && (
+ container.nodeType === ELEMENT_NODE_TYPE ||
+ container.nodeType === DOC_NODE_TYPE
+ ),
+ '_registerComponent(...): Target container is not a DOM element.'
+ ) : invariant(container && (
+ container.nodeType === ELEMENT_NODE_TYPE ||
+ container.nodeType === DOC_NODE_TYPE
+ )));
+
+ ReactBrowserEventEmitter.ensureScrollValueMonitoring();
+
+ var reactRootID = ReactMount.registerContainer(container);
+ instancesByReactRootID[reactRootID] = nextComponent;
+ return reactRootID;
+ },
+
+ /**
+ * Render a new component into the DOM.
+ * @param {ReactComponent} nextComponent component instance to render
+ * @param {DOMElement} container container to render into
+ * @param {boolean} shouldReuseMarkup if we should skip the markup insertion
+ * @return {ReactComponent} nextComponent
+ */
+ _renderNewRootComponent: ReactPerf.measure(
+ 'ReactMount',
+ '_renderNewRootComponent',
+ function(
+ nextComponent,
+ container,
+ shouldReuseMarkup) {
+ // Various parts of our code (such as ReactCompositeComponent's
+ // _renderValidatedComponent) assume that calls to render aren't nested;
+ // verify that that's the case.
+ ("production" !== process.env.NODE_ENV ? warning(
+ ReactCurrentOwner.current == null,
+ '_renderNewRootComponent(): Render methods should be a pure function ' +
+ 'of props and state; triggering nested component updates from ' +
+ 'render is not allowed. If necessary, trigger nested updates in ' +
+ 'componentDidUpdate.'
+ ) : null);
+
+ var componentInstance = instantiateReactComponent(nextComponent, null);
+ var reactRootID = ReactMount._registerComponent(
+ componentInstance,
+ container
+ );
+ componentInstance.mountComponentIntoNode(
+ reactRootID,
+ container,
+ shouldReuseMarkup
+ );
+
+ if ("production" !== process.env.NODE_ENV) {
+ // Record the root element in case it later gets transplanted.
+ rootElementsByReactRootID[reactRootID] =
+ getReactRootElementInContainer(container);
+ }
+
+ return componentInstance;
+ }
+ ),
+
+ /**
+ * Renders a React component into the DOM in the supplied `container`.
+ *
+ * If the React component was previously rendered into `container`, this will
+ * perform an update on it and only mutate the DOM as necessary to reflect the
+ * latest React component.
+ *
+ * @param {ReactElement} nextElement Component element to render.
+ * @param {DOMElement} container DOM element to render into.
+ * @param {?function} callback function triggered on completion
+ * @return {ReactComponent} Component instance rendered in `container`.
+ */
+ render: function(nextElement, container, callback) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ ReactElement.isValidElement(nextElement),
+ 'renderComponent(): Invalid component element.%s',
+ (
+ typeof nextElement === 'string' ?
+ ' Instead of passing an element string, make sure to instantiate ' +
+ 'it by passing it to React.createElement.' :
+ ReactLegacyElement.isValidFactory(nextElement) ?
+ ' Instead of passing a component class, make sure to instantiate ' +
+ 'it by passing it to React.createElement.' :
+ // Check if it quacks like a element
+ typeof nextElement.props !== "undefined" ?
+ ' This may be caused by unintentionally loading two independent ' +
+ 'copies of React.' :
+ ''
+ )
+ ) : invariant(ReactElement.isValidElement(nextElement)));
+
+ var prevComponent = instancesByReactRootID[getReactRootID(container)];
+
+ if (prevComponent) {
+ var prevElement = prevComponent._currentElement;
+ if (shouldUpdateReactComponent(prevElement, nextElement)) {
+ return ReactMount._updateRootComponent(
+ prevComponent,
+ nextElement,
+ container,
+ callback
+ );
+ } else {
+ ReactMount.unmountComponentAtNode(container);
+ }
+ }
+
+ var reactRootElement = getReactRootElementInContainer(container);
+ var containerHasReactMarkup =
+ reactRootElement && ReactMount.isRenderedByReact(reactRootElement);
+
+ var shouldReuseMarkup = containerHasReactMarkup && !prevComponent;
+
+ var component = ReactMount._renderNewRootComponent(
+ nextElement,
+ container,
+ shouldReuseMarkup
+ );
+ callback && callback.call(component);
+ return component;
+ },
+
+ /**
+ * Constructs a component instance of `constructor` with `initialProps` and
+ * renders it into the supplied `container`.
+ *
+ * @param {function} constructor React component constructor.
+ * @param {?object} props Initial props of the component instance.
+ * @param {DOMElement} container DOM element to render into.
+ * @return {ReactComponent} Component instance rendered in `container`.
+ */
+ constructAndRenderComponent: function(constructor, props, container) {
+ var element = createElement(constructor, props);
+ return ReactMount.render(element, container);
+ },
+
+ /**
+ * Constructs a component instance of `constructor` with `initialProps` and
+ * renders it into a container node identified by supplied `id`.
+ *
+ * @param {function} componentConstructor React component constructor
+ * @param {?object} props Initial props of the component instance.
+ * @param {string} id ID of the DOM element to render into.
+ * @return {ReactComponent} Component instance rendered in the container node.
+ */
+ constructAndRenderComponentByID: function(constructor, props, id) {
+ var domNode = document.getElementById(id);
+ ("production" !== process.env.NODE_ENV ? invariant(
+ domNode,
+ 'Tried to get element with id of "%s" but it is not present on the page.',
+ id
+ ) : invariant(domNode));
+ return ReactMount.constructAndRenderComponent(constructor, props, domNode);
+ },
+
+ /**
+ * Registers a container node into which React components will be rendered.
+ * This also creates the "reactRoot" ID that will be assigned to the element
+ * rendered within.
+ *
+ * @param {DOMElement} container DOM element to register as a container.
+ * @return {string} The "reactRoot" ID of elements rendered within.
+ */
+ registerContainer: function(container) {
+ var reactRootID = getReactRootID(container);
+ if (reactRootID) {
+ // If one exists, make sure it is a valid "reactRoot" ID.
+ reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(reactRootID);
+ }
+ if (!reactRootID) {
+ // No valid "reactRoot" ID found, create one.
+ reactRootID = ReactInstanceHandles.createReactRootID();
+ }
+ containersByReactRootID[reactRootID] = container;
+ return reactRootID;
+ },
+
+ /**
+ * Unmounts and destroys the React component rendered in the `container`.
+ *
+ * @param {DOMElement} container DOM element containing a React component.
+ * @return {boolean} True if a component was found in and unmounted from
+ * `container`
+ */
+ unmountComponentAtNode: function(container) {
+ // Various parts of our code (such as ReactCompositeComponent's
+ // _renderValidatedComponent) assume that calls to render aren't nested;
+ // verify that that's the case. (Strictly speaking, unmounting won't cause a
+ // render but we still don't expect to be in a render call here.)
+ ("production" !== process.env.NODE_ENV ? warning(
+ ReactCurrentOwner.current == null,
+ 'unmountComponentAtNode(): Render methods should be a pure function of ' +
+ 'props and state; triggering nested component updates from render is ' +
+ 'not allowed. If necessary, trigger nested updates in ' +
+ 'componentDidUpdate.'
+ ) : null);
+
+ var reactRootID = getReactRootID(container);
+ var component = instancesByReactRootID[reactRootID];
+ if (!component) {
+ return false;
+ }
+ ReactMount.unmountComponentFromNode(component, container);
+ delete instancesByReactRootID[reactRootID];
+ delete containersByReactRootID[reactRootID];
+ if ("production" !== process.env.NODE_ENV) {
+ delete rootElementsByReactRootID[reactRootID];
+ }
+ return true;
+ },
+
+ /**
+ * Unmounts a component and removes it from the DOM.
+ *
+ * @param {ReactComponent} instance React component instance.
+ * @param {DOMElement} container DOM element to unmount from.
+ * @final
+ * @internal
+ * @see {ReactMount.unmountComponentAtNode}
+ */
+ unmountComponentFromNode: function(instance, container) {
+ instance.unmountComponent();
+
+ if (container.nodeType === DOC_NODE_TYPE) {
+ container = container.documentElement;
+ }
+
+ // http://jsperf.com/emptying-a-node
+ while (container.lastChild) {
+ container.removeChild(container.lastChild);
+ }
+ },
+
+ /**
+ * Finds the container DOM element that contains React component to which the
+ * supplied DOM `id` belongs.
+ *
+ * @param {string} id The ID of an element rendered by a React component.
+ * @return {?DOMElement} DOM element that contains the `id`.
+ */
+ findReactContainerForID: function(id) {
+ var reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(id);
+ var container = containersByReactRootID[reactRootID];
+
+ if ("production" !== process.env.NODE_ENV) {
+ var rootElement = rootElementsByReactRootID[reactRootID];
+ if (rootElement && rootElement.parentNode !== container) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ // Call internalGetID here because getID calls isValid which calls
+ // findReactContainerForID (this function).
+ internalGetID(rootElement) === reactRootID,
+ 'ReactMount: Root element ID differed from reactRootID.'
+ ) : invariant(// Call internalGetID here because getID calls isValid which calls
+ // findReactContainerForID (this function).
+ internalGetID(rootElement) === reactRootID));
+
+ var containerChild = container.firstChild;
+ if (containerChild &&
+ reactRootID === internalGetID(containerChild)) {
+ // If the container has a new child with the same ID as the old
+ // root element, then rootElementsByReactRootID[reactRootID] is
+ // just stale and needs to be updated. The case that deserves a
+ // warning is when the container is empty.
+ rootElementsByReactRootID[reactRootID] = containerChild;
+ } else {
+ console.warn(
+ 'ReactMount: Root element has been removed from its original ' +
+ 'container. New container:', rootElement.parentNode
+ );
+ }
+ }
+ }
+
+ return container;
+ },
+
+ /**
+ * Finds an element rendered by React with the supplied ID.
+ *
+ * @param {string} id ID of a DOM node in the React component.
+ * @return {DOMElement} Root DOM node of the React component.
+ */
+ findReactNodeByID: function(id) {
+ var reactRoot = ReactMount.findReactContainerForID(id);
+ return ReactMount.findComponentRoot(reactRoot, id);
+ },
+
+ /**
+ * True if the supplied `node` is rendered by React.
+ *
+ * @param {*} node DOM Element to check.
+ * @return {boolean} True if the DOM Element appears to be rendered by React.
+ * @internal
+ */
+ isRenderedByReact: function(node) {
+ if (node.nodeType !== 1) {
+ // Not a DOMElement, therefore not a React component
+ return false;
+ }
+ var id = ReactMount.getID(node);
+ return id ? id.charAt(0) === SEPARATOR : false;
+ },
+
+ /**
+ * Traverses up the ancestors of the supplied node to find a node that is a
+ * DOM representation of a React component.
+ *
+ * @param {*} node
+ * @return {?DOMEventTarget}
+ * @internal
+ */
+ getFirstReactDOM: function(node) {
+ var current = node;
+ while (current && current.parentNode !== current) {
+ if (ReactMount.isRenderedByReact(current)) {
+ return current;
+ }
+ current = current.parentNode;
+ }
+ return null;
+ },
+
+ /**
+ * Finds a node with the supplied `targetID` inside of the supplied
+ * `ancestorNode`. Exploits the ID naming scheme to perform the search
+ * quickly.
+ *
+ * @param {DOMEventTarget} ancestorNode Search from this root.
+ * @pararm {string} targetID ID of the DOM representation of the component.
+ * @return {DOMEventTarget} DOM node with the supplied `targetID`.
+ * @internal
+ */
+ findComponentRoot: function(ancestorNode, targetID) {
+ var firstChildren = findComponentRootReusableArray;
+ var childIndex = 0;
+
+ var deepestAncestor = findDeepestCachedAncestor(targetID) || ancestorNode;
+
+ firstChildren[0] = deepestAncestor.firstChild;
+ firstChildren.length = 1;
+
+ while (childIndex < firstChildren.length) {
+ var child = firstChildren[childIndex++];
+ var targetChild;
+
+ while (child) {
+ var childID = ReactMount.getID(child);
+ if (childID) {
+ // Even if we find the node we're looking for, we finish looping
+ // through its siblings to ensure they're cached so that we don't have
+ // to revisit this node again. Otherwise, we make n^2 calls to getID
+ // when visiting the many children of a single node in order.
+
+ if (targetID === childID) {
+ targetChild = child;
+ } else if (ReactInstanceHandles.isAncestorIDOf(childID, targetID)) {
+ // If we find a child whose ID is an ancestor of the given ID,
+ // then we can be sure that we only want to search the subtree
+ // rooted at this child, so we can throw out the rest of the
+ // search state.
+ firstChildren.length = childIndex = 0;
+ firstChildren.push(child.firstChild);
+ }
+
+ } else {
+ // If this child had no ID, then there's a chance that it was
+ // injected automatically by the browser, as when a `<table>`
+ // element sprouts an extra `<tbody>` child as a side effect of
+ // `.innerHTML` parsing. Optimistically continue down this
+ // branch, but not before examining the other siblings.
+ firstChildren.push(child.firstChild);
+ }
+
+ child = child.nextSibling;
+ }
+
+ if (targetChild) {
+ // Emptying firstChildren/findComponentRootReusableArray is
+ // not necessary for correctness, but it helps the GC reclaim
+ // any nodes that were left at the end of the search.
+ firstChildren.length = 0;
+
+ return targetChild;
+ }
+ }
+
+ firstChildren.length = 0;
+
+ ("production" !== process.env.NODE_ENV ? invariant(
+ false,
+ 'findComponentRoot(..., %s): Unable to find element. This probably ' +
+ 'means the DOM was unexpectedly mutated (e.g., by the browser), ' +
+ 'usually due to forgetting a <tbody> when using tables, nesting tags ' +
+ 'like <form>, <p>, or <a>, or using non-SVG elements in an <svg> ' +
+ 'parent. ' +
+ 'Try inspecting the child nodes of the element with React ID `%s`.',
+ targetID,
+ ReactMount.getID(ancestorNode)
+ ) : invariant(false));
+ },
+
+
+ /**
+ * React ID utilities.
+ */
+
+ getReactRootID: getReactRootID,
+
+ getID: getID,
+
+ setID: setID,
+
+ getNode: getNode,
+
+ purgeID: purgeID
+};
+
+// Deprecations (remove for 0.13)
+ReactMount.renderComponent = deprecated(
+ 'ReactMount',
+ 'renderComponent',
+ 'render',
+ this,
+ ReactMount.render
+);
+
+module.exports = ReactMount;
+
+}).call(this,require('_process'))
+},{"./DOMProperty":58,"./ReactBrowserEventEmitter":79,"./ReactCurrentOwner":88,"./ReactElement":104,"./ReactInstanceHandles":112,"./ReactLegacyElement":113,"./ReactPerf":121,"./containsNode":161,"./deprecated":167,"./getReactRootElementInContainer":181,"./instantiateReactComponent":186,"./invariant":187,"./shouldUpdateReactComponent":203,"./warning":207,"_process":5}],117:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactMultiChild
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var ReactComponent = require("./ReactComponent");
+var ReactMultiChildUpdateTypes = require("./ReactMultiChildUpdateTypes");
+
+var flattenChildren = require("./flattenChildren");
+var instantiateReactComponent = require("./instantiateReactComponent");
+var shouldUpdateReactComponent = require("./shouldUpdateReactComponent");
+
+/**
+ * Updating children of a component may trigger recursive updates. The depth is
+ * used to batch recursive updates to render markup more efficiently.
+ *
+ * @type {number}
+ * @private
+ */
+var updateDepth = 0;
+
+/**
+ * Queue of update configuration objects.
+ *
+ * Each object has a `type` property that is in `ReactMultiChildUpdateTypes`.
+ *
+ * @type {array<object>}
+ * @private
+ */
+var updateQueue = [];
+
+/**
+ * Queue of markup to be rendered.
+ *
+ * @type {array<string>}
+ * @private
+ */
+var markupQueue = [];
+
+/**
+ * Enqueues markup to be rendered and inserted at a supplied index.
+ *
+ * @param {string} parentID ID of the parent component.
+ * @param {string} markup Markup that renders into an element.
+ * @param {number} toIndex Destination index.
+ * @private
+ */
+function enqueueMarkup(parentID, markup, toIndex) {
+ // NOTE: Null values reduce hidden classes.
+ updateQueue.push({
+ parentID: parentID,
+ parentNode: null,
+ type: ReactMultiChildUpdateTypes.INSERT_MARKUP,
+ markupIndex: markupQueue.push(markup) - 1,
+ textContent: null,
+ fromIndex: null,
+ toIndex: toIndex
+ });
+}
+
+/**
+ * Enqueues moving an existing element to another index.
+ *
+ * @param {string} parentID ID of the parent component.
+ * @param {number} fromIndex Source index of the existing element.
+ * @param {number} toIndex Destination index of the element.
+ * @private
+ */
+function enqueueMove(parentID, fromIndex, toIndex) {
+ // NOTE: Null values reduce hidden classes.
+ updateQueue.push({
+ parentID: parentID,
+ parentNode: null,
+ type: ReactMultiChildUpdateTypes.MOVE_EXISTING,
+ markupIndex: null,
+ textContent: null,
+ fromIndex: fromIndex,
+ toIndex: toIndex
+ });
+}
+
+/**
+ * Enqueues removing an element at an index.
+ *
+ * @param {string} parentID ID of the parent component.
+ * @param {number} fromIndex Index of the element to remove.
+ * @private
+ */
+function enqueueRemove(parentID, fromIndex) {
+ // NOTE: Null values reduce hidden classes.
+ updateQueue.push({
+ parentID: parentID,
+ parentNode: null,
+ type: ReactMultiChildUpdateTypes.REMOVE_NODE,
+ markupIndex: null,
+ textContent: null,
+ fromIndex: fromIndex,
+ toIndex: null
+ });
+}
+
+/**
+ * Enqueues setting the text content.
+ *
+ * @param {string} parentID ID of the parent component.
+ * @param {string} textContent Text content to set.
+ * @private
+ */
+function enqueueTextContent(parentID, textContent) {
+ // NOTE: Null values reduce hidden classes.
+ updateQueue.push({
+ parentID: parentID,
+ parentNode: null,
+ type: ReactMultiChildUpdateTypes.TEXT_CONTENT,
+ markupIndex: null,
+ textContent: textContent,
+ fromIndex: null,
+ toIndex: null
+ });
+}
+
+/**
+ * Processes any enqueued updates.
+ *
+ * @private
+ */
+function processQueue() {
+ if (updateQueue.length) {
+ ReactComponent.BackendIDOperations.dangerouslyProcessChildrenUpdates(
+ updateQueue,
+ markupQueue
+ );
+ clearQueue();
+ }
+}
+
+/**
+ * Clears any enqueued updates.
+ *
+ * @private
+ */
+function clearQueue() {
+ updateQueue.length = 0;
+ markupQueue.length = 0;
+}
+
+/**
+ * ReactMultiChild are capable of reconciling multiple children.
+ *
+ * @class ReactMultiChild
+ * @internal
+ */
+var ReactMultiChild = {
+
+ /**
+ * Provides common functionality for components that must reconcile multiple
+ * children. This is used by `ReactDOMComponent` to mount, update, and
+ * unmount child components.
+ *
+ * @lends {ReactMultiChild.prototype}
+ */
+ Mixin: {
+
+ /**
+ * Generates a "mount image" for each of the supplied children. In the case
+ * of `ReactDOMComponent`, a mount image is a string of markup.
+ *
+ * @param {?object} nestedChildren Nested child maps.
+ * @return {array} An array of mounted representations.
+ * @internal
+ */
+ mountChildren: function(nestedChildren, transaction) {
+ var children = flattenChildren(nestedChildren);
+ var mountImages = [];
+ var index = 0;
+ this._renderedChildren = children;
+ for (var name in children) {
+ var child = children[name];
+ if (children.hasOwnProperty(name)) {
+ // The rendered children must be turned into instances as they're
+ // mounted.
+ var childInstance = instantiateReactComponent(child, null);
+ children[name] = childInstance;
+ // Inlined for performance, see `ReactInstanceHandles.createReactID`.
+ var rootID = this._rootNodeID + name;
+ var mountImage = childInstance.mountComponent(
+ rootID,
+ transaction,
+ this._mountDepth + 1
+ );
+ childInstance._mountIndex = index;
+ mountImages.push(mountImage);
+ index++;
+ }
+ }
+ return mountImages;
+ },
+
+ /**
+ * Replaces any rendered children with a text content string.
+ *
+ * @param {string} nextContent String of content.
+ * @internal
+ */
+ updateTextContent: function(nextContent) {
+ updateDepth++;
+ var errorThrown = true;
+ try {
+ var prevChildren = this._renderedChildren;
+ // Remove any rendered children.
+ for (var name in prevChildren) {
+ if (prevChildren.hasOwnProperty(name)) {
+ this._unmountChildByName(prevChildren[name], name);
+ }
+ }
+ // Set new text content.
+ this.setTextContent(nextContent);
+ errorThrown = false;
+ } finally {
+ updateDepth--;
+ if (!updateDepth) {
+ errorThrown ? clearQueue() : processQueue();
+ }
+ }
+ },
+
+ /**
+ * Updates the rendered children with new children.
+ *
+ * @param {?object} nextNestedChildren Nested child maps.
+ * @param {ReactReconcileTransaction} transaction
+ * @internal
+ */
+ updateChildren: function(nextNestedChildren, transaction) {
+ updateDepth++;
+ var errorThrown = true;
+ try {
+ this._updateChildren(nextNestedChildren, transaction);
+ errorThrown = false;
+ } finally {
+ updateDepth--;
+ if (!updateDepth) {
+ errorThrown ? clearQueue() : processQueue();
+ }
+ }
+ },
+
+ /**
+ * Improve performance by isolating this hot code path from the try/catch
+ * block in `updateChildren`.
+ *
+ * @param {?object} nextNestedChildren Nested child maps.
+ * @param {ReactReconcileTransaction} transaction
+ * @final
+ * @protected
+ */
+ _updateChildren: function(nextNestedChildren, transaction) {
+ var nextChildren = flattenChildren(nextNestedChildren);
+ var prevChildren = this._renderedChildren;
+ if (!nextChildren && !prevChildren) {
+ return;
+ }
+ var name;
+ // `nextIndex` will increment for each child in `nextChildren`, but
+ // `lastIndex` will be the last index visited in `prevChildren`.
+ var lastIndex = 0;
+ var nextIndex = 0;
+ for (name in nextChildren) {
+ if (!nextChildren.hasOwnProperty(name)) {
+ continue;
+ }
+ var prevChild = prevChildren && prevChildren[name];
+ var prevElement = prevChild && prevChild._currentElement;
+ var nextElement = nextChildren[name];
+ if (shouldUpdateReactComponent(prevElement, nextElement)) {
+ this.moveChild(prevChild, nextIndex, lastIndex);
+ lastIndex = Math.max(prevChild._mountIndex, lastIndex);
+ prevChild.receiveComponent(nextElement, transaction);
+ prevChild._mountIndex = nextIndex;
+ } else {
+ if (prevChild) {
+ // Update `lastIndex` before `_mountIndex` gets unset by unmounting.
+ lastIndex = Math.max(prevChild._mountIndex, lastIndex);
+ this._unmountChildByName(prevChild, name);
+ }
+ // The child must be instantiated before it's mounted.
+ var nextChildInstance = instantiateReactComponent(
+ nextElement,
+ null
+ );
+ this._mountChildByNameAtIndex(
+ nextChildInstance, name, nextIndex, transaction
+ );
+ }
+ nextIndex++;
+ }
+ // Remove children that are no longer present.
+ for (name in prevChildren) {
+ if (prevChildren.hasOwnProperty(name) &&
+ !(nextChildren && nextChildren[name])) {
+ this._unmountChildByName(prevChildren[name], name);
+ }
+ }
+ },
+
+ /**
+ * Unmounts all rendered children. This should be used to clean up children
+ * when this component is unmounted.
+ *
+ * @internal
+ */
+ unmountChildren: function() {
+ var renderedChildren = this._renderedChildren;
+ for (var name in renderedChildren) {
+ var renderedChild = renderedChildren[name];
+ // TODO: When is this not true?
+ if (renderedChild.unmountComponent) {
+ renderedChild.unmountComponent();
+ }
+ }
+ this._renderedChildren = null;
+ },
+
+ /**
+ * Moves a child component to the supplied index.
+ *
+ * @param {ReactComponent} child Component to move.
+ * @param {number} toIndex Destination index of the element.
+ * @param {number} lastIndex Last index visited of the siblings of `child`.
+ * @protected
+ */
+ moveChild: function(child, toIndex, lastIndex) {
+ // If the index of `child` is less than `lastIndex`, then it needs to
+ // be moved. Otherwise, we do not need to move it because a child will be
+ // inserted or moved before `child`.
+ if (child._mountIndex < lastIndex) {
+ enqueueMove(this._rootNodeID, child._mountIndex, toIndex);
+ }
+ },
+
+ /**
+ * Creates a child component.
+ *
+ * @param {ReactComponent} child Component to create.
+ * @param {string} mountImage Markup to insert.
+ * @protected
+ */
+ createChild: function(child, mountImage) {
+ enqueueMarkup(this._rootNodeID, mountImage, child._mountIndex);
+ },
+
+ /**
+ * Removes a child component.
+ *
+ * @param {ReactComponent} child Child to remove.
+ * @protected
+ */
+ removeChild: function(child) {
+ enqueueRemove(this._rootNodeID, child._mountIndex);
+ },
+
+ /**
+ * Sets this text content string.
+ *
+ * @param {string} textContent Text content to set.
+ * @protected
+ */
+ setTextContent: function(textContent) {
+ enqueueTextContent(this._rootNodeID, textContent);
+ },
+
+ /**
+ * Mounts a child with the supplied name.
+ *
+ * NOTE: This is part of `updateChildren` and is here for readability.
+ *
+ * @param {ReactComponent} child Component to mount.
+ * @param {string} name Name of the child.
+ * @param {number} index Index at which to insert the child.
+ * @param {ReactReconcileTransaction} transaction
+ * @private
+ */
+ _mountChildByNameAtIndex: function(child, name, index, transaction) {
+ // Inlined for performance, see `ReactInstanceHandles.createReactID`.
+ var rootID = this._rootNodeID + name;
+ var mountImage = child.mountComponent(
+ rootID,
+ transaction,
+ this._mountDepth + 1
+ );
+ child._mountIndex = index;
+ this.createChild(child, mountImage);
+ this._renderedChildren = this._renderedChildren || {};
+ this._renderedChildren[name] = child;
+ },
+
+ /**
+ * Unmounts a rendered child by name.
+ *
+ * NOTE: This is part of `updateChildren` and is here for readability.
+ *
+ * @param {ReactComponent} child Component to unmount.
+ * @param {string} name Name of the child in `this._renderedChildren`.
+ * @private
+ */
+ _unmountChildByName: function(child, name) {
+ this.removeChild(child);
+ child._mountIndex = null;
+ child.unmountComponent();
+ delete this._renderedChildren[name];
+ }
+
+ }
+
+};
+
+module.exports = ReactMultiChild;
+
+},{"./ReactComponent":83,"./ReactMultiChildUpdateTypes":118,"./flattenChildren":171,"./instantiateReactComponent":186,"./shouldUpdateReactComponent":203}],118:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactMultiChildUpdateTypes
+ */
+
+"use strict";
+
+var keyMirror = require("./keyMirror");
+
+/**
+ * When a component's children are updated, a series of update configuration
+ * objects are created in order to batch and serialize the required changes.
+ *
+ * Enumerates all the possible types of update configurations.
+ *
+ * @internal
+ */
+var ReactMultiChildUpdateTypes = keyMirror({
+ INSERT_MARKUP: null,
+ MOVE_EXISTING: null,
+ REMOVE_NODE: null,
+ TEXT_CONTENT: null
+});
+
+module.exports = ReactMultiChildUpdateTypes;
+
+},{"./keyMirror":193}],119:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactNativeComponent
+ */
+
+"use strict";
+
+var assign = require("./Object.assign");
+var invariant = require("./invariant");
+
+var genericComponentClass = null;
+// This registry keeps track of wrapper classes around native tags
+var tagToComponentClass = {};
+
+var ReactNativeComponentInjection = {
+ // This accepts a class that receives the tag string. This is a catch all
+ // that can render any kind of tag.
+ injectGenericComponentClass: function(componentClass) {
+ genericComponentClass = componentClass;
+ },
+ // This accepts a keyed object with classes as values. Each key represents a
+ // tag. That particular tag will use this class instead of the generic one.
+ injectComponentClasses: function(componentClasses) {
+ assign(tagToComponentClass, componentClasses);
+ }
+};
+
+/**
+ * Create an internal class for a specific tag.
+ *
+ * @param {string} tag The tag for which to create an internal instance.
+ * @param {any} props The props passed to the instance constructor.
+ * @return {ReactComponent} component The injected empty component.
+ */
+function createInstanceForTag(tag, props, parentType) {
+ var componentClass = tagToComponentClass[tag];
+ if (componentClass == null) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ genericComponentClass,
+ 'There is no registered component for the tag %s',
+ tag
+ ) : invariant(genericComponentClass));
+ return new genericComponentClass(tag, props);
+ }
+ if (parentType === tag) {
+ // Avoid recursion
+ ("production" !== process.env.NODE_ENV ? invariant(
+ genericComponentClass,
+ 'There is no registered component for the tag %s',
+ tag
+ ) : invariant(genericComponentClass));
+ return new genericComponentClass(tag, props);
+ }
+ // Unwrap legacy factories
+ return new componentClass.type(props);
+}
+
+var ReactNativeComponent = {
+ createInstanceForTag: createInstanceForTag,
+ injection: ReactNativeComponentInjection
+};
+
+module.exports = ReactNativeComponent;
+
+}).call(this,require('_process'))
+},{"./Object.assign":75,"./invariant":187,"_process":5}],120:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactOwner
+ */
+
+"use strict";
+
+var emptyObject = require("./emptyObject");
+var invariant = require("./invariant");
+
+/**
+ * ReactOwners are capable of storing references to owned components.
+ *
+ * All components are capable of //being// referenced by owner components, but
+ * only ReactOwner components are capable of //referencing// owned components.
+ * The named reference is known as a "ref".
+ *
+ * Refs are available when mounted and updated during reconciliation.
+ *
+ * var MyComponent = React.createClass({
+ * render: function() {
+ * return (
+ * <div onClick={this.handleClick}>
+ * <CustomComponent ref="custom" />
+ * </div>
+ * );
+ * },
+ * handleClick: function() {
+ * this.refs.custom.handleClick();
+ * },
+ * componentDidMount: function() {
+ * this.refs.custom.initialize();
+ * }
+ * });
+ *
+ * Refs should rarely be used. When refs are used, they should only be done to
+ * control data that is not handled by React's data flow.
+ *
+ * @class ReactOwner
+ */
+var ReactOwner = {
+
+ /**
+ * @param {?object} object
+ * @return {boolean} True if `object` is a valid owner.
+ * @final
+ */
+ isValidOwner: function(object) {
+ return !!(
+ object &&
+ typeof object.attachRef === 'function' &&
+ typeof object.detachRef === 'function'
+ );
+ },
+
+ /**
+ * Adds a component by ref to an owner component.
+ *
+ * @param {ReactComponent} component Component to reference.
+ * @param {string} ref Name by which to refer to the component.
+ * @param {ReactOwner} owner Component on which to record the ref.
+ * @final
+ * @internal
+ */
+ addComponentAsRefTo: function(component, ref, owner) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ ReactOwner.isValidOwner(owner),
+ 'addComponentAsRefTo(...): Only a ReactOwner can have refs. This ' +
+ 'usually means that you\'re trying to add a ref to a component that ' +
+ 'doesn\'t have an owner (that is, was not created inside of another ' +
+ 'component\'s `render` method). Try rendering this component inside of ' +
+ 'a new top-level component which will hold the ref.'
+ ) : invariant(ReactOwner.isValidOwner(owner)));
+ owner.attachRef(ref, component);
+ },
+
+ /**
+ * Removes a component by ref from an owner component.
+ *
+ * @param {ReactComponent} component Component to dereference.
+ * @param {string} ref Name of the ref to remove.
+ * @param {ReactOwner} owner Component on which the ref is recorded.
+ * @final
+ * @internal
+ */
+ removeComponentAsRefFrom: function(component, ref, owner) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ ReactOwner.isValidOwner(owner),
+ 'removeComponentAsRefFrom(...): Only a ReactOwner can have refs. This ' +
+ 'usually means that you\'re trying to remove a ref to a component that ' +
+ 'doesn\'t have an owner (that is, was not created inside of another ' +
+ 'component\'s `render` method). Try rendering this component inside of ' +
+ 'a new top-level component which will hold the ref.'
+ ) : invariant(ReactOwner.isValidOwner(owner)));
+ // Check that `component` is still the current ref because we do not want to
+ // detach the ref if another component stole it.
+ if (owner.refs[ref] === component) {
+ owner.detachRef(ref);
+ }
+ },
+
+ /**
+ * A ReactComponent must mix this in to have refs.
+ *
+ * @lends {ReactOwner.prototype}
+ */
+ Mixin: {
+
+ construct: function() {
+ this.refs = emptyObject;
+ },
+
+ /**
+ * Lazily allocates the refs object and stores `component` as `ref`.
+ *
+ * @param {string} ref Reference name.
+ * @param {component} component Component to store as `ref`.
+ * @final
+ * @private
+ */
+ attachRef: function(ref, component) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ component.isOwnedBy(this),
+ 'attachRef(%s, ...): Only a component\'s owner can store a ref to it.',
+ ref
+ ) : invariant(component.isOwnedBy(this)));
+ var refs = this.refs === emptyObject ? (this.refs = {}) : this.refs;
+ refs[ref] = component;
+ },
+
+ /**
+ * Detaches a reference name.
+ *
+ * @param {string} ref Name to dereference.
+ * @final
+ * @private
+ */
+ detachRef: function(ref) {
+ delete this.refs[ref];
+ }
+
+ }
+
+};
+
+module.exports = ReactOwner;
+
+}).call(this,require('_process'))
+},{"./emptyObject":169,"./invariant":187,"_process":5}],121:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactPerf
+ * @typechecks static-only
+ */
+
+"use strict";
+
+/**
+ * ReactPerf is a general AOP system designed to measure performance. This
+ * module only has the hooks: see ReactDefaultPerf for the analysis tool.
+ */
+var ReactPerf = {
+ /**
+ * Boolean to enable/disable measurement. Set to false by default to prevent
+ * accidental logging and perf loss.
+ */
+ enableMeasure: false,
+
+ /**
+ * Holds onto the measure function in use. By default, don't measure
+ * anything, but we'll override this if we inject a measure function.
+ */
+ storedMeasure: _noMeasure,
+
+ /**
+ * Use this to wrap methods you want to measure. Zero overhead in production.
+ *
+ * @param {string} objName
+ * @param {string} fnName
+ * @param {function} func
+ * @return {function}
+ */
+ measure: function(objName, fnName, func) {
+ if ("production" !== process.env.NODE_ENV) {
+ var measuredFunc = null;
+ var wrapper = function() {
+ if (ReactPerf.enableMeasure) {
+ if (!measuredFunc) {
+ measuredFunc = ReactPerf.storedMeasure(objName, fnName, func);
+ }
+ return measuredFunc.apply(this, arguments);
+ }
+ return func.apply(this, arguments);
+ };
+ wrapper.displayName = objName + '_' + fnName;
+ return wrapper;
+ }
+ return func;
+ },
+
+ injection: {
+ /**
+ * @param {function} measure
+ */
+ injectMeasure: function(measure) {
+ ReactPerf.storedMeasure = measure;
+ }
+ }
+};
+
+/**
+ * Simply passes through the measured function, without measuring it.
+ *
+ * @param {string} objName
+ * @param {string} fnName
+ * @param {function} func
+ * @return {function}
+ */
+function _noMeasure(objName, fnName, func) {
+ return func;
+}
+
+module.exports = ReactPerf;
+
+}).call(this,require('_process'))
+},{"_process":5}],122:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactPropTransferer
+ */
+
+"use strict";
+
+var assign = require("./Object.assign");
+var emptyFunction = require("./emptyFunction");
+var invariant = require("./invariant");
+var joinClasses = require("./joinClasses");
+var warning = require("./warning");
+
+var didWarn = false;
+
+/**
+ * Creates a transfer strategy that will merge prop values using the supplied
+ * `mergeStrategy`. If a prop was previously unset, this just sets it.
+ *
+ * @param {function} mergeStrategy
+ * @return {function}
+ */
+function createTransferStrategy(mergeStrategy) {
+ return function(props, key, value) {
+ if (!props.hasOwnProperty(key)) {
+ props[key] = value;
+ } else {
+ props[key] = mergeStrategy(props[key], value);
+ }
+ };
+}
+
+var transferStrategyMerge = createTransferStrategy(function(a, b) {
+ // `merge` overrides the first object's (`props[key]` above) keys using the
+ // second object's (`value`) keys. An object's style's existing `propA` would
+ // get overridden. Flip the order here.
+ return assign({}, b, a);
+});
+
+/**
+ * Transfer strategies dictate how props are transferred by `transferPropsTo`.
+ * NOTE: if you add any more exceptions to this list you should be sure to
+ * update `cloneWithProps()` accordingly.
+ */
+var TransferStrategies = {
+ /**
+ * Never transfer `children`.
+ */
+ children: emptyFunction,
+ /**
+ * Transfer the `className` prop by merging them.
+ */
+ className: createTransferStrategy(joinClasses),
+ /**
+ * Transfer the `style` prop (which is an object) by merging them.
+ */
+ style: transferStrategyMerge
+};
+
+/**
+ * Mutates the first argument by transferring the properties from the second
+ * argument.
+ *
+ * @param {object} props
+ * @param {object} newProps
+ * @return {object}
+ */
+function transferInto(props, newProps) {
+ for (var thisKey in newProps) {
+ if (!newProps.hasOwnProperty(thisKey)) {
+ continue;
+ }
+
+ var transferStrategy = TransferStrategies[thisKey];
+
+ if (transferStrategy && TransferStrategies.hasOwnProperty(thisKey)) {
+ transferStrategy(props, thisKey, newProps[thisKey]);
+ } else if (!props.hasOwnProperty(thisKey)) {
+ props[thisKey] = newProps[thisKey];
+ }
+ }
+ return props;
+}
+
+/**
+ * ReactPropTransferer are capable of transferring props to another component
+ * using a `transferPropsTo` method.
+ *
+ * @class ReactPropTransferer
+ */
+var ReactPropTransferer = {
+
+ TransferStrategies: TransferStrategies,
+
+ /**
+ * Merge two props objects using TransferStrategies.
+ *
+ * @param {object} oldProps original props (they take precedence)
+ * @param {object} newProps new props to merge in
+ * @return {object} a new object containing both sets of props merged.
+ */
+ mergeProps: function(oldProps, newProps) {
+ return transferInto(assign({}, oldProps), newProps);
+ },
+
+ /**
+ * @lends {ReactPropTransferer.prototype}
+ */
+ Mixin: {
+
+ /**
+ * Transfer props from this component to a target component.
+ *
+ * Props that do not have an explicit transfer strategy will be transferred
+ * only if the target component does not already have the prop set.
+ *
+ * This is usually used to pass down props to a returned root component.
+ *
+ * @param {ReactElement} element Component receiving the properties.
+ * @return {ReactElement} The supplied `component`.
+ * @final
+ * @protected
+ */
+ transferPropsTo: function(element) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ element._owner === this,
+ '%s: You can\'t call transferPropsTo() on a component that you ' +
+ 'don\'t own, %s. This usually means you are calling ' +
+ 'transferPropsTo() on a component passed in as props or children.',
+ this.constructor.displayName,
+ typeof element.type === 'string' ?
+ element.type :
+ element.type.displayName
+ ) : invariant(element._owner === this));
+
+ if ("production" !== process.env.NODE_ENV) {
+ if (!didWarn) {
+ didWarn = true;
+ ("production" !== process.env.NODE_ENV ? warning(
+ false,
+ 'transferPropsTo is deprecated. ' +
+ 'See http://fb.me/react-transferpropsto for more information.'
+ ) : null);
+ }
+ }
+
+ // Because elements are immutable we have to merge into the existing
+ // props object rather than clone it.
+ transferInto(element.props, this.props);
+
+ return element;
+ }
+
+ }
+};
+
+module.exports = ReactPropTransferer;
+
+}).call(this,require('_process'))
+},{"./Object.assign":75,"./emptyFunction":168,"./invariant":187,"./joinClasses":192,"./warning":207,"_process":5}],123:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactPropTypeLocationNames
+ */
+
+"use strict";
+
+var ReactPropTypeLocationNames = {};
+
+if ("production" !== process.env.NODE_ENV) {
+ ReactPropTypeLocationNames = {
+ prop: 'prop',
+ context: 'context',
+ childContext: 'child context'
+ };
+}
+
+module.exports = ReactPropTypeLocationNames;
+
+}).call(this,require('_process'))
+},{"_process":5}],124:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactPropTypeLocations
+ */
+
+"use strict";
+
+var keyMirror = require("./keyMirror");
+
+var ReactPropTypeLocations = keyMirror({
+ prop: null,
+ context: null,
+ childContext: null
+});
+
+module.exports = ReactPropTypeLocations;
+
+},{"./keyMirror":193}],125:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactPropTypes
+ */
+
+"use strict";
+
+var ReactElement = require("./ReactElement");
+var ReactPropTypeLocationNames = require("./ReactPropTypeLocationNames");
+
+var deprecated = require("./deprecated");
+var emptyFunction = require("./emptyFunction");
+
+/**
+ * Collection of methods that allow declaration and validation of props that are
+ * supplied to React components. Example usage:
+ *
+ * var Props = require('ReactPropTypes');
+ * var MyArticle = React.createClass({
+ * propTypes: {
+ * // An optional string prop named "description".
+ * description: Props.string,
+ *
+ * // A required enum prop named "category".
+ * category: Props.oneOf(['News','Photos']).isRequired,
+ *
+ * // A prop named "dialog" that requires an instance of Dialog.
+ * dialog: Props.instanceOf(Dialog).isRequired
+ * },
+ * render: function() { ... }
+ * });
+ *
+ * A more formal specification of how these methods are used:
+ *
+ * type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...)
+ * decl := ReactPropTypes.{type}(.isRequired)?
+ *
+ * Each and every declaration produces a function with the same signature. This
+ * allows the creation of custom validation functions. For example:
+ *
+ * var MyLink = React.createClass({
+ * propTypes: {
+ * // An optional string or URI prop named "href".
+ * href: function(props, propName, componentName) {
+ * var propValue = props[propName];
+ * if (propValue != null && typeof propValue !== 'string' &&
+ * !(propValue instanceof URI)) {
+ * return new Error(
+ * 'Expected a string or an URI for ' + propName + ' in ' +
+ * componentName
+ * );
+ * }
+ * }
+ * },
+ * render: function() {...}
+ * });
+ *
+ * @internal
+ */
+
+var ANONYMOUS = '<<anonymous>>';
+
+var elementTypeChecker = createElementTypeChecker();
+var nodeTypeChecker = createNodeChecker();
+
+var ReactPropTypes = {
+ array: createPrimitiveTypeChecker('array'),
+ bool: createPrimitiveTypeChecker('boolean'),
+ func: createPrimitiveTypeChecker('function'),
+ number: createPrimitiveTypeChecker('number'),
+ object: createPrimitiveTypeChecker('object'),
+ string: createPrimitiveTypeChecker('string'),
+
+ any: createAnyTypeChecker(),
+ arrayOf: createArrayOfTypeChecker,
+ element: elementTypeChecker,
+ instanceOf: createInstanceTypeChecker,
+ node: nodeTypeChecker,
+ objectOf: createObjectOfTypeChecker,
+ oneOf: createEnumTypeChecker,
+ oneOfType: createUnionTypeChecker,
+ shape: createShapeTypeChecker,
+
+ component: deprecated(
+ 'React.PropTypes',
+ 'component',
+ 'element',
+ this,
+ elementTypeChecker
+ ),
+ renderable: deprecated(
+ 'React.PropTypes',
+ 'renderable',
+ 'node',
+ this,
+ nodeTypeChecker
+ )
+};
+
+function createChainableTypeChecker(validate) {
+ function checkType(isRequired, props, propName, componentName, location) {
+ componentName = componentName || ANONYMOUS;
+ if (props[propName] == null) {
+ var locationName = ReactPropTypeLocationNames[location];
+ if (isRequired) {
+ return new Error(
+ ("Required " + locationName + " `" + propName + "` was not specified in ")+
+ ("`" + componentName + "`.")
+ );
+ }
+ } else {
+ return validate(props, propName, componentName, location);
+ }
+ }
+
+ var chainedCheckType = checkType.bind(null, false);
+ chainedCheckType.isRequired = checkType.bind(null, true);
+
+ return chainedCheckType;
+}
+
+function createPrimitiveTypeChecker(expectedType) {
+ function validate(props, propName, componentName, location) {
+ var propValue = props[propName];
+ var propType = getPropType(propValue);
+ if (propType !== expectedType) {
+ var locationName = ReactPropTypeLocationNames[location];
+ // `propValue` being instance of, say, date/regexp, pass the 'object'
+ // check, but we can offer a more precise error message here rather than
+ // 'of type `object`'.
+ var preciseType = getPreciseType(propValue);
+
+ return new Error(
+ ("Invalid " + locationName + " `" + propName + "` of type `" + preciseType + "` ") +
+ ("supplied to `" + componentName + "`, expected `" + expectedType + "`.")
+ );
+ }
+ }
+ return createChainableTypeChecker(validate);
+}
+
+function createAnyTypeChecker() {
+ return createChainableTypeChecker(emptyFunction.thatReturns());
+}
+
+function createArrayOfTypeChecker(typeChecker) {
+ function validate(props, propName, componentName, location) {
+ var propValue = props[propName];
+ if (!Array.isArray(propValue)) {
+ var locationName = ReactPropTypeLocationNames[location];
+ var propType = getPropType(propValue);
+ return new Error(
+ ("Invalid " + locationName + " `" + propName + "` of type ") +
+ ("`" + propType + "` supplied to `" + componentName + "`, expected an array.")
+ );
+ }
+ for (var i = 0; i < propValue.length; i++) {
+ var error = typeChecker(propValue, i, componentName, location);
+ if (error instanceof Error) {
+ return error;
+ }
+ }
+ }
+ return createChainableTypeChecker(validate);
+}
+
+function createElementTypeChecker() {
+ function validate(props, propName, componentName, location) {
+ if (!ReactElement.isValidElement(props[propName])) {
+ var locationName = ReactPropTypeLocationNames[location];
+ return new Error(
+ ("Invalid " + locationName + " `" + propName + "` supplied to ") +
+ ("`" + componentName + "`, expected a ReactElement.")
+ );
+ }
+ }
+ return createChainableTypeChecker(validate);
+}
+
+function createInstanceTypeChecker(expectedClass) {
+ function validate(props, propName, componentName, location) {
+ if (!(props[propName] instanceof expectedClass)) {
+ var locationName = ReactPropTypeLocationNames[location];
+ var expectedClassName = expectedClass.name || ANONYMOUS;
+ return new Error(
+ ("Invalid " + locationName + " `" + propName + "` supplied to ") +
+ ("`" + componentName + "`, expected instance of `" + expectedClassName + "`.")
+ );
+ }
+ }
+ return createChainableTypeChecker(validate);
+}
+
+function createEnumTypeChecker(expectedValues) {
+ function validate(props, propName, componentName, location) {
+ var propValue = props[propName];
+ for (var i = 0; i < expectedValues.length; i++) {
+ if (propValue === expectedValues[i]) {
+ return;
+ }
+ }
+
+ var locationName = ReactPropTypeLocationNames[location];
+ var valuesString = JSON.stringify(expectedValues);
+ return new Error(
+ ("Invalid " + locationName + " `" + propName + "` of value `" + propValue + "` ") +
+ ("supplied to `" + componentName + "`, expected one of " + valuesString + ".")
+ );
+ }
+ return createChainableTypeChecker(validate);
+}
+
+function createObjectOfTypeChecker(typeChecker) {
+ function validate(props, propName, componentName, location) {
+ var propValue = props[propName];
+ var propType = getPropType(propValue);
+ if (propType !== 'object') {
+ var locationName = ReactPropTypeLocationNames[location];
+ return new Error(
+ ("Invalid " + locationName + " `" + propName + "` of type ") +
+ ("`" + propType + "` supplied to `" + componentName + "`, expected an object.")
+ );
+ }
+ for (var key in propValue) {
+ if (propValue.hasOwnProperty(key)) {
+ var error = typeChecker(propValue, key, componentName, location);
+ if (error instanceof Error) {
+ return error;
+ }
+ }
+ }
+ }
+ return createChainableTypeChecker(validate);
+}
+
+function createUnionTypeChecker(arrayOfTypeCheckers) {
+ function validate(props, propName, componentName, location) {
+ for (var i = 0; i < arrayOfTypeCheckers.length; i++) {
+ var checker = arrayOfTypeCheckers[i];
+ if (checker(props, propName, componentName, location) == null) {
+ return;
+ }
+ }
+
+ var locationName = ReactPropTypeLocationNames[location];
+ return new Error(
+ ("Invalid " + locationName + " `" + propName + "` supplied to ") +
+ ("`" + componentName + "`.")
+ );
+ }
+ return createChainableTypeChecker(validate);
+}
+
+function createNodeChecker() {
+ function validate(props, propName, componentName, location) {
+ if (!isNode(props[propName])) {
+ var locationName = ReactPropTypeLocationNames[location];
+ return new Error(
+ ("Invalid " + locationName + " `" + propName + "` supplied to ") +
+ ("`" + componentName + "`, expected a ReactNode.")
+ );
+ }
+ }
+ return createChainableTypeChecker(validate);
+}
+
+function createShapeTypeChecker(shapeTypes) {
+ function validate(props, propName, componentName, location) {
+ var propValue = props[propName];
+ var propType = getPropType(propValue);
+ if (propType !== 'object') {
+ var locationName = ReactPropTypeLocationNames[location];
+ return new Error(
+ ("Invalid " + locationName + " `" + propName + "` of type `" + propType + "` ") +
+ ("supplied to `" + componentName + "`, expected `object`.")
+ );
+ }
+ for (var key in shapeTypes) {
+ var checker = shapeTypes[key];
+ if (!checker) {
+ continue;
+ }
+ var error = checker(propValue, key, componentName, location);
+ if (error) {
+ return error;
+ }
+ }
+ }
+ return createChainableTypeChecker(validate, 'expected `object`');
+}
+
+function isNode(propValue) {
+ switch(typeof propValue) {
+ case 'number':
+ case 'string':
+ return true;
+ case 'boolean':
+ return !propValue;
+ case 'object':
+ if (Array.isArray(propValue)) {
+ return propValue.every(isNode);
+ }
+ if (ReactElement.isValidElement(propValue)) {
+ return true;
+ }
+ for (var k in propValue) {
+ if (!isNode(propValue[k])) {
+ return false;
+ }
+ }
+ return true;
+ default:
+ return false;
+ }
+}
+
+// Equivalent of `typeof` but with special handling for array and regexp.
+function getPropType(propValue) {
+ var propType = typeof propValue;
+ if (Array.isArray(propValue)) {
+ return 'array';
+ }
+ if (propValue instanceof RegExp) {
+ // Old webkits (at least until Android 4.0) return 'function' rather than
+ // 'object' for typeof a RegExp. We'll normalize this here so that /bla/
+ // passes PropTypes.object.
+ return 'object';
+ }
+ return propType;
+}
+
+// This handles more types than `getPropType`. Only used for error messages.
+// See `createPrimitiveTypeChecker`.
+function getPreciseType(propValue) {
+ var propType = getPropType(propValue);
+ if (propType === 'object') {
+ if (propValue instanceof Date) {
+ return 'date';
+ } else if (propValue instanceof RegExp) {
+ return 'regexp';
+ }
+ }
+ return propType;
+}
+
+module.exports = ReactPropTypes;
+
+},{"./ReactElement":104,"./ReactPropTypeLocationNames":123,"./deprecated":167,"./emptyFunction":168}],126:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactPutListenerQueue
+ */
+
+"use strict";
+
+var PooledClass = require("./PooledClass");
+var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");
+
+var assign = require("./Object.assign");
+
+function ReactPutListenerQueue() {
+ this.listenersToPut = [];
+}
+
+assign(ReactPutListenerQueue.prototype, {
+ enqueuePutListener: function(rootNodeID, propKey, propValue) {
+ this.listenersToPut.push({
+ rootNodeID: rootNodeID,
+ propKey: propKey,
+ propValue: propValue
+ });
+ },
+
+ putListeners: function() {
+ for (var i = 0; i < this.listenersToPut.length; i++) {
+ var listenerToPut = this.listenersToPut[i];
+ ReactBrowserEventEmitter.putListener(
+ listenerToPut.rootNodeID,
+ listenerToPut.propKey,
+ listenerToPut.propValue
+ );
+ }
+ },
+
+ reset: function() {
+ this.listenersToPut.length = 0;
+ },
+
+ destructor: function() {
+ this.reset();
+ }
+});
+
+PooledClass.addPoolingTo(ReactPutListenerQueue);
+
+module.exports = ReactPutListenerQueue;
+
+},{"./Object.assign":75,"./PooledClass":76,"./ReactBrowserEventEmitter":79}],127:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactReconcileTransaction
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var CallbackQueue = require("./CallbackQueue");
+var PooledClass = require("./PooledClass");
+var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");
+var ReactInputSelection = require("./ReactInputSelection");
+var ReactPutListenerQueue = require("./ReactPutListenerQueue");
+var Transaction = require("./Transaction");
+
+var assign = require("./Object.assign");
+
+/**
+ * Ensures that, when possible, the selection range (currently selected text
+ * input) is not disturbed by performing the transaction.
+ */
+var SELECTION_RESTORATION = {
+ /**
+ * @return {Selection} Selection information.
+ */
+ initialize: ReactInputSelection.getSelectionInformation,
+ /**
+ * @param {Selection} sel Selection information returned from `initialize`.
+ */
+ close: ReactInputSelection.restoreSelection
+};
+
+/**
+ * Suppresses events (blur/focus) that could be inadvertently dispatched due to
+ * high level DOM manipulations (like temporarily removing a text input from the
+ * DOM).
+ */
+var EVENT_SUPPRESSION = {
+ /**
+ * @return {boolean} The enabled status of `ReactBrowserEventEmitter` before
+ * the reconciliation.
+ */
+ initialize: function() {
+ var currentlyEnabled = ReactBrowserEventEmitter.isEnabled();
+ ReactBrowserEventEmitter.setEnabled(false);
+ return currentlyEnabled;
+ },
+
+ /**
+ * @param {boolean} previouslyEnabled Enabled status of
+ * `ReactBrowserEventEmitter` before the reconciliation occured. `close`
+ * restores the previous value.
+ */
+ close: function(previouslyEnabled) {
+ ReactBrowserEventEmitter.setEnabled(previouslyEnabled);
+ }
+};
+
+/**
+ * Provides a queue for collecting `componentDidMount` and
+ * `componentDidUpdate` callbacks during the the transaction.
+ */
+var ON_DOM_READY_QUEUEING = {
+ /**
+ * Initializes the internal `onDOMReady` queue.
+ */
+ initialize: function() {
+ this.reactMountReady.reset();
+ },
+
+ /**
+ * After DOM is flushed, invoke all registered `onDOMReady` callbacks.
+ */
+ close: function() {
+ this.reactMountReady.notifyAll();
+ }
+};
+
+var PUT_LISTENER_QUEUEING = {
+ initialize: function() {
+ this.putListenerQueue.reset();
+ },
+
+ close: function() {
+ this.putListenerQueue.putListeners();
+ }
+};
+
+/**
+ * Executed within the scope of the `Transaction` instance. Consider these as
+ * being member methods, but with an implied ordering while being isolated from
+ * each other.
+ */
+var TRANSACTION_WRAPPERS = [
+ PUT_LISTENER_QUEUEING,
+ SELECTION_RESTORATION,
+ EVENT_SUPPRESSION,
+ ON_DOM_READY_QUEUEING
+];
+
+/**
+ * Currently:
+ * - The order that these are listed in the transaction is critical:
+ * - Suppresses events.
+ * - Restores selection range.
+ *
+ * Future:
+ * - Restore document/overflow scroll positions that were unintentionally
+ * modified via DOM insertions above the top viewport boundary.
+ * - Implement/integrate with customized constraint based layout system and keep
+ * track of which dimensions must be remeasured.
+ *
+ * @class ReactReconcileTransaction
+ */
+function ReactReconcileTransaction() {
+ this.reinitializeTransaction();
+ // Only server-side rendering really needs this option (see
+ // `ReactServerRendering`), but server-side uses
+ // `ReactServerRenderingTransaction` instead. This option is here so that it's
+ // accessible and defaults to false when `ReactDOMComponent` and
+ // `ReactTextComponent` checks it in `mountComponent`.`
+ this.renderToStaticMarkup = false;
+ this.reactMountReady = CallbackQueue.getPooled(null);
+ this.putListenerQueue = ReactPutListenerQueue.getPooled();
+}
+
+var Mixin = {
+ /**
+ * @see Transaction
+ * @abstract
+ * @final
+ * @return {array<object>} List of operation wrap proceedures.
+ * TODO: convert to array<TransactionWrapper>
+ */
+ getTransactionWrappers: function() {
+ return TRANSACTION_WRAPPERS;
+ },
+
+ /**
+ * @return {object} The queue to collect `onDOMReady` callbacks with.
+ */
+ getReactMountReady: function() {
+ return this.reactMountReady;
+ },
+
+ getPutListenerQueue: function() {
+ return this.putListenerQueue;
+ },
+
+ /**
+ * `PooledClass` looks for this, and will invoke this before allowing this
+ * instance to be resused.
+ */
+ destructor: function() {
+ CallbackQueue.release(this.reactMountReady);
+ this.reactMountReady = null;
+
+ ReactPutListenerQueue.release(this.putListenerQueue);
+ this.putListenerQueue = null;
+ }
+};
+
+
+assign(ReactReconcileTransaction.prototype, Transaction.Mixin, Mixin);
+
+PooledClass.addPoolingTo(ReactReconcileTransaction);
+
+module.exports = ReactReconcileTransaction;
+
+},{"./CallbackQueue":53,"./Object.assign":75,"./PooledClass":76,"./ReactBrowserEventEmitter":79,"./ReactInputSelection":111,"./ReactPutListenerQueue":126,"./Transaction":154}],128:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactRootIndex
+ * @typechecks
+ */
+
+"use strict";
+
+var ReactRootIndexInjection = {
+ /**
+ * @param {function} _createReactRootIndex
+ */
+ injectCreateReactRootIndex: function(_createReactRootIndex) {
+ ReactRootIndex.createReactRootIndex = _createReactRootIndex;
+ }
+};
+
+var ReactRootIndex = {
+ createReactRootIndex: null,
+ injection: ReactRootIndexInjection
+};
+
+module.exports = ReactRootIndex;
+
+},{}],129:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @typechecks static-only
+ * @providesModule ReactServerRendering
+ */
+"use strict";
+
+var ReactElement = require("./ReactElement");
+var ReactInstanceHandles = require("./ReactInstanceHandles");
+var ReactMarkupChecksum = require("./ReactMarkupChecksum");
+var ReactServerRenderingTransaction =
+ require("./ReactServerRenderingTransaction");
+
+var instantiateReactComponent = require("./instantiateReactComponent");
+var invariant = require("./invariant");
+
+/**
+ * @param {ReactElement} element
+ * @return {string} the HTML markup
+ */
+function renderToString(element) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ ReactElement.isValidElement(element),
+ 'renderToString(): You must pass a valid ReactElement.'
+ ) : invariant(ReactElement.isValidElement(element)));
+
+ var transaction;
+ try {
+ var id = ReactInstanceHandles.createReactRootID();
+ transaction = ReactServerRenderingTransaction.getPooled(false);
+
+ return transaction.perform(function() {
+ var componentInstance = instantiateReactComponent(element, null);
+ var markup = componentInstance.mountComponent(id, transaction, 0);
+ return ReactMarkupChecksum.addChecksumToMarkup(markup);
+ }, null);
+ } finally {
+ ReactServerRenderingTransaction.release(transaction);
+ }
+}
+
+/**
+ * @param {ReactElement} element
+ * @return {string} the HTML markup, without the extra React ID and checksum
+ * (for generating static pages)
+ */
+function renderToStaticMarkup(element) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ ReactElement.isValidElement(element),
+ 'renderToStaticMarkup(): You must pass a valid ReactElement.'
+ ) : invariant(ReactElement.isValidElement(element)));
+
+ var transaction;
+ try {
+ var id = ReactInstanceHandles.createReactRootID();
+ transaction = ReactServerRenderingTransaction.getPooled(true);
+
+ return transaction.perform(function() {
+ var componentInstance = instantiateReactComponent(element, null);
+ return componentInstance.mountComponent(id, transaction, 0);
+ }, null);
+ } finally {
+ ReactServerRenderingTransaction.release(transaction);
+ }
+}
+
+module.exports = {
+ renderToString: renderToString,
+ renderToStaticMarkup: renderToStaticMarkup
+};
+
+}).call(this,require('_process'))
+},{"./ReactElement":104,"./ReactInstanceHandles":112,"./ReactMarkupChecksum":115,"./ReactServerRenderingTransaction":130,"./instantiateReactComponent":186,"./invariant":187,"_process":5}],130:[function(require,module,exports){
+/**
+ * Copyright 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactServerRenderingTransaction
+ * @typechecks
+ */
+
+"use strict";
+
+var PooledClass = require("./PooledClass");
+var CallbackQueue = require("./CallbackQueue");
+var ReactPutListenerQueue = require("./ReactPutListenerQueue");
+var Transaction = require("./Transaction");
+
+var assign = require("./Object.assign");
+var emptyFunction = require("./emptyFunction");
+
+/**
+ * Provides a `CallbackQueue` queue for collecting `onDOMReady` callbacks
+ * during the performing of the transaction.
+ */
+var ON_DOM_READY_QUEUEING = {
+ /**
+ * Initializes the internal `onDOMReady` queue.
+ */
+ initialize: function() {
+ this.reactMountReady.reset();
+ },
+
+ close: emptyFunction
+};
+
+var PUT_LISTENER_QUEUEING = {
+ initialize: function() {
+ this.putListenerQueue.reset();
+ },
+
+ close: emptyFunction
+};
+
+/**
+ * Executed within the scope of the `Transaction` instance. Consider these as
+ * being member methods, but with an implied ordering while being isolated from
+ * each other.
+ */
+var TRANSACTION_WRAPPERS = [
+ PUT_LISTENER_QUEUEING,
+ ON_DOM_READY_QUEUEING
+];
+
+/**
+ * @class ReactServerRenderingTransaction
+ * @param {boolean} renderToStaticMarkup
+ */
+function ReactServerRenderingTransaction(renderToStaticMarkup) {
+ this.reinitializeTransaction();
+ this.renderToStaticMarkup = renderToStaticMarkup;
+ this.reactMountReady = CallbackQueue.getPooled(null);
+ this.putListenerQueue = ReactPutListenerQueue.getPooled();
+}
+
+var Mixin = {
+ /**
+ * @see Transaction
+ * @abstract
+ * @final
+ * @return {array} Empty list of operation wrap proceedures.
+ */
+ getTransactionWrappers: function() {
+ return TRANSACTION_WRAPPERS;
+ },
+
+ /**
+ * @return {object} The queue to collect `onDOMReady` callbacks with.
+ */
+ getReactMountReady: function() {
+ return this.reactMountReady;
+ },
+
+ getPutListenerQueue: function() {
+ return this.putListenerQueue;
+ },
+
+ /**
+ * `PooledClass` looks for this, and will invoke this before allowing this
+ * instance to be resused.
+ */
+ destructor: function() {
+ CallbackQueue.release(this.reactMountReady);
+ this.reactMountReady = null;
+
+ ReactPutListenerQueue.release(this.putListenerQueue);
+ this.putListenerQueue = null;
+ }
+};
+
+
+assign(
+ ReactServerRenderingTransaction.prototype,
+ Transaction.Mixin,
+ Mixin
+);
+
+PooledClass.addPoolingTo(ReactServerRenderingTransaction);
+
+module.exports = ReactServerRenderingTransaction;
+
+},{"./CallbackQueue":53,"./Object.assign":75,"./PooledClass":76,"./ReactPutListenerQueue":126,"./Transaction":154,"./emptyFunction":168}],131:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactStateSetters
+ */
+
+"use strict";
+
+var ReactStateSetters = {
+ /**
+ * Returns a function that calls the provided function, and uses the result
+ * of that to set the component's state.
+ *
+ * @param {ReactCompositeComponent} component
+ * @param {function} funcReturningState Returned callback uses this to
+ * determine how to update state.
+ * @return {function} callback that when invoked uses funcReturningState to
+ * determined the object literal to setState.
+ */
+ createStateSetter: function(component, funcReturningState) {
+ return function(a, b, c, d, e, f) {
+ var partialState = funcReturningState.call(component, a, b, c, d, e, f);
+ if (partialState) {
+ component.setState(partialState);
+ }
+ };
+ },
+
+ /**
+ * Returns a single-argument callback that can be used to update a single
+ * key in the component's state.
+ *
+ * Note: this is memoized function, which makes it inexpensive to call.
+ *
+ * @param {ReactCompositeComponent} component
+ * @param {string} key The key in the state that you should update.
+ * @return {function} callback of 1 argument which calls setState() with
+ * the provided keyName and callback argument.
+ */
+ createStateKeySetter: function(component, key) {
+ // Memoize the setters.
+ var cache = component.__keySetters || (component.__keySetters = {});
+ return cache[key] || (cache[key] = createStateKeySetter(component, key));
+ }
+};
+
+function createStateKeySetter(component, key) {
+ // Partial state is allocated outside of the function closure so it can be
+ // reused with every call, avoiding memory allocation when this function
+ // is called.
+ var partialState = {};
+ return function stateKeySetter(value) {
+ partialState[key] = value;
+ component.setState(partialState);
+ };
+}
+
+ReactStateSetters.Mixin = {
+ /**
+ * Returns a function that calls the provided function, and uses the result
+ * of that to set the component's state.
+ *
+ * For example, these statements are equivalent:
+ *
+ * this.setState({x: 1});
+ * this.createStateSetter(function(xValue) {
+ * return {x: xValue};
+ * })(1);
+ *
+ * @param {function} funcReturningState Returned callback uses this to
+ * determine how to update state.
+ * @return {function} callback that when invoked uses funcReturningState to
+ * determined the object literal to setState.
+ */
+ createStateSetter: function(funcReturningState) {
+ return ReactStateSetters.createStateSetter(this, funcReturningState);
+ },
+
+ /**
+ * Returns a single-argument callback that can be used to update a single
+ * key in the component's state.
+ *
+ * For example, these statements are equivalent:
+ *
+ * this.setState({x: 1});
+ * this.createStateKeySetter('x')(1);
+ *
+ * Note: this is memoized function, which makes it inexpensive to call.
+ *
+ * @param {string} key The key in the state that you should update.
+ * @return {function} callback of 1 argument which calls setState() with
+ * the provided keyName and callback argument.
+ */
+ createStateKeySetter: function(key) {
+ return ReactStateSetters.createStateKeySetter(this, key);
+ }
+};
+
+module.exports = ReactStateSetters;
+
+},{}],132:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactTestUtils
+ */
+
+"use strict";
+
+var EventConstants = require("./EventConstants");
+var EventPluginHub = require("./EventPluginHub");
+var EventPropagators = require("./EventPropagators");
+var React = require("./React");
+var ReactElement = require("./ReactElement");
+var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");
+var ReactMount = require("./ReactMount");
+var ReactTextComponent = require("./ReactTextComponent");
+var ReactUpdates = require("./ReactUpdates");
+var SyntheticEvent = require("./SyntheticEvent");
+
+var assign = require("./Object.assign");
+
+var topLevelTypes = EventConstants.topLevelTypes;
+
+function Event(suffix) {}
+
+/**
+ * @class ReactTestUtils
+ */
+
+/**
+ * Todo: Support the entire DOM.scry query syntax. For now, these simple
+ * utilities will suffice for testing purposes.
+ * @lends ReactTestUtils
+ */
+var ReactTestUtils = {
+ renderIntoDocument: function(instance) {
+ var div = document.createElement('div');
+ // None of our tests actually require attaching the container to the
+ // DOM, and doing so creates a mess that we rely on test isolation to
+ // clean up, so we're going to stop honoring the name of this method
+ // (and probably rename it eventually) if no problems arise.
+ // document.documentElement.appendChild(div);
+ return React.render(instance, div);
+ },
+
+ isElement: function(element) {
+ return ReactElement.isValidElement(element);
+ },
+
+ isElementOfType: function(inst, convenienceConstructor) {
+ return (
+ ReactElement.isValidElement(inst) &&
+ inst.type === convenienceConstructor.type
+ );
+ },
+
+ isDOMComponent: function(inst) {
+ return !!(inst && inst.mountComponent && inst.tagName);
+ },
+
+ isDOMComponentElement: function(inst) {
+ return !!(inst &&
+ ReactElement.isValidElement(inst) &&
+ !!inst.tagName);
+ },
+
+ isCompositeComponent: function(inst) {
+ return typeof inst.render === 'function' &&
+ typeof inst.setState === 'function';
+ },
+
+ isCompositeComponentWithType: function(inst, type) {
+ return !!(ReactTestUtils.isCompositeComponent(inst) &&
+ (inst.constructor === type.type));
+ },
+
+ isCompositeComponentElement: function(inst) {
+ if (!ReactElement.isValidElement(inst)) {
+ return false;
+ }
+ // We check the prototype of the type that will get mounted, not the
+ // instance itself. This is a future proof way of duck typing.
+ var prototype = inst.type.prototype;
+ return (
+ typeof prototype.render === 'function' &&
+ typeof prototype.setState === 'function'
+ );
+ },
+
+ isCompositeComponentElementWithType: function(inst, type) {
+ return !!(ReactTestUtils.isCompositeComponentElement(inst) &&
+ (inst.constructor === type));
+ },
+
+ isTextComponent: function(inst) {
+ return inst instanceof ReactTextComponent.type;
+ },
+
+ findAllInRenderedTree: function(inst, test) {
+ if (!inst) {
+ return [];
+ }
+ var ret = test(inst) ? [inst] : [];
+ if (ReactTestUtils.isDOMComponent(inst)) {
+ var renderedChildren = inst._renderedChildren;
+ var key;
+ for (key in renderedChildren) {
+ if (!renderedChildren.hasOwnProperty(key)) {
+ continue;
+ }
+ ret = ret.concat(
+ ReactTestUtils.findAllInRenderedTree(renderedChildren[key], test)
+ );
+ }
+ } else if (ReactTestUtils.isCompositeComponent(inst)) {
+ ret = ret.concat(
+ ReactTestUtils.findAllInRenderedTree(inst._renderedComponent, test)
+ );
+ }
+ return ret;
+ },
+
+ /**
+ * Finds all instance of components in the rendered tree that are DOM
+ * components with the class name matching `className`.
+ * @return an array of all the matches.
+ */
+ scryRenderedDOMComponentsWithClass: function(root, className) {
+ return ReactTestUtils.findAllInRenderedTree(root, function(inst) {
+ var instClassName = inst.props.className;
+ return ReactTestUtils.isDOMComponent(inst) && (
+ instClassName &&
+ (' ' + instClassName + ' ').indexOf(' ' + className + ' ') !== -1
+ );
+ });
+ },
+
+ /**
+ * Like scryRenderedDOMComponentsWithClass but expects there to be one result,
+ * and returns that one result, or throws exception if there is any other
+ * number of matches besides one.
+ * @return {!ReactDOMComponent} The one match.
+ */
+ findRenderedDOMComponentWithClass: function(root, className) {
+ var all =
+ ReactTestUtils.scryRenderedDOMComponentsWithClass(root, className);
+ if (all.length !== 1) {
+ throw new Error('Did not find exactly one match for class:' + className);
+ }
+ return all[0];
+ },
+
+
+ /**
+ * Finds all instance of components in the rendered tree that are DOM
+ * components with the tag name matching `tagName`.
+ * @return an array of all the matches.
+ */
+ scryRenderedDOMComponentsWithTag: function(root, tagName) {
+ return ReactTestUtils.findAllInRenderedTree(root, function(inst) {
+ return ReactTestUtils.isDOMComponent(inst) &&
+ inst.tagName === tagName.toUpperCase();
+ });
+ },
+
+ /**
+ * Like scryRenderedDOMComponentsWithTag but expects there to be one result,
+ * and returns that one result, or throws exception if there is any other
+ * number of matches besides one.
+ * @return {!ReactDOMComponent} The one match.
+ */
+ findRenderedDOMComponentWithTag: function(root, tagName) {
+ var all = ReactTestUtils.scryRenderedDOMComponentsWithTag(root, tagName);
+ if (all.length !== 1) {
+ throw new Error('Did not find exactly one match for tag:' + tagName);
+ }
+ return all[0];
+ },
+
+
+ /**
+ * Finds all instances of components with type equal to `componentType`.
+ * @return an array of all the matches.
+ */
+ scryRenderedComponentsWithType: function(root, componentType) {
+ return ReactTestUtils.findAllInRenderedTree(root, function(inst) {
+ return ReactTestUtils.isCompositeComponentWithType(
+ inst,
+ componentType
+ );
+ });
+ },
+
+ /**
+ * Same as `scryRenderedComponentsWithType` but expects there to be one result
+ * and returns that one result, or throws exception if there is any other
+ * number of matches besides one.
+ * @return {!ReactComponent} The one match.
+ */
+ findRenderedComponentWithType: function(root, componentType) {
+ var all = ReactTestUtils.scryRenderedComponentsWithType(
+ root,
+ componentType
+ );
+ if (all.length !== 1) {
+ throw new Error(
+ 'Did not find exactly one match for componentType:' + componentType
+ );
+ }
+ return all[0];
+ },
+
+ /**
+ * Pass a mocked component module to this method to augment it with
+ * useful methods that allow it to be used as a dummy React component.
+ * Instead of rendering as usual, the component will become a simple
+ * <div> containing any provided children.
+ *
+ * @param {object} module the mock function object exported from a
+ * module that defines the component to be mocked
+ * @param {?string} mockTagName optional dummy root tag name to return
+ * from render method (overrides
+ * module.mockTagName if provided)
+ * @return {object} the ReactTestUtils object (for chaining)
+ */
+ mockComponent: function(module, mockTagName) {
+ mockTagName = mockTagName || module.mockTagName || "div";
+
+ var ConvenienceConstructor = React.createClass({displayName: "ConvenienceConstructor",
+ render: function() {
+ return React.createElement(
+ mockTagName,
+ null,
+ this.props.children
+ );
+ }
+ });
+
+ module.mockImplementation(ConvenienceConstructor);
+
+ module.type = ConvenienceConstructor.type;
+ module.isReactLegacyFactory = true;
+
+ return this;
+ },
+
+ /**
+ * Simulates a top level event being dispatched from a raw event that occured
+ * on an `Element` node.
+ * @param topLevelType {Object} A type from `EventConstants.topLevelTypes`
+ * @param {!Element} node The dom to simulate an event occurring on.
+ * @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.
+ */
+ simulateNativeEventOnNode: function(topLevelType, node, fakeNativeEvent) {
+ fakeNativeEvent.target = node;
+ ReactBrowserEventEmitter.ReactEventListener.dispatchEvent(
+ topLevelType,
+ fakeNativeEvent
+ );
+ },
+
+ /**
+ * Simulates a top level event being dispatched from a raw event that occured
+ * on the `ReactDOMComponent` `comp`.
+ * @param topLevelType {Object} A type from `EventConstants.topLevelTypes`.
+ * @param comp {!ReactDOMComponent}
+ * @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.
+ */
+ simulateNativeEventOnDOMComponent: function(
+ topLevelType,
+ comp,
+ fakeNativeEvent) {
+ ReactTestUtils.simulateNativeEventOnNode(
+ topLevelType,
+ comp.getDOMNode(),
+ fakeNativeEvent
+ );
+ },
+
+ nativeTouchData: function(x, y) {
+ return {
+ touches: [
+ {pageX: x, pageY: y}
+ ]
+ };
+ },
+
+ Simulate: null,
+ SimulateNative: {}
+};
+
+/**
+ * Exports:
+ *
+ * - `ReactTestUtils.Simulate.click(Element/ReactDOMComponent)`
+ * - `ReactTestUtils.Simulate.mouseMove(Element/ReactDOMComponent)`
+ * - `ReactTestUtils.Simulate.change(Element/ReactDOMComponent)`
+ * - ... (All keys from event plugin `eventTypes` objects)
+ */
+function makeSimulator(eventType) {
+ return function(domComponentOrNode, eventData) {
+ var node;
+ if (ReactTestUtils.isDOMComponent(domComponentOrNode)) {
+ node = domComponentOrNode.getDOMNode();
+ } else if (domComponentOrNode.tagName) {
+ node = domComponentOrNode;
+ }
+
+ var fakeNativeEvent = new Event();
+ fakeNativeEvent.target = node;
+ // We don't use SyntheticEvent.getPooled in order to not have to worry about
+ // properly destroying any properties assigned from `eventData` upon release
+ var event = new SyntheticEvent(
+ ReactBrowserEventEmitter.eventNameDispatchConfigs[eventType],
+ ReactMount.getID(node),
+ fakeNativeEvent
+ );
+ assign(event, eventData);
+ EventPropagators.accumulateTwoPhaseDispatches(event);
+
+ ReactUpdates.batchedUpdates(function() {
+ EventPluginHub.enqueueEvents(event);
+ EventPluginHub.processEventQueue();
+ });
+ };
+}
+
+function buildSimulators() {
+ ReactTestUtils.Simulate = {};
+
+ var eventType;
+ for (eventType in ReactBrowserEventEmitter.eventNameDispatchConfigs) {
+ /**
+ * @param {!Element || ReactDOMComponent} domComponentOrNode
+ * @param {?object} eventData Fake event data to use in SyntheticEvent.
+ */
+ ReactTestUtils.Simulate[eventType] = makeSimulator(eventType);
+ }
+}
+
+// Rebuild ReactTestUtils.Simulate whenever event plugins are injected
+var oldInjectEventPluginOrder = EventPluginHub.injection.injectEventPluginOrder;
+EventPluginHub.injection.injectEventPluginOrder = function() {
+ oldInjectEventPluginOrder.apply(this, arguments);
+ buildSimulators();
+};
+var oldInjectEventPlugins = EventPluginHub.injection.injectEventPluginsByName;
+EventPluginHub.injection.injectEventPluginsByName = function() {
+ oldInjectEventPlugins.apply(this, arguments);
+ buildSimulators();
+};
+
+buildSimulators();
+
+/**
+ * Exports:
+ *
+ * - `ReactTestUtils.SimulateNative.click(Element/ReactDOMComponent)`
+ * - `ReactTestUtils.SimulateNative.mouseMove(Element/ReactDOMComponent)`
+ * - `ReactTestUtils.SimulateNative.mouseIn/ReactDOMComponent)`
+ * - `ReactTestUtils.SimulateNative.mouseOut(Element/ReactDOMComponent)`
+ * - ... (All keys from `EventConstants.topLevelTypes`)
+ *
+ * Note: Top level event types are a subset of the entire set of handler types
+ * (which include a broader set of "synthetic" events). For example, onDragDone
+ * is a synthetic event. Except when testing an event plugin or React's event
+ * handling code specifically, you probably want to use ReactTestUtils.Simulate
+ * to dispatch synthetic events.
+ */
+
+function makeNativeSimulator(eventType) {
+ return function(domComponentOrNode, nativeEventData) {
+ var fakeNativeEvent = new Event(eventType);
+ assign(fakeNativeEvent, nativeEventData);
+ if (ReactTestUtils.isDOMComponent(domComponentOrNode)) {
+ ReactTestUtils.simulateNativeEventOnDOMComponent(
+ eventType,
+ domComponentOrNode,
+ fakeNativeEvent
+ );
+ } else if (!!domComponentOrNode.tagName) {
+ // Will allow on actual dom nodes.
+ ReactTestUtils.simulateNativeEventOnNode(
+ eventType,
+ domComponentOrNode,
+ fakeNativeEvent
+ );
+ }
+ };
+}
+
+var eventType;
+for (eventType in topLevelTypes) {
+ // Event type is stored as 'topClick' - we transform that to 'click'
+ var convenienceName = eventType.indexOf('top') === 0 ?
+ eventType.charAt(3).toLowerCase() + eventType.substr(4) : eventType;
+ /**
+ * @param {!Element || ReactDOMComponent} domComponentOrNode
+ * @param {?Event} nativeEventData Fake native event to use in SyntheticEvent.
+ */
+ ReactTestUtils.SimulateNative[convenienceName] =
+ makeNativeSimulator(eventType);
+}
+
+module.exports = ReactTestUtils;
+
+},{"./EventConstants":63,"./EventPluginHub":65,"./EventPropagators":68,"./Object.assign":75,"./React":77,"./ReactBrowserEventEmitter":79,"./ReactElement":104,"./ReactMount":116,"./ReactTextComponent":133,"./ReactUpdates":137,"./SyntheticEvent":146}],133:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactTextComponent
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var DOMPropertyOperations = require("./DOMPropertyOperations");
+var ReactComponent = require("./ReactComponent");
+var ReactElement = require("./ReactElement");
+
+var assign = require("./Object.assign");
+var escapeTextForBrowser = require("./escapeTextForBrowser");
+
+/**
+ * Text nodes violate a couple assumptions that React makes about components:
+ *
+ * - When mounting text into the DOM, adjacent text nodes are merged.
+ * - Text nodes cannot be assigned a React root ID.
+ *
+ * This component is used to wrap strings in elements so that they can undergo
+ * the same reconciliation that is applied to elements.
+ *
+ * TODO: Investigate representing React components in the DOM with text nodes.
+ *
+ * @class ReactTextComponent
+ * @extends ReactComponent
+ * @internal
+ */
+var ReactTextComponent = function(props) {
+ // This constructor and it's argument is currently used by mocks.
+};
+
+assign(ReactTextComponent.prototype, ReactComponent.Mixin, {
+
+ /**
+ * Creates the markup for this text node. This node is not intended to have
+ * any features besides containing text content.
+ *
+ * @param {string} rootID DOM ID of the root node.
+ * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
+ * @param {number} mountDepth number of components in the owner hierarchy
+ * @return {string} Markup for this text node.
+ * @internal
+ */
+ mountComponent: function(rootID, transaction, mountDepth) {
+ ReactComponent.Mixin.mountComponent.call(
+ this,
+ rootID,
+ transaction,
+ mountDepth
+ );
+
+ var escapedText = escapeTextForBrowser(this.props);
+
+ if (transaction.renderToStaticMarkup) {
+ // Normally we'd wrap this in a `span` for the reasons stated above, but
+ // since this is a situation where React won't take over (static pages),
+ // we can simply return the text as it is.
+ return escapedText;
+ }
+
+ return (
+ '<span ' + DOMPropertyOperations.createMarkupForID(rootID) + '>' +
+ escapedText +
+ '</span>'
+ );
+ },
+
+ /**
+ * Updates this component by updating the text content.
+ *
+ * @param {object} nextComponent Contains the next text content.
+ * @param {ReactReconcileTransaction} transaction
+ * @internal
+ */
+ receiveComponent: function(nextComponent, transaction) {
+ var nextProps = nextComponent.props;
+ if (nextProps !== this.props) {
+ this.props = nextProps;
+ ReactComponent.BackendIDOperations.updateTextContentByID(
+ this._rootNodeID,
+ nextProps
+ );
+ }
+ }
+
+});
+
+var ReactTextComponentFactory = function(text) {
+ // Bypass validation and configuration
+ return new ReactElement(ReactTextComponent, null, null, null, null, text);
+};
+
+ReactTextComponentFactory.type = ReactTextComponent;
+
+module.exports = ReactTextComponentFactory;
+
+},{"./DOMPropertyOperations":59,"./Object.assign":75,"./ReactComponent":83,"./ReactElement":104,"./escapeTextForBrowser":170}],134:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @typechecks static-only
+ * @providesModule ReactTransitionChildMapping
+ */
+
+"use strict";
+
+var ReactChildren = require("./ReactChildren");
+
+var ReactTransitionChildMapping = {
+ /**
+ * Given `this.props.children`, return an object mapping key to child. Just
+ * simple syntactic sugar around ReactChildren.map().
+ *
+ * @param {*} children `this.props.children`
+ * @return {object} Mapping of key to child
+ */
+ getChildMapping: function(children) {
+ return ReactChildren.map(children, function(child) {
+ return child;
+ });
+ },
+
+ /**
+ * When you're adding or removing children some may be added or removed in the
+ * same render pass. We want to show *both* since we want to simultaneously
+ * animate elements in and out. This function takes a previous set of keys
+ * and a new set of keys and merges them with its best guess of the correct
+ * ordering. In the future we may expose some of the utilities in
+ * ReactMultiChild to make this easy, but for now React itself does not
+ * directly have this concept of the union of prevChildren and nextChildren
+ * so we implement it here.
+ *
+ * @param {object} prev prev children as returned from
+ * `ReactTransitionChildMapping.getChildMapping()`.
+ * @param {object} next next children as returned from
+ * `ReactTransitionChildMapping.getChildMapping()`.
+ * @return {object} a key set that contains all keys in `prev` and all keys
+ * in `next` in a reasonable order.
+ */
+ mergeChildMappings: function(prev, next) {
+ prev = prev || {};
+ next = next || {};
+
+ function getValueForKey(key) {
+ if (next.hasOwnProperty(key)) {
+ return next[key];
+ } else {
+ return prev[key];
+ }
+ }
+
+ // For each key of `next`, the list of keys to insert before that key in
+ // the combined list
+ var nextKeysPending = {};
+
+ var pendingKeys = [];
+ for (var prevKey in prev) {
+ if (next.hasOwnProperty(prevKey)) {
+ if (pendingKeys.length) {
+ nextKeysPending[prevKey] = pendingKeys;
+ pendingKeys = [];
+ }
+ } else {
+ pendingKeys.push(prevKey);
+ }
+ }
+
+ var i;
+ var childMapping = {};
+ for (var nextKey in next) {
+ if (nextKeysPending.hasOwnProperty(nextKey)) {
+ for (i = 0; i < nextKeysPending[nextKey].length; i++) {
+ var pendingNextKey = nextKeysPending[nextKey][i];
+ childMapping[nextKeysPending[nextKey][i]] = getValueForKey(
+ pendingNextKey
+ );
+ }
+ }
+ childMapping[nextKey] = getValueForKey(nextKey);
+ }
+
+ // Finally, add the keys which didn't appear before any key in `next`
+ for (i = 0; i < pendingKeys.length; i++) {
+ childMapping[pendingKeys[i]] = getValueForKey(pendingKeys[i]);
+ }
+
+ return childMapping;
+ }
+};
+
+module.exports = ReactTransitionChildMapping;
+
+},{"./ReactChildren":82}],135:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactTransitionEvents
+ */
+
+"use strict";
+
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+
+/**
+ * EVENT_NAME_MAP is used to determine which event fired when a
+ * transition/animation ends, based on the style property used to
+ * define that event.
+ */
+var EVENT_NAME_MAP = {
+ transitionend: {
+ 'transition': 'transitionend',
+ 'WebkitTransition': 'webkitTransitionEnd',
+ 'MozTransition': 'mozTransitionEnd',
+ 'OTransition': 'oTransitionEnd',
+ 'msTransition': 'MSTransitionEnd'
+ },
+
+ animationend: {
+ 'animation': 'animationend',
+ 'WebkitAnimation': 'webkitAnimationEnd',
+ 'MozAnimation': 'mozAnimationEnd',
+ 'OAnimation': 'oAnimationEnd',
+ 'msAnimation': 'MSAnimationEnd'
+ }
+};
+
+var endEvents = [];
+
+function detectEvents() {
+ var testEl = document.createElement('div');
+ var style = testEl.style;
+
+ // On some platforms, in particular some releases of Android 4.x,
+ // the un-prefixed "animation" and "transition" properties are defined on the
+ // style object but the events that fire will still be prefixed, so we need
+ // to check if the un-prefixed events are useable, and if not remove them
+ // from the map
+ if (!('AnimationEvent' in window)) {
+ delete EVENT_NAME_MAP.animationend.animation;
+ }
+
+ if (!('TransitionEvent' in window)) {
+ delete EVENT_NAME_MAP.transitionend.transition;
+ }
+
+ for (var baseEventName in EVENT_NAME_MAP) {
+ var baseEvents = EVENT_NAME_MAP[baseEventName];
+ for (var styleName in baseEvents) {
+ if (styleName in style) {
+ endEvents.push(baseEvents[styleName]);
+ break;
+ }
+ }
+ }
+}
+
+if (ExecutionEnvironment.canUseDOM) {
+ detectEvents();
+}
+
+// We use the raw {add|remove}EventListener() call because EventListener
+// does not know how to remove event listeners and we really should
+// clean up. Also, these events are not triggered in older browsers
+// so we should be A-OK here.
+
+function addEventListener(node, eventName, eventListener) {
+ node.addEventListener(eventName, eventListener, false);
+}
+
+function removeEventListener(node, eventName, eventListener) {
+ node.removeEventListener(eventName, eventListener, false);
+}
+
+var ReactTransitionEvents = {
+ addEndEventListener: function(node, eventListener) {
+ if (endEvents.length === 0) {
+ // If CSS transitions are not supported, trigger an "end animation"
+ // event immediately.
+ window.setTimeout(eventListener, 0);
+ return;
+ }
+ endEvents.forEach(function(endEvent) {
+ addEventListener(node, endEvent, eventListener);
+ });
+ },
+
+ removeEndEventListener: function(node, eventListener) {
+ if (endEvents.length === 0) {
+ return;
+ }
+ endEvents.forEach(function(endEvent) {
+ removeEventListener(node, endEvent, eventListener);
+ });
+ }
+};
+
+module.exports = ReactTransitionEvents;
+
+},{"./ExecutionEnvironment":69}],136:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactTransitionGroup
+ */
+
+"use strict";
+
+var React = require("./React");
+var ReactTransitionChildMapping = require("./ReactTransitionChildMapping");
+
+var assign = require("./Object.assign");
+var cloneWithProps = require("./cloneWithProps");
+var emptyFunction = require("./emptyFunction");
+
+var ReactTransitionGroup = React.createClass({
+ displayName: 'ReactTransitionGroup',
+
+ propTypes: {
+ component: React.PropTypes.any,
+ childFactory: React.PropTypes.func
+ },
+
+ getDefaultProps: function() {
+ return {
+ component: 'span',
+ childFactory: emptyFunction.thatReturnsArgument
+ };
+ },
+
+ getInitialState: function() {
+ return {
+ children: ReactTransitionChildMapping.getChildMapping(this.props.children)
+ };
+ },
+
+ componentWillReceiveProps: function(nextProps) {
+ var nextChildMapping = ReactTransitionChildMapping.getChildMapping(
+ nextProps.children
+ );
+ var prevChildMapping = this.state.children;
+
+ this.setState({
+ children: ReactTransitionChildMapping.mergeChildMappings(
+ prevChildMapping,
+ nextChildMapping
+ )
+ });
+
+ var key;
+
+ for (key in nextChildMapping) {
+ var hasPrev = prevChildMapping && prevChildMapping.hasOwnProperty(key);
+ if (nextChildMapping[key] && !hasPrev &&
+ !this.currentlyTransitioningKeys[key]) {
+ this.keysToEnter.push(key);
+ }
+ }
+
+ for (key in prevChildMapping) {
+ var hasNext = nextChildMapping && nextChildMapping.hasOwnProperty(key);
+ if (prevChildMapping[key] && !hasNext &&
+ !this.currentlyTransitioningKeys[key]) {
+ this.keysToLeave.push(key);
+ }
+ }
+
+ // If we want to someday check for reordering, we could do it here.
+ },
+
+ componentWillMount: function() {
+ this.currentlyTransitioningKeys = {};
+ this.keysToEnter = [];
+ this.keysToLeave = [];
+ },
+
+ componentDidUpdate: function() {
+ var keysToEnter = this.keysToEnter;
+ this.keysToEnter = [];
+ keysToEnter.forEach(this.performEnter);
+
+ var keysToLeave = this.keysToLeave;
+ this.keysToLeave = [];
+ keysToLeave.forEach(this.performLeave);
+ },
+
+ performEnter: function(key) {
+ this.currentlyTransitioningKeys[key] = true;
+
+ var component = this.refs[key];
+
+ if (component.componentWillEnter) {
+ component.componentWillEnter(
+ this._handleDoneEntering.bind(this, key)
+ );
+ } else {
+ this._handleDoneEntering(key);
+ }
+ },
+
+ _handleDoneEntering: function(key) {
+ var component = this.refs[key];
+ if (component.componentDidEnter) {
+ component.componentDidEnter();
+ }
+
+ delete this.currentlyTransitioningKeys[key];
+
+ var currentChildMapping = ReactTransitionChildMapping.getChildMapping(
+ this.props.children
+ );
+
+ if (!currentChildMapping || !currentChildMapping.hasOwnProperty(key)) {
+ // This was removed before it had fully entered. Remove it.
+ this.performLeave(key);
+ }
+ },
+
+ performLeave: function(key) {
+ this.currentlyTransitioningKeys[key] = true;
+
+ var component = this.refs[key];
+ if (component.componentWillLeave) {
+ component.componentWillLeave(this._handleDoneLeaving.bind(this, key));
+ } else {
+ // Note that this is somewhat dangerous b/c it calls setState()
+ // again, effectively mutating the component before all the work
+ // is done.
+ this._handleDoneLeaving(key);
+ }
+ },
+
+ _handleDoneLeaving: function(key) {
+ var component = this.refs[key];
+
+ if (component.componentDidLeave) {
+ component.componentDidLeave();
+ }
+
+ delete this.currentlyTransitioningKeys[key];
+
+ var currentChildMapping = ReactTransitionChildMapping.getChildMapping(
+ this.props.children
+ );
+
+ if (currentChildMapping && currentChildMapping.hasOwnProperty(key)) {
+ // This entered again before it fully left. Add it again.
+ this.performEnter(key);
+ } else {
+ var newChildren = assign({}, this.state.children);
+ delete newChildren[key];
+ this.setState({children: newChildren});
+ }
+ },
+
+ render: function() {
+ // TODO: we could get rid of the need for the wrapper node
+ // by cloning a single child
+ var childrenToRender = {};
+ for (var key in this.state.children) {
+ var child = this.state.children[key];
+ if (child) {
+ // You may need to apply reactive updates to a child as it is leaving.
+ // The normal React way to do it won't work since the child will have
+ // already been removed. In case you need this behavior you can provide
+ // a childFactory function to wrap every child, even the ones that are
+ // leaving.
+ childrenToRender[key] = cloneWithProps(
+ this.props.childFactory(child),
+ {ref: key}
+ );
+ }
+ }
+ return React.createElement(
+ this.props.component,
+ this.props,
+ childrenToRender
+ );
+ }
+});
+
+module.exports = ReactTransitionGroup;
+
+},{"./Object.assign":75,"./React":77,"./ReactTransitionChildMapping":134,"./cloneWithProps":160,"./emptyFunction":168}],137:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactUpdates
+ */
+
+"use strict";
+
+var CallbackQueue = require("./CallbackQueue");
+var PooledClass = require("./PooledClass");
+var ReactCurrentOwner = require("./ReactCurrentOwner");
+var ReactPerf = require("./ReactPerf");
+var Transaction = require("./Transaction");
+
+var assign = require("./Object.assign");
+var invariant = require("./invariant");
+var warning = require("./warning");
+
+var dirtyComponents = [];
+var asapCallbackQueue = CallbackQueue.getPooled();
+var asapEnqueued = false;
+
+var batchingStrategy = null;
+
+function ensureInjected() {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ ReactUpdates.ReactReconcileTransaction && batchingStrategy,
+ 'ReactUpdates: must inject a reconcile transaction class and batching ' +
+ 'strategy'
+ ) : invariant(ReactUpdates.ReactReconcileTransaction && batchingStrategy));
+}
+
+var NESTED_UPDATES = {
+ initialize: function() {
+ this.dirtyComponentsLength = dirtyComponents.length;
+ },
+ close: function() {
+ if (this.dirtyComponentsLength !== dirtyComponents.length) {
+ // Additional updates were enqueued by componentDidUpdate handlers or
+ // similar; before our own UPDATE_QUEUEING wrapper closes, we want to run
+ // these new updates so that if A's componentDidUpdate calls setState on
+ // B, B will update before the callback A's updater provided when calling
+ // setState.
+ dirtyComponents.splice(0, this.dirtyComponentsLength);
+ flushBatchedUpdates();
+ } else {
+ dirtyComponents.length = 0;
+ }
+ }
+};
+
+var UPDATE_QUEUEING = {
+ initialize: function() {
+ this.callbackQueue.reset();
+ },
+ close: function() {
+ this.callbackQueue.notifyAll();
+ }
+};
+
+var TRANSACTION_WRAPPERS = [NESTED_UPDATES, UPDATE_QUEUEING];
+
+function ReactUpdatesFlushTransaction() {
+ this.reinitializeTransaction();
+ this.dirtyComponentsLength = null;
+ this.callbackQueue = CallbackQueue.getPooled();
+ this.reconcileTransaction =
+ ReactUpdates.ReactReconcileTransaction.getPooled();
+}
+
+assign(
+ ReactUpdatesFlushTransaction.prototype,
+ Transaction.Mixin, {
+ getTransactionWrappers: function() {
+ return TRANSACTION_WRAPPERS;
+ },
+
+ destructor: function() {
+ this.dirtyComponentsLength = null;
+ CallbackQueue.release(this.callbackQueue);
+ this.callbackQueue = null;
+ ReactUpdates.ReactReconcileTransaction.release(this.reconcileTransaction);
+ this.reconcileTransaction = null;
+ },
+
+ perform: function(method, scope, a) {
+ // Essentially calls `this.reconcileTransaction.perform(method, scope, a)`
+ // with this transaction's wrappers around it.
+ return Transaction.Mixin.perform.call(
+ this,
+ this.reconcileTransaction.perform,
+ this.reconcileTransaction,
+ method,
+ scope,
+ a
+ );
+ }
+});
+
+PooledClass.addPoolingTo(ReactUpdatesFlushTransaction);
+
+function batchedUpdates(callback, a, b) {
+ ensureInjected();
+ batchingStrategy.batchedUpdates(callback, a, b);
+}
+
+/**
+ * Array comparator for ReactComponents by owner depth
+ *
+ * @param {ReactComponent} c1 first component you're comparing
+ * @param {ReactComponent} c2 second component you're comparing
+ * @return {number} Return value usable by Array.prototype.sort().
+ */
+function mountDepthComparator(c1, c2) {
+ return c1._mountDepth - c2._mountDepth;
+}
+
+function runBatchedUpdates(transaction) {
+ var len = transaction.dirtyComponentsLength;
+ ("production" !== process.env.NODE_ENV ? invariant(
+ len === dirtyComponents.length,
+ 'Expected flush transaction\'s stored dirty-components length (%s) to ' +
+ 'match dirty-components array length (%s).',
+ len,
+ dirtyComponents.length
+ ) : invariant(len === dirtyComponents.length));
+
+ // Since reconciling a component higher in the owner hierarchy usually (not
+ // always -- see shouldComponentUpdate()) will reconcile children, reconcile
+ // them before their children by sorting the array.
+ dirtyComponents.sort(mountDepthComparator);
+
+ for (var i = 0; i < len; i++) {
+ // If a component is unmounted before pending changes apply, ignore them
+ // TODO: Queue unmounts in the same list to avoid this happening at all
+ var component = dirtyComponents[i];
+ if (component.isMounted()) {
+ // If performUpdateIfNecessary happens to enqueue any new updates, we
+ // shouldn't execute the callbacks until the next render happens, so
+ // stash the callbacks first
+ var callbacks = component._pendingCallbacks;
+ component._pendingCallbacks = null;
+ component.performUpdateIfNecessary(transaction.reconcileTransaction);
+
+ if (callbacks) {
+ for (var j = 0; j < callbacks.length; j++) {
+ transaction.callbackQueue.enqueue(
+ callbacks[j],
+ component
+ );
+ }
+ }
+ }
+ }
+}
+
+var flushBatchedUpdates = ReactPerf.measure(
+ 'ReactUpdates',
+ 'flushBatchedUpdates',
+ function() {
+ // ReactUpdatesFlushTransaction's wrappers will clear the dirtyComponents
+ // array and perform any updates enqueued by mount-ready handlers (i.e.,
+ // componentDidUpdate) but we need to check here too in order to catch
+ // updates enqueued by setState callbacks and asap calls.
+ while (dirtyComponents.length || asapEnqueued) {
+ if (dirtyComponents.length) {
+ var transaction = ReactUpdatesFlushTransaction.getPooled();
+ transaction.perform(runBatchedUpdates, null, transaction);
+ ReactUpdatesFlushTransaction.release(transaction);
+ }
+
+ if (asapEnqueued) {
+ asapEnqueued = false;
+ var queue = asapCallbackQueue;
+ asapCallbackQueue = CallbackQueue.getPooled();
+ queue.notifyAll();
+ CallbackQueue.release(queue);
+ }
+ }
+ }
+);
+
+/**
+ * Mark a component as needing a rerender, adding an optional callback to a
+ * list of functions which will be executed once the rerender occurs.
+ */
+function enqueueUpdate(component, callback) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !callback || typeof callback === "function",
+ 'enqueueUpdate(...): You called `setProps`, `replaceProps`, ' +
+ '`setState`, `replaceState`, or `forceUpdate` with a callback that ' +
+ 'isn\'t callable.'
+ ) : invariant(!callback || typeof callback === "function"));
+ ensureInjected();
+
+ // Various parts of our code (such as ReactCompositeComponent's
+ // _renderValidatedComponent) assume that calls to render aren't nested;
+ // verify that that's the case. (This is called by each top-level update
+ // function, like setProps, setState, forceUpdate, etc.; creation and
+ // destruction of top-level components is guarded in ReactMount.)
+ ("production" !== process.env.NODE_ENV ? warning(
+ ReactCurrentOwner.current == null,
+ 'enqueueUpdate(): Render methods should be a pure function of props ' +
+ 'and state; triggering nested component updates from render is not ' +
+ 'allowed. If necessary, trigger nested updates in ' +
+ 'componentDidUpdate.'
+ ) : null);
+
+ if (!batchingStrategy.isBatchingUpdates) {
+ batchingStrategy.batchedUpdates(enqueueUpdate, component, callback);
+ return;
+ }
+
+ dirtyComponents.push(component);
+
+ if (callback) {
+ if (component._pendingCallbacks) {
+ component._pendingCallbacks.push(callback);
+ } else {
+ component._pendingCallbacks = [callback];
+ }
+ }
+}
+
+/**
+ * Enqueue a callback to be run at the end of the current batching cycle. Throws
+ * if no updates are currently being performed.
+ */
+function asap(callback, context) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ batchingStrategy.isBatchingUpdates,
+ 'ReactUpdates.asap: Can\'t enqueue an asap callback in a context where' +
+ 'updates are not being batched.'
+ ) : invariant(batchingStrategy.isBatchingUpdates));
+ asapCallbackQueue.enqueue(callback, context);
+ asapEnqueued = true;
+}
+
+var ReactUpdatesInjection = {
+ injectReconcileTransaction: function(ReconcileTransaction) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ ReconcileTransaction,
+ 'ReactUpdates: must provide a reconcile transaction class'
+ ) : invariant(ReconcileTransaction));
+ ReactUpdates.ReactReconcileTransaction = ReconcileTransaction;
+ },
+
+ injectBatchingStrategy: function(_batchingStrategy) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ _batchingStrategy,
+ 'ReactUpdates: must provide a batching strategy'
+ ) : invariant(_batchingStrategy));
+ ("production" !== process.env.NODE_ENV ? invariant(
+ typeof _batchingStrategy.batchedUpdates === 'function',
+ 'ReactUpdates: must provide a batchedUpdates() function'
+ ) : invariant(typeof _batchingStrategy.batchedUpdates === 'function'));
+ ("production" !== process.env.NODE_ENV ? invariant(
+ typeof _batchingStrategy.isBatchingUpdates === 'boolean',
+ 'ReactUpdates: must provide an isBatchingUpdates boolean attribute'
+ ) : invariant(typeof _batchingStrategy.isBatchingUpdates === 'boolean'));
+ batchingStrategy = _batchingStrategy;
+ }
+};
+
+var ReactUpdates = {
+ /**
+ * React references `ReactReconcileTransaction` using this property in order
+ * to allow dependency injection.
+ *
+ * @internal
+ */
+ ReactReconcileTransaction: null,
+
+ batchedUpdates: batchedUpdates,
+ enqueueUpdate: enqueueUpdate,
+ flushBatchedUpdates: flushBatchedUpdates,
+ injection: ReactUpdatesInjection,
+ asap: asap
+};
+
+module.exports = ReactUpdates;
+
+}).call(this,require('_process'))
+},{"./CallbackQueue":53,"./Object.assign":75,"./PooledClass":76,"./ReactCurrentOwner":88,"./ReactPerf":121,"./Transaction":154,"./invariant":187,"./warning":207,"_process":5}],138:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactWithAddons
+ */
+
+/**
+ * This module exists purely in the open source project, and is meant as a way
+ * to create a separate standalone build of React. This build has "addons", or
+ * functionality we've built and think might be useful but doesn't have a good
+ * place to live inside React core.
+ */
+
+"use strict";
+
+var LinkedStateMixin = require("./LinkedStateMixin");
+var React = require("./React");
+var ReactComponentWithPureRenderMixin =
+ require("./ReactComponentWithPureRenderMixin");
+var ReactCSSTransitionGroup = require("./ReactCSSTransitionGroup");
+var ReactTransitionGroup = require("./ReactTransitionGroup");
+var ReactUpdates = require("./ReactUpdates");
+
+var cx = require("./cx");
+var cloneWithProps = require("./cloneWithProps");
+var update = require("./update");
+
+React.addons = {
+ CSSTransitionGroup: ReactCSSTransitionGroup,
+ LinkedStateMixin: LinkedStateMixin,
+ PureRenderMixin: ReactComponentWithPureRenderMixin,
+ TransitionGroup: ReactTransitionGroup,
+
+ batchedUpdates: ReactUpdates.batchedUpdates,
+ classSet: cx,
+ cloneWithProps: cloneWithProps,
+ update: update
+};
+
+if ("production" !== process.env.NODE_ENV) {
+ React.addons.Perf = require("./ReactDefaultPerf");
+ React.addons.TestUtils = require("./ReactTestUtils");
+}
+
+module.exports = React;
+
+}).call(this,require('_process'))
+},{"./LinkedStateMixin":71,"./React":77,"./ReactCSSTransitionGroup":80,"./ReactComponentWithPureRenderMixin":85,"./ReactDefaultPerf":102,"./ReactTestUtils":132,"./ReactTransitionGroup":136,"./ReactUpdates":137,"./cloneWithProps":160,"./cx":165,"./update":206,"_process":5}],139:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SVGDOMPropertyConfig
+ */
+
+/*jslint bitwise: true*/
+
+"use strict";
+
+var DOMProperty = require("./DOMProperty");
+
+var MUST_USE_ATTRIBUTE = DOMProperty.injection.MUST_USE_ATTRIBUTE;
+
+var SVGDOMPropertyConfig = {
+ Properties: {
+ cx: MUST_USE_ATTRIBUTE,
+ cy: MUST_USE_ATTRIBUTE,
+ d: MUST_USE_ATTRIBUTE,
+ dx: MUST_USE_ATTRIBUTE,
+ dy: MUST_USE_ATTRIBUTE,
+ fill: MUST_USE_ATTRIBUTE,
+ fillOpacity: MUST_USE_ATTRIBUTE,
+ fontFamily: MUST_USE_ATTRIBUTE,
+ fontSize: MUST_USE_ATTRIBUTE,
+ fx: MUST_USE_ATTRIBUTE,
+ fy: MUST_USE_ATTRIBUTE,
+ gradientTransform: MUST_USE_ATTRIBUTE,
+ gradientUnits: MUST_USE_ATTRIBUTE,
+ markerEnd: MUST_USE_ATTRIBUTE,
+ markerMid: MUST_USE_ATTRIBUTE,
+ markerStart: MUST_USE_ATTRIBUTE,
+ offset: MUST_USE_ATTRIBUTE,
+ opacity: MUST_USE_ATTRIBUTE,
+ patternContentUnits: MUST_USE_ATTRIBUTE,
+ patternUnits: MUST_USE_ATTRIBUTE,
+ points: MUST_USE_ATTRIBUTE,
+ preserveAspectRatio: MUST_USE_ATTRIBUTE,
+ r: MUST_USE_ATTRIBUTE,
+ rx: MUST_USE_ATTRIBUTE,
+ ry: MUST_USE_ATTRIBUTE,
+ spreadMethod: MUST_USE_ATTRIBUTE,
+ stopColor: MUST_USE_ATTRIBUTE,
+ stopOpacity: MUST_USE_ATTRIBUTE,
+ stroke: MUST_USE_ATTRIBUTE,
+ strokeDasharray: MUST_USE_ATTRIBUTE,
+ strokeLinecap: MUST_USE_ATTRIBUTE,
+ strokeOpacity: MUST_USE_ATTRIBUTE,
+ strokeWidth: MUST_USE_ATTRIBUTE,
+ textAnchor: MUST_USE_ATTRIBUTE,
+ transform: MUST_USE_ATTRIBUTE,
+ version: MUST_USE_ATTRIBUTE,
+ viewBox: MUST_USE_ATTRIBUTE,
+ x1: MUST_USE_ATTRIBUTE,
+ x2: MUST_USE_ATTRIBUTE,
+ x: MUST_USE_ATTRIBUTE,
+ y1: MUST_USE_ATTRIBUTE,
+ y2: MUST_USE_ATTRIBUTE,
+ y: MUST_USE_ATTRIBUTE
+ },
+ DOMAttributeNames: {
+ fillOpacity: 'fill-opacity',
+ fontFamily: 'font-family',
+ fontSize: 'font-size',
+ gradientTransform: 'gradientTransform',
+ gradientUnits: 'gradientUnits',
+ markerEnd: 'marker-end',
+ markerMid: 'marker-mid',
+ markerStart: 'marker-start',
+ patternContentUnits: 'patternContentUnits',
+ patternUnits: 'patternUnits',
+ preserveAspectRatio: 'preserveAspectRatio',
+ spreadMethod: 'spreadMethod',
+ stopColor: 'stop-color',
+ stopOpacity: 'stop-opacity',
+ strokeDasharray: 'stroke-dasharray',
+ strokeLinecap: 'stroke-linecap',
+ strokeOpacity: 'stroke-opacity',
+ strokeWidth: 'stroke-width',
+ textAnchor: 'text-anchor',
+ viewBox: 'viewBox'
+ }
+};
+
+module.exports = SVGDOMPropertyConfig;
+
+},{"./DOMProperty":58}],140:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SelectEventPlugin
+ */
+
+"use strict";
+
+var EventConstants = require("./EventConstants");
+var EventPropagators = require("./EventPropagators");
+var ReactInputSelection = require("./ReactInputSelection");
+var SyntheticEvent = require("./SyntheticEvent");
+
+var getActiveElement = require("./getActiveElement");
+var isTextInputElement = require("./isTextInputElement");
+var keyOf = require("./keyOf");
+var shallowEqual = require("./shallowEqual");
+
+var topLevelTypes = EventConstants.topLevelTypes;
+
+var eventTypes = {
+ select: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onSelect: null}),
+ captured: keyOf({onSelectCapture: null})
+ },
+ dependencies: [
+ topLevelTypes.topBlur,
+ topLevelTypes.topContextMenu,
+ topLevelTypes.topFocus,
+ topLevelTypes.topKeyDown,
+ topLevelTypes.topMouseDown,
+ topLevelTypes.topMouseUp,
+ topLevelTypes.topSelectionChange
+ ]
+ }
+};
+
+var activeElement = null;
+var activeElementID = null;
+var lastSelection = null;
+var mouseDown = false;
+
+/**
+ * Get an object which is a unique representation of the current selection.
+ *
+ * The return value will not be consistent across nodes or browsers, but
+ * two identical selections on the same node will return identical objects.
+ *
+ * @param {DOMElement} node
+ * @param {object}
+ */
+function getSelection(node) {
+ if ('selectionStart' in node &&
+ ReactInputSelection.hasSelectionCapabilities(node)) {
+ return {
+ start: node.selectionStart,
+ end: node.selectionEnd
+ };
+ } else if (window.getSelection) {
+ var selection = window.getSelection();
+ return {
+ anchorNode: selection.anchorNode,
+ anchorOffset: selection.anchorOffset,
+ focusNode: selection.focusNode,
+ focusOffset: selection.focusOffset
+ };
+ } else if (document.selection) {
+ var range = document.selection.createRange();
+ return {
+ parentElement: range.parentElement(),
+ text: range.text,
+ top: range.boundingTop,
+ left: range.boundingLeft
+ };
+ }
+}
+
+/**
+ * Poll selection to see whether it's changed.
+ *
+ * @param {object} nativeEvent
+ * @return {?SyntheticEvent}
+ */
+function constructSelectEvent(nativeEvent) {
+ // Ensure we have the right element, and that the user is not dragging a
+ // selection (this matches native `select` event behavior). In HTML5, select
+ // fires only on input and textarea thus if there's no focused element we
+ // won't dispatch.
+ if (mouseDown ||
+ activeElement == null ||
+ activeElement != getActiveElement()) {
+ return;
+ }
+
+ // Only fire when selection has actually changed.
+ var currentSelection = getSelection(activeElement);
+ if (!lastSelection || !shallowEqual(lastSelection, currentSelection)) {
+ lastSelection = currentSelection;
+
+ var syntheticEvent = SyntheticEvent.getPooled(
+ eventTypes.select,
+ activeElementID,
+ nativeEvent
+ );
+
+ syntheticEvent.type = 'select';
+ syntheticEvent.target = activeElement;
+
+ EventPropagators.accumulateTwoPhaseDispatches(syntheticEvent);
+
+ return syntheticEvent;
+ }
+}
+
+/**
+ * This plugin creates an `onSelect` event that normalizes select events
+ * across form elements.
+ *
+ * Supported elements are:
+ * - input (see `isTextInputElement`)
+ * - textarea
+ * - contentEditable
+ *
+ * This differs from native browser implementations in the following ways:
+ * - Fires on contentEditable fields as well as inputs.
+ * - Fires for collapsed selection.
+ * - Fires after user input.
+ */
+var SelectEventPlugin = {
+
+ eventTypes: eventTypes,
+
+ /**
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {DOMEventTarget} topLevelTarget The listening component root node.
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
+ * @param {object} nativeEvent Native browser event.
+ * @return {*} An accumulation of synthetic events.
+ * @see {EventPluginHub.extractEvents}
+ */
+ extractEvents: function(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID,
+ nativeEvent) {
+
+ switch (topLevelType) {
+ // Track the input node that has focus.
+ case topLevelTypes.topFocus:
+ if (isTextInputElement(topLevelTarget) ||
+ topLevelTarget.contentEditable === 'true') {
+ activeElement = topLevelTarget;
+ activeElementID = topLevelTargetID;
+ lastSelection = null;
+ }
+ break;
+ case topLevelTypes.topBlur:
+ activeElement = null;
+ activeElementID = null;
+ lastSelection = null;
+ break;
+
+ // Don't fire the event while the user is dragging. This matches the
+ // semantics of the native select event.
+ case topLevelTypes.topMouseDown:
+ mouseDown = true;
+ break;
+ case topLevelTypes.topContextMenu:
+ case topLevelTypes.topMouseUp:
+ mouseDown = false;
+ return constructSelectEvent(nativeEvent);
+
+ // Chrome and IE fire non-standard event when selection is changed (and
+ // sometimes when it hasn't).
+ // Firefox doesn't support selectionchange, so check selection status
+ // after each key entry. The selection changes after keydown and before
+ // keyup, but we check on keydown as well in the case of holding down a
+ // key, when multiple keydown events are fired but only one keyup is.
+ case topLevelTypes.topSelectionChange:
+ case topLevelTypes.topKeyDown:
+ case topLevelTypes.topKeyUp:
+ return constructSelectEvent(nativeEvent);
+ }
+ }
+};
+
+module.exports = SelectEventPlugin;
+
+},{"./EventConstants":63,"./EventPropagators":68,"./ReactInputSelection":111,"./SyntheticEvent":146,"./getActiveElement":174,"./isTextInputElement":190,"./keyOf":194,"./shallowEqual":202}],141:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ServerReactRootIndex
+ * @typechecks
+ */
+
+"use strict";
+
+/**
+ * Size of the reactRoot ID space. We generate random numbers for React root
+ * IDs and if there's a collision the events and DOM update system will
+ * get confused. In the future we need a way to generate GUIDs but for
+ * now this will work on a smaller scale.
+ */
+var GLOBAL_MOUNT_POINT_MAX = Math.pow(2, 53);
+
+var ServerReactRootIndex = {
+ createReactRootIndex: function() {
+ return Math.ceil(Math.random() * GLOBAL_MOUNT_POINT_MAX);
+ }
+};
+
+module.exports = ServerReactRootIndex;
+
+},{}],142:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SimpleEventPlugin
+ */
+
+"use strict";
+
+var EventConstants = require("./EventConstants");
+var EventPluginUtils = require("./EventPluginUtils");
+var EventPropagators = require("./EventPropagators");
+var SyntheticClipboardEvent = require("./SyntheticClipboardEvent");
+var SyntheticEvent = require("./SyntheticEvent");
+var SyntheticFocusEvent = require("./SyntheticFocusEvent");
+var SyntheticKeyboardEvent = require("./SyntheticKeyboardEvent");
+var SyntheticMouseEvent = require("./SyntheticMouseEvent");
+var SyntheticDragEvent = require("./SyntheticDragEvent");
+var SyntheticTouchEvent = require("./SyntheticTouchEvent");
+var SyntheticUIEvent = require("./SyntheticUIEvent");
+var SyntheticWheelEvent = require("./SyntheticWheelEvent");
+
+var getEventCharCode = require("./getEventCharCode");
+
+var invariant = require("./invariant");
+var keyOf = require("./keyOf");
+var warning = require("./warning");
+
+var topLevelTypes = EventConstants.topLevelTypes;
+
+var eventTypes = {
+ blur: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onBlur: true}),
+ captured: keyOf({onBlurCapture: true})
+ }
+ },
+ click: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onClick: true}),
+ captured: keyOf({onClickCapture: true})
+ }
+ },
+ contextMenu: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onContextMenu: true}),
+ captured: keyOf({onContextMenuCapture: true})
+ }
+ },
+ copy: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onCopy: true}),
+ captured: keyOf({onCopyCapture: true})
+ }
+ },
+ cut: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onCut: true}),
+ captured: keyOf({onCutCapture: true})
+ }
+ },
+ doubleClick: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onDoubleClick: true}),
+ captured: keyOf({onDoubleClickCapture: true})
+ }
+ },
+ drag: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onDrag: true}),
+ captured: keyOf({onDragCapture: true})
+ }
+ },
+ dragEnd: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onDragEnd: true}),
+ captured: keyOf({onDragEndCapture: true})
+ }
+ },
+ dragEnter: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onDragEnter: true}),
+ captured: keyOf({onDragEnterCapture: true})
+ }
+ },
+ dragExit: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onDragExit: true}),
+ captured: keyOf({onDragExitCapture: true})
+ }
+ },
+ dragLeave: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onDragLeave: true}),
+ captured: keyOf({onDragLeaveCapture: true})
+ }
+ },
+ dragOver: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onDragOver: true}),
+ captured: keyOf({onDragOverCapture: true})
+ }
+ },
+ dragStart: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onDragStart: true}),
+ captured: keyOf({onDragStartCapture: true})
+ }
+ },
+ drop: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onDrop: true}),
+ captured: keyOf({onDropCapture: true})
+ }
+ },
+ focus: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onFocus: true}),
+ captured: keyOf({onFocusCapture: true})
+ }
+ },
+ input: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onInput: true}),
+ captured: keyOf({onInputCapture: true})
+ }
+ },
+ keyDown: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onKeyDown: true}),
+ captured: keyOf({onKeyDownCapture: true})
+ }
+ },
+ keyPress: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onKeyPress: true}),
+ captured: keyOf({onKeyPressCapture: true})
+ }
+ },
+ keyUp: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onKeyUp: true}),
+ captured: keyOf({onKeyUpCapture: true})
+ }
+ },
+ load: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onLoad: true}),
+ captured: keyOf({onLoadCapture: true})
+ }
+ },
+ error: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onError: true}),
+ captured: keyOf({onErrorCapture: true})
+ }
+ },
+ // Note: We do not allow listening to mouseOver events. Instead, use the
+ // onMouseEnter/onMouseLeave created by `EnterLeaveEventPlugin`.
+ mouseDown: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onMouseDown: true}),
+ captured: keyOf({onMouseDownCapture: true})
+ }
+ },
+ mouseMove: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onMouseMove: true}),
+ captured: keyOf({onMouseMoveCapture: true})
+ }
+ },
+ mouseOut: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onMouseOut: true}),
+ captured: keyOf({onMouseOutCapture: true})
+ }
+ },
+ mouseOver: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onMouseOver: true}),
+ captured: keyOf({onMouseOverCapture: true})
+ }
+ },
+ mouseUp: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onMouseUp: true}),
+ captured: keyOf({onMouseUpCapture: true})
+ }
+ },
+ paste: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onPaste: true}),
+ captured: keyOf({onPasteCapture: true})
+ }
+ },
+ reset: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onReset: true}),
+ captured: keyOf({onResetCapture: true})
+ }
+ },
+ scroll: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onScroll: true}),
+ captured: keyOf({onScrollCapture: true})
+ }
+ },
+ submit: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onSubmit: true}),
+ captured: keyOf({onSubmitCapture: true})
+ }
+ },
+ touchCancel: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onTouchCancel: true}),
+ captured: keyOf({onTouchCancelCapture: true})
+ }
+ },
+ touchEnd: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onTouchEnd: true}),
+ captured: keyOf({onTouchEndCapture: true})
+ }
+ },
+ touchMove: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onTouchMove: true}),
+ captured: keyOf({onTouchMoveCapture: true})
+ }
+ },
+ touchStart: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onTouchStart: true}),
+ captured: keyOf({onTouchStartCapture: true})
+ }
+ },
+ wheel: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onWheel: true}),
+ captured: keyOf({onWheelCapture: true})
+ }
+ }
+};
+
+var topLevelEventsToDispatchConfig = {
+ topBlur: eventTypes.blur,
+ topClick: eventTypes.click,
+ topContextMenu: eventTypes.contextMenu,
+ topCopy: eventTypes.copy,
+ topCut: eventTypes.cut,
+ topDoubleClick: eventTypes.doubleClick,
+ topDrag: eventTypes.drag,
+ topDragEnd: eventTypes.dragEnd,
+ topDragEnter: eventTypes.dragEnter,
+ topDragExit: eventTypes.dragExit,
+ topDragLeave: eventTypes.dragLeave,
+ topDragOver: eventTypes.dragOver,
+ topDragStart: eventTypes.dragStart,
+ topDrop: eventTypes.drop,
+ topError: eventTypes.error,
+ topFocus: eventTypes.focus,
+ topInput: eventTypes.input,
+ topKeyDown: eventTypes.keyDown,
+ topKeyPress: eventTypes.keyPress,
+ topKeyUp: eventTypes.keyUp,
+ topLoad: eventTypes.load,
+ topMouseDown: eventTypes.mouseDown,
+ topMouseMove: eventTypes.mouseMove,
+ topMouseOut: eventTypes.mouseOut,
+ topMouseOver: eventTypes.mouseOver,
+ topMouseUp: eventTypes.mouseUp,
+ topPaste: eventTypes.paste,
+ topReset: eventTypes.reset,
+ topScroll: eventTypes.scroll,
+ topSubmit: eventTypes.submit,
+ topTouchCancel: eventTypes.touchCancel,
+ topTouchEnd: eventTypes.touchEnd,
+ topTouchMove: eventTypes.touchMove,
+ topTouchStart: eventTypes.touchStart,
+ topWheel: eventTypes.wheel
+};
+
+for (var topLevelType in topLevelEventsToDispatchConfig) {
+ topLevelEventsToDispatchConfig[topLevelType].dependencies = [topLevelType];
+}
+
+var SimpleEventPlugin = {
+
+ eventTypes: eventTypes,
+
+ /**
+ * Same as the default implementation, except cancels the event when return
+ * value is false. This behavior will be disabled in a future release.
+ *
+ * @param {object} Event to be dispatched.
+ * @param {function} Application-level callback.
+ * @param {string} domID DOM ID to pass to the callback.
+ */
+ executeDispatch: function(event, listener, domID) {
+ var returnValue = EventPluginUtils.executeDispatch(event, listener, domID);
+
+ ("production" !== process.env.NODE_ENV ? warning(
+ typeof returnValue !== 'boolean',
+ 'Returning `false` from an event handler is deprecated and will be ' +
+ 'ignored in a future release. Instead, manually call ' +
+ 'e.stopPropagation() or e.preventDefault(), as appropriate.'
+ ) : null);
+
+ if (returnValue === false) {
+ event.stopPropagation();
+ event.preventDefault();
+ }
+ },
+
+ /**
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {DOMEventTarget} topLevelTarget The listening component root node.
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
+ * @param {object} nativeEvent Native browser event.
+ * @return {*} An accumulation of synthetic events.
+ * @see {EventPluginHub.extractEvents}
+ */
+ extractEvents: function(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID,
+ nativeEvent) {
+ var dispatchConfig = topLevelEventsToDispatchConfig[topLevelType];
+ if (!dispatchConfig) {
+ return null;
+ }
+ var EventConstructor;
+ switch (topLevelType) {
+ case topLevelTypes.topInput:
+ case topLevelTypes.topLoad:
+ case topLevelTypes.topError:
+ case topLevelTypes.topReset:
+ case topLevelTypes.topSubmit:
+ // HTML Events
+ // @see http://www.w3.org/TR/html5/index.html#events-0
+ EventConstructor = SyntheticEvent;
+ break;
+ case topLevelTypes.topKeyPress:
+ // FireFox creates a keypress event for function keys too. This removes
+ // the unwanted keypress events. Enter is however both printable and
+ // non-printable. One would expect Tab to be as well (but it isn't).
+ if (getEventCharCode(nativeEvent) === 0) {
+ return null;
+ }
+ /* falls through */
+ case topLevelTypes.topKeyDown:
+ case topLevelTypes.topKeyUp:
+ EventConstructor = SyntheticKeyboardEvent;
+ break;
+ case topLevelTypes.topBlur:
+ case topLevelTypes.topFocus:
+ EventConstructor = SyntheticFocusEvent;
+ break;
+ case topLevelTypes.topClick:
+ // Firefox creates a click event on right mouse clicks. This removes the
+ // unwanted click events.
+ if (nativeEvent.button === 2) {
+ return null;
+ }
+ /* falls through */
+ case topLevelTypes.topContextMenu:
+ case topLevelTypes.topDoubleClick:
+ case topLevelTypes.topMouseDown:
+ case topLevelTypes.topMouseMove:
+ case topLevelTypes.topMouseOut:
+ case topLevelTypes.topMouseOver:
+ case topLevelTypes.topMouseUp:
+ EventConstructor = SyntheticMouseEvent;
+ break;
+ case topLevelTypes.topDrag:
+ case topLevelTypes.topDragEnd:
+ case topLevelTypes.topDragEnter:
+ case topLevelTypes.topDragExit:
+ case topLevelTypes.topDragLeave:
+ case topLevelTypes.topDragOver:
+ case topLevelTypes.topDragStart:
+ case topLevelTypes.topDrop:
+ EventConstructor = SyntheticDragEvent;
+ break;
+ case topLevelTypes.topTouchCancel:
+ case topLevelTypes.topTouchEnd:
+ case topLevelTypes.topTouchMove:
+ case topLevelTypes.topTouchStart:
+ EventConstructor = SyntheticTouchEvent;
+ break;
+ case topLevelTypes.topScroll:
+ EventConstructor = SyntheticUIEvent;
+ break;
+ case topLevelTypes.topWheel:
+ EventConstructor = SyntheticWheelEvent;
+ break;
+ case topLevelTypes.topCopy:
+ case topLevelTypes.topCut:
+ case topLevelTypes.topPaste:
+ EventConstructor = SyntheticClipboardEvent;
+ break;
+ }
+ ("production" !== process.env.NODE_ENV ? invariant(
+ EventConstructor,
+ 'SimpleEventPlugin: Unhandled event type, `%s`.',
+ topLevelType
+ ) : invariant(EventConstructor));
+ var event = EventConstructor.getPooled(
+ dispatchConfig,
+ topLevelTargetID,
+ nativeEvent
+ );
+ EventPropagators.accumulateTwoPhaseDispatches(event);
+ return event;
+ }
+
+};
+
+module.exports = SimpleEventPlugin;
+
+}).call(this,require('_process'))
+},{"./EventConstants":63,"./EventPluginUtils":67,"./EventPropagators":68,"./SyntheticClipboardEvent":143,"./SyntheticDragEvent":145,"./SyntheticEvent":146,"./SyntheticFocusEvent":147,"./SyntheticKeyboardEvent":149,"./SyntheticMouseEvent":150,"./SyntheticTouchEvent":151,"./SyntheticUIEvent":152,"./SyntheticWheelEvent":153,"./getEventCharCode":175,"./invariant":187,"./keyOf":194,"./warning":207,"_process":5}],143:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticClipboardEvent
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var SyntheticEvent = require("./SyntheticEvent");
+
+/**
+ * @interface Event
+ * @see http://www.w3.org/TR/clipboard-apis/
+ */
+var ClipboardEventInterface = {
+ clipboardData: function(event) {
+ return (
+ 'clipboardData' in event ?
+ event.clipboardData :
+ window.clipboardData
+ );
+ }
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticClipboardEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+ SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticEvent.augmentClass(SyntheticClipboardEvent, ClipboardEventInterface);
+
+module.exports = SyntheticClipboardEvent;
+
+
+},{"./SyntheticEvent":146}],144:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticCompositionEvent
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var SyntheticEvent = require("./SyntheticEvent");
+
+/**
+ * @interface Event
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents
+ */
+var CompositionEventInterface = {
+ data: null
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticCompositionEvent(
+ dispatchConfig,
+ dispatchMarker,
+ nativeEvent) {
+ SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticEvent.augmentClass(
+ SyntheticCompositionEvent,
+ CompositionEventInterface
+);
+
+module.exports = SyntheticCompositionEvent;
+
+
+},{"./SyntheticEvent":146}],145:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticDragEvent
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var SyntheticMouseEvent = require("./SyntheticMouseEvent");
+
+/**
+ * @interface DragEvent
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/
+ */
+var DragEventInterface = {
+ dataTransfer: null
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticDragEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+ SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticMouseEvent.augmentClass(SyntheticDragEvent, DragEventInterface);
+
+module.exports = SyntheticDragEvent;
+
+},{"./SyntheticMouseEvent":150}],146:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticEvent
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var PooledClass = require("./PooledClass");
+
+var assign = require("./Object.assign");
+var emptyFunction = require("./emptyFunction");
+var getEventTarget = require("./getEventTarget");
+
+/**
+ * @interface Event
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/
+ */
+var EventInterface = {
+ type: null,
+ target: getEventTarget,
+ // currentTarget is set when dispatching; no use in copying it here
+ currentTarget: emptyFunction.thatReturnsNull,
+ eventPhase: null,
+ bubbles: null,
+ cancelable: null,
+ timeStamp: function(event) {
+ return event.timeStamp || Date.now();
+ },
+ defaultPrevented: null,
+ isTrusted: null
+};
+
+/**
+ * Synthetic events are dispatched by event plugins, typically in response to a
+ * top-level event delegation handler.
+ *
+ * These systems should generally use pooling to reduce the frequency of garbage
+ * collection. The system should check `isPersistent` to determine whether the
+ * event should be released into the pool after being dispatched. Users that
+ * need a persisted event should invoke `persist`.
+ *
+ * Synthetic events (and subclasses) implement the DOM Level 3 Events API by
+ * normalizing browser quirks. Subclasses do not necessarily have to implement a
+ * DOM interface; custom application-specific events can also subclass this.
+ *
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ */
+function SyntheticEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+ this.dispatchConfig = dispatchConfig;
+ this.dispatchMarker = dispatchMarker;
+ this.nativeEvent = nativeEvent;
+
+ var Interface = this.constructor.Interface;
+ for (var propName in Interface) {
+ if (!Interface.hasOwnProperty(propName)) {
+ continue;
+ }
+ var normalize = Interface[propName];
+ if (normalize) {
+ this[propName] = normalize(nativeEvent);
+ } else {
+ this[propName] = nativeEvent[propName];
+ }
+ }
+
+ var defaultPrevented = nativeEvent.defaultPrevented != null ?
+ nativeEvent.defaultPrevented :
+ nativeEvent.returnValue === false;
+ if (defaultPrevented) {
+ this.isDefaultPrevented = emptyFunction.thatReturnsTrue;
+ } else {
+ this.isDefaultPrevented = emptyFunction.thatReturnsFalse;
+ }
+ this.isPropagationStopped = emptyFunction.thatReturnsFalse;
+}
+
+assign(SyntheticEvent.prototype, {
+
+ preventDefault: function() {
+ this.defaultPrevented = true;
+ var event = this.nativeEvent;
+ event.preventDefault ? event.preventDefault() : event.returnValue = false;
+ this.isDefaultPrevented = emptyFunction.thatReturnsTrue;
+ },
+
+ stopPropagation: function() {
+ var event = this.nativeEvent;
+ event.stopPropagation ? event.stopPropagation() : event.cancelBubble = true;
+ this.isPropagationStopped = emptyFunction.thatReturnsTrue;
+ },
+
+ /**
+ * We release all dispatched `SyntheticEvent`s after each event loop, adding
+ * them back into the pool. This allows a way to hold onto a reference that
+ * won't be added back into the pool.
+ */
+ persist: function() {
+ this.isPersistent = emptyFunction.thatReturnsTrue;
+ },
+
+ /**
+ * Checks if this event should be released back into the pool.
+ *
+ * @return {boolean} True if this should not be released, false otherwise.
+ */
+ isPersistent: emptyFunction.thatReturnsFalse,
+
+ /**
+ * `PooledClass` looks for `destructor` on each instance it releases.
+ */
+ destructor: function() {
+ var Interface = this.constructor.Interface;
+ for (var propName in Interface) {
+ this[propName] = null;
+ }
+ this.dispatchConfig = null;
+ this.dispatchMarker = null;
+ this.nativeEvent = null;
+ }
+
+});
+
+SyntheticEvent.Interface = EventInterface;
+
+/**
+ * Helper to reduce boilerplate when creating subclasses.
+ *
+ * @param {function} Class
+ * @param {?object} Interface
+ */
+SyntheticEvent.augmentClass = function(Class, Interface) {
+ var Super = this;
+
+ var prototype = Object.create(Super.prototype);
+ assign(prototype, Class.prototype);
+ Class.prototype = prototype;
+ Class.prototype.constructor = Class;
+
+ Class.Interface = assign({}, Super.Interface, Interface);
+ Class.augmentClass = Super.augmentClass;
+
+ PooledClass.addPoolingTo(Class, PooledClass.threeArgumentPooler);
+};
+
+PooledClass.addPoolingTo(SyntheticEvent, PooledClass.threeArgumentPooler);
+
+module.exports = SyntheticEvent;
+
+},{"./Object.assign":75,"./PooledClass":76,"./emptyFunction":168,"./getEventTarget":178}],147:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticFocusEvent
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var SyntheticUIEvent = require("./SyntheticUIEvent");
+
+/**
+ * @interface FocusEvent
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/
+ */
+var FocusEventInterface = {
+ relatedTarget: null
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticFocusEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+ SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticUIEvent.augmentClass(SyntheticFocusEvent, FocusEventInterface);
+
+module.exports = SyntheticFocusEvent;
+
+},{"./SyntheticUIEvent":152}],148:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticInputEvent
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var SyntheticEvent = require("./SyntheticEvent");
+
+/**
+ * @interface Event
+ * @see http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105
+ * /#events-inputevents
+ */
+var InputEventInterface = {
+ data: null
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticInputEvent(
+ dispatchConfig,
+ dispatchMarker,
+ nativeEvent) {
+ SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticEvent.augmentClass(
+ SyntheticInputEvent,
+ InputEventInterface
+);
+
+module.exports = SyntheticInputEvent;
+
+
+},{"./SyntheticEvent":146}],149:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticKeyboardEvent
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var SyntheticUIEvent = require("./SyntheticUIEvent");
+
+var getEventCharCode = require("./getEventCharCode");
+var getEventKey = require("./getEventKey");
+var getEventModifierState = require("./getEventModifierState");
+
+/**
+ * @interface KeyboardEvent
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/
+ */
+var KeyboardEventInterface = {
+ key: getEventKey,
+ location: null,
+ ctrlKey: null,
+ shiftKey: null,
+ altKey: null,
+ metaKey: null,
+ repeat: null,
+ locale: null,
+ getModifierState: getEventModifierState,
+ // Legacy Interface
+ charCode: function(event) {
+ // `charCode` is the result of a KeyPress event and represents the value of
+ // the actual printable character.
+
+ // KeyPress is deprecated, but its replacement is not yet final and not
+ // implemented in any major browser. Only KeyPress has charCode.
+ if (event.type === 'keypress') {
+ return getEventCharCode(event);
+ }
+ return 0;
+ },
+ keyCode: function(event) {
+ // `keyCode` is the result of a KeyDown/Up event and represents the value of
+ // physical keyboard key.
+
+ // The actual meaning of the value depends on the users' keyboard layout
+ // which cannot be detected. Assuming that it is a US keyboard layout
+ // provides a surprisingly accurate mapping for US and European users.
+ // Due to this, it is left to the user to implement at this time.
+ if (event.type === 'keydown' || event.type === 'keyup') {
+ return event.keyCode;
+ }
+ return 0;
+ },
+ which: function(event) {
+ // `which` is an alias for either `keyCode` or `charCode` depending on the
+ // type of the event.
+ if (event.type === 'keypress') {
+ return getEventCharCode(event);
+ }
+ if (event.type === 'keydown' || event.type === 'keyup') {
+ return event.keyCode;
+ }
+ return 0;
+ }
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticKeyboardEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+ SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticUIEvent.augmentClass(SyntheticKeyboardEvent, KeyboardEventInterface);
+
+module.exports = SyntheticKeyboardEvent;
+
+},{"./SyntheticUIEvent":152,"./getEventCharCode":175,"./getEventKey":176,"./getEventModifierState":177}],150:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticMouseEvent
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var SyntheticUIEvent = require("./SyntheticUIEvent");
+var ViewportMetrics = require("./ViewportMetrics");
+
+var getEventModifierState = require("./getEventModifierState");
+
+/**
+ * @interface MouseEvent
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/
+ */
+var MouseEventInterface = {
+ screenX: null,
+ screenY: null,
+ clientX: null,
+ clientY: null,
+ ctrlKey: null,
+ shiftKey: null,
+ altKey: null,
+ metaKey: null,
+ getModifierState: getEventModifierState,
+ button: function(event) {
+ // Webkit, Firefox, IE9+
+ // which: 1 2 3
+ // button: 0 1 2 (standard)
+ var button = event.button;
+ if ('which' in event) {
+ return button;
+ }
+ // IE<9
+ // which: undefined
+ // button: 0 0 0
+ // button: 1 4 2 (onmouseup)
+ return button === 2 ? 2 : button === 4 ? 1 : 0;
+ },
+ buttons: null,
+ relatedTarget: function(event) {
+ return event.relatedTarget || (
+ event.fromElement === event.srcElement ?
+ event.toElement :
+ event.fromElement
+ );
+ },
+ // "Proprietary" Interface.
+ pageX: function(event) {
+ return 'pageX' in event ?
+ event.pageX :
+ event.clientX + ViewportMetrics.currentScrollLeft;
+ },
+ pageY: function(event) {
+ return 'pageY' in event ?
+ event.pageY :
+ event.clientY + ViewportMetrics.currentScrollTop;
+ }
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticMouseEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+ SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticUIEvent.augmentClass(SyntheticMouseEvent, MouseEventInterface);
+
+module.exports = SyntheticMouseEvent;
+
+},{"./SyntheticUIEvent":152,"./ViewportMetrics":155,"./getEventModifierState":177}],151:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticTouchEvent
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var SyntheticUIEvent = require("./SyntheticUIEvent");
+
+var getEventModifierState = require("./getEventModifierState");
+
+/**
+ * @interface TouchEvent
+ * @see http://www.w3.org/TR/touch-events/
+ */
+var TouchEventInterface = {
+ touches: null,
+ targetTouches: null,
+ changedTouches: null,
+ altKey: null,
+ metaKey: null,
+ ctrlKey: null,
+ shiftKey: null,
+ getModifierState: getEventModifierState
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticTouchEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+ SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticUIEvent.augmentClass(SyntheticTouchEvent, TouchEventInterface);
+
+module.exports = SyntheticTouchEvent;
+
+},{"./SyntheticUIEvent":152,"./getEventModifierState":177}],152:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticUIEvent
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var SyntheticEvent = require("./SyntheticEvent");
+
+var getEventTarget = require("./getEventTarget");
+
+/**
+ * @interface UIEvent
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/
+ */
+var UIEventInterface = {
+ view: function(event) {
+ if (event.view) {
+ return event.view;
+ }
+
+ var target = getEventTarget(event);
+ if (target != null && target.window === target) {
+ // target is a window object
+ return target;
+ }
+
+ var doc = target.ownerDocument;
+ // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.
+ if (doc) {
+ return doc.defaultView || doc.parentWindow;
+ } else {
+ return window;
+ }
+ },
+ detail: function(event) {
+ return event.detail || 0;
+ }
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticEvent}
+ */
+function SyntheticUIEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+ SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticEvent.augmentClass(SyntheticUIEvent, UIEventInterface);
+
+module.exports = SyntheticUIEvent;
+
+},{"./SyntheticEvent":146,"./getEventTarget":178}],153:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticWheelEvent
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var SyntheticMouseEvent = require("./SyntheticMouseEvent");
+
+/**
+ * @interface WheelEvent
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/
+ */
+var WheelEventInterface = {
+ deltaX: function(event) {
+ return (
+ 'deltaX' in event ? event.deltaX :
+ // Fallback to `wheelDeltaX` for Webkit and normalize (right is positive).
+ 'wheelDeltaX' in event ? -event.wheelDeltaX : 0
+ );
+ },
+ deltaY: function(event) {
+ return (
+ 'deltaY' in event ? event.deltaY :
+ // Fallback to `wheelDeltaY` for Webkit and normalize (down is positive).
+ 'wheelDeltaY' in event ? -event.wheelDeltaY :
+ // Fallback to `wheelDelta` for IE<9 and normalize (down is positive).
+ 'wheelDelta' in event ? -event.wheelDelta : 0
+ );
+ },
+ deltaZ: null,
+
+ // Browsers without "deltaMode" is reporting in raw wheel delta where one
+ // notch on the scroll is always +/- 120, roughly equivalent to pixels.
+ // A good approximation of DOM_DELTA_LINE (1) is 5% of viewport size or
+ // ~40 pixels, for DOM_DELTA_SCREEN (2) it is 87.5% of viewport size.
+ deltaMode: null
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticMouseEvent}
+ */
+function SyntheticWheelEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+ SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticMouseEvent.augmentClass(SyntheticWheelEvent, WheelEventInterface);
+
+module.exports = SyntheticWheelEvent;
+
+},{"./SyntheticMouseEvent":150}],154:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule Transaction
+ */
+
+"use strict";
+
+var invariant = require("./invariant");
+
+/**
+ * `Transaction` creates a black box that is able to wrap any method such that
+ * certain invariants are maintained before and after the method is invoked
+ * (Even if an exception is thrown while invoking the wrapped method). Whoever
+ * instantiates a transaction can provide enforcers of the invariants at
+ * creation time. The `Transaction` class itself will supply one additional
+ * automatic invariant for you - the invariant that any transaction instance
+ * should not be run while it is already being run. You would typically create a
+ * single instance of a `Transaction` for reuse multiple times, that potentially
+ * is used to wrap several different methods. Wrappers are extremely simple -
+ * they only require implementing two methods.
+ *
+ * <pre>
+ * wrappers (injected at creation time)
+ * + +
+ * | |
+ * +-----------------|--------|--------------+
+ * | v | |
+ * | +---------------+ | |
+ * | +--| wrapper1 |---|----+ |
+ * | | +---------------+ v | |
+ * | | +-------------+ | |
+ * | | +----| wrapper2 |--------+ |
+ * | | | +-------------+ | | |
+ * | | | | | |
+ * | v v v v | wrapper
+ * | +---+ +---+ +---------+ +---+ +---+ | invariants
+ * perform(anyMethod) | | | | | | | | | | | | maintained
+ * +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|-------->
+ * | | | | | | | | | | | |
+ * | | | | | | | | | | | |
+ * | | | | | | | | | | | |
+ * | +---+ +---+ +---------+ +---+ +---+ |
+ * | initialize close |
+ * +-----------------------------------------+
+ * </pre>
+ *
+ * Use cases:
+ * - Preserving the input selection ranges before/after reconciliation.
+ * Restoring selection even in the event of an unexpected error.
+ * - Deactivating events while rearranging the DOM, preventing blurs/focuses,
+ * while guaranteeing that afterwards, the event system is reactivated.
+ * - Flushing a queue of collected DOM mutations to the main UI thread after a
+ * reconciliation takes place in a worker thread.
+ * - Invoking any collected `componentDidUpdate` callbacks after rendering new
+ * content.
+ * - (Future use case): Wrapping particular flushes of the `ReactWorker` queue
+ * to preserve the `scrollTop` (an automatic scroll aware DOM).
+ * - (Future use case): Layout calculations before and after DOM upates.
+ *
+ * Transactional plugin API:
+ * - A module that has an `initialize` method that returns any precomputation.
+ * - and a `close` method that accepts the precomputation. `close` is invoked
+ * when the wrapped process is completed, or has failed.
+ *
+ * @param {Array<TransactionalWrapper>} transactionWrapper Wrapper modules
+ * that implement `initialize` and `close`.
+ * @return {Transaction} Single transaction for reuse in thread.
+ *
+ * @class Transaction
+ */
+var Mixin = {
+ /**
+ * Sets up this instance so that it is prepared for collecting metrics. Does
+ * so such that this setup method may be used on an instance that is already
+ * initialized, in a way that does not consume additional memory upon reuse.
+ * That can be useful if you decide to make your subclass of this mixin a
+ * "PooledClass".
+ */
+ reinitializeTransaction: function() {
+ this.transactionWrappers = this.getTransactionWrappers();
+ if (!this.wrapperInitData) {
+ this.wrapperInitData = [];
+ } else {
+ this.wrapperInitData.length = 0;
+ }
+ this._isInTransaction = false;
+ },
+
+ _isInTransaction: false,
+
+ /**
+ * @abstract
+ * @return {Array<TransactionWrapper>} Array of transaction wrappers.
+ */
+ getTransactionWrappers: null,
+
+ isInTransaction: function() {
+ return !!this._isInTransaction;
+ },
+
+ /**
+ * Executes the function within a safety window. Use this for the top level
+ * methods that result in large amounts of computation/mutations that would
+ * need to be safety checked.
+ *
+ * @param {function} method Member of scope to call.
+ * @param {Object} scope Scope to invoke from.
+ * @param {Object?=} args... Arguments to pass to the method (optional).
+ * Helps prevent need to bind in many cases.
+ * @return Return value from `method`.
+ */
+ perform: function(method, scope, a, b, c, d, e, f) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !this.isInTransaction(),
+ 'Transaction.perform(...): Cannot initialize a transaction when there ' +
+ 'is already an outstanding transaction.'
+ ) : invariant(!this.isInTransaction()));
+ var errorThrown;
+ var ret;
+ try {
+ this._isInTransaction = true;
+ // Catching errors makes debugging more difficult, so we start with
+ // errorThrown set to true before setting it to false after calling
+ // close -- if it's still set to true in the finally block, it means
+ // one of these calls threw.
+ errorThrown = true;
+ this.initializeAll(0);
+ ret = method.call(scope, a, b, c, d, e, f);
+ errorThrown = false;
+ } finally {
+ try {
+ if (errorThrown) {
+ // If `method` throws, prefer to show that stack trace over any thrown
+ // by invoking `closeAll`.
+ try {
+ this.closeAll(0);
+ } catch (err) {
+ }
+ } else {
+ // Since `method` didn't throw, we don't want to silence the exception
+ // here.
+ this.closeAll(0);
+ }
+ } finally {
+ this._isInTransaction = false;
+ }
+ }
+ return ret;
+ },
+
+ initializeAll: function(startIndex) {
+ var transactionWrappers = this.transactionWrappers;
+ for (var i = startIndex; i < transactionWrappers.length; i++) {
+ var wrapper = transactionWrappers[i];
+ try {
+ // Catching errors makes debugging more difficult, so we start with the
+ // OBSERVED_ERROR state before overwriting it with the real return value
+ // of initialize -- if it's still set to OBSERVED_ERROR in the finally
+ // block, it means wrapper.initialize threw.
+ this.wrapperInitData[i] = Transaction.OBSERVED_ERROR;
+ this.wrapperInitData[i] = wrapper.initialize ?
+ wrapper.initialize.call(this) :
+ null;
+ } finally {
+ if (this.wrapperInitData[i] === Transaction.OBSERVED_ERROR) {
+ // The initializer for wrapper i threw an error; initialize the
+ // remaining wrappers but silence any exceptions from them to ensure
+ // that the first error is the one to bubble up.
+ try {
+ this.initializeAll(i + 1);
+ } catch (err) {
+ }
+ }
+ }
+ }
+ },
+
+ /**
+ * Invokes each of `this.transactionWrappers.close[i]` functions, passing into
+ * them the respective return values of `this.transactionWrappers.init[i]`
+ * (`close`rs that correspond to initializers that failed will not be
+ * invoked).
+ */
+ closeAll: function(startIndex) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ this.isInTransaction(),
+ 'Transaction.closeAll(): Cannot close transaction when none are open.'
+ ) : invariant(this.isInTransaction()));
+ var transactionWrappers = this.transactionWrappers;
+ for (var i = startIndex; i < transactionWrappers.length; i++) {
+ var wrapper = transactionWrappers[i];
+ var initData = this.wrapperInitData[i];
+ var errorThrown;
+ try {
+ // Catching errors makes debugging more difficult, so we start with
+ // errorThrown set to true before setting it to false after calling
+ // close -- if it's still set to true in the finally block, it means
+ // wrapper.close threw.
+ errorThrown = true;
+ if (initData !== Transaction.OBSERVED_ERROR) {
+ wrapper.close && wrapper.close.call(this, initData);
+ }
+ errorThrown = false;
+ } finally {
+ if (errorThrown) {
+ // The closer for wrapper i threw an error; close the remaining
+ // wrappers but silence any exceptions from them to ensure that the
+ // first error is the one to bubble up.
+ try {
+ this.closeAll(i + 1);
+ } catch (e) {
+ }
+ }
+ }
+ }
+ this.wrapperInitData.length = 0;
+ }
+};
+
+var Transaction = {
+
+ Mixin: Mixin,
+
+ /**
+ * Token to look for to determine if an error occured.
+ */
+ OBSERVED_ERROR: {}
+
+};
+
+module.exports = Transaction;
+
+}).call(this,require('_process'))
+},{"./invariant":187,"_process":5}],155:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ViewportMetrics
+ */
+
+"use strict";
+
+var getUnboundedScrollPosition = require("./getUnboundedScrollPosition");
+
+var ViewportMetrics = {
+
+ currentScrollLeft: 0,
+
+ currentScrollTop: 0,
+
+ refreshScrollValues: function() {
+ var scrollPosition = getUnboundedScrollPosition(window);
+ ViewportMetrics.currentScrollLeft = scrollPosition.x;
+ ViewportMetrics.currentScrollTop = scrollPosition.y;
+ }
+
+};
+
+module.exports = ViewportMetrics;
+
+},{"./getUnboundedScrollPosition":183}],156:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule accumulateInto
+ */
+
+"use strict";
+
+var invariant = require("./invariant");
+
+/**
+ *
+ * Accumulates items that must not be null or undefined into the first one. This
+ * is used to conserve memory by avoiding array allocations, and thus sacrifices
+ * API cleanness. Since `current` can be null before being passed in and not
+ * null after this function, make sure to assign it back to `current`:
+ *
+ * `a = accumulateInto(a, b);`
+ *
+ * This API should be sparingly used. Try `accumulate` for something cleaner.
+ *
+ * @return {*|array<*>} An accumulation of items.
+ */
+
+function accumulateInto(current, next) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ next != null,
+ 'accumulateInto(...): Accumulated items must not be null or undefined.'
+ ) : invariant(next != null));
+ if (current == null) {
+ return next;
+ }
+
+ // Both are not empty. Warning: Never call x.concat(y) when you are not
+ // certain that x is an Array (x could be a string with concat method).
+ var currentIsArray = Array.isArray(current);
+ var nextIsArray = Array.isArray(next);
+
+ if (currentIsArray && nextIsArray) {
+ current.push.apply(current, next);
+ return current;
+ }
+
+ if (currentIsArray) {
+ current.push(next);
+ return current;
+ }
+
+ if (nextIsArray) {
+ // A bit too dangerous to mutate `next`.
+ return [current].concat(next);
+ }
+
+ return [current, next];
+}
+
+module.exports = accumulateInto;
+
+}).call(this,require('_process'))
+},{"./invariant":187,"_process":5}],157:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule adler32
+ */
+
+/* jslint bitwise:true */
+
+"use strict";
+
+var MOD = 65521;
+
+// This is a clean-room implementation of adler32 designed for detecting
+// if markup is not what we expect it to be. It does not need to be
+// cryptographically strong, only reasonably good at detecting if markup
+// generated on the server is different than that on the client.
+function adler32(data) {
+ var a = 1;
+ var b = 0;
+ for (var i = 0; i < data.length; i++) {
+ a = (a + data.charCodeAt(i)) % MOD;
+ b = (b + a) % MOD;
+ }
+ return a | (b << 16);
+}
+
+module.exports = adler32;
+
+},{}],158:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule camelize
+ * @typechecks
+ */
+
+var _hyphenPattern = /-(.)/g;
+
+/**
+ * Camelcases a hyphenated string, for example:
+ *
+ * > camelize('background-color')
+ * < "backgroundColor"
+ *
+ * @param {string} string
+ * @return {string}
+ */
+function camelize(string) {
+ return string.replace(_hyphenPattern, function(_, character) {
+ return character.toUpperCase();
+ });
+}
+
+module.exports = camelize;
+
+},{}],159:[function(require,module,exports){
+/**
+ * Copyright 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule camelizeStyleName
+ * @typechecks
+ */
+
+"use strict";
+
+var camelize = require("./camelize");
+
+var msPattern = /^-ms-/;
+
+/**
+ * Camelcases a hyphenated CSS property name, for example:
+ *
+ * > camelizeStyleName('background-color')
+ * < "backgroundColor"
+ * > camelizeStyleName('-moz-transition')
+ * < "MozTransition"
+ * > camelizeStyleName('-ms-transition')
+ * < "msTransition"
+ *
+ * As Andi Smith suggests
+ * (http://www.andismith.com/blog/2012/02/modernizr-prefixed/), an `-ms` prefix
+ * is converted to lowercase `ms`.
+ *
+ * @param {string} string
+ * @return {string}
+ */
+function camelizeStyleName(string) {
+ return camelize(string.replace(msPattern, 'ms-'));
+}
+
+module.exports = camelizeStyleName;
+
+},{"./camelize":158}],160:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @typechecks
+ * @providesModule cloneWithProps
+ */
+
+"use strict";
+
+var ReactElement = require("./ReactElement");
+var ReactPropTransferer = require("./ReactPropTransferer");
+
+var keyOf = require("./keyOf");
+var warning = require("./warning");
+
+var CHILDREN_PROP = keyOf({children: null});
+
+/**
+ * Sometimes you want to change the props of a child passed to you. Usually
+ * this is to add a CSS class.
+ *
+ * @param {object} child child component you'd like to clone
+ * @param {object} props props you'd like to modify. They will be merged
+ * as if you used `transferPropsTo()`.
+ * @return {object} a clone of child with props merged in.
+ */
+function cloneWithProps(child, props) {
+ if ("production" !== process.env.NODE_ENV) {
+ ("production" !== process.env.NODE_ENV ? warning(
+ !child.ref,
+ 'You are calling cloneWithProps() on a child with a ref. This is ' +
+ 'dangerous because you\'re creating a new child which will not be ' +
+ 'added as a ref to its parent.'
+ ) : null);
+ }
+
+ var newProps = ReactPropTransferer.mergeProps(props, child.props);
+
+ // Use `child.props.children` if it is provided.
+ if (!newProps.hasOwnProperty(CHILDREN_PROP) &&
+ child.props.hasOwnProperty(CHILDREN_PROP)) {
+ newProps.children = child.props.children;
+ }
+
+ // The current API doesn't retain _owner and _context, which is why this
+ // doesn't use ReactElement.cloneAndReplaceProps.
+ return ReactElement.createElement(child.type, newProps);
+}
+
+module.exports = cloneWithProps;
+
+}).call(this,require('_process'))
+},{"./ReactElement":104,"./ReactPropTransferer":122,"./keyOf":194,"./warning":207,"_process":5}],161:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule containsNode
+ * @typechecks
+ */
+
+var isTextNode = require("./isTextNode");
+
+/*jslint bitwise:true */
+
+/**
+ * Checks if a given DOM node contains or is another DOM node.
+ *
+ * @param {?DOMNode} outerNode Outer DOM node.
+ * @param {?DOMNode} innerNode Inner DOM node.
+ * @return {boolean} True if `outerNode` contains or is `innerNode`.
+ */
+function containsNode(outerNode, innerNode) {
+ if (!outerNode || !innerNode) {
+ return false;
+ } else if (outerNode === innerNode) {
+ return true;
+ } else if (isTextNode(outerNode)) {
+ return false;
+ } else if (isTextNode(innerNode)) {
+ return containsNode(outerNode, innerNode.parentNode);
+ } else if (outerNode.contains) {
+ return outerNode.contains(innerNode);
+ } else if (outerNode.compareDocumentPosition) {
+ return !!(outerNode.compareDocumentPosition(innerNode) & 16);
+ } else {
+ return false;
+ }
+}
+
+module.exports = containsNode;
+
+},{"./isTextNode":191}],162:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule createArrayFrom
+ * @typechecks
+ */
+
+var toArray = require("./toArray");
+
+/**
+ * Perform a heuristic test to determine if an object is "array-like".
+ *
+ * A monk asked Joshu, a Zen master, "Has a dog Buddha nature?"
+ * Joshu replied: "Mu."
+ *
+ * This function determines if its argument has "array nature": it returns
+ * true if the argument is an actual array, an `arguments' object, or an
+ * HTMLCollection (e.g. node.childNodes or node.getElementsByTagName()).
+ *
+ * It will return false for other array-like objects like Filelist.
+ *
+ * @param {*} obj
+ * @return {boolean}
+ */
+function hasArrayNature(obj) {
+ return (
+ // not null/false
+ !!obj &&
+ // arrays are objects, NodeLists are functions in Safari
+ (typeof obj == 'object' || typeof obj == 'function') &&
+ // quacks like an array
+ ('length' in obj) &&
+ // not window
+ !('setInterval' in obj) &&
+ // no DOM node should be considered an array-like
+ // a 'select' element has 'length' and 'item' properties on IE8
+ (typeof obj.nodeType != 'number') &&
+ (
+ // a real array
+ (// HTMLCollection/NodeList
+ (Array.isArray(obj) ||
+ // arguments
+ ('callee' in obj) || 'item' in obj))
+ )
+ );
+}
+
+/**
+ * Ensure that the argument is an array by wrapping it in an array if it is not.
+ * Creates a copy of the argument if it is already an array.
+ *
+ * This is mostly useful idiomatically:
+ *
+ * var createArrayFrom = require('createArrayFrom');
+ *
+ * function takesOneOrMoreThings(things) {
+ * things = createArrayFrom(things);
+ * ...
+ * }
+ *
+ * This allows you to treat `things' as an array, but accept scalars in the API.
+ *
+ * If you need to convert an array-like object, like `arguments`, into an array
+ * use toArray instead.
+ *
+ * @param {*} obj
+ * @return {array}
+ */
+function createArrayFrom(obj) {
+ if (!hasArrayNature(obj)) {
+ return [obj];
+ } else if (Array.isArray(obj)) {
+ return obj.slice();
+ } else {
+ return toArray(obj);
+ }
+}
+
+module.exports = createArrayFrom;
+
+},{"./toArray":204}],163:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule createFullPageComponent
+ * @typechecks
+ */
+
+"use strict";
+
+// Defeat circular references by requiring this directly.
+var ReactCompositeComponent = require("./ReactCompositeComponent");
+var ReactElement = require("./ReactElement");
+
+var invariant = require("./invariant");
+
+/**
+ * Create a component that will throw an exception when unmounted.
+ *
+ * Components like <html> <head> and <body> can't be removed or added
+ * easily in a cross-browser way, however it's valuable to be able to
+ * take advantage of React's reconciliation for styling and <title>
+ * management. So we just document it and throw in dangerous cases.
+ *
+ * @param {string} tag The tag to wrap
+ * @return {function} convenience constructor of new component
+ */
+function createFullPageComponent(tag) {
+ var elementFactory = ReactElement.createFactory(tag);
+
+ var FullPageComponent = ReactCompositeComponent.createClass({
+ displayName: 'ReactFullPageComponent' + tag,
+
+ componentWillUnmount: function() {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ false,
+ '%s tried to unmount. Because of cross-browser quirks it is ' +
+ 'impossible to unmount some top-level components (eg <html>, <head>, ' +
+ 'and <body>) reliably and efficiently. To fix this, have a single ' +
+ 'top-level component that never unmounts render these elements.',
+ this.constructor.displayName
+ ) : invariant(false));
+ },
+
+ render: function() {
+ return elementFactory(this.props);
+ }
+ });
+
+ return FullPageComponent;
+}
+
+module.exports = createFullPageComponent;
+
+}).call(this,require('_process'))
+},{"./ReactCompositeComponent":86,"./ReactElement":104,"./invariant":187,"_process":5}],164:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule createNodesFromMarkup
+ * @typechecks
+ */
+
+/*jslint evil: true, sub: true */
+
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+
+var createArrayFrom = require("./createArrayFrom");
+var getMarkupWrap = require("./getMarkupWrap");
+var invariant = require("./invariant");
+
+/**
+ * Dummy container used to render all markup.
+ */
+var dummyNode =
+ ExecutionEnvironment.canUseDOM ? document.createElement('div') : null;
+
+/**
+ * Pattern used by `getNodeName`.
+ */
+var nodeNamePattern = /^\s*<(\w+)/;
+
+/**
+ * Extracts the `nodeName` of the first element in a string of markup.
+ *
+ * @param {string} markup String of markup.
+ * @return {?string} Node name of the supplied markup.
+ */
+function getNodeName(markup) {
+ var nodeNameMatch = markup.match(nodeNamePattern);
+ return nodeNameMatch && nodeNameMatch[1].toLowerCase();
+}
+
+/**
+ * Creates an array containing the nodes rendered from the supplied markup. The
+ * optionally supplied `handleScript` function will be invoked once for each
+ * <script> element that is rendered. If no `handleScript` function is supplied,
+ * an exception is thrown if any <script> elements are rendered.
+ *
+ * @param {string} markup A string of valid HTML markup.
+ * @param {?function} handleScript Invoked once for each rendered <script>.
+ * @return {array<DOMElement|DOMTextNode>} An array of rendered nodes.
+ */
+function createNodesFromMarkup(markup, handleScript) {
+ var node = dummyNode;
+ ("production" !== process.env.NODE_ENV ? invariant(!!dummyNode, 'createNodesFromMarkup dummy not initialized') : invariant(!!dummyNode));
+ var nodeName = getNodeName(markup);
+
+ var wrap = nodeName && getMarkupWrap(nodeName);
+ if (wrap) {
+ node.innerHTML = wrap[1] + markup + wrap[2];
+
+ var wrapDepth = wrap[0];
+ while (wrapDepth--) {
+ node = node.lastChild;
+ }
+ } else {
+ node.innerHTML = markup;
+ }
+
+ var scripts = node.getElementsByTagName('script');
+ if (scripts.length) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ handleScript,
+ 'createNodesFromMarkup(...): Unexpected <script> element rendered.'
+ ) : invariant(handleScript));
+ createArrayFrom(scripts).forEach(handleScript);
+ }
+
+ var nodes = createArrayFrom(node.childNodes);
+ while (node.lastChild) {
+ node.removeChild(node.lastChild);
+ }
+ return nodes;
+}
+
+module.exports = createNodesFromMarkup;
+
+}).call(this,require('_process'))
+},{"./ExecutionEnvironment":69,"./createArrayFrom":162,"./getMarkupWrap":179,"./invariant":187,"_process":5}],165:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule cx
+ */
+
+/**
+ * This function is used to mark string literals representing CSS class names
+ * so that they can be transformed statically. This allows for modularization
+ * and minification of CSS class names.
+ *
+ * In static_upstream, this function is actually implemented, but it should
+ * eventually be replaced with something more descriptive, and the transform
+ * that is used in the main stack should be ported for use elsewhere.
+ *
+ * @param string|object className to modularize, or an object of key/values.
+ * In the object case, the values are conditions that
+ * determine if the className keys should be included.
+ * @param [string ...] Variable list of classNames in the string case.
+ * @return string Renderable space-separated CSS className.
+ */
+function cx(classNames) {
+ if (typeof classNames == 'object') {
+ return Object.keys(classNames).filter(function(className) {
+ return classNames[className];
+ }).join(' ');
+ } else {
+ return Array.prototype.join.call(arguments, ' ');
+ }
+}
+
+module.exports = cx;
+
+},{}],166:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule dangerousStyleValue
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var CSSProperty = require("./CSSProperty");
+
+var isUnitlessNumber = CSSProperty.isUnitlessNumber;
+
+/**
+ * Convert a value into the proper css writable value. The style name `name`
+ * should be logical (no hyphens), as specified
+ * in `CSSProperty.isUnitlessNumber`.
+ *
+ * @param {string} name CSS property name such as `topMargin`.
+ * @param {*} value CSS property value such as `10px`.
+ * @return {string} Normalized style value with dimensions applied.
+ */
+function dangerousStyleValue(name, value) {
+ // Note that we've removed escapeTextForBrowser() calls here since the
+ // whole string will be escaped when the attribute is injected into
+ // the markup. If you provide unsafe user data here they can inject
+ // arbitrary CSS which may be problematic (I couldn't repro this):
+ // https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
+ // http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/
+ // This is not an XSS hole but instead a potential CSS injection issue
+ // which has lead to a greater discussion about how we're going to
+ // trust URLs moving forward. See #2115901
+
+ var isEmpty = value == null || typeof value === 'boolean' || value === '';
+ if (isEmpty) {
+ return '';
+ }
+
+ var isNonNumeric = isNaN(value);
+ if (isNonNumeric || value === 0 ||
+ isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name]) {
+ return '' + value; // cast to string
+ }
+
+ if (typeof value === 'string') {
+ value = value.trim();
+ }
+ return value + 'px';
+}
+
+module.exports = dangerousStyleValue;
+
+},{"./CSSProperty":51}],167:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule deprecated
+ */
+
+var assign = require("./Object.assign");
+var warning = require("./warning");
+
+/**
+ * This will log a single deprecation notice per function and forward the call
+ * on to the new API.
+ *
+ * @param {string} namespace The namespace of the call, eg 'React'
+ * @param {string} oldName The old function name, eg 'renderComponent'
+ * @param {string} newName The new function name, eg 'render'
+ * @param {*} ctx The context this forwarded call should run in
+ * @param {function} fn The function to forward on to
+ * @return {*} Will be the value as returned from `fn`
+ */
+function deprecated(namespace, oldName, newName, ctx, fn) {
+ var warned = false;
+ if ("production" !== process.env.NODE_ENV) {
+ var newFn = function() {
+ ("production" !== process.env.NODE_ENV ? warning(
+ warned,
+ (namespace + "." + oldName + " will be deprecated in a future version. ") +
+ ("Use " + namespace + "." + newName + " instead.")
+ ) : null);
+ warned = true;
+ return fn.apply(ctx, arguments);
+ };
+ newFn.displayName = (namespace + "_" + oldName);
+ // We need to make sure all properties of the original fn are copied over.
+ // In particular, this is needed to support PropTypes
+ return assign(newFn, fn);
+ }
+
+ return fn;
+}
+
+module.exports = deprecated;
+
+}).call(this,require('_process'))
+},{"./Object.assign":75,"./warning":207,"_process":5}],168:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule emptyFunction
+ */
+
+function makeEmptyFunction(arg) {
+ return function() {
+ return arg;
+ };
+}
+
+/**
+ * This function accepts and discards inputs; it has no side effects. This is
+ * primarily useful idiomatically for overridable function endpoints which
+ * always need to be callable, since JS lacks a null-call idiom ala Cocoa.
+ */
+function emptyFunction() {}
+
+emptyFunction.thatReturns = makeEmptyFunction;
+emptyFunction.thatReturnsFalse = makeEmptyFunction(false);
+emptyFunction.thatReturnsTrue = makeEmptyFunction(true);
+emptyFunction.thatReturnsNull = makeEmptyFunction(null);
+emptyFunction.thatReturnsThis = function() { return this; };
+emptyFunction.thatReturnsArgument = function(arg) { return arg; };
+
+module.exports = emptyFunction;
+
+},{}],169:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule emptyObject
+ */
+
+"use strict";
+
+var emptyObject = {};
+
+if ("production" !== process.env.NODE_ENV) {
+ Object.freeze(emptyObject);
+}
+
+module.exports = emptyObject;
+
+}).call(this,require('_process'))
+},{"_process":5}],170:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule escapeTextForBrowser
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var ESCAPE_LOOKUP = {
+ "&": "&amp;",
+ ">": "&gt;",
+ "<": "&lt;",
+ "\"": "&quot;",
+ "'": "&#x27;"
+};
+
+var ESCAPE_REGEX = /[&><"']/g;
+
+function escaper(match) {
+ return ESCAPE_LOOKUP[match];
+}
+
+/**
+ * Escapes text to prevent scripting attacks.
+ *
+ * @param {*} text Text value to escape.
+ * @return {string} An escaped string.
+ */
+function escapeTextForBrowser(text) {
+ return ('' + text).replace(ESCAPE_REGEX, escaper);
+}
+
+module.exports = escapeTextForBrowser;
+
+},{}],171:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule flattenChildren
+ */
+
+"use strict";
+
+var ReactTextComponent = require("./ReactTextComponent");
+
+var traverseAllChildren = require("./traverseAllChildren");
+var warning = require("./warning");
+
+/**
+ * @param {function} traverseContext Context passed through traversal.
+ * @param {?ReactComponent} child React child component.
+ * @param {!string} name String name of key path to child.
+ */
+function flattenSingleChildIntoContext(traverseContext, child, name) {
+ // We found a component instance.
+ var result = traverseContext;
+ var keyUnique = !result.hasOwnProperty(name);
+ ("production" !== process.env.NODE_ENV ? warning(
+ keyUnique,
+ 'flattenChildren(...): Encountered two children with the same key, ' +
+ '`%s`. Child keys must be unique; when two children share a key, only ' +
+ 'the first child will be used.',
+ name
+ ) : null);
+ if (keyUnique && child != null) {
+ var type = typeof child;
+ var normalizedValue;
+
+ if (type === 'string') {
+ normalizedValue = ReactTextComponent(child);
+ } else if (type === 'number') {
+ normalizedValue = ReactTextComponent('' + child);
+ } else {
+ normalizedValue = child;
+ }
+
+ result[name] = normalizedValue;
+ }
+}
+
+/**
+ * Flattens children that are typically specified as `props.children`. Any null
+ * children will not be included in the resulting object.
+ * @return {!object} flattened children keyed by name.
+ */
+function flattenChildren(children) {
+ if (children == null) {
+ return children;
+ }
+ var result = {};
+ traverseAllChildren(children, flattenSingleChildIntoContext, result);
+ return result;
+}
+
+module.exports = flattenChildren;
+
+}).call(this,require('_process'))
+},{"./ReactTextComponent":133,"./traverseAllChildren":205,"./warning":207,"_process":5}],172:[function(require,module,exports){
+/**
+ * Copyright 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule focusNode
+ */
+
+"use strict";
+
+/**
+ * @param {DOMElement} node input/textarea to focus
+ */
+function focusNode(node) {
+ // IE8 can throw "Can't move focus to the control because it is invisible,
+ // not enabled, or of a type that does not accept the focus." for all kinds of
+ // reasons that are too expensive and fragile to test.
+ try {
+ node.focus();
+ } catch(e) {
+ }
+}
+
+module.exports = focusNode;
+
+},{}],173:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule forEachAccumulated
+ */
+
+"use strict";
+
+/**
+ * @param {array} an "accumulation" of items which is either an Array or
+ * a single item. Useful when paired with the `accumulate` module. This is a
+ * simple utility that allows us to reason about a collection of items, but
+ * handling the case when there is exactly one item (and we do not need to
+ * allocate an array).
+ */
+var forEachAccumulated = function(arr, cb, scope) {
+ if (Array.isArray(arr)) {
+ arr.forEach(cb, scope);
+ } else if (arr) {
+ cb.call(scope, arr);
+ }
+};
+
+module.exports = forEachAccumulated;
+
+},{}],174:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getActiveElement
+ * @typechecks
+ */
+
+/**
+ * Same as document.activeElement but wraps in a try-catch block. In IE it is
+ * not safe to call document.activeElement if there is nothing focused.
+ *
+ * The activeElement will be null only if the document body is not yet defined.
+ */
+function getActiveElement() /*?DOMElement*/ {
+ try {
+ return document.activeElement || document.body;
+ } catch (e) {
+ return document.body;
+ }
+}
+
+module.exports = getActiveElement;
+
+},{}],175:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getEventCharCode
+ * @typechecks static-only
+ */
+
+"use strict";
+
+/**
+ * `charCode` represents the actual "character code" and is safe to use with
+ * `String.fromCharCode`. As such, only keys that correspond to printable
+ * characters produce a valid `charCode`, the only exception to this is Enter.
+ * The Tab-key is considered non-printable and does not have a `charCode`,
+ * presumably because it does not produce a tab-character in browsers.
+ *
+ * @param {object} nativeEvent Native browser event.
+ * @return {string} Normalized `charCode` property.
+ */
+function getEventCharCode(nativeEvent) {
+ var charCode;
+ var keyCode = nativeEvent.keyCode;
+
+ if ('charCode' in nativeEvent) {
+ charCode = nativeEvent.charCode;
+
+ // FF does not set `charCode` for the Enter-key, check against `keyCode`.
+ if (charCode === 0 && keyCode === 13) {
+ charCode = 13;
+ }
+ } else {
+ // IE8 does not implement `charCode`, but `keyCode` has the correct value.
+ charCode = keyCode;
+ }
+
+ // Some non-printable keys are reported in `charCode`/`keyCode`, discard them.
+ // Must not discard the (non-)printable Enter-key.
+ if (charCode >= 32 || charCode === 13) {
+ return charCode;
+ }
+
+ return 0;
+}
+
+module.exports = getEventCharCode;
+
+},{}],176:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getEventKey
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var getEventCharCode = require("./getEventCharCode");
+
+/**
+ * Normalization of deprecated HTML5 `key` values
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names
+ */
+var normalizeKey = {
+ 'Esc': 'Escape',
+ 'Spacebar': ' ',
+ 'Left': 'ArrowLeft',
+ 'Up': 'ArrowUp',
+ 'Right': 'ArrowRight',
+ 'Down': 'ArrowDown',
+ 'Del': 'Delete',
+ 'Win': 'OS',
+ 'Menu': 'ContextMenu',
+ 'Apps': 'ContextMenu',
+ 'Scroll': 'ScrollLock',
+ 'MozPrintableKey': 'Unidentified'
+};
+
+/**
+ * Translation from legacy `keyCode` to HTML5 `key`
+ * Only special keys supported, all others depend on keyboard layout or browser
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names
+ */
+var translateToKey = {
+ 8: 'Backspace',
+ 9: 'Tab',
+ 12: 'Clear',
+ 13: 'Enter',
+ 16: 'Shift',
+ 17: 'Control',
+ 18: 'Alt',
+ 19: 'Pause',
+ 20: 'CapsLock',
+ 27: 'Escape',
+ 32: ' ',
+ 33: 'PageUp',
+ 34: 'PageDown',
+ 35: 'End',
+ 36: 'Home',
+ 37: 'ArrowLeft',
+ 38: 'ArrowUp',
+ 39: 'ArrowRight',
+ 40: 'ArrowDown',
+ 45: 'Insert',
+ 46: 'Delete',
+ 112: 'F1', 113: 'F2', 114: 'F3', 115: 'F4', 116: 'F5', 117: 'F6',
+ 118: 'F7', 119: 'F8', 120: 'F9', 121: 'F10', 122: 'F11', 123: 'F12',
+ 144: 'NumLock',
+ 145: 'ScrollLock',
+ 224: 'Meta'
+};
+
+/**
+ * @param {object} nativeEvent Native browser event.
+ * @return {string} Normalized `key` property.
+ */
+function getEventKey(nativeEvent) {
+ if (nativeEvent.key) {
+ // Normalize inconsistent values reported by browsers due to
+ // implementations of a working draft specification.
+
+ // FireFox implements `key` but returns `MozPrintableKey` for all
+ // printable characters (normalized to `Unidentified`), ignore it.
+ var key = normalizeKey[nativeEvent.key] || nativeEvent.key;
+ if (key !== 'Unidentified') {
+ return key;
+ }
+ }
+
+ // Browser does not implement `key`, polyfill as much of it as we can.
+ if (nativeEvent.type === 'keypress') {
+ var charCode = getEventCharCode(nativeEvent);
+
+ // The enter-key is technically both printable and non-printable and can
+ // thus be captured by `keypress`, no other non-printable key should.
+ return charCode === 13 ? 'Enter' : String.fromCharCode(charCode);
+ }
+ if (nativeEvent.type === 'keydown' || nativeEvent.type === 'keyup') {
+ // While user keyboard layout determines the actual meaning of each
+ // `keyCode` value, almost all function keys have a universal value.
+ return translateToKey[nativeEvent.keyCode] || 'Unidentified';
+ }
+ return '';
+}
+
+module.exports = getEventKey;
+
+},{"./getEventCharCode":175}],177:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getEventModifierState
+ * @typechecks static-only
+ */
+
+"use strict";
+
+/**
+ * Translation from modifier key to the associated property in the event.
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/#keys-Modifiers
+ */
+
+var modifierKeyToProp = {
+ 'Alt': 'altKey',
+ 'Control': 'ctrlKey',
+ 'Meta': 'metaKey',
+ 'Shift': 'shiftKey'
+};
+
+// IE8 does not implement getModifierState so we simply map it to the only
+// modifier keys exposed by the event itself, does not support Lock-keys.
+// Currently, all major browsers except Chrome seems to support Lock-keys.
+function modifierStateGetter(keyArg) {
+ /*jshint validthis:true */
+ var syntheticEvent = this;
+ var nativeEvent = syntheticEvent.nativeEvent;
+ if (nativeEvent.getModifierState) {
+ return nativeEvent.getModifierState(keyArg);
+ }
+ var keyProp = modifierKeyToProp[keyArg];
+ return keyProp ? !!nativeEvent[keyProp] : false;
+}
+
+function getEventModifierState(nativeEvent) {
+ return modifierStateGetter;
+}
+
+module.exports = getEventModifierState;
+
+},{}],178:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getEventTarget
+ * @typechecks static-only
+ */
+
+"use strict";
+
+/**
+ * Gets the target node from a native browser event by accounting for
+ * inconsistencies in browser DOM APIs.
+ *
+ * @param {object} nativeEvent Native browser event.
+ * @return {DOMEventTarget} Target node.
+ */
+function getEventTarget(nativeEvent) {
+ var target = nativeEvent.target || nativeEvent.srcElement || window;
+ // Safari may fire events on text nodes (Node.TEXT_NODE is 3).
+ // @see http://www.quirksmode.org/js/events_properties.html
+ return target.nodeType === 3 ? target.parentNode : target;
+}
+
+module.exports = getEventTarget;
+
+},{}],179:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getMarkupWrap
+ */
+
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+
+var invariant = require("./invariant");
+
+/**
+ * Dummy container used to detect which wraps are necessary.
+ */
+var dummyNode =
+ ExecutionEnvironment.canUseDOM ? document.createElement('div') : null;
+
+/**
+ * Some browsers cannot use `innerHTML` to render certain elements standalone,
+ * so we wrap them, render the wrapped nodes, then extract the desired node.
+ *
+ * In IE8, certain elements cannot render alone, so wrap all elements ('*').
+ */
+var shouldWrap = {
+ // Force wrapping for SVG elements because if they get created inside a <div>,
+ // they will be initialized in the wrong namespace (and will not display).
+ 'circle': true,
+ 'defs': true,
+ 'ellipse': true,
+ 'g': true,
+ 'line': true,
+ 'linearGradient': true,
+ 'path': true,
+ 'polygon': true,
+ 'polyline': true,
+ 'radialGradient': true,
+ 'rect': true,
+ 'stop': true,
+ 'text': true
+};
+
+var selectWrap = [1, '<select multiple="true">', '</select>'];
+var tableWrap = [1, '<table>', '</table>'];
+var trWrap = [3, '<table><tbody><tr>', '</tr></tbody></table>'];
+
+var svgWrap = [1, '<svg>', '</svg>'];
+
+var markupWrap = {
+ '*': [1, '?<div>', '</div>'],
+
+ 'area': [1, '<map>', '</map>'],
+ 'col': [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
+ 'legend': [1, '<fieldset>', '</fieldset>'],
+ 'param': [1, '<object>', '</object>'],
+ 'tr': [2, '<table><tbody>', '</tbody></table>'],
+
+ 'optgroup': selectWrap,
+ 'option': selectWrap,
+
+ 'caption': tableWrap,
+ 'colgroup': tableWrap,
+ 'tbody': tableWrap,
+ 'tfoot': tableWrap,
+ 'thead': tableWrap,
+
+ 'td': trWrap,
+ 'th': trWrap,
+
+ 'circle': svgWrap,
+ 'defs': svgWrap,
+ 'ellipse': svgWrap,
+ 'g': svgWrap,
+ 'line': svgWrap,
+ 'linearGradient': svgWrap,
+ 'path': svgWrap,
+ 'polygon': svgWrap,
+ 'polyline': svgWrap,
+ 'radialGradient': svgWrap,
+ 'rect': svgWrap,
+ 'stop': svgWrap,
+ 'text': svgWrap
+};
+
+/**
+ * Gets the markup wrap configuration for the supplied `nodeName`.
+ *
+ * NOTE: This lazily detects which wraps are necessary for the current browser.
+ *
+ * @param {string} nodeName Lowercase `nodeName`.
+ * @return {?array} Markup wrap configuration, if applicable.
+ */
+function getMarkupWrap(nodeName) {
+ ("production" !== process.env.NODE_ENV ? invariant(!!dummyNode, 'Markup wrapping node not initialized') : invariant(!!dummyNode));
+ if (!markupWrap.hasOwnProperty(nodeName)) {
+ nodeName = '*';
+ }
+ if (!shouldWrap.hasOwnProperty(nodeName)) {
+ if (nodeName === '*') {
+ dummyNode.innerHTML = '<link />';
+ } else {
+ dummyNode.innerHTML = '<' + nodeName + '></' + nodeName + '>';
+ }
+ shouldWrap[nodeName] = !dummyNode.firstChild;
+ }
+ return shouldWrap[nodeName] ? markupWrap[nodeName] : null;
+}
+
+
+module.exports = getMarkupWrap;
+
+}).call(this,require('_process'))
+},{"./ExecutionEnvironment":69,"./invariant":187,"_process":5}],180:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getNodeForCharacterOffset
+ */
+
+"use strict";
+
+/**
+ * Given any node return the first leaf node without children.
+ *
+ * @param {DOMElement|DOMTextNode} node
+ * @return {DOMElement|DOMTextNode}
+ */
+function getLeafNode(node) {
+ while (node && node.firstChild) {
+ node = node.firstChild;
+ }
+ return node;
+}
+
+/**
+ * Get the next sibling within a container. This will walk up the
+ * DOM if a node's siblings have been exhausted.
+ *
+ * @param {DOMElement|DOMTextNode} node
+ * @return {?DOMElement|DOMTextNode}
+ */
+function getSiblingNode(node) {
+ while (node) {
+ if (node.nextSibling) {
+ return node.nextSibling;
+ }
+ node = node.parentNode;
+ }
+}
+
+/**
+ * Get object describing the nodes which contain characters at offset.
+ *
+ * @param {DOMElement|DOMTextNode} root
+ * @param {number} offset
+ * @return {?object}
+ */
+function getNodeForCharacterOffset(root, offset) {
+ var node = getLeafNode(root);
+ var nodeStart = 0;
+ var nodeEnd = 0;
+
+ while (node) {
+ if (node.nodeType == 3) {
+ nodeEnd = nodeStart + node.textContent.length;
+
+ if (nodeStart <= offset && nodeEnd >= offset) {
+ return {
+ node: node,
+ offset: offset - nodeStart
+ };
+ }
+
+ nodeStart = nodeEnd;
+ }
+
+ node = getLeafNode(getSiblingNode(node));
+ }
+}
+
+module.exports = getNodeForCharacterOffset;
+
+},{}],181:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getReactRootElementInContainer
+ */
+
+"use strict";
+
+var DOC_NODE_TYPE = 9;
+
+/**
+ * @param {DOMElement|DOMDocument} container DOM element that may contain
+ * a React component
+ * @return {?*} DOM element that may have the reactRoot ID, or null.
+ */
+function getReactRootElementInContainer(container) {
+ if (!container) {
+ return null;
+ }
+
+ if (container.nodeType === DOC_NODE_TYPE) {
+ return container.documentElement;
+ } else {
+ return container.firstChild;
+ }
+}
+
+module.exports = getReactRootElementInContainer;
+
+},{}],182:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getTextContentAccessor
+ */
+
+"use strict";
+
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+
+var contentKey = null;
+
+/**
+ * Gets the key used to access text content on a DOM node.
+ *
+ * @return {?string} Key used to access text content.
+ * @internal
+ */
+function getTextContentAccessor() {
+ if (!contentKey && ExecutionEnvironment.canUseDOM) {
+ // Prefer textContent to innerText because many browsers support both but
+ // SVG <text> elements don't support innerText even when <div> does.
+ contentKey = 'textContent' in document.documentElement ?
+ 'textContent' :
+ 'innerText';
+ }
+ return contentKey;
+}
+
+module.exports = getTextContentAccessor;
+
+},{"./ExecutionEnvironment":69}],183:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getUnboundedScrollPosition
+ * @typechecks
+ */
+
+"use strict";
+
+/**
+ * Gets the scroll position of the supplied element or window.
+ *
+ * The return values are unbounded, unlike `getScrollPosition`. This means they
+ * may be negative or exceed the element boundaries (which is possible using
+ * inertial scrolling).
+ *
+ * @param {DOMWindow|DOMElement} scrollable
+ * @return {object} Map with `x` and `y` keys.
+ */
+function getUnboundedScrollPosition(scrollable) {
+ if (scrollable === window) {
+ return {
+ x: window.pageXOffset || document.documentElement.scrollLeft,
+ y: window.pageYOffset || document.documentElement.scrollTop
+ };
+ }
+ return {
+ x: scrollable.scrollLeft,
+ y: scrollable.scrollTop
+ };
+}
+
+module.exports = getUnboundedScrollPosition;
+
+},{}],184:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule hyphenate
+ * @typechecks
+ */
+
+var _uppercasePattern = /([A-Z])/g;
+
+/**
+ * Hyphenates a camelcased string, for example:
+ *
+ * > hyphenate('backgroundColor')
+ * < "background-color"
+ *
+ * For CSS style names, use `hyphenateStyleName` instead which works properly
+ * with all vendor prefixes, including `ms`.
+ *
+ * @param {string} string
+ * @return {string}
+ */
+function hyphenate(string) {
+ return string.replace(_uppercasePattern, '-$1').toLowerCase();
+}
+
+module.exports = hyphenate;
+
+},{}],185:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule hyphenateStyleName
+ * @typechecks
+ */
+
+"use strict";
+
+var hyphenate = require("./hyphenate");
+
+var msPattern = /^ms-/;
+
+/**
+ * Hyphenates a camelcased CSS property name, for example:
+ *
+ * > hyphenateStyleName('backgroundColor')
+ * < "background-color"
+ * > hyphenateStyleName('MozTransition')
+ * < "-moz-transition"
+ * > hyphenateStyleName('msTransition')
+ * < "-ms-transition"
+ *
+ * As Modernizr suggests (http://modernizr.com/docs/#prefixed), an `ms` prefix
+ * is converted to `-ms-`.
+ *
+ * @param {string} string
+ * @return {string}
+ */
+function hyphenateStyleName(string) {
+ return hyphenate(string).replace(msPattern, '-ms-');
+}
+
+module.exports = hyphenateStyleName;
+
+},{"./hyphenate":184}],186:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule instantiateReactComponent
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var warning = require("./warning");
+
+var ReactElement = require("./ReactElement");
+var ReactLegacyElement = require("./ReactLegacyElement");
+var ReactNativeComponent = require("./ReactNativeComponent");
+var ReactEmptyComponent = require("./ReactEmptyComponent");
+
+/**
+ * Given an `element` create an instance that will actually be mounted.
+ *
+ * @param {object} element
+ * @param {*} parentCompositeType The composite type that resolved this.
+ * @return {object} A new instance of the element's constructor.
+ * @protected
+ */
+function instantiateReactComponent(element, parentCompositeType) {
+ var instance;
+
+ if ("production" !== process.env.NODE_ENV) {
+ ("production" !== process.env.NODE_ENV ? warning(
+ element && (typeof element.type === 'function' ||
+ typeof element.type === 'string'),
+ 'Only functions or strings can be mounted as React components.'
+ ) : null);
+
+ // Resolve mock instances
+ if (element.type._mockedReactClassConstructor) {
+ // If this is a mocked class, we treat the legacy factory as if it was the
+ // class constructor for future proofing unit tests. Because this might
+ // be mocked as a legacy factory, we ignore any warnings triggerd by
+ // this temporary hack.
+ ReactLegacyElement._isLegacyCallWarningEnabled = false;
+ try {
+ instance = new element.type._mockedReactClassConstructor(
+ element.props
+ );
+ } finally {
+ ReactLegacyElement._isLegacyCallWarningEnabled = true;
+ }
+
+ // If the mock implementation was a legacy factory, then it returns a
+ // element. We need to turn this into a real component instance.
+ if (ReactElement.isValidElement(instance)) {
+ instance = new instance.type(instance.props);
+ }
+
+ var render = instance.render;
+ if (!render) {
+ // For auto-mocked factories, the prototype isn't shimmed and therefore
+ // there is no render function on the instance. We replace the whole
+ // component with an empty component instance instead.
+ element = ReactEmptyComponent.getEmptyComponent();
+ } else {
+ if (render._isMockFunction && !render._getMockImplementation()) {
+ // Auto-mocked components may have a prototype with a mocked render
+ // function. For those, we'll need to mock the result of the render
+ // since we consider undefined to be invalid results from render.
+ render.mockImplementation(
+ ReactEmptyComponent.getEmptyComponent
+ );
+ }
+ instance.construct(element);
+ return instance;
+ }
+ }
+ }
+
+ // Special case string values
+ if (typeof element.type === 'string') {
+ instance = ReactNativeComponent.createInstanceForTag(
+ element.type,
+ element.props,
+ parentCompositeType
+ );
+ } else {
+ // Normal case for non-mocks and non-strings
+ instance = new element.type(element.props);
+ }
+
+ if ("production" !== process.env.NODE_ENV) {
+ ("production" !== process.env.NODE_ENV ? warning(
+ typeof instance.construct === 'function' &&
+ typeof instance.mountComponent === 'function' &&
+ typeof instance.receiveComponent === 'function',
+ 'Only React Components can be mounted.'
+ ) : null);
+ }
+
+ // This actually sets up the internal instance. This will become decoupled
+ // from the public instance in a future diff.
+ instance.construct(element);
+
+ return instance;
+}
+
+module.exports = instantiateReactComponent;
+
+}).call(this,require('_process'))
+},{"./ReactElement":104,"./ReactEmptyComponent":106,"./ReactLegacyElement":113,"./ReactNativeComponent":119,"./warning":207,"_process":5}],187:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule invariant
+ */
+
+"use strict";
+
+/**
+ * Use invariant() to assert state which your program assumes to be true.
+ *
+ * Provide sprintf-style format (only %s is supported) and arguments
+ * to provide information about what broke and what you were
+ * expecting.
+ *
+ * The invariant message will be stripped in production, but the invariant
+ * will remain to ensure logic does not differ in production.
+ */
+
+var invariant = function(condition, format, a, b, c, d, e, f) {
+ if ("production" !== process.env.NODE_ENV) {
+ if (format === undefined) {
+ throw new Error('invariant requires an error message argument');
+ }
+ }
+
+ if (!condition) {
+ var error;
+ if (format === undefined) {
+ error = new Error(
+ 'Minified exception occurred; use the non-minified dev environment ' +
+ 'for the full error message and additional helpful warnings.'
+ );
+ } else {
+ var args = [a, b, c, d, e, f];
+ var argIndex = 0;
+ error = new Error(
+ 'Invariant Violation: ' +
+ format.replace(/%s/g, function() { return args[argIndex++]; })
+ );
+ }
+
+ error.framesToPop = 1; // we don't care about invariant's own frame
+ throw error;
+ }
+};
+
+module.exports = invariant;
+
+}).call(this,require('_process'))
+},{"_process":5}],188:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule isEventSupported
+ */
+
+"use strict";
+
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+
+var useHasFeature;
+if (ExecutionEnvironment.canUseDOM) {
+ useHasFeature =
+ document.implementation &&
+ document.implementation.hasFeature &&
+ // always returns true in newer browsers as per the standard.
+ // @see http://dom.spec.whatwg.org/#dom-domimplementation-hasfeature
+ document.implementation.hasFeature('', '') !== true;
+}
+
+/**
+ * Checks if an event is supported in the current execution environment.
+ *
+ * NOTE: This will not work correctly for non-generic events such as `change`,
+ * `reset`, `load`, `error`, and `select`.
+ *
+ * Borrows from Modernizr.
+ *
+ * @param {string} eventNameSuffix Event name, e.g. "click".
+ * @param {?boolean} capture Check if the capture phase is supported.
+ * @return {boolean} True if the event is supported.
+ * @internal
+ * @license Modernizr 3.0.0pre (Custom Build) | MIT
+ */
+function isEventSupported(eventNameSuffix, capture) {
+ if (!ExecutionEnvironment.canUseDOM ||
+ capture && !('addEventListener' in document)) {
+ return false;
+ }
+
+ var eventName = 'on' + eventNameSuffix;
+ var isSupported = eventName in document;
+
+ if (!isSupported) {
+ var element = document.createElement('div');
+ element.setAttribute(eventName, 'return;');
+ isSupported = typeof element[eventName] === 'function';
+ }
+
+ if (!isSupported && useHasFeature && eventNameSuffix === 'wheel') {
+ // This is the only way to test support for the `wheel` event in IE9+.
+ isSupported = document.implementation.hasFeature('Events.wheel', '3.0');
+ }
+
+ return isSupported;
+}
+
+module.exports = isEventSupported;
+
+},{"./ExecutionEnvironment":69}],189:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule isNode
+ * @typechecks
+ */
+
+/**
+ * @param {*} object The object to check.
+ * @return {boolean} Whether or not the object is a DOM node.
+ */
+function isNode(object) {
+ return !!(object && (
+ typeof Node === 'function' ? object instanceof Node :
+ typeof object === 'object' &&
+ typeof object.nodeType === 'number' &&
+ typeof object.nodeName === 'string'
+ ));
+}
+
+module.exports = isNode;
+
+},{}],190:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule isTextInputElement
+ */
+
+"use strict";
+
+/**
+ * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary
+ */
+var supportedInputTypes = {
+ 'color': true,
+ 'date': true,
+ 'datetime': true,
+ 'datetime-local': true,
+ 'email': true,
+ 'month': true,
+ 'number': true,
+ 'password': true,
+ 'range': true,
+ 'search': true,
+ 'tel': true,
+ 'text': true,
+ 'time': true,
+ 'url': true,
+ 'week': true
+};
+
+function isTextInputElement(elem) {
+ return elem && (
+ (elem.nodeName === 'INPUT' && supportedInputTypes[elem.type]) ||
+ elem.nodeName === 'TEXTAREA'
+ );
+}
+
+module.exports = isTextInputElement;
+
+},{}],191:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule isTextNode
+ * @typechecks
+ */
+
+var isNode = require("./isNode");
+
+/**
+ * @param {*} object The object to check.
+ * @return {boolean} Whether or not the object is a DOM text node.
+ */
+function isTextNode(object) {
+ return isNode(object) && object.nodeType == 3;
+}
+
+module.exports = isTextNode;
+
+},{"./isNode":189}],192:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule joinClasses
+ * @typechecks static-only
+ */
+
+"use strict";
+
+/**
+ * Combines multiple className strings into one.
+ * http://jsperf.com/joinclasses-args-vs-array
+ *
+ * @param {...?string} classes
+ * @return {string}
+ */
+function joinClasses(className/*, ... */) {
+ if (!className) {
+ className = '';
+ }
+ var nextClass;
+ var argLength = arguments.length;
+ if (argLength > 1) {
+ for (var ii = 1; ii < argLength; ii++) {
+ nextClass = arguments[ii];
+ if (nextClass) {
+ className = (className ? className + ' ' : '') + nextClass;
+ }
+ }
+ }
+ return className;
+}
+
+module.exports = joinClasses;
+
+},{}],193:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule keyMirror
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var invariant = require("./invariant");
+
+/**
+ * Constructs an enumeration with keys equal to their value.
+ *
+ * For example:
+ *
+ * var COLORS = keyMirror({blue: null, red: null});
+ * var myColor = COLORS.blue;
+ * var isColorValid = !!COLORS[myColor];
+ *
+ * The last line could not be performed if the values of the generated enum were
+ * not equal to their keys.
+ *
+ * Input: {key1: val1, key2: val2}
+ * Output: {key1: key1, key2: key2}
+ *
+ * @param {object} obj
+ * @return {object}
+ */
+var keyMirror = function(obj) {
+ var ret = {};
+ var key;
+ ("production" !== process.env.NODE_ENV ? invariant(
+ obj instanceof Object && !Array.isArray(obj),
+ 'keyMirror(...): Argument must be an object.'
+ ) : invariant(obj instanceof Object && !Array.isArray(obj)));
+ for (key in obj) {
+ if (!obj.hasOwnProperty(key)) {
+ continue;
+ }
+ ret[key] = key;
+ }
+ return ret;
+};
+
+module.exports = keyMirror;
+
+}).call(this,require('_process'))
+},{"./invariant":187,"_process":5}],194:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule keyOf
+ */
+
+/**
+ * Allows extraction of a minified key. Let's the build system minify keys
+ * without loosing the ability to dynamically use key strings as values
+ * themselves. Pass in an object with a single key/val pair and it will return
+ * you the string key of that single record. Suppose you want to grab the
+ * value for a key 'className' inside of an object. Key/val minification may
+ * have aliased that key to be 'xa12'. keyOf({className: null}) will return
+ * 'xa12' in that case. Resolve keys you want to use once at startup time, then
+ * reuse those resolutions.
+ */
+var keyOf = function(oneKeyObj) {
+ var key;
+ for (key in oneKeyObj) {
+ if (!oneKeyObj.hasOwnProperty(key)) {
+ continue;
+ }
+ return key;
+ }
+ return null;
+};
+
+
+module.exports = keyOf;
+
+},{}],195:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule mapObject
+ */
+
+'use strict';
+
+var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+/**
+ * Executes the provided `callback` once for each enumerable own property in the
+ * object and constructs a new object from the results. The `callback` is
+ * invoked with three arguments:
+ *
+ * - the property value
+ * - the property name
+ * - the object being traversed
+ *
+ * Properties that are added after the call to `mapObject` will not be visited
+ * by `callback`. If the values of existing properties are changed, the value
+ * passed to `callback` will be the value at the time `mapObject` visits them.
+ * Properties that are deleted before being visited are not visited.
+ *
+ * @grep function objectMap()
+ * @grep function objMap()
+ *
+ * @param {?object} object
+ * @param {function} callback
+ * @param {*} context
+ * @return {?object}
+ */
+function mapObject(object, callback, context) {
+ if (!object) {
+ return null;
+ }
+ var result = {};
+ for (var name in object) {
+ if (hasOwnProperty.call(object, name)) {
+ result[name] = callback.call(context, object[name], name, object);
+ }
+ }
+ return result;
+}
+
+module.exports = mapObject;
+
+},{}],196:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule memoizeStringOnly
+ * @typechecks static-only
+ */
+
+"use strict";
+
+/**
+ * Memoizes the return value of a function that accepts one string argument.
+ *
+ * @param {function} callback
+ * @return {function}
+ */
+function memoizeStringOnly(callback) {
+ var cache = {};
+ return function(string) {
+ if (cache.hasOwnProperty(string)) {
+ return cache[string];
+ } else {
+ return cache[string] = callback.call(this, string);
+ }
+ };
+}
+
+module.exports = memoizeStringOnly;
+
+},{}],197:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule monitorCodeUse
+ */
+
+"use strict";
+
+var invariant = require("./invariant");
+
+/**
+ * Provides open-source compatible instrumentation for monitoring certain API
+ * uses before we're ready to issue a warning or refactor. It accepts an event
+ * name which may only contain the characters [a-z0-9_] and an optional data
+ * object with further information.
+ */
+
+function monitorCodeUse(eventName, data) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ eventName && !/[^a-z0-9_]/.test(eventName),
+ 'You must provide an eventName using only the characters [a-z0-9_]'
+ ) : invariant(eventName && !/[^a-z0-9_]/.test(eventName)));
+}
+
+module.exports = monitorCodeUse;
+
+}).call(this,require('_process'))
+},{"./invariant":187,"_process":5}],198:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule onlyChild
+ */
+"use strict";
+
+var ReactElement = require("./ReactElement");
+
+var invariant = require("./invariant");
+
+/**
+ * Returns the first child in a collection of children and verifies that there
+ * is only one child in the collection. The current implementation of this
+ * function assumes that a single child gets passed without a wrapper, but the
+ * purpose of this helper function is to abstract away the particular structure
+ * of children.
+ *
+ * @param {?object} children Child collection structure.
+ * @return {ReactComponent} The first and only `ReactComponent` contained in the
+ * structure.
+ */
+function onlyChild(children) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ ReactElement.isValidElement(children),
+ 'onlyChild must be passed a children with exactly one child.'
+ ) : invariant(ReactElement.isValidElement(children)));
+ return children;
+}
+
+module.exports = onlyChild;
+
+}).call(this,require('_process'))
+},{"./ReactElement":104,"./invariant":187,"_process":5}],199:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule performance
+ * @typechecks
+ */
+
+"use strict";
+
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+
+var performance;
+
+if (ExecutionEnvironment.canUseDOM) {
+ performance =
+ window.performance ||
+ window.msPerformance ||
+ window.webkitPerformance;
+}
+
+module.exports = performance || {};
+
+},{"./ExecutionEnvironment":69}],200:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule performanceNow
+ * @typechecks
+ */
+
+var performance = require("./performance");
+
+/**
+ * Detect if we can use `window.performance.now()` and gracefully fallback to
+ * `Date.now()` if it doesn't exist. We need to support Firefox < 15 for now
+ * because of Facebook's testing infrastructure.
+ */
+if (!performance || !performance.now) {
+ performance = Date;
+}
+
+var performanceNow = performance.now.bind(performance);
+
+module.exports = performanceNow;
+
+},{"./performance":199}],201:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule setInnerHTML
+ */
+
+"use strict";
+
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+
+var WHITESPACE_TEST = /^[ \r\n\t\f]/;
+var NONVISIBLE_TEST = /<(!--|link|noscript|meta|script|style)[ \r\n\t\f\/>]/;
+
+/**
+ * Set the innerHTML property of a node, ensuring that whitespace is preserved
+ * even in IE8.
+ *
+ * @param {DOMElement} node
+ * @param {string} html
+ * @internal
+ */
+var setInnerHTML = function(node, html) {
+ node.innerHTML = html;
+};
+
+if (ExecutionEnvironment.canUseDOM) {
+ // IE8: When updating a just created node with innerHTML only leading
+ // whitespace is removed. When updating an existing node with innerHTML
+ // whitespace in root TextNodes is also collapsed.
+ // @see quirksmode.org/bugreports/archives/2004/11/innerhtml_and_t.html
+
+ // Feature detection; only IE8 is known to behave improperly like this.
+ var testElement = document.createElement('div');
+ testElement.innerHTML = ' ';
+ if (testElement.innerHTML === '') {
+ setInnerHTML = function(node, html) {
+ // Magic theory: IE8 supposedly differentiates between added and updated
+ // nodes when processing innerHTML, innerHTML on updated nodes suffers
+ // from worse whitespace behavior. Re-adding a node like this triggers
+ // the initial and more favorable whitespace behavior.
+ // TODO: What to do on a detached node?
+ if (node.parentNode) {
+ node.parentNode.replaceChild(node, node);
+ }
+
+ // We also implement a workaround for non-visible tags disappearing into
+ // thin air on IE8, this only happens if there is no visible text
+ // in-front of the non-visible tags. Piggyback on the whitespace fix
+ // and simply check if any non-visible tags appear in the source.
+ if (WHITESPACE_TEST.test(html) ||
+ html[0] === '<' && NONVISIBLE_TEST.test(html)) {
+ // Recover leading whitespace by temporarily prepending any character.
+ // \uFEFF has the potential advantage of being zero-width/invisible.
+ node.innerHTML = '\uFEFF' + html;
+
+ // deleteData leaves an empty `TextNode` which offsets the index of all
+ // children. Definitely want to avoid this.
+ var textNode = node.firstChild;
+ if (textNode.data.length === 1) {
+ node.removeChild(textNode);
+ } else {
+ textNode.deleteData(0, 1);
+ }
+ } else {
+ node.innerHTML = html;
+ }
+ };
+ }
+}
+
+module.exports = setInnerHTML;
+
+},{"./ExecutionEnvironment":69}],202:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule shallowEqual
+ */
+
+"use strict";
+
+/**
+ * Performs equality by iterating through keys on an object and returning
+ * false when any key has values which are not strictly equal between
+ * objA and objB. Returns true when the values of all keys are strictly equal.
+ *
+ * @return {boolean}
+ */
+function shallowEqual(objA, objB) {
+ if (objA === objB) {
+ return true;
+ }
+ var key;
+ // Test for A's keys different from B.
+ for (key in objA) {
+ if (objA.hasOwnProperty(key) &&
+ (!objB.hasOwnProperty(key) || objA[key] !== objB[key])) {
+ return false;
+ }
+ }
+ // Test for B's keys missing from A.
+ for (key in objB) {
+ if (objB.hasOwnProperty(key) && !objA.hasOwnProperty(key)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+module.exports = shallowEqual;
+
+},{}],203:[function(require,module,exports){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule shouldUpdateReactComponent
+ * @typechecks static-only
+ */
+
+"use strict";
+
+/**
+ * Given a `prevElement` and `nextElement`, determines if the existing
+ * instance should be updated as opposed to being destroyed or replaced by a new
+ * instance. Both arguments are elements. This ensures that this logic can
+ * operate on stateless trees without any backing instance.
+ *
+ * @param {?object} prevElement
+ * @param {?object} nextElement
+ * @return {boolean} True if the existing instance should be updated.
+ * @protected
+ */
+function shouldUpdateReactComponent(prevElement, nextElement) {
+ if (prevElement && nextElement &&
+ prevElement.type === nextElement.type &&
+ prevElement.key === nextElement.key &&
+ prevElement._owner === nextElement._owner) {
+ return true;
+ }
+ return false;
+}
+
+module.exports = shouldUpdateReactComponent;
+
+},{}],204:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule toArray
+ * @typechecks
+ */
+
+var invariant = require("./invariant");
+
+/**
+ * Convert array-like objects to arrays.
+ *
+ * This API assumes the caller knows the contents of the data type. For less
+ * well defined inputs use createArrayFrom.
+ *
+ * @param {object|function|filelist} obj
+ * @return {array}
+ */
+function toArray(obj) {
+ var length = obj.length;
+
+ // Some browse builtin objects can report typeof 'function' (e.g. NodeList in
+ // old versions of Safari).
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !Array.isArray(obj) &&
+ (typeof obj === 'object' || typeof obj === 'function'),
+ 'toArray: Array-like object expected'
+ ) : invariant(!Array.isArray(obj) &&
+ (typeof obj === 'object' || typeof obj === 'function')));
+
+ ("production" !== process.env.NODE_ENV ? invariant(
+ typeof length === 'number',
+ 'toArray: Object needs a length property'
+ ) : invariant(typeof length === 'number'));
+
+ ("production" !== process.env.NODE_ENV ? invariant(
+ length === 0 ||
+ (length - 1) in obj,
+ 'toArray: Object should have keys for indices'
+ ) : invariant(length === 0 ||
+ (length - 1) in obj));
+
+ // Old IE doesn't give collections access to hasOwnProperty. Assume inputs
+ // without method will throw during the slice call and skip straight to the
+ // fallback.
+ if (obj.hasOwnProperty) {
+ try {
+ return Array.prototype.slice.call(obj);
+ } catch (e) {
+ // IE < 9 does not support Array#slice on collections objects
+ }
+ }
+
+ // Fall back to copying key by key. This assumes all keys have a value,
+ // so will not preserve sparsely populated inputs.
+ var ret = Array(length);
+ for (var ii = 0; ii < length; ii++) {
+ ret[ii] = obj[ii];
+ }
+ return ret;
+}
+
+module.exports = toArray;
+
+}).call(this,require('_process'))
+},{"./invariant":187,"_process":5}],205:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule traverseAllChildren
+ */
+
+"use strict";
+
+var ReactElement = require("./ReactElement");
+var ReactInstanceHandles = require("./ReactInstanceHandles");
+
+var invariant = require("./invariant");
+
+var SEPARATOR = ReactInstanceHandles.SEPARATOR;
+var SUBSEPARATOR = ':';
+
+/**
+ * TODO: Test that:
+ * 1. `mapChildren` transforms strings and numbers into `ReactTextComponent`.
+ * 2. it('should fail when supplied duplicate key', function() {
+ * 3. That a single child and an array with one item have the same key pattern.
+ * });
+ */
+
+var userProvidedKeyEscaperLookup = {
+ '=': '=0',
+ '.': '=1',
+ ':': '=2'
+};
+
+var userProvidedKeyEscapeRegex = /[=.:]/g;
+
+function userProvidedKeyEscaper(match) {
+ return userProvidedKeyEscaperLookup[match];
+}
+
+/**
+ * Generate a key string that identifies a component within a set.
+ *
+ * @param {*} component A component that could contain a manual key.
+ * @param {number} index Index that is used if a manual key is not provided.
+ * @return {string}
+ */
+function getComponentKey(component, index) {
+ if (component && component.key != null) {
+ // Explicit key
+ return wrapUserProvidedKey(component.key);
+ }
+ // Implicit key determined by the index in the set
+ return index.toString(36);
+}
+
+/**
+ * Escape a component key so that it is safe to use in a reactid.
+ *
+ * @param {*} key Component key to be escaped.
+ * @return {string} An escaped string.
+ */
+function escapeUserProvidedKey(text) {
+ return ('' + text).replace(
+ userProvidedKeyEscapeRegex,
+ userProvidedKeyEscaper
+ );
+}
+
+/**
+ * Wrap a `key` value explicitly provided by the user to distinguish it from
+ * implicitly-generated keys generated by a component's index in its parent.
+ *
+ * @param {string} key Value of a user-provided `key` attribute
+ * @return {string}
+ */
+function wrapUserProvidedKey(key) {
+ return '$' + escapeUserProvidedKey(key);
+}
+
+/**
+ * @param {?*} children Children tree container.
+ * @param {!string} nameSoFar Name of the key path so far.
+ * @param {!number} indexSoFar Number of children encountered until this point.
+ * @param {!function} callback Callback to invoke with each child found.
+ * @param {?*} traverseContext Used to pass information throughout the traversal
+ * process.
+ * @return {!number} The number of children in this subtree.
+ */
+var traverseAllChildrenImpl =
+ function(children, nameSoFar, indexSoFar, callback, traverseContext) {
+ var nextName, nextIndex;
+ var subtreeCount = 0; // Count of children found in the current subtree.
+ if (Array.isArray(children)) {
+ for (var i = 0; i < children.length; i++) {
+ var child = children[i];
+ nextName = (
+ nameSoFar +
+ (nameSoFar ? SUBSEPARATOR : SEPARATOR) +
+ getComponentKey(child, i)
+ );
+ nextIndex = indexSoFar + subtreeCount;
+ subtreeCount += traverseAllChildrenImpl(
+ child,
+ nextName,
+ nextIndex,
+ callback,
+ traverseContext
+ );
+ }
+ } else {
+ var type = typeof children;
+ var isOnlyChild = nameSoFar === '';
+ // If it's the only child, treat the name as if it was wrapped in an array
+ // so that it's consistent if the number of children grows
+ var storageName =
+ isOnlyChild ? SEPARATOR + getComponentKey(children, 0) : nameSoFar;
+ if (children == null || type === 'boolean') {
+ // All of the above are perceived as null.
+ callback(traverseContext, null, storageName, indexSoFar);
+ subtreeCount = 1;
+ } else if (type === 'string' || type === 'number' ||
+ ReactElement.isValidElement(children)) {
+ callback(traverseContext, children, storageName, indexSoFar);
+ subtreeCount = 1;
+ } else if (type === 'object') {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ !children || children.nodeType !== 1,
+ 'traverseAllChildren(...): Encountered an invalid child; DOM ' +
+ 'elements are not valid children of React components.'
+ ) : invariant(!children || children.nodeType !== 1));
+ for (var key in children) {
+ if (children.hasOwnProperty(key)) {
+ nextName = (
+ nameSoFar + (nameSoFar ? SUBSEPARATOR : SEPARATOR) +
+ wrapUserProvidedKey(key) + SUBSEPARATOR +
+ getComponentKey(children[key], 0)
+ );
+ nextIndex = indexSoFar + subtreeCount;
+ subtreeCount += traverseAllChildrenImpl(
+ children[key],
+ nextName,
+ nextIndex,
+ callback,
+ traverseContext
+ );
+ }
+ }
+ }
+ }
+ return subtreeCount;
+ };
+
+/**
+ * Traverses children that are typically specified as `props.children`, but
+ * might also be specified through attributes:
+ *
+ * - `traverseAllChildren(this.props.children, ...)`
+ * - `traverseAllChildren(this.props.leftPanelChildren, ...)`
+ *
+ * The `traverseContext` is an optional argument that is passed through the
+ * entire traversal. It can be used to store accumulations or anything else that
+ * the callback might find relevant.
+ *
+ * @param {?*} children Children tree object.
+ * @param {!function} callback To invoke upon traversing each child.
+ * @param {?*} traverseContext Context for traversal.
+ * @return {!number} The number of children in this subtree.
+ */
+function traverseAllChildren(children, callback, traverseContext) {
+ if (children == null) {
+ return 0;
+ }
+
+ return traverseAllChildrenImpl(children, '', 0, callback, traverseContext);
+}
+
+module.exports = traverseAllChildren;
+
+}).call(this,require('_process'))
+},{"./ReactElement":104,"./ReactInstanceHandles":112,"./invariant":187,"_process":5}],206:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule update
+ */
+
+"use strict";
+
+var assign = require("./Object.assign");
+var keyOf = require("./keyOf");
+var invariant = require("./invariant");
+
+function shallowCopy(x) {
+ if (Array.isArray(x)) {
+ return x.concat();
+ } else if (x && typeof x === 'object') {
+ return assign(new x.constructor(), x);
+ } else {
+ return x;
+ }
+}
+
+var COMMAND_PUSH = keyOf({$push: null});
+var COMMAND_UNSHIFT = keyOf({$unshift: null});
+var COMMAND_SPLICE = keyOf({$splice: null});
+var COMMAND_SET = keyOf({$set: null});
+var COMMAND_MERGE = keyOf({$merge: null});
+var COMMAND_APPLY = keyOf({$apply: null});
+
+var ALL_COMMANDS_LIST = [
+ COMMAND_PUSH,
+ COMMAND_UNSHIFT,
+ COMMAND_SPLICE,
+ COMMAND_SET,
+ COMMAND_MERGE,
+ COMMAND_APPLY
+];
+
+var ALL_COMMANDS_SET = {};
+
+ALL_COMMANDS_LIST.forEach(function(command) {
+ ALL_COMMANDS_SET[command] = true;
+});
+
+function invariantArrayCase(value, spec, command) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ Array.isArray(value),
+ 'update(): expected target of %s to be an array; got %s.',
+ command,
+ value
+ ) : invariant(Array.isArray(value)));
+ var specValue = spec[command];
+ ("production" !== process.env.NODE_ENV ? invariant(
+ Array.isArray(specValue),
+ 'update(): expected spec of %s to be an array; got %s. ' +
+ 'Did you forget to wrap your parameter in an array?',
+ command,
+ specValue
+ ) : invariant(Array.isArray(specValue)));
+}
+
+function update(value, spec) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ typeof spec === 'object',
+ 'update(): You provided a key path to update() that did not contain one ' +
+ 'of %s. Did you forget to include {%s: ...}?',
+ ALL_COMMANDS_LIST.join(', '),
+ COMMAND_SET
+ ) : invariant(typeof spec === 'object'));
+
+ if (spec.hasOwnProperty(COMMAND_SET)) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ Object.keys(spec).length === 1,
+ 'Cannot have more than one key in an object with %s',
+ COMMAND_SET
+ ) : invariant(Object.keys(spec).length === 1));
+
+ return spec[COMMAND_SET];
+ }
+
+ var nextValue = shallowCopy(value);
+
+ if (spec.hasOwnProperty(COMMAND_MERGE)) {
+ var mergeObj = spec[COMMAND_MERGE];
+ ("production" !== process.env.NODE_ENV ? invariant(
+ mergeObj && typeof mergeObj === 'object',
+ 'update(): %s expects a spec of type \'object\'; got %s',
+ COMMAND_MERGE,
+ mergeObj
+ ) : invariant(mergeObj && typeof mergeObj === 'object'));
+ ("production" !== process.env.NODE_ENV ? invariant(
+ nextValue && typeof nextValue === 'object',
+ 'update(): %s expects a target of type \'object\'; got %s',
+ COMMAND_MERGE,
+ nextValue
+ ) : invariant(nextValue && typeof nextValue === 'object'));
+ assign(nextValue, spec[COMMAND_MERGE]);
+ }
+
+ if (spec.hasOwnProperty(COMMAND_PUSH)) {
+ invariantArrayCase(value, spec, COMMAND_PUSH);
+ spec[COMMAND_PUSH].forEach(function(item) {
+ nextValue.push(item);
+ });
+ }
+
+ if (spec.hasOwnProperty(COMMAND_UNSHIFT)) {
+ invariantArrayCase(value, spec, COMMAND_UNSHIFT);
+ spec[COMMAND_UNSHIFT].forEach(function(item) {
+ nextValue.unshift(item);
+ });
+ }
+
+ if (spec.hasOwnProperty(COMMAND_SPLICE)) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ Array.isArray(value),
+ 'Expected %s target to be an array; got %s',
+ COMMAND_SPLICE,
+ value
+ ) : invariant(Array.isArray(value)));
+ ("production" !== process.env.NODE_ENV ? invariant(
+ Array.isArray(spec[COMMAND_SPLICE]),
+ 'update(): expected spec of %s to be an array of arrays; got %s. ' +
+ 'Did you forget to wrap your parameters in an array?',
+ COMMAND_SPLICE,
+ spec[COMMAND_SPLICE]
+ ) : invariant(Array.isArray(spec[COMMAND_SPLICE])));
+ spec[COMMAND_SPLICE].forEach(function(args) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ Array.isArray(args),
+ 'update(): expected spec of %s to be an array of arrays; got %s. ' +
+ 'Did you forget to wrap your parameters in an array?',
+ COMMAND_SPLICE,
+ spec[COMMAND_SPLICE]
+ ) : invariant(Array.isArray(args)));
+ nextValue.splice.apply(nextValue, args);
+ });
+ }
+
+ if (spec.hasOwnProperty(COMMAND_APPLY)) {
+ ("production" !== process.env.NODE_ENV ? invariant(
+ typeof spec[COMMAND_APPLY] === 'function',
+ 'update(): expected spec of %s to be a function; got %s.',
+ COMMAND_APPLY,
+ spec[COMMAND_APPLY]
+ ) : invariant(typeof spec[COMMAND_APPLY] === 'function'));
+ nextValue = spec[COMMAND_APPLY](nextValue);
+ }
+
+ for (var k in spec) {
+ if (!(ALL_COMMANDS_SET.hasOwnProperty(k) && ALL_COMMANDS_SET[k])) {
+ nextValue[k] = update(value[k], spec[k]);
+ }
+ }
+
+ return nextValue;
+}
+
+module.exports = update;
+
+}).call(this,require('_process'))
+},{"./Object.assign":75,"./invariant":187,"./keyOf":194,"_process":5}],207:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule warning
+ */
+
+"use strict";
+
+var emptyFunction = require("./emptyFunction");
+
+/**
+ * Similar to invariant but only logs a warning if the condition is not met.
+ * This can be used to log issues in development environments in critical
+ * paths. Removing the logging code for production environments will keep the
+ * same logic and follow the same code paths.
+ */
+
+var warning = emptyFunction;
+
+if ("production" !== process.env.NODE_ENV) {
+ warning = function(condition, format ) {for (var args=[],$__0=2,$__1=arguments.length;$__0<$__1;$__0++) args.push(arguments[$__0]);
+ if (format === undefined) {
+ throw new Error(
+ '`warning(condition, format, ...args)` requires a warning ' +
+ 'message argument'
+ );
+ }
+
+ if (!condition) {
+ var argIndex = 0;
+ console.warn('Warning: ' + format.replace(/%s/g, function() {return args[argIndex++];}));
+ }
+ };
+}
+
+module.exports = warning;
+
+}).call(this,require('_process'))
+},{"./emptyFunction":168,"_process":5}],"jquery":[function(require,module,exports){
+/*!
+ * jQuery JavaScript Library v2.1.3
+ * http://jquery.com/
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ *
+ * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2014-12-18T15:11Z
+ */
+
+(function( global, factory ) {
+
+ if ( typeof module === "object" && typeof module.exports === "object" ) {
+ // For CommonJS and CommonJS-like environments where a proper `window`
+ // is present, execute the factory and get jQuery.
+ // For environments that do not have a `window` with a `document`
+ // (such as Node.js), expose a factory as module.exports.
+ // This accentuates the need for the creation of a real `window`.
+ // e.g. var jQuery = require("jquery")(window);
+ // See ticket #14549 for more info.
+ module.exports = global.document ?
+ factory( global, true ) :
+ function( w ) {
+ if ( !w.document ) {
+ throw new Error( "jQuery requires a window with a document" );
+ }
+ return factory( w );
+ };
+ } else {
+ factory( global );
+ }
+
+// Pass this if window is not defined yet
+}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
+
+// Support: Firefox 18+
+// Can't be in strict mode, several libs including ASP.NET trace
+// the stack via arguments.caller.callee and Firefox dies if
+// you try to trace through "use strict" call chains. (#13335)
+//
+
+var arr = [];
+
+var slice = arr.slice;
+
+var concat = arr.concat;
+
+var push = arr.push;
+
+var indexOf = arr.indexOf;
+
+var class2type = {};
+
+var toString = class2type.toString;
+
+var hasOwn = class2type.hasOwnProperty;
+
+var support = {};
+
+
+
+var
+ // Use the correct document accordingly with window argument (sandbox)
+ document = window.document,
+
+ version = "2.1.3",
+
+ // Define a local copy of jQuery
+ jQuery = function( selector, context ) {
+ // The jQuery object is actually just the init constructor 'enhanced'
+ // Need init if jQuery is called (just allow error to be thrown if not included)
+ return new jQuery.fn.init( selector, context );
+ },
+
+ // Support: Android<4.1
+ // Make sure we trim BOM and NBSP
+ rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
+
+ // Matches dashed string for camelizing
+ rmsPrefix = /^-ms-/,
+ rdashAlpha = /-([\da-z])/gi,
+
+ // Used by jQuery.camelCase as callback to replace()
+ fcamelCase = function( all, letter ) {
+ return letter.toUpperCase();
+ };
+
+jQuery.fn = jQuery.prototype = {
+ // The current version of jQuery being used
+ jquery: version,
+
+ constructor: jQuery,
+
+ // Start with an empty selector
+ selector: "",
+
+ // The default length of a jQuery object is 0
+ length: 0,
+
+ toArray: function() {
+ return slice.call( this );
+ },
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+ return num != null ?
+
+ // Return just the one element from the set
+ ( num < 0 ? this[ num + this.length ] : this[ num ] ) :
+
+ // Return all the elements in a clean array
+ slice.call( this );
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems ) {
+
+ // Build a new jQuery matched element set
+ var ret = jQuery.merge( this.constructor(), elems );
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+ ret.context = this.context;
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Execute a callback for every element in the matched set.
+ // (You can seed the arguments with an array of args, but this is
+ // only used internally.)
+ each: function( callback, args ) {
+ return jQuery.each( this, callback, args );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map(this, function( elem, i ) {
+ return callback.call( elem, i, elem );
+ }));
+ },
+
+ slice: function() {
+ return this.pushStack( slice.apply( this, arguments ) );
+ },
+
+ first: function() {
+ return this.eq( 0 );
+ },
+
+ last: function() {
+ return this.eq( -1 );
+ },
+
+ eq: function( i ) {
+ var len = this.length,
+ j = +i + ( i < 0 ? len : 0 );
+ return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
+ },
+
+ end: function() {
+ return this.prevObject || this.constructor(null);
+ },
+
+ // For internal use only.
+ // Behaves like an Array's method, not like a jQuery method.
+ push: push,
+ sort: arr.sort,
+ splice: arr.splice
+};
+
+jQuery.extend = jQuery.fn.extend = function() {
+ var options, name, src, copy, copyIsArray, clone,
+ target = arguments[0] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+
+ // Skip the boolean and the target
+ target = arguments[ i ] || {};
+ i++;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+ target = {};
+ }
+
+ // Extend jQuery itself if only one argument is passed
+ if ( i === length ) {
+ target = this;
+ i--;
+ }
+
+ for ( ; i < length; i++ ) {
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null ) {
+ // Extend the base object
+ for ( name in options ) {
+ src = target[ name ];
+ copy = options[ name ];
+
+ // Prevent never-ending loop
+ if ( target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging plain objects or arrays
+ if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+ if ( copyIsArray ) {
+ copyIsArray = false;
+ clone = src && jQuery.isArray(src) ? src : [];
+
+ } else {
+ clone = src && jQuery.isPlainObject(src) ? src : {};
+ }
+
+ // Never move original objects, clone them
+ target[ name ] = jQuery.extend( deep, clone, copy );
+
+ // Don't bring in undefined values
+ } else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+jQuery.extend({
+ // Unique for each copy of jQuery on the page
+ expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
+
+ // Assume jQuery is ready without the ready module
+ isReady: true,
+
+ error: function( msg ) {
+ throw new Error( msg );
+ },
+
+ noop: function() {},
+
+ isFunction: function( obj ) {
+ return jQuery.type(obj) === "function";
+ },
+
+ isArray: Array.isArray,
+
+ isWindow: function( obj ) {
+ return obj != null && obj === obj.window;
+ },
+
+ isNumeric: function( obj ) {
+ // parseFloat NaNs numeric-cast false positives (null|true|false|"")
+ // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
+ // subtraction forces infinities to NaN
+ // adding 1 corrects loss of precision from parseFloat (#15100)
+ return !jQuery.isArray( obj ) && (obj - parseFloat( obj ) + 1) >= 0;
+ },
+
+ isPlainObject: function( obj ) {
+ // Not plain objects:
+ // - Any object or value whose internal [[Class]] property is not "[object Object]"
+ // - DOM nodes
+ // - window
+ if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ if ( obj.constructor &&
+ !hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
+ return false;
+ }
+
+ // If the function hasn't returned already, we're confident that
+ // |obj| is a plain object, created by {} or constructed with new Object
+ return true;
+ },
+
+ isEmptyObject: function( obj ) {
+ var name;
+ for ( name in obj ) {
+ return false;
+ }
+ return true;
+ },
+
+ type: function( obj ) {
+ if ( obj == null ) {
+ return obj + "";
+ }
+ // Support: Android<4.0, iOS<6 (functionish RegExp)
+ return typeof obj === "object" || typeof obj === "function" ?
+ class2type[ toString.call(obj) ] || "object" :
+ typeof obj;
+ },
+
+ // Evaluates a script in a global context
+ globalEval: function( code ) {
+ var script,
+ indirect = eval;
+
+ code = jQuery.trim( code );
+
+ if ( code ) {
+ // If the code includes a valid, prologue position
+ // strict mode pragma, execute code by injecting a
+ // script tag into the document.
+ if ( code.indexOf("use strict") === 1 ) {
+ script = document.createElement("script");
+ script.text = code;
+ document.head.appendChild( script ).parentNode.removeChild( script );
+ } else {
+ // Otherwise, avoid the DOM node creation, insertion
+ // and removal by using an indirect global eval
+ indirect( code );
+ }
+ }
+ },
+
+ // Convert dashed to camelCase; used by the css and data modules
+ // Support: IE9-11+
+ // Microsoft forgot to hump their vendor prefix (#9572)
+ camelCase: function( string ) {
+ return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+ },
+
+ nodeName: function( elem, name ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+ },
+
+ // args is for internal usage only
+ each: function( obj, callback, args ) {
+ var value,
+ i = 0,
+ length = obj.length,
+ isArray = isArraylike( obj );
+
+ if ( args ) {
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback.apply( obj[ i ], args );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ value = callback.apply( obj[ i ], args );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ }
+
+ // A special, fast, case for the most common use of each
+ } else {
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback.call( obj[ i ], i, obj[ i ] );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ value = callback.call( obj[ i ], i, obj[ i ] );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ }
+ }
+
+ return obj;
+ },
+
+ // Support: Android<4.1
+ trim: function( text ) {
+ return text == null ?
+ "" :
+ ( text + "" ).replace( rtrim, "" );
+ },
+
+ // results is for internal usage only
+ makeArray: function( arr, results ) {
+ var ret = results || [];
+
+ if ( arr != null ) {
+ if ( isArraylike( Object(arr) ) ) {
+ jQuery.merge( ret,
+ typeof arr === "string" ?
+ [ arr ] : arr
+ );
+ } else {
+ push.call( ret, arr );
+ }
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, arr, i ) {
+ return arr == null ? -1 : indexOf.call( arr, elem, i );
+ },
+
+ merge: function( first, second ) {
+ var len = +second.length,
+ j = 0,
+ i = first.length;
+
+ for ( ; j < len; j++ ) {
+ first[ i++ ] = second[ j ];
+ }
+
+ first.length = i;
+
+ return first;
+ },
+
+ grep: function( elems, callback, invert ) {
+ var callbackInverse,
+ matches = [],
+ i = 0,
+ length = elems.length,
+ callbackExpect = !invert;
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( ; i < length; i++ ) {
+ callbackInverse = !callback( elems[ i ], i );
+ if ( callbackInverse !== callbackExpect ) {
+ matches.push( elems[ i ] );
+ }
+ }
+
+ return matches;
+ },
+
+ // arg is for internal usage only
+ map: function( elems, callback, arg ) {
+ var value,
+ i = 0,
+ length = elems.length,
+ isArray = isArraylike( elems ),
+ ret = [];
+
+ // Go through the array, translating each of the items to their new values
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret.push( value );
+ }
+ }
+
+ // Go through every key on the object,
+ } else {
+ for ( i in elems ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret.push( value );
+ }
+ }
+ }
+
+ // Flatten any nested arrays
+ return concat.apply( [], ret );
+ },
+
+ // A global GUID counter for objects
+ guid: 1,
+
+ // Bind a function to a context, optionally partially applying any
+ // arguments.
+ proxy: function( fn, context ) {
+ var tmp, args, proxy;
+
+ if ( typeof context === "string" ) {
+ tmp = fn[ context ];
+ context = fn;
+ fn = tmp;
+ }
+
+ // Quick check to determine if target is callable, in the spec
+ // this throws a TypeError, but we will just return undefined.
+ if ( !jQuery.isFunction( fn ) ) {
+ return undefined;
+ }
+
+ // Simulated bind
+ args = slice.call( arguments, 2 );
+ proxy = function() {
+ return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
+ };
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+ return proxy;
+ },
+
+ now: Date.now,
+
+ // jQuery.support is not used in Core but other projects attach their
+ // properties to it so it needs to exist.
+ support: support
+});
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+function isArraylike( obj ) {
+ var length = obj.length,
+ type = jQuery.type( obj );
+
+ if ( type === "function" || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ if ( obj.nodeType === 1 && length ) {
+ return true;
+ }
+
+ return type === "array" || length === 0 ||
+ typeof length === "number" && length > 0 && ( length - 1 ) in obj;
+}
+var Sizzle =
+/*!
+ * Sizzle CSS Selector Engine v2.2.0-pre
+ * http://sizzlejs.com/
+ *
+ * Copyright 2008, 2014 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2014-12-16
+ */
+(function( window ) {
+
+var i,
+ support,
+ Expr,
+ getText,
+ isXML,
+ tokenize,
+ compile,
+ select,
+ outermostContext,
+ sortInput,
+ hasDuplicate,
+
+ // Local document vars
+ setDocument,
+ document,
+ docElem,
+ documentIsHTML,
+ rbuggyQSA,
+ rbuggyMatches,
+ matches,
+ contains,
+
+ // Instance-specific data
+ expando = "sizzle" + 1 * new Date(),
+ preferredDoc = window.document,
+ dirruns = 0,
+ done = 0,
+ classCache = createCache(),
+ tokenCache = createCache(),
+ compilerCache = createCache(),
+ sortOrder = function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ }
+ return 0;
+ },
+
+ // General-purpose constants
+ MAX_NEGATIVE = 1 << 31,
+
+ // Instance methods
+ hasOwn = ({}).hasOwnProperty,
+ arr = [],
+ pop = arr.pop,
+ push_native = arr.push,
+ push = arr.push,
+ slice = arr.slice,
+ // Use a stripped-down indexOf as it's faster than native
+ // http://jsperf.com/thor-indexof-vs-for/5
+ indexOf = function( list, elem ) {
+ var i = 0,
+ len = list.length;
+ for ( ; i < len; i++ ) {
+ if ( list[i] === elem ) {
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
+
+ // Regular expressions
+
+ // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
+ whitespace = "[\\x20\\t\\r\\n\\f]",
+ // http://www.w3.org/TR/css3-syntax/#characters
+ characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
+
+ // Loosely modeled on CSS identifier characters
+ // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
+ // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+ identifier = characterEncoding.replace( "w", "w#" ),
+
+ // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
+ attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace +
+ // Operator (capture 2)
+ "*([*^$|!~]?=)" + whitespace +
+ // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
+ "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
+ "*\\]",
+
+ pseudos = ":(" + characterEncoding + ")(?:\\((" +
+ // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
+ // 1. quoted (capture 3; capture 4 or capture 5)
+ "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
+ // 2. simple (capture 6)
+ "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
+ // 3. anything else (capture 2)
+ ".*" +
+ ")\\)|)",
+
+ // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+ rwhitespace = new RegExp( whitespace + "+", "g" ),
+ rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
+
+ rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+ rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
+
+ rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
+
+ rpseudo = new RegExp( pseudos ),
+ ridentifier = new RegExp( "^" + identifier + "$" ),
+
+ matchExpr = {
+ "ID": new RegExp( "^#(" + characterEncoding + ")" ),
+ "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
+ "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
+ "ATTR": new RegExp( "^" + attributes ),
+ "PSEUDO": new RegExp( "^" + pseudos ),
+ "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
+ "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
+ "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+ "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
+ // For use in libraries implementing .is()
+ // We use this for POS matching in `select`
+ "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
+ whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
+ },
+
+ rinputs = /^(?:input|select|textarea|button)$/i,
+ rheader = /^h\d$/i,
+
+ rnative = /^[^{]+\{\s*\[native \w/,
+
+ // Easily-parseable/retrievable ID or TAG or CLASS selectors
+ rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
+
+ rsibling = /[+~]/,
+ rescape = /'|\\/g,
+
+ // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
+ runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
+ funescape = function( _, escaped, escapedWhitespace ) {
+ var high = "0x" + escaped - 0x10000;
+ // NaN means non-codepoint
+ // Support: Firefox<24
+ // Workaround erroneous numeric interpretation of +"0x"
+ return high !== high || escapedWhitespace ?
+ escaped :
+ high < 0 ?
+ // BMP codepoint
+ String.fromCharCode( high + 0x10000 ) :
+ // Supplemental Plane codepoint (surrogate pair)
+ String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
+ },
+
+ // Used for iframes
+ // See setDocument()
+ // Removing the function wrapper causes a "Permission Denied"
+ // error in IE
+ unloadHandler = function() {
+ setDocument();
+ };
+
+// Optimize for push.apply( _, NodeList )
+try {
+ push.apply(
+ (arr = slice.call( preferredDoc.childNodes )),
+ preferredDoc.childNodes
+ );
+ // Support: Android<4.0
+ // Detect silently failing push.apply
+ arr[ preferredDoc.childNodes.length ].nodeType;
+} catch ( e ) {
+ push = { apply: arr.length ?
+
+ // Leverage slice if possible
+ function( target, els ) {
+ push_native.apply( target, slice.call(els) );
+ } :
+
+ // Support: IE<9
+ // Otherwise append directly
+ function( target, els ) {
+ var j = target.length,
+ i = 0;
+ // Can't trust NodeList.length
+ while ( (target[j++] = els[i++]) ) {}
+ target.length = j - 1;
+ }
+ };
+}
+
+function Sizzle( selector, context, results, seed ) {
+ var match, elem, m, nodeType,
+ // QSA vars
+ i, groups, old, nid, newContext, newSelector;
+
+ if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
+ setDocument( context );
+ }
+
+ context = context || document;
+ results = results || [];
+ nodeType = context.nodeType;
+
+ if ( typeof selector !== "string" || !selector ||
+ nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
+
+ return results;
+ }
+
+ if ( !seed && documentIsHTML ) {
+
+ // Try to shortcut find operations when possible (e.g., not under DocumentFragment)
+ if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {
+ // Speed-up: Sizzle("#ID")
+ if ( (m = match[1]) ) {
+ if ( nodeType === 9 ) {
+ elem = context.getElementById( m );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document (jQuery #6963)
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE, Opera, and Webkit return items
+ // by name instead of ID
+ if ( elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ } else {
+ return results;
+ }
+ } else {
+ // Context is not a document
+ if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
+ contains( context, elem ) && elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ }
+
+ // Speed-up: Sizzle("TAG")
+ } else if ( match[2] ) {
+ push.apply( results, context.getElementsByTagName( selector ) );
+ return results;
+
+ // Speed-up: Sizzle(".CLASS")
+ } else if ( (m = match[3]) && support.getElementsByClassName ) {
+ push.apply( results, context.getElementsByClassName( m ) );
+ return results;
+ }
+ }
+
+ // QSA path
+ if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
+ nid = old = expando;
+ newContext = context;
+ newSelector = nodeType !== 1 && selector;
+
+ // qSA works strangely on Element-rooted queries
+ // We can work around this by specifying an extra ID on the root
+ // and working up from there (Thanks to Andrew Dupont for the technique)
+ // IE 8 doesn't work on object elements
+ if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+ groups = tokenize( selector );
+
+ if ( (old = context.getAttribute("id")) ) {
+ nid = old.replace( rescape, "\\$&" );
+ } else {
+ context.setAttribute( "id", nid );
+ }
+ nid = "[id='" + nid + "'] ";
+
+ i = groups.length;
+ while ( i-- ) {
+ groups[i] = nid + toSelector( groups[i] );
+ }
+ newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
+ newSelector = groups.join(",");
+ }
+
+ if ( newSelector ) {
+ try {
+ push.apply( results,
+ newContext.querySelectorAll( newSelector )
+ );
+ return results;
+ } catch(qsaError) {
+ } finally {
+ if ( !old ) {
+ context.removeAttribute("id");
+ }
+ }
+ }
+ }
+ }
+
+ // All others
+ return select( selector.replace( rtrim, "$1" ), context, results, seed );
+}
+
+/**
+ * Create key-value caches of limited size
+ * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
+ * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
+ * deleting the oldest entry
+ */
+function createCache() {
+ var keys = [];
+
+ function cache( key, value ) {
+ // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
+ if ( keys.push( key + " " ) > Expr.cacheLength ) {
+ // Only keep the most recent entries
+ delete cache[ keys.shift() ];
+ }
+ return (cache[ key + " " ] = value);
+ }
+ return cache;
+}
+
+/**
+ * Mark a function for special use by Sizzle
+ * @param {Function} fn The function to mark
+ */
+function markFunction( fn ) {
+ fn[ expando ] = true;
+ return fn;
+}
+
+/**
+ * Support testing using an element
+ * @param {Function} fn Passed the created div and expects a boolean result
+ */
+function assert( fn ) {
+ var div = document.createElement("div");
+
+ try {
+ return !!fn( div );
+ } catch (e) {
+ return false;
+ } finally {
+ // Remove from its parent by default
+ if ( div.parentNode ) {
+ div.parentNode.removeChild( div );
+ }
+ // release memory in IE
+ div = null;
+ }
+}
+
+/**
+ * Adds the same handler for all of the specified attrs
+ * @param {String} attrs Pipe-separated list of attributes
+ * @param {Function} handler The method that will be applied
+ */
+function addHandle( attrs, handler ) {
+ var arr = attrs.split("|"),
+ i = attrs.length;
+
+ while ( i-- ) {
+ Expr.attrHandle[ arr[i] ] = handler;
+ }
+}
+
+/**
+ * Checks document order of two siblings
+ * @param {Element} a
+ * @param {Element} b
+ * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
+ */
+function siblingCheck( a, b ) {
+ var cur = b && a,
+ diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
+ ( ~b.sourceIndex || MAX_NEGATIVE ) -
+ ( ~a.sourceIndex || MAX_NEGATIVE );
+
+ // Use IE sourceIndex if available on both nodes
+ if ( diff ) {
+ return diff;
+ }
+
+ // Check if b follows a
+ if ( cur ) {
+ while ( (cur = cur.nextSibling) ) {
+ if ( cur === b ) {
+ return -1;
+ }
+ }
+ }
+
+ return a ? 1 : -1;
+}
+
+/**
+ * Returns a function to use in pseudos for input types
+ * @param {String} type
+ */
+function createInputPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for buttons
+ * @param {String} type
+ */
+function createButtonPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for positionals
+ * @param {Function} fn
+ */
+function createPositionalPseudo( fn ) {
+ return markFunction(function( argument ) {
+ argument = +argument;
+ return markFunction(function( seed, matches ) {
+ var j,
+ matchIndexes = fn( [], seed.length, argument ),
+ i = matchIndexes.length;
+
+ // Match elements found at the specified indexes
+ while ( i-- ) {
+ if ( seed[ (j = matchIndexes[i]) ] ) {
+ seed[j] = !(matches[j] = seed[j]);
+ }
+ }
+ });
+ });
+}
+
+/**
+ * Checks a node for validity as a Sizzle context
+ * @param {Element|Object=} context
+ * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
+ */
+function testContext( context ) {
+ return context && typeof context.getElementsByTagName !== "undefined" && context;
+}
+
+// Expose support vars for convenience
+support = Sizzle.support = {};
+
+/**
+ * Detects XML nodes
+ * @param {Element|Object} elem An element or a document
+ * @returns {Boolean} True iff elem is a non-HTML XML node
+ */
+isXML = Sizzle.isXML = function( elem ) {
+ // documentElement is verified for cases where it doesn't yet exist
+ // (such as loading iframes in IE - #4833)
+ var documentElement = elem && (elem.ownerDocument || elem).documentElement;
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+/**
+ * Sets document-related variables once based on the current document
+ * @param {Element|Object} [doc] An element or document object to use to set the document
+ * @returns {Object} Returns the current document
+ */
+setDocument = Sizzle.setDocument = function( node ) {
+ var hasCompare, parent,
+ doc = node ? node.ownerDocument || node : preferredDoc;
+
+ // If no document and documentElement is available, return
+ if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
+ return document;
+ }
+
+ // Set our document
+ document = doc;
+ docElem = doc.documentElement;
+ parent = doc.defaultView;
+
+ // Support: IE>8
+ // If iframe document is assigned to "document" variable and if iframe has been reloaded,
+ // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
+ // IE6-8 do not support the defaultView property so parent will be undefined
+ if ( parent && parent !== parent.top ) {
+ // IE11 does not have attachEvent, so all must suffer
+ if ( parent.addEventListener ) {
+ parent.addEventListener( "unload", unloadHandler, false );
+ } else if ( parent.attachEvent ) {
+ parent.attachEvent( "onunload", unloadHandler );
+ }
+ }
+
+ /* Support tests
+ ---------------------------------------------------------------------- */
+ documentIsHTML = !isXML( doc );
+
+ /* Attributes
+ ---------------------------------------------------------------------- */
+
+ // Support: IE<8
+ // Verify that getAttribute really returns attributes and not properties
+ // (excepting IE8 booleans)
+ support.attributes = assert(function( div ) {
+ div.className = "i";
+ return !div.getAttribute("className");
+ });
+
+ /* getElement(s)By*
+ ---------------------------------------------------------------------- */
+
+ // Check if getElementsByTagName("*") returns only elements
+ support.getElementsByTagName = assert(function( div ) {
+ div.appendChild( doc.createComment("") );
+ return !div.getElementsByTagName("*").length;
+ });
+
+ // Support: IE<9
+ support.getElementsByClassName = rnative.test( doc.getElementsByClassName );
+
+ // Support: IE<10
+ // Check if getElementById returns elements by name
+ // The broken getElementById methods don't pick up programatically-set names,
+ // so use a roundabout getElementsByName test
+ support.getById = assert(function( div ) {
+ docElem.appendChild( div ).id = expando;
+ return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
+ });
+
+ // ID find and filter
+ if ( support.getById ) {
+ Expr.find["ID"] = function( id, context ) {
+ if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
+ var m = context.getElementById( id );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ return m && m.parentNode ? [ m ] : [];
+ }
+ };
+ Expr.filter["ID"] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ return elem.getAttribute("id") === attrId;
+ };
+ };
+ } else {
+ // Support: IE6/7
+ // getElementById is not reliable as a find shortcut
+ delete Expr.find["ID"];
+
+ Expr.filter["ID"] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
+ return node && node.value === attrId;
+ };
+ };
+ }
+
+ // Tag
+ Expr.find["TAG"] = support.getElementsByTagName ?
+ function( tag, context ) {
+ if ( typeof context.getElementsByTagName !== "undefined" ) {
+ return context.getElementsByTagName( tag );
+
+ // DocumentFragment nodes don't have gEBTN
+ } else if ( support.qsa ) {
+ return context.querySelectorAll( tag );
+ }
+ } :
+
+ function( tag, context ) {
+ var elem,
+ tmp = [],
+ i = 0,
+ // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
+ results = context.getElementsByTagName( tag );
+
+ // Filter out possible comments
+ if ( tag === "*" ) {
+ while ( (elem = results[i++]) ) {
+ if ( elem.nodeType === 1 ) {
+ tmp.push( elem );
+ }
+ }
+
+ return tmp;
+ }
+ return results;
+ };
+
+ // Class
+ Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
+ if ( documentIsHTML ) {
+ return context.getElementsByClassName( className );
+ }
+ };
+
+ /* QSA/matchesSelector
+ ---------------------------------------------------------------------- */
+
+ // QSA and matchesSelector support
+
+ // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+ rbuggyMatches = [];
+
+ // qSa(:focus) reports false when true (Chrome 21)
+ // We allow this because of a bug in IE8/9 that throws an error
+ // whenever `document.activeElement` is accessed on an iframe
+ // So, we allow :focus to pass through QSA all the time to avoid the IE error
+ // See http://bugs.jquery.com/ticket/13378
+ rbuggyQSA = [];
+
+ if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
+ // Build QSA regex
+ // Regex strategy adopted from Diego Perini
+ assert(function( div ) {
+ // Select is set to empty string on purpose
+ // This is to test IE's treatment of not explicitly
+ // setting a boolean content attribute,
+ // since its presence should be enough
+ // http://bugs.jquery.com/ticket/12359
+ docElem.appendChild( div ).innerHTML = "<a id='" + expando + "'></a>" +
+ "<select id='" + expando + "-\f]' msallowcapture=''>" +
+ "<option selected=''></option></select>";
+
+ // Support: IE8, Opera 11-12.16
+ // Nothing should be selected when empty strings follow ^= or $= or *=
+ // The test attribute must be unknown in Opera but "safe" for WinRT
+ // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
+ if ( div.querySelectorAll("[msallowcapture^='']").length ) {
+ rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
+ }
+
+ // Support: IE8
+ // Boolean attributes and "value" are not treated correctly
+ if ( !div.querySelectorAll("[selected]").length ) {
+ rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
+ }
+
+ // Support: Chrome<29, Android<4.2+, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.7+
+ if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
+ rbuggyQSA.push("~=");
+ }
+
+ // Webkit/Opera - :checked should return selected option elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ // IE8 throws error here and will not see later tests
+ if ( !div.querySelectorAll(":checked").length ) {
+ rbuggyQSA.push(":checked");
+ }
+
+ // Support: Safari 8+, iOS 8+
+ // https://bugs.webkit.org/show_bug.cgi?id=136851
+ // In-page `selector#id sibing-combinator selector` fails
+ if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) {
+ rbuggyQSA.push(".#.+[+~]");
+ }
+ });
+
+ assert(function( div ) {
+ // Support: Windows 8 Native Apps
+ // The type and name attributes are restricted during .innerHTML assignment
+ var input = doc.createElement("input");
+ input.setAttribute( "type", "hidden" );
+ div.appendChild( input ).setAttribute( "name", "D" );
+
+ // Support: IE8
+ // Enforce case-sensitivity of name attribute
+ if ( div.querySelectorAll("[name=d]").length ) {
+ rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
+ }
+
+ // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+ // IE8 throws error here and will not see later tests
+ if ( !div.querySelectorAll(":enabled").length ) {
+ rbuggyQSA.push( ":enabled", ":disabled" );
+ }
+
+ // Opera 10-11 does not throw on post-comma invalid pseudos
+ div.querySelectorAll("*,:x");
+ rbuggyQSA.push(",.*:");
+ });
+ }
+
+ if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
+ docElem.webkitMatchesSelector ||
+ docElem.mozMatchesSelector ||
+ docElem.oMatchesSelector ||
+ docElem.msMatchesSelector) )) ) {
+
+ assert(function( div ) {
+ // Check to see if it's possible to do matchesSelector
+ // on a disconnected node (IE 9)
+ support.disconnectedMatch = matches.call( div, "div" );
+
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ matches.call( div, "[s!='']:x" );
+ rbuggyMatches.push( "!=", pseudos );
+ });
+ }
+
+ rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
+ rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
+
+ /* Contains
+ ---------------------------------------------------------------------- */
+ hasCompare = rnative.test( docElem.compareDocumentPosition );
+
+ // Element contains another
+ // Purposefully does not implement inclusive descendent
+ // As in, an element does not contain itself
+ contains = hasCompare || rnative.test( docElem.contains ) ?
+ function( a, b ) {
+ var adown = a.nodeType === 9 ? a.documentElement : a,
+ bup = b && b.parentNode;
+ return a === bup || !!( bup && bup.nodeType === 1 && (
+ adown.contains ?
+ adown.contains( bup ) :
+ a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
+ ));
+ } :
+ function( a, b ) {
+ if ( b ) {
+ while ( (b = b.parentNode) ) {
+ if ( b === a ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+
+ /* Sorting
+ ---------------------------------------------------------------------- */
+
+ // Document order sorting
+ sortOrder = hasCompare ?
+ function( a, b ) {
+
+ // Flag for duplicate removal
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ // Sort on method existence if only one input has compareDocumentPosition
+ var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
+ if ( compare ) {
+ return compare;
+ }
+
+ // Calculate position if both inputs belong to the same document
+ compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
+ a.compareDocumentPosition( b ) :
+
+ // Otherwise we know they are disconnected
+ 1;
+
+ // Disconnected nodes
+ if ( compare & 1 ||
+ (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
+
+ // Choose the first element that is related to our preferred document
+ if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
+ return -1;
+ }
+ if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
+ return 1;
+ }
+
+ // Maintain original order
+ return sortInput ?
+ ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
+ 0;
+ }
+
+ return compare & 4 ? -1 : 1;
+ } :
+ function( a, b ) {
+ // Exit early if the nodes are identical
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ var cur,
+ i = 0,
+ aup = a.parentNode,
+ bup = b.parentNode,
+ ap = [ a ],
+ bp = [ b ];
+
+ // Parentless nodes are either documents or disconnected
+ if ( !aup || !bup ) {
+ return a === doc ? -1 :
+ b === doc ? 1 :
+ aup ? -1 :
+ bup ? 1 :
+ sortInput ?
+ ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
+ 0;
+
+ // If the nodes are siblings, we can do a quick check
+ } else if ( aup === bup ) {
+ return siblingCheck( a, b );
+ }
+
+ // Otherwise we need full lists of their ancestors for comparison
+ cur = a;
+ while ( (cur = cur.parentNode) ) {
+ ap.unshift( cur );
+ }
+ cur = b;
+ while ( (cur = cur.parentNode) ) {
+ bp.unshift( cur );
+ }
+
+ // Walk down the tree looking for a discrepancy
+ while ( ap[i] === bp[i] ) {
+ i++;
+ }
+
+ return i ?
+ // Do a sibling check if the nodes have a common ancestor
+ siblingCheck( ap[i], bp[i] ) :
+
+ // Otherwise nodes in our document sort first
+ ap[i] === preferredDoc ? -1 :
+ bp[i] === preferredDoc ? 1 :
+ 0;
+ };
+
+ return doc;
+};
+
+Sizzle.matches = function( expr, elements ) {
+ return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+ // Set document vars if needed
+ if ( ( elem.ownerDocument || elem ) !== document ) {
+ setDocument( elem );
+ }
+
+ // Make sure that attribute selectors are quoted
+ expr = expr.replace( rattributeQuotes, "='$1']" );
+
+ if ( support.matchesSelector && documentIsHTML &&
+ ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
+ ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
+
+ try {
+ var ret = matches.call( elem, expr );
+
+ // IE 9's matchesSelector returns false on disconnected nodes
+ if ( ret || support.disconnectedMatch ||
+ // As well, disconnected nodes are said to be in a document
+ // fragment in IE 9
+ elem.document && elem.document.nodeType !== 11 ) {
+ return ret;
+ }
+ } catch (e) {}
+ }
+
+ return Sizzle( expr, document, null, [ elem ] ).length > 0;
+};
+
+Sizzle.contains = function( context, elem ) {
+ // Set document vars if needed
+ if ( ( context.ownerDocument || context ) !== document ) {
+ setDocument( context );
+ }
+ return contains( context, elem );
+};
+
+Sizzle.attr = function( elem, name ) {
+ // Set document vars if needed
+ if ( ( elem.ownerDocument || elem ) !== document ) {
+ setDocument( elem );
+ }
+
+ var fn = Expr.attrHandle[ name.toLowerCase() ],
+ // Don't get fooled by Object.prototype properties (jQuery #13807)
+ val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
+ fn( elem, name, !documentIsHTML ) :
+ undefined;
+
+ return val !== undefined ?
+ val :
+ support.attributes || !documentIsHTML ?
+ elem.getAttribute( name ) :
+ (val = elem.getAttributeNode(name)) && val.specified ?
+ val.value :
+ null;
+};
+
+Sizzle.error = function( msg ) {
+ throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+/**
+ * Document sorting and removing duplicates
+ * @param {ArrayLike} results
+ */
+Sizzle.uniqueSort = function( results ) {
+ var elem,
+ duplicates = [],
+ j = 0,
+ i = 0;
+
+ // Unless we *know* we can detect duplicates, assume their presence
+ hasDuplicate = !support.detectDuplicates;
+ sortInput = !support.sortStable && results.slice( 0 );
+ results.sort( sortOrder );
+
+ if ( hasDuplicate ) {
+ while ( (elem = results[i++]) ) {
+ if ( elem === results[ i ] ) {
+ j = duplicates.push( i );
+ }
+ }
+ while ( j-- ) {
+ results.splice( duplicates[ j ], 1 );
+ }
+ }
+
+ // Clear input after sorting to release objects
+ // See https://github.com/jquery/sizzle/pull/225
+ sortInput = null;
+
+ return results;
+};
+
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+ var node,
+ ret = "",
+ i = 0,
+ nodeType = elem.nodeType;
+
+ if ( !nodeType ) {
+ // If no nodeType, this is expected to be an array
+ while ( (node = elem[i++]) ) {
+ // Do not traverse comment nodes
+ ret += getText( node );
+ }
+ } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+ // Use textContent for elements
+ // innerText usage removed for consistency of new lines (jQuery #11153)
+ if ( typeof elem.textContent === "string" ) {
+ return elem.textContent;
+ } else {
+ // Traverse its children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ ret += getText( elem );
+ }
+ }
+ } else if ( nodeType === 3 || nodeType === 4 ) {
+ return elem.nodeValue;
+ }
+ // Do not include comment or processing instruction nodes
+
+ return ret;
+};
+
+Expr = Sizzle.selectors = {
+
+ // Can be adjusted by the user
+ cacheLength: 50,
+
+ createPseudo: markFunction,
+
+ match: matchExpr,
+
+ attrHandle: {},
+
+ find: {},
+
+ relative: {
+ ">": { dir: "parentNode", first: true },
+ " ": { dir: "parentNode" },
+ "+": { dir: "previousSibling", first: true },
+ "~": { dir: "previousSibling" }
+ },
+
+ preFilter: {
+ "ATTR": function( match ) {
+ match[1] = match[1].replace( runescape, funescape );
+
+ // Move the given value to match[3] whether quoted or unquoted
+ match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
+
+ if ( match[2] === "~=" ) {
+ match[3] = " " + match[3] + " ";
+ }
+
+ return match.slice( 0, 4 );
+ },
+
+ "CHILD": function( match ) {
+ /* matches from matchExpr["CHILD"]
+ 1 type (only|nth|...)
+ 2 what (child|of-type)
+ 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+ 4 xn-component of xn+y argument ([+-]?\d*n|)
+ 5 sign of xn-component
+ 6 x of xn-component
+ 7 sign of y-component
+ 8 y of y-component
+ */
+ match[1] = match[1].toLowerCase();
+
+ if ( match[1].slice( 0, 3 ) === "nth" ) {
+ // nth-* requires argument
+ if ( !match[3] ) {
+ Sizzle.error( match[0] );
+ }
+
+ // numeric x and y parameters for Expr.filter.CHILD
+ // remember that false/true cast respectively to 0/1
+ match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
+ match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
+
+ // other types prohibit arguments
+ } else if ( match[3] ) {
+ Sizzle.error( match[0] );
+ }
+
+ return match;
+ },
+
+ "PSEUDO": function( match ) {
+ var excess,
+ unquoted = !match[6] && match[2];
+
+ if ( matchExpr["CHILD"].test( match[0] ) ) {
+ return null;
+ }
+
+ // Accept quoted arguments as-is
+ if ( match[3] ) {
+ match[2] = match[4] || match[5] || "";
+
+ // Strip excess characters from unquoted arguments
+ } else if ( unquoted && rpseudo.test( unquoted ) &&
+ // Get excess from tokenize (recursively)
+ (excess = tokenize( unquoted, true )) &&
+ // advance to the next closing parenthesis
+ (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
+
+ // excess is a negative index
+ match[0] = match[0].slice( 0, excess );
+ match[2] = unquoted.slice( 0, excess );
+ }
+
+ // Return only captures needed by the pseudo filter method (type and argument)
+ return match.slice( 0, 3 );
+ }
+ },
+
+ filter: {
+
+ "TAG": function( nodeNameSelector ) {
+ var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
+ return nodeNameSelector === "*" ?
+ function() { return true; } :
+ function( elem ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+ };
+ },
+
+ "CLASS": function( className ) {
+ var pattern = classCache[ className + " " ];
+
+ return pattern ||
+ (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
+ classCache( className, function( elem ) {
+ return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" );
+ });
+ },
+
+ "ATTR": function( name, operator, check ) {
+ return function( elem ) {
+ var result = Sizzle.attr( elem, name );
+
+ if ( result == null ) {
+ return operator === "!=";
+ }
+ if ( !operator ) {
+ return true;
+ }
+
+ result += "";
+
+ return operator === "=" ? result === check :
+ operator === "!=" ? result !== check :
+ operator === "^=" ? check && result.indexOf( check ) === 0 :
+ operator === "*=" ? check && result.indexOf( check ) > -1 :
+ operator === "$=" ? check && result.slice( -check.length ) === check :
+ operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
+ operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
+ false;
+ };
+ },
+
+ "CHILD": function( type, what, argument, first, last ) {
+ var simple = type.slice( 0, 3 ) !== "nth",
+ forward = type.slice( -4 ) !== "last",
+ ofType = what === "of-type";
+
+ return first === 1 && last === 0 ?
+
+ // Shortcut for :nth-*(n)
+ function( elem ) {
+ return !!elem.parentNode;
+ } :
+
+ function( elem, context, xml ) {
+ var cache, outerCache, node, diff, nodeIndex, start,
+ dir = simple !== forward ? "nextSibling" : "previousSibling",
+ parent = elem.parentNode,
+ name = ofType && elem.nodeName.toLowerCase(),
+ useCache = !xml && !ofType;
+
+ if ( parent ) {
+
+ // :(first|last|only)-(child|of-type)
+ if ( simple ) {
+ while ( dir ) {
+ node = elem;
+ while ( (node = node[ dir ]) ) {
+ if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
+ return false;
+ }
+ }
+ // Reverse direction for :only-* (if we haven't yet done so)
+ start = dir = type === "only" && !start && "nextSibling";
+ }
+ return true;
+ }
+
+ start = [ forward ? parent.firstChild : parent.lastChild ];
+
+ // non-xml :nth-child(...) stores cache data on `parent`
+ if ( forward && useCache ) {
+ // Seek `elem` from a previously-cached index
+ outerCache = parent[ expando ] || (parent[ expando ] = {});
+ cache = outerCache[ type ] || [];
+ nodeIndex = cache[0] === dirruns && cache[1];
+ diff = cache[0] === dirruns && cache[2];
+ node = nodeIndex && parent.childNodes[ nodeIndex ];
+
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
+
+ // Fallback to seeking `elem` from the start
+ (diff = nodeIndex = 0) || start.pop()) ) {
+
+ // When found, cache indexes on `parent` and break
+ if ( node.nodeType === 1 && ++diff && node === elem ) {
+ outerCache[ type ] = [ dirruns, nodeIndex, diff ];
+ break;
+ }
+ }
+
+ // Use previously-cached element index if available
+ } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
+ diff = cache[1];
+
+ // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
+ } else {
+ // Use the same loop as above to seek `elem` from the start
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
+ (diff = nodeIndex = 0) || start.pop()) ) {
+
+ if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
+ // Cache the index of each encountered element
+ if ( useCache ) {
+ (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
+ }
+
+ if ( node === elem ) {
+ break;
+ }
+ }
+ }
+ }
+
+ // Incorporate the offset, then check against cycle size
+ diff -= last;
+ return diff === first || ( diff % first === 0 && diff / first >= 0 );
+ }
+ };
+ },
+
+ "PSEUDO": function( pseudo, argument ) {
+ // pseudo-class names are case-insensitive
+ // http://www.w3.org/TR/selectors/#pseudo-classes
+ // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+ // Remember that setFilters inherits from pseudos
+ var args,
+ fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+ Sizzle.error( "unsupported pseudo: " + pseudo );
+
+ // The user may use createPseudo to indicate that
+ // arguments are needed to create the filter function
+ // just as Sizzle does
+ if ( fn[ expando ] ) {
+ return fn( argument );
+ }
+
+ // But maintain support for old signatures
+ if ( fn.length > 1 ) {
+ args = [ pseudo, pseudo, "", argument ];
+ return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+ markFunction(function( seed, matches ) {
+ var idx,
+ matched = fn( seed, argument ),
+ i = matched.length;
+ while ( i-- ) {
+ idx = indexOf( seed, matched[i] );
+ seed[ idx ] = !( matches[ idx ] = matched[i] );
+ }
+ }) :
+ function( elem ) {
+ return fn( elem, 0, args );
+ };
+ }
+
+ return fn;
+ }
+ },
+
+ pseudos: {
+ // Potentially complex pseudos
+ "not": markFunction(function( selector ) {
+ // Trim the selector passed to compile
+ // to avoid treating leading and trailing
+ // spaces as combinators
+ var input = [],
+ results = [],
+ matcher = compile( selector.replace( rtrim, "$1" ) );
+
+ return matcher[ expando ] ?
+ markFunction(function( seed, matches, context, xml ) {
+ var elem,
+ unmatched = matcher( seed, null, xml, [] ),
+ i = seed.length;
+
+ // Match elements unmatched by `matcher`
+ while ( i-- ) {
+ if ( (elem = unmatched[i]) ) {
+ seed[i] = !(matches[i] = elem);
+ }
+ }
+ }) :
+ function( elem, context, xml ) {
+ input[0] = elem;
+ matcher( input, null, xml, results );
+ // Don't keep the element (issue #299)
+ input[0] = null;
+ return !results.pop();
+ };
+ }),
+
+ "has": markFunction(function( selector ) {
+ return function( elem ) {
+ return Sizzle( selector, elem ).length > 0;
+ };
+ }),
+
+ "contains": markFunction(function( text ) {
+ text = text.replace( runescape, funescape );
+ return function( elem ) {
+ return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
+ };
+ }),
+
+ // "Whether an element is represented by a :lang() selector
+ // is based solely on the element's language value
+ // being equal to the identifier C,
+ // or beginning with the identifier C immediately followed by "-".
+ // The matching of C against the element's language value is performed case-insensitively.
+ // The identifier C does not have to be a valid language name."
+ // http://www.w3.org/TR/selectors/#lang-pseudo
+ "lang": markFunction( function( lang ) {
+ // lang value must be a valid identifier
+ if ( !ridentifier.test(lang || "") ) {
+ Sizzle.error( "unsupported lang: " + lang );
+ }
+ lang = lang.replace( runescape, funescape ).toLowerCase();
+ return function( elem ) {
+ var elemLang;
+ do {
+ if ( (elemLang = documentIsHTML ?
+ elem.lang :
+ elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
+
+ elemLang = elemLang.toLowerCase();
+ return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
+ }
+ } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
+ return false;
+ };
+ }),
+
+ // Miscellaneous
+ "target": function( elem ) {
+ var hash = window.location && window.location.hash;
+ return hash && hash.slice( 1 ) === elem.id;
+ },
+
+ "root": function( elem ) {
+ return elem === docElem;
+ },
+
+ "focus": function( elem ) {
+ return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
+ },
+
+ // Boolean properties
+ "enabled": function( elem ) {
+ return elem.disabled === false;
+ },
+
+ "disabled": function( elem ) {
+ return elem.disabled === true;
+ },
+
+ "checked": function( elem ) {
+ // In CSS3, :checked should return both checked and selected elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ var nodeName = elem.nodeName.toLowerCase();
+ return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
+ },
+
+ "selected": function( elem ) {
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ if ( elem.parentNode ) {
+ elem.parentNode.selectedIndex;
+ }
+
+ return elem.selected === true;
+ },
+
+ // Contents
+ "empty": function( elem ) {
+ // http://www.w3.org/TR/selectors/#empty-pseudo
+ // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
+ // but not by others (comment: 8; processing instruction: 7; etc.)
+ // nodeType < 6 works because attributes (2) do not appear as children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ if ( elem.nodeType < 6 ) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ "parent": function( elem ) {
+ return !Expr.pseudos["empty"]( elem );
+ },
+
+ // Element/input types
+ "header": function( elem ) {
+ return rheader.test( elem.nodeName );
+ },
+
+ "input": function( elem ) {
+ return rinputs.test( elem.nodeName );
+ },
+
+ "button": function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === "button" || name === "button";
+ },
+
+ "text": function( elem ) {
+ var attr;
+ return elem.nodeName.toLowerCase() === "input" &&
+ elem.type === "text" &&
+
+ // Support: IE<8
+ // New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
+ ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
+ },
+
+ // Position-in-collection
+ "first": createPositionalPseudo(function() {
+ return [ 0 ];
+ }),
+
+ "last": createPositionalPseudo(function( matchIndexes, length ) {
+ return [ length - 1 ];
+ }),
+
+ "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ return [ argument < 0 ? argument + length : argument ];
+ }),
+
+ "even": createPositionalPseudo(function( matchIndexes, length ) {
+ var i = 0;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "odd": createPositionalPseudo(function( matchIndexes, length ) {
+ var i = 1;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ var i = argument < 0 ? argument + length : argument;
+ for ( ; --i >= 0; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ var i = argument < 0 ? argument + length : argument;
+ for ( ; ++i < length; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ })
+ }
+};
+
+Expr.pseudos["nth"] = Expr.pseudos["eq"];
+
+// Add button/input type pseudos
+for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
+ Expr.pseudos[ i ] = createInputPseudo( i );
+}
+for ( i in { submit: true, reset: true } ) {
+ Expr.pseudos[ i ] = createButtonPseudo( i );
+}
+
+// Easy API for creating new setFilters
+function setFilters() {}
+setFilters.prototype = Expr.filters = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
+tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
+ var matched, match, tokens, type,
+ soFar, groups, preFilters,
+ cached = tokenCache[ selector + " " ];
+
+ if ( cached ) {
+ return parseOnly ? 0 : cached.slice( 0 );
+ }
+
+ soFar = selector;
+ groups = [];
+ preFilters = Expr.preFilter;
+
+ while ( soFar ) {
+
+ // Comma and first run
+ if ( !matched || (match = rcomma.exec( soFar )) ) {
+ if ( match ) {
+ // Don't consume trailing commas as valid
+ soFar = soFar.slice( match[0].length ) || soFar;
+ }
+ groups.push( (tokens = []) );
+ }
+
+ matched = false;
+
+ // Combinators
+ if ( (match = rcombinators.exec( soFar )) ) {
+ matched = match.shift();
+ tokens.push({
+ value: matched,
+ // Cast descendant combinators to space
+ type: match[0].replace( rtrim, " " )
+ });
+ soFar = soFar.slice( matched.length );
+ }
+
+ // Filters
+ for ( type in Expr.filter ) {
+ if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
+ (match = preFilters[ type ]( match ))) ) {
+ matched = match.shift();
+ tokens.push({
+ value: matched,
+ type: type,
+ matches: match
+ });
+ soFar = soFar.slice( matched.length );
+ }
+ }
+
+ if ( !matched ) {
+ break;
+ }
+ }
+
+ // Return the length of the invalid excess
+ // if we're just parsing
+ // Otherwise, throw an error or return tokens
+ return parseOnly ?
+ soFar.length :
+ soFar ?
+ Sizzle.error( selector ) :
+ // Cache the tokens
+ tokenCache( selector, groups ).slice( 0 );
+};
+
+function toSelector( tokens ) {
+ var i = 0,
+ len = tokens.length,
+ selector = "";
+ for ( ; i < len; i++ ) {
+ selector += tokens[i].value;
+ }
+ return selector;
+}
+
+function addCombinator( matcher, combinator, base ) {
+ var dir = combinator.dir,
+ checkNonElements = base && dir === "parentNode",
+ doneName = done++;
+
+ return combinator.first ?
+ // Check against closest ancestor/preceding element
+ function( elem, context, xml ) {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ return matcher( elem, context, xml );
+ }
+ }
+ } :
+
+ // Check against all ancestor/preceding elements
+ function( elem, context, xml ) {
+ var oldCache, outerCache,
+ newCache = [ dirruns, doneName ];
+
+ // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
+ if ( xml ) {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ if ( matcher( elem, context, xml ) ) {
+ return true;
+ }
+ }
+ }
+ } else {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ outerCache = elem[ expando ] || (elem[ expando ] = {});
+ if ( (oldCache = outerCache[ dir ]) &&
+ oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
+
+ // Assign to newCache so results back-propagate to previous elements
+ return (newCache[ 2 ] = oldCache[ 2 ]);
+ } else {
+ // Reuse newcache so results back-propagate to previous elements
+ outerCache[ dir ] = newCache;
+
+ // A match means we're done; a fail means we have to keep checking
+ if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ };
+}
+
+function elementMatcher( matchers ) {
+ return matchers.length > 1 ?
+ function( elem, context, xml ) {
+ var i = matchers.length;
+ while ( i-- ) {
+ if ( !matchers[i]( elem, context, xml ) ) {
+ return false;
+ }
+ }
+ return true;
+ } :
+ matchers[0];
+}
+
+function multipleContexts( selector, contexts, results ) {
+ var i = 0,
+ len = contexts.length;
+ for ( ; i < len; i++ ) {
+ Sizzle( selector, contexts[i], results );
+ }
+ return results;
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+ var elem,
+ newUnmatched = [],
+ i = 0,
+ len = unmatched.length,
+ mapped = map != null;
+
+ for ( ; i < len; i++ ) {
+ if ( (elem = unmatched[i]) ) {
+ if ( !filter || filter( elem, context, xml ) ) {
+ newUnmatched.push( elem );
+ if ( mapped ) {
+ map.push( i );
+ }
+ }
+ }
+ }
+
+ return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
+ if ( postFilter && !postFilter[ expando ] ) {
+ postFilter = setMatcher( postFilter );
+ }
+ if ( postFinder && !postFinder[ expando ] ) {
+ postFinder = setMatcher( postFinder, postSelector );
+ }
+ return markFunction(function( seed, results, context, xml ) {
+ var temp, i, elem,
+ preMap = [],
+ postMap = [],
+ preexisting = results.length,
+
+ // Get initial elements from seed or context
+ elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
+
+ // Prefilter to get matcher input, preserving a map for seed-results synchronization
+ matcherIn = preFilter && ( seed || !selector ) ?
+ condense( elems, preMap, preFilter, context, xml ) :
+ elems,
+
+ matcherOut = matcher ?
+ // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+ postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+
+ // ...intermediate processing is necessary
+ [] :
+
+ // ...otherwise use results directly
+ results :
+ matcherIn;
+
+ // Find primary matches
+ if ( matcher ) {
+ matcher( matcherIn, matcherOut, context, xml );
+ }
+
+ // Apply postFilter
+ if ( postFilter ) {
+ temp = condense( matcherOut, postMap );
+ postFilter( temp, [], context, xml );
+
+ // Un-match failing elements by moving them back to matcherIn
+ i = temp.length;
+ while ( i-- ) {
+ if ( (elem = temp[i]) ) {
+ matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
+ }
+ }
+ }
+
+ if ( seed ) {
+ if ( postFinder || preFilter ) {
+ if ( postFinder ) {
+ // Get the final matcherOut by condensing this intermediate into postFinder contexts
+ temp = [];
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) ) {
+ // Restore matcherIn since elem is not yet a final match
+ temp.push( (matcherIn[i] = elem) );
+ }
+ }
+ postFinder( null, (matcherOut = []), temp, xml );
+ }
+
+ // Move matched elements from seed to results to keep them synchronized
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) &&
+ (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {
+
+ seed[temp] = !(results[temp] = elem);
+ }
+ }
+ }
+
+ // Add elements to results, through postFinder if defined
+ } else {
+ matcherOut = condense(
+ matcherOut === results ?
+ matcherOut.splice( preexisting, matcherOut.length ) :
+ matcherOut
+ );
+ if ( postFinder ) {
+ postFinder( null, results, matcherOut, xml );
+ } else {
+ push.apply( results, matcherOut );
+ }
+ }
+ });
+}
+
+function matcherFromTokens( tokens ) {
+ var checkContext, matcher, j,
+ len = tokens.length,
+ leadingRelative = Expr.relative[ tokens[0].type ],
+ implicitRelative = leadingRelative || Expr.relative[" "],
+ i = leadingRelative ? 1 : 0,
+
+ // The foundational matcher ensures that elements are reachable from top-level context(s)
+ matchContext = addCombinator( function( elem ) {
+ return elem === checkContext;
+ }, implicitRelative, true ),
+ matchAnyContext = addCombinator( function( elem ) {
+ return indexOf( checkContext, elem ) > -1;
+ }, implicitRelative, true ),
+ matchers = [ function( elem, context, xml ) {
+ var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+ (checkContext = context).nodeType ?
+ matchContext( elem, context, xml ) :
+ matchAnyContext( elem, context, xml ) );
+ // Avoid hanging onto element (issue #299)
+ checkContext = null;
+ return ret;
+ } ];
+
+ for ( ; i < len; i++ ) {
+ if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
+ matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
+ } else {
+ matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
+
+ // Return special upon seeing a positional matcher
+ if ( matcher[ expando ] ) {
+ // Find the next relative operator (if any) for proper handling
+ j = ++i;
+ for ( ; j < len; j++ ) {
+ if ( Expr.relative[ tokens[j].type ] ) {
+ break;
+ }
+ }
+ return setMatcher(
+ i > 1 && elementMatcher( matchers ),
+ i > 1 && toSelector(
+ // If the preceding token was a descendant combinator, insert an implicit any-element `*`
+ tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
+ ).replace( rtrim, "$1" ),
+ matcher,
+ i < j && matcherFromTokens( tokens.slice( i, j ) ),
+ j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
+ j < len && toSelector( tokens )
+ );
+ }
+ matchers.push( matcher );
+ }
+ }
+
+ return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+ var bySet = setMatchers.length > 0,
+ byElement = elementMatchers.length > 0,
+ superMatcher = function( seed, context, xml, results, outermost ) {
+ var elem, j, matcher,
+ matchedCount = 0,
+ i = "0",
+ unmatched = seed && [],
+ setMatched = [],
+ contextBackup = outermostContext,
+ // We must always have either seed elements or outermost context
+ elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
+ // Use integer dirruns iff this is the outermost matcher
+ dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
+ len = elems.length;
+
+ if ( outermost ) {
+ outermostContext = context !== document && context;
+ }
+
+ // Add elements passing elementMatchers directly to results
+ // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
+ // Support: IE<9, Safari
+ // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
+ for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
+ if ( byElement && elem ) {
+ j = 0;
+ while ( (matcher = elementMatchers[j++]) ) {
+ if ( matcher( elem, context, xml ) ) {
+ results.push( elem );
+ break;
+ }
+ }
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ }
+ }
+
+ // Track unmatched elements for set filters
+ if ( bySet ) {
+ // They will have gone through all possible matchers
+ if ( (elem = !matcher && elem) ) {
+ matchedCount--;
+ }
+
+ // Lengthen the array for every element, matched or not
+ if ( seed ) {
+ unmatched.push( elem );
+ }
+ }
+ }
+
+ // Apply set filters to unmatched elements
+ matchedCount += i;
+ if ( bySet && i !== matchedCount ) {
+ j = 0;
+ while ( (matcher = setMatchers[j++]) ) {
+ matcher( unmatched, setMatched, context, xml );
+ }
+
+ if ( seed ) {
+ // Reintegrate element matches to eliminate the need for sorting
+ if ( matchedCount > 0 ) {
+ while ( i-- ) {
+ if ( !(unmatched[i] || setMatched[i]) ) {
+ setMatched[i] = pop.call( results );
+ }
+ }
+ }
+
+ // Discard index placeholder values to get only actual matches
+ setMatched = condense( setMatched );
+ }
+
+ // Add matches to results
+ push.apply( results, setMatched );
+
+ // Seedless set matches succeeding multiple successful matchers stipulate sorting
+ if ( outermost && !seed && setMatched.length > 0 &&
+ ( matchedCount + setMatchers.length ) > 1 ) {
+
+ Sizzle.uniqueSort( results );
+ }
+ }
+
+ // Override manipulation of globals by nested matchers
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ outermostContext = contextBackup;
+ }
+
+ return unmatched;
+ };
+
+ return bySet ?
+ markFunction( superMatcher ) :
+ superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
+ var i,
+ setMatchers = [],
+ elementMatchers = [],
+ cached = compilerCache[ selector + " " ];
+
+ if ( !cached ) {
+ // Generate a function of recursive functions that can be used to check each element
+ if ( !match ) {
+ match = tokenize( selector );
+ }
+ i = match.length;
+ while ( i-- ) {
+ cached = matcherFromTokens( match[i] );
+ if ( cached[ expando ] ) {
+ setMatchers.push( cached );
+ } else {
+ elementMatchers.push( cached );
+ }
+ }
+
+ // Cache the compiled function
+ cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
+
+ // Save selector and tokenization
+ cached.selector = selector;
+ }
+ return cached;
+};
+
+/**
+ * A low-level selection function that works with Sizzle's compiled
+ * selector functions
+ * @param {String|Function} selector A selector or a pre-compiled
+ * selector function built with Sizzle.compile
+ * @param {Element} context
+ * @param {Array} [results]
+ * @param {Array} [seed] A set of elements to match against
+ */
+select = Sizzle.select = function( selector, context, results, seed ) {
+ var i, tokens, token, type, find,
+ compiled = typeof selector === "function" && selector,
+ match = !seed && tokenize( (selector = compiled.selector || selector) );
+
+ results = results || [];
+
+ // Try to minimize operations if there is no seed and only one group
+ if ( match.length === 1 ) {
+
+ // Take a shortcut and set the context if the root selector is an ID
+ tokens = match[0] = match[0].slice( 0 );
+ if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
+ support.getById && context.nodeType === 9 && documentIsHTML &&
+ Expr.relative[ tokens[1].type ] ) {
+
+ context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
+ if ( !context ) {
+ return results;
+
+ // Precompiled matchers will still verify ancestry, so step up a level
+ } else if ( compiled ) {
+ context = context.parentNode;
+ }
+
+ selector = selector.slice( tokens.shift().value.length );
+ }
+
+ // Fetch a seed set for right-to-left matching
+ i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
+ while ( i-- ) {
+ token = tokens[i];
+
+ // Abort if we hit a combinator
+ if ( Expr.relative[ (type = token.type) ] ) {
+ break;
+ }
+ if ( (find = Expr.find[ type ]) ) {
+ // Search, expanding context for leading sibling combinators
+ if ( (seed = find(
+ token.matches[0].replace( runescape, funescape ),
+ rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
+ )) ) {
+
+ // If seed is empty or no tokens remain, we can return early
+ tokens.splice( i, 1 );
+ selector = seed.length && toSelector( tokens );
+ if ( !selector ) {
+ push.apply( results, seed );
+ return results;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ // Compile and execute a filtering function if one is not provided
+ // Provide `match` to avoid retokenization if we modified the selector above
+ ( compiled || compile( selector, match ) )(
+ seed,
+ context,
+ !documentIsHTML,
+ results,
+ rsibling.test( selector ) && testContext( context.parentNode ) || context
+ );
+ return results;
+};
+
+// One-time assignments
+
+// Sort stability
+support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
+
+// Support: Chrome 14-35+
+// Always assume duplicates if they aren't passed to the comparison function
+support.detectDuplicates = !!hasDuplicate;
+
+// Initialize against the default document
+setDocument();
+
+// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
+// Detached nodes confoundingly follow *each other*
+support.sortDetached = assert(function( div1 ) {
+ // Should return 1, but returns 4 (following)
+ return div1.compareDocumentPosition( document.createElement("div") ) & 1;
+});
+
+// Support: IE<8
+// Prevent attribute/property "interpolation"
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !assert(function( div ) {
+ div.innerHTML = "<a href='#'></a>";
+ return div.firstChild.getAttribute("href") === "#" ;
+}) ) {
+ addHandle( "type|href|height|width", function( elem, name, isXML ) {
+ if ( !isXML ) {
+ return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
+ }
+ });
+}
+
+// Support: IE<9
+// Use defaultValue in place of getAttribute("value")
+if ( !support.attributes || !assert(function( div ) {
+ div.innerHTML = "<input/>";
+ div.firstChild.setAttribute( "value", "" );
+ return div.firstChild.getAttribute( "value" ) === "";
+}) ) {
+ addHandle( "value", function( elem, name, isXML ) {
+ if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
+ return elem.defaultValue;
+ }
+ });
+}
+
+// Support: IE<9
+// Use getAttributeNode to fetch booleans when getAttribute lies
+if ( !assert(function( div ) {
+ return div.getAttribute("disabled") == null;
+}) ) {
+ addHandle( booleans, function( elem, name, isXML ) {
+ var val;
+ if ( !isXML ) {
+ return elem[ name ] === true ? name.toLowerCase() :
+ (val = elem.getAttributeNode( name )) && val.specified ?
+ val.value :
+ null;
+ }
+ });
+}
+
+return Sizzle;
+
+})( window );
+
+
+
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.pseudos;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+
+var rneedsContext = jQuery.expr.match.needsContext;
+
+var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/);
+
+
+
+var risSimple = /^.[^:#\[\.,]*$/;
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, not ) {
+ if ( jQuery.isFunction( qualifier ) ) {
+ return jQuery.grep( elements, function( elem, i ) {
+ /* jshint -W018 */
+ return !!qualifier.call( elem, i, elem ) !== not;
+ });
+
+ }
+
+ if ( qualifier.nodeType ) {
+ return jQuery.grep( elements, function( elem ) {
+ return ( elem === qualifier ) !== not;
+ });
+
+ }
+
+ if ( typeof qualifier === "string" ) {
+ if ( risSimple.test( qualifier ) ) {
+ return jQuery.filter( qualifier, elements, not );
+ }
+
+ qualifier = jQuery.filter( qualifier, elements );
+ }
+
+ return jQuery.grep( elements, function( elem ) {
+ return ( indexOf.call( qualifier, elem ) >= 0 ) !== not;
+ });
+}
+
+jQuery.filter = function( expr, elems, not ) {
+ var elem = elems[ 0 ];
+
+ if ( not ) {
+ expr = ":not(" + expr + ")";
+ }
+
+ return elems.length === 1 && elem.nodeType === 1 ?
+ jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
+ jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
+ return elem.nodeType === 1;
+ }));
+};
+
+jQuery.fn.extend({
+ find: function( selector ) {
+ var i,
+ len = this.length,
+ ret = [],
+ self = this;
+
+ if ( typeof selector !== "string" ) {
+ return this.pushStack( jQuery( selector ).filter(function() {
+ for ( i = 0; i < len; i++ ) {
+ if ( jQuery.contains( self[ i ], this ) ) {
+ return true;
+ }
+ }
+ }) );
+ }
+
+ for ( i = 0; i < len; i++ ) {
+ jQuery.find( selector, self[ i ], ret );
+ }
+
+ // Needed because $( selector, context ) becomes $( context ).find( selector )
+ ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
+ ret.selector = this.selector ? this.selector + " " + selector : selector;
+ return ret;
+ },
+ filter: function( selector ) {
+ return this.pushStack( winnow(this, selector || [], false) );
+ },
+ not: function( selector ) {
+ return this.pushStack( winnow(this, selector || [], true) );
+ },
+ is: function( selector ) {
+ return !!winnow(
+ this,
+
+ // If this is a positional/relative selector, check membership in the returned set
+ // so $("p:first").is("p:last") won't return true for a doc with two "p".
+ typeof selector === "string" && rneedsContext.test( selector ) ?
+ jQuery( selector ) :
+ selector || [],
+ false
+ ).length;
+ }
+});
+
+
+// Initialize a jQuery object
+
+
+// A central reference to the root jQuery(document)
+var rootjQuery,
+
+ // A simple way to check for HTML strings
+ // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
+ // Strict HTML recognition (#11290: must start with <)
+ rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
+
+ init = jQuery.fn.init = function( selector, context ) {
+ var match, elem;
+
+ // HANDLE: $(""), $(null), $(undefined), $(false)
+ if ( !selector ) {
+ return this;
+ }
+
+ // Handle HTML strings
+ if ( typeof selector === "string" ) {
+ if ( selector[0] === "<" && selector[ selector.length - 1 ] === ">" && selector.length >= 3 ) {
+ // Assume that strings that start and end with <> are HTML and skip the regex check
+ match = [ null, selector, null ];
+
+ } else {
+ match = rquickExpr.exec( selector );
+ }
+
+ // Match html or make sure no context is specified for #id
+ if ( match && (match[1] || !context) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[1] ) {
+ context = context instanceof jQuery ? context[0] : context;
+
+ // Option to run scripts is true for back-compat
+ // Intentionally let the error be thrown if parseHTML is not present
+ jQuery.merge( this, jQuery.parseHTML(
+ match[1],
+ context && context.nodeType ? context.ownerDocument || context : document,
+ true
+ ) );
+
+ // HANDLE: $(html, props)
+ if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
+ for ( match in context ) {
+ // Properties of context are called as methods if possible
+ if ( jQuery.isFunction( this[ match ] ) ) {
+ this[ match ]( context[ match ] );
+
+ // ...and otherwise set as attributes
+ } else {
+ this.attr( match, context[ match ] );
+ }
+ }
+ }
+
+ return this;
+
+ // HANDLE: $(#id)
+ } else {
+ elem = document.getElementById( match[2] );
+
+ // Support: Blackberry 4.6
+ // gEBID returns nodes no longer in the document (#6963)
+ if ( elem && elem.parentNode ) {
+ // Inject the element directly into the jQuery object
+ this.length = 1;
+ this[0] = elem;
+ }
+
+ this.context = document;
+ this.selector = selector;
+ return this;
+ }
+
+ // HANDLE: $(expr, $(...))
+ } else if ( !context || context.jquery ) {
+ return ( context || rootjQuery ).find( selector );
+
+ // HANDLE: $(expr, context)
+ // (which is just equivalent to: $(context).find(expr)
+ } else {
+ return this.constructor( context ).find( selector );
+ }
+
+ // HANDLE: $(DOMElement)
+ } else if ( selector.nodeType ) {
+ this.context = this[0] = selector;
+ this.length = 1;
+ return this;
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( jQuery.isFunction( selector ) ) {
+ return typeof rootjQuery.ready !== "undefined" ?
+ rootjQuery.ready( selector ) :
+ // Execute immediately if ready is not present
+ selector( jQuery );
+ }
+
+ if ( selector.selector !== undefined ) {
+ this.selector = selector.selector;
+ this.context = selector.context;
+ }
+
+ return jQuery.makeArray( selector, this );
+ };
+
+// Give the init function the jQuery prototype for later instantiation
+init.prototype = jQuery.fn;
+
+// Initialize central reference
+rootjQuery = jQuery( document );
+
+
+var rparentsprev = /^(?:parents|prev(?:Until|All))/,
+ // Methods guaranteed to produce a unique set when starting from a unique set
+ guaranteedUnique = {
+ children: true,
+ contents: true,
+ next: true,
+ prev: true
+ };
+
+jQuery.extend({
+ dir: function( elem, dir, until ) {
+ var matched = [],
+ truncate = until !== undefined;
+
+ while ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) {
+ if ( elem.nodeType === 1 ) {
+ if ( truncate && jQuery( elem ).is( until ) ) {
+ break;
+ }
+ matched.push( elem );
+ }
+ }
+ return matched;
+ },
+
+ sibling: function( n, elem ) {
+ var matched = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType === 1 && n !== elem ) {
+ matched.push( n );
+ }
+ }
+
+ return matched;
+ }
+});
+
+jQuery.fn.extend({
+ has: function( target ) {
+ var targets = jQuery( target, this ),
+ l = targets.length;
+
+ return this.filter(function() {
+ var i = 0;
+ for ( ; i < l; i++ ) {
+ if ( jQuery.contains( this, targets[i] ) ) {
+ return true;
+ }
+ }
+ });
+ },
+
+ closest: function( selectors, context ) {
+ var cur,
+ i = 0,
+ l = this.length,
+ matched = [],
+ pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
+ jQuery( selectors, context || this.context ) :
+ 0;
+
+ for ( ; i < l; i++ ) {
+ for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
+ // Always skip document fragments
+ if ( cur.nodeType < 11 && (pos ?
+ pos.index(cur) > -1 :
+
+ // Don't pass non-elements to Sizzle
+ cur.nodeType === 1 &&
+ jQuery.find.matchesSelector(cur, selectors)) ) {
+
+ matched.push( cur );
+ break;
+ }
+ }
+ }
+
+ return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
+ },
+
+ // Determine the position of an element within the set
+ index: function( elem ) {
+
+ // No argument, return index in parent
+ if ( !elem ) {
+ return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
+ }
+
+ // Index in selector
+ if ( typeof elem === "string" ) {
+ return indexOf.call( jQuery( elem ), this[ 0 ] );
+ }
+
+ // Locate the position of the desired element
+ return indexOf.call( this,
+
+ // If it receives a jQuery object, the first element is used
+ elem.jquery ? elem[ 0 ] : elem
+ );
+ },
+
+ add: function( selector, context ) {
+ return this.pushStack(
+ jQuery.unique(
+ jQuery.merge( this.get(), jQuery( selector, context ) )
+ )
+ );
+ },
+
+ addBack: function( selector ) {
+ return this.add( selector == null ?
+ this.prevObject : this.prevObject.filter(selector)
+ );
+ }
+});
+
+function sibling( cur, dir ) {
+ while ( (cur = cur[dir]) && cur.nodeType !== 1 ) {}
+ return cur;
+}
+
+jQuery.each({
+ parent: function( elem ) {
+ var parent = elem.parentNode;
+ return parent && parent.nodeType !== 11 ? parent : null;
+ },
+ parents: function( elem ) {
+ return jQuery.dir( elem, "parentNode" );
+ },
+ parentsUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "parentNode", until );
+ },
+ next: function( elem ) {
+ return sibling( elem, "nextSibling" );
+ },
+ prev: function( elem ) {
+ return sibling( elem, "previousSibling" );
+ },
+ nextAll: function( elem ) {
+ return jQuery.dir( elem, "nextSibling" );
+ },
+ prevAll: function( elem ) {
+ return jQuery.dir( elem, "previousSibling" );
+ },
+ nextUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "nextSibling", until );
+ },
+ prevUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "previousSibling", until );
+ },
+ siblings: function( elem ) {
+ return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
+ },
+ children: function( elem ) {
+ return jQuery.sibling( elem.firstChild );
+ },
+ contents: function( elem ) {
+ return elem.contentDocument || jQuery.merge( [], elem.childNodes );
+ }
+}, function( name, fn ) {
+ jQuery.fn[ name ] = function( until, selector ) {
+ var matched = jQuery.map( this, fn, until );
+
+ if ( name.slice( -5 ) !== "Until" ) {
+ selector = until;
+ }
+
+ if ( selector && typeof selector === "string" ) {
+ matched = jQuery.filter( selector, matched );
+ }
+
+ if ( this.length > 1 ) {
+ // Remove duplicates
+ if ( !guaranteedUnique[ name ] ) {
+ jQuery.unique( matched );
+ }
+
+ // Reverse order for parents* and prev-derivatives
+ if ( rparentsprev.test( name ) ) {
+ matched.reverse();
+ }
+ }
+
+ return this.pushStack( matched );
+ };
+});
+var rnotwhite = (/\S+/g);
+
+
+
+// String to Object options format cache
+var optionsCache = {};
+
+// Convert String-formatted options into Object-formatted ones and store in cache
+function createOptions( options ) {
+ var object = optionsCache[ options ] = {};
+ jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
+ object[ flag ] = true;
+ });
+ return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ * options: an optional list of space-separated options that will change how
+ * the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ * once: will ensure the callback list can only be fired once (like a Deferred)
+ *
+ * memory: will keep track of previous values and will call any callback added
+ * after the list has been fired right away with the latest "memorized"
+ * values (like a Deferred)
+ *
+ * unique: will ensure a callback can only be added once (no duplicate in the list)
+ *
+ * stopOnFalse: interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+ // Convert options from String-formatted to Object-formatted if needed
+ // (we check in cache first)
+ options = typeof options === "string" ?
+ ( optionsCache[ options ] || createOptions( options ) ) :
+ jQuery.extend( {}, options );
+
+ var // Last fire value (for non-forgettable lists)
+ memory,
+ // Flag to know if list was already fired
+ fired,
+ // Flag to know if list is currently firing
+ firing,
+ // First callback to fire (used internally by add and fireWith)
+ firingStart,
+ // End of the loop when firing
+ firingLength,
+ // Index of currently firing callback (modified by remove if needed)
+ firingIndex,
+ // Actual callback list
+ list = [],
+ // Stack of fire calls for repeatable lists
+ stack = !options.once && [],
+ // Fire callbacks
+ fire = function( data ) {
+ memory = options.memory && data;
+ fired = true;
+ firingIndex = firingStart || 0;
+ firingStart = 0;
+ firingLength = list.length;
+ firing = true;
+ for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+ if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
+ memory = false; // To prevent further calls using add
+ break;
+ }
+ }
+ firing = false;
+ if ( list ) {
+ if ( stack ) {
+ if ( stack.length ) {
+ fire( stack.shift() );
+ }
+ } else if ( memory ) {
+ list = [];
+ } else {
+ self.disable();
+ }
+ }
+ },
+ // Actual Callbacks object
+ self = {
+ // Add a callback or a collection of callbacks to the list
+ add: function() {
+ if ( list ) {
+ // First, we save the current length
+ var start = list.length;
+ (function add( args ) {
+ jQuery.each( args, function( _, arg ) {
+ var type = jQuery.type( arg );
+ if ( type === "function" ) {
+ if ( !options.unique || !self.has( arg ) ) {
+ list.push( arg );
+ }
+ } else if ( arg && arg.length && type !== "string" ) {
+ // Inspect recursively
+ add( arg );
+ }
+ });
+ })( arguments );
+ // Do we need to add the callbacks to the
+ // current firing batch?
+ if ( firing ) {
+ firingLength = list.length;
+ // With memory, if we're not firing then
+ // we should call right away
+ } else if ( memory ) {
+ firingStart = start;
+ fire( memory );
+ }
+ }
+ return this;
+ },
+ // Remove a callback from the list
+ remove: function() {
+ if ( list ) {
+ jQuery.each( arguments, function( _, arg ) {
+ var index;
+ while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+ list.splice( index, 1 );
+ // Handle firing indexes
+ if ( firing ) {
+ if ( index <= firingLength ) {
+ firingLength--;
+ }
+ if ( index <= firingIndex ) {
+ firingIndex--;
+ }
+ }
+ }
+ });
+ }
+ return this;
+ },
+ // Check if a given callback is in the list.
+ // If no argument is given, return whether or not list has callbacks attached.
+ has: function( fn ) {
+ return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
+ },
+ // Remove all callbacks from the list
+ empty: function() {
+ list = [];
+ firingLength = 0;
+ return this;
+ },
+ // Have the list do nothing anymore
+ disable: function() {
+ list = stack = memory = undefined;
+ return this;
+ },
+ // Is it disabled?
+ disabled: function() {
+ return !list;
+ },
+ // Lock the list in its current state
+ lock: function() {
+ stack = undefined;
+ if ( !memory ) {
+ self.disable();
+ }
+ return this;
+ },
+ // Is it locked?
+ locked: function() {
+ return !stack;
+ },
+ // Call all callbacks with the given context and arguments
+ fireWith: function( context, args ) {
+ if ( list && ( !fired || stack ) ) {
+ args = args || [];
+ args = [ context, args.slice ? args.slice() : args ];
+ if ( firing ) {
+ stack.push( args );
+ } else {
+ fire( args );
+ }
+ }
+ return this;
+ },
+ // Call all the callbacks with the given arguments
+ fire: function() {
+ self.fireWith( this, arguments );
+ return this;
+ },
+ // To know if the callbacks have already been called at least once
+ fired: function() {
+ return !!fired;
+ }
+ };
+
+ return self;
+};
+
+
+jQuery.extend({
+
+ Deferred: function( func ) {
+ var tuples = [
+ // action, add listener, listener list, final state
+ [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
+ [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
+ [ "notify", "progress", jQuery.Callbacks("memory") ]
+ ],
+ state = "pending",
+ promise = {
+ state: function() {
+ return state;
+ },
+ always: function() {
+ deferred.done( arguments ).fail( arguments );
+ return this;
+ },
+ then: function( /* fnDone, fnFail, fnProgress */ ) {
+ var fns = arguments;
+ return jQuery.Deferred(function( newDefer ) {
+ jQuery.each( tuples, function( i, tuple ) {
+ var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
+ // deferred[ done | fail | progress ] for forwarding actions to newDefer
+ deferred[ tuple[1] ](function() {
+ var returned = fn && fn.apply( this, arguments );
+ if ( returned && jQuery.isFunction( returned.promise ) ) {
+ returned.promise()
+ .done( newDefer.resolve )
+ .fail( newDefer.reject )
+ .progress( newDefer.notify );
+ } else {
+ newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
+ }
+ });
+ });
+ fns = null;
+ }).promise();
+ },
+ // Get a promise for this deferred
+ // If obj is provided, the promise aspect is added to the object
+ promise: function( obj ) {
+ return obj != null ? jQuery.extend( obj, promise ) : promise;
+ }
+ },
+ deferred = {};
+
+ // Keep pipe for back-compat
+ promise.pipe = promise.then;
+
+ // Add list-specific methods
+ jQuery.each( tuples, function( i, tuple ) {
+ var list = tuple[ 2 ],
+ stateString = tuple[ 3 ];
+
+ // promise[ done | fail | progress ] = list.add
+ promise[ tuple[1] ] = list.add;
+
+ // Handle state
+ if ( stateString ) {
+ list.add(function() {
+ // state = [ resolved | rejected ]
+ state = stateString;
+
+ // [ reject_list | resolve_list ].disable; progress_list.lock
+ }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
+ }
+
+ // deferred[ resolve | reject | notify ]
+ deferred[ tuple[0] ] = function() {
+ deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
+ return this;
+ };
+ deferred[ tuple[0] + "With" ] = list.fireWith;
+ });
+
+ // Make the deferred a promise
+ promise.promise( deferred );
+
+ // Call given func if any
+ if ( func ) {
+ func.call( deferred, deferred );
+ }
+
+ // All done!
+ return deferred;
+ },
+
+ // Deferred helper
+ when: function( subordinate /* , ..., subordinateN */ ) {
+ var i = 0,
+ resolveValues = slice.call( arguments ),
+ length = resolveValues.length,
+
+ // the count of uncompleted subordinates
+ remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
+
+ // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
+ deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
+
+ // Update function for both resolve and progress values
+ updateFunc = function( i, contexts, values ) {
+ return function( value ) {
+ contexts[ i ] = this;
+ values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
+ if ( values === progressValues ) {
+ deferred.notifyWith( contexts, values );
+ } else if ( !( --remaining ) ) {
+ deferred.resolveWith( contexts, values );
+ }
+ };
+ },
+
+ progressValues, progressContexts, resolveContexts;
+
+ // Add listeners to Deferred subordinates; treat others as resolved
+ if ( length > 1 ) {
+ progressValues = new Array( length );
+ progressContexts = new Array( length );
+ resolveContexts = new Array( length );
+ for ( ; i < length; i++ ) {
+ if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
+ resolveValues[ i ].promise()
+ .done( updateFunc( i, resolveContexts, resolveValues ) )
+ .fail( deferred.reject )
+ .progress( updateFunc( i, progressContexts, progressValues ) );
+ } else {
+ --remaining;
+ }
+ }
+ }
+
+ // If we're not waiting on anything, resolve the master
+ if ( !remaining ) {
+ deferred.resolveWith( resolveContexts, resolveValues );
+ }
+
+ return deferred.promise();
+ }
+});
+
+
+// The deferred used on DOM ready
+var readyList;
+
+jQuery.fn.ready = function( fn ) {
+ // Add the callback
+ jQuery.ready.promise().done( fn );
+
+ return this;
+};
+
+jQuery.extend({
+ // Is the DOM ready to be used? Set to true once it occurs.
+ isReady: false,
+
+ // A counter to track how many items to wait for before
+ // the ready event fires. See #6781
+ readyWait: 1,
+
+ // Hold (or release) the ready event
+ holdReady: function( hold ) {
+ if ( hold ) {
+ jQuery.readyWait++;
+ } else {
+ jQuery.ready( true );
+ }
+ },
+
+ // Handle when the DOM is ready
+ ready: function( wait ) {
+
+ // Abort if there are pending holds or we're already ready
+ if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+ return;
+ }
+
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If a normal DOM Ready event fired, decrement, and wait if need be
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
+ return;
+ }
+
+ // If there are functions bound, to execute
+ readyList.resolveWith( document, [ jQuery ] );
+
+ // Trigger any bound ready events
+ if ( jQuery.fn.triggerHandler ) {
+ jQuery( document ).triggerHandler( "ready" );
+ jQuery( document ).off( "ready" );
+ }
+ }
+});
+
+/**
+ * The ready event handler and self cleanup method
+ */
+function completed() {
+ document.removeEventListener( "DOMContentLoaded", completed, false );
+ window.removeEventListener( "load", completed, false );
+ jQuery.ready();
+}
+
+jQuery.ready.promise = function( obj ) {
+ if ( !readyList ) {
+
+ readyList = jQuery.Deferred();
+
+ // Catch cases where $(document).ready() is called after the browser event has already occurred.
+ // We once tried to use readyState "interactive" here, but it caused issues like the one
+ // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
+ if ( document.readyState === "complete" ) {
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ setTimeout( jQuery.ready );
+
+ } else {
+
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", completed, false );
+
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", completed, false );
+ }
+ }
+ return readyList.promise( obj );
+};
+
+// Kick off the DOM ready check even if the user does not
+jQuery.ready.promise();
+
+
+
+
+// Multifunctional method to get and set values of a collection
+// The value/s can optionally be executed if it's a function
+var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
+ var i = 0,
+ len = elems.length,
+ bulk = key == null;
+
+ // Sets many values
+ if ( jQuery.type( key ) === "object" ) {
+ chainable = true;
+ for ( i in key ) {
+ jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
+ }
+
+ // Sets one value
+ } else if ( value !== undefined ) {
+ chainable = true;
+
+ if ( !jQuery.isFunction( value ) ) {
+ raw = true;
+ }
+
+ if ( bulk ) {
+ // Bulk operations run against the entire set
+ if ( raw ) {
+ fn.call( elems, value );
+ fn = null;
+
+ // ...except when executing function values
+ } else {
+ bulk = fn;
+ fn = function( elem, key, value ) {
+ return bulk.call( jQuery( elem ), value );
+ };
+ }
+ }
+
+ if ( fn ) {
+ for ( ; i < len; i++ ) {
+ fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
+ }
+ }
+ }
+
+ return chainable ?
+ elems :
+
+ // Gets
+ bulk ?
+ fn.call( elems ) :
+ len ? fn( elems[0], key ) : emptyGet;
+};
+
+
+/**
+ * Determines whether an object can have data
+ */
+jQuery.acceptData = function( owner ) {
+ // Accepts only:
+ // - Node
+ // - Node.ELEMENT_NODE
+ // - Node.DOCUMENT_NODE
+ // - Object
+ // - Any
+ /* jshint -W018 */
+ return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
+};
+
+
+function Data() {
+ // Support: Android<4,
+ // Old WebKit does not have Object.preventExtensions/freeze method,
+ // return new empty object instead with no [[set]] accessor
+ Object.defineProperty( this.cache = {}, 0, {
+ get: function() {
+ return {};
+ }
+ });
+
+ this.expando = jQuery.expando + Data.uid++;
+}
+
+Data.uid = 1;
+Data.accepts = jQuery.acceptData;
+
+Data.prototype = {
+ key: function( owner ) {
+ // We can accept data for non-element nodes in modern browsers,
+ // but we should not, see #8335.
+ // Always return the key for a frozen object.
+ if ( !Data.accepts( owner ) ) {
+ return 0;
+ }
+
+ var descriptor = {},
+ // Check if the owner object already has a cache key
+ unlock = owner[ this.expando ];
+
+ // If not, create one
+ if ( !unlock ) {
+ unlock = Data.uid++;
+
+ // Secure it in a non-enumerable, non-writable property
+ try {
+ descriptor[ this.expando ] = { value: unlock };
+ Object.defineProperties( owner, descriptor );
+
+ // Support: Android<4
+ // Fallback to a less secure definition
+ } catch ( e ) {
+ descriptor[ this.expando ] = unlock;
+ jQuery.extend( owner, descriptor );
+ }
+ }
+
+ // Ensure the cache object
+ if ( !this.cache[ unlock ] ) {
+ this.cache[ unlock ] = {};
+ }
+
+ return unlock;
+ },
+ set: function( owner, data, value ) {
+ var prop,
+ // There may be an unlock assigned to this node,
+ // if there is no entry for this "owner", create one inline
+ // and set the unlock as though an owner entry had always existed
+ unlock = this.key( owner ),
+ cache = this.cache[ unlock ];
+
+ // Handle: [ owner, key, value ] args
+ if ( typeof data === "string" ) {
+ cache[ data ] = value;
+
+ // Handle: [ owner, { properties } ] args
+ } else {
+ // Fresh assignments by object are shallow copied
+ if ( jQuery.isEmptyObject( cache ) ) {
+ jQuery.extend( this.cache[ unlock ], data );
+ // Otherwise, copy the properties one-by-one to the cache object
+ } else {
+ for ( prop in data ) {
+ cache[ prop ] = data[ prop ];
+ }
+ }
+ }
+ return cache;
+ },
+ get: function( owner, key ) {
+ // Either a valid cache is found, or will be created.
+ // New caches will be created and the unlock returned,
+ // allowing direct access to the newly created
+ // empty data object. A valid owner object must be provided.
+ var cache = this.cache[ this.key( owner ) ];
+
+ return key === undefined ?
+ cache : cache[ key ];
+ },
+ access: function( owner, key, value ) {
+ var stored;
+ // In cases where either:
+ //
+ // 1. No key was specified
+ // 2. A string key was specified, but no value provided
+ //
+ // Take the "read" path and allow the get method to determine
+ // which value to return, respectively either:
+ //
+ // 1. The entire cache object
+ // 2. The data stored at the key
+ //
+ if ( key === undefined ||
+ ((key && typeof key === "string") && value === undefined) ) {
+
+ stored = this.get( owner, key );
+
+ return stored !== undefined ?
+ stored : this.get( owner, jQuery.camelCase(key) );
+ }
+
+ // [*]When the key is not a string, or both a key and value
+ // are specified, set or extend (existing objects) with either:
+ //
+ // 1. An object of properties
+ // 2. A key and value
+ //
+ this.set( owner, key, value );
+
+ // Since the "set" path can have two possible entry points
+ // return the expected data based on which path was taken[*]
+ return value !== undefined ? value : key;
+ },
+ remove: function( owner, key ) {
+ var i, name, camel,
+ unlock = this.key( owner ),
+ cache = this.cache[ unlock ];
+
+ if ( key === undefined ) {
+ this.cache[ unlock ] = {};
+
+ } else {
+ // Support array or space separated string of keys
+ if ( jQuery.isArray( key ) ) {
+ // If "name" is an array of keys...
+ // When data is initially created, via ("key", "val") signature,
+ // keys will be converted to camelCase.
+ // Since there is no way to tell _how_ a key was added, remove
+ // both plain key and camelCase key. #12786
+ // This will only penalize the array argument path.
+ name = key.concat( key.map( jQuery.camelCase ) );
+ } else {
+ camel = jQuery.camelCase( key );
+ // Try the string as a key before any manipulation
+ if ( key in cache ) {
+ name = [ key, camel ];
+ } else {
+ // If a key with the spaces exists, use it.
+ // Otherwise, create an array by matching non-whitespace
+ name = camel;
+ name = name in cache ?
+ [ name ] : ( name.match( rnotwhite ) || [] );
+ }
+ }
+
+ i = name.length;
+ while ( i-- ) {
+ delete cache[ name[ i ] ];
+ }
+ }
+ },
+ hasData: function( owner ) {
+ return !jQuery.isEmptyObject(
+ this.cache[ owner[ this.expando ] ] || {}
+ );
+ },
+ discard: function( owner ) {
+ if ( owner[ this.expando ] ) {
+ delete this.cache[ owner[ this.expando ] ];
+ }
+ }
+};
+var data_priv = new Data();
+
+var data_user = new Data();
+
+
+
+// Implementation Summary
+//
+// 1. Enforce API surface and semantic compatibility with 1.9.x branch
+// 2. Improve the module's maintainability by reducing the storage
+// paths to a single mechanism.
+// 3. Use the same single mechanism to support "private" and "user" data.
+// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
+// 5. Avoid exposing implementation details on user objects (eg. expando properties)
+// 6. Provide a clear path for implementation upgrade to WeakMap in 2014
+
+var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
+ rmultiDash = /([A-Z])/g;
+
+function dataAttr( elem, key, data ) {
+ var name;
+
+ // If nothing was found internally, try to fetch any
+ // data from the HTML5 data-* attribute
+ if ( data === undefined && elem.nodeType === 1 ) {
+ name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+ data = elem.getAttribute( name );
+
+ if ( typeof data === "string" ) {
+ try {
+ data = data === "true" ? true :
+ data === "false" ? false :
+ data === "null" ? null :
+ // Only convert to a number if it doesn't change the string
+ +data + "" === data ? +data :
+ rbrace.test( data ) ? jQuery.parseJSON( data ) :
+ data;
+ } catch( e ) {}
+
+ // Make sure we set the data so it isn't changed later
+ data_user.set( elem, key, data );
+ } else {
+ data = undefined;
+ }
+ }
+ return data;
+}
+
+jQuery.extend({
+ hasData: function( elem ) {
+ return data_user.hasData( elem ) || data_priv.hasData( elem );
+ },
+
+ data: function( elem, name, data ) {
+ return data_user.access( elem, name, data );
+ },
+
+ removeData: function( elem, name ) {
+ data_user.remove( elem, name );
+ },
+
+ // TODO: Now that all calls to _data and _removeData have been replaced
+ // with direct calls to data_priv methods, these can be deprecated.
+ _data: function( elem, name, data ) {
+ return data_priv.access( elem, name, data );
+ },
+
+ _removeData: function( elem, name ) {
+ data_priv.remove( elem, name );
+ }
+});
+
+jQuery.fn.extend({
+ data: function( key, value ) {
+ var i, name, data,
+ elem = this[ 0 ],
+ attrs = elem && elem.attributes;
+
+ // Gets all values
+ if ( key === undefined ) {
+ if ( this.length ) {
+ data = data_user.get( elem );
+
+ if ( elem.nodeType === 1 && !data_priv.get( elem, "hasDataAttrs" ) ) {
+ i = attrs.length;
+ while ( i-- ) {
+
+ // Support: IE11+
+ // The attrs elements can be null (#14894)
+ if ( attrs[ i ] ) {
+ name = attrs[ i ].name;
+ if ( name.indexOf( "data-" ) === 0 ) {
+ name = jQuery.camelCase( name.slice(5) );
+ dataAttr( elem, name, data[ name ] );
+ }
+ }
+ }
+ data_priv.set( elem, "hasDataAttrs", true );
+ }
+ }
+
+ return data;
+ }
+
+ // Sets multiple values
+ if ( typeof key === "object" ) {
+ return this.each(function() {
+ data_user.set( this, key );
+ });
+ }
+
+ return access( this, function( value ) {
+ var data,
+ camelKey = jQuery.camelCase( key );
+
+ // The calling jQuery object (element matches) is not empty
+ // (and therefore has an element appears at this[ 0 ]) and the
+ // `value` parameter was not undefined. An empty jQuery object
+ // will result in `undefined` for elem = this[ 0 ] which will
+ // throw an exception if an attempt to read a data cache is made.
+ if ( elem && value === undefined ) {
+ // Attempt to get data from the cache
+ // with the key as-is
+ data = data_user.get( elem, key );
+ if ( data !== undefined ) {
+ return data;
+ }
+
+ // Attempt to get data from the cache
+ // with the key camelized
+ data = data_user.get( elem, camelKey );
+ if ( data !== undefined ) {
+ return data;
+ }
+
+ // Attempt to "discover" the data in
+ // HTML5 custom data-* attrs
+ data = dataAttr( elem, camelKey, undefined );
+ if ( data !== undefined ) {
+ return data;
+ }
+
+ // We tried really hard, but the data doesn't exist.
+ return;
+ }
+
+ // Set the data...
+ this.each(function() {
+ // First, attempt to store a copy or reference of any
+ // data that might've been store with a camelCased key.
+ var data = data_user.get( this, camelKey );
+
+ // For HTML5 data-* attribute interop, we have to
+ // store property names with dashes in a camelCase form.
+ // This might not apply to all properties...*
+ data_user.set( this, camelKey, value );
+
+ // *... In the case of properties that might _actually_
+ // have dashes, we need to also store a copy of that
+ // unchanged property.
+ if ( key.indexOf("-") !== -1 && data !== undefined ) {
+ data_user.set( this, key, value );
+ }
+ });
+ }, null, value, arguments.length > 1, null, true );
+ },
+
+ removeData: function( key ) {
+ return this.each(function() {
+ data_user.remove( this, key );
+ });
+ }
+});
+
+
+jQuery.extend({
+ queue: function( elem, type, data ) {
+ var queue;
+
+ if ( elem ) {
+ type = ( type || "fx" ) + "queue";
+ queue = data_priv.get( elem, type );
+
+ // Speed up dequeue by getting out quickly if this is just a lookup
+ if ( data ) {
+ if ( !queue || jQuery.isArray( data ) ) {
+ queue = data_priv.access( elem, type, jQuery.makeArray(data) );
+ } else {
+ queue.push( data );
+ }
+ }
+ return queue || [];
+ }
+ },
+
+ dequeue: function( elem, type ) {
+ type = type || "fx";
+
+ var queue = jQuery.queue( elem, type ),
+ startLength = queue.length,
+ fn = queue.shift(),
+ hooks = jQuery._queueHooks( elem, type ),
+ next = function() {
+ jQuery.dequeue( elem, type );
+ };
+
+ // If the fx queue is dequeued, always remove the progress sentinel
+ if ( fn === "inprogress" ) {
+ fn = queue.shift();
+ startLength--;
+ }
+
+ if ( fn ) {
+
+ // Add a progress sentinel to prevent the fx queue from being
+ // automatically dequeued
+ if ( type === "fx" ) {
+ queue.unshift( "inprogress" );
+ }
+
+ // Clear up the last queue stop function
+ delete hooks.stop;
+ fn.call( elem, next, hooks );
+ }
+
+ if ( !startLength && hooks ) {
+ hooks.empty.fire();
+ }
+ },
+
+ // Not public - generate a queueHooks object, or return the current one
+ _queueHooks: function( elem, type ) {
+ var key = type + "queueHooks";
+ return data_priv.get( elem, key ) || data_priv.access( elem, key, {
+ empty: jQuery.Callbacks("once memory").add(function() {
+ data_priv.remove( elem, [ type + "queue", key ] );
+ })
+ });
+ }
+});
+
+jQuery.fn.extend({
+ queue: function( type, data ) {
+ var setter = 2;
+
+ if ( typeof type !== "string" ) {
+ data = type;
+ type = "fx";
+ setter--;
+ }
+
+ if ( arguments.length < setter ) {
+ return jQuery.queue( this[0], type );
+ }
+
+ return data === undefined ?
+ this :
+ this.each(function() {
+ var queue = jQuery.queue( this, type, data );
+
+ // Ensure a hooks for this queue
+ jQuery._queueHooks( this, type );
+
+ if ( type === "fx" && queue[0] !== "inprogress" ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ dequeue: function( type ) {
+ return this.each(function() {
+ jQuery.dequeue( this, type );
+ });
+ },
+ clearQueue: function( type ) {
+ return this.queue( type || "fx", [] );
+ },
+ // Get a promise resolved when queues of a certain type
+ // are emptied (fx is the type by default)
+ promise: function( type, obj ) {
+ var tmp,
+ count = 1,
+ defer = jQuery.Deferred(),
+ elements = this,
+ i = this.length,
+ resolve = function() {
+ if ( !( --count ) ) {
+ defer.resolveWith( elements, [ elements ] );
+ }
+ };
+
+ if ( typeof type !== "string" ) {
+ obj = type;
+ type = undefined;
+ }
+ type = type || "fx";
+
+ while ( i-- ) {
+ tmp = data_priv.get( elements[ i ], type + "queueHooks" );
+ if ( tmp && tmp.empty ) {
+ count++;
+ tmp.empty.add( resolve );
+ }
+ }
+ resolve();
+ return defer.promise( obj );
+ }
+});
+var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source;
+
+var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
+
+var isHidden = function( elem, el ) {
+ // isHidden might be called from jQuery#filter function;
+ // in that case, element will be second argument
+ elem = el || elem;
+ return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
+ };
+
+var rcheckableType = (/^(?:checkbox|radio)$/i);
+
+
+
+(function() {
+ var fragment = document.createDocumentFragment(),
+ div = fragment.appendChild( document.createElement( "div" ) ),
+ input = document.createElement( "input" );
+
+ // Support: Safari<=5.1
+ // Check state lost if the name is set (#11217)
+ // Support: Windows Web Apps (WWA)
+ // `name` and `type` must use .setAttribute for WWA (#14901)
+ input.setAttribute( "type", "radio" );
+ input.setAttribute( "checked", "checked" );
+ input.setAttribute( "name", "t" );
+
+ div.appendChild( input );
+
+ // Support: Safari<=5.1, Android<4.2
+ // Older WebKit doesn't clone checked state correctly in fragments
+ support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ // Support: IE<=11+
+ // Make sure textarea (and checkbox) defaultValue is properly cloned
+ div.innerHTML = "<textarea>x</textarea>";
+ support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
+})();
+var strundefined = typeof undefined;
+
+
+
+support.focusinBubbles = "onfocusin" in window;
+
+
+var
+ rkeyEvent = /^key/,
+ rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/,
+ rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+ rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
+
+function returnTrue() {
+ return true;
+}
+
+function returnFalse() {
+ return false;
+}
+
+function safeActiveElement() {
+ try {
+ return document.activeElement;
+ } catch ( err ) { }
+}
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+ global: {},
+
+ add: function( elem, types, handler, data, selector ) {
+
+ var handleObjIn, eventHandle, tmp,
+ events, t, handleObj,
+ special, handlers, type, namespaces, origType,
+ elemData = data_priv.get( elem );
+
+ // Don't attach events to noData or text/comment nodes (but allow plain objects)
+ if ( !elemData ) {
+ return;
+ }
+
+ // Caller can pass in an object of custom data in lieu of the handler
+ if ( handler.handler ) {
+ handleObjIn = handler;
+ handler = handleObjIn.handler;
+ selector = handleObjIn.selector;
+ }
+
+ // Make sure that the handler has a unique ID, used to find/remove it later
+ if ( !handler.guid ) {
+ handler.guid = jQuery.guid++;
+ }
+
+ // Init the element's event structure and main handler, if this is the first
+ if ( !(events = elemData.events) ) {
+ events = elemData.events = {};
+ }
+ if ( !(eventHandle = elemData.handle) ) {
+ eventHandle = elemData.handle = function( e ) {
+ // Discard the second event of a jQuery.event.trigger() and
+ // when an event is called after a page has unloaded
+ return typeof jQuery !== strundefined && jQuery.event.triggered !== e.type ?
+ jQuery.event.dispatch.apply( elem, arguments ) : undefined;
+ };
+ }
+
+ // Handle multiple events separated by a space
+ types = ( types || "" ).match( rnotwhite ) || [ "" ];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tmp[1];
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+ // There *must* be a type, no attaching namespace-only handlers
+ if ( !type ) {
+ continue;
+ }
+
+ // If event changes its type, use the special event handlers for the changed type
+ special = jQuery.event.special[ type ] || {};
+
+ // If selector defined, determine special event api type, otherwise given type
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+
+ // Update special based on newly reset type
+ special = jQuery.event.special[ type ] || {};
+
+ // handleObj is passed to all event handlers
+ handleObj = jQuery.extend({
+ type: type,
+ origType: origType,
+ data: data,
+ handler: handler,
+ guid: handler.guid,
+ selector: selector,
+ needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+ namespace: namespaces.join(".")
+ }, handleObjIn );
+
+ // Init the event handler queue if we're the first
+ if ( !(handlers = events[ type ]) ) {
+ handlers = events[ type ] = [];
+ handlers.delegateCount = 0;
+
+ // Only use addEventListener if the special events handler returns false
+ if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, eventHandle, false );
+ }
+ }
+ }
+
+ if ( special.add ) {
+ special.add.call( elem, handleObj );
+
+ if ( !handleObj.handler.guid ) {
+ handleObj.handler.guid = handler.guid;
+ }
+ }
+
+ // Add to the element's handler list, delegates in front
+ if ( selector ) {
+ handlers.splice( handlers.delegateCount++, 0, handleObj );
+ } else {
+ handlers.push( handleObj );
+ }
+
+ // Keep track of which events have ever been used, for event optimization
+ jQuery.event.global[ type ] = true;
+ }
+
+ },
+
+ // Detach an event or set of events from an element
+ remove: function( elem, types, handler, selector, mappedTypes ) {
+
+ var j, origCount, tmp,
+ events, t, handleObj,
+ special, handlers, type, namespaces, origType,
+ elemData = data_priv.hasData( elem ) && data_priv.get( elem );
+
+ if ( !elemData || !(events = elemData.events) ) {
+ return;
+ }
+
+ // Once for each type.namespace in types; type may be omitted
+ types = ( types || "" ).match( rnotwhite ) || [ "" ];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tmp[1];
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+ // Unbind all events (on this namespace, if provided) for the element
+ if ( !type ) {
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+ }
+ continue;
+ }
+
+ special = jQuery.event.special[ type ] || {};
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+ handlers = events[ type ] || [];
+ tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
+
+ // Remove matching events
+ origCount = j = handlers.length;
+ while ( j-- ) {
+ handleObj = handlers[ j ];
+
+ if ( ( mappedTypes || origType === handleObj.origType ) &&
+ ( !handler || handler.guid === handleObj.guid ) &&
+ ( !tmp || tmp.test( handleObj.namespace ) ) &&
+ ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+ handlers.splice( j, 1 );
+
+ if ( handleObj.selector ) {
+ handlers.delegateCount--;
+ }
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
+ }
+ }
+ }
+
+ // Remove generic event handler if we removed something and no more handlers exist
+ // (avoids potential for endless recursion during removal of special event handlers)
+ if ( origCount && !handlers.length ) {
+ if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+ jQuery.removeEvent( elem, type, elemData.handle );
+ }
+
+ delete events[ type ];
+ }
+ }
+
+ // Remove the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ delete elemData.handle;
+ data_priv.remove( elem, "events" );
+ }
+ },
+
+ trigger: function( event, data, elem, onlyHandlers ) {
+
+ var i, cur, tmp, bubbleType, ontype, handle, special,
+ eventPath = [ elem || document ],
+ type = hasOwn.call( event, "type" ) ? event.type : event,
+ namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
+
+ cur = tmp = elem = elem || document;
+
+ // Don't do events on text and comment nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return;
+ }
+
+ // focus/blur morphs to focusin/out; ensure we're not firing them right now
+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+ return;
+ }
+
+ if ( type.indexOf(".") >= 0 ) {
+ // Namespaced trigger; create a regexp to match event type in handle()
+ namespaces = type.split(".");
+ type = namespaces.shift();
+ namespaces.sort();
+ }
+ ontype = type.indexOf(":") < 0 && "on" + type;
+
+ // Caller can pass in a jQuery.Event object, Object, or just an event type string
+ event = event[ jQuery.expando ] ?
+ event :
+ new jQuery.Event( type, typeof event === "object" && event );
+
+ // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
+ event.isTrigger = onlyHandlers ? 2 : 3;
+ event.namespace = namespaces.join(".");
+ event.namespace_re = event.namespace ?
+ new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
+ null;
+
+ // Clean up the event in case it is being reused
+ event.result = undefined;
+ if ( !event.target ) {
+ event.target = elem;
+ }
+
+ // Clone any incoming data and prepend the event, creating the handler arg list
+ data = data == null ?
+ [ event ] :
+ jQuery.makeArray( data, [ event ] );
+
+ // Allow special events to draw outside the lines
+ special = jQuery.event.special[ type ] || {};
+ if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
+ return;
+ }
+
+ // Determine event propagation path in advance, per W3C events spec (#9951)
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+ if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+ bubbleType = special.delegateType || type;
+ if ( !rfocusMorph.test( bubbleType + type ) ) {
+ cur = cur.parentNode;
+ }
+ for ( ; cur; cur = cur.parentNode ) {
+ eventPath.push( cur );
+ tmp = cur;
+ }
+
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
+ if ( tmp === (elem.ownerDocument || document) ) {
+ eventPath.push( tmp.defaultView || tmp.parentWindow || window );
+ }
+ }
+
+ // Fire handlers on the event path
+ i = 0;
+ while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
+
+ event.type = i > 1 ?
+ bubbleType :
+ special.bindType || type;
+
+ // jQuery handler
+ handle = ( data_priv.get( cur, "events" ) || {} )[ event.type ] && data_priv.get( cur, "handle" );
+ if ( handle ) {
+ handle.apply( cur, data );
+ }
+
+ // Native handler
+ handle = ontype && cur[ ontype ];
+ if ( handle && handle.apply && jQuery.acceptData( cur ) ) {
+ event.result = handle.apply( cur, data );
+ if ( event.result === false ) {
+ event.preventDefault();
+ }
+ }
+ }
+ event.type = type;
+
+ // If nobody prevented the default action, do it now
+ if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+ if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
+ jQuery.acceptData( elem ) ) {
+
+ // Call a native DOM method on the target with the same name name as the event.
+ // Don't do default actions on window, that's where global variables be (#6170)
+ if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {
+
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ tmp = elem[ ontype ];
+
+ if ( tmp ) {
+ elem[ ontype ] = null;
+ }
+
+ // Prevent re-triggering of the same event, since we already bubbled it above
+ jQuery.event.triggered = type;
+ elem[ type ]();
+ jQuery.event.triggered = undefined;
+
+ if ( tmp ) {
+ elem[ ontype ] = tmp;
+ }
+ }
+ }
+ }
+
+ return event.result;
+ },
+
+ dispatch: function( event ) {
+
+ // Make a writable jQuery.Event from the native event object
+ event = jQuery.event.fix( event );
+
+ var i, j, ret, matched, handleObj,
+ handlerQueue = [],
+ args = slice.call( arguments ),
+ handlers = ( data_priv.get( this, "events" ) || {} )[ event.type ] || [],
+ special = jQuery.event.special[ event.type ] || {};
+
+ // Use the fix-ed jQuery.Event rather than the (read-only) native event
+ args[0] = event;
+ event.delegateTarget = this;
+
+ // Call the preDispatch hook for the mapped type, and let it bail if desired
+ if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+ return;
+ }
+
+ // Determine handlers
+ handlerQueue = jQuery.event.handlers.call( this, event, handlers );
+
+ // Run delegates first; they may want to stop propagation beneath us
+ i = 0;
+ while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
+ event.currentTarget = matched.elem;
+
+ j = 0;
+ while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
+
+ // Triggered event must either 1) have no namespace, or 2) have namespace(s)
+ // a subset or equal to those in the bound event (both can have no namespace).
+ if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
+
+ event.handleObj = handleObj;
+ event.data = handleObj.data;
+
+ ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+ .apply( matched.elem, args );
+
+ if ( ret !== undefined ) {
+ if ( (event.result = ret) === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+ }
+ }
+ }
+
+ // Call the postDispatch hook for the mapped type
+ if ( special.postDispatch ) {
+ special.postDispatch.call( this, event );
+ }
+
+ return event.result;
+ },
+
+ handlers: function( event, handlers ) {
+ var i, matches, sel, handleObj,
+ handlerQueue = [],
+ delegateCount = handlers.delegateCount,
+ cur = event.target;
+
+ // Find delegate handlers
+ // Black-hole SVG <use> instance trees (#13180)
+ // Avoid non-left-click bubbling in Firefox (#3861)
+ if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
+
+ for ( ; cur !== this; cur = cur.parentNode || this ) {
+
+ // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
+ if ( cur.disabled !== true || event.type !== "click" ) {
+ matches = [];
+ for ( i = 0; i < delegateCount; i++ ) {
+ handleObj = handlers[ i ];
+
+ // Don't conflict with Object.prototype properties (#13203)
+ sel = handleObj.selector + " ";
+
+ if ( matches[ sel ] === undefined ) {
+ matches[ sel ] = handleObj.needsContext ?
+ jQuery( sel, this ).index( cur ) >= 0 :
+ jQuery.find( sel, this, null, [ cur ] ).length;
+ }
+ if ( matches[ sel ] ) {
+ matches.push( handleObj );
+ }
+ }
+ if ( matches.length ) {
+ handlerQueue.push({ elem: cur, handlers: matches });
+ }
+ }
+ }
+ }
+
+ // Add the remaining (directly-bound) handlers
+ if ( delegateCount < handlers.length ) {
+ handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
+ }
+
+ return handlerQueue;
+ },
+
+ // Includes some event props shared by KeyEvent and MouseEvent
+ props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
+
+ fixHooks: {},
+
+ keyHooks: {
+ props: "char charCode key keyCode".split(" "),
+ filter: function( event, original ) {
+
+ // Add which for key events
+ if ( event.which == null ) {
+ event.which = original.charCode != null ? original.charCode : original.keyCode;
+ }
+
+ return event;
+ }
+ },
+
+ mouseHooks: {
+ props: "button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
+ filter: function( event, original ) {
+ var eventDoc, doc, body,
+ button = original.button;
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && original.clientX != null ) {
+ eventDoc = event.target.ownerDocument || document;
+ doc = eventDoc.documentElement;
+ body = eventDoc.body;
+
+ event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
+ event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
+ }
+
+ // Add which for click: 1 === left; 2 === middle; 3 === right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && button !== undefined ) {
+ event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
+ }
+
+ return event;
+ }
+ },
+
+ fix: function( event ) {
+ if ( event[ jQuery.expando ] ) {
+ return event;
+ }
+
+ // Create a writable copy of the event object and normalize some properties
+ var i, prop, copy,
+ type = event.type,
+ originalEvent = event,
+ fixHook = this.fixHooks[ type ];
+
+ if ( !fixHook ) {
+ this.fixHooks[ type ] = fixHook =
+ rmouseEvent.test( type ) ? this.mouseHooks :
+ rkeyEvent.test( type ) ? this.keyHooks :
+ {};
+ }
+ copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
+
+ event = new jQuery.Event( originalEvent );
+
+ i = copy.length;
+ while ( i-- ) {
+ prop = copy[ i ];
+ event[ prop ] = originalEvent[ prop ];
+ }
+
+ // Support: Cordova 2.5 (WebKit) (#13255)
+ // All events should have a target; Cordova deviceready doesn't
+ if ( !event.target ) {
+ event.target = document;
+ }
+
+ // Support: Safari 6.0+, Chrome<28
+ // Target should not be a text node (#504, #13143)
+ if ( event.target.nodeType === 3 ) {
+ event.target = event.target.parentNode;
+ }
+
+ return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
+ },
+
+ special: {
+ load: {
+ // Prevent triggered image.load events from bubbling to window.load
+ noBubble: true
+ },
+ focus: {
+ // Fire native event if possible so blur/focus sequence is correct
+ trigger: function() {
+ if ( this !== safeActiveElement() && this.focus ) {
+ this.focus();
+ return false;
+ }
+ },
+ delegateType: "focusin"
+ },
+ blur: {
+ trigger: function() {
+ if ( this === safeActiveElement() && this.blur ) {
+ this.blur();
+ return false;
+ }
+ },
+ delegateType: "focusout"
+ },
+ click: {
+ // For checkbox, fire native event so checked state will be right
+ trigger: function() {
+ if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) {
+ this.click();
+ return false;
+ }
+ },
+
+ // For cross-browser consistency, don't fire native .click() on links
+ _default: function( event ) {
+ return jQuery.nodeName( event.target, "a" );
+ }
+ },
+
+ beforeunload: {
+ postDispatch: function( event ) {
+
+ // Support: Firefox 20+
+ // Firefox doesn't alert if the returnValue field is not set.
+ if ( event.result !== undefined && event.originalEvent ) {
+ event.originalEvent.returnValue = event.result;
+ }
+ }
+ }
+ },
+
+ simulate: function( type, elem, event, bubble ) {
+ // Piggyback on a donor event to simulate a different one.
+ // Fake originalEvent to avoid donor's stopPropagation, but if the
+ // simulated event prevents default then we do the same on the donor.
+ var e = jQuery.extend(
+ new jQuery.Event(),
+ event,
+ {
+ type: type,
+ isSimulated: true,
+ originalEvent: {}
+ }
+ );
+ if ( bubble ) {
+ jQuery.event.trigger( e, null, elem );
+ } else {
+ jQuery.event.dispatch.call( elem, e );
+ }
+ if ( e.isDefaultPrevented() ) {
+ event.preventDefault();
+ }
+ }
+};
+
+jQuery.removeEvent = function( elem, type, handle ) {
+ if ( elem.removeEventListener ) {
+ elem.removeEventListener( type, handle, false );
+ }
+};
+
+jQuery.Event = function( src, props ) {
+ // Allow instantiation without the 'new' keyword
+ if ( !(this instanceof jQuery.Event) ) {
+ return new jQuery.Event( src, props );
+ }
+
+ // Event object
+ if ( src && src.type ) {
+ this.originalEvent = src;
+ this.type = src.type;
+
+ // Events bubbling up the document may have been marked as prevented
+ // by a handler lower down the tree; reflect the correct value.
+ this.isDefaultPrevented = src.defaultPrevented ||
+ src.defaultPrevented === undefined &&
+ // Support: Android<4.0
+ src.returnValue === false ?
+ returnTrue :
+ returnFalse;
+
+ // Event type
+ } else {
+ this.type = src;
+ }
+
+ // Put explicitly provided properties onto the event object
+ if ( props ) {
+ jQuery.extend( this, props );
+ }
+
+ // Create a timestamp if incoming event doesn't have one
+ this.timeStamp = src && src.timeStamp || jQuery.now();
+
+ // Mark it as fixed
+ this[ jQuery.expando ] = true;
+};
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+ isDefaultPrevented: returnFalse,
+ isPropagationStopped: returnFalse,
+ isImmediatePropagationStopped: returnFalse,
+
+ preventDefault: function() {
+ var e = this.originalEvent;
+
+ this.isDefaultPrevented = returnTrue;
+
+ if ( e && e.preventDefault ) {
+ e.preventDefault();
+ }
+ },
+ stopPropagation: function() {
+ var e = this.originalEvent;
+
+ this.isPropagationStopped = returnTrue;
+
+ if ( e && e.stopPropagation ) {
+ e.stopPropagation();
+ }
+ },
+ stopImmediatePropagation: function() {
+ var e = this.originalEvent;
+
+ this.isImmediatePropagationStopped = returnTrue;
+
+ if ( e && e.stopImmediatePropagation ) {
+ e.stopImmediatePropagation();
+ }
+
+ this.stopPropagation();
+ }
+};
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+// Support: Chrome 15+
+jQuery.each({
+ mouseenter: "mouseover",
+ mouseleave: "mouseout",
+ pointerenter: "pointerover",
+ pointerleave: "pointerout"
+}, function( orig, fix ) {
+ jQuery.event.special[ orig ] = {
+ delegateType: fix,
+ bindType: fix,
+
+ handle: function( event ) {
+ var ret,
+ target = this,
+ related = event.relatedTarget,
+ handleObj = event.handleObj;
+
+ // For mousenter/leave call the handler if related is outside the target.
+ // NB: No relatedTarget if the mouse left/entered the browser window
+ if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
+ event.type = handleObj.origType;
+ ret = handleObj.handler.apply( this, arguments );
+ event.type = fix;
+ }
+ return ret;
+ }
+ };
+});
+
+// Support: Firefox, Chrome, Safari
+// Create "bubbling" focus and blur events
+if ( !support.focusinBubbles ) {
+ jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+ // Attach a single capturing handler on the document while someone wants focusin/focusout
+ var handler = function( event ) {
+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
+ };
+
+ jQuery.event.special[ fix ] = {
+ setup: function() {
+ var doc = this.ownerDocument || this,
+ attaches = data_priv.access( doc, fix );
+
+ if ( !attaches ) {
+ doc.addEventListener( orig, handler, true );
+ }
+ data_priv.access( doc, fix, ( attaches || 0 ) + 1 );
+ },
+ teardown: function() {
+ var doc = this.ownerDocument || this,
+ attaches = data_priv.access( doc, fix ) - 1;
+
+ if ( !attaches ) {
+ doc.removeEventListener( orig, handler, true );
+ data_priv.remove( doc, fix );
+
+ } else {
+ data_priv.access( doc, fix, attaches );
+ }
+ }
+ };
+ });
+}
+
+jQuery.fn.extend({
+
+ on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+ var origFn, type;
+
+ // Types can be a map of types/handlers
+ if ( typeof types === "object" ) {
+ // ( types-Object, selector, data )
+ if ( typeof selector !== "string" ) {
+ // ( types-Object, data )
+ data = data || selector;
+ selector = undefined;
+ }
+ for ( type in types ) {
+ this.on( type, selector, data, types[ type ], one );
+ }
+ return this;
+ }
+
+ if ( data == null && fn == null ) {
+ // ( types, fn )
+ fn = selector;
+ data = selector = undefined;
+ } else if ( fn == null ) {
+ if ( typeof selector === "string" ) {
+ // ( types, selector, fn )
+ fn = data;
+ data = undefined;
+ } else {
+ // ( types, data, fn )
+ fn = data;
+ data = selector;
+ selector = undefined;
+ }
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ } else if ( !fn ) {
+ return this;
+ }
+
+ if ( one === 1 ) {
+ origFn = fn;
+ fn = function( event ) {
+ // Can use an empty set, since event contains the info
+ jQuery().off( event );
+ return origFn.apply( this, arguments );
+ };
+ // Use same guid so caller can remove using origFn
+ fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+ }
+ return this.each( function() {
+ jQuery.event.add( this, types, fn, data, selector );
+ });
+ },
+ one: function( types, selector, data, fn ) {
+ return this.on( types, selector, data, fn, 1 );
+ },
+ off: function( types, selector, fn ) {
+ var handleObj, type;
+ if ( types && types.preventDefault && types.handleObj ) {
+ // ( event ) dispatched jQuery.Event
+ handleObj = types.handleObj;
+ jQuery( types.delegateTarget ).off(
+ handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
+ handleObj.selector,
+ handleObj.handler
+ );
+ return this;
+ }
+ if ( typeof types === "object" ) {
+ // ( types-object [, selector] )
+ for ( type in types ) {
+ this.off( type, selector, types[ type ] );
+ }
+ return this;
+ }
+ if ( selector === false || typeof selector === "function" ) {
+ // ( types [, fn] )
+ fn = selector;
+ selector = undefined;
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ }
+ return this.each(function() {
+ jQuery.event.remove( this, types, fn, selector );
+ });
+ },
+
+ trigger: function( type, data ) {
+ return this.each(function() {
+ jQuery.event.trigger( type, data, this );
+ });
+ },
+ triggerHandler: function( type, data ) {
+ var elem = this[0];
+ if ( elem ) {
+ return jQuery.event.trigger( type, data, elem, true );
+ }
+ }
+});
+
+
+var
+ rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
+ rtagName = /<([\w:]+)/,
+ rhtml = /<|&#?\w+;/,
+ rnoInnerhtml = /<(?:script|style|link)/i,
+ // checked="checked" or checked
+ rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+ rscriptType = /^$|\/(?:java|ecma)script/i,
+ rscriptTypeMasked = /^true\/(.*)/,
+ rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
+
+ // We have to close these tags to support XHTML (#13200)
+ wrapMap = {
+
+ // Support: IE9
+ option: [ 1, "<select multiple='multiple'>", "</select>" ],
+
+ thead: [ 1, "<table>", "</table>" ],
+ col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
+ tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+ td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+
+ _default: [ 0, "", "" ]
+ };
+
+// Support: IE9
+wrapMap.optgroup = wrapMap.option;
+
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+// Support: 1.x compatibility
+// Manipulating tables requires a tbody
+function manipulationTarget( elem, content ) {
+ return jQuery.nodeName( elem, "table" ) &&
+ jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ?
+
+ elem.getElementsByTagName("tbody")[0] ||
+ elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
+ elem;
+}
+
+// Replace/restore the type attribute of script elements for safe DOM manipulation
+function disableScript( elem ) {
+ elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type;
+ return elem;
+}
+function restoreScript( elem ) {
+ var match = rscriptTypeMasked.exec( elem.type );
+
+ if ( match ) {
+ elem.type = match[ 1 ];
+ } else {
+ elem.removeAttribute("type");
+ }
+
+ return elem;
+}
+
+// Mark scripts as having already been evaluated
+function setGlobalEval( elems, refElements ) {
+ var i = 0,
+ l = elems.length;
+
+ for ( ; i < l; i++ ) {
+ data_priv.set(
+ elems[ i ], "globalEval", !refElements || data_priv.get( refElements[ i ], "globalEval" )
+ );
+ }
+}
+
+function cloneCopyEvent( src, dest ) {
+ var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
+
+ if ( dest.nodeType !== 1 ) {
+ return;
+ }
+
+ // 1. Copy private data: events, handlers, etc.
+ if ( data_priv.hasData( src ) ) {
+ pdataOld = data_priv.access( src );
+ pdataCur = data_priv.set( dest, pdataOld );
+ events = pdataOld.events;
+
+ if ( events ) {
+ delete pdataCur.handle;
+ pdataCur.events = {};
+
+ for ( type in events ) {
+ for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+ jQuery.event.add( dest, type, events[ type ][ i ] );
+ }
+ }
+ }
+ }
+
+ // 2. Copy user data
+ if ( data_user.hasData( src ) ) {
+ udataOld = data_user.access( src );
+ udataCur = jQuery.extend( {}, udataOld );
+
+ data_user.set( dest, udataCur );
+ }
+}
+
+function getAll( context, tag ) {
+ var ret = context.getElementsByTagName ? context.getElementsByTagName( tag || "*" ) :
+ context.querySelectorAll ? context.querySelectorAll( tag || "*" ) :
+ [];
+
+ return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
+ jQuery.merge( [ context ], ret ) :
+ ret;
+}
+
+// Fix IE bugs, see support tests
+function fixInput( src, dest ) {
+ var nodeName = dest.nodeName.toLowerCase();
+
+ // Fails to persist the checked state of a cloned checkbox or radio button.
+ if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
+ dest.checked = src.checked;
+
+ // Fails to return the selected option to the default selected state when cloning options
+ } else if ( nodeName === "input" || nodeName === "textarea" ) {
+ dest.defaultValue = src.defaultValue;
+ }
+}
+
+jQuery.extend({
+ clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+ var i, l, srcElements, destElements,
+ clone = elem.cloneNode( true ),
+ inPage = jQuery.contains( elem.ownerDocument, elem );
+
+ // Fix IE cloning issues
+ if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
+ !jQuery.isXMLDoc( elem ) ) {
+
+ // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
+ destElements = getAll( clone );
+ srcElements = getAll( elem );
+
+ for ( i = 0, l = srcElements.length; i < l; i++ ) {
+ fixInput( srcElements[ i ], destElements[ i ] );
+ }
+ }
+
+ // Copy the events from the original to the clone
+ if ( dataAndEvents ) {
+ if ( deepDataAndEvents ) {
+ srcElements = srcElements || getAll( elem );
+ destElements = destElements || getAll( clone );
+
+ for ( i = 0, l = srcElements.length; i < l; i++ ) {
+ cloneCopyEvent( srcElements[ i ], destElements[ i ] );
+ }
+ } else {
+ cloneCopyEvent( elem, clone );
+ }
+ }
+
+ // Preserve script evaluation history
+ destElements = getAll( clone, "script" );
+ if ( destElements.length > 0 ) {
+ setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
+ }
+
+ // Return the cloned set
+ return clone;
+ },
+
+ buildFragment: function( elems, context, scripts, selection ) {
+ var elem, tmp, tag, wrap, contains, j,
+ fragment = context.createDocumentFragment(),
+ nodes = [],
+ i = 0,
+ l = elems.length;
+
+ for ( ; i < l; i++ ) {
+ elem = elems[ i ];
+
+ if ( elem || elem === 0 ) {
+
+ // Add nodes directly
+ if ( jQuery.type( elem ) === "object" ) {
+ // Support: QtWebKit, PhantomJS
+ // push.apply(_, arraylike) throws on ancient WebKit
+ jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
+
+ // Convert non-html into a text node
+ } else if ( !rhtml.test( elem ) ) {
+ nodes.push( context.createTextNode( elem ) );
+
+ // Convert html into DOM nodes
+ } else {
+ tmp = tmp || fragment.appendChild( context.createElement("div") );
+
+ // Deserialize a standard representation
+ tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
+ wrap = wrapMap[ tag ] || wrapMap._default;
+ tmp.innerHTML = wrap[ 1 ] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[ 2 ];
+
+ // Descend through wrappers to the right content
+ j = wrap[ 0 ];
+ while ( j-- ) {
+ tmp = tmp.lastChild;
+ }
+
+ // Support: QtWebKit, PhantomJS
+ // push.apply(_, arraylike) throws on ancient WebKit
+ jQuery.merge( nodes, tmp.childNodes );
+
+ // Remember the top-level container
+ tmp = fragment.firstChild;
+
+ // Ensure the created nodes are orphaned (#12392)
+ tmp.textContent = "";
+ }
+ }
+ }
+
+ // Remove wrapper from fragment
+ fragment.textContent = "";
+
+ i = 0;
+ while ( (elem = nodes[ i++ ]) ) {
+
+ // #4087 - If origin and destination elements are the same, and this is
+ // that element, do not do anything
+ if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
+ continue;
+ }
+
+ contains = jQuery.contains( elem.ownerDocument, elem );
+
+ // Append to fragment
+ tmp = getAll( fragment.appendChild( elem ), "script" );
+
+ // Preserve script evaluation history
+ if ( contains ) {
+ setGlobalEval( tmp );
+ }
+
+ // Capture executables
+ if ( scripts ) {
+ j = 0;
+ while ( (elem = tmp[ j++ ]) ) {
+ if ( rscriptType.test( elem.type || "" ) ) {
+ scripts.push( elem );
+ }
+ }
+ }
+ }
+
+ return fragment;
+ },
+
+ cleanData: function( elems ) {
+ var data, elem, type, key,
+ special = jQuery.event.special,
+ i = 0;
+
+ for ( ; (elem = elems[ i ]) !== undefined; i++ ) {
+ if ( jQuery.acceptData( elem ) ) {
+ key = elem[ data_priv.expando ];
+
+ if ( key && (data = data_priv.cache[ key ]) ) {
+ if ( data.events ) {
+ for ( type in data.events ) {
+ if ( special[ type ] ) {
+ jQuery.event.remove( elem, type );
+
+ // This is a shortcut to avoid jQuery.event.remove's overhead
+ } else {
+ jQuery.removeEvent( elem, type, data.handle );
+ }
+ }
+ }
+ if ( data_priv.cache[ key ] ) {
+ // Discard any remaining `private` data
+ delete data_priv.cache[ key ];
+ }
+ }
+ }
+ // Discard any remaining `user` data
+ delete data_user.cache[ elem[ data_user.expando ] ];
+ }
+ }
+});
+
+jQuery.fn.extend({
+ text: function( value ) {
+ return access( this, function( value ) {
+ return value === undefined ?
+ jQuery.text( this ) :
+ this.empty().each(function() {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ this.textContent = value;
+ }
+ });
+ }, null, value, arguments.length );
+ },
+
+ append: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ var target = manipulationTarget( this, elem );
+ target.appendChild( elem );
+ }
+ });
+ },
+
+ prepend: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ var target = manipulationTarget( this, elem );
+ target.insertBefore( elem, target.firstChild );
+ }
+ });
+ },
+
+ before: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this );
+ }
+ });
+ },
+
+ after: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ }
+ });
+ },
+
+ remove: function( selector, keepData /* Internal Use Only */ ) {
+ var elem,
+ elems = selector ? jQuery.filter( selector, this ) : this,
+ i = 0;
+
+ for ( ; (elem = elems[i]) != null; i++ ) {
+ if ( !keepData && elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem ) );
+ }
+
+ if ( elem.parentNode ) {
+ if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
+ setGlobalEval( getAll( elem, "script" ) );
+ }
+ elem.parentNode.removeChild( elem );
+ }
+ }
+
+ return this;
+ },
+
+ empty: function() {
+ var elem,
+ i = 0;
+
+ for ( ; (elem = this[i]) != null; i++ ) {
+ if ( elem.nodeType === 1 ) {
+
+ // Prevent memory leaks
+ jQuery.cleanData( getAll( elem, false ) );
+
+ // Remove any remaining nodes
+ elem.textContent = "";
+ }
+ }
+
+ return this;
+ },
+
+ clone: function( dataAndEvents, deepDataAndEvents ) {
+ dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+ deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+ return this.map(function() {
+ return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+ });
+ },
+
+ html: function( value ) {
+ return access( this, function( value ) {
+ var elem = this[ 0 ] || {},
+ i = 0,
+ l = this.length;
+
+ if ( value === undefined && elem.nodeType === 1 ) {
+ return elem.innerHTML;
+ }
+
+ // See if we can take a shortcut and just use innerHTML
+ if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+ !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
+
+ value = value.replace( rxhtmlTag, "<$1></$2>" );
+
+ try {
+ for ( ; i < l; i++ ) {
+ elem = this[ i ] || {};
+
+ // Remove element nodes and prevent memory leaks
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem, false ) );
+ elem.innerHTML = value;
+ }
+ }
+
+ elem = 0;
+
+ // If using innerHTML throws an exception, use the fallback method
+ } catch( e ) {}
+ }
+
+ if ( elem ) {
+ this.empty().append( value );
+ }
+ }, null, value, arguments.length );
+ },
+
+ replaceWith: function() {
+ var arg = arguments[ 0 ];
+
+ // Make the changes, replacing each context element with the new content
+ this.domManip( arguments, function( elem ) {
+ arg = this.parentNode;
+
+ jQuery.cleanData( getAll( this ) );
+
+ if ( arg ) {
+ arg.replaceChild( elem, this );
+ }
+ });
+
+ // Force removal if there was no new content (e.g., from empty arguments)
+ return arg && (arg.length || arg.nodeType) ? this : this.remove();
+ },
+
+ detach: function( selector ) {
+ return this.remove( selector, true );
+ },
+
+ domManip: function( args, callback ) {
+
+ // Flatten any nested arrays
+ args = concat.apply( [], args );
+
+ var fragment, first, scripts, hasScripts, node, doc,
+ i = 0,
+ l = this.length,
+ set = this,
+ iNoClone = l - 1,
+ value = args[ 0 ],
+ isFunction = jQuery.isFunction( value );
+
+ // We can't cloneNode fragments that contain checked, in WebKit
+ if ( isFunction ||
+ ( l > 1 && typeof value === "string" &&
+ !support.checkClone && rchecked.test( value ) ) ) {
+ return this.each(function( index ) {
+ var self = set.eq( index );
+ if ( isFunction ) {
+ args[ 0 ] = value.call( this, index, self.html() );
+ }
+ self.domManip( args, callback );
+ });
+ }
+
+ if ( l ) {
+ fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
+ first = fragment.firstChild;
+
+ if ( fragment.childNodes.length === 1 ) {
+ fragment = first;
+ }
+
+ if ( first ) {
+ scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
+ hasScripts = scripts.length;
+
+ // Use the original fragment for the last item instead of the first because it can end up
+ // being emptied incorrectly in certain situations (#8070).
+ for ( ; i < l; i++ ) {
+ node = fragment;
+
+ if ( i !== iNoClone ) {
+ node = jQuery.clone( node, true, true );
+
+ // Keep references to cloned scripts for later restoration
+ if ( hasScripts ) {
+ // Support: QtWebKit
+ // jQuery.merge because push.apply(_, arraylike) throws
+ jQuery.merge( scripts, getAll( node, "script" ) );
+ }
+ }
+
+ callback.call( this[ i ], node, i );
+ }
+
+ if ( hasScripts ) {
+ doc = scripts[ scripts.length - 1 ].ownerDocument;
+
+ // Reenable scripts
+ jQuery.map( scripts, restoreScript );
+
+ // Evaluate executable scripts on first document insertion
+ for ( i = 0; i < hasScripts; i++ ) {
+ node = scripts[ i ];
+ if ( rscriptType.test( node.type || "" ) &&
+ !data_priv.access( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
+
+ if ( node.src ) {
+ // Optional AJAX dependency, but won't run scripts if not present
+ if ( jQuery._evalUrl ) {
+ jQuery._evalUrl( node.src );
+ }
+ } else {
+ jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return this;
+ }
+});
+
+jQuery.each({
+ appendTo: "append",
+ prependTo: "prepend",
+ insertBefore: "before",
+ insertAfter: "after",
+ replaceAll: "replaceWith"
+}, function( name, original ) {
+ jQuery.fn[ name ] = function( selector ) {
+ var elems,
+ ret = [],
+ insert = jQuery( selector ),
+ last = insert.length - 1,
+ i = 0;
+
+ for ( ; i <= last; i++ ) {
+ elems = i === last ? this : this.clone( true );
+ jQuery( insert[ i ] )[ original ]( elems );
+
+ // Support: QtWebKit
+ // .get() because push.apply(_, arraylike) throws
+ push.apply( ret, elems.get() );
+ }
+
+ return this.pushStack( ret );
+ };
+});
+
+
+var iframe,
+ elemdisplay = {};
+
+/**
+ * Retrieve the actual display of a element
+ * @param {String} name nodeName of the element
+ * @param {Object} doc Document object
+ */
+// Called only from within defaultDisplay
+function actualDisplay( name, doc ) {
+ var style,
+ elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
+
+ // getDefaultComputedStyle might be reliably used only on attached element
+ display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ?
+
+ // Use of this method is a temporary fix (more like optimization) until something better comes along,
+ // since it was removed from specification and supported only in FF
+ style.display : jQuery.css( elem[ 0 ], "display" );
+
+ // We don't have any data stored on the element,
+ // so use "detach" method as fast way to get rid of the element
+ elem.detach();
+
+ return display;
+}
+
+/**
+ * Try to determine the default display value of an element
+ * @param {String} nodeName
+ */
+function defaultDisplay( nodeName ) {
+ var doc = document,
+ display = elemdisplay[ nodeName ];
+
+ if ( !display ) {
+ display = actualDisplay( nodeName, doc );
+
+ // If the simple way fails, read from inside an iframe
+ if ( display === "none" || !display ) {
+
+ // Use the already-created iframe if possible
+ iframe = (iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" )).appendTo( doc.documentElement );
+
+ // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
+ doc = iframe[ 0 ].contentDocument;
+
+ // Support: IE
+ doc.write();
+ doc.close();
+
+ display = actualDisplay( nodeName, doc );
+ iframe.detach();
+ }
+
+ // Store the correct default display
+ elemdisplay[ nodeName ] = display;
+ }
+
+ return display;
+}
+var rmargin = (/^margin/);
+
+var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
+
+var getStyles = function( elem ) {
+ // Support: IE<=11+, Firefox<=30+ (#15098, #14150)
+ // IE throws on elements created in popups
+ // FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
+ if ( elem.ownerDocument.defaultView.opener ) {
+ return elem.ownerDocument.defaultView.getComputedStyle( elem, null );
+ }
+
+ return window.getComputedStyle( elem, null );
+ };
+
+
+
+function curCSS( elem, name, computed ) {
+ var width, minWidth, maxWidth, ret,
+ style = elem.style;
+
+ computed = computed || getStyles( elem );
+
+ // Support: IE9
+ // getPropertyValue is only needed for .css('filter') (#12537)
+ if ( computed ) {
+ ret = computed.getPropertyValue( name ) || computed[ name ];
+ }
+
+ if ( computed ) {
+
+ if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
+ ret = jQuery.style( elem, name );
+ }
+
+ // Support: iOS < 6
+ // A tribute to the "awesome hack by Dean Edwards"
+ // iOS < 6 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
+ // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
+ if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
+
+ // Remember the original values
+ width = style.width;
+ minWidth = style.minWidth;
+ maxWidth = style.maxWidth;
+
+ // Put in the new values to get a computed value out
+ style.minWidth = style.maxWidth = style.width = ret;
+ ret = computed.width;
+
+ // Revert the changed values
+ style.width = width;
+ style.minWidth = minWidth;
+ style.maxWidth = maxWidth;
+ }
+ }
+
+ return ret !== undefined ?
+ // Support: IE
+ // IE returns zIndex value as an integer.
+ ret + "" :
+ ret;
+}
+
+
+function addGetHookIf( conditionFn, hookFn ) {
+ // Define the hook, we'll check on the first run if it's really needed.
+ return {
+ get: function() {
+ if ( conditionFn() ) {
+ // Hook not needed (or it's not possible to use it due
+ // to missing dependency), remove it.
+ delete this.get;
+ return;
+ }
+
+ // Hook needed; redefine it so that the support test is not executed again.
+ return (this.get = hookFn).apply( this, arguments );
+ }
+ };
+}
+
+
+(function() {
+ var pixelPositionVal, boxSizingReliableVal,
+ docElem = document.documentElement,
+ container = document.createElement( "div" ),
+ div = document.createElement( "div" );
+
+ if ( !div.style ) {
+ return;
+ }
+
+ // Support: IE9-11+
+ // Style of cloned element affects source element cloned (#8908)
+ div.style.backgroundClip = "content-box";
+ div.cloneNode( true ).style.backgroundClip = "";
+ support.clearCloneStyle = div.style.backgroundClip === "content-box";
+
+ container.style.cssText = "border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;" +
+ "position:absolute";
+ container.appendChild( div );
+
+ // Executing both pixelPosition & boxSizingReliable tests require only one layout
+ // so they're executed at the same time to save the second computation.
+ function computePixelPositionAndBoxSizingReliable() {
+ div.style.cssText =
+ // Support: Firefox<29, Android 2.3
+ // Vendor-prefix box-sizing
+ "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;" +
+ "box-sizing:border-box;display:block;margin-top:1%;top:1%;" +
+ "border:1px;padding:1px;width:4px;position:absolute";
+ div.innerHTML = "";
+ docElem.appendChild( container );
+
+ var divStyle = window.getComputedStyle( div, null );
+ pixelPositionVal = divStyle.top !== "1%";
+ boxSizingReliableVal = divStyle.width === "4px";
+
+ docElem.removeChild( container );
+ }
+
+ // Support: node.js jsdom
+ // Don't assume that getComputedStyle is a property of the global object
+ if ( window.getComputedStyle ) {
+ jQuery.extend( support, {
+ pixelPosition: function() {
+
+ // This test is executed only once but we still do memoizing
+ // since we can use the boxSizingReliable pre-computing.
+ // No need to check if the test was already performed, though.
+ computePixelPositionAndBoxSizingReliable();
+ return pixelPositionVal;
+ },
+ boxSizingReliable: function() {
+ if ( boxSizingReliableVal == null ) {
+ computePixelPositionAndBoxSizingReliable();
+ }
+ return boxSizingReliableVal;
+ },
+ reliableMarginRight: function() {
+
+ // Support: Android 2.3
+ // Check if div with explicit width and no margin-right incorrectly
+ // gets computed margin-right based on width of container. (#3333)
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ // This support function is only executed once so no memoizing is needed.
+ var ret,
+ marginDiv = div.appendChild( document.createElement( "div" ) );
+
+ // Reset CSS: box-sizing; display; margin; border; padding
+ marginDiv.style.cssText = div.style.cssText =
+ // Support: Firefox<29, Android 2.3
+ // Vendor-prefix box-sizing
+ "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
+ "box-sizing:content-box;display:block;margin:0;border:0;padding:0";
+ marginDiv.style.marginRight = marginDiv.style.width = "0";
+ div.style.width = "1px";
+ docElem.appendChild( container );
+
+ ret = !parseFloat( window.getComputedStyle( marginDiv, null ).marginRight );
+
+ docElem.removeChild( container );
+ div.removeChild( marginDiv );
+
+ return ret;
+ }
+ });
+ }
+})();
+
+
+// A method for quickly swapping in/out CSS properties to get correct calculations.
+jQuery.swap = function( elem, options, callback, args ) {
+ var ret, name,
+ old = {};
+
+ // Remember the old values, and insert the new ones
+ for ( name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ ret = callback.apply( elem, args || [] );
+
+ // Revert the old values
+ for ( name in options ) {
+ elem.style[ name ] = old[ name ];
+ }
+
+ return ret;
+};
+
+
+var
+ // Swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
+ // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+ rdisplayswap = /^(none|table(?!-c[ea]).+)/,
+ rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ),
+ rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ),
+
+ cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+ cssNormalTransform = {
+ letterSpacing: "0",
+ fontWeight: "400"
+ },
+
+ cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
+
+// Return a css property mapped to a potentially vendor prefixed property
+function vendorPropName( style, name ) {
+
+ // Shortcut for names that are not vendor prefixed
+ if ( name in style ) {
+ return name;
+ }
+
+ // Check for vendor prefixed names
+ var capName = name[0].toUpperCase() + name.slice(1),
+ origName = name,
+ i = cssPrefixes.length;
+
+ while ( i-- ) {
+ name = cssPrefixes[ i ] + capName;
+ if ( name in style ) {
+ return name;
+ }
+ }
+
+ return origName;
+}
+
+function setPositiveNumber( elem, value, subtract ) {
+ var matches = rnumsplit.exec( value );
+ return matches ?
+ // Guard against undefined "subtract", e.g., when used as in cssHooks
+ Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
+ value;
+}
+
+function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
+ var i = extra === ( isBorderBox ? "border" : "content" ) ?
+ // If we already have the right measurement, avoid augmentation
+ 4 :
+ // Otherwise initialize for horizontal or vertical properties
+ name === "width" ? 1 : 0,
+
+ val = 0;
+
+ for ( ; i < 4; i += 2 ) {
+ // Both box models exclude margin, so add it if we want it
+ if ( extra === "margin" ) {
+ val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
+ }
+
+ if ( isBorderBox ) {
+ // border-box includes padding, so remove it if we want content
+ if ( extra === "content" ) {
+ val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+ }
+
+ // At this point, extra isn't border nor margin, so remove border
+ if ( extra !== "margin" ) {
+ val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+ } else {
+ // At this point, extra isn't content, so add padding
+ val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+
+ // At this point, extra isn't content nor padding, so add border
+ if ( extra !== "padding" ) {
+ val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+ }
+ }
+
+ return val;
+}
+
+function getWidthOrHeight( elem, name, extra ) {
+
+ // Start with offset property, which is equivalent to the border-box value
+ var valueIsBorderBox = true,
+ val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+ styles = getStyles( elem ),
+ isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
+
+ // Some non-html elements return undefined for offsetWidth, so check for null/undefined
+ // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
+ // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
+ if ( val <= 0 || val == null ) {
+ // Fall back to computed then uncomputed css if necessary
+ val = curCSS( elem, name, styles );
+ if ( val < 0 || val == null ) {
+ val = elem.style[ name ];
+ }
+
+ // Computed unit is not pixels. Stop here and return.
+ if ( rnumnonpx.test(val) ) {
+ return val;
+ }
+
+ // Check for style in case a browser which returns unreliable values
+ // for getComputedStyle silently falls back to the reliable elem.style
+ valueIsBorderBox = isBorderBox &&
+ ( support.boxSizingReliable() || val === elem.style[ name ] );
+
+ // Normalize "", auto, and prepare for extra
+ val = parseFloat( val ) || 0;
+ }
+
+ // Use the active box-sizing model to add/subtract irrelevant styles
+ return ( val +
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra || ( isBorderBox ? "border" : "content" ),
+ valueIsBorderBox,
+ styles
+ )
+ ) + "px";
+}
+
+function showHide( elements, show ) {
+ var display, elem, hidden,
+ values = [],
+ index = 0,
+ length = elements.length;
+
+ for ( ; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+
+ values[ index ] = data_priv.get( elem, "olddisplay" );
+ display = elem.style.display;
+ if ( show ) {
+ // Reset the inline display of this element to learn if it is
+ // being hidden by cascaded rules or not
+ if ( !values[ index ] && display === "none" ) {
+ elem.style.display = "";
+ }
+
+ // Set elements which have been overridden with display: none
+ // in a stylesheet to whatever the default browser style is
+ // for such an element
+ if ( elem.style.display === "" && isHidden( elem ) ) {
+ values[ index ] = data_priv.access( elem, "olddisplay", defaultDisplay(elem.nodeName) );
+ }
+ } else {
+ hidden = isHidden( elem );
+
+ if ( display !== "none" || !hidden ) {
+ data_priv.set( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
+ }
+ }
+ }
+
+ // Set the display of most of the elements in a second loop
+ // to avoid the constant reflow
+ for ( index = 0; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+ if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
+ elem.style.display = show ? values[ index ] || "" : "none";
+ }
+ }
+
+ return elements;
+}
+
+jQuery.extend({
+
+ // Add in style property hooks for overriding the default
+ // behavior of getting and setting a style property
+ cssHooks: {
+ opacity: {
+ get: function( elem, computed ) {
+ if ( computed ) {
+
+ // We should always get a number back from opacity
+ var ret = curCSS( elem, "opacity" );
+ return ret === "" ? "1" : ret;
+ }
+ }
+ }
+ },
+
+ // Don't automatically add "px" to these possibly-unitless properties
+ cssNumber: {
+ "columnCount": true,
+ "fillOpacity": true,
+ "flexGrow": true,
+ "flexShrink": true,
+ "fontWeight": true,
+ "lineHeight": true,
+ "opacity": true,
+ "order": true,
+ "orphans": true,
+ "widows": true,
+ "zIndex": true,
+ "zoom": true
+ },
+
+ // Add in properties whose names you wish to fix before
+ // setting or getting the value
+ cssProps: {
+ "float": "cssFloat"
+ },
+
+ // Get and set the style property on a DOM Node
+ style: function( elem, name, value, extra ) {
+
+ // Don't set styles on text and comment nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+ return;
+ }
+
+ // Make sure that we're working with the right name
+ var ret, type, hooks,
+ origName = jQuery.camelCase( name ),
+ style = elem.style;
+
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
+
+ // Gets hook for the prefixed version, then unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // Check if we're setting a value
+ if ( value !== undefined ) {
+ type = typeof value;
+
+ // Convert "+=" or "-=" to relative numbers (#7345)
+ if ( type === "string" && (ret = rrelNum.exec( value )) ) {
+ value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
+ // Fixes bug #9237
+ type = "number";
+ }
+
+ // Make sure that null and NaN values aren't set (#7116)
+ if ( value == null || value !== value ) {
+ return;
+ }
+
+ // If a number, add 'px' to the (except for certain CSS properties)
+ if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+ value += "px";
+ }
+
+ // Support: IE9-11+
+ // background-* props affect original clone's values
+ if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
+ style[ name ] = "inherit";
+ }
+
+ // If a hook was provided, use that value, otherwise just set the specified value
+ if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
+ style[ name ] = value;
+ }
+
+ } else {
+ // If a hook was provided get the non-computed value from there
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+ return ret;
+ }
+
+ // Otherwise just get the value from the style object
+ return style[ name ];
+ }
+ },
+
+ css: function( elem, name, extra, styles ) {
+ var val, num, hooks,
+ origName = jQuery.camelCase( name );
+
+ // Make sure that we're working with the right name
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
+
+ // Try prefixed name followed by the unprefixed name
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // If a hook was provided get the computed value from there
+ if ( hooks && "get" in hooks ) {
+ val = hooks.get( elem, true, extra );
+ }
+
+ // Otherwise, if a way to get the computed value exists, use that
+ if ( val === undefined ) {
+ val = curCSS( elem, name, styles );
+ }
+
+ // Convert "normal" to computed value
+ if ( val === "normal" && name in cssNormalTransform ) {
+ val = cssNormalTransform[ name ];
+ }
+
+ // Make numeric if forced or a qualifier was provided and val looks numeric
+ if ( extra === "" || extra ) {
+ num = parseFloat( val );
+ return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
+ }
+ return val;
+ }
+});
+
+jQuery.each([ "height", "width" ], function( i, name ) {
+ jQuery.cssHooks[ name ] = {
+ get: function( elem, computed, extra ) {
+ if ( computed ) {
+
+ // Certain elements can have dimension info if we invisibly show them
+ // but it must have a current display style that would benefit
+ return rdisplayswap.test( jQuery.css( elem, "display" ) ) && elem.offsetWidth === 0 ?
+ jQuery.swap( elem, cssShow, function() {
+ return getWidthOrHeight( elem, name, extra );
+ }) :
+ getWidthOrHeight( elem, name, extra );
+ }
+ },
+
+ set: function( elem, value, extra ) {
+ var styles = extra && getStyles( elem );
+ return setPositiveNumber( elem, value, extra ?
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra,
+ jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+ styles
+ ) : 0
+ );
+ }
+ };
+});
+
+// Support: Android 2.3
+jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
+ function( elem, computed ) {
+ if ( computed ) {
+ return jQuery.swap( elem, { "display": "inline-block" },
+ curCSS, [ elem, "marginRight" ] );
+ }
+ }
+);
+
+// These hooks are used by animate to expand properties
+jQuery.each({
+ margin: "",
+ padding: "",
+ border: "Width"
+}, function( prefix, suffix ) {
+ jQuery.cssHooks[ prefix + suffix ] = {
+ expand: function( value ) {
+ var i = 0,
+ expanded = {},
+
+ // Assumes a single number if not a string
+ parts = typeof value === "string" ? value.split(" ") : [ value ];
+
+ for ( ; i < 4; i++ ) {
+ expanded[ prefix + cssExpand[ i ] + suffix ] =
+ parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+ }
+
+ return expanded;
+ }
+ };
+
+ if ( !rmargin.test( prefix ) ) {
+ jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
+ }
+});
+
+jQuery.fn.extend({
+ css: function( name, value ) {
+ return access( this, function( elem, name, value ) {
+ var styles, len,
+ map = {},
+ i = 0;
+
+ if ( jQuery.isArray( name ) ) {
+ styles = getStyles( elem );
+ len = name.length;
+
+ for ( ; i < len; i++ ) {
+ map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
+ }
+
+ return map;
+ }
+
+ return value !== undefined ?
+ jQuery.style( elem, name, value ) :
+ jQuery.css( elem, name );
+ }, name, value, arguments.length > 1 );
+ },
+ show: function() {
+ return showHide( this, true );
+ },
+ hide: function() {
+ return showHide( this );
+ },
+ toggle: function( state ) {
+ if ( typeof state === "boolean" ) {
+ return state ? this.show() : this.hide();
+ }
+
+ return this.each(function() {
+ if ( isHidden( this ) ) {
+ jQuery( this ).show();
+ } else {
+ jQuery( this ).hide();
+ }
+ });
+ }
+});
+
+
+function Tween( elem, options, prop, end, easing ) {
+ return new Tween.prototype.init( elem, options, prop, end, easing );
+}
+jQuery.Tween = Tween;
+
+Tween.prototype = {
+ constructor: Tween,
+ init: function( elem, options, prop, end, easing, unit ) {
+ this.elem = elem;
+ this.prop = prop;
+ this.easing = easing || "swing";
+ this.options = options;
+ this.start = this.now = this.cur();
+ this.end = end;
+ this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+ },
+ cur: function() {
+ var hooks = Tween.propHooks[ this.prop ];
+
+ return hooks && hooks.get ?
+ hooks.get( this ) :
+ Tween.propHooks._default.get( this );
+ },
+ run: function( percent ) {
+ var eased,
+ hooks = Tween.propHooks[ this.prop ];
+
+ if ( this.options.duration ) {
+ this.pos = eased = jQuery.easing[ this.easing ](
+ percent, this.options.duration * percent, 0, 1, this.options.duration
+ );
+ } else {
+ this.pos = eased = percent;
+ }
+ this.now = ( this.end - this.start ) * eased + this.start;
+
+ if ( this.options.step ) {
+ this.options.step.call( this.elem, this.now, this );
+ }
+
+ if ( hooks && hooks.set ) {
+ hooks.set( this );
+ } else {
+ Tween.propHooks._default.set( this );
+ }
+ return this;
+ }
+};
+
+Tween.prototype.init.prototype = Tween.prototype;
+
+Tween.propHooks = {
+ _default: {
+ get: function( tween ) {
+ var result;
+
+ if ( tween.elem[ tween.prop ] != null &&
+ (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
+ return tween.elem[ tween.prop ];
+ }
+
+ // Passing an empty string as a 3rd parameter to .css will automatically
+ // attempt a parseFloat and fallback to a string if the parse fails.
+ // Simple values such as "10px" are parsed to Float;
+ // complex values such as "rotate(1rad)" are returned as-is.
+ result = jQuery.css( tween.elem, tween.prop, "" );
+ // Empty strings, null, undefined and "auto" are converted to 0.
+ return !result || result === "auto" ? 0 : result;
+ },
+ set: function( tween ) {
+ // Use step hook for back compat.
+ // Use cssHook if its there.
+ // Use .style if available and use plain properties where available.
+ if ( jQuery.fx.step[ tween.prop ] ) {
+ jQuery.fx.step[ tween.prop ]( tween );
+ } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
+ jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
+ } else {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+ }
+};
+
+// Support: IE9
+// Panic based approach to setting things on disconnected nodes
+Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
+ set: function( tween ) {
+ if ( tween.elem.nodeType && tween.elem.parentNode ) {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+};
+
+jQuery.easing = {
+ linear: function( p ) {
+ return p;
+ },
+ swing: function( p ) {
+ return 0.5 - Math.cos( p * Math.PI ) / 2;
+ }
+};
+
+jQuery.fx = Tween.prototype.init;
+
+// Back Compat <1.8 extension point
+jQuery.fx.step = {};
+
+
+
+
+var
+ fxNow, timerId,
+ rfxtypes = /^(?:toggle|show|hide)$/,
+ rfxnum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ),
+ rrun = /queueHooks$/,
+ animationPrefilters = [ defaultPrefilter ],
+ tweeners = {
+ "*": [ function( prop, value ) {
+ var tween = this.createTween( prop, value ),
+ target = tween.cur(),
+ parts = rfxnum.exec( value ),
+ unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
+
+ // Starting value computation is required for potential unit mismatches
+ start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
+ rfxnum.exec( jQuery.css( tween.elem, prop ) ),
+ scale = 1,
+ maxIterations = 20;
+
+ if ( start && start[ 3 ] !== unit ) {
+ // Trust units reported by jQuery.css
+ unit = unit || start[ 3 ];
+
+ // Make sure we update the tween properties later on
+ parts = parts || [];
+
+ // Iteratively approximate from a nonzero starting point
+ start = +target || 1;
+
+ do {
+ // If previous iteration zeroed out, double until we get *something*.
+ // Use string for doubling so we don't accidentally see scale as unchanged below
+ scale = scale || ".5";
+
+ // Adjust and apply
+ start = start / scale;
+ jQuery.style( tween.elem, prop, start + unit );
+
+ // Update scale, tolerating zero or NaN from tween.cur(),
+ // break the loop if scale is unchanged or perfect, or if we've just had enough
+ } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
+ }
+
+ // Update tween properties
+ if ( parts ) {
+ start = tween.start = +start || +target || 0;
+ tween.unit = unit;
+ // If a +=/-= token was provided, we're doing a relative animation
+ tween.end = parts[ 1 ] ?
+ start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
+ +parts[ 2 ];
+ }
+
+ return tween;
+ } ]
+ };
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+ setTimeout(function() {
+ fxNow = undefined;
+ });
+ return ( fxNow = jQuery.now() );
+}
+
+// Generate parameters to create a standard animation
+function genFx( type, includeWidth ) {
+ var which,
+ i = 0,
+ attrs = { height: type };
+
+ // If we include width, step value is 1 to do all cssExpand values,
+ // otherwise step value is 2 to skip over Left and Right
+ includeWidth = includeWidth ? 1 : 0;
+ for ( ; i < 4 ; i += 2 - includeWidth ) {
+ which = cssExpand[ i ];
+ attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
+ }
+
+ if ( includeWidth ) {
+ attrs.opacity = attrs.width = type;
+ }
+
+ return attrs;
+}
+
+function createTween( value, prop, animation ) {
+ var tween,
+ collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
+ index = 0,
+ length = collection.length;
+ for ( ; index < length; index++ ) {
+ if ( (tween = collection[ index ].call( animation, prop, value )) ) {
+
+ // We're done with this property
+ return tween;
+ }
+ }
+}
+
+function defaultPrefilter( elem, props, opts ) {
+ /* jshint validthis: true */
+ var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
+ anim = this,
+ orig = {},
+ style = elem.style,
+ hidden = elem.nodeType && isHidden( elem ),
+ dataShow = data_priv.get( elem, "fxshow" );
+
+ // Handle queue: false promises
+ if ( !opts.queue ) {
+ hooks = jQuery._queueHooks( elem, "fx" );
+ if ( hooks.unqueued == null ) {
+ hooks.unqueued = 0;
+ oldfire = hooks.empty.fire;
+ hooks.empty.fire = function() {
+ if ( !hooks.unqueued ) {
+ oldfire();
+ }
+ };
+ }
+ hooks.unqueued++;
+
+ anim.always(function() {
+ // Ensure the complete handler is called before this completes
+ anim.always(function() {
+ hooks.unqueued--;
+ if ( !jQuery.queue( elem, "fx" ).length ) {
+ hooks.empty.fire();
+ }
+ });
+ });
+ }
+
+ // Height/width overflow pass
+ if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
+ // Make sure that nothing sneaks out
+ // Record all 3 overflow attributes because IE9-10 do not
+ // change the overflow attribute when overflowX and
+ // overflowY are set to the same value
+ opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
+
+ // Set display property to inline-block for height/width
+ // animations on inline elements that are having width/height animated
+ display = jQuery.css( elem, "display" );
+
+ // Test default display if display is currently "none"
+ checkDisplay = display === "none" ?
+ data_priv.get( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;
+
+ if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) {
+ style.display = "inline-block";
+ }
+ }
+
+ if ( opts.overflow ) {
+ style.overflow = "hidden";
+ anim.always(function() {
+ style.overflow = opts.overflow[ 0 ];
+ style.overflowX = opts.overflow[ 1 ];
+ style.overflowY = opts.overflow[ 2 ];
+ });
+ }
+
+ // show/hide pass
+ for ( prop in props ) {
+ value = props[ prop ];
+ if ( rfxtypes.exec( value ) ) {
+ delete props[ prop ];
+ toggle = toggle || value === "toggle";
+ if ( value === ( hidden ? "hide" : "show" ) ) {
+
+ // If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden
+ if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
+ hidden = true;
+ } else {
+ continue;
+ }
+ }
+ orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
+
+ // Any non-fx value stops us from restoring the original display value
+ } else {
+ display = undefined;
+ }
+ }
+
+ if ( !jQuery.isEmptyObject( orig ) ) {
+ if ( dataShow ) {
+ if ( "hidden" in dataShow ) {
+ hidden = dataShow.hidden;
+ }
+ } else {
+ dataShow = data_priv.access( elem, "fxshow", {} );
+ }
+
+ // Store state if its toggle - enables .stop().toggle() to "reverse"
+ if ( toggle ) {
+ dataShow.hidden = !hidden;
+ }
+ if ( hidden ) {
+ jQuery( elem ).show();
+ } else {
+ anim.done(function() {
+ jQuery( elem ).hide();
+ });
+ }
+ anim.done(function() {
+ var prop;
+
+ data_priv.remove( elem, "fxshow" );
+ for ( prop in orig ) {
+ jQuery.style( elem, prop, orig[ prop ] );
+ }
+ });
+ for ( prop in orig ) {
+ tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
+
+ if ( !( prop in dataShow ) ) {
+ dataShow[ prop ] = tween.start;
+ if ( hidden ) {
+ tween.end = tween.start;
+ tween.start = prop === "width" || prop === "height" ? 1 : 0;
+ }
+ }
+ }
+
+ // If this is a noop like .hide().hide(), restore an overwritten display value
+ } else if ( (display === "none" ? defaultDisplay( elem.nodeName ) : display) === "inline" ) {
+ style.display = display;
+ }
+}
+
+function propFilter( props, specialEasing ) {
+ var index, name, easing, value, hooks;
+
+ // camelCase, specialEasing and expand cssHook pass
+ for ( index in props ) {
+ name = jQuery.camelCase( index );
+ easing = specialEasing[ name ];
+ value = props[ index ];
+ if ( jQuery.isArray( value ) ) {
+ easing = value[ 1 ];
+ value = props[ index ] = value[ 0 ];
+ }
+
+ if ( index !== name ) {
+ props[ name ] = value;
+ delete props[ index ];
+ }
+
+ hooks = jQuery.cssHooks[ name ];
+ if ( hooks && "expand" in hooks ) {
+ value = hooks.expand( value );
+ delete props[ name ];
+
+ // Not quite $.extend, this won't overwrite existing keys.
+ // Reusing 'index' because we have the correct "name"
+ for ( index in value ) {
+ if ( !( index in props ) ) {
+ props[ index ] = value[ index ];
+ specialEasing[ index ] = easing;
+ }
+ }
+ } else {
+ specialEasing[ name ] = easing;
+ }
+ }
+}
+
+function Animation( elem, properties, options ) {
+ var result,
+ stopped,
+ index = 0,
+ length = animationPrefilters.length,
+ deferred = jQuery.Deferred().always( function() {
+ // Don't match elem in the :animated selector
+ delete tick.elem;
+ }),
+ tick = function() {
+ if ( stopped ) {
+ return false;
+ }
+ var currentTime = fxNow || createFxNow(),
+ remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
+ // Support: Android 2.3
+ // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)
+ temp = remaining / animation.duration || 0,
+ percent = 1 - temp,
+ index = 0,
+ length = animation.tweens.length;
+
+ for ( ; index < length ; index++ ) {
+ animation.tweens[ index ].run( percent );
+ }
+
+ deferred.notifyWith( elem, [ animation, percent, remaining ]);
+
+ if ( percent < 1 && length ) {
+ return remaining;
+ } else {
+ deferred.resolveWith( elem, [ animation ] );
+ return false;
+ }
+ },
+ animation = deferred.promise({
+ elem: elem,
+ props: jQuery.extend( {}, properties ),
+ opts: jQuery.extend( true, { specialEasing: {} }, options ),
+ originalProperties: properties,
+ originalOptions: options,
+ startTime: fxNow || createFxNow(),
+ duration: options.duration,
+ tweens: [],
+ createTween: function( prop, end ) {
+ var tween = jQuery.Tween( elem, animation.opts, prop, end,
+ animation.opts.specialEasing[ prop ] || animation.opts.easing );
+ animation.tweens.push( tween );
+ return tween;
+ },
+ stop: function( gotoEnd ) {
+ var index = 0,
+ // If we are going to the end, we want to run all the tweens
+ // otherwise we skip this part
+ length = gotoEnd ? animation.tweens.length : 0;
+ if ( stopped ) {
+ return this;
+ }
+ stopped = true;
+ for ( ; index < length ; index++ ) {
+ animation.tweens[ index ].run( 1 );
+ }
+
+ // Resolve when we played the last frame; otherwise, reject
+ if ( gotoEnd ) {
+ deferred.resolveWith( elem, [ animation, gotoEnd ] );
+ } else {
+ deferred.rejectWith( elem, [ animation, gotoEnd ] );
+ }
+ return this;
+ }
+ }),
+ props = animation.props;
+
+ propFilter( props, animation.opts.specialEasing );
+
+ for ( ; index < length ; index++ ) {
+ result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
+ if ( result ) {
+ return result;
+ }
+ }
+
+ jQuery.map( props, createTween, animation );
+
+ if ( jQuery.isFunction( animation.opts.start ) ) {
+ animation.opts.start.call( elem, animation );
+ }
+
+ jQuery.fx.timer(
+ jQuery.extend( tick, {
+ elem: elem,
+ anim: animation,
+ queue: animation.opts.queue
+ })
+ );
+
+ // attach callbacks from options
+ return animation.progress( animation.opts.progress )
+ .done( animation.opts.done, animation.opts.complete )
+ .fail( animation.opts.fail )
+ .always( animation.opts.always );
+}
+
+jQuery.Animation = jQuery.extend( Animation, {
+
+ tweener: function( props, callback ) {
+ if ( jQuery.isFunction( props ) ) {
+ callback = props;
+ props = [ "*" ];
+ } else {
+ props = props.split(" ");
+ }
+
+ var prop,
+ index = 0,
+ length = props.length;
+
+ for ( ; index < length ; index++ ) {
+ prop = props[ index ];
+ tweeners[ prop ] = tweeners[ prop ] || [];
+ tweeners[ prop ].unshift( callback );
+ }
+ },
+
+ prefilter: function( callback, prepend ) {
+ if ( prepend ) {
+ animationPrefilters.unshift( callback );
+ } else {
+ animationPrefilters.push( callback );
+ }
+ }
+});
+
+jQuery.speed = function( speed, easing, fn ) {
+ var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+ complete: fn || !fn && easing ||
+ jQuery.isFunction( speed ) && speed,
+ duration: speed,
+ easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
+ };
+
+ opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+ opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+
+ // Normalize opt.queue - true/undefined/null -> "fx"
+ if ( opt.queue == null || opt.queue === true ) {
+ opt.queue = "fx";
+ }
+
+ // Queueing
+ opt.old = opt.complete;
+
+ opt.complete = function() {
+ if ( jQuery.isFunction( opt.old ) ) {
+ opt.old.call( this );
+ }
+
+ if ( opt.queue ) {
+ jQuery.dequeue( this, opt.queue );
+ }
+ };
+
+ return opt;
+};
+
+jQuery.fn.extend({
+ fadeTo: function( speed, to, easing, callback ) {
+
+ // Show any hidden elements after setting opacity to 0
+ return this.filter( isHidden ).css( "opacity", 0 ).show()
+
+ // Animate to the value specified
+ .end().animate({ opacity: to }, speed, easing, callback );
+ },
+ animate: function( prop, speed, easing, callback ) {
+ var empty = jQuery.isEmptyObject( prop ),
+ optall = jQuery.speed( speed, easing, callback ),
+ doAnimation = function() {
+ // Operate on a copy of prop so per-property easing won't be lost
+ var anim = Animation( this, jQuery.extend( {}, prop ), optall );
+
+ // Empty animations, or finishing resolves immediately
+ if ( empty || data_priv.get( this, "finish" ) ) {
+ anim.stop( true );
+ }
+ };
+ doAnimation.finish = doAnimation;
+
+ return empty || optall.queue === false ?
+ this.each( doAnimation ) :
+ this.queue( optall.queue, doAnimation );
+ },
+ stop: function( type, clearQueue, gotoEnd ) {
+ var stopQueue = function( hooks ) {
+ var stop = hooks.stop;
+ delete hooks.stop;
+ stop( gotoEnd );
+ };
+
+ if ( typeof type !== "string" ) {
+ gotoEnd = clearQueue;
+ clearQueue = type;
+ type = undefined;
+ }
+ if ( clearQueue && type !== false ) {
+ this.queue( type || "fx", [] );
+ }
+
+ return this.each(function() {
+ var dequeue = true,
+ index = type != null && type + "queueHooks",
+ timers = jQuery.timers,
+ data = data_priv.get( this );
+
+ if ( index ) {
+ if ( data[ index ] && data[ index ].stop ) {
+ stopQueue( data[ index ] );
+ }
+ } else {
+ for ( index in data ) {
+ if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
+ stopQueue( data[ index ] );
+ }
+ }
+ }
+
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
+ timers[ index ].anim.stop( gotoEnd );
+ dequeue = false;
+ timers.splice( index, 1 );
+ }
+ }
+
+ // Start the next in the queue if the last step wasn't forced.
+ // Timers currently will call their complete callbacks, which
+ // will dequeue but only if they were gotoEnd.
+ if ( dequeue || !gotoEnd ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ finish: function( type ) {
+ if ( type !== false ) {
+ type = type || "fx";
+ }
+ return this.each(function() {
+ var index,
+ data = data_priv.get( this ),
+ queue = data[ type + "queue" ],
+ hooks = data[ type + "queueHooks" ],
+ timers = jQuery.timers,
+ length = queue ? queue.length : 0;
+
+ // Enable finishing flag on private data
+ data.finish = true;
+
+ // Empty the queue first
+ jQuery.queue( this, type, [] );
+
+ if ( hooks && hooks.stop ) {
+ hooks.stop.call( this, true );
+ }
+
+ // Look for any active animations, and finish them
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
+ timers[ index ].anim.stop( true );
+ timers.splice( index, 1 );
+ }
+ }
+
+ // Look for any animations in the old queue and finish them
+ for ( index = 0; index < length; index++ ) {
+ if ( queue[ index ] && queue[ index ].finish ) {
+ queue[ index ].finish.call( this );
+ }
+ }
+
+ // Turn off finishing flag
+ delete data.finish;
+ });
+ }
+});
+
+jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
+ var cssFn = jQuery.fn[ name ];
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return speed == null || typeof speed === "boolean" ?
+ cssFn.apply( this, arguments ) :
+ this.animate( genFx( name, true ), speed, easing, callback );
+ };
+});
+
+// Generate shortcuts for custom animations
+jQuery.each({
+ slideDown: genFx("show"),
+ slideUp: genFx("hide"),
+ slideToggle: genFx("toggle"),
+ fadeIn: { opacity: "show" },
+ fadeOut: { opacity: "hide" },
+ fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return this.animate( props, speed, easing, callback );
+ };
+});
+
+jQuery.timers = [];
+jQuery.fx.tick = function() {
+ var timer,
+ i = 0,
+ timers = jQuery.timers;
+
+ fxNow = jQuery.now();
+
+ for ( ; i < timers.length; i++ ) {
+ timer = timers[ i ];
+ // Checks the timer has not already been removed
+ if ( !timer() && timers[ i ] === timer ) {
+ timers.splice( i--, 1 );
+ }
+ }
+
+ if ( !timers.length ) {
+ jQuery.fx.stop();
+ }
+ fxNow = undefined;
+};
+
+jQuery.fx.timer = function( timer ) {
+ jQuery.timers.push( timer );
+ if ( timer() ) {
+ jQuery.fx.start();
+ } else {
+ jQuery.timers.pop();
+ }
+};
+
+jQuery.fx.interval = 13;
+
+jQuery.fx.start = function() {
+ if ( !timerId ) {
+ timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
+ }
+};
+
+jQuery.fx.stop = function() {
+ clearInterval( timerId );
+ timerId = null;
+};
+
+jQuery.fx.speeds = {
+ slow: 600,
+ fast: 200,
+ // Default speed
+ _default: 400
+};
+
+
+// Based off of the plugin by Clint Helfers, with permission.
+// http://blindsignals.com/index.php/2009/07/jquery-delay/
+jQuery.fn.delay = function( time, type ) {
+ time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+ type = type || "fx";
+
+ return this.queue( type, function( next, hooks ) {
+ var timeout = setTimeout( next, time );
+ hooks.stop = function() {
+ clearTimeout( timeout );
+ };
+ });
+};
+
+
+(function() {
+ var input = document.createElement( "input" ),
+ select = document.createElement( "select" ),
+ opt = select.appendChild( document.createElement( "option" ) );
+
+ input.type = "checkbox";
+
+ // Support: iOS<=5.1, Android<=4.2+
+ // Default value for a checkbox should be "on"
+ support.checkOn = input.value !== "";
+
+ // Support: IE<=11+
+ // Must access selectedIndex to make default options select
+ support.optSelected = opt.selected;
+
+ // Support: Android<=2.3
+ // Options inside disabled selects are incorrectly marked as disabled
+ select.disabled = true;
+ support.optDisabled = !opt.disabled;
+
+ // Support: IE<=11+
+ // An input loses its value after becoming a radio
+ input = document.createElement( "input" );
+ input.value = "t";
+ input.type = "radio";
+ support.radioValue = input.value === "t";
+})();
+
+
+var nodeHook, boolHook,
+ attrHandle = jQuery.expr.attrHandle;
+
+jQuery.fn.extend({
+ attr: function( name, value ) {
+ return access( this, jQuery.attr, name, value, arguments.length > 1 );
+ },
+
+ removeAttr: function( name ) {
+ return this.each(function() {
+ jQuery.removeAttr( this, name );
+ });
+ }
+});
+
+jQuery.extend({
+ attr: function( elem, name, value ) {
+ var hooks, ret,
+ nType = elem.nodeType;
+
+ // don't get/set attributes on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ // Fallback to prop when attributes are not supported
+ if ( typeof elem.getAttribute === strundefined ) {
+ return jQuery.prop( elem, name, value );
+ }
+
+ // All attributes are lowercase
+ // Grab necessary hook if one is defined
+ if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
+ name = name.toLowerCase();
+ hooks = jQuery.attrHooks[ name ] ||
+ ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
+ }
+
+ if ( value !== undefined ) {
+
+ if ( value === null ) {
+ jQuery.removeAttr( elem, name );
+
+ } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ elem.setAttribute( name, value + "" );
+ return value;
+ }
+
+ } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+ return ret;
+
+ } else {
+ ret = jQuery.find.attr( elem, name );
+
+ // Non-existent attributes return null, we normalize to undefined
+ return ret == null ?
+ undefined :
+ ret;
+ }
+ },
+
+ removeAttr: function( elem, value ) {
+ var name, propName,
+ i = 0,
+ attrNames = value && value.match( rnotwhite );
+
+ if ( attrNames && elem.nodeType === 1 ) {
+ while ( (name = attrNames[i++]) ) {
+ propName = jQuery.propFix[ name ] || name;
+
+ // Boolean attributes get special treatment (#10870)
+ if ( jQuery.expr.match.bool.test( name ) ) {
+ // Set corresponding property to false
+ elem[ propName ] = false;
+ }
+
+ elem.removeAttribute( name );
+ }
+ }
+ },
+
+ attrHooks: {
+ type: {
+ set: function( elem, value ) {
+ if ( !support.radioValue && value === "radio" &&
+ jQuery.nodeName( elem, "input" ) ) {
+ var val = elem.value;
+ elem.setAttribute( "type", value );
+ if ( val ) {
+ elem.value = val;
+ }
+ return value;
+ }
+ }
+ }
+ }
+});
+
+// Hooks for boolean attributes
+boolHook = {
+ set: function( elem, value, name ) {
+ if ( value === false ) {
+ // Remove boolean attributes when set to false
+ jQuery.removeAttr( elem, name );
+ } else {
+ elem.setAttribute( name, name );
+ }
+ return name;
+ }
+};
+jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
+ var getter = attrHandle[ name ] || jQuery.find.attr;
+
+ attrHandle[ name ] = function( elem, name, isXML ) {
+ var ret, handle;
+ if ( !isXML ) {
+ // Avoid an infinite loop by temporarily removing this function from the getter
+ handle = attrHandle[ name ];
+ attrHandle[ name ] = ret;
+ ret = getter( elem, name, isXML ) != null ?
+ name.toLowerCase() :
+ null;
+ attrHandle[ name ] = handle;
+ }
+ return ret;
+ };
+});
+
+
+
+
+var rfocusable = /^(?:input|select|textarea|button)$/i;
+
+jQuery.fn.extend({
+ prop: function( name, value ) {
+ return access( this, jQuery.prop, name, value, arguments.length > 1 );
+ },
+
+ removeProp: function( name ) {
+ return this.each(function() {
+ delete this[ jQuery.propFix[ name ] || name ];
+ });
+ }
+});
+
+jQuery.extend({
+ propFix: {
+ "for": "htmlFor",
+ "class": "className"
+ },
+
+ prop: function( elem, name, value ) {
+ var ret, hooks, notxml,
+ nType = elem.nodeType;
+
+ // Don't get/set properties on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ if ( notxml ) {
+ // Fix name and attach hooks
+ name = jQuery.propFix[ name ] || name;
+ hooks = jQuery.propHooks[ name ];
+ }
+
+ if ( value !== undefined ) {
+ return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
+ ret :
+ ( elem[ name ] = value );
+
+ } else {
+ return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
+ ret :
+ elem[ name ];
+ }
+ },
+
+ propHooks: {
+ tabIndex: {
+ get: function( elem ) {
+ return elem.hasAttribute( "tabindex" ) || rfocusable.test( elem.nodeName ) || elem.href ?
+ elem.tabIndex :
+ -1;
+ }
+ }
+ }
+});
+
+if ( !support.optSelected ) {
+ jQuery.propHooks.selected = {
+ get: function( elem ) {
+ var parent = elem.parentNode;
+ if ( parent && parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ return null;
+ }
+ };
+}
+
+jQuery.each([
+ "tabIndex",
+ "readOnly",
+ "maxLength",
+ "cellSpacing",
+ "cellPadding",
+ "rowSpan",
+ "colSpan",
+ "useMap",
+ "frameBorder",
+ "contentEditable"
+], function() {
+ jQuery.propFix[ this.toLowerCase() ] = this;
+});
+
+
+
+
+var rclass = /[\t\r\n\f]/g;
+
+jQuery.fn.extend({
+ addClass: function( value ) {
+ var classes, elem, cur, clazz, j, finalValue,
+ proceed = typeof value === "string" && value,
+ i = 0,
+ len = this.length;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).addClass( value.call( this, j, this.className ) );
+ });
+ }
+
+ if ( proceed ) {
+ // The disjunction here is for better compressibility (see removeClass)
+ classes = ( value || "" ).match( rnotwhite ) || [];
+
+ for ( ; i < len; i++ ) {
+ elem = this[ i ];
+ cur = elem.nodeType === 1 && ( elem.className ?
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
+ " "
+ );
+
+ if ( cur ) {
+ j = 0;
+ while ( (clazz = classes[j++]) ) {
+ if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
+ cur += clazz + " ";
+ }
+ }
+
+ // only assign if different to avoid unneeded rendering.
+ finalValue = jQuery.trim( cur );
+ if ( elem.className !== finalValue ) {
+ elem.className = finalValue;
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ removeClass: function( value ) {
+ var classes, elem, cur, clazz, j, finalValue,
+ proceed = arguments.length === 0 || typeof value === "string" && value,
+ i = 0,
+ len = this.length;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).removeClass( value.call( this, j, this.className ) );
+ });
+ }
+ if ( proceed ) {
+ classes = ( value || "" ).match( rnotwhite ) || [];
+
+ for ( ; i < len; i++ ) {
+ elem = this[ i ];
+ // This expression is here for better compressibility (see addClass)
+ cur = elem.nodeType === 1 && ( elem.className ?
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
+ ""
+ );
+
+ if ( cur ) {
+ j = 0;
+ while ( (clazz = classes[j++]) ) {
+ // Remove *all* instances
+ while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
+ cur = cur.replace( " " + clazz + " ", " " );
+ }
+ }
+
+ // Only assign if different to avoid unneeded rendering.
+ finalValue = value ? jQuery.trim( cur ) : "";
+ if ( elem.className !== finalValue ) {
+ elem.className = finalValue;
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ toggleClass: function( value, stateVal ) {
+ var type = typeof value;
+
+ if ( typeof stateVal === "boolean" && type === "string" ) {
+ return stateVal ? this.addClass( value ) : this.removeClass( value );
+ }
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( i ) {
+ jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
+ });
+ }
+
+ return this.each(function() {
+ if ( type === "string" ) {
+ // Toggle individual class names
+ var className,
+ i = 0,
+ self = jQuery( this ),
+ classNames = value.match( rnotwhite ) || [];
+
+ while ( (className = classNames[ i++ ]) ) {
+ // Check each className given, space separated list
+ if ( self.hasClass( className ) ) {
+ self.removeClass( className );
+ } else {
+ self.addClass( className );
+ }
+ }
+
+ // Toggle whole class name
+ } else if ( type === strundefined || type === "boolean" ) {
+ if ( this.className ) {
+ // store className if set
+ data_priv.set( this, "__className__", this.className );
+ }
+
+ // If the element has a class name or if we're passed `false`,
+ // then remove the whole classname (if there was one, the above saved it).
+ // Otherwise bring back whatever was previously saved (if anything),
+ // falling back to the empty string if nothing was stored.
+ this.className = this.className || value === false ? "" : data_priv.get( this, "__className__" ) || "";
+ }
+ });
+ },
+
+ hasClass: function( selector ) {
+ var className = " " + selector + " ",
+ i = 0,
+ l = this.length;
+ for ( ; i < l; i++ ) {
+ if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+});
+
+
+
+
+var rreturn = /\r/g;
+
+jQuery.fn.extend({
+ val: function( value ) {
+ var hooks, ret, isFunction,
+ elem = this[0];
+
+ if ( !arguments.length ) {
+ if ( elem ) {
+ hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+ return ret;
+ }
+
+ ret = elem.value;
+
+ return typeof ret === "string" ?
+ // Handle most common string cases
+ ret.replace(rreturn, "") :
+ // Handle cases where value is null/undef or number
+ ret == null ? "" : ret;
+ }
+
+ return;
+ }
+
+ isFunction = jQuery.isFunction( value );
+
+ return this.each(function( i ) {
+ var val;
+
+ if ( this.nodeType !== 1 ) {
+ return;
+ }
+
+ if ( isFunction ) {
+ val = value.call( this, i, jQuery( this ).val() );
+ } else {
+ val = value;
+ }
+
+ // Treat null/undefined as ""; convert numbers to string
+ if ( val == null ) {
+ val = "";
+
+ } else if ( typeof val === "number" ) {
+ val += "";
+
+ } else if ( jQuery.isArray( val ) ) {
+ val = jQuery.map( val, function( value ) {
+ return value == null ? "" : value + "";
+ });
+ }
+
+ hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+ // If set returns undefined, fall back to normal setting
+ if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
+ this.value = val;
+ }
+ });
+ }
+});
+
+jQuery.extend({
+ valHooks: {
+ option: {
+ get: function( elem ) {
+ var val = jQuery.find.attr( elem, "value" );
+ return val != null ?
+ val :
+ // Support: IE10-11+
+ // option.text throws exceptions (#14686, #14858)
+ jQuery.trim( jQuery.text( elem ) );
+ }
+ },
+ select: {
+ get: function( elem ) {
+ var value, option,
+ options = elem.options,
+ index = elem.selectedIndex,
+ one = elem.type === "select-one" || index < 0,
+ values = one ? null : [],
+ max = one ? index + 1 : options.length,
+ i = index < 0 ?
+ max :
+ one ? index : 0;
+
+ // Loop through all the selected options
+ for ( ; i < max; i++ ) {
+ option = options[ i ];
+
+ // IE6-9 doesn't update selected after form reset (#2551)
+ if ( ( option.selected || i === index ) &&
+ // Don't return options that are disabled or in a disabled optgroup
+ ( support.optDisabled ? !option.disabled : option.getAttribute( "disabled" ) === null ) &&
+ ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
+
+ // Get the specific value for the option
+ value = jQuery( option ).val();
+
+ // We don't need an array for one selects
+ if ( one ) {
+ return value;
+ }
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ return values;
+ },
+
+ set: function( elem, value ) {
+ var optionSet, option,
+ options = elem.options,
+ values = jQuery.makeArray( value ),
+ i = options.length;
+
+ while ( i-- ) {
+ option = options[ i ];
+ if ( (option.selected = jQuery.inArray( option.value, values ) >= 0) ) {
+ optionSet = true;
+ }
+ }
+
+ // Force browsers to behave consistently when non-matching value is set
+ if ( !optionSet ) {
+ elem.selectedIndex = -1;
+ }
+ return values;
+ }
+ }
+ }
+});
+
+// Radios and checkboxes getter/setter
+jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = {
+ set: function( elem, value ) {
+ if ( jQuery.isArray( value ) ) {
+ return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
+ }
+ }
+ };
+ if ( !support.checkOn ) {
+ jQuery.valHooks[ this ].get = function( elem ) {
+ return elem.getAttribute("value") === null ? "on" : elem.value;
+ };
+ }
+});
+
+
+
+
+// Return jQuery for attributes-only inclusion
+
+
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+ "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+ "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
+
+ // Handle event binding
+ jQuery.fn[ name ] = function( data, fn ) {
+ return arguments.length > 0 ?
+ this.on( name, null, data, fn ) :
+ this.trigger( name );
+ };
+});
+
+jQuery.fn.extend({
+ hover: function( fnOver, fnOut ) {
+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+ },
+
+ bind: function( types, data, fn ) {
+ return this.on( types, null, data, fn );
+ },
+ unbind: function( types, fn ) {
+ return this.off( types, null, fn );
+ },
+
+ delegate: function( selector, types, data, fn ) {
+ return this.on( types, selector, data, fn );
+ },
+ undelegate: function( selector, types, fn ) {
+ // ( namespace ) or ( selector, types [, fn] )
+ return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
+ }
+});
+
+
+var nonce = jQuery.now();
+
+var rquery = (/\?/);
+
+
+
+// Support: Android 2.3
+// Workaround failure to string-cast null input
+jQuery.parseJSON = function( data ) {
+ return JSON.parse( data + "" );
+};
+
+
+// Cross-browser xml parsing
+jQuery.parseXML = function( data ) {
+ var xml, tmp;
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+
+ // Support: IE9
+ try {
+ tmp = new DOMParser();
+ xml = tmp.parseFromString( data, "text/xml" );
+ } catch ( e ) {
+ xml = undefined;
+ }
+
+ if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
+ jQuery.error( "Invalid XML: " + data );
+ }
+ return xml;
+};
+
+
+var
+ rhash = /#.*$/,
+ rts = /([?&])_=[^&]*/,
+ rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
+ // #7653, #8125, #8152: local protocol detection
+ rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
+ rnoContent = /^(?:GET|HEAD)$/,
+ rprotocol = /^\/\//,
+ rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,
+
+ /* Prefilters
+ * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+ * 2) These are called:
+ * - BEFORE asking for a transport
+ * - AFTER param serialization (s.data is a string if s.processData is true)
+ * 3) key is the dataType
+ * 4) the catchall symbol "*" can be used
+ * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+ */
+ prefilters = {},
+
+ /* Transports bindings
+ * 1) key is the dataType
+ * 2) the catchall symbol "*" can be used
+ * 3) selection will start with transport dataType and THEN go to "*" if needed
+ */
+ transports = {},
+
+ // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+ allTypes = "*/".concat( "*" ),
+
+ // Document location
+ ajaxLocation = window.location.href,
+
+ // Segment location into parts
+ ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+ // dataTypeExpression is optional and defaults to "*"
+ return function( dataTypeExpression, func ) {
+
+ if ( typeof dataTypeExpression !== "string" ) {
+ func = dataTypeExpression;
+ dataTypeExpression = "*";
+ }
+
+ var dataType,
+ i = 0,
+ dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];
+
+ if ( jQuery.isFunction( func ) ) {
+ // For each dataType in the dataTypeExpression
+ while ( (dataType = dataTypes[i++]) ) {
+ // Prepend if requested
+ if ( dataType[0] === "+" ) {
+ dataType = dataType.slice( 1 ) || "*";
+ (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
+
+ // Otherwise append
+ } else {
+ (structure[ dataType ] = structure[ dataType ] || []).push( func );
+ }
+ }
+ }
+ };
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
+
+ var inspected = {},
+ seekingTransport = ( structure === transports );
+
+ function inspect( dataType ) {
+ var selected;
+ inspected[ dataType ] = true;
+ jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
+ var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
+ if ( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
+ options.dataTypes.unshift( dataTypeOrTransport );
+ inspect( dataTypeOrTransport );
+ return false;
+ } else if ( seekingTransport ) {
+ return !( selected = dataTypeOrTransport );
+ }
+ });
+ return selected;
+ }
+
+ return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+ var key, deep,
+ flatOptions = jQuery.ajaxSettings.flatOptions || {};
+
+ for ( key in src ) {
+ if ( src[ key ] !== undefined ) {
+ ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
+ }
+ }
+ if ( deep ) {
+ jQuery.extend( true, target, deep );
+ }
+
+ return target;
+}
+
+/* Handles responses to an ajax request:
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+
+ var ct, type, finalDataType, firstDataType,
+ contents = s.contents,
+ dataTypes = s.dataTypes;
+
+ // Remove auto dataType and get content-type in the process
+ while ( dataTypes[ 0 ] === "*" ) {
+ dataTypes.shift();
+ if ( ct === undefined ) {
+ ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
+ }
+ }
+
+ // Check if we're dealing with a known content-type
+ if ( ct ) {
+ for ( type in contents ) {
+ if ( contents[ type ] && contents[ type ].test( ct ) ) {
+ dataTypes.unshift( type );
+ break;
+ }
+ }
+ }
+
+ // Check to see if we have a response for the expected dataType
+ if ( dataTypes[ 0 ] in responses ) {
+ finalDataType = dataTypes[ 0 ];
+ } else {
+ // Try convertible dataTypes
+ for ( type in responses ) {
+ if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+ finalDataType = type;
+ break;
+ }
+ if ( !firstDataType ) {
+ firstDataType = type;
+ }
+ }
+ // Or just use first one
+ finalDataType = finalDataType || firstDataType;
+ }
+
+ // If we found a dataType
+ // We add the dataType to the list if needed
+ // and return the corresponding response
+ if ( finalDataType ) {
+ if ( finalDataType !== dataTypes[ 0 ] ) {
+ dataTypes.unshift( finalDataType );
+ }
+ return responses[ finalDataType ];
+ }
+}
+
+/* Chain conversions given the request and the original response
+ * Also sets the responseXXX fields on the jqXHR instance
+ */
+function ajaxConvert( s, response, jqXHR, isSuccess ) {
+ var conv2, current, conv, tmp, prev,
+ converters = {},
+ // Work with a copy of dataTypes in case we need to modify it for conversion
+ dataTypes = s.dataTypes.slice();
+
+ // Create converters map with lowercased keys
+ if ( dataTypes[ 1 ] ) {
+ for ( conv in s.converters ) {
+ converters[ conv.toLowerCase() ] = s.converters[ conv ];
+ }
+ }
+
+ current = dataTypes.shift();
+
+ // Convert to each sequential dataType
+ while ( current ) {
+
+ if ( s.responseFields[ current ] ) {
+ jqXHR[ s.responseFields[ current ] ] = response;
+ }
+
+ // Apply the dataFilter if provided
+ if ( !prev && isSuccess && s.dataFilter ) {
+ response = s.dataFilter( response, s.dataType );
+ }
+
+ prev = current;
+ current = dataTypes.shift();
+
+ if ( current ) {
+
+ // There's only work to do if current dataType is non-auto
+ if ( current === "*" ) {
+
+ current = prev;
+
+ // Convert response if prev dataType is non-auto and differs from current
+ } else if ( prev !== "*" && prev !== current ) {
+
+ // Seek a direct converter
+ conv = converters[ prev + " " + current ] || converters[ "* " + current ];
+
+ // If none found, seek a pair
+ if ( !conv ) {
+ for ( conv2 in converters ) {
+
+ // If conv2 outputs current
+ tmp = conv2.split( " " );
+ if ( tmp[ 1 ] === current ) {
+
+ // If prev can be converted to accepted input
+ conv = converters[ prev + " " + tmp[ 0 ] ] ||
+ converters[ "* " + tmp[ 0 ] ];
+ if ( conv ) {
+ // Condense equivalence converters
+ if ( conv === true ) {
+ conv = converters[ conv2 ];
+
+ // Otherwise, insert the intermediate dataType
+ } else if ( converters[ conv2 ] !== true ) {
+ current = tmp[ 0 ];
+ dataTypes.unshift( tmp[ 1 ] );
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // Apply converter (if not an equivalence)
+ if ( conv !== true ) {
+
+ // Unless errors are allowed to bubble, catch and return them
+ if ( conv && s[ "throws" ] ) {
+ response = conv( response );
+ } else {
+ try {
+ response = conv( response );
+ } catch ( e ) {
+ return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return { state: "success", data: response };
+}
+
+jQuery.extend({
+
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+ etag: {},
+
+ ajaxSettings: {
+ url: ajaxLocation,
+ type: "GET",
+ isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+ global: true,
+ processData: true,
+ async: true,
+ contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+ /*
+ timeout: 0,
+ data: null,
+ dataType: null,
+ username: null,
+ password: null,
+ cache: null,
+ throws: false,
+ traditional: false,
+ headers: {},
+ */
+
+ accepts: {
+ "*": allTypes,
+ text: "text/plain",
+ html: "text/html",
+ xml: "application/xml, text/xml",
+ json: "application/json, text/javascript"
+ },
+
+ contents: {
+ xml: /xml/,
+ html: /html/,
+ json: /json/
+ },
+
+ responseFields: {
+ xml: "responseXML",
+ text: "responseText",
+ json: "responseJSON"
+ },
+
+ // Data converters
+ // Keys separate source (or catchall "*") and destination types with a single space
+ converters: {
+
+ // Convert anything to text
+ "* text": String,
+
+ // Text to html (true = no transformation)
+ "text html": true,
+
+ // Evaluate text as a json expression
+ "text json": jQuery.parseJSON,
+
+ // Parse text as xml
+ "text xml": jQuery.parseXML
+ },
+
+ // For options that shouldn't be deep extended:
+ // you can add your own custom options here if
+ // and when you create one that shouldn't be
+ // deep extended (see ajaxExtend)
+ flatOptions: {
+ url: true,
+ context: true
+ }
+ },
+
+ // Creates a full fledged settings object into target
+ // with both ajaxSettings and settings fields.
+ // If target is omitted, writes into ajaxSettings.
+ ajaxSetup: function( target, settings ) {
+ return settings ?
+
+ // Building a settings object
+ ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
+
+ // Extending ajaxSettings
+ ajaxExtend( jQuery.ajaxSettings, target );
+ },
+
+ ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+ ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+ // Main method
+ ajax: function( url, options ) {
+
+ // If url is an object, simulate pre-1.5 signature
+ if ( typeof url === "object" ) {
+ options = url;
+ url = undefined;
+ }
+
+ // Force options to be an object
+ options = options || {};
+
+ var transport,
+ // URL without anti-cache param
+ cacheURL,
+ // Response headers
+ responseHeadersString,
+ responseHeaders,
+ // timeout handle
+ timeoutTimer,
+ // Cross-domain detection vars
+ parts,
+ // To know if global events are to be dispatched
+ fireGlobals,
+ // Loop variable
+ i,
+ // Create the final options object
+ s = jQuery.ajaxSetup( {}, options ),
+ // Callbacks context
+ callbackContext = s.context || s,
+ // Context for global events is callbackContext if it is a DOM node or jQuery collection
+ globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
+ jQuery( callbackContext ) :
+ jQuery.event,
+ // Deferreds
+ deferred = jQuery.Deferred(),
+ completeDeferred = jQuery.Callbacks("once memory"),
+ // Status-dependent callbacks
+ statusCode = s.statusCode || {},
+ // Headers (they are sent all at once)
+ requestHeaders = {},
+ requestHeadersNames = {},
+ // The jqXHR state
+ state = 0,
+ // Default abort message
+ strAbort = "canceled",
+ // Fake xhr
+ jqXHR = {
+ readyState: 0,
+
+ // Builds headers hashtable if needed
+ getResponseHeader: function( key ) {
+ var match;
+ if ( state === 2 ) {
+ if ( !responseHeaders ) {
+ responseHeaders = {};
+ while ( (match = rheaders.exec( responseHeadersString )) ) {
+ responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+ }
+ }
+ match = responseHeaders[ key.toLowerCase() ];
+ }
+ return match == null ? null : match;
+ },
+
+ // Raw string
+ getAllResponseHeaders: function() {
+ return state === 2 ? responseHeadersString : null;
+ },
+
+ // Caches the header
+ setRequestHeader: function( name, value ) {
+ var lname = name.toLowerCase();
+ if ( !state ) {
+ name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+ requestHeaders[ name ] = value;
+ }
+ return this;
+ },
+
+ // Overrides response content-type header
+ overrideMimeType: function( type ) {
+ if ( !state ) {
+ s.mimeType = type;
+ }
+ return this;
+ },
+
+ // Status-dependent callbacks
+ statusCode: function( map ) {
+ var code;
+ if ( map ) {
+ if ( state < 2 ) {
+ for ( code in map ) {
+ // Lazy-add the new callback in a way that preserves old ones
+ statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
+ }
+ } else {
+ // Execute the appropriate callbacks
+ jqXHR.always( map[ jqXHR.status ] );
+ }
+ }
+ return this;
+ },
+
+ // Cancel the request
+ abort: function( statusText ) {
+ var finalText = statusText || strAbort;
+ if ( transport ) {
+ transport.abort( finalText );
+ }
+ done( 0, finalText );
+ return this;
+ }
+ };
+
+ // Attach deferreds
+ deferred.promise( jqXHR ).complete = completeDeferred.add;
+ jqXHR.success = jqXHR.done;
+ jqXHR.error = jqXHR.fail;
+
+ // Remove hash character (#7531: and string promotion)
+ // Add protocol if not provided (prefilters might expect it)
+ // Handle falsy url in the settings object (#10093: consistency with old signature)
+ // We also use the url parameter if available
+ s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" )
+ .replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+ // Alias method option to type as per ticket #12004
+ s.type = options.method || options.type || s.method || s.type;
+
+ // Extract dataTypes list
+ s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];
+
+ // A cross-domain request is in order when we have a protocol:host:port mismatch
+ if ( s.crossDomain == null ) {
+ parts = rurl.exec( s.url.toLowerCase() );
+ s.crossDomain = !!( parts &&
+ ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
+ ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
+ ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
+ );
+ }
+
+ // Convert data if not already a string
+ if ( s.data && s.processData && typeof s.data !== "string" ) {
+ s.data = jQuery.param( s.data, s.traditional );
+ }
+
+ // Apply prefilters
+ inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+ // If request was aborted inside a prefilter, stop there
+ if ( state === 2 ) {
+ return jqXHR;
+ }
+
+ // We can fire global events as of now if asked to
+ // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
+ fireGlobals = jQuery.event && s.global;
+
+ // Watch for a new set of requests
+ if ( fireGlobals && jQuery.active++ === 0 ) {
+ jQuery.event.trigger("ajaxStart");
+ }
+
+ // Uppercase the type
+ s.type = s.type.toUpperCase();
+
+ // Determine if request has content
+ s.hasContent = !rnoContent.test( s.type );
+
+ // Save the URL in case we're toying with the If-Modified-Since
+ // and/or If-None-Match header later on
+ cacheURL = s.url;
+
+ // More options handling for requests with no content
+ if ( !s.hasContent ) {
+
+ // If data is available, append data to url
+ if ( s.data ) {
+ cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
+ // #9682: remove data so that it's not used in an eventual retry
+ delete s.data;
+ }
+
+ // Add anti-cache in url if needed
+ if ( s.cache === false ) {
+ s.url = rts.test( cacheURL ) ?
+
+ // If there is already a '_' parameter, set its value
+ cacheURL.replace( rts, "$1_=" + nonce++ ) :
+
+ // Otherwise add one to the end
+ cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++;
+ }
+ }
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ if ( jQuery.lastModified[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
+ }
+ if ( jQuery.etag[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
+ }
+ }
+
+ // Set the correct header, if data is being sent
+ if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+ jqXHR.setRequestHeader( "Content-Type", s.contentType );
+ }
+
+ // Set the Accepts header for the server, depending on the dataType
+ jqXHR.setRequestHeader(
+ "Accept",
+ s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+ s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+ s.accepts[ "*" ]
+ );
+
+ // Check for headers option
+ for ( i in s.headers ) {
+ jqXHR.setRequestHeader( i, s.headers[ i ] );
+ }
+
+ // Allow custom headers/mimetypes and early abort
+ if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+ // Abort if not done already and return
+ return jqXHR.abort();
+ }
+
+ // Aborting is no longer a cancellation
+ strAbort = "abort";
+
+ // Install callbacks on deferreds
+ for ( i in { success: 1, error: 1, complete: 1 } ) {
+ jqXHR[ i ]( s[ i ] );
+ }
+
+ // Get transport
+ transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+ // If no transport, we auto-abort
+ if ( !transport ) {
+ done( -1, "No Transport" );
+ } else {
+ jqXHR.readyState = 1;
+
+ // Send global event
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+ }
+ // Timeout
+ if ( s.async && s.timeout > 0 ) {
+ timeoutTimer = setTimeout(function() {
+ jqXHR.abort("timeout");
+ }, s.timeout );
+ }
+
+ try {
+ state = 1;
+ transport.send( requestHeaders, done );
+ } catch ( e ) {
+ // Propagate exception as error if not done
+ if ( state < 2 ) {
+ done( -1, e );
+ // Simply rethrow otherwise
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ // Callback for when everything is done
+ function done( status, nativeStatusText, responses, headers ) {
+ var isSuccess, success, error, response, modified,
+ statusText = nativeStatusText;
+
+ // Called once
+ if ( state === 2 ) {
+ return;
+ }
+
+ // State is "done" now
+ state = 2;
+
+ // Clear timeout if it exists
+ if ( timeoutTimer ) {
+ clearTimeout( timeoutTimer );
+ }
+
+ // Dereference transport for early garbage collection
+ // (no matter how long the jqXHR object will be used)
+ transport = undefined;
+
+ // Cache response headers
+ responseHeadersString = headers || "";
+
+ // Set readyState
+ jqXHR.readyState = status > 0 ? 4 : 0;
+
+ // Determine if successful
+ isSuccess = status >= 200 && status < 300 || status === 304;
+
+ // Get response data
+ if ( responses ) {
+ response = ajaxHandleResponses( s, jqXHR, responses );
+ }
+
+ // Convert no matter what (that way responseXXX fields are always set)
+ response = ajaxConvert( s, response, jqXHR, isSuccess );
+
+ // If successful, handle type chaining
+ if ( isSuccess ) {
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ modified = jqXHR.getResponseHeader("Last-Modified");
+ if ( modified ) {
+ jQuery.lastModified[ cacheURL ] = modified;
+ }
+ modified = jqXHR.getResponseHeader("etag");
+ if ( modified ) {
+ jQuery.etag[ cacheURL ] = modified;
+ }
+ }
+
+ // if no content
+ if ( status === 204 || s.type === "HEAD" ) {
+ statusText = "nocontent";
+
+ // if not modified
+ } else if ( status === 304 ) {
+ statusText = "notmodified";
+
+ // If we have data, let's convert it
+ } else {
+ statusText = response.state;
+ success = response.data;
+ error = response.error;
+ isSuccess = !error;
+ }
+ } else {
+ // Extract error from statusText and normalize for non-aborts
+ error = statusText;
+ if ( status || !statusText ) {
+ statusText = "error";
+ if ( status < 0 ) {
+ status = 0;
+ }
+ }
+ }
+
+ // Set data for the fake xhr object
+ jqXHR.status = status;
+ jqXHR.statusText = ( nativeStatusText || statusText ) + "";
+
+ // Success/Error
+ if ( isSuccess ) {
+ deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+ } else {
+ deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+ }
+
+ // Status-dependent callbacks
+ jqXHR.statusCode( statusCode );
+ statusCode = undefined;
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
+ [ jqXHR, s, isSuccess ? success : error ] );
+ }
+
+ // Complete
+ completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+ // Handle the global AJAX counter
+ if ( !( --jQuery.active ) ) {
+ jQuery.event.trigger("ajaxStop");
+ }
+ }
+ }
+
+ return jqXHR;
+ },
+
+ getJSON: function( url, data, callback ) {
+ return jQuery.get( url, data, callback, "json" );
+ },
+
+ getScript: function( url, callback ) {
+ return jQuery.get( url, undefined, callback, "script" );
+ }
+});
+
+jQuery.each( [ "get", "post" ], function( i, method ) {
+ jQuery[ method ] = function( url, data, callback, type ) {
+ // Shift arguments if data argument was omitted
+ if ( jQuery.isFunction( data ) ) {
+ type = type || callback;
+ callback = data;
+ data = undefined;
+ }
+
+ return jQuery.ajax({
+ url: url,
+ type: method,
+ dataType: type,
+ data: data,
+ success: callback
+ });
+ };
+});
+
+
+jQuery._evalUrl = function( url ) {
+ return jQuery.ajax({
+ url: url,
+ type: "GET",
+ dataType: "script",
+ async: false,
+ global: false,
+ "throws": true
+ });
+};
+
+
+jQuery.fn.extend({
+ wrapAll: function( html ) {
+ var wrap;
+
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function( i ) {
+ jQuery( this ).wrapAll( html.call(this, i) );
+ });
+ }
+
+ if ( this[ 0 ] ) {
+
+ // The elements to wrap the target around
+ wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
+
+ if ( this[ 0 ].parentNode ) {
+ wrap.insertBefore( this[ 0 ] );
+ }
+
+ wrap.map(function() {
+ var elem = this;
+
+ while ( elem.firstElementChild ) {
+ elem = elem.firstElementChild;
+ }
+
+ return elem;
+ }).append( this );
+ }
+
+ return this;
+ },
+
+ wrapInner: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function( i ) {
+ jQuery( this ).wrapInner( html.call(this, i) );
+ });
+ }
+
+ return this.each(function() {
+ var self = jQuery( this ),
+ contents = self.contents();
+
+ if ( contents.length ) {
+ contents.wrapAll( html );
+
+ } else {
+ self.append( html );
+ }
+ });
+ },
+
+ wrap: function( html ) {
+ var isFunction = jQuery.isFunction( html );
+
+ return this.each(function( i ) {
+ jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
+ });
+ },
+
+ unwrap: function() {
+ return this.parent().each(function() {
+ if ( !jQuery.nodeName( this, "body" ) ) {
+ jQuery( this ).replaceWith( this.childNodes );
+ }
+ }).end();
+ }
+});
+
+
+jQuery.expr.filters.hidden = function( elem ) {
+ // Support: Opera <= 12.12
+ // Opera reports offsetWidths and offsetHeights less than zero on some elements
+ return elem.offsetWidth <= 0 && elem.offsetHeight <= 0;
+};
+jQuery.expr.filters.visible = function( elem ) {
+ return !jQuery.expr.filters.hidden( elem );
+};
+
+
+
+
+var r20 = /%20/g,
+ rbracket = /\[\]$/,
+ rCRLF = /\r?\n/g,
+ rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
+ rsubmittable = /^(?:input|select|textarea|keygen)/i;
+
+function buildParams( prefix, obj, traditional, add ) {
+ var name;
+
+ if ( jQuery.isArray( obj ) ) {
+ // Serialize array item.
+ jQuery.each( obj, function( i, v ) {
+ if ( traditional || rbracket.test( prefix ) ) {
+ // Treat each array item as a scalar.
+ add( prefix, v );
+
+ } else {
+ // Item is non-scalar (array or object), encode its numeric index.
+ buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
+ }
+ });
+
+ } else if ( !traditional && jQuery.type( obj ) === "object" ) {
+ // Serialize object item.
+ for ( name in obj ) {
+ buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+ }
+
+ } else {
+ // Serialize scalar item.
+ add( prefix, obj );
+ }
+}
+
+// Serialize an array of form elements or a set of
+// key/values into a query string
+jQuery.param = function( a, traditional ) {
+ var prefix,
+ s = [],
+ add = function( key, value ) {
+ // If value is a function, invoke it and return its value
+ value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
+ s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+ };
+
+ // Set traditional to true for jQuery <= 1.3.2 behavior.
+ if ( traditional === undefined ) {
+ traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
+ }
+
+ // If an array was passed in, assume that it is an array of form elements.
+ if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+ // Serialize the form elements
+ jQuery.each( a, function() {
+ add( this.name, this.value );
+ });
+
+ } else {
+ // If traditional, encode the "old" way (the way 1.3.2 or older
+ // did it), otherwise encode params recursively.
+ for ( prefix in a ) {
+ buildParams( prefix, a[ prefix ], traditional, add );
+ }
+ }
+
+ // Return the resulting serialization
+ return s.join( "&" ).replace( r20, "+" );
+};
+
+jQuery.fn.extend({
+ serialize: function() {
+ return jQuery.param( this.serializeArray() );
+ },
+ serializeArray: function() {
+ return this.map(function() {
+ // Can add propHook for "elements" to filter or add form elements
+ var elements = jQuery.prop( this, "elements" );
+ return elements ? jQuery.makeArray( elements ) : this;
+ })
+ .filter(function() {
+ var type = this.type;
+
+ // Use .is( ":disabled" ) so that fieldset[disabled] works
+ return this.name && !jQuery( this ).is( ":disabled" ) &&
+ rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
+ ( this.checked || !rcheckableType.test( type ) );
+ })
+ .map(function( i, elem ) {
+ var val = jQuery( this ).val();
+
+ return val == null ?
+ null :
+ jQuery.isArray( val ) ?
+ jQuery.map( val, function( val ) {
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }) :
+ { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }).get();
+ }
+});
+
+
+jQuery.ajaxSettings.xhr = function() {
+ try {
+ return new XMLHttpRequest();
+ } catch( e ) {}
+};
+
+var xhrId = 0,
+ xhrCallbacks = {},
+ xhrSuccessStatus = {
+ // file protocol always yields status code 0, assume 200
+ 0: 200,
+ // Support: IE9
+ // #1450: sometimes IE returns 1223 when it should be 204
+ 1223: 204
+ },
+ xhrSupported = jQuery.ajaxSettings.xhr();
+
+// Support: IE9
+// Open requests must be manually aborted on unload (#5280)
+// See https://support.microsoft.com/kb/2856746 for more info
+if ( window.attachEvent ) {
+ window.attachEvent( "onunload", function() {
+ for ( var key in xhrCallbacks ) {
+ xhrCallbacks[ key ]();
+ }
+ });
+}
+
+support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
+support.ajax = xhrSupported = !!xhrSupported;
+
+jQuery.ajaxTransport(function( options ) {
+ var callback;
+
+ // Cross domain only allowed if supported through XMLHttpRequest
+ if ( support.cors || xhrSupported && !options.crossDomain ) {
+ return {
+ send: function( headers, complete ) {
+ var i,
+ xhr = options.xhr(),
+ id = ++xhrId;
+
+ xhr.open( options.type, options.url, options.async, options.username, options.password );
+
+ // Apply custom fields if provided
+ if ( options.xhrFields ) {
+ for ( i in options.xhrFields ) {
+ xhr[ i ] = options.xhrFields[ i ];
+ }
+ }
+
+ // Override mime type if needed
+ if ( options.mimeType && xhr.overrideMimeType ) {
+ xhr.overrideMimeType( options.mimeType );
+ }
+
+ // X-Requested-With header
+ // For cross-domain requests, seeing as conditions for a preflight are
+ // akin to a jigsaw puzzle, we simply never set it to be sure.
+ // (it can always be set on a per-request basis or even using ajaxSetup)
+ // For same-domain requests, won't change header if already provided.
+ if ( !options.crossDomain && !headers["X-Requested-With"] ) {
+ headers["X-Requested-With"] = "XMLHttpRequest";
+ }
+
+ // Set headers
+ for ( i in headers ) {
+ xhr.setRequestHeader( i, headers[ i ] );
+ }
+
+ // Callback
+ callback = function( type ) {
+ return function() {
+ if ( callback ) {
+ delete xhrCallbacks[ id ];
+ callback = xhr.onload = xhr.onerror = null;
+
+ if ( type === "abort" ) {
+ xhr.abort();
+ } else if ( type === "error" ) {
+ complete(
+ // file: protocol always yields status 0; see #8605, #14207
+ xhr.status,
+ xhr.statusText
+ );
+ } else {
+ complete(
+ xhrSuccessStatus[ xhr.status ] || xhr.status,
+ xhr.statusText,
+ // Support: IE9
+ // Accessing binary-data responseText throws an exception
+ // (#11426)
+ typeof xhr.responseText === "string" ? {
+ text: xhr.responseText
+ } : undefined,
+ xhr.getAllResponseHeaders()
+ );
+ }
+ }
+ };
+ };
+
+ // Listen to events
+ xhr.onload = callback();
+ xhr.onerror = callback("error");
+
+ // Create the abort callback
+ callback = xhrCallbacks[ id ] = callback("abort");
+
+ try {
+ // Do send the request (this may raise an exception)
+ xhr.send( options.hasContent && options.data || null );
+ } catch ( e ) {
+ // #14683: Only rethrow if this hasn't been notified as an error yet
+ if ( callback ) {
+ throw e;
+ }
+ }
+ },
+
+ abort: function() {
+ if ( callback ) {
+ callback();
+ }
+ }
+ };
+ }
+});
+
+
+
+
+// Install script dataType
+jQuery.ajaxSetup({
+ accepts: {
+ script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+ },
+ contents: {
+ script: /(?:java|ecma)script/
+ },
+ converters: {
+ "text script": function( text ) {
+ jQuery.globalEval( text );
+ return text;
+ }
+ }
+});
+
+// Handle cache's special case and crossDomain
+jQuery.ajaxPrefilter( "script", function( s ) {
+ if ( s.cache === undefined ) {
+ s.cache = false;
+ }
+ if ( s.crossDomain ) {
+ s.type = "GET";
+ }
+});
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function( s ) {
+ // This transport only deals with cross domain requests
+ if ( s.crossDomain ) {
+ var script, callback;
+ return {
+ send: function( _, complete ) {
+ script = jQuery("<script>").prop({
+ async: true,
+ charset: s.scriptCharset,
+ src: s.url
+ }).on(
+ "load error",
+ callback = function( evt ) {
+ script.remove();
+ callback = null;
+ if ( evt ) {
+ complete( evt.type === "error" ? 404 : 200, evt.type );
+ }
+ }
+ );
+ document.head.appendChild( script[ 0 ] );
+ },
+ abort: function() {
+ if ( callback ) {
+ callback();
+ }
+ }
+ };
+ }
+});
+
+
+
+
+var oldCallbacks = [],
+ rjsonp = /(=)\?(?=&|$)|\?\?/;
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+ jsonp: "callback",
+ jsonpCallback: function() {
+ var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
+ this[ callback ] = true;
+ return callback;
+ }
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+ var callbackName, overwritten, responseContainer,
+ jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
+ "url" :
+ typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
+ );
+
+ // Handle iff the expected data type is "jsonp" or we have a parameter to set
+ if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
+
+ // Get callback name, remembering preexisting value associated with it
+ callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
+ s.jsonpCallback() :
+ s.jsonpCallback;
+
+ // Insert callback into url or form data
+ if ( jsonProp ) {
+ s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
+ } else if ( s.jsonp !== false ) {
+ s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
+ }
+
+ // Use data converter to retrieve json after script execution
+ s.converters["script json"] = function() {
+ if ( !responseContainer ) {
+ jQuery.error( callbackName + " was not called" );
+ }
+ return responseContainer[ 0 ];
+ };
+
+ // force json dataType
+ s.dataTypes[ 0 ] = "json";
+
+ // Install callback
+ overwritten = window[ callbackName ];
+ window[ callbackName ] = function() {
+ responseContainer = arguments;
+ };
+
+ // Clean-up function (fires after converters)
+ jqXHR.always(function() {
+ // Restore preexisting value
+ window[ callbackName ] = overwritten;
+
+ // Save back as free
+ if ( s[ callbackName ] ) {
+ // make sure that re-using the options doesn't screw things around
+ s.jsonpCallback = originalSettings.jsonpCallback;
+
+ // save the callback name for future use
+ oldCallbacks.push( callbackName );
+ }
+
+ // Call if it was a function and we have a response
+ if ( responseContainer && jQuery.isFunction( overwritten ) ) {
+ overwritten( responseContainer[ 0 ] );
+ }
+
+ responseContainer = overwritten = undefined;
+ });
+
+ // Delegate to script
+ return "script";
+ }
+});
+
+
+
+
+// data: string of html
+// context (optional): If specified, the fragment will be created in this context, defaults to document
+// keepScripts (optional): If true, will include scripts passed in the html string
+jQuery.parseHTML = function( data, context, keepScripts ) {
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+ if ( typeof context === "boolean" ) {
+ keepScripts = context;
+ context = false;
+ }
+ context = context || document;
+
+ var parsed = rsingleTag.exec( data ),
+ scripts = !keepScripts && [];
+
+ // Single tag
+ if ( parsed ) {
+ return [ context.createElement( parsed[1] ) ];
+ }
+
+ parsed = jQuery.buildFragment( [ data ], context, scripts );
+
+ if ( scripts && scripts.length ) {
+ jQuery( scripts ).remove();
+ }
+
+ return jQuery.merge( [], parsed.childNodes );
+};
+
+
+// Keep a copy of the old load method
+var _load = jQuery.fn.load;
+
+/**
+ * Load a url into a page
+ */
+jQuery.fn.load = function( url, params, callback ) {
+ if ( typeof url !== "string" && _load ) {
+ return _load.apply( this, arguments );
+ }
+
+ var selector, type, response,
+ self = this,
+ off = url.indexOf(" ");
+
+ if ( off >= 0 ) {
+ selector = jQuery.trim( url.slice( off ) );
+ url = url.slice( 0, off );
+ }
+
+ // If it's a function
+ if ( jQuery.isFunction( params ) ) {
+
+ // We assume that it's the callback
+ callback = params;
+ params = undefined;
+
+ // Otherwise, build a param string
+ } else if ( params && typeof params === "object" ) {
+ type = "POST";
+ }
+
+ // If we have elements to modify, make the request
+ if ( self.length > 0 ) {
+ jQuery.ajax({
+ url: url,
+
+ // if "type" variable is undefined, then "GET" method will be used
+ type: type,
+ dataType: "html",
+ data: params
+ }).done(function( responseText ) {
+
+ // Save response for use in complete callback
+ response = arguments;
+
+ self.html( selector ?
+
+ // If a selector was specified, locate the right elements in a dummy div
+ // Exclude scripts to avoid IE 'Permission Denied' errors
+ jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
+
+ // Otherwise use the full result
+ responseText );
+
+ }).complete( callback && function( jqXHR, status ) {
+ self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
+ });
+ }
+
+ return this;
+};
+
+
+
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) {
+ jQuery.fn[ type ] = function( fn ) {
+ return this.on( type, fn );
+ };
+});
+
+
+
+
+jQuery.expr.filters.animated = function( elem ) {
+ return jQuery.grep(jQuery.timers, function( fn ) {
+ return elem === fn.elem;
+ }).length;
+};
+
+
+
+
+var docElem = window.document.documentElement;
+
+/**
+ * Gets a window from an element
+ */
+function getWindow( elem ) {
+ return jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;
+}
+
+jQuery.offset = {
+ setOffset: function( elem, options, i ) {
+ var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
+ position = jQuery.css( elem, "position" ),
+ curElem = jQuery( elem ),
+ props = {};
+
+ // Set position first, in-case top/left are set even on static elem
+ if ( position === "static" ) {
+ elem.style.position = "relative";
+ }
+
+ curOffset = curElem.offset();
+ curCSSTop = jQuery.css( elem, "top" );
+ curCSSLeft = jQuery.css( elem, "left" );
+ calculatePosition = ( position === "absolute" || position === "fixed" ) &&
+ ( curCSSTop + curCSSLeft ).indexOf("auto") > -1;
+
+ // Need to be able to calculate position if either
+ // top or left is auto and position is either absolute or fixed
+ if ( calculatePosition ) {
+ curPosition = curElem.position();
+ curTop = curPosition.top;
+ curLeft = curPosition.left;
+
+ } else {
+ curTop = parseFloat( curCSSTop ) || 0;
+ curLeft = parseFloat( curCSSLeft ) || 0;
+ }
+
+ if ( jQuery.isFunction( options ) ) {
+ options = options.call( elem, i, curOffset );
+ }
+
+ if ( options.top != null ) {
+ props.top = ( options.top - curOffset.top ) + curTop;
+ }
+ if ( options.left != null ) {
+ props.left = ( options.left - curOffset.left ) + curLeft;
+ }
+
+ if ( "using" in options ) {
+ options.using.call( elem, props );
+
+ } else {
+ curElem.css( props );
+ }
+ }
+};
+
+jQuery.fn.extend({
+ offset: function( options ) {
+ if ( arguments.length ) {
+ return options === undefined ?
+ this :
+ this.each(function( i ) {
+ jQuery.offset.setOffset( this, options, i );
+ });
+ }
+
+ var docElem, win,
+ elem = this[ 0 ],
+ box = { top: 0, left: 0 },
+ doc = elem && elem.ownerDocument;
+
+ if ( !doc ) {
+ return;
+ }
+
+ docElem = doc.documentElement;
+
+ // Make sure it's not a disconnected DOM node
+ if ( !jQuery.contains( docElem, elem ) ) {
+ return box;
+ }
+
+ // Support: BlackBerry 5, iOS 3 (original iPhone)
+ // If we don't have gBCR, just use 0,0 rather than error
+ if ( typeof elem.getBoundingClientRect !== strundefined ) {
+ box = elem.getBoundingClientRect();
+ }
+ win = getWindow( doc );
+ return {
+ top: box.top + win.pageYOffset - docElem.clientTop,
+ left: box.left + win.pageXOffset - docElem.clientLeft
+ };
+ },
+
+ position: function() {
+ if ( !this[ 0 ] ) {
+ return;
+ }
+
+ var offsetParent, offset,
+ elem = this[ 0 ],
+ parentOffset = { top: 0, left: 0 };
+
+ // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent
+ if ( jQuery.css( elem, "position" ) === "fixed" ) {
+ // Assume getBoundingClientRect is there when computed position is fixed
+ offset = elem.getBoundingClientRect();
+
+ } else {
+ // Get *real* offsetParent
+ offsetParent = this.offsetParent();
+
+ // Get correct offsets
+ offset = this.offset();
+ if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
+ parentOffset = offsetParent.offset();
+ }
+
+ // Add offsetParent borders
+ parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
+ parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
+ }
+
+ // Subtract parent offsets and element margins
+ return {
+ top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
+ left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
+ };
+ },
+
+ offsetParent: function() {
+ return this.map(function() {
+ var offsetParent = this.offsetParent || docElem;
+
+ while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position" ) === "static" ) ) {
+ offsetParent = offsetParent.offsetParent;
+ }
+
+ return offsetParent || docElem;
+ });
+ }
+});
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
+ var top = "pageYOffset" === prop;
+
+ jQuery.fn[ method ] = function( val ) {
+ return access( this, function( elem, method, val ) {
+ var win = getWindow( elem );
+
+ if ( val === undefined ) {
+ return win ? win[ prop ] : elem[ method ];
+ }
+
+ if ( win ) {
+ win.scrollTo(
+ !top ? val : window.pageXOffset,
+ top ? val : window.pageYOffset
+ );
+
+ } else {
+ elem[ method ] = val;
+ }
+ }, method, val, arguments.length, null );
+ };
+});
+
+// Support: Safari<7+, Chrome<37+
+// Add the top/left cssHooks using jQuery.fn.position
+// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+// Blink bug: https://code.google.com/p/chromium/issues/detail?id=229280
+// getComputedStyle returns percent when specified for top/left/bottom/right;
+// rather than make the css module depend on the offset module, just check for it here
+jQuery.each( [ "top", "left" ], function( i, prop ) {
+ jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
+ function( elem, computed ) {
+ if ( computed ) {
+ computed = curCSS( elem, prop );
+ // If curCSS returns percentage, fallback to offset
+ return rnumnonpx.test( computed ) ?
+ jQuery( elem ).position()[ prop ] + "px" :
+ computed;
+ }
+ }
+ );
+});
+
+
+// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+ jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
+ // Margin is only for outerHeight, outerWidth
+ jQuery.fn[ funcName ] = function( margin, value ) {
+ var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
+ extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
+
+ return access( this, function( elem, type, value ) {
+ var doc;
+
+ if ( jQuery.isWindow( elem ) ) {
+ // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
+ // isn't a whole lot we can do. See pull request at this URL for discussion:
+ // https://github.com/jquery/jquery/pull/764
+ return elem.document.documentElement[ "client" + name ];
+ }
+
+ // Get document width or height
+ if ( elem.nodeType === 9 ) {
+ doc = elem.documentElement;
+
+ // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
+ // whichever is greatest
+ return Math.max(
+ elem.body[ "scroll" + name ], doc[ "scroll" + name ],
+ elem.body[ "offset" + name ], doc[ "offset" + name ],
+ doc[ "client" + name ]
+ );
+ }
+
+ return value === undefined ?
+ // Get width or height on the element, requesting but not forcing parseFloat
+ jQuery.css( elem, type, extra ) :
+
+ // Set width or height on the element
+ jQuery.style( elem, type, value, extra );
+ }, type, chainable ? margin : undefined, chainable, null );
+ };
+ });
+});
+
+
+// The number of elements contained in the matched element set
+jQuery.fn.size = function() {
+ return this.length;
+};
+
+jQuery.fn.andSelf = jQuery.fn.addBack;
+
+
+
+
+// Register as a named AMD module, since jQuery can be concatenated with other
+// files that may use define, but not via a proper concatenation script that
+// understands anonymous AMD modules. A named AMD is safest and most robust
+// way to register. Lowercase jquery is used because AMD module names are
+// derived from file names, and jQuery is normally delivered in a lowercase
+// file name. Do this after creating the global so that if an AMD module wants
+// to call noConflict to hide this version of jQuery, it will work.
+
+// Note that for maximum portability, libraries that are not jQuery should
+// declare themselves as anonymous modules, and avoid setting a global if an
+// AMD loader is present. jQuery is a special case. For more information, see
+// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
+
+if ( typeof define === "function" && define.amd ) {
+ define( "jquery", [], function() {
+ return jQuery;
+ });
+}
+
+
+
+
+var
+ // Map over jQuery in case of overwrite
+ _jQuery = window.jQuery,
+
+ // Map over the $ in case of overwrite
+ _$ = window.$;
+
+jQuery.noConflict = function( deep ) {
+ if ( window.$ === jQuery ) {
+ window.$ = _$;
+ }
+
+ if ( deep && window.jQuery === jQuery ) {
+ window.jQuery = _jQuery;
+ }
+
+ return jQuery;
+};
+
+// Expose jQuery and $ identifiers, even in AMD
+// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
+// and CommonJS for browser emulators (#13566)
+if ( typeof noGlobal === strundefined ) {
+ window.jQuery = window.$ = jQuery;
+}
+
+
+
+
+return jQuery;
+
+}));
+
+},{}],"lodash":[function(require,module,exports){
+(function (global){
+/**
+ * @license
+ * Lo-Dash 2.4.1 (Custom Build) <http://lodash.com/>
+ * Build: `lodash modern -o ./dist/lodash.js`
+ * Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.5.2 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ * Available under MIT license <http://lodash.com/license>
+ */
+;(function() {
+
+ /** Used as a safe reference for `undefined` in pre ES5 environments */
+ var undefined;
+
+ /** Used to pool arrays and objects used internally */
+ var arrayPool = [],
+ objectPool = [];
+
+ /** Used to generate unique IDs */
+ var idCounter = 0;
+
+ /** Used to prefix keys to avoid issues with `__proto__` and properties on `Object.prototype` */
+ var keyPrefix = +new Date + '';
+
+ /** Used as the size when optimizations are enabled for large arrays */
+ var largeArraySize = 75;
+
+ /** Used as the max size of the `arrayPool` and `objectPool` */
+ var maxPoolSize = 40;
+
+ /** Used to detect and test whitespace */
+ var whitespace = (
+ // whitespace
+ ' \t\x0B\f\xA0\ufeff' +
+
+ // line terminators
+ '\n\r\u2028\u2029' +
+
+ // unicode category "Zs" space separators
+ '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'
+ );
+
+ /** Used to match empty string literals in compiled template source */
+ var reEmptyStringLeading = /\b__p \+= '';/g,
+ reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
+ reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
+
+ /**
+ * Used to match ES6 template delimiters
+ * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-literals-string-literals
+ */
+ var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
+
+ /** Used to match regexp flags from their coerced string values */
+ var reFlags = /\w*$/;
+
+ /** Used to detected named functions */
+ var reFuncName = /^\s*function[ \n\r\t]+\w/;
+
+ /** Used to match "interpolate" template delimiters */
+ var reInterpolate = /<%=([\s\S]+?)%>/g;
+
+ /** Used to match leading whitespace and zeros to be removed */
+ var reLeadingSpacesAndZeros = RegExp('^[' + whitespace + ']*0+(?=.$)');
+
+ /** Used to ensure capturing order of template delimiters */
+ var reNoMatch = /($^)/;
+
+ /** Used to detect functions containing a `this` reference */
+ var reThis = /\bthis\b/;
+
+ /** Used to match unescaped characters in compiled string literals */
+ var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g;
+
+ /** Used to assign default `context` object properties */
+ var contextProps = [
+ 'Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object',
+ 'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN',
+ 'parseInt', 'setTimeout'
+ ];
+
+ /** Used to make template sourceURLs easier to identify */
+ var templateCounter = 0;
+
+ /** `Object#toString` result shortcuts */
+ var argsClass = '[object Arguments]',
+ arrayClass = '[object Array]',
+ boolClass = '[object Boolean]',
+ dateClass = '[object Date]',
+ funcClass = '[object Function]',
+ numberClass = '[object Number]',
+ objectClass = '[object Object]',
+ regexpClass = '[object RegExp]',
+ stringClass = '[object String]';
+
+ /** Used to identify object classifications that `_.clone` supports */
+ var cloneableClasses = {};
+ cloneableClasses[funcClass] = false;
+ cloneableClasses[argsClass] = cloneableClasses[arrayClass] =
+ cloneableClasses[boolClass] = cloneableClasses[dateClass] =
+ cloneableClasses[numberClass] = cloneableClasses[objectClass] =
+ cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true;
+
+ /** Used as an internal `_.debounce` options object */
+ var debounceOptions = {
+ 'leading': false,
+ 'maxWait': 0,
+ 'trailing': false
+ };
+
+ /** Used as the property descriptor for `__bindData__` */
+ var descriptor = {
+ 'configurable': false,
+ 'enumerable': false,
+ 'value': null,
+ 'writable': false
+ };
+
+ /** Used to determine if values are of the language type Object */
+ var objectTypes = {
+ 'boolean': false,
+ 'function': true,
+ 'object': true,
+ 'number': false,
+ 'string': false,
+ 'undefined': false
+ };
+
+ /** Used to escape characters for inclusion in compiled string literals */
+ var stringEscapes = {
+ '\\': '\\',
+ "'": "'",
+ '\n': 'n',
+ '\r': 'r',
+ '\t': 't',
+ '\u2028': 'u2028',
+ '\u2029': 'u2029'
+ };
+
+ /** Used as a reference to the global object */
+ var root = (objectTypes[typeof window] && window) || this;
+
+ /** Detect free variable `exports` */
+ var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
+
+ /** Detect free variable `module` */
+ var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
+
+ /** Detect the popular CommonJS extension `module.exports` */
+ var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
+
+ /** Detect free variable `global` from Node.js or Browserified code and use it as `root` */
+ var freeGlobal = objectTypes[typeof global] && global;
+ if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) {
+ root = freeGlobal;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * The base implementation of `_.indexOf` without support for binary searches
+ * or `fromIndex` constraints.
+ *
+ * @private
+ * @param {Array} array The array to search.
+ * @param {*} value The value to search for.
+ * @param {number} [fromIndex=0] The index to search from.
+ * @returns {number} Returns the index of the matched value or `-1`.
+ */
+ function baseIndexOf(array, value, fromIndex) {
+ var index = (fromIndex || 0) - 1,
+ length = array ? array.length : 0;
+
+ while (++index < length) {
+ if (array[index] === value) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * An implementation of `_.contains` for cache objects that mimics the return
+ * signature of `_.indexOf` by returning `0` if the value is found, else `-1`.
+ *
+ * @private
+ * @param {Object} cache The cache object to inspect.
+ * @param {*} value The value to search for.
+ * @returns {number} Returns `0` if `value` is found, else `-1`.
+ */
+ function cacheIndexOf(cache, value) {
+ var type = typeof value;
+ cache = cache.cache;
+
+ if (type == 'boolean' || value == null) {
+ return cache[value] ? 0 : -1;
+ }
+ if (type != 'number' && type != 'string') {
+ type = 'object';
+ }
+ var key = type == 'number' ? value : keyPrefix + value;
+ cache = (cache = cache[type]) && cache[key];
+
+ return type == 'object'
+ ? (cache && baseIndexOf(cache, value) > -1 ? 0 : -1)
+ : (cache ? 0 : -1);
+ }
+
+ /**
+ * Adds a given value to the corresponding cache object.
+ *
+ * @private
+ * @param {*} value The value to add to the cache.
+ */
+ function cachePush(value) {
+ var cache = this.cache,
+ type = typeof value;
+
+ if (type == 'boolean' || value == null) {
+ cache[value] = true;
+ } else {
+ if (type != 'number' && type != 'string') {
+ type = 'object';
+ }
+ var key = type == 'number' ? value : keyPrefix + value,
+ typeCache = cache[type] || (cache[type] = {});
+
+ if (type == 'object') {
+ (typeCache[key] || (typeCache[key] = [])).push(value);
+ } else {
+ typeCache[key] = true;
+ }
+ }
+ }
+
+ /**
+ * Used by `_.max` and `_.min` as the default callback when a given
+ * collection is a string value.
+ *
+ * @private
+ * @param {string} value The character to inspect.
+ * @returns {number} Returns the code unit of given character.
+ */
+ function charAtCallback(value) {
+ return value.charCodeAt(0);
+ }
+
+ /**
+ * Used by `sortBy` to compare transformed `collection` elements, stable sorting
+ * them in ascending order.
+ *
+ * @private
+ * @param {Object} a The object to compare to `b`.
+ * @param {Object} b The object to compare to `a`.
+ * @returns {number} Returns the sort order indicator of `1` or `-1`.
+ */
+ function compareAscending(a, b) {
+ var ac = a.criteria,
+ bc = b.criteria,
+ index = -1,
+ length = ac.length;
+
+ while (++index < length) {
+ var value = ac[index],
+ other = bc[index];
+
+ if (value !== other) {
+ if (value > other || typeof value == 'undefined') {
+ return 1;
+ }
+ if (value < other || typeof other == 'undefined') {
+ return -1;
+ }
+ }
+ }
+ // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
+ // that causes it, under certain circumstances, to return the same value for
+ // `a` and `b`. See https://github.com/jashkenas/underscore/pull/1247
+ //
+ // This also ensures a stable sort in V8 and other engines.
+ // See http://code.google.com/p/v8/issues/detail?id=90
+ return a.index - b.index;
+ }
+
+ /**
+ * Creates a cache object to optimize linear searches of large arrays.
+ *
+ * @private
+ * @param {Array} [array=[]] The array to search.
+ * @returns {null|Object} Returns the cache object or `null` if caching should not be used.
+ */
+ function createCache(array) {
+ var index = -1,
+ length = array.length,
+ first = array[0],
+ mid = array[(length / 2) | 0],
+ last = array[length - 1];
+
+ if (first && typeof first == 'object' &&
+ mid && typeof mid == 'object' && last && typeof last == 'object') {
+ return false;
+ }
+ var cache = getObject();
+ cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false;
+
+ var result = getObject();
+ result.array = array;
+ result.cache = cache;
+ result.push = cachePush;
+
+ while (++index < length) {
+ result.push(array[index]);
+ }
+ return result;
+ }
+
+ /**
+ * Used by `template` to escape characters for inclusion in compiled
+ * string literals.
+ *
+ * @private
+ * @param {string} match The matched character to escape.
+ * @returns {string} Returns the escaped character.
+ */
+ function escapeStringChar(match) {
+ return '\\' + stringEscapes[match];
+ }
+
+ /**
+ * Gets an array from the array pool or creates a new one if the pool is empty.
+ *
+ * @private
+ * @returns {Array} The array from the pool.
+ */
+ function getArray() {
+ return arrayPool.pop() || [];
+ }
+
+ /**
+ * Gets an object from the object pool or creates a new one if the pool is empty.
+ *
+ * @private
+ * @returns {Object} The object from the pool.
+ */
+ function getObject() {
+ return objectPool.pop() || {
+ 'array': null,
+ 'cache': null,
+ 'criteria': null,
+ 'false': false,
+ 'index': 0,
+ 'null': false,
+ 'number': null,
+ 'object': null,
+ 'push': null,
+ 'string': null,
+ 'true': false,
+ 'undefined': false,
+ 'value': null
+ };
+ }
+
+ /**
+ * Releases the given array back to the array pool.
+ *
+ * @private
+ * @param {Array} [array] The array to release.
+ */
+ function releaseArray(array) {
+ array.length = 0;
+ if (arrayPool.length < maxPoolSize) {
+ arrayPool.push(array);
+ }
+ }
+
+ /**
+ * Releases the given object back to the object pool.
+ *
+ * @private
+ * @param {Object} [object] The object to release.
+ */
+ function releaseObject(object) {
+ var cache = object.cache;
+ if (cache) {
+ releaseObject(cache);
+ }
+ object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null;
+ if (objectPool.length < maxPoolSize) {
+ objectPool.push(object);
+ }
+ }
+
+ /**
+ * Slices the `collection` from the `start` index up to, but not including,
+ * the `end` index.
+ *
+ * Note: This function is used instead of `Array#slice` to support node lists
+ * in IE < 9 and to ensure dense arrays are returned.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to slice.
+ * @param {number} start The start index.
+ * @param {number} end The end index.
+ * @returns {Array} Returns the new array.
+ */
+ function slice(array, start, end) {
+ start || (start = 0);
+ if (typeof end == 'undefined') {
+ end = array ? array.length : 0;
+ }
+ var index = -1,
+ length = end - start || 0,
+ result = Array(length < 0 ? 0 : length);
+
+ while (++index < length) {
+ result[index] = array[start + index];
+ }
+ return result;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Create a new `lodash` function using the given context object.
+ *
+ * @static
+ * @memberOf _
+ * @category Utilities
+ * @param {Object} [context=root] The context object.
+ * @returns {Function} Returns the `lodash` function.
+ */
+ function runInContext(context) {
+ // Avoid issues with some ES3 environments that attempt to use values, named
+ // after built-in constructors like `Object`, for the creation of literals.
+ // ES5 clears this up by stating that literals must use built-in constructors.
+ // See http://es5.github.io/#x11.1.5.
+ context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root;
+
+ /** Native constructor references */
+ var Array = context.Array,
+ Boolean = context.Boolean,
+ Date = context.Date,
+ Function = context.Function,
+ Math = context.Math,
+ Number = context.Number,
+ Object = context.Object,
+ RegExp = context.RegExp,
+ String = context.String,
+ TypeError = context.TypeError;
+
+ /**
+ * Used for `Array` method references.
+ *
+ * Normally `Array.prototype` would suffice, however, using an array literal
+ * avoids issues in Narwhal.
+ */
+ var arrayRef = [];
+
+ /** Used for native method references */
+ var objectProto = Object.prototype;
+
+ /** Used to restore the original `_` reference in `noConflict` */
+ var oldDash = context._;
+
+ /** Used to resolve the internal [[Class]] of values */
+ var toString = objectProto.toString;
+
+ /** Used to detect if a method is native */
+ var reNative = RegExp('^' +
+ String(toString)
+ .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
+ .replace(/toString| for [^\]]+/g, '.*?') + '$'
+ );
+
+ /** Native method shortcuts */
+ var ceil = Math.ceil,
+ clearTimeout = context.clearTimeout,
+ floor = Math.floor,
+ fnToString = Function.prototype.toString,
+ getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
+ hasOwnProperty = objectProto.hasOwnProperty,
+ push = arrayRef.push,
+ setTimeout = context.setTimeout,
+ splice = arrayRef.splice,
+ unshift = arrayRef.unshift;
+
+ /** Used to set meta data on functions */
+ var defineProperty = (function() {
+ // IE 8 only accepts DOM elements
+ try {
+ var o = {},
+ func = isNative(func = Object.defineProperty) && func,
+ result = func(o, o, o) && func;
+ } catch(e) { }
+ return result;
+ }());
+
+ /* Native method shortcuts for methods with the same name as other `lodash` methods */
+ var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate,
+ nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray,
+ nativeIsFinite = context.isFinite,
+ nativeIsNaN = context.isNaN,
+ nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys,
+ nativeMax = Math.max,
+ nativeMin = Math.min,
+ nativeParseInt = context.parseInt,
+ nativeRandom = Math.random;
+
+ /** Used to lookup a built-in constructor by [[Class]] */
+ var ctorByClass = {};
+ ctorByClass[arrayClass] = Array;
+ ctorByClass[boolClass] = Boolean;
+ ctorByClass[dateClass] = Date;
+ ctorByClass[funcClass] = Function;
+ ctorByClass[objectClass] = Object;
+ ctorByClass[numberClass] = Number;
+ ctorByClass[regexpClass] = RegExp;
+ ctorByClass[stringClass] = String;
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Creates a `lodash` object which wraps the given value to enable intuitive
+ * method chaining.
+ *
+ * In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
+ * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
+ * and `unshift`
+ *
+ * Chaining is supported in custom builds as long as the `value` method is
+ * implicitly or explicitly included in the build.
+ *
+ * The chainable wrapper functions are:
+ * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`,
+ * `compose`, `concat`, `countBy`, `create`, `createCallback`, `curry`,
+ * `debounce`, `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`,
+ * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`,
+ * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`,
+ * `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`,
+ * `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `pull`, `push`,
+ * `range`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`,
+ * `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`, `transform`,
+ * `union`, `uniq`, `unshift`, `unzip`, `values`, `where`, `without`, `wrap`,
+ * and `zip`
+ *
+ * The non-chainable wrapper functions are:
+ * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `findIndex`,
+ * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `has`, `identity`,
+ * `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`,
+ * `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`,
+ * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`,
+ * `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, `pop`, `random`, `reduce`,
+ * `reduceRight`, `result`, `shift`, `size`, `some`, `sortedIndex`, `runInContext`,
+ * `template`, `unescape`, `uniqueId`, and `value`
+ *
+ * The wrapper functions `first` and `last` return wrapped values when `n` is
+ * provided, otherwise they return unwrapped values.
+ *
+ * Explicit chaining can be enabled by using the `_.chain` method.
+ *
+ * @name _
+ * @constructor
+ * @category Chaining
+ * @param {*} value The value to wrap in a `lodash` instance.
+ * @returns {Object} Returns a `lodash` instance.
+ * @example
+ *
+ * var wrapped = _([1, 2, 3]);
+ *
+ * // returns an unwrapped value
+ * wrapped.reduce(function(sum, num) {
+ * return sum + num;
+ * });
+ * // => 6
+ *
+ * // returns a wrapped value
+ * var squares = wrapped.map(function(num) {
+ * return num * num;
+ * });
+ *
+ * _.isArray(squares);
+ * // => false
+ *
+ * _.isArray(squares.value());
+ * // => true
+ */
+ function lodash(value) {
+ // don't wrap if already wrapped, even if wrapped by a different `lodash` constructor
+ return (value && typeof value == 'object' && !isArray(value) && hasOwnProperty.call(value, '__wrapped__'))
+ ? value
+ : new lodashWrapper(value);
+ }
+
+ /**
+ * A fast path for creating `lodash` wrapper objects.
+ *
+ * @private
+ * @param {*} value The value to wrap in a `lodash` instance.
+ * @param {boolean} chainAll A flag to enable chaining for all methods
+ * @returns {Object} Returns a `lodash` instance.
+ */
+ function lodashWrapper(value, chainAll) {
+ this.__chain__ = !!chainAll;
+ this.__wrapped__ = value;
+ }
+ // ensure `new lodashWrapper` is an instance of `lodash`
+ lodashWrapper.prototype = lodash.prototype;
+
+ /**
+ * An object used to flag environments features.
+ *
+ * @static
+ * @memberOf _
+ * @type Object
+ */
+ var support = lodash.support = {};
+
+ /**
+ * Detect if functions can be decompiled by `Function#toString`
+ * (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps).
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ support.funcDecomp = !isNative(context.WinRTError) && reThis.test(runInContext);
+
+ /**
+ * Detect if `Function#name` is supported (all but IE).
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ support.funcNames = typeof Function.name == 'string';
+
+ /**
+ * By default, the template delimiters used by Lo-Dash are similar to those in
+ * embedded Ruby (ERB). Change the following template settings to use alternative
+ * delimiters.
+ *
+ * @static
+ * @memberOf _
+ * @type Object
+ */
+ lodash.templateSettings = {
+
+ /**
+ * Used to detect `data` property values to be HTML-escaped.
+ *
+ * @memberOf _.templateSettings
+ * @type RegExp
+ */
+ 'escape': /<%-([\s\S]+?)%>/g,
+
+ /**
+ * Used to detect code to be evaluated.
+ *
+ * @memberOf _.templateSettings
+ * @type RegExp
+ */
+ 'evaluate': /<%([\s\S]+?)%>/g,
+
+ /**
+ * Used to detect `data` property values to inject.
+ *
+ * @memberOf _.templateSettings
+ * @type RegExp
+ */
+ 'interpolate': reInterpolate,
+
+ /**
+ * Used to reference the data object in the template text.
+ *
+ * @memberOf _.templateSettings
+ * @type string
+ */
+ 'variable': '',
+
+ /**
+ * Used to import variables into the compiled template.
+ *
+ * @memberOf _.templateSettings
+ * @type Object
+ */
+ 'imports': {
+
+ /**
+ * A reference to the `lodash` function.
+ *
+ * @memberOf _.templateSettings.imports
+ * @type Function
+ */
+ '_': lodash
+ }
+ };
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * The base implementation of `_.bind` that creates the bound function and
+ * sets its meta data.
+ *
+ * @private
+ * @param {Array} bindData The bind data array.
+ * @returns {Function} Returns the new bound function.
+ */
+ function baseBind(bindData) {
+ var func = bindData[0],
+ partialArgs = bindData[2],
+ thisArg = bindData[4];
+
+ function bound() {
+ // `Function#bind` spec
+ // http://es5.github.io/#x15.3.4.5
+ if (partialArgs) {
+ // avoid `arguments` object deoptimizations by using `slice` instead
+ // of `Array.prototype.slice.call` and not assigning `arguments` to a
+ // variable as a ternary expression
+ var args = slice(partialArgs);
+ push.apply(args, arguments);
+ }
+ // mimic the constructor's `return` behavior
+ // http://es5.github.io/#x13.2.2
+ if (this instanceof bound) {
+ // ensure `new bound` is an instance of `func`
+ var thisBinding = baseCreate(func.prototype),
+ result = func.apply(thisBinding, args || arguments);
+ return isObject(result) ? result : thisBinding;
+ }
+ return func.apply(thisArg, args || arguments);
+ }
+ setBindData(bound, bindData);
+ return bound;
+ }
+
+ /**
+ * The base implementation of `_.clone` without argument juggling or support
+ * for `thisArg` binding.
+ *
+ * @private
+ * @param {*} value The value to clone.
+ * @param {boolean} [isDeep=false] Specify a deep clone.
+ * @param {Function} [callback] The function to customize cloning values.
+ * @param {Array} [stackA=[]] Tracks traversed source objects.
+ * @param {Array} [stackB=[]] Associates clones with source counterparts.
+ * @returns {*} Returns the cloned value.
+ */
+ function baseClone(value, isDeep, callback, stackA, stackB) {
+ if (callback) {
+ var result = callback(value);
+ if (typeof result != 'undefined') {
+ return result;
+ }
+ }
+ // inspect [[Class]]
+ var isObj = isObject(value);
+ if (isObj) {
+ var className = toString.call(value);
+ if (!cloneableClasses[className]) {
+ return value;
+ }
+ var ctor = ctorByClass[className];
+ switch (className) {
+ case boolClass:
+ case dateClass:
+ return new ctor(+value);
+
+ case numberClass:
+ case stringClass:
+ return new ctor(value);
+
+ case regexpClass:
+ result = ctor(value.source, reFlags.exec(value));
+ result.lastIndex = value.lastIndex;
+ return result;
+ }
+ } else {
+ return value;
+ }
+ var isArr = isArray(value);
+ if (isDeep) {
+ // check for circular references and return corresponding clone
+ var initedStack = !stackA;
+ stackA || (stackA = getArray());
+ stackB || (stackB = getArray());
+
+ var length = stackA.length;
+ while (length--) {
+ if (stackA[length] == value) {
+ return stackB[length];
+ }
+ }
+ result = isArr ? ctor(value.length) : {};
+ }
+ else {
+ result = isArr ? slice(value) : assign({}, value);
+ }
+ // add array properties assigned by `RegExp#exec`
+ if (isArr) {
+ if (hasOwnProperty.call(value, 'index')) {
+ result.index = value.index;
+ }
+ if (hasOwnProperty.call(value, 'input')) {
+ result.input = value.input;
+ }
+ }
+ // exit for shallow clone
+ if (!isDeep) {
+ return result;
+ }
+ // add the source value to the stack of traversed objects
+ // and associate it with its clone
+ stackA.push(value);
+ stackB.push(result);
+
+ // recursively populate clone (susceptible to call stack limits)
+ (isArr ? forEach : forOwn)(value, function(objValue, key) {
+ result[key] = baseClone(objValue, isDeep, callback, stackA, stackB);
+ });
+
+ if (initedStack) {
+ releaseArray(stackA);
+ releaseArray(stackB);
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.create` without support for assigning
+ * properties to the created object.
+ *
+ * @private
+ * @param {Object} prototype The object to inherit from.
+ * @returns {Object} Returns the new object.
+ */
+ function baseCreate(prototype, properties) {
+ return isObject(prototype) ? nativeCreate(prototype) : {};
+ }
+ // fallback for browsers without `Object.create`
+ if (!nativeCreate) {
+ baseCreate = (function() {
+ function Object() {}
+ return function(prototype) {
+ if (isObject(prototype)) {
+ Object.prototype = prototype;
+ var result = new Object;
+ Object.prototype = null;
+ }
+ return result || context.Object();
+ };
+ }());
+ }
+
+ /**
+ * The base implementation of `_.createCallback` without support for creating
+ * "_.pluck" or "_.where" style callbacks.
+ *
+ * @private
+ * @param {*} [func=identity] The value to convert to a callback.
+ * @param {*} [thisArg] The `this` binding of the created callback.
+ * @param {number} [argCount] The number of arguments the callback accepts.
+ * @returns {Function} Returns a callback function.
+ */
+ function baseCreateCallback(func, thisArg, argCount) {
+ if (typeof func != 'function') {
+ return identity;
+ }
+ // exit early for no `thisArg` or already bound by `Function#bind`
+ if (typeof thisArg == 'undefined' || !('prototype' in func)) {
+ return func;
+ }
+ var bindData = func.__bindData__;
+ if (typeof bindData == 'undefined') {
+ if (support.funcNames) {
+ bindData = !func.name;
+ }
+ bindData = bindData || !support.funcDecomp;
+ if (!bindData) {
+ var source = fnToString.call(func);
+ if (!support.funcNames) {
+ bindData = !reFuncName.test(source);
+ }
+ if (!bindData) {
+ // checks if `func` references the `this` keyword and stores the result
+ bindData = reThis.test(source);
+ setBindData(func, bindData);
+ }
+ }
+ }
+ // exit early if there are no `this` references or `func` is bound
+ if (bindData === false || (bindData !== true && bindData[1] & 1)) {
+ return func;
+ }
+ switch (argCount) {
+ case 1: return function(value) {
+ return func.call(thisArg, value);
+ };
+ case 2: return function(a, b) {
+ return func.call(thisArg, a, b);
+ };
+ case 3: return function(value, index, collection) {
+ return func.call(thisArg, value, index, collection);
+ };
+ case 4: return function(accumulator, value, index, collection) {
+ return func.call(thisArg, accumulator, value, index, collection);
+ };
+ }
+ return bind(func, thisArg);
+ }
+
+ /**
+ * The base implementation of `createWrapper` that creates the wrapper and
+ * sets its meta data.
+ *
+ * @private
+ * @param {Array} bindData The bind data array.
+ * @returns {Function} Returns the new function.
+ */
+ function baseCreateWrapper(bindData) {
+ var func = bindData[0],
+ bitmask = bindData[1],
+ partialArgs = bindData[2],
+ partialRightArgs = bindData[3],
+ thisArg = bindData[4],
+ arity = bindData[5];
+
+ var isBind = bitmask & 1,
+ isBindKey = bitmask & 2,
+ isCurry = bitmask & 4,
+ isCurryBound = bitmask & 8,
+ key = func;
+
+ function bound() {
+ var thisBinding = isBind ? thisArg : this;
+ if (partialArgs) {
+ var args = slice(partialArgs);
+ push.apply(args, arguments);
+ }
+ if (partialRightArgs || isCurry) {
+ args || (args = slice(arguments));
+ if (partialRightArgs) {
+ push.apply(args, partialRightArgs);
+ }
+ if (isCurry && args.length < arity) {
+ bitmask |= 16 & ~32;
+ return baseCreateWrapper([func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity]);
+ }
+ }
+ args || (args = arguments);
+ if (isBindKey) {
+ func = thisBinding[key];
+ }
+ if (this instanceof bound) {
+ thisBinding = baseCreate(func.prototype);
+ var result = func.apply(thisBinding, args);
+ return isObject(result) ? result : thisBinding;
+ }
+ return func.apply(thisBinding, args);
+ }
+ setBindData(bound, bindData);
+ return bound;
+ }
+
+ /**
+ * The base implementation of `_.difference` that accepts a single array
+ * of values to exclude.
+ *
+ * @private
+ * @param {Array} array The array to process.
+ * @param {Array} [values] The array of values to exclude.
+ * @returns {Array} Returns a new array of filtered values.
+ */
+ function baseDifference(array, values) {
+ var index = -1,
+ indexOf = getIndexOf(),
+ length = array ? array.length : 0,
+ isLarge = length >= largeArraySize && indexOf === baseIndexOf,
+ result = [];
+
+ if (isLarge) {
+ var cache = createCache(values);
+ if (cache) {
+ indexOf = cacheIndexOf;
+ values = cache;
+ } else {
+ isLarge = false;
+ }
+ }
+ while (++index < length) {
+ var value = array[index];
+ if (indexOf(values, value) < 0) {
+ result.push(value);
+ }
+ }
+ if (isLarge) {
+ releaseObject(values);
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.flatten` without support for callback
+ * shorthands or `thisArg` binding.
+ *
+ * @private
+ * @param {Array} array The array to flatten.
+ * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
+ * @param {boolean} [isStrict=false] A flag to restrict flattening to arrays and `arguments` objects.
+ * @param {number} [fromIndex=0] The index to start from.
+ * @returns {Array} Returns a new flattened array.
+ */
+ function baseFlatten(array, isShallow, isStrict, fromIndex) {
+ var index = (fromIndex || 0) - 1,
+ length = array ? array.length : 0,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index];
+
+ if (value && typeof value == 'object' && typeof value.length == 'number'
+ && (isArray(value) || isArguments(value))) {
+ // recursively flatten arrays (susceptible to call stack limits)
+ if (!isShallow) {
+ value = baseFlatten(value, isShallow, isStrict);
+ }
+ var valIndex = -1,
+ valLength = value.length,
+ resIndex = result.length;
+
+ result.length += valLength;
+ while (++valIndex < valLength) {
+ result[resIndex++] = value[valIndex];
+ }
+ } else if (!isStrict) {
+ result.push(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.isEqual`, without support for `thisArg` binding,
+ * that allows partial "_.where" style comparisons.
+ *
+ * @private
+ * @param {*} a The value to compare.
+ * @param {*} b The other value to compare.
+ * @param {Function} [callback] The function to customize comparing values.
+ * @param {Function} [isWhere=false] A flag to indicate performing partial comparisons.
+ * @param {Array} [stackA=[]] Tracks traversed `a` objects.
+ * @param {Array} [stackB=[]] Tracks traversed `b` objects.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ */
+ function baseIsEqual(a, b, callback, isWhere, stackA, stackB) {
+ // used to indicate that when comparing objects, `a` has at least the properties of `b`
+ if (callback) {
+ var result = callback(a, b);
+ if (typeof result != 'undefined') {
+ return !!result;
+ }
+ }
+ // exit early for identical values
+ if (a === b) {
+ // treat `+0` vs. `-0` as not equal
+ return a !== 0 || (1 / a == 1 / b);
+ }
+ var type = typeof a,
+ otherType = typeof b;
+
+ // exit early for unlike primitive values
+ if (a === a &&
+ !(a && objectTypes[type]) &&
+ !(b && objectTypes[otherType])) {
+ return false;
+ }
+ // exit early for `null` and `undefined` avoiding ES3's Function#call behavior
+ // http://es5.github.io/#x15.3.4.4
+ if (a == null || b == null) {
+ return a === b;
+ }
+ // compare [[Class]] names
+ var className = toString.call(a),
+ otherClass = toString.call(b);
+
+ if (className == argsClass) {
+ className = objectClass;
+ }
+ if (otherClass == argsClass) {
+ otherClass = objectClass;
+ }
+ if (className != otherClass) {
+ return false;
+ }
+ switch (className) {
+ case boolClass:
+ case dateClass:
+ // coerce dates and booleans to numbers, dates to milliseconds and booleans
+ // to `1` or `0` treating invalid dates coerced to `NaN` as not equal
+ return +a == +b;
+
+ case numberClass:
+ // treat `NaN` vs. `NaN` as equal
+ return (a != +a)
+ ? b != +b
+ // but treat `+0` vs. `-0` as not equal
+ : (a == 0 ? (1 / a == 1 / b) : a == +b);
+
+ case regexpClass:
+ case stringClass:
+ // coerce regexes to strings (http://es5.github.io/#x15.10.6.4)
+ // treat string primitives and their corresponding object instances as equal
+ return a == String(b);
+ }
+ var isArr = className == arrayClass;
+ if (!isArr) {
+ // unwrap any `lodash` wrapped values
+ var aWrapped = hasOwnProperty.call(a, '__wrapped__'),
+ bWrapped = hasOwnProperty.call(b, '__wrapped__');
+
+ if (aWrapped || bWrapped) {
+ return baseIsEqual(aWrapped ? a.__wrapped__ : a, bWrapped ? b.__wrapped__ : b, callback, isWhere, stackA, stackB);
+ }
+ // exit for functions and DOM nodes
+ if (className != objectClass) {
+ return false;
+ }
+ // in older versions of Opera, `arguments` objects have `Array` constructors
+ var ctorA = a.constructor,
+ ctorB = b.constructor;
+
+ // non `Object` object instances with different constructors are not equal
+ if (ctorA != ctorB &&
+ !(isFunction(ctorA) && ctorA instanceof ctorA && isFunction(ctorB) && ctorB instanceof ctorB) &&
+ ('constructor' in a && 'constructor' in b)
+ ) {
+ return false;
+ }
+ }
+ // assume cyclic structures are equal
+ // the algorithm for detecting cyclic structures is adapted from ES 5.1
+ // section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3)
+ var initedStack = !stackA;
+ stackA || (stackA = getArray());
+ stackB || (stackB = getArray());
+
+ var length = stackA.length;
+ while (length--) {
+ if (stackA[length] == a) {
+ return stackB[length] == b;
+ }
+ }
+ var size = 0;
+ result = true;
+
+ // add `a` and `b` to the stack of traversed objects
+ stackA.push(a);
+ stackB.push(b);
+
+ // recursively compare objects and arrays (susceptible to call stack limits)
+ if (isArr) {
+ // compare lengths to determine if a deep comparison is necessary
+ length = a.length;
+ size = b.length;
+ result = size == length;
+
+ if (result || isWhere) {
+ // deep compare the contents, ignoring non-numeric properties
+ while (size--) {
+ var index = length,
+ value = b[size];
+
+ if (isWhere) {
+ while (index--) {
+ if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) {
+ break;
+ }
+ }
+ } else if (!(result = baseIsEqual(a[size], value, callback, isWhere, stackA, stackB))) {
+ break;
+ }
+ }
+ }
+ }
+ else {
+ // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys`
+ // which, in this case, is more costly
+ forIn(b, function(value, key, b) {
+ if (hasOwnProperty.call(b, key)) {
+ // count the number of properties.
+ size++;
+ // deep compare each property value.
+ return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB));
+ }
+ });
+
+ if (result && !isWhere) {
+ // ensure both objects have the same number of properties
+ forIn(a, function(value, key, a) {
+ if (hasOwnProperty.call(a, key)) {
+ // `size` will be `-1` if `a` has more properties than `b`
+ return (result = --size > -1);
+ }
+ });
+ }
+ }
+ stackA.pop();
+ stackB.pop();
+
+ if (initedStack) {
+ releaseArray(stackA);
+ releaseArray(stackB);
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.merge` without argument juggling or support
+ * for `thisArg` binding.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {Function} [callback] The function to customize merging properties.
+ * @param {Array} [stackA=[]] Tracks traversed source objects.
+ * @param {Array} [stackB=[]] Associates values with source counterparts.
+ */
+ function baseMerge(object, source, callback, stackA, stackB) {
+ (isArray(source) ? forEach : forOwn)(source, function(source, key) {
+ var found,
+ isArr,
+ result = source,
+ value = object[key];
+
+ if (source && ((isArr = isArray(source)) || isPlainObject(source))) {
+ // avoid merging previously merged cyclic sources
+ var stackLength = stackA.length;
+ while (stackLength--) {
+ if ((found = stackA[stackLength] == source)) {
+ value = stackB[stackLength];
+ break;
+ }
+ }
+ if (!found) {
+ var isShallow;
+ if (callback) {
+ result = callback(value, source);
+ if ((isShallow = typeof result != 'undefined')) {
+ value = result;
+ }
+ }
+ if (!isShallow) {
+ value = isArr
+ ? (isArray(value) ? value : [])
+ : (isPlainObject(value) ? value : {});
+ }
+ // add `source` and associated `value` to the stack of traversed objects
+ stackA.push(source);
+ stackB.push(value);
+
+ // recursively merge objects and arrays (susceptible to call stack limits)
+ if (!isShallow) {
+ baseMerge(value, source, callback, stackA, stackB);
+ }
+ }
+ }
+ else {
+ if (callback) {
+ result = callback(value, source);
+ if (typeof result == 'undefined') {
+ result = source;
+ }
+ }
+ if (typeof result != 'undefined') {
+ value = result;
+ }
+ }
+ object[key] = value;
+ });
+ }
+
+ /**
+ * The base implementation of `_.random` without argument juggling or support
+ * for returning floating-point numbers.
+ *
+ * @private
+ * @param {number} min The minimum possible value.
+ * @param {number} max The maximum possible value.
+ * @returns {number} Returns a random number.
+ */
+ function baseRandom(min, max) {
+ return min + floor(nativeRandom() * (max - min + 1));
+ }
+
+ /**
+ * The base implementation of `_.uniq` without support for callback shorthands
+ * or `thisArg` binding.
+ *
+ * @private
+ * @param {Array} array The array to process.
+ * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
+ * @param {Function} [callback] The function called per iteration.
+ * @returns {Array} Returns a duplicate-value-free array.
+ */
+ function baseUniq(array, isSorted, callback) {
+ var index = -1,
+ indexOf = getIndexOf(),
+ length = array ? array.length : 0,
+ result = [];
+
+ var isLarge = !isSorted && length >= largeArraySize && indexOf === baseIndexOf,
+ seen = (callback || isLarge) ? getArray() : result;
+
+ if (isLarge) {
+ var cache = createCache(seen);
+ indexOf = cacheIndexOf;
+ seen = cache;
+ }
+ while (++index < length) {
+ var value = array[index],
+ computed = callback ? callback(value, index, array) : value;
+
+ if (isSorted
+ ? !index || seen[seen.length - 1] !== computed
+ : indexOf(seen, computed) < 0
+ ) {
+ if (callback || isLarge) {
+ seen.push(computed);
+ }
+ result.push(value);
+ }
+ }
+ if (isLarge) {
+ releaseArray(seen.array);
+ releaseObject(seen);
+ } else if (callback) {
+ releaseArray(seen);
+ }
+ return result;
+ }
+
+ /**
+ * Creates a function that aggregates a collection, creating an object composed
+ * of keys generated from the results of running each element of the collection
+ * through a callback. The given `setter` function sets the keys and values
+ * of the composed object.
+ *
+ * @private
+ * @param {Function} setter The setter function.
+ * @returns {Function} Returns the new aggregator function.
+ */
+ function createAggregator(setter) {
+ return function(collection, callback, thisArg) {
+ var result = {};
+ callback = lodash.createCallback(callback, thisArg, 3);
+
+ var index = -1,
+ length = collection ? collection.length : 0;
+
+ if (typeof length == 'number') {
+ while (++index < length) {
+ var value = collection[index];
+ setter(result, value, callback(value, index, collection), collection);
+ }
+ } else {
+ forOwn(collection, function(value, key, collection) {
+ setter(result, value, callback(value, key, collection), collection);
+ });
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that, when called, either curries or invokes `func`
+ * with an optional `this` binding and partially applied arguments.
+ *
+ * @private
+ * @param {Function|string} func The function or method name to reference.
+ * @param {number} bitmask The bitmask of method flags to compose.
+ * The bitmask may be composed of the following flags:
+ * 1 - `_.bind`
+ * 2 - `_.bindKey`
+ * 4 - `_.curry`
+ * 8 - `_.curry` (bound)
+ * 16 - `_.partial`
+ * 32 - `_.partialRight`
+ * @param {Array} [partialArgs] An array of arguments to prepend to those
+ * provided to the new function.
+ * @param {Array} [partialRightArgs] An array of arguments to append to those
+ * provided to the new function.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {number} [arity] The arity of `func`.
+ * @returns {Function} Returns the new function.
+ */
+ function createWrapper(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) {
+ var isBind = bitmask & 1,
+ isBindKey = bitmask & 2,
+ isCurry = bitmask & 4,
+ isCurryBound = bitmask & 8,
+ isPartial = bitmask & 16,
+ isPartialRight = bitmask & 32;
+
+ if (!isBindKey && !isFunction(func)) {
+ throw new TypeError;
+ }
+ if (isPartial && !partialArgs.length) {
+ bitmask &= ~16;
+ isPartial = partialArgs = false;
+ }
+ if (isPartialRight && !partialRightArgs.length) {
+ bitmask &= ~32;
+ isPartialRight = partialRightArgs = false;
+ }
+ var bindData = func && func.__bindData__;
+ if (bindData && bindData !== true) {
+ // clone `bindData`
+ bindData = slice(bindData);
+ if (bindData[2]) {
+ bindData[2] = slice(bindData[2]);
+ }
+ if (bindData[3]) {
+ bindData[3] = slice(bindData[3]);
+ }
+ // set `thisBinding` is not previously bound
+ if (isBind && !(bindData[1] & 1)) {
+ bindData[4] = thisArg;
+ }
+ // set if previously bound but not currently (subsequent curried functions)
+ if (!isBind && bindData[1] & 1) {
+ bitmask |= 8;
+ }
+ // set curried arity if not yet set
+ if (isCurry && !(bindData[1] & 4)) {
+ bindData[5] = arity;
+ }
+ // append partial left arguments
+ if (isPartial) {
+ push.apply(bindData[2] || (bindData[2] = []), partialArgs);
+ }
+ // append partial right arguments
+ if (isPartialRight) {
+ unshift.apply(bindData[3] || (bindData[3] = []), partialRightArgs);
+ }
+ // merge flags
+ bindData[1] |= bitmask;
+ return createWrapper.apply(null, bindData);
+ }
+ // fast path for `_.bind`
+ var creater = (bitmask == 1 || bitmask === 17) ? baseBind : baseCreateWrapper;
+ return creater([func, bitmask, partialArgs, partialRightArgs, thisArg, arity]);
+ }
+
+ /**
+ * Used by `escape` to convert characters to HTML entities.
+ *
+ * @private
+ * @param {string} match The matched character to escape.
+ * @returns {string} Returns the escaped character.
+ */
+ function escapeHtmlChar(match) {
+ return htmlEscapes[match];
+ }
+
+ /**
+ * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
+ * customized, this method returns the custom method, otherwise it returns
+ * the `baseIndexOf` function.
+ *
+ * @private
+ * @returns {Function} Returns the "indexOf" function.
+ */
+ function getIndexOf() {
+ var result = (result = lodash.indexOf) === indexOf ? baseIndexOf : result;
+ return result;
+ }
+
+ /**
+ * Checks if `value` is a native function.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if the `value` is a native function, else `false`.
+ */
+ function isNative(value) {
+ return typeof value == 'function' && reNative.test(value);
+ }
+
+ /**
+ * Sets `this` binding data on a given function.
+ *
+ * @private
+ * @param {Function} func The function to set data on.
+ * @param {Array} value The data array to set.
+ */
+ var setBindData = !defineProperty ? noop : function(func, value) {
+ descriptor.value = value;
+ defineProperty(func, '__bindData__', descriptor);
+ };
+
+ /**
+ * A fallback implementation of `isPlainObject` which checks if a given value
+ * is an object created by the `Object` constructor, assuming objects created
+ * by the `Object` constructor have no inherited enumerable properties and that
+ * there are no `Object.prototype` extensions.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
+ */
+ function shimIsPlainObject(value) {
+ var ctor,
+ result;
+
+ // avoid non Object objects, `arguments` objects, and DOM elements
+ if (!(value && toString.call(value) == objectClass) ||
+ (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor))) {
+ return false;
+ }
+ // In most environments an object's own properties are iterated before
+ // its inherited properties. If the last iterated property is an object's
+ // own property then there are no inherited enumerable properties.
+ forIn(value, function(value, key) {
+ result = key;
+ });
+ return typeof result == 'undefined' || hasOwnProperty.call(value, result);
+ }
+
+ /**
+ * Used by `unescape` to convert HTML entities to characters.
+ *
+ * @private
+ * @param {string} match The matched character to unescape.
+ * @returns {string} Returns the unescaped character.
+ */
+ function unescapeHtmlChar(match) {
+ return htmlUnescapes[match];
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Checks if `value` is an `arguments` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if the `value` is an `arguments` object, else `false`.
+ * @example
+ *
+ * (function() { return _.isArguments(arguments); })(1, 2, 3);
+ * // => true
+ *
+ * _.isArguments([1, 2, 3]);
+ * // => false
+ */
+ function isArguments(value) {
+ return value && typeof value == 'object' && typeof value.length == 'number' &&
+ toString.call(value) == argsClass || false;
+ }
+
+ /**
+ * Checks if `value` is an array.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Objects
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if the `value` is an array, else `false`.
+ * @example
+ *
+ * (function() { return _.isArray(arguments); })();
+ * // => false
+ *
+ * _.isArray([1, 2, 3]);
+ * // => true
+ */
+ var isArray = nativeIsArray || function(value) {
+ return value && typeof value == 'object' && typeof value.length == 'number' &&
+ toString.call(value) == arrayClass || false;
+ };
+
+ /**
+ * A fallback implementation of `Object.keys` which produces an array of the
+ * given object's own enumerable property names.
+ *
+ * @private
+ * @type Function
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns an array of property names.
+ */
+ var shimKeys = function(object) {
+ var index, iterable = object, result = [];
+ if (!iterable) return result;
+ if (!(objectTypes[typeof object])) return result;
+ for (index in iterable) {
+ if (hasOwnProperty.call(iterable, index)) {
+ result.push(index);
+ }
+ }
+ return result
+ };
+
+ /**
+ * Creates an array composed of the own enumerable property names of an object.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns an array of property names.
+ * @example
+ *
+ * _.keys({ 'one': 1, 'two': 2, 'three': 3 });
+ * // => ['one', 'two', 'three'] (property order is not guaranteed across environments)
+ */
+ var keys = !nativeKeys ? shimKeys : function(object) {
+ if (!isObject(object)) {
+ return [];
+ }
+ return nativeKeys(object);
+ };
+
+ /**
+ * Used to convert characters to HTML entities:
+ *
+ * Though the `>` character is escaped for symmetry, characters like `>` and `/`
+ * don't require escaping in HTML and have no special meaning unless they're part
+ * of a tag or an unquoted attribute value.
+ * http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact")
+ */
+ var htmlEscapes = {
+ '&': '&amp;',
+ '<': '&lt;',
+ '>': '&gt;',
+ '"': '&quot;',
+ "'": '&#39;'
+ };
+
+ /** Used to convert HTML entities to characters */
+ var htmlUnescapes = invert(htmlEscapes);
+
+ /** Used to match HTML entities and HTML characters */
+ var reEscapedHtml = RegExp('(' + keys(htmlUnescapes).join('|') + ')', 'g'),
+ reUnescapedHtml = RegExp('[' + keys(htmlEscapes).join('') + ']', 'g');
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Assigns own enumerable properties of source object(s) to the destination
+ * object. Subsequent sources will overwrite property assignments of previous
+ * sources. If a callback is provided it will be executed to produce the
+ * assigned values. The callback is bound to `thisArg` and invoked with two
+ * arguments; (objectValue, sourceValue).
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @alias extend
+ * @category Objects
+ * @param {Object} object The destination object.
+ * @param {...Object} [source] The source objects.
+ * @param {Function} [callback] The function to customize assigning values.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Object} Returns the destination object.
+ * @example
+ *
+ * _.assign({ 'name': 'fred' }, { 'employer': 'slate' });
+ * // => { 'name': 'fred', 'employer': 'slate' }
+ *
+ * var defaults = _.partialRight(_.assign, function(a, b) {
+ * return typeof a == 'undefined' ? b : a;
+ * });
+ *
+ * var object = { 'name': 'barney' };
+ * defaults(object, { 'name': 'fred', 'employer': 'slate' });
+ * // => { 'name': 'barney', 'employer': 'slate' }
+ */
+ var assign = function(object, source, guard) {
+ var index, iterable = object, result = iterable;
+ if (!iterable) return result;
+ var args = arguments,
+ argsIndex = 0,
+ argsLength = typeof guard == 'number' ? 2 : args.length;
+ if (argsLength > 3 && typeof args[argsLength - 2] == 'function') {
+ var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2);
+ } else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {
+ callback = args[--argsLength];
+ }
+ while (++argsIndex < argsLength) {
+ iterable = args[argsIndex];
+ if (iterable && objectTypes[typeof iterable]) {
+ var ownIndex = -1,
+ ownProps = objectTypes[typeof iterable] && keys(iterable),
+ length = ownProps ? ownProps.length : 0;
+
+ while (++ownIndex < length) {
+ index = ownProps[ownIndex];
+ result[index] = callback ? callback(result[index], iterable[index]) : iterable[index];
+ }
+ }
+ }
+ return result
+ };
+
+ /**
+ * Creates a clone of `value`. If `isDeep` is `true` nested objects will also
+ * be cloned, otherwise they will be assigned by reference. If a callback
+ * is provided it will be executed to produce the cloned values. If the
+ * callback returns `undefined` cloning will be handled by the method instead.
+ * The callback is bound to `thisArg` and invoked with one argument; (value).
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {*} value The value to clone.
+ * @param {boolean} [isDeep=false] Specify a deep clone.
+ * @param {Function} [callback] The function to customize cloning values.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {*} Returns the cloned value.
+ * @example
+ *
+ * var characters = [
+ * { 'name': 'barney', 'age': 36 },
+ * { 'name': 'fred', 'age': 40 }
+ * ];
+ *
+ * var shallow = _.clone(characters);
+ * shallow[0] === characters[0];
+ * // => true
+ *
+ * var deep = _.clone(characters, true);
+ * deep[0] === characters[0];
+ * // => false
+ *
+ * _.mixin({
+ * 'clone': _.partialRight(_.clone, function(value) {
+ * return _.isElement(value) ? value.cloneNode(false) : undefined;
+ * })
+ * });
+ *
+ * var clone = _.clone(document.body);
+ * clone.childNodes.length;
+ * // => 0
+ */
+ function clone(value, isDeep, callback, thisArg) {
+ // allows working with "Collections" methods without using their `index`
+ // and `collection` arguments for `isDeep` and `callback`
+ if (typeof isDeep != 'boolean' && isDeep != null) {
+ thisArg = callback;
+ callback = isDeep;
+ isDeep = false;
+ }
+ return baseClone(value, isDeep, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
+ }
+
+ /**
+ * Creates a deep clone of `value`. If a callback is provided it will be
+ * executed to produce the cloned values. If the callback returns `undefined`
+ * cloning will be handled by the method instead. The callback is bound to
+ * `thisArg` and invoked with one argument; (value).
+ *
+ * Note: This method is loosely based on the structured clone algorithm. Functions
+ * and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and
+ * objects created by constructors other than `Object` are cloned to plain `Object` objects.
+ * See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {*} value The value to deep clone.
+ * @param {Function} [callback] The function to customize cloning values.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {*} Returns the deep cloned value.
+ * @example
+ *
+ * var characters = [
+ * { 'name': 'barney', 'age': 36 },
+ * { 'name': 'fred', 'age': 40 }
+ * ];
+ *
+ * var deep = _.cloneDeep(characters);
+ * deep[0] === characters[0];
+ * // => false
+ *
+ * var view = {
+ * 'label': 'docs',
+ * 'node': element
+ * };
+ *
+ * var clone = _.cloneDeep(view, function(value) {
+ * return _.isElement(value) ? value.cloneNode(true) : undefined;
+ * });
+ *
+ * clone.node == view.node;
+ * // => false
+ */
+ function cloneDeep(value, callback, thisArg) {
+ return baseClone(value, true, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
+ }
+
+ /**
+ * Creates an object that inherits from the given `prototype` object. If a
+ * `properties` object is provided its own enumerable properties are assigned
+ * to the created object.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Object} prototype The object to inherit from.
+ * @param {Object} [properties] The properties to assign to the object.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * function Shape() {
+ * this.x = 0;
+ * this.y = 0;
+ * }
+ *
+ * function Circle() {
+ * Shape.call(this);
+ * }
+ *
+ * Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle });
+ *
+ * var circle = new Circle;
+ * circle instanceof Circle;
+ * // => true
+ *
+ * circle instanceof Shape;
+ * // => true
+ */
+ function create(prototype, properties) {
+ var result = baseCreate(prototype);
+ return properties ? assign(result, properties) : result;
+ }
+
+ /**
+ * Assigns own enumerable properties of source object(s) to the destination
+ * object for all destination properties that resolve to `undefined`. Once a
+ * property is set, additional defaults of the same property will be ignored.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Objects
+ * @param {Object} object The destination object.
+ * @param {...Object} [source] The source objects.
+ * @param- {Object} [guard] Allows working with `_.reduce` without using its
+ * `key` and `object` arguments as sources.
+ * @returns {Object} Returns the destination object.
+ * @example
+ *
+ * var object = { 'name': 'barney' };
+ * _.defaults(object, { 'name': 'fred', 'employer': 'slate' });
+ * // => { 'name': 'barney', 'employer': 'slate' }
+ */
+ var defaults = function(object, source, guard) {
+ var index, iterable = object, result = iterable;
+ if (!iterable) return result;
+ var args = arguments,
+ argsIndex = 0,
+ argsLength = typeof guard == 'number' ? 2 : args.length;
+ while (++argsIndex < argsLength) {
+ iterable = args[argsIndex];
+ if (iterable && objectTypes[typeof iterable]) {
+ var ownIndex = -1,
+ ownProps = objectTypes[typeof iterable] && keys(iterable),
+ length = ownProps ? ownProps.length : 0;
+
+ while (++ownIndex < length) {
+ index = ownProps[ownIndex];
+ if (typeof result[index] == 'undefined') result[index] = iterable[index];
+ }
+ }
+ }
+ return result
+ };
+
+ /**
+ * This method is like `_.findIndex` except that it returns the key of the
+ * first element that passes the callback check, instead of the element itself.
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Object} object The object to search.
+ * @param {Function|Object|string} [callback=identity] The function called per
+ * iteration. If a property name or object is provided it will be used to
+ * create a "_.pluck" or "_.where" style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {string|undefined} Returns the key of the found element, else `undefined`.
+ * @example
+ *
+ * var characters = {
+ * 'barney': { 'age': 36, 'blocked': false },
+ * 'fred': { 'age': 40, 'blocked': true },
+ * 'pebbles': { 'age': 1, 'blocked': false }
+ * };
+ *
+ * _.findKey(characters, function(chr) {
+ * return chr.age < 40;
+ * });
+ * // => 'barney' (property order is not guaranteed across environments)
+ *
+ * // using "_.where" callback shorthand
+ * _.findKey(characters, { 'age': 1 });
+ * // => 'pebbles'
+ *
+ * // using "_.pluck" callback shorthand
+ * _.findKey(characters, 'blocked');
+ * // => 'fred'
+ */
+ function findKey(object, callback, thisArg) {
+ var result;
+ callback = lodash.createCallback(callback, thisArg, 3);
+ forOwn(object, function(value, key, object) {
+ if (callback(value, key, object)) {
+ result = key;
+ return false;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * This method is like `_.findKey` except that it iterates over elements
+ * of a `collection` in the opposite order.
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Object} object The object to search.
+ * @param {Function|Object|string} [callback=identity] The function called per
+ * iteration. If a property name or object is provided it will be used to
+ * create a "_.pluck" or "_.where" style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {string|undefined} Returns the key of the found element, else `undefined`.
+ * @example
+ *
+ * var characters = {
+ * 'barney': { 'age': 36, 'blocked': true },
+ * 'fred': { 'age': 40, 'blocked': false },
+ * 'pebbles': { 'age': 1, 'blocked': true }
+ * };
+ *
+ * _.findLastKey(characters, function(chr) {
+ * return chr.age < 40;
+ * });
+ * // => returns `pebbles`, assuming `_.findKey` returns `barney`
+ *
+ * // using "_.where" callback shorthand
+ * _.findLastKey(characters, { 'age': 40 });
+ * // => 'fred'
+ *
+ * // using "_.pluck" callback shorthand
+ * _.findLastKey(characters, 'blocked');
+ * // => 'pebbles'
+ */
+ function findLastKey(object, callback, thisArg) {
+ var result;
+ callback = lodash.createCallback(callback, thisArg, 3);
+ forOwnRight(object, function(value, key, object) {
+ if (callback(value, key, object)) {
+ result = key;
+ return false;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * Iterates over own and inherited enumerable properties of an object,
+ * executing the callback for each property. The callback is bound to `thisArg`
+ * and invoked with three arguments; (value, key, object). Callbacks may exit
+ * iteration early by explicitly returning `false`.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Objects
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [callback=identity] The function called per iteration.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * function Shape() {
+ * this.x = 0;
+ * this.y = 0;
+ * }
+ *
+ * Shape.prototype.move = function(x, y) {
+ * this.x += x;
+ * this.y += y;
+ * };
+ *
+ * _.forIn(new Shape, function(value, key) {
+ * console.log(key);
+ * });
+ * // => logs 'x', 'y', and 'move' (property order is not guaranteed across environments)
+ */
+ var forIn = function(collection, callback, thisArg) {
+ var index, iterable = collection, result = iterable;
+ if (!iterable) return result;
+ if (!objectTypes[typeof iterable]) return result;
+ callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
+ for (index in iterable) {
+ if (callback(iterable[index], index, collection) === false) return result;
+ }
+ return result
+ };
+
+ /**
+ * This method is like `_.forIn` except that it iterates over elements
+ * of a `collection` in the opposite order.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [callback=identity] The function called per iteration.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * function Shape() {
+ * this.x = 0;
+ * this.y = 0;
+ * }
+ *
+ * Shape.prototype.move = function(x, y) {
+ * this.x += x;
+ * this.y += y;
+ * };
+ *
+ * _.forInRight(new Shape, function(value, key) {
+ * console.log(key);
+ * });
+ * // => logs 'move', 'y', and 'x' assuming `_.forIn ` logs 'x', 'y', and 'move'
+ */
+ function forInRight(object, callback, thisArg) {
+ var pairs = [];
+
+ forIn(object, function(value, key) {
+ pairs.push(key, value);
+ });
+
+ var length = pairs.length;
+ callback = baseCreateCallback(callback, thisArg, 3);
+ while (length--) {
+ if (callback(pairs[length--], pairs[length], object) === false) {
+ break;
+ }
+ }
+ return object;
+ }
+
+ /**
+ * Iterates over own enumerable properties of an object, executing the callback
+ * for each property. The callback is bound to `thisArg` and invoked with three
+ * arguments; (value, key, object). Callbacks may exit iteration early by
+ * explicitly returning `false`.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Objects
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [callback=identity] The function called per iteration.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
+ * console.log(key);
+ * });
+ * // => logs '0', '1', and 'length' (property order is not guaranteed across environments)
+ */
+ var forOwn = function(collection, callback, thisArg) {
+ var index, iterable = collection, result = iterable;
+ if (!iterable) return result;
+ if (!objectTypes[typeof iterable]) return result;
+ callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
+ var ownIndex = -1,
+ ownProps = objectTypes[typeof iterable] && keys(iterable),
+ length = ownProps ? ownProps.length : 0;
+
+ while (++ownIndex < length) {
+ index = ownProps[ownIndex];
+ if (callback(iterable[index], index, collection) === false) return result;
+ }
+ return result
+ };
+
+ /**
+ * This method is like `_.forOwn` except that it iterates over elements
+ * of a `collection` in the opposite order.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [callback=identity] The function called per iteration.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
+ * console.log(key);
+ * });
+ * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length'
+ */
+ function forOwnRight(object, callback, thisArg) {
+ var props = keys(object),
+ length = props.length;
+
+ callback = baseCreateCallback(callback, thisArg, 3);
+ while (length--) {
+ var key = props[length];
+ if (callback(object[key], key, object) === false) {
+ break;
+ }
+ }
+ return object;
+ }
+
+ /**
+ * Creates a sorted array of property names of all enumerable properties,
+ * own and inherited, of `object` that have function values.
+ *
+ * @static
+ * @memberOf _
+ * @alias methods
+ * @category Objects
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns an array of property names that have function values.
+ * @example
+ *
+ * _.functions(_);
+ * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
+ */
+ function functions(object) {
+ var result = [];
+ forIn(object, function(value, key) {
+ if (isFunction(value)) {
+ result.push(key);
+ }
+ });
+ return result.sort();
+ }
+
+ /**
+ * Checks if the specified property name exists as a direct property of `object`,
+ * instead of an inherited property.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Object} object The object to inspect.
+ * @param {string} key The name of the property to check.
+ * @returns {boolean} Returns `true` if key is a direct property, else `false`.
+ * @example
+ *
+ * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
+ * // => true
+ */
+ function has(object, key) {
+ return object ? hasOwnProperty.call(object, key) : false;
+ }
+
+ /**
+ * Creates an object composed of the inverted keys and values of the given object.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Object} object The object to invert.
+ * @returns {Object} Returns the created inverted object.
+ * @example
+ *
+ * _.invert({ 'first': 'fred', 'second': 'barney' });
+ * // => { 'fred': 'first', 'barney': 'second' }
+ */
+ function invert(object) {
+ var index = -1,
+ props = keys(object),
+ length = props.length,
+ result = {};
+
+ while (++index < length) {
+ var key = props[index];
+ result[object[key]] = key;
+ }
+ return result;
+ }
+
+ /**
+ * Checks if `value` is a boolean value.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if the `value` is a boolean value, else `false`.
+ * @example
+ *
+ * _.isBoolean(null);
+ * // => false
+ */
+ function isBoolean(value) {
+ return value === true || value === false ||
+ value && typeof value == 'object' && toString.call(value) == boolClass || false;
+ }
+
+ /**
+ * Checks if `value` is a date.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if the `value` is a date, else `false`.
+ * @example
+ *
+ * _.isDate(new Date);
+ * // => true
+ */
+ function isDate(value) {
+ return value && typeof value == 'object' && toString.call(value) == dateClass || false;
+ }
+
+ /**
+ * Checks if `value` is a DOM element.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if the `value` is a DOM element, else `false`.
+ * @example
+ *
+ * _.isElement(document.body);
+ * // => true
+ */
+ function isElement(value) {
+ return value && value.nodeType === 1 || false;
+ }
+
+ /**
+ * Checks if `value` is empty. Arrays, strings, or `arguments` objects with a
+ * length of `0` and objects with no own enumerable properties are considered
+ * "empty".
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Array|Object|string} value The value to inspect.
+ * @returns {boolean} Returns `true` if the `value` is empty, else `false`.
+ * @example
+ *
+ * _.isEmpty([1, 2, 3]);
+ * // => false
+ *
+ * _.isEmpty({});
+ * // => true
+ *
+ * _.isEmpty('');
+ * // => true
+ */
+ function isEmpty(value) {
+ var result = true;
+ if (!value) {
+ return result;
+ }
+ var className = toString.call(value),
+ length = value.length;
+
+ if ((className == arrayClass || className == stringClass || className == argsClass ) ||
+ (className == objectClass && typeof length == 'number' && isFunction(value.splice))) {
+ return !length;
+ }
+ forOwn(value, function() {
+ return (result = false);
+ });
+ return result;
+ }
+
+ /**
+ * Performs a deep comparison between two values to determine if they are
+ * equivalent to each other. If a callback is provided it will be executed
+ * to compare values. If the callback returns `undefined` comparisons will
+ * be handled by the method instead. The callback is bound to `thisArg` and
+ * invoked with two arguments; (a, b).
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {*} a The value to compare.
+ * @param {*} b The other value to compare.
+ * @param {Function} [callback] The function to customize comparing values.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ * @example
+ *
+ * var object = { 'name': 'fred' };
+ * var copy = { 'name': 'fred' };
+ *
+ * object == copy;
+ * // => false
+ *
+ * _.isEqual(object, copy);
+ * // => true
+ *
+ * var words = ['hello', 'goodbye'];
+ * var otherWords = ['hi', 'goodbye'];
+ *
+ * _.isEqual(words, otherWords, function(a, b) {
+ * var reGreet = /^(?:hello|hi)$/i,
+ * aGreet = _.isString(a) && reGreet.test(a),
+ * bGreet = _.isString(b) && reGreet.test(b);
+ *
+ * return (aGreet || bGreet) ? (aGreet == bGreet) : undefined;
+ * });
+ * // => true
+ */
+ function isEqual(a, b, callback, thisArg) {
+ return baseIsEqual(a, b, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 2));
+ }
+
+ /**
+ * Checks if `value` is, or can be coerced to, a finite number.
+ *
+ * Note: This is not the same as native `isFinite` which will return true for
+ * booleans and empty strings. See http://es5.github.io/#x15.1.2.5.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if the `value` is finite, else `false`.
+ * @example
+ *
+ * _.isFinite(-101);
+ * // => true
+ *
+ * _.isFinite('10');
+ * // => true
+ *
+ * _.isFinite(true);
+ * // => false
+ *
+ * _.isFinite('');
+ * // => false
+ *
+ * _.isFinite(Infinity);
+ * // => false
+ */
+ function isFinite(value) {
+ return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value));
+ }
+
+ /**
+ * Checks if `value` is a function.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if the `value` is a function, else `false`.
+ * @example
+ *
+ * _.isFunction(_);
+ * // => true
+ */
+ function isFunction(value) {
+ return typeof value == 'function';
+ }
+
+ /**
+ * Checks if `value` is the language type of Object.
+ * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if the `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(1);
+ * // => false
+ */
+ function isObject(value) {
+ // check if the value is the ECMAScript language type of Object
+ // http://es5.github.io/#x8
+ // and avoid a V8 bug
+ // http://code.google.com/p/v8/issues/detail?id=2291
+ return !!(value && objectTypes[typeof value]);
+ }
+
+ /**
+ * Checks if `value` is `NaN`.
+ *
+ * Note: This is not the same as native `isNaN` which will return `true` for
+ * `undefined` and other non-numeric values. See http://es5.github.io/#x15.1.2.4.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if the `value` is `NaN`, else `false`.
+ * @example
+ *
+ * _.isNaN(NaN);
+ * // => true
+ *
+ * _.isNaN(new Number(NaN));
+ * // => true
+ *
+ * isNaN(undefined);
+ * // => true
+ *
+ * _.isNaN(undefined);
+ * // => false
+ */
+ function isNaN(value) {
+ // `NaN` as a primitive is the only value that is not equal to itself
+ // (perform the [[Class]] check first to avoid errors with some host objects in IE)
+ return isNumber(value) && value != +value;
+ }
+
+ /**
+ * Checks if `value` is `null`.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if the `value` is `null`, else `false`.
+ * @example
+ *
+ * _.isNull(null);
+ * // => true
+ *
+ * _.isNull(undefined);
+ * // => false
+ */
+ function isNull(value) {
+ return value === null;
+ }
+
+ /**
+ * Checks if `value` is a number.
+ *
+ * Note: `NaN` is considered a number. See http://es5.github.io/#x8.5.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if the `value` is a number, else `false`.
+ * @example
+ *
+ * _.isNumber(8.4 * 5);
+ * // => true
+ */
+ function isNumber(value) {
+ return typeof value == 'number' ||
+ value && typeof value == 'object' && toString.call(value) == numberClass || false;
+ }
+
+ /**
+ * Checks if `value` is an object created by the `Object` constructor.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
+ * @example
+ *
+ * function Shape() {
+ * this.x = 0;
+ * this.y = 0;
+ * }
+ *
+ * _.isPlainObject(new Shape);
+ * // => false
+ *
+ * _.isPlainObject([1, 2, 3]);
+ * // => false
+ *
+ * _.isPlainObject({ 'x': 0, 'y': 0 });
+ * // => true
+ */
+ var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) {
+ if (!(value && toString.call(value) == objectClass)) {
+ return false;
+ }
+ var valueOf = value.valueOf,
+ objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
+
+ return objProto
+ ? (value == objProto || getPrototypeOf(value) == objProto)
+ : shimIsPlainObject(value);
+ };
+
+ /**
+ * Checks if `value` is a regular expression.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if the `value` is a regular expression, else `false`.
+ * @example
+ *
+ * _.isRegExp(/fred/);
+ * // => true
+ */
+ function isRegExp(value) {
+ return value && typeof value == 'object' && toString.call(value) == regexpClass || false;
+ }
+
+ /**
+ * Checks if `value` is a string.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if the `value` is a string, else `false`.
+ * @example
+ *
+ * _.isString('fred');
+ * // => true
+ */
+ function isString(value) {
+ return typeof value == 'string' ||
+ value && typeof value == 'object' && toString.call(value) == stringClass || false;
+ }
+
+ /**
+ * Checks if `value` is `undefined`.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if the `value` is `undefined`, else `false`.
+ * @example
+ *
+ * _.isUndefined(void 0);
+ * // => true
+ */
+ function isUndefined(value) {
+ return typeof value == 'undefined';
+ }
+
+ /**
+ * Creates an object with the same keys as `object` and values generated by
+ * running each own enumerable property of `object` through the callback.
+ * The callback is bound to `thisArg` and invoked with three arguments;
+ * (value, key, object).
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Object} object The object to iterate over.
+ * @param {Function|Object|string} [callback=identity] The function called
+ * per iteration. If a property name or object is provided it will be used
+ * to create a "_.pluck" or "_.where" style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Array} Returns a new object with values of the results of each `callback` execution.
+ * @example
+ *
+ * _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; });
+ * // => { 'a': 3, 'b': 6, 'c': 9 }
+ *
+ * var characters = {
+ * 'fred': { 'name': 'fred', 'age': 40 },
+ * 'pebbles': { 'name': 'pebbles', 'age': 1 }
+ * };
+ *
+ * // using "_.pluck" callback shorthand
+ * _.mapValues(characters, 'age');
+ * // => { 'fred': 40, 'pebbles': 1 }
+ */
+ function mapValues(object, callback, thisArg) {
+ var result = {};
+ callback = lodash.createCallback(callback, thisArg, 3);
+
+ forOwn(object, function(value, key, object) {
+ result[key] = callback(value, key, object);
+ });
+ return result;
+ }
+
+ /**
+ * Recursively merges own enumerable properties of the source object(s), that
+ * don't resolve to `undefined` into the destination object. Subsequent sources
+ * will overwrite property assignments of previous sources. If a callback is
+ * provided it will be executed to produce the merged values of the destination
+ * and source properties. If the callback returns `undefined` merging will
+ * be handled by the method instead. The callback is bound to `thisArg` and
+ * invoked with two arguments; (objectValue, sourceValue).
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Object} object The destination object.
+ * @param {...Object} [source] The source objects.
+ * @param {Function} [callback] The function to customize merging properties.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Object} Returns the destination object.
+ * @example
+ *
+ * var names = {
+ * 'characters': [
+ * { 'name': 'barney' },
+ * { 'name': 'fred' }
+ * ]
+ * };
+ *
+ * var ages = {
+ * 'characters': [
+ * { 'age': 36 },
+ * { 'age': 40 }
+ * ]
+ * };
+ *
+ * _.merge(names, ages);
+ * // => { 'characters': [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] }
+ *
+ * var food = {
+ * 'fruits': ['apple'],
+ * 'vegetables': ['beet']
+ * };
+ *
+ * var otherFood = {
+ * 'fruits': ['banana'],
+ * 'vegetables': ['carrot']
+ * };
+ *
+ * _.merge(food, otherFood, function(a, b) {
+ * return _.isArray(a) ? a.concat(b) : undefined;
+ * });
+ * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] }
+ */
+ function merge(object) {
+ var args = arguments,
+ length = 2;
+
+ if (!isObject(object)) {
+ return object;
+ }
+ // allows working with `_.reduce` and `_.reduceRight` without using
+ // their `index` and `collection` arguments
+ if (typeof args[2] != 'number') {
+ length = args.length;
+ }
+ if (length > 3 && typeof args[length - 2] == 'function') {
+ var callback = baseCreateCallback(args[--length - 1], args[length--], 2);
+ } else if (length > 2 && typeof args[length - 1] == 'function') {
+ callback = args[--length];
+ }
+ var sources = slice(arguments, 1, length),
+ index = -1,
+ stackA = getArray(),
+ stackB = getArray();
+
+ while (++index < length) {
+ baseMerge(object, sources[index], callback, stackA, stackB);
+ }
+ releaseArray(stackA);
+ releaseArray(stackB);
+ return object;
+ }
+
+ /**
+ * Creates a shallow clone of `object` excluding the specified properties.
+ * Property names may be specified as individual arguments or as arrays of
+ * property names. If a callback is provided it will be executed for each
+ * property of `object` omitting the properties the callback returns truey
+ * for. The callback is bound to `thisArg` and invoked with three arguments;
+ * (value, key, object).
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Object} object The source object.
+ * @param {Function|...string|string[]} [callback] The properties to omit or the
+ * function called per iteration.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Object} Returns an object without the omitted properties.
+ * @example
+ *
+ * _.omit({ 'name': 'fred', 'age': 40 }, 'age');
+ * // => { 'name': 'fred' }
+ *
+ * _.omit({ 'name': 'fred', 'age': 40 }, function(value) {
+ * return typeof value == 'number';
+ * });
+ * // => { 'name': 'fred' }
+ */
+ function omit(object, callback, thisArg) {
+ var result = {};
+ if (typeof callback != 'function') {
+ var props = [];
+ forIn(object, function(value, key) {
+ props.push(key);
+ });
+ props = baseDifference(props, baseFlatten(arguments, true, false, 1));
+
+ var index = -1,
+ length = props.length;
+
+ while (++index < length) {
+ var key = props[index];
+ result[key] = object[key];
+ }
+ } else {
+ callback = lodash.createCallback(callback, thisArg, 3);
+ forIn(object, function(value, key, object) {
+ if (!callback(value, key, object)) {
+ result[key] = value;
+ }
+ });
+ }
+ return result;
+ }
+
+ /**
+ * Creates a two dimensional array of an object's key-value pairs,
+ * i.e. `[[key1, value1], [key2, value2]]`.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns new array of key-value pairs.
+ * @example
+ *
+ * _.pairs({ 'barney': 36, 'fred': 40 });
+ * // => [['barney', 36], ['fred', 40]] (property order is not guaranteed across environments)
+ */
+ function pairs(object) {
+ var index = -1,
+ props = keys(object),
+ length = props.length,
+ result = Array(length);
+
+ while (++index < length) {
+ var key = props[index];
+ result[index] = [key, object[key]];
+ }
+ return result;
+ }
+
+ /**
+ * Creates a shallow clone of `object` composed of the specified properties.
+ * Property names may be specified as individual arguments or as arrays of
+ * property names. If a callback is provided it will be executed for each
+ * property of `object` picking the properties the callback returns truey
+ * for. The callback is bound to `thisArg` and invoked with three arguments;
+ * (value, key, object).
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Object} object The source object.
+ * @param {Function|...string|string[]} [callback] The function called per
+ * iteration or property names to pick, specified as individual property
+ * names or arrays of property names.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Object} Returns an object composed of the picked properties.
+ * @example
+ *
+ * _.pick({ 'name': 'fred', '_userid': 'fred1' }, 'name');
+ * // => { 'name': 'fred' }
+ *
+ * _.pick({ 'name': 'fred', '_userid': 'fred1' }, function(value, key) {
+ * return key.charAt(0) != '_';
+ * });
+ * // => { 'name': 'fred' }
+ */
+ function pick(object, callback, thisArg) {
+ var result = {};
+ if (typeof callback != 'function') {
+ var index = -1,
+ props = baseFlatten(arguments, true, false, 1),
+ length = isObject(object) ? props.length : 0;
+
+ while (++index < length) {
+ var key = props[index];
+ if (key in object) {
+ result[key] = object[key];
+ }
+ }
+ } else {
+ callback = lodash.createCallback(callback, thisArg, 3);
+ forIn(object, function(value, key, object) {
+ if (callback(value, key, object)) {
+ result[key] = value;
+ }
+ });
+ }
+ return result;
+ }
+
+ /**
+ * An alternative to `_.reduce` this method transforms `object` to a new
+ * `accumulator` object which is the result of running each of its own
+ * enumerable properties through a callback, with each callback execution
+ * potentially mutating the `accumulator` object. The callback is bound to
+ * `thisArg` and invoked with four arguments; (accumulator, value, key, object).
+ * Callbacks may exit iteration early by explicitly returning `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Array|Object} object The object to iterate over.
+ * @param {Function} [callback=identity] The function called per iteration.
+ * @param {*} [accumulator] The custom accumulator value.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {*} Returns the accumulated value.
+ * @example
+ *
+ * var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) {
+ * num *= num;
+ * if (num % 2) {
+ * return result.push(num) < 3;
+ * }
+ * });
+ * // => [1, 9, 25]
+ *
+ * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
+ * result[key] = num * 3;
+ * });
+ * // => { 'a': 3, 'b': 6, 'c': 9 }
+ */
+ function transform(object, callback, accumulator, thisArg) {
+ var isArr = isArray(object);
+ if (accumulator == null) {
+ if (isArr) {
+ accumulator = [];
+ } else {
+ var ctor = object && object.constructor,
+ proto = ctor && ctor.prototype;
+
+ accumulator = baseCreate(proto);
+ }
+ }
+ if (callback) {
+ callback = lodash.createCallback(callback, thisArg, 4);
+ (isArr ? forEach : forOwn)(object, function(value, index, object) {
+ return callback(accumulator, value, index, object);
+ });
+ }
+ return accumulator;
+ }
+
+ /**
+ * Creates an array composed of the own enumerable property values of `object`.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns an array of property values.
+ * @example
+ *
+ * _.values({ 'one': 1, 'two': 2, 'three': 3 });
+ * // => [1, 2, 3] (property order is not guaranteed across environments)
+ */
+ function values(object) {
+ var index = -1,
+ props = keys(object),
+ length = props.length,
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = object[props[index]];
+ }
+ return result;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Creates an array of elements from the specified indexes, or keys, of the
+ * `collection`. Indexes may be specified as individual arguments or as arrays
+ * of indexes.
+ *
+ * @static
+ * @memberOf _
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {...(number|number[]|string|string[])} [index] The indexes of `collection`
+ * to retrieve, specified as individual indexes or arrays of indexes.
+ * @returns {Array} Returns a new array of elements corresponding to the
+ * provided indexes.
+ * @example
+ *
+ * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
+ * // => ['a', 'c', 'e']
+ *
+ * _.at(['fred', 'barney', 'pebbles'], 0, 2);
+ * // => ['fred', 'pebbles']
+ */
+ function at(collection) {
+ var args = arguments,
+ index = -1,
+ props = baseFlatten(args, true, false, 1),
+ length = (args[2] && args[2][args[1]] === collection) ? 1 : props.length,
+ result = Array(length);
+
+ while(++index < length) {
+ result[index] = collection[props[index]];
+ }
+ return result;
+ }
+
+ /**
+ * Checks if a given value is present in a collection using strict equality
+ * for comparisons, i.e. `===`. If `fromIndex` is negative, it is used as the
+ * offset from the end of the collection.
+ *
+ * @static
+ * @memberOf _
+ * @alias include
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {*} target The value to check for.
+ * @param {number} [fromIndex=0] The index to search from.
+ * @returns {boolean} Returns `true` if the `target` element is found, else `false`.
+ * @example
+ *
+ * _.contains([1, 2, 3], 1);
+ * // => true
+ *
+ * _.contains([1, 2, 3], 1, 2);
+ * // => false
+ *
+ * _.contains({ 'name': 'fred', 'age': 40 }, 'fred');
+ * // => true
+ *
+ * _.contains('pebbles', 'eb');
+ * // => true
+ */
+ function contains(collection, target, fromIndex) {
+ var index = -1,
+ indexOf = getIndexOf(),
+ length = collection ? collection.length : 0,
+ result = false;
+
+ fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0;
+ if (isArray(collection)) {
+ result = indexOf(collection, target, fromIndex) > -1;
+ } else if (typeof length == 'number') {
+ result = (isString(collection) ? collection.indexOf(target, fromIndex) : indexOf(collection, target, fromIndex)) > -1;
+ } else {
+ forOwn(collection, function(value) {
+ if (++index >= fromIndex) {
+ return !(result = value === target);
+ }
+ });
+ }
+ return result;
+ }
+
+ /**
+ * Creates an object composed of keys generated from the results of running
+ * each element of `collection` through the callback. The corresponding value
+ * of each key is the number of times the key was returned by the callback.
+ * The callback is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [callback=identity] The function called
+ * per iteration. If a property name or object is provided it will be used
+ * to create a "_.pluck" or "_.where" style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Object} Returns the composed aggregate object.
+ * @example
+ *
+ * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); });
+ * // => { '4': 1, '6': 2 }
+ *
+ * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
+ * // => { '4': 1, '6': 2 }
+ *
+ * _.countBy(['one', 'two', 'three'], 'length');
+ * // => { '3': 2, '5': 1 }
+ */
+ var countBy = createAggregator(function(result, value, key) {
+ (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1);
+ });
+
+ /**
+ * Checks if the given callback returns truey value for **all** elements of
+ * a collection. The callback is bound to `thisArg` and invoked with three
+ * arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias all
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [callback=identity] The function called
+ * per iteration. If a property name or object is provided it will be used
+ * to create a "_.pluck" or "_.where" style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {boolean} Returns `true` if all elements passed the callback check,
+ * else `false`.
+ * @example
+ *
+ * _.every([true, 1, null, 'yes']);
+ * // => false
+ *
+ * var characters = [
+ * { 'name': 'barney', 'age': 36 },
+ * { 'name': 'fred', 'age': 40 }
+ * ];
+ *
+ * // using "_.pluck" callback shorthand
+ * _.every(characters, 'age');
+ * // => true
+ *
+ * // using "_.where" callback shorthand
+ * _.every(characters, { 'age': 36 });
+ * // => false
+ */
+ function every(collection, callback, thisArg) {
+ var result = true;
+ callback = lodash.createCallback(callback, thisArg, 3);
+
+ var index = -1,
+ length = collection ? collection.length : 0;
+
+ if (typeof length == 'number') {
+ while (++index < length) {
+ if (!(result = !!callback(collection[index], index, collection))) {
+ break;
+ }
+ }
+ } else {
+ forOwn(collection, function(value, index, collection) {
+ return (result = !!callback(value, index, collection));
+ });
+ }
+ return result;
+ }
+
+ /**
+ * Iterates over elements of a collection, returning an array of all elements
+ * the callback returns truey for. The callback is bound to `thisArg` and
+ * invoked with three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias select
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [callback=identity] The function called
+ * per iteration. If a property name or object is provided it will be used
+ * to create a "_.pluck" or "_.where" style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Array} Returns a new array of elements that passed the callback check.
+ * @example
+ *
+ * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
+ * // => [2, 4, 6]
+ *
+ * var characters = [
+ * { 'name': 'barney', 'age': 36, 'blocked': false },
+ * { 'name': 'fred', 'age': 40, 'blocked': true }
+ * ];
+ *
+ * // using "_.pluck" callback shorthand
+ * _.filter(characters, 'blocked');
+ * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
+ *
+ * // using "_.where" callback shorthand
+ * _.filter(characters, { 'age': 36 });
+ * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
+ */
+ function filter(collection, callback, thisArg) {
+ var result = [];
+ callback = lodash.createCallback(callback, thisArg, 3);
+
+ var index = -1,
+ length = collection ? collection.length : 0;
+
+ if (typeof length == 'number') {
+ while (++index < length) {
+ var value = collection[index];
+ if (callback(value, index, collection)) {
+ result.push(value);
+ }
+ }
+ } else {
+ forOwn(collection, function(value, index, collection) {
+ if (callback(value, index, collection)) {
+ result.push(value);
+ }
+ });
+ }
+ return result;
+ }
+
+ /**
+ * Iterates over elements of a collection, returning the first element that
+ * the callback returns truey for. The callback is bound to `thisArg` and
+ * invoked with three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias detect, findWhere
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [callback=identity] The function called
+ * per iteration. If a property name or object is provided it will be used
+ * to create a "_.pluck" or "_.where" style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {*} Returns the found element, else `undefined`.
+ * @example
+ *
+ * var characters = [
+ * { 'name': 'barney', 'age': 36, 'blocked': false },
+ * { 'name': 'fred', 'age': 40, 'blocked': true },
+ * { 'name': 'pebbles', 'age': 1, 'blocked': false }
+ * ];
+ *
+ * _.find(characters, function(chr) {
+ * return chr.age < 40;
+ * });
+ * // => { 'name': 'barney', 'age': 36, 'blocked': false }
+ *
+ * // using "_.where" callback shorthand
+ * _.find(characters, { 'age': 1 });
+ * // => { 'name': 'pebbles', 'age': 1, 'blocked': false }
+ *
+ * // using "_.pluck" callback shorthand
+ * _.find(characters, 'blocked');
+ * // => { 'name': 'fred', 'age': 40, 'blocked': true }
+ */
+ function find(collection, callback, thisArg) {
+ callback = lodash.createCallback(callback, thisArg, 3);
+
+ var index = -1,
+ length = collection ? collection.length : 0;
+
+ if (typeof length == 'number') {
+ while (++index < length) {
+ var value = collection[index];
+ if (callback(value, index, collection)) {
+ return value;
+ }
+ }
+ } else {
+ var result;
+ forOwn(collection, function(value, index, collection) {
+ if (callback(value, index, collection)) {
+ result = value;
+ return false;
+ }
+ });
+ return result;
+ }
+ }
+
+ /**
+ * This method is like `_.find` except that it iterates over elements
+ * of a `collection` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [callback=identity] The function called
+ * per iteration. If a property name or object is provided it will be used
+ * to create a "_.pluck" or "_.where" style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {*} Returns the found element, else `undefined`.
+ * @example
+ *
+ * _.findLast([1, 2, 3, 4], function(num) {
+ * return num % 2 == 1;
+ * });
+ * // => 3
+ */
+ function findLast(collection, callback, thisArg) {
+ var result;
+ callback = lodash.createCallback(callback, thisArg, 3);
+ forEachRight(collection, function(value, index, collection) {
+ if (callback(value, index, collection)) {
+ result = value;
+ return false;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * Iterates over elements of a collection, executing the callback for each
+ * element. The callback is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection). Callbacks may exit iteration early by
+ * explicitly returning `false`.
+ *
+ * Note: As with other "Collections" methods, objects with a `length` property
+ * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
+ * may be used for object iteration.
+ *
+ * @static
+ * @memberOf _
+ * @alias each
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [callback=identity] The function called per iteration.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Array|Object|string} Returns `collection`.
+ * @example
+ *
+ * _([1, 2, 3]).forEach(function(num) { console.log(num); }).join(',');
+ * // => logs each number and returns '1,2,3'
+ *
+ * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { console.log(num); });
+ * // => logs each number and returns the object (property order is not guaranteed across environments)
+ */
+ function forEach(collection, callback, thisArg) {
+ var index = -1,
+ length = collection ? collection.length : 0;
+
+ callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
+ if (typeof length == 'number') {
+ while (++index < length) {
+ if (callback(collection[index], index, collection) === false) {
+ break;
+ }
+ }
+ } else {
+ forOwn(collection, callback);
+ }
+ return collection;
+ }
+
+ /**
+ * This method is like `_.forEach` except that it iterates over elements
+ * of a `collection` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @alias eachRight
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [callback=identity] The function called per iteration.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Array|Object|string} Returns `collection`.
+ * @example
+ *
+ * _([1, 2, 3]).forEachRight(function(num) { console.log(num); }).join(',');
+ * // => logs each number from right to left and returns '3,2,1'
+ */
+ function forEachRight(collection, callback, thisArg) {
+ var length = collection ? collection.length : 0;
+ callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
+ if (typeof length == 'number') {
+ while (length--) {
+ if (callback(collection[length], length, collection) === false) {
+ break;
+ }
+ }
+ } else {
+ var props = keys(collection);
+ length = props.length;
+ forOwn(collection, function(value, key, collection) {
+ key = props ? props[--length] : --length;
+ return callback(collection[key], key, collection);
+ });
+ }
+ return collection;
+ }
+
+ /**
+ * Creates an object composed of keys generated from the results of running
+ * each element of a collection through the callback. The corresponding value
+ * of each key is an array of the elements responsible for generating the key.
+ * The callback is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`
+ *
+ * @static
+ * @memberOf _
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [callback=identity] The function called
+ * per iteration. If a property name or object is provided it will be used
+ * to create a "_.pluck" or "_.where" style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Object} Returns the composed aggregate object.
+ * @example
+ *
+ * _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); });
+ * // => { '4': [4.2], '6': [6.1, 6.4] }
+ *
+ * _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
+ * // => { '4': [4.2], '6': [6.1, 6.4] }
+ *
+ * // using "_.pluck" callback shorthand
+ * _.groupBy(['one', 'two', 'three'], 'length');
+ * // => { '3': ['one', 'two'], '5': ['three'] }
+ */
+ var groupBy = createAggregator(function(result, value, key) {
+ (hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value);
+ });
+
+ /**
+ * Creates an object composed of keys generated from the results of running
+ * each element of the collection through the given callback. The corresponding
+ * value of each key is the last element responsible for generating the key.
+ * The callback is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [callback=identity] The function called
+ * per iteration. If a property name or object is provided it will be used
+ * to create a "_.pluck" or "_.where" style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Object} Returns the composed aggregate object.
+ * @example
+ *
+ * var keys = [
+ * { 'dir': 'left', 'code': 97 },
+ * { 'dir': 'right', 'code': 100 }
+ * ];
+ *
+ * _.indexBy(keys, 'dir');
+ * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
+ *
+ * _.indexBy(keys, function(key) { return String.fromCharCode(key.code); });
+ * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
+ *
+ * _.indexBy(characters, function(key) { this.fromCharCode(key.code); }, String);
+ * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
+ */
+ var indexBy = createAggregator(function(result, value, key) {
+ result[key] = value;
+ });
+
+ /**
+ * Invokes the method named by `methodName` on each element in the `collection`
+ * returning an array of the results of each invoked method. Additional arguments
+ * will be provided to each invoked method. If `methodName` is a function it
+ * will be invoked for, and `this` bound to, each element in the `collection`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|string} methodName The name of the method to invoke or
+ * the function invoked per iteration.
+ * @param {...*} [arg] Arguments to invoke the method with.
+ * @returns {Array} Returns a new array of the results of each invoked method.
+ * @example
+ *
+ * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
+ * // => [[1, 5, 7], [1, 2, 3]]
+ *
+ * _.invoke([123, 456], String.prototype.split, '');
+ * // => [['1', '2', '3'], ['4', '5', '6']]
+ */
+ function invoke(collection, methodName) {
+ var args = slice(arguments, 2),
+ index = -1,
+ isFunc = typeof methodName == 'function',
+ length = collection ? collection.length : 0,
+ result = Array(typeof length == 'number' ? length : 0);
+
+ forEach(collection, function(value) {
+ result[++index] = (isFunc ? methodName : value[methodName]).apply(value, args);
+ });
+ return result;
+ }
+
+ /**
+ * Creates an array of values by running each element in the collection
+ * through the callback. The callback is bound to `thisArg` and invoked with
+ * three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias collect
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [callback=identity] The function called
+ * per iteration. If a property name or object is provided it will be used
+ * to create a "_.pluck" or "_.where" style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Array} Returns a new array of the results of each `callback` execution.
+ * @example
+ *
+ * _.map([1, 2, 3], function(num) { return num * 3; });
+ * // => [3, 6, 9]
+ *
+ * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
+ * // => [3, 6, 9] (property order is not guaranteed across environments)
+ *
+ * var characters = [
+ * { 'name': 'barney', 'age': 36 },
+ * { 'name': 'fred', 'age': 40 }
+ * ];
+ *
+ * // using "_.pluck" callback shorthand
+ * _.map(characters, 'name');
+ * // => ['barney', 'fred']
+ */
+ function map(collection, callback, thisArg) {
+ var index = -1,
+ length = collection ? collection.length : 0;
+
+ callback = lodash.createCallback(callback, thisArg, 3);
+ if (typeof length == 'number') {
+ var result = Array(length);
+ while (++index < length) {
+ result[index] = callback(collection[index], index, collection);
+ }
+ } else {
+ result = [];
+ forOwn(collection, function(value, key, collection) {
+ result[++index] = callback(value, key, collection);
+ });
+ }
+ return result;
+ }
+
+ /**
+ * Retrieves the maximum value of a collection. If the collection is empty or
+ * falsey `-Infinity` is returned. If a callback is provided it will be executed
+ * for each value in the collection to generate the criterion by which the value
+ * is ranked. The callback is bound to `thisArg` and invoked with three
+ * arguments; (value, index, collection).
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [callback=identity] The function called
+ * per iteration. If a property name or object is provided it will be used
+ * to create a "_.pluck" or "_.where" style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {*} Returns the maximum value.
+ * @example
+ *
+ * _.max([4, 2, 8, 6]);
+ * // => 8
+ *
+ * var characters = [
+ * { 'name': 'barney', 'age': 36 },
+ * { 'name': 'fred', 'age': 40 }
+ * ];
+ *
+ * _.max(characters, function(chr) { return chr.age; });
+ * // => { 'name': 'fred', 'age': 40 };
+ *
+ * // using "_.pluck" callback shorthand
+ * _.max(characters, 'age');
+ * // => { 'name': 'fred', 'age': 40 };
+ */
+ function max(collection, callback, thisArg) {
+ var computed = -Infinity,
+ result = computed;
+
+ // allows working with functions like `_.map` without using
+ // their `index` argument as a callback
+ if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) {
+ callback = null;
+ }
+ if (callback == null && isArray(collection)) {
+ var index = -1,
+ length = collection.length;
+
+ while (++index < length) {
+ var value = collection[index];
+ if (value > result) {
+ result = value;
+ }
+ }
+ } else {
+ callback = (callback == null && isString(collection))
+ ? charAtCallback
+ : lodash.createCallback(callback, thisArg, 3);
+
+ forEach(collection, function(value, index, collection) {
+ var current = callback(value, index, collection);
+ if (current > computed) {
+ computed = current;
+ result = value;
+ }
+ });
+ }
+ return result;
+ }
+
+ /**
+ * Retrieves the minimum value of a collection. If the collection is empty or
+ * falsey `Infinity` is returned. If a callback is provided it will be executed
+ * for each value in the collection to generate the criterion by which the value
+ * is ranked. The callback is bound to `thisArg` and invoked with three
+ * arguments; (value, index, collection).
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [callback=identity] The function called
+ * per iteration. If a property name or object is provided it will be used
+ * to create a "_.pluck" or "_.where" style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {*} Returns the minimum value.
+ * @example
+ *
+ * _.min([4, 2, 8, 6]);
+ * // => 2
+ *
+ * var characters = [
+ * { 'name': 'barney', 'age': 36 },
+ * { 'name': 'fred', 'age': 40 }
+ * ];
+ *
+ * _.min(characters, function(chr) { return chr.age; });
+ * // => { 'name': 'barney', 'age': 36 };
+ *
+ * // using "_.pluck" callback shorthand
+ * _.min(characters, 'age');
+ * // => { 'name': 'barney', 'age': 36 };
+ */
+ function min(collection, callback, thisArg) {
+ var computed = Infinity,
+ result = computed;
+
+ // allows working with functions like `_.map` without using
+ // their `index` argument as a callback
+ if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) {
+ callback = null;
+ }
+ if (callback == null && isArray(collection)) {
+ var index = -1,
+ length = collection.length;
+
+ while (++index < length) {
+ var value = collection[index];
+ if (value < result) {
+ result = value;
+ }
+ }
+ } else {
+ callback = (callback == null && isString(collection))
+ ? charAtCallback
+ : lodash.createCallback(callback, thisArg, 3);
+
+ forEach(collection, function(value, index, collection) {
+ var current = callback(value, index, collection);
+ if (current < computed) {
+ computed = current;
+ result = value;
+ }
+ });
+ }
+ return result;
+ }
+
+ /**
+ * Retrieves the value of a specified property from all elements in the collection.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {string} property The name of the property to pluck.
+ * @returns {Array} Returns a new array of property values.
+ * @example
+ *
+ * var characters = [
+ * { 'name': 'barney', 'age': 36 },
+ * { 'name': 'fred', 'age': 40 }
+ * ];
+ *
+ * _.pluck(characters, 'name');
+ * // => ['barney', 'fred']
+ */
+ var pluck = map;
+
+ /**
+ * Reduces a collection to a value which is the accumulated result of running
+ * each element in the collection through the callback, where each successive
+ * callback execution consumes the return value of the previous execution. If
+ * `accumulator` is not provided the first element of the collection will be
+ * used as the initial `accumulator` value. The callback is bound to `thisArg`
+ * and invoked with four arguments; (accumulator, value, index|key, collection).
+ *
+ * @static
+ * @memberOf _
+ * @alias foldl, inject
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [callback=identity] The function called per iteration.
+ * @param {*} [accumulator] Initial value of the accumulator.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {*} Returns the accumulated value.
+ * @example
+ *
+ * var sum = _.reduce([1, 2, 3], function(sum, num) {
+ * return sum + num;
+ * });
+ * // => 6
+ *
+ * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
+ * result[key] = num * 3;
+ * return result;
+ * }, {});
+ * // => { 'a': 3, 'b': 6, 'c': 9 }
+ */
+ function reduce(collection, callback, accumulator, thisArg) {
+ if (!collection) return accumulator;
+ var noaccum = arguments.length < 3;
+ callback = lodash.createCallback(callback, thisArg, 4);
+
+ var index = -1,
+ length = collection.length;
+
+ if (typeof length == 'number') {
+ if (noaccum) {
+ accumulator = collection[++index];
+ }
+ while (++index < length) {
+ accumulator = callback(accumulator, collection[index], index, collection);
+ }
+ } else {
+ forOwn(collection, function(value, index, collection) {
+ accumulator = noaccum
+ ? (noaccum = false, value)
+ : callback(accumulator, value, index, collection)
+ });
+ }
+ return accumulator;
+ }
+
+ /**
+ * This method is like `_.reduce` except that it iterates over elements
+ * of a `collection` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @alias foldr
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [callback=identity] The function called per iteration.
+ * @param {*} [accumulator] Initial value of the accumulator.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {*} Returns the accumulated value.
+ * @example
+ *
+ * var list = [[0, 1], [2, 3], [4, 5]];
+ * var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
+ * // => [4, 5, 2, 3, 0, 1]
+ */
+ function reduceRight(collection, callback, accumulator, thisArg) {
+ var noaccum = arguments.length < 3;
+ callback = lodash.createCallback(callback, thisArg, 4);
+ forEachRight(collection, function(value, index, collection) {
+ accumulator = noaccum
+ ? (noaccum = false, value)
+ : callback(accumulator, value, index, collection);
+ });
+ return accumulator;
+ }
+
+ /**
+ * The opposite of `_.filter` this method returns the elements of a
+ * collection that the callback does **not** return truey for.
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [callback=identity] The function called
+ * per iteration. If a property name or object is provided it will be used
+ * to create a "_.pluck" or "_.where" style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Array} Returns a new array of elements that failed the callback check.
+ * @example
+ *
+ * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
+ * // => [1, 3, 5]
+ *
+ * var characters = [
+ * { 'name': 'barney', 'age': 36, 'blocked': false },
+ * { 'name': 'fred', 'age': 40, 'blocked': true }
+ * ];
+ *
+ * // using "_.pluck" callback shorthand
+ * _.reject(characters, 'blocked');
+ * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
+ *
+ * // using "_.where" callback shorthand
+ * _.reject(characters, { 'age': 36 });
+ * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
+ */
+ function reject(collection, callback, thisArg) {
+ callback = lodash.createCallback(callback, thisArg, 3);
+ return filter(collection, function(value, index, collection) {
+ return !callback(value, index, collection);
+ });
+ }
+
+ /**
+ * Retrieves a random element or `n` random elements from a collection.
+ *
+ * @static
+ * @memberOf _
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to sample.
+ * @param {number} [n] The number of elements to sample.
+ * @param- {Object} [guard] Allows working with functions like `_.map`
+ * without using their `index` arguments as `n`.
+ * @returns {Array} Returns the random sample(s) of `collection`.
+ * @example
+ *
+ * _.sample([1, 2, 3, 4]);
+ * // => 2
+ *
+ * _.sample([1, 2, 3, 4], 2);
+ * // => [3, 1]
+ */
+ function sample(collection, n, guard) {
+ if (collection && typeof collection.length != 'number') {
+ collection = values(collection);
+ }
+ if (n == null || guard) {
+ return collection ? collection[baseRandom(0, collection.length - 1)] : undefined;
+ }
+ var result = shuffle(collection);
+ result.length = nativeMin(nativeMax(0, n), result.length);
+ return result;
+ }
+
+ /**
+ * Creates an array of shuffled values, using a version of the Fisher-Yates
+ * shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
+ *
+ * @static
+ * @memberOf _
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to shuffle.
+ * @returns {Array} Returns a new shuffled collection.
+ * @example
+ *
+ * _.shuffle([1, 2, 3, 4, 5, 6]);
+ * // => [4, 1, 6, 3, 5, 2]
+ */
+ function shuffle(collection) {
+ var index = -1,
+ length = collection ? collection.length : 0,
+ result = Array(typeof length == 'number' ? length : 0);
+
+ forEach(collection, function(value) {
+ var rand = baseRandom(0, ++index);
+ result[index] = result[rand];
+ result[rand] = value;
+ });
+ return result;
+ }
+
+ /**
+ * Gets the size of the `collection` by returning `collection.length` for arrays
+ * and array-like objects or the number of own enumerable properties for objects.
+ *
+ * @static
+ * @memberOf _
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to inspect.
+ * @returns {number} Returns `collection.length` or number of own enumerable properties.
+ * @example
+ *
+ * _.size([1, 2]);
+ * // => 2
+ *
+ * _.size({ 'one': 1, 'two': 2, 'three': 3 });
+ * // => 3
+ *
+ * _.size('pebbles');
+ * // => 7
+ */
+ function size(collection) {
+ var length = collection ? collection.length : 0;
+ return typeof length == 'number' ? length : keys(collection).length;
+ }
+
+ /**
+ * Checks if the callback returns a truey value for **any** element of a
+ * collection. The function returns as soon as it finds a passing value and
+ * does not iterate over the entire collection. The callback is bound to
+ * `thisArg` and invoked with three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias any
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [callback=identity] The function called
+ * per iteration. If a property name or object is provided it will be used
+ * to create a "_.pluck" or "_.where" style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {boolean} Returns `true` if any element passed the callback check,
+ * else `false`.
+ * @example
+ *
+ * _.some([null, 0, 'yes', false], Boolean);
+ * // => true
+ *
+ * var characters = [
+ * { 'name': 'barney', 'age': 36, 'blocked': false },
+ * { 'name': 'fred', 'age': 40, 'blocked': true }
+ * ];
+ *
+ * // using "_.pluck" callback shorthand
+ * _.some(characters, 'blocked');
+ * // => true
+ *
+ * // using "_.where" callback shorthand
+ * _.some(characters, { 'age': 1 });
+ * // => false
+ */
+ function some(collection, callback, thisArg) {
+ var result;
+ callback = lodash.createCallback(callback, thisArg, 3);
+
+ var index = -1,
+ length = collection ? collection.length : 0;
+
+ if (typeof length == 'number') {
+ while (++index < length) {
+ if ((result = callback(collection[index], index, collection))) {
+ break;
+ }
+ }
+ } else {
+ forOwn(collection, function(value, index, collection) {
+ return !(result = callback(value, index, collection));
+ });
+ }
+ return !!result;
+ }
+
+ /**
+ * Creates an array of elements, sorted in ascending order by the results of
+ * running each element in a collection through the callback. This method
+ * performs a stable sort, that is, it will preserve the original sort order
+ * of equal elements. The callback is bound to `thisArg` and invoked with
+ * three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an array of property names is provided for `callback` the collection
+ * will be sorted by each property value.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Array|Function|Object|string} [callback=identity] The function called
+ * per iteration. If a property name or object is provided it will be used
+ * to create a "_.pluck" or "_.where" style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Array} Returns a new array of sorted elements.
+ * @example
+ *
+ * _.sortBy([1, 2, 3], function(num) { return Math.sin(num); });
+ * // => [3, 1, 2]
+ *
+ * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math);
+ * // => [3, 1, 2]
+ *
+ * var characters = [
+ * { 'name': 'barney', 'age': 36 },
+ * { 'name': 'fred', 'age': 40 },
+ * { 'name': 'barney', 'age': 26 },
+ * { 'name': 'fred', 'age': 30 }
+ * ];
+ *
+ * // using "_.pluck" callback shorthand
+ * _.map(_.sortBy(characters, 'age'), _.values);
+ * // => [['barney', 26], ['fred', 30], ['barney', 36], ['fred', 40]]
+ *
+ * // sorting by multiple properties
+ * _.map(_.sortBy(characters, ['name', 'age']), _.values);
+ * // = > [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]]
+ */
+ function sortBy(collection, callback, thisArg) {
+ var index = -1,
+ isArr = isArray(callback),
+ length = collection ? collection.length : 0,
+ result = Array(typeof length == 'number' ? length : 0);
+
+ if (!isArr) {
+ callback = lodash.createCallback(callback, thisArg, 3);
+ }
+ forEach(collection, function(value, key, collection) {
+ var object = result[++index] = getObject();
+ if (isArr) {
+ object.criteria = map(callback, function(key) { return value[key]; });
+ } else {
+ (object.criteria = getArray())[0] = callback(value, key, collection);
+ }
+ object.index = index;
+ object.value = value;
+ });
+
+ length = result.length;
+ result.sort(compareAscending);
+ while (length--) {
+ var object = result[length];
+ result[length] = object.value;
+ if (!isArr) {
+ releaseArray(object.criteria);
+ }
+ releaseObject(object);
+ }
+ return result;
+ }
+
+ /**
+ * Converts the `collection` to an array.
+ *
+ * @static
+ * @memberOf _
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to convert.
+ * @returns {Array} Returns the new converted array.
+ * @example
+ *
+ * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
+ * // => [2, 3, 4]
+ */
+ function toArray(collection) {
+ if (collection && typeof collection.length == 'number') {
+ return slice(collection);
+ }
+ return values(collection);
+ }
+
+ /**
+ * Performs a deep comparison of each element in a `collection` to the given
+ * `properties` object, returning an array of all elements that have equivalent
+ * property values.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Collections
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Object} props The object of property values to filter by.
+ * @returns {Array} Returns a new array of elements that have the given properties.
+ * @example
+ *
+ * var characters = [
+ * { 'name': 'barney', 'age': 36, 'pets': ['hoppy'] },
+ * { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }
+ * ];
+ *
+ * _.where(characters, { 'age': 36 });
+ * // => [{ 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }]
+ *
+ * _.where(characters, { 'pets': ['dino'] });
+ * // => [{ 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }]
+ */
+ var where = filter;
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Creates an array with all falsey values removed. The values `false`, `null`,
+ * `0`, `""`, `undefined`, and `NaN` are all falsey.
+ *
+ * @static
+ * @memberOf _
+ * @category Arrays
+ * @param {Array} array The array to compact.
+ * @returns {Array} Returns a new array of filtered values.
+ * @example
+ *
+ * _.compact([0, 1, false, 2, '', 3]);
+ * // => [1, 2, 3]
+ */
+ function compact(array) {
+ var index = -1,
+ length = array ? array.length : 0,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index];
+ if (value) {
+ result.push(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array excluding all values of the provided arrays using strict
+ * equality for comparisons, i.e. `===`.
+ *
+ * @static
+ * @memberOf _
+ * @category Arrays
+ * @param {Array} array The array to process.
+ * @param {...Array} [values] The arrays of values to exclude.
+ * @returns {Array} Returns a new array of filtered values.
+ * @example
+ *
+ * _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
+ * // => [1, 3, 4]
+ */
+ function difference(array) {
+ return baseDifference(array, baseFlatten(arguments, true, true, 1));
+ }
+
+ /**
+ * This method is like `_.find` except that it returns the index of the first
+ * element that passes the callback check, instead of the element itself.
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Arrays
+ * @param {Array} array The array to search.
+ * @param {Function|Object|string} [callback=identity] The function called
+ * per iteration. If a property name or object is provided it will be used
+ * to create a "_.pluck" or "_.where" style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {number} Returns the index of the found element, else `-1`.
+ * @example
+ *
+ * var characters = [
+ * { 'name': 'barney', 'age': 36, 'blocked': false },
+ * { 'name': 'fred', 'age': 40, 'blocked': true },
+ * { 'name': 'pebbles', 'age': 1, 'blocked': false }
+ * ];
+ *
+ * _.findIndex(characters, function(chr) {
+ * return chr.age < 20;
+ * });
+ * // => 2
+ *
+ * // using "_.where" callback shorthand
+ * _.findIndex(characters, { 'age': 36 });
+ * // => 0
+ *
+ * // using "_.pluck" callback shorthand
+ * _.findIndex(characters, 'blocked');
+ * // => 1
+ */
+ function findIndex(array, callback, thisArg) {
+ var index = -1,
+ length = array ? array.length : 0;
+
+ callback = lodash.createCallback(callback, thisArg, 3);
+ while (++index < length) {
+ if (callback(array[index], index, array)) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * This method is like `_.findIndex` except that it iterates over elements
+ * of a `collection` from right to left.
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Arrays
+ * @param {Array} array The array to search.
+ * @param {Function|Object|string} [callback=identity] The function called
+ * per iteration. If a property name or object is provided it will be used
+ * to create a "_.pluck" or "_.where" style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {number} Returns the index of the found element, else `-1`.
+ * @example
+ *
+ * var characters = [
+ * { 'name': 'barney', 'age': 36, 'blocked': true },
+ * { 'name': 'fred', 'age': 40, 'blocked': false },
+ * { 'name': 'pebbles', 'age': 1, 'blocked': true }
+ * ];
+ *
+ * _.findLastIndex(characters, function(chr) {
+ * return chr.age > 30;
+ * });
+ * // => 1
+ *
+ * // using "_.where" callback shorthand
+ * _.findLastIndex(characters, { 'age': 36 });
+ * // => 0
+ *
+ * // using "_.pluck" callback shorthand
+ * _.findLastIndex(characters, 'blocked');
+ * // => 2
+ */
+ function findLastIndex(array, callback, thisArg) {
+ var length = array ? array.length : 0;
+ callback = lodash.createCallback(callback, thisArg, 3);
+ while (length--) {
+ if (callback(array[length], length, array)) {
+ return length;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Gets the first element or first `n` elements of an array. If a callback
+ * is provided elements at the beginning of the array are returned as long
+ * as the callback returns truey. The callback is bound to `thisArg` and
+ * invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias head, take
+ * @category Arrays
+ * @param {Array} array The array to query.
+ * @param {Function|Object|number|string} [callback] The function called
+ * per element or the number of elements to return. If a property name or
+ * object is provided it will be used to create a "_.pluck" or "_.where"
+ * style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {*} Returns the first element(s) of `array`.
+ * @example
+ *
+ * _.first([1, 2, 3]);
+ * // => 1
+ *
+ * _.first([1, 2, 3], 2);
+ * // => [1, 2]
+ *
+ * _.first([1, 2, 3], function(num) {
+ * return num < 3;
+ * });
+ * // => [1, 2]
+ *
+ * var characters = [
+ * { 'name': 'barney', 'blocked': true, 'employer': 'slate' },
+ * { 'name': 'fred', 'blocked': false, 'employer': 'slate' },
+ * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
+ * ];
+ *
+ * // using "_.pluck" callback shorthand
+ * _.first(characters, 'blocked');
+ * // => [{ 'name': 'barney', 'blocked': true, 'employer': 'slate' }]
+ *
+ * // using "_.where" callback shorthand
+ * _.pluck(_.first(characters, { 'employer': 'slate' }), 'name');
+ * // => ['barney', 'fred']
+ */
+ function first(array, callback, thisArg) {
+ var n = 0,
+ length = array ? array.length : 0;
+
+ if (typeof callback != 'number' && callback != null) {
+ var index = -1;
+ callback = lodash.createCallback(callback, thisArg, 3);
+ while (++index < length && callback(array[index], index, array)) {
+ n++;
+ }
+ } else {
+ n = callback;
+ if (n == null || thisArg) {
+ return array ? array[0] : undefined;
+ }
+ }
+ return slice(array, 0, nativeMin(nativeMax(0, n), length));
+ }
+
+ /**
+ * Flattens a nested array (the nesting can be to any depth). If `isShallow`
+ * is truey, the array will only be flattened a single level. If a callback
+ * is provided each element of the array is passed through the callback before
+ * flattening. The callback is bound to `thisArg` and invoked with three
+ * arguments; (value, index, array).
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Arrays
+ * @param {Array} array The array to flatten.
+ * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
+ * @param {Function|Object|string} [callback=identity] The function called
+ * per iteration. If a property name or object is provided it will be used
+ * to create a "_.pluck" or "_.where" style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Array} Returns a new flattened array.
+ * @example
+ *
+ * _.flatten([1, [2], [3, [[4]]]]);
+ * // => [1, 2, 3, 4];
+ *
+ * _.flatten([1, [2], [3, [[4]]]], true);
+ * // => [1, 2, 3, [[4]]];
+ *
+ * var characters = [
+ * { 'name': 'barney', 'age': 30, 'pets': ['hoppy'] },
+ * { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }
+ * ];
+ *
+ * // using "_.pluck" callback shorthand
+ * _.flatten(characters, 'pets');
+ * // => ['hoppy', 'baby puss', 'dino']
+ */
+ function flatten(array, isShallow, callback, thisArg) {
+ // juggle arguments
+ if (typeof isShallow != 'boolean' && isShallow != null) {
+ thisArg = callback;
+ callback = (typeof isShallow != 'function' && thisArg && thisArg[isShallow] === array) ? null : isShallow;
+ isShallow = false;
+ }
+ if (callback != null) {
+ array = map(array, callback, thisArg);
+ }
+ return baseFlatten(array, isShallow);
+ }
+
+ /**
+ * Gets the index at which the first occurrence of `value` is found using
+ * strict equality for comparisons, i.e. `===`. If the array is already sorted
+ * providing `true` for `fromIndex` will run a faster binary search.
+ *
+ * @static
+ * @memberOf _
+ * @category Arrays
+ * @param {Array} array The array to search.
+ * @param {*} value The value to search for.
+ * @param {boolean|number} [fromIndex=0] The index to search from or `true`
+ * to perform a binary search on a sorted array.
+ * @returns {number} Returns the index of the matched value or `-1`.
+ * @example
+ *
+ * _.indexOf([1, 2, 3, 1, 2, 3], 2);
+ * // => 1
+ *
+ * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
+ * // => 4
+ *
+ * _.indexOf([1, 1, 2, 2, 3, 3], 2, true);
+ * // => 2
+ */
+ function indexOf(array, value, fromIndex) {
+ if (typeof fromIndex == 'number') {
+ var length = array ? array.length : 0;
+ fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0);
+ } else if (fromIndex) {
+ var index = sortedIndex(array, value);
+ return array[index] === value ? index : -1;
+ }
+ return baseIndexOf(array, value, fromIndex);
+ }
+
+ /**
+ * Gets all but the last element or last `n` elements of an array. If a
+ * callback is provided elements at the end of the array are excluded from
+ * the result as long as the callback returns truey. The callback is bound
+ * to `thisArg` and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Arrays
+ * @param {Array} array The array to query.
+ * @param {Function|Object|number|string} [callback=1] The function called
+ * per element or the number of elements to exclude. If a property name or
+ * object is provided it will be used to create a "_.pluck" or "_.where"
+ * style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Array} Returns a slice of `array`.
+ * @example
+ *
+ * _.initial([1, 2, 3]);
+ * // => [1, 2]
+ *
+ * _.initial([1, 2, 3], 2);
+ * // => [1]
+ *
+ * _.initial([1, 2, 3], function(num) {
+ * return num > 1;
+ * });
+ * // => [1]
+ *
+ * var characters = [
+ * { 'name': 'barney', 'blocked': false, 'employer': 'slate' },
+ * { 'name': 'fred', 'blocked': true, 'employer': 'slate' },
+ * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
+ * ];
+ *
+ * // using "_.pluck" callback shorthand
+ * _.initial(characters, 'blocked');
+ * // => [{ 'name': 'barney', 'blocked': false, 'employer': 'slate' }]
+ *
+ * // using "_.where" callback shorthand
+ * _.pluck(_.initial(characters, { 'employer': 'na' }), 'name');
+ * // => ['barney', 'fred']
+ */
+ function initial(array, callback, thisArg) {
+ var n = 0,
+ length = array ? array.length : 0;
+
+ if (typeof callback != 'number' && callback != null) {
+ var index = length;
+ callback = lodash.createCallback(callback, thisArg, 3);
+ while (index-- && callback(array[index], index, array)) {
+ n++;
+ }
+ } else {
+ n = (callback == null || thisArg) ? 1 : callback || n;
+ }
+ return slice(array, 0, nativeMin(nativeMax(0, length - n), length));
+ }
+
+ /**
+ * Creates an array of unique values present in all provided arrays using
+ * strict equality for comparisons, i.e. `===`.
+ *
+ * @static
+ * @memberOf _
+ * @category Arrays
+ * @param {...Array} [array] The arrays to inspect.
+ * @returns {Array} Returns an array of shared values.
+ * @example
+ *
+ * _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]);
+ * // => [1, 2]
+ */
+ function intersection() {
+ var args = [],
+ argsIndex = -1,
+ argsLength = arguments.length,
+ caches = getArray(),
+ indexOf = getIndexOf(),
+ trustIndexOf = indexOf === baseIndexOf,
+ seen = getArray();
+
+ while (++argsIndex < argsLength) {
+ var value = arguments[argsIndex];
+ if (isArray(value) || isArguments(value)) {
+ args.push(value);
+ caches.push(trustIndexOf && value.length >= largeArraySize &&
+ createCache(argsIndex ? args[argsIndex] : seen));
+ }
+ }
+ var array = args[0],
+ index = -1,
+ length = array ? array.length : 0,
+ result = [];
+
+ outer:
+ while (++index < length) {
+ var cache = caches[0];
+ value = array[index];
+
+ if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) {
+ argsIndex = argsLength;
+ (cache || seen).push(value);
+ while (--argsIndex) {
+ cache = caches[argsIndex];
+ if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) {
+ continue outer;
+ }
+ }
+ result.push(value);
+ }
+ }
+ while (argsLength--) {
+ cache = caches[argsLength];
+ if (cache) {
+ releaseObject(cache);
+ }
+ }
+ releaseArray(caches);
+ releaseArray(seen);
+ return result;
+ }
+
+ /**
+ * Gets the last element or last `n` elements of an array. If a callback is
+ * provided elements at the end of the array are returned as long as the
+ * callback returns truey. The callback is bound to `thisArg` and invoked
+ * with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Arrays
+ * @param {Array} array The array to query.
+ * @param {Function|Object|number|string} [callback] The function called
+ * per element or the number of elements to return. If a property name or
+ * object is provided it will be used to create a "_.pluck" or "_.where"
+ * style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {*} Returns the last element(s) of `array`.
+ * @example
+ *
+ * _.last([1, 2, 3]);
+ * // => 3
+ *
+ * _.last([1, 2, 3], 2);
+ * // => [2, 3]
+ *
+ * _.last([1, 2, 3], function(num) {
+ * return num > 1;
+ * });
+ * // => [2, 3]
+ *
+ * var characters = [
+ * { 'name': 'barney', 'blocked': false, 'employer': 'slate' },
+ * { 'name': 'fred', 'blocked': true, 'employer': 'slate' },
+ * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
+ * ];
+ *
+ * // using "_.pluck" callback shorthand
+ * _.pluck(_.last(characters, 'blocked'), 'name');
+ * // => ['fred', 'pebbles']
+ *
+ * // using "_.where" callback shorthand
+ * _.last(characters, { 'employer': 'na' });
+ * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
+ */
+ function last(array, callback, thisArg) {
+ var n = 0,
+ length = array ? array.length : 0;
+
+ if (typeof callback != 'number' && callback != null) {
+ var index = length;
+ callback = lodash.createCallback(callback, thisArg, 3);
+ while (index-- && callback(array[index], index, array)) {
+ n++;
+ }
+ } else {
+ n = callback;
+ if (n == null || thisArg) {
+ return array ? array[length - 1] : undefined;
+ }
+ }
+ return slice(array, nativeMax(0, length - n));
+ }
+
+ /**
+ * Gets the index at which the last occurrence of `value` is found using strict
+ * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
+ * as the offset from the end of the collection.
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Arrays
+ * @param {Array} array The array to search.
+ * @param {*} value The value to search for.
+ * @param {number} [fromIndex=array.length-1] The index to search from.
+ * @returns {number} Returns the index of the matched value or `-1`.
+ * @example
+ *
+ * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
+ * // => 4
+ *
+ * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
+ * // => 1
+ */
+ function lastIndexOf(array, value, fromIndex) {
+ var index = array ? array.length : 0;
+ if (typeof fromIndex == 'number') {
+ index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1;
+ }
+ while (index--) {
+ if (array[index] === value) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Removes all provided values from the given array using strict equality for
+ * comparisons, i.e. `===`.
+ *
+ * @static
+ * @memberOf _
+ * @category Arrays
+ * @param {Array} array The array to modify.
+ * @param {...*} [value] The values to remove.
+ * @returns {Array} Returns `array`.
+ * @example
+ *
+ * var array = [1, 2, 3, 1, 2, 3];
+ * _.pull(array, 2, 3);
+ * console.log(array);
+ * // => [1, 1]
+ */
+ function pull(array) {
+ var args = arguments,
+ argsIndex = 0,
+ argsLength = args.length,
+ length = array ? array.length : 0;
+
+ while (++argsIndex < argsLength) {
+ var index = -1,
+ value = args[argsIndex];
+ while (++index < length) {
+ if (array[index] === value) {
+ splice.call(array, index--, 1);
+ length--;
+ }
+ }
+ }
+ return array;
+ }
+
+ /**
+ * Creates an array of numbers (positive and/or negative) progressing from
+ * `start` up to but not including `end`. If `start` is less than `stop` a
+ * zero-length range is created unless a negative `step` is specified.
+ *
+ * @static
+ * @memberOf _
+ * @category Arrays
+ * @param {number} [start=0] The start of the range.
+ * @param {number} end The end of the range.
+ * @param {number} [step=1] The value to increment or decrement by.
+ * @returns {Array} Returns a new range array.
+ * @example
+ *
+ * _.range(4);
+ * // => [0, 1, 2, 3]
+ *
+ * _.range(1, 5);
+ * // => [1, 2, 3, 4]
+ *
+ * _.range(0, 20, 5);
+ * // => [0, 5, 10, 15]
+ *
+ * _.range(0, -4, -1);
+ * // => [0, -1, -2, -3]
+ *
+ * _.range(1, 4, 0);
+ * // => [1, 1, 1]
+ *
+ * _.range(0);
+ * // => []
+ */
+ function range(start, end, step) {
+ start = +start || 0;
+ step = typeof step == 'number' ? step : (+step || 1);
+
+ if (end == null) {
+ end = start;
+ start = 0;
+ }
+ // use `Array(length)` so engines like Chakra and V8 avoid slower modes
+ // http://youtu.be/XAqIpGU8ZZk#t=17m25s
+ var index = -1,
+ length = nativeMax(0, ceil((end - start) / (step || 1))),
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = start;
+ start += step;
+ }
+ return result;
+ }
+
+ /**
+ * Removes all elements from an array that the callback returns truey for
+ * and returns an array of removed elements. The callback is bound to `thisArg`
+ * and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Arrays
+ * @param {Array} array The array to modify.
+ * @param {Function|Object|string} [callback=identity] The function called
+ * per iteration. If a property name or object is provided it will be used
+ * to create a "_.pluck" or "_.where" style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Array} Returns a new array of removed elements.
+ * @example
+ *
+ * var array = [1, 2, 3, 4, 5, 6];
+ * var evens = _.remove(array, function(num) { return num % 2 == 0; });
+ *
+ * console.log(array);
+ * // => [1, 3, 5]
+ *
+ * console.log(evens);
+ * // => [2, 4, 6]
+ */
+ function remove(array, callback, thisArg) {
+ var index = -1,
+ length = array ? array.length : 0,
+ result = [];
+
+ callback = lodash.createCallback(callback, thisArg, 3);
+ while (++index < length) {
+ var value = array[index];
+ if (callback(value, index, array)) {
+ result.push(value);
+ splice.call(array, index--, 1);
+ length--;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The opposite of `_.initial` this method gets all but the first element or
+ * first `n` elements of an array. If a callback function is provided elements
+ * at the beginning of the array are excluded from the result as long as the
+ * callback returns truey. The callback is bound to `thisArg` and invoked
+ * with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias drop, tail
+ * @category Arrays
+ * @param {Array} array The array to query.
+ * @param {Function|Object|number|string} [callback=1] The function called
+ * per element or the number of elements to exclude. If a property name or
+ * object is provided it will be used to create a "_.pluck" or "_.where"
+ * style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Array} Returns a slice of `array`.
+ * @example
+ *
+ * _.rest([1, 2, 3]);
+ * // => [2, 3]
+ *
+ * _.rest([1, 2, 3], 2);
+ * // => [3]
+ *
+ * _.rest([1, 2, 3], function(num) {
+ * return num < 3;
+ * });
+ * // => [3]
+ *
+ * var characters = [
+ * { 'name': 'barney', 'blocked': true, 'employer': 'slate' },
+ * { 'name': 'fred', 'blocked': false, 'employer': 'slate' },
+ * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
+ * ];
+ *
+ * // using "_.pluck" callback shorthand
+ * _.pluck(_.rest(characters, 'blocked'), 'name');
+ * // => ['fred', 'pebbles']
+ *
+ * // using "_.where" callback shorthand
+ * _.rest(characters, { 'employer': 'slate' });
+ * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
+ */
+ function rest(array, callback, thisArg) {
+ if (typeof callback != 'number' && callback != null) {
+ var n = 0,
+ index = -1,
+ length = array ? array.length : 0;
+
+ callback = lodash.createCallback(callback, thisArg, 3);
+ while (++index < length && callback(array[index], index, array)) {
+ n++;
+ }
+ } else {
+ n = (callback == null || thisArg) ? 1 : nativeMax(0, callback);
+ }
+ return slice(array, n);
+ }
+
+ /**
+ * Uses a binary search to determine the smallest index at which a value
+ * should be inserted into a given sorted array in order to maintain the sort
+ * order of the array. If a callback is provided it will be executed for
+ * `value` and each element of `array` to compute their sort ranking. The
+ * callback is bound to `thisArg` and invoked with one argument; (value).
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Arrays
+ * @param {Array} array The array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {Function|Object|string} [callback=identity] The function called
+ * per iteration. If a property name or object is provided it will be used
+ * to create a "_.pluck" or "_.where" style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ * @example
+ *
+ * _.sortedIndex([20, 30, 50], 40);
+ * // => 2
+ *
+ * // using "_.pluck" callback shorthand
+ * _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
+ * // => 2
+ *
+ * var dict = {
+ * 'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 }
+ * };
+ *
+ * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
+ * return dict.wordToNumber[word];
+ * });
+ * // => 2
+ *
+ * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
+ * return this.wordToNumber[word];
+ * }, dict);
+ * // => 2
+ */
+ function sortedIndex(array, value, callback, thisArg) {
+ var low = 0,
+ high = array ? array.length : low;
+
+ // explicitly reference `identity` for better inlining in Firefox
+ callback = callback ? lodash.createCallback(callback, thisArg, 1) : identity;
+ value = callback(value);
+
+ while (low < high) {
+ var mid = (low + high) >>> 1;
+ (callback(array[mid]) < value)
+ ? low = mid + 1
+ : high = mid;
+ }
+ return low;
+ }
+
+ /**
+ * Creates an array of unique values, in order, of the provided arrays using
+ * strict equality for comparisons, i.e. `===`.
+ *
+ * @static
+ * @memberOf _
+ * @category Arrays
+ * @param {...Array} [array] The arrays to inspect.
+ * @returns {Array} Returns an array of combined values.
+ * @example
+ *
+ * _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]);
+ * // => [1, 2, 3, 5, 4]
+ */
+ function union() {
+ return baseUniq(baseFlatten(arguments, true, true));
+ }
+
+ /**
+ * Creates a duplicate-value-free version of an array using strict equality
+ * for comparisons, i.e. `===`. If the array is sorted, providing
+ * `true` for `isSorted` will use a faster algorithm. If a callback is provided
+ * each element of `array` is passed through the callback before uniqueness
+ * is computed. The callback is bound to `thisArg` and invoked with three
+ * arguments; (value, index, array).
+ *
+ * If a property name is provided for `callback` the created "_.pluck" style
+ * callback will return the property value of the given element.
+ *
+ * If an object is provided for `callback` the created "_.where" style callback
+ * will return `true` for elements that have the properties of the given object,
+ * else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias unique
+ * @category Arrays
+ * @param {Array} array The array to process.
+ * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
+ * @param {Function|Object|string} [callback=identity] The function called
+ * per iteration. If a property name or object is provided it will be used
+ * to create a "_.pluck" or "_.where" style callback, respectively.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Array} Returns a duplicate-value-free array.
+ * @example
+ *
+ * _.uniq([1, 2, 1, 3, 1]);
+ * // => [1, 2, 3]
+ *
+ * _.uniq([1, 1, 2, 2, 3], true);
+ * // => [1, 2, 3]
+ *
+ * _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); });
+ * // => ['A', 'b', 'C']
+ *
+ * _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math);
+ * // => [1, 2.5, 3]
+ *
+ * // using "_.pluck" callback shorthand
+ * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
+ * // => [{ 'x': 1 }, { 'x': 2 }]
+ */
+ function uniq(array, isSorted, callback, thisArg) {
+ // juggle arguments
+ if (typeof isSorted != 'boolean' && isSorted != null) {
+ thisArg = callback;
+ callback = (typeof isSorted != 'function' && thisArg && thisArg[isSorted] === array) ? null : isSorted;
+ isSorted = false;
+ }
+ if (callback != null) {
+ callback = lodash.createCallback(callback, thisArg, 3);
+ }
+ return baseUniq(array, isSorted, callback);
+ }
+
+ /**
+ * Creates an array excluding all provided values using strict equality for
+ * comparisons, i.e. `===`.
+ *
+ * @static
+ * @memberOf _
+ * @category Arrays
+ * @param {Array} array The array to filter.
+ * @param {...*} [value] The values to exclude.
+ * @returns {Array} Returns a new array of filtered values.
+ * @example
+ *
+ * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
+ * // => [2, 3, 4]
+ */
+ function without(array) {
+ return baseDifference(array, slice(arguments, 1));
+ }
+
+ /**
+ * Creates an array that is the symmetric difference of the provided arrays.
+ * See http://en.wikipedia.org/wiki/Symmetric_difference.
+ *
+ * @static
+ * @memberOf _
+ * @category Arrays
+ * @param {...Array} [array] The arrays to inspect.
+ * @returns {Array} Returns an array of values.
+ * @example
+ *
+ * _.xor([1, 2, 3], [5, 2, 1, 4]);
+ * // => [3, 5, 4]
+ *
+ * _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]);
+ * // => [1, 4, 5]
+ */
+ function xor() {
+ var index = -1,
+ length = arguments.length;
+
+ while (++index < length) {
+ var array = arguments[index];
+ if (isArray(array) || isArguments(array)) {
+ var result = result
+ ? baseUniq(baseDifference(result, array).concat(baseDifference(array, result)))
+ : array;
+ }
+ }
+ return result || [];
+ }
+
+ /**
+ * Creates an array of grouped elements, the first of which contains the first
+ * elements of the given arrays, the second of which contains the second
+ * elements of the given arrays, and so on.
+ *
+ * @static
+ * @memberOf _
+ * @alias unzip
+ * @category Arrays
+ * @param {...Array} [array] Arrays to process.
+ * @returns {Array} Returns a new array of grouped elements.
+ * @example
+ *
+ * _.zip(['fred', 'barney'], [30, 40], [true, false]);
+ * // => [['fred', 30, true], ['barney', 40, false]]
+ */
+ function zip() {
+ var array = arguments.length > 1 ? arguments : arguments[0],
+ index = -1,
+ length = array ? max(pluck(array, 'length')) : 0,
+ result = Array(length < 0 ? 0 : length);
+
+ while (++index < length) {
+ result[index] = pluck(array, index);
+ }
+ return result;
+ }
+
+ /**
+ * Creates an object composed from arrays of `keys` and `values`. Provide
+ * either a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`
+ * or two arrays, one of `keys` and one of corresponding `values`.
+ *
+ * @static
+ * @memberOf _
+ * @alias object
+ * @category Arrays
+ * @param {Array} keys The array of keys.
+ * @param {Array} [values=[]] The array of values.
+ * @returns {Object} Returns an object composed of the given keys and
+ * corresponding values.
+ * @example
+ *
+ * _.zipObject(['fred', 'barney'], [30, 40]);
+ * // => { 'fred': 30, 'barney': 40 }
+ */
+ function zipObject(keys, values) {
+ var index = -1,
+ length = keys ? keys.length : 0,
+ result = {};
+
+ if (!values && length && !isArray(keys[0])) {
+ values = [];
+ }
+ while (++index < length) {
+ var key = keys[index];
+ if (values) {
+ result[key] = values[index];
+ } else if (key) {
+ result[key[0]] = key[1];
+ }
+ }
+ return result;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Creates a function that executes `func`, with the `this` binding and
+ * arguments of the created function, only after being called `n` times.
+ *
+ * @static
+ * @memberOf _
+ * @category Functions
+ * @param {number} n The number of times the function must be called before
+ * `func` is executed.
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * var saves = ['profile', 'settings'];
+ *
+ * var done = _.after(saves.length, function() {
+ * console.log('Done saving!');
+ * });
+ *
+ * _.forEach(saves, function(type) {
+ * asyncSave({ 'type': type, 'complete': done });
+ * });
+ * // => logs 'Done saving!', after all saves have completed
+ */
+ function after(n, func) {
+ if (!isFunction(func)) {
+ throw new TypeError;
+ }
+ return function() {
+ if (--n < 1) {
+ return func.apply(this, arguments);
+ }
+ };
+ }
+
+ /**
+ * Creates a function that, when called, invokes `func` with the `this`
+ * binding of `thisArg` and prepends any additional `bind` arguments to those
+ * provided to the bound function.
+ *
+ * @static
+ * @memberOf _
+ * @category Functions
+ * @param {Function} func The function to bind.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {...*} [arg] Arguments to be partially applied.
+ * @returns {Function} Returns the new bound function.
+ * @example
+ *
+ * var func = function(greeting) {
+ * return greeting + ' ' + this.name;
+ * };
+ *
+ * func = _.bind(func, { 'name': 'fred' }, 'hi');
+ * func();
+ * // => 'hi fred'
+ */
+ function bind(func, thisArg) {
+ return arguments.length > 2
+ ? createWrapper(func, 17, slice(arguments, 2), null, thisArg)
+ : createWrapper(func, 1, null, null, thisArg);
+ }
+
+ /**
+ * Binds methods of an object to the object itself, overwriting the existing
+ * method. Method names may be specified as individual arguments or as arrays
+ * of method names. If no method names are provided all the function properties
+ * of `object` will be bound.
+ *
+ * @static
+ * @memberOf _
+ * @category Functions
+ * @param {Object} object The object to bind and assign the bound methods to.
+ * @param {...string} [methodName] The object method names to
+ * bind, specified as individual method names or arrays of method names.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * var view = {
+ * 'label': 'docs',
+ * 'onClick': function() { console.log('clicked ' + this.label); }
+ * };
+ *
+ * _.bindAll(view);
+ * jQuery('#docs').on('click', view.onClick);
+ * // => logs 'clicked docs', when the button is clicked
+ */
+ function bindAll(object) {
+ var funcs = arguments.length > 1 ? baseFlatten(arguments, true, false, 1) : functions(object),
+ index = -1,
+ length = funcs.length;
+
+ while (++index < length) {
+ var key = funcs[index];
+ object[key] = createWrapper(object[key], 1, null, null, object);
+ }
+ return object;
+ }
+
+ /**
+ * Creates a function that, when called, invokes the method at `object[key]`
+ * and prepends any additional `bindKey` arguments to those provided to the bound
+ * function. This method differs from `_.bind` by allowing bound functions to
+ * reference methods that will be redefined or don't yet exist.
+ * See http://michaux.ca/articles/lazy-function-definition-pattern.
+ *
+ * @static
+ * @memberOf _
+ * @category Functions
+ * @param {Object} object The object the method belongs to.
+ * @param {string} key The key of the method.
+ * @param {...*} [arg] Arguments to be partially applied.
+ * @returns {Function} Returns the new bound function.
+ * @example
+ *
+ * var object = {
+ * 'name': 'fred',
+ * 'greet': function(greeting) {
+ * return greeting + ' ' + this.name;
+ * }
+ * };
+ *
+ * var func = _.bindKey(object, 'greet', 'hi');
+ * func();
+ * // => 'hi fred'
+ *
+ * object.greet = function(greeting) {
+ * return greeting + 'ya ' + this.name + '!';
+ * };
+ *
+ * func();
+ * // => 'hiya fred!'
+ */
+ function bindKey(object, key) {
+ return arguments.length > 2
+ ? createWrapper(key, 19, slice(arguments, 2), null, object)
+ : createWrapper(key, 3, null, null, object);
+ }
+
+ /**
+ * Creates a function that is the composition of the provided functions,
+ * where each function consumes the return value of the function that follows.
+ * For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`.
+ * Each function is executed with the `this` binding of the composed function.
+ *
+ * @static
+ * @memberOf _
+ * @category Functions
+ * @param {...Function} [func] Functions to compose.
+ * @returns {Function} Returns the new composed function.
+ * @example
+ *
+ * var realNameMap = {
+ * 'pebbles': 'penelope'
+ * };
+ *
+ * var format = function(name) {
+ * name = realNameMap[name.toLowerCase()] || name;
+ * return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();
+ * };
+ *
+ * var greet = function(formatted) {
+ * return 'Hiya ' + formatted + '!';
+ * };
+ *
+ * var welcome = _.compose(greet, format);
+ * welcome('pebbles');
+ * // => 'Hiya Penelope!'
+ */
+ function compose() {
+ var funcs = arguments,
+ length = funcs.length;
+
+ while (length--) {
+ if (!isFunction(funcs[length])) {
+ throw new TypeError;
+ }
+ }
+ return function() {
+ var args = arguments,
+ length = funcs.length;
+
+ while (length--) {
+ args = [funcs[length].apply(this, args)];
+ }
+ return args[0];
+ };
+ }
+
+ /**
+ * Creates a function which accepts one or more arguments of `func` that when
+ * invoked either executes `func` returning its result, if all `func` arguments
+ * have been provided, or returns a function that accepts one or more of the
+ * remaining `func` arguments, and so on. The arity of `func` can be specified
+ * if `func.length` is not sufficient.
+ *
+ * @static
+ * @memberOf _
+ * @category Functions
+ * @param {Function} func The function to curry.
+ * @param {number} [arity=func.length] The arity of `func`.
+ * @returns {Function} Returns the new curried function.
+ * @example
+ *
+ * var curried = _.curry(function(a, b, c) {
+ * console.log(a + b + c);
+ * });
+ *
+ * curried(1)(2)(3);
+ * // => 6
+ *
+ * curried(1, 2)(3);
+ * // => 6
+ *
+ * curried(1, 2, 3);
+ * // => 6
+ */
+ function curry(func, arity) {
+ arity = typeof arity == 'number' ? arity : (+arity || func.length);
+ return createWrapper(func, 4, null, null, null, arity);
+ }
+
+ /**
+ * Creates a function that will delay the execution of `func` until after
+ * `wait` milliseconds have elapsed since the last time it was invoked.
+ * Provide an options object to indicate that `func` should be invoked on
+ * the leading and/or trailing edge of the `wait` timeout. Subsequent calls
+ * to the debounced function will return the result of the last `func` call.
+ *
+ * Note: If `leading` and `trailing` options are `true` `func` will be called
+ * on the trailing edge of the timeout only if the the debounced function is
+ * invoked more than once during the `wait` timeout.
+ *
+ * @static
+ * @memberOf _
+ * @category Functions
+ * @param {Function} func The function to debounce.
+ * @param {number} wait The number of milliseconds to delay.
+ * @param {Object} [options] The options object.
+ * @param {boolean} [options.leading=false] Specify execution on the leading edge of the timeout.
+ * @param {number} [options.maxWait] The maximum time `func` is allowed to be delayed before it's called.
+ * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
+ * @returns {Function} Returns the new debounced function.
+ * @example
+ *
+ * // avoid costly calculations while the window size is in flux
+ * var lazyLayout = _.debounce(calculateLayout, 150);
+ * jQuery(window).on('resize', lazyLayout);
+ *
+ * // execute `sendMail` when the click event is fired, debouncing subsequent calls
+ * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
+ * 'leading': true,
+ * 'trailing': false
+ * });
+ *
+ * // ensure `batchLog` is executed once after 1 second of debounced calls
+ * var source = new EventSource('/stream');
+ * source.addEventListener('message', _.debounce(batchLog, 250, {
+ * 'maxWait': 1000
+ * }, false);
+ */
+ function debounce(func, wait, options) {
+ var args,
+ maxTimeoutId,
+ result,
+ stamp,
+ thisArg,
+ timeoutId,
+ trailingCall,
+ lastCalled = 0,
+ maxWait = false,
+ trailing = true;
+
+ if (!isFunction(func)) {
+ throw new TypeError;
+ }
+ wait = nativeMax(0, wait) || 0;
+ if (options === true) {
+ var leading = true;
+ trailing = false;
+ } else if (isObject(options)) {
+ leading = options.leading;
+ maxWait = 'maxWait' in options && (nativeMax(wait, options.maxWait) || 0);
+ trailing = 'trailing' in options ? options.trailing : trailing;
+ }
+ var delayed = function() {
+ var remaining = wait - (now() - stamp);
+ if (remaining <= 0) {
+ if (maxTimeoutId) {
+ clearTimeout(maxTimeoutId);
+ }
+ var isCalled = trailingCall;
+ maxTimeoutId = timeoutId = trailingCall = undefined;
+ if (isCalled) {
+ lastCalled = now();
+ result = func.apply(thisArg, args);
+ if (!timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
+ }
+ } else {
+ timeoutId = setTimeout(delayed, remaining);
+ }
+ };
+
+ var maxDelayed = function() {
+ if (timeoutId) {
+ clearTimeout(timeoutId);
+ }
+ maxTimeoutId = timeoutId = trailingCall = undefined;
+ if (trailing || (maxWait !== wait)) {
+ lastCalled = now();
+ result = func.apply(thisArg, args);
+ if (!timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
+ }
+ };
+
+ return function() {
+ args = arguments;
+ stamp = now();
+ thisArg = this;
+ trailingCall = trailing && (timeoutId || !leading);
+
+ if (maxWait === false) {
+ var leadingCall = leading && !timeoutId;
+ } else {
+ if (!maxTimeoutId && !leading) {
+ lastCalled = stamp;
+ }
+ var remaining = maxWait - (stamp - lastCalled),
+ isCalled = remaining <= 0;
+
+ if (isCalled) {
+ if (maxTimeoutId) {
+ maxTimeoutId = clearTimeout(maxTimeoutId);
+ }
+ lastCalled = stamp;
+ result = func.apply(thisArg, args);
+ }
+ else if (!maxTimeoutId) {
+ maxTimeoutId = setTimeout(maxDelayed, remaining);
+ }
+ }
+ if (isCalled && timeoutId) {
+ timeoutId = clearTimeout(timeoutId);
+ }
+ else if (!timeoutId && wait !== maxWait) {
+ timeoutId = setTimeout(delayed, wait);
+ }
+ if (leadingCall) {
+ isCalled = true;
+ result = func.apply(thisArg, args);
+ }
+ if (isCalled && !timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Defers executing the `func` function until the current call stack has cleared.
+ * Additional arguments will be provided to `func` when it is invoked.
+ *
+ * @static
+ * @memberOf _
+ * @category Functions
+ * @param {Function} func The function to defer.
+ * @param {...*} [arg] Arguments to invoke the function with.
+ * @returns {number} Returns the timer id.
+ * @example
+ *
+ * _.defer(function(text) { console.log(text); }, 'deferred');
+ * // logs 'deferred' after one or more milliseconds
+ */
+ function defer(func) {
+ if (!isFunction(func)) {
+ throw new TypeError;
+ }
+ var args = slice(arguments, 1);
+ return setTimeout(function() { func.apply(undefined, args); }, 1);
+ }
+
+ /**
+ * Executes the `func` function after `wait` milliseconds. Additional arguments
+ * will be provided to `func` when it is invoked.
+ *
+ * @static
+ * @memberOf _
+ * @category Functions
+ * @param {Function} func The function to delay.
+ * @param {number} wait The number of milliseconds to delay execution.
+ * @param {...*} [arg] Arguments to invoke the function with.
+ * @returns {number} Returns the timer id.
+ * @example
+ *
+ * _.delay(function(text) { console.log(text); }, 1000, 'later');
+ * // => logs 'later' after one second
+ */
+ function delay(func, wait) {
+ if (!isFunction(func)) {
+ throw new TypeError;
+ }
+ var args = slice(arguments, 2);
+ return setTimeout(function() { func.apply(undefined, args); }, wait);
+ }
+
+ /**
+ * Creates a function that memoizes the result of `func`. If `resolver` is
+ * provided it will be used to determine the cache key for storing the result
+ * based on the arguments provided to the memoized function. By default, the
+ * first argument provided to the memoized function is used as the cache key.
+ * The `func` is executed with the `this` binding of the memoized function.
+ * The result cache is exposed as the `cache` property on the memoized function.
+ *
+ * @static
+ * @memberOf _
+ * @category Functions
+ * @param {Function} func The function to have its output memoized.
+ * @param {Function} [resolver] A function used to resolve the cache key.
+ * @returns {Function} Returns the new memoizing function.
+ * @example
+ *
+ * var fibonacci = _.memoize(function(n) {
+ * return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
+ * });
+ *
+ * fibonacci(9)
+ * // => 34
+ *
+ * var data = {
+ * 'fred': { 'name': 'fred', 'age': 40 },
+ * 'pebbles': { 'name': 'pebbles', 'age': 1 }
+ * };
+ *
+ * // modifying the result cache
+ * var get = _.memoize(function(name) { return data[name]; }, _.identity);
+ * get('pebbles');
+ * // => { 'name': 'pebbles', 'age': 1 }
+ *
+ * get.cache.pebbles.name = 'penelope';
+ * get('pebbles');
+ * // => { 'name': 'penelope', 'age': 1 }
+ */
+ function memoize(func, resolver) {
+ if (!isFunction(func)) {
+ throw new TypeError;
+ }
+ var memoized = function() {
+ var cache = memoized.cache,
+ key = resolver ? resolver.apply(this, arguments) : keyPrefix + arguments[0];
+
+ return hasOwnProperty.call(cache, key)
+ ? cache[key]
+ : (cache[key] = func.apply(this, arguments));
+ }
+ memoized.cache = {};
+ return memoized;
+ }
+
+ /**
+ * Creates a function that is restricted to execute `func` once. Repeat calls to
+ * the function will return the value of the first call. The `func` is executed
+ * with the `this` binding of the created function.
+ *
+ * @static
+ * @memberOf _
+ * @category Functions
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * var initialize = _.once(createApplication);
+ * initialize();
+ * initialize();
+ * // `initialize` executes `createApplication` once
+ */
+ function once(func) {
+ var ran,
+ result;
+
+ if (!isFunction(func)) {
+ throw new TypeError;
+ }
+ return function() {
+ if (ran) {
+ return result;
+ }
+ ran = true;
+ result = func.apply(this, arguments);
+
+ // clear the `func` variable so the function may be garbage collected
+ func = null;
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that, when called, invokes `func` with any additional
+ * `partial` arguments prepended to those provided to the new function. This
+ * method is similar to `_.bind` except it does **not** alter the `this` binding.
+ *
+ * @static
+ * @memberOf _
+ * @category Functions
+ * @param {Function} func The function to partially apply arguments to.
+ * @param {...*} [arg] Arguments to be partially applied.
+ * @returns {Function} Returns the new partially applied function.
+ * @example
+ *
+ * var greet = function(greeting, name) { return greeting + ' ' + name; };
+ * var hi = _.partial(greet, 'hi');
+ * hi('fred');
+ * // => 'hi fred'
+ */
+ function partial(func) {
+ return createWrapper(func, 16, slice(arguments, 1));
+ }
+
+ /**
+ * This method is like `_.partial` except that `partial` arguments are
+ * appended to those provided to the new function.
+ *
+ * @static
+ * @memberOf _
+ * @category Functions
+ * @param {Function} func The function to partially apply arguments to.
+ * @param {...*} [arg] Arguments to be partially applied.
+ * @returns {Function} Returns the new partially applied function.
+ * @example
+ *
+ * var defaultsDeep = _.partialRight(_.merge, _.defaults);
+ *
+ * var options = {
+ * 'variable': 'data',
+ * 'imports': { 'jq': $ }
+ * };
+ *
+ * defaultsDeep(options, _.templateSettings);
+ *
+ * options.variable
+ * // => 'data'
+ *
+ * options.imports
+ * // => { '_': _, 'jq': $ }
+ */
+ function partialRight(func) {
+ return createWrapper(func, 32, null, slice(arguments, 1));
+ }
+
+ /**
+ * Creates a function that, when executed, will only call the `func` function
+ * at most once per every `wait` milliseconds. Provide an options object to
+ * indicate that `func` should be invoked on the leading and/or trailing edge
+ * of the `wait` timeout. Subsequent calls to the throttled function will
+ * return the result of the last `func` call.
+ *
+ * Note: If `leading` and `trailing` options are `true` `func` will be called
+ * on the trailing edge of the timeout only if the the throttled function is
+ * invoked more than once during the `wait` timeout.
+ *
+ * @static
+ * @memberOf _
+ * @category Functions
+ * @param {Function} func The function to throttle.
+ * @param {number} wait The number of milliseconds to throttle executions to.
+ * @param {Object} [options] The options object.
+ * @param {boolean} [options.leading=true] Specify execution on the leading edge of the timeout.
+ * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
+ * @returns {Function} Returns the new throttled function.
+ * @example
+ *
+ * // avoid excessively updating the position while scrolling
+ * var throttled = _.throttle(updatePosition, 100);
+ * jQuery(window).on('scroll', throttled);
+ *
+ * // execute `renewToken` when the click event is fired, but not more than once every 5 minutes
+ * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, {
+ * 'trailing': false
+ * }));
+ */
+ function throttle(func, wait, options) {
+ var leading = true,
+ trailing = true;
+
+ if (!isFunction(func)) {
+ throw new TypeError;
+ }
+ if (options === false) {
+ leading = false;
+ } else if (isObject(options)) {
+ leading = 'leading' in options ? options.leading : leading;
+ trailing = 'trailing' in options ? options.trailing : trailing;
+ }
+ debounceOptions.leading = leading;
+ debounceOptions.maxWait = wait;
+ debounceOptions.trailing = trailing;
+
+ return debounce(func, wait, debounceOptions);
+ }
+
+ /**
+ * Creates a function that provides `value` to the wrapper function as its
+ * first argument. Additional arguments provided to the function are appended
+ * to those provided to the wrapper function. The wrapper is executed with
+ * the `this` binding of the created function.
+ *
+ * @static
+ * @memberOf _
+ * @category Functions
+ * @param {*} value The value to wrap.
+ * @param {Function} wrapper The wrapper function.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var p = _.wrap(_.escape, function(func, text) {
+ * return '<p>' + func(text) + '</p>';
+ * });
+ *
+ * p('Fred, Wilma, & Pebbles');
+ * // => '<p>Fred, Wilma, &amp; Pebbles</p>'
+ */
+ function wrap(value, wrapper) {
+ return createWrapper(wrapper, 16, [value]);
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Creates a function that returns `value`.
+ *
+ * @static
+ * @memberOf _
+ * @category Utilities
+ * @param {*} value The value to return from the new function.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var object = { 'name': 'fred' };
+ * var getter = _.constant(object);
+ * getter() === object;
+ * // => true
+ */
+ function constant(value) {
+ return function() {
+ return value;
+ };
+ }
+
+ /**
+ * Produces a callback bound to an optional `thisArg`. If `func` is a property
+ * name the created callback will return the property value for a given element.
+ * If `func` is an object the created callback will return `true` for elements
+ * that contain the equivalent object properties, otherwise it will return `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Utilities
+ * @param {*} [func=identity] The value to convert to a callback.
+ * @param {*} [thisArg] The `this` binding of the created callback.
+ * @param {number} [argCount] The number of arguments the callback accepts.
+ * @returns {Function} Returns a callback function.
+ * @example
+ *
+ * var characters = [
+ * { 'name': 'barney', 'age': 36 },
+ * { 'name': 'fred', 'age': 40 }
+ * ];
+ *
+ * // wrap to create custom callback shorthands
+ * _.createCallback = _.wrap(_.createCallback, function(func, callback, thisArg) {
+ * var match = /^(.+?)__([gl]t)(.+)$/.exec(callback);
+ * return !match ? func(callback, thisArg) : function(object) {
+ * return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3];
+ * };
+ * });
+ *
+ * _.filter(characters, 'age__gt38');
+ * // => [{ 'name': 'fred', 'age': 40 }]
+ */
+ function createCallback(func, thisArg, argCount) {
+ var type = typeof func;
+ if (func == null || type == 'function') {
+ return baseCreateCallback(func, thisArg, argCount);
+ }
+ // handle "_.pluck" style callback shorthands
+ if (type != 'object') {
+ return property(func);
+ }
+ var props = keys(func),
+ key = props[0],
+ a = func[key];
+
+ // handle "_.where" style callback shorthands
+ if (props.length == 1 && a === a && !isObject(a)) {
+ // fast path the common case of providing an object with a single
+ // property containing a primitive value
+ return function(object) {
+ var b = object[key];
+ return a === b && (a !== 0 || (1 / a == 1 / b));
+ };
+ }
+ return function(object) {
+ var length = props.length,
+ result = false;
+
+ while (length--) {
+ if (!(result = baseIsEqual(object[props[length]], func[props[length]], null, true))) {
+ break;
+ }
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their
+ * corresponding HTML entities.
+ *
+ * @static
+ * @memberOf _
+ * @category Utilities
+ * @param {string} string The string to escape.
+ * @returns {string} Returns the escaped string.
+ * @example
+ *
+ * _.escape('Fred, Wilma, & Pebbles');
+ * // => 'Fred, Wilma, &amp; Pebbles'
+ */
+ function escape(string) {
+ return string == null ? '' : String(string).replace(reUnescapedHtml, escapeHtmlChar);
+ }
+
+ /**
+ * This method returns the first argument provided to it.
+ *
+ * @static
+ * @memberOf _
+ * @category Utilities
+ * @param {*} value Any value.
+ * @returns {*} Returns `value`.
+ * @example
+ *
+ * var object = { 'name': 'fred' };
+ * _.identity(object) === object;
+ * // => true
+ */
+ function identity(value) {
+ return value;
+ }
+
+ /**
+ * Adds function properties of a source object to the destination object.
+ * If `object` is a function methods will be added to its prototype as well.
+ *
+ * @static
+ * @memberOf _
+ * @category Utilities
+ * @param {Function|Object} [object=lodash] object The destination object.
+ * @param {Object} source The object of functions to add.
+ * @param {Object} [options] The options object.
+ * @param {boolean} [options.chain=true] Specify whether the functions added are chainable.
+ * @example
+ *
+ * function capitalize(string) {
+ * return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
+ * }
+ *
+ * _.mixin({ 'capitalize': capitalize });
+ * _.capitalize('fred');
+ * // => 'Fred'
+ *
+ * _('fred').capitalize().value();
+ * // => 'Fred'
+ *
+ * _.mixin({ 'capitalize': capitalize }, { 'chain': false });
+ * _('fred').capitalize();
+ * // => 'Fred'
+ */
+ function mixin(object, source, options) {
+ var chain = true,
+ methodNames = source && functions(source);
+
+ if (!source || (!options && !methodNames.length)) {
+ if (options == null) {
+ options = source;
+ }
+ ctor = lodashWrapper;
+ source = object;
+ object = lodash;
+ methodNames = functions(source);
+ }
+ if (options === false) {
+ chain = false;
+ } else if (isObject(options) && 'chain' in options) {
+ chain = options.chain;
+ }
+ var ctor = object,
+ isFunc = isFunction(ctor);
+
+ forEach(methodNames, function(methodName) {
+ var func = object[methodName] = source[methodName];
+ if (isFunc) {
+ ctor.prototype[methodName] = function() {
+ var chainAll = this.__chain__,
+ value = this.__wrapped__,
+ args = [value];
+
+ push.apply(args, arguments);
+ var result = func.apply(object, args);
+ if (chain || chainAll) {
+ if (value === result && isObject(result)) {
+ return this;
+ }
+ result = new ctor(result);
+ result.__chain__ = chainAll;
+ }
+ return result;
+ };
+ }
+ });
+ }
+
+ /**
+ * Reverts the '_' variable to its previous value and returns a reference to
+ * the `lodash` function.
+ *
+ * @static
+ * @memberOf _
+ * @category Utilities
+ * @returns {Function} Returns the `lodash` function.
+ * @example
+ *
+ * var lodash = _.noConflict();
+ */
+ function noConflict() {
+ context._ = oldDash;
+ return this;
+ }
+
+ /**
+ * A no-operation function.
+ *
+ * @static
+ * @memberOf _
+ * @category Utilities
+ * @example
+ *
+ * var object = { 'name': 'fred' };
+ * _.noop(object) === undefined;
+ * // => true
+ */
+ function noop() {
+ // no operation performed
+ }
+
+ /**
+ * Gets the number of milliseconds that have elapsed since the Unix epoch
+ * (1 January 1970 00:00:00 UTC).
+ *
+ * @static
+ * @memberOf _
+ * @category Utilities
+ * @example
+ *
+ * var stamp = _.now();
+ * _.defer(function() { console.log(_.now() - stamp); });
+ * // => logs the number of milliseconds it took for the deferred function to be called
+ */
+ var now = isNative(now = Date.now) && now || function() {
+ return new Date().getTime();
+ };
+
+ /**
+ * Converts the given value into an integer of the specified radix.
+ * If `radix` is `undefined` or `0` a `radix` of `10` is used unless the
+ * `value` is a hexadecimal, in which case a `radix` of `16` is used.
+ *
+ * Note: This method avoids differences in native ES3 and ES5 `parseInt`
+ * implementations. See http://es5.github.io/#E.
+ *
+ * @static
+ * @memberOf _
+ * @category Utilities
+ * @param {string} value The value to parse.
+ * @param {number} [radix] The radix used to interpret the value to parse.
+ * @returns {number} Returns the new integer value.
+ * @example
+ *
+ * _.parseInt('08');
+ * // => 8
+ */
+ var parseInt = nativeParseInt(whitespace + '08') == 8 ? nativeParseInt : function(value, radix) {
+ // Firefox < 21 and Opera < 15 follow the ES3 specified implementation of `parseInt`
+ return nativeParseInt(isString(value) ? value.replace(reLeadingSpacesAndZeros, '') : value, radix || 0);
+ };
+
+ /**
+ * Creates a "_.pluck" style function, which returns the `key` value of a
+ * given object.
+ *
+ * @static
+ * @memberOf _
+ * @category Utilities
+ * @param {string} key The name of the property to retrieve.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var characters = [
+ * { 'name': 'fred', 'age': 40 },
+ * { 'name': 'barney', 'age': 36 }
+ * ];
+ *
+ * var getName = _.property('name');
+ *
+ * _.map(characters, getName);
+ * // => ['barney', 'fred']
+ *
+ * _.sortBy(characters, getName);
+ * // => [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }]
+ */
+ function property(key) {
+ return function(object) {
+ return object[key];
+ };
+ }
+
+ /**
+ * Produces a random number between `min` and `max` (inclusive). If only one
+ * argument is provided a number between `0` and the given number will be
+ * returned. If `floating` is truey or either `min` or `max` are floats a
+ * floating-point number will be returned instead of an integer.
+ *
+ * @static
+ * @memberOf _
+ * @category Utilities
+ * @param {number} [min=0] The minimum possible value.
+ * @param {number} [max=1] The maximum possible value.
+ * @param {boolean} [floating=false] Specify returning a floating-point number.
+ * @returns {number} Returns a random number.
+ * @example
+ *
+ * _.random(0, 5);
+ * // => an integer between 0 and 5
+ *
+ * _.random(5);
+ * // => also an integer between 0 and 5
+ *
+ * _.random(5, true);
+ * // => a floating-point number between 0 and 5
+ *
+ * _.random(1.2, 5.2);
+ * // => a floating-point number between 1.2 and 5.2
+ */
+ function random(min, max, floating) {
+ var noMin = min == null,
+ noMax = max == null;
+
+ if (floating == null) {
+ if (typeof min == 'boolean' && noMax) {
+ floating = min;
+ min = 1;
+ }
+ else if (!noMax && typeof max == 'boolean') {
+ floating = max;
+ noMax = true;
+ }
+ }
+ if (noMin && noMax) {
+ max = 1;
+ }
+ min = +min || 0;
+ if (noMax) {
+ max = min;
+ min = 0;
+ } else {
+ max = +max || 0;
+ }
+ if (floating || min % 1 || max % 1) {
+ var rand = nativeRandom();
+ return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1)))), max);
+ }
+ return baseRandom(min, max);
+ }
+
+ /**
+ * Resolves the value of property `key` on `object`. If `key` is a function
+ * it will be invoked with the `this` binding of `object` and its result returned,
+ * else the property value is returned. If `object` is falsey then `undefined`
+ * is returned.
+ *
+ * @static
+ * @memberOf _
+ * @category Utilities
+ * @param {Object} object The object to inspect.
+ * @param {string} key The name of the property to resolve.
+ * @returns {*} Returns the resolved value.
+ * @example
+ *
+ * var object = {
+ * 'cheese': 'crumpets',
+ * 'stuff': function() {
+ * return 'nonsense';
+ * }
+ * };
+ *
+ * _.result(object, 'cheese');
+ * // => 'crumpets'
+ *
+ * _.result(object, 'stuff');
+ * // => 'nonsense'
+ */
+ function result(object, key) {
+ if (object) {
+ var value = object[key];
+ return isFunction(value) ? object[key]() : value;
+ }
+ }
+
+ /**
+ * A micro-templating method that handles arbitrary delimiters, preserves
+ * whitespace, and correctly escapes quotes within interpolated code.
+ *
+ * Note: In the development build, `_.template` utilizes sourceURLs for easier
+ * debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
+ *
+ * For more information on precompiling templates see:
+ * http://lodash.com/custom-builds
+ *
+ * For more information on Chrome extension sandboxes see:
+ * http://developer.chrome.com/stable/extensions/sandboxingEval.html
+ *
+ * @static
+ * @memberOf _
+ * @category Utilities
+ * @param {string} text The template text.
+ * @param {Object} data The data object used to populate the text.
+ * @param {Object} [options] The options object.
+ * @param {RegExp} [options.escape] The "escape" delimiter.
+ * @param {RegExp} [options.evaluate] The "evaluate" delimiter.
+ * @param {Object} [options.imports] An object to import into the template as local variables.
+ * @param {RegExp} [options.interpolate] The "interpolate" delimiter.
+ * @param {string} [sourceURL] The sourceURL of the template's compiled source.
+ * @param {string} [variable] The data object variable name.
+ * @returns {Function|string} Returns a compiled function when no `data` object
+ * is given, else it returns the interpolated text.
+ * @example
+ *
+ * // using the "interpolate" delimiter to create a compiled template
+ * var compiled = _.template('hello <%= name %>');
+ * compiled({ 'name': 'fred' });
+ * // => 'hello fred'
+ *
+ * // using the "escape" delimiter to escape HTML in data property values
+ * _.template('<b><%- value %></b>', { 'value': '<script>' });
+ * // => '<b>&lt;script&gt;</b>'
+ *
+ * // using the "evaluate" delimiter to generate HTML
+ * var list = '<% _.forEach(people, function(name) { %><li><%- name %></li><% }); %>';
+ * _.template(list, { 'people': ['fred', 'barney'] });
+ * // => '<li>fred</li><li>barney</li>'
+ *
+ * // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
+ * _.template('hello ${ name }', { 'name': 'pebbles' });
+ * // => 'hello pebbles'
+ *
+ * // using the internal `print` function in "evaluate" delimiters
+ * _.template('<% print("hello " + name); %>!', { 'name': 'barney' });
+ * // => 'hello barney!'
+ *
+ * // using a custom template delimiters
+ * _.templateSettings = {
+ * 'interpolate': /{{([\s\S]+?)}}/g
+ * };
+ *
+ * _.template('hello {{ name }}!', { 'name': 'mustache' });
+ * // => 'hello mustache!'
+ *
+ * // using the `imports` option to import jQuery
+ * var list = '<% jq.each(people, function(name) { %><li><%- name %></li><% }); %>';
+ * _.template(list, { 'people': ['fred', 'barney'] }, { 'imports': { 'jq': jQuery } });
+ * // => '<li>fred</li><li>barney</li>'
+ *
+ * // using the `sourceURL` option to specify a custom sourceURL for the template
+ * var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' });
+ * compiled(data);
+ * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
+ *
+ * // using the `variable` option to ensure a with-statement isn't used in the compiled template
+ * var compiled = _.template('hi <%= data.name %>!', null, { 'variable': 'data' });
+ * compiled.source;
+ * // => function(data) {
+ * var __t, __p = '', __e = _.escape;
+ * __p += 'hi ' + ((__t = ( data.name )) == null ? '' : __t) + '!';
+ * return __p;
+ * }
+ *
+ * // using the `source` property to inline compiled templates for meaningful
+ * // line numbers in error messages and a stack trace
+ * fs.writeFileSync(path.join(cwd, 'jst.js'), '\
+ * var JST = {\
+ * "main": ' + _.template(mainText).source + '\
+ * };\
+ * ');
+ */
+ function template(text, data, options) {
+ // based on John Resig's `tmpl` implementation
+ // http://ejohn.org/blog/javascript-micro-templating/
+ // and Laura Doktorova's doT.js
+ // https://github.com/olado/doT
+ var settings = lodash.templateSettings;
+ text = String(text || '');
+
+ // avoid missing dependencies when `iteratorTemplate` is not defined
+ options = defaults({}, options, settings);
+
+ var imports = defaults({}, options.imports, settings.imports),
+ importsKeys = keys(imports),
+ importsValues = values(imports);
+
+ var isEvaluating,
+ index = 0,
+ interpolate = options.interpolate || reNoMatch,
+ source = "__p += '";
+
+ // compile the regexp to match each delimiter
+ var reDelimiters = RegExp(
+ (options.escape || reNoMatch).source + '|' +
+ interpolate.source + '|' +
+ (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
+ (options.evaluate || reNoMatch).source + '|$'
+ , 'g');
+
+ text.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
+ interpolateValue || (interpolateValue = esTemplateValue);
+
+ // escape characters that cannot be included in string literals
+ source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar);
+
+ // replace delimiters with snippets
+ if (escapeValue) {
+ source += "' +\n__e(" + escapeValue + ") +\n'";
+ }
+ if (evaluateValue) {
+ isEvaluating = true;
+ source += "';\n" + evaluateValue + ";\n__p += '";
+ }
+ if (interpolateValue) {
+ source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
+ }
+ index = offset + match.length;
+
+ // the JS engine embedded in Adobe products requires returning the `match`
+ // string in order to produce the correct `offset` value
+ return match;
+ });
+
+ source += "';\n";
+
+ // if `variable` is not specified, wrap a with-statement around the generated
+ // code to add the data object to the top of the scope chain
+ var variable = options.variable,
+ hasVariable = variable;
+
+ if (!hasVariable) {
+ variable = 'obj';
+ source = 'with (' + variable + ') {\n' + source + '\n}\n';
+ }
+ // cleanup code by stripping empty strings
+ source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
+ .replace(reEmptyStringMiddle, '$1')
+ .replace(reEmptyStringTrailing, '$1;');
+
+ // frame code as the function body
+ source = 'function(' + variable + ') {\n' +
+ (hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') +
+ "var __t, __p = '', __e = _.escape" +
+ (isEvaluating
+ ? ', __j = Array.prototype.join;\n' +
+ "function print() { __p += __j.call(arguments, '') }\n"
+ : ';\n'
+ ) +
+ source +
+ 'return __p\n}';
+
+ // Use a sourceURL for easier debugging.
+ // http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
+ var sourceURL = '\n/*\n//# sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']') + '\n*/';
+
+ try {
+ var result = Function(importsKeys, 'return ' + source + sourceURL).apply(undefined, importsValues);
+ } catch(e) {
+ e.source = source;
+ throw e;
+ }
+ if (data) {
+ return result(data);
+ }
+ // provide the compiled function's source by its `toString` method, in
+ // supported environments, or the `source` property as a convenience for
+ // inlining compiled templates during the build process
+ result.source = source;
+ return result;
+ }
+
+ /**
+ * Executes the callback `n` times, returning an array of the results
+ * of each callback execution. The callback is bound to `thisArg` and invoked
+ * with one argument; (index).
+ *
+ * @static
+ * @memberOf _
+ * @category Utilities
+ * @param {number} n The number of times to execute the callback.
+ * @param {Function} callback The function called per iteration.
+ * @param {*} [thisArg] The `this` binding of `callback`.
+ * @returns {Array} Returns an array of the results of each `callback` execution.
+ * @example
+ *
+ * var diceRolls = _.times(3, _.partial(_.random, 1, 6));
+ * // => [3, 6, 4]
+ *
+ * _.times(3, function(n) { mage.castSpell(n); });
+ * // => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, and `2` respectively
+ *
+ * _.times(3, function(n) { this.cast(n); }, mage);
+ * // => also calls `mage.castSpell(n)` three times
+ */
+ function times(n, callback, thisArg) {
+ n = (n = +n) > -1 ? n : 0;
+ var index = -1,
+ result = Array(n);
+
+ callback = baseCreateCallback(callback, thisArg, 1);
+ while (++index < n) {
+ result[index] = callback(index);
+ }
+ return result;
+ }
+
+ /**
+ * The inverse of `_.escape` this method converts the HTML entities
+ * `&amp;`, `&lt;`, `&gt;`, `&quot;`, and `&#39;` in `string` to their
+ * corresponding characters.
+ *
+ * @static
+ * @memberOf _
+ * @category Utilities
+ * @param {string} string The string to unescape.
+ * @returns {string} Returns the unescaped string.
+ * @example
+ *
+ * _.unescape('Fred, Barney &amp; Pebbles');
+ * // => 'Fred, Barney & Pebbles'
+ */
+ function unescape(string) {
+ return string == null ? '' : String(string).replace(reEscapedHtml, unescapeHtmlChar);
+ }
+
+ /**
+ * Generates a unique ID. If `prefix` is provided the ID will be appended to it.
+ *
+ * @static
+ * @memberOf _
+ * @category Utilities
+ * @param {string} [prefix] The value to prefix the ID with.
+ * @returns {string} Returns the unique ID.
+ * @example
+ *
+ * _.uniqueId('contact_');
+ * // => 'contact_104'
+ *
+ * _.uniqueId();
+ * // => '105'
+ */
+ function uniqueId(prefix) {
+ var id = ++idCounter;
+ return String(prefix == null ? '' : prefix) + id;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Creates a `lodash` object that wraps the given value with explicit
+ * method chaining enabled.
+ *
+ * @static
+ * @memberOf _
+ * @category Chaining
+ * @param {*} value The value to wrap.
+ * @returns {Object} Returns the wrapper object.
+ * @example
+ *
+ * var characters = [
+ * { 'name': 'barney', 'age': 36 },
+ * { 'name': 'fred', 'age': 40 },
+ * { 'name': 'pebbles', 'age': 1 }
+ * ];
+ *
+ * var youngest = _.chain(characters)
+ * .sortBy('age')
+ * .map(function(chr) { return chr.name + ' is ' + chr.age; })
+ * .first()
+ * .value();
+ * // => 'pebbles is 1'
+ */
+ function chain(value) {
+ value = new lodashWrapper(value);
+ value.__chain__ = true;
+ return value;
+ }
+
+ /**
+ * Invokes `interceptor` with the `value` as the first argument and then
+ * returns `value`. The purpose of this method is to "tap into" a method
+ * chain in order to perform operations on intermediate results within
+ * the chain.
+ *
+ * @static
+ * @memberOf _
+ * @category Chaining
+ * @param {*} value The value to provide to `interceptor`.
+ * @param {Function} interceptor The function to invoke.
+ * @returns {*} Returns `value`.
+ * @example
+ *
+ * _([1, 2, 3, 4])
+ * .tap(function(array) { array.pop(); })
+ * .reverse()
+ * .value();
+ * // => [3, 2, 1]
+ */
+ function tap(value, interceptor) {
+ interceptor(value);
+ return value;
+ }
+
+ /**
+ * Enables explicit method chaining on the wrapper object.
+ *
+ * @name chain
+ * @memberOf _
+ * @category Chaining
+ * @returns {*} Returns the wrapper object.
+ * @example
+ *
+ * var characters = [
+ * { 'name': 'barney', 'age': 36 },
+ * { 'name': 'fred', 'age': 40 }
+ * ];
+ *
+ * // without explicit chaining
+ * _(characters).first();
+ * // => { 'name': 'barney', 'age': 36 }
+ *
+ * // with explicit chaining
+ * _(characters).chain()
+ * .first()
+ * .pick('age')
+ * .value();
+ * // => { 'age': 36 }
+ */
+ function wrapperChain() {
+ this.__chain__ = true;
+ return this;
+ }
+
+ /**
+ * Produces the `toString` result of the wrapped value.
+ *
+ * @name toString
+ * @memberOf _
+ * @category Chaining
+ * @returns {string} Returns the string result.
+ * @example
+ *
+ * _([1, 2, 3]).toString();
+ * // => '1,2,3'
+ */
+ function wrapperToString() {
+ return String(this.__wrapped__);
+ }
+
+ /**
+ * Extracts the wrapped value.
+ *
+ * @name valueOf
+ * @memberOf _
+ * @alias value
+ * @category Chaining
+ * @returns {*} Returns the wrapped value.
+ * @example
+ *
+ * _([1, 2, 3]).valueOf();
+ * // => [1, 2, 3]
+ */
+ function wrapperValueOf() {
+ return this.__wrapped__;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ // add functions that return wrapped values when chaining
+ lodash.after = after;
+ lodash.assign = assign;
+ lodash.at = at;
+ lodash.bind = bind;
+ lodash.bindAll = bindAll;
+ lodash.bindKey = bindKey;
+ lodash.chain = chain;
+ lodash.compact = compact;
+ lodash.compose = compose;
+ lodash.constant = constant;
+ lodash.countBy = countBy;
+ lodash.create = create;
+ lodash.createCallback = createCallback;
+ lodash.curry = curry;
+ lodash.debounce = debounce;
+ lodash.defaults = defaults;
+ lodash.defer = defer;
+ lodash.delay = delay;
+ lodash.difference = difference;
+ lodash.filter = filter;
+ lodash.flatten = flatten;
+ lodash.forEach = forEach;
+ lodash.forEachRight = forEachRight;
+ lodash.forIn = forIn;
+ lodash.forInRight = forInRight;
+ lodash.forOwn = forOwn;
+ lodash.forOwnRight = forOwnRight;
+ lodash.functions = functions;
+ lodash.groupBy = groupBy;
+ lodash.indexBy = indexBy;
+ lodash.initial = initial;
+ lodash.intersection = intersection;
+ lodash.invert = invert;
+ lodash.invoke = invoke;
+ lodash.keys = keys;
+ lodash.map = map;
+ lodash.mapValues = mapValues;
+ lodash.max = max;
+ lodash.memoize = memoize;
+ lodash.merge = merge;
+ lodash.min = min;
+ lodash.omit = omit;
+ lodash.once = once;
+ lodash.pairs = pairs;
+ lodash.partial = partial;
+ lodash.partialRight = partialRight;
+ lodash.pick = pick;
+ lodash.pluck = pluck;
+ lodash.property = property;
+ lodash.pull = pull;
+ lodash.range = range;
+ lodash.reject = reject;
+ lodash.remove = remove;
+ lodash.rest = rest;
+ lodash.shuffle = shuffle;
+ lodash.sortBy = sortBy;
+ lodash.tap = tap;
+ lodash.throttle = throttle;
+ lodash.times = times;
+ lodash.toArray = toArray;
+ lodash.transform = transform;
+ lodash.union = union;
+ lodash.uniq = uniq;
+ lodash.values = values;
+ lodash.where = where;
+ lodash.without = without;
+ lodash.wrap = wrap;
+ lodash.xor = xor;
+ lodash.zip = zip;
+ lodash.zipObject = zipObject;
+
+ // add aliases
+ lodash.collect = map;
+ lodash.drop = rest;
+ lodash.each = forEach;
+ lodash.eachRight = forEachRight;
+ lodash.extend = assign;
+ lodash.methods = functions;
+ lodash.object = zipObject;
+ lodash.select = filter;
+ lodash.tail = rest;
+ lodash.unique = uniq;
+ lodash.unzip = zip;
+
+ // add functions to `lodash.prototype`
+ mixin(lodash);
+
+ /*--------------------------------------------------------------------------*/
+
+ // add functions that return unwrapped values when chaining
+ lodash.clone = clone;
+ lodash.cloneDeep = cloneDeep;
+ lodash.contains = contains;
+ lodash.escape = escape;
+ lodash.every = every;
+ lodash.find = find;
+ lodash.findIndex = findIndex;
+ lodash.findKey = findKey;
+ lodash.findLast = findLast;
+ lodash.findLastIndex = findLastIndex;
+ lodash.findLastKey = findLastKey;
+ lodash.has = has;
+ lodash.identity = identity;
+ lodash.indexOf = indexOf;
+ lodash.isArguments = isArguments;
+ lodash.isArray = isArray;
+ lodash.isBoolean = isBoolean;
+ lodash.isDate = isDate;
+ lodash.isElement = isElement;
+ lodash.isEmpty = isEmpty;
+ lodash.isEqual = isEqual;
+ lodash.isFinite = isFinite;
+ lodash.isFunction = isFunction;
+ lodash.isNaN = isNaN;
+ lodash.isNull = isNull;
+ lodash.isNumber = isNumber;
+ lodash.isObject = isObject;
+ lodash.isPlainObject = isPlainObject;
+ lodash.isRegExp = isRegExp;
+ lodash.isString = isString;
+ lodash.isUndefined = isUndefined;
+ lodash.lastIndexOf = lastIndexOf;
+ lodash.mixin = mixin;
+ lodash.noConflict = noConflict;
+ lodash.noop = noop;
+ lodash.now = now;
+ lodash.parseInt = parseInt;
+ lodash.random = random;
+ lodash.reduce = reduce;
+ lodash.reduceRight = reduceRight;
+ lodash.result = result;
+ lodash.runInContext = runInContext;
+ lodash.size = size;
+ lodash.some = some;
+ lodash.sortedIndex = sortedIndex;
+ lodash.template = template;
+ lodash.unescape = unescape;
+ lodash.uniqueId = uniqueId;
+
+ // add aliases
+ lodash.all = every;
+ lodash.any = some;
+ lodash.detect = find;
+ lodash.findWhere = find;
+ lodash.foldl = reduce;
+ lodash.foldr = reduceRight;
+ lodash.include = contains;
+ lodash.inject = reduce;
+
+ mixin(function() {
+ var source = {}
+ forOwn(lodash, function(func, methodName) {
+ if (!lodash.prototype[methodName]) {
+ source[methodName] = func;
+ }
+ });
+ return source;
+ }(), false);
+
+ /*--------------------------------------------------------------------------*/
+
+ // add functions capable of returning wrapped and unwrapped values when chaining
+ lodash.first = first;
+ lodash.last = last;
+ lodash.sample = sample;
+
+ // add aliases
+ lodash.take = first;
+ lodash.head = first;
+
+ forOwn(lodash, function(func, methodName) {
+ var callbackable = methodName !== 'sample';
+ if (!lodash.prototype[methodName]) {
+ lodash.prototype[methodName]= function(n, guard) {
+ var chainAll = this.__chain__,
+ result = func(this.__wrapped__, n, guard);
+
+ return !chainAll && (n == null || (guard && !(callbackable && typeof n == 'function')))
+ ? result
+ : new lodashWrapper(result, chainAll);
+ };
+ }
+ });
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * The semantic version number.
+ *
+ * @static
+ * @memberOf _
+ * @type string
+ */
+ lodash.VERSION = '2.4.1';
+
+ // add "Chaining" functions to the wrapper
+ lodash.prototype.chain = wrapperChain;
+ lodash.prototype.toString = wrapperToString;
+ lodash.prototype.value = wrapperValueOf;
+ lodash.prototype.valueOf = wrapperValueOf;
+
+ // add `Array` functions that return unwrapped values
+ forEach(['join', 'pop', 'shift'], function(methodName) {
+ var func = arrayRef[methodName];
+ lodash.prototype[methodName] = function() {
+ var chainAll = this.__chain__,
+ result = func.apply(this.__wrapped__, arguments);
+
+ return chainAll
+ ? new lodashWrapper(result, chainAll)
+ : result;
+ };
+ });
+
+ // add `Array` functions that return the existing wrapped value
+ forEach(['push', 'reverse', 'sort', 'unshift'], function(methodName) {
+ var func = arrayRef[methodName];
+ lodash.prototype[methodName] = function() {
+ func.apply(this.__wrapped__, arguments);
+ return this;
+ };
+ });
+
+ // add `Array` functions that return new wrapped values
+ forEach(['concat', 'slice', 'splice'], function(methodName) {
+ var func = arrayRef[methodName];
+ lodash.prototype[methodName] = function() {
+ return new lodashWrapper(func.apply(this.__wrapped__, arguments), this.__chain__);
+ };
+ });
+
+ return lodash;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ // expose Lo-Dash
+ var _ = runInContext();
+
+ // some AMD build optimizers like r.js check for condition patterns like the following:
+ if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
+ // Expose Lo-Dash to the global object even when an AMD loader is present in
+ // case Lo-Dash is loaded with a RequireJS shim config.
+ // See http://requirejs.org/docs/api.html#config-shim
+ root._ = _;
+
+ // define as an anonymous module so, through path mapping, it can be
+ // referenced as the "underscore" module
+ define(function() {
+ return _;
+ });
+ }
+ // check for `exports` after `define` in case a build optimizer adds an `exports` object
+ else if (freeExports && freeModule) {
+ // in Node.js or RingoJS
+ if (moduleExports) {
+ (freeModule.exports = _)._ = _;
+ }
+ // in Narwhal or Rhino -require
+ else {
+ freeExports._ = _;
+ }
+ }
+ else {
+ // in a browser or Rhino
+ root._ = _;
+ }
+}.call(this));
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+},{}],"react-router":[function(require,module,exports){
+exports.DefaultRoute = require('./components/DefaultRoute');
+exports.Link = require('./components/Link');
+exports.NotFoundRoute = require('./components/NotFoundRoute');
+exports.Redirect = require('./components/Redirect');
+exports.Route = require('./components/Route');
+exports.RouteHandler = require('./components/RouteHandler');
+
+exports.HashLocation = require('./locations/HashLocation');
+exports.HistoryLocation = require('./locations/HistoryLocation');
+exports.RefreshLocation = require('./locations/RefreshLocation');
+
+exports.ImitateBrowserBehavior = require('./behaviors/ImitateBrowserBehavior');
+exports.ScrollToTopBehavior = require('./behaviors/ScrollToTopBehavior');
+
+exports.Navigation = require('./mixins/Navigation');
+exports.State = require('./mixins/State');
+
+exports.create = require('./utils/createRouter');
+exports.run = require('./utils/runRouter');
+
+exports.History = require('./utils/History');
+
+},{"./behaviors/ImitateBrowserBehavior":7,"./behaviors/ScrollToTopBehavior":8,"./components/DefaultRoute":9,"./components/Link":10,"./components/NotFoundRoute":11,"./components/Redirect":12,"./components/Route":13,"./components/RouteHandler":14,"./locations/HashLocation":15,"./locations/HistoryLocation":16,"./locations/RefreshLocation":17,"./mixins/Navigation":19,"./mixins/State":23,"./utils/History":26,"./utils/createRouter":32,"./utils/runRouter":36}],"react/addons":[function(require,module,exports){
+module.exports = require('./lib/ReactWithAddons');
+
+},{"./lib/ReactWithAddons":138}],"react":[function(require,module,exports){
+module.exports = require('./lib/React');
+
+},{"./lib/React":77}]},{},["jquery","lodash","react","react-router","react/addons"])
+//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnVmZmVyL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9ub2RlX21vZHVsZXMvYmFzZTY0LWpzL2xpYi9iNjQuanMiLCJub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnVmZmVyL25vZGVfbW9kdWxlcy9pZWVlNzU0L2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9ub2RlX21vZHVsZXMvaXMtYXJyYXkvaW5kZXguanMiLCJub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvcHJvY2Vzcy9icm93c2VyLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0LXJvdXRlci9tb2R1bGVzL2FjdGlvbnMvTG9jYXRpb25BY3Rpb25zLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0LXJvdXRlci9tb2R1bGVzL2JlaGF2aW9ycy9JbWl0YXRlQnJvd3NlckJlaGF2aW9yLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0LXJvdXRlci9tb2R1bGVzL2JlaGF2aW9ycy9TY3JvbGxUb1RvcEJlaGF2aW9yLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0LXJvdXRlci9tb2R1bGVzL2NvbXBvbmVudHMvRGVmYXVsdFJvdXRlLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0LXJvdXRlci9tb2R1bGVzL2NvbXBvbmVudHMvTGluay5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC1yb3V0ZXIvbW9kdWxlcy9jb21wb25lbnRzL05vdEZvdW5kUm91dGUuanMiLCJub2RlX21vZHVsZXMvcmVhY3Qtcm91dGVyL21vZHVsZXMvY29tcG9uZW50cy9SZWRpcmVjdC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC1yb3V0ZXIvbW9kdWxlcy9jb21wb25lbnRzL1JvdXRlLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0LXJvdXRlci9tb2R1bGVzL2NvbXBvbmVudHMvUm91dGVIYW5kbGVyLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0LXJvdXRlci9tb2R1bGVzL2xvY2F0aW9ucy9IYXNoTG9jYXRpb24uanMiLCJub2RlX21vZHVsZXMvcmVhY3Qtcm91dGVyL21vZHVsZXMvbG9jYXRpb25zL0hpc3RvcnlMb2NhdGlvbi5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC1yb3V0ZXIvbW9kdWxlcy9sb2NhdGlvbnMvUmVmcmVzaExvY2F0aW9uLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0LXJvdXRlci9tb2R1bGVzL21peGlucy9GYWtlTm9kZS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC1yb3V0ZXIvbW9kdWxlcy9taXhpbnMvTmF2aWdhdGlvbi5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC1yb3V0ZXIvbW9kdWxlcy9taXhpbnMvTmF2aWdhdGlvbkNvbnRleHQuanMiLCJub2RlX21vZHVsZXMvcmVhY3Qtcm91dGVyL21vZHVsZXMvbWl4aW5zL1JvdXRlSGFuZGxlci5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC1yb3V0ZXIvbW9kdWxlcy9taXhpbnMvU2Nyb2xsaW5nLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0LXJvdXRlci9tb2R1bGVzL21peGlucy9TdGF0ZS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC1yb3V0ZXIvbW9kdWxlcy9taXhpbnMvU3RhdGVDb250ZXh0LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0LXJvdXRlci9tb2R1bGVzL3V0aWxzL0NhbmNlbGxhdGlvbi5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC1yb3V0ZXIvbW9kdWxlcy91dGlscy9IaXN0b3J5LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0LXJvdXRlci9tb2R1bGVzL3V0aWxzL1BhdGguanMiLCJub2RlX21vZHVsZXMvcmVhY3Qtcm91dGVyL21vZHVsZXMvdXRpbHMvUHJvbWlzZS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC1yb3V0ZXIvbW9kdWxlcy91dGlscy9Qcm9wVHlwZXMuanMiLCJub2RlX21vZHVsZXMvcmVhY3Qtcm91dGVyL21vZHVsZXMvdXRpbHMvUmVkaXJlY3QuanMiLCJub2RlX21vZHVsZXMvcmVhY3Qtcm91dGVyL21vZHVsZXMvdXRpbHMvVHJhbnNpdGlvbi5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC1yb3V0ZXIvbW9kdWxlcy91dGlscy9jcmVhdGVSb3V0ZXIuanMiLCJub2RlX21vZHVsZXMvcmVhY3Qtcm91dGVyL21vZHVsZXMvdXRpbHMvY3JlYXRlUm91dGVzRnJvbUNoaWxkcmVuLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0LXJvdXRlci9tb2R1bGVzL3V0aWxzL2dldFdpbmRvd1Njcm9sbFBvc2l0aW9uLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0LXJvdXRlci9tb2R1bGVzL3V0aWxzL3JldmVyc2VkQXJyYXkuanMiLCJub2RlX21vZHVsZXMvcmVhY3Qtcm91dGVyL21vZHVsZXMvdXRpbHMvcnVuUm91dGVyLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0LXJvdXRlci9tb2R1bGVzL3V0aWxzL3N1cHBvcnRzSGlzdG9yeS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC1yb3V0ZXIvbm9kZV9tb2R1bGVzL3FzL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0LXJvdXRlci9ub2RlX21vZHVsZXMvcXMvbGliL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0LXJvdXRlci9ub2RlX21vZHVsZXMvcXMvbGliL3BhcnNlLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0LXJvdXRlci9ub2RlX21vZHVsZXMvcXMvbGliL3N0cmluZ2lmeS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC1yb3V0ZXIvbm9kZV9tb2R1bGVzL3FzL2xpYi91dGlscy5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC1yb3V0ZXIvbm9kZV9tb2R1bGVzL3doZW4vbGliL1Byb21pc2UuanMiLCJub2RlX21vZHVsZXMvcmVhY3Qtcm91dGVyL25vZGVfbW9kdWxlcy93aGVuL2xpYi9RdWV1ZS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC1yb3V0ZXIvbm9kZV9tb2R1bGVzL3doZW4vbGliL1NjaGVkdWxlci5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC1yb3V0ZXIvbm9kZV9tb2R1bGVzL3doZW4vbGliL2FzeW5jLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0LXJvdXRlci9ub2RlX21vZHVsZXMvd2hlbi9saWIvbWFrZVByb21pc2UuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL0F1dG9Gb2N1c01peGluLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9CZWZvcmVJbnB1dEV2ZW50UGx1Z2luLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9DU1NDb3JlLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9DU1NQcm9wZXJ0eS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvQ1NTUHJvcGVydHlPcGVyYXRpb25zLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9DYWxsYmFja1F1ZXVlLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9DaGFuZ2VFdmVudFBsdWdpbi5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvQ2xpZW50UmVhY3RSb290SW5kZXguanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL0NvbXBvc2l0aW9uRXZlbnRQbHVnaW4uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL0RPTUNoaWxkcmVuT3BlcmF0aW9ucy5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvRE9NUHJvcGVydHkuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL0RPTVByb3BlcnR5T3BlcmF0aW9ucy5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvRGFuZ2VyLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9EZWZhdWx0RXZlbnRQbHVnaW5PcmRlci5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvRW50ZXJMZWF2ZUV2ZW50UGx1Z2luLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9FdmVudENvbnN0YW50cy5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvRXZlbnRMaXN0ZW5lci5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvRXZlbnRQbHVnaW5IdWIuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL0V2ZW50UGx1Z2luUmVnaXN0cnkuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL0V2ZW50UGx1Z2luVXRpbHMuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL0V2ZW50UHJvcGFnYXRvcnMuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL0V4ZWN1dGlvbkVudmlyb25tZW50LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9IVE1MRE9NUHJvcGVydHlDb25maWcuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL0xpbmtlZFN0YXRlTWl4aW4uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL0xpbmtlZFZhbHVlVXRpbHMuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL0xvY2FsRXZlbnRUcmFwTWl4aW4uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL01vYmlsZVNhZmFyaUNsaWNrRXZlbnRQbHVnaW4uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL09iamVjdC5hc3NpZ24uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1Bvb2xlZENsYXNzLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RCcm93c2VyQ29tcG9uZW50TWl4aW4uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RDU1NUcmFuc2l0aW9uR3JvdXAuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0Q1NTVHJhbnNpdGlvbkdyb3VwQ2hpbGQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0Q2hpbGRyZW4uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0Q29tcG9uZW50LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdENvbXBvbmVudEJyb3dzZXJFbnZpcm9ubWVudC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RDb21wb25lbnRXaXRoUHVyZVJlbmRlck1peGluLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdENvbXBvc2l0ZUNvbXBvbmVudC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RDb250ZXh0LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdEN1cnJlbnRPd25lci5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RET00uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0RE9NQnV0dG9uLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdERPTUNvbXBvbmVudC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RET01Gb3JtLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdERPTUlET3BlcmF0aW9ucy5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RET01JbWcuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0RE9NSW5wdXQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0RE9NT3B0aW9uLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdERPTVNlbGVjdC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RET01TZWxlY3Rpb24uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0RE9NVGV4dGFyZWEuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0RGVmYXVsdEJhdGNoaW5nU3RyYXRlZ3kuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0RGVmYXVsdEluamVjdGlvbi5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3REZWZhdWx0UGVyZi5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3REZWZhdWx0UGVyZkFuYWx5c2lzLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdEVsZW1lbnQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0RWxlbWVudFZhbGlkYXRvci5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RFbXB0eUNvbXBvbmVudC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RFcnJvclV0aWxzLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdEV2ZW50RW1pdHRlck1peGluLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdEV2ZW50TGlzdGVuZXIuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0SW5qZWN0aW9uLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdElucHV0U2VsZWN0aW9uLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdEluc3RhbmNlSGFuZGxlcy5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RMZWdhY3lFbGVtZW50LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdExpbmsuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0TWFya3VwQ2hlY2tzdW0uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0TW91bnQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0TXVsdGlDaGlsZC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RNdWx0aUNoaWxkVXBkYXRlVHlwZXMuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0TmF0aXZlQ29tcG9uZW50LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdE93bmVyLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdFBlcmYuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0UHJvcFRyYW5zZmVyZXIuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0UHJvcFR5cGVMb2NhdGlvbk5hbWVzLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdFByb3BUeXBlTG9jYXRpb25zLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdFByb3BUeXBlcy5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RQdXRMaXN0ZW5lclF1ZXVlLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9uLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdFJvb3RJbmRleC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RTZXJ2ZXJSZW5kZXJpbmcuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0U2VydmVyUmVuZGVyaW5nVHJhbnNhY3Rpb24uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0U3RhdGVTZXR0ZXJzLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdFRlc3RVdGlscy5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RUZXh0Q29tcG9uZW50LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdFRyYW5zaXRpb25DaGlsZE1hcHBpbmcuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0VHJhbnNpdGlvbkV2ZW50cy5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RUcmFuc2l0aW9uR3JvdXAuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0VXBkYXRlcy5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RXaXRoQWRkb25zLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9TVkdET01Qcm9wZXJ0eUNvbmZpZy5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvU2VsZWN0RXZlbnRQbHVnaW4uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1NlcnZlclJlYWN0Um9vdEluZGV4LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9TaW1wbGVFdmVudFBsdWdpbi5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvU3ludGhldGljQ2xpcGJvYXJkRXZlbnQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1N5bnRoZXRpY0NvbXBvc2l0aW9uRXZlbnQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1N5bnRoZXRpY0RyYWdFdmVudC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvU3ludGhldGljRXZlbnQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1N5bnRoZXRpY0ZvY3VzRXZlbnQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1N5bnRoZXRpY0lucHV0RXZlbnQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1N5bnRoZXRpY0tleWJvYXJkRXZlbnQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1N5bnRoZXRpY01vdXNlRXZlbnQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1N5bnRoZXRpY1RvdWNoRXZlbnQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1N5bnRoZXRpY1VJRXZlbnQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1N5bnRoZXRpY1doZWVsRXZlbnQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1RyYW5zYWN0aW9uLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9WaWV3cG9ydE1ldHJpY3MuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2FjY3VtdWxhdGVJbnRvLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9hZGxlcjMyLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9jYW1lbGl6ZS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvY2FtZWxpemVTdHlsZU5hbWUuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2Nsb25lV2l0aFByb3BzLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9jb250YWluc05vZGUuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2NyZWF0ZUFycmF5RnJvbS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvY3JlYXRlRnVsbFBhZ2VDb21wb25lbnQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2NyZWF0ZU5vZGVzRnJvbU1hcmt1cC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvY3guanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2Rhbmdlcm91c1N0eWxlVmFsdWUuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2RlcHJlY2F0ZWQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2VtcHR5RnVuY3Rpb24uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2VtcHR5T2JqZWN0LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9lc2NhcGVUZXh0Rm9yQnJvd3Nlci5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvZmxhdHRlbkNoaWxkcmVuLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9mb2N1c05vZGUuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2ZvckVhY2hBY2N1bXVsYXRlZC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvZ2V0QWN0aXZlRWxlbWVudC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvZ2V0RXZlbnRDaGFyQ29kZS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvZ2V0RXZlbnRLZXkuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2dldEV2ZW50TW9kaWZpZXJTdGF0ZS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvZ2V0RXZlbnRUYXJnZXQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2dldE1hcmt1cFdyYXAuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2dldE5vZGVGb3JDaGFyYWN0ZXJPZmZzZXQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2dldFJlYWN0Um9vdEVsZW1lbnRJbkNvbnRhaW5lci5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvZ2V0VGV4dENvbnRlbnRBY2Nlc3Nvci5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvZ2V0VW5ib3VuZGVkU2Nyb2xsUG9zaXRpb24uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2h5cGhlbmF0ZS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvaHlwaGVuYXRlU3R5bGVOYW1lLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9pbnN0YW50aWF0ZVJlYWN0Q29tcG9uZW50LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9pbnZhcmlhbnQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2lzRXZlbnRTdXBwb3J0ZWQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2lzTm9kZS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvaXNUZXh0SW5wdXRFbGVtZW50LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9pc1RleHROb2RlLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9qb2luQ2xhc3Nlcy5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIva2V5TWlycm9yLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9rZXlPZi5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvbWFwT2JqZWN0LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9tZW1vaXplU3RyaW5nT25seS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvbW9uaXRvckNvZGVVc2UuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL29ubHlDaGlsZC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvcGVyZm9ybWFuY2UuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL3BlcmZvcm1hbmNlTm93LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9zZXRJbm5lckhUTUwuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL3NoYWxsb3dFcXVhbC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvc2hvdWxkVXBkYXRlUmVhY3RDb21wb25lbnQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL3RvQXJyYXkuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL3RyYXZlcnNlQWxsQ2hpbGRyZW4uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL3VwZGF0ZS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvd2FybmluZy5qcyIsIm5vZGVfbW9kdWxlcy9qcXVlcnkvZGlzdC9qcXVlcnkuanMiLCJub2RlX21vZHVsZXMvbG9kYXNoL2Rpc3QvbG9kYXNoLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0LXJvdXRlci9tb2R1bGVzL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2FkZG9ucy5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9yZWFjdC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1aENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0RkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNiQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0dBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3SEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5RkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaklBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaGZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xCQTtBQUNBOztBQ0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMURBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNXhCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1WEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDalFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3S0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDelNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25NQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdFJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqV0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6YkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5NUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9EQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcmVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaExBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25EQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdExBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9NQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xRQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1TUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwUEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4UkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0VBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0SUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN1VBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyUEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4ckJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFhQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaFdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3REQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5S0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0dBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFaQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25HQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoU0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDak1BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMWFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1SkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL09BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDci9SQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25vTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckJBO0FBQ0E7O0FDREE7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIvKiFcbiAqIFRoZSBidWZmZXIgbW9kdWxlIGZyb20gbm9kZS5qcywgZm9yIHRoZSBicm93c2VyLlxuICpcbiAqIEBhdXRob3IgICBGZXJvc3MgQWJvdWtoYWRpamVoIDxmZXJvc3NAZmVyb3NzLm9yZz4gPGh0dHA6Ly9mZXJvc3Mub3JnPlxuICogQGxpY2Vuc2UgIE1JVFxuICovXG5cbnZhciBiYXNlNjQgPSByZXF1aXJlKCdiYXNlNjQtanMnKVxudmFyIGllZWU3NTQgPSByZXF1aXJlKCdpZWVlNzU0JylcbnZhciBpc0FycmF5ID0gcmVxdWlyZSgnaXMtYXJyYXknKVxuXG5leHBvcnRzLkJ1ZmZlciA9IEJ1ZmZlclxuZXhwb3J0cy5TbG93QnVmZmVyID0gQnVmZmVyXG5leHBvcnRzLklOU1BFQ1RfTUFYX0JZVEVTID0gNTBcbkJ1ZmZlci5wb29sU2l6ZSA9IDgxOTIgLy8gbm90IHVzZWQgYnkgdGhpcyBpbXBsZW1lbnRhdGlvblxuXG52YXIga01heExlbmd0aCA9IDB4M2ZmZmZmZmZcblxuLyoqXG4gKiBJZiBgQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlRgOlxuICogICA9PT0gdHJ1ZSAgICBVc2UgVWludDhBcnJheSBpbXBsZW1lbnRhdGlvbiAoZmFzdGVzdClcbiAqICAgPT09IGZhbHNlICAgVXNlIE9iamVjdCBpbXBsZW1lbnRhdGlvbiAobW9zdCBjb21wYXRpYmxlLCBldmVuIElFNilcbiAqXG4gKiBCcm93c2VycyB0aGF0IHN1cHBvcnQgdHlwZWQgYXJyYXlzIGFyZSBJRSAxMCssIEZpcmVmb3ggNCssIENocm9tZSA3KywgU2FmYXJpIDUuMSssXG4gKiBPcGVyYSAxMS42KywgaU9TIDQuMisuXG4gKlxuICogTm90ZTpcbiAqXG4gKiAtIEltcGxlbWVudGF0aW9uIG11c3Qgc3VwcG9ydCBhZGRpbmcgbmV3IHByb3BlcnRpZXMgdG8gYFVpbnQ4QXJyYXlgIGluc3RhbmNlcy5cbiAqICAgRmlyZWZveCA0LTI5IGxhY2tlZCBzdXBwb3J0LCBmaXhlZCBpbiBGaXJlZm94IDMwKy5cbiAqICAgU2VlOiBodHRwczovL2J1Z3ppbGxhLm1vemlsbGEub3JnL3Nob3dfYnVnLmNnaT9pZD02OTU0MzguXG4gKlxuICogIC0gQ2hyb21lIDktMTAgaXMgbWlzc2luZyB0aGUgYFR5cGVkQXJyYXkucHJvdG90eXBlLnN1YmFycmF5YCBmdW5jdGlvbi5cbiAqXG4gKiAgLSBJRTEwIGhhcyBhIGJyb2tlbiBgVHlwZWRBcnJheS5wcm90b3R5cGUuc3ViYXJyYXlgIGZ1bmN0aW9uIHdoaWNoIHJldHVybnMgYXJyYXlzIG9mXG4gKiAgICBpbmNvcnJlY3QgbGVuZ3RoIGluIHNvbWUgc2l0dWF0aW9ucy5cbiAqXG4gKiBXZSBkZXRlY3QgdGhlc2UgYnVnZ3kgYnJvd3NlcnMgYW5kIHNldCBgQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlRgIHRvIGBmYWxzZWAgc28gdGhleSB3aWxsXG4gKiBnZXQgdGhlIE9iamVjdCBpbXBsZW1lbnRhdGlvbiwgd2hpY2ggaXMgc2xvd2VyIGJ1dCB3aWxsIHdvcmsgY29ycmVjdGx5LlxuICovXG5CdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCA9IChmdW5jdGlvbiAoKSB7XG4gIHRyeSB7XG4gICAgdmFyIGJ1ZiA9IG5ldyBBcnJheUJ1ZmZlcigwKVxuICAgIHZhciBhcnIgPSBuZXcgVWludDhBcnJheShidWYpXG4gICAgYXJyLmZvbyA9IGZ1bmN0aW9uICgpIHsgcmV0dXJuIDQyIH1cbiAgICByZXR1cm4gNDIgPT09IGFyci5mb28oKSAmJiAvLyB0eXBlZCBhcnJheSBpbnN0YW5jZXMgY2FuIGJlIGF1Z21lbnRlZFxuICAgICAgICB0eXBlb2YgYXJyLnN1YmFycmF5ID09PSAnZnVuY3Rpb24nICYmIC8vIGNocm9tZSA5LTEwIGxhY2sgYHN1YmFycmF5YFxuICAgICAgICBuZXcgVWludDhBcnJheSgxKS5zdWJhcnJheSgxLCAxKS5ieXRlTGVuZ3RoID09PSAwIC8vIGllMTAgaGFzIGJyb2tlbiBgc3ViYXJyYXlgXG4gIH0gY2F0Y2ggKGUpIHtcbiAgICByZXR1cm4gZmFsc2VcbiAgfVxufSkoKVxuXG4vKipcbiAqIENsYXNzOiBCdWZmZXJcbiAqID09PT09PT09PT09PT1cbiAqXG4gKiBUaGUgQnVmZmVyIGNvbnN0cnVjdG9yIHJldHVybnMgaW5zdGFuY2VzIG9mIGBVaW50OEFycmF5YCB0aGF0IGFyZSBhdWdtZW50ZWRcbiAqIHdpdGggZnVuY3Rpb24gcHJvcGVydGllcyBmb3IgYWxsIHRoZSBub2RlIGBCdWZmZXJgIEFQSSBmdW5jdGlvbnMuIFdlIHVzZVxuICogYFVpbnQ4QXJyYXlgIHNvIHRoYXQgc3F1YXJlIGJyYWNrZXQgbm90YXRpb24gd29ya3MgYXMgZXhwZWN0ZWQgLS0gaXQgcmV0dXJuc1xuICogYSBzaW5nbGUgb2N0ZXQuXG4gKlxuICogQnkgYXVnbWVudGluZyB0aGUgaW5zdGFuY2VzLCB3ZSBjYW4gYXZvaWQgbW9kaWZ5aW5nIHRoZSBgVWludDhBcnJheWBcbiAqIHByb3RvdHlwZS5cbiAqL1xuZnVuY3Rpb24gQnVmZmVyIChzdWJqZWN0LCBlbmNvZGluZywgbm9aZXJvKSB7XG4gIGlmICghKHRoaXMgaW5zdGFuY2VvZiBCdWZmZXIpKVxuICAgIHJldHVybiBuZXcgQnVmZmVyKHN1YmplY3QsIGVuY29kaW5nLCBub1plcm8pXG5cbiAgdmFyIHR5cGUgPSB0eXBlb2Ygc3ViamVjdFxuXG4gIC8vIEZpbmQgdGhlIGxlbmd0aFxuICB2YXIgbGVuZ3RoXG4gIGlmICh0eXBlID09PSAnbnVtYmVyJylcbiAgICBsZW5ndGggPSBzdWJqZWN0ID4gMCA/IHN1YmplY3QgPj4+IDAgOiAwXG4gIGVsc2UgaWYgKHR5cGUgPT09ICdzdHJpbmcnKSB7XG4gICAgaWYgKGVuY29kaW5nID09PSAnYmFzZTY0JylcbiAgICAgIHN1YmplY3QgPSBiYXNlNjRjbGVhbihzdWJqZWN0KVxuICAgIGxlbmd0aCA9IEJ1ZmZlci5ieXRlTGVuZ3RoKHN1YmplY3QsIGVuY29kaW5nKVxuICB9IGVsc2UgaWYgKHR5cGUgPT09ICdvYmplY3QnICYmIHN1YmplY3QgIT09IG51bGwpIHsgLy8gYXNzdW1lIG9iamVjdCBpcyBhcnJheS1saWtlXG4gICAgaWYgKHN1YmplY3QudHlwZSA9PT0gJ0J1ZmZlcicgJiYgaXNBcnJheShzdWJqZWN0LmRhdGEpKVxuICAgICAgc3ViamVjdCA9IHN1YmplY3QuZGF0YVxuICAgIGxlbmd0aCA9ICtzdWJqZWN0Lmxlbmd0aCA+IDAgPyBNYXRoLmZsb29yKCtzdWJqZWN0Lmxlbmd0aCkgOiAwXG4gIH0gZWxzZVxuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ211c3Qgc3RhcnQgd2l0aCBudW1iZXIsIGJ1ZmZlciwgYXJyYXkgb3Igc3RyaW5nJylcblxuICBpZiAodGhpcy5sZW5ndGggPiBrTWF4TGVuZ3RoKVxuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdBdHRlbXB0IHRvIGFsbG9jYXRlIEJ1ZmZlciBsYXJnZXIgdGhhbiBtYXhpbXVtICcgK1xuICAgICAgJ3NpemU6IDB4JyArIGtNYXhMZW5ndGgudG9TdHJpbmcoMTYpICsgJyBieXRlcycpXG5cbiAgdmFyIGJ1ZlxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICAvLyBQcmVmZXJyZWQ6IFJldHVybiBhbiBhdWdtZW50ZWQgYFVpbnQ4QXJyYXlgIGluc3RhbmNlIGZvciBiZXN0IHBlcmZvcm1hbmNlXG4gICAgYnVmID0gQnVmZmVyLl9hdWdtZW50KG5ldyBVaW50OEFycmF5KGxlbmd0aCkpXG4gIH0gZWxzZSB7XG4gICAgLy8gRmFsbGJhY2s6IFJldHVybiBUSElTIGluc3RhbmNlIG9mIEJ1ZmZlciAoY3JlYXRlZCBieSBgbmV3YClcbiAgICBidWYgPSB0aGlzXG4gICAgYnVmLmxlbmd0aCA9IGxlbmd0aFxuICAgIGJ1Zi5faXNCdWZmZXIgPSB0cnVlXG4gIH1cblxuICB2YXIgaVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQgJiYgdHlwZW9mIHN1YmplY3QuYnl0ZUxlbmd0aCA9PT0gJ251bWJlcicpIHtcbiAgICAvLyBTcGVlZCBvcHRpbWl6YXRpb24gLS0gdXNlIHNldCBpZiB3ZSdyZSBjb3B5aW5nIGZyb20gYSB0eXBlZCBhcnJheVxuICAgIGJ1Zi5fc2V0KHN1YmplY3QpXG4gIH0gZWxzZSBpZiAoaXNBcnJheWlzaChzdWJqZWN0KSkge1xuICAgIC8vIFRyZWF0IGFycmF5LWlzaCBvYmplY3RzIGFzIGEgYnl0ZSBhcnJheVxuICAgIGlmIChCdWZmZXIuaXNCdWZmZXIoc3ViamVjdCkpIHtcbiAgICAgIGZvciAoaSA9IDA7IGkgPCBsZW5ndGg7IGkrKylcbiAgICAgICAgYnVmW2ldID0gc3ViamVjdC5yZWFkVUludDgoaSlcbiAgICB9IGVsc2Uge1xuICAgICAgZm9yIChpID0gMDsgaSA8IGxlbmd0aDsgaSsrKVxuICAgICAgICBidWZbaV0gPSAoKHN1YmplY3RbaV0gJSAyNTYpICsgMjU2KSAlIDI1NlxuICAgIH1cbiAgfSBlbHNlIGlmICh0eXBlID09PSAnc3RyaW5nJykge1xuICAgIGJ1Zi53cml0ZShzdWJqZWN0LCAwLCBlbmNvZGluZylcbiAgfSBlbHNlIGlmICh0eXBlID09PSAnbnVtYmVyJyAmJiAhQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQgJiYgIW5vWmVybykge1xuICAgIGZvciAoaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgYnVmW2ldID0gMFxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBidWZcbn1cblxuQnVmZmVyLmlzQnVmZmVyID0gZnVuY3Rpb24gKGIpIHtcbiAgcmV0dXJuICEhKGIgIT0gbnVsbCAmJiBiLl9pc0J1ZmZlcilcbn1cblxuQnVmZmVyLmNvbXBhcmUgPSBmdW5jdGlvbiAoYSwgYikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihhKSB8fCAhQnVmZmVyLmlzQnVmZmVyKGIpKVxuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0FyZ3VtZW50cyBtdXN0IGJlIEJ1ZmZlcnMnKVxuXG4gIHZhciB4ID0gYS5sZW5ndGhcbiAgdmFyIHkgPSBiLmxlbmd0aFxuICBmb3IgKHZhciBpID0gMCwgbGVuID0gTWF0aC5taW4oeCwgeSk7IGkgPCBsZW4gJiYgYVtpXSA9PT0gYltpXTsgaSsrKSB7fVxuICBpZiAoaSAhPT0gbGVuKSB7XG4gICAgeCA9IGFbaV1cbiAgICB5ID0gYltpXVxuICB9XG4gIGlmICh4IDwgeSkgcmV0dXJuIC0xXG4gIGlmICh5IDwgeCkgcmV0dXJuIDFcbiAgcmV0dXJuIDBcbn1cblxuQnVmZmVyLmlzRW5jb2RpbmcgPSBmdW5jdGlvbiAoZW5jb2RpbmcpIHtcbiAgc3dpdGNoIChTdHJpbmcoZW5jb2RpbmcpLnRvTG93ZXJDYXNlKCkpIHtcbiAgICBjYXNlICdoZXgnOlxuICAgIGNhc2UgJ3V0ZjgnOlxuICAgIGNhc2UgJ3V0Zi04JzpcbiAgICBjYXNlICdhc2NpaSc6XG4gICAgY2FzZSAnYmluYXJ5JzpcbiAgICBjYXNlICdiYXNlNjQnOlxuICAgIGNhc2UgJ3Jhdyc6XG4gICAgY2FzZSAndWNzMic6XG4gICAgY2FzZSAndWNzLTInOlxuICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgIGNhc2UgJ3V0Zi0xNmxlJzpcbiAgICAgIHJldHVybiB0cnVlXG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiBmYWxzZVxuICB9XG59XG5cbkJ1ZmZlci5jb25jYXQgPSBmdW5jdGlvbiAobGlzdCwgdG90YWxMZW5ndGgpIHtcbiAgaWYgKCFpc0FycmF5KGxpc3QpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdVc2FnZTogQnVmZmVyLmNvbmNhdChsaXN0WywgbGVuZ3RoXSknKVxuXG4gIGlmIChsaXN0Lmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBuZXcgQnVmZmVyKDApXG4gIH0gZWxzZSBpZiAobGlzdC5sZW5ndGggPT09IDEpIHtcbiAgICByZXR1cm4gbGlzdFswXVxuICB9XG5cbiAgdmFyIGlcbiAgaWYgKHRvdGFsTGVuZ3RoID09PSB1bmRlZmluZWQpIHtcbiAgICB0b3RhbExlbmd0aCA9IDBcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGlzdC5sZW5ndGg7IGkrKykge1xuICAgICAgdG90YWxMZW5ndGggKz0gbGlzdFtpXS5sZW5ndGhcbiAgICB9XG4gIH1cblxuICB2YXIgYnVmID0gbmV3IEJ1ZmZlcih0b3RhbExlbmd0aClcbiAgdmFyIHBvcyA9IDBcbiAgZm9yIChpID0gMDsgaSA8IGxpc3QubGVuZ3RoOyBpKyspIHtcbiAgICB2YXIgaXRlbSA9IGxpc3RbaV1cbiAgICBpdGVtLmNvcHkoYnVmLCBwb3MpXG4gICAgcG9zICs9IGl0ZW0ubGVuZ3RoXG4gIH1cbiAgcmV0dXJuIGJ1ZlxufVxuXG5CdWZmZXIuYnl0ZUxlbmd0aCA9IGZ1bmN0aW9uIChzdHIsIGVuY29kaW5nKSB7XG4gIHZhciByZXRcbiAgc3RyID0gc3RyICsgJydcbiAgc3dpdGNoIChlbmNvZGluZyB8fCAndXRmOCcpIHtcbiAgICBjYXNlICdhc2NpaSc6XG4gICAgY2FzZSAnYmluYXJ5JzpcbiAgICBjYXNlICdyYXcnOlxuICAgICAgcmV0ID0gc3RyLmxlbmd0aFxuICAgICAgYnJlYWtcbiAgICBjYXNlICd1Y3MyJzpcbiAgICBjYXNlICd1Y3MtMic6XG4gICAgY2FzZSAndXRmMTZsZSc6XG4gICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgcmV0ID0gc3RyLmxlbmd0aCAqIDJcbiAgICAgIGJyZWFrXG4gICAgY2FzZSAnaGV4JzpcbiAgICAgIHJldCA9IHN0ci5sZW5ndGggPj4+IDFcbiAgICAgIGJyZWFrXG4gICAgY2FzZSAndXRmOCc6XG4gICAgY2FzZSAndXRmLTgnOlxuICAgICAgcmV0ID0gdXRmOFRvQnl0ZXMoc3RyKS5sZW5ndGhcbiAgICAgIGJyZWFrXG4gICAgY2FzZSAnYmFzZTY0JzpcbiAgICAgIHJldCA9IGJhc2U2NFRvQnl0ZXMoc3RyKS5sZW5ndGhcbiAgICAgIGJyZWFrXG4gICAgZGVmYXVsdDpcbiAgICAgIHJldCA9IHN0ci5sZW5ndGhcbiAgfVxuICByZXR1cm4gcmV0XG59XG5cbi8vIHByZS1zZXQgZm9yIHZhbHVlcyB0aGF0IG1heSBleGlzdCBpbiB0aGUgZnV0dXJlXG5CdWZmZXIucHJvdG90eXBlLmxlbmd0aCA9IHVuZGVmaW5lZFxuQnVmZmVyLnByb3RvdHlwZS5wYXJlbnQgPSB1bmRlZmluZWRcblxuLy8gdG9TdHJpbmcoZW5jb2RpbmcsIHN0YXJ0PTAsIGVuZD1idWZmZXIubGVuZ3RoKVxuQnVmZmVyLnByb3RvdHlwZS50b1N0cmluZyA9IGZ1bmN0aW9uIChlbmNvZGluZywgc3RhcnQsIGVuZCkge1xuICB2YXIgbG93ZXJlZENhc2UgPSBmYWxzZVxuXG4gIHN0YXJ0ID0gc3RhcnQgPj4+IDBcbiAgZW5kID0gZW5kID09PSB1bmRlZmluZWQgfHwgZW5kID09PSBJbmZpbml0eSA/IHRoaXMubGVuZ3RoIDogZW5kID4+PiAwXG5cbiAgaWYgKCFlbmNvZGluZykgZW5jb2RpbmcgPSAndXRmOCdcbiAgaWYgKHN0YXJ0IDwgMCkgc3RhcnQgPSAwXG4gIGlmIChlbmQgPiB0aGlzLmxlbmd0aCkgZW5kID0gdGhpcy5sZW5ndGhcbiAgaWYgKGVuZCA8PSBzdGFydCkgcmV0dXJuICcnXG5cbiAgd2hpbGUgKHRydWUpIHtcbiAgICBzd2l0Y2ggKGVuY29kaW5nKSB7XG4gICAgICBjYXNlICdoZXgnOlxuICAgICAgICByZXR1cm4gaGV4U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAndXRmOCc6XG4gICAgICBjYXNlICd1dGYtOCc6XG4gICAgICAgIHJldHVybiB1dGY4U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAnYXNjaWknOlxuICAgICAgICByZXR1cm4gYXNjaWlTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICdiaW5hcnknOlxuICAgICAgICByZXR1cm4gYmluYXJ5U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAnYmFzZTY0JzpcbiAgICAgICAgcmV0dXJuIGJhc2U2NFNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ3VjczInOlxuICAgICAgY2FzZSAndWNzLTInOlxuICAgICAgY2FzZSAndXRmMTZsZSc6XG4gICAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICAgIHJldHVybiB1dGYxNmxlU2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgaWYgKGxvd2VyZWRDYXNlKVxuICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ1Vua25vd24gZW5jb2Rpbmc6ICcgKyBlbmNvZGluZylcbiAgICAgICAgZW5jb2RpbmcgPSAoZW5jb2RpbmcgKyAnJykudG9Mb3dlckNhc2UoKVxuICAgICAgICBsb3dlcmVkQ2FzZSA9IHRydWVcbiAgICB9XG4gIH1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS5lcXVhbHMgPSBmdW5jdGlvbiAoYikge1xuICBpZighQnVmZmVyLmlzQnVmZmVyKGIpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudCBtdXN0IGJlIGEgQnVmZmVyJylcbiAgcmV0dXJuIEJ1ZmZlci5jb21wYXJlKHRoaXMsIGIpID09PSAwXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuaW5zcGVjdCA9IGZ1bmN0aW9uICgpIHtcbiAgdmFyIHN0ciA9ICcnXG4gIHZhciBtYXggPSBleHBvcnRzLklOU1BFQ1RfTUFYX0JZVEVTXG4gIGlmICh0aGlzLmxlbmd0aCA+IDApIHtcbiAgICBzdHIgPSB0aGlzLnRvU3RyaW5nKCdoZXgnLCAwLCBtYXgpLm1hdGNoKC8uezJ9L2cpLmpvaW4oJyAnKVxuICAgIGlmICh0aGlzLmxlbmd0aCA+IG1heClcbiAgICAgIHN0ciArPSAnIC4uLiAnXG4gIH1cbiAgcmV0dXJuICc8QnVmZmVyICcgKyBzdHIgKyAnPidcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5jb21wYXJlID0gZnVuY3Rpb24gKGIpIHtcbiAgaWYgKCFCdWZmZXIuaXNCdWZmZXIoYikpIHRocm93IG5ldyBUeXBlRXJyb3IoJ0FyZ3VtZW50IG11c3QgYmUgYSBCdWZmZXInKVxuICByZXR1cm4gQnVmZmVyLmNvbXBhcmUodGhpcywgYilcbn1cblxuLy8gYGdldGAgd2lsbCBiZSByZW1vdmVkIGluIE5vZGUgMC4xMytcbkJ1ZmZlci5wcm90b3R5cGUuZ2V0ID0gZnVuY3Rpb24gKG9mZnNldCkge1xuICBjb25zb2xlLmxvZygnLmdldCgpIGlzIGRlcHJlY2F0ZWQuIEFjY2VzcyB1c2luZyBhcnJheSBpbmRleGVzIGluc3RlYWQuJylcbiAgcmV0dXJuIHRoaXMucmVhZFVJbnQ4KG9mZnNldClcbn1cblxuLy8gYHNldGAgd2lsbCBiZSByZW1vdmVkIGluIE5vZGUgMC4xMytcbkJ1ZmZlci5wcm90b3R5cGUuc2V0ID0gZnVuY3Rpb24gKHYsIG9mZnNldCkge1xuICBjb25zb2xlLmxvZygnLnNldCgpIGlzIGRlcHJlY2F0ZWQuIEFjY2VzcyB1c2luZyBhcnJheSBpbmRleGVzIGluc3RlYWQuJylcbiAgcmV0dXJuIHRoaXMud3JpdGVVSW50OCh2LCBvZmZzZXQpXG59XG5cbmZ1bmN0aW9uIGhleFdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgb2Zmc2V0ID0gTnVtYmVyKG9mZnNldCkgfHwgMFxuICB2YXIgcmVtYWluaW5nID0gYnVmLmxlbmd0aCAtIG9mZnNldFxuICBpZiAoIWxlbmd0aCkge1xuICAgIGxlbmd0aCA9IHJlbWFpbmluZ1xuICB9IGVsc2Uge1xuICAgIGxlbmd0aCA9IE51bWJlcihsZW5ndGgpXG4gICAgaWYgKGxlbmd0aCA+IHJlbWFpbmluZykge1xuICAgICAgbGVuZ3RoID0gcmVtYWluaW5nXG4gICAgfVxuICB9XG5cbiAgLy8gbXVzdCBiZSBhbiBldmVuIG51bWJlciBvZiBkaWdpdHNcbiAgdmFyIHN0ckxlbiA9IHN0cmluZy5sZW5ndGhcbiAgaWYgKHN0ckxlbiAlIDIgIT09IDApIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBoZXggc3RyaW5nJylcblxuICBpZiAobGVuZ3RoID4gc3RyTGVuIC8gMikge1xuICAgIGxlbmd0aCA9IHN0ckxlbiAvIDJcbiAgfVxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIGJ5dGUgPSBwYXJzZUludChzdHJpbmcuc3Vic3RyKGkgKiAyLCAyKSwgMTYpXG4gICAgaWYgKGlzTmFOKGJ5dGUpKSB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgaGV4IHN0cmluZycpXG4gICAgYnVmW29mZnNldCArIGldID0gYnl0ZVxuICB9XG4gIHJldHVybiBpXG59XG5cbmZ1bmN0aW9uIHV0ZjhXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHZhciBjaGFyc1dyaXR0ZW4gPSBibGl0QnVmZmVyKHV0ZjhUb0J5dGVzKHN0cmluZyksIGJ1Ziwgb2Zmc2V0LCBsZW5ndGgpXG4gIHJldHVybiBjaGFyc1dyaXR0ZW5cbn1cblxuZnVuY3Rpb24gYXNjaWlXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHZhciBjaGFyc1dyaXR0ZW4gPSBibGl0QnVmZmVyKGFzY2lpVG9CeXRlcyhzdHJpbmcpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxuICByZXR1cm4gY2hhcnNXcml0dGVuXG59XG5cbmZ1bmN0aW9uIGJpbmFyeVdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGFzY2lpV3JpdGUoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5mdW5jdGlvbiBiYXNlNjRXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHZhciBjaGFyc1dyaXR0ZW4gPSBibGl0QnVmZmVyKGJhc2U2NFRvQnl0ZXMoc3RyaW5nKSwgYnVmLCBvZmZzZXQsIGxlbmd0aClcbiAgcmV0dXJuIGNoYXJzV3JpdHRlblxufVxuXG5mdW5jdGlvbiB1dGYxNmxlV3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICB2YXIgY2hhcnNXcml0dGVuID0gYmxpdEJ1ZmZlcih1dGYxNmxlVG9CeXRlcyhzdHJpbmcpLCBidWYsIG9mZnNldCwgbGVuZ3RoLCAyKVxuICByZXR1cm4gY2hhcnNXcml0dGVuXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGUgPSBmdW5jdGlvbiAoc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCwgZW5jb2RpbmcpIHtcbiAgLy8gU3VwcG9ydCBib3RoIChzdHJpbmcsIG9mZnNldCwgbGVuZ3RoLCBlbmNvZGluZylcbiAgLy8gYW5kIHRoZSBsZWdhY3kgKHN0cmluZywgZW5jb2RpbmcsIG9mZnNldCwgbGVuZ3RoKVxuICBpZiAoaXNGaW5pdGUob2Zmc2V0KSkge1xuICAgIGlmICghaXNGaW5pdGUobGVuZ3RoKSkge1xuICAgICAgZW5jb2RpbmcgPSBsZW5ndGhcbiAgICAgIGxlbmd0aCA9IHVuZGVmaW5lZFxuICAgIH1cbiAgfSBlbHNlIHsgIC8vIGxlZ2FjeVxuICAgIHZhciBzd2FwID0gZW5jb2RpbmdcbiAgICBlbmNvZGluZyA9IG9mZnNldFxuICAgIG9mZnNldCA9IGxlbmd0aFxuICAgIGxlbmd0aCA9IHN3YXBcbiAgfVxuXG4gIG9mZnNldCA9IE51bWJlcihvZmZzZXQpIHx8IDBcbiAgdmFyIHJlbWFpbmluZyA9IHRoaXMubGVuZ3RoIC0gb2Zmc2V0XG4gIGlmICghbGVuZ3RoKSB7XG4gICAgbGVuZ3RoID0gcmVtYWluaW5nXG4gIH0gZWxzZSB7XG4gICAgbGVuZ3RoID0gTnVtYmVyKGxlbmd0aClcbiAgICBpZiAobGVuZ3RoID4gcmVtYWluaW5nKSB7XG4gICAgICBsZW5ndGggPSByZW1haW5pbmdcbiAgICB9XG4gIH1cbiAgZW5jb2RpbmcgPSBTdHJpbmcoZW5jb2RpbmcgfHwgJ3V0ZjgnKS50b0xvd2VyQ2FzZSgpXG5cbiAgdmFyIHJldFxuICBzd2l0Y2ggKGVuY29kaW5nKSB7XG4gICAgY2FzZSAnaGV4JzpcbiAgICAgIHJldCA9IGhleFdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG4gICAgICBicmVha1xuICAgIGNhc2UgJ3V0ZjgnOlxuICAgIGNhc2UgJ3V0Zi04JzpcbiAgICAgIHJldCA9IHV0ZjhXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuICAgICAgYnJlYWtcbiAgICBjYXNlICdhc2NpaSc6XG4gICAgICByZXQgPSBhc2NpaVdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG4gICAgICBicmVha1xuICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgICByZXQgPSBiaW5hcnlXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuICAgICAgYnJlYWtcbiAgICBjYXNlICdiYXNlNjQnOlxuICAgICAgcmV0ID0gYmFzZTY0V3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcbiAgICAgIGJyZWFrXG4gICAgY2FzZSAndWNzMic6XG4gICAgY2FzZSAndWNzLTInOlxuICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgIGNhc2UgJ3V0Zi0xNmxlJzpcbiAgICAgIHJldCA9IHV0ZjE2bGVXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuICAgICAgYnJlYWtcbiAgICBkZWZhdWx0OlxuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignVW5rbm93biBlbmNvZGluZzogJyArIGVuY29kaW5nKVxuICB9XG4gIHJldHVybiByZXRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS50b0pTT04gPSBmdW5jdGlvbiAoKSB7XG4gIHJldHVybiB7XG4gICAgdHlwZTogJ0J1ZmZlcicsXG4gICAgZGF0YTogQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwodGhpcy5fYXJyIHx8IHRoaXMsIDApXG4gIH1cbn1cblxuZnVuY3Rpb24gYmFzZTY0U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICBpZiAoc3RhcnQgPT09IDAgJiYgZW5kID09PSBidWYubGVuZ3RoKSB7XG4gICAgcmV0dXJuIGJhc2U2NC5mcm9tQnl0ZUFycmF5KGJ1ZilcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gYmFzZTY0LmZyb21CeXRlQXJyYXkoYnVmLnNsaWNlKHN0YXJ0LCBlbmQpKVxuICB9XG59XG5cbmZ1bmN0aW9uIHV0ZjhTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciByZXMgPSAnJ1xuICB2YXIgdG1wID0gJydcbiAgZW5kID0gTWF0aC5taW4oYnVmLmxlbmd0aCwgZW5kKVxuXG4gIGZvciAodmFyIGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgaWYgKGJ1ZltpXSA8PSAweDdGKSB7XG4gICAgICByZXMgKz0gZGVjb2RlVXRmOENoYXIodG1wKSArIFN0cmluZy5mcm9tQ2hhckNvZGUoYnVmW2ldKVxuICAgICAgdG1wID0gJydcbiAgICB9IGVsc2Uge1xuICAgICAgdG1wICs9ICclJyArIGJ1ZltpXS50b1N0cmluZygxNilcbiAgICB9XG4gIH1cblxuICByZXR1cm4gcmVzICsgZGVjb2RlVXRmOENoYXIodG1wKVxufVxuXG5mdW5jdGlvbiBhc2NpaVNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIHJldCA9ICcnXG4gIGVuZCA9IE1hdGgubWluKGJ1Zi5sZW5ndGgsIGVuZClcblxuICBmb3IgKHZhciBpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgIHJldCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGJ1ZltpXSlcbiAgfVxuICByZXR1cm4gcmV0XG59XG5cbmZ1bmN0aW9uIGJpbmFyeVNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgcmV0dXJuIGFzY2lpU2xpY2UoYnVmLCBzdGFydCwgZW5kKVxufVxuXG5mdW5jdGlvbiBoZXhTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciBsZW4gPSBidWYubGVuZ3RoXG5cbiAgaWYgKCFzdGFydCB8fCBzdGFydCA8IDApIHN0YXJ0ID0gMFxuICBpZiAoIWVuZCB8fCBlbmQgPCAwIHx8IGVuZCA+IGxlbikgZW5kID0gbGVuXG5cbiAgdmFyIG91dCA9ICcnXG4gIGZvciAodmFyIGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgb3V0ICs9IHRvSGV4KGJ1ZltpXSlcbiAgfVxuICByZXR1cm4gb3V0XG59XG5cbmZ1bmN0aW9uIHV0ZjE2bGVTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciBieXRlcyA9IGJ1Zi5zbGljZShzdGFydCwgZW5kKVxuICB2YXIgcmVzID0gJydcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBieXRlcy5sZW5ndGg7IGkgKz0gMikge1xuICAgIHJlcyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGJ5dGVzW2ldICsgYnl0ZXNbaSArIDFdICogMjU2KVxuICB9XG4gIHJldHVybiByZXNcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5zbGljZSA9IGZ1bmN0aW9uIChzdGFydCwgZW5kKSB7XG4gIHZhciBsZW4gPSB0aGlzLmxlbmd0aFxuICBzdGFydCA9IH5+c3RhcnRcbiAgZW5kID0gZW5kID09PSB1bmRlZmluZWQgPyBsZW4gOiB+fmVuZFxuXG4gIGlmIChzdGFydCA8IDApIHtcbiAgICBzdGFydCArPSBsZW47XG4gICAgaWYgKHN0YXJ0IDwgMClcbiAgICAgIHN0YXJ0ID0gMFxuICB9IGVsc2UgaWYgKHN0YXJ0ID4gbGVuKSB7XG4gICAgc3RhcnQgPSBsZW5cbiAgfVxuXG4gIGlmIChlbmQgPCAwKSB7XG4gICAgZW5kICs9IGxlblxuICAgIGlmIChlbmQgPCAwKVxuICAgICAgZW5kID0gMFxuICB9IGVsc2UgaWYgKGVuZCA+IGxlbikge1xuICAgIGVuZCA9IGxlblxuICB9XG5cbiAgaWYgKGVuZCA8IHN0YXJ0KVxuICAgIGVuZCA9IHN0YXJ0XG5cbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgcmV0dXJuIEJ1ZmZlci5fYXVnbWVudCh0aGlzLnN1YmFycmF5KHN0YXJ0LCBlbmQpKVxuICB9IGVsc2Uge1xuICAgIHZhciBzbGljZUxlbiA9IGVuZCAtIHN0YXJ0XG4gICAgdmFyIG5ld0J1ZiA9IG5ldyBCdWZmZXIoc2xpY2VMZW4sIHVuZGVmaW5lZCwgdHJ1ZSlcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNsaWNlTGVuOyBpKyspIHtcbiAgICAgIG5ld0J1ZltpXSA9IHRoaXNbaSArIHN0YXJ0XVxuICAgIH1cbiAgICByZXR1cm4gbmV3QnVmXG4gIH1cbn1cblxuLypcbiAqIE5lZWQgdG8gbWFrZSBzdXJlIHRoYXQgYnVmZmVyIGlzbid0IHRyeWluZyB0byB3cml0ZSBvdXQgb2YgYm91bmRzLlxuICovXG5mdW5jdGlvbiBjaGVja09mZnNldCAob2Zmc2V0LCBleHQsIGxlbmd0aCkge1xuICBpZiAoKG9mZnNldCAlIDEpICE9PSAwIHx8IG9mZnNldCA8IDApXG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ29mZnNldCBpcyBub3QgdWludCcpXG4gIGlmIChvZmZzZXQgKyBleHQgPiBsZW5ndGgpXG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ1RyeWluZyB0byBhY2Nlc3MgYmV5b25kIGJ1ZmZlciBsZW5ndGgnKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50OCA9IGZ1bmN0aW9uIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpXG4gICAgY2hlY2tPZmZzZXQob2Zmc2V0LCAxLCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIHRoaXNbb2Zmc2V0XVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50MTZMRSA9IGZ1bmN0aW9uIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpXG4gICAgY2hlY2tPZmZzZXQob2Zmc2V0LCAyLCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIHRoaXNbb2Zmc2V0XSB8ICh0aGlzW29mZnNldCArIDFdIDw8IDgpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQxNkJFID0gZnVuY3Rpb24gKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydClcbiAgICBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSA8PCA4KSB8IHRoaXNbb2Zmc2V0ICsgMV1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDMyTEUgPSBmdW5jdGlvbiAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KVxuICAgIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICgodGhpc1tvZmZzZXRdKSB8XG4gICAgICAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KSB8XG4gICAgICAodGhpc1tvZmZzZXQgKyAyXSA8PCAxNikpICtcbiAgICAgICh0aGlzW29mZnNldCArIDNdICogMHgxMDAwMDAwKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50MzJCRSA9IGZ1bmN0aW9uIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpXG4gICAgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSAqIDB4MTAwMDAwMCkgK1xuICAgICAgKCh0aGlzW29mZnNldCArIDFdIDw8IDE2KSB8XG4gICAgICAodGhpc1tvZmZzZXQgKyAyXSA8PCA4KSB8XG4gICAgICB0aGlzW29mZnNldCArIDNdKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQ4ID0gZnVuY3Rpb24gKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydClcbiAgICBjaGVja09mZnNldChvZmZzZXQsIDEsIHRoaXMubGVuZ3RoKVxuICBpZiAoISh0aGlzW29mZnNldF0gJiAweDgwKSlcbiAgICByZXR1cm4gKHRoaXNbb2Zmc2V0XSlcbiAgcmV0dXJuICgoMHhmZiAtIHRoaXNbb2Zmc2V0XSArIDEpICogLTEpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDE2TEUgPSBmdW5jdGlvbiAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KVxuICAgIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldF0gfCAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KVxuICByZXR1cm4gKHZhbCAmIDB4ODAwMCkgPyB2YWwgfCAweEZGRkYwMDAwIDogdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDE2QkUgPSBmdW5jdGlvbiAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KVxuICAgIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldCArIDFdIHwgKHRoaXNbb2Zmc2V0XSA8PCA4KVxuICByZXR1cm4gKHZhbCAmIDB4ODAwMCkgPyB2YWwgfCAweEZGRkYwMDAwIDogdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDMyTEUgPSBmdW5jdGlvbiAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KVxuICAgIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICh0aGlzW29mZnNldF0pIHxcbiAgICAgICh0aGlzW29mZnNldCArIDFdIDw8IDgpIHxcbiAgICAgICh0aGlzW29mZnNldCArIDJdIDw8IDE2KSB8XG4gICAgICAodGhpc1tvZmZzZXQgKyAzXSA8PCAyNClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MzJCRSA9IGZ1bmN0aW9uIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpXG4gICAgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSA8PCAyNCkgfFxuICAgICAgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgMTYpIHxcbiAgICAgICh0aGlzW29mZnNldCArIDJdIDw8IDgpIHxcbiAgICAgICh0aGlzW29mZnNldCArIDNdKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRGbG9hdExFID0gZnVuY3Rpb24gKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydClcbiAgICBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gaWVlZTc1NC5yZWFkKHRoaXMsIG9mZnNldCwgdHJ1ZSwgMjMsIDQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEZsb2F0QkUgPSBmdW5jdGlvbiAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KVxuICAgIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCBmYWxzZSwgMjMsIDQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZERvdWJsZUxFID0gZnVuY3Rpb24gKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydClcbiAgICBjaGVja09mZnNldChvZmZzZXQsIDgsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gaWVlZTc1NC5yZWFkKHRoaXMsIG9mZnNldCwgdHJ1ZSwgNTIsIDgpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZERvdWJsZUJFID0gZnVuY3Rpb24gKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydClcbiAgICBjaGVja09mZnNldChvZmZzZXQsIDgsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gaWVlZTc1NC5yZWFkKHRoaXMsIG9mZnNldCwgZmFsc2UsIDUyLCA4KVxufVxuXG5mdW5jdGlvbiBjaGVja0ludCAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBleHQsIG1heCwgbWluKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGJ1ZikpIHRocm93IG5ldyBUeXBlRXJyb3IoJ2J1ZmZlciBtdXN0IGJlIGEgQnVmZmVyIGluc3RhbmNlJylcbiAgaWYgKHZhbHVlID4gbWF4IHx8IHZhbHVlIDwgbWluKSB0aHJvdyBuZXcgVHlwZUVycm9yKCd2YWx1ZSBpcyBvdXQgb2YgYm91bmRzJylcbiAgaWYgKG9mZnNldCArIGV4dCA+IGJ1Zi5sZW5ndGgpIHRocm93IG5ldyBUeXBlRXJyb3IoJ2luZGV4IG91dCBvZiByYW5nZScpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50OCA9IGZ1bmN0aW9uICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgPj4+IDBcbiAgaWYgKCFub0Fzc2VydClcbiAgICBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAxLCAweGZmLCAwKVxuICBpZiAoIUJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB2YWx1ZSA9IE1hdGguZmxvb3IodmFsdWUpXG4gIHRoaXNbb2Zmc2V0XSA9IHZhbHVlXG4gIHJldHVybiBvZmZzZXQgKyAxXG59XG5cbmZ1bmN0aW9uIG9iamVjdFdyaXRlVUludDE2IChidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbikge1xuICBpZiAodmFsdWUgPCAwKSB2YWx1ZSA9IDB4ZmZmZiArIHZhbHVlICsgMVxuICBmb3IgKHZhciBpID0gMCwgaiA9IE1hdGgubWluKGJ1Zi5sZW5ndGggLSBvZmZzZXQsIDIpOyBpIDwgajsgaSsrKSB7XG4gICAgYnVmW29mZnNldCArIGldID0gKHZhbHVlICYgKDB4ZmYgPDwgKDggKiAobGl0dGxlRW5kaWFuID8gaSA6IDEgLSBpKSkpKSA+Pj5cbiAgICAgIChsaXR0bGVFbmRpYW4gPyBpIDogMSAtIGkpICogOFxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50MTZMRSA9IGZ1bmN0aW9uICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgPj4+IDBcbiAgaWYgKCFub0Fzc2VydClcbiAgICBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweGZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9IHZhbHVlXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgfSBlbHNlIG9iamVjdFdyaXRlVUludDE2KHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50MTZCRSA9IGZ1bmN0aW9uICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgPj4+IDBcbiAgaWYgKCFub0Fzc2VydClcbiAgICBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweGZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDFdID0gdmFsdWVcbiAgfSBlbHNlIG9iamVjdFdyaXRlVUludDE2KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlKVxuICByZXR1cm4gb2Zmc2V0ICsgMlxufVxuXG5mdW5jdGlvbiBvYmplY3RXcml0ZVVJbnQzMiAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4pIHtcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmZmZmZmZmICsgdmFsdWUgKyAxXG4gIGZvciAodmFyIGkgPSAwLCBqID0gTWF0aC5taW4oYnVmLmxlbmd0aCAtIG9mZnNldCwgNCk7IGkgPCBqOyBpKyspIHtcbiAgICBidWZbb2Zmc2V0ICsgaV0gPSAodmFsdWUgPj4+IChsaXR0bGVFbmRpYW4gPyBpIDogMyAtIGkpICogOCkgJiAweGZmXG4gIH1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQzMkxFID0gZnVuY3Rpb24gKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCA+Pj4gMFxuICBpZiAoIW5vQXNzZXJ0KVxuICAgIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDQsIDB4ZmZmZmZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0ICsgM10gPSAodmFsdWUgPj4+IDI0KVxuICAgIHRoaXNbb2Zmc2V0ICsgMl0gPSAodmFsdWUgPj4+IDE2KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXRdID0gdmFsdWVcbiAgfSBlbHNlIG9iamVjdFdyaXRlVUludDMyKHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50MzJCRSA9IGZ1bmN0aW9uICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgPj4+IDBcbiAgaWYgKCFub0Fzc2VydClcbiAgICBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweGZmZmZmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDI0KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDE2KVxuICAgIHRoaXNbb2Zmc2V0ICsgMl0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9IHZhbHVlXG4gIH0gZWxzZSBvYmplY3RXcml0ZVVJbnQzMih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDggPSBmdW5jdGlvbiAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0ID4+PiAwXG4gIGlmICghbm9Bc3NlcnQpXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMSwgMHg3ZiwgLTB4ODApXG4gIGlmICghQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHZhbHVlID0gTWF0aC5mbG9vcih2YWx1ZSlcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmICsgdmFsdWUgKyAxXG4gIHRoaXNbb2Zmc2V0XSA9IHZhbHVlXG4gIHJldHVybiBvZmZzZXQgKyAxXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQxNkxFID0gZnVuY3Rpb24gKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCA+Pj4gMFxuICBpZiAoIW5vQXNzZXJ0KVxuICAgIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDIsIDB4N2ZmZiwgLTB4ODAwMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gdmFsdWVcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICB9IGVsc2Ugb2JqZWN0V3JpdGVVSW50MTYodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSlcbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDE2QkUgPSBmdW5jdGlvbiAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0ID4+PiAwXG4gIGlmICghbm9Bc3NlcnQpXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMiwgMHg3ZmZmLCAtMHg4MDAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9IHZhbHVlXG4gIH0gZWxzZSBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDMyTEUgPSBmdW5jdGlvbiAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0ID4+PiAwXG4gIGlmICghbm9Bc3NlcnQpXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgNCwgMHg3ZmZmZmZmZiwgLTB4ODAwMDAwMDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9IHZhbHVlXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDJdID0gKHZhbHVlID4+PiAxNilcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlID4+PiAyNClcbiAgfSBlbHNlIG9iamVjdFdyaXRlVUludDMyKHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQzMkJFID0gZnVuY3Rpb24gKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCA+Pj4gMFxuICBpZiAoIW5vQXNzZXJ0KVxuICAgIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDQsIDB4N2ZmZmZmZmYsIC0weDgwMDAwMDAwKVxuICBpZiAodmFsdWUgPCAwKSB2YWx1ZSA9IDB4ZmZmZmZmZmYgKyB2YWx1ZSArIDFcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlID4+PiAyNClcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiAxNilcbiAgICB0aGlzW29mZnNldCArIDJdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0ICsgM10gPSB2YWx1ZVxuICB9IGVsc2Ugb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbmZ1bmN0aW9uIGNoZWNrSUVFRTc1NCAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBleHQsIG1heCwgbWluKSB7XG4gIGlmICh2YWx1ZSA+IG1heCB8fCB2YWx1ZSA8IG1pbikgdGhyb3cgbmV3IFR5cGVFcnJvcigndmFsdWUgaXMgb3V0IG9mIGJvdW5kcycpXG4gIGlmIChvZmZzZXQgKyBleHQgPiBidWYubGVuZ3RoKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdpbmRleCBvdXQgb2YgcmFuZ2UnKVxufVxuXG5mdW5jdGlvbiB3cml0ZUZsb2F0IChidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydClcbiAgICBjaGVja0lFRUU3NTQoYnVmLCB2YWx1ZSwgb2Zmc2V0LCA0LCAzLjQwMjgyMzQ2NjM4NTI4ODZlKzM4LCAtMy40MDI4MjM0NjYzODUyODg2ZSszOClcbiAgaWVlZTc1NC53cml0ZShidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgMjMsIDQpXG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVGbG9hdExFID0gZnVuY3Rpb24gKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHJldHVybiB3cml0ZUZsb2F0KHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUsIG5vQXNzZXJ0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlRmxvYXRCRSA9IGZ1bmN0aW9uICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVGbG9hdCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSwgbm9Bc3NlcnQpXG59XG5cbmZ1bmN0aW9uIHdyaXRlRG91YmxlIChidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydClcbiAgICBjaGVja0lFRUU3NTQoYnVmLCB2YWx1ZSwgb2Zmc2V0LCA4LCAxLjc5NzY5MzEzNDg2MjMxNTdFKzMwOCwgLTEuNzk3NjkzMTM0ODYyMzE1N0UrMzA4KVxuICBpZWVlNzU0LndyaXRlKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuLCA1MiwgOClcbiAgcmV0dXJuIG9mZnNldCArIDhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZURvdWJsZUxFID0gZnVuY3Rpb24gKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHJldHVybiB3cml0ZURvdWJsZSh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlLCBub0Fzc2VydClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZURvdWJsZUJFID0gZnVuY3Rpb24gKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHJldHVybiB3cml0ZURvdWJsZSh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSwgbm9Bc3NlcnQpXG59XG5cbi8vIGNvcHkodGFyZ2V0QnVmZmVyLCB0YXJnZXRTdGFydD0wLCBzb3VyY2VTdGFydD0wLCBzb3VyY2VFbmQ9YnVmZmVyLmxlbmd0aClcbkJ1ZmZlci5wcm90b3R5cGUuY29weSA9IGZ1bmN0aW9uICh0YXJnZXQsIHRhcmdldF9zdGFydCwgc3RhcnQsIGVuZCkge1xuICB2YXIgc291cmNlID0gdGhpc1xuXG4gIGlmICghc3RhcnQpIHN0YXJ0ID0gMFxuICBpZiAoIWVuZCAmJiBlbmQgIT09IDApIGVuZCA9IHRoaXMubGVuZ3RoXG4gIGlmICghdGFyZ2V0X3N0YXJ0KSB0YXJnZXRfc3RhcnQgPSAwXG5cbiAgLy8gQ29weSAwIGJ5dGVzOyB3ZSdyZSBkb25lXG4gIGlmIChlbmQgPT09IHN0YXJ0KSByZXR1cm5cbiAgaWYgKHRhcmdldC5sZW5ndGggPT09IDAgfHwgc291cmNlLmxlbmd0aCA9PT0gMCkgcmV0dXJuXG5cbiAgLy8gRmF0YWwgZXJyb3IgY29uZGl0aW9uc1xuICBpZiAoZW5kIDwgc3RhcnQpIHRocm93IG5ldyBUeXBlRXJyb3IoJ3NvdXJjZUVuZCA8IHNvdXJjZVN0YXJ0JylcbiAgaWYgKHRhcmdldF9zdGFydCA8IDAgfHwgdGFyZ2V0X3N0YXJ0ID49IHRhcmdldC5sZW5ndGgpXG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcigndGFyZ2V0U3RhcnQgb3V0IG9mIGJvdW5kcycpXG4gIGlmIChzdGFydCA8IDAgfHwgc3RhcnQgPj0gc291cmNlLmxlbmd0aCkgdGhyb3cgbmV3IFR5cGVFcnJvcignc291cmNlU3RhcnQgb3V0IG9mIGJvdW5kcycpXG4gIGlmIChlbmQgPCAwIHx8IGVuZCA+IHNvdXJjZS5sZW5ndGgpIHRocm93IG5ldyBUeXBlRXJyb3IoJ3NvdXJjZUVuZCBvdXQgb2YgYm91bmRzJylcblxuICAvLyBBcmUgd2Ugb29iP1xuICBpZiAoZW5kID4gdGhpcy5sZW5ndGgpXG4gICAgZW5kID0gdGhpcy5sZW5ndGhcbiAgaWYgKHRhcmdldC5sZW5ndGggLSB0YXJnZXRfc3RhcnQgPCBlbmQgLSBzdGFydClcbiAgICBlbmQgPSB0YXJnZXQubGVuZ3RoIC0gdGFyZ2V0X3N0YXJ0ICsgc3RhcnRcblxuICB2YXIgbGVuID0gZW5kIC0gc3RhcnRcblxuICBpZiAobGVuIDwgMTAwMCB8fCAhQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICB0YXJnZXRbaSArIHRhcmdldF9zdGFydF0gPSB0aGlzW2kgKyBzdGFydF1cbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdGFyZ2V0Ll9zZXQodGhpcy5zdWJhcnJheShzdGFydCwgc3RhcnQgKyBsZW4pLCB0YXJnZXRfc3RhcnQpXG4gIH1cbn1cblxuLy8gZmlsbCh2YWx1ZSwgc3RhcnQ9MCwgZW5kPWJ1ZmZlci5sZW5ndGgpXG5CdWZmZXIucHJvdG90eXBlLmZpbGwgPSBmdW5jdGlvbiAodmFsdWUsIHN0YXJ0LCBlbmQpIHtcbiAgaWYgKCF2YWx1ZSkgdmFsdWUgPSAwXG4gIGlmICghc3RhcnQpIHN0YXJ0ID0gMFxuICBpZiAoIWVuZCkgZW5kID0gdGhpcy5sZW5ndGhcblxuICBpZiAoZW5kIDwgc3RhcnQpIHRocm93IG5ldyBUeXBlRXJyb3IoJ2VuZCA8IHN0YXJ0JylcblxuICAvLyBGaWxsIDAgYnl0ZXM7IHdlJ3JlIGRvbmVcbiAgaWYgKGVuZCA9PT0gc3RhcnQpIHJldHVyblxuICBpZiAodGhpcy5sZW5ndGggPT09IDApIHJldHVyblxuXG4gIGlmIChzdGFydCA8IDAgfHwgc3RhcnQgPj0gdGhpcy5sZW5ndGgpIHRocm93IG5ldyBUeXBlRXJyb3IoJ3N0YXJ0IG91dCBvZiBib3VuZHMnKVxuICBpZiAoZW5kIDwgMCB8fCBlbmQgPiB0aGlzLmxlbmd0aCkgdGhyb3cgbmV3IFR5cGVFcnJvcignZW5kIG91dCBvZiBib3VuZHMnKVxuXG4gIHZhciBpXG4gIGlmICh0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInKSB7XG4gICAgZm9yIChpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgICAgdGhpc1tpXSA9IHZhbHVlXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHZhciBieXRlcyA9IHV0ZjhUb0J5dGVzKHZhbHVlLnRvU3RyaW5nKCkpXG4gICAgdmFyIGxlbiA9IGJ5dGVzLmxlbmd0aFxuICAgIGZvciAoaSA9IHN0YXJ0OyBpIDwgZW5kOyBpKyspIHtcbiAgICAgIHRoaXNbaV0gPSBieXRlc1tpICUgbGVuXVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0aGlzXG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIG5ldyBgQXJyYXlCdWZmZXJgIHdpdGggdGhlICpjb3BpZWQqIG1lbW9yeSBvZiB0aGUgYnVmZmVyIGluc3RhbmNlLlxuICogQWRkZWQgaW4gTm9kZSAwLjEyLiBPbmx5IGF2YWlsYWJsZSBpbiBicm93c2VycyB0aGF0IHN1cHBvcnQgQXJyYXlCdWZmZXIuXG4gKi9cbkJ1ZmZlci5wcm90b3R5cGUudG9BcnJheUJ1ZmZlciA9IGZ1bmN0aW9uICgpIHtcbiAgaWYgKHR5cGVvZiBVaW50OEFycmF5ICE9PSAndW5kZWZpbmVkJykge1xuICAgIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgICAgcmV0dXJuIChuZXcgQnVmZmVyKHRoaXMpKS5idWZmZXJcbiAgICB9IGVsc2Uge1xuICAgICAgdmFyIGJ1ZiA9IG5ldyBVaW50OEFycmF5KHRoaXMubGVuZ3RoKVxuICAgICAgZm9yICh2YXIgaSA9IDAsIGxlbiA9IGJ1Zi5sZW5ndGg7IGkgPCBsZW47IGkgKz0gMSkge1xuICAgICAgICBidWZbaV0gPSB0aGlzW2ldXG4gICAgICB9XG4gICAgICByZXR1cm4gYnVmLmJ1ZmZlclxuICAgIH1cbiAgfSBlbHNlIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdCdWZmZXIudG9BcnJheUJ1ZmZlciBub3Qgc3VwcG9ydGVkIGluIHRoaXMgYnJvd3NlcicpXG4gIH1cbn1cblxuLy8gSEVMUEVSIEZVTkNUSU9OU1xuLy8gPT09PT09PT09PT09PT09PVxuXG52YXIgQlAgPSBCdWZmZXIucHJvdG90eXBlXG5cbi8qKlxuICogQXVnbWVudCBhIFVpbnQ4QXJyYXkgKmluc3RhbmNlKiAobm90IHRoZSBVaW50OEFycmF5IGNsYXNzISkgd2l0aCBCdWZmZXIgbWV0aG9kc1xuICovXG5CdWZmZXIuX2F1Z21lbnQgPSBmdW5jdGlvbiAoYXJyKSB7XG4gIGFyci5jb25zdHJ1Y3RvciA9IEJ1ZmZlclxuICBhcnIuX2lzQnVmZmVyID0gdHJ1ZVxuXG4gIC8vIHNhdmUgcmVmZXJlbmNlIHRvIG9yaWdpbmFsIFVpbnQ4QXJyYXkgZ2V0L3NldCBtZXRob2RzIGJlZm9yZSBvdmVyd3JpdGluZ1xuICBhcnIuX2dldCA9IGFyci5nZXRcbiAgYXJyLl9zZXQgPSBhcnIuc2V0XG5cbiAgLy8gZGVwcmVjYXRlZCwgd2lsbCBiZSByZW1vdmVkIGluIG5vZGUgMC4xMytcbiAgYXJyLmdldCA9IEJQLmdldFxuICBhcnIuc2V0ID0gQlAuc2V0XG5cbiAgYXJyLndyaXRlID0gQlAud3JpdGVcbiAgYXJyLnRvU3RyaW5nID0gQlAudG9TdHJpbmdcbiAgYXJyLnRvTG9jYWxlU3RyaW5nID0gQlAudG9TdHJpbmdcbiAgYXJyLnRvSlNPTiA9IEJQLnRvSlNPTlxuICBhcnIuZXF1YWxzID0gQlAuZXF1YWxzXG4gIGFyci5jb21wYXJlID0gQlAuY29tcGFyZVxuICBhcnIuY29weSA9IEJQLmNvcHlcbiAgYXJyLnNsaWNlID0gQlAuc2xpY2VcbiAgYXJyLnJlYWRVSW50OCA9IEJQLnJlYWRVSW50OFxuICBhcnIucmVhZFVJbnQxNkxFID0gQlAucmVhZFVJbnQxNkxFXG4gIGFyci5yZWFkVUludDE2QkUgPSBCUC5yZWFkVUludDE2QkVcbiAgYXJyLnJlYWRVSW50MzJMRSA9IEJQLnJlYWRVSW50MzJMRVxuICBhcnIucmVhZFVJbnQzMkJFID0gQlAucmVhZFVJbnQzMkJFXG4gIGFyci5yZWFkSW50OCA9IEJQLnJlYWRJbnQ4XG4gIGFyci5yZWFkSW50MTZMRSA9IEJQLnJlYWRJbnQxNkxFXG4gIGFyci5yZWFkSW50MTZCRSA9IEJQLnJlYWRJbnQxNkJFXG4gIGFyci5yZWFkSW50MzJMRSA9IEJQLnJlYWRJbnQzMkxFXG4gIGFyci5yZWFkSW50MzJCRSA9IEJQLnJlYWRJbnQzMkJFXG4gIGFyci5yZWFkRmxvYXRMRSA9IEJQLnJlYWRGbG9hdExFXG4gIGFyci5yZWFkRmxvYXRCRSA9IEJQLnJlYWRGbG9hdEJFXG4gIGFyci5yZWFkRG91YmxlTEUgPSBCUC5yZWFkRG91YmxlTEVcbiAgYXJyLnJlYWREb3VibGVCRSA9IEJQLnJlYWREb3VibGVCRVxuICBhcnIud3JpdGVVSW50OCA9IEJQLndyaXRlVUludDhcbiAgYXJyLndyaXRlVUludDE2TEUgPSBCUC53cml0ZVVJbnQxNkxFXG4gIGFyci53cml0ZVVJbnQxNkJFID0gQlAud3JpdGVVSW50MTZCRVxuICBhcnIud3JpdGVVSW50MzJMRSA9IEJQLndyaXRlVUludDMyTEVcbiAgYXJyLndyaXRlVUludDMyQkUgPSBCUC53cml0ZVVJbnQzMkJFXG4gIGFyci53cml0ZUludDggPSBCUC53cml0ZUludDhcbiAgYXJyLndyaXRlSW50MTZMRSA9IEJQLndyaXRlSW50MTZMRVxuICBhcnIud3JpdGVJbnQxNkJFID0gQlAud3JpdGVJbnQxNkJFXG4gIGFyci53cml0ZUludDMyTEUgPSBCUC53cml0ZUludDMyTEVcbiAgYXJyLndyaXRlSW50MzJCRSA9IEJQLndyaXRlSW50MzJCRVxuICBhcnIud3JpdGVGbG9hdExFID0gQlAud3JpdGVGbG9hdExFXG4gIGFyci53cml0ZUZsb2F0QkUgPSBCUC53cml0ZUZsb2F0QkVcbiAgYXJyLndyaXRlRG91YmxlTEUgPSBCUC53cml0ZURvdWJsZUxFXG4gIGFyci53cml0ZURvdWJsZUJFID0gQlAud3JpdGVEb3VibGVCRVxuICBhcnIuZmlsbCA9IEJQLmZpbGxcbiAgYXJyLmluc3BlY3QgPSBCUC5pbnNwZWN0XG4gIGFyci50b0FycmF5QnVmZmVyID0gQlAudG9BcnJheUJ1ZmZlclxuXG4gIHJldHVybiBhcnJcbn1cblxudmFyIElOVkFMSURfQkFTRTY0X1JFID0gL1teK1xcLzAtOUEtel0vZ1xuXG5mdW5jdGlvbiBiYXNlNjRjbGVhbiAoc3RyKSB7XG4gIC8vIE5vZGUgc3RyaXBzIG91dCBpbnZhbGlkIGNoYXJhY3RlcnMgbGlrZSBcXG4gYW5kIFxcdCBmcm9tIHRoZSBzdHJpbmcsIGJhc2U2NC1qcyBkb2VzIG5vdFxuICBzdHIgPSBzdHJpbmd0cmltKHN0cikucmVwbGFjZShJTlZBTElEX0JBU0U2NF9SRSwgJycpXG4gIC8vIE5vZGUgYWxsb3dzIGZvciBub24tcGFkZGVkIGJhc2U2NCBzdHJpbmdzIChtaXNzaW5nIHRyYWlsaW5nID09PSksIGJhc2U2NC1qcyBkb2VzIG5vdFxuICB3aGlsZSAoc3RyLmxlbmd0aCAlIDQgIT09IDApIHtcbiAgICBzdHIgPSBzdHIgKyAnPSdcbiAgfVxuICByZXR1cm4gc3RyXG59XG5cbmZ1bmN0aW9uIHN0cmluZ3RyaW0gKHN0cikge1xuICBpZiAoc3RyLnRyaW0pIHJldHVybiBzdHIudHJpbSgpXG4gIHJldHVybiBzdHIucmVwbGFjZSgvXlxccyt8XFxzKyQvZywgJycpXG59XG5cbmZ1bmN0aW9uIGlzQXJyYXlpc2ggKHN1YmplY3QpIHtcbiAgcmV0dXJuIGlzQXJyYXkoc3ViamVjdCkgfHwgQnVmZmVyLmlzQnVmZmVyKHN1YmplY3QpIHx8XG4gICAgICBzdWJqZWN0ICYmIHR5cGVvZiBzdWJqZWN0ID09PSAnb2JqZWN0JyAmJlxuICAgICAgdHlwZW9mIHN1YmplY3QubGVuZ3RoID09PSAnbnVtYmVyJ1xufVxuXG5mdW5jdGlvbiB0b0hleCAobikge1xuICBpZiAobiA8IDE2KSByZXR1cm4gJzAnICsgbi50b1N0cmluZygxNilcbiAgcmV0dXJuIG4udG9TdHJpbmcoMTYpXG59XG5cbmZ1bmN0aW9uIHV0ZjhUb0J5dGVzIChzdHIpIHtcbiAgdmFyIGJ5dGVBcnJheSA9IFtdXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgc3RyLmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIGIgPSBzdHIuY2hhckNvZGVBdChpKVxuICAgIGlmIChiIDw9IDB4N0YpIHtcbiAgICAgIGJ5dGVBcnJheS5wdXNoKGIpXG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBzdGFydCA9IGlcbiAgICAgIGlmIChiID49IDB4RDgwMCAmJiBiIDw9IDB4REZGRikgaSsrXG4gICAgICB2YXIgaCA9IGVuY29kZVVSSUNvbXBvbmVudChzdHIuc2xpY2Uoc3RhcnQsIGkrMSkpLnN1YnN0cigxKS5zcGxpdCgnJScpXG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IGgubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgYnl0ZUFycmF5LnB1c2gocGFyc2VJbnQoaFtqXSwgMTYpKVxuICAgICAgfVxuICAgIH1cbiAgfVxuICByZXR1cm4gYnl0ZUFycmF5XG59XG5cbmZ1bmN0aW9uIGFzY2lpVG9CeXRlcyAoc3RyKSB7XG4gIHZhciBieXRlQXJyYXkgPSBbXVxuICBmb3IgKHZhciBpID0gMDsgaSA8IHN0ci5sZW5ndGg7IGkrKykge1xuICAgIC8vIE5vZGUncyBjb2RlIHNlZW1zIHRvIGJlIGRvaW5nIHRoaXMgYW5kIG5vdCAmIDB4N0YuLlxuICAgIGJ5dGVBcnJheS5wdXNoKHN0ci5jaGFyQ29kZUF0KGkpICYgMHhGRilcbiAgfVxuICByZXR1cm4gYnl0ZUFycmF5XG59XG5cbmZ1bmN0aW9uIHV0ZjE2bGVUb0J5dGVzIChzdHIpIHtcbiAgdmFyIGMsIGhpLCBsb1xuICB2YXIgYnl0ZUFycmF5ID0gW11cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBzdHIubGVuZ3RoOyBpKyspIHtcbiAgICBjID0gc3RyLmNoYXJDb2RlQXQoaSlcbiAgICBoaSA9IGMgPj4gOFxuICAgIGxvID0gYyAlIDI1NlxuICAgIGJ5dGVBcnJheS5wdXNoKGxvKVxuICAgIGJ5dGVBcnJheS5wdXNoKGhpKVxuICB9XG5cbiAgcmV0dXJuIGJ5dGVBcnJheVxufVxuXG5mdW5jdGlvbiBiYXNlNjRUb0J5dGVzIChzdHIpIHtcbiAgcmV0dXJuIGJhc2U2NC50b0J5dGVBcnJheShzdHIpXG59XG5cbmZ1bmN0aW9uIGJsaXRCdWZmZXIgKHNyYywgZHN0LCBvZmZzZXQsIGxlbmd0aCwgdW5pdFNpemUpIHtcbiAgaWYgKHVuaXRTaXplKSBsZW5ndGggLT0gbGVuZ3RoICUgdW5pdFNpemU7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICBpZiAoKGkgKyBvZmZzZXQgPj0gZHN0Lmxlbmd0aCkgfHwgKGkgPj0gc3JjLmxlbmd0aCkpXG4gICAgICBicmVha1xuICAgIGRzdFtpICsgb2Zmc2V0XSA9IHNyY1tpXVxuICB9XG4gIHJldHVybiBpXG59XG5cbmZ1bmN0aW9uIGRlY29kZVV0ZjhDaGFyIChzdHIpIHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gZGVjb2RlVVJJQ29tcG9uZW50KHN0cilcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgcmV0dXJuIFN0cmluZy5mcm9tQ2hhckNvZGUoMHhGRkZEKSAvLyBVVEYgOCBpbnZhbGlkIGNoYXJcbiAgfVxufVxuIiwidmFyIGxvb2t1cCA9ICdBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OSsvJztcblxuOyhmdW5jdGlvbiAoZXhwb3J0cykge1xuXHQndXNlIHN0cmljdCc7XG5cbiAgdmFyIEFyciA9ICh0eXBlb2YgVWludDhBcnJheSAhPT0gJ3VuZGVmaW5lZCcpXG4gICAgPyBVaW50OEFycmF5XG4gICAgOiBBcnJheVxuXG5cdHZhciBQTFVTICAgPSAnKycuY2hhckNvZGVBdCgwKVxuXHR2YXIgU0xBU0ggID0gJy8nLmNoYXJDb2RlQXQoMClcblx0dmFyIE5VTUJFUiA9ICcwJy5jaGFyQ29kZUF0KDApXG5cdHZhciBMT1dFUiAgPSAnYScuY2hhckNvZGVBdCgwKVxuXHR2YXIgVVBQRVIgID0gJ0EnLmNoYXJDb2RlQXQoMClcblxuXHRmdW5jdGlvbiBkZWNvZGUgKGVsdCkge1xuXHRcdHZhciBjb2RlID0gZWx0LmNoYXJDb2RlQXQoMClcblx0XHRpZiAoY29kZSA9PT0gUExVUylcblx0XHRcdHJldHVybiA2MiAvLyAnKydcblx0XHRpZiAoY29kZSA9PT0gU0xBU0gpXG5cdFx0XHRyZXR1cm4gNjMgLy8gJy8nXG5cdFx0aWYgKGNvZGUgPCBOVU1CRVIpXG5cdFx0XHRyZXR1cm4gLTEgLy9ubyBtYXRjaFxuXHRcdGlmIChjb2RlIDwgTlVNQkVSICsgMTApXG5cdFx0XHRyZXR1cm4gY29kZSAtIE5VTUJFUiArIDI2ICsgMjZcblx0XHRpZiAoY29kZSA8IFVQUEVSICsgMjYpXG5cdFx0XHRyZXR1cm4gY29kZSAtIFVQUEVSXG5cdFx0aWYgKGNvZGUgPCBMT1dFUiArIDI2KVxuXHRcdFx0cmV0dXJuIGNvZGUgLSBMT1dFUiArIDI2XG5cdH1cblxuXHRmdW5jdGlvbiBiNjRUb0J5dGVBcnJheSAoYjY0KSB7XG5cdFx0dmFyIGksIGosIGwsIHRtcCwgcGxhY2VIb2xkZXJzLCBhcnJcblxuXHRcdGlmIChiNjQubGVuZ3RoICUgNCA+IDApIHtcblx0XHRcdHRocm93IG5ldyBFcnJvcignSW52YWxpZCBzdHJpbmcuIExlbmd0aCBtdXN0IGJlIGEgbXVsdGlwbGUgb2YgNCcpXG5cdFx0fVxuXG5cdFx0Ly8gdGhlIG51bWJlciBvZiBlcXVhbCBzaWducyAocGxhY2UgaG9sZGVycylcblx0XHQvLyBpZiB0aGVyZSBhcmUgdHdvIHBsYWNlaG9sZGVycywgdGhhbiB0aGUgdHdvIGNoYXJhY3RlcnMgYmVmb3JlIGl0XG5cdFx0Ly8gcmVwcmVzZW50IG9uZSBieXRlXG5cdFx0Ly8gaWYgdGhlcmUgaXMgb25seSBvbmUsIHRoZW4gdGhlIHRocmVlIGNoYXJhY3RlcnMgYmVmb3JlIGl0IHJlcHJlc2VudCAyIGJ5dGVzXG5cdFx0Ly8gdGhpcyBpcyBqdXN0IGEgY2hlYXAgaGFjayB0byBub3QgZG8gaW5kZXhPZiB0d2ljZVxuXHRcdHZhciBsZW4gPSBiNjQubGVuZ3RoXG5cdFx0cGxhY2VIb2xkZXJzID0gJz0nID09PSBiNjQuY2hhckF0KGxlbiAtIDIpID8gMiA6ICc9JyA9PT0gYjY0LmNoYXJBdChsZW4gLSAxKSA/IDEgOiAwXG5cblx0XHQvLyBiYXNlNjQgaXMgNC8zICsgdXAgdG8gdHdvIGNoYXJhY3RlcnMgb2YgdGhlIG9yaWdpbmFsIGRhdGFcblx0XHRhcnIgPSBuZXcgQXJyKGI2NC5sZW5ndGggKiAzIC8gNCAtIHBsYWNlSG9sZGVycylcblxuXHRcdC8vIGlmIHRoZXJlIGFyZSBwbGFjZWhvbGRlcnMsIG9ubHkgZ2V0IHVwIHRvIHRoZSBsYXN0IGNvbXBsZXRlIDQgY2hhcnNcblx0XHRsID0gcGxhY2VIb2xkZXJzID4gMCA/IGI2NC5sZW5ndGggLSA0IDogYjY0Lmxlbmd0aFxuXG5cdFx0dmFyIEwgPSAwXG5cblx0XHRmdW5jdGlvbiBwdXNoICh2KSB7XG5cdFx0XHRhcnJbTCsrXSA9IHZcblx0XHR9XG5cblx0XHRmb3IgKGkgPSAwLCBqID0gMDsgaSA8IGw7IGkgKz0gNCwgaiArPSAzKSB7XG5cdFx0XHR0bXAgPSAoZGVjb2RlKGI2NC5jaGFyQXQoaSkpIDw8IDE4KSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMSkpIDw8IDEyKSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMikpIDw8IDYpIHwgZGVjb2RlKGI2NC5jaGFyQXQoaSArIDMpKVxuXHRcdFx0cHVzaCgodG1wICYgMHhGRjAwMDApID4+IDE2KVxuXHRcdFx0cHVzaCgodG1wICYgMHhGRjAwKSA+PiA4KVxuXHRcdFx0cHVzaCh0bXAgJiAweEZGKVxuXHRcdH1cblxuXHRcdGlmIChwbGFjZUhvbGRlcnMgPT09IDIpIHtcblx0XHRcdHRtcCA9IChkZWNvZGUoYjY0LmNoYXJBdChpKSkgPDwgMikgfCAoZGVjb2RlKGI2NC5jaGFyQXQoaSArIDEpKSA+PiA0KVxuXHRcdFx0cHVzaCh0bXAgJiAweEZGKVxuXHRcdH0gZWxzZSBpZiAocGxhY2VIb2xkZXJzID09PSAxKSB7XG5cdFx0XHR0bXAgPSAoZGVjb2RlKGI2NC5jaGFyQXQoaSkpIDw8IDEwKSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMSkpIDw8IDQpIHwgKGRlY29kZShiNjQuY2hhckF0KGkgKyAyKSkgPj4gMilcblx0XHRcdHB1c2goKHRtcCA+PiA4KSAmIDB4RkYpXG5cdFx0XHRwdXNoKHRtcCAmIDB4RkYpXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGFyclxuXHR9XG5cblx0ZnVuY3Rpb24gdWludDhUb0Jhc2U2NCAodWludDgpIHtcblx0XHR2YXIgaSxcblx0XHRcdGV4dHJhQnl0ZXMgPSB1aW50OC5sZW5ndGggJSAzLCAvLyBpZiB3ZSBoYXZlIDEgYnl0ZSBsZWZ0LCBwYWQgMiBieXRlc1xuXHRcdFx0b3V0cHV0ID0gXCJcIixcblx0XHRcdHRlbXAsIGxlbmd0aFxuXG5cdFx0ZnVuY3Rpb24gZW5jb2RlIChudW0pIHtcblx0XHRcdHJldHVybiBsb29rdXAuY2hhckF0KG51bSlcblx0XHR9XG5cblx0XHRmdW5jdGlvbiB0cmlwbGV0VG9CYXNlNjQgKG51bSkge1xuXHRcdFx0cmV0dXJuIGVuY29kZShudW0gPj4gMTggJiAweDNGKSArIGVuY29kZShudW0gPj4gMTIgJiAweDNGKSArIGVuY29kZShudW0gPj4gNiAmIDB4M0YpICsgZW5jb2RlKG51bSAmIDB4M0YpXG5cdFx0fVxuXG5cdFx0Ly8gZ28gdGhyb3VnaCB0aGUgYXJyYXkgZXZlcnkgdGhyZWUgYnl0ZXMsIHdlJ2xsIGRlYWwgd2l0aCB0cmFpbGluZyBzdHVmZiBsYXRlclxuXHRcdGZvciAoaSA9IDAsIGxlbmd0aCA9IHVpbnQ4Lmxlbmd0aCAtIGV4dHJhQnl0ZXM7IGkgPCBsZW5ndGg7IGkgKz0gMykge1xuXHRcdFx0dGVtcCA9ICh1aW50OFtpXSA8PCAxNikgKyAodWludDhbaSArIDFdIDw8IDgpICsgKHVpbnQ4W2kgKyAyXSlcblx0XHRcdG91dHB1dCArPSB0cmlwbGV0VG9CYXNlNjQodGVtcClcblx0XHR9XG5cblx0XHQvLyBwYWQgdGhlIGVuZCB3aXRoIHplcm9zLCBidXQgbWFrZSBzdXJlIHRvIG5vdCBmb3JnZXQgdGhlIGV4dHJhIGJ5dGVzXG5cdFx0c3dpdGNoIChleHRyYUJ5dGVzKSB7XG5cdFx0XHRjYXNlIDE6XG5cdFx0XHRcdHRlbXAgPSB1aW50OFt1aW50OC5sZW5ndGggLSAxXVxuXHRcdFx0XHRvdXRwdXQgKz0gZW5jb2RlKHRlbXAgPj4gMilcblx0XHRcdFx0b3V0cHV0ICs9IGVuY29kZSgodGVtcCA8PCA0KSAmIDB4M0YpXG5cdFx0XHRcdG91dHB1dCArPSAnPT0nXG5cdFx0XHRcdGJyZWFrXG5cdFx0XHRjYXNlIDI6XG5cdFx0XHRcdHRlbXAgPSAodWludDhbdWludDgubGVuZ3RoIC0gMl0gPDwgOCkgKyAodWludDhbdWludDgubGVuZ3RoIC0gMV0pXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUodGVtcCA+PiAxMClcblx0XHRcdFx0b3V0cHV0ICs9IGVuY29kZSgodGVtcCA+PiA0KSAmIDB4M0YpXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUoKHRlbXAgPDwgMikgJiAweDNGKVxuXHRcdFx0XHRvdXRwdXQgKz0gJz0nXG5cdFx0XHRcdGJyZWFrXG5cdFx0fVxuXG5cdFx0cmV0dXJuIG91dHB1dFxuXHR9XG5cblx0ZXhwb3J0cy50b0J5dGVBcnJheSA9IGI2NFRvQnl0ZUFycmF5XG5cdGV4cG9ydHMuZnJvbUJ5dGVBcnJheSA9IHVpbnQ4VG9CYXNlNjRcbn0odHlwZW9mIGV4cG9ydHMgPT09ICd1bmRlZmluZWQnID8gKHRoaXMuYmFzZTY0anMgPSB7fSkgOiBleHBvcnRzKSlcbiIsImV4cG9ydHMucmVhZCA9IGZ1bmN0aW9uKGJ1ZmZlciwgb2Zmc2V0LCBpc0xFLCBtTGVuLCBuQnl0ZXMpIHtcbiAgdmFyIGUsIG0sXG4gICAgICBlTGVuID0gbkJ5dGVzICogOCAtIG1MZW4gLSAxLFxuICAgICAgZU1heCA9ICgxIDw8IGVMZW4pIC0gMSxcbiAgICAgIGVCaWFzID0gZU1heCA+PiAxLFxuICAgICAgbkJpdHMgPSAtNyxcbiAgICAgIGkgPSBpc0xFID8gKG5CeXRlcyAtIDEpIDogMCxcbiAgICAgIGQgPSBpc0xFID8gLTEgOiAxLFxuICAgICAgcyA9IGJ1ZmZlcltvZmZzZXQgKyBpXTtcblxuICBpICs9IGQ7XG5cbiAgZSA9IHMgJiAoKDEgPDwgKC1uQml0cykpIC0gMSk7XG4gIHMgPj49ICgtbkJpdHMpO1xuICBuQml0cyArPSBlTGVuO1xuICBmb3IgKDsgbkJpdHMgPiAwOyBlID0gZSAqIDI1NiArIGJ1ZmZlcltvZmZzZXQgKyBpXSwgaSArPSBkLCBuQml0cyAtPSA4KTtcblxuICBtID0gZSAmICgoMSA8PCAoLW5CaXRzKSkgLSAxKTtcbiAgZSA+Pj0gKC1uQml0cyk7XG4gIG5CaXRzICs9IG1MZW47XG4gIGZvciAoOyBuQml0cyA+IDA7IG0gPSBtICogMjU2ICsgYnVmZmVyW29mZnNldCArIGldLCBpICs9IGQsIG5CaXRzIC09IDgpO1xuXG4gIGlmIChlID09PSAwKSB7XG4gICAgZSA9IDEgLSBlQmlhcztcbiAgfSBlbHNlIGlmIChlID09PSBlTWF4KSB7XG4gICAgcmV0dXJuIG0gPyBOYU4gOiAoKHMgPyAtMSA6IDEpICogSW5maW5pdHkpO1xuICB9IGVsc2Uge1xuICAgIG0gPSBtICsgTWF0aC5wb3coMiwgbUxlbik7XG4gICAgZSA9IGUgLSBlQmlhcztcbiAgfVxuICByZXR1cm4gKHMgPyAtMSA6IDEpICogbSAqIE1hdGgucG93KDIsIGUgLSBtTGVuKTtcbn07XG5cbmV4cG9ydHMud3JpdGUgPSBmdW5jdGlvbihidWZmZXIsIHZhbHVlLCBvZmZzZXQsIGlzTEUsIG1MZW4sIG5CeXRlcykge1xuICB2YXIgZSwgbSwgYyxcbiAgICAgIGVMZW4gPSBuQnl0ZXMgKiA4IC0gbUxlbiAtIDEsXG4gICAgICBlTWF4ID0gKDEgPDwgZUxlbikgLSAxLFxuICAgICAgZUJpYXMgPSBlTWF4ID4+IDEsXG4gICAgICBydCA9IChtTGVuID09PSAyMyA/IE1hdGgucG93KDIsIC0yNCkgLSBNYXRoLnBvdygyLCAtNzcpIDogMCksXG4gICAgICBpID0gaXNMRSA/IDAgOiAobkJ5dGVzIC0gMSksXG4gICAgICBkID0gaXNMRSA/IDEgOiAtMSxcbiAgICAgIHMgPSB2YWx1ZSA8IDAgfHwgKHZhbHVlID09PSAwICYmIDEgLyB2YWx1ZSA8IDApID8gMSA6IDA7XG5cbiAgdmFsdWUgPSBNYXRoLmFicyh2YWx1ZSk7XG5cbiAgaWYgKGlzTmFOKHZhbHVlKSB8fCB2YWx1ZSA9PT0gSW5maW5pdHkpIHtcbiAgICBtID0gaXNOYU4odmFsdWUpID8gMSA6IDA7XG4gICAgZSA9IGVNYXg7XG4gIH0gZWxzZSB7XG4gICAgZSA9IE1hdGguZmxvb3IoTWF0aC5sb2codmFsdWUpIC8gTWF0aC5MTjIpO1xuICAgIGlmICh2YWx1ZSAqIChjID0gTWF0aC5wb3coMiwgLWUpKSA8IDEpIHtcbiAgICAgIGUtLTtcbiAgICAgIGMgKj0gMjtcbiAgICB9XG4gICAgaWYgKGUgKyBlQmlhcyA+PSAxKSB7XG4gICAgICB2YWx1ZSArPSBydCAvIGM7XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhbHVlICs9IHJ0ICogTWF0aC5wb3coMiwgMSAtIGVCaWFzKTtcbiAgICB9XG4gICAgaWYgKHZhbHVlICogYyA+PSAyKSB7XG4gICAgICBlKys7XG4gICAgICBjIC89IDI7XG4gICAgfVxuXG4gICAgaWYgKGUgKyBlQmlhcyA+PSBlTWF4KSB7XG4gICAgICBtID0gMDtcbiAgICAgIGUgPSBlTWF4O1xuICAgIH0gZWxzZSBpZiAoZSArIGVCaWFzID49IDEpIHtcbiAgICAgIG0gPSAodmFsdWUgKiBjIC0gMSkgKiBNYXRoLnBvdygyLCBtTGVuKTtcbiAgICAgIGUgPSBlICsgZUJpYXM7XG4gICAgfSBlbHNlIHtcbiAgICAgIG0gPSB2YWx1ZSAqIE1hdGgucG93KDIsIGVCaWFzIC0gMSkgKiBNYXRoLnBvdygyLCBtTGVuKTtcbiAgICAgIGUgPSAwO1xuICAgIH1cbiAgfVxuXG4gIGZvciAoOyBtTGVuID49IDg7IGJ1ZmZlcltvZmZzZXQgKyBpXSA9IG0gJiAweGZmLCBpICs9IGQsIG0gLz0gMjU2LCBtTGVuIC09IDgpO1xuXG4gIGUgPSAoZSA8PCBtTGVuKSB8IG07XG4gIGVMZW4gKz0gbUxlbjtcbiAgZm9yICg7IGVMZW4gPiAwOyBidWZmZXJbb2Zmc2V0ICsgaV0gPSBlICYgMHhmZiwgaSArPSBkLCBlIC89IDI1NiwgZUxlbiAtPSA4KTtcblxuICBidWZmZXJbb2Zmc2V0ICsgaSAtIGRdIHw9IHMgKiAxMjg7XG59O1xuIiwiXG4vKipcbiAqIGlzQXJyYXlcbiAqL1xuXG52YXIgaXNBcnJheSA9IEFycmF5LmlzQXJyYXk7XG5cbi8qKlxuICogdG9TdHJpbmdcbiAqL1xuXG52YXIgc3RyID0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZztcblxuLyoqXG4gKiBXaGV0aGVyIG9yIG5vdCB0aGUgZ2l2ZW4gYHZhbGBcbiAqIGlzIGFuIGFycmF5LlxuICpcbiAqIGV4YW1wbGU6XG4gKlxuICogICAgICAgIGlzQXJyYXkoW10pO1xuICogICAgICAgIC8vID4gdHJ1ZVxuICogICAgICAgIGlzQXJyYXkoYXJndW1lbnRzKTtcbiAqICAgICAgICAvLyA+IGZhbHNlXG4gKiAgICAgICAgaXNBcnJheSgnJyk7XG4gKiAgICAgICAgLy8gPiBmYWxzZVxuICpcbiAqIEBwYXJhbSB7bWl4ZWR9IHZhbFxuICogQHJldHVybiB7Ym9vbH1cbiAqL1xuXG5tb2R1bGUuZXhwb3J0cyA9IGlzQXJyYXkgfHwgZnVuY3Rpb24gKHZhbCkge1xuICByZXR1cm4gISEgdmFsICYmICdbb2JqZWN0IEFycmF5XScgPT0gc3RyLmNhbGwodmFsKTtcbn07XG4iLCIvLyBzaGltIGZvciB1c2luZyBwcm9jZXNzIGluIGJyb3dzZXJcblxudmFyIHByb2Nlc3MgPSBtb2R1bGUuZXhwb3J0cyA9IHt9O1xuXG5wcm9jZXNzLm5leHRUaWNrID0gKGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgY2FuU2V0SW1tZWRpYXRlID0gdHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCdcbiAgICAmJiB3aW5kb3cuc2V0SW1tZWRpYXRlO1xuICAgIHZhciBjYW5NdXRhdGlvbk9ic2VydmVyID0gdHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCdcbiAgICAmJiB3aW5kb3cuTXV0YXRpb25PYnNlcnZlcjtcbiAgICB2YXIgY2FuUG9zdCA9IHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnXG4gICAgJiYgd2luZG93LnBvc3RNZXNzYWdlICYmIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyXG4gICAgO1xuXG4gICAgaWYgKGNhblNldEltbWVkaWF0ZSkge1xuICAgICAgICByZXR1cm4gZnVuY3Rpb24gKGYpIHsgcmV0dXJuIHdpbmRvdy5zZXRJbW1lZGlhdGUoZikgfTtcbiAgICB9XG5cbiAgICB2YXIgcXVldWUgPSBbXTtcblxuICAgIGlmIChjYW5NdXRhdGlvbk9ic2VydmVyKSB7XG4gICAgICAgIHZhciBoaWRkZW5EaXYgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwiZGl2XCIpO1xuICAgICAgICB2YXIgb2JzZXJ2ZXIgPSBuZXcgTXV0YXRpb25PYnNlcnZlcihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgcXVldWVMaXN0ID0gcXVldWUuc2xpY2UoKTtcbiAgICAgICAgICAgIHF1ZXVlLmxlbmd0aCA9IDA7XG4gICAgICAgICAgICBxdWV1ZUxpc3QuZm9yRWFjaChmdW5jdGlvbiAoZm4pIHtcbiAgICAgICAgICAgICAgICBmbigpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIG9ic2VydmVyLm9ic2VydmUoaGlkZGVuRGl2LCB7IGF0dHJpYnV0ZXM6IHRydWUgfSk7XG5cbiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIG5leHRUaWNrKGZuKSB7XG4gICAgICAgICAgICBpZiAoIXF1ZXVlLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIGhpZGRlbkRpdi5zZXRBdHRyaWJ1dGUoJ3llcycsICdubycpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcXVldWUucHVzaChmbik7XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgaWYgKGNhblBvc3QpIHtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ21lc3NhZ2UnLCBmdW5jdGlvbiAoZXYpIHtcbiAgICAgICAgICAgIHZhciBzb3VyY2UgPSBldi5zb3VyY2U7XG4gICAgICAgICAgICBpZiAoKHNvdXJjZSA9PT0gd2luZG93IHx8IHNvdXJjZSA9PT0gbnVsbCkgJiYgZXYuZGF0YSA9PT0gJ3Byb2Nlc3MtdGljaycpIHtcbiAgICAgICAgICAgICAgICBldi5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgICAgICAgICBpZiAocXVldWUubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgZm4gPSBxdWV1ZS5zaGlmdCgpO1xuICAgICAgICAgICAgICAgICAgICBmbigpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSwgdHJ1ZSk7XG5cbiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIG5leHRUaWNrKGZuKSB7XG4gICAgICAgICAgICBxdWV1ZS5wdXNoKGZuKTtcbiAgICAgICAgICAgIHdpbmRvdy5wb3N0TWVzc2FnZSgncHJvY2Vzcy10aWNrJywgJyonKTtcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICByZXR1cm4gZnVuY3Rpb24gbmV4dFRpY2soZm4pIHtcbiAgICAgICAgc2V0VGltZW91dChmbiwgMCk7XG4gICAgfTtcbn0pKCk7XG5cbnByb2Nlc3MudGl0bGUgPSAnYnJvd3Nlcic7XG5wcm9jZXNzLmJyb3dzZXIgPSB0cnVlO1xucHJvY2Vzcy5lbnYgPSB7fTtcbnByb2Nlc3MuYXJndiA9IFtdO1xuXG5mdW5jdGlvbiBub29wKCkge31cblxucHJvY2Vzcy5vbiA9IG5vb3A7XG5wcm9jZXNzLmFkZExpc3RlbmVyID0gbm9vcDtcbnByb2Nlc3Mub25jZSA9IG5vb3A7XG5wcm9jZXNzLm9mZiA9IG5vb3A7XG5wcm9jZXNzLnJlbW92ZUxpc3RlbmVyID0gbm9vcDtcbnByb2Nlc3MucmVtb3ZlQWxsTGlzdGVuZXJzID0gbm9vcDtcbnByb2Nlc3MuZW1pdCA9IG5vb3A7XG5cbnByb2Nlc3MuYmluZGluZyA9IGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdwcm9jZXNzLmJpbmRpbmcgaXMgbm90IHN1cHBvcnRlZCcpO1xufTtcblxuLy8gVE9ETyhzaHR5bG1hbilcbnByb2Nlc3MuY3dkID0gZnVuY3Rpb24gKCkgeyByZXR1cm4gJy8nIH07XG5wcm9jZXNzLmNoZGlyID0gZnVuY3Rpb24gKGRpcikge1xuICAgIHRocm93IG5ldyBFcnJvcigncHJvY2Vzcy5jaGRpciBpcyBub3Qgc3VwcG9ydGVkJyk7XG59O1xuIiwiLyoqXG4gKiBBY3Rpb25zIHRoYXQgbW9kaWZ5IHRoZSBVUkwuXG4gKi9cbnZhciBMb2NhdGlvbkFjdGlvbnMgPSB7XG5cbiAgLyoqXG4gICAqIEluZGljYXRlcyBhIG5ldyBsb2NhdGlvbiBpcyBiZWluZyBwdXNoZWQgdG8gdGhlIGhpc3Rvcnkgc3RhY2suXG4gICAqL1xuICBQVVNIOiAncHVzaCcsXG5cbiAgLyoqXG4gICAqIEluZGljYXRlcyB0aGUgY3VycmVudCBsb2NhdGlvbiBzaG91bGQgYmUgcmVwbGFjZWQuXG4gICAqL1xuICBSRVBMQUNFOiAncmVwbGFjZScsXG5cbiAgLyoqXG4gICAqIEluZGljYXRlcyB0aGUgbW9zdCByZWNlbnQgZW50cnkgc2hvdWxkIGJlIHJlbW92ZWQgZnJvbSB0aGUgaGlzdG9yeSBzdGFjay5cbiAgICovXG4gIFBPUDogJ3BvcCdcblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBMb2NhdGlvbkFjdGlvbnM7XG4iLCJ2YXIgTG9jYXRpb25BY3Rpb25zID0gcmVxdWlyZSgnLi4vYWN0aW9ucy9Mb2NhdGlvbkFjdGlvbnMnKTtcblxuLyoqXG4gKiBBIHNjcm9sbCBiZWhhdmlvciB0aGF0IGF0dGVtcHRzIHRvIGltaXRhdGUgdGhlIGRlZmF1bHQgYmVoYXZpb3JcbiAqIG9mIG1vZGVybiBicm93c2Vycy5cbiAqL1xudmFyIEltaXRhdGVCcm93c2VyQmVoYXZpb3IgPSB7XG5cbiAgdXBkYXRlU2Nyb2xsUG9zaXRpb246IGZ1bmN0aW9uIChwb3NpdGlvbiwgYWN0aW9uVHlwZSkge1xuICAgIHN3aXRjaCAoYWN0aW9uVHlwZSkge1xuICAgICAgY2FzZSBMb2NhdGlvbkFjdGlvbnMuUFVTSDpcbiAgICAgIGNhc2UgTG9jYXRpb25BY3Rpb25zLlJFUExBQ0U6XG4gICAgICAgIHdpbmRvdy5zY3JvbGxUbygwLCAwKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIExvY2F0aW9uQWN0aW9ucy5QT1A6XG4gICAgICAgIGlmIChwb3NpdGlvbikge1xuICAgICAgICAgIHdpbmRvdy5zY3JvbGxUbyhwb3NpdGlvbi54LCBwb3NpdGlvbi55KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB3aW5kb3cuc2Nyb2xsVG8oMCwgMCk7XG4gICAgICAgIH1cbiAgICAgICAgYnJlYWs7XG4gICAgfVxuICB9XG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gSW1pdGF0ZUJyb3dzZXJCZWhhdmlvcjtcbiIsIi8qKlxuICogQSBzY3JvbGwgYmVoYXZpb3IgdGhhdCBhbHdheXMgc2Nyb2xscyB0byB0aGUgdG9wIG9mIHRoZSBwYWdlXG4gKiBhZnRlciBhIHRyYW5zaXRpb24uXG4gKi9cbnZhciBTY3JvbGxUb1RvcEJlaGF2aW9yID0ge1xuXG4gIHVwZGF0ZVNjcm9sbFBvc2l0aW9uOiBmdW5jdGlvbiAoKSB7XG4gICAgd2luZG93LnNjcm9sbFRvKDAsIDApO1xuICB9XG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gU2Nyb2xsVG9Ub3BCZWhhdmlvcjtcbiIsInZhciBSZWFjdCA9IHJlcXVpcmUoJ3JlYWN0Jyk7XG52YXIgRmFrZU5vZGUgPSByZXF1aXJlKCcuLi9taXhpbnMvRmFrZU5vZGUnKTtcbnZhciBQcm9wVHlwZXMgPSByZXF1aXJlKCcuLi91dGlscy9Qcm9wVHlwZXMnKTtcblxuLyoqXG4gKiBBIDxEZWZhdWx0Um91dGU+IGNvbXBvbmVudCBpcyBhIHNwZWNpYWwga2luZCBvZiA8Um91dGU+IHRoYXRcbiAqIHJlbmRlcnMgd2hlbiBpdHMgcGFyZW50IG1hdGNoZXMgYnV0IG5vbmUgb2YgaXRzIHNpYmxpbmdzIGRvLlxuICogT25seSBvbmUgc3VjaCByb3V0ZSBtYXkgYmUgdXNlZCBhdCBhbnkgZ2l2ZW4gbGV2ZWwgaW4gdGhlXG4gKiByb3V0ZSBoaWVyYXJjaHkuXG4gKi9cbnZhciBEZWZhdWx0Um91dGUgPSBSZWFjdC5jcmVhdGVDbGFzcyh7XG5cbiAgZGlzcGxheU5hbWU6ICdEZWZhdWx0Um91dGUnLFxuXG4gIG1peGluczogWyBGYWtlTm9kZSBdLFxuXG4gIHByb3BUeXBlczoge1xuICAgIG5hbWU6IFJlYWN0LlByb3BUeXBlcy5zdHJpbmcsXG4gICAgcGF0aDogUHJvcFR5cGVzLmZhbHN5LFxuICAgIGhhbmRsZXI6IFJlYWN0LlByb3BUeXBlcy5mdW5jLmlzUmVxdWlyZWRcbiAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBEZWZhdWx0Um91dGU7XG4iLCJ2YXIgUmVhY3QgPSByZXF1aXJlKCdyZWFjdCcpO1xudmFyIGNsYXNzU2V0ID0gcmVxdWlyZSgncmVhY3QvbGliL2N4Jyk7XG52YXIgYXNzaWduID0gcmVxdWlyZSgncmVhY3QvbGliL09iamVjdC5hc3NpZ24nKTtcbnZhciBOYXZpZ2F0aW9uID0gcmVxdWlyZSgnLi4vbWl4aW5zL05hdmlnYXRpb24nKTtcbnZhciBTdGF0ZSA9IHJlcXVpcmUoJy4uL21peGlucy9TdGF0ZScpO1xuXG5mdW5jdGlvbiBpc0xlZnRDbGlja0V2ZW50KGV2ZW50KSB7XG4gIHJldHVybiBldmVudC5idXR0b24gPT09IDA7XG59XG5cbmZ1bmN0aW9uIGlzTW9kaWZpZWRFdmVudChldmVudCkge1xuICByZXR1cm4gISEoZXZlbnQubWV0YUtleSB8fCBldmVudC5hbHRLZXkgfHwgZXZlbnQuY3RybEtleSB8fCBldmVudC5zaGlmdEtleSk7XG59XG5cbi8qKlxuICogPExpbms+IGNvbXBvbmVudHMgYXJlIHVzZWQgdG8gY3JlYXRlIGFuIDxhPiBlbGVtZW50IHRoYXQgbGlua3MgdG8gYSByb3V0ZS5cbiAqIFdoZW4gdGhhdCByb3V0ZSBpcyBhY3RpdmUsIHRoZSBsaW5rIGdldHMgYW4gXCJhY3RpdmVcIiBjbGFzcyBuYW1lIChvciB0aGVcbiAqIHZhbHVlIG9mIGl0cyBgYWN0aXZlQ2xhc3NOYW1lYCBwcm9wKS5cbiAqXG4gKiBGb3IgZXhhbXBsZSwgYXNzdW1pbmcgeW91IGhhdmUgdGhlIGZvbGxvd2luZyByb3V0ZTpcbiAqXG4gKiAgIDxSb3V0ZSBuYW1lPVwic2hvd1Bvc3RcIiBwYXRoPVwiL3Bvc3RzLzpwb3N0SURcIiBoYW5kbGVyPXtQb3N0fS8+XG4gKlxuICogWW91IGNvdWxkIHVzZSB0aGUgZm9sbG93aW5nIGNvbXBvbmVudCB0byBsaW5rIHRvIHRoYXQgcm91dGU6XG4gKlxuICogICA8TGluayB0bz1cInNob3dQb3N0XCIgcGFyYW1zPXt7IHBvc3RJRDogXCIxMjNcIiB9fSAvPlxuICpcbiAqIEluIGFkZGl0aW9uIHRvIHBhcmFtcywgbGlua3MgbWF5IHBhc3MgYWxvbmcgcXVlcnkgc3RyaW5nIHBhcmFtZXRlcnNcbiAqIHVzaW5nIHRoZSBgcXVlcnlgIHByb3AuXG4gKlxuICogICA8TGluayB0bz1cInNob3dQb3N0XCIgcGFyYW1zPXt7IHBvc3RJRDogXCIxMjNcIiB9fSBxdWVyeT17eyBzaG93OnRydWUgfX0vPlxuICovXG52YXIgTGluayA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtcblxuICBkaXNwbGF5TmFtZTogJ0xpbmsnLFxuXG4gIG1peGluczogWyBOYXZpZ2F0aW9uLCBTdGF0ZSBdLFxuXG4gIHByb3BUeXBlczoge1xuICAgIGFjdGl2ZUNsYXNzTmFtZTogUmVhY3QuUHJvcFR5cGVzLnN0cmluZy5pc1JlcXVpcmVkLFxuICAgIHRvOiBSZWFjdC5Qcm9wVHlwZXMuc3RyaW5nLmlzUmVxdWlyZWQsXG4gICAgcGFyYW1zOiBSZWFjdC5Qcm9wVHlwZXMub2JqZWN0LFxuICAgIHF1ZXJ5OiBSZWFjdC5Qcm9wVHlwZXMub2JqZWN0LFxuICAgIG9uQ2xpY2s6IFJlYWN0LlByb3BUeXBlcy5mdW5jXG4gIH0sXG5cbiAgZ2V0RGVmYXVsdFByb3BzOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGFjdGl2ZUNsYXNzTmFtZTogJ2FjdGl2ZSdcbiAgICB9O1xuICB9LFxuXG4gIGhhbmRsZUNsaWNrOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICB2YXIgYWxsb3dUcmFuc2l0aW9uID0gdHJ1ZTtcbiAgICB2YXIgY2xpY2tSZXN1bHQ7XG5cbiAgICBpZiAodGhpcy5wcm9wcy5vbkNsaWNrKVxuICAgICAgY2xpY2tSZXN1bHQgPSB0aGlzLnByb3BzLm9uQ2xpY2soZXZlbnQpO1xuXG4gICAgaWYgKGlzTW9kaWZpZWRFdmVudChldmVudCkgfHwgIWlzTGVmdENsaWNrRXZlbnQoZXZlbnQpKVxuICAgICAgcmV0dXJuO1xuXG4gICAgaWYgKGNsaWNrUmVzdWx0ID09PSBmYWxzZSB8fCBldmVudC5kZWZhdWx0UHJldmVudGVkID09PSB0cnVlKVxuICAgICAgYWxsb3dUcmFuc2l0aW9uID0gZmFsc2U7XG5cbiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG4gICAgaWYgKGFsbG93VHJhbnNpdGlvbilcbiAgICAgIHRoaXMudHJhbnNpdGlvblRvKHRoaXMucHJvcHMudG8sIHRoaXMucHJvcHMucGFyYW1zLCB0aGlzLnByb3BzLnF1ZXJ5KTtcbiAgfSxcblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgdmFsdWUgb2YgdGhlIFwiaHJlZlwiIGF0dHJpYnV0ZSB0byB1c2Ugb24gdGhlIERPTSBlbGVtZW50LlxuICAgKi9cbiAgZ2V0SHJlZjogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLm1ha2VIcmVmKHRoaXMucHJvcHMudG8sIHRoaXMucHJvcHMucGFyYW1zLCB0aGlzLnByb3BzLnF1ZXJ5KTtcbiAgfSxcblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgdmFsdWUgb2YgdGhlIFwiY2xhc3NcIiBhdHRyaWJ1dGUgdG8gdXNlIG9uIHRoZSBET00gZWxlbWVudCwgd2hpY2ggY29udGFpbnNcbiAgICogdGhlIHZhbHVlIG9mIHRoZSBhY3RpdmVDbGFzc05hbWUgcHJvcGVydHkgd2hlbiB0aGlzIDxMaW5rPiBpcyBhY3RpdmUuXG4gICAqL1xuICBnZXRDbGFzc05hbWU6IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgY2xhc3NOYW1lcyA9IHt9O1xuXG4gICAgaWYgKHRoaXMucHJvcHMuY2xhc3NOYW1lKVxuICAgICAgY2xhc3NOYW1lc1t0aGlzLnByb3BzLmNsYXNzTmFtZV0gPSB0cnVlO1xuXG4gICAgaWYgKHRoaXMuaXNBY3RpdmUodGhpcy5wcm9wcy50bywgdGhpcy5wcm9wcy5wYXJhbXMsIHRoaXMucHJvcHMucXVlcnkpKVxuICAgICAgY2xhc3NOYW1lc1t0aGlzLnByb3BzLmFjdGl2ZUNsYXNzTmFtZV0gPSB0cnVlO1xuXG4gICAgcmV0dXJuIGNsYXNzU2V0KGNsYXNzTmFtZXMpO1xuICB9LFxuXG4gIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgIHZhciBwcm9wcyA9IGFzc2lnbih7fSwgdGhpcy5wcm9wcywge1xuICAgICAgaHJlZjogdGhpcy5nZXRIcmVmKCksXG4gICAgICBjbGFzc05hbWU6IHRoaXMuZ2V0Q2xhc3NOYW1lKCksXG4gICAgICBvbkNsaWNrOiB0aGlzLmhhbmRsZUNsaWNrXG4gICAgfSk7XG5cbiAgICByZXR1cm4gUmVhY3QuRE9NLmEocHJvcHMsIHRoaXMucHJvcHMuY2hpbGRyZW4pO1xuICB9XG5cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IExpbms7XG4iLCJ2YXIgUmVhY3QgPSByZXF1aXJlKCdyZWFjdCcpO1xudmFyIEZha2VOb2RlID0gcmVxdWlyZSgnLi4vbWl4aW5zL0Zha2VOb2RlJyk7XG52YXIgUHJvcFR5cGVzID0gcmVxdWlyZSgnLi4vdXRpbHMvUHJvcFR5cGVzJyk7XG5cbi8qKlxuICogQSA8Tm90Rm91bmRSb3V0ZT4gaXMgYSBzcGVjaWFsIGtpbmQgb2YgPFJvdXRlPiB0aGF0XG4gKiByZW5kZXJzIHdoZW4gdGhlIGJlZ2lubmluZyBvZiBpdHMgcGFyZW50J3MgcGF0aCBtYXRjaGVzXG4gKiBidXQgbm9uZSBvZiBpdHMgc2libGluZ3MgZG8sIGluY2x1ZGluZyBhbnkgPERlZmF1bHRSb3V0ZT4uXG4gKiBPbmx5IG9uZSBzdWNoIHJvdXRlIG1heSBiZSB1c2VkIGF0IGFueSBnaXZlbiBsZXZlbCBpbiB0aGVcbiAqIHJvdXRlIGhpZXJhcmNoeS5cbiAqL1xudmFyIE5vdEZvdW5kUm91dGUgPSBSZWFjdC5jcmVhdGVDbGFzcyh7XG5cbiAgZGlzcGxheU5hbWU6ICdOb3RGb3VuZFJvdXRlJyxcblxuICBtaXhpbnM6IFsgRmFrZU5vZGUgXSxcblxuICBwcm9wVHlwZXM6IHtcbiAgICBuYW1lOiBSZWFjdC5Qcm9wVHlwZXMuc3RyaW5nLFxuICAgIHBhdGg6IFByb3BUeXBlcy5mYWxzeSxcbiAgICBoYW5kbGVyOiBSZWFjdC5Qcm9wVHlwZXMuZnVuYy5pc1JlcXVpcmVkXG4gIH1cblxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gTm90Rm91bmRSb3V0ZTtcbiIsInZhciBSZWFjdCA9IHJlcXVpcmUoJ3JlYWN0Jyk7XG52YXIgRmFrZU5vZGUgPSByZXF1aXJlKCcuLi9taXhpbnMvRmFrZU5vZGUnKTtcbnZhciBQcm9wVHlwZXMgPSByZXF1aXJlKCcuLi91dGlscy9Qcm9wVHlwZXMnKTtcblxuLyoqXG4gKiBBIDxSZWRpcmVjdD4gY29tcG9uZW50IGlzIGEgc3BlY2lhbCBraW5kIG9mIDxSb3V0ZT4gdGhhdCBhbHdheXNcbiAqIHJlZGlyZWN0cyB0byBhbm90aGVyIHJvdXRlIHdoZW4gaXQgbWF0Y2hlcy5cbiAqL1xudmFyIFJlZGlyZWN0ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe1xuXG4gIGRpc3BsYXlOYW1lOiAnUmVkaXJlY3QnLFxuXG4gIG1peGluczogWyBGYWtlTm9kZSBdLFxuXG4gIHByb3BUeXBlczoge1xuICAgIHBhdGg6IFJlYWN0LlByb3BUeXBlcy5zdHJpbmcsXG4gICAgZnJvbTogUmVhY3QuUHJvcFR5cGVzLnN0cmluZywgLy8gQWxpYXMgZm9yIHBhdGguXG4gICAgdG86IFJlYWN0LlByb3BUeXBlcy5zdHJpbmcsXG4gICAgaGFuZGxlcjogUHJvcFR5cGVzLmZhbHN5XG4gIH1cblxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gUmVkaXJlY3Q7XG4iLCJ2YXIgUmVhY3QgPSByZXF1aXJlKCdyZWFjdCcpO1xudmFyIEZha2VOb2RlID0gcmVxdWlyZSgnLi4vbWl4aW5zL0Zha2VOb2RlJyk7XG5cbi8qKlxuICogPFJvdXRlPiBjb21wb25lbnRzIHNwZWNpZnkgY29tcG9uZW50cyB0aGF0IGFyZSByZW5kZXJlZCB0byB0aGUgcGFnZSB3aGVuIHRoZVxuICogVVJMIG1hdGNoZXMgYSBnaXZlbiBwYXR0ZXJuLlxuICpcbiAqIFJvdXRlcyBhcmUgYXJyYW5nZWQgaW4gYSBuZXN0ZWQgdHJlZSBzdHJ1Y3R1cmUuIFdoZW4gYSBuZXcgVVJMIGlzIHJlcXVlc3RlZCxcbiAqIHRoZSB0cmVlIGlzIHNlYXJjaGVkIGRlcHRoLWZpcnN0IHRvIGZpbmQgYSByb3V0ZSB3aG9zZSBwYXRoIG1hdGNoZXMgdGhlIFVSTC5cbiAqIFdoZW4gb25lIGlzIGZvdW5kLCBhbGwgcm91dGVzIGluIHRoZSB0cmVlIHRoYXQgbGVhZCB0byBpdCBhcmUgY29uc2lkZXJlZFxuICogXCJhY3RpdmVcIiBhbmQgdGhlaXIgY29tcG9uZW50cyBhcmUgcmVuZGVyZWQgaW50byB0aGUgRE9NLCBuZXN0ZWQgaW4gdGhlIHNhbWVcbiAqIG9yZGVyIGFzIHRoZXkgYXJlIGluIHRoZSB0cmVlLlxuICpcbiAqIFRoZSBwcmVmZXJyZWQgd2F5IHRvIGNvbmZpZ3VyZSBhIHJvdXRlciBpcyB1c2luZyBKU1guIFRoZSBYTUwtbGlrZSBzeW50YXggaXNcbiAqIGEgZ3JlYXQgd2F5IHRvIHZpc3VhbGl6ZSBob3cgcm91dGVzIGFyZSBsYWlkIG91dCBpbiBhbiBhcHBsaWNhdGlvbi5cbiAqXG4gKiAgIHZhciByb3V0ZXMgPSBbXG4gKiAgICAgPFJvdXRlIGhhbmRsZXI9e0FwcH0+XG4gKiAgICAgICA8Um91dGUgbmFtZT1cImxvZ2luXCIgaGFuZGxlcj17TG9naW59Lz5cbiAqICAgICAgIDxSb3V0ZSBuYW1lPVwibG9nb3V0XCIgaGFuZGxlcj17TG9nb3V0fS8+XG4gKiAgICAgICA8Um91dGUgbmFtZT1cImFib3V0XCIgaGFuZGxlcj17QWJvdXR9Lz5cbiAqICAgICA8L1JvdXRlPlxuICogICBdO1xuICogICBcbiAqICAgUm91dGVyLnJ1bihyb3V0ZXMsIGZ1bmN0aW9uIChIYW5kbGVyKSB7XG4gKiAgICAgUmVhY3QucmVuZGVyKDxIYW5kbGVyLz4sIGRvY3VtZW50LmJvZHkpO1xuICogICB9KTtcbiAqXG4gKiBIYW5kbGVycyBmb3IgUm91dGUgY29tcG9uZW50cyB0aGF0IGNvbnRhaW4gY2hpbGRyZW4gY2FuIHJlbmRlciB0aGVpciBhY3RpdmVcbiAqIGNoaWxkIHJvdXRlIHVzaW5nIGEgPFJvdXRlSGFuZGxlcj4gZWxlbWVudC5cbiAqXG4gKiAgIHZhciBBcHAgPSBSZWFjdC5jcmVhdGVDbGFzcyh7XG4gKiAgICAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG4gKiAgICAgICByZXR1cm4gKFxuICogICAgICAgICA8ZGl2IGNsYXNzPVwiYXBwbGljYXRpb25cIj5cbiAqICAgICAgICAgICA8Um91dGVIYW5kbGVyLz5cbiAqICAgICAgICAgPC9kaXY+XG4gKiAgICAgICApO1xuICogICAgIH1cbiAqICAgfSk7XG4gKi9cbnZhciBSb3V0ZSA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtcblxuICBkaXNwbGF5TmFtZTogJ1JvdXRlJyxcblxuICBtaXhpbnM6IFsgRmFrZU5vZGUgXSxcblxuICBwcm9wVHlwZXM6IHtcbiAgICBuYW1lOiBSZWFjdC5Qcm9wVHlwZXMuc3RyaW5nLFxuICAgIHBhdGg6IFJlYWN0LlByb3BUeXBlcy5zdHJpbmcsXG4gICAgaGFuZGxlcjogUmVhY3QuUHJvcFR5cGVzLmZ1bmMuaXNSZXF1aXJlZCxcbiAgICBpZ25vcmVTY3JvbGxCZWhhdmlvcjogUmVhY3QuUHJvcFR5cGVzLmJvb2xcbiAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBSb3V0ZTtcbiIsInZhciBSZWFjdCA9IHJlcXVpcmUoJ3JlYWN0Jyk7XG52YXIgUm91dGVIYW5kbGVyTWl4aW4gPSByZXF1aXJlKCcuLi9taXhpbnMvUm91dGVIYW5kbGVyJyk7XG5cbi8qKlxuICogQSA8Um91dGVIYW5kbGVyPiBjb21wb25lbnQgcmVuZGVycyB0aGUgYWN0aXZlIGNoaWxkIHJvdXRlIGhhbmRsZXJcbiAqIHdoZW4gcm91dGVzIGFyZSBuZXN0ZWQuXG4gKi9cbnZhciBSb3V0ZUhhbmRsZXIgPSBSZWFjdC5jcmVhdGVDbGFzcyh7XG5cbiAgZGlzcGxheU5hbWU6ICdSb3V0ZUhhbmRsZXInLFxuXG4gIG1peGluczogW1JvdXRlSGFuZGxlck1peGluXSxcblxuICBnZXREZWZhdWx0UHJvcHM6IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgcmVmOiAnX19yb3V0ZUhhbmRsZXJfXydcbiAgICB9O1xuICB9LFxuXG4gIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLmdldFJvdXRlSGFuZGxlcigpO1xuICB9XG5cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJvdXRlSGFuZGxlcjtcbiIsInZhciBMb2NhdGlvbkFjdGlvbnMgPSByZXF1aXJlKCcuLi9hY3Rpb25zL0xvY2F0aW9uQWN0aW9ucycpO1xudmFyIEhpc3RvcnkgPSByZXF1aXJlKCcuLi91dGlscy9IaXN0b3J5Jyk7XG52YXIgUGF0aCA9IHJlcXVpcmUoJy4uL3V0aWxzL1BhdGgnKTtcblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBjdXJyZW50IFVSTCBwYXRoIGZyb20gdGhlIGBoYXNoYCBwb3J0aW9uIG9mIHRoZSBVUkwsIGluY2x1ZGluZ1xuICogcXVlcnkgc3RyaW5nLlxuICovXG5mdW5jdGlvbiBnZXRIYXNoUGF0aCgpIHtcbiAgcmV0dXJuIFBhdGguZGVjb2RlKFxuICAgIC8vIFdlIGNhbid0IHVzZSB3aW5kb3cubG9jYXRpb24uaGFzaCBoZXJlIGJlY2F1c2UgaXQncyBub3RcbiAgICAvLyBjb25zaXN0ZW50IGFjcm9zcyBicm93c2VycyAtIEZpcmVmb3ggd2lsbCBwcmUtZGVjb2RlIGl0IVxuICAgIHdpbmRvdy5sb2NhdGlvbi5ocmVmLnNwbGl0KCcjJylbMV0gfHwgJydcbiAgKTtcbn1cblxudmFyIF9hY3Rpb25UeXBlO1xuXG5mdW5jdGlvbiBlbnN1cmVTbGFzaCgpIHtcbiAgdmFyIHBhdGggPSBnZXRIYXNoUGF0aCgpO1xuXG4gIGlmIChwYXRoLmNoYXJBdCgwKSA9PT0gJy8nKVxuICAgIHJldHVybiB0cnVlO1xuXG4gIEhhc2hMb2NhdGlvbi5yZXBsYWNlKCcvJyArIHBhdGgpO1xuXG4gIHJldHVybiBmYWxzZTtcbn1cblxudmFyIF9jaGFuZ2VMaXN0ZW5lcnMgPSBbXTtcblxuZnVuY3Rpb24gbm90aWZ5Q2hhbmdlKHR5cGUpIHtcbiAgaWYgKHR5cGUgPT09IExvY2F0aW9uQWN0aW9ucy5QVVNIKVxuICAgIEhpc3RvcnkubGVuZ3RoICs9IDE7XG5cbiAgdmFyIGNoYW5nZSA9IHtcbiAgICBwYXRoOiBnZXRIYXNoUGF0aCgpLFxuICAgIHR5cGU6IHR5cGVcbiAgfTtcblxuICBfY2hhbmdlTGlzdGVuZXJzLmZvckVhY2goZnVuY3Rpb24gKGxpc3RlbmVyKSB7XG4gICAgbGlzdGVuZXIoY2hhbmdlKTtcbiAgfSk7XG59XG5cbnZhciBfaXNMaXN0ZW5pbmcgPSBmYWxzZTtcblxuZnVuY3Rpb24gb25IYXNoQ2hhbmdlKCkge1xuICBpZiAoZW5zdXJlU2xhc2goKSkge1xuICAgIC8vIElmIHdlIGRvbid0IGhhdmUgYW4gX2FjdGlvblR5cGUgdGhlbiBhbGwgd2Uga25vdyBpcyB0aGUgaGFzaFxuICAgIC8vIGNoYW5nZWQuIEl0IHdhcyBwcm9iYWJseSBjYXVzZWQgYnkgdGhlIHVzZXIgY2xpY2tpbmcgdGhlIEJhY2tcbiAgICAvLyBidXR0b24sIGJ1dCBtYXkgaGF2ZSBhbHNvIGJlZW4gdGhlIEZvcndhcmQgYnV0dG9uIG9yIG1hbnVhbFxuICAgIC8vIG1hbmlwdWxhdGlvbi4gU28ganVzdCBndWVzcyAncG9wJy5cbiAgICBub3RpZnlDaGFuZ2UoX2FjdGlvblR5cGUgfHwgTG9jYXRpb25BY3Rpb25zLlBPUCk7XG4gICAgX2FjdGlvblR5cGUgPSBudWxsO1xuICB9XG59XG5cbi8qKlxuICogQSBMb2NhdGlvbiB0aGF0IHVzZXMgYHdpbmRvdy5sb2NhdGlvbi5oYXNoYC5cbiAqL1xudmFyIEhhc2hMb2NhdGlvbiA9IHtcblxuICBhZGRDaGFuZ2VMaXN0ZW5lcjogZnVuY3Rpb24gKGxpc3RlbmVyKSB7XG4gICAgX2NoYW5nZUxpc3RlbmVycy5wdXNoKGxpc3RlbmVyKTtcblxuICAgIC8vIERvIHRoaXMgQkVGT1JFIGxpc3RlbmluZyBmb3IgaGFzaGNoYW5nZS5cbiAgICBlbnN1cmVTbGFzaCgpO1xuXG4gICAgaWYgKF9pc0xpc3RlbmluZylcbiAgICAgIHJldHVybjtcblxuICAgIGlmICh3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcikge1xuICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ2hhc2hjaGFuZ2UnLCBvbkhhc2hDaGFuZ2UsIGZhbHNlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgd2luZG93LmF0dGFjaEV2ZW50KCdvbmhhc2hjaGFuZ2UnLCBvbkhhc2hDaGFuZ2UpO1xuICAgIH1cblxuICAgIF9pc0xpc3RlbmluZyA9IHRydWU7XG4gIH0sXG5cbiAgcmVtb3ZlQ2hhbmdlTGlzdGVuZXI6IGZ1bmN0aW9uKGxpc3RlbmVyKSB7XG4gICAgZm9yICh2YXIgaSA9IDAsIGwgPSBfY2hhbmdlTGlzdGVuZXJzLmxlbmd0aDsgaSA8IGw7IGkgKyspIHtcbiAgICAgIGlmIChfY2hhbmdlTGlzdGVuZXJzW2ldID09PSBsaXN0ZW5lcikge1xuICAgICAgICBfY2hhbmdlTGlzdGVuZXJzLnNwbGljZShpLCAxKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKSB7XG4gICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcignaGFzaGNoYW5nZScsIG9uSGFzaENoYW5nZSwgZmFsc2UpO1xuICAgIH0gZWxzZSB7XG4gICAgICB3aW5kb3cucmVtb3ZlRXZlbnQoJ29uaGFzaGNoYW5nZScsIG9uSGFzaENoYW5nZSk7XG4gICAgfVxuXG4gICAgaWYgKF9jaGFuZ2VMaXN0ZW5lcnMubGVuZ3RoID09PSAwKVxuICAgICAgX2lzTGlzdGVuaW5nID0gZmFsc2U7XG4gIH0sXG5cblxuXG4gIHB1c2g6IGZ1bmN0aW9uIChwYXRoKSB7XG4gICAgX2FjdGlvblR5cGUgPSBMb2NhdGlvbkFjdGlvbnMuUFVTSDtcbiAgICB3aW5kb3cubG9jYXRpb24uaGFzaCA9IFBhdGguZW5jb2RlKHBhdGgpO1xuICB9LFxuXG4gIHJlcGxhY2U6IGZ1bmN0aW9uIChwYXRoKSB7XG4gICAgX2FjdGlvblR5cGUgPSBMb2NhdGlvbkFjdGlvbnMuUkVQTEFDRTtcbiAgICB3aW5kb3cubG9jYXRpb24ucmVwbGFjZSh3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUgKyAnIycgKyBQYXRoLmVuY29kZShwYXRoKSk7XG4gIH0sXG5cbiAgcG9wOiBmdW5jdGlvbiAoKSB7XG4gICAgX2FjdGlvblR5cGUgPSBMb2NhdGlvbkFjdGlvbnMuUE9QO1xuICAgIEhpc3RvcnkuYmFjaygpO1xuICB9LFxuXG4gIGdldEN1cnJlbnRQYXRoOiBnZXRIYXNoUGF0aCxcblxuICB0b1N0cmluZzogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiAnPEhhc2hMb2NhdGlvbj4nO1xuICB9XG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gSGFzaExvY2F0aW9uO1xuIiwidmFyIExvY2F0aW9uQWN0aW9ucyA9IHJlcXVpcmUoJy4uL2FjdGlvbnMvTG9jYXRpb25BY3Rpb25zJyk7XG52YXIgSGlzdG9yeSA9IHJlcXVpcmUoJy4uL3V0aWxzL0hpc3RvcnknKTtcbnZhciBQYXRoID0gcmVxdWlyZSgnLi4vdXRpbHMvUGF0aCcpO1xuXG4vKipcbiAqIFJldHVybnMgdGhlIGN1cnJlbnQgVVJMIHBhdGggZnJvbSBgd2luZG93LmxvY2F0aW9uYCwgaW5jbHVkaW5nIHF1ZXJ5IHN0cmluZy5cbiAqL1xuZnVuY3Rpb24gZ2V0V2luZG93UGF0aCgpIHtcbiAgcmV0dXJuIFBhdGguZGVjb2RlKFxuICAgIHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZSArIHdpbmRvdy5sb2NhdGlvbi5zZWFyY2hcbiAgKTtcbn1cblxudmFyIF9jaGFuZ2VMaXN0ZW5lcnMgPSBbXTtcblxuZnVuY3Rpb24gbm90aWZ5Q2hhbmdlKHR5cGUpIHtcbiAgdmFyIGNoYW5nZSA9IHtcbiAgICBwYXRoOiBnZXRXaW5kb3dQYXRoKCksXG4gICAgdHlwZTogdHlwZVxuICB9O1xuXG4gIF9jaGFuZ2VMaXN0ZW5lcnMuZm9yRWFjaChmdW5jdGlvbiAobGlzdGVuZXIpIHtcbiAgICBsaXN0ZW5lcihjaGFuZ2UpO1xuICB9KTtcbn1cblxudmFyIF9pc0xpc3RlbmluZyA9IGZhbHNlO1xuXG5mdW5jdGlvbiBvblBvcFN0YXRlKCkge1xuICBub3RpZnlDaGFuZ2UoTG9jYXRpb25BY3Rpb25zLlBPUCk7XG59XG5cbi8qKlxuICogQSBMb2NhdGlvbiB0aGF0IHVzZXMgSFRNTDUgaGlzdG9yeS5cbiAqL1xudmFyIEhpc3RvcnlMb2NhdGlvbiA9IHtcblxuICBhZGRDaGFuZ2VMaXN0ZW5lcjogZnVuY3Rpb24gKGxpc3RlbmVyKSB7XG4gICAgX2NoYW5nZUxpc3RlbmVycy5wdXNoKGxpc3RlbmVyKTtcblxuICAgIGlmIChfaXNMaXN0ZW5pbmcpXG4gICAgICByZXR1cm47XG5cbiAgICBpZiAod2luZG93LmFkZEV2ZW50TGlzdGVuZXIpIHtcbiAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdwb3BzdGF0ZScsIG9uUG9wU3RhdGUsIGZhbHNlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgd2luZG93LmF0dGFjaEV2ZW50KCdwb3BzdGF0ZScsIG9uUG9wU3RhdGUpO1xuICAgIH1cblxuICAgIF9pc0xpc3RlbmluZyA9IHRydWU7XG4gIH0sXG5cbiAgcmVtb3ZlQ2hhbmdlTGlzdGVuZXI6IGZ1bmN0aW9uKGxpc3RlbmVyKSB7XG4gICAgZm9yICh2YXIgaSA9IDAsIGwgPSBfY2hhbmdlTGlzdGVuZXJzLmxlbmd0aDsgaSA8IGw7IGkgKyspIHtcbiAgICAgIGlmIChfY2hhbmdlTGlzdGVuZXJzW2ldID09PSBsaXN0ZW5lcikge1xuICAgICAgICBfY2hhbmdlTGlzdGVuZXJzLnNwbGljZShpLCAxKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKSB7XG4gICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcigncG9wc3RhdGUnLCBvblBvcFN0YXRlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgd2luZG93LnJlbW92ZUV2ZW50KCdwb3BzdGF0ZScsIG9uUG9wU3RhdGUpO1xuICAgIH1cblxuICAgIGlmIChfY2hhbmdlTGlzdGVuZXJzLmxlbmd0aCA9PT0gMClcbiAgICAgIF9pc0xpc3RlbmluZyA9IGZhbHNlO1xuICB9LFxuXG5cblxuICBwdXNoOiBmdW5jdGlvbiAocGF0aCkge1xuICAgIHdpbmRvdy5oaXN0b3J5LnB1c2hTdGF0ZSh7IHBhdGg6IHBhdGggfSwgJycsIFBhdGguZW5jb2RlKHBhdGgpKTtcbiAgICBIaXN0b3J5Lmxlbmd0aCArPSAxO1xuICAgIG5vdGlmeUNoYW5nZShMb2NhdGlvbkFjdGlvbnMuUFVTSCk7XG4gIH0sXG5cbiAgcmVwbGFjZTogZnVuY3Rpb24gKHBhdGgpIHtcbiAgICB3aW5kb3cuaGlzdG9yeS5yZXBsYWNlU3RhdGUoeyBwYXRoOiBwYXRoIH0sICcnLCBQYXRoLmVuY29kZShwYXRoKSk7XG4gICAgbm90aWZ5Q2hhbmdlKExvY2F0aW9uQWN0aW9ucy5SRVBMQUNFKTtcbiAgfSxcblxuICBwb3A6IEhpc3RvcnkuYmFjayxcblxuICBnZXRDdXJyZW50UGF0aDogZ2V0V2luZG93UGF0aCxcblxuICB0b1N0cmluZzogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiAnPEhpc3RvcnlMb2NhdGlvbj4nO1xuICB9XG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gSGlzdG9yeUxvY2F0aW9uO1xuIiwidmFyIEhpc3RvcnlMb2NhdGlvbiA9IHJlcXVpcmUoJy4vSGlzdG9yeUxvY2F0aW9uJyk7XG52YXIgSGlzdG9yeSA9IHJlcXVpcmUoJy4uL3V0aWxzL0hpc3RvcnknKTtcbnZhciBQYXRoID0gcmVxdWlyZSgnLi4vdXRpbHMvUGF0aCcpO1xuXG4vKipcbiAqIEEgTG9jYXRpb24gdGhhdCB1c2VzIGZ1bGwgcGFnZSByZWZyZXNoZXMuIFRoaXMgaXMgdXNlZCBhc1xuICogdGhlIGZhbGxiYWNrIGZvciBIaXN0b3J5TG9jYXRpb24gaW4gYnJvd3NlcnMgdGhhdCBkbyBub3RcbiAqIHN1cHBvcnQgdGhlIEhUTUw1IGhpc3RvcnkgQVBJLlxuICovXG52YXIgUmVmcmVzaExvY2F0aW9uID0ge1xuXG4gIHB1c2g6IGZ1bmN0aW9uIChwYXRoKSB7XG4gICAgd2luZG93LmxvY2F0aW9uID0gUGF0aC5lbmNvZGUocGF0aCk7XG4gIH0sXG5cbiAgcmVwbGFjZTogZnVuY3Rpb24gKHBhdGgpIHtcbiAgICB3aW5kb3cubG9jYXRpb24ucmVwbGFjZShQYXRoLmVuY29kZShwYXRoKSk7XG4gIH0sXG5cbiAgcG9wOiBIaXN0b3J5LmJhY2ssXG5cbiAgZ2V0Q3VycmVudFBhdGg6IEhpc3RvcnlMb2NhdGlvbi5nZXRDdXJyZW50UGF0aCxcblxuICB0b1N0cmluZzogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiAnPFJlZnJlc2hMb2NhdGlvbj4nO1xuICB9XG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUmVmcmVzaExvY2F0aW9uO1xuIiwidmFyIGludmFyaWFudCA9IHJlcXVpcmUoJ3JlYWN0L2xpYi9pbnZhcmlhbnQnKTtcblxudmFyIEZha2VOb2RlID0ge1xuXG4gIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgIGludmFyaWFudChcbiAgICAgIGZhbHNlLFxuICAgICAgJyVzIGVsZW1lbnRzIHNob3VsZCBub3QgYmUgcmVuZGVyZWQnLFxuICAgICAgdGhpcy5jb25zdHJ1Y3Rvci5kaXNwbGF5TmFtZVxuICAgICk7XG4gIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBGYWtlTm9kZTtcbiIsInZhciBSZWFjdCA9IHJlcXVpcmUoJ3JlYWN0Jyk7XG5cbi8qKlxuICogQSBtaXhpbiBmb3IgY29tcG9uZW50cyB0aGF0IG1vZGlmeSB0aGUgVVJMLlxuICpcbiAqIEV4YW1wbGU6XG4gKlxuICogICB2YXIgTXlMaW5rID0gUmVhY3QuY3JlYXRlQ2xhc3Moe1xuICogICAgIG1peGluczogWyBSb3V0ZXIuTmF2aWdhdGlvbiBdLFxuICogICAgIGhhbmRsZUNsaWNrOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAqICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gKiAgICAgICB0aGlzLnRyYW5zaXRpb25UbygnYVJvdXRlJywgeyB0aGU6ICdwYXJhbXMnIH0sIHsgdGhlOiAncXVlcnknIH0pO1xuICogICAgIH0sXG4gKiAgICAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG4gKiAgICAgICByZXR1cm4gKFxuICogICAgICAgICA8YSBvbkNsaWNrPXt0aGlzLmhhbmRsZUNsaWNrfT5DbGljayBtZSE8L2E+XG4gKiAgICAgICApO1xuICogICAgIH1cbiAqICAgfSk7XG4gKi9cbnZhciBOYXZpZ2F0aW9uID0ge1xuXG4gIGNvbnRleHRUeXBlczoge1xuICAgIG1ha2VQYXRoOiBSZWFjdC5Qcm9wVHlwZXMuZnVuYy5pc1JlcXVpcmVkLFxuICAgIG1ha2VIcmVmOiBSZWFjdC5Qcm9wVHlwZXMuZnVuYy5pc1JlcXVpcmVkLFxuICAgIHRyYW5zaXRpb25UbzogUmVhY3QuUHJvcFR5cGVzLmZ1bmMuaXNSZXF1aXJlZCxcbiAgICByZXBsYWNlV2l0aDogUmVhY3QuUHJvcFR5cGVzLmZ1bmMuaXNSZXF1aXJlZCxcbiAgICBnb0JhY2s6IFJlYWN0LlByb3BUeXBlcy5mdW5jLmlzUmVxdWlyZWRcbiAgfSxcblxuICAvKipcbiAgICogUmV0dXJucyBhbiBhYnNvbHV0ZSBVUkwgcGF0aCBjcmVhdGVkIGZyb20gdGhlIGdpdmVuIHJvdXRlXG4gICAqIG5hbWUsIFVSTCBwYXJhbWV0ZXJzLCBhbmQgcXVlcnkgdmFsdWVzLlxuICAgKi9cbiAgbWFrZVBhdGg6IGZ1bmN0aW9uICh0bywgcGFyYW1zLCBxdWVyeSkge1xuICAgIHJldHVybiB0aGlzLmNvbnRleHQubWFrZVBhdGgodG8sIHBhcmFtcywgcXVlcnkpO1xuICB9LFxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGEgc3RyaW5nIHRoYXQgbWF5IHNhZmVseSBiZSB1c2VkIGFzIHRoZSBocmVmIG9mIGFcbiAgICogbGluayB0byB0aGUgcm91dGUgd2l0aCB0aGUgZ2l2ZW4gbmFtZS5cbiAgICovXG4gIG1ha2VIcmVmOiBmdW5jdGlvbiAodG8sIHBhcmFtcywgcXVlcnkpIHtcbiAgICByZXR1cm4gdGhpcy5jb250ZXh0Lm1ha2VIcmVmKHRvLCBwYXJhbXMsIHF1ZXJ5KTtcbiAgfSxcblxuICAvKipcbiAgICogVHJhbnNpdGlvbnMgdG8gdGhlIFVSTCBzcGVjaWZpZWQgaW4gdGhlIGFyZ3VtZW50cyBieSBwdXNoaW5nXG4gICAqIGEgbmV3IFVSTCBvbnRvIHRoZSBoaXN0b3J5IHN0YWNrLlxuICAgKi9cbiAgdHJhbnNpdGlvblRvOiBmdW5jdGlvbiAodG8sIHBhcmFtcywgcXVlcnkpIHtcbiAgICB0aGlzLmNvbnRleHQudHJhbnNpdGlvblRvKHRvLCBwYXJhbXMsIHF1ZXJ5KTtcbiAgfSxcblxuICAvKipcbiAgICogVHJhbnNpdGlvbnMgdG8gdGhlIFVSTCBzcGVjaWZpZWQgaW4gdGhlIGFyZ3VtZW50cyBieSByZXBsYWNpbmdcbiAgICogdGhlIGN1cnJlbnQgVVJMIGluIHRoZSBoaXN0b3J5IHN0YWNrLlxuICAgKi9cbiAgcmVwbGFjZVdpdGg6IGZ1bmN0aW9uICh0bywgcGFyYW1zLCBxdWVyeSkge1xuICAgIHRoaXMuY29udGV4dC5yZXBsYWNlV2l0aCh0bywgcGFyYW1zLCBxdWVyeSk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFRyYW5zaXRpb25zIHRvIHRoZSBwcmV2aW91cyBVUkwuXG4gICAqL1xuICBnb0JhY2s6IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmNvbnRleHQuZ29CYWNrKCk7XG4gIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBOYXZpZ2F0aW9uO1xuIiwidmFyIFJlYWN0ID0gcmVxdWlyZSgncmVhY3QnKTtcblxuLyoqXG4gKiBQcm92aWRlcyB0aGUgcm91dGVyIHdpdGggY29udGV4dCBmb3IgUm91dGVyLk5hdmlnYXRpb24uXG4gKi9cbnZhciBOYXZpZ2F0aW9uQ29udGV4dCA9IHtcblxuICBjaGlsZENvbnRleHRUeXBlczoge1xuICAgIG1ha2VQYXRoOiBSZWFjdC5Qcm9wVHlwZXMuZnVuYy5pc1JlcXVpcmVkLFxuICAgIG1ha2VIcmVmOiBSZWFjdC5Qcm9wVHlwZXMuZnVuYy5pc1JlcXVpcmVkLFxuICAgIHRyYW5zaXRpb25UbzogUmVhY3QuUHJvcFR5cGVzLmZ1bmMuaXNSZXF1aXJlZCxcbiAgICByZXBsYWNlV2l0aDogUmVhY3QuUHJvcFR5cGVzLmZ1bmMuaXNSZXF1aXJlZCxcbiAgICBnb0JhY2s6IFJlYWN0LlByb3BUeXBlcy5mdW5jLmlzUmVxdWlyZWRcbiAgfSxcblxuICBnZXRDaGlsZENvbnRleHQ6IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgbWFrZVBhdGg6IHRoaXMuY29uc3RydWN0b3IubWFrZVBhdGgsXG4gICAgICBtYWtlSHJlZjogdGhpcy5jb25zdHJ1Y3Rvci5tYWtlSHJlZixcbiAgICAgIHRyYW5zaXRpb25UbzogdGhpcy5jb25zdHJ1Y3Rvci50cmFuc2l0aW9uVG8sXG4gICAgICByZXBsYWNlV2l0aDogdGhpcy5jb25zdHJ1Y3Rvci5yZXBsYWNlV2l0aCxcbiAgICAgIGdvQmFjazogdGhpcy5jb25zdHJ1Y3Rvci5nb0JhY2tcbiAgICB9O1xuICB9XG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gTmF2aWdhdGlvbkNvbnRleHQ7XG4iLCJ2YXIgUmVhY3QgPSByZXF1aXJlKCdyZWFjdCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgY29udGV4dFR5cGVzOiB7XG4gICAgZ2V0Um91dGVBdERlcHRoOiBSZWFjdC5Qcm9wVHlwZXMuZnVuYy5pc1JlcXVpcmVkLFxuICAgIGdldFJvdXRlQ29tcG9uZW50czogUmVhY3QuUHJvcFR5cGVzLmZ1bmMuaXNSZXF1aXJlZCxcbiAgICByb3V0ZUhhbmRsZXJzOiBSZWFjdC5Qcm9wVHlwZXMuYXJyYXkuaXNSZXF1aXJlZFxuICB9LFxuXG4gIGNoaWxkQ29udGV4dFR5cGVzOiB7XG4gICAgcm91dGVIYW5kbGVyczogUmVhY3QuUHJvcFR5cGVzLmFycmF5LmlzUmVxdWlyZWRcbiAgfSxcblxuICBnZXRDaGlsZENvbnRleHQ6IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgcm91dGVIYW5kbGVyczogdGhpcy5jb250ZXh0LnJvdXRlSGFuZGxlcnMuY29uY2F0KFsgdGhpcyBdKVxuICAgIH07XG4gIH0sXG5cbiAgZ2V0Um91dGVEZXB0aDogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLmNvbnRleHQucm91dGVIYW5kbGVycy5sZW5ndGggLSAxO1xuICB9LFxuXG4gIGNvbXBvbmVudERpZE1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5fdXBkYXRlUm91dGVDb21wb25lbnQoKTtcbiAgfSxcblxuICBjb21wb25lbnREaWRVcGRhdGU6IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLl91cGRhdGVSb3V0ZUNvbXBvbmVudCgpO1xuICB9LFxuXG4gIF91cGRhdGVSb3V0ZUNvbXBvbmVudDogZnVuY3Rpb24gKCkge1xuICAgIHZhciBkZXB0aCA9IHRoaXMuZ2V0Um91dGVEZXB0aCgpO1xuICAgIHZhciBjb21wb25lbnRzID0gdGhpcy5jb250ZXh0LmdldFJvdXRlQ29tcG9uZW50cygpO1xuICAgIGNvbXBvbmVudHNbZGVwdGhdID0gdGhpcy5yZWZzW3RoaXMucHJvcHMucmVmIHx8ICdfX3JvdXRlSGFuZGxlcl9fJ107XG4gIH0sXG5cbiAgZ2V0Um91dGVIYW5kbGVyOiBmdW5jdGlvbiAocHJvcHMpIHtcbiAgICB2YXIgcm91dGUgPSB0aGlzLmNvbnRleHQuZ2V0Um91dGVBdERlcHRoKHRoaXMuZ2V0Um91dGVEZXB0aCgpKTtcbiAgICByZXR1cm4gcm91dGUgPyBSZWFjdC5jcmVhdGVFbGVtZW50KHJvdXRlLmhhbmRsZXIsIHByb3BzIHx8IHRoaXMucHJvcHMpIDogbnVsbDtcbiAgfVxufTsiLCJ2YXIgaW52YXJpYW50ID0gcmVxdWlyZSgncmVhY3QvbGliL2ludmFyaWFudCcpO1xudmFyIGNhblVzZURPTSA9IHJlcXVpcmUoJ3JlYWN0L2xpYi9FeGVjdXRpb25FbnZpcm9ubWVudCcpLmNhblVzZURPTTtcbnZhciBnZXRXaW5kb3dTY3JvbGxQb3NpdGlvbiA9IHJlcXVpcmUoJy4uL3V0aWxzL2dldFdpbmRvd1Njcm9sbFBvc2l0aW9uJyk7XG5cbmZ1bmN0aW9uIHNob3VsZFVwZGF0ZVNjcm9sbChzdGF0ZSwgcHJldlN0YXRlKSB7XG4gIGlmICghcHJldlN0YXRlKVxuICAgIHJldHVybiB0cnVlO1xuXG4gIC8vIERvbid0IHVwZGF0ZSBzY3JvbGwgcG9zaXRpb24gd2hlbiBvbmx5IHRoZSBxdWVyeSBoYXMgY2hhbmdlZC5cbiAgaWYgKHN0YXRlLnBhdGhuYW1lID09PSBwcmV2U3RhdGUucGF0aG5hbWUpXG4gICAgcmV0dXJuIGZhbHNlO1xuXG4gIHZhciByb3V0ZXMgPSBzdGF0ZS5yb3V0ZXM7XG4gIHZhciBwcmV2Um91dGVzID0gcHJldlN0YXRlLnJvdXRlcztcblxuICB2YXIgc2hhcmVkQW5jZXN0b3JSb3V0ZXMgPSByb3V0ZXMuZmlsdGVyKGZ1bmN0aW9uIChyb3V0ZSkge1xuICAgIHJldHVybiBwcmV2Um91dGVzLmluZGV4T2Yocm91dGUpICE9PSAtMTtcbiAgfSk7XG5cbiAgcmV0dXJuICFzaGFyZWRBbmNlc3RvclJvdXRlcy5zb21lKGZ1bmN0aW9uIChyb3V0ZSkge1xuICAgIHJldHVybiByb3V0ZS5pZ25vcmVTY3JvbGxCZWhhdmlvcjtcbiAgfSk7XG59XG5cbi8qKlxuICogUHJvdmlkZXMgdGhlIHJvdXRlciB3aXRoIHRoZSBhYmlsaXR5IHRvIG1hbmFnZSB3aW5kb3cgc2Nyb2xsIHBvc2l0aW9uXG4gKiBhY2NvcmRpbmcgdG8gaXRzIHNjcm9sbCBiZWhhdmlvci5cbiAqL1xudmFyIFNjcm9sbGluZyA9IHtcblxuICBzdGF0aWNzOiB7XG4gICAgLyoqXG4gICAgICogUmVjb3JkcyBjdXJlbnQgc2Nyb2xsIHBvc2l0aW9uIGFzIHRoZSBsYXN0IGtub3duIHBvc2l0aW9uIGZvciB0aGUgZ2l2ZW4gVVJMIHBhdGguXG4gICAgICovXG4gICAgcmVjb3JkU2Nyb2xsUG9zaXRpb246IGZ1bmN0aW9uIChwYXRoKSB7XG4gICAgICBpZiAoIXRoaXMuc2Nyb2xsSGlzdG9yeSlcbiAgICAgICAgdGhpcy5zY3JvbGxIaXN0b3J5ID0ge307XG5cbiAgICAgIHRoaXMuc2Nyb2xsSGlzdG9yeVtwYXRoXSA9IGdldFdpbmRvd1Njcm9sbFBvc2l0aW9uKCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGxhc3Qga25vd24gc2Nyb2xsIHBvc2l0aW9uIGZvciB0aGUgZ2l2ZW4gVVJMIHBhdGguXG4gICAgICovXG4gICAgZ2V0U2Nyb2xsUG9zaXRpb246IGZ1bmN0aW9uIChwYXRoKSB7XG4gICAgICBpZiAoIXRoaXMuc2Nyb2xsSGlzdG9yeSlcbiAgICAgICAgdGhpcy5zY3JvbGxIaXN0b3J5ID0ge307XG5cbiAgICAgIHJldHVybiB0aGlzLnNjcm9sbEhpc3RvcnlbcGF0aF0gfHwgbnVsbDtcbiAgICB9XG4gIH0sXG5cbiAgY29tcG9uZW50V2lsbE1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgaW52YXJpYW50KFxuICAgICAgdGhpcy5nZXRTY3JvbGxCZWhhdmlvcigpID09IG51bGwgfHwgY2FuVXNlRE9NLFxuICAgICAgJ0Nhbm5vdCB1c2Ugc2Nyb2xsIGJlaGF2aW9yIHdpdGhvdXQgYSBET00nXG4gICAgKTtcbiAgfSxcblxuICBjb21wb25lbnREaWRNb3VudDogZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuX3VwZGF0ZVNjcm9sbCgpO1xuICB9LFxuXG4gIGNvbXBvbmVudERpZFVwZGF0ZTogZnVuY3Rpb24gKHByZXZQcm9wcywgcHJldlN0YXRlKSB7XG4gICAgdGhpcy5fdXBkYXRlU2Nyb2xsKHByZXZTdGF0ZSk7XG4gIH0sXG5cbiAgX3VwZGF0ZVNjcm9sbDogZnVuY3Rpb24gKHByZXZTdGF0ZSkge1xuICAgIGlmICghc2hvdWxkVXBkYXRlU2Nyb2xsKHRoaXMuc3RhdGUsIHByZXZTdGF0ZSkpXG4gICAgICByZXR1cm47XG5cbiAgICB2YXIgc2Nyb2xsQmVoYXZpb3IgPSB0aGlzLmdldFNjcm9sbEJlaGF2aW9yKCk7XG5cbiAgICBpZiAoc2Nyb2xsQmVoYXZpb3IpXG4gICAgICBzY3JvbGxCZWhhdmlvci51cGRhdGVTY3JvbGxQb3NpdGlvbihcbiAgICAgICAgdGhpcy5jb25zdHJ1Y3Rvci5nZXRTY3JvbGxQb3NpdGlvbih0aGlzLnN0YXRlLnBhdGgpLFxuICAgICAgICB0aGlzLnN0YXRlLmFjdGlvblxuICAgICAgKTtcbiAgfVxuXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFNjcm9sbGluZztcbiIsInZhciBSZWFjdCA9IHJlcXVpcmUoJ3JlYWN0Jyk7XG5cbi8qKlxuICogQSBtaXhpbiBmb3IgY29tcG9uZW50cyB0aGF0IG5lZWQgdG8ga25vdyB0aGUgcGF0aCwgcm91dGVzLCBVUkxcbiAqIHBhcmFtcyBhbmQgcXVlcnkgdGhhdCBhcmUgY3VycmVudGx5IGFjdGl2ZS5cbiAqXG4gKiBFeGFtcGxlOlxuICpcbiAqICAgdmFyIEFib3V0TGluayA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtcbiAqICAgICBtaXhpbnM6IFsgUm91dGVyLlN0YXRlIF0sXG4gKiAgICAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG4gKiAgICAgICB2YXIgY2xhc3NOYW1lID0gdGhpcy5wcm9wcy5jbGFzc05hbWU7XG4gKiAgIFxuICogICAgICAgaWYgKHRoaXMuaXNBY3RpdmUoJ2Fib3V0JykpXG4gKiAgICAgICAgIGNsYXNzTmFtZSArPSAnIGlzLWFjdGl2ZSc7XG4gKiAgIFxuICogICAgICAgcmV0dXJuIFJlYWN0LkRPTS5hKHsgY2xhc3NOYW1lOiBjbGFzc05hbWUgfSwgdGhpcy5wcm9wcy5jaGlsZHJlbik7XG4gKiAgICAgfVxuICogICB9KTtcbiAqL1xudmFyIFN0YXRlID0ge1xuXG4gIGNvbnRleHRUeXBlczoge1xuICAgIGdldEN1cnJlbnRQYXRoOiBSZWFjdC5Qcm9wVHlwZXMuZnVuYy5pc1JlcXVpcmVkLFxuICAgIGdldEN1cnJlbnRSb3V0ZXM6IFJlYWN0LlByb3BUeXBlcy5mdW5jLmlzUmVxdWlyZWQsXG4gICAgZ2V0Q3VycmVudFBhdGhuYW1lOiBSZWFjdC5Qcm9wVHlwZXMuZnVuYy5pc1JlcXVpcmVkLFxuICAgIGdldEN1cnJlbnRQYXJhbXM6IFJlYWN0LlByb3BUeXBlcy5mdW5jLmlzUmVxdWlyZWQsXG4gICAgZ2V0Q3VycmVudFF1ZXJ5OiBSZWFjdC5Qcm9wVHlwZXMuZnVuYy5pc1JlcXVpcmVkLFxuICAgIGlzQWN0aXZlOiBSZWFjdC5Qcm9wVHlwZXMuZnVuYy5pc1JlcXVpcmVkXG4gIH0sXG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGN1cnJlbnQgVVJMIHBhdGguXG4gICAqL1xuICBnZXRQYXRoOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuY29udGV4dC5nZXRDdXJyZW50UGF0aCgpO1xuICB9LFxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGFuIGFycmF5IG9mIHRoZSByb3V0ZXMgdGhhdCBhcmUgY3VycmVudGx5IGFjdGl2ZS5cbiAgICovXG4gIGdldFJvdXRlczogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLmNvbnRleHQuZ2V0Q3VycmVudFJvdXRlcygpO1xuICB9LFxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IFVSTCBwYXRoIHdpdGhvdXQgdGhlIHF1ZXJ5IHN0cmluZy5cbiAgICovXG4gIGdldFBhdGhuYW1lOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuY29udGV4dC5nZXRDdXJyZW50UGF0aG5hbWUoKTtcbiAgfSxcblxuICAvKipcbiAgICogUmV0dXJucyBhbiBvYmplY3Qgb2YgdGhlIFVSTCBwYXJhbXMgdGhhdCBhcmUgY3VycmVudGx5IGFjdGl2ZS5cbiAgICovXG4gIGdldFBhcmFtczogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLmNvbnRleHQuZ2V0Q3VycmVudFBhcmFtcygpO1xuICB9LFxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGFuIG9iamVjdCBvZiB0aGUgcXVlcnkgcGFyYW1zIHRoYXQgYXJlIGN1cnJlbnRseSBhY3RpdmUuXG4gICAqL1xuICBnZXRRdWVyeTogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLmNvbnRleHQuZ2V0Q3VycmVudFF1ZXJ5KCk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEEgaGVscGVyIG1ldGhvZCB0byBkZXRlcm1pbmUgaWYgYSBnaXZlbiByb3V0ZSwgcGFyYW1zLCBhbmQgcXVlcnlcbiAgICogYXJlIGFjdGl2ZS5cbiAgICovXG4gIGlzQWN0aXZlOiBmdW5jdGlvbiAodG8sIHBhcmFtcywgcXVlcnkpIHtcbiAgICByZXR1cm4gdGhpcy5jb250ZXh0LmlzQWN0aXZlKHRvLCBwYXJhbXMsIHF1ZXJ5KTtcbiAgfVxuXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0YXRlO1xuIiwidmFyIFJlYWN0ID0gcmVxdWlyZSgncmVhY3QnKTtcbnZhciBhc3NpZ24gPSByZXF1aXJlKCdyZWFjdC9saWIvT2JqZWN0LmFzc2lnbicpO1xudmFyIFBhdGggPSByZXF1aXJlKCcuLi91dGlscy9QYXRoJyk7XG5cbmZ1bmN0aW9uIHJvdXRlSXNBY3RpdmUoYWN0aXZlUm91dGVzLCByb3V0ZU5hbWUpIHtcbiAgcmV0dXJuIGFjdGl2ZVJvdXRlcy5zb21lKGZ1bmN0aW9uIChyb3V0ZSkge1xuICAgIHJldHVybiByb3V0ZS5uYW1lID09PSByb3V0ZU5hbWU7XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBwYXJhbXNBcmVBY3RpdmUoYWN0aXZlUGFyYW1zLCBwYXJhbXMpIHtcbiAgZm9yICh2YXIgcHJvcGVydHkgaW4gcGFyYW1zKVxuICAgIGlmIChTdHJpbmcoYWN0aXZlUGFyYW1zW3Byb3BlcnR5XSkgIT09IFN0cmluZyhwYXJhbXNbcHJvcGVydHldKSlcbiAgICAgIHJldHVybiBmYWxzZTtcblxuICByZXR1cm4gdHJ1ZTtcbn1cblxuZnVuY3Rpb24gcXVlcnlJc0FjdGl2ZShhY3RpdmVRdWVyeSwgcXVlcnkpIHtcbiAgZm9yICh2YXIgcHJvcGVydHkgaW4gcXVlcnkpXG4gICAgaWYgKFN0cmluZyhhY3RpdmVRdWVyeVtwcm9wZXJ0eV0pICE9PSBTdHJpbmcocXVlcnlbcHJvcGVydHldKSlcbiAgICAgIHJldHVybiBmYWxzZTtcblxuICByZXR1cm4gdHJ1ZTtcbn1cblxuLyoqXG4gKiBQcm92aWRlcyB0aGUgcm91dGVyIHdpdGggY29udGV4dCBmb3IgUm91dGVyLlN0YXRlLlxuICovXG52YXIgU3RhdGVDb250ZXh0ID0ge1xuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IFVSTCBwYXRoICsgcXVlcnkgc3RyaW5nLlxuICAgKi9cbiAgZ2V0Q3VycmVudFBhdGg6IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5zdGF0ZS5wYXRoO1xuICB9LFxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGEgcmVhZC1vbmx5IGFycmF5IG9mIHRoZSBjdXJyZW50bHkgYWN0aXZlIHJvdXRlcy5cbiAgICovXG4gIGdldEN1cnJlbnRSb3V0ZXM6IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5zdGF0ZS5yb3V0ZXMuc2xpY2UoMCk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGN1cnJlbnQgVVJMIHBhdGggd2l0aG91dCB0aGUgcXVlcnkgc3RyaW5nLlxuICAgKi9cbiAgZ2V0Q3VycmVudFBhdGhuYW1lOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuc3RhdGUucGF0aG5hbWU7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSByZWFkLW9ubHkgb2JqZWN0IG9mIHRoZSBjdXJyZW50bHkgYWN0aXZlIFVSTCBwYXJhbWV0ZXJzLlxuICAgKi9cbiAgZ2V0Q3VycmVudFBhcmFtczogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBhc3NpZ24oe30sIHRoaXMuc3RhdGUucGFyYW1zKTtcbiAgfSxcblxuICAvKipcbiAgICogUmV0dXJucyBhIHJlYWQtb25seSBvYmplY3Qgb2YgdGhlIGN1cnJlbnRseSBhY3RpdmUgcXVlcnkgcGFyYW1ldGVycy5cbiAgICovXG4gIGdldEN1cnJlbnRRdWVyeTogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBhc3NpZ24oe30sIHRoaXMuc3RhdGUucXVlcnkpO1xuICB9LFxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRydWUgaWYgdGhlIGdpdmVuIHJvdXRlLCBwYXJhbXMsIGFuZCBxdWVyeSBhcmUgYWN0aXZlLlxuICAgKi9cbiAgaXNBY3RpdmU6IGZ1bmN0aW9uICh0bywgcGFyYW1zLCBxdWVyeSkge1xuICAgIGlmIChQYXRoLmlzQWJzb2x1dGUodG8pKVxuICAgICAgcmV0dXJuIHRvID09PSB0aGlzLnN0YXRlLnBhdGg7XG5cbiAgICByZXR1cm4gcm91dGVJc0FjdGl2ZSh0aGlzLnN0YXRlLnJvdXRlcywgdG8pICYmXG4gICAgICBwYXJhbXNBcmVBY3RpdmUodGhpcy5zdGF0ZS5wYXJhbXMsIHBhcmFtcykgJiZcbiAgICAgIChxdWVyeSA9PSBudWxsIHx8IHF1ZXJ5SXNBY3RpdmUodGhpcy5zdGF0ZS5xdWVyeSwgcXVlcnkpKTtcbiAgfSxcblxuICBjaGlsZENvbnRleHRUeXBlczoge1xuICAgIGdldEN1cnJlbnRQYXRoOiBSZWFjdC5Qcm9wVHlwZXMuZnVuYy5pc1JlcXVpcmVkLFxuICAgIGdldEN1cnJlbnRSb3V0ZXM6IFJlYWN0LlByb3BUeXBlcy5mdW5jLmlzUmVxdWlyZWQsXG4gICAgZ2V0Q3VycmVudFBhdGhuYW1lOiBSZWFjdC5Qcm9wVHlwZXMuZnVuYy5pc1JlcXVpcmVkLFxuICAgIGdldEN1cnJlbnRQYXJhbXM6IFJlYWN0LlByb3BUeXBlcy5mdW5jLmlzUmVxdWlyZWQsXG4gICAgZ2V0Q3VycmVudFF1ZXJ5OiBSZWFjdC5Qcm9wVHlwZXMuZnVuYy5pc1JlcXVpcmVkLFxuICAgIGlzQWN0aXZlOiBSZWFjdC5Qcm9wVHlwZXMuZnVuYy5pc1JlcXVpcmVkXG4gIH0sXG5cbiAgZ2V0Q2hpbGRDb250ZXh0OiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGdldEN1cnJlbnRQYXRoOiB0aGlzLmdldEN1cnJlbnRQYXRoLFxuICAgICAgZ2V0Q3VycmVudFJvdXRlczogdGhpcy5nZXRDdXJyZW50Um91dGVzLFxuICAgICAgZ2V0Q3VycmVudFBhdGhuYW1lOiB0aGlzLmdldEN1cnJlbnRQYXRobmFtZSxcbiAgICAgIGdldEN1cnJlbnRQYXJhbXM6IHRoaXMuZ2V0Q3VycmVudFBhcmFtcyxcbiAgICAgIGdldEN1cnJlbnRRdWVyeTogdGhpcy5nZXRDdXJyZW50UXVlcnksXG4gICAgICBpc0FjdGl2ZTogdGhpcy5pc0FjdGl2ZVxuICAgIH07XG4gIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdGF0ZUNvbnRleHQ7XG4iLCIvKipcbiAqIFJlcHJlc2VudHMgYSBjYW5jZWxsYXRpb24gY2F1c2VkIGJ5IG5hdmlnYXRpbmcgYXdheVxuICogYmVmb3JlIHRoZSBwcmV2aW91cyB0cmFuc2l0aW9uIGhhcyBmdWxseSByZXNvbHZlZC5cbiAqL1xuZnVuY3Rpb24gQ2FuY2VsbGF0aW9uKCkgeyB9XG5cbm1vZHVsZS5leHBvcnRzID0gQ2FuY2VsbGF0aW9uO1xuIiwidmFyIGludmFyaWFudCA9IHJlcXVpcmUoJ3JlYWN0L2xpYi9pbnZhcmlhbnQnKTtcbnZhciBjYW5Vc2VET00gPSByZXF1aXJlKCdyZWFjdC9saWIvRXhlY3V0aW9uRW52aXJvbm1lbnQnKS5jYW5Vc2VET007XG5cbnZhciBIaXN0b3J5ID0ge1xuXG4gIC8qKlxuICAgKiBTZW5kcyB0aGUgYnJvd3NlciBiYWNrIG9uZSBlbnRyeSBpbiB0aGUgaGlzdG9yeS5cbiAgICovXG4gIGJhY2s6IGZ1bmN0aW9uICgpIHtcbiAgICBpbnZhcmlhbnQoXG4gICAgICBjYW5Vc2VET00sXG4gICAgICAnQ2Fubm90IHVzZSBIaXN0b3J5LmJhY2sgd2l0aG91dCBhIERPTSdcbiAgICApO1xuXG4gICAgLy8gRG8gdGhpcyBmaXJzdCBzbyB0aGF0IEhpc3RvcnkubGVuZ3RoIHdpbGxcbiAgICAvLyBiZSBhY2N1cmF0ZSBpbiBsb2NhdGlvbiBjaGFuZ2UgbGlzdGVuZXJzLlxuICAgIEhpc3RvcnkubGVuZ3RoIC09IDE7XG5cbiAgICB3aW5kb3cuaGlzdG9yeS5iYWNrKCk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFRoZSBjdXJyZW50IG51bWJlciBvZiBlbnRyaWVzIGluIHRoZSBoaXN0b3J5LlxuICAgKi9cbiAgbGVuZ3RoOiAxXG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gSGlzdG9yeTtcbiIsInZhciBpbnZhcmlhbnQgPSByZXF1aXJlKCdyZWFjdC9saWIvaW52YXJpYW50Jyk7XG52YXIgbWVyZ2UgPSByZXF1aXJlKCdxcy9saWIvdXRpbHMnKS5tZXJnZTtcbnZhciBxcyA9IHJlcXVpcmUoJ3FzJyk7XG5cbnZhciBwYXJhbUNvbXBpbGVNYXRjaGVyID0gLzooW2EtekEtWl8kXVthLXpBLVowLTlfJF0qKXxbKi4oKVxcW1xcXVxcXFwrfHt9XiRdL2c7XG52YXIgcGFyYW1JbmplY3RNYXRjaGVyID0gLzooW2EtekEtWl8kXVthLXpBLVowLTlfJD9dKls/XT8pfFsqXS9nO1xudmFyIHBhcmFtSW5qZWN0VHJhaWxpbmdTbGFzaE1hdGNoZXIgPSAvXFwvXFwvXFw/fFxcL1xcPy9nO1xudmFyIHF1ZXJ5TWF0Y2hlciA9IC9cXD8oLispLztcblxudmFyIF9jb21waWxlZFBhdHRlcm5zID0ge307XG5cbmZ1bmN0aW9uIGNvbXBpbGVQYXR0ZXJuKHBhdHRlcm4pIHtcbiAgaWYgKCEocGF0dGVybiBpbiBfY29tcGlsZWRQYXR0ZXJucykpIHtcbiAgICB2YXIgcGFyYW1OYW1lcyA9IFtdO1xuICAgIHZhciBzb3VyY2UgPSBwYXR0ZXJuLnJlcGxhY2UocGFyYW1Db21waWxlTWF0Y2hlciwgZnVuY3Rpb24gKG1hdGNoLCBwYXJhbU5hbWUpIHtcbiAgICAgIGlmIChwYXJhbU5hbWUpIHtcbiAgICAgICAgcGFyYW1OYW1lcy5wdXNoKHBhcmFtTmFtZSk7XG4gICAgICAgIHJldHVybiAnKFteLz8jXSspJztcbiAgICAgIH0gZWxzZSBpZiAobWF0Y2ggPT09ICcqJykge1xuICAgICAgICBwYXJhbU5hbWVzLnB1c2goJ3NwbGF0Jyk7XG4gICAgICAgIHJldHVybiAnKC4qPyknO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuICdcXFxcJyArIG1hdGNoO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgX2NvbXBpbGVkUGF0dGVybnNbcGF0dGVybl0gPSB7XG4gICAgICBtYXRjaGVyOiBuZXcgUmVnRXhwKCdeJyArIHNvdXJjZSArICckJywgJ2knKSxcbiAgICAgIHBhcmFtTmFtZXM6IHBhcmFtTmFtZXNcbiAgICB9O1xuICB9XG5cbiAgcmV0dXJuIF9jb21waWxlZFBhdHRlcm5zW3BhdHRlcm5dO1xufVxuXG52YXIgUGF0aCA9IHtcblxuICAvKipcbiAgICogU2FmZWx5IGRlY29kZXMgc3BlY2lhbCBjaGFyYWN0ZXJzIGluIHRoZSBnaXZlbiBVUkwgcGF0aC5cbiAgICovXG4gIGRlY29kZTogZnVuY3Rpb24gKHBhdGgpIHtcbiAgICByZXR1cm4gZGVjb2RlVVJJKHBhdGgucmVwbGFjZSgvXFwrL2csICcgJykpO1xuICB9LFxuXG4gIC8qKlxuICAgKiBTYWZlbHkgZW5jb2RlcyBzcGVjaWFsIGNoYXJhY3RlcnMgaW4gdGhlIGdpdmVuIFVSTCBwYXRoLlxuICAgKi9cbiAgZW5jb2RlOiBmdW5jdGlvbiAocGF0aCkge1xuICAgIHJldHVybiBlbmNvZGVVUkkocGF0aCkucmVwbGFjZSgvJTIwL2csICcrJyk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFJldHVybnMgYW4gYXJyYXkgb2YgdGhlIG5hbWVzIG9mIGFsbCBwYXJhbWV0ZXJzIGluIHRoZSBnaXZlbiBwYXR0ZXJuLlxuICAgKi9cbiAgZXh0cmFjdFBhcmFtTmFtZXM6IGZ1bmN0aW9uIChwYXR0ZXJuKSB7XG4gICAgcmV0dXJuIGNvbXBpbGVQYXR0ZXJuKHBhdHRlcm4pLnBhcmFtTmFtZXM7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEV4dHJhY3RzIHRoZSBwb3J0aW9ucyBvZiB0aGUgZ2l2ZW4gVVJMIHBhdGggdGhhdCBtYXRjaCB0aGUgZ2l2ZW4gcGF0dGVyblxuICAgKiBhbmQgcmV0dXJucyBhbiBvYmplY3Qgb2YgcGFyYW0gbmFtZSA9PiB2YWx1ZSBwYWlycy4gUmV0dXJucyBudWxsIGlmIHRoZVxuICAgKiBwYXR0ZXJuIGRvZXMgbm90IG1hdGNoIHRoZSBnaXZlbiBwYXRoLlxuICAgKi9cbiAgZXh0cmFjdFBhcmFtczogZnVuY3Rpb24gKHBhdHRlcm4sIHBhdGgpIHtcbiAgICB2YXIgb2JqZWN0ID0gY29tcGlsZVBhdHRlcm4ocGF0dGVybik7XG4gICAgdmFyIG1hdGNoID0gcGF0aC5tYXRjaChvYmplY3QubWF0Y2hlcik7XG5cbiAgICBpZiAoIW1hdGNoKVxuICAgICAgcmV0dXJuIG51bGw7XG5cbiAgICB2YXIgcGFyYW1zID0ge307XG5cbiAgICBvYmplY3QucGFyYW1OYW1lcy5mb3JFYWNoKGZ1bmN0aW9uIChwYXJhbU5hbWUsIGluZGV4KSB7XG4gICAgICBwYXJhbXNbcGFyYW1OYW1lXSA9IG1hdGNoW2luZGV4ICsgMV07XG4gICAgfSk7XG5cbiAgICByZXR1cm4gcGFyYW1zO1xuICB9LFxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGEgdmVyc2lvbiBvZiB0aGUgZ2l2ZW4gcm91dGUgcGF0aCB3aXRoIHBhcmFtcyBpbnRlcnBvbGF0ZWQuIFRocm93c1xuICAgKiBpZiB0aGVyZSBpcyBhIGR5bmFtaWMgc2VnbWVudCBvZiB0aGUgcm91dGUgcGF0aCBmb3Igd2hpY2ggdGhlcmUgaXMgbm8gcGFyYW0uXG4gICAqL1xuICBpbmplY3RQYXJhbXM6IGZ1bmN0aW9uIChwYXR0ZXJuLCBwYXJhbXMpIHtcbiAgICBwYXJhbXMgPSBwYXJhbXMgfHwge307XG5cbiAgICB2YXIgc3BsYXRJbmRleCA9IDA7XG5cbiAgICByZXR1cm4gcGF0dGVybi5yZXBsYWNlKHBhcmFtSW5qZWN0TWF0Y2hlciwgZnVuY3Rpb24gKG1hdGNoLCBwYXJhbU5hbWUpIHtcbiAgICAgIHBhcmFtTmFtZSA9IHBhcmFtTmFtZSB8fCAnc3BsYXQnO1xuXG4gICAgICAvLyBJZiBwYXJhbSBpcyBvcHRpb25hbCBkb24ndCBjaGVjayBmb3IgZXhpc3RlbmNlXG4gICAgICBpZiAocGFyYW1OYW1lLnNsaWNlKC0xKSAhPT0gJz8nKSB7XG4gICAgICAgIGludmFyaWFudChcbiAgICAgICAgICBwYXJhbXNbcGFyYW1OYW1lXSAhPSBudWxsLFxuICAgICAgICAgICdNaXNzaW5nIFwiJyArIHBhcmFtTmFtZSArICdcIiBwYXJhbWV0ZXIgZm9yIHBhdGggXCInICsgcGF0dGVybiArICdcIidcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHBhcmFtTmFtZSA9IHBhcmFtTmFtZS5zbGljZSgwLCAtMSk7XG5cbiAgICAgICAgaWYgKHBhcmFtc1twYXJhbU5hbWVdID09IG51bGwpXG4gICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgfVxuXG4gICAgICB2YXIgc2VnbWVudDtcbiAgICAgIGlmIChwYXJhbU5hbWUgPT09ICdzcGxhdCcgJiYgQXJyYXkuaXNBcnJheShwYXJhbXNbcGFyYW1OYW1lXSkpIHtcbiAgICAgICAgc2VnbWVudCA9IHBhcmFtc1twYXJhbU5hbWVdW3NwbGF0SW5kZXgrK107XG5cbiAgICAgICAgaW52YXJpYW50KFxuICAgICAgICAgIHNlZ21lbnQgIT0gbnVsbCxcbiAgICAgICAgICAnTWlzc2luZyBzcGxhdCAjICcgKyBzcGxhdEluZGV4ICsgJyBmb3IgcGF0aCBcIicgKyBwYXR0ZXJuICsgJ1wiJ1xuICAgICAgICApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc2VnbWVudCA9IHBhcmFtc1twYXJhbU5hbWVdO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gc2VnbWVudDtcbiAgICB9KS5yZXBsYWNlKHBhcmFtSW5qZWN0VHJhaWxpbmdTbGFzaE1hdGNoZXIsICcvJyk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFJldHVybnMgYW4gb2JqZWN0IHRoYXQgaXMgdGhlIHJlc3VsdCBvZiBwYXJzaW5nIGFueSBxdWVyeSBzdHJpbmcgY29udGFpbmVkXG4gICAqIGluIHRoZSBnaXZlbiBwYXRoLCBudWxsIGlmIHRoZSBwYXRoIGNvbnRhaW5zIG5vIHF1ZXJ5IHN0cmluZy5cbiAgICovXG4gIGV4dHJhY3RRdWVyeTogZnVuY3Rpb24gKHBhdGgpIHtcbiAgICB2YXIgbWF0Y2ggPSBwYXRoLm1hdGNoKHF1ZXJ5TWF0Y2hlcik7XG4gICAgcmV0dXJuIG1hdGNoICYmIHFzLnBhcnNlKG1hdGNoWzFdKTtcbiAgfSxcblxuICAvKipcbiAgICogUmV0dXJucyBhIHZlcnNpb24gb2YgdGhlIGdpdmVuIHBhdGggd2l0aG91dCB0aGUgcXVlcnkgc3RyaW5nLlxuICAgKi9cbiAgd2l0aG91dFF1ZXJ5OiBmdW5jdGlvbiAocGF0aCkge1xuICAgIHJldHVybiBwYXRoLnJlcGxhY2UocXVlcnlNYXRjaGVyLCAnJyk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSB2ZXJzaW9uIG9mIHRoZSBnaXZlbiBwYXRoIHdpdGggdGhlIHBhcmFtZXRlcnMgaW4gdGhlIGdpdmVuXG4gICAqIHF1ZXJ5IG1lcmdlZCBpbnRvIHRoZSBxdWVyeSBzdHJpbmcuXG4gICAqL1xuICB3aXRoUXVlcnk6IGZ1bmN0aW9uIChwYXRoLCBxdWVyeSkge1xuICAgIHZhciBleGlzdGluZ1F1ZXJ5ID0gUGF0aC5leHRyYWN0UXVlcnkocGF0aCk7XG5cbiAgICBpZiAoZXhpc3RpbmdRdWVyeSlcbiAgICAgIHF1ZXJ5ID0gcXVlcnkgPyBtZXJnZShleGlzdGluZ1F1ZXJ5LCBxdWVyeSkgOiBleGlzdGluZ1F1ZXJ5O1xuXG4gICAgdmFyIHF1ZXJ5U3RyaW5nID0gcXVlcnkgJiYgcXMuc3RyaW5naWZ5KHF1ZXJ5KTtcblxuICAgIGlmIChxdWVyeVN0cmluZylcbiAgICAgIHJldHVybiBQYXRoLndpdGhvdXRRdWVyeShwYXRoKSArICc/JyArIHF1ZXJ5U3RyaW5nO1xuXG4gICAgcmV0dXJuIHBhdGg7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFJldHVybnMgdHJ1ZSBpZiB0aGUgZ2l2ZW4gcGF0aCBpcyBhYnNvbHV0ZS5cbiAgICovXG4gIGlzQWJzb2x1dGU6IGZ1bmN0aW9uIChwYXRoKSB7XG4gICAgcmV0dXJuIHBhdGguY2hhckF0KDApID09PSAnLyc7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSBub3JtYWxpemVkIHZlcnNpb24gb2YgdGhlIGdpdmVuIHBhdGguXG4gICAqL1xuICBub3JtYWxpemU6IGZ1bmN0aW9uIChwYXRoLCBwYXJlbnRSb3V0ZSkge1xuICAgIHJldHVybiBwYXRoLnJlcGxhY2UoL15cXC8qLywgJy8nKTtcbiAgfSxcblxuICAvKipcbiAgICogSm9pbnMgdHdvIFVSTCBwYXRocyB0b2dldGhlci5cbiAgICovXG4gIGpvaW46IGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgcmV0dXJuIGEucmVwbGFjZSgvXFwvKiQvLCAnLycpICsgYjtcbiAgfVxuXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFBhdGg7XG4iLCJ2YXIgUHJvbWlzZSA9IHJlcXVpcmUoJ3doZW4vbGliL1Byb21pc2UnKTtcblxuLy8gVE9ETzogVXNlIHByb2Nlc3MuZW52Lk5PREVfRU5WIGNoZWNrICsgZW52aWZ5IHRvIGVuYWJsZVxuLy8gd2hlbidzIHByb21pc2UgbW9uaXRvciBoZXJlIHdoZW4gaW4gZGV2LlxuXG5tb2R1bGUuZXhwb3J0cyA9IFByb21pc2U7XG4iLCJ2YXIgUHJvcFR5cGVzID0ge1xuXG4gIC8qKlxuICAgKiBSZXF1aXJlcyB0aGF0IHRoZSB2YWx1ZSBvZiBhIHByb3AgYmUgZmFsc3kuXG4gICAqL1xuICBmYWxzeTogZnVuY3Rpb24gKHByb3BzLCBwcm9wTmFtZSwgY29tcG9uZW50TmFtZSkge1xuICAgIGlmIChwcm9wc1twcm9wTmFtZV0pXG4gICAgICByZXR1cm4gbmV3IEVycm9yKCc8JyArIGNvbXBvbmVudE5hbWUgKyAnPiBtYXkgbm90IGhhdmUgYSBcIicgKyBwcm9wTmFtZSArICdcIiBwcm9wJyk7XG4gIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBQcm9wVHlwZXM7XG4iLCIvKipcbiAqIEVuY2Fwc3VsYXRlcyBhIHJlZGlyZWN0IHRvIHRoZSBnaXZlbiByb3V0ZS5cbiAqL1xuZnVuY3Rpb24gUmVkaXJlY3QodG8sIHBhcmFtcywgcXVlcnkpIHtcbiAgdGhpcy50byA9IHRvO1xuICB0aGlzLnBhcmFtcyA9IHBhcmFtcztcbiAgdGhpcy5xdWVyeSA9IHF1ZXJ5O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IFJlZGlyZWN0O1xuIiwidmFyIGFzc2lnbiA9IHJlcXVpcmUoJ3JlYWN0L2xpYi9PYmplY3QuYXNzaWduJyk7XG52YXIgcmV2ZXJzZWRBcnJheSA9IHJlcXVpcmUoJy4vcmV2ZXJzZWRBcnJheScpO1xudmFyIFJlZGlyZWN0ID0gcmVxdWlyZSgnLi9SZWRpcmVjdCcpO1xudmFyIFByb21pc2UgPSByZXF1aXJlKCcuL1Byb21pc2UnKTtcblxuLyoqXG4gKiBSdW5zIGFsbCBob29rIGZ1bmN0aW9ucyBzZXJpYWxseSBhbmQgY2FsbHMgY2FsbGJhY2soZXJyb3IpIHdoZW4gZmluaXNoZWQuXG4gKiBBIGhvb2sgbWF5IHJldHVybiBhIHByb21pc2UgaWYgaXQgbmVlZHMgdG8gZXhlY3V0ZSBhc3luY2hyb25vdXNseS5cbiAqL1xuZnVuY3Rpb24gcnVuSG9va3MoaG9va3MsIGNhbGxiYWNrKSB7XG4gIHZhciBwcm9taXNlO1xuICB0cnkge1xuICAgIHByb21pc2UgPSBob29rcy5yZWR1Y2UoZnVuY3Rpb24gKHByb21pc2UsIGhvb2spIHtcbiAgICAgIC8vIFRoZSBmaXJzdCBob29rIHRvIHVzZSB0cmFuc2l0aW9uLndhaXQgbWFrZXMgdGhlIHJlc3RcbiAgICAgIC8vIG9mIHRoZSB0cmFuc2l0aW9uIGFzeW5jIGZyb20gdGhhdCBwb2ludCBmb3J3YXJkLlxuICAgICAgcmV0dXJuIHByb21pc2UgPyBwcm9taXNlLnRoZW4oaG9vaykgOiBob29rKCk7XG4gICAgfSwgbnVsbCk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgcmV0dXJuIGNhbGxiYWNrKGVycm9yKTsgLy8gU3luYyBlcnJvci5cbiAgfVxuXG4gIGlmIChwcm9taXNlKSB7XG4gICAgLy8gVXNlIHNldFRpbWVvdXQgdG8gYnJlYWsgdGhlIHByb21pc2UgY2hhaW4uXG4gICAgcHJvbWlzZS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgIHNldFRpbWVvdXQoY2FsbGJhY2spO1xuICAgIH0sIGZ1bmN0aW9uIChlcnJvcikge1xuICAgICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNhbGxiYWNrKGVycm9yKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9IGVsc2Uge1xuICAgIGNhbGxiYWNrKCk7XG4gIH1cbn1cblxuLyoqXG4gKiBDYWxscyB0aGUgd2lsbFRyYW5zaXRpb25Gcm9tIGhvb2sgb2YgYWxsIGhhbmRsZXJzIGluIHRoZSBnaXZlbiBtYXRjaGVzXG4gKiBzZXJpYWxseSBpbiByZXZlcnNlIHdpdGggdGhlIHRyYW5zaXRpb24gb2JqZWN0IGFuZCB0aGUgY3VycmVudCBpbnN0YW5jZSBvZlxuICogdGhlIHJvdXRlJ3MgaGFuZGxlciwgc28gdGhhdCB0aGUgZGVlcGVzdCBuZXN0ZWQgaGFuZGxlcnMgYXJlIGNhbGxlZCBmaXJzdC5cbiAqIENhbGxzIGNhbGxiYWNrKGVycm9yKSB3aGVuIGZpbmlzaGVkLlxuICovXG5mdW5jdGlvbiBydW5UcmFuc2l0aW9uRnJvbUhvb2tzKHRyYW5zaXRpb24sIHJvdXRlcywgY29tcG9uZW50cywgY2FsbGJhY2spIHtcbiAgY29tcG9uZW50cyA9IHJldmVyc2VkQXJyYXkoY29tcG9uZW50cyk7XG5cbiAgdmFyIGhvb2tzID0gcmV2ZXJzZWRBcnJheShyb3V0ZXMpLm1hcChmdW5jdGlvbiAocm91dGUsIGluZGV4KSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uICgpIHtcbiAgICAgIHZhciBoYW5kbGVyID0gcm91dGUuaGFuZGxlcjtcblxuICAgICAgaWYgKCF0cmFuc2l0aW9uLmlzQWJvcnRlZCAmJiBoYW5kbGVyLndpbGxUcmFuc2l0aW9uRnJvbSlcbiAgICAgICAgcmV0dXJuIGhhbmRsZXIud2lsbFRyYW5zaXRpb25Gcm9tKHRyYW5zaXRpb24sIGNvbXBvbmVudHNbaW5kZXhdKTtcblxuICAgICAgdmFyIHByb21pc2UgPSB0cmFuc2l0aW9uLl9wcm9taXNlO1xuICAgICAgdHJhbnNpdGlvbi5fcHJvbWlzZSA9IG51bGw7XG5cbiAgICAgIHJldHVybiBwcm9taXNlO1xuICAgIH07XG4gIH0pO1xuXG4gIHJ1bkhvb2tzKGhvb2tzLCBjYWxsYmFjayk7XG59XG5cbi8qKlxuICogQ2FsbHMgdGhlIHdpbGxUcmFuc2l0aW9uVG8gaG9vayBvZiBhbGwgaGFuZGxlcnMgaW4gdGhlIGdpdmVuIG1hdGNoZXNcbiAqIHNlcmlhbGx5IHdpdGggdGhlIHRyYW5zaXRpb24gb2JqZWN0IGFuZCBhbnkgcGFyYW1zIHRoYXQgYXBwbHkgdG8gdGhhdFxuICogaGFuZGxlci4gQ2FsbHMgY2FsbGJhY2soZXJyb3IpIHdoZW4gZmluaXNoZWQuXG4gKi9cbmZ1bmN0aW9uIHJ1blRyYW5zaXRpb25Ub0hvb2tzKHRyYW5zaXRpb24sIHJvdXRlcywgcGFyYW1zLCBxdWVyeSwgY2FsbGJhY2spIHtcbiAgdmFyIGhvb2tzID0gcm91dGVzLm1hcChmdW5jdGlvbiAocm91dGUpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKCkge1xuICAgICAgdmFyIGhhbmRsZXIgPSByb3V0ZS5oYW5kbGVyO1xuXG4gICAgICBpZiAoIXRyYW5zaXRpb24uaXNBYm9ydGVkICYmIGhhbmRsZXIud2lsbFRyYW5zaXRpb25UbylcbiAgICAgICAgaGFuZGxlci53aWxsVHJhbnNpdGlvblRvKHRyYW5zaXRpb24sIHBhcmFtcywgcXVlcnkpO1xuXG4gICAgICB2YXIgcHJvbWlzZSA9IHRyYW5zaXRpb24uX3Byb21pc2U7XG4gICAgICB0cmFuc2l0aW9uLl9wcm9taXNlID0gbnVsbDtcblxuICAgICAgcmV0dXJuIHByb21pc2U7XG4gICAgfTtcbiAgfSk7XG5cbiAgcnVuSG9va3MoaG9va3MsIGNhbGxiYWNrKTtcbn1cblxuLyoqXG4gKiBFbmNhcHN1bGF0ZXMgYSB0cmFuc2l0aW9uIHRvIGEgZ2l2ZW4gcGF0aC5cbiAqXG4gKiBUaGUgd2lsbFRyYW5zaXRpb25UbyBhbmQgd2lsbFRyYW5zaXRpb25Gcm9tIGhhbmRsZXJzIHJlY2VpdmVcbiAqIGFuIGluc3RhbmNlIG9mIHRoaXMgY2xhc3MgYXMgdGhlaXIgZmlyc3QgYXJndW1lbnQuXG4gKi9cbmZ1bmN0aW9uIFRyYW5zaXRpb24ocGF0aCwgcmV0cnkpIHtcbiAgdGhpcy5wYXRoID0gcGF0aDtcbiAgdGhpcy5hYm9ydFJlYXNvbiA9IG51bGw7XG4gIHRoaXMuaXNBYm9ydGVkID0gZmFsc2U7XG4gIHRoaXMucmV0cnkgPSByZXRyeS5iaW5kKHRoaXMpO1xuICB0aGlzLl9wcm9taXNlID0gbnVsbDtcbn1cblxuYXNzaWduKFRyYW5zaXRpb24ucHJvdG90eXBlLCB7XG5cbiAgYWJvcnQ6IGZ1bmN0aW9uIChyZWFzb24pIHtcbiAgICBpZiAodGhpcy5pc0Fib3J0ZWQpIHtcbiAgICAgIC8vIEZpcnN0IGFib3J0IHdpbnMuXG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5hYm9ydFJlYXNvbiA9IHJlYXNvbjtcbiAgICB0aGlzLmlzQWJvcnRlZCA9IHRydWU7XG4gIH0sXG5cbiAgcmVkaXJlY3Q6IGZ1bmN0aW9uICh0bywgcGFyYW1zLCBxdWVyeSkge1xuICAgIHRoaXMuYWJvcnQobmV3IFJlZGlyZWN0KHRvLCBwYXJhbXMsIHF1ZXJ5KSk7XG4gIH0sXG5cbiAgd2FpdDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgdGhpcy5fcHJvbWlzZSA9IFByb21pc2UucmVzb2x2ZSh2YWx1ZSk7XG4gIH0sXG5cbiAgZnJvbTogZnVuY3Rpb24gKHJvdXRlcywgY29tcG9uZW50cywgY2FsbGJhY2spIHtcbiAgICByZXR1cm4gcnVuVHJhbnNpdGlvbkZyb21Ib29rcyh0aGlzLCByb3V0ZXMsIGNvbXBvbmVudHMsIGNhbGxiYWNrKTtcbiAgfSxcblxuICB0bzogZnVuY3Rpb24gKHJvdXRlcywgcGFyYW1zLCBxdWVyeSwgY2FsbGJhY2spIHtcbiAgICByZXR1cm4gcnVuVHJhbnNpdGlvblRvSG9va3ModGhpcywgcm91dGVzLCBwYXJhbXMsIHF1ZXJ5LCBjYWxsYmFjayk7XG4gIH1cblxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gVHJhbnNpdGlvbjtcbiIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKiBqc2hpbnQgLVcwNTggKi9cbnZhciBSZWFjdCA9IHJlcXVpcmUoJ3JlYWN0Jyk7XG52YXIgd2FybmluZyA9IHJlcXVpcmUoJ3JlYWN0L2xpYi93YXJuaW5nJyk7XG52YXIgaW52YXJpYW50ID0gcmVxdWlyZSgncmVhY3QvbGliL2ludmFyaWFudCcpO1xudmFyIGNhblVzZURPTSA9IHJlcXVpcmUoJ3JlYWN0L2xpYi9FeGVjdXRpb25FbnZpcm9ubWVudCcpLmNhblVzZURPTTtcbnZhciBJbWl0YXRlQnJvd3NlckJlaGF2aW9yID0gcmVxdWlyZSgnLi4vYmVoYXZpb3JzL0ltaXRhdGVCcm93c2VyQmVoYXZpb3InKTtcbnZhciBSb3V0ZUhhbmRsZXIgPSByZXF1aXJlKCcuLi9jb21wb25lbnRzL1JvdXRlSGFuZGxlcicpO1xudmFyIExvY2F0aW9uQWN0aW9ucyA9IHJlcXVpcmUoJy4uL2FjdGlvbnMvTG9jYXRpb25BY3Rpb25zJyk7XG52YXIgSGFzaExvY2F0aW9uID0gcmVxdWlyZSgnLi4vbG9jYXRpb25zL0hhc2hMb2NhdGlvbicpO1xudmFyIEhpc3RvcnlMb2NhdGlvbiA9IHJlcXVpcmUoJy4uL2xvY2F0aW9ucy9IaXN0b3J5TG9jYXRpb24nKTtcbnZhciBSZWZyZXNoTG9jYXRpb24gPSByZXF1aXJlKCcuLi9sb2NhdGlvbnMvUmVmcmVzaExvY2F0aW9uJyk7XG52YXIgTmF2aWdhdGlvbkNvbnRleHQgPSByZXF1aXJlKCcuLi9taXhpbnMvTmF2aWdhdGlvbkNvbnRleHQnKTtcbnZhciBTdGF0ZUNvbnRleHQgPSByZXF1aXJlKCcuLi9taXhpbnMvU3RhdGVDb250ZXh0Jyk7XG52YXIgU2Nyb2xsaW5nID0gcmVxdWlyZSgnLi4vbWl4aW5zL1Njcm9sbGluZycpO1xudmFyIGNyZWF0ZVJvdXRlc0Zyb21DaGlsZHJlbiA9IHJlcXVpcmUoJy4vY3JlYXRlUm91dGVzRnJvbUNoaWxkcmVuJyk7XG52YXIgc3VwcG9ydHNIaXN0b3J5ID0gcmVxdWlyZSgnLi9zdXBwb3J0c0hpc3RvcnknKTtcbnZhciBUcmFuc2l0aW9uID0gcmVxdWlyZSgnLi9UcmFuc2l0aW9uJyk7XG52YXIgUHJvcFR5cGVzID0gcmVxdWlyZSgnLi9Qcm9wVHlwZXMnKTtcbnZhciBSZWRpcmVjdCA9IHJlcXVpcmUoJy4vUmVkaXJlY3QnKTtcbnZhciBIaXN0b3J5ID0gcmVxdWlyZSgnLi9IaXN0b3J5Jyk7XG52YXIgQ2FuY2VsbGF0aW9uID0gcmVxdWlyZSgnLi9DYW5jZWxsYXRpb24nKTtcbnZhciBQYXRoID0gcmVxdWlyZSgnLi9QYXRoJyk7XG5cbi8qKlxuICogVGhlIGRlZmF1bHQgbG9jYXRpb24gZm9yIG5ldyByb3V0ZXJzLlxuICovXG52YXIgREVGQVVMVF9MT0NBVElPTiA9IGNhblVzZURPTSA/IEhhc2hMb2NhdGlvbiA6ICcvJztcblxuLyoqXG4gKiBUaGUgZGVmYXVsdCBzY3JvbGwgYmVoYXZpb3IgZm9yIG5ldyByb3V0ZXJzLlxuICovXG52YXIgREVGQVVMVF9TQ1JPTExfQkVIQVZJT1IgPSBjYW5Vc2VET00gPyBJbWl0YXRlQnJvd3NlckJlaGF2aW9yIDogbnVsbDtcblxuLyoqXG4gKiBUaGUgZGVmYXVsdCBlcnJvciBoYW5kbGVyIGZvciBuZXcgcm91dGVycy5cbiAqL1xuZnVuY3Rpb24gZGVmYXVsdEVycm9ySGFuZGxlcihlcnJvcikge1xuICAvLyBUaHJvdyBzbyB3ZSBkb24ndCBzaWxlbnRseSBzd2FsbG93IGFzeW5jIGVycm9ycy5cbiAgdGhyb3cgZXJyb3I7IC8vIFRoaXMgZXJyb3IgcHJvYmFibHkgb3JpZ2luYXRlZCBpbiBhIHRyYW5zaXRpb24gaG9vay5cbn1cblxuLyoqXG4gKiBUaGUgZGVmYXVsdCBhYm9ydGVkIHRyYW5zaXRpb24gaGFuZGxlciBmb3IgbmV3IHJvdXRlcnMuXG4gKi9cbmZ1bmN0aW9uIGRlZmF1bHRBYm9ydEhhbmRsZXIoYWJvcnRSZWFzb24sIGxvY2F0aW9uKSB7XG4gIGlmICh0eXBlb2YgbG9jYXRpb24gPT09ICdzdHJpbmcnKVxuICAgIHRocm93IG5ldyBFcnJvcignVW5oYW5kbGVkIGFib3J0ZWQgdHJhbnNpdGlvbiEgUmVhc29uOiAnICsgYWJvcnRSZWFzb24pO1xuXG4gIGlmIChhYm9ydFJlYXNvbiBpbnN0YW5jZW9mIENhbmNlbGxhdGlvbikge1xuICAgIHJldHVybjtcbiAgfSBlbHNlIGlmIChhYm9ydFJlYXNvbiBpbnN0YW5jZW9mIFJlZGlyZWN0KSB7XG4gICAgbG9jYXRpb24ucmVwbGFjZSh0aGlzLm1ha2VQYXRoKGFib3J0UmVhc29uLnRvLCBhYm9ydFJlYXNvbi5wYXJhbXMsIGFib3J0UmVhc29uLnF1ZXJ5KSk7XG4gIH0gZWxzZSB7XG4gICAgbG9jYXRpb24ucG9wKCk7XG4gIH1cbn1cblxuZnVuY3Rpb24gZmluZE1hdGNoKHBhdGhuYW1lLCByb3V0ZXMsIGRlZmF1bHRSb3V0ZSwgbm90Rm91bmRSb3V0ZSkge1xuICB2YXIgbWF0Y2gsIHJvdXRlLCBwYXJhbXM7XG5cbiAgZm9yICh2YXIgaSA9IDAsIGxlbiA9IHJvdXRlcy5sZW5ndGg7IGkgPCBsZW47ICsraSkge1xuICAgIHJvdXRlID0gcm91dGVzW2ldO1xuXG4gICAgLy8gQ2hlY2sgdGhlIHN1YnRyZWUgZmlyc3QgdG8gZmluZCB0aGUgbW9zdCBkZWVwbHktbmVzdGVkIG1hdGNoLlxuICAgIG1hdGNoID0gZmluZE1hdGNoKHBhdGhuYW1lLCByb3V0ZS5jaGlsZFJvdXRlcywgcm91dGUuZGVmYXVsdFJvdXRlLCByb3V0ZS5ub3RGb3VuZFJvdXRlKTtcblxuICAgIGlmIChtYXRjaCAhPSBudWxsKSB7XG4gICAgICBtYXRjaC5yb3V0ZXMudW5zaGlmdChyb3V0ZSk7XG4gICAgICByZXR1cm4gbWF0Y2g7XG4gICAgfVxuXG4gICAgLy8gTm8gcm91dGVzIGluIHRoZSBzdWJ0cmVlIG1hdGNoZWQsIHNvIGNoZWNrIHRoaXMgcm91dGUuXG4gICAgcGFyYW1zID0gUGF0aC5leHRyYWN0UGFyYW1zKHJvdXRlLnBhdGgsIHBhdGhuYW1lKTtcblxuICAgIGlmIChwYXJhbXMpXG4gICAgICByZXR1cm4gY3JlYXRlTWF0Y2gocm91dGUsIHBhcmFtcyk7XG4gIH1cblxuICAvLyBObyByb3V0ZXMgbWF0Y2hlZCwgc28gdHJ5IHRoZSBkZWZhdWx0IHJvdXRlIGlmIHRoZXJlIGlzIG9uZS5cbiAgaWYgKGRlZmF1bHRSb3V0ZSAmJiAocGFyYW1zID0gUGF0aC5leHRyYWN0UGFyYW1zKGRlZmF1bHRSb3V0ZS5wYXRoLCBwYXRobmFtZSkpKVxuICAgIHJldHVybiBjcmVhdGVNYXRjaChkZWZhdWx0Um91dGUsIHBhcmFtcyk7XG5cbiAgLy8gTGFzdCBhdHRlbXB0OiBkb2VzIHRoZSBcIm5vdCBmb3VuZFwiIHJvdXRlIG1hdGNoP1xuICBpZiAobm90Rm91bmRSb3V0ZSAmJiAocGFyYW1zID0gUGF0aC5leHRyYWN0UGFyYW1zKG5vdEZvdW5kUm91dGUucGF0aCwgcGF0aG5hbWUpKSlcbiAgICByZXR1cm4gY3JlYXRlTWF0Y2gobm90Rm91bmRSb3V0ZSwgcGFyYW1zKTtcblxuICByZXR1cm4gbWF0Y2g7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZU1hdGNoKHJvdXRlLCBwYXJhbXMpIHtcbiAgcmV0dXJuIHsgcm91dGVzOiBbIHJvdXRlIF0sIHBhcmFtczogcGFyYW1zIH07XG59XG5cbmZ1bmN0aW9uIGhhc1Byb3BlcnRpZXMob2JqZWN0LCBwcm9wZXJ0aWVzKSB7XG4gIGZvciAodmFyIHByb3BlcnR5TmFtZSBpbiBwcm9wZXJ0aWVzKVxuICAgIGlmIChwcm9wZXJ0aWVzLmhhc093blByb3BlcnR5KHByb3BlcnR5TmFtZSkgJiYgb2JqZWN0W3Byb3BlcnR5TmFtZV0gIT09IHByb3BlcnRpZXNbcHJvcGVydHlOYW1lXSlcbiAgICAgIHJldHVybiBmYWxzZTtcblxuICByZXR1cm4gdHJ1ZTtcbn1cblxuZnVuY3Rpb24gaGFzTWF0Y2gocm91dGVzLCByb3V0ZSwgcHJldlBhcmFtcywgbmV4dFBhcmFtcywgcHJldlF1ZXJ5LCBuZXh0UXVlcnkpIHtcbiAgcmV0dXJuIHJvdXRlcy5zb21lKGZ1bmN0aW9uIChyKSB7XG4gICAgaWYgKHIgIT09IHJvdXRlKVxuICAgICAgcmV0dXJuIGZhbHNlO1xuXG4gICAgdmFyIHBhcmFtTmFtZXMgPSByb3V0ZS5wYXJhbU5hbWVzO1xuICAgIHZhciBwYXJhbU5hbWU7XG5cbiAgICAvLyBFbnN1cmUgdGhhdCBhbGwgcGFyYW1zIHRoZSByb3V0ZSBjYXJlcyBhYm91dCBkaWQgbm90IGNoYW5nZS5cbiAgICBmb3IgKHZhciBpID0gMCwgbGVuID0gcGFyYW1OYW1lcy5sZW5ndGg7IGkgPCBsZW47ICsraSkge1xuICAgICAgcGFyYW1OYW1lID0gcGFyYW1OYW1lc1tpXTtcblxuICAgICAgaWYgKG5leHRQYXJhbXNbcGFyYW1OYW1lXSAhPT0gcHJldlBhcmFtc1twYXJhbU5hbWVdKVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLy8gRW5zdXJlIHRoZSBxdWVyeSBoYXNuJ3QgY2hhbmdlZC5cbiAgICByZXR1cm4gaGFzUHJvcGVydGllcyhwcmV2UXVlcnksIG5leHRRdWVyeSkgJiYgaGFzUHJvcGVydGllcyhuZXh0UXVlcnksIHByZXZRdWVyeSk7XG4gIH0pO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYW5kIHJldHVybnMgYSBuZXcgcm91dGVyIHVzaW5nIHRoZSBnaXZlbiBvcHRpb25zLiBBIHJvdXRlclxuICogaXMgYSBSZWFjdENvbXBvbmVudCBjbGFzcyB0aGF0IGtub3dzIGhvdyB0byByZWFjdCB0byBjaGFuZ2VzIGluIHRoZVxuICogVVJMIGFuZCBrZWVwIHRoZSBjb250ZW50cyBvZiB0aGUgcGFnZSBpbiBzeW5jLlxuICpcbiAqIE9wdGlvbnMgbWF5IGJlIGFueSBvZiB0aGUgZm9sbG93aW5nOlxuICpcbiAqIC0gcm91dGVzICAgICAgICAgICAocmVxdWlyZWQpIFRoZSByb3V0ZSBjb25maWdcbiAqIC0gbG9jYXRpb24gICAgICAgICBUaGUgbG9jYXRpb24gdG8gdXNlLiBEZWZhdWx0cyB0byBIYXNoTG9jYXRpb24gd2hlblxuICogICAgICAgICAgICAgICAgICAgIHRoZSBET00gaXMgYXZhaWxhYmxlLCBcIi9cIiBvdGhlcndpc2VcbiAqIC0gc2Nyb2xsQmVoYXZpb3IgICBUaGUgc2Nyb2xsIGJlaGF2aW9yIHRvIHVzZS4gRGVmYXVsdHMgdG8gSW1pdGF0ZUJyb3dzZXJCZWhhdmlvclxuICogICAgICAgICAgICAgICAgICAgIHdoZW4gdGhlIERPTSBpcyBhdmFpbGFibGUsIG51bGwgb3RoZXJ3aXNlXG4gKiAtIG9uRXJyb3IgICAgICAgICAgQSBmdW5jdGlvbiB0aGF0IGlzIHVzZWQgdG8gaGFuZGxlIGVycm9yc1xuICogLSBvbkFib3J0ICAgICAgICAgIEEgZnVuY3Rpb24gdGhhdCBpcyB1c2VkIHRvIGhhbmRsZSBhYm9ydGVkIHRyYW5zaXRpb25zXG4gKlxuICogV2hlbiByZW5kZXJpbmcgaW4gYSBzZXJ2ZXItc2lkZSBlbnZpcm9ubWVudCwgdGhlIGxvY2F0aW9uIHNob3VsZCBzaW1wbHlcbiAqIGJlIHRoZSBVUkwgcGF0aCB0aGF0IHdhcyB1c2VkIGluIHRoZSByZXF1ZXN0LCBpbmNsdWRpbmcgdGhlIHF1ZXJ5IHN0cmluZy5cbiAqL1xuZnVuY3Rpb24gY3JlYXRlUm91dGVyKG9wdGlvbnMpIHtcbiAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgaWYgKHR5cGVvZiBvcHRpb25zID09PSAnZnVuY3Rpb24nKSB7XG4gICAgb3B0aW9ucyA9IHsgcm91dGVzOiBvcHRpb25zIH07IC8vIFJvdXRlci5jcmVhdGUoPFJvdXRlPilcbiAgfSBlbHNlIGlmIChBcnJheS5pc0FycmF5KG9wdGlvbnMpKSB7XG4gICAgb3B0aW9ucyA9IHsgcm91dGVzOiBvcHRpb25zIH07IC8vIFJvdXRlci5jcmVhdGUoWyA8Um91dGU+LCA8Um91dGU+IF0pXG4gIH1cblxuICB2YXIgcm91dGVzID0gW107XG4gIHZhciBuYW1lZFJvdXRlcyA9IHt9O1xuICB2YXIgY29tcG9uZW50cyA9IFtdO1xuICB2YXIgbG9jYXRpb24gPSBvcHRpb25zLmxvY2F0aW9uIHx8IERFRkFVTFRfTE9DQVRJT047XG4gIHZhciBzY3JvbGxCZWhhdmlvciA9IG9wdGlvbnMuc2Nyb2xsQmVoYXZpb3IgfHwgREVGQVVMVF9TQ1JPTExfQkVIQVZJT1I7XG4gIHZhciBvbkVycm9yID0gb3B0aW9ucy5vbkVycm9yIHx8IGRlZmF1bHRFcnJvckhhbmRsZXI7XG4gIHZhciBvbkFib3J0ID0gb3B0aW9ucy5vbkFib3J0IHx8IGRlZmF1bHRBYm9ydEhhbmRsZXI7XG4gIHZhciBzdGF0ZSA9IHt9O1xuICB2YXIgbmV4dFN0YXRlID0ge307XG4gIHZhciBwZW5kaW5nVHJhbnNpdGlvbiA9IG51bGw7XG5cbiAgZnVuY3Rpb24gdXBkYXRlU3RhdGUoKSB7XG4gICAgc3RhdGUgPSBuZXh0U3RhdGU7XG4gICAgbmV4dFN0YXRlID0ge307XG4gIH1cblxuICBpZiAodHlwZW9mIGxvY2F0aW9uID09PSAnc3RyaW5nJykge1xuICAgIHdhcm5pbmcoXG4gICAgICAhY2FuVXNlRE9NIHx8IHByb2Nlc3MuZW52Lk5PREVfRU5WID09PSAndGVzdCcsXG4gICAgICAnWW91IHNob3VsZCBub3QgdXNlIGEgc3RhdGljIGxvY2F0aW9uIGluIGEgRE9NIGVudmlyb25tZW50IGJlY2F1c2UgJyArXG4gICAgICAndGhlIHJvdXRlciB3aWxsIG5vdCBiZSBrZXB0IGluIHN5bmMgd2l0aCB0aGUgY3VycmVudCBVUkwnXG4gICAgKTtcbiAgfSBlbHNlIHtcbiAgICBpbnZhcmlhbnQoXG4gICAgICBjYW5Vc2VET00sXG4gICAgICAnWW91IGNhbm5vdCB1c2UgJXMgd2l0aG91dCBhIERPTScsXG4gICAgICBsb2NhdGlvblxuICAgICk7XG4gIH1cblxuICAvLyBBdXRvbWF0aWNhbGx5IGZhbGwgYmFjayB0byBmdWxsIHBhZ2UgcmVmcmVzaGVzIGluXG4gIC8vIGJyb3dzZXJzIHRoYXQgZG9uJ3Qgc3VwcG9ydCB0aGUgSFRNTCBoaXN0b3J5IEFQSS5cbiAgaWYgKGxvY2F0aW9uID09PSBIaXN0b3J5TG9jYXRpb24gJiYgIXN1cHBvcnRzSGlzdG9yeSgpKVxuICAgIGxvY2F0aW9uID0gUmVmcmVzaExvY2F0aW9uO1xuXG4gIHZhciByb3V0ZXIgPSBSZWFjdC5jcmVhdGVDbGFzcyh7XG5cbiAgICBkaXNwbGF5TmFtZTogJ1JvdXRlcicsXG5cbiAgICBtaXhpbnM6IFsgTmF2aWdhdGlvbkNvbnRleHQsIFN0YXRlQ29udGV4dCwgU2Nyb2xsaW5nIF0sXG5cbiAgICBzdGF0aWNzOiB7XG5cbiAgICAgIGRlZmF1bHRSb3V0ZTogbnVsbCxcbiAgICAgIG5vdEZvdW5kUm91dGU6IG51bGwsXG5cbiAgICAgIC8qKlxuICAgICAgICogQWRkcyByb3V0ZXMgdG8gdGhpcyByb3V0ZXIgZnJvbSB0aGUgZ2l2ZW4gY2hpbGRyZW4gb2JqZWN0IChzZWUgUmVhY3RDaGlsZHJlbikuXG4gICAgICAgKi9cbiAgICAgIGFkZFJvdXRlczogZnVuY3Rpb24gKGNoaWxkcmVuKSB7XG4gICAgICAgIHJvdXRlcy5wdXNoLmFwcGx5KHJvdXRlcywgY3JlYXRlUm91dGVzRnJvbUNoaWxkcmVuKGNoaWxkcmVuLCB0aGlzLCBuYW1lZFJvdXRlcykpO1xuICAgICAgfSxcblxuICAgICAgLyoqXG4gICAgICAgKiBSZXR1cm5zIGFuIGFic29sdXRlIFVSTCBwYXRoIGNyZWF0ZWQgZnJvbSB0aGUgZ2l2ZW4gcm91dGVcbiAgICAgICAqIG5hbWUsIFVSTCBwYXJhbWV0ZXJzLCBhbmQgcXVlcnkuXG4gICAgICAgKi9cbiAgICAgIG1ha2VQYXRoOiBmdW5jdGlvbiAodG8sIHBhcmFtcywgcXVlcnkpIHtcbiAgICAgICAgdmFyIHBhdGg7XG4gICAgICAgIGlmIChQYXRoLmlzQWJzb2x1dGUodG8pKSB7XG4gICAgICAgICAgcGF0aCA9IFBhdGgubm9ybWFsaXplKHRvKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB2YXIgcm91dGUgPSBuYW1lZFJvdXRlc1t0b107XG5cbiAgICAgICAgICBpbnZhcmlhbnQoXG4gICAgICAgICAgICByb3V0ZSxcbiAgICAgICAgICAgICdVbmFibGUgdG8gZmluZCA8Um91dGUgbmFtZT1cIiVzXCI+JyxcbiAgICAgICAgICAgIHRvXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIHBhdGggPSByb3V0ZS5wYXRoO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIFBhdGgud2l0aFF1ZXJ5KFBhdGguaW5qZWN0UGFyYW1zKHBhdGgsIHBhcmFtcyksIHF1ZXJ5KTtcbiAgICAgIH0sXG5cbiAgICAgIC8qKlxuICAgICAgICogUmV0dXJucyBhIHN0cmluZyB0aGF0IG1heSBzYWZlbHkgYmUgdXNlZCBhcyB0aGUgaHJlZiBvZiBhIGxpbmtcbiAgICAgICAqIHRvIHRoZSByb3V0ZSB3aXRoIHRoZSBnaXZlbiBuYW1lLCBVUkwgcGFyYW1ldGVycywgYW5kIHF1ZXJ5LlxuICAgICAgICovXG4gICAgICBtYWtlSHJlZjogZnVuY3Rpb24gKHRvLCBwYXJhbXMsIHF1ZXJ5KSB7XG4gICAgICAgIHZhciBwYXRoID0gdGhpcy5tYWtlUGF0aCh0bywgcGFyYW1zLCBxdWVyeSk7XG4gICAgICAgIHJldHVybiAobG9jYXRpb24gPT09IEhhc2hMb2NhdGlvbikgPyAnIycgKyBwYXRoIDogcGF0aDtcbiAgICAgIH0sXG5cbiAgICAgIC8qKlxuICAgICAgICogVHJhbnNpdGlvbnMgdG8gdGhlIFVSTCBzcGVjaWZpZWQgaW4gdGhlIGFyZ3VtZW50cyBieSBwdXNoaW5nXG4gICAgICAgKiBhIG5ldyBVUkwgb250byB0aGUgaGlzdG9yeSBzdGFjay5cbiAgICAgICAqL1xuICAgICAgdHJhbnNpdGlvblRvOiBmdW5jdGlvbiAodG8sIHBhcmFtcywgcXVlcnkpIHtcbiAgICAgICAgaW52YXJpYW50KFxuICAgICAgICAgIHR5cGVvZiBsb2NhdGlvbiAhPT0gJ3N0cmluZycsXG4gICAgICAgICAgJ1lvdSBjYW5ub3QgdXNlIHRyYW5zaXRpb25UbyB3aXRoIGEgc3RhdGljIGxvY2F0aW9uJ1xuICAgICAgICApO1xuXG4gICAgICAgIHZhciBwYXRoID0gdGhpcy5tYWtlUGF0aCh0bywgcGFyYW1zLCBxdWVyeSk7XG5cbiAgICAgICAgaWYgKHBlbmRpbmdUcmFuc2l0aW9uKSB7XG4gICAgICAgICAgLy8gUmVwbGFjZSBzbyBwZW5kaW5nIGxvY2F0aW9uIGRvZXMgbm90IHN0YXkgaW4gaGlzdG9yeS5cbiAgICAgICAgICBsb2NhdGlvbi5yZXBsYWNlKHBhdGgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGxvY2F0aW9uLnB1c2gocGF0aCk7XG4gICAgICAgIH1cbiAgICAgIH0sXG5cbiAgICAgIC8qKlxuICAgICAgICogVHJhbnNpdGlvbnMgdG8gdGhlIFVSTCBzcGVjaWZpZWQgaW4gdGhlIGFyZ3VtZW50cyBieSByZXBsYWNpbmdcbiAgICAgICAqIHRoZSBjdXJyZW50IFVSTCBpbiB0aGUgaGlzdG9yeSBzdGFjay5cbiAgICAgICAqL1xuICAgICAgcmVwbGFjZVdpdGg6IGZ1bmN0aW9uICh0bywgcGFyYW1zLCBxdWVyeSkge1xuICAgICAgICBpbnZhcmlhbnQoXG4gICAgICAgICAgdHlwZW9mIGxvY2F0aW9uICE9PSAnc3RyaW5nJyxcbiAgICAgICAgICAnWW91IGNhbm5vdCB1c2UgcmVwbGFjZVdpdGggd2l0aCBhIHN0YXRpYyBsb2NhdGlvbidcbiAgICAgICAgKTtcblxuICAgICAgICBsb2NhdGlvbi5yZXBsYWNlKHRoaXMubWFrZVBhdGgodG8sIHBhcmFtcywgcXVlcnkpKTtcbiAgICAgIH0sXG5cbiAgICAgIC8qKlxuICAgICAgICogVHJhbnNpdGlvbnMgdG8gdGhlIHByZXZpb3VzIFVSTCBpZiBvbmUgaXMgYXZhaWxhYmxlLiBSZXR1cm5zIHRydWUgaWYgdGhlXG4gICAgICAgKiByb3V0ZXIgd2FzIGFibGUgdG8gZ28gYmFjaywgZmFsc2Ugb3RoZXJ3aXNlLlxuICAgICAgICpcbiAgICAgICAqIE5vdGU6IFRoZSByb3V0ZXIgb25seSB0cmFja3MgaGlzdG9yeSBlbnRyaWVzIGluIHlvdXIgYXBwbGljYXRpb24sIG5vdCB0aGVcbiAgICAgICAqIGN1cnJlbnQgYnJvd3NlciBzZXNzaW9uLCBzbyB5b3UgY2FuIHNhZmVseSBjYWxsIHRoaXMgZnVuY3Rpb24gd2l0aG91dCBndWFyZGluZ1xuICAgICAgICogYWdhaW5zdCBzZW5kaW5nIHRoZSB1c2VyIGJhY2sgdG8gc29tZSBvdGhlciBzaXRlLiBIb3dldmVyLCB3aGVuIHVzaW5nXG4gICAgICAgKiBSZWZyZXNoTG9jYXRpb24gKHdoaWNoIGlzIHRoZSBmYWxsYmFjayBmb3IgSGlzdG9yeUxvY2F0aW9uIGluIGJyb3dzZXJzIHRoYXRcbiAgICAgICAqIGRvbid0IHN1cHBvcnQgSFRNTDUgaGlzdG9yeSkgdGhpcyBtZXRob2Qgd2lsbCAqYWx3YXlzKiBzZW5kIHRoZSBjbGllbnQgYmFja1xuICAgICAgICogYmVjYXVzZSB3ZSBjYW5ub3QgcmVsaWFibHkgdHJhY2sgaGlzdG9yeSBsZW5ndGguXG4gICAgICAgKi9cbiAgICAgIGdvQmFjazogZnVuY3Rpb24gKCkge1xuICAgICAgICBpbnZhcmlhbnQoXG4gICAgICAgICAgdHlwZW9mIGxvY2F0aW9uICE9PSAnc3RyaW5nJyxcbiAgICAgICAgICAnWW91IGNhbm5vdCB1c2UgZ29CYWNrIHdpdGggYSBzdGF0aWMgbG9jYXRpb24nXG4gICAgICAgICk7XG5cbiAgICAgICAgaWYgKEhpc3RvcnkubGVuZ3RoID4gMSB8fCBsb2NhdGlvbiA9PT0gUmVmcmVzaExvY2F0aW9uKSB7XG4gICAgICAgICAgbG9jYXRpb24ucG9wKCk7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICB3YXJuaW5nKGZhbHNlLCAnZ29CYWNrKCkgd2FzIGlnbm9yZWQgYmVjYXVzZSB0aGVyZSBpcyBubyByb3V0ZXIgaGlzdG9yeScpO1xuXG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH0sXG5cbiAgICAgIC8qKlxuICAgICAgICogUGVyZm9ybXMgYSBtYXRjaCBvZiB0aGUgZ2l2ZW4gcGF0aG5hbWUgYWdhaW5zdCB0aGlzIHJvdXRlciBhbmQgcmV0dXJucyBhbiBvYmplY3RcbiAgICAgICAqIHdpdGggdGhlIHsgcm91dGVzLCBwYXJhbXMgfSB0aGF0IG1hdGNoLiBSZXR1cm5zIG51bGwgaWYgbm8gbWF0Y2ggY2FuIGJlIG1hZGUuXG4gICAgICAgKi9cbiAgICAgIG1hdGNoOiBmdW5jdGlvbiAocGF0aG5hbWUpIHtcbiAgICAgICAgcmV0dXJuIGZpbmRNYXRjaChwYXRobmFtZSwgcm91dGVzLCB0aGlzLmRlZmF1bHRSb3V0ZSwgdGhpcy5ub3RGb3VuZFJvdXRlKSB8fCBudWxsO1xuICAgICAgfSxcblxuICAgICAgLyoqXG4gICAgICAgKiBQZXJmb3JtcyBhIHRyYW5zaXRpb24gdG8gdGhlIGdpdmVuIHBhdGggYW5kIGNhbGxzIGNhbGxiYWNrKGVycm9yLCBhYm9ydFJlYXNvbilcbiAgICAgICAqIHdoZW4gdGhlIHRyYW5zaXRpb24gaXMgZmluaXNoZWQuIElmIGJvdGggYXJndW1lbnRzIGFyZSBudWxsIHRoZSByb3V0ZXIncyBzdGF0ZVxuICAgICAgICogd2FzIHVwZGF0ZWQuIE90aGVyd2lzZSB0aGUgdHJhbnNpdGlvbiBkaWQgbm90IGNvbXBsZXRlLlxuICAgICAgICpcbiAgICAgICAqIEluIGEgdHJhbnNpdGlvbiwgYSByb3V0ZXIgZmlyc3QgZGV0ZXJtaW5lcyB3aGljaCByb3V0ZXMgYXJlIGludm9sdmVkIGJ5IGJlZ2lubmluZ1xuICAgICAgICogd2l0aCB0aGUgY3VycmVudCByb3V0ZSwgdXAgdGhlIHJvdXRlIHRyZWUgdG8gdGhlIGZpcnN0IHBhcmVudCByb3V0ZSB0aGF0IGlzIHNoYXJlZFxuICAgICAgICogd2l0aCB0aGUgZGVzdGluYXRpb24gcm91dGUsIGFuZCBiYWNrIGRvd24gdGhlIHRyZWUgdG8gdGhlIGRlc3RpbmF0aW9uIHJvdXRlLiBUaGVcbiAgICAgICAqIHdpbGxUcmFuc2l0aW9uRnJvbSBob29rIGlzIGludm9rZWQgb24gYWxsIHJvdXRlIGhhbmRsZXJzIHdlJ3JlIHRyYW5zaXRpb25pbmcgYXdheVxuICAgICAgICogZnJvbSwgaW4gcmV2ZXJzZSBuZXN0aW5nIG9yZGVyLiBMaWtld2lzZSwgdGhlIHdpbGxUcmFuc2l0aW9uVG8gaG9vayBpcyBpbnZva2VkIG9uXG4gICAgICAgKiBhbGwgcm91dGUgaGFuZGxlcnMgd2UncmUgdHJhbnNpdGlvbmluZyB0by5cbiAgICAgICAqXG4gICAgICAgKiBCb3RoIHdpbGxUcmFuc2l0aW9uRnJvbSBhbmQgd2lsbFRyYW5zaXRpb25UbyBob29rcyBtYXkgZWl0aGVyIGFib3J0IG9yIHJlZGlyZWN0IHRoZVxuICAgICAgICogdHJhbnNpdGlvbi4gVG8gcmVzb2x2ZSBhc3luY2hyb25vdXNseSwgdGhleSBtYXkgdXNlIHRyYW5zaXRpb24ud2FpdChwcm9taXNlKS4gSWYgbm9cbiAgICAgICAqIGhvb2tzIHdhaXQsIHRoZSB0cmFuc2l0aW9uIGlzIGZ1bGx5IHN5bmNocm9ub3VzLlxuICAgICAgICovXG4gICAgICBkaXNwYXRjaDogZnVuY3Rpb24gKHBhdGgsIGFjdGlvbiwgY2FsbGJhY2spIHtcbiAgICAgICAgaWYgKHBlbmRpbmdUcmFuc2l0aW9uKSB7XG4gICAgICAgICAgcGVuZGluZ1RyYW5zaXRpb24uYWJvcnQobmV3IENhbmNlbGxhdGlvbik7XG4gICAgICAgICAgcGVuZGluZ1RyYW5zaXRpb24gPSBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHByZXZQYXRoID0gc3RhdGUucGF0aDtcbiAgICAgICAgaWYgKHByZXZQYXRoID09PSBwYXRoKVxuICAgICAgICAgIHJldHVybjsgLy8gTm90aGluZyB0byBkbyFcblxuICAgICAgICAvLyBSZWNvcmQgdGhlIHNjcm9sbCBwb3NpdGlvbiBhcyBlYXJseSBhcyBwb3NzaWJsZSB0b1xuICAgICAgICAvLyBnZXQgaXQgYmVmb3JlIGJyb3dzZXJzIHRyeSB1cGRhdGUgaXQgYXV0b21hdGljYWxseS5cbiAgICAgICAgaWYgKHByZXZQYXRoICYmIGFjdGlvbiAhPT0gTG9jYXRpb25BY3Rpb25zLlJFUExBQ0UpXG4gICAgICAgICAgdGhpcy5yZWNvcmRTY3JvbGxQb3NpdGlvbihwcmV2UGF0aCk7XG5cbiAgICAgICAgdmFyIHBhdGhuYW1lID0gUGF0aC53aXRob3V0UXVlcnkocGF0aCk7XG4gICAgICAgIHZhciBtYXRjaCA9IHRoaXMubWF0Y2gocGF0aG5hbWUpO1xuXG4gICAgICAgIHdhcm5pbmcoXG4gICAgICAgICAgbWF0Y2ggIT0gbnVsbCxcbiAgICAgICAgICAnTm8gcm91dGUgbWF0Y2hlcyBwYXRoIFwiJXNcIi4gTWFrZSBzdXJlIHlvdSBoYXZlIDxSb3V0ZSBwYXRoPVwiJXNcIj4gc29tZXdoZXJlIGluIHlvdXIgcm91dGVzJyxcbiAgICAgICAgICBwYXRoLCBwYXRoXG4gICAgICAgICk7XG5cbiAgICAgICAgaWYgKG1hdGNoID09IG51bGwpXG4gICAgICAgICAgbWF0Y2ggPSB7fTtcblxuICAgICAgICB2YXIgcHJldlJvdXRlcyA9IHN0YXRlLnJvdXRlcyB8fCBbXTtcbiAgICAgICAgdmFyIHByZXZQYXJhbXMgPSBzdGF0ZS5wYXJhbXMgfHwge307XG4gICAgICAgIHZhciBwcmV2UXVlcnkgPSBzdGF0ZS5xdWVyeSB8fCB7fTtcblxuICAgICAgICB2YXIgbmV4dFJvdXRlcyA9IG1hdGNoLnJvdXRlcyB8fCBbXTtcbiAgICAgICAgdmFyIG5leHRQYXJhbXMgPSBtYXRjaC5wYXJhbXMgfHwge307XG4gICAgICAgIHZhciBuZXh0UXVlcnkgPSBQYXRoLmV4dHJhY3RRdWVyeShwYXRoKSB8fCB7fTtcblxuICAgICAgICB2YXIgZnJvbVJvdXRlcywgdG9Sb3V0ZXM7XG4gICAgICAgIGlmIChwcmV2Um91dGVzLmxlbmd0aCkge1xuICAgICAgICAgIGZyb21Sb3V0ZXMgPSBwcmV2Um91dGVzLmZpbHRlcihmdW5jdGlvbiAocm91dGUpIHtcbiAgICAgICAgICAgIHJldHVybiAhaGFzTWF0Y2gobmV4dFJvdXRlcywgcm91dGUsIHByZXZQYXJhbXMsIG5leHRQYXJhbXMsIHByZXZRdWVyeSwgbmV4dFF1ZXJ5KTtcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIHRvUm91dGVzID0gbmV4dFJvdXRlcy5maWx0ZXIoZnVuY3Rpb24gKHJvdXRlKSB7XG4gICAgICAgICAgICByZXR1cm4gIWhhc01hdGNoKHByZXZSb3V0ZXMsIHJvdXRlLCBwcmV2UGFyYW1zLCBuZXh0UGFyYW1zLCBwcmV2UXVlcnksIG5leHRRdWVyeSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZnJvbVJvdXRlcyA9IFtdO1xuICAgICAgICAgIHRvUm91dGVzID0gbmV4dFJvdXRlcztcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciB0cmFuc2l0aW9uID0gbmV3IFRyYW5zaXRpb24ocGF0aCwgdGhpcy5yZXBsYWNlV2l0aC5iaW5kKHRoaXMsIHBhdGgpKTtcbiAgICAgICAgcGVuZGluZ1RyYW5zaXRpb24gPSB0cmFuc2l0aW9uO1xuXG4gICAgICAgIHRyYW5zaXRpb24uZnJvbShmcm9tUm91dGVzLCBjb21wb25lbnRzLCBmdW5jdGlvbiAoZXJyb3IpIHtcbiAgICAgICAgICBpZiAoZXJyb3IgfHwgdHJhbnNpdGlvbi5pc0Fib3J0ZWQpXG4gICAgICAgICAgICByZXR1cm4gY2FsbGJhY2suY2FsbChyb3V0ZXIsIGVycm9yLCB0cmFuc2l0aW9uKTtcblxuICAgICAgICAgIHRyYW5zaXRpb24udG8odG9Sb3V0ZXMsIG5leHRQYXJhbXMsIG5leHRRdWVyeSwgZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICBpZiAoZXJyb3IgfHwgdHJhbnNpdGlvbi5pc0Fib3J0ZWQpXG4gICAgICAgICAgICAgIHJldHVybiBjYWxsYmFjay5jYWxsKHJvdXRlciwgZXJyb3IsIHRyYW5zaXRpb24pO1xuXG4gICAgICAgICAgICBuZXh0U3RhdGUucGF0aCA9IHBhdGg7XG4gICAgICAgICAgICBuZXh0U3RhdGUuYWN0aW9uID0gYWN0aW9uO1xuICAgICAgICAgICAgbmV4dFN0YXRlLnBhdGhuYW1lID0gcGF0aG5hbWU7XG4gICAgICAgICAgICBuZXh0U3RhdGUucm91dGVzID0gbmV4dFJvdXRlcztcbiAgICAgICAgICAgIG5leHRTdGF0ZS5wYXJhbXMgPSBuZXh0UGFyYW1zO1xuICAgICAgICAgICAgbmV4dFN0YXRlLnF1ZXJ5ID0gbmV4dFF1ZXJ5O1xuXG4gICAgICAgICAgICBjYWxsYmFjay5jYWxsKHJvdXRlciwgbnVsbCwgdHJhbnNpdGlvbik7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgfSxcblxuICAgICAgLyoqXG4gICAgICAgKiBTdGFydHMgdGhpcyByb3V0ZXIgYW5kIGNhbGxzIGNhbGxiYWNrKHJvdXRlciwgc3RhdGUpIHdoZW4gdGhlIHJvdXRlIGNoYW5nZXMuXG4gICAgICAgKlxuICAgICAgICogSWYgdGhlIHJvdXRlcidzIGxvY2F0aW9uIGlzIHN0YXRpYyAoaS5lLiBhIFVSTCBwYXRoIGluIGEgc2VydmVyIGVudmlyb25tZW50KVxuICAgICAgICogdGhlIGNhbGxiYWNrIGlzIGNhbGxlZCBvbmx5IG9uY2UuIE90aGVyd2lzZSwgdGhlIGxvY2F0aW9uIHNob3VsZCBiZSBvbmUgb2YgdGhlXG4gICAgICAgKiBSb3V0ZXIuKkxvY2F0aW9uIG9iamVjdHMgKGUuZy4gUm91dGVyLkhhc2hMb2NhdGlvbiBvciBSb3V0ZXIuSGlzdG9yeUxvY2F0aW9uKS5cbiAgICAgICAqL1xuICAgICAgcnVuOiBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgICAgICAgdmFyIGRpc3BhdGNoSGFuZGxlciA9IGZ1bmN0aW9uIChlcnJvciwgdHJhbnNpdGlvbikge1xuICAgICAgICAgIHBlbmRpbmdUcmFuc2l0aW9uID0gbnVsbDtcblxuICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgb25FcnJvci5jYWxsKHJvdXRlciwgZXJyb3IpO1xuICAgICAgICAgIH0gZWxzZSBpZiAodHJhbnNpdGlvbi5pc0Fib3J0ZWQpIHtcbiAgICAgICAgICAgIG9uQWJvcnQuY2FsbChyb3V0ZXIsIHRyYW5zaXRpb24uYWJvcnRSZWFzb24sIGxvY2F0aW9uKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY2FsbGJhY2suY2FsbChyb3V0ZXIsIHJvdXRlciwgbmV4dFN0YXRlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgaWYgKHR5cGVvZiBsb2NhdGlvbiA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICByb3V0ZXIuZGlzcGF0Y2gobG9jYXRpb24sIG51bGwsIGRpc3BhdGNoSGFuZGxlcik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gTGlzdGVuIGZvciBjaGFuZ2VzIHRvIHRoZSBsb2NhdGlvbi5cbiAgICAgICAgICB2YXIgY2hhbmdlTGlzdGVuZXIgPSBmdW5jdGlvbiAoY2hhbmdlKSB7XG4gICAgICAgICAgICByb3V0ZXIuZGlzcGF0Y2goY2hhbmdlLnBhdGgsIGNoYW5nZS50eXBlLCBkaXNwYXRjaEhhbmRsZXIpO1xuICAgICAgICAgIH07XG5cbiAgICAgICAgICBpZiAobG9jYXRpb24uYWRkQ2hhbmdlTGlzdGVuZXIpXG4gICAgICAgICAgICBsb2NhdGlvbi5hZGRDaGFuZ2VMaXN0ZW5lcihjaGFuZ2VMaXN0ZW5lcik7XG5cbiAgICAgICAgICAvLyBCb290c3RyYXAgdXNpbmcgdGhlIGN1cnJlbnQgcGF0aC5cbiAgICAgICAgICByb3V0ZXIuZGlzcGF0Y2gobG9jYXRpb24uZ2V0Q3VycmVudFBhdGgoKSwgbnVsbCwgZGlzcGF0Y2hIYW5kbGVyKTtcbiAgICAgICAgfVxuICAgICAgfSxcblxuICAgICAgdGVhcmRvd246IGZ1bmN0aW9uKCkge1xuICAgICAgICBsb2NhdGlvbi5yZW1vdmVDaGFuZ2VMaXN0ZW5lcih0aGlzLmNoYW5nZUxpc3RlbmVyKTtcbiAgICAgIH1cblxuICAgIH0sXG5cbiAgICBwcm9wVHlwZXM6IHtcbiAgICAgIGNoaWxkcmVuOiBQcm9wVHlwZXMuZmFsc3lcbiAgICB9LFxuXG4gICAgZ2V0TG9jYXRpb246IGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBsb2NhdGlvbjtcbiAgICB9LFxuXG4gICAgZ2V0U2Nyb2xsQmVoYXZpb3I6IGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBzY3JvbGxCZWhhdmlvcjtcbiAgICB9LFxuXG4gICAgZ2V0Um91dGVBdERlcHRoOiBmdW5jdGlvbiAoZGVwdGgpIHtcbiAgICAgIHZhciByb3V0ZXMgPSB0aGlzLnN0YXRlLnJvdXRlcztcbiAgICAgIHJldHVybiByb3V0ZXMgJiYgcm91dGVzW2RlcHRoXTtcbiAgICB9LFxuXG4gICAgZ2V0Um91dGVDb21wb25lbnRzOiBmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gY29tcG9uZW50cztcbiAgICB9LFxuXG4gICAgZ2V0SW5pdGlhbFN0YXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgICB1cGRhdGVTdGF0ZSgpO1xuICAgICAgcmV0dXJuIHN0YXRlO1xuICAgIH0sXG5cbiAgICBjb21wb25lbnRXaWxsUmVjZWl2ZVByb3BzOiBmdW5jdGlvbiAoKSB7XG4gICAgICB1cGRhdGVTdGF0ZSgpO1xuICAgICAgdGhpcy5zZXRTdGF0ZShzdGF0ZSk7XG4gICAgfSxcblxuICAgIGNvbXBvbmVudFdpbGxVbm1vdW50OiBmdW5jdGlvbigpIHtcbiAgICAgIHJvdXRlci50ZWFyZG93bigpO1xuICAgIH0sXG5cbiAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiB0aGlzLmdldFJvdXRlQXREZXB0aCgwKSA/IFJlYWN0LmNyZWF0ZUVsZW1lbnQoUm91dGVIYW5kbGVyLCB0aGlzLnByb3BzKSA6IG51bGw7XG4gICAgfSxcblxuICAgIGNoaWxkQ29udGV4dFR5cGVzOiB7XG4gICAgICBnZXRSb3V0ZUF0RGVwdGg6IFJlYWN0LlByb3BUeXBlcy5mdW5jLmlzUmVxdWlyZWQsXG4gICAgICBnZXRSb3V0ZUNvbXBvbmVudHM6IFJlYWN0LlByb3BUeXBlcy5mdW5jLmlzUmVxdWlyZWQsXG4gICAgICByb3V0ZUhhbmRsZXJzOiBSZWFjdC5Qcm9wVHlwZXMuYXJyYXkuaXNSZXF1aXJlZFxuICAgIH0sXG5cbiAgICBnZXRDaGlsZENvbnRleHQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGdldFJvdXRlQ29tcG9uZW50czogdGhpcy5nZXRSb3V0ZUNvbXBvbmVudHMsXG4gICAgICAgIGdldFJvdXRlQXREZXB0aDogdGhpcy5nZXRSb3V0ZUF0RGVwdGgsXG4gICAgICAgIHJvdXRlSGFuZGxlcnM6IFsgdGhpcyBdXG4gICAgICB9O1xuICAgIH1cblxuICB9KTtcblxuICBpZiAob3B0aW9ucy5yb3V0ZXMpXG4gICAgcm91dGVyLmFkZFJvdXRlcyhvcHRpb25zLnJvdXRlcyk7XG5cbiAgcmV0dXJuIHJvdXRlcjtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBjcmVhdGVSb3V0ZXI7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qIGpzaGludCAtVzA4NCAqL1xudmFyIFJlYWN0ID0gcmVxdWlyZSgncmVhY3QnKTtcbnZhciB3YXJuaW5nID0gcmVxdWlyZSgncmVhY3QvbGliL3dhcm5pbmcnKTtcbnZhciBpbnZhcmlhbnQgPSByZXF1aXJlKCdyZWFjdC9saWIvaW52YXJpYW50Jyk7XG52YXIgRGVmYXVsdFJvdXRlID0gcmVxdWlyZSgnLi4vY29tcG9uZW50cy9EZWZhdWx0Um91dGUnKTtcbnZhciBOb3RGb3VuZFJvdXRlID0gcmVxdWlyZSgnLi4vY29tcG9uZW50cy9Ob3RGb3VuZFJvdXRlJyk7XG52YXIgUmVkaXJlY3QgPSByZXF1aXJlKCcuLi9jb21wb25lbnRzL1JlZGlyZWN0Jyk7XG52YXIgUm91dGUgPSByZXF1aXJlKCcuLi9jb21wb25lbnRzL1JvdXRlJyk7XG52YXIgUGF0aCA9IHJlcXVpcmUoJy4vUGF0aCcpO1xuXG52YXIgQ09ORklHX0VMRU1FTlRfVFlQRVMgPSBbXG4gIERlZmF1bHRSb3V0ZS50eXBlLFxuICBOb3RGb3VuZFJvdXRlLnR5cGUsXG4gIFJlZGlyZWN0LnR5cGUsXG4gIFJvdXRlLnR5cGVcbl07XG5cbmZ1bmN0aW9uIGNyZWF0ZVJlZGlyZWN0SGFuZGxlcih0bywgX3BhcmFtcywgX3F1ZXJ5KSB7XG4gIHJldHVybiBSZWFjdC5jcmVhdGVDbGFzcyh7XG4gICAgc3RhdGljczoge1xuICAgICAgd2lsbFRyYW5zaXRpb25UbzogZnVuY3Rpb24gKHRyYW5zaXRpb24sIHBhcmFtcywgcXVlcnkpIHtcbiAgICAgICAgdHJhbnNpdGlvbi5yZWRpcmVjdCh0bywgX3BhcmFtcyB8fCBwYXJhbXMsIF9xdWVyeSB8fCBxdWVyeSk7XG4gICAgICB9XG4gICAgfSxcblxuICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICB9KTtcbn1cblxuZnVuY3Rpb24gY2hlY2tQcm9wVHlwZXMoY29tcG9uZW50TmFtZSwgcHJvcFR5cGVzLCBwcm9wcykge1xuICBmb3IgKHZhciBwcm9wTmFtZSBpbiBwcm9wVHlwZXMpIHtcbiAgICBpZiAocHJvcFR5cGVzLmhhc093blByb3BlcnR5KHByb3BOYW1lKSkge1xuICAgICAgdmFyIGVycm9yID0gcHJvcFR5cGVzW3Byb3BOYW1lXShwcm9wcywgcHJvcE5hbWUsIGNvbXBvbmVudE5hbWUpO1xuXG4gICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvcilcbiAgICAgICAgd2FybmluZyhmYWxzZSwgZXJyb3IubWVzc2FnZSk7XG4gICAgfVxuICB9XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZVJvdXRlKGVsZW1lbnQsIHBhcmVudFJvdXRlLCBuYW1lZFJvdXRlcykge1xuICB2YXIgdHlwZSA9IGVsZW1lbnQudHlwZTtcbiAgdmFyIHByb3BzID0gZWxlbWVudC5wcm9wcztcbiAgdmFyIGNvbXBvbmVudE5hbWUgPSAodHlwZSAmJiB0eXBlLmRpc3BsYXlOYW1lKSB8fCAnVW5rbm93bkNvbXBvbmVudCc7XG5cbiAgaW52YXJpYW50KFxuICAgIENPTkZJR19FTEVNRU5UX1RZUEVTLmluZGV4T2YodHlwZSkgIT09IC0xLFxuICAgICdVbnJlY29nbml6ZWQgcm91dGUgY29uZmlndXJhdGlvbiBlbGVtZW50IFwiPCVzPlwiJyxcbiAgICBjb21wb25lbnROYW1lXG4gICk7XG5cbiAgaWYgKHR5cGUucHJvcFR5cGVzKVxuICAgIGNoZWNrUHJvcFR5cGVzKGNvbXBvbmVudE5hbWUsIHR5cGUucHJvcFR5cGVzLCBwcm9wcyk7XG5cbiAgdmFyIHJvdXRlID0geyBuYW1lOiBwcm9wcy5uYW1lIH07XG5cbiAgaWYgKHByb3BzLmlnbm9yZVNjcm9sbEJlaGF2aW9yKSB7XG4gICAgcm91dGUuaWdub3JlU2Nyb2xsQmVoYXZpb3IgPSB0cnVlO1xuICB9XG5cbiAgaWYgKHR5cGUgPT09IFJlZGlyZWN0LnR5cGUpIHtcbiAgICByb3V0ZS5oYW5kbGVyID0gY3JlYXRlUmVkaXJlY3RIYW5kbGVyKHByb3BzLnRvLCBwcm9wcy5wYXJhbXMsIHByb3BzLnF1ZXJ5KTtcbiAgICBwcm9wcy5wYXRoID0gcHJvcHMucGF0aCB8fCBwcm9wcy5mcm9tIHx8ICcqJztcbiAgfSBlbHNlIHtcbiAgICByb3V0ZS5oYW5kbGVyID0gcHJvcHMuaGFuZGxlcjtcbiAgfVxuXG4gIHZhciBwYXJlbnRQYXRoID0gKHBhcmVudFJvdXRlICYmIHBhcmVudFJvdXRlLnBhdGgpIHx8ICcvJztcblxuICBpZiAoKHByb3BzLnBhdGggfHwgcHJvcHMubmFtZSkgJiYgdHlwZSAhPT0gRGVmYXVsdFJvdXRlLnR5cGUgJiYgdHlwZSAhPT0gTm90Rm91bmRSb3V0ZS50eXBlKSB7XG4gICAgdmFyIHBhdGggPSBwcm9wcy5wYXRoIHx8IHByb3BzLm5hbWU7XG5cbiAgICAvLyBSZWxhdGl2ZSBwYXRocyBleHRlbmQgdGhlaXIgcGFyZW50LlxuICAgIGlmICghUGF0aC5pc0Fic29sdXRlKHBhdGgpKVxuICAgICAgcGF0aCA9IFBhdGguam9pbihwYXJlbnRQYXRoLCBwYXRoKTtcblxuICAgIHJvdXRlLnBhdGggPSBQYXRoLm5vcm1hbGl6ZShwYXRoKTtcbiAgfSBlbHNlIHtcbiAgICByb3V0ZS5wYXRoID0gcGFyZW50UGF0aDtcblxuICAgIGlmICh0eXBlID09PSBOb3RGb3VuZFJvdXRlLnR5cGUpXG4gICAgICByb3V0ZS5wYXRoICs9ICcqJztcbiAgfVxuXG4gIHJvdXRlLnBhcmFtTmFtZXMgPSBQYXRoLmV4dHJhY3RQYXJhbU5hbWVzKHJvdXRlLnBhdGgpO1xuXG4gIC8vIE1ha2Ugc3VyZSB0aGUgcm91dGUncyBwYXRoIGhhcyBhbGwgcGFyYW1zIGl0cyBwYXJlbnQgbmVlZHMuXG4gIGlmIChwYXJlbnRSb3V0ZSAmJiBBcnJheS5pc0FycmF5KHBhcmVudFJvdXRlLnBhcmFtTmFtZXMpKSB7XG4gICAgcGFyZW50Um91dGUucGFyYW1OYW1lcy5mb3JFYWNoKGZ1bmN0aW9uIChwYXJhbU5hbWUpIHtcbiAgICAgIGludmFyaWFudChcbiAgICAgICAgcm91dGUucGFyYW1OYW1lcy5pbmRleE9mKHBhcmFtTmFtZSkgIT09IC0xLFxuICAgICAgICAnVGhlIG5lc3RlZCByb3V0ZSBwYXRoIFwiJXNcIiBpcyBtaXNzaW5nIHRoZSBcIiVzXCIgcGFyYW1ldGVyIG9mIGl0cyBwYXJlbnQgcGF0aCBcIiVzXCInLFxuICAgICAgICByb3V0ZS5wYXRoLCBwYXJhbU5hbWUsIHBhcmVudFJvdXRlLnBhdGhcbiAgICAgICk7XG4gICAgfSk7XG4gIH1cblxuICAvLyBNYWtlIHN1cmUgdGhlIHJvdXRlIGNhbiBiZSBsb29rZWQgdXAgYnkgPExpbms+cy5cbiAgaWYgKHByb3BzLm5hbWUpIHtcbiAgICBpbnZhcmlhbnQoXG4gICAgICBuYW1lZFJvdXRlc1twcm9wcy5uYW1lXSA9PSBudWxsLFxuICAgICAgJ1lvdSBjYW5ub3QgdXNlIHRoZSBuYW1lIFwiJXNcIiBmb3IgbW9yZSB0aGFuIG9uZSByb3V0ZScsXG4gICAgICBwcm9wcy5uYW1lXG4gICAgKTtcblxuICAgIG5hbWVkUm91dGVzW3Byb3BzLm5hbWVdID0gcm91dGU7XG4gIH1cblxuICAvLyBIYW5kbGUgPE5vdEZvdW5kUm91dGU+LlxuICBpZiAodHlwZSA9PT0gTm90Rm91bmRSb3V0ZS50eXBlKSB7XG4gICAgaW52YXJpYW50KFxuICAgICAgcGFyZW50Um91dGUsXG4gICAgICAnPE5vdEZvdW5kUm91dGU+IG11c3QgaGF2ZSBhIHBhcmVudCA8Um91dGU+J1xuICAgICk7XG5cbiAgICBpbnZhcmlhbnQoXG4gICAgICBwYXJlbnRSb3V0ZS5ub3RGb3VuZFJvdXRlID09IG51bGwsXG4gICAgICAnWW91IG1heSBub3QgaGF2ZSBtb3JlIHRoYW4gb25lIDxOb3RGb3VuZFJvdXRlPiBwZXIgPFJvdXRlPidcbiAgICApO1xuXG4gICAgcGFyZW50Um91dGUubm90Rm91bmRSb3V0ZSA9IHJvdXRlO1xuXG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICAvLyBIYW5kbGUgPERlZmF1bHRSb3V0ZT4uXG4gIGlmICh0eXBlID09PSBEZWZhdWx0Um91dGUudHlwZSkge1xuICAgIGludmFyaWFudChcbiAgICAgIHBhcmVudFJvdXRlLFxuICAgICAgJzxEZWZhdWx0Um91dGU+IG11c3QgaGF2ZSBhIHBhcmVudCA8Um91dGU+J1xuICAgICk7XG5cbiAgICBpbnZhcmlhbnQoXG4gICAgICBwYXJlbnRSb3V0ZS5kZWZhdWx0Um91dGUgPT0gbnVsbCxcbiAgICAgICdZb3UgbWF5IG5vdCBoYXZlIG1vcmUgdGhhbiBvbmUgPERlZmF1bHRSb3V0ZT4gcGVyIDxSb3V0ZT4nXG4gICAgKTtcblxuICAgIHBhcmVudFJvdXRlLmRlZmF1bHRSb3V0ZSA9IHJvdXRlO1xuXG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICByb3V0ZS5jaGlsZFJvdXRlcyA9IGNyZWF0ZVJvdXRlc0Zyb21DaGlsZHJlbihwcm9wcy5jaGlsZHJlbiwgcm91dGUsIG5hbWVkUm91dGVzKTtcblxuICByZXR1cm4gcm91dGU7XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhbmQgcmV0dXJucyBhbiBhcnJheSBvZiByb3V0ZSBvYmplY3RzIGZyb20gdGhlIGdpdmVuIFJlYWN0Q2hpbGRyZW4uXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZVJvdXRlc0Zyb21DaGlsZHJlbihjaGlsZHJlbiwgcGFyZW50Um91dGUsIG5hbWVkUm91dGVzKSB7XG4gIHZhciByb3V0ZXMgPSBbXTtcblxuICBSZWFjdC5DaGlsZHJlbi5mb3JFYWNoKGNoaWxkcmVuLCBmdW5jdGlvbiAoY2hpbGQpIHtcbiAgICAvLyBFeGNsdWRlIDxEZWZhdWx0Um91dGU+cyBhbmQgPE5vdEZvdW5kUm91dGU+cy5cbiAgICBpZiAoY2hpbGQgPSBjcmVhdGVSb3V0ZShjaGlsZCwgcGFyZW50Um91dGUsIG5hbWVkUm91dGVzKSlcbiAgICAgIHJvdXRlcy5wdXNoKGNoaWxkKTtcbiAgfSk7XG5cbiAgcmV0dXJuIHJvdXRlcztcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBjcmVhdGVSb3V0ZXNGcm9tQ2hpbGRyZW47XG4iLCJ2YXIgaW52YXJpYW50ID0gcmVxdWlyZSgncmVhY3QvbGliL2ludmFyaWFudCcpO1xudmFyIGNhblVzZURPTSA9IHJlcXVpcmUoJ3JlYWN0L2xpYi9FeGVjdXRpb25FbnZpcm9ubWVudCcpLmNhblVzZURPTTtcblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBjdXJyZW50IHNjcm9sbCBwb3NpdGlvbiBvZiB0aGUgd2luZG93IGFzIHsgeCwgeSB9LlxuICovXG5mdW5jdGlvbiBnZXRXaW5kb3dTY3JvbGxQb3NpdGlvbigpIHtcbiAgaW52YXJpYW50KFxuICAgIGNhblVzZURPTSxcbiAgICAnQ2Fubm90IGdldCBjdXJyZW50IHNjcm9sbCBwb3NpdGlvbiB3aXRob3V0IGEgRE9NJ1xuICApO1xuXG4gIHJldHVybiB7XG4gICAgeDogd2luZG93LnBhZ2VYT2Zmc2V0IHx8IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zY3JvbGxMZWZ0LFxuICAgIHk6IHdpbmRvdy5wYWdlWU9mZnNldCB8fCBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuc2Nyb2xsVG9wXG4gIH07XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZ2V0V2luZG93U2Nyb2xsUG9zaXRpb247XG4iLCJmdW5jdGlvbiByZXZlcnNlZEFycmF5KGFycmF5KSB7XG4gIHJldHVybiBhcnJheS5zbGljZSgwKS5yZXZlcnNlKCk7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gcmV2ZXJzZWRBcnJheTtcbiIsInZhciBjcmVhdGVSb3V0ZXIgPSByZXF1aXJlKCcuL2NyZWF0ZVJvdXRlcicpO1xuXG4vKipcbiAqIEEgaGlnaC1sZXZlbCBjb252ZW5pZW5jZSBtZXRob2QgdGhhdCBjcmVhdGVzLCBjb25maWd1cmVzLCBhbmRcbiAqIHJ1bnMgYSByb3V0ZXIgaW4gb25lIHNob3QuIFRoZSBtZXRob2Qgc2lnbmF0dXJlIGlzOlxuICpcbiAqICAgUm91dGVyLnJ1bihyb3V0ZXNbLCBsb2NhdGlvbiBdLCBjYWxsYmFjayk7XG4gKlxuICogVXNpbmcgYHdpbmRvdy5sb2NhdGlvbi5oYXNoYCB0byBtYW5hZ2UgdGhlIFVSTCwgeW91IGNvdWxkIGRvOlxuICpcbiAqICAgUm91dGVyLnJ1bihyb3V0ZXMsIGZ1bmN0aW9uIChIYW5kbGVyKSB7XG4gKiAgICAgUmVhY3QucmVuZGVyKDxIYW5kbGVyLz4sIGRvY3VtZW50LmJvZHkpO1xuICogICB9KTtcbiAqIFxuICogVXNpbmcgSFRNTDUgaGlzdG9yeSBhbmQgYSBjdXN0b20gXCJjdXJzb3JcIiBwcm9wOlxuICogXG4gKiAgIFJvdXRlci5ydW4ocm91dGVzLCBSb3V0ZXIuSGlzdG9yeUxvY2F0aW9uLCBmdW5jdGlvbiAoSGFuZGxlcikge1xuICogICAgIFJlYWN0LnJlbmRlcig8SGFuZGxlciBjdXJzb3I9e2N1cnNvcn0vPiwgZG9jdW1lbnQuYm9keSk7XG4gKiAgIH0pO1xuICpcbiAqIFJldHVybnMgdGhlIG5ld2x5IGNyZWF0ZWQgcm91dGVyLlxuICpcbiAqIE5vdGU6IElmIHlvdSBuZWVkIHRvIHNwZWNpZnkgZnVydGhlciBvcHRpb25zIGZvciB5b3VyIHJvdXRlciBzdWNoXG4gKiBhcyBlcnJvci9hYm9ydCBoYW5kbGluZyBvciBjdXN0b20gc2Nyb2xsIGJlaGF2aW9yLCB1c2UgUm91dGVyLmNyZWF0ZVxuICogaW5zdGVhZC5cbiAqXG4gKiAgIHZhciByb3V0ZXIgPSBSb3V0ZXIuY3JlYXRlKG9wdGlvbnMpO1xuICogICByb3V0ZXIucnVuKGZ1bmN0aW9uIChIYW5kbGVyKSB7XG4gKiAgICAgLy8gLi4uXG4gKiAgIH0pO1xuICovXG5mdW5jdGlvbiBydW5Sb3V0ZXIocm91dGVzLCBsb2NhdGlvbiwgY2FsbGJhY2spIHtcbiAgaWYgKHR5cGVvZiBsb2NhdGlvbiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgIGNhbGxiYWNrID0gbG9jYXRpb247XG4gICAgbG9jYXRpb24gPSBudWxsO1xuICB9XG5cbiAgdmFyIHJvdXRlciA9IGNyZWF0ZVJvdXRlcih7XG4gICAgcm91dGVzOiByb3V0ZXMsXG4gICAgbG9jYXRpb246IGxvY2F0aW9uXG4gIH0pO1xuXG4gIHJvdXRlci5ydW4oY2FsbGJhY2spO1xuXG4gIHJldHVybiByb3V0ZXI7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gcnVuUm91dGVyO1xuIiwiZnVuY3Rpb24gc3VwcG9ydHNIaXN0b3J5KCkge1xuICAvKiEgdGFrZW4gZnJvbSBtb2Rlcm5penJcbiAgICogaHR0cHM6Ly9naXRodWIuY29tL01vZGVybml6ci9Nb2Rlcm5penIvYmxvYi9tYXN0ZXIvTElDRU5TRVxuICAgKiBodHRwczovL2dpdGh1Yi5jb20vTW9kZXJuaXpyL01vZGVybml6ci9ibG9iL21hc3Rlci9mZWF0dXJlLWRldGVjdHMvaGlzdG9yeS5qc1xuICAgKiBjaGFuZ2VkIHRvIGF2b2lkIGZhbHNlIG5lZ2F0aXZlcyBmb3IgV2luZG93cyBQaG9uZXM6IGh0dHBzOi8vZ2l0aHViLmNvbS9yYWNrdC9yZWFjdC1yb3V0ZXIvaXNzdWVzLzU4NlxuICAgKi9cbiAgdmFyIHVhID0gbmF2aWdhdG9yLnVzZXJBZ2VudDtcbiAgaWYgKCh1YS5pbmRleE9mKCdBbmRyb2lkIDIuJykgIT09IC0xIHx8XG4gICAgICAodWEuaW5kZXhPZignQW5kcm9pZCA0LjAnKSAhPT0gLTEpKSAmJlxuICAgICAgdWEuaW5kZXhPZignTW9iaWxlIFNhZmFyaScpICE9PSAtMSAmJlxuICAgICAgdWEuaW5kZXhPZignQ2hyb21lJykgPT09IC0xICYmXG4gICAgICB1YS5pbmRleE9mKCdXaW5kb3dzIFBob25lJykgPT09IC0xKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIHJldHVybiAod2luZG93Lmhpc3RvcnkgJiYgJ3B1c2hTdGF0ZScgaW4gd2luZG93Lmhpc3RvcnkpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHN1cHBvcnRzSGlzdG9yeTtcbiIsIm1vZHVsZS5leHBvcnRzID0gcmVxdWlyZSgnLi9saWInKTtcbiIsIi8vIExvYWQgbW9kdWxlc1xuXG52YXIgU3RyaW5naWZ5ID0gcmVxdWlyZSgnLi9zdHJpbmdpZnknKTtcbnZhciBQYXJzZSA9IHJlcXVpcmUoJy4vcGFyc2UnKTtcblxuXG4vLyBEZWNsYXJlIGludGVybmFsc1xuXG52YXIgaW50ZXJuYWxzID0ge307XG5cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgc3RyaW5naWZ5OiBTdHJpbmdpZnksXG4gICAgcGFyc2U6IFBhcnNlXG59O1xuIiwiLy8gTG9hZCBtb2R1bGVzXG5cbnZhciBVdGlscyA9IHJlcXVpcmUoJy4vdXRpbHMnKTtcblxuXG4vLyBEZWNsYXJlIGludGVybmFsc1xuXG52YXIgaW50ZXJuYWxzID0ge1xuICAgIGRlbGltaXRlcjogJyYnLFxuICAgIGRlcHRoOiA1LFxuICAgIGFycmF5TGltaXQ6IDIwLFxuICAgIHBhcmFtZXRlckxpbWl0OiAxMDAwXG59O1xuXG5cbmludGVybmFscy5wYXJzZVZhbHVlcyA9IGZ1bmN0aW9uIChzdHIsIG9wdGlvbnMpIHtcblxuICAgIHZhciBvYmogPSB7fTtcbiAgICB2YXIgcGFydHMgPSBzdHIuc3BsaXQob3B0aW9ucy5kZWxpbWl0ZXIsIG9wdGlvbnMucGFyYW1ldGVyTGltaXQgPT09IEluZmluaXR5ID8gdW5kZWZpbmVkIDogb3B0aW9ucy5wYXJhbWV0ZXJMaW1pdCk7XG5cbiAgICBmb3IgKHZhciBpID0gMCwgaWwgPSBwYXJ0cy5sZW5ndGg7IGkgPCBpbDsgKytpKSB7XG4gICAgICAgIHZhciBwYXJ0ID0gcGFydHNbaV07XG4gICAgICAgIHZhciBwb3MgPSBwYXJ0LmluZGV4T2YoJ109JykgPT09IC0xID8gcGFydC5pbmRleE9mKCc9JykgOiBwYXJ0LmluZGV4T2YoJ109JykgKyAxO1xuXG4gICAgICAgIGlmIChwb3MgPT09IC0xKSB7XG4gICAgICAgICAgICBvYmpbVXRpbHMuZGVjb2RlKHBhcnQpXSA9ICcnO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdmFyIGtleSA9IFV0aWxzLmRlY29kZShwYXJ0LnNsaWNlKDAsIHBvcykpO1xuICAgICAgICAgICAgdmFyIHZhbCA9IFV0aWxzLmRlY29kZShwYXJ0LnNsaWNlKHBvcyArIDEpKTtcblxuICAgICAgICAgICAgaWYgKCFvYmpba2V5XSkge1xuICAgICAgICAgICAgICAgIG9ialtrZXldID0gdmFsO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgb2JqW2tleV0gPSBbXS5jb25jYXQob2JqW2tleV0pLmNvbmNhdCh2YWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIG9iajtcbn07XG5cblxuaW50ZXJuYWxzLnBhcnNlT2JqZWN0ID0gZnVuY3Rpb24gKGNoYWluLCB2YWwsIG9wdGlvbnMpIHtcblxuICAgIGlmICghY2hhaW4ubGVuZ3RoKSB7XG4gICAgICAgIHJldHVybiB2YWw7XG4gICAgfVxuXG4gICAgdmFyIHJvb3QgPSBjaGFpbi5zaGlmdCgpO1xuXG4gICAgdmFyIG9iaiA9IHt9O1xuICAgIGlmIChyb290ID09PSAnW10nKSB7XG4gICAgICAgIG9iaiA9IFtdO1xuICAgICAgICBvYmogPSBvYmouY29uY2F0KGludGVybmFscy5wYXJzZU9iamVjdChjaGFpbiwgdmFsLCBvcHRpb25zKSk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB2YXIgY2xlYW5Sb290ID0gcm9vdFswXSA9PT0gJ1snICYmIHJvb3Rbcm9vdC5sZW5ndGggLSAxXSA9PT0gJ10nID8gcm9vdC5zbGljZSgxLCByb290Lmxlbmd0aCAtIDEpIDogcm9vdDtcbiAgICAgICAgdmFyIGluZGV4ID0gcGFyc2VJbnQoY2xlYW5Sb290LCAxMCk7XG4gICAgICAgIGlmICghaXNOYU4oaW5kZXgpICYmXG4gICAgICAgICAgICByb290ICE9PSBjbGVhblJvb3QgJiZcbiAgICAgICAgICAgIGluZGV4IDw9IG9wdGlvbnMuYXJyYXlMaW1pdCkge1xuXG4gICAgICAgICAgICBvYmogPSBbXTtcbiAgICAgICAgICAgIG9ialtpbmRleF0gPSBpbnRlcm5hbHMucGFyc2VPYmplY3QoY2hhaW4sIHZhbCwgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBvYmpbY2xlYW5Sb290XSA9IGludGVybmFscy5wYXJzZU9iamVjdChjaGFpbiwgdmFsLCBvcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBvYmo7XG59O1xuXG5cbmludGVybmFscy5wYXJzZUtleXMgPSBmdW5jdGlvbiAoa2V5LCB2YWwsIG9wdGlvbnMpIHtcblxuICAgIGlmICgha2V5KSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBUaGUgcmVnZXggY2h1bmtzXG5cbiAgICB2YXIgcGFyZW50ID0gL14oW15cXFtcXF1dKikvO1xuICAgIHZhciBjaGlsZCA9IC8oXFxbW15cXFtcXF1dKlxcXSkvZztcblxuICAgIC8vIEdldCB0aGUgcGFyZW50XG5cbiAgICB2YXIgc2VnbWVudCA9IHBhcmVudC5leGVjKGtleSk7XG5cbiAgICAvLyBEb24ndCBhbGxvdyB0aGVtIHRvIG92ZXJ3cml0ZSBvYmplY3QgcHJvdG90eXBlIHByb3BlcnRpZXNcblxuICAgIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5KHNlZ21lbnRbMV0pKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBTdGFzaCB0aGUgcGFyZW50IGlmIGl0IGV4aXN0c1xuXG4gICAgdmFyIGtleXMgPSBbXTtcbiAgICBpZiAoc2VnbWVudFsxXSkge1xuICAgICAgICBrZXlzLnB1c2goc2VnbWVudFsxXSk7XG4gICAgfVxuXG4gICAgLy8gTG9vcCB0aHJvdWdoIGNoaWxkcmVuIGFwcGVuZGluZyB0byB0aGUgYXJyYXkgdW50aWwgd2UgaGl0IGRlcHRoXG5cbiAgICB2YXIgaSA9IDA7XG4gICAgd2hpbGUgKChzZWdtZW50ID0gY2hpbGQuZXhlYyhrZXkpKSAhPT0gbnVsbCAmJiBpIDwgb3B0aW9ucy5kZXB0aCkge1xuXG4gICAgICAgICsraTtcbiAgICAgICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5KHNlZ21lbnRbMV0ucmVwbGFjZSgvXFxbfFxcXS9nLCAnJykpKSB7XG4gICAgICAgICAgICBrZXlzLnB1c2goc2VnbWVudFsxXSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBJZiB0aGVyZSdzIGEgcmVtYWluZGVyLCBqdXN0IGFkZCB3aGF0ZXZlciBpcyBsZWZ0XG5cbiAgICBpZiAoc2VnbWVudCkge1xuICAgICAgICBrZXlzLnB1c2goJ1snICsga2V5LnNsaWNlKHNlZ21lbnQuaW5kZXgpICsgJ10nKTtcbiAgICB9XG5cbiAgICByZXR1cm4gaW50ZXJuYWxzLnBhcnNlT2JqZWN0KGtleXMsIHZhbCwgb3B0aW9ucyk7XG59O1xuXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKHN0ciwgb3B0aW9ucykge1xuXG4gICAgaWYgKHN0ciA9PT0gJycgfHxcbiAgICAgICAgc3RyID09PSBudWxsIHx8XG4gICAgICAgIHR5cGVvZiBzdHIgPT09ICd1bmRlZmluZWQnKSB7XG5cbiAgICAgICAgcmV0dXJuIHt9O1xuICAgIH1cblxuICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgIG9wdGlvbnMuZGVsaW1pdGVyID0gdHlwZW9mIG9wdGlvbnMuZGVsaW1pdGVyID09PSAnc3RyaW5nJyB8fCBVdGlscy5pc1JlZ0V4cChvcHRpb25zLmRlbGltaXRlcikgPyBvcHRpb25zLmRlbGltaXRlciA6IGludGVybmFscy5kZWxpbWl0ZXI7XG4gICAgb3B0aW9ucy5kZXB0aCA9IHR5cGVvZiBvcHRpb25zLmRlcHRoID09PSAnbnVtYmVyJyA/IG9wdGlvbnMuZGVwdGggOiBpbnRlcm5hbHMuZGVwdGg7XG4gICAgb3B0aW9ucy5hcnJheUxpbWl0ID0gdHlwZW9mIG9wdGlvbnMuYXJyYXlMaW1pdCA9PT0gJ251bWJlcicgPyBvcHRpb25zLmFycmF5TGltaXQgOiBpbnRlcm5hbHMuYXJyYXlMaW1pdDtcbiAgICBvcHRpb25zLnBhcmFtZXRlckxpbWl0ID0gdHlwZW9mIG9wdGlvbnMucGFyYW1ldGVyTGltaXQgPT09ICdudW1iZXInID8gb3B0aW9ucy5wYXJhbWV0ZXJMaW1pdCA6IGludGVybmFscy5wYXJhbWV0ZXJMaW1pdDtcblxuICAgIHZhciB0ZW1wT2JqID0gdHlwZW9mIHN0ciA9PT0gJ3N0cmluZycgPyBpbnRlcm5hbHMucGFyc2VWYWx1ZXMoc3RyLCBvcHRpb25zKSA6IHN0cjtcbiAgICB2YXIgb2JqID0ge307XG5cbiAgICAvLyBJdGVyYXRlIG92ZXIgdGhlIGtleXMgYW5kIHNldHVwIHRoZSBuZXcgb2JqZWN0XG5cbiAgICB2YXIga2V5cyA9IE9iamVjdC5rZXlzKHRlbXBPYmopO1xuICAgIGZvciAodmFyIGkgPSAwLCBpbCA9IGtleXMubGVuZ3RoOyBpIDwgaWw7ICsraSkge1xuICAgICAgICB2YXIga2V5ID0ga2V5c1tpXTtcbiAgICAgICAgdmFyIG5ld09iaiA9IGludGVybmFscy5wYXJzZUtleXMoa2V5LCB0ZW1wT2JqW2tleV0sIG9wdGlvbnMpO1xuICAgICAgICBvYmogPSBVdGlscy5tZXJnZShvYmosIG5ld09iaik7XG4gICAgfVxuXG4gICAgcmV0dXJuIFV0aWxzLmNvbXBhY3Qob2JqKTtcbn07XG4iLCIvLyBMb2FkIG1vZHVsZXNcblxudmFyIFV0aWxzID0gcmVxdWlyZSgnLi91dGlscycpO1xuXG5cbi8vIERlY2xhcmUgaW50ZXJuYWxzXG5cbnZhciBpbnRlcm5hbHMgPSB7XG4gICAgZGVsaW1pdGVyOiAnJidcbn07XG5cblxuaW50ZXJuYWxzLnN0cmluZ2lmeSA9IGZ1bmN0aW9uIChvYmosIHByZWZpeCkge1xuXG4gICAgaWYgKFV0aWxzLmlzQnVmZmVyKG9iaikpIHtcbiAgICAgICAgb2JqID0gb2JqLnRvU3RyaW5nKCk7XG4gICAgfVxuICAgIGVsc2UgaWYgKG9iaiBpbnN0YW5jZW9mIERhdGUpIHtcbiAgICAgICAgb2JqID0gb2JqLnRvSVNPU3RyaW5nKCk7XG4gICAgfVxuICAgIGVsc2UgaWYgKG9iaiA9PT0gbnVsbCkge1xuICAgICAgICBvYmogPSAnJztcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIG9iaiA9PT0gJ3N0cmluZycgfHxcbiAgICAgICAgdHlwZW9mIG9iaiA9PT0gJ251bWJlcicgfHxcbiAgICAgICAgdHlwZW9mIG9iaiA9PT0gJ2Jvb2xlYW4nKSB7XG5cbiAgICAgICAgcmV0dXJuIFtlbmNvZGVVUklDb21wb25lbnQocHJlZml4KSArICc9JyArIGVuY29kZVVSSUNvbXBvbmVudChvYmopXTtcbiAgICB9XG5cbiAgICB2YXIgdmFsdWVzID0gW107XG5cbiAgICBmb3IgKHZhciBrZXkgaW4gb2JqKSB7XG4gICAgICAgIGlmIChvYmouaGFzT3duUHJvcGVydHkoa2V5KSkge1xuICAgICAgICAgICAgdmFsdWVzID0gdmFsdWVzLmNvbmNhdChpbnRlcm5hbHMuc3RyaW5naWZ5KG9ialtrZXldLCBwcmVmaXggKyAnWycgKyBrZXkgKyAnXScpKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB2YWx1ZXM7XG59O1xuXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKG9iaiwgb3B0aW9ucykge1xuXG4gICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgdmFyIGRlbGltaXRlciA9IHR5cGVvZiBvcHRpb25zLmRlbGltaXRlciA9PT0gJ3VuZGVmaW5lZCcgPyBpbnRlcm5hbHMuZGVsaW1pdGVyIDogb3B0aW9ucy5kZWxpbWl0ZXI7XG5cbiAgICB2YXIga2V5cyA9IFtdO1xuXG4gICAgZm9yICh2YXIga2V5IGluIG9iaikge1xuICAgICAgICBpZiAob2JqLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgICAgIGtleXMgPSBrZXlzLmNvbmNhdChpbnRlcm5hbHMuc3RyaW5naWZ5KG9ialtrZXldLCBrZXkpKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBrZXlzLmpvaW4oZGVsaW1pdGVyKTtcbn07XG4iLCIoZnVuY3Rpb24gKEJ1ZmZlcil7XG4vLyBMb2FkIG1vZHVsZXNcblxuXG4vLyBEZWNsYXJlIGludGVybmFsc1xuXG52YXIgaW50ZXJuYWxzID0ge307XG5cblxuZXhwb3J0cy5hcnJheVRvT2JqZWN0ID0gZnVuY3Rpb24gKHNvdXJjZSkge1xuXG4gICAgdmFyIG9iaiA9IHt9O1xuICAgIGZvciAodmFyIGkgPSAwLCBpbCA9IHNvdXJjZS5sZW5ndGg7IGkgPCBpbDsgKytpKSB7XG4gICAgICAgIGlmICh0eXBlb2Ygc291cmNlW2ldICE9PSAndW5kZWZpbmVkJykge1xuXG4gICAgICAgICAgICBvYmpbaV0gPSBzb3VyY2VbaV07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gb2JqO1xufTtcblxuXG5leHBvcnRzLm1lcmdlID0gZnVuY3Rpb24gKHRhcmdldCwgc291cmNlKSB7XG5cbiAgICBpZiAoIXNvdXJjZSkge1xuICAgICAgICByZXR1cm4gdGFyZ2V0O1xuICAgIH1cblxuICAgIGlmIChBcnJheS5pc0FycmF5KHNvdXJjZSkpIHtcbiAgICAgICAgZm9yICh2YXIgaSA9IDAsIGlsID0gc291cmNlLmxlbmd0aDsgaSA8IGlsOyArK2kpIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygc291cmNlW2ldICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdGFyZ2V0W2ldID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgICAgICB0YXJnZXRbaV0gPSBleHBvcnRzLm1lcmdlKHRhcmdldFtpXSwgc291cmNlW2ldKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRhcmdldFtpXSA9IHNvdXJjZVtpXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGFyZ2V0O1xuICAgIH1cblxuICAgIGlmIChBcnJheS5pc0FycmF5KHRhcmdldCkpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBzb3VyY2UgIT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICB0YXJnZXQucHVzaChzb3VyY2UpO1xuICAgICAgICAgICAgcmV0dXJuIHRhcmdldDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRhcmdldCA9IGV4cG9ydHMuYXJyYXlUb09iamVjdCh0YXJnZXQpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgdmFyIGtleXMgPSBPYmplY3Qua2V5cyhzb3VyY2UpO1xuICAgIGZvciAodmFyIGsgPSAwLCBrbCA9IGtleXMubGVuZ3RoOyBrIDwga2w7ICsraykge1xuICAgICAgICB2YXIga2V5ID0ga2V5c1trXTtcbiAgICAgICAgdmFyIHZhbHVlID0gc291cmNlW2tleV07XG5cbiAgICAgICAgaWYgKHZhbHVlICYmXG4gICAgICAgICAgICB0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnKSB7XG5cbiAgICAgICAgICAgIGlmICghdGFyZ2V0W2tleV0pIHtcbiAgICAgICAgICAgICAgICB0YXJnZXRba2V5XSA9IHZhbHVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgdGFyZ2V0W2tleV0gPSBleHBvcnRzLm1lcmdlKHRhcmdldFtrZXldLCB2YWx1ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB0YXJnZXRba2V5XSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRhcmdldDtcbn07XG5cblxuZXhwb3J0cy5kZWNvZGUgPSBmdW5jdGlvbiAoc3RyKSB7XG5cbiAgICB0cnkge1xuICAgICAgICByZXR1cm4gZGVjb2RlVVJJQ29tcG9uZW50KHN0ci5yZXBsYWNlKC9cXCsvZywgJyAnKSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICByZXR1cm4gc3RyO1xuICAgIH1cbn07XG5cblxuZXhwb3J0cy5jb21wYWN0ID0gZnVuY3Rpb24gKG9iaiwgcmVmcykge1xuXG4gICAgaWYgKHR5cGVvZiBvYmogIT09ICdvYmplY3QnIHx8XG4gICAgICAgIG9iaiA9PT0gbnVsbCkge1xuXG4gICAgICAgIHJldHVybiBvYmo7XG4gICAgfVxuXG4gICAgcmVmcyA9IHJlZnMgfHwgW107XG4gICAgdmFyIGxvb2t1cCA9IHJlZnMuaW5kZXhPZihvYmopO1xuICAgIGlmIChsb29rdXAgIT09IC0xKSB7XG4gICAgICAgIHJldHVybiByZWZzW2xvb2t1cF07XG4gICAgfVxuXG4gICAgcmVmcy5wdXNoKG9iaik7XG5cbiAgICBpZiAoQXJyYXkuaXNBcnJheShvYmopKSB7XG4gICAgICAgIHZhciBjb21wYWN0ZWQgPSBbXTtcblxuICAgICAgICBmb3IgKHZhciBpID0gMCwgbCA9IG9iai5sZW5ndGg7IGkgPCBsOyArK2kpIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygb2JqW2ldICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgIGNvbXBhY3RlZC5wdXNoKG9ialtpXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gY29tcGFjdGVkO1xuICAgIH1cblxuICAgIHZhciBrZXlzID0gT2JqZWN0LmtleXMob2JqKTtcbiAgICBmb3IgKHZhciBpID0gMCwgaWwgPSBrZXlzLmxlbmd0aDsgaSA8IGlsOyArK2kpIHtcbiAgICAgICAgdmFyIGtleSA9IGtleXNbaV07XG4gICAgICAgIG9ialtrZXldID0gZXhwb3J0cy5jb21wYWN0KG9ialtrZXldLCByZWZzKTtcbiAgICB9XG5cbiAgICByZXR1cm4gb2JqO1xufTtcblxuXG5leHBvcnRzLmlzUmVnRXhwID0gZnVuY3Rpb24gKG9iaikge1xuICAgIHJldHVybiBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwob2JqKSA9PT0gJ1tvYmplY3QgUmVnRXhwXSc7XG59O1xuXG5cbmV4cG9ydHMuaXNCdWZmZXIgPSBmdW5jdGlvbiAob2JqKSB7XG5cbiAgICBpZiAodHlwZW9mIEJ1ZmZlciAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgcmV0dXJuIEJ1ZmZlci5pc0J1ZmZlcihvYmopO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn07XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKFwiYnVmZmVyXCIpLkJ1ZmZlcikiLCIvKiogQGxpY2Vuc2UgTUlUIExpY2Vuc2UgKGMpIGNvcHlyaWdodCAyMDEwLTIwMTQgb3JpZ2luYWwgYXV0aG9yIG9yIGF1dGhvcnMgKi9cbi8qKiBAYXV0aG9yIEJyaWFuIENhdmFsaWVyICovXG4vKiogQGF1dGhvciBKb2huIEhhbm4gKi9cblxuKGZ1bmN0aW9uKGRlZmluZSkgeyAndXNlIHN0cmljdCc7XG5kZWZpbmUoZnVuY3Rpb24gKHJlcXVpcmUpIHtcblxuXHR2YXIgbWFrZVByb21pc2UgPSByZXF1aXJlKCcuL21ha2VQcm9taXNlJyk7XG5cdHZhciBTY2hlZHVsZXIgPSByZXF1aXJlKCcuL1NjaGVkdWxlcicpO1xuXHR2YXIgYXN5bmMgPSByZXF1aXJlKCcuL2FzeW5jJyk7XG5cblx0cmV0dXJuIG1ha2VQcm9taXNlKHtcblx0XHRzY2hlZHVsZXI6IG5ldyBTY2hlZHVsZXIoYXN5bmMpXG5cdH0pO1xuXG59KTtcbn0pKHR5cGVvZiBkZWZpbmUgPT09ICdmdW5jdGlvbicgJiYgZGVmaW5lLmFtZCA/IGRlZmluZSA6IGZ1bmN0aW9uIChmYWN0b3J5KSB7IG1vZHVsZS5leHBvcnRzID0gZmFjdG9yeShyZXF1aXJlKTsgfSk7XG4iLCIvKiogQGxpY2Vuc2UgTUlUIExpY2Vuc2UgKGMpIGNvcHlyaWdodCAyMDEwLTIwMTQgb3JpZ2luYWwgYXV0aG9yIG9yIGF1dGhvcnMgKi9cbi8qKiBAYXV0aG9yIEJyaWFuIENhdmFsaWVyICovXG4vKiogQGF1dGhvciBKb2huIEhhbm4gKi9cblxuKGZ1bmN0aW9uKGRlZmluZSkgeyAndXNlIHN0cmljdCc7XG5kZWZpbmUoZnVuY3Rpb24oKSB7XG5cdC8qKlxuXHQgKiBDaXJjdWxhciBxdWV1ZVxuXHQgKiBAcGFyYW0ge251bWJlcn0gY2FwYWNpdHlQb3cyIHBvd2VyIG9mIDIgdG8gd2hpY2ggdGhpcyBxdWV1ZSdzIGNhcGFjaXR5XG5cdCAqICB3aWxsIGJlIHNldCBpbml0aWFsbHkuIGVnIHdoZW4gY2FwYWNpdHlQb3cyID09IDMsIHF1ZXVlIGNhcGFjaXR5XG5cdCAqICB3aWxsIGJlIDguXG5cdCAqIEBjb25zdHJ1Y3RvclxuXHQgKi9cblx0ZnVuY3Rpb24gUXVldWUoY2FwYWNpdHlQb3cyKSB7XG5cdFx0dGhpcy5oZWFkID0gdGhpcy50YWlsID0gdGhpcy5sZW5ndGggPSAwO1xuXHRcdHRoaXMuYnVmZmVyID0gbmV3IEFycmF5KDEgPDwgY2FwYWNpdHlQb3cyKTtcblx0fVxuXG5cdFF1ZXVlLnByb3RvdHlwZS5wdXNoID0gZnVuY3Rpb24oeCkge1xuXHRcdGlmKHRoaXMubGVuZ3RoID09PSB0aGlzLmJ1ZmZlci5sZW5ndGgpIHtcblx0XHRcdHRoaXMuX2Vuc3VyZUNhcGFjaXR5KHRoaXMubGVuZ3RoICogMik7XG5cdFx0fVxuXG5cdFx0dGhpcy5idWZmZXJbdGhpcy50YWlsXSA9IHg7XG5cdFx0dGhpcy50YWlsID0gKHRoaXMudGFpbCArIDEpICYgKHRoaXMuYnVmZmVyLmxlbmd0aCAtIDEpO1xuXHRcdCsrdGhpcy5sZW5ndGg7XG5cdFx0cmV0dXJuIHRoaXMubGVuZ3RoO1xuXHR9O1xuXG5cdFF1ZXVlLnByb3RvdHlwZS5zaGlmdCA9IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB4ID0gdGhpcy5idWZmZXJbdGhpcy5oZWFkXTtcblx0XHR0aGlzLmJ1ZmZlclt0aGlzLmhlYWRdID0gdm9pZCAwO1xuXHRcdHRoaXMuaGVhZCA9ICh0aGlzLmhlYWQgKyAxKSAmICh0aGlzLmJ1ZmZlci5sZW5ndGggLSAxKTtcblx0XHQtLXRoaXMubGVuZ3RoO1xuXHRcdHJldHVybiB4O1xuXHR9O1xuXG5cdFF1ZXVlLnByb3RvdHlwZS5fZW5zdXJlQ2FwYWNpdHkgPSBmdW5jdGlvbihjYXBhY2l0eSkge1xuXHRcdHZhciBoZWFkID0gdGhpcy5oZWFkO1xuXHRcdHZhciBidWZmZXIgPSB0aGlzLmJ1ZmZlcjtcblx0XHR2YXIgbmV3QnVmZmVyID0gbmV3IEFycmF5KGNhcGFjaXR5KTtcblx0XHR2YXIgaSA9IDA7XG5cdFx0dmFyIGxlbjtcblxuXHRcdGlmKGhlYWQgPT09IDApIHtcblx0XHRcdGxlbiA9IHRoaXMubGVuZ3RoO1xuXHRcdFx0Zm9yKDsgaTxsZW47ICsraSkge1xuXHRcdFx0XHRuZXdCdWZmZXJbaV0gPSBidWZmZXJbaV07XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdGNhcGFjaXR5ID0gYnVmZmVyLmxlbmd0aDtcblx0XHRcdGxlbiA9IHRoaXMudGFpbDtcblx0XHRcdGZvcig7IGhlYWQ8Y2FwYWNpdHk7ICsraSwgKytoZWFkKSB7XG5cdFx0XHRcdG5ld0J1ZmZlcltpXSA9IGJ1ZmZlcltoZWFkXTtcblx0XHRcdH1cblxuXHRcdFx0Zm9yKGhlYWQ9MDsgaGVhZDxsZW47ICsraSwgKytoZWFkKSB7XG5cdFx0XHRcdG5ld0J1ZmZlcltpXSA9IGJ1ZmZlcltoZWFkXTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHR0aGlzLmJ1ZmZlciA9IG5ld0J1ZmZlcjtcblx0XHR0aGlzLmhlYWQgPSAwO1xuXHRcdHRoaXMudGFpbCA9IHRoaXMubGVuZ3RoO1xuXHR9O1xuXG5cdHJldHVybiBRdWV1ZTtcblxufSk7XG59KHR5cGVvZiBkZWZpbmUgPT09ICdmdW5jdGlvbicgJiYgZGVmaW5lLmFtZCA/IGRlZmluZSA6IGZ1bmN0aW9uKGZhY3RvcnkpIHsgbW9kdWxlLmV4cG9ydHMgPSBmYWN0b3J5KCk7IH0pKTtcbiIsIi8qKiBAbGljZW5zZSBNSVQgTGljZW5zZSAoYykgY29weXJpZ2h0IDIwMTAtMjAxNCBvcmlnaW5hbCBhdXRob3Igb3IgYXV0aG9ycyAqL1xuLyoqIEBhdXRob3IgQnJpYW4gQ2F2YWxpZXIgKi9cbi8qKiBAYXV0aG9yIEpvaG4gSGFubiAqL1xuXG4oZnVuY3Rpb24oZGVmaW5lKSB7ICd1c2Ugc3RyaWN0JztcbmRlZmluZShmdW5jdGlvbihyZXF1aXJlKSB7XG5cblx0dmFyIFF1ZXVlID0gcmVxdWlyZSgnLi9RdWV1ZScpO1xuXG5cdC8vIENyZWRpdCB0byBUd2lzb2wgKGh0dHBzOi8vZ2l0aHViLmNvbS9Ud2lzb2wpIGZvciBzdWdnZXN0aW5nXG5cdC8vIHRoaXMgdHlwZSBvZiBleHRlbnNpYmxlIHF1ZXVlICsgdHJhbXBvbGluZSBhcHByb2FjaCBmb3IgbmV4dC10aWNrIGNvbmZsYXRpb24uXG5cblx0LyoqXG5cdCAqIEFzeW5jIHRhc2sgc2NoZWR1bGVyXG5cdCAqIEBwYXJhbSB7ZnVuY3Rpb259IGFzeW5jIGZ1bmN0aW9uIHRvIHNjaGVkdWxlIGEgc2luZ2xlIGFzeW5jIGZ1bmN0aW9uXG5cdCAqIEBjb25zdHJ1Y3RvclxuXHQgKi9cblx0ZnVuY3Rpb24gU2NoZWR1bGVyKGFzeW5jKSB7XG5cdFx0dGhpcy5fYXN5bmMgPSBhc3luYztcblx0XHR0aGlzLl9xdWV1ZSA9IG5ldyBRdWV1ZSgxNSk7XG5cdFx0dGhpcy5fYWZ0ZXJRdWV1ZSA9IG5ldyBRdWV1ZSg1KTtcblx0XHR0aGlzLl9ydW5uaW5nID0gZmFsc2U7XG5cblx0XHR2YXIgc2VsZiA9IHRoaXM7XG5cdFx0dGhpcy5kcmFpbiA9IGZ1bmN0aW9uKCkge1xuXHRcdFx0c2VsZi5fZHJhaW4oKTtcblx0XHR9O1xuXHR9XG5cblx0LyoqXG5cdCAqIEVucXVldWUgYSB0YXNrXG5cdCAqIEBwYXJhbSB7eyBydW46ZnVuY3Rpb24gfX0gdGFza1xuXHQgKi9cblx0U2NoZWR1bGVyLnByb3RvdHlwZS5lbnF1ZXVlID0gZnVuY3Rpb24odGFzaykge1xuXHRcdHRoaXMuX2FkZCh0aGlzLl9xdWV1ZSwgdGFzayk7XG5cdH07XG5cblx0LyoqXG5cdCAqIEVucXVldWUgYSB0YXNrIHRvIHJ1biBhZnRlciB0aGUgbWFpbiB0YXNrIHF1ZXVlXG5cdCAqIEBwYXJhbSB7eyBydW46ZnVuY3Rpb24gfX0gdGFza1xuXHQgKi9cblx0U2NoZWR1bGVyLnByb3RvdHlwZS5hZnRlclF1ZXVlID0gZnVuY3Rpb24odGFzaykge1xuXHRcdHRoaXMuX2FkZCh0aGlzLl9hZnRlclF1ZXVlLCB0YXNrKTtcblx0fTtcblxuXHQvKipcblx0ICogRHJhaW4gdGhlIGhhbmRsZXIgcXVldWUgZW50aXJlbHksIGFuZCB0aGVuIHRoZSBhZnRlciBxdWV1ZVxuXHQgKi9cblx0U2NoZWR1bGVyLnByb3RvdHlwZS5fZHJhaW4gPSBmdW5jdGlvbigpIHtcblx0XHRydW5RdWV1ZSh0aGlzLl9xdWV1ZSk7XG5cdFx0dGhpcy5fcnVubmluZyA9IGZhbHNlO1xuXHRcdHJ1blF1ZXVlKHRoaXMuX2FmdGVyUXVldWUpO1xuXHR9O1xuXG5cdC8qKlxuXHQgKiBBZGQgYSB0YXNrIHRvIHRoZSBxLCBhbmQgc2NoZWR1bGUgZHJhaW4gaWYgbm90IGFscmVhZHkgc2NoZWR1bGVkXG5cdCAqIEBwYXJhbSB7UXVldWV9IHF1ZXVlXG5cdCAqIEBwYXJhbSB7e3J1bjpmdW5jdGlvbn19IHRhc2tcblx0ICogQHByaXZhdGVcblx0ICovXG5cdFNjaGVkdWxlci5wcm90b3R5cGUuX2FkZCA9IGZ1bmN0aW9uKHF1ZXVlLCB0YXNrKSB7XG5cdFx0cXVldWUucHVzaCh0YXNrKTtcblx0XHRpZighdGhpcy5fcnVubmluZykge1xuXHRcdFx0dGhpcy5fcnVubmluZyA9IHRydWU7XG5cdFx0XHR0aGlzLl9hc3luYyh0aGlzLmRyYWluKTtcblx0XHR9XG5cdH07XG5cblx0LyoqXG5cdCAqIFJ1biBhbGwgdGhlIHRhc2tzIGluIHRoZSBxXG5cdCAqIEBwYXJhbSBxdWV1ZVxuXHQgKi9cblx0ZnVuY3Rpb24gcnVuUXVldWUocXVldWUpIHtcblx0XHR3aGlsZShxdWV1ZS5sZW5ndGggPiAwKSB7XG5cdFx0XHRxdWV1ZS5zaGlmdCgpLnJ1bigpO1xuXHRcdH1cblx0fVxuXG5cdHJldHVybiBTY2hlZHVsZXI7XG5cbn0pO1xufSh0eXBlb2YgZGVmaW5lID09PSAnZnVuY3Rpb24nICYmIGRlZmluZS5hbWQgPyBkZWZpbmUgOiBmdW5jdGlvbihmYWN0b3J5KSB7IG1vZHVsZS5leHBvcnRzID0gZmFjdG9yeShyZXF1aXJlKTsgfSkpO1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKiBAbGljZW5zZSBNSVQgTGljZW5zZSAoYykgY29weXJpZ2h0IDIwMTAtMjAxNCBvcmlnaW5hbCBhdXRob3Igb3IgYXV0aG9ycyAqL1xuLyoqIEBhdXRob3IgQnJpYW4gQ2F2YWxpZXIgKi9cbi8qKiBAYXV0aG9yIEpvaG4gSGFubiAqL1xuXG4oZnVuY3Rpb24oZGVmaW5lKSB7ICd1c2Ugc3RyaWN0JztcbmRlZmluZShmdW5jdGlvbihyZXF1aXJlKSB7XG5cblx0Ly8gU25pZmYgXCJiZXN0XCIgYXN5bmMgc2NoZWR1bGluZyBvcHRpb25cblx0Ly8gUHJlZmVyIHByb2Nlc3MubmV4dFRpY2sgb3IgTXV0YXRpb25PYnNlcnZlciwgdGhlbiBjaGVjayBmb3Jcblx0Ly8gdmVydHggYW5kIGZpbmFsbHkgZmFsbCBiYWNrIHRvIHNldFRpbWVvdXRcblxuXHQvKmpzaGludCBtYXhjb21wbGV4aXR5OjYqL1xuXHQvKmdsb2JhbCBwcm9jZXNzLGRvY3VtZW50LHNldFRpbWVvdXQsTXV0YXRpb25PYnNlcnZlcixXZWJLaXRNdXRhdGlvbk9ic2VydmVyKi9cblx0dmFyIG5leHRUaWNrLCBNdXRhdGlvbk9icztcblxuXHRpZiAodHlwZW9mIHByb2Nlc3MgIT09ICd1bmRlZmluZWQnICYmIHByb2Nlc3MgIT09IG51bGwgJiZcblx0XHR0eXBlb2YgcHJvY2Vzcy5uZXh0VGljayA9PT0gJ2Z1bmN0aW9uJykge1xuXHRcdG5leHRUaWNrID0gZnVuY3Rpb24oZikge1xuXHRcdFx0cHJvY2Vzcy5uZXh0VGljayhmKTtcblx0XHR9O1xuXG5cdH0gZWxzZSBpZiAoTXV0YXRpb25PYnMgPVxuXHRcdCh0eXBlb2YgTXV0YXRpb25PYnNlcnZlciA9PT0gJ2Z1bmN0aW9uJyAmJiBNdXRhdGlvbk9ic2VydmVyKSB8fFxuXHRcdCh0eXBlb2YgV2ViS2l0TXV0YXRpb25PYnNlcnZlciA9PT0gJ2Z1bmN0aW9uJyAmJiBXZWJLaXRNdXRhdGlvbk9ic2VydmVyKSkge1xuXHRcdG5leHRUaWNrID0gKGZ1bmN0aW9uIChkb2N1bWVudCwgTXV0YXRpb25PYnNlcnZlcikge1xuXHRcdFx0dmFyIHNjaGVkdWxlZDtcblx0XHRcdHZhciBlbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuXHRcdFx0dmFyIG8gPSBuZXcgTXV0YXRpb25PYnNlcnZlcihydW4pO1xuXHRcdFx0by5vYnNlcnZlKGVsLCB7IGF0dHJpYnV0ZXM6IHRydWUgfSk7XG5cblx0XHRcdGZ1bmN0aW9uIHJ1bigpIHtcblx0XHRcdFx0dmFyIGYgPSBzY2hlZHVsZWQ7XG5cdFx0XHRcdHNjaGVkdWxlZCA9IHZvaWQgMDtcblx0XHRcdFx0ZigpO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gZnVuY3Rpb24gKGYpIHtcblx0XHRcdFx0c2NoZWR1bGVkID0gZjtcblx0XHRcdFx0ZWwuc2V0QXR0cmlidXRlKCdjbGFzcycsICd4Jyk7XG5cdFx0XHR9O1xuXHRcdH0oZG9jdW1lbnQsIE11dGF0aW9uT2JzKSk7XG5cblx0fSBlbHNlIHtcblx0XHRuZXh0VGljayA9IChmdW5jdGlvbihjanNSZXF1aXJlKSB7XG5cdFx0XHR2YXIgdmVydHg7XG5cdFx0XHR0cnkge1xuXHRcdFx0XHQvLyB2ZXJ0LnggMS54IHx8IDIueFxuXHRcdFx0XHR2ZXJ0eCA9IGNqc1JlcXVpcmUoJ3ZlcnR4Jyk7XG5cdFx0XHR9IGNhdGNoIChpZ25vcmUpIHt9XG5cblx0XHRcdGlmICh2ZXJ0eCkge1xuXHRcdFx0XHRpZiAodHlwZW9mIHZlcnR4LnJ1bk9uTG9vcCA9PT0gJ2Z1bmN0aW9uJykge1xuXHRcdFx0XHRcdHJldHVybiB2ZXJ0eC5ydW5Pbkxvb3A7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKHR5cGVvZiB2ZXJ0eC5ydW5PbkNvbnRleHQgPT09ICdmdW5jdGlvbicpIHtcblx0XHRcdFx0XHRyZXR1cm4gdmVydHgucnVuT25Db250ZXh0O1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdC8vIGNhcHR1cmUgc2V0VGltZW91dCB0byBhdm9pZCBiZWluZyBjYXVnaHQgYnkgZmFrZSB0aW1lcnNcblx0XHRcdC8vIHVzZWQgaW4gdGltZSBiYXNlZCB0ZXN0c1xuXHRcdFx0dmFyIGNhcHR1cmVkU2V0VGltZW91dCA9IHNldFRpbWVvdXQ7XG5cdFx0XHRyZXR1cm4gZnVuY3Rpb24gKHQpIHtcblx0XHRcdFx0Y2FwdHVyZWRTZXRUaW1lb3V0KHQsIDApO1xuXHRcdFx0fTtcblx0XHR9KHJlcXVpcmUpKTtcblx0fVxuXG5cdHJldHVybiBuZXh0VGljaztcbn0pO1xufSh0eXBlb2YgZGVmaW5lID09PSAnZnVuY3Rpb24nICYmIGRlZmluZS5hbWQgPyBkZWZpbmUgOiBmdW5jdGlvbihmYWN0b3J5KSB7IG1vZHVsZS5leHBvcnRzID0gZmFjdG9yeShyZXF1aXJlKTsgfSkpO1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIvKiogQGxpY2Vuc2UgTUlUIExpY2Vuc2UgKGMpIGNvcHlyaWdodCAyMDEwLTIwMTQgb3JpZ2luYWwgYXV0aG9yIG9yIGF1dGhvcnMgKi9cbi8qKiBAYXV0aG9yIEJyaWFuIENhdmFsaWVyICovXG4vKiogQGF1dGhvciBKb2huIEhhbm4gKi9cblxuKGZ1bmN0aW9uKGRlZmluZSkgeyAndXNlIHN0cmljdCc7XG5kZWZpbmUoZnVuY3Rpb24oKSB7XG5cblx0cmV0dXJuIGZ1bmN0aW9uIG1ha2VQcm9taXNlKGVudmlyb25tZW50KSB7XG5cblx0XHR2YXIgdGFza3MgPSBlbnZpcm9ubWVudC5zY2hlZHVsZXI7XG5cblx0XHR2YXIgb2JqZWN0Q3JlYXRlID0gT2JqZWN0LmNyZWF0ZSB8fFxuXHRcdFx0ZnVuY3Rpb24ocHJvdG8pIHtcblx0XHRcdFx0ZnVuY3Rpb24gQ2hpbGQoKSB7fVxuXHRcdFx0XHRDaGlsZC5wcm90b3R5cGUgPSBwcm90bztcblx0XHRcdFx0cmV0dXJuIG5ldyBDaGlsZCgpO1xuXHRcdFx0fTtcblxuXHRcdC8qKlxuXHRcdCAqIENyZWF0ZSBhIHByb21pc2Ugd2hvc2UgZmF0ZSBpcyBkZXRlcm1pbmVkIGJ5IHJlc29sdmVyXG5cdFx0ICogQGNvbnN0cnVjdG9yXG5cdFx0ICogQHJldHVybnMge1Byb21pc2V9IHByb21pc2Vcblx0XHQgKiBAbmFtZSBQcm9taXNlXG5cdFx0ICovXG5cdFx0ZnVuY3Rpb24gUHJvbWlzZShyZXNvbHZlciwgaGFuZGxlcikge1xuXHRcdFx0dGhpcy5faGFuZGxlciA9IHJlc29sdmVyID09PSBIYW5kbGVyID8gaGFuZGxlciA6IGluaXQocmVzb2x2ZXIpO1xuXHRcdH1cblxuXHRcdC8qKlxuXHRcdCAqIFJ1biB0aGUgc3VwcGxpZWQgcmVzb2x2ZXJcblx0XHQgKiBAcGFyYW0gcmVzb2x2ZXJcblx0XHQgKiBAcmV0dXJucyB7UGVuZGluZ31cblx0XHQgKi9cblx0XHRmdW5jdGlvbiBpbml0KHJlc29sdmVyKSB7XG5cdFx0XHR2YXIgaGFuZGxlciA9IG5ldyBQZW5kaW5nKCk7XG5cblx0XHRcdHRyeSB7XG5cdFx0XHRcdHJlc29sdmVyKHByb21pc2VSZXNvbHZlLCBwcm9taXNlUmVqZWN0LCBwcm9taXNlTm90aWZ5KTtcblx0XHRcdH0gY2F0Y2ggKGUpIHtcblx0XHRcdFx0cHJvbWlzZVJlamVjdChlKTtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGhhbmRsZXI7XG5cblx0XHRcdC8qKlxuXHRcdFx0ICogVHJhbnNpdGlvbiBmcm9tIHByZS1yZXNvbHV0aW9uIHN0YXRlIHRvIHBvc3QtcmVzb2x1dGlvbiBzdGF0ZSwgbm90aWZ5aW5nXG5cdFx0XHQgKiBhbGwgbGlzdGVuZXJzIG9mIHRoZSB1bHRpbWF0ZSBmdWxmaWxsbWVudCBvciByZWplY3Rpb25cblx0XHRcdCAqIEBwYXJhbSB7Kn0geCByZXNvbHV0aW9uIHZhbHVlXG5cdFx0XHQgKi9cblx0XHRcdGZ1bmN0aW9uIHByb21pc2VSZXNvbHZlICh4KSB7XG5cdFx0XHRcdGhhbmRsZXIucmVzb2x2ZSh4KTtcblx0XHRcdH1cblx0XHRcdC8qKlxuXHRcdFx0ICogUmVqZWN0IHRoaXMgcHJvbWlzZSB3aXRoIHJlYXNvbiwgd2hpY2ggd2lsbCBiZSB1c2VkIHZlcmJhdGltXG5cdFx0XHQgKiBAcGFyYW0ge0Vycm9yfCp9IHJlYXNvbiByZWplY3Rpb24gcmVhc29uLCBzdHJvbmdseSBzdWdnZXN0ZWRcblx0XHRcdCAqICAgdG8gYmUgYW4gRXJyb3IgdHlwZVxuXHRcdFx0ICovXG5cdFx0XHRmdW5jdGlvbiBwcm9taXNlUmVqZWN0IChyZWFzb24pIHtcblx0XHRcdFx0aGFuZGxlci5yZWplY3QocmVhc29uKTtcblx0XHRcdH1cblxuXHRcdFx0LyoqXG5cdFx0XHQgKiBJc3N1ZSBhIHByb2dyZXNzIGV2ZW50LCBub3RpZnlpbmcgYWxsIHByb2dyZXNzIGxpc3RlbmVyc1xuXHRcdFx0ICogQHBhcmFtIHsqfSB4IHByb2dyZXNzIGV2ZW50IHBheWxvYWQgdG8gcGFzcyB0byBhbGwgbGlzdGVuZXJzXG5cdFx0XHQgKi9cblx0XHRcdGZ1bmN0aW9uIHByb21pc2VOb3RpZnkgKHgpIHtcblx0XHRcdFx0aGFuZGxlci5ub3RpZnkoeCk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gQ3JlYXRpb25cblxuXHRcdFByb21pc2UucmVzb2x2ZSA9IHJlc29sdmU7XG5cdFx0UHJvbWlzZS5yZWplY3QgPSByZWplY3Q7XG5cdFx0UHJvbWlzZS5uZXZlciA9IG5ldmVyO1xuXG5cdFx0UHJvbWlzZS5fZGVmZXIgPSBkZWZlcjtcblx0XHRQcm9taXNlLl9oYW5kbGVyID0gZ2V0SGFuZGxlcjtcblxuXHRcdC8qKlxuXHRcdCAqIFJldHVybnMgYSB0cnVzdGVkIHByb21pc2UuIElmIHggaXMgYWxyZWFkeSBhIHRydXN0ZWQgcHJvbWlzZSwgaXQgaXNcblx0XHQgKiByZXR1cm5lZCwgb3RoZXJ3aXNlIHJldHVybnMgYSBuZXcgdHJ1c3RlZCBQcm9taXNlIHdoaWNoIGZvbGxvd3MgeC5cblx0XHQgKiBAcGFyYW0gIHsqfSB4XG5cdFx0ICogQHJldHVybiB7UHJvbWlzZX0gcHJvbWlzZVxuXHRcdCAqL1xuXHRcdGZ1bmN0aW9uIHJlc29sdmUoeCkge1xuXHRcdFx0cmV0dXJuIGlzUHJvbWlzZSh4KSA/IHhcblx0XHRcdFx0OiBuZXcgUHJvbWlzZShIYW5kbGVyLCBuZXcgQXN5bmMoZ2V0SGFuZGxlcih4KSkpO1xuXHRcdH1cblxuXHRcdC8qKlxuXHRcdCAqIFJldHVybiBhIHJlamVjdCBwcm9taXNlIHdpdGggeCBhcyBpdHMgcmVhc29uICh4IGlzIHVzZWQgdmVyYmF0aW0pXG5cdFx0ICogQHBhcmFtIHsqfSB4XG5cdFx0ICogQHJldHVybnMge1Byb21pc2V9IHJlamVjdGVkIHByb21pc2Vcblx0XHQgKi9cblx0XHRmdW5jdGlvbiByZWplY3QoeCkge1xuXHRcdFx0cmV0dXJuIG5ldyBQcm9taXNlKEhhbmRsZXIsIG5ldyBBc3luYyhuZXcgUmVqZWN0ZWQoeCkpKTtcblx0XHR9XG5cblx0XHQvKipcblx0XHQgKiBSZXR1cm4gYSBwcm9taXNlIHRoYXQgcmVtYWlucyBwZW5kaW5nIGZvcmV2ZXJcblx0XHQgKiBAcmV0dXJucyB7UHJvbWlzZX0gZm9yZXZlci1wZW5kaW5nIHByb21pc2UuXG5cdFx0ICovXG5cdFx0ZnVuY3Rpb24gbmV2ZXIoKSB7XG5cdFx0XHRyZXR1cm4gZm9yZXZlclBlbmRpbmdQcm9taXNlOyAvLyBTaG91bGQgYmUgZnJvemVuXG5cdFx0fVxuXG5cdFx0LyoqXG5cdFx0ICogQ3JlYXRlcyBhbiBpbnRlcm5hbCB7cHJvbWlzZSwgcmVzb2x2ZXJ9IHBhaXJcblx0XHQgKiBAcHJpdmF0ZVxuXHRcdCAqIEByZXR1cm5zIHtQcm9taXNlfVxuXHRcdCAqL1xuXHRcdGZ1bmN0aW9uIGRlZmVyKCkge1xuXHRcdFx0cmV0dXJuIG5ldyBQcm9taXNlKEhhbmRsZXIsIG5ldyBQZW5kaW5nKCkpO1xuXHRcdH1cblxuXHRcdC8vIFRyYW5zZm9ybWF0aW9uIGFuZCBmbG93IGNvbnRyb2xcblxuXHRcdC8qKlxuXHRcdCAqIFRyYW5zZm9ybSB0aGlzIHByb21pc2UncyBmdWxmaWxsbWVudCB2YWx1ZSwgcmV0dXJuaW5nIGEgbmV3IFByb21pc2Vcblx0XHQgKiBmb3IgdGhlIHRyYW5zZm9ybWVkIHJlc3VsdC4gIElmIHRoZSBwcm9taXNlIGNhbm5vdCBiZSBmdWxmaWxsZWQsIG9uUmVqZWN0ZWRcblx0XHQgKiBpcyBjYWxsZWQgd2l0aCB0aGUgcmVhc29uLiAgb25Qcm9ncmVzcyAqbWF5KiBiZSBjYWxsZWQgd2l0aCB1cGRhdGVzIHRvd2FyZFxuXHRcdCAqIHRoaXMgcHJvbWlzZSdzIGZ1bGZpbGxtZW50LlxuXHRcdCAqIEBwYXJhbSB7ZnVuY3Rpb249fSBvbkZ1bGZpbGxlZCBmdWxmaWxsbWVudCBoYW5kbGVyXG5cdFx0ICogQHBhcmFtIHtmdW5jdGlvbj19IG9uUmVqZWN0ZWQgcmVqZWN0aW9uIGhhbmRsZXJcblx0XHQgKiBAZGVwcmVjYXRlZCBAcGFyYW0ge2Z1bmN0aW9uPX0gb25Qcm9ncmVzcyBwcm9ncmVzcyBoYW5kbGVyXG5cdFx0ICogQHJldHVybiB7UHJvbWlzZX0gbmV3IHByb21pc2Vcblx0XHQgKi9cblx0XHRQcm9taXNlLnByb3RvdHlwZS50aGVuID0gZnVuY3Rpb24ob25GdWxmaWxsZWQsIG9uUmVqZWN0ZWQpIHtcblx0XHRcdHZhciBwYXJlbnQgPSB0aGlzLl9oYW5kbGVyO1xuXHRcdFx0dmFyIHN0YXRlID0gcGFyZW50LmpvaW4oKS5zdGF0ZSgpO1xuXG5cdFx0XHRpZiAoKHR5cGVvZiBvbkZ1bGZpbGxlZCAhPT0gJ2Z1bmN0aW9uJyAmJiBzdGF0ZSA+IDApIHx8XG5cdFx0XHRcdCh0eXBlb2Ygb25SZWplY3RlZCAhPT0gJ2Z1bmN0aW9uJyAmJiBzdGF0ZSA8IDApKSB7XG5cdFx0XHRcdC8vIFNob3J0IGNpcmN1aXQ6IHZhbHVlIHdpbGwgbm90IGNoYW5nZSwgc2ltcGx5IHNoYXJlIGhhbmRsZXJcblx0XHRcdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKEhhbmRsZXIsIHBhcmVudCk7XG5cdFx0XHR9XG5cblx0XHRcdHZhciBwID0gdGhpcy5fYmVnZXQoKTtcblx0XHRcdHZhciBjaGlsZCA9IHAuX2hhbmRsZXI7XG5cblx0XHRcdHBhcmVudC5jaGFpbihjaGlsZCwgcGFyZW50LnJlY2VpdmVyLCBvbkZ1bGZpbGxlZCwgb25SZWplY3RlZCxcblx0XHRcdFx0XHRhcmd1bWVudHMubGVuZ3RoID4gMiA/IGFyZ3VtZW50c1syXSA6IHZvaWQgMCk7XG5cblx0XHRcdHJldHVybiBwO1xuXHRcdH07XG5cblx0XHQvKipcblx0XHQgKiBJZiB0aGlzIHByb21pc2UgY2Fubm90IGJlIGZ1bGZpbGxlZCBkdWUgdG8gYW4gZXJyb3IsIGNhbGwgb25SZWplY3RlZCB0b1xuXHRcdCAqIGhhbmRsZSB0aGUgZXJyb3IuIFNob3J0Y3V0IGZvciAudGhlbih1bmRlZmluZWQsIG9uUmVqZWN0ZWQpXG5cdFx0ICogQHBhcmFtIHtmdW5jdGlvbj99IG9uUmVqZWN0ZWRcblx0XHQgKiBAcmV0dXJuIHtQcm9taXNlfVxuXHRcdCAqL1xuXHRcdFByb21pc2UucHJvdG90eXBlWydjYXRjaCddID0gZnVuY3Rpb24ob25SZWplY3RlZCkge1xuXHRcdFx0cmV0dXJuIHRoaXMudGhlbih2b2lkIDAsIG9uUmVqZWN0ZWQpO1xuXHRcdH07XG5cblx0XHQvKipcblx0XHQgKiBDcmVhdGVzIGEgbmV3LCBwZW5kaW5nIHByb21pc2Ugb2YgdGhlIHNhbWUgdHlwZSBhcyB0aGlzIHByb21pc2Vcblx0XHQgKiBAcHJpdmF0ZVxuXHRcdCAqIEByZXR1cm5zIHtQcm9taXNlfVxuXHRcdCAqL1xuXHRcdFByb21pc2UucHJvdG90eXBlLl9iZWdldCA9IGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIHBhcmVudCA9IHRoaXMuX2hhbmRsZXI7XG5cdFx0XHR2YXIgY2hpbGQgPSBuZXcgUGVuZGluZyhwYXJlbnQucmVjZWl2ZXIsIHBhcmVudC5qb2luKCkuY29udGV4dCk7XG5cdFx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoSGFuZGxlciwgY2hpbGQpO1xuXHRcdH07XG5cblx0XHQvLyBBcnJheSBjb21iaW5hdG9yc1xuXG5cdFx0UHJvbWlzZS5hbGwgPSBhbGw7XG5cdFx0UHJvbWlzZS5yYWNlID0gcmFjZTtcblxuXHRcdC8qKlxuXHRcdCAqIFJldHVybiBhIHByb21pc2UgdGhhdCB3aWxsIGZ1bGZpbGwgd2hlbiBhbGwgcHJvbWlzZXMgaW4gdGhlXG5cdFx0ICogaW5wdXQgYXJyYXkgaGF2ZSBmdWxmaWxsZWQsIG9yIHdpbGwgcmVqZWN0IHdoZW4gb25lIG9mIHRoZVxuXHRcdCAqIHByb21pc2VzIHJlamVjdHMuXG5cdFx0ICogQHBhcmFtIHthcnJheX0gcHJvbWlzZXMgYXJyYXkgb2YgcHJvbWlzZXNcblx0XHQgKiBAcmV0dXJucyB7UHJvbWlzZX0gcHJvbWlzZSBmb3IgYXJyYXkgb2YgZnVsZmlsbG1lbnQgdmFsdWVzXG5cdFx0ICovXG5cdFx0ZnVuY3Rpb24gYWxsKHByb21pc2VzKSB7XG5cdFx0XHQvKmpzaGludCBtYXhjb21wbGV4aXR5OjgqL1xuXHRcdFx0dmFyIHJlc29sdmVyID0gbmV3IFBlbmRpbmcoKTtcblx0XHRcdHZhciBwZW5kaW5nID0gcHJvbWlzZXMubGVuZ3RoID4+PiAwO1xuXHRcdFx0dmFyIHJlc3VsdHMgPSBuZXcgQXJyYXkocGVuZGluZyk7XG5cblx0XHRcdHZhciBpLCBoLCB4LCBzO1xuXHRcdFx0Zm9yIChpID0gMDsgaSA8IHByb21pc2VzLmxlbmd0aDsgKytpKSB7XG5cdFx0XHRcdHggPSBwcm9taXNlc1tpXTtcblxuXHRcdFx0XHRpZiAoeCA9PT0gdm9pZCAwICYmICEoaSBpbiBwcm9taXNlcykpIHtcblx0XHRcdFx0XHQtLXBlbmRpbmc7XG5cdFx0XHRcdFx0Y29udGludWU7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAobWF5YmVUaGVuYWJsZSh4KSkge1xuXHRcdFx0XHRcdGggPSBnZXRIYW5kbGVyTWF5YmVUaGVuYWJsZSh4KTtcblxuXHRcdFx0XHRcdHMgPSBoLnN0YXRlKCk7XG5cdFx0XHRcdFx0aWYgKHMgPT09IDApIHtcblx0XHRcdFx0XHRcdGguZm9sZChzZXR0bGVBdCwgaSwgcmVzdWx0cywgcmVzb2x2ZXIpO1xuXHRcdFx0XHRcdH0gZWxzZSBpZiAocyA+IDApIHtcblx0XHRcdFx0XHRcdHJlc3VsdHNbaV0gPSBoLnZhbHVlO1xuXHRcdFx0XHRcdFx0LS1wZW5kaW5nO1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHR1bnJlcG9ydFJlbWFpbmluZyhwcm9taXNlcywgaSsxLCBoKTtcblx0XHRcdFx0XHRcdHJlc29sdmVyLmJlY29tZShoKTtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHJlc3VsdHNbaV0gPSB4O1xuXHRcdFx0XHRcdC0tcGVuZGluZztcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHRpZihwZW5kaW5nID09PSAwKSB7XG5cdFx0XHRcdHJlc29sdmVyLmJlY29tZShuZXcgRnVsZmlsbGVkKHJlc3VsdHMpKTtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIG5ldyBQcm9taXNlKEhhbmRsZXIsIHJlc29sdmVyKTtcblxuXHRcdFx0ZnVuY3Rpb24gc2V0dGxlQXQoaSwgeCwgcmVzb2x2ZXIpIHtcblx0XHRcdFx0Lypqc2hpbnQgdmFsaWR0aGlzOnRydWUqL1xuXHRcdFx0XHR0aGlzW2ldID0geDtcblx0XHRcdFx0aWYoLS1wZW5kaW5nID09PSAwKSB7XG5cdFx0XHRcdFx0cmVzb2x2ZXIuYmVjb21lKG5ldyBGdWxmaWxsZWQodGhpcykpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gdW5yZXBvcnRSZW1haW5pbmcocHJvbWlzZXMsIHN0YXJ0LCByZWplY3RlZEhhbmRsZXIpIHtcblx0XHRcdHZhciBpLCBoLCB4O1xuXHRcdFx0Zm9yKGk9c3RhcnQ7IGk8cHJvbWlzZXMubGVuZ3RoOyArK2kpIHtcblx0XHRcdFx0eCA9IHByb21pc2VzW2ldO1xuXHRcdFx0XHRpZihtYXliZVRoZW5hYmxlKHgpKSB7XG5cdFx0XHRcdFx0aCA9IGdldEhhbmRsZXJNYXliZVRoZW5hYmxlKHgpO1xuXG5cdFx0XHRcdFx0aWYoaCAhPT0gcmVqZWN0ZWRIYW5kbGVyKSB7XG5cdFx0XHRcdFx0XHRoLnZpc2l0KGgsIHZvaWQgMCwgaC5fdW5yZXBvcnQpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8qKlxuXHRcdCAqIEZ1bGZpbGwtcmVqZWN0IGNvbXBldGl0aXZlIHJhY2UuIFJldHVybiBhIHByb21pc2UgdGhhdCB3aWxsIHNldHRsZVxuXHRcdCAqIHRvIHRoZSBzYW1lIHN0YXRlIGFzIHRoZSBlYXJsaWVzdCBpbnB1dCBwcm9taXNlIHRvIHNldHRsZS5cblx0XHQgKlxuXHRcdCAqIFdBUk5JTkc6IFRoZSBFUzYgUHJvbWlzZSBzcGVjIHJlcXVpcmVzIHRoYXQgcmFjZSgpaW5nIGFuIGVtcHR5IGFycmF5XG5cdFx0ICogbXVzdCByZXR1cm4gYSBwcm9taXNlIHRoYXQgaXMgcGVuZGluZyBmb3JldmVyLiAgVGhpcyBpbXBsZW1lbnRhdGlvblxuXHRcdCAqIHJldHVybnMgYSBzaW5nbGV0b24gZm9yZXZlci1wZW5kaW5nIHByb21pc2UsIHRoZSBzYW1lIHNpbmdsZXRvbiB0aGF0IGlzXG5cdFx0ICogcmV0dXJuZWQgYnkgUHJvbWlzZS5uZXZlcigpLCB0aHVzIGNhbiBiZSBjaGVja2VkIHdpdGggPT09XG5cdFx0ICpcblx0XHQgKiBAcGFyYW0ge2FycmF5fSBwcm9taXNlcyBhcnJheSBvZiBwcm9taXNlcyB0byByYWNlXG5cdFx0ICogQHJldHVybnMge1Byb21pc2V9IGlmIGlucHV0IGlzIG5vbi1lbXB0eSwgYSBwcm9taXNlIHRoYXQgd2lsbCBzZXR0bGVcblx0XHQgKiB0byB0aGUgc2FtZSBvdXRjb21lIGFzIHRoZSBlYXJsaWVzdCBpbnB1dCBwcm9taXNlIHRvIHNldHRsZS4gaWYgZW1wdHlcblx0XHQgKiBpcyBlbXB0eSwgcmV0dXJucyBhIHByb21pc2UgdGhhdCB3aWxsIG5ldmVyIHNldHRsZS5cblx0XHQgKi9cblx0XHRmdW5jdGlvbiByYWNlKHByb21pc2VzKSB7XG5cdFx0XHQvLyBTaWdoLCByYWNlKFtdKSBpcyB1bnRlc3RhYmxlIHVubGVzcyB3ZSByZXR1cm4gKnNvbWV0aGluZypcblx0XHRcdC8vIHRoYXQgaXMgcmVjb2duaXphYmxlIHdpdGhvdXQgY2FsbGluZyAudGhlbigpIG9uIGl0LlxuXHRcdFx0aWYoT2JqZWN0KHByb21pc2VzKSA9PT0gcHJvbWlzZXMgJiYgcHJvbWlzZXMubGVuZ3RoID09PSAwKSB7XG5cdFx0XHRcdHJldHVybiBuZXZlcigpO1xuXHRcdFx0fVxuXG5cdFx0XHR2YXIgaCA9IG5ldyBQZW5kaW5nKCk7XG5cdFx0XHR2YXIgaSwgeDtcblx0XHRcdGZvcihpPTA7IGk8cHJvbWlzZXMubGVuZ3RoOyArK2kpIHtcblx0XHRcdFx0eCA9IHByb21pc2VzW2ldO1xuXHRcdFx0XHRpZiAoeCAhPT0gdm9pZCAwICYmIGkgaW4gcHJvbWlzZXMpIHtcblx0XHRcdFx0XHRnZXRIYW5kbGVyKHgpLnZpc2l0KGgsIGgucmVzb2x2ZSwgaC5yZWplY3QpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gbmV3IFByb21pc2UoSGFuZGxlciwgaCk7XG5cdFx0fVxuXG5cdFx0Ly8gUHJvbWlzZSBpbnRlcm5hbHNcblx0XHQvLyBCZWxvdyB0aGlzLCBldmVyeXRoaW5nIGlzIEBwcml2YXRlXG5cblx0XHQvKipcblx0XHQgKiBHZXQgYW4gYXBwcm9wcmlhdGUgaGFuZGxlciBmb3IgeCwgd2l0aG91dCBjaGVja2luZyBmb3IgY3ljbGVzXG5cdFx0ICogQHBhcmFtIHsqfSB4XG5cdFx0ICogQHJldHVybnMge29iamVjdH0gaGFuZGxlclxuXHRcdCAqL1xuXHRcdGZ1bmN0aW9uIGdldEhhbmRsZXIoeCkge1xuXHRcdFx0aWYoaXNQcm9taXNlKHgpKSB7XG5cdFx0XHRcdHJldHVybiB4Ll9oYW5kbGVyLmpvaW4oKTtcblx0XHRcdH1cblx0XHRcdHJldHVybiBtYXliZVRoZW5hYmxlKHgpID8gZ2V0SGFuZGxlclVudHJ1c3RlZCh4KSA6IG5ldyBGdWxmaWxsZWQoeCk7XG5cdFx0fVxuXG5cdFx0LyoqXG5cdFx0ICogR2V0IGEgaGFuZGxlciBmb3IgdGhlbmFibGUgeC5cblx0XHQgKiBOT1RFOiBZb3UgbXVzdCBvbmx5IGNhbGwgdGhpcyBpZiBtYXliZVRoZW5hYmxlKHgpID09IHRydWVcblx0XHQgKiBAcGFyYW0ge29iamVjdHxmdW5jdGlvbnxQcm9taXNlfSB4XG5cdFx0ICogQHJldHVybnMge29iamVjdH0gaGFuZGxlclxuXHRcdCAqL1xuXHRcdGZ1bmN0aW9uIGdldEhhbmRsZXJNYXliZVRoZW5hYmxlKHgpIHtcblx0XHRcdHJldHVybiBpc1Byb21pc2UoeCkgPyB4Ll9oYW5kbGVyLmpvaW4oKSA6IGdldEhhbmRsZXJVbnRydXN0ZWQoeCk7XG5cdFx0fVxuXG5cdFx0LyoqXG5cdFx0ICogR2V0IGEgaGFuZGxlciBmb3IgcG90ZW50aWFsbHkgdW50cnVzdGVkIHRoZW5hYmxlIHhcblx0XHQgKiBAcGFyYW0geyp9IHhcblx0XHQgKiBAcmV0dXJucyB7b2JqZWN0fSBoYW5kbGVyXG5cdFx0ICovXG5cdFx0ZnVuY3Rpb24gZ2V0SGFuZGxlclVudHJ1c3RlZCh4KSB7XG5cdFx0XHR0cnkge1xuXHRcdFx0XHR2YXIgdW50cnVzdGVkVGhlbiA9IHgudGhlbjtcblx0XHRcdFx0cmV0dXJuIHR5cGVvZiB1bnRydXN0ZWRUaGVuID09PSAnZnVuY3Rpb24nXG5cdFx0XHRcdFx0PyBuZXcgVGhlbmFibGUodW50cnVzdGVkVGhlbiwgeClcblx0XHRcdFx0XHQ6IG5ldyBGdWxmaWxsZWQoeCk7XG5cdFx0XHR9IGNhdGNoKGUpIHtcblx0XHRcdFx0cmV0dXJuIG5ldyBSZWplY3RlZChlKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvKipcblx0XHQgKiBIYW5kbGVyIGZvciBhIHByb21pc2UgdGhhdCBpcyBwZW5kaW5nIGZvcmV2ZXJcblx0XHQgKiBAY29uc3RydWN0b3Jcblx0XHQgKi9cblx0XHRmdW5jdGlvbiBIYW5kbGVyKCkge31cblxuXHRcdEhhbmRsZXIucHJvdG90eXBlLndoZW5cblx0XHRcdD0gSGFuZGxlci5wcm90b3R5cGUuYmVjb21lXG5cdFx0XHQ9IEhhbmRsZXIucHJvdG90eXBlLm5vdGlmeVxuXHRcdFx0PSBIYW5kbGVyLnByb3RvdHlwZS5mYWlsXG5cdFx0XHQ9IEhhbmRsZXIucHJvdG90eXBlLl91bnJlcG9ydFxuXHRcdFx0PSBIYW5kbGVyLnByb3RvdHlwZS5fcmVwb3J0XG5cdFx0XHQ9IG5vb3A7XG5cblx0XHRIYW5kbGVyLnByb3RvdHlwZS5fc3RhdGUgPSAwO1xuXG5cdFx0SGFuZGxlci5wcm90b3R5cGUuc3RhdGUgPSBmdW5jdGlvbigpIHtcblx0XHRcdHJldHVybiB0aGlzLl9zdGF0ZTtcblx0XHR9O1xuXG5cdFx0LyoqXG5cdFx0ICogUmVjdXJzaXZlbHkgY29sbGFwc2UgaGFuZGxlciBjaGFpbiB0byBmaW5kIHRoZSBoYW5kbGVyXG5cdFx0ICogbmVhcmVzdCB0byB0aGUgZnVsbHkgcmVzb2x2ZWQgdmFsdWUuXG5cdFx0ICogQHJldHVybnMge29iamVjdH0gaGFuZGxlciBuZWFyZXN0IHRoZSBmdWxseSByZXNvbHZlZCB2YWx1ZVxuXHRcdCAqL1xuXHRcdEhhbmRsZXIucHJvdG90eXBlLmpvaW4gPSBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBoID0gdGhpcztcblx0XHRcdHdoaWxlKGguaGFuZGxlciAhPT0gdm9pZCAwKSB7XG5cdFx0XHRcdGggPSBoLmhhbmRsZXI7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gaDtcblx0XHR9O1xuXG5cdFx0SGFuZGxlci5wcm90b3R5cGUuY2hhaW4gPSBmdW5jdGlvbih0bywgcmVjZWl2ZXIsIGZ1bGZpbGxlZCwgcmVqZWN0ZWQsIHByb2dyZXNzKSB7XG5cdFx0XHR0aGlzLndoZW4oe1xuXHRcdFx0XHRyZXNvbHZlcjogdG8sXG5cdFx0XHRcdHJlY2VpdmVyOiByZWNlaXZlcixcblx0XHRcdFx0ZnVsZmlsbGVkOiBmdWxmaWxsZWQsXG5cdFx0XHRcdHJlamVjdGVkOiByZWplY3RlZCxcblx0XHRcdFx0cHJvZ3Jlc3M6IHByb2dyZXNzXG5cdFx0XHR9KTtcblx0XHR9O1xuXG5cdFx0SGFuZGxlci5wcm90b3R5cGUudmlzaXQgPSBmdW5jdGlvbihyZWNlaXZlciwgZnVsZmlsbGVkLCByZWplY3RlZCwgcHJvZ3Jlc3MpIHtcblx0XHRcdHRoaXMuY2hhaW4oZmFpbElmUmVqZWN0ZWQsIHJlY2VpdmVyLCBmdWxmaWxsZWQsIHJlamVjdGVkLCBwcm9ncmVzcyk7XG5cdFx0fTtcblxuXHRcdEhhbmRsZXIucHJvdG90eXBlLmZvbGQgPSBmdW5jdGlvbihmLCB6LCBjLCB0bykge1xuXHRcdFx0dGhpcy52aXNpdCh0bywgZnVuY3Rpb24oeCkge1xuXHRcdFx0XHRmLmNhbGwoYywgeiwgeCwgdGhpcyk7XG5cdFx0XHR9LCB0by5yZWplY3QsIHRvLm5vdGlmeSk7XG5cdFx0fTtcblxuXHRcdC8qKlxuXHRcdCAqIEhhbmRsZXIgdGhhdCBpbnZva2VzIGZhaWwoKSBvbiBhbnkgaGFuZGxlciBpdCBiZWNvbWVzXG5cdFx0ICogQGNvbnN0cnVjdG9yXG5cdFx0ICovXG5cdFx0ZnVuY3Rpb24gRmFpbElmUmVqZWN0ZWQoKSB7fVxuXG5cdFx0aW5oZXJpdChIYW5kbGVyLCBGYWlsSWZSZWplY3RlZCk7XG5cblx0XHRGYWlsSWZSZWplY3RlZC5wcm90b3R5cGUuYmVjb21lID0gZnVuY3Rpb24oaCkge1xuXHRcdFx0aC5mYWlsKCk7XG5cdFx0fTtcblxuXHRcdHZhciBmYWlsSWZSZWplY3RlZCA9IG5ldyBGYWlsSWZSZWplY3RlZCgpO1xuXG5cdFx0LyoqXG5cdFx0ICogSGFuZGxlciB0aGF0IG1hbmFnZXMgYSBxdWV1ZSBvZiBjb25zdW1lcnMgd2FpdGluZyBvbiBhIHBlbmRpbmcgcHJvbWlzZVxuXHRcdCAqIEBjb25zdHJ1Y3RvclxuXHRcdCAqL1xuXHRcdGZ1bmN0aW9uIFBlbmRpbmcocmVjZWl2ZXIsIGluaGVyaXRlZENvbnRleHQpIHtcblx0XHRcdFByb21pc2UuY3JlYXRlQ29udGV4dCh0aGlzLCBpbmhlcml0ZWRDb250ZXh0KTtcblxuXHRcdFx0dGhpcy5jb25zdW1lcnMgPSB2b2lkIDA7XG5cdFx0XHR0aGlzLnJlY2VpdmVyID0gcmVjZWl2ZXI7XG5cdFx0XHR0aGlzLmhhbmRsZXIgPSB2b2lkIDA7XG5cdFx0XHR0aGlzLnJlc29sdmVkID0gZmFsc2U7XG5cdFx0fVxuXG5cdFx0aW5oZXJpdChIYW5kbGVyLCBQZW5kaW5nKTtcblxuXHRcdFBlbmRpbmcucHJvdG90eXBlLl9zdGF0ZSA9IDA7XG5cblx0XHRQZW5kaW5nLnByb3RvdHlwZS5yZXNvbHZlID0gZnVuY3Rpb24oeCkge1xuXHRcdFx0dGhpcy5iZWNvbWUoZ2V0SGFuZGxlcih4KSk7XG5cdFx0fTtcblxuXHRcdFBlbmRpbmcucHJvdG90eXBlLnJlamVjdCA9IGZ1bmN0aW9uKHgpIHtcblx0XHRcdGlmKHRoaXMucmVzb2x2ZWQpIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLmJlY29tZShuZXcgUmVqZWN0ZWQoeCkpO1xuXHRcdH07XG5cblx0XHRQZW5kaW5nLnByb3RvdHlwZS5qb2luID0gZnVuY3Rpb24oKSB7XG5cdFx0XHRpZiAoIXRoaXMucmVzb2x2ZWQpIHtcblx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHR9XG5cblx0XHRcdHZhciBoID0gdGhpcztcblxuXHRcdFx0d2hpbGUgKGguaGFuZGxlciAhPT0gdm9pZCAwKSB7XG5cdFx0XHRcdGggPSBoLmhhbmRsZXI7XG5cdFx0XHRcdGlmIChoID09PSB0aGlzKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHRoaXMuaGFuZGxlciA9IGN5Y2xlKCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGg7XG5cdFx0fTtcblxuXHRcdFBlbmRpbmcucHJvdG90eXBlLnJ1biA9IGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIHEgPSB0aGlzLmNvbnN1bWVycztcblx0XHRcdHZhciBoYW5kbGVyID0gdGhpcy5qb2luKCk7XG5cdFx0XHR0aGlzLmNvbnN1bWVycyA9IHZvaWQgMDtcblxuXHRcdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCBxLmxlbmd0aDsgKytpKSB7XG5cdFx0XHRcdGhhbmRsZXIud2hlbihxW2ldKTtcblx0XHRcdH1cblx0XHR9O1xuXG5cdFx0UGVuZGluZy5wcm90b3R5cGUuYmVjb21lID0gZnVuY3Rpb24oaGFuZGxlcikge1xuXHRcdFx0aWYodGhpcy5yZXNvbHZlZCkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMucmVzb2x2ZWQgPSB0cnVlO1xuXHRcdFx0dGhpcy5oYW5kbGVyID0gaGFuZGxlcjtcblx0XHRcdGlmKHRoaXMuY29uc3VtZXJzICE9PSB2b2lkIDApIHtcblx0XHRcdFx0dGFza3MuZW5xdWV1ZSh0aGlzKTtcblx0XHRcdH1cblxuXHRcdFx0aWYodGhpcy5jb250ZXh0ICE9PSB2b2lkIDApIHtcblx0XHRcdFx0aGFuZGxlci5fcmVwb3J0KHRoaXMuY29udGV4dCk7XG5cdFx0XHR9XG5cdFx0fTtcblxuXHRcdFBlbmRpbmcucHJvdG90eXBlLndoZW4gPSBmdW5jdGlvbihjb250aW51YXRpb24pIHtcblx0XHRcdGlmKHRoaXMucmVzb2x2ZWQpIHtcblx0XHRcdFx0dGFza3MuZW5xdWV1ZShuZXcgQ29udGludWF0aW9uVGFzayhjb250aW51YXRpb24sIHRoaXMuaGFuZGxlcikpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0aWYodGhpcy5jb25zdW1lcnMgPT09IHZvaWQgMCkge1xuXHRcdFx0XHRcdHRoaXMuY29uc3VtZXJzID0gW2NvbnRpbnVhdGlvbl07XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0dGhpcy5jb25zdW1lcnMucHVzaChjb250aW51YXRpb24pO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fTtcblxuXHRcdFBlbmRpbmcucHJvdG90eXBlLm5vdGlmeSA9IGZ1bmN0aW9uKHgpIHtcblx0XHRcdGlmKCF0aGlzLnJlc29sdmVkKSB7XG5cdFx0XHRcdHRhc2tzLmVucXVldWUobmV3IFByb2dyZXNzVGFzayh4LCB0aGlzKSk7XG5cdFx0XHR9XG5cdFx0fTtcblxuXHRcdFBlbmRpbmcucHJvdG90eXBlLmZhaWwgPSBmdW5jdGlvbihjb250ZXh0KSB7XG5cdFx0XHR2YXIgYyA9IHR5cGVvZiBjb250ZXh0ID09PSAndW5kZWZpbmVkJyA/IHRoaXMuY29udGV4dCA6IGNvbnRleHQ7XG5cdFx0XHR0aGlzLnJlc29sdmVkICYmIHRoaXMuaGFuZGxlci5qb2luKCkuZmFpbChjKTtcblx0XHR9O1xuXG5cdFx0UGVuZGluZy5wcm90b3R5cGUuX3JlcG9ydCA9IGZ1bmN0aW9uKGNvbnRleHQpIHtcblx0XHRcdHRoaXMucmVzb2x2ZWQgJiYgdGhpcy5oYW5kbGVyLmpvaW4oKS5fcmVwb3J0KGNvbnRleHQpO1xuXHRcdH07XG5cblx0XHRQZW5kaW5nLnByb3RvdHlwZS5fdW5yZXBvcnQgPSBmdW5jdGlvbigpIHtcblx0XHRcdHRoaXMucmVzb2x2ZWQgJiYgdGhpcy5oYW5kbGVyLmpvaW4oKS5fdW5yZXBvcnQoKTtcblx0XHR9O1xuXG5cdFx0LyoqXG5cdFx0ICogV3JhcCBhbm90aGVyIGhhbmRsZXIgYW5kIGZvcmNlIGl0IGludG8gYSBmdXR1cmUgc3RhY2tcblx0XHQgKiBAcGFyYW0ge29iamVjdH0gaGFuZGxlclxuXHRcdCAqIEBjb25zdHJ1Y3RvclxuXHRcdCAqL1xuXHRcdGZ1bmN0aW9uIEFzeW5jKGhhbmRsZXIpIHtcblx0XHRcdHRoaXMuaGFuZGxlciA9IGhhbmRsZXI7XG5cdFx0fVxuXG5cdFx0aW5oZXJpdChIYW5kbGVyLCBBc3luYyk7XG5cblx0XHRBc3luYy5wcm90b3R5cGUud2hlbiA9IGZ1bmN0aW9uKGNvbnRpbnVhdGlvbikge1xuXHRcdFx0dGFza3MuZW5xdWV1ZShuZXcgQ29udGludWF0aW9uVGFzayhjb250aW51YXRpb24sIHRoaXMpKTtcblx0XHR9O1xuXG5cdFx0QXN5bmMucHJvdG90eXBlLl9yZXBvcnQgPSBmdW5jdGlvbihjb250ZXh0KSB7XG5cdFx0XHR0aGlzLmpvaW4oKS5fcmVwb3J0KGNvbnRleHQpO1xuXHRcdH07XG5cblx0XHRBc3luYy5wcm90b3R5cGUuX3VucmVwb3J0ID0gZnVuY3Rpb24oKSB7XG5cdFx0XHR0aGlzLmpvaW4oKS5fdW5yZXBvcnQoKTtcblx0XHR9O1xuXG5cdFx0LyoqXG5cdFx0ICogSGFuZGxlciB0aGF0IHdyYXBzIGFuIHVudHJ1c3RlZCB0aGVuYWJsZSBhbmQgYXNzaW1pbGF0ZXMgaXQgaW4gYSBmdXR1cmUgc3RhY2tcblx0XHQgKiBAcGFyYW0ge2Z1bmN0aW9ufSB0aGVuXG5cdFx0ICogQHBhcmFtIHt7dGhlbjogZnVuY3Rpb259fSB0aGVuYWJsZVxuXHRcdCAqIEBjb25zdHJ1Y3RvclxuXHRcdCAqL1xuXHRcdGZ1bmN0aW9uIFRoZW5hYmxlKHRoZW4sIHRoZW5hYmxlKSB7XG5cdFx0XHRQZW5kaW5nLmNhbGwodGhpcyk7XG5cdFx0XHR0YXNrcy5lbnF1ZXVlKG5ldyBBc3NpbWlsYXRlVGFzayh0aGVuLCB0aGVuYWJsZSwgdGhpcykpO1xuXHRcdH1cblxuXHRcdGluaGVyaXQoUGVuZGluZywgVGhlbmFibGUpO1xuXG5cdFx0LyoqXG5cdFx0ICogSGFuZGxlciBmb3IgYSBmdWxmaWxsZWQgcHJvbWlzZVxuXHRcdCAqIEBwYXJhbSB7Kn0geCBmdWxmaWxsbWVudCB2YWx1ZVxuXHRcdCAqIEBjb25zdHJ1Y3RvclxuXHRcdCAqL1xuXHRcdGZ1bmN0aW9uIEZ1bGZpbGxlZCh4KSB7XG5cdFx0XHRQcm9taXNlLmNyZWF0ZUNvbnRleHQodGhpcyk7XG5cdFx0XHR0aGlzLnZhbHVlID0geDtcblx0XHR9XG5cblx0XHRpbmhlcml0KEhhbmRsZXIsIEZ1bGZpbGxlZCk7XG5cblx0XHRGdWxmaWxsZWQucHJvdG90eXBlLl9zdGF0ZSA9IDE7XG5cblx0XHRGdWxmaWxsZWQucHJvdG90eXBlLmZvbGQgPSBmdW5jdGlvbihmLCB6LCBjLCB0bykge1xuXHRcdFx0cnVuQ29udGludWF0aW9uMyhmLCB6LCB0aGlzLCBjLCB0byk7XG5cdFx0fTtcblxuXHRcdEZ1bGZpbGxlZC5wcm90b3R5cGUud2hlbiA9IGZ1bmN0aW9uKGNvbnQpIHtcblx0XHRcdHJ1bkNvbnRpbnVhdGlvbjEoY29udC5mdWxmaWxsZWQsIHRoaXMsIGNvbnQucmVjZWl2ZXIsIGNvbnQucmVzb2x2ZXIpO1xuXHRcdH07XG5cblx0XHR2YXIgZXJyb3JJZCA9IDA7XG5cblx0XHQvKipcblx0XHQgKiBIYW5kbGVyIGZvciBhIHJlamVjdGVkIHByb21pc2Vcblx0XHQgKiBAcGFyYW0geyp9IHggcmVqZWN0aW9uIHJlYXNvblxuXHRcdCAqIEBjb25zdHJ1Y3RvclxuXHRcdCAqL1xuXHRcdGZ1bmN0aW9uIFJlamVjdGVkKHgpIHtcblx0XHRcdFByb21pc2UuY3JlYXRlQ29udGV4dCh0aGlzKTtcblxuXHRcdFx0dGhpcy5pZCA9ICsrZXJyb3JJZDtcblx0XHRcdHRoaXMudmFsdWUgPSB4O1xuXHRcdFx0dGhpcy5oYW5kbGVkID0gZmFsc2U7XG5cdFx0XHR0aGlzLnJlcG9ydGVkID0gZmFsc2U7XG5cblx0XHRcdHRoaXMuX3JlcG9ydCgpO1xuXHRcdH1cblxuXHRcdGluaGVyaXQoSGFuZGxlciwgUmVqZWN0ZWQpO1xuXG5cdFx0UmVqZWN0ZWQucHJvdG90eXBlLl9zdGF0ZSA9IC0xO1xuXG5cdFx0UmVqZWN0ZWQucHJvdG90eXBlLmZvbGQgPSBmdW5jdGlvbihmLCB6LCBjLCB0bykge1xuXHRcdFx0dG8uYmVjb21lKHRoaXMpO1xuXHRcdH07XG5cblx0XHRSZWplY3RlZC5wcm90b3R5cGUud2hlbiA9IGZ1bmN0aW9uKGNvbnQpIHtcblx0XHRcdGlmKHR5cGVvZiBjb250LnJlamVjdGVkID09PSAnZnVuY3Rpb24nKSB7XG5cdFx0XHRcdHRoaXMuX3VucmVwb3J0KCk7XG5cdFx0XHR9XG5cdFx0XHRydW5Db250aW51YXRpb24xKGNvbnQucmVqZWN0ZWQsIHRoaXMsIGNvbnQucmVjZWl2ZXIsIGNvbnQucmVzb2x2ZXIpO1xuXHRcdH07XG5cblx0XHRSZWplY3RlZC5wcm90b3R5cGUuX3JlcG9ydCA9IGZ1bmN0aW9uKGNvbnRleHQpIHtcblx0XHRcdHRhc2tzLmFmdGVyUXVldWUobmV3IFJlcG9ydFRhc2sodGhpcywgY29udGV4dCkpO1xuXHRcdH07XG5cblx0XHRSZWplY3RlZC5wcm90b3R5cGUuX3VucmVwb3J0ID0gZnVuY3Rpb24oKSB7XG5cdFx0XHR0aGlzLmhhbmRsZWQgPSB0cnVlO1xuXHRcdFx0dGFza3MuYWZ0ZXJRdWV1ZShuZXcgVW5yZXBvcnRUYXNrKHRoaXMpKTtcblx0XHR9O1xuXG5cdFx0UmVqZWN0ZWQucHJvdG90eXBlLmZhaWwgPSBmdW5jdGlvbihjb250ZXh0KSB7XG5cdFx0XHRQcm9taXNlLm9uRmF0YWxSZWplY3Rpb24odGhpcywgY29udGV4dCA9PT0gdm9pZCAwID8gdGhpcy5jb250ZXh0IDogY29udGV4dCk7XG5cdFx0fTtcblxuXHRcdGZ1bmN0aW9uIFJlcG9ydFRhc2socmVqZWN0aW9uLCBjb250ZXh0KSB7XG5cdFx0XHR0aGlzLnJlamVjdGlvbiA9IHJlamVjdGlvbjtcblx0XHRcdHRoaXMuY29udGV4dCA9IGNvbnRleHQ7XG5cdFx0fVxuXG5cdFx0UmVwb3J0VGFzay5wcm90b3R5cGUucnVuID0gZnVuY3Rpb24oKSB7XG5cdFx0XHRpZighdGhpcy5yZWplY3Rpb24uaGFuZGxlZCkge1xuXHRcdFx0XHR0aGlzLnJlamVjdGlvbi5yZXBvcnRlZCA9IHRydWU7XG5cdFx0XHRcdFByb21pc2Uub25Qb3RlbnRpYWxseVVuaGFuZGxlZFJlamVjdGlvbih0aGlzLnJlamVjdGlvbiwgdGhpcy5jb250ZXh0KTtcblx0XHRcdH1cblx0XHR9O1xuXG5cdFx0ZnVuY3Rpb24gVW5yZXBvcnRUYXNrKHJlamVjdGlvbikge1xuXHRcdFx0dGhpcy5yZWplY3Rpb24gPSByZWplY3Rpb247XG5cdFx0fVxuXG5cdFx0VW5yZXBvcnRUYXNrLnByb3RvdHlwZS5ydW4gPSBmdW5jdGlvbigpIHtcblx0XHRcdGlmKHRoaXMucmVqZWN0aW9uLnJlcG9ydGVkKSB7XG5cdFx0XHRcdFByb21pc2Uub25Qb3RlbnRpYWxseVVuaGFuZGxlZFJlamVjdGlvbkhhbmRsZWQodGhpcy5yZWplY3Rpb24pO1xuXHRcdFx0fVxuXHRcdH07XG5cblx0XHQvLyBVbmhhbmRsZWQgcmVqZWN0aW9uIGhvb2tzXG5cdFx0Ly8gQnkgZGVmYXVsdCwgZXZlcnl0aGluZyBpcyBhIG5vb3BcblxuXHRcdC8vIFRPRE86IEJldHRlciBuYW1lczogXCJhbm5vdGF0ZVwiP1xuXHRcdFByb21pc2UuY3JlYXRlQ29udGV4dFxuXHRcdFx0PSBQcm9taXNlLmVudGVyQ29udGV4dFxuXHRcdFx0PSBQcm9taXNlLmV4aXRDb250ZXh0XG5cdFx0XHQ9IFByb21pc2Uub25Qb3RlbnRpYWxseVVuaGFuZGxlZFJlamVjdGlvblxuXHRcdFx0PSBQcm9taXNlLm9uUG90ZW50aWFsbHlVbmhhbmRsZWRSZWplY3Rpb25IYW5kbGVkXG5cdFx0XHQ9IFByb21pc2Uub25GYXRhbFJlamVjdGlvblxuXHRcdFx0PSBub29wO1xuXG5cdFx0Ly8gRXJyb3JzIGFuZCBzaW5nbGV0b25zXG5cblx0XHR2YXIgZm9yZXZlclBlbmRpbmdIYW5kbGVyID0gbmV3IEhhbmRsZXIoKTtcblx0XHR2YXIgZm9yZXZlclBlbmRpbmdQcm9taXNlID0gbmV3IFByb21pc2UoSGFuZGxlciwgZm9yZXZlclBlbmRpbmdIYW5kbGVyKTtcblxuXHRcdGZ1bmN0aW9uIGN5Y2xlKCkge1xuXHRcdFx0cmV0dXJuIG5ldyBSZWplY3RlZChuZXcgVHlwZUVycm9yKCdQcm9taXNlIGN5Y2xlJykpO1xuXHRcdH1cblxuXHRcdC8vIFRhc2sgcnVubmVyc1xuXG5cdFx0LyoqXG5cdFx0ICogUnVuIGEgc2luZ2xlIGNvbnN1bWVyXG5cdFx0ICogQGNvbnN0cnVjdG9yXG5cdFx0ICovXG5cdFx0ZnVuY3Rpb24gQ29udGludWF0aW9uVGFzayhjb250aW51YXRpb24sIGhhbmRsZXIpIHtcblx0XHRcdHRoaXMuY29udGludWF0aW9uID0gY29udGludWF0aW9uO1xuXHRcdFx0dGhpcy5oYW5kbGVyID0gaGFuZGxlcjtcblx0XHR9XG5cblx0XHRDb250aW51YXRpb25UYXNrLnByb3RvdHlwZS5ydW4gPSBmdW5jdGlvbigpIHtcblx0XHRcdHRoaXMuaGFuZGxlci5qb2luKCkud2hlbih0aGlzLmNvbnRpbnVhdGlvbik7XG5cdFx0fTtcblxuXHRcdC8qKlxuXHRcdCAqIFJ1biBhIHF1ZXVlIG9mIHByb2dyZXNzIGhhbmRsZXJzXG5cdFx0ICogQGNvbnN0cnVjdG9yXG5cdFx0ICovXG5cdFx0ZnVuY3Rpb24gUHJvZ3Jlc3NUYXNrKHZhbHVlLCBoYW5kbGVyKSB7XG5cdFx0XHR0aGlzLmhhbmRsZXIgPSBoYW5kbGVyO1xuXHRcdFx0dGhpcy52YWx1ZSA9IHZhbHVlO1xuXHRcdH1cblxuXHRcdFByb2dyZXNzVGFzay5wcm90b3R5cGUucnVuID0gZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgcSA9IHRoaXMuaGFuZGxlci5jb25zdW1lcnM7XG5cdFx0XHRpZihxID09PSB2b2lkIDApIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHRmb3IgKHZhciBjLCBpID0gMDsgaSA8IHEubGVuZ3RoOyArK2kpIHtcblx0XHRcdFx0YyA9IHFbaV07XG5cdFx0XHRcdHJ1bk5vdGlmeShjLnByb2dyZXNzLCB0aGlzLnZhbHVlLCB0aGlzLmhhbmRsZXIsIGMucmVjZWl2ZXIsIGMucmVzb2x2ZXIpO1xuXHRcdFx0fVxuXHRcdH07XG5cblx0XHQvKipcblx0XHQgKiBBc3NpbWlsYXRlIGEgdGhlbmFibGUsIHNlbmRpbmcgaXQncyB2YWx1ZSB0byByZXNvbHZlclxuXHRcdCAqIEBwYXJhbSB7ZnVuY3Rpb259IHRoZW5cblx0XHQgKiBAcGFyYW0ge29iamVjdHxmdW5jdGlvbn0gdGhlbmFibGVcblx0XHQgKiBAcGFyYW0ge29iamVjdH0gcmVzb2x2ZXJcblx0XHQgKiBAY29uc3RydWN0b3Jcblx0XHQgKi9cblx0XHRmdW5jdGlvbiBBc3NpbWlsYXRlVGFzayh0aGVuLCB0aGVuYWJsZSwgcmVzb2x2ZXIpIHtcblx0XHRcdHRoaXMuX3RoZW4gPSB0aGVuO1xuXHRcdFx0dGhpcy50aGVuYWJsZSA9IHRoZW5hYmxlO1xuXHRcdFx0dGhpcy5yZXNvbHZlciA9IHJlc29sdmVyO1xuXHRcdH1cblxuXHRcdEFzc2ltaWxhdGVUYXNrLnByb3RvdHlwZS5ydW4gPSBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBoID0gdGhpcy5yZXNvbHZlcjtcblx0XHRcdHRyeUFzc2ltaWxhdGUodGhpcy5fdGhlbiwgdGhpcy50aGVuYWJsZSwgX3Jlc29sdmUsIF9yZWplY3QsIF9ub3RpZnkpO1xuXG5cdFx0XHRmdW5jdGlvbiBfcmVzb2x2ZSh4KSB7IGgucmVzb2x2ZSh4KTsgfVxuXHRcdFx0ZnVuY3Rpb24gX3JlamVjdCh4KSAgeyBoLnJlamVjdCh4KTsgfVxuXHRcdFx0ZnVuY3Rpb24gX25vdGlmeSh4KSAgeyBoLm5vdGlmeSh4KTsgfVxuXHRcdH07XG5cblx0XHRmdW5jdGlvbiB0cnlBc3NpbWlsYXRlKHRoZW4sIHRoZW5hYmxlLCByZXNvbHZlLCByZWplY3QsIG5vdGlmeSkge1xuXHRcdFx0dHJ5IHtcblx0XHRcdFx0dGhlbi5jYWxsKHRoZW5hYmxlLCByZXNvbHZlLCByZWplY3QsIG5vdGlmeSk7XG5cdFx0XHR9IGNhdGNoIChlKSB7XG5cdFx0XHRcdHJlamVjdChlKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBPdGhlciBoZWxwZXJzXG5cblx0XHQvKipcblx0XHQgKiBAcGFyYW0geyp9IHhcblx0XHQgKiBAcmV0dXJucyB7Ym9vbGVhbn0gdHJ1ZSBpZmYgeCBpcyBhIHRydXN0ZWQgUHJvbWlzZVxuXHRcdCAqL1xuXHRcdGZ1bmN0aW9uIGlzUHJvbWlzZSh4KSB7XG5cdFx0XHRyZXR1cm4geCBpbnN0YW5jZW9mIFByb21pc2U7XG5cdFx0fVxuXG5cdFx0LyoqXG5cdFx0ICogVGVzdCBqdXN0IGVub3VnaCB0byBydWxlIG91dCBwcmltaXRpdmVzLCBpbiBvcmRlciB0byB0YWtlIGZhc3RlclxuXHRcdCAqIHBhdGhzIGluIHNvbWUgY29kZVxuXHRcdCAqIEBwYXJhbSB7Kn0geFxuXHRcdCAqIEByZXR1cm5zIHtib29sZWFufSBmYWxzZSBpZmYgeCBpcyBndWFyYW50ZWVkICpub3QqIHRvIGJlIGEgdGhlbmFibGVcblx0XHQgKi9cblx0XHRmdW5jdGlvbiBtYXliZVRoZW5hYmxlKHgpIHtcblx0XHRcdHJldHVybiAodHlwZW9mIHggPT09ICdvYmplY3QnIHx8IHR5cGVvZiB4ID09PSAnZnVuY3Rpb24nKSAmJiB4ICE9PSBudWxsO1xuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIHJ1bkNvbnRpbnVhdGlvbjEoZiwgaCwgcmVjZWl2ZXIsIG5leHQpIHtcblx0XHRcdGlmKHR5cGVvZiBmICE9PSAnZnVuY3Rpb24nKSB7XG5cdFx0XHRcdHJldHVybiBuZXh0LmJlY29tZShoKTtcblx0XHRcdH1cblxuXHRcdFx0UHJvbWlzZS5lbnRlckNvbnRleHQoaCk7XG5cdFx0XHR0cnlDYXRjaFJlamVjdChmLCBoLnZhbHVlLCByZWNlaXZlciwgbmV4dCk7XG5cdFx0XHRQcm9taXNlLmV4aXRDb250ZXh0KCk7XG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gcnVuQ29udGludWF0aW9uMyhmLCB4LCBoLCByZWNlaXZlciwgbmV4dCkge1xuXHRcdFx0aWYodHlwZW9mIGYgIT09ICdmdW5jdGlvbicpIHtcblx0XHRcdFx0cmV0dXJuIG5leHQuYmVjb21lKGgpO1xuXHRcdFx0fVxuXG5cdFx0XHRQcm9taXNlLmVudGVyQ29udGV4dChoKTtcblx0XHRcdHRyeUNhdGNoUmVqZWN0MyhmLCB4LCBoLnZhbHVlLCByZWNlaXZlciwgbmV4dCk7XG5cdFx0XHRQcm9taXNlLmV4aXRDb250ZXh0KCk7XG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gcnVuTm90aWZ5KGYsIHgsIGgsIHJlY2VpdmVyLCBuZXh0KSB7XG5cdFx0XHRpZih0eXBlb2YgZiAhPT0gJ2Z1bmN0aW9uJykge1xuXHRcdFx0XHRyZXR1cm4gbmV4dC5ub3RpZnkoeCk7XG5cdFx0XHR9XG5cblx0XHRcdFByb21pc2UuZW50ZXJDb250ZXh0KGgpO1xuXHRcdFx0dHJ5Q2F0Y2hSZXR1cm4oZiwgeCwgcmVjZWl2ZXIsIG5leHQpO1xuXHRcdFx0UHJvbWlzZS5leGl0Q29udGV4dCgpO1xuXHRcdH1cblxuXHRcdC8qKlxuXHRcdCAqIFJldHVybiBmLmNhbGwodGhpc0FyZywgeCksIG9yIGlmIGl0IHRocm93cyByZXR1cm4gYSByZWplY3RlZCBwcm9taXNlIGZvclxuXHRcdCAqIHRoZSB0aHJvd24gZXhjZXB0aW9uXG5cdFx0ICovXG5cdFx0ZnVuY3Rpb24gdHJ5Q2F0Y2hSZWplY3QoZiwgeCwgdGhpc0FyZywgbmV4dCkge1xuXHRcdFx0dHJ5IHtcblx0XHRcdFx0bmV4dC5iZWNvbWUoZ2V0SGFuZGxlcihmLmNhbGwodGhpc0FyZywgeCkpKTtcblx0XHRcdH0gY2F0Y2goZSkge1xuXHRcdFx0XHRuZXh0LmJlY29tZShuZXcgUmVqZWN0ZWQoZSkpO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8qKlxuXHRcdCAqIFNhbWUgYXMgYWJvdmUsIGJ1dCBpbmNsdWRlcyB0aGUgZXh0cmEgYXJndW1lbnQgcGFyYW1ldGVyLlxuXHRcdCAqL1xuXHRcdGZ1bmN0aW9uIHRyeUNhdGNoUmVqZWN0MyhmLCB4LCB5LCB0aGlzQXJnLCBuZXh0KSB7XG5cdFx0XHR0cnkge1xuXHRcdFx0XHRmLmNhbGwodGhpc0FyZywgeCwgeSwgbmV4dCk7XG5cdFx0XHR9IGNhdGNoKGUpIHtcblx0XHRcdFx0bmV4dC5iZWNvbWUobmV3IFJlamVjdGVkKGUpKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvKipcblx0XHQgKiBSZXR1cm4gZi5jYWxsKHRoaXNBcmcsIHgpLCBvciBpZiBpdCB0aHJvd3MsICpyZXR1cm4qIHRoZSBleGNlcHRpb25cblx0XHQgKi9cblx0XHRmdW5jdGlvbiB0cnlDYXRjaFJldHVybihmLCB4LCB0aGlzQXJnLCBuZXh0KSB7XG5cdFx0XHR0cnkge1xuXHRcdFx0XHRuZXh0Lm5vdGlmeShmLmNhbGwodGhpc0FyZywgeCkpO1xuXHRcdFx0fSBjYXRjaChlKSB7XG5cdFx0XHRcdG5leHQubm90aWZ5KGUpO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGluaGVyaXQoUGFyZW50LCBDaGlsZCkge1xuXHRcdFx0Q2hpbGQucHJvdG90eXBlID0gb2JqZWN0Q3JlYXRlKFBhcmVudC5wcm90b3R5cGUpO1xuXHRcdFx0Q2hpbGQucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQ2hpbGQ7XG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gbm9vcCgpIHt9XG5cblx0XHRyZXR1cm4gUHJvbWlzZTtcblx0fTtcbn0pO1xufSh0eXBlb2YgZGVmaW5lID09PSAnZnVuY3Rpb24nICYmIGRlZmluZS5hbWQgPyBkZWZpbmUgOiBmdW5jdGlvbihmYWN0b3J5KSB7IG1vZHVsZS5leHBvcnRzID0gZmFjdG9yeSgpOyB9KSk7XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgQXV0b0ZvY3VzTWl4aW5cbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBmb2N1c05vZGUgPSByZXF1aXJlKFwiLi9mb2N1c05vZGVcIik7XG5cbnZhciBBdXRvRm9jdXNNaXhpbiA9IHtcbiAgY29tcG9uZW50RGlkTW91bnQ6IGZ1bmN0aW9uKCkge1xuICAgIGlmICh0aGlzLnByb3BzLmF1dG9Gb2N1cykge1xuICAgICAgZm9jdXNOb2RlKHRoaXMuZ2V0RE9NTm9kZSgpKTtcbiAgICB9XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gQXV0b0ZvY3VzTWl4aW47XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgQmVmb3JlSW5wdXRFdmVudFBsdWdpblxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIEV2ZW50Q29uc3RhbnRzID0gcmVxdWlyZShcIi4vRXZlbnRDb25zdGFudHNcIik7XG52YXIgRXZlbnRQcm9wYWdhdG9ycyA9IHJlcXVpcmUoXCIuL0V2ZW50UHJvcGFnYXRvcnNcIik7XG52YXIgRXhlY3V0aW9uRW52aXJvbm1lbnQgPSByZXF1aXJlKFwiLi9FeGVjdXRpb25FbnZpcm9ubWVudFwiKTtcbnZhciBTeW50aGV0aWNJbnB1dEV2ZW50ID0gcmVxdWlyZShcIi4vU3ludGhldGljSW5wdXRFdmVudFwiKTtcblxudmFyIGtleU9mID0gcmVxdWlyZShcIi4va2V5T2ZcIik7XG5cbnZhciBjYW5Vc2VUZXh0SW5wdXRFdmVudCA9IChcbiAgRXhlY3V0aW9uRW52aXJvbm1lbnQuY2FuVXNlRE9NICYmXG4gICdUZXh0RXZlbnQnIGluIHdpbmRvdyAmJlxuICAhKCdkb2N1bWVudE1vZGUnIGluIGRvY3VtZW50IHx8IGlzUHJlc3RvKCkpXG4pO1xuXG4vKipcbiAqIE9wZXJhIDw9IDEyIGluY2x1ZGVzIFRleHRFdmVudCBpbiB3aW5kb3csIGJ1dCBkb2VzIG5vdCBmaXJlXG4gKiB0ZXh0IGlucHV0IGV2ZW50cy4gUmVseSBvbiBrZXlwcmVzcyBpbnN0ZWFkLlxuICovXG5mdW5jdGlvbiBpc1ByZXN0bygpIHtcbiAgdmFyIG9wZXJhID0gd2luZG93Lm9wZXJhO1xuICByZXR1cm4gKFxuICAgIHR5cGVvZiBvcGVyYSA9PT0gJ29iamVjdCcgJiZcbiAgICB0eXBlb2Ygb3BlcmEudmVyc2lvbiA9PT0gJ2Z1bmN0aW9uJyAmJlxuICAgIHBhcnNlSW50KG9wZXJhLnZlcnNpb24oKSwgMTApIDw9IDEyXG4gICk7XG59XG5cbnZhciBTUEFDRUJBUl9DT0RFID0gMzI7XG52YXIgU1BBQ0VCQVJfQ0hBUiA9IFN0cmluZy5mcm9tQ2hhckNvZGUoU1BBQ0VCQVJfQ09ERSk7XG5cbnZhciB0b3BMZXZlbFR5cGVzID0gRXZlbnRDb25zdGFudHMudG9wTGV2ZWxUeXBlcztcblxuLy8gRXZlbnRzIGFuZCB0aGVpciBjb3JyZXNwb25kaW5nIHByb3BlcnR5IG5hbWVzLlxudmFyIGV2ZW50VHlwZXMgPSB7XG4gIGJlZm9yZUlucHV0OiB7XG4gICAgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXM6IHtcbiAgICAgIGJ1YmJsZWQ6IGtleU9mKHtvbkJlZm9yZUlucHV0OiBudWxsfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uQmVmb3JlSW5wdXRDYXB0dXJlOiBudWxsfSlcbiAgICB9LFxuICAgIGRlcGVuZGVuY2llczogW1xuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BDb21wb3NpdGlvbkVuZCxcbiAgICAgIHRvcExldmVsVHlwZXMudG9wS2V5UHJlc3MsXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcFRleHRJbnB1dCxcbiAgICAgIHRvcExldmVsVHlwZXMudG9wUGFzdGVcbiAgICBdXG4gIH1cbn07XG5cbi8vIFRyYWNrIGNoYXJhY3RlcnMgaW5zZXJ0ZWQgdmlhIGtleXByZXNzIGFuZCBjb21wb3NpdGlvbiBldmVudHMuXG52YXIgZmFsbGJhY2tDaGFycyA9IG51bGw7XG5cbi8vIFRyYWNrIHdoZXRoZXIgd2UndmUgZXZlciBoYW5kbGVkIGEga2V5cHJlc3Mgb24gdGhlIHNwYWNlIGtleS5cbnZhciBoYXNTcGFjZUtleXByZXNzID0gZmFsc2U7XG5cbi8qKlxuICogUmV0dXJuIHdoZXRoZXIgYSBuYXRpdmUga2V5cHJlc3MgZXZlbnQgaXMgYXNzdW1lZCB0byBiZSBhIGNvbW1hbmQuXG4gKiBUaGlzIGlzIHJlcXVpcmVkIGJlY2F1c2UgRmlyZWZveCBmaXJlcyBga2V5cHJlc3NgIGV2ZW50cyBmb3Iga2V5IGNvbW1hbmRzXG4gKiAoY3V0LCBjb3B5LCBzZWxlY3QtYWxsLCBldGMuKSBldmVuIHRob3VnaCBubyBjaGFyYWN0ZXIgaXMgaW5zZXJ0ZWQuXG4gKi9cbmZ1bmN0aW9uIGlzS2V5cHJlc3NDb21tYW5kKG5hdGl2ZUV2ZW50KSB7XG4gIHJldHVybiAoXG4gICAgKG5hdGl2ZUV2ZW50LmN0cmxLZXkgfHwgbmF0aXZlRXZlbnQuYWx0S2V5IHx8IG5hdGl2ZUV2ZW50Lm1ldGFLZXkpICYmXG4gICAgLy8gY3RybEtleSAmJiBhbHRLZXkgaXMgZXF1aXZhbGVudCB0byBBbHRHciwgYW5kIGlzIG5vdCBhIGNvbW1hbmQuXG4gICAgIShuYXRpdmVFdmVudC5jdHJsS2V5ICYmIG5hdGl2ZUV2ZW50LmFsdEtleSlcbiAgKTtcbn1cblxuLyoqXG4gKiBDcmVhdGUgYW4gYG9uQmVmb3JlSW5wdXRgIGV2ZW50IHRvIG1hdGNoXG4gKiBodHRwOi8vd3d3LnczLm9yZy9UUi8yMDEzL1dELURPTS1MZXZlbC0zLUV2ZW50cy0yMDEzMTEwNS8jZXZlbnRzLWlucHV0ZXZlbnRzLlxuICpcbiAqIFRoaXMgZXZlbnQgcGx1Z2luIGlzIGJhc2VkIG9uIHRoZSBuYXRpdmUgYHRleHRJbnB1dGAgZXZlbnRcbiAqIGF2YWlsYWJsZSBpbiBDaHJvbWUsIFNhZmFyaSwgT3BlcmEsIGFuZCBJRS4gVGhpcyBldmVudCBmaXJlcyBhZnRlclxuICogYG9uS2V5UHJlc3NgIGFuZCBgb25Db21wb3NpdGlvbkVuZGAsIGJ1dCBiZWZvcmUgYG9uSW5wdXRgLlxuICpcbiAqIGBiZWZvcmVJbnB1dGAgaXMgc3BlYydkIGJ1dCBub3QgaW1wbGVtZW50ZWQgaW4gYW55IGJyb3dzZXJzLCBhbmRcbiAqIHRoZSBgaW5wdXRgIGV2ZW50IGRvZXMgbm90IHByb3ZpZGUgYW55IHVzZWZ1bCBpbmZvcm1hdGlvbiBhYm91dCB3aGF0IGhhc1xuICogYWN0dWFsbHkgYmVlbiBhZGRlZCwgY29udHJhcnkgdG8gdGhlIHNwZWMuIFRodXMsIGB0ZXh0SW5wdXRgIGlzIHRoZSBiZXN0XG4gKiBhdmFpbGFibGUgZXZlbnQgdG8gaWRlbnRpZnkgdGhlIGNoYXJhY3RlcnMgdGhhdCBoYXZlIGFjdHVhbGx5IGJlZW4gaW5zZXJ0ZWRcbiAqIGludG8gdGhlIHRhcmdldCBub2RlLlxuICovXG52YXIgQmVmb3JlSW5wdXRFdmVudFBsdWdpbiA9IHtcblxuICBldmVudFR5cGVzOiBldmVudFR5cGVzLFxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gdG9wTGV2ZWxUeXBlIFJlY29yZCBmcm9tIGBFdmVudENvbnN0YW50c2AuXG4gICAqIEBwYXJhbSB7RE9NRXZlbnRUYXJnZXR9IHRvcExldmVsVGFyZ2V0IFRoZSBsaXN0ZW5pbmcgY29tcG9uZW50IHJvb3Qgbm9kZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHRvcExldmVsVGFyZ2V0SUQgSUQgb2YgYHRvcExldmVsVGFyZ2V0YC5cbiAgICogQHBhcmFtIHtvYmplY3R9IG5hdGl2ZUV2ZW50IE5hdGl2ZSBicm93c2VyIGV2ZW50LlxuICAgKiBAcmV0dXJuIHsqfSBBbiBhY2N1bXVsYXRpb24gb2Ygc3ludGhldGljIGV2ZW50cy5cbiAgICogQHNlZSB7RXZlbnRQbHVnaW5IdWIuZXh0cmFjdEV2ZW50c31cbiAgICovXG4gIGV4dHJhY3RFdmVudHM6IGZ1bmN0aW9uKFxuICAgICAgdG9wTGV2ZWxUeXBlLFxuICAgICAgdG9wTGV2ZWxUYXJnZXQsXG4gICAgICB0b3BMZXZlbFRhcmdldElELFxuICAgICAgbmF0aXZlRXZlbnQpIHtcblxuICAgIHZhciBjaGFycztcblxuICAgIGlmIChjYW5Vc2VUZXh0SW5wdXRFdmVudCkge1xuICAgICAgc3dpdGNoICh0b3BMZXZlbFR5cGUpIHtcbiAgICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcEtleVByZXNzOlxuICAgICAgICAgIC8qKlxuICAgICAgICAgICAqIElmIG5hdGl2ZSBgdGV4dElucHV0YCBldmVudHMgYXJlIGF2YWlsYWJsZSwgb3VyIGdvYWwgaXMgdG8gbWFrZVxuICAgICAgICAgICAqIHVzZSBvZiB0aGVtLiBIb3dldmVyLCB0aGVyZSBpcyBhIHNwZWNpYWwgY2FzZTogdGhlIHNwYWNlYmFyIGtleS5cbiAgICAgICAgICAgKiBJbiBXZWJraXQsIHByZXZlbnRpbmcgZGVmYXVsdCBvbiBhIHNwYWNlYmFyIGB0ZXh0SW5wdXRgIGV2ZW50XG4gICAgICAgICAgICogY2FuY2VscyBjaGFyYWN0ZXIgaW5zZXJ0aW9uLCBidXQgaXQgKmFsc28qIGNhdXNlcyB0aGUgYnJvd3NlclxuICAgICAgICAgICAqIHRvIGZhbGwgYmFjayB0byBpdHMgZGVmYXVsdCBzcGFjZWJhciBiZWhhdmlvciBvZiBzY3JvbGxpbmcgdGhlXG4gICAgICAgICAgICogcGFnZS5cbiAgICAgICAgICAgKlxuICAgICAgICAgICAqIFRyYWNraW5nIGF0OlxuICAgICAgICAgICAqIGh0dHBzOi8vY29kZS5nb29nbGUuY29tL3AvY2hyb21pdW0vaXNzdWVzL2RldGFpbD9pZD0zNTUxMDNcbiAgICAgICAgICAgKlxuICAgICAgICAgICAqIFRvIGF2b2lkIHRoaXMgaXNzdWUsIHVzZSB0aGUga2V5cHJlc3MgZXZlbnQgYXMgaWYgbm8gYHRleHRJbnB1dGBcbiAgICAgICAgICAgKiBldmVudCBpcyBhdmFpbGFibGUuXG4gICAgICAgICAgICovXG4gICAgICAgICAgdmFyIHdoaWNoID0gbmF0aXZlRXZlbnQud2hpY2g7XG4gICAgICAgICAgaWYgKHdoaWNoICE9PSBTUEFDRUJBUl9DT0RFKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaGFzU3BhY2VLZXlwcmVzcyA9IHRydWU7XG4gICAgICAgICAgY2hhcnMgPSBTUEFDRUJBUl9DSEFSO1xuICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BUZXh0SW5wdXQ6XG4gICAgICAgICAgLy8gUmVjb3JkIHRoZSBjaGFyYWN0ZXJzIHRvIGJlIGFkZGVkIHRvIHRoZSBET00uXG4gICAgICAgICAgY2hhcnMgPSBuYXRpdmVFdmVudC5kYXRhO1xuXG4gICAgICAgICAgLy8gSWYgaXQncyBhIHNwYWNlYmFyIGNoYXJhY3RlciwgYXNzdW1lIHRoYXQgd2UgaGF2ZSBhbHJlYWR5IGhhbmRsZWRcbiAgICAgICAgICAvLyBpdCBhdCB0aGUga2V5cHJlc3MgbGV2ZWwgYW5kIGJhaWwgaW1tZWRpYXRlbHkuIEFuZHJvaWQgQ2hyb21lXG4gICAgICAgICAgLy8gZG9lc24ndCBnaXZlIHVzIGtleWNvZGVzLCBzbyB3ZSBuZWVkIHRvIGJsYWNrbGlzdCBpdC5cbiAgICAgICAgICBpZiAoY2hhcnMgPT09IFNQQUNFQkFSX0NIQVIgJiYgaGFzU3BhY2VLZXlwcmVzcykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIE90aGVyd2lzZSwgY2Fycnkgb24uXG4gICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAvLyBGb3Igb3RoZXIgbmF0aXZlIGV2ZW50IHR5cGVzLCBkbyBub3RoaW5nLlxuICAgICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgc3dpdGNoICh0b3BMZXZlbFR5cGUpIHtcbiAgICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcFBhc3RlOlxuICAgICAgICAgIC8vIElmIGEgcGFzdGUgZXZlbnQgb2NjdXJzIGFmdGVyIGEga2V5cHJlc3MsIHRocm93IG91dCB0aGUgaW5wdXRcbiAgICAgICAgICAvLyBjaGFycy4gUGFzdGUgZXZlbnRzIHNob3VsZCBub3QgbGVhZCB0byBCZWZvcmVJbnB1dCBldmVudHMuXG4gICAgICAgICAgZmFsbGJhY2tDaGFycyA9IG51bGw7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BLZXlQcmVzczpcbiAgICAgICAgICAvKipcbiAgICAgICAgICAgKiBBcyBvZiB2MjcsIEZpcmVmb3ggbWF5IGZpcmUga2V5cHJlc3MgZXZlbnRzIGV2ZW4gd2hlbiBubyBjaGFyYWN0ZXJcbiAgICAgICAgICAgKiB3aWxsIGJlIGluc2VydGVkLiBBIGZldyBwb3NzaWJpbGl0aWVzOlxuICAgICAgICAgICAqXG4gICAgICAgICAgICogLSBgd2hpY2hgIGlzIGAwYC4gQXJyb3cga2V5cywgRXNjIGtleSwgZXRjLlxuICAgICAgICAgICAqXG4gICAgICAgICAgICogLSBgd2hpY2hgIGlzIHRoZSBwcmVzc2VkIGtleSBjb2RlLCBidXQgbm8gY2hhciBpcyBhdmFpbGFibGUuXG4gICAgICAgICAgICogICBFeDogJ0FsdEdyICsgZGAgaW4gUG9saXNoLiBUaGVyZSBpcyBubyBtb2RpZmllZCBjaGFyYWN0ZXIgZm9yXG4gICAgICAgICAgICogICB0aGlzIGtleSBjb21iaW5hdGlvbiBhbmQgbm8gY2hhcmFjdGVyIGlzIGluc2VydGVkIGludG8gdGhlXG4gICAgICAgICAgICogICBkb2N1bWVudCwgYnV0IEZGIGZpcmVzIHRoZSBrZXlwcmVzcyBmb3IgY2hhciBjb2RlIGAxMDBgIGFueXdheS5cbiAgICAgICAgICAgKiAgIE5vIGBpbnB1dGAgZXZlbnQgd2lsbCBvY2N1ci5cbiAgICAgICAgICAgKlxuICAgICAgICAgICAqIC0gYHdoaWNoYCBpcyB0aGUgcHJlc3NlZCBrZXkgY29kZSwgYnV0IGEgY29tbWFuZCBjb21iaW5hdGlvbiBpc1xuICAgICAgICAgICAqICAgYmVpbmcgdXNlZC4gRXg6IGBDbWQrQ2AuIE5vIGNoYXJhY3RlciBpcyBpbnNlcnRlZCwgYW5kIG5vXG4gICAgICAgICAgICogICBgaW5wdXRgIGV2ZW50IHdpbGwgb2NjdXIuXG4gICAgICAgICAgICovXG4gICAgICAgICAgaWYgKG5hdGl2ZUV2ZW50LndoaWNoICYmICFpc0tleXByZXNzQ29tbWFuZChuYXRpdmVFdmVudCkpIHtcbiAgICAgICAgICAgIGZhbGxiYWNrQ2hhcnMgPSBTdHJpbmcuZnJvbUNoYXJDb2RlKG5hdGl2ZUV2ZW50LndoaWNoKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BDb21wb3NpdGlvbkVuZDpcbiAgICAgICAgICBmYWxsYmFja0NoYXJzID0gbmF0aXZlRXZlbnQuZGF0YTtcbiAgICAgICAgICBicmVhaztcbiAgICAgIH1cblxuICAgICAgLy8gSWYgbm8gY2hhbmdlcyBoYXZlIG9jY3VycmVkIHRvIHRoZSBmYWxsYmFjayBzdHJpbmcsIG5vIHJlbGV2YW50XG4gICAgICAvLyBldmVudCBoYXMgZmlyZWQgYW5kIHdlJ3JlIGRvbmUuXG4gICAgICBpZiAoZmFsbGJhY2tDaGFycyA9PT0gbnVsbCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNoYXJzID0gZmFsbGJhY2tDaGFycztcbiAgICB9XG5cbiAgICAvLyBJZiBubyBjaGFyYWN0ZXJzIGFyZSBiZWluZyBpbnNlcnRlZCwgbm8gQmVmb3JlSW5wdXQgZXZlbnQgc2hvdWxkXG4gICAgLy8gYmUgZmlyZWQuXG4gICAgaWYgKCFjaGFycykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHZhciBldmVudCA9IFN5bnRoZXRpY0lucHV0RXZlbnQuZ2V0UG9vbGVkKFxuICAgICAgZXZlbnRUeXBlcy5iZWZvcmVJbnB1dCxcbiAgICAgIHRvcExldmVsVGFyZ2V0SUQsXG4gICAgICBuYXRpdmVFdmVudFxuICAgICk7XG5cbiAgICBldmVudC5kYXRhID0gY2hhcnM7XG4gICAgZmFsbGJhY2tDaGFycyA9IG51bGw7XG4gICAgRXZlbnRQcm9wYWdhdG9ycy5hY2N1bXVsYXRlVHdvUGhhc2VEaXNwYXRjaGVzKGV2ZW50KTtcbiAgICByZXR1cm4gZXZlbnQ7XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gQmVmb3JlSW5wdXRFdmVudFBsdWdpbjtcbiIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgQ1NTQ29yZVxuICogQHR5cGVjaGVja3NcbiAqL1xuXG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG4vKipcbiAqIFRoZSBDU1NDb3JlIG1vZHVsZSBzcGVjaWZpZXMgdGhlIEFQSSAoYW5kIGltcGxlbWVudHMgbW9zdCBvZiB0aGUgbWV0aG9kcylcbiAqIHRoYXQgc2hvdWxkIGJlIHVzZWQgd2hlbiBkZWFsaW5nIHdpdGggdGhlIGRpc3BsYXkgb2YgZWxlbWVudHMgKHZpYSB0aGVpclxuICogQ1NTIGNsYXNzZXMgYW5kIHZpc2liaWxpdHkgb24gc2NyZWVuLiBJdCBpcyBhbiBBUEkgZm9jdXNlZCBvbiBtdXRhdGluZyB0aGVcbiAqIGRpc3BsYXkgYW5kIG5vdCByZWFkaW5nIGl0IGFzIG5vIGxvZ2ljYWwgc3RhdGUgc2hvdWxkIGJlIGVuY29kZWQgaW4gdGhlXG4gKiBkaXNwbGF5IG9mIGVsZW1lbnRzLlxuICovXG5cbnZhciBDU1NDb3JlID0ge1xuXG4gIC8qKlxuICAgKiBBZGRzIHRoZSBjbGFzcyBwYXNzZWQgaW4gdG8gdGhlIGVsZW1lbnQgaWYgaXQgZG9lc24ndCBhbHJlYWR5IGhhdmUgaXQuXG4gICAqXG4gICAqIEBwYXJhbSB7RE9NRWxlbWVudH0gZWxlbWVudCB0aGUgZWxlbWVudCB0byBzZXQgdGhlIGNsYXNzIG9uXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjbGFzc05hbWUgdGhlIENTUyBjbGFzc05hbWVcbiAgICogQHJldHVybiB7RE9NRWxlbWVudH0gdGhlIGVsZW1lbnQgcGFzc2VkIGluXG4gICAqL1xuICBhZGRDbGFzczogZnVuY3Rpb24oZWxlbWVudCwgY2xhc3NOYW1lKSB7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICEvXFxzLy50ZXN0KGNsYXNzTmFtZSksXG4gICAgICAnQ1NTQ29yZS5hZGRDbGFzcyB0YWtlcyBvbmx5IGEgc2luZ2xlIGNsYXNzIG5hbWUuIFwiJXNcIiBjb250YWlucyAnICtcbiAgICAgICdtdWx0aXBsZSBjbGFzc2VzLicsIGNsYXNzTmFtZVxuICAgICkgOiBpbnZhcmlhbnQoIS9cXHMvLnRlc3QoY2xhc3NOYW1lKSkpO1xuXG4gICAgaWYgKGNsYXNzTmFtZSkge1xuICAgICAgaWYgKGVsZW1lbnQuY2xhc3NMaXN0KSB7XG4gICAgICAgIGVsZW1lbnQuY2xhc3NMaXN0LmFkZChjbGFzc05hbWUpO1xuICAgICAgfSBlbHNlIGlmICghQ1NTQ29yZS5oYXNDbGFzcyhlbGVtZW50LCBjbGFzc05hbWUpKSB7XG4gICAgICAgIGVsZW1lbnQuY2xhc3NOYW1lID0gZWxlbWVudC5jbGFzc05hbWUgKyAnICcgKyBjbGFzc05hbWU7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBlbGVtZW50O1xuICB9LFxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIHRoZSBjbGFzcyBwYXNzZWQgaW4gZnJvbSB0aGUgZWxlbWVudFxuICAgKlxuICAgKiBAcGFyYW0ge0RPTUVsZW1lbnR9IGVsZW1lbnQgdGhlIGVsZW1lbnQgdG8gc2V0IHRoZSBjbGFzcyBvblxuICAgKiBAcGFyYW0ge3N0cmluZ30gY2xhc3NOYW1lIHRoZSBDU1MgY2xhc3NOYW1lXG4gICAqIEByZXR1cm4ge0RPTUVsZW1lbnR9IHRoZSBlbGVtZW50IHBhc3NlZCBpblxuICAgKi9cbiAgcmVtb3ZlQ2xhc3M6IGZ1bmN0aW9uKGVsZW1lbnQsIGNsYXNzTmFtZSkge1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAhL1xccy8udGVzdChjbGFzc05hbWUpLFxuICAgICAgJ0NTU0NvcmUucmVtb3ZlQ2xhc3MgdGFrZXMgb25seSBhIHNpbmdsZSBjbGFzcyBuYW1lLiBcIiVzXCIgY29udGFpbnMgJyArXG4gICAgICAnbXVsdGlwbGUgY2xhc3Nlcy4nLCBjbGFzc05hbWVcbiAgICApIDogaW52YXJpYW50KCEvXFxzLy50ZXN0KGNsYXNzTmFtZSkpKTtcblxuICAgIGlmIChjbGFzc05hbWUpIHtcbiAgICAgIGlmIChlbGVtZW50LmNsYXNzTGlzdCkge1xuICAgICAgICBlbGVtZW50LmNsYXNzTGlzdC5yZW1vdmUoY2xhc3NOYW1lKTtcbiAgICAgIH0gZWxzZSBpZiAoQ1NTQ29yZS5oYXNDbGFzcyhlbGVtZW50LCBjbGFzc05hbWUpKSB7XG4gICAgICAgIGVsZW1lbnQuY2xhc3NOYW1lID0gZWxlbWVudC5jbGFzc05hbWVcbiAgICAgICAgICAucmVwbGFjZShuZXcgUmVnRXhwKCcoXnxcXFxccyknICsgY2xhc3NOYW1lICsgJyg/OlxcXFxzfCQpJywgJ2cnKSwgJyQxJylcbiAgICAgICAgICAucmVwbGFjZSgvXFxzKy9nLCAnICcpIC8vIG11bHRpcGxlIHNwYWNlcyB0byBvbmVcbiAgICAgICAgICAucmVwbGFjZSgvXlxccyp8XFxzKiQvZywgJycpOyAvLyB0cmltIHRoZSBlbmRzXG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBlbGVtZW50O1xuICB9LFxuXG4gIC8qKlxuICAgKiBIZWxwZXIgdG8gYWRkIG9yIHJlbW92ZSBhIGNsYXNzIGZyb20gYW4gZWxlbWVudCBiYXNlZCBvbiBhIGNvbmRpdGlvbi5cbiAgICpcbiAgICogQHBhcmFtIHtET01FbGVtZW50fSBlbGVtZW50IHRoZSBlbGVtZW50IHRvIHNldCB0aGUgY2xhc3Mgb25cbiAgICogQHBhcmFtIHtzdHJpbmd9IGNsYXNzTmFtZSB0aGUgQ1NTIGNsYXNzTmFtZVxuICAgKiBAcGFyYW0geyp9IGJvb2wgY29uZGl0aW9uIHRvIHdoZXRoZXIgdG8gYWRkIG9yIHJlbW92ZSB0aGUgY2xhc3NcbiAgICogQHJldHVybiB7RE9NRWxlbWVudH0gdGhlIGVsZW1lbnQgcGFzc2VkIGluXG4gICAqL1xuICBjb25kaXRpb25DbGFzczogZnVuY3Rpb24oZWxlbWVudCwgY2xhc3NOYW1lLCBib29sKSB7XG4gICAgcmV0dXJuIChib29sID8gQ1NTQ29yZS5hZGRDbGFzcyA6IENTU0NvcmUucmVtb3ZlQ2xhc3MpKGVsZW1lbnQsIGNsYXNzTmFtZSk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFRlc3RzIHdoZXRoZXIgdGhlIGVsZW1lbnQgaGFzIHRoZSBjbGFzcyBzcGVjaWZpZWQuXG4gICAqXG4gICAqIEBwYXJhbSB7RE9NTm9kZXxET01XaW5kb3d9IGVsZW1lbnQgdGhlIGVsZW1lbnQgdG8gc2V0IHRoZSBjbGFzcyBvblxuICAgKiBAcGFyYW0ge3N0cmluZ30gY2xhc3NOYW1lIHRoZSBDU1MgY2xhc3NOYW1lXG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IHRydWUgaWYgdGhlIGVsZW1lbnQgaGFzIHRoZSBjbGFzcywgZmFsc2UgaWYgbm90XG4gICAqL1xuICBoYXNDbGFzczogZnVuY3Rpb24oZWxlbWVudCwgY2xhc3NOYW1lKSB7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICEvXFxzLy50ZXN0KGNsYXNzTmFtZSksXG4gICAgICAnQ1NTLmhhc0NsYXNzIHRha2VzIG9ubHkgYSBzaW5nbGUgY2xhc3MgbmFtZS4nXG4gICAgKSA6IGludmFyaWFudCghL1xccy8udGVzdChjbGFzc05hbWUpKSk7XG4gICAgaWYgKGVsZW1lbnQuY2xhc3NMaXN0KSB7XG4gICAgICByZXR1cm4gISFjbGFzc05hbWUgJiYgZWxlbWVudC5jbGFzc0xpc3QuY29udGFpbnMoY2xhc3NOYW1lKTtcbiAgICB9XG4gICAgcmV0dXJuICgnICcgKyBlbGVtZW50LmNsYXNzTmFtZSArICcgJykuaW5kZXhPZignICcgKyBjbGFzc05hbWUgKyAnICcpID4gLTE7XG4gIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBDU1NDb3JlO1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgQ1NTUHJvcGVydHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxuLyoqXG4gKiBDU1MgcHJvcGVydGllcyB3aGljaCBhY2NlcHQgbnVtYmVycyBidXQgYXJlIG5vdCBpbiB1bml0cyBvZiBcInB4XCIuXG4gKi9cbnZhciBpc1VuaXRsZXNzTnVtYmVyID0ge1xuICBjb2x1bW5Db3VudDogdHJ1ZSxcbiAgZmxleDogdHJ1ZSxcbiAgZmxleEdyb3c6IHRydWUsXG4gIGZsZXhTaHJpbms6IHRydWUsXG4gIGZvbnRXZWlnaHQ6IHRydWUsXG4gIGxpbmVDbGFtcDogdHJ1ZSxcbiAgbGluZUhlaWdodDogdHJ1ZSxcbiAgb3BhY2l0eTogdHJ1ZSxcbiAgb3JkZXI6IHRydWUsXG4gIG9ycGhhbnM6IHRydWUsXG4gIHdpZG93czogdHJ1ZSxcbiAgekluZGV4OiB0cnVlLFxuICB6b29tOiB0cnVlLFxuXG4gIC8vIFNWRy1yZWxhdGVkIHByb3BlcnRpZXNcbiAgZmlsbE9wYWNpdHk6IHRydWUsXG4gIHN0cm9rZU9wYWNpdHk6IHRydWVcbn07XG5cbi8qKlxuICogQHBhcmFtIHtzdHJpbmd9IHByZWZpeCB2ZW5kb3Itc3BlY2lmaWMgcHJlZml4LCBlZzogV2Via2l0XG4gKiBAcGFyYW0ge3N0cmluZ30ga2V5IHN0eWxlIG5hbWUsIGVnOiB0cmFuc2l0aW9uRHVyYXRpb25cbiAqIEByZXR1cm4ge3N0cmluZ30gc3R5bGUgbmFtZSBwcmVmaXhlZCB3aXRoIGBwcmVmaXhgLCBwcm9wZXJseSBjYW1lbENhc2VkLCBlZzpcbiAqIFdlYmtpdFRyYW5zaXRpb25EdXJhdGlvblxuICovXG5mdW5jdGlvbiBwcmVmaXhLZXkocHJlZml4LCBrZXkpIHtcbiAgcmV0dXJuIHByZWZpeCArIGtleS5jaGFyQXQoMCkudG9VcHBlckNhc2UoKSArIGtleS5zdWJzdHJpbmcoMSk7XG59XG5cbi8qKlxuICogU3VwcG9ydCBzdHlsZSBuYW1lcyB0aGF0IG1heSBjb21lIHBhc3NlZCBpbiBwcmVmaXhlZCBieSBhZGRpbmcgcGVybXV0YXRpb25zXG4gKiBvZiB2ZW5kb3IgcHJlZml4ZXMuXG4gKi9cbnZhciBwcmVmaXhlcyA9IFsnV2Via2l0JywgJ21zJywgJ01veicsICdPJ107XG5cbi8vIFVzaW5nIE9iamVjdC5rZXlzIGhlcmUsIG9yIGVsc2UgdGhlIHZhbmlsbGEgZm9yLWluIGxvb3AgbWFrZXMgSUU4IGdvIGludG8gYW5cbi8vIGluZmluaXRlIGxvb3AsIGJlY2F1c2UgaXQgaXRlcmF0ZXMgb3ZlciB0aGUgbmV3bHkgYWRkZWQgcHJvcHMgdG9vLlxuT2JqZWN0LmtleXMoaXNVbml0bGVzc051bWJlcikuZm9yRWFjaChmdW5jdGlvbihwcm9wKSB7XG4gIHByZWZpeGVzLmZvckVhY2goZnVuY3Rpb24ocHJlZml4KSB7XG4gICAgaXNVbml0bGVzc051bWJlcltwcmVmaXhLZXkocHJlZml4LCBwcm9wKV0gPSBpc1VuaXRsZXNzTnVtYmVyW3Byb3BdO1xuICB9KTtcbn0pO1xuXG4vKipcbiAqIE1vc3Qgc3R5bGUgcHJvcGVydGllcyBjYW4gYmUgdW5zZXQgYnkgZG9pbmcgLnN0eWxlW3Byb3BdID0gJycgYnV0IElFOFxuICogZG9lc24ndCBsaWtlIGRvaW5nIHRoYXQgd2l0aCBzaG9ydGhhbmQgcHJvcGVydGllcyBzbyBmb3IgdGhlIHByb3BlcnRpZXMgdGhhdFxuICogSUU4IGJyZWFrcyBvbiwgd2hpY2ggYXJlIGxpc3RlZCBoZXJlLCB3ZSBpbnN0ZWFkIHVuc2V0IGVhY2ggb2YgdGhlXG4gKiBpbmRpdmlkdWFsIHByb3BlcnRpZXMuIFNlZSBodHRwOi8vYnVncy5qcXVlcnkuY29tL3RpY2tldC8xMjM4NS5cbiAqIFRoZSA0LXZhbHVlICdjbG9jaycgcHJvcGVydGllcyBsaWtlIG1hcmdpbiwgcGFkZGluZywgYm9yZGVyLXdpZHRoIHNlZW0gdG9cbiAqIGJlaGF2ZSB3aXRob3V0IGFueSBwcm9ibGVtcy4gQ3VyaW91c2x5LCBsaXN0LXN0eWxlIHdvcmtzIHRvbyB3aXRob3V0IGFueVxuICogc3BlY2lhbCBwcm9kZGluZy5cbiAqL1xudmFyIHNob3J0aGFuZFByb3BlcnR5RXhwYW5zaW9ucyA9IHtcbiAgYmFja2dyb3VuZDoge1xuICAgIGJhY2tncm91bmRJbWFnZTogdHJ1ZSxcbiAgICBiYWNrZ3JvdW5kUG9zaXRpb246IHRydWUsXG4gICAgYmFja2dyb3VuZFJlcGVhdDogdHJ1ZSxcbiAgICBiYWNrZ3JvdW5kQ29sb3I6IHRydWVcbiAgfSxcbiAgYm9yZGVyOiB7XG4gICAgYm9yZGVyV2lkdGg6IHRydWUsXG4gICAgYm9yZGVyU3R5bGU6IHRydWUsXG4gICAgYm9yZGVyQ29sb3I6IHRydWVcbiAgfSxcbiAgYm9yZGVyQm90dG9tOiB7XG4gICAgYm9yZGVyQm90dG9tV2lkdGg6IHRydWUsXG4gICAgYm9yZGVyQm90dG9tU3R5bGU6IHRydWUsXG4gICAgYm9yZGVyQm90dG9tQ29sb3I6IHRydWVcbiAgfSxcbiAgYm9yZGVyTGVmdDoge1xuICAgIGJvcmRlckxlZnRXaWR0aDogdHJ1ZSxcbiAgICBib3JkZXJMZWZ0U3R5bGU6IHRydWUsXG4gICAgYm9yZGVyTGVmdENvbG9yOiB0cnVlXG4gIH0sXG4gIGJvcmRlclJpZ2h0OiB7XG4gICAgYm9yZGVyUmlnaHRXaWR0aDogdHJ1ZSxcbiAgICBib3JkZXJSaWdodFN0eWxlOiB0cnVlLFxuICAgIGJvcmRlclJpZ2h0Q29sb3I6IHRydWVcbiAgfSxcbiAgYm9yZGVyVG9wOiB7XG4gICAgYm9yZGVyVG9wV2lkdGg6IHRydWUsXG4gICAgYm9yZGVyVG9wU3R5bGU6IHRydWUsXG4gICAgYm9yZGVyVG9wQ29sb3I6IHRydWVcbiAgfSxcbiAgZm9udDoge1xuICAgIGZvbnRTdHlsZTogdHJ1ZSxcbiAgICBmb250VmFyaWFudDogdHJ1ZSxcbiAgICBmb250V2VpZ2h0OiB0cnVlLFxuICAgIGZvbnRTaXplOiB0cnVlLFxuICAgIGxpbmVIZWlnaHQ6IHRydWUsXG4gICAgZm9udEZhbWlseTogdHJ1ZVxuICB9XG59O1xuXG52YXIgQ1NTUHJvcGVydHkgPSB7XG4gIGlzVW5pdGxlc3NOdW1iZXI6IGlzVW5pdGxlc3NOdW1iZXIsXG4gIHNob3J0aGFuZFByb3BlcnR5RXhwYW5zaW9uczogc2hvcnRoYW5kUHJvcGVydHlFeHBhbnNpb25zXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IENTU1Byb3BlcnR5O1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBDU1NQcm9wZXJ0eU9wZXJhdGlvbnNcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBDU1NQcm9wZXJ0eSA9IHJlcXVpcmUoXCIuL0NTU1Byb3BlcnR5XCIpO1xudmFyIEV4ZWN1dGlvbkVudmlyb25tZW50ID0gcmVxdWlyZShcIi4vRXhlY3V0aW9uRW52aXJvbm1lbnRcIik7XG5cbnZhciBjYW1lbGl6ZVN0eWxlTmFtZSA9IHJlcXVpcmUoXCIuL2NhbWVsaXplU3R5bGVOYW1lXCIpO1xudmFyIGRhbmdlcm91c1N0eWxlVmFsdWUgPSByZXF1aXJlKFwiLi9kYW5nZXJvdXNTdHlsZVZhbHVlXCIpO1xudmFyIGh5cGhlbmF0ZVN0eWxlTmFtZSA9IHJlcXVpcmUoXCIuL2h5cGhlbmF0ZVN0eWxlTmFtZVwiKTtcbnZhciBtZW1vaXplU3RyaW5nT25seSA9IHJlcXVpcmUoXCIuL21lbW9pemVTdHJpbmdPbmx5XCIpO1xudmFyIHdhcm5pbmcgPSByZXF1aXJlKFwiLi93YXJuaW5nXCIpO1xuXG52YXIgcHJvY2Vzc1N0eWxlTmFtZSA9IG1lbW9pemVTdHJpbmdPbmx5KGZ1bmN0aW9uKHN0eWxlTmFtZSkge1xuICByZXR1cm4gaHlwaGVuYXRlU3R5bGVOYW1lKHN0eWxlTmFtZSk7XG59KTtcblxudmFyIHN0eWxlRmxvYXRBY2Nlc3NvciA9ICdjc3NGbG9hdCc7XG5pZiAoRXhlY3V0aW9uRW52aXJvbm1lbnQuY2FuVXNlRE9NKSB7XG4gIC8vIElFOCBvbmx5IHN1cHBvcnRzIGFjY2Vzc2luZyBjc3NGbG9hdCAoc3RhbmRhcmQpIGFzIHN0eWxlRmxvYXRcbiAgaWYgKGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zdHlsZS5jc3NGbG9hdCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgc3R5bGVGbG9hdEFjY2Vzc29yID0gJ3N0eWxlRmxvYXQnO1xuICB9XG59XG5cbmlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgdmFyIHdhcm5lZFN0eWxlTmFtZXMgPSB7fTtcblxuICB2YXIgd2Fybkh5cGhlbmF0ZWRTdHlsZU5hbWUgPSBmdW5jdGlvbihuYW1lKSB7XG4gICAgaWYgKHdhcm5lZFN0eWxlTmFtZXMuaGFzT3duUHJvcGVydHkobmFtZSkgJiYgd2FybmVkU3R5bGVOYW1lc1tuYW1lXSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHdhcm5lZFN0eWxlTmFtZXNbbmFtZV0gPSB0cnVlO1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyB3YXJuaW5nKFxuICAgICAgZmFsc2UsXG4gICAgICAnVW5zdXBwb3J0ZWQgc3R5bGUgcHJvcGVydHkgJyArIG5hbWUgKyAnLiBEaWQgeW91IG1lYW4gJyArXG4gICAgICBjYW1lbGl6ZVN0eWxlTmFtZShuYW1lKSArICc/J1xuICAgICkgOiBudWxsKTtcbiAgfTtcbn1cblxuLyoqXG4gKiBPcGVyYXRpb25zIGZvciBkZWFsaW5nIHdpdGggQ1NTIHByb3BlcnRpZXMuXG4gKi9cbnZhciBDU1NQcm9wZXJ0eU9wZXJhdGlvbnMgPSB7XG5cbiAgLyoqXG4gICAqIFNlcmlhbGl6ZXMgYSBtYXBwaW5nIG9mIHN0eWxlIHByb3BlcnRpZXMgZm9yIHVzZSBhcyBpbmxpbmUgc3R5bGVzOlxuICAgKlxuICAgKiAgID4gY3JlYXRlTWFya3VwRm9yU3R5bGVzKHt3aWR0aDogJzIwMHB4JywgaGVpZ2h0OiAwfSlcbiAgICogICBcIndpZHRoOjIwMHB4O2hlaWdodDowO1wiXG4gICAqXG4gICAqIFVuZGVmaW5lZCB2YWx1ZXMgYXJlIGlnbm9yZWQgc28gdGhhdCBkZWNsYXJhdGl2ZSBwcm9ncmFtbWluZyBpcyBlYXNpZXIuXG4gICAqIFRoZSByZXN1bHQgc2hvdWxkIGJlIEhUTUwtZXNjYXBlZCBiZWZvcmUgaW5zZXJ0aW9uIGludG8gdGhlIERPTS5cbiAgICpcbiAgICogQHBhcmFtIHtvYmplY3R9IHN0eWxlc1xuICAgKiBAcmV0dXJuIHs/c3RyaW5nfVxuICAgKi9cbiAgY3JlYXRlTWFya3VwRm9yU3R5bGVzOiBmdW5jdGlvbihzdHlsZXMpIHtcbiAgICB2YXIgc2VyaWFsaXplZCA9ICcnO1xuICAgIGZvciAodmFyIHN0eWxlTmFtZSBpbiBzdHlsZXMpIHtcbiAgICAgIGlmICghc3R5bGVzLmhhc093blByb3BlcnR5KHN0eWxlTmFtZSkpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgICAgIGlmIChzdHlsZU5hbWUuaW5kZXhPZignLScpID4gLTEpIHtcbiAgICAgICAgICB3YXJuSHlwaGVuYXRlZFN0eWxlTmFtZShzdHlsZU5hbWUpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICB2YXIgc3R5bGVWYWx1ZSA9IHN0eWxlc1tzdHlsZU5hbWVdO1xuICAgICAgaWYgKHN0eWxlVmFsdWUgIT0gbnVsbCkge1xuICAgICAgICBzZXJpYWxpemVkICs9IHByb2Nlc3NTdHlsZU5hbWUoc3R5bGVOYW1lKSArICc6JztcbiAgICAgICAgc2VyaWFsaXplZCArPSBkYW5nZXJvdXNTdHlsZVZhbHVlKHN0eWxlTmFtZSwgc3R5bGVWYWx1ZSkgKyAnOyc7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBzZXJpYWxpemVkIHx8IG51bGw7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFNldHMgdGhlIHZhbHVlIGZvciBtdWx0aXBsZSBzdHlsZXMgb24gYSBub2RlLiAgSWYgYSB2YWx1ZSBpcyBzcGVjaWZpZWQgYXNcbiAgICogJycgKGVtcHR5IHN0cmluZyksIHRoZSBjb3JyZXNwb25kaW5nIHN0eWxlIHByb3BlcnR5IHdpbGwgYmUgdW5zZXQuXG4gICAqXG4gICAqIEBwYXJhbSB7RE9NRWxlbWVudH0gbm9kZVxuICAgKiBAcGFyYW0ge29iamVjdH0gc3R5bGVzXG4gICAqL1xuICBzZXRWYWx1ZUZvclN0eWxlczogZnVuY3Rpb24obm9kZSwgc3R5bGVzKSB7XG4gICAgdmFyIHN0eWxlID0gbm9kZS5zdHlsZTtcbiAgICBmb3IgKHZhciBzdHlsZU5hbWUgaW4gc3R5bGVzKSB7XG4gICAgICBpZiAoIXN0eWxlcy5oYXNPd25Qcm9wZXJ0eShzdHlsZU5hbWUpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgICBpZiAoc3R5bGVOYW1lLmluZGV4T2YoJy0nKSA+IC0xKSB7XG4gICAgICAgICAgd2Fybkh5cGhlbmF0ZWRTdHlsZU5hbWUoc3R5bGVOYW1lKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgdmFyIHN0eWxlVmFsdWUgPSBkYW5nZXJvdXNTdHlsZVZhbHVlKHN0eWxlTmFtZSwgc3R5bGVzW3N0eWxlTmFtZV0pO1xuICAgICAgaWYgKHN0eWxlTmFtZSA9PT0gJ2Zsb2F0Jykge1xuICAgICAgICBzdHlsZU5hbWUgPSBzdHlsZUZsb2F0QWNjZXNzb3I7XG4gICAgICB9XG4gICAgICBpZiAoc3R5bGVWYWx1ZSkge1xuICAgICAgICBzdHlsZVtzdHlsZU5hbWVdID0gc3R5bGVWYWx1ZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciBleHBhbnNpb24gPSBDU1NQcm9wZXJ0eS5zaG9ydGhhbmRQcm9wZXJ0eUV4cGFuc2lvbnNbc3R5bGVOYW1lXTtcbiAgICAgICAgaWYgKGV4cGFuc2lvbikge1xuICAgICAgICAgIC8vIFNob3J0aGFuZCBwcm9wZXJ0eSB0aGF0IElFOCB3b24ndCBsaWtlIHVuc2V0dGluZywgc28gdW5zZXQgZWFjaFxuICAgICAgICAgIC8vIGNvbXBvbmVudCB0byBwbGFjYXRlIGl0XG4gICAgICAgICAgZm9yICh2YXIgaW5kaXZpZHVhbFN0eWxlTmFtZSBpbiBleHBhbnNpb24pIHtcbiAgICAgICAgICAgIHN0eWxlW2luZGl2aWR1YWxTdHlsZU5hbWVdID0gJyc7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHN0eWxlW3N0eWxlTmFtZV0gPSAnJztcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IENTU1Byb3BlcnR5T3BlcmF0aW9ucztcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBDYWxsYmFja1F1ZXVlXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBQb29sZWRDbGFzcyA9IHJlcXVpcmUoXCIuL1Bvb2xlZENsYXNzXCIpO1xuXG52YXIgYXNzaWduID0gcmVxdWlyZShcIi4vT2JqZWN0LmFzc2lnblwiKTtcbnZhciBpbnZhcmlhbnQgPSByZXF1aXJlKFwiLi9pbnZhcmlhbnRcIik7XG5cbi8qKlxuICogQSBzcGVjaWFsaXplZCBwc2V1ZG8tZXZlbnQgbW9kdWxlIHRvIGhlbHAga2VlcCB0cmFjayBvZiBjb21wb25lbnRzIHdhaXRpbmcgdG9cbiAqIGJlIG5vdGlmaWVkIHdoZW4gdGhlaXIgRE9NIHJlcHJlc2VudGF0aW9ucyBhcmUgYXZhaWxhYmxlIGZvciB1c2UuXG4gKlxuICogVGhpcyBpbXBsZW1lbnRzIGBQb29sZWRDbGFzc2AsIHNvIHlvdSBzaG91bGQgbmV2ZXIgbmVlZCB0byBpbnN0YW50aWF0ZSB0aGlzLlxuICogSW5zdGVhZCwgdXNlIGBDYWxsYmFja1F1ZXVlLmdldFBvb2xlZCgpYC5cbiAqXG4gKiBAY2xhc3MgUmVhY3RNb3VudFJlYWR5XG4gKiBAaW1wbGVtZW50cyBQb29sZWRDbGFzc1xuICogQGludGVybmFsXG4gKi9cbmZ1bmN0aW9uIENhbGxiYWNrUXVldWUoKSB7XG4gIHRoaXMuX2NhbGxiYWNrcyA9IG51bGw7XG4gIHRoaXMuX2NvbnRleHRzID0gbnVsbDtcbn1cblxuYXNzaWduKENhbGxiYWNrUXVldWUucHJvdG90eXBlLCB7XG5cbiAgLyoqXG4gICAqIEVucXVldWVzIGEgY2FsbGJhY2sgdG8gYmUgaW52b2tlZCB3aGVuIGBub3RpZnlBbGxgIGlzIGludm9rZWQuXG4gICAqXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IGNhbGxiYWNrIEludm9rZWQgd2hlbiBgbm90aWZ5QWxsYCBpcyBpbnZva2VkLlxuICAgKiBAcGFyYW0gez9vYmplY3R9IGNvbnRleHQgQ29udGV4dCB0byBjYWxsIGBjYWxsYmFja2Agd2l0aC5cbiAgICogQGludGVybmFsXG4gICAqL1xuICBlbnF1ZXVlOiBmdW5jdGlvbihjYWxsYmFjaywgY29udGV4dCkge1xuICAgIHRoaXMuX2NhbGxiYWNrcyA9IHRoaXMuX2NhbGxiYWNrcyB8fCBbXTtcbiAgICB0aGlzLl9jb250ZXh0cyA9IHRoaXMuX2NvbnRleHRzIHx8IFtdO1xuICAgIHRoaXMuX2NhbGxiYWNrcy5wdXNoKGNhbGxiYWNrKTtcbiAgICB0aGlzLl9jb250ZXh0cy5wdXNoKGNvbnRleHQpO1xuICB9LFxuXG4gIC8qKlxuICAgKiBJbnZva2VzIGFsbCBlbnF1ZXVlZCBjYWxsYmFja3MgYW5kIGNsZWFycyB0aGUgcXVldWUuIFRoaXMgaXMgaW52b2tlZCBhZnRlclxuICAgKiB0aGUgRE9NIHJlcHJlc2VudGF0aW9uIG9mIGEgY29tcG9uZW50IGhhcyBiZWVuIGNyZWF0ZWQgb3IgdXBkYXRlZC5cbiAgICpcbiAgICogQGludGVybmFsXG4gICAqL1xuICBub3RpZnlBbGw6IGZ1bmN0aW9uKCkge1xuICAgIHZhciBjYWxsYmFja3MgPSB0aGlzLl9jYWxsYmFja3M7XG4gICAgdmFyIGNvbnRleHRzID0gdGhpcy5fY29udGV4dHM7XG4gICAgaWYgKGNhbGxiYWNrcykge1xuICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgY2FsbGJhY2tzLmxlbmd0aCA9PT0gY29udGV4dHMubGVuZ3RoLFxuICAgICAgICBcIk1pc21hdGNoZWQgbGlzdCBvZiBjb250ZXh0cyBpbiBjYWxsYmFjayBxdWV1ZVwiXG4gICAgICApIDogaW52YXJpYW50KGNhbGxiYWNrcy5sZW5ndGggPT09IGNvbnRleHRzLmxlbmd0aCkpO1xuICAgICAgdGhpcy5fY2FsbGJhY2tzID0gbnVsbDtcbiAgICAgIHRoaXMuX2NvbnRleHRzID0gbnVsbDtcbiAgICAgIGZvciAodmFyIGkgPSAwLCBsID0gY2FsbGJhY2tzLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgICAgICBjYWxsYmFja3NbaV0uY2FsbChjb250ZXh0c1tpXSk7XG4gICAgICB9XG4gICAgICBjYWxsYmFja3MubGVuZ3RoID0gMDtcbiAgICAgIGNvbnRleHRzLmxlbmd0aCA9IDA7XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBSZXNldHMgdGhlIGludGVybmFsIHF1ZXVlLlxuICAgKlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHJlc2V0OiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLl9jYWxsYmFja3MgPSBudWxsO1xuICAgIHRoaXMuX2NvbnRleHRzID0gbnVsbDtcbiAgfSxcblxuICAvKipcbiAgICogYFBvb2xlZENsYXNzYCBsb29rcyBmb3IgdGhpcy5cbiAgICovXG4gIGRlc3RydWN0b3I6IGZ1bmN0aW9uKCkge1xuICAgIHRoaXMucmVzZXQoKTtcbiAgfVxuXG59KTtcblxuUG9vbGVkQ2xhc3MuYWRkUG9vbGluZ1RvKENhbGxiYWNrUXVldWUpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IENhbGxiYWNrUXVldWU7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBDaGFuZ2VFdmVudFBsdWdpblxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgRXZlbnRDb25zdGFudHMgPSByZXF1aXJlKFwiLi9FdmVudENvbnN0YW50c1wiKTtcbnZhciBFdmVudFBsdWdpbkh1YiA9IHJlcXVpcmUoXCIuL0V2ZW50UGx1Z2luSHViXCIpO1xudmFyIEV2ZW50UHJvcGFnYXRvcnMgPSByZXF1aXJlKFwiLi9FdmVudFByb3BhZ2F0b3JzXCIpO1xudmFyIEV4ZWN1dGlvbkVudmlyb25tZW50ID0gcmVxdWlyZShcIi4vRXhlY3V0aW9uRW52aXJvbm1lbnRcIik7XG52YXIgUmVhY3RVcGRhdGVzID0gcmVxdWlyZShcIi4vUmVhY3RVcGRhdGVzXCIpO1xudmFyIFN5bnRoZXRpY0V2ZW50ID0gcmVxdWlyZShcIi4vU3ludGhldGljRXZlbnRcIik7XG5cbnZhciBpc0V2ZW50U3VwcG9ydGVkID0gcmVxdWlyZShcIi4vaXNFdmVudFN1cHBvcnRlZFwiKTtcbnZhciBpc1RleHRJbnB1dEVsZW1lbnQgPSByZXF1aXJlKFwiLi9pc1RleHRJbnB1dEVsZW1lbnRcIik7XG52YXIga2V5T2YgPSByZXF1aXJlKFwiLi9rZXlPZlwiKTtcblxudmFyIHRvcExldmVsVHlwZXMgPSBFdmVudENvbnN0YW50cy50b3BMZXZlbFR5cGVzO1xuXG52YXIgZXZlbnRUeXBlcyA9IHtcbiAgY2hhbmdlOiB7XG4gICAgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXM6IHtcbiAgICAgIGJ1YmJsZWQ6IGtleU9mKHtvbkNoYW5nZTogbnVsbH0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbkNoYW5nZUNhcHR1cmU6IG51bGx9KVxuICAgIH0sXG4gICAgZGVwZW5kZW5jaWVzOiBbXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcEJsdXIsXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcENoYW5nZSxcbiAgICAgIHRvcExldmVsVHlwZXMudG9wQ2xpY2ssXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcEZvY3VzLFxuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BJbnB1dCxcbiAgICAgIHRvcExldmVsVHlwZXMudG9wS2V5RG93bixcbiAgICAgIHRvcExldmVsVHlwZXMudG9wS2V5VXAsXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcFNlbGVjdGlvbkNoYW5nZVxuICAgIF1cbiAgfVxufTtcblxuLyoqXG4gKiBGb3IgSUUgc2hpbXNcbiAqL1xudmFyIGFjdGl2ZUVsZW1lbnQgPSBudWxsO1xudmFyIGFjdGl2ZUVsZW1lbnRJRCA9IG51bGw7XG52YXIgYWN0aXZlRWxlbWVudFZhbHVlID0gbnVsbDtcbnZhciBhY3RpdmVFbGVtZW50VmFsdWVQcm9wID0gbnVsbDtcblxuLyoqXG4gKiBTRUNUSU9OOiBoYW5kbGUgYGNoYW5nZWAgZXZlbnRcbiAqL1xuZnVuY3Rpb24gc2hvdWxkVXNlQ2hhbmdlRXZlbnQoZWxlbSkge1xuICByZXR1cm4gKFxuICAgIGVsZW0ubm9kZU5hbWUgPT09ICdTRUxFQ1QnIHx8XG4gICAgKGVsZW0ubm9kZU5hbWUgPT09ICdJTlBVVCcgJiYgZWxlbS50eXBlID09PSAnZmlsZScpXG4gICk7XG59XG5cbnZhciBkb2VzQ2hhbmdlRXZlbnRCdWJibGUgPSBmYWxzZTtcbmlmIChFeGVjdXRpb25FbnZpcm9ubWVudC5jYW5Vc2VET00pIHtcbiAgLy8gU2VlIGBoYW5kbGVDaGFuZ2VgIGNvbW1lbnQgYmVsb3dcbiAgZG9lc0NoYW5nZUV2ZW50QnViYmxlID0gaXNFdmVudFN1cHBvcnRlZCgnY2hhbmdlJykgJiYgKFxuICAgICEoJ2RvY3VtZW50TW9kZScgaW4gZG9jdW1lbnQpIHx8IGRvY3VtZW50LmRvY3VtZW50TW9kZSA+IDhcbiAgKTtcbn1cblxuZnVuY3Rpb24gbWFudWFsRGlzcGF0Y2hDaGFuZ2VFdmVudChuYXRpdmVFdmVudCkge1xuICB2YXIgZXZlbnQgPSBTeW50aGV0aWNFdmVudC5nZXRQb29sZWQoXG4gICAgZXZlbnRUeXBlcy5jaGFuZ2UsXG4gICAgYWN0aXZlRWxlbWVudElELFxuICAgIG5hdGl2ZUV2ZW50XG4gICk7XG4gIEV2ZW50UHJvcGFnYXRvcnMuYWNjdW11bGF0ZVR3b1BoYXNlRGlzcGF0Y2hlcyhldmVudCk7XG5cbiAgLy8gSWYgY2hhbmdlIGFuZCBwcm9wZXJ0eWNoYW5nZSBidWJibGVkLCB3ZSdkIGp1c3QgYmluZCB0byBpdCBsaWtlIGFsbCB0aGVcbiAgLy8gb3RoZXIgZXZlbnRzIGFuZCBoYXZlIGl0IGdvIHRocm91Z2ggUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLiBTaW5jZSBpdFxuICAvLyBkb2Vzbid0LCB3ZSBtYW51YWxseSBsaXN0ZW4gZm9yIHRoZSBldmVudHMgYW5kIHNvIHdlIGhhdmUgdG8gZW5xdWV1ZSBhbmRcbiAgLy8gcHJvY2VzcyB0aGUgYWJzdHJhY3QgZXZlbnQgbWFudWFsbHkuXG4gIC8vXG4gIC8vIEJhdGNoaW5nIGlzIG5lY2Vzc2FyeSBoZXJlIGluIG9yZGVyIHRvIGVuc3VyZSB0aGF0IGFsbCBldmVudCBoYW5kbGVycyBydW5cbiAgLy8gYmVmb3JlIHRoZSBuZXh0IHJlcmVuZGVyIChpbmNsdWRpbmcgZXZlbnQgaGFuZGxlcnMgYXR0YWNoZWQgdG8gYW5jZXN0b3JcbiAgLy8gZWxlbWVudHMgaW5zdGVhZCBvZiBkaXJlY3RseSBvbiB0aGUgaW5wdXQpLiBXaXRob3V0IHRoaXMsIGNvbnRyb2xsZWRcbiAgLy8gY29tcG9uZW50cyBkb24ndCB3b3JrIHByb3Blcmx5IGluIGNvbmp1bmN0aW9uIHdpdGggZXZlbnQgYnViYmxpbmcgYmVjYXVzZVxuICAvLyB0aGUgY29tcG9uZW50IGlzIHJlcmVuZGVyZWQgYW5kIHRoZSB2YWx1ZSByZXZlcnRlZCBiZWZvcmUgYWxsIHRoZSBldmVudFxuICAvLyBoYW5kbGVycyBjYW4gcnVuLiBTZWUgaHR0cHM6Ly9naXRodWIuY29tL2ZhY2Vib29rL3JlYWN0L2lzc3Vlcy83MDguXG4gIFJlYWN0VXBkYXRlcy5iYXRjaGVkVXBkYXRlcyhydW5FdmVudEluQmF0Y2gsIGV2ZW50KTtcbn1cblxuZnVuY3Rpb24gcnVuRXZlbnRJbkJhdGNoKGV2ZW50KSB7XG4gIEV2ZW50UGx1Z2luSHViLmVucXVldWVFdmVudHMoZXZlbnQpO1xuICBFdmVudFBsdWdpbkh1Yi5wcm9jZXNzRXZlbnRRdWV1ZSgpO1xufVxuXG5mdW5jdGlvbiBzdGFydFdhdGNoaW5nRm9yQ2hhbmdlRXZlbnRJRTgodGFyZ2V0LCB0YXJnZXRJRCkge1xuICBhY3RpdmVFbGVtZW50ID0gdGFyZ2V0O1xuICBhY3RpdmVFbGVtZW50SUQgPSB0YXJnZXRJRDtcbiAgYWN0aXZlRWxlbWVudC5hdHRhY2hFdmVudCgnb25jaGFuZ2UnLCBtYW51YWxEaXNwYXRjaENoYW5nZUV2ZW50KTtcbn1cblxuZnVuY3Rpb24gc3RvcFdhdGNoaW5nRm9yQ2hhbmdlRXZlbnRJRTgoKSB7XG4gIGlmICghYWN0aXZlRWxlbWVudCkge1xuICAgIHJldHVybjtcbiAgfVxuICBhY3RpdmVFbGVtZW50LmRldGFjaEV2ZW50KCdvbmNoYW5nZScsIG1hbnVhbERpc3BhdGNoQ2hhbmdlRXZlbnQpO1xuICBhY3RpdmVFbGVtZW50ID0gbnVsbDtcbiAgYWN0aXZlRWxlbWVudElEID0gbnVsbDtcbn1cblxuZnVuY3Rpb24gZ2V0VGFyZ2V0SURGb3JDaGFuZ2VFdmVudChcbiAgICB0b3BMZXZlbFR5cGUsXG4gICAgdG9wTGV2ZWxUYXJnZXQsXG4gICAgdG9wTGV2ZWxUYXJnZXRJRCkge1xuICBpZiAodG9wTGV2ZWxUeXBlID09PSB0b3BMZXZlbFR5cGVzLnRvcENoYW5nZSkge1xuICAgIHJldHVybiB0b3BMZXZlbFRhcmdldElEO1xuICB9XG59XG5mdW5jdGlvbiBoYW5kbGVFdmVudHNGb3JDaGFuZ2VFdmVudElFOChcbiAgICB0b3BMZXZlbFR5cGUsXG4gICAgdG9wTGV2ZWxUYXJnZXQsXG4gICAgdG9wTGV2ZWxUYXJnZXRJRCkge1xuICBpZiAodG9wTGV2ZWxUeXBlID09PSB0b3BMZXZlbFR5cGVzLnRvcEZvY3VzKSB7XG4gICAgLy8gc3RvcFdhdGNoaW5nKCkgc2hvdWxkIGJlIGEgbm9vcCBoZXJlIGJ1dCB3ZSBjYWxsIGl0IGp1c3QgaW4gY2FzZSB3ZVxuICAgIC8vIG1pc3NlZCBhIGJsdXIgZXZlbnQgc29tZWhvdy5cbiAgICBzdG9wV2F0Y2hpbmdGb3JDaGFuZ2VFdmVudElFOCgpO1xuICAgIHN0YXJ0V2F0Y2hpbmdGb3JDaGFuZ2VFdmVudElFOCh0b3BMZXZlbFRhcmdldCwgdG9wTGV2ZWxUYXJnZXRJRCk7XG4gIH0gZWxzZSBpZiAodG9wTGV2ZWxUeXBlID09PSB0b3BMZXZlbFR5cGVzLnRvcEJsdXIpIHtcbiAgICBzdG9wV2F0Y2hpbmdGb3JDaGFuZ2VFdmVudElFOCgpO1xuICB9XG59XG5cblxuLyoqXG4gKiBTRUNUSU9OOiBoYW5kbGUgYGlucHV0YCBldmVudFxuICovXG52YXIgaXNJbnB1dEV2ZW50U3VwcG9ydGVkID0gZmFsc2U7XG5pZiAoRXhlY3V0aW9uRW52aXJvbm1lbnQuY2FuVXNlRE9NKSB7XG4gIC8vIElFOSBjbGFpbXMgdG8gc3VwcG9ydCB0aGUgaW5wdXQgZXZlbnQgYnV0IGZhaWxzIHRvIHRyaWdnZXIgaXQgd2hlblxuICAvLyBkZWxldGluZyB0ZXh0LCBzbyB3ZSBpZ25vcmUgaXRzIGlucHV0IGV2ZW50c1xuICBpc0lucHV0RXZlbnRTdXBwb3J0ZWQgPSBpc0V2ZW50U3VwcG9ydGVkKCdpbnB1dCcpICYmIChcbiAgICAhKCdkb2N1bWVudE1vZGUnIGluIGRvY3VtZW50KSB8fCBkb2N1bWVudC5kb2N1bWVudE1vZGUgPiA5XG4gICk7XG59XG5cbi8qKlxuICogKEZvciBvbGQgSUUuKSBSZXBsYWNlbWVudCBnZXR0ZXIvc2V0dGVyIGZvciB0aGUgYHZhbHVlYCBwcm9wZXJ0eSB0aGF0IGdldHNcbiAqIHNldCBvbiB0aGUgYWN0aXZlIGVsZW1lbnQuXG4gKi9cbnZhciBuZXdWYWx1ZVByb3AgPSAge1xuICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiBhY3RpdmVFbGVtZW50VmFsdWVQcm9wLmdldC5jYWxsKHRoaXMpO1xuICB9LFxuICBzZXQ6IGZ1bmN0aW9uKHZhbCkge1xuICAgIC8vIENhc3QgdG8gYSBzdHJpbmcgc28gd2UgY2FuIGRvIGVxdWFsaXR5IGNoZWNrcy5cbiAgICBhY3RpdmVFbGVtZW50VmFsdWUgPSAnJyArIHZhbDtcbiAgICBhY3RpdmVFbGVtZW50VmFsdWVQcm9wLnNldC5jYWxsKHRoaXMsIHZhbCk7XG4gIH1cbn07XG5cbi8qKlxuICogKEZvciBvbGQgSUUuKSBTdGFydHMgdHJhY2tpbmcgcHJvcGVydHljaGFuZ2UgZXZlbnRzIG9uIHRoZSBwYXNzZWQtaW4gZWxlbWVudFxuICogYW5kIG92ZXJyaWRlIHRoZSB2YWx1ZSBwcm9wZXJ0eSBzbyB0aGF0IHdlIGNhbiBkaXN0aW5ndWlzaCB1c2VyIGV2ZW50cyBmcm9tXG4gKiB2YWx1ZSBjaGFuZ2VzIGluIEpTLlxuICovXG5mdW5jdGlvbiBzdGFydFdhdGNoaW5nRm9yVmFsdWVDaGFuZ2UodGFyZ2V0LCB0YXJnZXRJRCkge1xuICBhY3RpdmVFbGVtZW50ID0gdGFyZ2V0O1xuICBhY3RpdmVFbGVtZW50SUQgPSB0YXJnZXRJRDtcbiAgYWN0aXZlRWxlbWVudFZhbHVlID0gdGFyZ2V0LnZhbHVlO1xuICBhY3RpdmVFbGVtZW50VmFsdWVQcm9wID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihcbiAgICB0YXJnZXQuY29uc3RydWN0b3IucHJvdG90eXBlLFxuICAgICd2YWx1ZSdcbiAgKTtcblxuICBPYmplY3QuZGVmaW5lUHJvcGVydHkoYWN0aXZlRWxlbWVudCwgJ3ZhbHVlJywgbmV3VmFsdWVQcm9wKTtcbiAgYWN0aXZlRWxlbWVudC5hdHRhY2hFdmVudCgnb25wcm9wZXJ0eWNoYW5nZScsIGhhbmRsZVByb3BlcnR5Q2hhbmdlKTtcbn1cblxuLyoqXG4gKiAoRm9yIG9sZCBJRS4pIFJlbW92ZXMgdGhlIGV2ZW50IGxpc3RlbmVycyBmcm9tIHRoZSBjdXJyZW50bHktdHJhY2tlZCBlbGVtZW50LFxuICogaWYgYW55IGV4aXN0cy5cbiAqL1xuZnVuY3Rpb24gc3RvcFdhdGNoaW5nRm9yVmFsdWVDaGFuZ2UoKSB7XG4gIGlmICghYWN0aXZlRWxlbWVudCkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIGRlbGV0ZSByZXN0b3JlcyB0aGUgb3JpZ2luYWwgcHJvcGVydHkgZGVmaW5pdGlvblxuICBkZWxldGUgYWN0aXZlRWxlbWVudC52YWx1ZTtcbiAgYWN0aXZlRWxlbWVudC5kZXRhY2hFdmVudCgnb25wcm9wZXJ0eWNoYW5nZScsIGhhbmRsZVByb3BlcnR5Q2hhbmdlKTtcblxuICBhY3RpdmVFbGVtZW50ID0gbnVsbDtcbiAgYWN0aXZlRWxlbWVudElEID0gbnVsbDtcbiAgYWN0aXZlRWxlbWVudFZhbHVlID0gbnVsbDtcbiAgYWN0aXZlRWxlbWVudFZhbHVlUHJvcCA9IG51bGw7XG59XG5cbi8qKlxuICogKEZvciBvbGQgSUUuKSBIYW5kbGVzIGEgcHJvcGVydHljaGFuZ2UgZXZlbnQsIHNlbmRpbmcgYSBgY2hhbmdlYCBldmVudCBpZlxuICogdGhlIHZhbHVlIG9mIHRoZSBhY3RpdmUgZWxlbWVudCBoYXMgY2hhbmdlZC5cbiAqL1xuZnVuY3Rpb24gaGFuZGxlUHJvcGVydHlDaGFuZ2UobmF0aXZlRXZlbnQpIHtcbiAgaWYgKG5hdGl2ZUV2ZW50LnByb3BlcnR5TmFtZSAhPT0gJ3ZhbHVlJykge1xuICAgIHJldHVybjtcbiAgfVxuICB2YXIgdmFsdWUgPSBuYXRpdmVFdmVudC5zcmNFbGVtZW50LnZhbHVlO1xuICBpZiAodmFsdWUgPT09IGFjdGl2ZUVsZW1lbnRWYWx1ZSkge1xuICAgIHJldHVybjtcbiAgfVxuICBhY3RpdmVFbGVtZW50VmFsdWUgPSB2YWx1ZTtcblxuICBtYW51YWxEaXNwYXRjaENoYW5nZUV2ZW50KG5hdGl2ZUV2ZW50KTtcbn1cblxuLyoqXG4gKiBJZiBhIGBjaGFuZ2VgIGV2ZW50IHNob3VsZCBiZSBmaXJlZCwgcmV0dXJucyB0aGUgdGFyZ2V0J3MgSUQuXG4gKi9cbmZ1bmN0aW9uIGdldFRhcmdldElERm9ySW5wdXRFdmVudChcbiAgICB0b3BMZXZlbFR5cGUsXG4gICAgdG9wTGV2ZWxUYXJnZXQsXG4gICAgdG9wTGV2ZWxUYXJnZXRJRCkge1xuICBpZiAodG9wTGV2ZWxUeXBlID09PSB0b3BMZXZlbFR5cGVzLnRvcElucHV0KSB7XG4gICAgLy8gSW4gbW9kZXJuIGJyb3dzZXJzIChpLmUuLCBub3QgSUU4IG9yIElFOSksIHRoZSBpbnB1dCBldmVudCBpcyBleGFjdGx5XG4gICAgLy8gd2hhdCB3ZSB3YW50IHNvIGZhbGwgdGhyb3VnaCBoZXJlIGFuZCB0cmlnZ2VyIGFuIGFic3RyYWN0IGV2ZW50XG4gICAgcmV0dXJuIHRvcExldmVsVGFyZ2V0SUQ7XG4gIH1cbn1cblxuLy8gRm9yIElFOCBhbmQgSUU5LlxuZnVuY3Rpb24gaGFuZGxlRXZlbnRzRm9ySW5wdXRFdmVudElFKFxuICAgIHRvcExldmVsVHlwZSxcbiAgICB0b3BMZXZlbFRhcmdldCxcbiAgICB0b3BMZXZlbFRhcmdldElEKSB7XG4gIGlmICh0b3BMZXZlbFR5cGUgPT09IHRvcExldmVsVHlwZXMudG9wRm9jdXMpIHtcbiAgICAvLyBJbiBJRTgsIHdlIGNhbiBjYXB0dXJlIGFsbW9zdCBhbGwgLnZhbHVlIGNoYW5nZXMgYnkgYWRkaW5nIGFcbiAgICAvLyBwcm9wZXJ0eWNoYW5nZSBoYW5kbGVyIGFuZCBsb29raW5nIGZvciBldmVudHMgd2l0aCBwcm9wZXJ0eU5hbWVcbiAgICAvLyBlcXVhbCB0byAndmFsdWUnXG4gICAgLy8gSW4gSUU5LCBwcm9wZXJ0eWNoYW5nZSBmaXJlcyBmb3IgbW9zdCBpbnB1dCBldmVudHMgYnV0IGlzIGJ1Z2d5IGFuZFxuICAgIC8vIGRvZXNuJ3QgZmlyZSB3aGVuIHRleHQgaXMgZGVsZXRlZCwgYnV0IGNvbnZlbmllbnRseSwgc2VsZWN0aW9uY2hhbmdlXG4gICAgLy8gYXBwZWFycyB0byBmaXJlIGluIGFsbCBvZiB0aGUgcmVtYWluaW5nIGNhc2VzIHNvIHdlIGNhdGNoIHRob3NlIGFuZFxuICAgIC8vIGZvcndhcmQgdGhlIGV2ZW50IGlmIHRoZSB2YWx1ZSBoYXMgY2hhbmdlZFxuICAgIC8vIEluIGVpdGhlciBjYXNlLCB3ZSBkb24ndCB3YW50IHRvIGNhbGwgdGhlIGV2ZW50IGhhbmRsZXIgaWYgdGhlIHZhbHVlXG4gICAgLy8gaXMgY2hhbmdlZCBmcm9tIEpTIHNvIHdlIHJlZGVmaW5lIGEgc2V0dGVyIGZvciBgLnZhbHVlYCB0aGF0IHVwZGF0ZXNcbiAgICAvLyBvdXIgYWN0aXZlRWxlbWVudFZhbHVlIHZhcmlhYmxlLCBhbGxvd2luZyB1cyB0byBpZ25vcmUgdGhvc2UgY2hhbmdlc1xuICAgIC8vXG4gICAgLy8gc3RvcFdhdGNoaW5nKCkgc2hvdWxkIGJlIGEgbm9vcCBoZXJlIGJ1dCB3ZSBjYWxsIGl0IGp1c3QgaW4gY2FzZSB3ZVxuICAgIC8vIG1pc3NlZCBhIGJsdXIgZXZlbnQgc29tZWhvdy5cbiAgICBzdG9wV2F0Y2hpbmdGb3JWYWx1ZUNoYW5nZSgpO1xuICAgIHN0YXJ0V2F0Y2hpbmdGb3JWYWx1ZUNoYW5nZSh0b3BMZXZlbFRhcmdldCwgdG9wTGV2ZWxUYXJnZXRJRCk7XG4gIH0gZWxzZSBpZiAodG9wTGV2ZWxUeXBlID09PSB0b3BMZXZlbFR5cGVzLnRvcEJsdXIpIHtcbiAgICBzdG9wV2F0Y2hpbmdGb3JWYWx1ZUNoYW5nZSgpO1xuICB9XG59XG5cbi8vIEZvciBJRTggYW5kIElFOS5cbmZ1bmN0aW9uIGdldFRhcmdldElERm9ySW5wdXRFdmVudElFKFxuICAgIHRvcExldmVsVHlwZSxcbiAgICB0b3BMZXZlbFRhcmdldCxcbiAgICB0b3BMZXZlbFRhcmdldElEKSB7XG4gIGlmICh0b3BMZXZlbFR5cGUgPT09IHRvcExldmVsVHlwZXMudG9wU2VsZWN0aW9uQ2hhbmdlIHx8XG4gICAgICB0b3BMZXZlbFR5cGUgPT09IHRvcExldmVsVHlwZXMudG9wS2V5VXAgfHxcbiAgICAgIHRvcExldmVsVHlwZSA9PT0gdG9wTGV2ZWxUeXBlcy50b3BLZXlEb3duKSB7XG4gICAgLy8gT24gdGhlIHNlbGVjdGlvbmNoYW5nZSBldmVudCwgdGhlIHRhcmdldCBpcyBqdXN0IGRvY3VtZW50IHdoaWNoIGlzbid0XG4gICAgLy8gaGVscGZ1bCBmb3IgdXMgc28ganVzdCBjaGVjayBhY3RpdmVFbGVtZW50IGluc3RlYWQuXG4gICAgLy9cbiAgICAvLyA5OSUgb2YgdGhlIHRpbWUsIGtleWRvd24gYW5kIGtleXVwIGFyZW4ndCBuZWNlc3NhcnkuIElFOCBmYWlscyB0byBmaXJlXG4gICAgLy8gcHJvcGVydHljaGFuZ2Ugb24gdGhlIGZpcnN0IGlucHV0IGV2ZW50IGFmdGVyIHNldHRpbmcgYHZhbHVlYCBmcm9tIGFcbiAgICAvLyBzY3JpcHQgYW5kIGZpcmVzIG9ubHkga2V5ZG93biwga2V5cHJlc3MsIGtleXVwLiBDYXRjaGluZyBrZXl1cCB1c3VhbGx5XG4gICAgLy8gZ2V0cyBpdCBhbmQgY2F0Y2hpbmcga2V5ZG93biBsZXRzIHVzIGZpcmUgYW4gZXZlbnQgZm9yIHRoZSBmaXJzdFxuICAgIC8vIGtleXN0cm9rZSBpZiB1c2VyIGRvZXMgYSBrZXkgcmVwZWF0IChpdCdsbCBiZSBhIGxpdHRsZSBkZWxheWVkOiByaWdodFxuICAgIC8vIGJlZm9yZSB0aGUgc2Vjb25kIGtleXN0cm9rZSkuIE90aGVyIGlucHV0IG1ldGhvZHMgKGUuZy4sIHBhc3RlKSBzZWVtIHRvXG4gICAgLy8gZmlyZSBzZWxlY3Rpb25jaGFuZ2Ugbm9ybWFsbHkuXG4gICAgaWYgKGFjdGl2ZUVsZW1lbnQgJiYgYWN0aXZlRWxlbWVudC52YWx1ZSAhPT0gYWN0aXZlRWxlbWVudFZhbHVlKSB7XG4gICAgICBhY3RpdmVFbGVtZW50VmFsdWUgPSBhY3RpdmVFbGVtZW50LnZhbHVlO1xuICAgICAgcmV0dXJuIGFjdGl2ZUVsZW1lbnRJRDtcbiAgICB9XG4gIH1cbn1cblxuXG4vKipcbiAqIFNFQ1RJT046IGhhbmRsZSBgY2xpY2tgIGV2ZW50XG4gKi9cbmZ1bmN0aW9uIHNob3VsZFVzZUNsaWNrRXZlbnQoZWxlbSkge1xuICAvLyBVc2UgdGhlIGBjbGlja2AgZXZlbnQgdG8gZGV0ZWN0IGNoYW5nZXMgdG8gY2hlY2tib3ggYW5kIHJhZGlvIGlucHV0cy5cbiAgLy8gVGhpcyBhcHByb2FjaCB3b3JrcyBhY3Jvc3MgYWxsIGJyb3dzZXJzLCB3aGVyZWFzIGBjaGFuZ2VgIGRvZXMgbm90IGZpcmVcbiAgLy8gdW50aWwgYGJsdXJgIGluIElFOC5cbiAgcmV0dXJuIChcbiAgICBlbGVtLm5vZGVOYW1lID09PSAnSU5QVVQnICYmXG4gICAgKGVsZW0udHlwZSA9PT0gJ2NoZWNrYm94JyB8fCBlbGVtLnR5cGUgPT09ICdyYWRpbycpXG4gICk7XG59XG5cbmZ1bmN0aW9uIGdldFRhcmdldElERm9yQ2xpY2tFdmVudChcbiAgICB0b3BMZXZlbFR5cGUsXG4gICAgdG9wTGV2ZWxUYXJnZXQsXG4gICAgdG9wTGV2ZWxUYXJnZXRJRCkge1xuICBpZiAodG9wTGV2ZWxUeXBlID09PSB0b3BMZXZlbFR5cGVzLnRvcENsaWNrKSB7XG4gICAgcmV0dXJuIHRvcExldmVsVGFyZ2V0SUQ7XG4gIH1cbn1cblxuLyoqXG4gKiBUaGlzIHBsdWdpbiBjcmVhdGVzIGFuIGBvbkNoYW5nZWAgZXZlbnQgdGhhdCBub3JtYWxpemVzIGNoYW5nZSBldmVudHNcbiAqIGFjcm9zcyBmb3JtIGVsZW1lbnRzLiBUaGlzIGV2ZW50IGZpcmVzIGF0IGEgdGltZSB3aGVuIGl0J3MgcG9zc2libGUgdG9cbiAqIGNoYW5nZSB0aGUgZWxlbWVudCdzIHZhbHVlIHdpdGhvdXQgc2VlaW5nIGEgZmxpY2tlci5cbiAqXG4gKiBTdXBwb3J0ZWQgZWxlbWVudHMgYXJlOlxuICogLSBpbnB1dCAoc2VlIGBpc1RleHRJbnB1dEVsZW1lbnRgKVxuICogLSB0ZXh0YXJlYVxuICogLSBzZWxlY3RcbiAqL1xudmFyIENoYW5nZUV2ZW50UGx1Z2luID0ge1xuXG4gIGV2ZW50VHlwZXM6IGV2ZW50VHlwZXMsXG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0b3BMZXZlbFR5cGUgUmVjb3JkIGZyb20gYEV2ZW50Q29uc3RhbnRzYC5cbiAgICogQHBhcmFtIHtET01FdmVudFRhcmdldH0gdG9wTGV2ZWxUYXJnZXQgVGhlIGxpc3RlbmluZyBjb21wb25lbnQgcm9vdCBub2RlLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gdG9wTGV2ZWxUYXJnZXRJRCBJRCBvZiBgdG9wTGV2ZWxUYXJnZXRgLlxuICAgKiBAcGFyYW0ge29iamVjdH0gbmF0aXZlRXZlbnQgTmF0aXZlIGJyb3dzZXIgZXZlbnQuXG4gICAqIEByZXR1cm4geyp9IEFuIGFjY3VtdWxhdGlvbiBvZiBzeW50aGV0aWMgZXZlbnRzLlxuICAgKiBAc2VlIHtFdmVudFBsdWdpbkh1Yi5leHRyYWN0RXZlbnRzfVxuICAgKi9cbiAgZXh0cmFjdEV2ZW50czogZnVuY3Rpb24oXG4gICAgICB0b3BMZXZlbFR5cGUsXG4gICAgICB0b3BMZXZlbFRhcmdldCxcbiAgICAgIHRvcExldmVsVGFyZ2V0SUQsXG4gICAgICBuYXRpdmVFdmVudCkge1xuXG4gICAgdmFyIGdldFRhcmdldElERnVuYywgaGFuZGxlRXZlbnRGdW5jO1xuICAgIGlmIChzaG91bGRVc2VDaGFuZ2VFdmVudCh0b3BMZXZlbFRhcmdldCkpIHtcbiAgICAgIGlmIChkb2VzQ2hhbmdlRXZlbnRCdWJibGUpIHtcbiAgICAgICAgZ2V0VGFyZ2V0SURGdW5jID0gZ2V0VGFyZ2V0SURGb3JDaGFuZ2VFdmVudDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGhhbmRsZUV2ZW50RnVuYyA9IGhhbmRsZUV2ZW50c0ZvckNoYW5nZUV2ZW50SUU4O1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoaXNUZXh0SW5wdXRFbGVtZW50KHRvcExldmVsVGFyZ2V0KSkge1xuICAgICAgaWYgKGlzSW5wdXRFdmVudFN1cHBvcnRlZCkge1xuICAgICAgICBnZXRUYXJnZXRJREZ1bmMgPSBnZXRUYXJnZXRJREZvcklucHV0RXZlbnQ7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBnZXRUYXJnZXRJREZ1bmMgPSBnZXRUYXJnZXRJREZvcklucHV0RXZlbnRJRTtcbiAgICAgICAgaGFuZGxlRXZlbnRGdW5jID0gaGFuZGxlRXZlbnRzRm9ySW5wdXRFdmVudElFO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoc2hvdWxkVXNlQ2xpY2tFdmVudCh0b3BMZXZlbFRhcmdldCkpIHtcbiAgICAgIGdldFRhcmdldElERnVuYyA9IGdldFRhcmdldElERm9yQ2xpY2tFdmVudDtcbiAgICB9XG5cbiAgICBpZiAoZ2V0VGFyZ2V0SURGdW5jKSB7XG4gICAgICB2YXIgdGFyZ2V0SUQgPSBnZXRUYXJnZXRJREZ1bmMoXG4gICAgICAgIHRvcExldmVsVHlwZSxcbiAgICAgICAgdG9wTGV2ZWxUYXJnZXQsXG4gICAgICAgIHRvcExldmVsVGFyZ2V0SURcbiAgICAgICk7XG4gICAgICBpZiAodGFyZ2V0SUQpIHtcbiAgICAgICAgdmFyIGV2ZW50ID0gU3ludGhldGljRXZlbnQuZ2V0UG9vbGVkKFxuICAgICAgICAgIGV2ZW50VHlwZXMuY2hhbmdlLFxuICAgICAgICAgIHRhcmdldElELFxuICAgICAgICAgIG5hdGl2ZUV2ZW50XG4gICAgICAgICk7XG4gICAgICAgIEV2ZW50UHJvcGFnYXRvcnMuYWNjdW11bGF0ZVR3b1BoYXNlRGlzcGF0Y2hlcyhldmVudCk7XG4gICAgICAgIHJldHVybiBldmVudDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoaGFuZGxlRXZlbnRGdW5jKSB7XG4gICAgICBoYW5kbGVFdmVudEZ1bmMoXG4gICAgICAgIHRvcExldmVsVHlwZSxcbiAgICAgICAgdG9wTGV2ZWxUYXJnZXQsXG4gICAgICAgIHRvcExldmVsVGFyZ2V0SURcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gQ2hhbmdlRXZlbnRQbHVnaW47XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgQ2xpZW50UmVhY3RSb290SW5kZXhcbiAqIEB0eXBlY2hlY2tzXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBuZXh0UmVhY3RSb290SW5kZXggPSAwO1xuXG52YXIgQ2xpZW50UmVhY3RSb290SW5kZXggPSB7XG4gIGNyZWF0ZVJlYWN0Um9vdEluZGV4OiBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gbmV4dFJlYWN0Um9vdEluZGV4Kys7XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gQ2xpZW50UmVhY3RSb290SW5kZXg7XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgQ29tcG9zaXRpb25FdmVudFBsdWdpblxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIEV2ZW50Q29uc3RhbnRzID0gcmVxdWlyZShcIi4vRXZlbnRDb25zdGFudHNcIik7XG52YXIgRXZlbnRQcm9wYWdhdG9ycyA9IHJlcXVpcmUoXCIuL0V2ZW50UHJvcGFnYXRvcnNcIik7XG52YXIgRXhlY3V0aW9uRW52aXJvbm1lbnQgPSByZXF1aXJlKFwiLi9FeGVjdXRpb25FbnZpcm9ubWVudFwiKTtcbnZhciBSZWFjdElucHV0U2VsZWN0aW9uID0gcmVxdWlyZShcIi4vUmVhY3RJbnB1dFNlbGVjdGlvblwiKTtcbnZhciBTeW50aGV0aWNDb21wb3NpdGlvbkV2ZW50ID0gcmVxdWlyZShcIi4vU3ludGhldGljQ29tcG9zaXRpb25FdmVudFwiKTtcblxudmFyIGdldFRleHRDb250ZW50QWNjZXNzb3IgPSByZXF1aXJlKFwiLi9nZXRUZXh0Q29udGVudEFjY2Vzc29yXCIpO1xudmFyIGtleU9mID0gcmVxdWlyZShcIi4va2V5T2ZcIik7XG5cbnZhciBFTkRfS0VZQ09ERVMgPSBbOSwgMTMsIDI3LCAzMl07IC8vIFRhYiwgUmV0dXJuLCBFc2MsIFNwYWNlXG52YXIgU1RBUlRfS0VZQ09ERSA9IDIyOTtcblxudmFyIHVzZUNvbXBvc2l0aW9uRXZlbnQgPSAoXG4gIEV4ZWN1dGlvbkVudmlyb25tZW50LmNhblVzZURPTSAmJlxuICAnQ29tcG9zaXRpb25FdmVudCcgaW4gd2luZG93XG4pO1xuXG4vLyBJbiBJRTkrLCB3ZSBoYXZlIGFjY2VzcyB0byBjb21wb3NpdGlvbiBldmVudHMsIGJ1dCB0aGUgZGF0YSBzdXBwbGllZFxuLy8gYnkgdGhlIG5hdGl2ZSBjb21wb3NpdGlvbmVuZCBldmVudCBtYXkgYmUgaW5jb3JyZWN0LiBJbiBLb3JlYW4sIGZvciBleGFtcGxlLFxuLy8gdGhlIGNvbXBvc2l0aW9uZW5kIGV2ZW50IGNvbnRhaW5zIG9ubHkgb25lIGNoYXJhY3RlciByZWdhcmRsZXNzIG9mXG4vLyBob3cgbWFueSBjaGFyYWN0ZXJzIGhhdmUgYmVlbiBjb21wb3NlZCBzaW5jZSBjb21wb3NpdGlvbnN0YXJ0LlxuLy8gV2UgdGhlcmVmb3JlIHVzZSB0aGUgZmFsbGJhY2sgZGF0YSB3aGlsZSBzdGlsbCB1c2luZyB0aGUgbmF0aXZlXG4vLyBldmVudHMgYXMgdHJpZ2dlcnMuXG52YXIgdXNlRmFsbGJhY2tEYXRhID0gKFxuICAhdXNlQ29tcG9zaXRpb25FdmVudCB8fFxuICAoXG4gICAgJ2RvY3VtZW50TW9kZScgaW4gZG9jdW1lbnQgJiZcbiAgICBkb2N1bWVudC5kb2N1bWVudE1vZGUgPiA4ICYmXG4gICAgZG9jdW1lbnQuZG9jdW1lbnRNb2RlIDw9IDExXG4gIClcbik7XG5cbnZhciB0b3BMZXZlbFR5cGVzID0gRXZlbnRDb25zdGFudHMudG9wTGV2ZWxUeXBlcztcbnZhciBjdXJyZW50Q29tcG9zaXRpb24gPSBudWxsO1xuXG4vLyBFdmVudHMgYW5kIHRoZWlyIGNvcnJlc3BvbmRpbmcgcHJvcGVydHkgbmFtZXMuXG52YXIgZXZlbnRUeXBlcyA9IHtcbiAgY29tcG9zaXRpb25FbmQ6IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uQ29tcG9zaXRpb25FbmQ6IG51bGx9KSxcbiAgICAgIGNhcHR1cmVkOiBrZXlPZih7b25Db21wb3NpdGlvbkVuZENhcHR1cmU6IG51bGx9KVxuICAgIH0sXG4gICAgZGVwZW5kZW5jaWVzOiBbXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcEJsdXIsXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcENvbXBvc2l0aW9uRW5kLFxuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BLZXlEb3duLFxuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BLZXlQcmVzcyxcbiAgICAgIHRvcExldmVsVHlwZXMudG9wS2V5VXAsXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcE1vdXNlRG93blxuICAgIF1cbiAgfSxcbiAgY29tcG9zaXRpb25TdGFydDoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25Db21wb3NpdGlvblN0YXJ0OiBudWxsfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uQ29tcG9zaXRpb25TdGFydENhcHR1cmU6IG51bGx9KVxuICAgIH0sXG4gICAgZGVwZW5kZW5jaWVzOiBbXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcEJsdXIsXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcENvbXBvc2l0aW9uU3RhcnQsXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcEtleURvd24sXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcEtleVByZXNzLFxuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BLZXlVcCxcbiAgICAgIHRvcExldmVsVHlwZXMudG9wTW91c2VEb3duXG4gICAgXVxuICB9LFxuICBjb21wb3NpdGlvblVwZGF0ZToge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25Db21wb3NpdGlvblVwZGF0ZTogbnVsbH0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbkNvbXBvc2l0aW9uVXBkYXRlQ2FwdHVyZTogbnVsbH0pXG4gICAgfSxcbiAgICBkZXBlbmRlbmNpZXM6IFtcbiAgICAgIHRvcExldmVsVHlwZXMudG9wQmx1cixcbiAgICAgIHRvcExldmVsVHlwZXMudG9wQ29tcG9zaXRpb25VcGRhdGUsXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcEtleURvd24sXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcEtleVByZXNzLFxuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BLZXlVcCxcbiAgICAgIHRvcExldmVsVHlwZXMudG9wTW91c2VEb3duXG4gICAgXVxuICB9XG59O1xuXG4vKipcbiAqIFRyYW5zbGF0ZSBuYXRpdmUgdG9wIGxldmVsIGV2ZW50cyBpbnRvIGV2ZW50IHR5cGVzLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB0b3BMZXZlbFR5cGVcbiAqIEByZXR1cm4ge29iamVjdH1cbiAqL1xuZnVuY3Rpb24gZ2V0Q29tcG9zaXRpb25FdmVudFR5cGUodG9wTGV2ZWxUeXBlKSB7XG4gIHN3aXRjaCAodG9wTGV2ZWxUeXBlKSB7XG4gICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcENvbXBvc2l0aW9uU3RhcnQ6XG4gICAgICByZXR1cm4gZXZlbnRUeXBlcy5jb21wb3NpdGlvblN0YXJ0O1xuICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BDb21wb3NpdGlvbkVuZDpcbiAgICAgIHJldHVybiBldmVudFR5cGVzLmNvbXBvc2l0aW9uRW5kO1xuICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BDb21wb3NpdGlvblVwZGF0ZTpcbiAgICAgIHJldHVybiBldmVudFR5cGVzLmNvbXBvc2l0aW9uVXBkYXRlO1xuICB9XG59XG5cbi8qKlxuICogRG9lcyBvdXIgZmFsbGJhY2sgYmVzdC1ndWVzcyBtb2RlbCB0aGluayB0aGlzIGV2ZW50IHNpZ25pZmllcyB0aGF0XG4gKiBjb21wb3NpdGlvbiBoYXMgYmVndW4/XG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHRvcExldmVsVHlwZVxuICogQHBhcmFtIHtvYmplY3R9IG5hdGl2ZUV2ZW50XG4gKiBAcmV0dXJuIHtib29sZWFufVxuICovXG5mdW5jdGlvbiBpc0ZhbGxiYWNrU3RhcnQodG9wTGV2ZWxUeXBlLCBuYXRpdmVFdmVudCkge1xuICByZXR1cm4gKFxuICAgIHRvcExldmVsVHlwZSA9PT0gdG9wTGV2ZWxUeXBlcy50b3BLZXlEb3duICYmXG4gICAgbmF0aXZlRXZlbnQua2V5Q29kZSA9PT0gU1RBUlRfS0VZQ09ERVxuICApO1xufVxuXG4vKipcbiAqIERvZXMgb3VyIGZhbGxiYWNrIG1vZGUgdGhpbmsgdGhhdCB0aGlzIGV2ZW50IGlzIHRoZSBlbmQgb2YgY29tcG9zaXRpb24/XG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHRvcExldmVsVHlwZVxuICogQHBhcmFtIHtvYmplY3R9IG5hdGl2ZUV2ZW50XG4gKiBAcmV0dXJuIHtib29sZWFufVxuICovXG5mdW5jdGlvbiBpc0ZhbGxiYWNrRW5kKHRvcExldmVsVHlwZSwgbmF0aXZlRXZlbnQpIHtcbiAgc3dpdGNoICh0b3BMZXZlbFR5cGUpIHtcbiAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wS2V5VXA6XG4gICAgICAvLyBDb21tYW5kIGtleXMgaW5zZXJ0IG9yIGNsZWFyIElNRSBpbnB1dC5cbiAgICAgIHJldHVybiAoRU5EX0tFWUNPREVTLmluZGV4T2YobmF0aXZlRXZlbnQua2V5Q29kZSkgIT09IC0xKTtcbiAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wS2V5RG93bjpcbiAgICAgIC8vIEV4cGVjdCBJTUUga2V5Q29kZSBvbiBlYWNoIGtleWRvd24uIElmIHdlIGdldCBhbnkgb3RoZXJcbiAgICAgIC8vIGNvZGUgd2UgbXVzdCBoYXZlIGV4aXRlZCBlYXJsaWVyLlxuICAgICAgcmV0dXJuIChuYXRpdmVFdmVudC5rZXlDb2RlICE9PSBTVEFSVF9LRVlDT0RFKTtcbiAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wS2V5UHJlc3M6XG4gICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcE1vdXNlRG93bjpcbiAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wQmx1cjpcbiAgICAgIC8vIEV2ZW50cyBhcmUgbm90IHBvc3NpYmxlIHdpdGhvdXQgY2FuY2VsbGluZyBJTUUuXG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIGZhbHNlO1xuICB9XG59XG5cbi8qKlxuICogSGVscGVyIGNsYXNzIHN0b3JlcyBpbmZvcm1hdGlvbiBhYm91dCBzZWxlY3Rpb24gYW5kIGRvY3VtZW50IHN0YXRlXG4gKiBzbyB3ZSBjYW4gZmlndXJlIG91dCB3aGF0IGNoYW5nZWQgYXQgYSBsYXRlciBkYXRlLlxuICpcbiAqIEBwYXJhbSB7RE9NRXZlbnRUYXJnZXR9IHJvb3RcbiAqL1xuZnVuY3Rpb24gRmFsbGJhY2tDb21wb3NpdGlvblN0YXRlKHJvb3QpIHtcbiAgdGhpcy5yb290ID0gcm9vdDtcbiAgdGhpcy5zdGFydFNlbGVjdGlvbiA9IFJlYWN0SW5wdXRTZWxlY3Rpb24uZ2V0U2VsZWN0aW9uKHJvb3QpO1xuICB0aGlzLnN0YXJ0VmFsdWUgPSB0aGlzLmdldFRleHQoKTtcbn1cblxuLyoqXG4gKiBHZXQgY3VycmVudCB0ZXh0IG9mIGlucHV0LlxuICpcbiAqIEByZXR1cm4ge3N0cmluZ31cbiAqL1xuRmFsbGJhY2tDb21wb3NpdGlvblN0YXRlLnByb3RvdHlwZS5nZXRUZXh0ID0gZnVuY3Rpb24oKSB7XG4gIHJldHVybiB0aGlzLnJvb3QudmFsdWUgfHwgdGhpcy5yb290W2dldFRleHRDb250ZW50QWNjZXNzb3IoKV07XG59O1xuXG4vKipcbiAqIFRleHQgdGhhdCBoYXMgY2hhbmdlZCBzaW5jZSB0aGUgc3RhcnQgb2YgY29tcG9zaXRpb24uXG4gKlxuICogQHJldHVybiB7c3RyaW5nfVxuICovXG5GYWxsYmFja0NvbXBvc2l0aW9uU3RhdGUucHJvdG90eXBlLmdldERhdGEgPSBmdW5jdGlvbigpIHtcbiAgdmFyIGVuZFZhbHVlID0gdGhpcy5nZXRUZXh0KCk7XG4gIHZhciBwcmVmaXhMZW5ndGggPSB0aGlzLnN0YXJ0U2VsZWN0aW9uLnN0YXJ0O1xuICB2YXIgc3VmZml4TGVuZ3RoID0gdGhpcy5zdGFydFZhbHVlLmxlbmd0aCAtIHRoaXMuc3RhcnRTZWxlY3Rpb24uZW5kO1xuXG4gIHJldHVybiBlbmRWYWx1ZS5zdWJzdHIoXG4gICAgcHJlZml4TGVuZ3RoLFxuICAgIGVuZFZhbHVlLmxlbmd0aCAtIHN1ZmZpeExlbmd0aCAtIHByZWZpeExlbmd0aFxuICApO1xufTtcblxuLyoqXG4gKiBUaGlzIHBsdWdpbiBjcmVhdGVzIGBvbkNvbXBvc2l0aW9uU3RhcnRgLCBgb25Db21wb3NpdGlvblVwZGF0ZWAgYW5kXG4gKiBgb25Db21wb3NpdGlvbkVuZGAgZXZlbnRzIG9uIGlucHV0cywgdGV4dGFyZWFzIGFuZCBjb250ZW50RWRpdGFibGVcbiAqIG5vZGVzLlxuICovXG52YXIgQ29tcG9zaXRpb25FdmVudFBsdWdpbiA9IHtcblxuICBldmVudFR5cGVzOiBldmVudFR5cGVzLFxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gdG9wTGV2ZWxUeXBlIFJlY29yZCBmcm9tIGBFdmVudENvbnN0YW50c2AuXG4gICAqIEBwYXJhbSB7RE9NRXZlbnRUYXJnZXR9IHRvcExldmVsVGFyZ2V0IFRoZSBsaXN0ZW5pbmcgY29tcG9uZW50IHJvb3Qgbm9kZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHRvcExldmVsVGFyZ2V0SUQgSUQgb2YgYHRvcExldmVsVGFyZ2V0YC5cbiAgICogQHBhcmFtIHtvYmplY3R9IG5hdGl2ZUV2ZW50IE5hdGl2ZSBicm93c2VyIGV2ZW50LlxuICAgKiBAcmV0dXJuIHsqfSBBbiBhY2N1bXVsYXRpb24gb2Ygc3ludGhldGljIGV2ZW50cy5cbiAgICogQHNlZSB7RXZlbnRQbHVnaW5IdWIuZXh0cmFjdEV2ZW50c31cbiAgICovXG4gIGV4dHJhY3RFdmVudHM6IGZ1bmN0aW9uKFxuICAgICAgdG9wTGV2ZWxUeXBlLFxuICAgICAgdG9wTGV2ZWxUYXJnZXQsXG4gICAgICB0b3BMZXZlbFRhcmdldElELFxuICAgICAgbmF0aXZlRXZlbnQpIHtcblxuICAgIHZhciBldmVudFR5cGU7XG4gICAgdmFyIGRhdGE7XG5cbiAgICBpZiAodXNlQ29tcG9zaXRpb25FdmVudCkge1xuICAgICAgZXZlbnRUeXBlID0gZ2V0Q29tcG9zaXRpb25FdmVudFR5cGUodG9wTGV2ZWxUeXBlKTtcbiAgICB9IGVsc2UgaWYgKCFjdXJyZW50Q29tcG9zaXRpb24pIHtcbiAgICAgIGlmIChpc0ZhbGxiYWNrU3RhcnQodG9wTGV2ZWxUeXBlLCBuYXRpdmVFdmVudCkpIHtcbiAgICAgICAgZXZlbnRUeXBlID0gZXZlbnRUeXBlcy5jb21wb3NpdGlvblN0YXJ0O1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoaXNGYWxsYmFja0VuZCh0b3BMZXZlbFR5cGUsIG5hdGl2ZUV2ZW50KSkge1xuICAgICAgZXZlbnRUeXBlID0gZXZlbnRUeXBlcy5jb21wb3NpdGlvbkVuZDtcbiAgICB9XG5cbiAgICBpZiAodXNlRmFsbGJhY2tEYXRhKSB7XG4gICAgICAvLyBUaGUgY3VycmVudCBjb21wb3NpdGlvbiBpcyBzdG9yZWQgc3RhdGljYWxseSBhbmQgbXVzdCBub3QgYmVcbiAgICAgIC8vIG92ZXJ3cml0dGVuIHdoaWxlIGNvbXBvc2l0aW9uIGNvbnRpbnVlcy5cbiAgICAgIGlmICghY3VycmVudENvbXBvc2l0aW9uICYmIGV2ZW50VHlwZSA9PT0gZXZlbnRUeXBlcy5jb21wb3NpdGlvblN0YXJ0KSB7XG4gICAgICAgIGN1cnJlbnRDb21wb3NpdGlvbiA9IG5ldyBGYWxsYmFja0NvbXBvc2l0aW9uU3RhdGUodG9wTGV2ZWxUYXJnZXQpO1xuICAgICAgfSBlbHNlIGlmIChldmVudFR5cGUgPT09IGV2ZW50VHlwZXMuY29tcG9zaXRpb25FbmQpIHtcbiAgICAgICAgaWYgKGN1cnJlbnRDb21wb3NpdGlvbikge1xuICAgICAgICAgIGRhdGEgPSBjdXJyZW50Q29tcG9zaXRpb24uZ2V0RGF0YSgpO1xuICAgICAgICAgIGN1cnJlbnRDb21wb3NpdGlvbiA9IG51bGw7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoZXZlbnRUeXBlKSB7XG4gICAgICB2YXIgZXZlbnQgPSBTeW50aGV0aWNDb21wb3NpdGlvbkV2ZW50LmdldFBvb2xlZChcbiAgICAgICAgZXZlbnRUeXBlLFxuICAgICAgICB0b3BMZXZlbFRhcmdldElELFxuICAgICAgICBuYXRpdmVFdmVudFxuICAgICAgKTtcbiAgICAgIGlmIChkYXRhKSB7XG4gICAgICAgIC8vIEluamVjdCBkYXRhIGdlbmVyYXRlZCBmcm9tIGZhbGxiYWNrIHBhdGggaW50byB0aGUgc3ludGhldGljIGV2ZW50LlxuICAgICAgICAvLyBUaGlzIG1hdGNoZXMgdGhlIHByb3BlcnR5IG9mIG5hdGl2ZSBDb21wb3NpdGlvbkV2ZW50SW50ZXJmYWNlLlxuICAgICAgICBldmVudC5kYXRhID0gZGF0YTtcbiAgICAgIH1cbiAgICAgIEV2ZW50UHJvcGFnYXRvcnMuYWNjdW11bGF0ZVR3b1BoYXNlRGlzcGF0Y2hlcyhldmVudCk7XG4gICAgICByZXR1cm4gZXZlbnQ7XG4gICAgfVxuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IENvbXBvc2l0aW9uRXZlbnRQbHVnaW47XG4iLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIERPTUNoaWxkcmVuT3BlcmF0aW9uc1xuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIERhbmdlciA9IHJlcXVpcmUoXCIuL0RhbmdlclwiKTtcbnZhciBSZWFjdE11bHRpQ2hpbGRVcGRhdGVUeXBlcyA9IHJlcXVpcmUoXCIuL1JlYWN0TXVsdGlDaGlsZFVwZGF0ZVR5cGVzXCIpO1xuXG52YXIgZ2V0VGV4dENvbnRlbnRBY2Nlc3NvciA9IHJlcXVpcmUoXCIuL2dldFRleHRDb250ZW50QWNjZXNzb3JcIik7XG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG4vKipcbiAqIFRoZSBET00gcHJvcGVydHkgdG8gdXNlIHdoZW4gc2V0dGluZyB0ZXh0IGNvbnRlbnQuXG4gKlxuICogQHR5cGUge3N0cmluZ31cbiAqIEBwcml2YXRlXG4gKi9cbnZhciB0ZXh0Q29udGVudEFjY2Vzc29yID0gZ2V0VGV4dENvbnRlbnRBY2Nlc3NvcigpO1xuXG4vKipcbiAqIEluc2VydHMgYGNoaWxkTm9kZWAgYXMgYSBjaGlsZCBvZiBgcGFyZW50Tm9kZWAgYXQgdGhlIGBpbmRleGAuXG4gKlxuICogQHBhcmFtIHtET01FbGVtZW50fSBwYXJlbnROb2RlIFBhcmVudCBub2RlIGluIHdoaWNoIHRvIGluc2VydC5cbiAqIEBwYXJhbSB7RE9NRWxlbWVudH0gY2hpbGROb2RlIENoaWxkIG5vZGUgdG8gaW5zZXJ0LlxuICogQHBhcmFtIHtudW1iZXJ9IGluZGV4IEluZGV4IGF0IHdoaWNoIHRvIGluc2VydCB0aGUgY2hpbGQuXG4gKiBAaW50ZXJuYWxcbiAqL1xuZnVuY3Rpb24gaW5zZXJ0Q2hpbGRBdChwYXJlbnROb2RlLCBjaGlsZE5vZGUsIGluZGV4KSB7XG4gIC8vIEJ5IGV4cGxvaXRpbmcgYXJyYXlzIHJldHVybmluZyBgdW5kZWZpbmVkYCBmb3IgYW4gdW5kZWZpbmVkIGluZGV4LCB3ZSBjYW5cbiAgLy8gcmVseSBleGNsdXNpdmVseSBvbiBgaW5zZXJ0QmVmb3JlKG5vZGUsIG51bGwpYCBpbnN0ZWFkIG9mIGFsc28gdXNpbmdcbiAgLy8gYGFwcGVuZENoaWxkKG5vZGUpYC4gSG93ZXZlciwgdXNpbmcgYHVuZGVmaW5lZGAgaXMgbm90IGFsbG93ZWQgYnkgYWxsXG4gIC8vIGJyb3dzZXJzIHNvIHdlIG11c3QgcmVwbGFjZSBpdCB3aXRoIGBudWxsYC5cbiAgcGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUoXG4gICAgY2hpbGROb2RlLFxuICAgIHBhcmVudE5vZGUuY2hpbGROb2Rlc1tpbmRleF0gfHwgbnVsbFxuICApO1xufVxuXG52YXIgdXBkYXRlVGV4dENvbnRlbnQ7XG5pZiAodGV4dENvbnRlbnRBY2Nlc3NvciA9PT0gJ3RleHRDb250ZW50Jykge1xuICAvKipcbiAgICogU2V0cyB0aGUgdGV4dCBjb250ZW50IG9mIGBub2RlYCB0byBgdGV4dGAuXG4gICAqXG4gICAqIEBwYXJhbSB7RE9NRWxlbWVudH0gbm9kZSBOb2RlIHRvIGNoYW5nZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGV4dCBOZXcgdGV4dCBjb250ZW50XG4gICAqL1xuICB1cGRhdGVUZXh0Q29udGVudCA9IGZ1bmN0aW9uKG5vZGUsIHRleHQpIHtcbiAgICBub2RlLnRleHRDb250ZW50ID0gdGV4dDtcbiAgfTtcbn0gZWxzZSB7XG4gIC8qKlxuICAgKiBTZXRzIHRoZSB0ZXh0IGNvbnRlbnQgb2YgYG5vZGVgIHRvIGB0ZXh0YC5cbiAgICpcbiAgICogQHBhcmFtIHtET01FbGVtZW50fSBub2RlIE5vZGUgdG8gY2hhbmdlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IE5ldyB0ZXh0IGNvbnRlbnRcbiAgICovXG4gIHVwZGF0ZVRleHRDb250ZW50ID0gZnVuY3Rpb24obm9kZSwgdGV4dCkge1xuICAgIC8vIEluIG9yZGVyIHRvIHByZXNlcnZlIG5ld2xpbmVzIGNvcnJlY3RseSwgd2UgY2FuJ3QgdXNlIC5pbm5lclRleHQgdG8gc2V0XG4gICAgLy8gdGhlIGNvbnRlbnRzIChzZWUgIzEwODApLCBzbyB3ZSBlbXB0eSB0aGUgZWxlbWVudCB0aGVuIGFwcGVuZCBhIHRleHQgbm9kZVxuICAgIHdoaWxlIChub2RlLmZpcnN0Q2hpbGQpIHtcbiAgICAgIG5vZGUucmVtb3ZlQ2hpbGQobm9kZS5maXJzdENoaWxkKTtcbiAgICB9XG4gICAgaWYgKHRleHQpIHtcbiAgICAgIHZhciBkb2MgPSBub2RlLm93bmVyRG9jdW1lbnQgfHwgZG9jdW1lbnQ7XG4gICAgICBub2RlLmFwcGVuZENoaWxkKGRvYy5jcmVhdGVUZXh0Tm9kZSh0ZXh0KSk7XG4gICAgfVxuICB9O1xufVxuXG4vKipcbiAqIE9wZXJhdGlvbnMgZm9yIHVwZGF0aW5nIHdpdGggRE9NIGNoaWxkcmVuLlxuICovXG52YXIgRE9NQ2hpbGRyZW5PcGVyYXRpb25zID0ge1xuXG4gIGRhbmdlcm91c2x5UmVwbGFjZU5vZGVXaXRoTWFya3VwOiBEYW5nZXIuZGFuZ2Vyb3VzbHlSZXBsYWNlTm9kZVdpdGhNYXJrdXAsXG5cbiAgdXBkYXRlVGV4dENvbnRlbnQ6IHVwZGF0ZVRleHRDb250ZW50LFxuXG4gIC8qKlxuICAgKiBVcGRhdGVzIGEgY29tcG9uZW50J3MgY2hpbGRyZW4gYnkgcHJvY2Vzc2luZyBhIHNlcmllcyBvZiB1cGRhdGVzLiBUaGVcbiAgICogdXBkYXRlIGNvbmZpZ3VyYXRpb25zIGFyZSBlYWNoIGV4cGVjdGVkIHRvIGhhdmUgYSBgcGFyZW50Tm9kZWAgcHJvcGVydHkuXG4gICAqXG4gICAqIEBwYXJhbSB7YXJyYXk8b2JqZWN0Pn0gdXBkYXRlcyBMaXN0IG9mIHVwZGF0ZSBjb25maWd1cmF0aW9ucy5cbiAgICogQHBhcmFtIHthcnJheTxzdHJpbmc+fSBtYXJrdXBMaXN0IExpc3Qgb2YgbWFya3VwIHN0cmluZ3MuXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgcHJvY2Vzc1VwZGF0ZXM6IGZ1bmN0aW9uKHVwZGF0ZXMsIG1hcmt1cExpc3QpIHtcbiAgICB2YXIgdXBkYXRlO1xuICAgIC8vIE1hcHBpbmcgZnJvbSBwYXJlbnQgSURzIHRvIGluaXRpYWwgY2hpbGQgb3JkZXJpbmdzLlxuICAgIHZhciBpbml0aWFsQ2hpbGRyZW4gPSBudWxsO1xuICAgIC8vIExpc3Qgb2YgY2hpbGRyZW4gdGhhdCB3aWxsIGJlIG1vdmVkIG9yIHJlbW92ZWQuXG4gICAgdmFyIHVwZGF0ZWRDaGlsZHJlbiA9IG51bGw7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgdXBkYXRlID0gdXBkYXRlc1tpXTsgaSsrKSB7XG4gICAgICBpZiAodXBkYXRlLnR5cGUgPT09IFJlYWN0TXVsdGlDaGlsZFVwZGF0ZVR5cGVzLk1PVkVfRVhJU1RJTkcgfHxcbiAgICAgICAgICB1cGRhdGUudHlwZSA9PT0gUmVhY3RNdWx0aUNoaWxkVXBkYXRlVHlwZXMuUkVNT1ZFX05PREUpIHtcbiAgICAgICAgdmFyIHVwZGF0ZWRJbmRleCA9IHVwZGF0ZS5mcm9tSW5kZXg7XG4gICAgICAgIHZhciB1cGRhdGVkQ2hpbGQgPSB1cGRhdGUucGFyZW50Tm9kZS5jaGlsZE5vZGVzW3VwZGF0ZWRJbmRleF07XG4gICAgICAgIHZhciBwYXJlbnRJRCA9IHVwZGF0ZS5wYXJlbnRJRDtcblxuICAgICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICAgIHVwZGF0ZWRDaGlsZCxcbiAgICAgICAgICAncHJvY2Vzc1VwZGF0ZXMoKTogVW5hYmxlIHRvIGZpbmQgY2hpbGQgJXMgb2YgZWxlbWVudC4gVGhpcyAnICtcbiAgICAgICAgICAncHJvYmFibHkgbWVhbnMgdGhlIERPTSB3YXMgdW5leHBlY3RlZGx5IG11dGF0ZWQgKGUuZy4sIGJ5IHRoZSAnICtcbiAgICAgICAgICAnYnJvd3NlciksIHVzdWFsbHkgZHVlIHRvIGZvcmdldHRpbmcgYSA8dGJvZHk+IHdoZW4gdXNpbmcgdGFibGVzLCAnICtcbiAgICAgICAgICAnbmVzdGluZyB0YWdzIGxpa2UgPGZvcm0+LCA8cD4sIG9yIDxhPiwgb3IgdXNpbmcgbm9uLVNWRyBlbGVtZW50cyAnK1xuICAgICAgICAgICdpbiBhbiA8c3ZnPiBwYXJlbnQuIFRyeSBpbnNwZWN0aW5nIHRoZSBjaGlsZCBub2RlcyBvZiB0aGUgZWxlbWVudCAnICtcbiAgICAgICAgICAnd2l0aCBSZWFjdCBJRCBgJXNgLicsXG4gICAgICAgICAgdXBkYXRlZEluZGV4LFxuICAgICAgICAgIHBhcmVudElEXG4gICAgICAgICkgOiBpbnZhcmlhbnQodXBkYXRlZENoaWxkKSk7XG5cbiAgICAgICAgaW5pdGlhbENoaWxkcmVuID0gaW5pdGlhbENoaWxkcmVuIHx8IHt9O1xuICAgICAgICBpbml0aWFsQ2hpbGRyZW5bcGFyZW50SURdID0gaW5pdGlhbENoaWxkcmVuW3BhcmVudElEXSB8fCBbXTtcbiAgICAgICAgaW5pdGlhbENoaWxkcmVuW3BhcmVudElEXVt1cGRhdGVkSW5kZXhdID0gdXBkYXRlZENoaWxkO1xuXG4gICAgICAgIHVwZGF0ZWRDaGlsZHJlbiA9IHVwZGF0ZWRDaGlsZHJlbiB8fCBbXTtcbiAgICAgICAgdXBkYXRlZENoaWxkcmVuLnB1c2godXBkYXRlZENoaWxkKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB2YXIgcmVuZGVyZWRNYXJrdXAgPSBEYW5nZXIuZGFuZ2Vyb3VzbHlSZW5kZXJNYXJrdXAobWFya3VwTGlzdCk7XG5cbiAgICAvLyBSZW1vdmUgdXBkYXRlZCBjaGlsZHJlbiBmaXJzdCBzbyB0aGF0IGB0b0luZGV4YCBpcyBjb25zaXN0ZW50LlxuICAgIGlmICh1cGRhdGVkQ2hpbGRyZW4pIHtcbiAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgdXBkYXRlZENoaWxkcmVuLmxlbmd0aDsgaisrKSB7XG4gICAgICAgIHVwZGF0ZWRDaGlsZHJlbltqXS5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKHVwZGF0ZWRDaGlsZHJlbltqXSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgZm9yICh2YXIgayA9IDA7IHVwZGF0ZSA9IHVwZGF0ZXNba107IGsrKykge1xuICAgICAgc3dpdGNoICh1cGRhdGUudHlwZSkge1xuICAgICAgICBjYXNlIFJlYWN0TXVsdGlDaGlsZFVwZGF0ZVR5cGVzLklOU0VSVF9NQVJLVVA6XG4gICAgICAgICAgaW5zZXJ0Q2hpbGRBdChcbiAgICAgICAgICAgIHVwZGF0ZS5wYXJlbnROb2RlLFxuICAgICAgICAgICAgcmVuZGVyZWRNYXJrdXBbdXBkYXRlLm1hcmt1cEluZGV4XSxcbiAgICAgICAgICAgIHVwZGF0ZS50b0luZGV4XG4gICAgICAgICAgKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBSZWFjdE11bHRpQ2hpbGRVcGRhdGVUeXBlcy5NT1ZFX0VYSVNUSU5HOlxuICAgICAgICAgIGluc2VydENoaWxkQXQoXG4gICAgICAgICAgICB1cGRhdGUucGFyZW50Tm9kZSxcbiAgICAgICAgICAgIGluaXRpYWxDaGlsZHJlblt1cGRhdGUucGFyZW50SURdW3VwZGF0ZS5mcm9tSW5kZXhdLFxuICAgICAgICAgICAgdXBkYXRlLnRvSW5kZXhcbiAgICAgICAgICApO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFJlYWN0TXVsdGlDaGlsZFVwZGF0ZVR5cGVzLlRFWFRfQ09OVEVOVDpcbiAgICAgICAgICB1cGRhdGVUZXh0Q29udGVudChcbiAgICAgICAgICAgIHVwZGF0ZS5wYXJlbnROb2RlLFxuICAgICAgICAgICAgdXBkYXRlLnRleHRDb250ZW50XG4gICAgICAgICAgKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBSZWFjdE11bHRpQ2hpbGRVcGRhdGVUeXBlcy5SRU1PVkVfTk9ERTpcbiAgICAgICAgICAvLyBBbHJlYWR5IHJlbW92ZWQgYnkgdGhlIGZvci1sb29wIGFib3ZlLlxuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IERPTUNoaWxkcmVuT3BlcmF0aW9ucztcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBET01Qcm9wZXJ0eVxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG4vKmpzbGludCBiaXR3aXNlOiB0cnVlICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG5mdW5jdGlvbiBjaGVja01hc2sodmFsdWUsIGJpdG1hc2spIHtcbiAgcmV0dXJuICh2YWx1ZSAmIGJpdG1hc2spID09PSBiaXRtYXNrO1xufVxuXG52YXIgRE9NUHJvcGVydHlJbmplY3Rpb24gPSB7XG4gIC8qKlxuICAgKiBNYXBwaW5nIGZyb20gbm9ybWFsaXplZCwgY2FtZWxjYXNlZCBwcm9wZXJ0eSBuYW1lcyB0byBhIGNvbmZpZ3VyYXRpb24gdGhhdFxuICAgKiBzcGVjaWZpZXMgaG93IHRoZSBhc3NvY2lhdGVkIERPTSBwcm9wZXJ0eSBzaG91bGQgYmUgYWNjZXNzZWQgb3IgcmVuZGVyZWQuXG4gICAqL1xuICBNVVNUX1VTRV9BVFRSSUJVVEU6IDB4MSxcbiAgTVVTVF9VU0VfUFJPUEVSVFk6IDB4MixcbiAgSEFTX1NJREVfRUZGRUNUUzogMHg0LFxuICBIQVNfQk9PTEVBTl9WQUxVRTogMHg4LFxuICBIQVNfTlVNRVJJQ19WQUxVRTogMHgxMCxcbiAgSEFTX1BPU0lUSVZFX05VTUVSSUNfVkFMVUU6IDB4MjAgfCAweDEwLFxuICBIQVNfT1ZFUkxPQURFRF9CT09MRUFOX1ZBTFVFOiAweDQwLFxuXG4gIC8qKlxuICAgKiBJbmplY3Qgc29tZSBzcGVjaWFsaXplZCBrbm93bGVkZ2UgYWJvdXQgdGhlIERPTS4gVGhpcyB0YWtlcyBhIGNvbmZpZyBvYmplY3RcbiAgICogd2l0aCB0aGUgZm9sbG93aW5nIHByb3BlcnRpZXM6XG4gICAqXG4gICAqIGlzQ3VzdG9tQXR0cmlidXRlOiBmdW5jdGlvbiB0aGF0IGdpdmVuIGFuIGF0dHJpYnV0ZSBuYW1lIHdpbGwgcmV0dXJuIHRydWVcbiAgICogaWYgaXQgY2FuIGJlIGluc2VydGVkIGludG8gdGhlIERPTSB2ZXJiYXRpbS4gVXNlZnVsIGZvciBkYXRhLSogb3IgYXJpYS0qXG4gICAqIGF0dHJpYnV0ZXMgd2hlcmUgaXQncyBpbXBvc3NpYmxlIHRvIGVudW1lcmF0ZSBhbGwgb2YgdGhlIHBvc3NpYmxlXG4gICAqIGF0dHJpYnV0ZSBuYW1lcyxcbiAgICpcbiAgICogUHJvcGVydGllczogb2JqZWN0IG1hcHBpbmcgRE9NIHByb3BlcnR5IG5hbWUgdG8gb25lIG9mIHRoZVxuICAgKiBET01Qcm9wZXJ0eUluamVjdGlvbiBjb25zdGFudHMgb3IgbnVsbC4gSWYgeW91ciBhdHRyaWJ1dGUgaXNuJ3QgaW4gaGVyZSxcbiAgICogaXQgd29uJ3QgZ2V0IHdyaXR0ZW4gdG8gdGhlIERPTS5cbiAgICpcbiAgICogRE9NQXR0cmlidXRlTmFtZXM6IG9iamVjdCBtYXBwaW5nIFJlYWN0IGF0dHJpYnV0ZSBuYW1lIHRvIHRoZSBET01cbiAgICogYXR0cmlidXRlIG5hbWUuIEF0dHJpYnV0ZSBuYW1lcyBub3Qgc3BlY2lmaWVkIHVzZSB0aGUgKipsb3dlcmNhc2UqKlxuICAgKiBub3JtYWxpemVkIG5hbWUuXG4gICAqXG4gICAqIERPTVByb3BlcnR5TmFtZXM6IHNpbWlsYXIgdG8gRE9NQXR0cmlidXRlTmFtZXMgYnV0IGZvciBET00gcHJvcGVydGllcy5cbiAgICogUHJvcGVydHkgbmFtZXMgbm90IHNwZWNpZmllZCB1c2UgdGhlIG5vcm1hbGl6ZWQgbmFtZS5cbiAgICpcbiAgICogRE9NTXV0YXRpb25NZXRob2RzOiBQcm9wZXJ0aWVzIHRoYXQgcmVxdWlyZSBzcGVjaWFsIG11dGF0aW9uIG1ldGhvZHMuIElmXG4gICAqIGB2YWx1ZWAgaXMgdW5kZWZpbmVkLCB0aGUgbXV0YXRpb24gbWV0aG9kIHNob3VsZCB1bnNldCB0aGUgcHJvcGVydHkuXG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBkb21Qcm9wZXJ0eUNvbmZpZyB0aGUgY29uZmlnIGFzIGRlc2NyaWJlZCBhYm92ZS5cbiAgICovXG4gIGluamVjdERPTVByb3BlcnR5Q29uZmlnOiBmdW5jdGlvbihkb21Qcm9wZXJ0eUNvbmZpZykge1xuICAgIHZhciBQcm9wZXJ0aWVzID0gZG9tUHJvcGVydHlDb25maWcuUHJvcGVydGllcyB8fCB7fTtcbiAgICB2YXIgRE9NQXR0cmlidXRlTmFtZXMgPSBkb21Qcm9wZXJ0eUNvbmZpZy5ET01BdHRyaWJ1dGVOYW1lcyB8fCB7fTtcbiAgICB2YXIgRE9NUHJvcGVydHlOYW1lcyA9IGRvbVByb3BlcnR5Q29uZmlnLkRPTVByb3BlcnR5TmFtZXMgfHwge307XG4gICAgdmFyIERPTU11dGF0aW9uTWV0aG9kcyA9IGRvbVByb3BlcnR5Q29uZmlnLkRPTU11dGF0aW9uTWV0aG9kcyB8fCB7fTtcblxuICAgIGlmIChkb21Qcm9wZXJ0eUNvbmZpZy5pc0N1c3RvbUF0dHJpYnV0ZSkge1xuICAgICAgRE9NUHJvcGVydHkuX2lzQ3VzdG9tQXR0cmlidXRlRnVuY3Rpb25zLnB1c2goXG4gICAgICAgIGRvbVByb3BlcnR5Q29uZmlnLmlzQ3VzdG9tQXR0cmlidXRlXG4gICAgICApO1xuICAgIH1cblxuICAgIGZvciAodmFyIHByb3BOYW1lIGluIFByb3BlcnRpZXMpIHtcbiAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgICFET01Qcm9wZXJ0eS5pc1N0YW5kYXJkTmFtZS5oYXNPd25Qcm9wZXJ0eShwcm9wTmFtZSksXG4gICAgICAgICdpbmplY3RET01Qcm9wZXJ0eUNvbmZpZyguLi4pOiBZb3VcXCdyZSB0cnlpbmcgdG8gaW5qZWN0IERPTSBwcm9wZXJ0eSAnICtcbiAgICAgICAgJ1xcJyVzXFwnIHdoaWNoIGhhcyBhbHJlYWR5IGJlZW4gaW5qZWN0ZWQuIFlvdSBtYXkgYmUgYWNjaWRlbnRhbGx5ICcgK1xuICAgICAgICAnaW5qZWN0aW5nIHRoZSBzYW1lIERPTSBwcm9wZXJ0eSBjb25maWcgdHdpY2UsIG9yIHlvdSBtYXkgYmUgJyArXG4gICAgICAgICdpbmplY3RpbmcgdHdvIGNvbmZpZ3MgdGhhdCBoYXZlIGNvbmZsaWN0aW5nIHByb3BlcnR5IG5hbWVzLicsXG4gICAgICAgIHByb3BOYW1lXG4gICAgICApIDogaW52YXJpYW50KCFET01Qcm9wZXJ0eS5pc1N0YW5kYXJkTmFtZS5oYXNPd25Qcm9wZXJ0eShwcm9wTmFtZSkpKTtcblxuICAgICAgRE9NUHJvcGVydHkuaXNTdGFuZGFyZE5hbWVbcHJvcE5hbWVdID0gdHJ1ZTtcblxuICAgICAgdmFyIGxvd2VyQ2FzZWQgPSBwcm9wTmFtZS50b0xvd2VyQ2FzZSgpO1xuICAgICAgRE9NUHJvcGVydHkuZ2V0UG9zc2libGVTdGFuZGFyZE5hbWVbbG93ZXJDYXNlZF0gPSBwcm9wTmFtZTtcblxuICAgICAgaWYgKERPTUF0dHJpYnV0ZU5hbWVzLmhhc093blByb3BlcnR5KHByb3BOYW1lKSkge1xuICAgICAgICB2YXIgYXR0cmlidXRlTmFtZSA9IERPTUF0dHJpYnV0ZU5hbWVzW3Byb3BOYW1lXTtcbiAgICAgICAgRE9NUHJvcGVydHkuZ2V0UG9zc2libGVTdGFuZGFyZE5hbWVbYXR0cmlidXRlTmFtZV0gPSBwcm9wTmFtZTtcbiAgICAgICAgRE9NUHJvcGVydHkuZ2V0QXR0cmlidXRlTmFtZVtwcm9wTmFtZV0gPSBhdHRyaWJ1dGVOYW1lO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgRE9NUHJvcGVydHkuZ2V0QXR0cmlidXRlTmFtZVtwcm9wTmFtZV0gPSBsb3dlckNhc2VkO1xuICAgICAgfVxuXG4gICAgICBET01Qcm9wZXJ0eS5nZXRQcm9wZXJ0eU5hbWVbcHJvcE5hbWVdID1cbiAgICAgICAgRE9NUHJvcGVydHlOYW1lcy5oYXNPd25Qcm9wZXJ0eShwcm9wTmFtZSkgP1xuICAgICAgICAgIERPTVByb3BlcnR5TmFtZXNbcHJvcE5hbWVdIDpcbiAgICAgICAgICBwcm9wTmFtZTtcblxuICAgICAgaWYgKERPTU11dGF0aW9uTWV0aG9kcy5oYXNPd25Qcm9wZXJ0eShwcm9wTmFtZSkpIHtcbiAgICAgICAgRE9NUHJvcGVydHkuZ2V0TXV0YXRpb25NZXRob2RbcHJvcE5hbWVdID0gRE9NTXV0YXRpb25NZXRob2RzW3Byb3BOYW1lXTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIERPTVByb3BlcnR5LmdldE11dGF0aW9uTWV0aG9kW3Byb3BOYW1lXSA9IG51bGw7XG4gICAgICB9XG5cbiAgICAgIHZhciBwcm9wQ29uZmlnID0gUHJvcGVydGllc1twcm9wTmFtZV07XG4gICAgICBET01Qcm9wZXJ0eS5tdXN0VXNlQXR0cmlidXRlW3Byb3BOYW1lXSA9XG4gICAgICAgIGNoZWNrTWFzayhwcm9wQ29uZmlnLCBET01Qcm9wZXJ0eUluamVjdGlvbi5NVVNUX1VTRV9BVFRSSUJVVEUpO1xuICAgICAgRE9NUHJvcGVydHkubXVzdFVzZVByb3BlcnR5W3Byb3BOYW1lXSA9XG4gICAgICAgIGNoZWNrTWFzayhwcm9wQ29uZmlnLCBET01Qcm9wZXJ0eUluamVjdGlvbi5NVVNUX1VTRV9QUk9QRVJUWSk7XG4gICAgICBET01Qcm9wZXJ0eS5oYXNTaWRlRWZmZWN0c1twcm9wTmFtZV0gPVxuICAgICAgICBjaGVja01hc2socHJvcENvbmZpZywgRE9NUHJvcGVydHlJbmplY3Rpb24uSEFTX1NJREVfRUZGRUNUUyk7XG4gICAgICBET01Qcm9wZXJ0eS5oYXNCb29sZWFuVmFsdWVbcHJvcE5hbWVdID1cbiAgICAgICAgY2hlY2tNYXNrKHByb3BDb25maWcsIERPTVByb3BlcnR5SW5qZWN0aW9uLkhBU19CT09MRUFOX1ZBTFVFKTtcbiAgICAgIERPTVByb3BlcnR5Lmhhc051bWVyaWNWYWx1ZVtwcm9wTmFtZV0gPVxuICAgICAgICBjaGVja01hc2socHJvcENvbmZpZywgRE9NUHJvcGVydHlJbmplY3Rpb24uSEFTX05VTUVSSUNfVkFMVUUpO1xuICAgICAgRE9NUHJvcGVydHkuaGFzUG9zaXRpdmVOdW1lcmljVmFsdWVbcHJvcE5hbWVdID1cbiAgICAgICAgY2hlY2tNYXNrKHByb3BDb25maWcsIERPTVByb3BlcnR5SW5qZWN0aW9uLkhBU19QT1NJVElWRV9OVU1FUklDX1ZBTFVFKTtcbiAgICAgIERPTVByb3BlcnR5Lmhhc092ZXJsb2FkZWRCb29sZWFuVmFsdWVbcHJvcE5hbWVdID1cbiAgICAgICAgY2hlY2tNYXNrKHByb3BDb25maWcsIERPTVByb3BlcnR5SW5qZWN0aW9uLkhBU19PVkVSTE9BREVEX0JPT0xFQU5fVkFMVUUpO1xuXG4gICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICAhRE9NUHJvcGVydHkubXVzdFVzZUF0dHJpYnV0ZVtwcm9wTmFtZV0gfHxcbiAgICAgICAgICAhRE9NUHJvcGVydHkubXVzdFVzZVByb3BlcnR5W3Byb3BOYW1lXSxcbiAgICAgICAgJ0RPTVByb3BlcnR5OiBDYW5ub3QgcmVxdWlyZSB1c2luZyBib3RoIGF0dHJpYnV0ZSBhbmQgcHJvcGVydHk6ICVzJyxcbiAgICAgICAgcHJvcE5hbWVcbiAgICAgICkgOiBpbnZhcmlhbnQoIURPTVByb3BlcnR5Lm11c3RVc2VBdHRyaWJ1dGVbcHJvcE5hbWVdIHx8XG4gICAgICAgICFET01Qcm9wZXJ0eS5tdXN0VXNlUHJvcGVydHlbcHJvcE5hbWVdKSk7XG4gICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICBET01Qcm9wZXJ0eS5tdXN0VXNlUHJvcGVydHlbcHJvcE5hbWVdIHx8XG4gICAgICAgICAgIURPTVByb3BlcnR5Lmhhc1NpZGVFZmZlY3RzW3Byb3BOYW1lXSxcbiAgICAgICAgJ0RPTVByb3BlcnR5OiBQcm9wZXJ0aWVzIHRoYXQgaGF2ZSBzaWRlIGVmZmVjdHMgbXVzdCB1c2UgcHJvcGVydHk6ICVzJyxcbiAgICAgICAgcHJvcE5hbWVcbiAgICAgICkgOiBpbnZhcmlhbnQoRE9NUHJvcGVydHkubXVzdFVzZVByb3BlcnR5W3Byb3BOYW1lXSB8fFxuICAgICAgICAhRE9NUHJvcGVydHkuaGFzU2lkZUVmZmVjdHNbcHJvcE5hbWVdKSk7XG4gICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICAhIURPTVByb3BlcnR5Lmhhc0Jvb2xlYW5WYWx1ZVtwcm9wTmFtZV0gK1xuICAgICAgICAgICEhRE9NUHJvcGVydHkuaGFzTnVtZXJpY1ZhbHVlW3Byb3BOYW1lXSArXG4gICAgICAgICAgISFET01Qcm9wZXJ0eS5oYXNPdmVybG9hZGVkQm9vbGVhblZhbHVlW3Byb3BOYW1lXSA8PSAxLFxuICAgICAgICAnRE9NUHJvcGVydHk6IFZhbHVlIGNhbiBiZSBvbmUgb2YgYm9vbGVhbiwgb3ZlcmxvYWRlZCBib29sZWFuLCBvciAnICtcbiAgICAgICAgJ251bWVyaWMgdmFsdWUsIGJ1dCBub3QgYSBjb21iaW5hdGlvbjogJXMnLFxuICAgICAgICBwcm9wTmFtZVxuICAgICAgKSA6IGludmFyaWFudCghIURPTVByb3BlcnR5Lmhhc0Jvb2xlYW5WYWx1ZVtwcm9wTmFtZV0gK1xuICAgICAgICAhIURPTVByb3BlcnR5Lmhhc051bWVyaWNWYWx1ZVtwcm9wTmFtZV0gK1xuICAgICAgICAhIURPTVByb3BlcnR5Lmhhc092ZXJsb2FkZWRCb29sZWFuVmFsdWVbcHJvcE5hbWVdIDw9IDEpKTtcbiAgICB9XG4gIH1cbn07XG52YXIgZGVmYXVsdFZhbHVlQ2FjaGUgPSB7fTtcblxuLyoqXG4gKiBET01Qcm9wZXJ0eSBleHBvcnRzIGxvb2t1cCBvYmplY3RzIHRoYXQgY2FuIGJlIHVzZWQgbGlrZSBmdW5jdGlvbnM6XG4gKlxuICogICA+IERPTVByb3BlcnR5LmlzVmFsaWRbJ2lkJ11cbiAqICAgdHJ1ZVxuICogICA+IERPTVByb3BlcnR5LmlzVmFsaWRbJ2Zvb2JhciddXG4gKiAgIHVuZGVmaW5lZFxuICpcbiAqIEFsdGhvdWdoIHRoaXMgbWF5IGJlIGNvbmZ1c2luZywgaXQgcGVyZm9ybXMgYmV0dGVyIGluIGdlbmVyYWwuXG4gKlxuICogQHNlZSBodHRwOi8vanNwZXJmLmNvbS9rZXktZXhpc3RzXG4gKiBAc2VlIGh0dHA6Ly9qc3BlcmYuY29tL2tleS1taXNzaW5nXG4gKi9cbnZhciBET01Qcm9wZXJ0eSA9IHtcblxuICBJRF9BVFRSSUJVVEVfTkFNRTogJ2RhdGEtcmVhY3RpZCcsXG5cbiAgLyoqXG4gICAqIENoZWNrcyB3aGV0aGVyIGEgcHJvcGVydHkgbmFtZSBpcyBhIHN0YW5kYXJkIHByb3BlcnR5LlxuICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgKi9cbiAgaXNTdGFuZGFyZE5hbWU6IHt9LFxuXG4gIC8qKlxuICAgKiBNYXBwaW5nIGZyb20gbG93ZXJjYXNlIHByb3BlcnR5IG5hbWVzIHRvIHRoZSBwcm9wZXJseSBjYXNlZCB2ZXJzaW9uLCB1c2VkXG4gICAqIHRvIHdhcm4gaW4gdGhlIGNhc2Ugb2YgbWlzc2luZyBwcm9wZXJ0aWVzLlxuICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgKi9cbiAgZ2V0UG9zc2libGVTdGFuZGFyZE5hbWU6IHt9LFxuXG4gIC8qKlxuICAgKiBNYXBwaW5nIGZyb20gbm9ybWFsaXplZCBuYW1lcyB0byBhdHRyaWJ1dGUgbmFtZXMgdGhhdCBkaWZmZXIuIEF0dHJpYnV0ZVxuICAgKiBuYW1lcyBhcmUgdXNlZCB3aGVuIHJlbmRlcmluZyBtYXJrdXAgb3Igd2l0aCBgKkF0dHJpYnV0ZSgpYC5cbiAgICogQHR5cGUge09iamVjdH1cbiAgICovXG4gIGdldEF0dHJpYnV0ZU5hbWU6IHt9LFxuXG4gIC8qKlxuICAgKiBNYXBwaW5nIGZyb20gbm9ybWFsaXplZCBuYW1lcyB0byBwcm9wZXJ0aWVzIG9uIERPTSBub2RlIGluc3RhbmNlcy5cbiAgICogKFRoaXMgaW5jbHVkZXMgcHJvcGVydGllcyB0aGF0IG11dGF0ZSBkdWUgdG8gZXh0ZXJuYWwgZmFjdG9ycy4pXG4gICAqIEB0eXBlIHtPYmplY3R9XG4gICAqL1xuICBnZXRQcm9wZXJ0eU5hbWU6IHt9LFxuXG4gIC8qKlxuICAgKiBNYXBwaW5nIGZyb20gbm9ybWFsaXplZCBuYW1lcyB0byBtdXRhdGlvbiBtZXRob2RzLiBUaGlzIHdpbGwgb25seSBleGlzdCBpZlxuICAgKiBtdXRhdGlvbiBjYW5ub3QgYmUgc2V0IHNpbXBseSBieSB0aGUgcHJvcGVydHkgb3IgYHNldEF0dHJpYnV0ZSgpYC5cbiAgICogQHR5cGUge09iamVjdH1cbiAgICovXG4gIGdldE11dGF0aW9uTWV0aG9kOiB7fSxcblxuICAvKipcbiAgICogV2hldGhlciB0aGUgcHJvcGVydHkgbXVzdCBiZSBhY2Nlc3NlZCBhbmQgbXV0YXRlZCBhcyBhbiBvYmplY3QgcHJvcGVydHkuXG4gICAqIEB0eXBlIHtPYmplY3R9XG4gICAqL1xuICBtdXN0VXNlQXR0cmlidXRlOiB7fSxcblxuICAvKipcbiAgICogV2hldGhlciB0aGUgcHJvcGVydHkgbXVzdCBiZSBhY2Nlc3NlZCBhbmQgbXV0YXRlZCB1c2luZyBgKkF0dHJpYnV0ZSgpYC5cbiAgICogKFRoaXMgaW5jbHVkZXMgYW55dGhpbmcgdGhhdCBmYWlscyBgPHByb3BOYW1lPiBpbiA8ZWxlbWVudD5gLilcbiAgICogQHR5cGUge09iamVjdH1cbiAgICovXG4gIG11c3RVc2VQcm9wZXJ0eToge30sXG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgb3Igbm90IHNldHRpbmcgYSB2YWx1ZSBjYXVzZXMgc2lkZSBlZmZlY3RzIHN1Y2ggYXMgdHJpZ2dlcmluZ1xuICAgKiByZXNvdXJjZXMgdG8gYmUgbG9hZGVkIG9yIHRleHQgc2VsZWN0aW9uIGNoYW5nZXMuIFdlIG11c3QgZW5zdXJlIHRoYXRcbiAgICogdGhlIHZhbHVlIGlzIG9ubHkgc2V0IGlmIGl0IGhhcyBjaGFuZ2VkLlxuICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgKi9cbiAgaGFzU2lkZUVmZmVjdHM6IHt9LFxuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoZSBwcm9wZXJ0eSBzaG91bGQgYmUgcmVtb3ZlZCB3aGVuIHNldCB0byBhIGZhbHNleSB2YWx1ZS5cbiAgICogQHR5cGUge09iamVjdH1cbiAgICovXG4gIGhhc0Jvb2xlYW5WYWx1ZToge30sXG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIHByb3BlcnR5IG11c3QgYmUgbnVtZXJpYyBvciBwYXJzZSBhcyBhXG4gICAqIG51bWVyaWMgYW5kIHNob3VsZCBiZSByZW1vdmVkIHdoZW4gc2V0IHRvIGEgZmFsc2V5IHZhbHVlLlxuICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgKi9cbiAgaGFzTnVtZXJpY1ZhbHVlOiB7fSxcblxuICAvKipcbiAgICogV2hldGhlciB0aGUgcHJvcGVydHkgbXVzdCBiZSBwb3NpdGl2ZSBudW1lcmljIG9yIHBhcnNlIGFzIGEgcG9zaXRpdmVcbiAgICogbnVtZXJpYyBhbmQgc2hvdWxkIGJlIHJlbW92ZWQgd2hlbiBzZXQgdG8gYSBmYWxzZXkgdmFsdWUuXG4gICAqIEB0eXBlIHtPYmplY3R9XG4gICAqL1xuICBoYXNQb3NpdGl2ZU51bWVyaWNWYWx1ZToge30sXG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIHByb3BlcnR5IGNhbiBiZSB1c2VkIGFzIGEgZmxhZyBhcyB3ZWxsIGFzIHdpdGggYSB2YWx1ZS4gUmVtb3ZlZFxuICAgKiB3aGVuIHN0cmljdGx5IGVxdWFsIHRvIGZhbHNlOyBwcmVzZW50IHdpdGhvdXQgYSB2YWx1ZSB3aGVuIHN0cmljdGx5IGVxdWFsXG4gICAqIHRvIHRydWU7IHByZXNlbnQgd2l0aCBhIHZhbHVlIG90aGVyd2lzZS5cbiAgICogQHR5cGUge09iamVjdH1cbiAgICovXG4gIGhhc092ZXJsb2FkZWRCb29sZWFuVmFsdWU6IHt9LFxuXG4gIC8qKlxuICAgKiBBbGwgb2YgdGhlIGlzQ3VzdG9tQXR0cmlidXRlKCkgZnVuY3Rpb25zIHRoYXQgaGF2ZSBiZWVuIGluamVjdGVkLlxuICAgKi9cbiAgX2lzQ3VzdG9tQXR0cmlidXRlRnVuY3Rpb25zOiBbXSxcblxuICAvKipcbiAgICogQ2hlY2tzIHdoZXRoZXIgYSBwcm9wZXJ0eSBuYW1lIGlzIGEgY3VzdG9tIGF0dHJpYnV0ZS5cbiAgICogQG1ldGhvZFxuICAgKi9cbiAgaXNDdXN0b21BdHRyaWJ1dGU6IGZ1bmN0aW9uKGF0dHJpYnV0ZU5hbWUpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IERPTVByb3BlcnR5Ll9pc0N1c3RvbUF0dHJpYnV0ZUZ1bmN0aW9ucy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIGlzQ3VzdG9tQXR0cmlidXRlRm4gPSBET01Qcm9wZXJ0eS5faXNDdXN0b21BdHRyaWJ1dGVGdW5jdGlvbnNbaV07XG4gICAgICBpZiAoaXNDdXN0b21BdHRyaWJ1dGVGbihhdHRyaWJ1dGVOYW1lKSkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9LFxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBkZWZhdWx0IHByb3BlcnR5IHZhbHVlIGZvciBhIERPTSBwcm9wZXJ0eSAoaS5lLiwgbm90IGFuXG4gICAqIGF0dHJpYnV0ZSkuIE1vc3QgZGVmYXVsdCB2YWx1ZXMgYXJlICcnIG9yIGZhbHNlLCBidXQgbm90IGFsbC4gV29yc2UgeWV0LFxuICAgKiBzb21lIChpbiBwYXJ0aWN1bGFyLCBgdHlwZWApIHZhcnkgZGVwZW5kaW5nIG9uIHRoZSB0eXBlIG9mIGVsZW1lbnQuXG4gICAqXG4gICAqIFRPRE86IElzIGl0IGJldHRlciB0byBncmFiIGFsbCB0aGUgcG9zc2libGUgcHJvcGVydGllcyB3aGVuIGNyZWF0aW5nIGFuXG4gICAqIGVsZW1lbnQgdG8gYXZvaWQgaGF2aW5nIHRvIGNyZWF0ZSB0aGUgc2FtZSBlbGVtZW50IHR3aWNlP1xuICAgKi9cbiAgZ2V0RGVmYXVsdFZhbHVlRm9yUHJvcGVydHk6IGZ1bmN0aW9uKG5vZGVOYW1lLCBwcm9wKSB7XG4gICAgdmFyIG5vZGVEZWZhdWx0cyA9IGRlZmF1bHRWYWx1ZUNhY2hlW25vZGVOYW1lXTtcbiAgICB2YXIgdGVzdEVsZW1lbnQ7XG4gICAgaWYgKCFub2RlRGVmYXVsdHMpIHtcbiAgICAgIGRlZmF1bHRWYWx1ZUNhY2hlW25vZGVOYW1lXSA9IG5vZGVEZWZhdWx0cyA9IHt9O1xuICAgIH1cbiAgICBpZiAoIShwcm9wIGluIG5vZGVEZWZhdWx0cykpIHtcbiAgICAgIHRlc3RFbGVtZW50ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChub2RlTmFtZSk7XG4gICAgICBub2RlRGVmYXVsdHNbcHJvcF0gPSB0ZXN0RWxlbWVudFtwcm9wXTtcbiAgICB9XG4gICAgcmV0dXJuIG5vZGVEZWZhdWx0c1twcm9wXTtcbiAgfSxcblxuICBpbmplY3Rpb246IERPTVByb3BlcnR5SW5qZWN0aW9uXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IERPTVByb3BlcnR5O1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIERPTVByb3BlcnR5T3BlcmF0aW9uc1xuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIERPTVByb3BlcnR5ID0gcmVxdWlyZShcIi4vRE9NUHJvcGVydHlcIik7XG5cbnZhciBlc2NhcGVUZXh0Rm9yQnJvd3NlciA9IHJlcXVpcmUoXCIuL2VzY2FwZVRleHRGb3JCcm93c2VyXCIpO1xudmFyIG1lbW9pemVTdHJpbmdPbmx5ID0gcmVxdWlyZShcIi4vbWVtb2l6ZVN0cmluZ09ubHlcIik7XG52YXIgd2FybmluZyA9IHJlcXVpcmUoXCIuL3dhcm5pbmdcIik7XG5cbmZ1bmN0aW9uIHNob3VsZElnbm9yZVZhbHVlKG5hbWUsIHZhbHVlKSB7XG4gIHJldHVybiB2YWx1ZSA9PSBudWxsIHx8XG4gICAgKERPTVByb3BlcnR5Lmhhc0Jvb2xlYW5WYWx1ZVtuYW1lXSAmJiAhdmFsdWUpIHx8XG4gICAgKERPTVByb3BlcnR5Lmhhc051bWVyaWNWYWx1ZVtuYW1lXSAmJiBpc05hTih2YWx1ZSkpIHx8XG4gICAgKERPTVByb3BlcnR5Lmhhc1Bvc2l0aXZlTnVtZXJpY1ZhbHVlW25hbWVdICYmICh2YWx1ZSA8IDEpKSB8fFxuICAgIChET01Qcm9wZXJ0eS5oYXNPdmVybG9hZGVkQm9vbGVhblZhbHVlW25hbWVdICYmIHZhbHVlID09PSBmYWxzZSk7XG59XG5cbnZhciBwcm9jZXNzQXR0cmlidXRlTmFtZUFuZFByZWZpeCA9IG1lbW9pemVTdHJpbmdPbmx5KGZ1bmN0aW9uKG5hbWUpIHtcbiAgcmV0dXJuIGVzY2FwZVRleHRGb3JCcm93c2VyKG5hbWUpICsgJz1cIic7XG59KTtcblxuaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICB2YXIgcmVhY3RQcm9wcyA9IHtcbiAgICBjaGlsZHJlbjogdHJ1ZSxcbiAgICBkYW5nZXJvdXNseVNldElubmVySFRNTDogdHJ1ZSxcbiAgICBrZXk6IHRydWUsXG4gICAgcmVmOiB0cnVlXG4gIH07XG4gIHZhciB3YXJuZWRQcm9wZXJ0aWVzID0ge307XG5cbiAgdmFyIHdhcm5Vbmtub3duUHJvcGVydHkgPSBmdW5jdGlvbihuYW1lKSB7XG4gICAgaWYgKHJlYWN0UHJvcHMuaGFzT3duUHJvcGVydHkobmFtZSkgJiYgcmVhY3RQcm9wc1tuYW1lXSB8fFxuICAgICAgICB3YXJuZWRQcm9wZXJ0aWVzLmhhc093blByb3BlcnR5KG5hbWUpICYmIHdhcm5lZFByb3BlcnRpZXNbbmFtZV0pIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB3YXJuZWRQcm9wZXJ0aWVzW25hbWVdID0gdHJ1ZTtcbiAgICB2YXIgbG93ZXJDYXNlZE5hbWUgPSBuYW1lLnRvTG93ZXJDYXNlKCk7XG5cbiAgICAvLyBkYXRhLSogYXR0cmlidXRlcyBzaG91bGQgYmUgbG93ZXJjYXNlOyBzdWdnZXN0IHRoZSBsb3dlcmNhc2UgdmVyc2lvblxuICAgIHZhciBzdGFuZGFyZE5hbWUgPSAoXG4gICAgICBET01Qcm9wZXJ0eS5pc0N1c3RvbUF0dHJpYnV0ZShsb3dlckNhc2VkTmFtZSkgP1xuICAgICAgICBsb3dlckNhc2VkTmFtZSA6XG4gICAgICBET01Qcm9wZXJ0eS5nZXRQb3NzaWJsZVN0YW5kYXJkTmFtZS5oYXNPd25Qcm9wZXJ0eShsb3dlckNhc2VkTmFtZSkgP1xuICAgICAgICBET01Qcm9wZXJ0eS5nZXRQb3NzaWJsZVN0YW5kYXJkTmFtZVtsb3dlckNhc2VkTmFtZV0gOlxuICAgICAgICBudWxsXG4gICAgKTtcblxuICAgIC8vIEZvciBub3csIG9ubHkgd2FybiB3aGVuIHdlIGhhdmUgYSBzdWdnZXN0ZWQgY29ycmVjdGlvbi4gVGhpcyBwcmV2ZW50c1xuICAgIC8vIGxvZ2dpbmcgdG9vIG11Y2ggd2hlbiB1c2luZyB0cmFuc2ZlclByb3BzVG8uXG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IHdhcm5pbmcoXG4gICAgICBzdGFuZGFyZE5hbWUgPT0gbnVsbCxcbiAgICAgICdVbmtub3duIERPTSBwcm9wZXJ0eSAnICsgbmFtZSArICcuIERpZCB5b3UgbWVhbiAnICsgc3RhbmRhcmROYW1lICsgJz8nXG4gICAgKSA6IG51bGwpO1xuXG4gIH07XG59XG5cbi8qKlxuICogT3BlcmF0aW9ucyBmb3IgZGVhbGluZyB3aXRoIERPTSBwcm9wZXJ0aWVzLlxuICovXG52YXIgRE9NUHJvcGVydHlPcGVyYXRpb25zID0ge1xuXG4gIC8qKlxuICAgKiBDcmVhdGVzIG1hcmt1cCBmb3IgdGhlIElEIHByb3BlcnR5LlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gaWQgVW5lc2NhcGVkIElELlxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IE1hcmt1cCBzdHJpbmcuXG4gICAqL1xuICBjcmVhdGVNYXJrdXBGb3JJRDogZnVuY3Rpb24oaWQpIHtcbiAgICByZXR1cm4gcHJvY2Vzc0F0dHJpYnV0ZU5hbWVBbmRQcmVmaXgoRE9NUHJvcGVydHkuSURfQVRUUklCVVRFX05BTUUpICtcbiAgICAgIGVzY2FwZVRleHRGb3JCcm93c2VyKGlkKSArICdcIic7XG4gIH0sXG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgbWFya3VwIGZvciBhIHByb3BlcnR5LlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZVxuICAgKiBAcGFyYW0geyp9IHZhbHVlXG4gICAqIEByZXR1cm4gez9zdHJpbmd9IE1hcmt1cCBzdHJpbmcsIG9yIG51bGwgaWYgdGhlIHByb3BlcnR5IHdhcyBpbnZhbGlkLlxuICAgKi9cbiAgY3JlYXRlTWFya3VwRm9yUHJvcGVydHk6IGZ1bmN0aW9uKG5hbWUsIHZhbHVlKSB7XG4gICAgaWYgKERPTVByb3BlcnR5LmlzU3RhbmRhcmROYW1lLmhhc093blByb3BlcnR5KG5hbWUpICYmXG4gICAgICAgIERPTVByb3BlcnR5LmlzU3RhbmRhcmROYW1lW25hbWVdKSB7XG4gICAgICBpZiAoc2hvdWxkSWdub3JlVmFsdWUobmFtZSwgdmFsdWUpKSB7XG4gICAgICAgIHJldHVybiAnJztcbiAgICAgIH1cbiAgICAgIHZhciBhdHRyaWJ1dGVOYW1lID0gRE9NUHJvcGVydHkuZ2V0QXR0cmlidXRlTmFtZVtuYW1lXTtcbiAgICAgIGlmIChET01Qcm9wZXJ0eS5oYXNCb29sZWFuVmFsdWVbbmFtZV0gfHxcbiAgICAgICAgICAoRE9NUHJvcGVydHkuaGFzT3ZlcmxvYWRlZEJvb2xlYW5WYWx1ZVtuYW1lXSAmJiB2YWx1ZSA9PT0gdHJ1ZSkpIHtcbiAgICAgICAgcmV0dXJuIGVzY2FwZVRleHRGb3JCcm93c2VyKGF0dHJpYnV0ZU5hbWUpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHByb2Nlc3NBdHRyaWJ1dGVOYW1lQW5kUHJlZml4KGF0dHJpYnV0ZU5hbWUpICtcbiAgICAgICAgZXNjYXBlVGV4dEZvckJyb3dzZXIodmFsdWUpICsgJ1wiJztcbiAgICB9IGVsc2UgaWYgKERPTVByb3BlcnR5LmlzQ3VzdG9tQXR0cmlidXRlKG5hbWUpKSB7XG4gICAgICBpZiAodmFsdWUgPT0gbnVsbCkge1xuICAgICAgICByZXR1cm4gJyc7XG4gICAgICB9XG4gICAgICByZXR1cm4gcHJvY2Vzc0F0dHJpYnV0ZU5hbWVBbmRQcmVmaXgobmFtZSkgK1xuICAgICAgICBlc2NhcGVUZXh0Rm9yQnJvd3Nlcih2YWx1ZSkgKyAnXCInO1xuICAgIH0gZWxzZSBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgICB3YXJuVW5rbm93blByb3BlcnR5KG5hbWUpO1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbiAgfSxcblxuICAvKipcbiAgICogU2V0cyB0aGUgdmFsdWUgZm9yIGEgcHJvcGVydHkgb24gYSBub2RlLlxuICAgKlxuICAgKiBAcGFyYW0ge0RPTUVsZW1lbnR9IG5vZGVcbiAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWVcbiAgICogQHBhcmFtIHsqfSB2YWx1ZVxuICAgKi9cbiAgc2V0VmFsdWVGb3JQcm9wZXJ0eTogZnVuY3Rpb24obm9kZSwgbmFtZSwgdmFsdWUpIHtcbiAgICBpZiAoRE9NUHJvcGVydHkuaXNTdGFuZGFyZE5hbWUuaGFzT3duUHJvcGVydHkobmFtZSkgJiZcbiAgICAgICAgRE9NUHJvcGVydHkuaXNTdGFuZGFyZE5hbWVbbmFtZV0pIHtcbiAgICAgIHZhciBtdXRhdGlvbk1ldGhvZCA9IERPTVByb3BlcnR5LmdldE11dGF0aW9uTWV0aG9kW25hbWVdO1xuICAgICAgaWYgKG11dGF0aW9uTWV0aG9kKSB7XG4gICAgICAgIG11dGF0aW9uTWV0aG9kKG5vZGUsIHZhbHVlKTtcbiAgICAgIH0gZWxzZSBpZiAoc2hvdWxkSWdub3JlVmFsdWUobmFtZSwgdmFsdWUpKSB7XG4gICAgICAgIHRoaXMuZGVsZXRlVmFsdWVGb3JQcm9wZXJ0eShub2RlLCBuYW1lKTtcbiAgICAgIH0gZWxzZSBpZiAoRE9NUHJvcGVydHkubXVzdFVzZUF0dHJpYnV0ZVtuYW1lXSkge1xuICAgICAgICAvLyBgc2V0QXR0cmlidXRlYCB3aXRoIG9iamVjdHMgYmVjb21lcyBvbmx5IGBbb2JqZWN0XWAgaW4gSUU4LzksXG4gICAgICAgIC8vICgnJyArIHZhbHVlKSBtYWtlcyBpdCBvdXRwdXQgdGhlIGNvcnJlY3QgdG9TdHJpbmcoKS12YWx1ZS5cbiAgICAgICAgbm9kZS5zZXRBdHRyaWJ1dGUoRE9NUHJvcGVydHkuZ2V0QXR0cmlidXRlTmFtZVtuYW1lXSwgJycgKyB2YWx1ZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2YXIgcHJvcE5hbWUgPSBET01Qcm9wZXJ0eS5nZXRQcm9wZXJ0eU5hbWVbbmFtZV07XG4gICAgICAgIC8vIE11c3QgZXhwbGljaXRseSBjYXN0IHZhbHVlcyBmb3IgSEFTX1NJREVfRUZGRUNUUy1wcm9wZXJ0aWVzIHRvIHRoZVxuICAgICAgICAvLyBwcm9wZXJ0eSB0eXBlIGJlZm9yZSBjb21wYXJpbmc7IG9ubHkgYHZhbHVlYCBkb2VzIGFuZCBpcyBzdHJpbmcuXG4gICAgICAgIGlmICghRE9NUHJvcGVydHkuaGFzU2lkZUVmZmVjdHNbbmFtZV0gfHxcbiAgICAgICAgICAgICgnJyArIG5vZGVbcHJvcE5hbWVdKSAhPT0gKCcnICsgdmFsdWUpKSB7XG4gICAgICAgICAgLy8gQ29udHJhcnkgdG8gYHNldEF0dHJpYnV0ZWAsIG9iamVjdCBwcm9wZXJ0aWVzIGFyZSBwcm9wZXJseVxuICAgICAgICAgIC8vIGB0b1N0cmluZ2BlZCBieSBJRTgvOS5cbiAgICAgICAgICBub2RlW3Byb3BOYW1lXSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChET01Qcm9wZXJ0eS5pc0N1c3RvbUF0dHJpYnV0ZShuYW1lKSkge1xuICAgICAgaWYgKHZhbHVlID09IG51bGwpIHtcbiAgICAgICAgbm9kZS5yZW1vdmVBdHRyaWJ1dGUobmFtZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBub2RlLnNldEF0dHJpYnV0ZShuYW1lLCAnJyArIHZhbHVlKTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgd2FyblVua25vd25Qcm9wZXJ0eShuYW1lKTtcbiAgICB9XG4gIH0sXG5cbiAgLyoqXG4gICAqIERlbGV0ZXMgdGhlIHZhbHVlIGZvciBhIHByb3BlcnR5IG9uIGEgbm9kZS5cbiAgICpcbiAgICogQHBhcmFtIHtET01FbGVtZW50fSBub2RlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lXG4gICAqL1xuICBkZWxldGVWYWx1ZUZvclByb3BlcnR5OiBmdW5jdGlvbihub2RlLCBuYW1lKSB7XG4gICAgaWYgKERPTVByb3BlcnR5LmlzU3RhbmRhcmROYW1lLmhhc093blByb3BlcnR5KG5hbWUpICYmXG4gICAgICAgIERPTVByb3BlcnR5LmlzU3RhbmRhcmROYW1lW25hbWVdKSB7XG4gICAgICB2YXIgbXV0YXRpb25NZXRob2QgPSBET01Qcm9wZXJ0eS5nZXRNdXRhdGlvbk1ldGhvZFtuYW1lXTtcbiAgICAgIGlmIChtdXRhdGlvbk1ldGhvZCkge1xuICAgICAgICBtdXRhdGlvbk1ldGhvZChub2RlLCB1bmRlZmluZWQpO1xuICAgICAgfSBlbHNlIGlmIChET01Qcm9wZXJ0eS5tdXN0VXNlQXR0cmlidXRlW25hbWVdKSB7XG4gICAgICAgIG5vZGUucmVtb3ZlQXR0cmlidXRlKERPTVByb3BlcnR5LmdldEF0dHJpYnV0ZU5hbWVbbmFtZV0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdmFyIHByb3BOYW1lID0gRE9NUHJvcGVydHkuZ2V0UHJvcGVydHlOYW1lW25hbWVdO1xuICAgICAgICB2YXIgZGVmYXVsdFZhbHVlID0gRE9NUHJvcGVydHkuZ2V0RGVmYXVsdFZhbHVlRm9yUHJvcGVydHkoXG4gICAgICAgICAgbm9kZS5ub2RlTmFtZSxcbiAgICAgICAgICBwcm9wTmFtZVxuICAgICAgICApO1xuICAgICAgICBpZiAoIURPTVByb3BlcnR5Lmhhc1NpZGVFZmZlY3RzW25hbWVdIHx8XG4gICAgICAgICAgICAoJycgKyBub2RlW3Byb3BOYW1lXSkgIT09IGRlZmF1bHRWYWx1ZSkge1xuICAgICAgICAgIG5vZGVbcHJvcE5hbWVdID0gZGVmYXVsdFZhbHVlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChET01Qcm9wZXJ0eS5pc0N1c3RvbUF0dHJpYnV0ZShuYW1lKSkge1xuICAgICAgbm9kZS5yZW1vdmVBdHRyaWJ1dGUobmFtZSk7XG4gICAgfSBlbHNlIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgIHdhcm5Vbmtub3duUHJvcGVydHkobmFtZSk7XG4gICAgfVxuICB9XG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gRE9NUHJvcGVydHlPcGVyYXRpb25zO1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIERhbmdlclxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG4vKmpzbGludCBldmlsOiB0cnVlLCBzdWI6IHRydWUgKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBFeGVjdXRpb25FbnZpcm9ubWVudCA9IHJlcXVpcmUoXCIuL0V4ZWN1dGlvbkVudmlyb25tZW50XCIpO1xuXG52YXIgY3JlYXRlTm9kZXNGcm9tTWFya3VwID0gcmVxdWlyZShcIi4vY3JlYXRlTm9kZXNGcm9tTWFya3VwXCIpO1xudmFyIGVtcHR5RnVuY3Rpb24gPSByZXF1aXJlKFwiLi9lbXB0eUZ1bmN0aW9uXCIpO1xudmFyIGdldE1hcmt1cFdyYXAgPSByZXF1aXJlKFwiLi9nZXRNYXJrdXBXcmFwXCIpO1xudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcblxudmFyIE9QRU5fVEFHX05BTUVfRVhQID0gL14oPFteIFxcLz5dKykvO1xudmFyIFJFU1VMVF9JTkRFWF9BVFRSID0gJ2RhdGEtZGFuZ2VyLWluZGV4JztcblxuLyoqXG4gKiBFeHRyYWN0cyB0aGUgYG5vZGVOYW1lYCBmcm9tIGEgc3RyaW5nIG9mIG1hcmt1cC5cbiAqXG4gKiBOT1RFOiBFeHRyYWN0aW5nIHRoZSBgbm9kZU5hbWVgIGRvZXMgbm90IHJlcXVpcmUgYSByZWd1bGFyIGV4cHJlc3Npb24gbWF0Y2hcbiAqIGJlY2F1c2Ugd2UgbWFrZSBhc3N1bXB0aW9ucyBhYm91dCBSZWFjdC1nZW5lcmF0ZWQgbWFya3VwIChpLmUuIHRoZXJlIGFyZSBub1xuICogc3BhY2VzIHN1cnJvdW5kaW5nIHRoZSBvcGVuaW5nIHRhZyBhbmQgdGhlcmUgaXMgYXQgbGVhc3Qgb25lIGF0dHJpYnV0ZSkuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IG1hcmt1cCBTdHJpbmcgb2YgbWFya3VwLlxuICogQHJldHVybiB7c3RyaW5nfSBOb2RlIG5hbWUgb2YgdGhlIHN1cHBsaWVkIG1hcmt1cC5cbiAqIEBzZWUgaHR0cDovL2pzcGVyZi5jb20vZXh0cmFjdC1ub2RlbmFtZVxuICovXG5mdW5jdGlvbiBnZXROb2RlTmFtZShtYXJrdXApIHtcbiAgcmV0dXJuIG1hcmt1cC5zdWJzdHJpbmcoMSwgbWFya3VwLmluZGV4T2YoJyAnKSk7XG59XG5cbnZhciBEYW5nZXIgPSB7XG5cbiAgLyoqXG4gICAqIFJlbmRlcnMgbWFya3VwIGludG8gYW4gYXJyYXkgb2Ygbm9kZXMuIFRoZSBtYXJrdXAgaXMgZXhwZWN0ZWQgdG8gcmVuZGVyXG4gICAqIGludG8gYSBsaXN0IG9mIHJvb3Qgbm9kZXMuIEFsc28sIHRoZSBsZW5ndGggb2YgYHJlc3VsdExpc3RgIGFuZFxuICAgKiBgbWFya3VwTGlzdGAgc2hvdWxkIGJlIHRoZSBzYW1lLlxuICAgKlxuICAgKiBAcGFyYW0ge2FycmF5PHN0cmluZz59IG1hcmt1cExpc3QgTGlzdCBvZiBtYXJrdXAgc3RyaW5ncyB0byByZW5kZXIuXG4gICAqIEByZXR1cm4ge2FycmF5PERPTUVsZW1lbnQ+fSBMaXN0IG9mIHJlbmRlcmVkIG5vZGVzLlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIGRhbmdlcm91c2x5UmVuZGVyTWFya3VwOiBmdW5jdGlvbihtYXJrdXBMaXN0KSB7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgIEV4ZWN1dGlvbkVudmlyb25tZW50LmNhblVzZURPTSxcbiAgICAgICdkYW5nZXJvdXNseVJlbmRlck1hcmt1cCguLi4pOiBDYW5ub3QgcmVuZGVyIG1hcmt1cCBpbiBhIHdvcmtlciAnICtcbiAgICAgICd0aHJlYWQuIE1ha2Ugc3VyZSBgd2luZG93YCBhbmQgYGRvY3VtZW50YCBhcmUgYXZhaWxhYmxlIGdsb2JhbGx5ICcgK1xuICAgICAgJ2JlZm9yZSByZXF1aXJpbmcgUmVhY3Qgd2hlbiB1bml0IHRlc3Rpbmcgb3IgdXNlICcgK1xuICAgICAgJ1JlYWN0LnJlbmRlclRvU3RyaW5nIGZvciBzZXJ2ZXIgcmVuZGVyaW5nLidcbiAgICApIDogaW52YXJpYW50KEV4ZWN1dGlvbkVudmlyb25tZW50LmNhblVzZURPTSkpO1xuICAgIHZhciBub2RlTmFtZTtcbiAgICB2YXIgbWFya3VwQnlOb2RlTmFtZSA9IHt9O1xuICAgIC8vIEdyb3VwIG1hcmt1cCBieSBgbm9kZU5hbWVgIGlmIGEgd3JhcCBpcyBuZWNlc3NhcnksIGVsc2UgYnkgJyonLlxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbWFya3VwTGlzdC5sZW5ndGg7IGkrKykge1xuICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgbWFya3VwTGlzdFtpXSxcbiAgICAgICAgJ2Rhbmdlcm91c2x5UmVuZGVyTWFya3VwKC4uLik6IE1pc3NpbmcgbWFya3VwLidcbiAgICAgICkgOiBpbnZhcmlhbnQobWFya3VwTGlzdFtpXSkpO1xuICAgICAgbm9kZU5hbWUgPSBnZXROb2RlTmFtZShtYXJrdXBMaXN0W2ldKTtcbiAgICAgIG5vZGVOYW1lID0gZ2V0TWFya3VwV3JhcChub2RlTmFtZSkgPyBub2RlTmFtZSA6ICcqJztcbiAgICAgIG1hcmt1cEJ5Tm9kZU5hbWVbbm9kZU5hbWVdID0gbWFya3VwQnlOb2RlTmFtZVtub2RlTmFtZV0gfHwgW107XG4gICAgICBtYXJrdXBCeU5vZGVOYW1lW25vZGVOYW1lXVtpXSA9IG1hcmt1cExpc3RbaV07XG4gICAgfVxuICAgIHZhciByZXN1bHRMaXN0ID0gW107XG4gICAgdmFyIHJlc3VsdExpc3RBc3NpZ25tZW50Q291bnQgPSAwO1xuICAgIGZvciAobm9kZU5hbWUgaW4gbWFya3VwQnlOb2RlTmFtZSkge1xuICAgICAgaWYgKCFtYXJrdXBCeU5vZGVOYW1lLmhhc093blByb3BlcnR5KG5vZGVOYW1lKSkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIHZhciBtYXJrdXBMaXN0QnlOb2RlTmFtZSA9IG1hcmt1cEJ5Tm9kZU5hbWVbbm9kZU5hbWVdO1xuXG4gICAgICAvLyBUaGlzIGZvci1pbiBsb29wIHNraXBzIHRoZSBob2xlcyBvZiB0aGUgc3BhcnNlIGFycmF5LiBUaGUgb3JkZXIgb2ZcbiAgICAgIC8vIGl0ZXJhdGlvbiBzaG91bGQgZm9sbG93IHRoZSBvcmRlciBvZiBhc3NpZ25tZW50LCB3aGljaCBoYXBwZW5zIHRvIG1hdGNoXG4gICAgICAvLyBudW1lcmljYWwgaW5kZXggb3JkZXIsIGJ1dCB3ZSBkb24ndCByZWx5IG9uIHRoYXQuXG4gICAgICBmb3IgKHZhciByZXN1bHRJbmRleCBpbiBtYXJrdXBMaXN0QnlOb2RlTmFtZSkge1xuICAgICAgICBpZiAobWFya3VwTGlzdEJ5Tm9kZU5hbWUuaGFzT3duUHJvcGVydHkocmVzdWx0SW5kZXgpKSB7XG4gICAgICAgICAgdmFyIG1hcmt1cCA9IG1hcmt1cExpc3RCeU5vZGVOYW1lW3Jlc3VsdEluZGV4XTtcblxuICAgICAgICAgIC8vIFB1c2ggdGhlIHJlcXVlc3RlZCBtYXJrdXAgd2l0aCBhbiBhZGRpdGlvbmFsIFJFU1VMVF9JTkRFWF9BVFRSXG4gICAgICAgICAgLy8gYXR0cmlidXRlLiAgSWYgdGhlIG1hcmt1cCBkb2VzIG5vdCBzdGFydCB3aXRoIGEgPCBjaGFyYWN0ZXIsIGl0XG4gICAgICAgICAgLy8gd2lsbCBiZSBkaXNjYXJkZWQgYmVsb3cgKHdpdGggYW4gYXBwcm9wcmlhdGUgY29uc29sZS5lcnJvcikuXG4gICAgICAgICAgbWFya3VwTGlzdEJ5Tm9kZU5hbWVbcmVzdWx0SW5kZXhdID0gbWFya3VwLnJlcGxhY2UoXG4gICAgICAgICAgICBPUEVOX1RBR19OQU1FX0VYUCxcbiAgICAgICAgICAgIC8vIFRoaXMgaW5kZXggd2lsbCBiZSBwYXJzZWQgYmFjayBvdXQgYmVsb3cuXG4gICAgICAgICAgICAnJDEgJyArIFJFU1VMVF9JTkRFWF9BVFRSICsgJz1cIicgKyByZXN1bHRJbmRleCArICdcIiAnXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBSZW5kZXIgZWFjaCBncm91cCBvZiBtYXJrdXAgd2l0aCBzaW1pbGFyIHdyYXBwaW5nIGBub2RlTmFtZWAuXG4gICAgICB2YXIgcmVuZGVyTm9kZXMgPSBjcmVhdGVOb2Rlc0Zyb21NYXJrdXAoXG4gICAgICAgIG1hcmt1cExpc3RCeU5vZGVOYW1lLmpvaW4oJycpLFxuICAgICAgICBlbXB0eUZ1bmN0aW9uIC8vIERvIG5vdGhpbmcgc3BlY2lhbCB3aXRoIDxzY3JpcHQ+IHRhZ3MuXG4gICAgICApO1xuXG4gICAgICBmb3IgKGkgPSAwOyBpIDwgcmVuZGVyTm9kZXMubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgdmFyIHJlbmRlck5vZGUgPSByZW5kZXJOb2Rlc1tpXTtcbiAgICAgICAgaWYgKHJlbmRlck5vZGUuaGFzQXR0cmlidXRlICYmXG4gICAgICAgICAgICByZW5kZXJOb2RlLmhhc0F0dHJpYnV0ZShSRVNVTFRfSU5ERVhfQVRUUikpIHtcblxuICAgICAgICAgIHJlc3VsdEluZGV4ID0gK3JlbmRlck5vZGUuZ2V0QXR0cmlidXRlKFJFU1VMVF9JTkRFWF9BVFRSKTtcbiAgICAgICAgICByZW5kZXJOb2RlLnJlbW92ZUF0dHJpYnV0ZShSRVNVTFRfSU5ERVhfQVRUUik7XG5cbiAgICAgICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICAgICAgIXJlc3VsdExpc3QuaGFzT3duUHJvcGVydHkocmVzdWx0SW5kZXgpLFxuICAgICAgICAgICAgJ0RhbmdlcjogQXNzaWduaW5nIHRvIGFuIGFscmVhZHktb2NjdXBpZWQgcmVzdWx0IGluZGV4LidcbiAgICAgICAgICApIDogaW52YXJpYW50KCFyZXN1bHRMaXN0Lmhhc093blByb3BlcnR5KHJlc3VsdEluZGV4KSkpO1xuXG4gICAgICAgICAgcmVzdWx0TGlzdFtyZXN1bHRJbmRleF0gPSByZW5kZXJOb2RlO1xuXG4gICAgICAgICAgLy8gVGhpcyBzaG91bGQgbWF0Y2ggcmVzdWx0TGlzdC5sZW5ndGggYW5kIG1hcmt1cExpc3QubGVuZ3RoIHdoZW5cbiAgICAgICAgICAvLyB3ZSdyZSBkb25lLlxuICAgICAgICAgIHJlc3VsdExpc3RBc3NpZ25tZW50Q291bnQgKz0gMTtcblxuICAgICAgICB9IGVsc2UgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXG4gICAgICAgICAgICBcIkRhbmdlcjogRGlzY2FyZGluZyB1bmV4cGVjdGVkIG5vZGU6XCIsXG4gICAgICAgICAgICByZW5kZXJOb2RlXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEFsdGhvdWdoIHJlc3VsdExpc3Qgd2FzIHBvcHVsYXRlZCBvdXQgb2Ygb3JkZXIsIGl0IHNob3VsZCBub3cgYmUgYSBkZW5zZVxuICAgIC8vIGFycmF5LlxuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICByZXN1bHRMaXN0QXNzaWdubWVudENvdW50ID09PSByZXN1bHRMaXN0Lmxlbmd0aCxcbiAgICAgICdEYW5nZXI6IERpZCBub3QgYXNzaWduIHRvIGV2ZXJ5IGluZGV4IG9mIHJlc3VsdExpc3QuJ1xuICAgICkgOiBpbnZhcmlhbnQocmVzdWx0TGlzdEFzc2lnbm1lbnRDb3VudCA9PT0gcmVzdWx0TGlzdC5sZW5ndGgpKTtcblxuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICByZXN1bHRMaXN0Lmxlbmd0aCA9PT0gbWFya3VwTGlzdC5sZW5ndGgsXG4gICAgICAnRGFuZ2VyOiBFeHBlY3RlZCBtYXJrdXAgdG8gcmVuZGVyICVzIG5vZGVzLCBidXQgcmVuZGVyZWQgJXMuJyxcbiAgICAgIG1hcmt1cExpc3QubGVuZ3RoLFxuICAgICAgcmVzdWx0TGlzdC5sZW5ndGhcbiAgICApIDogaW52YXJpYW50KHJlc3VsdExpc3QubGVuZ3RoID09PSBtYXJrdXBMaXN0Lmxlbmd0aCkpO1xuXG4gICAgcmV0dXJuIHJlc3VsdExpc3Q7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFJlcGxhY2VzIGEgbm9kZSB3aXRoIGEgc3RyaW5nIG9mIG1hcmt1cCBhdCBpdHMgY3VycmVudCBwb3NpdGlvbiB3aXRoaW4gaXRzXG4gICAqIHBhcmVudC4gVGhlIG1hcmt1cCBtdXN0IHJlbmRlciBpbnRvIGEgc2luZ2xlIHJvb3Qgbm9kZS5cbiAgICpcbiAgICogQHBhcmFtIHtET01FbGVtZW50fSBvbGRDaGlsZCBDaGlsZCBub2RlIHRvIHJlcGxhY2UuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtYXJrdXAgTWFya3VwIHRvIHJlbmRlciBpbiBwbGFjZSBvZiB0aGUgY2hpbGQgbm9kZS5cbiAgICogQGludGVybmFsXG4gICAqL1xuICBkYW5nZXJvdXNseVJlcGxhY2VOb2RlV2l0aE1hcmt1cDogZnVuY3Rpb24ob2xkQ2hpbGQsIG1hcmt1cCkge1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICBFeGVjdXRpb25FbnZpcm9ubWVudC5jYW5Vc2VET00sXG4gICAgICAnZGFuZ2Vyb3VzbHlSZXBsYWNlTm9kZVdpdGhNYXJrdXAoLi4uKTogQ2Fubm90IHJlbmRlciBtYXJrdXAgaW4gYSAnICtcbiAgICAgICd3b3JrZXIgdGhyZWFkLiBNYWtlIHN1cmUgYHdpbmRvd2AgYW5kIGBkb2N1bWVudGAgYXJlIGF2YWlsYWJsZSAnICtcbiAgICAgICdnbG9iYWxseSBiZWZvcmUgcmVxdWlyaW5nIFJlYWN0IHdoZW4gdW5pdCB0ZXN0aW5nIG9yIHVzZSAnICtcbiAgICAgICdSZWFjdC5yZW5kZXJUb1N0cmluZyBmb3Igc2VydmVyIHJlbmRlcmluZy4nXG4gICAgKSA6IGludmFyaWFudChFeGVjdXRpb25FbnZpcm9ubWVudC5jYW5Vc2VET00pKTtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KG1hcmt1cCwgJ2Rhbmdlcm91c2x5UmVwbGFjZU5vZGVXaXRoTWFya3VwKC4uLik6IE1pc3NpbmcgbWFya3VwLicpIDogaW52YXJpYW50KG1hcmt1cCkpO1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICBvbGRDaGlsZC50YWdOYW1lLnRvTG93ZXJDYXNlKCkgIT09ICdodG1sJyxcbiAgICAgICdkYW5nZXJvdXNseVJlcGxhY2VOb2RlV2l0aE1hcmt1cCguLi4pOiBDYW5ub3QgcmVwbGFjZSBtYXJrdXAgb2YgdGhlICcgK1xuICAgICAgJzxodG1sPiBub2RlLiBUaGlzIGlzIGJlY2F1c2UgYnJvd3NlciBxdWlya3MgbWFrZSB0aGlzIHVucmVsaWFibGUgJyArXG4gICAgICAnYW5kL29yIHNsb3cuIElmIHlvdSB3YW50IHRvIHJlbmRlciB0byB0aGUgcm9vdCB5b3UgbXVzdCB1c2UgJyArXG4gICAgICAnc2VydmVyIHJlbmRlcmluZy4gU2VlIHJlbmRlckNvbXBvbmVudFRvU3RyaW5nKCkuJ1xuICAgICkgOiBpbnZhcmlhbnQob2xkQ2hpbGQudGFnTmFtZS50b0xvd2VyQ2FzZSgpICE9PSAnaHRtbCcpKTtcblxuICAgIHZhciBuZXdDaGlsZCA9IGNyZWF0ZU5vZGVzRnJvbU1hcmt1cChtYXJrdXAsIGVtcHR5RnVuY3Rpb24pWzBdO1xuICAgIG9sZENoaWxkLnBhcmVudE5vZGUucmVwbGFjZUNoaWxkKG5ld0NoaWxkLCBvbGRDaGlsZCk7XG4gIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBEYW5nZXI7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBEZWZhdWx0RXZlbnRQbHVnaW5PcmRlclxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG4gdmFyIGtleU9mID0gcmVxdWlyZShcIi4va2V5T2ZcIik7XG5cbi8qKlxuICogTW9kdWxlIHRoYXQgaXMgaW5qZWN0YWJsZSBpbnRvIGBFdmVudFBsdWdpbkh1YmAsIHRoYXQgc3BlY2lmaWVzIGFcbiAqIGRldGVybWluaXN0aWMgb3JkZXJpbmcgb2YgYEV2ZW50UGx1Z2luYHMuIEEgY29udmVuaWVudCB3YXkgdG8gcmVhc29uIGFib3V0XG4gKiBwbHVnaW5zLCB3aXRob3V0IGhhdmluZyB0byBwYWNrYWdlIGV2ZXJ5IG9uZSBvZiB0aGVtLiBUaGlzIGlzIGJldHRlciB0aGFuXG4gKiBoYXZpbmcgcGx1Z2lucyBiZSBvcmRlcmVkIGluIHRoZSBzYW1lIG9yZGVyIHRoYXQgdGhleSBhcmUgaW5qZWN0ZWQgYmVjYXVzZVxuICogdGhhdCBvcmRlcmluZyB3b3VsZCBiZSBpbmZsdWVuY2VkIGJ5IHRoZSBwYWNrYWdpbmcgb3JkZXIuXG4gKiBgUmVzcG9uZGVyRXZlbnRQbHVnaW5gIG11c3Qgb2NjdXIgYmVmb3JlIGBTaW1wbGVFdmVudFBsdWdpbmAgc28gdGhhdFxuICogcHJldmVudGluZyBkZWZhdWx0IG9uIGV2ZW50cyBpcyBjb252ZW5pZW50IGluIGBTaW1wbGVFdmVudFBsdWdpbmAgaGFuZGxlcnMuXG4gKi9cbnZhciBEZWZhdWx0RXZlbnRQbHVnaW5PcmRlciA9IFtcbiAga2V5T2Yoe1Jlc3BvbmRlckV2ZW50UGx1Z2luOiBudWxsfSksXG4gIGtleU9mKHtTaW1wbGVFdmVudFBsdWdpbjogbnVsbH0pLFxuICBrZXlPZih7VGFwRXZlbnRQbHVnaW46IG51bGx9KSxcbiAga2V5T2Yoe0VudGVyTGVhdmVFdmVudFBsdWdpbjogbnVsbH0pLFxuICBrZXlPZih7Q2hhbmdlRXZlbnRQbHVnaW46IG51bGx9KSxcbiAga2V5T2Yoe1NlbGVjdEV2ZW50UGx1Z2luOiBudWxsfSksXG4gIGtleU9mKHtDb21wb3NpdGlvbkV2ZW50UGx1Z2luOiBudWxsfSksXG4gIGtleU9mKHtCZWZvcmVJbnB1dEV2ZW50UGx1Z2luOiBudWxsfSksXG4gIGtleU9mKHtBbmFseXRpY3NFdmVudFBsdWdpbjogbnVsbH0pLFxuICBrZXlPZih7TW9iaWxlU2FmYXJpQ2xpY2tFdmVudFBsdWdpbjogbnVsbH0pXG5dO1xuXG5tb2R1bGUuZXhwb3J0cyA9IERlZmF1bHRFdmVudFBsdWdpbk9yZGVyO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIEVudGVyTGVhdmVFdmVudFBsdWdpblxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIEV2ZW50Q29uc3RhbnRzID0gcmVxdWlyZShcIi4vRXZlbnRDb25zdGFudHNcIik7XG52YXIgRXZlbnRQcm9wYWdhdG9ycyA9IHJlcXVpcmUoXCIuL0V2ZW50UHJvcGFnYXRvcnNcIik7XG52YXIgU3ludGhldGljTW91c2VFdmVudCA9IHJlcXVpcmUoXCIuL1N5bnRoZXRpY01vdXNlRXZlbnRcIik7XG5cbnZhciBSZWFjdE1vdW50ID0gcmVxdWlyZShcIi4vUmVhY3RNb3VudFwiKTtcbnZhciBrZXlPZiA9IHJlcXVpcmUoXCIuL2tleU9mXCIpO1xuXG52YXIgdG9wTGV2ZWxUeXBlcyA9IEV2ZW50Q29uc3RhbnRzLnRvcExldmVsVHlwZXM7XG52YXIgZ2V0Rmlyc3RSZWFjdERPTSA9IFJlYWN0TW91bnQuZ2V0Rmlyc3RSZWFjdERPTTtcblxudmFyIGV2ZW50VHlwZXMgPSB7XG4gIG1vdXNlRW50ZXI6IHtcbiAgICByZWdpc3RyYXRpb25OYW1lOiBrZXlPZih7b25Nb3VzZUVudGVyOiBudWxsfSksXG4gICAgZGVwZW5kZW5jaWVzOiBbXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcE1vdXNlT3V0LFxuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BNb3VzZU92ZXJcbiAgICBdXG4gIH0sXG4gIG1vdXNlTGVhdmU6IHtcbiAgICByZWdpc3RyYXRpb25OYW1lOiBrZXlPZih7b25Nb3VzZUxlYXZlOiBudWxsfSksXG4gICAgZGVwZW5kZW5jaWVzOiBbXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcE1vdXNlT3V0LFxuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BNb3VzZU92ZXJcbiAgICBdXG4gIH1cbn07XG5cbnZhciBleHRyYWN0ZWRFdmVudHMgPSBbbnVsbCwgbnVsbF07XG5cbnZhciBFbnRlckxlYXZlRXZlbnRQbHVnaW4gPSB7XG5cbiAgZXZlbnRUeXBlczogZXZlbnRUeXBlcyxcblxuICAvKipcbiAgICogRm9yIGFsbW9zdCBldmVyeSBpbnRlcmFjdGlvbiB3ZSBjYXJlIGFib3V0LCB0aGVyZSB3aWxsIGJlIGJvdGggYSB0b3AtbGV2ZWxcbiAgICogYG1vdXNlb3ZlcmAgYW5kIGBtb3VzZW91dGAgZXZlbnQgdGhhdCBvY2N1cnMuIE9ubHkgdXNlIGBtb3VzZW91dGAgc28gdGhhdFxuICAgKiB3ZSBkbyBub3QgZXh0cmFjdCBkdXBsaWNhdGUgZXZlbnRzLiBIb3dldmVyLCBtb3ZpbmcgdGhlIG1vdXNlIGludG8gdGhlXG4gICAqIGJyb3dzZXIgZnJvbSBvdXRzaWRlIHdpbGwgbm90IGZpcmUgYSBgbW91c2VvdXRgIGV2ZW50LiBJbiB0aGlzIGNhc2UsIHdlIHVzZVxuICAgKiB0aGUgYG1vdXNlb3ZlcmAgdG9wLWxldmVsIGV2ZW50LlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gdG9wTGV2ZWxUeXBlIFJlY29yZCBmcm9tIGBFdmVudENvbnN0YW50c2AuXG4gICAqIEBwYXJhbSB7RE9NRXZlbnRUYXJnZXR9IHRvcExldmVsVGFyZ2V0IFRoZSBsaXN0ZW5pbmcgY29tcG9uZW50IHJvb3Qgbm9kZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHRvcExldmVsVGFyZ2V0SUQgSUQgb2YgYHRvcExldmVsVGFyZ2V0YC5cbiAgICogQHBhcmFtIHtvYmplY3R9IG5hdGl2ZUV2ZW50IE5hdGl2ZSBicm93c2VyIGV2ZW50LlxuICAgKiBAcmV0dXJuIHsqfSBBbiBhY2N1bXVsYXRpb24gb2Ygc3ludGhldGljIGV2ZW50cy5cbiAgICogQHNlZSB7RXZlbnRQbHVnaW5IdWIuZXh0cmFjdEV2ZW50c31cbiAgICovXG4gIGV4dHJhY3RFdmVudHM6IGZ1bmN0aW9uKFxuICAgICAgdG9wTGV2ZWxUeXBlLFxuICAgICAgdG9wTGV2ZWxUYXJnZXQsXG4gICAgICB0b3BMZXZlbFRhcmdldElELFxuICAgICAgbmF0aXZlRXZlbnQpIHtcbiAgICBpZiAodG9wTGV2ZWxUeXBlID09PSB0b3BMZXZlbFR5cGVzLnRvcE1vdXNlT3ZlciAmJlxuICAgICAgICAobmF0aXZlRXZlbnQucmVsYXRlZFRhcmdldCB8fCBuYXRpdmVFdmVudC5mcm9tRWxlbWVudCkpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICBpZiAodG9wTGV2ZWxUeXBlICE9PSB0b3BMZXZlbFR5cGVzLnRvcE1vdXNlT3V0ICYmXG4gICAgICAgIHRvcExldmVsVHlwZSAhPT0gdG9wTGV2ZWxUeXBlcy50b3BNb3VzZU92ZXIpIHtcbiAgICAgIC8vIE11c3Qgbm90IGJlIGEgbW91c2UgaW4gb3IgbW91c2Ugb3V0IC0gaWdub3JpbmcuXG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICB2YXIgd2luO1xuICAgIGlmICh0b3BMZXZlbFRhcmdldC53aW5kb3cgPT09IHRvcExldmVsVGFyZ2V0KSB7XG4gICAgICAvLyBgdG9wTGV2ZWxUYXJnZXRgIGlzIHByb2JhYmx5IGEgd2luZG93IG9iamVjdC5cbiAgICAgIHdpbiA9IHRvcExldmVsVGFyZ2V0O1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBUT0RPOiBGaWd1cmUgb3V0IHdoeSBgb3duZXJEb2N1bWVudGAgaXMgc29tZXRpbWVzIHVuZGVmaW5lZCBpbiBJRTguXG4gICAgICB2YXIgZG9jID0gdG9wTGV2ZWxUYXJnZXQub3duZXJEb2N1bWVudDtcbiAgICAgIGlmIChkb2MpIHtcbiAgICAgICAgd2luID0gZG9jLmRlZmF1bHRWaWV3IHx8IGRvYy5wYXJlbnRXaW5kb3c7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB3aW4gPSB3aW5kb3c7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdmFyIGZyb20sIHRvO1xuICAgIGlmICh0b3BMZXZlbFR5cGUgPT09IHRvcExldmVsVHlwZXMudG9wTW91c2VPdXQpIHtcbiAgICAgIGZyb20gPSB0b3BMZXZlbFRhcmdldDtcbiAgICAgIHRvID1cbiAgICAgICAgZ2V0Rmlyc3RSZWFjdERPTShuYXRpdmVFdmVudC5yZWxhdGVkVGFyZ2V0IHx8IG5hdGl2ZUV2ZW50LnRvRWxlbWVudCkgfHxcbiAgICAgICAgd2luO1xuICAgIH0gZWxzZSB7XG4gICAgICBmcm9tID0gd2luO1xuICAgICAgdG8gPSB0b3BMZXZlbFRhcmdldDtcbiAgICB9XG5cbiAgICBpZiAoZnJvbSA9PT0gdG8pIHtcbiAgICAgIC8vIE5vdGhpbmcgcGVydGFpbnMgdG8gb3VyIG1hbmFnZWQgY29tcG9uZW50cy5cbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHZhciBmcm9tSUQgPSBmcm9tID8gUmVhY3RNb3VudC5nZXRJRChmcm9tKSA6ICcnO1xuICAgIHZhciB0b0lEID0gdG8gPyBSZWFjdE1vdW50LmdldElEKHRvKSA6ICcnO1xuXG4gICAgdmFyIGxlYXZlID0gU3ludGhldGljTW91c2VFdmVudC5nZXRQb29sZWQoXG4gICAgICBldmVudFR5cGVzLm1vdXNlTGVhdmUsXG4gICAgICBmcm9tSUQsXG4gICAgICBuYXRpdmVFdmVudFxuICAgICk7XG4gICAgbGVhdmUudHlwZSA9ICdtb3VzZWxlYXZlJztcbiAgICBsZWF2ZS50YXJnZXQgPSBmcm9tO1xuICAgIGxlYXZlLnJlbGF0ZWRUYXJnZXQgPSB0bztcblxuICAgIHZhciBlbnRlciA9IFN5bnRoZXRpY01vdXNlRXZlbnQuZ2V0UG9vbGVkKFxuICAgICAgZXZlbnRUeXBlcy5tb3VzZUVudGVyLFxuICAgICAgdG9JRCxcbiAgICAgIG5hdGl2ZUV2ZW50XG4gICAgKTtcbiAgICBlbnRlci50eXBlID0gJ21vdXNlZW50ZXInO1xuICAgIGVudGVyLnRhcmdldCA9IHRvO1xuICAgIGVudGVyLnJlbGF0ZWRUYXJnZXQgPSBmcm9tO1xuXG4gICAgRXZlbnRQcm9wYWdhdG9ycy5hY2N1bXVsYXRlRW50ZXJMZWF2ZURpc3BhdGNoZXMobGVhdmUsIGVudGVyLCBmcm9tSUQsIHRvSUQpO1xuXG4gICAgZXh0cmFjdGVkRXZlbnRzWzBdID0gbGVhdmU7XG4gICAgZXh0cmFjdGVkRXZlbnRzWzFdID0gZW50ZXI7XG5cbiAgICByZXR1cm4gZXh0cmFjdGVkRXZlbnRzO1xuICB9XG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gRW50ZXJMZWF2ZUV2ZW50UGx1Z2luO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIEV2ZW50Q29uc3RhbnRzXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBrZXlNaXJyb3IgPSByZXF1aXJlKFwiLi9rZXlNaXJyb3JcIik7XG5cbnZhciBQcm9wYWdhdGlvblBoYXNlcyA9IGtleU1pcnJvcih7YnViYmxlZDogbnVsbCwgY2FwdHVyZWQ6IG51bGx9KTtcblxuLyoqXG4gKiBUeXBlcyBvZiByYXcgc2lnbmFscyBmcm9tIHRoZSBicm93c2VyIGNhdWdodCBhdCB0aGUgdG9wIGxldmVsLlxuICovXG52YXIgdG9wTGV2ZWxUeXBlcyA9IGtleU1pcnJvcih7XG4gIHRvcEJsdXI6IG51bGwsXG4gIHRvcENoYW5nZTogbnVsbCxcbiAgdG9wQ2xpY2s6IG51bGwsXG4gIHRvcENvbXBvc2l0aW9uRW5kOiBudWxsLFxuICB0b3BDb21wb3NpdGlvblN0YXJ0OiBudWxsLFxuICB0b3BDb21wb3NpdGlvblVwZGF0ZTogbnVsbCxcbiAgdG9wQ29udGV4dE1lbnU6IG51bGwsXG4gIHRvcENvcHk6IG51bGwsXG4gIHRvcEN1dDogbnVsbCxcbiAgdG9wRG91YmxlQ2xpY2s6IG51bGwsXG4gIHRvcERyYWc6IG51bGwsXG4gIHRvcERyYWdFbmQ6IG51bGwsXG4gIHRvcERyYWdFbnRlcjogbnVsbCxcbiAgdG9wRHJhZ0V4aXQ6IG51bGwsXG4gIHRvcERyYWdMZWF2ZTogbnVsbCxcbiAgdG9wRHJhZ092ZXI6IG51bGwsXG4gIHRvcERyYWdTdGFydDogbnVsbCxcbiAgdG9wRHJvcDogbnVsbCxcbiAgdG9wRXJyb3I6IG51bGwsXG4gIHRvcEZvY3VzOiBudWxsLFxuICB0b3BJbnB1dDogbnVsbCxcbiAgdG9wS2V5RG93bjogbnVsbCxcbiAgdG9wS2V5UHJlc3M6IG51bGwsXG4gIHRvcEtleVVwOiBudWxsLFxuICB0b3BMb2FkOiBudWxsLFxuICB0b3BNb3VzZURvd246IG51bGwsXG4gIHRvcE1vdXNlTW92ZTogbnVsbCxcbiAgdG9wTW91c2VPdXQ6IG51bGwsXG4gIHRvcE1vdXNlT3ZlcjogbnVsbCxcbiAgdG9wTW91c2VVcDogbnVsbCxcbiAgdG9wUGFzdGU6IG51bGwsXG4gIHRvcFJlc2V0OiBudWxsLFxuICB0b3BTY3JvbGw6IG51bGwsXG4gIHRvcFNlbGVjdGlvbkNoYW5nZTogbnVsbCxcbiAgdG9wU3VibWl0OiBudWxsLFxuICB0b3BUZXh0SW5wdXQ6IG51bGwsXG4gIHRvcFRvdWNoQ2FuY2VsOiBudWxsLFxuICB0b3BUb3VjaEVuZDogbnVsbCxcbiAgdG9wVG91Y2hNb3ZlOiBudWxsLFxuICB0b3BUb3VjaFN0YXJ0OiBudWxsLFxuICB0b3BXaGVlbDogbnVsbFxufSk7XG5cbnZhciBFdmVudENvbnN0YW50cyA9IHtcbiAgdG9wTGV2ZWxUeXBlczogdG9wTGV2ZWxUeXBlcyxcbiAgUHJvcGFnYXRpb25QaGFzZXM6IFByb3BhZ2F0aW9uUGhhc2VzXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEV2ZW50Q29uc3RhbnRzO1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCBGYWNlYm9vaywgSW5jLlxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBFdmVudExpc3RlbmVyXG4gKiBAdHlwZWNoZWNrc1xuICovXG5cbnZhciBlbXB0eUZ1bmN0aW9uID0gcmVxdWlyZShcIi4vZW1wdHlGdW5jdGlvblwiKTtcblxuLyoqXG4gKiBVcHN0cmVhbSB2ZXJzaW9uIG9mIGV2ZW50IGxpc3RlbmVyLiBEb2VzIG5vdCB0YWtlIGludG8gYWNjb3VudCBzcGVjaWZpY1xuICogbmF0dXJlIG9mIHBsYXRmb3JtLlxuICovXG52YXIgRXZlbnRMaXN0ZW5lciA9IHtcbiAgLyoqXG4gICAqIExpc3RlbiB0byBET00gZXZlbnRzIGR1cmluZyB0aGUgYnViYmxlIHBoYXNlLlxuICAgKlxuICAgKiBAcGFyYW0ge0RPTUV2ZW50VGFyZ2V0fSB0YXJnZXQgRE9NIGVsZW1lbnQgdG8gcmVnaXN0ZXIgbGlzdGVuZXIgb24uXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBldmVudFR5cGUgRXZlbnQgdHlwZSwgZS5nLiAnY2xpY2snIG9yICdtb3VzZW92ZXInLlxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBjYWxsYmFjayBDYWxsYmFjayBmdW5jdGlvbi5cbiAgICogQHJldHVybiB7b2JqZWN0fSBPYmplY3Qgd2l0aCBhIGByZW1vdmVgIG1ldGhvZC5cbiAgICovXG4gIGxpc3RlbjogZnVuY3Rpb24odGFyZ2V0LCBldmVudFR5cGUsIGNhbGxiYWNrKSB7XG4gICAgaWYgKHRhcmdldC5hZGRFdmVudExpc3RlbmVyKSB7XG4gICAgICB0YXJnZXQuYWRkRXZlbnRMaXN0ZW5lcihldmVudFR5cGUsIGNhbGxiYWNrLCBmYWxzZSk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICByZW1vdmU6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgIHRhcmdldC5yZW1vdmVFdmVudExpc3RlbmVyKGV2ZW50VHlwZSwgY2FsbGJhY2ssIGZhbHNlKTtcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICB9IGVsc2UgaWYgKHRhcmdldC5hdHRhY2hFdmVudCkge1xuICAgICAgdGFyZ2V0LmF0dGFjaEV2ZW50KCdvbicgKyBldmVudFR5cGUsIGNhbGxiYWNrKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHJlbW92ZTogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgdGFyZ2V0LmRldGFjaEV2ZW50KCdvbicgKyBldmVudFR5cGUsIGNhbGxiYWNrKTtcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICB9XG4gIH0sXG5cbiAgLyoqXG4gICAqIExpc3RlbiB0byBET00gZXZlbnRzIGR1cmluZyB0aGUgY2FwdHVyZSBwaGFzZS5cbiAgICpcbiAgICogQHBhcmFtIHtET01FdmVudFRhcmdldH0gdGFyZ2V0IERPTSBlbGVtZW50IHRvIHJlZ2lzdGVyIGxpc3RlbmVyIG9uLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gZXZlbnRUeXBlIEV2ZW50IHR5cGUsIGUuZy4gJ2NsaWNrJyBvciAnbW91c2VvdmVyJy5cbiAgICogQHBhcmFtIHtmdW5jdGlvbn0gY2FsbGJhY2sgQ2FsbGJhY2sgZnVuY3Rpb24uXG4gICAqIEByZXR1cm4ge29iamVjdH0gT2JqZWN0IHdpdGggYSBgcmVtb3ZlYCBtZXRob2QuXG4gICAqL1xuICBjYXB0dXJlOiBmdW5jdGlvbih0YXJnZXQsIGV2ZW50VHlwZSwgY2FsbGJhY2spIHtcbiAgICBpZiAoIXRhcmdldC5hZGRFdmVudExpc3RlbmVyKSB7XG4gICAgICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXG4gICAgICAgICAgJ0F0dGVtcHRlZCB0byBsaXN0ZW4gdG8gZXZlbnRzIGR1cmluZyB0aGUgY2FwdHVyZSBwaGFzZSBvbiBhICcgK1xuICAgICAgICAgICdicm93c2VyIHRoYXQgZG9lcyBub3Qgc3VwcG9ydCB0aGUgY2FwdHVyZSBwaGFzZS4gWW91ciBhcHBsaWNhdGlvbiAnICtcbiAgICAgICAgICAnd2lsbCBub3QgcmVjZWl2ZSBzb21lIGV2ZW50cy4nXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICByZXR1cm4ge1xuICAgICAgICByZW1vdmU6IGVtcHR5RnVuY3Rpb25cbiAgICAgIH07XG4gICAgfSBlbHNlIHtcbiAgICAgIHRhcmdldC5hZGRFdmVudExpc3RlbmVyKGV2ZW50VHlwZSwgY2FsbGJhY2ssIHRydWUpO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgcmVtb3ZlOiBmdW5jdGlvbigpIHtcbiAgICAgICAgICB0YXJnZXQucmVtb3ZlRXZlbnRMaXN0ZW5lcihldmVudFR5cGUsIGNhbGxiYWNrLCB0cnVlKTtcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICB9XG4gIH0sXG5cbiAgcmVnaXN0ZXJEZWZhdWx0OiBmdW5jdGlvbigpIHt9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEV2ZW50TGlzdGVuZXI7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgRXZlbnRQbHVnaW5IdWJcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIEV2ZW50UGx1Z2luUmVnaXN0cnkgPSByZXF1aXJlKFwiLi9FdmVudFBsdWdpblJlZ2lzdHJ5XCIpO1xudmFyIEV2ZW50UGx1Z2luVXRpbHMgPSByZXF1aXJlKFwiLi9FdmVudFBsdWdpblV0aWxzXCIpO1xuXG52YXIgYWNjdW11bGF0ZUludG8gPSByZXF1aXJlKFwiLi9hY2N1bXVsYXRlSW50b1wiKTtcbnZhciBmb3JFYWNoQWNjdW11bGF0ZWQgPSByZXF1aXJlKFwiLi9mb3JFYWNoQWNjdW11bGF0ZWRcIik7XG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG4vKipcbiAqIEludGVybmFsIHN0b3JlIGZvciBldmVudCBsaXN0ZW5lcnNcbiAqL1xudmFyIGxpc3RlbmVyQmFuayA9IHt9O1xuXG4vKipcbiAqIEludGVybmFsIHF1ZXVlIG9mIGV2ZW50cyB0aGF0IGhhdmUgYWNjdW11bGF0ZWQgdGhlaXIgZGlzcGF0Y2hlcyBhbmQgYXJlXG4gKiB3YWl0aW5nIHRvIGhhdmUgdGhlaXIgZGlzcGF0Y2hlcyBleGVjdXRlZC5cbiAqL1xudmFyIGV2ZW50UXVldWUgPSBudWxsO1xuXG4vKipcbiAqIERpc3BhdGNoZXMgYW4gZXZlbnQgYW5kIHJlbGVhc2VzIGl0IGJhY2sgaW50byB0aGUgcG9vbCwgdW5sZXNzIHBlcnNpc3RlbnQuXG4gKlxuICogQHBhcmFtIHs/b2JqZWN0fSBldmVudCBTeW50aGV0aWMgZXZlbnQgdG8gYmUgZGlzcGF0Y2hlZC5cbiAqIEBwcml2YXRlXG4gKi9cbnZhciBleGVjdXRlRGlzcGF0Y2hlc0FuZFJlbGVhc2UgPSBmdW5jdGlvbihldmVudCkge1xuICBpZiAoZXZlbnQpIHtcbiAgICB2YXIgZXhlY3V0ZURpc3BhdGNoID0gRXZlbnRQbHVnaW5VdGlscy5leGVjdXRlRGlzcGF0Y2g7XG4gICAgLy8gUGx1Z2lucyBjYW4gcHJvdmlkZSBjdXN0b20gYmVoYXZpb3Igd2hlbiBkaXNwYXRjaGluZyBldmVudHMuXG4gICAgdmFyIFBsdWdpbk1vZHVsZSA9IEV2ZW50UGx1Z2luUmVnaXN0cnkuZ2V0UGx1Z2luTW9kdWxlRm9yRXZlbnQoZXZlbnQpO1xuICAgIGlmIChQbHVnaW5Nb2R1bGUgJiYgUGx1Z2luTW9kdWxlLmV4ZWN1dGVEaXNwYXRjaCkge1xuICAgICAgZXhlY3V0ZURpc3BhdGNoID0gUGx1Z2luTW9kdWxlLmV4ZWN1dGVEaXNwYXRjaDtcbiAgICB9XG4gICAgRXZlbnRQbHVnaW5VdGlscy5leGVjdXRlRGlzcGF0Y2hlc0luT3JkZXIoZXZlbnQsIGV4ZWN1dGVEaXNwYXRjaCk7XG5cbiAgICBpZiAoIWV2ZW50LmlzUGVyc2lzdGVudCgpKSB7XG4gICAgICBldmVudC5jb25zdHJ1Y3Rvci5yZWxlYXNlKGV2ZW50KTtcbiAgICB9XG4gIH1cbn07XG5cbi8qKlxuICogLSBgSW5zdGFuY2VIYW5kbGVgOiBbcmVxdWlyZWRdIE1vZHVsZSB0aGF0IHBlcmZvcm1zIGxvZ2ljYWwgdHJhdmVyc2FscyBvZiBET01cbiAqICAgaGllcmFyY2h5IGdpdmVuIGlkcyBvZiB0aGUgbG9naWNhbCBET00gZWxlbWVudHMgaW52b2x2ZWQuXG4gKi9cbnZhciBJbnN0YW5jZUhhbmRsZSA9IG51bGw7XG5cbmZ1bmN0aW9uIHZhbGlkYXRlSW5zdGFuY2VIYW5kbGUoKSB7XG4gIHZhciBpbnZhbGlkID0gIUluc3RhbmNlSGFuZGxlfHxcbiAgICAhSW5zdGFuY2VIYW5kbGUudHJhdmVyc2VUd29QaGFzZSB8fFxuICAgICFJbnN0YW5jZUhhbmRsZS50cmF2ZXJzZUVudGVyTGVhdmU7XG4gIGlmIChpbnZhbGlkKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdJbnN0YW5jZUhhbmRsZSBub3QgaW5qZWN0ZWQgYmVmb3JlIHVzZSEnKTtcbiAgfVxufVxuXG4vKipcbiAqIFRoaXMgaXMgYSB1bmlmaWVkIGludGVyZmFjZSBmb3IgZXZlbnQgcGx1Z2lucyB0byBiZSBpbnN0YWxsZWQgYW5kIGNvbmZpZ3VyZWQuXG4gKlxuICogRXZlbnQgcGx1Z2lucyBjYW4gaW1wbGVtZW50IHRoZSBmb2xsb3dpbmcgcHJvcGVydGllczpcbiAqXG4gKiAgIGBleHRyYWN0RXZlbnRzYCB7ZnVuY3Rpb24oc3RyaW5nLCBET01FdmVudFRhcmdldCwgc3RyaW5nLCBvYmplY3QpOiAqfVxuICogICAgIFJlcXVpcmVkLiBXaGVuIGEgdG9wLWxldmVsIGV2ZW50IGlzIGZpcmVkLCB0aGlzIG1ldGhvZCBpcyBleHBlY3RlZCB0b1xuICogICAgIGV4dHJhY3Qgc3ludGhldGljIGV2ZW50cyB0aGF0IHdpbGwgaW4gdHVybiBiZSBxdWV1ZWQgYW5kIGRpc3BhdGNoZWQuXG4gKlxuICogICBgZXZlbnRUeXBlc2Age29iamVjdH1cbiAqICAgICBPcHRpb25hbCwgcGx1Z2lucyB0aGF0IGZpcmUgZXZlbnRzIG11c3QgcHVibGlzaCBhIG1hcHBpbmcgb2YgcmVnaXN0cmF0aW9uXG4gKiAgICAgbmFtZXMgdGhhdCBhcmUgdXNlZCB0byByZWdpc3RlciBsaXN0ZW5lcnMuIFZhbHVlcyBvZiB0aGlzIG1hcHBpbmcgbXVzdFxuICogICAgIGJlIG9iamVjdHMgdGhhdCBjb250YWluIGByZWdpc3RyYXRpb25OYW1lYCBvciBgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXNgLlxuICpcbiAqICAgYGV4ZWN1dGVEaXNwYXRjaGAge2Z1bmN0aW9uKG9iamVjdCwgZnVuY3Rpb24sIHN0cmluZyl9XG4gKiAgICAgT3B0aW9uYWwsIGFsbG93cyBwbHVnaW5zIHRvIG92ZXJyaWRlIGhvdyBhbiBldmVudCBnZXRzIGRpc3BhdGNoZWQuIEJ5XG4gKiAgICAgZGVmYXVsdCwgdGhlIGxpc3RlbmVyIGlzIHNpbXBseSBpbnZva2VkLlxuICpcbiAqIEVhY2ggcGx1Z2luIHRoYXQgaXMgaW5qZWN0ZWQgaW50byBgRXZlbnRzUGx1Z2luSHViYCBpcyBpbW1lZGlhdGVseSBvcGVyYWJsZS5cbiAqXG4gKiBAcHVibGljXG4gKi9cbnZhciBFdmVudFBsdWdpbkh1YiA9IHtcblxuICAvKipcbiAgICogTWV0aG9kcyBmb3IgaW5qZWN0aW5nIGRlcGVuZGVuY2llcy5cbiAgICovXG4gIGluamVjdGlvbjoge1xuXG4gICAgLyoqXG4gICAgICogQHBhcmFtIHtvYmplY3R9IEluamVjdGVkTW91bnRcbiAgICAgKiBAcHVibGljXG4gICAgICovXG4gICAgaW5qZWN0TW91bnQ6IEV2ZW50UGx1Z2luVXRpbHMuaW5qZWN0aW9uLmluamVjdE1vdW50LFxuXG4gICAgLyoqXG4gICAgICogQHBhcmFtIHtvYmplY3R9IEluamVjdGVkSW5zdGFuY2VIYW5kbGVcbiAgICAgKiBAcHVibGljXG4gICAgICovXG4gICAgaW5qZWN0SW5zdGFuY2VIYW5kbGU6IGZ1bmN0aW9uKEluamVjdGVkSW5zdGFuY2VIYW5kbGUpIHtcbiAgICAgIEluc3RhbmNlSGFuZGxlID0gSW5qZWN0ZWRJbnN0YW5jZUhhbmRsZTtcbiAgICAgIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgICAgdmFsaWRhdGVJbnN0YW5jZUhhbmRsZSgpO1xuICAgICAgfVxuICAgIH0sXG5cbiAgICBnZXRJbnN0YW5jZUhhbmRsZTogZnVuY3Rpb24oKSB7XG4gICAgICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgICAgIHZhbGlkYXRlSW5zdGFuY2VIYW5kbGUoKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBJbnN0YW5jZUhhbmRsZTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQHBhcmFtIHthcnJheX0gSW5qZWN0ZWRFdmVudFBsdWdpbk9yZGVyXG4gICAgICogQHB1YmxpY1xuICAgICAqL1xuICAgIGluamVjdEV2ZW50UGx1Z2luT3JkZXI6IEV2ZW50UGx1Z2luUmVnaXN0cnkuaW5qZWN0RXZlbnRQbHVnaW5PcmRlcixcblxuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBpbmplY3RlZE5hbWVzVG9QbHVnaW5zIE1hcCBmcm9tIG5hbWVzIHRvIHBsdWdpbiBtb2R1bGVzLlxuICAgICAqL1xuICAgIGluamVjdEV2ZW50UGx1Z2luc0J5TmFtZTogRXZlbnRQbHVnaW5SZWdpc3RyeS5pbmplY3RFdmVudFBsdWdpbnNCeU5hbWVcblxuICB9LFxuXG4gIGV2ZW50TmFtZURpc3BhdGNoQ29uZmlnczogRXZlbnRQbHVnaW5SZWdpc3RyeS5ldmVudE5hbWVEaXNwYXRjaENvbmZpZ3MsXG5cbiAgcmVnaXN0cmF0aW9uTmFtZU1vZHVsZXM6IEV2ZW50UGx1Z2luUmVnaXN0cnkucmVnaXN0cmF0aW9uTmFtZU1vZHVsZXMsXG5cbiAgLyoqXG4gICAqIFN0b3JlcyBgbGlzdGVuZXJgIGF0IGBsaXN0ZW5lckJhbmtbcmVnaXN0cmF0aW9uTmFtZV1baWRdYC4gSXMgaWRlbXBvdGVudC5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IGlkIElEIG9mIHRoZSBET00gZWxlbWVudC5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHJlZ2lzdHJhdGlvbk5hbWUgTmFtZSBvZiBsaXN0ZW5lciAoZS5nLiBgb25DbGlja2ApLlxuICAgKiBAcGFyYW0gez9mdW5jdGlvbn0gbGlzdGVuZXIgVGhlIGNhbGxiYWNrIHRvIHN0b3JlLlxuICAgKi9cbiAgcHV0TGlzdGVuZXI6IGZ1bmN0aW9uKGlkLCByZWdpc3RyYXRpb25OYW1lLCBsaXN0ZW5lcikge1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAhbGlzdGVuZXIgfHwgdHlwZW9mIGxpc3RlbmVyID09PSAnZnVuY3Rpb24nLFxuICAgICAgJ0V4cGVjdGVkICVzIGxpc3RlbmVyIHRvIGJlIGEgZnVuY3Rpb24sIGluc3RlYWQgZ290IHR5cGUgJXMnLFxuICAgICAgcmVnaXN0cmF0aW9uTmFtZSwgdHlwZW9mIGxpc3RlbmVyXG4gICAgKSA6IGludmFyaWFudCghbGlzdGVuZXIgfHwgdHlwZW9mIGxpc3RlbmVyID09PSAnZnVuY3Rpb24nKSk7XG5cbiAgICB2YXIgYmFua0ZvclJlZ2lzdHJhdGlvbk5hbWUgPVxuICAgICAgbGlzdGVuZXJCYW5rW3JlZ2lzdHJhdGlvbk5hbWVdIHx8IChsaXN0ZW5lckJhbmtbcmVnaXN0cmF0aW9uTmFtZV0gPSB7fSk7XG4gICAgYmFua0ZvclJlZ2lzdHJhdGlvbk5hbWVbaWRdID0gbGlzdGVuZXI7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpZCBJRCBvZiB0aGUgRE9NIGVsZW1lbnQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSByZWdpc3RyYXRpb25OYW1lIE5hbWUgb2YgbGlzdGVuZXIgKGUuZy4gYG9uQ2xpY2tgKS5cbiAgICogQHJldHVybiB7P2Z1bmN0aW9ufSBUaGUgc3RvcmVkIGNhbGxiYWNrLlxuICAgKi9cbiAgZ2V0TGlzdGVuZXI6IGZ1bmN0aW9uKGlkLCByZWdpc3RyYXRpb25OYW1lKSB7XG4gICAgdmFyIGJhbmtGb3JSZWdpc3RyYXRpb25OYW1lID0gbGlzdGVuZXJCYW5rW3JlZ2lzdHJhdGlvbk5hbWVdO1xuICAgIHJldHVybiBiYW5rRm9yUmVnaXN0cmF0aW9uTmFtZSAmJiBiYW5rRm9yUmVnaXN0cmF0aW9uTmFtZVtpZF07XG4gIH0sXG5cbiAgLyoqXG4gICAqIERlbGV0ZXMgYSBsaXN0ZW5lciBmcm9tIHRoZSByZWdpc3RyYXRpb24gYmFuay5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IGlkIElEIG9mIHRoZSBET00gZWxlbWVudC5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHJlZ2lzdHJhdGlvbk5hbWUgTmFtZSBvZiBsaXN0ZW5lciAoZS5nLiBgb25DbGlja2ApLlxuICAgKi9cbiAgZGVsZXRlTGlzdGVuZXI6IGZ1bmN0aW9uKGlkLCByZWdpc3RyYXRpb25OYW1lKSB7XG4gICAgdmFyIGJhbmtGb3JSZWdpc3RyYXRpb25OYW1lID0gbGlzdGVuZXJCYW5rW3JlZ2lzdHJhdGlvbk5hbWVdO1xuICAgIGlmIChiYW5rRm9yUmVnaXN0cmF0aW9uTmFtZSkge1xuICAgICAgZGVsZXRlIGJhbmtGb3JSZWdpc3RyYXRpb25OYW1lW2lkXTtcbiAgICB9XG4gIH0sXG5cbiAgLyoqXG4gICAqIERlbGV0ZXMgYWxsIGxpc3RlbmVycyBmb3IgdGhlIERPTSBlbGVtZW50IHdpdGggdGhlIHN1cHBsaWVkIElELlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gaWQgSUQgb2YgdGhlIERPTSBlbGVtZW50LlxuICAgKi9cbiAgZGVsZXRlQWxsTGlzdGVuZXJzOiBmdW5jdGlvbihpZCkge1xuICAgIGZvciAodmFyIHJlZ2lzdHJhdGlvbk5hbWUgaW4gbGlzdGVuZXJCYW5rKSB7XG4gICAgICBkZWxldGUgbGlzdGVuZXJCYW5rW3JlZ2lzdHJhdGlvbk5hbWVdW2lkXTtcbiAgICB9XG4gIH0sXG5cbiAgLyoqXG4gICAqIEFsbG93cyByZWdpc3RlcmVkIHBsdWdpbnMgYW4gb3Bwb3J0dW5pdHkgdG8gZXh0cmFjdCBldmVudHMgZnJvbSB0b3AtbGV2ZWxcbiAgICogbmF0aXZlIGJyb3dzZXIgZXZlbnRzLlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gdG9wTGV2ZWxUeXBlIFJlY29yZCBmcm9tIGBFdmVudENvbnN0YW50c2AuXG4gICAqIEBwYXJhbSB7RE9NRXZlbnRUYXJnZXR9IHRvcExldmVsVGFyZ2V0IFRoZSBsaXN0ZW5pbmcgY29tcG9uZW50IHJvb3Qgbm9kZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHRvcExldmVsVGFyZ2V0SUQgSUQgb2YgYHRvcExldmVsVGFyZ2V0YC5cbiAgICogQHBhcmFtIHtvYmplY3R9IG5hdGl2ZUV2ZW50IE5hdGl2ZSBicm93c2VyIGV2ZW50LlxuICAgKiBAcmV0dXJuIHsqfSBBbiBhY2N1bXVsYXRpb24gb2Ygc3ludGhldGljIGV2ZW50cy5cbiAgICogQGludGVybmFsXG4gICAqL1xuICBleHRyYWN0RXZlbnRzOiBmdW5jdGlvbihcbiAgICAgIHRvcExldmVsVHlwZSxcbiAgICAgIHRvcExldmVsVGFyZ2V0LFxuICAgICAgdG9wTGV2ZWxUYXJnZXRJRCxcbiAgICAgIG5hdGl2ZUV2ZW50KSB7XG4gICAgdmFyIGV2ZW50cztcbiAgICB2YXIgcGx1Z2lucyA9IEV2ZW50UGx1Z2luUmVnaXN0cnkucGx1Z2lucztcbiAgICBmb3IgKHZhciBpID0gMCwgbCA9IHBsdWdpbnMubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XG4gICAgICAvLyBOb3QgZXZlcnkgcGx1Z2luIGluIHRoZSBvcmRlcmluZyBtYXkgYmUgbG9hZGVkIGF0IHJ1bnRpbWUuXG4gICAgICB2YXIgcG9zc2libGVQbHVnaW4gPSBwbHVnaW5zW2ldO1xuICAgICAgaWYgKHBvc3NpYmxlUGx1Z2luKSB7XG4gICAgICAgIHZhciBleHRyYWN0ZWRFdmVudHMgPSBwb3NzaWJsZVBsdWdpbi5leHRyYWN0RXZlbnRzKFxuICAgICAgICAgIHRvcExldmVsVHlwZSxcbiAgICAgICAgICB0b3BMZXZlbFRhcmdldCxcbiAgICAgICAgICB0b3BMZXZlbFRhcmdldElELFxuICAgICAgICAgIG5hdGl2ZUV2ZW50XG4gICAgICAgICk7XG4gICAgICAgIGlmIChleHRyYWN0ZWRFdmVudHMpIHtcbiAgICAgICAgICBldmVudHMgPSBhY2N1bXVsYXRlSW50byhldmVudHMsIGV4dHJhY3RlZEV2ZW50cyk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGV2ZW50cztcbiAgfSxcblxuICAvKipcbiAgICogRW5xdWV1ZXMgYSBzeW50aGV0aWMgZXZlbnQgdGhhdCBzaG91bGQgYmUgZGlzcGF0Y2hlZCB3aGVuXG4gICAqIGBwcm9jZXNzRXZlbnRRdWV1ZWAgaXMgaW52b2tlZC5cbiAgICpcbiAgICogQHBhcmFtIHsqfSBldmVudHMgQW4gYWNjdW11bGF0aW9uIG9mIHN5bnRoZXRpYyBldmVudHMuXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgZW5xdWV1ZUV2ZW50czogZnVuY3Rpb24oZXZlbnRzKSB7XG4gICAgaWYgKGV2ZW50cykge1xuICAgICAgZXZlbnRRdWV1ZSA9IGFjY3VtdWxhdGVJbnRvKGV2ZW50UXVldWUsIGV2ZW50cyk7XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBEaXNwYXRjaGVzIGFsbCBzeW50aGV0aWMgZXZlbnRzIG9uIHRoZSBldmVudCBxdWV1ZS5cbiAgICpcbiAgICogQGludGVybmFsXG4gICAqL1xuICBwcm9jZXNzRXZlbnRRdWV1ZTogZnVuY3Rpb24oKSB7XG4gICAgLy8gU2V0IGBldmVudFF1ZXVlYCB0byBudWxsIGJlZm9yZSBwcm9jZXNzaW5nIGl0IHNvIHRoYXQgd2UgY2FuIHRlbGwgaWYgbW9yZVxuICAgIC8vIGV2ZW50cyBnZXQgZW5xdWV1ZWQgd2hpbGUgcHJvY2Vzc2luZy5cbiAgICB2YXIgcHJvY2Vzc2luZ0V2ZW50UXVldWUgPSBldmVudFF1ZXVlO1xuICAgIGV2ZW50UXVldWUgPSBudWxsO1xuICAgIGZvckVhY2hBY2N1bXVsYXRlZChwcm9jZXNzaW5nRXZlbnRRdWV1ZSwgZXhlY3V0ZURpc3BhdGNoZXNBbmRSZWxlYXNlKTtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgIWV2ZW50UXVldWUsXG4gICAgICAncHJvY2Vzc0V2ZW50UXVldWUoKTogQWRkaXRpb25hbCBldmVudHMgd2VyZSBlbnF1ZXVlZCB3aGlsZSBwcm9jZXNzaW5nICcgK1xuICAgICAgJ2FuIGV2ZW50IHF1ZXVlLiBTdXBwb3J0IGZvciB0aGlzIGhhcyBub3QgeWV0IGJlZW4gaW1wbGVtZW50ZWQuJ1xuICAgICkgOiBpbnZhcmlhbnQoIWV2ZW50UXVldWUpKTtcbiAgfSxcblxuICAvKipcbiAgICogVGhlc2UgYXJlIG5lZWRlZCBmb3IgdGVzdHMgb25seS4gRG8gbm90IHVzZSFcbiAgICovXG4gIF9fcHVyZ2U6IGZ1bmN0aW9uKCkge1xuICAgIGxpc3RlbmVyQmFuayA9IHt9O1xuICB9LFxuXG4gIF9fZ2V0TGlzdGVuZXJCYW5rOiBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gbGlzdGVuZXJCYW5rO1xuICB9XG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gRXZlbnRQbHVnaW5IdWI7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgRXZlbnRQbHVnaW5SZWdpc3RyeVxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcblxuLyoqXG4gKiBJbmplY3RhYmxlIG9yZGVyaW5nIG9mIGV2ZW50IHBsdWdpbnMuXG4gKi9cbnZhciBFdmVudFBsdWdpbk9yZGVyID0gbnVsbDtcblxuLyoqXG4gKiBJbmplY3RhYmxlIG1hcHBpbmcgZnJvbSBuYW1lcyB0byBldmVudCBwbHVnaW4gbW9kdWxlcy5cbiAqL1xudmFyIG5hbWVzVG9QbHVnaW5zID0ge307XG5cbi8qKlxuICogUmVjb21wdXRlcyB0aGUgcGx1Z2luIGxpc3QgdXNpbmcgdGhlIGluamVjdGVkIHBsdWdpbnMgYW5kIHBsdWdpbiBvcmRlcmluZy5cbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiByZWNvbXB1dGVQbHVnaW5PcmRlcmluZygpIHtcbiAgaWYgKCFFdmVudFBsdWdpbk9yZGVyKSB7XG4gICAgLy8gV2FpdCB1bnRpbCBhbiBgRXZlbnRQbHVnaW5PcmRlcmAgaXMgaW5qZWN0ZWQuXG4gICAgcmV0dXJuO1xuICB9XG4gIGZvciAodmFyIHBsdWdpbk5hbWUgaW4gbmFtZXNUb1BsdWdpbnMpIHtcbiAgICB2YXIgUGx1Z2luTW9kdWxlID0gbmFtZXNUb1BsdWdpbnNbcGx1Z2luTmFtZV07XG4gICAgdmFyIHBsdWdpbkluZGV4ID0gRXZlbnRQbHVnaW5PcmRlci5pbmRleE9mKHBsdWdpbk5hbWUpO1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICBwbHVnaW5JbmRleCA+IC0xLFxuICAgICAgJ0V2ZW50UGx1Z2luUmVnaXN0cnk6IENhbm5vdCBpbmplY3QgZXZlbnQgcGx1Z2lucyB0aGF0IGRvIG5vdCBleGlzdCBpbiAnICtcbiAgICAgICd0aGUgcGx1Z2luIG9yZGVyaW5nLCBgJXNgLicsXG4gICAgICBwbHVnaW5OYW1lXG4gICAgKSA6IGludmFyaWFudChwbHVnaW5JbmRleCA+IC0xKSk7XG4gICAgaWYgKEV2ZW50UGx1Z2luUmVnaXN0cnkucGx1Z2luc1twbHVnaW5JbmRleF0pIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgUGx1Z2luTW9kdWxlLmV4dHJhY3RFdmVudHMsXG4gICAgICAnRXZlbnRQbHVnaW5SZWdpc3RyeTogRXZlbnQgcGx1Z2lucyBtdXN0IGltcGxlbWVudCBhbiBgZXh0cmFjdEV2ZW50c2AgJyArXG4gICAgICAnbWV0aG9kLCBidXQgYCVzYCBkb2VzIG5vdC4nLFxuICAgICAgcGx1Z2luTmFtZVxuICAgICkgOiBpbnZhcmlhbnQoUGx1Z2luTW9kdWxlLmV4dHJhY3RFdmVudHMpKTtcbiAgICBFdmVudFBsdWdpblJlZ2lzdHJ5LnBsdWdpbnNbcGx1Z2luSW5kZXhdID0gUGx1Z2luTW9kdWxlO1xuICAgIHZhciBwdWJsaXNoZWRFdmVudHMgPSBQbHVnaW5Nb2R1bGUuZXZlbnRUeXBlcztcbiAgICBmb3IgKHZhciBldmVudE5hbWUgaW4gcHVibGlzaGVkRXZlbnRzKSB7XG4gICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICBwdWJsaXNoRXZlbnRGb3JQbHVnaW4oXG4gICAgICAgICAgcHVibGlzaGVkRXZlbnRzW2V2ZW50TmFtZV0sXG4gICAgICAgICAgUGx1Z2luTW9kdWxlLFxuICAgICAgICAgIGV2ZW50TmFtZVxuICAgICAgICApLFxuICAgICAgICAnRXZlbnRQbHVnaW5SZWdpc3RyeTogRmFpbGVkIHRvIHB1Ymxpc2ggZXZlbnQgYCVzYCBmb3IgcGx1Z2luIGAlc2AuJyxcbiAgICAgICAgZXZlbnROYW1lLFxuICAgICAgICBwbHVnaW5OYW1lXG4gICAgICApIDogaW52YXJpYW50KHB1Ymxpc2hFdmVudEZvclBsdWdpbihcbiAgICAgICAgcHVibGlzaGVkRXZlbnRzW2V2ZW50TmFtZV0sXG4gICAgICAgIFBsdWdpbk1vZHVsZSxcbiAgICAgICAgZXZlbnROYW1lXG4gICAgICApKSk7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogUHVibGlzaGVzIGFuIGV2ZW50IHNvIHRoYXQgaXQgY2FuIGJlIGRpc3BhdGNoZWQgYnkgdGhlIHN1cHBsaWVkIHBsdWdpbi5cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gZGlzcGF0Y2hDb25maWcgRGlzcGF0Y2ggY29uZmlndXJhdGlvbiBmb3IgdGhlIGV2ZW50LlxuICogQHBhcmFtIHtvYmplY3R9IFBsdWdpbk1vZHVsZSBQbHVnaW4gcHVibGlzaGluZyB0aGUgZXZlbnQuXG4gKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIHRoZSBldmVudCB3YXMgc3VjY2Vzc2Z1bGx5IHB1Ymxpc2hlZC5cbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIHB1Ymxpc2hFdmVudEZvclBsdWdpbihkaXNwYXRjaENvbmZpZywgUGx1Z2luTW9kdWxlLCBldmVudE5hbWUpIHtcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAhRXZlbnRQbHVnaW5SZWdpc3RyeS5ldmVudE5hbWVEaXNwYXRjaENvbmZpZ3MuaGFzT3duUHJvcGVydHkoZXZlbnROYW1lKSxcbiAgICAnRXZlbnRQbHVnaW5IdWI6IE1vcmUgdGhhbiBvbmUgcGx1Z2luIGF0dGVtcHRlZCB0byBwdWJsaXNoIHRoZSBzYW1lICcgK1xuICAgICdldmVudCBuYW1lLCBgJXNgLicsXG4gICAgZXZlbnROYW1lXG4gICkgOiBpbnZhcmlhbnQoIUV2ZW50UGx1Z2luUmVnaXN0cnkuZXZlbnROYW1lRGlzcGF0Y2hDb25maWdzLmhhc093blByb3BlcnR5KGV2ZW50TmFtZSkpKTtcbiAgRXZlbnRQbHVnaW5SZWdpc3RyeS5ldmVudE5hbWVEaXNwYXRjaENvbmZpZ3NbZXZlbnROYW1lXSA9IGRpc3BhdGNoQ29uZmlnO1xuXG4gIHZhciBwaGFzZWRSZWdpc3RyYXRpb25OYW1lcyA9IGRpc3BhdGNoQ29uZmlnLnBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzO1xuICBpZiAocGhhc2VkUmVnaXN0cmF0aW9uTmFtZXMpIHtcbiAgICBmb3IgKHZhciBwaGFzZU5hbWUgaW4gcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXMpIHtcbiAgICAgIGlmIChwaGFzZWRSZWdpc3RyYXRpb25OYW1lcy5oYXNPd25Qcm9wZXJ0eShwaGFzZU5hbWUpKSB7XG4gICAgICAgIHZhciBwaGFzZWRSZWdpc3RyYXRpb25OYW1lID0gcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXNbcGhhc2VOYW1lXTtcbiAgICAgICAgcHVibGlzaFJlZ2lzdHJhdGlvbk5hbWUoXG4gICAgICAgICAgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZSxcbiAgICAgICAgICBQbHVnaW5Nb2R1bGUsXG4gICAgICAgICAgZXZlbnROYW1lXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xuICB9IGVsc2UgaWYgKGRpc3BhdGNoQ29uZmlnLnJlZ2lzdHJhdGlvbk5hbWUpIHtcbiAgICBwdWJsaXNoUmVnaXN0cmF0aW9uTmFtZShcbiAgICAgIGRpc3BhdGNoQ29uZmlnLnJlZ2lzdHJhdGlvbk5hbWUsXG4gICAgICBQbHVnaW5Nb2R1bGUsXG4gICAgICBldmVudE5hbWVcbiAgICApO1xuICAgIHJldHVybiB0cnVlO1xuICB9XG4gIHJldHVybiBmYWxzZTtcbn1cblxuLyoqXG4gKiBQdWJsaXNoZXMgYSByZWdpc3RyYXRpb24gbmFtZSB0aGF0IGlzIHVzZWQgdG8gaWRlbnRpZnkgZGlzcGF0Y2hlZCBldmVudHMgYW5kXG4gKiBjYW4gYmUgdXNlZCB3aXRoIGBFdmVudFBsdWdpbkh1Yi5wdXRMaXN0ZW5lcmAgdG8gcmVnaXN0ZXIgbGlzdGVuZXJzLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSByZWdpc3RyYXRpb25OYW1lIFJlZ2lzdHJhdGlvbiBuYW1lIHRvIGFkZC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBQbHVnaW5Nb2R1bGUgUGx1Z2luIHB1Ymxpc2hpbmcgdGhlIGV2ZW50LlxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gcHVibGlzaFJlZ2lzdHJhdGlvbk5hbWUocmVnaXN0cmF0aW9uTmFtZSwgUGx1Z2luTW9kdWxlLCBldmVudE5hbWUpIHtcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAhRXZlbnRQbHVnaW5SZWdpc3RyeS5yZWdpc3RyYXRpb25OYW1lTW9kdWxlc1tyZWdpc3RyYXRpb25OYW1lXSxcbiAgICAnRXZlbnRQbHVnaW5IdWI6IE1vcmUgdGhhbiBvbmUgcGx1Z2luIGF0dGVtcHRlZCB0byBwdWJsaXNoIHRoZSBzYW1lICcgK1xuICAgICdyZWdpc3RyYXRpb24gbmFtZSwgYCVzYC4nLFxuICAgIHJlZ2lzdHJhdGlvbk5hbWVcbiAgKSA6IGludmFyaWFudCghRXZlbnRQbHVnaW5SZWdpc3RyeS5yZWdpc3RyYXRpb25OYW1lTW9kdWxlc1tyZWdpc3RyYXRpb25OYW1lXSkpO1xuICBFdmVudFBsdWdpblJlZ2lzdHJ5LnJlZ2lzdHJhdGlvbk5hbWVNb2R1bGVzW3JlZ2lzdHJhdGlvbk5hbWVdID0gUGx1Z2luTW9kdWxlO1xuICBFdmVudFBsdWdpblJlZ2lzdHJ5LnJlZ2lzdHJhdGlvbk5hbWVEZXBlbmRlbmNpZXNbcmVnaXN0cmF0aW9uTmFtZV0gPVxuICAgIFBsdWdpbk1vZHVsZS5ldmVudFR5cGVzW2V2ZW50TmFtZV0uZGVwZW5kZW5jaWVzO1xufVxuXG4vKipcbiAqIFJlZ2lzdGVycyBwbHVnaW5zIHNvIHRoYXQgdGhleSBjYW4gZXh0cmFjdCBhbmQgZGlzcGF0Y2ggZXZlbnRzLlxuICpcbiAqIEBzZWUge0V2ZW50UGx1Z2luSHVifVxuICovXG52YXIgRXZlbnRQbHVnaW5SZWdpc3RyeSA9IHtcblxuICAvKipcbiAgICogT3JkZXJlZCBsaXN0IG9mIGluamVjdGVkIHBsdWdpbnMuXG4gICAqL1xuICBwbHVnaW5zOiBbXSxcblxuICAvKipcbiAgICogTWFwcGluZyBmcm9tIGV2ZW50IG5hbWUgdG8gZGlzcGF0Y2ggY29uZmlnXG4gICAqL1xuICBldmVudE5hbWVEaXNwYXRjaENvbmZpZ3M6IHt9LFxuXG4gIC8qKlxuICAgKiBNYXBwaW5nIGZyb20gcmVnaXN0cmF0aW9uIG5hbWUgdG8gcGx1Z2luIG1vZHVsZVxuICAgKi9cbiAgcmVnaXN0cmF0aW9uTmFtZU1vZHVsZXM6IHt9LFxuXG4gIC8qKlxuICAgKiBNYXBwaW5nIGZyb20gcmVnaXN0cmF0aW9uIG5hbWUgdG8gZXZlbnQgbmFtZVxuICAgKi9cbiAgcmVnaXN0cmF0aW9uTmFtZURlcGVuZGVuY2llczoge30sXG5cbiAgLyoqXG4gICAqIEluamVjdHMgYW4gb3JkZXJpbmcgb2YgcGx1Z2lucyAoYnkgcGx1Z2luIG5hbWUpLiBUaGlzIGFsbG93cyB0aGUgb3JkZXJpbmdcbiAgICogdG8gYmUgZGVjb3VwbGVkIGZyb20gaW5qZWN0aW9uIG9mIHRoZSBhY3R1YWwgcGx1Z2lucyBzbyB0aGF0IG9yZGVyaW5nIGlzXG4gICAqIGFsd2F5cyBkZXRlcm1pbmlzdGljIHJlZ2FyZGxlc3Mgb2YgcGFja2FnaW5nLCBvbi10aGUtZmx5IGluamVjdGlvbiwgZXRjLlxuICAgKlxuICAgKiBAcGFyYW0ge2FycmF5fSBJbmplY3RlZEV2ZW50UGx1Z2luT3JkZXJcbiAgICogQGludGVybmFsXG4gICAqIEBzZWUge0V2ZW50UGx1Z2luSHViLmluamVjdGlvbi5pbmplY3RFdmVudFBsdWdpbk9yZGVyfVxuICAgKi9cbiAgaW5qZWN0RXZlbnRQbHVnaW5PcmRlcjogZnVuY3Rpb24oSW5qZWN0ZWRFdmVudFBsdWdpbk9yZGVyKSB7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICFFdmVudFBsdWdpbk9yZGVyLFxuICAgICAgJ0V2ZW50UGx1Z2luUmVnaXN0cnk6IENhbm5vdCBpbmplY3QgZXZlbnQgcGx1Z2luIG9yZGVyaW5nIG1vcmUgdGhhbiAnICtcbiAgICAgICdvbmNlLiBZb3UgYXJlIGxpa2VseSB0cnlpbmcgdG8gbG9hZCBtb3JlIHRoYW4gb25lIGNvcHkgb2YgUmVhY3QuJ1xuICAgICkgOiBpbnZhcmlhbnQoIUV2ZW50UGx1Z2luT3JkZXIpKTtcbiAgICAvLyBDbG9uZSB0aGUgb3JkZXJpbmcgc28gaXQgY2Fubm90IGJlIGR5bmFtaWNhbGx5IG11dGF0ZWQuXG4gICAgRXZlbnRQbHVnaW5PcmRlciA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKEluamVjdGVkRXZlbnRQbHVnaW5PcmRlcik7XG4gICAgcmVjb21wdXRlUGx1Z2luT3JkZXJpbmcoKTtcbiAgfSxcblxuICAvKipcbiAgICogSW5qZWN0cyBwbHVnaW5zIHRvIGJlIHVzZWQgYnkgYEV2ZW50UGx1Z2luSHViYC4gVGhlIHBsdWdpbiBuYW1lcyBtdXN0IGJlXG4gICAqIGluIHRoZSBvcmRlcmluZyBpbmplY3RlZCBieSBgaW5qZWN0RXZlbnRQbHVnaW5PcmRlcmAuXG4gICAqXG4gICAqIFBsdWdpbnMgY2FuIGJlIGluamVjdGVkIGFzIHBhcnQgb2YgcGFnZSBpbml0aWFsaXphdGlvbiBvciBvbi10aGUtZmx5LlxuICAgKlxuICAgKiBAcGFyYW0ge29iamVjdH0gaW5qZWN0ZWROYW1lc1RvUGx1Z2lucyBNYXAgZnJvbSBuYW1lcyB0byBwbHVnaW4gbW9kdWxlcy5cbiAgICogQGludGVybmFsXG4gICAqIEBzZWUge0V2ZW50UGx1Z2luSHViLmluamVjdGlvbi5pbmplY3RFdmVudFBsdWdpbnNCeU5hbWV9XG4gICAqL1xuICBpbmplY3RFdmVudFBsdWdpbnNCeU5hbWU6IGZ1bmN0aW9uKGluamVjdGVkTmFtZXNUb1BsdWdpbnMpIHtcbiAgICB2YXIgaXNPcmRlcmluZ0RpcnR5ID0gZmFsc2U7XG4gICAgZm9yICh2YXIgcGx1Z2luTmFtZSBpbiBpbmplY3RlZE5hbWVzVG9QbHVnaW5zKSB7XG4gICAgICBpZiAoIWluamVjdGVkTmFtZXNUb1BsdWdpbnMuaGFzT3duUHJvcGVydHkocGx1Z2luTmFtZSkpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICB2YXIgUGx1Z2luTW9kdWxlID0gaW5qZWN0ZWROYW1lc1RvUGx1Z2luc1twbHVnaW5OYW1lXTtcbiAgICAgIGlmICghbmFtZXNUb1BsdWdpbnMuaGFzT3duUHJvcGVydHkocGx1Z2luTmFtZSkgfHxcbiAgICAgICAgICBuYW1lc1RvUGx1Z2luc1twbHVnaW5OYW1lXSAhPT0gUGx1Z2luTW9kdWxlKSB7XG4gICAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgICAgIW5hbWVzVG9QbHVnaW5zW3BsdWdpbk5hbWVdLFxuICAgICAgICAgICdFdmVudFBsdWdpblJlZ2lzdHJ5OiBDYW5ub3QgaW5qZWN0IHR3byBkaWZmZXJlbnQgZXZlbnQgcGx1Z2lucyAnICtcbiAgICAgICAgICAndXNpbmcgdGhlIHNhbWUgbmFtZSwgYCVzYC4nLFxuICAgICAgICAgIHBsdWdpbk5hbWVcbiAgICAgICAgKSA6IGludmFyaWFudCghbmFtZXNUb1BsdWdpbnNbcGx1Z2luTmFtZV0pKTtcbiAgICAgICAgbmFtZXNUb1BsdWdpbnNbcGx1Z2luTmFtZV0gPSBQbHVnaW5Nb2R1bGU7XG4gICAgICAgIGlzT3JkZXJpbmdEaXJ0eSA9IHRydWU7XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChpc09yZGVyaW5nRGlydHkpIHtcbiAgICAgIHJlY29tcHV0ZVBsdWdpbk9yZGVyaW5nKCk7XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBMb29rcyB1cCB0aGUgcGx1Z2luIGZvciB0aGUgc3VwcGxpZWQgZXZlbnQuXG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBldmVudCBBIHN5bnRoZXRpYyBldmVudC5cbiAgICogQHJldHVybiB7P29iamVjdH0gVGhlIHBsdWdpbiB0aGF0IGNyZWF0ZWQgdGhlIHN1cHBsaWVkIGV2ZW50LlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIGdldFBsdWdpbk1vZHVsZUZvckV2ZW50OiBmdW5jdGlvbihldmVudCkge1xuICAgIHZhciBkaXNwYXRjaENvbmZpZyA9IGV2ZW50LmRpc3BhdGNoQ29uZmlnO1xuICAgIGlmIChkaXNwYXRjaENvbmZpZy5yZWdpc3RyYXRpb25OYW1lKSB7XG4gICAgICByZXR1cm4gRXZlbnRQbHVnaW5SZWdpc3RyeS5yZWdpc3RyYXRpb25OYW1lTW9kdWxlc1tcbiAgICAgICAgZGlzcGF0Y2hDb25maWcucmVnaXN0cmF0aW9uTmFtZVxuICAgICAgXSB8fCBudWxsO1xuICAgIH1cbiAgICBmb3IgKHZhciBwaGFzZSBpbiBkaXNwYXRjaENvbmZpZy5waGFzZWRSZWdpc3RyYXRpb25OYW1lcykge1xuICAgICAgaWYgKCFkaXNwYXRjaENvbmZpZy5waGFzZWRSZWdpc3RyYXRpb25OYW1lcy5oYXNPd25Qcm9wZXJ0eShwaGFzZSkpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICB2YXIgUGx1Z2luTW9kdWxlID0gRXZlbnRQbHVnaW5SZWdpc3RyeS5yZWdpc3RyYXRpb25OYW1lTW9kdWxlc1tcbiAgICAgICAgZGlzcGF0Y2hDb25maWcucGhhc2VkUmVnaXN0cmF0aW9uTmFtZXNbcGhhc2VdXG4gICAgICBdO1xuICAgICAgaWYgKFBsdWdpbk1vZHVsZSkge1xuICAgICAgICByZXR1cm4gUGx1Z2luTW9kdWxlO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbiAgfSxcblxuICAvKipcbiAgICogRXhwb3NlZCBmb3IgdW5pdCB0ZXN0aW5nLlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgX3Jlc2V0RXZlbnRQbHVnaW5zOiBmdW5jdGlvbigpIHtcbiAgICBFdmVudFBsdWdpbk9yZGVyID0gbnVsbDtcbiAgICBmb3IgKHZhciBwbHVnaW5OYW1lIGluIG5hbWVzVG9QbHVnaW5zKSB7XG4gICAgICBpZiAobmFtZXNUb1BsdWdpbnMuaGFzT3duUHJvcGVydHkocGx1Z2luTmFtZSkpIHtcbiAgICAgICAgZGVsZXRlIG5hbWVzVG9QbHVnaW5zW3BsdWdpbk5hbWVdO1xuICAgICAgfVxuICAgIH1cbiAgICBFdmVudFBsdWdpblJlZ2lzdHJ5LnBsdWdpbnMubGVuZ3RoID0gMDtcblxuICAgIHZhciBldmVudE5hbWVEaXNwYXRjaENvbmZpZ3MgPSBFdmVudFBsdWdpblJlZ2lzdHJ5LmV2ZW50TmFtZURpc3BhdGNoQ29uZmlncztcbiAgICBmb3IgKHZhciBldmVudE5hbWUgaW4gZXZlbnROYW1lRGlzcGF0Y2hDb25maWdzKSB7XG4gICAgICBpZiAoZXZlbnROYW1lRGlzcGF0Y2hDb25maWdzLmhhc093blByb3BlcnR5KGV2ZW50TmFtZSkpIHtcbiAgICAgICAgZGVsZXRlIGV2ZW50TmFtZURpc3BhdGNoQ29uZmlnc1tldmVudE5hbWVdO1xuICAgICAgfVxuICAgIH1cblxuICAgIHZhciByZWdpc3RyYXRpb25OYW1lTW9kdWxlcyA9IEV2ZW50UGx1Z2luUmVnaXN0cnkucmVnaXN0cmF0aW9uTmFtZU1vZHVsZXM7XG4gICAgZm9yICh2YXIgcmVnaXN0cmF0aW9uTmFtZSBpbiByZWdpc3RyYXRpb25OYW1lTW9kdWxlcykge1xuICAgICAgaWYgKHJlZ2lzdHJhdGlvbk5hbWVNb2R1bGVzLmhhc093blByb3BlcnR5KHJlZ2lzdHJhdGlvbk5hbWUpKSB7XG4gICAgICAgIGRlbGV0ZSByZWdpc3RyYXRpb25OYW1lTW9kdWxlc1tyZWdpc3RyYXRpb25OYW1lXTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBFdmVudFBsdWdpblJlZ2lzdHJ5O1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIEV2ZW50UGx1Z2luVXRpbHNcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIEV2ZW50Q29uc3RhbnRzID0gcmVxdWlyZShcIi4vRXZlbnRDb25zdGFudHNcIik7XG5cbnZhciBpbnZhcmlhbnQgPSByZXF1aXJlKFwiLi9pbnZhcmlhbnRcIik7XG5cbi8qKlxuICogSW5qZWN0ZWQgZGVwZW5kZW5jaWVzOlxuICovXG5cbi8qKlxuICogLSBgTW91bnRgOiBbcmVxdWlyZWRdIE1vZHVsZSB0aGF0IGNhbiBjb252ZXJ0IGJldHdlZW4gUmVhY3QgZG9tIElEcyBhbmRcbiAqICAgYWN0dWFsIG5vZGUgcmVmZXJlbmNlcy5cbiAqL1xudmFyIGluamVjdGlvbiA9IHtcbiAgTW91bnQ6IG51bGwsXG4gIGluamVjdE1vdW50OiBmdW5jdGlvbihJbmplY3RlZE1vdW50KSB7XG4gICAgaW5qZWN0aW9uLk1vdW50ID0gSW5qZWN0ZWRNb3VudDtcbiAgICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICBJbmplY3RlZE1vdW50ICYmIEluamVjdGVkTW91bnQuZ2V0Tm9kZSxcbiAgICAgICAgJ0V2ZW50UGx1Z2luVXRpbHMuaW5qZWN0aW9uLmluamVjdE1vdW50KC4uLik6IEluamVjdGVkIE1vdW50IG1vZHVsZSAnICtcbiAgICAgICAgJ2lzIG1pc3NpbmcgZ2V0Tm9kZS4nXG4gICAgICApIDogaW52YXJpYW50KEluamVjdGVkTW91bnQgJiYgSW5qZWN0ZWRNb3VudC5nZXROb2RlKSk7XG4gICAgfVxuICB9XG59O1xuXG52YXIgdG9wTGV2ZWxUeXBlcyA9IEV2ZW50Q29uc3RhbnRzLnRvcExldmVsVHlwZXM7XG5cbmZ1bmN0aW9uIGlzRW5kaXNoKHRvcExldmVsVHlwZSkge1xuICByZXR1cm4gdG9wTGV2ZWxUeXBlID09PSB0b3BMZXZlbFR5cGVzLnRvcE1vdXNlVXAgfHxcbiAgICAgICAgIHRvcExldmVsVHlwZSA9PT0gdG9wTGV2ZWxUeXBlcy50b3BUb3VjaEVuZCB8fFxuICAgICAgICAgdG9wTGV2ZWxUeXBlID09PSB0b3BMZXZlbFR5cGVzLnRvcFRvdWNoQ2FuY2VsO1xufVxuXG5mdW5jdGlvbiBpc01vdmVpc2godG9wTGV2ZWxUeXBlKSB7XG4gIHJldHVybiB0b3BMZXZlbFR5cGUgPT09IHRvcExldmVsVHlwZXMudG9wTW91c2VNb3ZlIHx8XG4gICAgICAgICB0b3BMZXZlbFR5cGUgPT09IHRvcExldmVsVHlwZXMudG9wVG91Y2hNb3ZlO1xufVxuZnVuY3Rpb24gaXNTdGFydGlzaCh0b3BMZXZlbFR5cGUpIHtcbiAgcmV0dXJuIHRvcExldmVsVHlwZSA9PT0gdG9wTGV2ZWxUeXBlcy50b3BNb3VzZURvd24gfHxcbiAgICAgICAgIHRvcExldmVsVHlwZSA9PT0gdG9wTGV2ZWxUeXBlcy50b3BUb3VjaFN0YXJ0O1xufVxuXG5cbnZhciB2YWxpZGF0ZUV2ZW50RGlzcGF0Y2hlcztcbmlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgdmFsaWRhdGVFdmVudERpc3BhdGNoZXMgPSBmdW5jdGlvbihldmVudCkge1xuICAgIHZhciBkaXNwYXRjaExpc3RlbmVycyA9IGV2ZW50Ll9kaXNwYXRjaExpc3RlbmVycztcbiAgICB2YXIgZGlzcGF0Y2hJRHMgPSBldmVudC5fZGlzcGF0Y2hJRHM7XG5cbiAgICB2YXIgbGlzdGVuZXJzSXNBcnIgPSBBcnJheS5pc0FycmF5KGRpc3BhdGNoTGlzdGVuZXJzKTtcbiAgICB2YXIgaWRzSXNBcnIgPSBBcnJheS5pc0FycmF5KGRpc3BhdGNoSURzKTtcbiAgICB2YXIgSURzTGVuID0gaWRzSXNBcnIgPyBkaXNwYXRjaElEcy5sZW5ndGggOiBkaXNwYXRjaElEcyA/IDEgOiAwO1xuICAgIHZhciBsaXN0ZW5lcnNMZW4gPSBsaXN0ZW5lcnNJc0FyciA/XG4gICAgICBkaXNwYXRjaExpc3RlbmVycy5sZW5ndGggOlxuICAgICAgZGlzcGF0Y2hMaXN0ZW5lcnMgPyAxIDogMDtcblxuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICBpZHNJc0FyciA9PT0gbGlzdGVuZXJzSXNBcnIgJiYgSURzTGVuID09PSBsaXN0ZW5lcnNMZW4sXG4gICAgICAnRXZlbnRQbHVnaW5VdGlsczogSW52YWxpZCBgZXZlbnRgLidcbiAgICApIDogaW52YXJpYW50KGlkc0lzQXJyID09PSBsaXN0ZW5lcnNJc0FyciAmJiBJRHNMZW4gPT09IGxpc3RlbmVyc0xlbikpO1xuICB9O1xufVxuXG4vKipcbiAqIEludm9rZXMgYGNiKGV2ZW50LCBsaXN0ZW5lciwgaWQpYC4gQXZvaWRzIHVzaW5nIGNhbGwgaWYgbm8gc2NvcGUgaXNcbiAqIHByb3ZpZGVkLiBUaGUgYChsaXN0ZW5lcixpZClgIHBhaXIgZWZmZWN0aXZlbHkgZm9ybXMgdGhlIFwiZGlzcGF0Y2hcIiBidXQgYXJlXG4gKiBrZXB0IHNlcGFyYXRlIHRvIGNvbnNlcnZlIG1lbW9yeS5cbiAqL1xuZnVuY3Rpb24gZm9yRWFjaEV2ZW50RGlzcGF0Y2goZXZlbnQsIGNiKSB7XG4gIHZhciBkaXNwYXRjaExpc3RlbmVycyA9IGV2ZW50Ll9kaXNwYXRjaExpc3RlbmVycztcbiAgdmFyIGRpc3BhdGNoSURzID0gZXZlbnQuX2Rpc3BhdGNoSURzO1xuICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgdmFsaWRhdGVFdmVudERpc3BhdGNoZXMoZXZlbnQpO1xuICB9XG4gIGlmIChBcnJheS5pc0FycmF5KGRpc3BhdGNoTGlzdGVuZXJzKSkge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZGlzcGF0Y2hMaXN0ZW5lcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmIChldmVudC5pc1Byb3BhZ2F0aW9uU3RvcHBlZCgpKSB7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgLy8gTGlzdGVuZXJzIGFuZCBJRHMgYXJlIHR3byBwYXJhbGxlbCBhcnJheXMgdGhhdCBhcmUgYWx3YXlzIGluIHN5bmMuXG4gICAgICBjYihldmVudCwgZGlzcGF0Y2hMaXN0ZW5lcnNbaV0sIGRpc3BhdGNoSURzW2ldKTtcbiAgICB9XG4gIH0gZWxzZSBpZiAoZGlzcGF0Y2hMaXN0ZW5lcnMpIHtcbiAgICBjYihldmVudCwgZGlzcGF0Y2hMaXN0ZW5lcnMsIGRpc3BhdGNoSURzKTtcbiAgfVxufVxuXG4vKipcbiAqIERlZmF1bHQgaW1wbGVtZW50YXRpb24gb2YgUGx1Z2luTW9kdWxlLmV4ZWN1dGVEaXNwYXRjaCgpLlxuICogQHBhcmFtIHtTeW50aGV0aWNFdmVudH0gU3ludGhldGljRXZlbnQgdG8gaGFuZGxlXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBBcHBsaWNhdGlvbi1sZXZlbCBjYWxsYmFja1xuICogQHBhcmFtIHtzdHJpbmd9IGRvbUlEIERPTSBpZCB0byBwYXNzIHRvIHRoZSBjYWxsYmFjay5cbiAqL1xuZnVuY3Rpb24gZXhlY3V0ZURpc3BhdGNoKGV2ZW50LCBsaXN0ZW5lciwgZG9tSUQpIHtcbiAgZXZlbnQuY3VycmVudFRhcmdldCA9IGluamVjdGlvbi5Nb3VudC5nZXROb2RlKGRvbUlEKTtcbiAgdmFyIHJldHVyblZhbHVlID0gbGlzdGVuZXIoZXZlbnQsIGRvbUlEKTtcbiAgZXZlbnQuY3VycmVudFRhcmdldCA9IG51bGw7XG4gIHJldHVybiByZXR1cm5WYWx1ZTtcbn1cblxuLyoqXG4gKiBTdGFuZGFyZC9zaW1wbGUgaXRlcmF0aW9uIHRocm91Z2ggYW4gZXZlbnQncyBjb2xsZWN0ZWQgZGlzcGF0Y2hlcy5cbiAqL1xuZnVuY3Rpb24gZXhlY3V0ZURpc3BhdGNoZXNJbk9yZGVyKGV2ZW50LCBleGVjdXRlRGlzcGF0Y2gpIHtcbiAgZm9yRWFjaEV2ZW50RGlzcGF0Y2goZXZlbnQsIGV4ZWN1dGVEaXNwYXRjaCk7XG4gIGV2ZW50Ll9kaXNwYXRjaExpc3RlbmVycyA9IG51bGw7XG4gIGV2ZW50Ll9kaXNwYXRjaElEcyA9IG51bGw7XG59XG5cbi8qKlxuICogU3RhbmRhcmQvc2ltcGxlIGl0ZXJhdGlvbiB0aHJvdWdoIGFuIGV2ZW50J3MgY29sbGVjdGVkIGRpc3BhdGNoZXMsIGJ1dCBzdG9wc1xuICogYXQgdGhlIGZpcnN0IGRpc3BhdGNoIGV4ZWN1dGlvbiByZXR1cm5pbmcgdHJ1ZSwgYW5kIHJldHVybnMgdGhhdCBpZC5cbiAqXG4gKiBAcmV0dXJuIGlkIG9mIHRoZSBmaXJzdCBkaXNwYXRjaCBleGVjdXRpb24gd2hvJ3MgbGlzdGVuZXIgcmV0dXJucyB0cnVlLCBvclxuICogbnVsbCBpZiBubyBsaXN0ZW5lciByZXR1cm5lZCB0cnVlLlxuICovXG5mdW5jdGlvbiBleGVjdXRlRGlzcGF0Y2hlc0luT3JkZXJTdG9wQXRUcnVlSW1wbChldmVudCkge1xuICB2YXIgZGlzcGF0Y2hMaXN0ZW5lcnMgPSBldmVudC5fZGlzcGF0Y2hMaXN0ZW5lcnM7XG4gIHZhciBkaXNwYXRjaElEcyA9IGV2ZW50Ll9kaXNwYXRjaElEcztcbiAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgIHZhbGlkYXRlRXZlbnREaXNwYXRjaGVzKGV2ZW50KTtcbiAgfVxuICBpZiAoQXJyYXkuaXNBcnJheShkaXNwYXRjaExpc3RlbmVycykpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGRpc3BhdGNoTGlzdGVuZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAoZXZlbnQuaXNQcm9wYWdhdGlvblN0b3BwZWQoKSkge1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIC8vIExpc3RlbmVycyBhbmQgSURzIGFyZSB0d28gcGFyYWxsZWwgYXJyYXlzIHRoYXQgYXJlIGFsd2F5cyBpbiBzeW5jLlxuICAgICAgaWYgKGRpc3BhdGNoTGlzdGVuZXJzW2ldKGV2ZW50LCBkaXNwYXRjaElEc1tpXSkpIHtcbiAgICAgICAgcmV0dXJuIGRpc3BhdGNoSURzW2ldO1xuICAgICAgfVxuICAgIH1cbiAgfSBlbHNlIGlmIChkaXNwYXRjaExpc3RlbmVycykge1xuICAgIGlmIChkaXNwYXRjaExpc3RlbmVycyhldmVudCwgZGlzcGF0Y2hJRHMpKSB7XG4gICAgICByZXR1cm4gZGlzcGF0Y2hJRHM7XG4gICAgfVxuICB9XG4gIHJldHVybiBudWxsO1xufVxuXG4vKipcbiAqIEBzZWUgZXhlY3V0ZURpc3BhdGNoZXNJbk9yZGVyU3RvcEF0VHJ1ZUltcGxcbiAqL1xuZnVuY3Rpb24gZXhlY3V0ZURpc3BhdGNoZXNJbk9yZGVyU3RvcEF0VHJ1ZShldmVudCkge1xuICB2YXIgcmV0ID0gZXhlY3V0ZURpc3BhdGNoZXNJbk9yZGVyU3RvcEF0VHJ1ZUltcGwoZXZlbnQpO1xuICBldmVudC5fZGlzcGF0Y2hJRHMgPSBudWxsO1xuICBldmVudC5fZGlzcGF0Y2hMaXN0ZW5lcnMgPSBudWxsO1xuICByZXR1cm4gcmV0O1xufVxuXG4vKipcbiAqIEV4ZWN1dGlvbiBvZiBhIFwiZGlyZWN0XCIgZGlzcGF0Y2ggLSB0aGVyZSBtdXN0IGJlIGF0IG1vc3Qgb25lIGRpc3BhdGNoXG4gKiBhY2N1bXVsYXRlZCBvbiB0aGUgZXZlbnQgb3IgaXQgaXMgY29uc2lkZXJlZCBhbiBlcnJvci4gSXQgZG9lc24ndCByZWFsbHkgbWFrZVxuICogc2Vuc2UgZm9yIGFuIGV2ZW50IHdpdGggbXVsdGlwbGUgZGlzcGF0Y2hlcyAoYnViYmxlZCkgdG8ga2VlcCB0cmFjayBvZiB0aGVcbiAqIHJldHVybiB2YWx1ZXMgYXQgZWFjaCBkaXNwYXRjaCBleGVjdXRpb24sIGJ1dCBpdCBkb2VzIHRlbmQgdG8gbWFrZSBzZW5zZSB3aGVuXG4gKiBkZWFsaW5nIHdpdGggXCJkaXJlY3RcIiBkaXNwYXRjaGVzLlxuICpcbiAqIEByZXR1cm4gVGhlIHJldHVybiB2YWx1ZSBvZiBleGVjdXRpbmcgdGhlIHNpbmdsZSBkaXNwYXRjaC5cbiAqL1xuZnVuY3Rpb24gZXhlY3V0ZURpcmVjdERpc3BhdGNoKGV2ZW50KSB7XG4gIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICB2YWxpZGF0ZUV2ZW50RGlzcGF0Y2hlcyhldmVudCk7XG4gIH1cbiAgdmFyIGRpc3BhdGNoTGlzdGVuZXIgPSBldmVudC5fZGlzcGF0Y2hMaXN0ZW5lcnM7XG4gIHZhciBkaXNwYXRjaElEID0gZXZlbnQuX2Rpc3BhdGNoSURzO1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICFBcnJheS5pc0FycmF5KGRpc3BhdGNoTGlzdGVuZXIpLFxuICAgICdleGVjdXRlRGlyZWN0RGlzcGF0Y2goLi4uKTogSW52YWxpZCBgZXZlbnRgLidcbiAgKSA6IGludmFyaWFudCghQXJyYXkuaXNBcnJheShkaXNwYXRjaExpc3RlbmVyKSkpO1xuICB2YXIgcmVzID0gZGlzcGF0Y2hMaXN0ZW5lciA/XG4gICAgZGlzcGF0Y2hMaXN0ZW5lcihldmVudCwgZGlzcGF0Y2hJRCkgOlxuICAgIG51bGw7XG4gIGV2ZW50Ll9kaXNwYXRjaExpc3RlbmVycyA9IG51bGw7XG4gIGV2ZW50Ll9kaXNwYXRjaElEcyA9IG51bGw7XG4gIHJldHVybiByZXM7XG59XG5cbi8qKlxuICogQHBhcmFtIHtTeW50aGV0aWNFdmVudH0gZXZlbnRcbiAqIEByZXR1cm4ge2Jvb2x9IFRydWUgaWZmIG51bWJlciBvZiBkaXNwYXRjaGVzIGFjY3VtdWxhdGVkIGlzIGdyZWF0ZXIgdGhhbiAwLlxuICovXG5mdW5jdGlvbiBoYXNEaXNwYXRjaGVzKGV2ZW50KSB7XG4gIHJldHVybiAhIWV2ZW50Ll9kaXNwYXRjaExpc3RlbmVycztcbn1cblxuLyoqXG4gKiBHZW5lcmFsIHV0aWxpdGllcyB0aGF0IGFyZSB1c2VmdWwgaW4gY3JlYXRpbmcgY3VzdG9tIEV2ZW50IFBsdWdpbnMuXG4gKi9cbnZhciBFdmVudFBsdWdpblV0aWxzID0ge1xuICBpc0VuZGlzaDogaXNFbmRpc2gsXG4gIGlzTW92ZWlzaDogaXNNb3ZlaXNoLFxuICBpc1N0YXJ0aXNoOiBpc1N0YXJ0aXNoLFxuXG4gIGV4ZWN1dGVEaXJlY3REaXNwYXRjaDogZXhlY3V0ZURpcmVjdERpc3BhdGNoLFxuICBleGVjdXRlRGlzcGF0Y2g6IGV4ZWN1dGVEaXNwYXRjaCxcbiAgZXhlY3V0ZURpc3BhdGNoZXNJbk9yZGVyOiBleGVjdXRlRGlzcGF0Y2hlc0luT3JkZXIsXG4gIGV4ZWN1dGVEaXNwYXRjaGVzSW5PcmRlclN0b3BBdFRydWU6IGV4ZWN1dGVEaXNwYXRjaGVzSW5PcmRlclN0b3BBdFRydWUsXG4gIGhhc0Rpc3BhdGNoZXM6IGhhc0Rpc3BhdGNoZXMsXG4gIGluamVjdGlvbjogaW5qZWN0aW9uLFxuICB1c2VUb3VjaEV2ZW50czogZmFsc2Vcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gRXZlbnRQbHVnaW5VdGlscztcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBFdmVudFByb3BhZ2F0b3JzXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBFdmVudENvbnN0YW50cyA9IHJlcXVpcmUoXCIuL0V2ZW50Q29uc3RhbnRzXCIpO1xudmFyIEV2ZW50UGx1Z2luSHViID0gcmVxdWlyZShcIi4vRXZlbnRQbHVnaW5IdWJcIik7XG5cbnZhciBhY2N1bXVsYXRlSW50byA9IHJlcXVpcmUoXCIuL2FjY3VtdWxhdGVJbnRvXCIpO1xudmFyIGZvckVhY2hBY2N1bXVsYXRlZCA9IHJlcXVpcmUoXCIuL2ZvckVhY2hBY2N1bXVsYXRlZFwiKTtcblxudmFyIFByb3BhZ2F0aW9uUGhhc2VzID0gRXZlbnRDb25zdGFudHMuUHJvcGFnYXRpb25QaGFzZXM7XG52YXIgZ2V0TGlzdGVuZXIgPSBFdmVudFBsdWdpbkh1Yi5nZXRMaXN0ZW5lcjtcblxuLyoqXG4gKiBTb21lIGV2ZW50IHR5cGVzIGhhdmUgYSBub3Rpb24gb2YgZGlmZmVyZW50IHJlZ2lzdHJhdGlvbiBuYW1lcyBmb3IgZGlmZmVyZW50XG4gKiBcInBoYXNlc1wiIG9mIHByb3BhZ2F0aW9uLiBUaGlzIGZpbmRzIGxpc3RlbmVycyBieSBhIGdpdmVuIHBoYXNlLlxuICovXG5mdW5jdGlvbiBsaXN0ZW5lckF0UGhhc2UoaWQsIGV2ZW50LCBwcm9wYWdhdGlvblBoYXNlKSB7XG4gIHZhciByZWdpc3RyYXRpb25OYW1lID1cbiAgICBldmVudC5kaXNwYXRjaENvbmZpZy5waGFzZWRSZWdpc3RyYXRpb25OYW1lc1twcm9wYWdhdGlvblBoYXNlXTtcbiAgcmV0dXJuIGdldExpc3RlbmVyKGlkLCByZWdpc3RyYXRpb25OYW1lKTtcbn1cblxuLyoqXG4gKiBUYWdzIGEgYFN5bnRoZXRpY0V2ZW50YCB3aXRoIGRpc3BhdGNoZWQgbGlzdGVuZXJzLiBDcmVhdGluZyB0aGlzIGZ1bmN0aW9uXG4gKiBoZXJlLCBhbGxvd3MgdXMgdG8gbm90IGhhdmUgdG8gYmluZCBvciBjcmVhdGUgZnVuY3Rpb25zIGZvciBlYWNoIGV2ZW50LlxuICogTXV0YXRpbmcgdGhlIGV2ZW50J3MgbWVtYmVycyBhbGxvd3MgdXMgdG8gbm90IGhhdmUgdG8gY3JlYXRlIGEgd3JhcHBpbmdcbiAqIFwiZGlzcGF0Y2hcIiBvYmplY3QgdGhhdCBwYWlycyB0aGUgZXZlbnQgd2l0aCB0aGUgbGlzdGVuZXIuXG4gKi9cbmZ1bmN0aW9uIGFjY3VtdWxhdGVEaXJlY3Rpb25hbERpc3BhdGNoZXMoZG9tSUQsIHVwd2FyZHMsIGV2ZW50KSB7XG4gIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICBpZiAoIWRvbUlEKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Rpc3BhdGNoaW5nIGlkIG11c3Qgbm90IGJlIG51bGwnKTtcbiAgICB9XG4gIH1cbiAgdmFyIHBoYXNlID0gdXB3YXJkcyA/IFByb3BhZ2F0aW9uUGhhc2VzLmJ1YmJsZWQgOiBQcm9wYWdhdGlvblBoYXNlcy5jYXB0dXJlZDtcbiAgdmFyIGxpc3RlbmVyID0gbGlzdGVuZXJBdFBoYXNlKGRvbUlELCBldmVudCwgcGhhc2UpO1xuICBpZiAobGlzdGVuZXIpIHtcbiAgICBldmVudC5fZGlzcGF0Y2hMaXN0ZW5lcnMgPVxuICAgICAgYWNjdW11bGF0ZUludG8oZXZlbnQuX2Rpc3BhdGNoTGlzdGVuZXJzLCBsaXN0ZW5lcik7XG4gICAgZXZlbnQuX2Rpc3BhdGNoSURzID0gYWNjdW11bGF0ZUludG8oZXZlbnQuX2Rpc3BhdGNoSURzLCBkb21JRCk7XG4gIH1cbn1cblxuLyoqXG4gKiBDb2xsZWN0IGRpc3BhdGNoZXMgKG11c3QgYmUgZW50aXJlbHkgY29sbGVjdGVkIGJlZm9yZSBkaXNwYXRjaGluZyAtIHNlZSB1bml0XG4gKiB0ZXN0cykuIExhemlseSBhbGxvY2F0ZSB0aGUgYXJyYXkgdG8gY29uc2VydmUgbWVtb3J5LiAgV2UgbXVzdCBsb29wIHRocm91Z2hcbiAqIGVhY2ggZXZlbnQgYW5kIHBlcmZvcm0gdGhlIHRyYXZlcnNhbCBmb3IgZWFjaCBvbmUuIFdlIGNhbiBub3QgcGVyZm9ybSBhXG4gKiBzaW5nbGUgdHJhdmVyc2FsIGZvciB0aGUgZW50aXJlIGNvbGxlY3Rpb24gb2YgZXZlbnRzIGJlY2F1c2UgZWFjaCBldmVudCBtYXlcbiAqIGhhdmUgYSBkaWZmZXJlbnQgdGFyZ2V0LlxuICovXG5mdW5jdGlvbiBhY2N1bXVsYXRlVHdvUGhhc2VEaXNwYXRjaGVzU2luZ2xlKGV2ZW50KSB7XG4gIGlmIChldmVudCAmJiBldmVudC5kaXNwYXRjaENvbmZpZy5waGFzZWRSZWdpc3RyYXRpb25OYW1lcykge1xuICAgIEV2ZW50UGx1Z2luSHViLmluamVjdGlvbi5nZXRJbnN0YW5jZUhhbmRsZSgpLnRyYXZlcnNlVHdvUGhhc2UoXG4gICAgICBldmVudC5kaXNwYXRjaE1hcmtlcixcbiAgICAgIGFjY3VtdWxhdGVEaXJlY3Rpb25hbERpc3BhdGNoZXMsXG4gICAgICBldmVudFxuICAgICk7XG4gIH1cbn1cblxuXG4vKipcbiAqIEFjY3VtdWxhdGVzIHdpdGhvdXQgcmVnYXJkIHRvIGRpcmVjdGlvbiwgZG9lcyBub3QgbG9vayBmb3IgcGhhc2VkXG4gKiByZWdpc3RyYXRpb24gbmFtZXMuIFNhbWUgYXMgYGFjY3VtdWxhdGVEaXJlY3REaXNwYXRjaGVzU2luZ2xlYCBidXQgd2l0aG91dFxuICogcmVxdWlyaW5nIHRoYXQgdGhlIGBkaXNwYXRjaE1hcmtlcmAgYmUgdGhlIHNhbWUgYXMgdGhlIGRpc3BhdGNoZWQgSUQuXG4gKi9cbmZ1bmN0aW9uIGFjY3VtdWxhdGVEaXNwYXRjaGVzKGlkLCBpZ25vcmVkRGlyZWN0aW9uLCBldmVudCkge1xuICBpZiAoZXZlbnQgJiYgZXZlbnQuZGlzcGF0Y2hDb25maWcucmVnaXN0cmF0aW9uTmFtZSkge1xuICAgIHZhciByZWdpc3RyYXRpb25OYW1lID0gZXZlbnQuZGlzcGF0Y2hDb25maWcucmVnaXN0cmF0aW9uTmFtZTtcbiAgICB2YXIgbGlzdGVuZXIgPSBnZXRMaXN0ZW5lcihpZCwgcmVnaXN0cmF0aW9uTmFtZSk7XG4gICAgaWYgKGxpc3RlbmVyKSB7XG4gICAgICBldmVudC5fZGlzcGF0Y2hMaXN0ZW5lcnMgPVxuICAgICAgICBhY2N1bXVsYXRlSW50byhldmVudC5fZGlzcGF0Y2hMaXN0ZW5lcnMsIGxpc3RlbmVyKTtcbiAgICAgIGV2ZW50Ll9kaXNwYXRjaElEcyA9IGFjY3VtdWxhdGVJbnRvKGV2ZW50Ll9kaXNwYXRjaElEcywgaWQpO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIEFjY3VtdWxhdGVzIGRpc3BhdGNoZXMgb24gYW4gYFN5bnRoZXRpY0V2ZW50YCwgYnV0IG9ubHkgZm9yIHRoZVxuICogYGRpc3BhdGNoTWFya2VyYC5cbiAqIEBwYXJhbSB7U3ludGhldGljRXZlbnR9IGV2ZW50XG4gKi9cbmZ1bmN0aW9uIGFjY3VtdWxhdGVEaXJlY3REaXNwYXRjaGVzU2luZ2xlKGV2ZW50KSB7XG4gIGlmIChldmVudCAmJiBldmVudC5kaXNwYXRjaENvbmZpZy5yZWdpc3RyYXRpb25OYW1lKSB7XG4gICAgYWNjdW11bGF0ZURpc3BhdGNoZXMoZXZlbnQuZGlzcGF0Y2hNYXJrZXIsIG51bGwsIGV2ZW50KTtcbiAgfVxufVxuXG5mdW5jdGlvbiBhY2N1bXVsYXRlVHdvUGhhc2VEaXNwYXRjaGVzKGV2ZW50cykge1xuICBmb3JFYWNoQWNjdW11bGF0ZWQoZXZlbnRzLCBhY2N1bXVsYXRlVHdvUGhhc2VEaXNwYXRjaGVzU2luZ2xlKTtcbn1cblxuZnVuY3Rpb24gYWNjdW11bGF0ZUVudGVyTGVhdmVEaXNwYXRjaGVzKGxlYXZlLCBlbnRlciwgZnJvbUlELCB0b0lEKSB7XG4gIEV2ZW50UGx1Z2luSHViLmluamVjdGlvbi5nZXRJbnN0YW5jZUhhbmRsZSgpLnRyYXZlcnNlRW50ZXJMZWF2ZShcbiAgICBmcm9tSUQsXG4gICAgdG9JRCxcbiAgICBhY2N1bXVsYXRlRGlzcGF0Y2hlcyxcbiAgICBsZWF2ZSxcbiAgICBlbnRlclxuICApO1xufVxuXG5cbmZ1bmN0aW9uIGFjY3VtdWxhdGVEaXJlY3REaXNwYXRjaGVzKGV2ZW50cykge1xuICBmb3JFYWNoQWNjdW11bGF0ZWQoZXZlbnRzLCBhY2N1bXVsYXRlRGlyZWN0RGlzcGF0Y2hlc1NpbmdsZSk7XG59XG5cblxuXG4vKipcbiAqIEEgc21hbGwgc2V0IG9mIHByb3BhZ2F0aW9uIHBhdHRlcm5zLCBlYWNoIG9mIHdoaWNoIHdpbGwgYWNjZXB0IGEgc21hbGwgYW1vdW50XG4gKiBvZiBpbmZvcm1hdGlvbiwgYW5kIGdlbmVyYXRlIGEgc2V0IG9mIFwiZGlzcGF0Y2ggcmVhZHkgZXZlbnQgb2JqZWN0c1wiIC0gd2hpY2hcbiAqIGFyZSBzZXRzIG9mIGV2ZW50cyB0aGF0IGhhdmUgYWxyZWFkeSBiZWVuIGFubm90YXRlZCB3aXRoIGEgc2V0IG9mIGRpc3BhdGNoZWRcbiAqIGxpc3RlbmVyIGZ1bmN0aW9ucy9pZHMuIFRoZSBBUEkgaXMgZGVzaWduZWQgdGhpcyB3YXkgdG8gZGlzY291cmFnZSB0aGVzZVxuICogcHJvcGFnYXRpb24gc3RyYXRlZ2llcyBmcm9tIGFjdHVhbGx5IGV4ZWN1dGluZyB0aGUgZGlzcGF0Y2hlcywgc2luY2Ugd2VcbiAqIGFsd2F5cyB3YW50IHRvIGNvbGxlY3QgdGhlIGVudGlyZSBzZXQgb2YgZGlzcGF0Y2hlcyBiZWZvcmUgZXhlY3V0aW5nIGV2ZW50IGFcbiAqIHNpbmdsZSBvbmUuXG4gKlxuICogQGNvbnN0cnVjdG9yIEV2ZW50UHJvcGFnYXRvcnNcbiAqL1xudmFyIEV2ZW50UHJvcGFnYXRvcnMgPSB7XG4gIGFjY3VtdWxhdGVUd29QaGFzZURpc3BhdGNoZXM6IGFjY3VtdWxhdGVUd29QaGFzZURpc3BhdGNoZXMsXG4gIGFjY3VtdWxhdGVEaXJlY3REaXNwYXRjaGVzOiBhY2N1bXVsYXRlRGlyZWN0RGlzcGF0Y2hlcyxcbiAgYWNjdW11bGF0ZUVudGVyTGVhdmVEaXNwYXRjaGVzOiBhY2N1bXVsYXRlRW50ZXJMZWF2ZURpc3BhdGNoZXNcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gRXZlbnRQcm9wYWdhdG9ycztcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIEV4ZWN1dGlvbkVudmlyb25tZW50XG4gKi9cblxuLypqc2xpbnQgZXZpbDogdHJ1ZSAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIGNhblVzZURPTSA9ICEhKFxuICB0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyAmJlxuICB3aW5kb3cuZG9jdW1lbnQgJiZcbiAgd2luZG93LmRvY3VtZW50LmNyZWF0ZUVsZW1lbnRcbik7XG5cbi8qKlxuICogU2ltcGxlLCBsaWdodHdlaWdodCBtb2R1bGUgYXNzaXN0aW5nIHdpdGggdGhlIGRldGVjdGlvbiBhbmQgY29udGV4dCBvZlxuICogV29ya2VyLiBIZWxwcyBhdm9pZCBjaXJjdWxhciBkZXBlbmRlbmNpZXMgYW5kIGFsbG93cyBjb2RlIHRvIHJlYXNvbiBhYm91dFxuICogd2hldGhlciBvciBub3QgdGhleSBhcmUgaW4gYSBXb3JrZXIsIGV2ZW4gaWYgdGhleSBuZXZlciBpbmNsdWRlIHRoZSBtYWluXG4gKiBgUmVhY3RXb3JrZXJgIGRlcGVuZGVuY3kuXG4gKi9cbnZhciBFeGVjdXRpb25FbnZpcm9ubWVudCA9IHtcblxuICBjYW5Vc2VET006IGNhblVzZURPTSxcblxuICBjYW5Vc2VXb3JrZXJzOiB0eXBlb2YgV29ya2VyICE9PSAndW5kZWZpbmVkJyxcblxuICBjYW5Vc2VFdmVudExpc3RlbmVyczpcbiAgICBjYW5Vc2VET00gJiYgISEod2luZG93LmFkZEV2ZW50TGlzdGVuZXIgfHwgd2luZG93LmF0dGFjaEV2ZW50KSxcblxuICBjYW5Vc2VWaWV3cG9ydDogY2FuVXNlRE9NICYmICEhd2luZG93LnNjcmVlbixcblxuICBpc0luV29ya2VyOiAhY2FuVXNlRE9NIC8vIEZvciBub3csIHRoaXMgaXMgdHJ1ZSAtIG1pZ2h0IGNoYW5nZSBpbiB0aGUgZnV0dXJlLlxuXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEV4ZWN1dGlvbkVudmlyb25tZW50O1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIEhUTUxET01Qcm9wZXJ0eUNvbmZpZ1xuICovXG5cbi8qanNsaW50IGJpdHdpc2U6IHRydWUqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIERPTVByb3BlcnR5ID0gcmVxdWlyZShcIi4vRE9NUHJvcGVydHlcIik7XG52YXIgRXhlY3V0aW9uRW52aXJvbm1lbnQgPSByZXF1aXJlKFwiLi9FeGVjdXRpb25FbnZpcm9ubWVudFwiKTtcblxudmFyIE1VU1RfVVNFX0FUVFJJQlVURSA9IERPTVByb3BlcnR5LmluamVjdGlvbi5NVVNUX1VTRV9BVFRSSUJVVEU7XG52YXIgTVVTVF9VU0VfUFJPUEVSVFkgPSBET01Qcm9wZXJ0eS5pbmplY3Rpb24uTVVTVF9VU0VfUFJPUEVSVFk7XG52YXIgSEFTX0JPT0xFQU5fVkFMVUUgPSBET01Qcm9wZXJ0eS5pbmplY3Rpb24uSEFTX0JPT0xFQU5fVkFMVUU7XG52YXIgSEFTX1NJREVfRUZGRUNUUyA9IERPTVByb3BlcnR5LmluamVjdGlvbi5IQVNfU0lERV9FRkZFQ1RTO1xudmFyIEhBU19OVU1FUklDX1ZBTFVFID0gRE9NUHJvcGVydHkuaW5qZWN0aW9uLkhBU19OVU1FUklDX1ZBTFVFO1xudmFyIEhBU19QT1NJVElWRV9OVU1FUklDX1ZBTFVFID1cbiAgRE9NUHJvcGVydHkuaW5qZWN0aW9uLkhBU19QT1NJVElWRV9OVU1FUklDX1ZBTFVFO1xudmFyIEhBU19PVkVSTE9BREVEX0JPT0xFQU5fVkFMVUUgPVxuICBET01Qcm9wZXJ0eS5pbmplY3Rpb24uSEFTX09WRVJMT0FERURfQk9PTEVBTl9WQUxVRTtcblxudmFyIGhhc1NWRztcbmlmIChFeGVjdXRpb25FbnZpcm9ubWVudC5jYW5Vc2VET00pIHtcbiAgdmFyIGltcGxlbWVudGF0aW9uID0gZG9jdW1lbnQuaW1wbGVtZW50YXRpb247XG4gIGhhc1NWRyA9IChcbiAgICBpbXBsZW1lbnRhdGlvbiAmJlxuICAgIGltcGxlbWVudGF0aW9uLmhhc0ZlYXR1cmUgJiZcbiAgICBpbXBsZW1lbnRhdGlvbi5oYXNGZWF0dXJlKFxuICAgICAgJ2h0dHA6Ly93d3cudzMub3JnL1RSL1NWRzExL2ZlYXR1cmUjQmFzaWNTdHJ1Y3R1cmUnLFxuICAgICAgJzEuMSdcbiAgICApXG4gICk7XG59XG5cblxudmFyIEhUTUxET01Qcm9wZXJ0eUNvbmZpZyA9IHtcbiAgaXNDdXN0b21BdHRyaWJ1dGU6IFJlZ0V4cC5wcm90b3R5cGUudGVzdC5iaW5kKFxuICAgIC9eKGRhdGF8YXJpYSktW2Etel9dW2EtelxcZF8uXFwtXSokL1xuICApLFxuICBQcm9wZXJ0aWVzOiB7XG4gICAgLyoqXG4gICAgICogU3RhbmRhcmQgUHJvcGVydGllc1xuICAgICAqL1xuICAgIGFjY2VwdDogbnVsbCxcbiAgICBhY2NlcHRDaGFyc2V0OiBudWxsLFxuICAgIGFjY2Vzc0tleTogbnVsbCxcbiAgICBhY3Rpb246IG51bGwsXG4gICAgYWxsb3dGdWxsU2NyZWVuOiBNVVNUX1VTRV9BVFRSSUJVVEUgfCBIQVNfQk9PTEVBTl9WQUxVRSxcbiAgICBhbGxvd1RyYW5zcGFyZW5jeTogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIGFsdDogbnVsbCxcbiAgICBhc3luYzogSEFTX0JPT0xFQU5fVkFMVUUsXG4gICAgYXV0b0NvbXBsZXRlOiBudWxsLFxuICAgIC8vIGF1dG9Gb2N1cyBpcyBwb2x5ZmlsbGVkL25vcm1hbGl6ZWQgYnkgQXV0b0ZvY3VzTWl4aW5cbiAgICAvLyBhdXRvRm9jdXM6IEhBU19CT09MRUFOX1ZBTFVFLFxuICAgIGF1dG9QbGF5OiBIQVNfQk9PTEVBTl9WQUxVRSxcbiAgICBjZWxsUGFkZGluZzogbnVsbCxcbiAgICBjZWxsU3BhY2luZzogbnVsbCxcbiAgICBjaGFyU2V0OiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgY2hlY2tlZDogTVVTVF9VU0VfUFJPUEVSVFkgfCBIQVNfQk9PTEVBTl9WQUxVRSxcbiAgICBjbGFzc0lEOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgLy8gVG8gc2V0IGNsYXNzTmFtZSBvbiBTVkcgZWxlbWVudHMsIGl0J3MgbmVjZXNzYXJ5IHRvIHVzZSAuc2V0QXR0cmlidXRlO1xuICAgIC8vIHRoaXMgd29ya3Mgb24gSFRNTCBlbGVtZW50cyB0b28gaW4gYWxsIGJyb3dzZXJzIGV4Y2VwdCBJRTguIENvbnZlbmllbnRseSxcbiAgICAvLyBJRTggZG9lc24ndCBzdXBwb3J0IFNWRyBhbmQgc28gd2UgY2FuIHNpbXBseSB1c2UgdGhlIGF0dHJpYnV0ZSBpblxuICAgIC8vIGJyb3dzZXJzIHRoYXQgc3VwcG9ydCBTVkcgYW5kIHRoZSBwcm9wZXJ0eSBpbiBicm93c2VycyB0aGF0IGRvbid0LFxuICAgIC8vIHJlZ2FyZGxlc3Mgb2Ygd2hldGhlciB0aGUgZWxlbWVudCBpcyBIVE1MIG9yIFNWRy5cbiAgICBjbGFzc05hbWU6IGhhc1NWRyA/IE1VU1RfVVNFX0FUVFJJQlVURSA6IE1VU1RfVVNFX1BST1BFUlRZLFxuICAgIGNvbHM6IE1VU1RfVVNFX0FUVFJJQlVURSB8IEhBU19QT1NJVElWRV9OVU1FUklDX1ZBTFVFLFxuICAgIGNvbFNwYW46IG51bGwsXG4gICAgY29udGVudDogbnVsbCxcbiAgICBjb250ZW50RWRpdGFibGU6IG51bGwsXG4gICAgY29udGV4dE1lbnU6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBjb250cm9sczogTVVTVF9VU0VfUFJPUEVSVFkgfCBIQVNfQk9PTEVBTl9WQUxVRSxcbiAgICBjb29yZHM6IG51bGwsXG4gICAgY3Jvc3NPcmlnaW46IG51bGwsXG4gICAgZGF0YTogbnVsbCwgLy8gRm9yIGA8b2JqZWN0IC8+YCBhY3RzIGFzIGBzcmNgLlxuICAgIGRhdGVUaW1lOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgZGVmZXI6IEhBU19CT09MRUFOX1ZBTFVFLFxuICAgIGRpcjogbnVsbCxcbiAgICBkaXNhYmxlZDogTVVTVF9VU0VfQVRUUklCVVRFIHwgSEFTX0JPT0xFQU5fVkFMVUUsXG4gICAgZG93bmxvYWQ6IEhBU19PVkVSTE9BREVEX0JPT0xFQU5fVkFMVUUsXG4gICAgZHJhZ2dhYmxlOiBudWxsLFxuICAgIGVuY1R5cGU6IG51bGwsXG4gICAgZm9ybTogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIGZvcm1BY3Rpb246IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBmb3JtRW5jVHlwZTogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIGZvcm1NZXRob2Q6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBmb3JtTm9WYWxpZGF0ZTogSEFTX0JPT0xFQU5fVkFMVUUsXG4gICAgZm9ybVRhcmdldDogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIGZyYW1lQm9yZGVyOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgaGVpZ2h0OiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgaGlkZGVuOiBNVVNUX1VTRV9BVFRSSUJVVEUgfCBIQVNfQk9PTEVBTl9WQUxVRSxcbiAgICBocmVmOiBudWxsLFxuICAgIGhyZWZMYW5nOiBudWxsLFxuICAgIGh0bWxGb3I6IG51bGwsXG4gICAgaHR0cEVxdWl2OiBudWxsLFxuICAgIGljb246IG51bGwsXG4gICAgaWQ6IE1VU1RfVVNFX1BST1BFUlRZLFxuICAgIGxhYmVsOiBudWxsLFxuICAgIGxhbmc6IG51bGwsXG4gICAgbGlzdDogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIGxvb3A6IE1VU1RfVVNFX1BST1BFUlRZIHwgSEFTX0JPT0xFQU5fVkFMVUUsXG4gICAgbWFuaWZlc3Q6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBtYXJnaW5IZWlnaHQ6IG51bGwsXG4gICAgbWFyZ2luV2lkdGg6IG51bGwsXG4gICAgbWF4OiBudWxsLFxuICAgIG1heExlbmd0aDogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIG1lZGlhOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgbWVkaWFHcm91cDogbnVsbCxcbiAgICBtZXRob2Q6IG51bGwsXG4gICAgbWluOiBudWxsLFxuICAgIG11bHRpcGxlOiBNVVNUX1VTRV9QUk9QRVJUWSB8IEhBU19CT09MRUFOX1ZBTFVFLFxuICAgIG11dGVkOiBNVVNUX1VTRV9QUk9QRVJUWSB8IEhBU19CT09MRUFOX1ZBTFVFLFxuICAgIG5hbWU6IG51bGwsXG4gICAgbm9WYWxpZGF0ZTogSEFTX0JPT0xFQU5fVkFMVUUsXG4gICAgb3BlbjogbnVsbCxcbiAgICBwYXR0ZXJuOiBudWxsLFxuICAgIHBsYWNlaG9sZGVyOiBudWxsLFxuICAgIHBvc3RlcjogbnVsbCxcbiAgICBwcmVsb2FkOiBudWxsLFxuICAgIHJhZGlvR3JvdXA6IG51bGwsXG4gICAgcmVhZE9ubHk6IE1VU1RfVVNFX1BST1BFUlRZIHwgSEFTX0JPT0xFQU5fVkFMVUUsXG4gICAgcmVsOiBudWxsLFxuICAgIHJlcXVpcmVkOiBIQVNfQk9PTEVBTl9WQUxVRSxcbiAgICByb2xlOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgcm93czogTVVTVF9VU0VfQVRUUklCVVRFIHwgSEFTX1BPU0lUSVZFX05VTUVSSUNfVkFMVUUsXG4gICAgcm93U3BhbjogbnVsbCxcbiAgICBzYW5kYm94OiBudWxsLFxuICAgIHNjb3BlOiBudWxsLFxuICAgIHNjcm9sbGluZzogbnVsbCxcbiAgICBzZWFtbGVzczogTVVTVF9VU0VfQVRUUklCVVRFIHwgSEFTX0JPT0xFQU5fVkFMVUUsXG4gICAgc2VsZWN0ZWQ6IE1VU1RfVVNFX1BST1BFUlRZIHwgSEFTX0JPT0xFQU5fVkFMVUUsXG4gICAgc2hhcGU6IG51bGwsXG4gICAgc2l6ZTogTVVTVF9VU0VfQVRUUklCVVRFIHwgSEFTX1BPU0lUSVZFX05VTUVSSUNfVkFMVUUsXG4gICAgc2l6ZXM6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBzcGFuOiBIQVNfUE9TSVRJVkVfTlVNRVJJQ19WQUxVRSxcbiAgICBzcGVsbENoZWNrOiBudWxsLFxuICAgIHNyYzogbnVsbCxcbiAgICBzcmNEb2M6IE1VU1RfVVNFX1BST1BFUlRZLFxuICAgIHNyY1NldDogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIHN0YXJ0OiBIQVNfTlVNRVJJQ19WQUxVRSxcbiAgICBzdGVwOiBudWxsLFxuICAgIHN0eWxlOiBudWxsLFxuICAgIHRhYkluZGV4OiBudWxsLFxuICAgIHRhcmdldDogbnVsbCxcbiAgICB0aXRsZTogbnVsbCxcbiAgICB0eXBlOiBudWxsLFxuICAgIHVzZU1hcDogbnVsbCxcbiAgICB2YWx1ZTogTVVTVF9VU0VfUFJPUEVSVFkgfCBIQVNfU0lERV9FRkZFQ1RTLFxuICAgIHdpZHRoOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgd21vZGU6IE1VU1RfVVNFX0FUVFJJQlVURSxcblxuICAgIC8qKlxuICAgICAqIE5vbi1zdGFuZGFyZCBQcm9wZXJ0aWVzXG4gICAgICovXG4gICAgYXV0b0NhcGl0YWxpemU6IG51bGwsIC8vIFN1cHBvcnRlZCBpbiBNb2JpbGUgU2FmYXJpIGZvciBrZXlib2FyZCBoaW50c1xuICAgIGF1dG9Db3JyZWN0OiBudWxsLCAvLyBTdXBwb3J0ZWQgaW4gTW9iaWxlIFNhZmFyaSBmb3Iga2V5Ym9hcmQgaGludHNcbiAgICBpdGVtUHJvcDogTVVTVF9VU0VfQVRUUklCVVRFLCAvLyBNaWNyb2RhdGE6IGh0dHA6Ly9zY2hlbWEub3JnL2RvY3MvZ3MuaHRtbFxuICAgIGl0ZW1TY29wZTogTVVTVF9VU0VfQVRUUklCVVRFIHwgSEFTX0JPT0xFQU5fVkFMVUUsIC8vIE1pY3JvZGF0YTogaHR0cDovL3NjaGVtYS5vcmcvZG9jcy9ncy5odG1sXG4gICAgaXRlbVR5cGU6IE1VU1RfVVNFX0FUVFJJQlVURSwgLy8gTWljcm9kYXRhOiBodHRwOi8vc2NoZW1hLm9yZy9kb2NzL2dzLmh0bWxcbiAgICBwcm9wZXJ0eTogbnVsbCAvLyBTdXBwb3J0cyBPRyBpbiBtZXRhIHRhZ3NcbiAgfSxcbiAgRE9NQXR0cmlidXRlTmFtZXM6IHtcbiAgICBhY2NlcHRDaGFyc2V0OiAnYWNjZXB0LWNoYXJzZXQnLFxuICAgIGNsYXNzTmFtZTogJ2NsYXNzJyxcbiAgICBodG1sRm9yOiAnZm9yJyxcbiAgICBodHRwRXF1aXY6ICdodHRwLWVxdWl2J1xuICB9LFxuICBET01Qcm9wZXJ0eU5hbWVzOiB7XG4gICAgYXV0b0NhcGl0YWxpemU6ICdhdXRvY2FwaXRhbGl6ZScsXG4gICAgYXV0b0NvbXBsZXRlOiAnYXV0b2NvbXBsZXRlJyxcbiAgICBhdXRvQ29ycmVjdDogJ2F1dG9jb3JyZWN0JyxcbiAgICBhdXRvRm9jdXM6ICdhdXRvZm9jdXMnLFxuICAgIGF1dG9QbGF5OiAnYXV0b3BsYXknLFxuICAgIGVuY1R5cGU6ICdlbmN0eXBlJyxcbiAgICBocmVmTGFuZzogJ2hyZWZsYW5nJyxcbiAgICByYWRpb0dyb3VwOiAncmFkaW9ncm91cCcsXG4gICAgc3BlbGxDaGVjazogJ3NwZWxsY2hlY2snLFxuICAgIHNyY0RvYzogJ3NyY2RvYycsXG4gICAgc3JjU2V0OiAnc3Jjc2V0J1xuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEhUTUxET01Qcm9wZXJ0eUNvbmZpZztcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBMaW5rZWRTdGF0ZU1peGluXG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgUmVhY3RMaW5rID0gcmVxdWlyZShcIi4vUmVhY3RMaW5rXCIpO1xudmFyIFJlYWN0U3RhdGVTZXR0ZXJzID0gcmVxdWlyZShcIi4vUmVhY3RTdGF0ZVNldHRlcnNcIik7XG5cbi8qKlxuICogQSBzaW1wbGUgbWl4aW4gYXJvdW5kIFJlYWN0TGluay5mb3JTdGF0ZSgpLlxuICovXG52YXIgTGlua2VkU3RhdGVNaXhpbiA9IHtcbiAgLyoqXG4gICAqIENyZWF0ZSBhIFJlYWN0TGluayB0aGF0J3MgbGlua2VkIHRvIHBhcnQgb2YgdGhpcyBjb21wb25lbnQncyBzdGF0ZS4gVGhlXG4gICAqIFJlYWN0TGluayB3aWxsIGhhdmUgdGhlIGN1cnJlbnQgdmFsdWUgb2YgdGhpcy5zdGF0ZVtrZXldIGFuZCB3aWxsIGNhbGxcbiAgICogc2V0U3RhdGUoKSB3aGVuIGEgY2hhbmdlIGlzIHJlcXVlc3RlZC5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IGtleSBzdGF0ZSBrZXkgdG8gdXBkYXRlLiBOb3RlOiB5b3UgbWF5IHdhbnQgdG8gdXNlIGtleU9mKClcbiAgICogaWYgeW91J3JlIHVzaW5nIEdvb2dsZSBDbG9zdXJlIENvbXBpbGVyIGFkdmFuY2VkIG1vZGUuXG4gICAqIEByZXR1cm4ge1JlYWN0TGlua30gUmVhY3RMaW5rIGluc3RhbmNlIGxpbmtpbmcgdG8gdGhlIHN0YXRlLlxuICAgKi9cbiAgbGlua1N0YXRlOiBmdW5jdGlvbihrZXkpIHtcbiAgICByZXR1cm4gbmV3IFJlYWN0TGluayhcbiAgICAgIHRoaXMuc3RhdGVba2V5XSxcbiAgICAgIFJlYWN0U3RhdGVTZXR0ZXJzLmNyZWF0ZVN0YXRlS2V5U2V0dGVyKHRoaXMsIGtleSlcbiAgICApO1xuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IExpbmtlZFN0YXRlTWl4aW47XG4iLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIExpbmtlZFZhbHVlVXRpbHNcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBSZWFjdFByb3BUeXBlcyA9IHJlcXVpcmUoXCIuL1JlYWN0UHJvcFR5cGVzXCIpO1xuXG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG52YXIgaGFzUmVhZE9ubHlWYWx1ZSA9IHtcbiAgJ2J1dHRvbic6IHRydWUsXG4gICdjaGVja2JveCc6IHRydWUsXG4gICdpbWFnZSc6IHRydWUsXG4gICdoaWRkZW4nOiB0cnVlLFxuICAncmFkaW8nOiB0cnVlLFxuICAncmVzZXQnOiB0cnVlLFxuICAnc3VibWl0JzogdHJ1ZVxufTtcblxuZnVuY3Rpb24gX2Fzc2VydFNpbmdsZUxpbmsoaW5wdXQpIHtcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICBpbnB1dC5wcm9wcy5jaGVja2VkTGluayA9PSBudWxsIHx8IGlucHV0LnByb3BzLnZhbHVlTGluayA9PSBudWxsLFxuICAgICdDYW5ub3QgcHJvdmlkZSBhIGNoZWNrZWRMaW5rIGFuZCBhIHZhbHVlTGluay4gSWYgeW91IHdhbnQgdG8gdXNlICcgK1xuICAgICdjaGVja2VkTGluaywgeW91IHByb2JhYmx5IGRvblxcJ3Qgd2FudCB0byB1c2UgdmFsdWVMaW5rIGFuZCB2aWNlIHZlcnNhLidcbiAgKSA6IGludmFyaWFudChpbnB1dC5wcm9wcy5jaGVja2VkTGluayA9PSBudWxsIHx8IGlucHV0LnByb3BzLnZhbHVlTGluayA9PSBudWxsKSk7XG59XG5mdW5jdGlvbiBfYXNzZXJ0VmFsdWVMaW5rKGlucHV0KSB7XG4gIF9hc3NlcnRTaW5nbGVMaW5rKGlucHV0KTtcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICBpbnB1dC5wcm9wcy52YWx1ZSA9PSBudWxsICYmIGlucHV0LnByb3BzLm9uQ2hhbmdlID09IG51bGwsXG4gICAgJ0Nhbm5vdCBwcm92aWRlIGEgdmFsdWVMaW5rIGFuZCBhIHZhbHVlIG9yIG9uQ2hhbmdlIGV2ZW50LiBJZiB5b3Ugd2FudCAnICtcbiAgICAndG8gdXNlIHZhbHVlIG9yIG9uQ2hhbmdlLCB5b3UgcHJvYmFibHkgZG9uXFwndCB3YW50IHRvIHVzZSB2YWx1ZUxpbmsuJ1xuICApIDogaW52YXJpYW50KGlucHV0LnByb3BzLnZhbHVlID09IG51bGwgJiYgaW5wdXQucHJvcHMub25DaGFuZ2UgPT0gbnVsbCkpO1xufVxuXG5mdW5jdGlvbiBfYXNzZXJ0Q2hlY2tlZExpbmsoaW5wdXQpIHtcbiAgX2Fzc2VydFNpbmdsZUxpbmsoaW5wdXQpO1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgIGlucHV0LnByb3BzLmNoZWNrZWQgPT0gbnVsbCAmJiBpbnB1dC5wcm9wcy5vbkNoYW5nZSA9PSBudWxsLFxuICAgICdDYW5ub3QgcHJvdmlkZSBhIGNoZWNrZWRMaW5rIGFuZCBhIGNoZWNrZWQgcHJvcGVydHkgb3Igb25DaGFuZ2UgZXZlbnQuICcgK1xuICAgICdJZiB5b3Ugd2FudCB0byB1c2UgY2hlY2tlZCBvciBvbkNoYW5nZSwgeW91IHByb2JhYmx5IGRvblxcJ3Qgd2FudCB0byAnICtcbiAgICAndXNlIGNoZWNrZWRMaW5rJ1xuICApIDogaW52YXJpYW50KGlucHV0LnByb3BzLmNoZWNrZWQgPT0gbnVsbCAmJiBpbnB1dC5wcm9wcy5vbkNoYW5nZSA9PSBudWxsKSk7XG59XG5cbi8qKlxuICogQHBhcmFtIHtTeW50aGV0aWNFdmVudH0gZSBjaGFuZ2UgZXZlbnQgdG8gaGFuZGxlXG4gKi9cbmZ1bmN0aW9uIF9oYW5kbGVMaW5rZWRWYWx1ZUNoYW5nZShlKSB7XG4gIC8qanNoaW50IHZhbGlkdGhpczp0cnVlICovXG4gIHRoaXMucHJvcHMudmFsdWVMaW5rLnJlcXVlc3RDaGFuZ2UoZS50YXJnZXQudmFsdWUpO1xufVxuXG4vKipcbiAgKiBAcGFyYW0ge1N5bnRoZXRpY0V2ZW50fSBlIGNoYW5nZSBldmVudCB0byBoYW5kbGVcbiAgKi9cbmZ1bmN0aW9uIF9oYW5kbGVMaW5rZWRDaGVja0NoYW5nZShlKSB7XG4gIC8qanNoaW50IHZhbGlkdGhpczp0cnVlICovXG4gIHRoaXMucHJvcHMuY2hlY2tlZExpbmsucmVxdWVzdENoYW5nZShlLnRhcmdldC5jaGVja2VkKTtcbn1cblxuLyoqXG4gKiBQcm92aWRlIGEgbGlua2VkIGB2YWx1ZWAgYXR0cmlidXRlIGZvciBjb250cm9sbGVkIGZvcm1zLiBZb3Ugc2hvdWxkIG5vdCB1c2VcbiAqIHRoaXMgb3V0c2lkZSBvZiB0aGUgUmVhY3RET00gY29udHJvbGxlZCBmb3JtIGNvbXBvbmVudHMuXG4gKi9cbnZhciBMaW5rZWRWYWx1ZVV0aWxzID0ge1xuICBNaXhpbjoge1xuICAgIHByb3BUeXBlczoge1xuICAgICAgdmFsdWU6IGZ1bmN0aW9uKHByb3BzLCBwcm9wTmFtZSwgY29tcG9uZW50TmFtZSkge1xuICAgICAgICBpZiAoIXByb3BzW3Byb3BOYW1lXSB8fFxuICAgICAgICAgICAgaGFzUmVhZE9ubHlWYWx1ZVtwcm9wcy50eXBlXSB8fFxuICAgICAgICAgICAgcHJvcHMub25DaGFuZ2UgfHxcbiAgICAgICAgICAgIHByb3BzLnJlYWRPbmx5IHx8XG4gICAgICAgICAgICBwcm9wcy5kaXNhYmxlZCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbmV3IEVycm9yKFxuICAgICAgICAgICdZb3UgcHJvdmlkZWQgYSBgdmFsdWVgIHByb3AgdG8gYSBmb3JtIGZpZWxkIHdpdGhvdXQgYW4gJyArXG4gICAgICAgICAgJ2BvbkNoYW5nZWAgaGFuZGxlci4gVGhpcyB3aWxsIHJlbmRlciBhIHJlYWQtb25seSBmaWVsZC4gSWYgJyArXG4gICAgICAgICAgJ3RoZSBmaWVsZCBzaG91bGQgYmUgbXV0YWJsZSB1c2UgYGRlZmF1bHRWYWx1ZWAuIE90aGVyd2lzZSwgJyArXG4gICAgICAgICAgJ3NldCBlaXRoZXIgYG9uQ2hhbmdlYCBvciBgcmVhZE9ubHlgLidcbiAgICAgICAgKTtcbiAgICAgIH0sXG4gICAgICBjaGVja2VkOiBmdW5jdGlvbihwcm9wcywgcHJvcE5hbWUsIGNvbXBvbmVudE5hbWUpIHtcbiAgICAgICAgaWYgKCFwcm9wc1twcm9wTmFtZV0gfHxcbiAgICAgICAgICAgIHByb3BzLm9uQ2hhbmdlIHx8XG4gICAgICAgICAgICBwcm9wcy5yZWFkT25seSB8fFxuICAgICAgICAgICAgcHJvcHMuZGlzYWJsZWQpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG5ldyBFcnJvcihcbiAgICAgICAgICAnWW91IHByb3ZpZGVkIGEgYGNoZWNrZWRgIHByb3AgdG8gYSBmb3JtIGZpZWxkIHdpdGhvdXQgYW4gJyArXG4gICAgICAgICAgJ2BvbkNoYW5nZWAgaGFuZGxlci4gVGhpcyB3aWxsIHJlbmRlciBhIHJlYWQtb25seSBmaWVsZC4gSWYgJyArXG4gICAgICAgICAgJ3RoZSBmaWVsZCBzaG91bGQgYmUgbXV0YWJsZSB1c2UgYGRlZmF1bHRDaGVja2VkYC4gT3RoZXJ3aXNlLCAnICtcbiAgICAgICAgICAnc2V0IGVpdGhlciBgb25DaGFuZ2VgIG9yIGByZWFkT25seWAuJ1xuICAgICAgICApO1xuICAgICAgfSxcbiAgICAgIG9uQ2hhbmdlOiBSZWFjdFByb3BUeXBlcy5mdW5jXG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge1JlYWN0Q29tcG9uZW50fSBpbnB1dCBGb3JtIGNvbXBvbmVudFxuICAgKiBAcmV0dXJuIHsqfSBjdXJyZW50IHZhbHVlIG9mIHRoZSBpbnB1dCBlaXRoZXIgZnJvbSB2YWx1ZSBwcm9wIG9yIGxpbmsuXG4gICAqL1xuICBnZXRWYWx1ZTogZnVuY3Rpb24oaW5wdXQpIHtcbiAgICBpZiAoaW5wdXQucHJvcHMudmFsdWVMaW5rKSB7XG4gICAgICBfYXNzZXJ0VmFsdWVMaW5rKGlucHV0KTtcbiAgICAgIHJldHVybiBpbnB1dC5wcm9wcy52YWx1ZUxpbmsudmFsdWU7XG4gICAgfVxuICAgIHJldHVybiBpbnB1dC5wcm9wcy52YWx1ZTtcbiAgfSxcblxuICAvKipcbiAgICogQHBhcmFtIHtSZWFjdENvbXBvbmVudH0gaW5wdXQgRm9ybSBjb21wb25lbnRcbiAgICogQHJldHVybiB7Kn0gY3VycmVudCBjaGVja2VkIHN0YXR1cyBvZiB0aGUgaW5wdXQgZWl0aGVyIGZyb20gY2hlY2tlZCBwcm9wXG4gICAqICAgICAgICAgICAgIG9yIGxpbmsuXG4gICAqL1xuICBnZXRDaGVja2VkOiBmdW5jdGlvbihpbnB1dCkge1xuICAgIGlmIChpbnB1dC5wcm9wcy5jaGVja2VkTGluaykge1xuICAgICAgX2Fzc2VydENoZWNrZWRMaW5rKGlucHV0KTtcbiAgICAgIHJldHVybiBpbnB1dC5wcm9wcy5jaGVja2VkTGluay52YWx1ZTtcbiAgICB9XG4gICAgcmV0dXJuIGlucHV0LnByb3BzLmNoZWNrZWQ7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7UmVhY3RDb21wb25lbnR9IGlucHV0IEZvcm0gY29tcG9uZW50XG4gICAqIEByZXR1cm4ge2Z1bmN0aW9ufSBjaGFuZ2UgY2FsbGJhY2sgZWl0aGVyIGZyb20gb25DaGFuZ2UgcHJvcCBvciBsaW5rLlxuICAgKi9cbiAgZ2V0T25DaGFuZ2U6IGZ1bmN0aW9uKGlucHV0KSB7XG4gICAgaWYgKGlucHV0LnByb3BzLnZhbHVlTGluaykge1xuICAgICAgX2Fzc2VydFZhbHVlTGluayhpbnB1dCk7XG4gICAgICByZXR1cm4gX2hhbmRsZUxpbmtlZFZhbHVlQ2hhbmdlO1xuICAgIH0gZWxzZSBpZiAoaW5wdXQucHJvcHMuY2hlY2tlZExpbmspIHtcbiAgICAgIF9hc3NlcnRDaGVja2VkTGluayhpbnB1dCk7XG4gICAgICByZXR1cm4gX2hhbmRsZUxpbmtlZENoZWNrQ2hhbmdlO1xuICAgIH1cbiAgICByZXR1cm4gaW5wdXQucHJvcHMub25DaGFuZ2U7XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gTGlua2VkVmFsdWVVdGlscztcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgTG9jYWxFdmVudFRyYXBNaXhpblxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyID0gcmVxdWlyZShcIi4vUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyXCIpO1xuXG52YXIgYWNjdW11bGF0ZUludG8gPSByZXF1aXJlKFwiLi9hY2N1bXVsYXRlSW50b1wiKTtcbnZhciBmb3JFYWNoQWNjdW11bGF0ZWQgPSByZXF1aXJlKFwiLi9mb3JFYWNoQWNjdW11bGF0ZWRcIik7XG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG5mdW5jdGlvbiByZW1vdmUoZXZlbnQpIHtcbiAgZXZlbnQucmVtb3ZlKCk7XG59XG5cbnZhciBMb2NhbEV2ZW50VHJhcE1peGluID0ge1xuICB0cmFwQnViYmxlZEV2ZW50OmZ1bmN0aW9uKHRvcExldmVsVHlwZSwgaGFuZGxlckJhc2VOYW1lKSB7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudCh0aGlzLmlzTW91bnRlZCgpLCAnTXVzdCBiZSBtb3VudGVkIHRvIHRyYXAgZXZlbnRzJykgOiBpbnZhcmlhbnQodGhpcy5pc01vdW50ZWQoKSkpO1xuICAgIHZhciBsaXN0ZW5lciA9IFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci50cmFwQnViYmxlZEV2ZW50KFxuICAgICAgdG9wTGV2ZWxUeXBlLFxuICAgICAgaGFuZGxlckJhc2VOYW1lLFxuICAgICAgdGhpcy5nZXRET01Ob2RlKClcbiAgICApO1xuICAgIHRoaXMuX2xvY2FsRXZlbnRMaXN0ZW5lcnMgPVxuICAgICAgYWNjdW11bGF0ZUludG8odGhpcy5fbG9jYWxFdmVudExpc3RlbmVycywgbGlzdGVuZXIpO1xuICB9LFxuXG4gIC8vIHRyYXBDYXB0dXJlZEV2ZW50IHdvdWxkIGxvb2sgbmVhcmx5IGlkZW50aWNhbC4gV2UgZG9uJ3QgaW1wbGVtZW50IHRoYXRcbiAgLy8gbWV0aG9kIGJlY2F1c2UgaXQgaXNuJ3QgY3VycmVudGx5IG5lZWRlZC5cblxuICBjb21wb25lbnRXaWxsVW5tb3VudDpmdW5jdGlvbigpIHtcbiAgICBpZiAodGhpcy5fbG9jYWxFdmVudExpc3RlbmVycykge1xuICAgICAgZm9yRWFjaEFjY3VtdWxhdGVkKHRoaXMuX2xvY2FsRXZlbnRMaXN0ZW5lcnMsIHJlbW92ZSk7XG4gICAgfVxuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IExvY2FsRXZlbnRUcmFwTWl4aW47XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBNb2JpbGVTYWZhcmlDbGlja0V2ZW50UGx1Z2luXG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgRXZlbnRDb25zdGFudHMgPSByZXF1aXJlKFwiLi9FdmVudENvbnN0YW50c1wiKTtcblxudmFyIGVtcHR5RnVuY3Rpb24gPSByZXF1aXJlKFwiLi9lbXB0eUZ1bmN0aW9uXCIpO1xuXG52YXIgdG9wTGV2ZWxUeXBlcyA9IEV2ZW50Q29uc3RhbnRzLnRvcExldmVsVHlwZXM7XG5cbi8qKlxuICogTW9iaWxlIFNhZmFyaSBkb2VzIG5vdCBmaXJlIHByb3Blcmx5IGJ1YmJsZSBjbGljayBldmVudHMgb24gbm9uLWludGVyYWN0aXZlXG4gKiBlbGVtZW50cywgd2hpY2ggbWVhbnMgZGVsZWdhdGVkIGNsaWNrIGxpc3RlbmVycyBkbyBub3QgZmlyZS4gVGhlIHdvcmthcm91bmRcbiAqIGZvciB0aGlzIGJ1ZyBpbnZvbHZlcyBhdHRhY2hpbmcgYW4gZW1wdHkgY2xpY2sgbGlzdGVuZXIgb24gdGhlIHRhcmdldCBub2RlLlxuICpcbiAqIFRoaXMgcGFydGljdWxhciBwbHVnaW4gd29ya3MgYXJvdW5kIHRoZSBidWcgYnkgYXR0YWNoaW5nIGFuIGVtcHR5IGNsaWNrXG4gKiBsaXN0ZW5lciBvbiBgdG91Y2hzdGFydGAgKHdoaWNoIGRvZXMgZmlyZSBvbiBldmVyeSBlbGVtZW50KS5cbiAqL1xudmFyIE1vYmlsZVNhZmFyaUNsaWNrRXZlbnRQbHVnaW4gPSB7XG5cbiAgZXZlbnRUeXBlczogbnVsbCxcblxuICAvKipcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRvcExldmVsVHlwZSBSZWNvcmQgZnJvbSBgRXZlbnRDb25zdGFudHNgLlxuICAgKiBAcGFyYW0ge0RPTUV2ZW50VGFyZ2V0fSB0b3BMZXZlbFRhcmdldCBUaGUgbGlzdGVuaW5nIGNvbXBvbmVudCByb290IG5vZGUuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0b3BMZXZlbFRhcmdldElEIElEIG9mIGB0b3BMZXZlbFRhcmdldGAuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudCBOYXRpdmUgYnJvd3NlciBldmVudC5cbiAgICogQHJldHVybiB7Kn0gQW4gYWNjdW11bGF0aW9uIG9mIHN5bnRoZXRpYyBldmVudHMuXG4gICAqIEBzZWUge0V2ZW50UGx1Z2luSHViLmV4dHJhY3RFdmVudHN9XG4gICAqL1xuICBleHRyYWN0RXZlbnRzOiBmdW5jdGlvbihcbiAgICAgIHRvcExldmVsVHlwZSxcbiAgICAgIHRvcExldmVsVGFyZ2V0LFxuICAgICAgdG9wTGV2ZWxUYXJnZXRJRCxcbiAgICAgIG5hdGl2ZUV2ZW50KSB7XG4gICAgaWYgKHRvcExldmVsVHlwZSA9PT0gdG9wTGV2ZWxUeXBlcy50b3BUb3VjaFN0YXJ0KSB7XG4gICAgICB2YXIgdGFyZ2V0ID0gbmF0aXZlRXZlbnQudGFyZ2V0O1xuICAgICAgaWYgKHRhcmdldCAmJiAhdGFyZ2V0Lm9uY2xpY2spIHtcbiAgICAgICAgdGFyZ2V0Lm9uY2xpY2sgPSBlbXB0eUZ1bmN0aW9uO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1vYmlsZVNhZmFyaUNsaWNrRXZlbnRQbHVnaW47XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIE9iamVjdC5hc3NpZ25cbiAqL1xuXG4vLyBodHRwczovL3Blb3BsZS5tb3ppbGxhLm9yZy9+am9yZW5kb3JmZi9lczYtZHJhZnQuaHRtbCNzZWMtb2JqZWN0LmFzc2lnblxuXG5mdW5jdGlvbiBhc3NpZ24odGFyZ2V0LCBzb3VyY2VzKSB7XG4gIGlmICh0YXJnZXQgPT0gbnVsbCkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ09iamVjdC5hc3NpZ24gdGFyZ2V0IGNhbm5vdCBiZSBudWxsIG9yIHVuZGVmaW5lZCcpO1xuICB9XG5cbiAgdmFyIHRvID0gT2JqZWN0KHRhcmdldCk7XG4gIHZhciBoYXNPd25Qcm9wZXJ0eSA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHk7XG5cbiAgZm9yICh2YXIgbmV4dEluZGV4ID0gMTsgbmV4dEluZGV4IDwgYXJndW1lbnRzLmxlbmd0aDsgbmV4dEluZGV4KyspIHtcbiAgICB2YXIgbmV4dFNvdXJjZSA9IGFyZ3VtZW50c1tuZXh0SW5kZXhdO1xuICAgIGlmIChuZXh0U291cmNlID09IG51bGwpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIHZhciBmcm9tID0gT2JqZWN0KG5leHRTb3VyY2UpO1xuXG4gICAgLy8gV2UgZG9uJ3QgY3VycmVudGx5IHN1cHBvcnQgYWNjZXNzb3JzIG5vciBwcm94aWVzLiBUaGVyZWZvcmUgdGhpc1xuICAgIC8vIGNvcHkgY2Fubm90IHRocm93LiBJZiB3ZSBldmVyIHN1cHBvcnRlZCB0aGlzIHRoZW4gd2UgbXVzdCBoYW5kbGVcbiAgICAvLyBleGNlcHRpb25zIGFuZCBzaWRlLWVmZmVjdHMuIFdlIGRvbid0IHN1cHBvcnQgc3ltYm9scyBzbyB0aGV5IHdvbid0XG4gICAgLy8gYmUgdHJhbnNmZXJyZWQuXG5cbiAgICBmb3IgKHZhciBrZXkgaW4gZnJvbSkge1xuICAgICAgaWYgKGhhc093blByb3BlcnR5LmNhbGwoZnJvbSwga2V5KSkge1xuICAgICAgICB0b1trZXldID0gZnJvbVtrZXldO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0bztcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gYXNzaWduO1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBQb29sZWRDbGFzc1xuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG4vKipcbiAqIFN0YXRpYyBwb29sZXJzLiBTZXZlcmFsIGN1c3RvbSB2ZXJzaW9ucyBmb3IgZWFjaCBwb3RlbnRpYWwgbnVtYmVyIG9mXG4gKiBhcmd1bWVudHMuIEEgY29tcGxldGVseSBnZW5lcmljIHBvb2xlciBpcyBlYXN5IHRvIGltcGxlbWVudCwgYnV0IHdvdWxkXG4gKiByZXF1aXJlIGFjY2Vzc2luZyB0aGUgYGFyZ3VtZW50c2Agb2JqZWN0LiBJbiBlYWNoIG9mIHRoZXNlLCBgdGhpc2AgcmVmZXJzIHRvXG4gKiB0aGUgQ2xhc3MgaXRzZWxmLCBub3QgYW4gaW5zdGFuY2UuIElmIGFueSBvdGhlcnMgYXJlIG5lZWRlZCwgc2ltcGx5IGFkZCB0aGVtXG4gKiBoZXJlLCBvciBpbiB0aGVpciBvd24gZmlsZXMuXG4gKi9cbnZhciBvbmVBcmd1bWVudFBvb2xlciA9IGZ1bmN0aW9uKGNvcHlGaWVsZHNGcm9tKSB7XG4gIHZhciBLbGFzcyA9IHRoaXM7XG4gIGlmIChLbGFzcy5pbnN0YW5jZVBvb2wubGVuZ3RoKSB7XG4gICAgdmFyIGluc3RhbmNlID0gS2xhc3MuaW5zdGFuY2VQb29sLnBvcCgpO1xuICAgIEtsYXNzLmNhbGwoaW5zdGFuY2UsIGNvcHlGaWVsZHNGcm9tKTtcbiAgICByZXR1cm4gaW5zdGFuY2U7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIG5ldyBLbGFzcyhjb3B5RmllbGRzRnJvbSk7XG4gIH1cbn07XG5cbnZhciB0d29Bcmd1bWVudFBvb2xlciA9IGZ1bmN0aW9uKGExLCBhMikge1xuICB2YXIgS2xhc3MgPSB0aGlzO1xuICBpZiAoS2xhc3MuaW5zdGFuY2VQb29sLmxlbmd0aCkge1xuICAgIHZhciBpbnN0YW5jZSA9IEtsYXNzLmluc3RhbmNlUG9vbC5wb3AoKTtcbiAgICBLbGFzcy5jYWxsKGluc3RhbmNlLCBhMSwgYTIpO1xuICAgIHJldHVybiBpbnN0YW5jZTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gbmV3IEtsYXNzKGExLCBhMik7XG4gIH1cbn07XG5cbnZhciB0aHJlZUFyZ3VtZW50UG9vbGVyID0gZnVuY3Rpb24oYTEsIGEyLCBhMykge1xuICB2YXIgS2xhc3MgPSB0aGlzO1xuICBpZiAoS2xhc3MuaW5zdGFuY2VQb29sLmxlbmd0aCkge1xuICAgIHZhciBpbnN0YW5jZSA9IEtsYXNzLmluc3RhbmNlUG9vbC5wb3AoKTtcbiAgICBLbGFzcy5jYWxsKGluc3RhbmNlLCBhMSwgYTIsIGEzKTtcbiAgICByZXR1cm4gaW5zdGFuY2U7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIG5ldyBLbGFzcyhhMSwgYTIsIGEzKTtcbiAgfVxufTtcblxudmFyIGZpdmVBcmd1bWVudFBvb2xlciA9IGZ1bmN0aW9uKGExLCBhMiwgYTMsIGE0LCBhNSkge1xuICB2YXIgS2xhc3MgPSB0aGlzO1xuICBpZiAoS2xhc3MuaW5zdGFuY2VQb29sLmxlbmd0aCkge1xuICAgIHZhciBpbnN0YW5jZSA9IEtsYXNzLmluc3RhbmNlUG9vbC5wb3AoKTtcbiAgICBLbGFzcy5jYWxsKGluc3RhbmNlLCBhMSwgYTIsIGEzLCBhNCwgYTUpO1xuICAgIHJldHVybiBpbnN0YW5jZTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gbmV3IEtsYXNzKGExLCBhMiwgYTMsIGE0LCBhNSk7XG4gIH1cbn07XG5cbnZhciBzdGFuZGFyZFJlbGVhc2VyID0gZnVuY3Rpb24oaW5zdGFuY2UpIHtcbiAgdmFyIEtsYXNzID0gdGhpcztcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICBpbnN0YW5jZSBpbnN0YW5jZW9mIEtsYXNzLFxuICAgICdUcnlpbmcgdG8gcmVsZWFzZSBhbiBpbnN0YW5jZSBpbnRvIGEgcG9vbCBvZiBhIGRpZmZlcmVudCB0eXBlLidcbiAgKSA6IGludmFyaWFudChpbnN0YW5jZSBpbnN0YW5jZW9mIEtsYXNzKSk7XG4gIGlmIChpbnN0YW5jZS5kZXN0cnVjdG9yKSB7XG4gICAgaW5zdGFuY2UuZGVzdHJ1Y3RvcigpO1xuICB9XG4gIGlmIChLbGFzcy5pbnN0YW5jZVBvb2wubGVuZ3RoIDwgS2xhc3MucG9vbFNpemUpIHtcbiAgICBLbGFzcy5pbnN0YW5jZVBvb2wucHVzaChpbnN0YW5jZSk7XG4gIH1cbn07XG5cbnZhciBERUZBVUxUX1BPT0xfU0laRSA9IDEwO1xudmFyIERFRkFVTFRfUE9PTEVSID0gb25lQXJndW1lbnRQb29sZXI7XG5cbi8qKlxuICogQXVnbWVudHMgYENvcHlDb25zdHJ1Y3RvcmAgdG8gYmUgYSBwb29sYWJsZSBjbGFzcywgYXVnbWVudGluZyBvbmx5IHRoZSBjbGFzc1xuICogaXRzZWxmIChzdGF0aWNhbGx5KSBub3QgYWRkaW5nIGFueSBwcm90b3R5cGljYWwgZmllbGRzLiBBbnkgQ29weUNvbnN0cnVjdG9yXG4gKiB5b3UgZ2l2ZSB0aGlzIG1heSBoYXZlIGEgYHBvb2xTaXplYCBwcm9wZXJ0eSwgYW5kIHdpbGwgbG9vayBmb3IgYVxuICogcHJvdG90eXBpY2FsIGBkZXN0cnVjdG9yYCBvbiBpbnN0YW5jZXMgKG9wdGlvbmFsKS5cbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBDb3B5Q29uc3RydWN0b3IgQ29uc3RydWN0b3IgdGhhdCBjYW4gYmUgdXNlZCB0byByZXNldC5cbiAqIEBwYXJhbSB7RnVuY3Rpb259IHBvb2xlciBDdXN0b21pemFibGUgcG9vbGVyLlxuICovXG52YXIgYWRkUG9vbGluZ1RvID0gZnVuY3Rpb24oQ29weUNvbnN0cnVjdG9yLCBwb29sZXIpIHtcbiAgdmFyIE5ld0tsYXNzID0gQ29weUNvbnN0cnVjdG9yO1xuICBOZXdLbGFzcy5pbnN0YW5jZVBvb2wgPSBbXTtcbiAgTmV3S2xhc3MuZ2V0UG9vbGVkID0gcG9vbGVyIHx8IERFRkFVTFRfUE9PTEVSO1xuICBpZiAoIU5ld0tsYXNzLnBvb2xTaXplKSB7XG4gICAgTmV3S2xhc3MucG9vbFNpemUgPSBERUZBVUxUX1BPT0xfU0laRTtcbiAgfVxuICBOZXdLbGFzcy5yZWxlYXNlID0gc3RhbmRhcmRSZWxlYXNlcjtcbiAgcmV0dXJuIE5ld0tsYXNzO1xufTtcblxudmFyIFBvb2xlZENsYXNzID0ge1xuICBhZGRQb29saW5nVG86IGFkZFBvb2xpbmdUbyxcbiAgb25lQXJndW1lbnRQb29sZXI6IG9uZUFyZ3VtZW50UG9vbGVyLFxuICB0d29Bcmd1bWVudFBvb2xlcjogdHdvQXJndW1lbnRQb29sZXIsXG4gIHRocmVlQXJndW1lbnRQb29sZXI6IHRocmVlQXJndW1lbnRQb29sZXIsXG4gIGZpdmVBcmd1bWVudFBvb2xlcjogZml2ZUFyZ3VtZW50UG9vbGVyXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFBvb2xlZENsYXNzO1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBET01Qcm9wZXJ0eU9wZXJhdGlvbnMgPSByZXF1aXJlKFwiLi9ET01Qcm9wZXJ0eU9wZXJhdGlvbnNcIik7XG52YXIgRXZlbnRQbHVnaW5VdGlscyA9IHJlcXVpcmUoXCIuL0V2ZW50UGx1Z2luVXRpbHNcIik7XG52YXIgUmVhY3RDaGlsZHJlbiA9IHJlcXVpcmUoXCIuL1JlYWN0Q2hpbGRyZW5cIik7XG52YXIgUmVhY3RDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdENvbXBvbmVudFwiKTtcbnZhciBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudCA9IHJlcXVpcmUoXCIuL1JlYWN0Q29tcG9zaXRlQ29tcG9uZW50XCIpO1xudmFyIFJlYWN0Q29udGV4dCA9IHJlcXVpcmUoXCIuL1JlYWN0Q29udGV4dFwiKTtcbnZhciBSZWFjdEN1cnJlbnRPd25lciA9IHJlcXVpcmUoXCIuL1JlYWN0Q3VycmVudE93bmVyXCIpO1xudmFyIFJlYWN0RWxlbWVudCA9IHJlcXVpcmUoXCIuL1JlYWN0RWxlbWVudFwiKTtcbnZhciBSZWFjdEVsZW1lbnRWYWxpZGF0b3IgPSByZXF1aXJlKFwiLi9SZWFjdEVsZW1lbnRWYWxpZGF0b3JcIik7XG52YXIgUmVhY3RET00gPSByZXF1aXJlKFwiLi9SZWFjdERPTVwiKTtcbnZhciBSZWFjdERPTUNvbXBvbmVudCA9IHJlcXVpcmUoXCIuL1JlYWN0RE9NQ29tcG9uZW50XCIpO1xudmFyIFJlYWN0RGVmYXVsdEluamVjdGlvbiA9IHJlcXVpcmUoXCIuL1JlYWN0RGVmYXVsdEluamVjdGlvblwiKTtcbnZhciBSZWFjdEluc3RhbmNlSGFuZGxlcyA9IHJlcXVpcmUoXCIuL1JlYWN0SW5zdGFuY2VIYW5kbGVzXCIpO1xudmFyIFJlYWN0TGVnYWN5RWxlbWVudCA9IHJlcXVpcmUoXCIuL1JlYWN0TGVnYWN5RWxlbWVudFwiKTtcbnZhciBSZWFjdE1vdW50ID0gcmVxdWlyZShcIi4vUmVhY3RNb3VudFwiKTtcbnZhciBSZWFjdE11bHRpQ2hpbGQgPSByZXF1aXJlKFwiLi9SZWFjdE11bHRpQ2hpbGRcIik7XG52YXIgUmVhY3RQZXJmID0gcmVxdWlyZShcIi4vUmVhY3RQZXJmXCIpO1xudmFyIFJlYWN0UHJvcFR5cGVzID0gcmVxdWlyZShcIi4vUmVhY3RQcm9wVHlwZXNcIik7XG52YXIgUmVhY3RTZXJ2ZXJSZW5kZXJpbmcgPSByZXF1aXJlKFwiLi9SZWFjdFNlcnZlclJlbmRlcmluZ1wiKTtcbnZhciBSZWFjdFRleHRDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdFRleHRDb21wb25lbnRcIik7XG5cbnZhciBhc3NpZ24gPSByZXF1aXJlKFwiLi9PYmplY3QuYXNzaWduXCIpO1xudmFyIGRlcHJlY2F0ZWQgPSByZXF1aXJlKFwiLi9kZXByZWNhdGVkXCIpO1xudmFyIG9ubHlDaGlsZCA9IHJlcXVpcmUoXCIuL29ubHlDaGlsZFwiKTtcblxuUmVhY3REZWZhdWx0SW5qZWN0aW9uLmluamVjdCgpO1xuXG52YXIgY3JlYXRlRWxlbWVudCA9IFJlYWN0RWxlbWVudC5jcmVhdGVFbGVtZW50O1xudmFyIGNyZWF0ZUZhY3RvcnkgPSBSZWFjdEVsZW1lbnQuY3JlYXRlRmFjdG9yeTtcblxuaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICBjcmVhdGVFbGVtZW50ID0gUmVhY3RFbGVtZW50VmFsaWRhdG9yLmNyZWF0ZUVsZW1lbnQ7XG4gIGNyZWF0ZUZhY3RvcnkgPSBSZWFjdEVsZW1lbnRWYWxpZGF0b3IuY3JlYXRlRmFjdG9yeTtcbn1cblxuLy8gVE9ETzogRHJvcCBsZWdhY3kgZWxlbWVudHMgb25jZSBjbGFzc2VzIG5vIGxvbmdlciBleHBvcnQgdGhlc2UgZmFjdG9yaWVzXG5jcmVhdGVFbGVtZW50ID0gUmVhY3RMZWdhY3lFbGVtZW50LndyYXBDcmVhdGVFbGVtZW50KFxuICBjcmVhdGVFbGVtZW50XG4pO1xuY3JlYXRlRmFjdG9yeSA9IFJlYWN0TGVnYWN5RWxlbWVudC53cmFwQ3JlYXRlRmFjdG9yeShcbiAgY3JlYXRlRmFjdG9yeVxuKTtcblxudmFyIHJlbmRlciA9IFJlYWN0UGVyZi5tZWFzdXJlKCdSZWFjdCcsICdyZW5kZXInLCBSZWFjdE1vdW50LnJlbmRlcik7XG5cbnZhciBSZWFjdCA9IHtcbiAgQ2hpbGRyZW46IHtcbiAgICBtYXA6IFJlYWN0Q2hpbGRyZW4ubWFwLFxuICAgIGZvckVhY2g6IFJlYWN0Q2hpbGRyZW4uZm9yRWFjaCxcbiAgICBjb3VudDogUmVhY3RDaGlsZHJlbi5jb3VudCxcbiAgICBvbmx5OiBvbmx5Q2hpbGRcbiAgfSxcbiAgRE9NOiBSZWFjdERPTSxcbiAgUHJvcFR5cGVzOiBSZWFjdFByb3BUeXBlcyxcbiAgaW5pdGlhbGl6ZVRvdWNoRXZlbnRzOiBmdW5jdGlvbihzaG91bGRVc2VUb3VjaCkge1xuICAgIEV2ZW50UGx1Z2luVXRpbHMudXNlVG91Y2hFdmVudHMgPSBzaG91bGRVc2VUb3VjaDtcbiAgfSxcbiAgY3JlYXRlQ2xhc3M6IFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50LmNyZWF0ZUNsYXNzLFxuICBjcmVhdGVFbGVtZW50OiBjcmVhdGVFbGVtZW50LFxuICBjcmVhdGVGYWN0b3J5OiBjcmVhdGVGYWN0b3J5LFxuICBjb25zdHJ1Y3RBbmRSZW5kZXJDb21wb25lbnQ6IFJlYWN0TW91bnQuY29uc3RydWN0QW5kUmVuZGVyQ29tcG9uZW50LFxuICBjb25zdHJ1Y3RBbmRSZW5kZXJDb21wb25lbnRCeUlEOiBSZWFjdE1vdW50LmNvbnN0cnVjdEFuZFJlbmRlckNvbXBvbmVudEJ5SUQsXG4gIHJlbmRlcjogcmVuZGVyLFxuICByZW5kZXJUb1N0cmluZzogUmVhY3RTZXJ2ZXJSZW5kZXJpbmcucmVuZGVyVG9TdHJpbmcsXG4gIHJlbmRlclRvU3RhdGljTWFya3VwOiBSZWFjdFNlcnZlclJlbmRlcmluZy5yZW5kZXJUb1N0YXRpY01hcmt1cCxcbiAgdW5tb3VudENvbXBvbmVudEF0Tm9kZTogUmVhY3RNb3VudC51bm1vdW50Q29tcG9uZW50QXROb2RlLFxuICBpc1ZhbGlkQ2xhc3M6IFJlYWN0TGVnYWN5RWxlbWVudC5pc1ZhbGlkQ2xhc3MsXG4gIGlzVmFsaWRFbGVtZW50OiBSZWFjdEVsZW1lbnQuaXNWYWxpZEVsZW1lbnQsXG4gIHdpdGhDb250ZXh0OiBSZWFjdENvbnRleHQud2l0aENvbnRleHQsXG5cbiAgLy8gSG9vayBmb3IgSlNYIHNwcmVhZCwgZG9uJ3QgdXNlIHRoaXMgZm9yIGFueXRoaW5nIGVsc2UuXG4gIF9fc3ByZWFkOiBhc3NpZ24sXG5cbiAgLy8gRGVwcmVjYXRpb25zIChyZW1vdmUgZm9yIDAuMTMpXG4gIHJlbmRlckNvbXBvbmVudDogZGVwcmVjYXRlZChcbiAgICAnUmVhY3QnLFxuICAgICdyZW5kZXJDb21wb25lbnQnLFxuICAgICdyZW5kZXInLFxuICAgIHRoaXMsXG4gICAgcmVuZGVyXG4gICksXG4gIHJlbmRlckNvbXBvbmVudFRvU3RyaW5nOiBkZXByZWNhdGVkKFxuICAgICdSZWFjdCcsXG4gICAgJ3JlbmRlckNvbXBvbmVudFRvU3RyaW5nJyxcbiAgICAncmVuZGVyVG9TdHJpbmcnLFxuICAgIHRoaXMsXG4gICAgUmVhY3RTZXJ2ZXJSZW5kZXJpbmcucmVuZGVyVG9TdHJpbmdcbiAgKSxcbiAgcmVuZGVyQ29tcG9uZW50VG9TdGF0aWNNYXJrdXA6IGRlcHJlY2F0ZWQoXG4gICAgJ1JlYWN0JyxcbiAgICAncmVuZGVyQ29tcG9uZW50VG9TdGF0aWNNYXJrdXAnLFxuICAgICdyZW5kZXJUb1N0YXRpY01hcmt1cCcsXG4gICAgdGhpcyxcbiAgICBSZWFjdFNlcnZlclJlbmRlcmluZy5yZW5kZXJUb1N0YXRpY01hcmt1cFxuICApLFxuICBpc1ZhbGlkQ29tcG9uZW50OiBkZXByZWNhdGVkKFxuICAgICdSZWFjdCcsXG4gICAgJ2lzVmFsaWRDb21wb25lbnQnLFxuICAgICdpc1ZhbGlkRWxlbWVudCcsXG4gICAgdGhpcyxcbiAgICBSZWFjdEVsZW1lbnQuaXNWYWxpZEVsZW1lbnRcbiAgKVxufTtcblxuLy8gSW5qZWN0IHRoZSBydW50aW1lIGludG8gYSBkZXZ0b29scyBnbG9iYWwgaG9vayByZWdhcmRsZXNzIG9mIGJyb3dzZXIuXG4vLyBBbGxvd3MgZm9yIGRlYnVnZ2luZyB3aGVuIHRoZSBob29rIGlzIGluamVjdGVkIG9uIHRoZSBwYWdlLlxuaWYgKFxuICB0eXBlb2YgX19SRUFDVF9ERVZUT09MU19HTE9CQUxfSE9PS19fICE9PSAndW5kZWZpbmVkJyAmJlxuICB0eXBlb2YgX19SRUFDVF9ERVZUT09MU19HTE9CQUxfSE9PS19fLmluamVjdCA9PT0gJ2Z1bmN0aW9uJykge1xuICBfX1JFQUNUX0RFVlRPT0xTX0dMT0JBTF9IT09LX18uaW5qZWN0KHtcbiAgICBDb21wb25lbnQ6IFJlYWN0Q29tcG9uZW50LFxuICAgIEN1cnJlbnRPd25lcjogUmVhY3RDdXJyZW50T3duZXIsXG4gICAgRE9NQ29tcG9uZW50OiBSZWFjdERPTUNvbXBvbmVudCxcbiAgICBET01Qcm9wZXJ0eU9wZXJhdGlvbnM6IERPTVByb3BlcnR5T3BlcmF0aW9ucyxcbiAgICBJbnN0YW5jZUhhbmRsZXM6IFJlYWN0SW5zdGFuY2VIYW5kbGVzLFxuICAgIE1vdW50OiBSZWFjdE1vdW50LFxuICAgIE11bHRpQ2hpbGQ6IFJlYWN0TXVsdGlDaGlsZCxcbiAgICBUZXh0Q29tcG9uZW50OiBSZWFjdFRleHRDb21wb25lbnRcbiAgfSk7XG59XG5cbmlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgdmFyIEV4ZWN1dGlvbkVudmlyb25tZW50ID0gcmVxdWlyZShcIi4vRXhlY3V0aW9uRW52aXJvbm1lbnRcIik7XG4gIGlmIChFeGVjdXRpb25FbnZpcm9ubWVudC5jYW5Vc2VET00gJiYgd2luZG93LnRvcCA9PT0gd2luZG93LnNlbGYpIHtcblxuICAgIC8vIElmIHdlJ3JlIGluIENocm9tZSwgbG9vayBmb3IgdGhlIGRldnRvb2xzIG1hcmtlciBhbmQgcHJvdmlkZSBhIGRvd25sb2FkXG4gICAgLy8gbGluayBpZiBub3QgaW5zdGFsbGVkLlxuICAgIGlmIChuYXZpZ2F0b3IudXNlckFnZW50LmluZGV4T2YoJ0Nocm9tZScpID4gLTEpIHtcbiAgICAgIGlmICh0eXBlb2YgX19SRUFDVF9ERVZUT09MU19HTE9CQUxfSE9PS19fID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICBjb25zb2xlLmRlYnVnKFxuICAgICAgICAgICdEb3dubG9hZCB0aGUgUmVhY3QgRGV2VG9vbHMgZm9yIGEgYmV0dGVyIGRldmVsb3BtZW50IGV4cGVyaWVuY2U6ICcgK1xuICAgICAgICAgICdodHRwOi8vZmIubWUvcmVhY3QtZGV2dG9vbHMnXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdmFyIGV4cGVjdGVkRmVhdHVyZXMgPSBbXG4gICAgICAvLyBzaGltc1xuICAgICAgQXJyYXkuaXNBcnJheSxcbiAgICAgIEFycmF5LnByb3RvdHlwZS5ldmVyeSxcbiAgICAgIEFycmF5LnByb3RvdHlwZS5mb3JFYWNoLFxuICAgICAgQXJyYXkucHJvdG90eXBlLmluZGV4T2YsXG4gICAgICBBcnJheS5wcm90b3R5cGUubWFwLFxuICAgICAgRGF0ZS5ub3csXG4gICAgICBGdW5jdGlvbi5wcm90b3R5cGUuYmluZCxcbiAgICAgIE9iamVjdC5rZXlzLFxuICAgICAgU3RyaW5nLnByb3RvdHlwZS5zcGxpdCxcbiAgICAgIFN0cmluZy5wcm90b3R5cGUudHJpbSxcblxuICAgICAgLy8gc2hhbXNcbiAgICAgIE9iamVjdC5jcmVhdGUsXG4gICAgICBPYmplY3QuZnJlZXplXG4gICAgXTtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZXhwZWN0ZWRGZWF0dXJlcy5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKCFleHBlY3RlZEZlYXR1cmVzW2ldKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXG4gICAgICAgICAgJ09uZSBvciBtb3JlIEVTNSBzaGltL3NoYW1zIGV4cGVjdGVkIGJ5IFJlYWN0IGFyZSBub3QgYXZhaWxhYmxlOiAnICtcbiAgICAgICAgICAnaHR0cDovL2ZiLm1lL3JlYWN0LXdhcm5pbmctcG9seWZpbGxzJ1xuICAgICAgICApO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuLy8gVmVyc2lvbiBleGlzdHMgb25seSBpbiB0aGUgb3Blbi1zb3VyY2UgdmVyc2lvbiBvZiBSZWFjdCwgbm90IGluIEZhY2Vib29rJ3Ncbi8vIGludGVybmFsIHZlcnNpb24uXG5SZWFjdC52ZXJzaW9uID0gJzAuMTIuMic7XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3Q7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RCcm93c2VyQ29tcG9uZW50TWl4aW5cbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFJlYWN0RW1wdHlDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdEVtcHR5Q29tcG9uZW50XCIpO1xudmFyIFJlYWN0TW91bnQgPSByZXF1aXJlKFwiLi9SZWFjdE1vdW50XCIpO1xuXG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG52YXIgUmVhY3RCcm93c2VyQ29tcG9uZW50TWl4aW4gPSB7XG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBET00gbm9kZSByZW5kZXJlZCBieSB0aGlzIGNvbXBvbmVudC5cbiAgICpcbiAgICogQHJldHVybiB7RE9NRWxlbWVudH0gVGhlIHJvb3Qgbm9kZSBvZiB0aGlzIGNvbXBvbmVudC5cbiAgICogQGZpbmFsXG4gICAqIEBwcm90ZWN0ZWRcbiAgICovXG4gIGdldERPTU5vZGU6IGZ1bmN0aW9uKCkge1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICB0aGlzLmlzTW91bnRlZCgpLFxuICAgICAgJ2dldERPTU5vZGUoKTogQSBjb21wb25lbnQgbXVzdCBiZSBtb3VudGVkIHRvIGhhdmUgYSBET00gbm9kZS4nXG4gICAgKSA6IGludmFyaWFudCh0aGlzLmlzTW91bnRlZCgpKSk7XG4gICAgaWYgKFJlYWN0RW1wdHlDb21wb25lbnQuaXNOdWxsQ29tcG9uZW50SUQodGhpcy5fcm9vdE5vZGVJRCkpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICByZXR1cm4gUmVhY3RNb3VudC5nZXROb2RlKHRoaXMuX3Jvb3ROb2RlSUQpO1xuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0QnJvd3NlckNvbXBvbmVudE1peGluO1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyXG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgRXZlbnRDb25zdGFudHMgPSByZXF1aXJlKFwiLi9FdmVudENvbnN0YW50c1wiKTtcbnZhciBFdmVudFBsdWdpbkh1YiA9IHJlcXVpcmUoXCIuL0V2ZW50UGx1Z2luSHViXCIpO1xudmFyIEV2ZW50UGx1Z2luUmVnaXN0cnkgPSByZXF1aXJlKFwiLi9FdmVudFBsdWdpblJlZ2lzdHJ5XCIpO1xudmFyIFJlYWN0RXZlbnRFbWl0dGVyTWl4aW4gPSByZXF1aXJlKFwiLi9SZWFjdEV2ZW50RW1pdHRlck1peGluXCIpO1xudmFyIFZpZXdwb3J0TWV0cmljcyA9IHJlcXVpcmUoXCIuL1ZpZXdwb3J0TWV0cmljc1wiKTtcblxudmFyIGFzc2lnbiA9IHJlcXVpcmUoXCIuL09iamVjdC5hc3NpZ25cIik7XG52YXIgaXNFdmVudFN1cHBvcnRlZCA9IHJlcXVpcmUoXCIuL2lzRXZlbnRTdXBwb3J0ZWRcIik7XG5cbi8qKlxuICogU3VtbWFyeSBvZiBgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyYCBldmVudCBoYW5kbGluZzpcbiAqXG4gKiAgLSBUb3AtbGV2ZWwgZGVsZWdhdGlvbiBpcyB1c2VkIHRvIHRyYXAgbW9zdCBuYXRpdmUgYnJvd3NlciBldmVudHMuIFRoaXNcbiAqICAgIG1heSBvbmx5IG9jY3VyIGluIHRoZSBtYWluIHRocmVhZCBhbmQgaXMgdGhlIHJlc3BvbnNpYmlsaXR5IG9mXG4gKiAgICBSZWFjdEV2ZW50TGlzdGVuZXIsIHdoaWNoIGlzIGluamVjdGVkIGFuZCBjYW4gdGhlcmVmb3JlIHN1cHBvcnQgcGx1Z2dhYmxlXG4gKiAgICBldmVudCBzb3VyY2VzLiBUaGlzIGlzIHRoZSBvbmx5IHdvcmsgdGhhdCBvY2N1cnMgaW4gdGhlIG1haW4gdGhyZWFkLlxuICpcbiAqICAtIFdlIG5vcm1hbGl6ZSBhbmQgZGUtZHVwbGljYXRlIGV2ZW50cyB0byBhY2NvdW50IGZvciBicm93c2VyIHF1aXJrcy4gVGhpc1xuICogICAgbWF5IGJlIGRvbmUgaW4gdGhlIHdvcmtlciB0aHJlYWQuXG4gKlxuICogIC0gRm9yd2FyZCB0aGVzZSBuYXRpdmUgZXZlbnRzICh3aXRoIHRoZSBhc3NvY2lhdGVkIHRvcC1sZXZlbCB0eXBlIHVzZWQgdG9cbiAqICAgIHRyYXAgaXQpIHRvIGBFdmVudFBsdWdpbkh1YmAsIHdoaWNoIGluIHR1cm4gd2lsbCBhc2sgcGx1Z2lucyBpZiB0aGV5IHdhbnRcbiAqICAgIHRvIGV4dHJhY3QgYW55IHN5bnRoZXRpYyBldmVudHMuXG4gKlxuICogIC0gVGhlIGBFdmVudFBsdWdpbkh1YmAgd2lsbCB0aGVuIHByb2Nlc3MgZWFjaCBldmVudCBieSBhbm5vdGF0aW5nIHRoZW0gd2l0aFxuICogICAgXCJkaXNwYXRjaGVzXCIsIGEgc2VxdWVuY2Ugb2YgbGlzdGVuZXJzIGFuZCBJRHMgdGhhdCBjYXJlIGFib3V0IHRoYXQgZXZlbnQuXG4gKlxuICogIC0gVGhlIGBFdmVudFBsdWdpbkh1YmAgdGhlbiBkaXNwYXRjaGVzIHRoZSBldmVudHMuXG4gKlxuICogT3ZlcnZpZXcgb2YgUmVhY3QgYW5kIHRoZSBldmVudCBzeXN0ZW06XG4gKlxuICogKy0tLS0tLS0tLS0tLSsgICAgLlxuICogfCAgICBET00gICAgIHwgICAgLlxuICogKy0tLS0tLS0tLS0tLSsgICAgLlxuICogICAgICAgfCAgICAgICAgICAgLlxuICogICAgICAgdiAgICAgICAgICAgLlxuICogKy0tLS0tLS0tLS0tLSsgICAgLlxuICogfCBSZWFjdEV2ZW50IHwgICAgLlxuICogfCAgTGlzdGVuZXIgIHwgICAgLlxuICogKy0tLS0tLS0tLS0tLSsgICAgLiAgICAgICAgICAgICAgICAgICAgICAgICArLS0tLS0tLS0tLS0rXG4gKiAgICAgICB8ICAgICAgICAgICAuICAgICAgICAgICAgICAgKy0tLS0tLS0tK3xTaW1wbGVFdmVudHxcbiAqICAgICAgIHwgICAgICAgICAgIC4gICAgICAgICAgICAgICB8ICAgICAgICAgfFBsdWdpbiAgICAgfFxuICogKy0tLS0tfC0tLS0tLSsgICAgLiAgICAgICAgICAgICAgIHYgICAgICAgICArLS0tLS0tLS0tLS0rXG4gKiB8ICAgICB8ICAgICAgfCAgICAuICAgICstLS0tLS0tLS0tLS0tLSsgICAgICAgICAgICAgICAgICAgICstLS0tLS0tLS0tLS0rXG4gKiB8ICAgICArLS0tLS0tLS0tLS0uLS0tPnxFdmVudFBsdWdpbkh1YnwgICAgICAgICAgICAgICAgICAgIHwgICAgRXZlbnQgICB8XG4gKiB8ICAgICAgICAgICAgfCAgICAuICAgIHwgICAgICAgICAgICAgIHwgICAgICstLS0tLS0tLS0tLSsgIHwgUHJvcGFnYXRvcnN8XG4gKiB8IFJlYWN0RXZlbnQgfCAgICAuICAgIHwgICAgICAgICAgICAgIHwgICAgIHxUYXBFdmVudCAgIHwgIHwtLS0tLS0tLS0tLS18XG4gKiB8ICBFbWl0dGVyICAgfCAgICAuICAgIHwgICAgICAgICAgICAgIHw8LS0tK3xQbHVnaW4gICAgIHwgIHxvdGhlciBwbHVnaW58XG4gKiB8ICAgICAgICAgICAgfCAgICAuICAgIHwgICAgICAgICAgICAgIHwgICAgICstLS0tLS0tLS0tLSsgIHwgIHV0aWxpdGllcyB8XG4gKiB8ICAgICArLS0tLS0tLS0tLS0uLS0tPnwgICAgICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICstLS0tLS0tLS0tLS0rXG4gKiB8ICAgICB8ICAgICAgfCAgICAuICAgICstLS0tLS0tLS0tLS0tLStcbiAqICstLS0tLXwtLS0tLS0rICAgIC4gICAgICAgICAgICAgICAgXiAgICAgICAgKy0tLS0tLS0tLS0tK1xuICogICAgICAgfCAgICAgICAgICAgLiAgICAgICAgICAgICAgICB8ICAgICAgICB8RW50ZXIvTGVhdmV8XG4gKiAgICAgICArICAgICAgICAgICAuICAgICAgICAgICAgICAgICstLS0tLS0tK3xQbHVnaW4gICAgIHxcbiAqICstLS0tLS0tLS0tLS0tKyAgIC4gICAgICAgICAgICAgICAgICAgICAgICAgKy0tLS0tLS0tLS0tK1xuICogfCBhcHBsaWNhdGlvbiB8ICAgLlxuICogfC0tLS0tLS0tLS0tLS18ICAgLlxuICogfCAgICAgICAgICAgICB8ICAgLlxuICogfCAgICAgICAgICAgICB8ICAgLlxuICogKy0tLS0tLS0tLS0tLS0rICAgLlxuICogICAgICAgICAgICAgICAgICAgLlxuICogICAgUmVhY3QgQ29yZSAgICAgLiAgR2VuZXJhbCBQdXJwb3NlIEV2ZW50IFBsdWdpbiBTeXN0ZW1cbiAqL1xuXG52YXIgYWxyZWFkeUxpc3RlbmluZ1RvID0ge307XG52YXIgaXNNb25pdG9yaW5nU2Nyb2xsVmFsdWUgPSBmYWxzZTtcbnZhciByZWFjdFRvcExpc3RlbmVyc0NvdW50ZXIgPSAwO1xuXG4vLyBGb3IgZXZlbnRzIGxpa2UgJ3N1Ym1pdCcgd2hpY2ggZG9uJ3QgY29uc2lzdGVudGx5IGJ1YmJsZSAod2hpY2ggd2UgdHJhcCBhdCBhXG4vLyBsb3dlciBub2RlIHRoYW4gYGRvY3VtZW50YCksIGJpbmRpbmcgYXQgYGRvY3VtZW50YCB3b3VsZCBjYXVzZSBkdXBsaWNhdGVcbi8vIGV2ZW50cyBzbyB3ZSBkb24ndCBpbmNsdWRlIHRoZW0gaGVyZVxudmFyIHRvcEV2ZW50TWFwcGluZyA9IHtcbiAgdG9wQmx1cjogJ2JsdXInLFxuICB0b3BDaGFuZ2U6ICdjaGFuZ2UnLFxuICB0b3BDbGljazogJ2NsaWNrJyxcbiAgdG9wQ29tcG9zaXRpb25FbmQ6ICdjb21wb3NpdGlvbmVuZCcsXG4gIHRvcENvbXBvc2l0aW9uU3RhcnQ6ICdjb21wb3NpdGlvbnN0YXJ0JyxcbiAgdG9wQ29tcG9zaXRpb25VcGRhdGU6ICdjb21wb3NpdGlvbnVwZGF0ZScsXG4gIHRvcENvbnRleHRNZW51OiAnY29udGV4dG1lbnUnLFxuICB0b3BDb3B5OiAnY29weScsXG4gIHRvcEN1dDogJ2N1dCcsXG4gIHRvcERvdWJsZUNsaWNrOiAnZGJsY2xpY2snLFxuICB0b3BEcmFnOiAnZHJhZycsXG4gIHRvcERyYWdFbmQ6ICdkcmFnZW5kJyxcbiAgdG9wRHJhZ0VudGVyOiAnZHJhZ2VudGVyJyxcbiAgdG9wRHJhZ0V4aXQ6ICdkcmFnZXhpdCcsXG4gIHRvcERyYWdMZWF2ZTogJ2RyYWdsZWF2ZScsXG4gIHRvcERyYWdPdmVyOiAnZHJhZ292ZXInLFxuICB0b3BEcmFnU3RhcnQ6ICdkcmFnc3RhcnQnLFxuICB0b3BEcm9wOiAnZHJvcCcsXG4gIHRvcEZvY3VzOiAnZm9jdXMnLFxuICB0b3BJbnB1dDogJ2lucHV0JyxcbiAgdG9wS2V5RG93bjogJ2tleWRvd24nLFxuICB0b3BLZXlQcmVzczogJ2tleXByZXNzJyxcbiAgdG9wS2V5VXA6ICdrZXl1cCcsXG4gIHRvcE1vdXNlRG93bjogJ21vdXNlZG93bicsXG4gIHRvcE1vdXNlTW92ZTogJ21vdXNlbW92ZScsXG4gIHRvcE1vdXNlT3V0OiAnbW91c2VvdXQnLFxuICB0b3BNb3VzZU92ZXI6ICdtb3VzZW92ZXInLFxuICB0b3BNb3VzZVVwOiAnbW91c2V1cCcsXG4gIHRvcFBhc3RlOiAncGFzdGUnLFxuICB0b3BTY3JvbGw6ICdzY3JvbGwnLFxuICB0b3BTZWxlY3Rpb25DaGFuZ2U6ICdzZWxlY3Rpb25jaGFuZ2UnLFxuICB0b3BUZXh0SW5wdXQ6ICd0ZXh0SW5wdXQnLFxuICB0b3BUb3VjaENhbmNlbDogJ3RvdWNoY2FuY2VsJyxcbiAgdG9wVG91Y2hFbmQ6ICd0b3VjaGVuZCcsXG4gIHRvcFRvdWNoTW92ZTogJ3RvdWNobW92ZScsXG4gIHRvcFRvdWNoU3RhcnQ6ICd0b3VjaHN0YXJ0JyxcbiAgdG9wV2hlZWw6ICd3aGVlbCdcbn07XG5cbi8qKlxuICogVG8gZW5zdXJlIG5vIGNvbmZsaWN0cyB3aXRoIG90aGVyIHBvdGVudGlhbCBSZWFjdCBpbnN0YW5jZXMgb24gdGhlIHBhZ2VcbiAqL1xudmFyIHRvcExpc3RlbmVyc0lES2V5ID0gXCJfcmVhY3RMaXN0ZW5lcnNJRFwiICsgU3RyaW5nKE1hdGgucmFuZG9tKCkpLnNsaWNlKDIpO1xuXG5mdW5jdGlvbiBnZXRMaXN0ZW5pbmdGb3JEb2N1bWVudChtb3VudEF0KSB7XG4gIC8vIEluIElFOCwgYG1vdW50QXRgIGlzIGEgaG9zdCBvYmplY3QgYW5kIGRvZXNuJ3QgaGF2ZSBgaGFzT3duUHJvcGVydHlgXG4gIC8vIGRpcmVjdGx5LlxuICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChtb3VudEF0LCB0b3BMaXN0ZW5lcnNJREtleSkpIHtcbiAgICBtb3VudEF0W3RvcExpc3RlbmVyc0lES2V5XSA9IHJlYWN0VG9wTGlzdGVuZXJzQ291bnRlcisrO1xuICAgIGFscmVhZHlMaXN0ZW5pbmdUb1ttb3VudEF0W3RvcExpc3RlbmVyc0lES2V5XV0gPSB7fTtcbiAgfVxuICByZXR1cm4gYWxyZWFkeUxpc3RlbmluZ1RvW21vdW50QXRbdG9wTGlzdGVuZXJzSURLZXldXTtcbn1cblxuLyoqXG4gKiBgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyYCBpcyB1c2VkIHRvIGF0dGFjaCB0b3AtbGV2ZWwgZXZlbnQgbGlzdGVuZXJzLiBGb3JcbiAqIGV4YW1wbGU6XG4gKlxuICogICBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIucHV0TGlzdGVuZXIoJ215SUQnLCAnb25DbGljaycsIG15RnVuY3Rpb24pO1xuICpcbiAqIFRoaXMgd291bGQgYWxsb2NhdGUgYSBcInJlZ2lzdHJhdGlvblwiIG9mIGAoJ29uQ2xpY2snLCBteUZ1bmN0aW9uKWAgb24gJ215SUQnLlxuICpcbiAqIEBpbnRlcm5hbFxuICovXG52YXIgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyID0gYXNzaWduKHt9LCBSZWFjdEV2ZW50RW1pdHRlck1peGluLCB7XG5cbiAgLyoqXG4gICAqIEluamVjdGFibGUgZXZlbnQgYmFja2VuZFxuICAgKi9cbiAgUmVhY3RFdmVudExpc3RlbmVyOiBudWxsLFxuXG4gIGluamVjdGlvbjoge1xuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBSZWFjdEV2ZW50TGlzdGVuZXJcbiAgICAgKi9cbiAgICBpbmplY3RSZWFjdEV2ZW50TGlzdGVuZXI6IGZ1bmN0aW9uKFJlYWN0RXZlbnRMaXN0ZW5lcikge1xuICAgICAgUmVhY3RFdmVudExpc3RlbmVyLnNldEhhbmRsZVRvcExldmVsKFxuICAgICAgICBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIuaGFuZGxlVG9wTGV2ZWxcbiAgICAgICk7XG4gICAgICBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIuUmVhY3RFdmVudExpc3RlbmVyID0gUmVhY3RFdmVudExpc3RlbmVyO1xuICAgIH1cbiAgfSxcblxuICAvKipcbiAgICogU2V0cyB3aGV0aGVyIG9yIG5vdCBhbnkgY3JlYXRlZCBjYWxsYmFja3Mgc2hvdWxkIGJlIGVuYWJsZWQuXG4gICAqXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gZW5hYmxlZCBUcnVlIGlmIGNhbGxiYWNrcyBzaG91bGQgYmUgZW5hYmxlZC5cbiAgICovXG4gIHNldEVuYWJsZWQ6IGZ1bmN0aW9uKGVuYWJsZWQpIHtcbiAgICBpZiAoUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLlJlYWN0RXZlbnRMaXN0ZW5lcikge1xuICAgICAgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLlJlYWN0RXZlbnRMaXN0ZW5lci5zZXRFbmFibGVkKGVuYWJsZWQpO1xuICAgIH1cbiAgfSxcblxuICAvKipcbiAgICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiBjYWxsYmFja3MgYXJlIGVuYWJsZWQuXG4gICAqL1xuICBpc0VuYWJsZWQ6IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiAhIShcbiAgICAgIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5SZWFjdEV2ZW50TGlzdGVuZXIgJiZcbiAgICAgIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5SZWFjdEV2ZW50TGlzdGVuZXIuaXNFbmFibGVkKClcbiAgICApO1xuICB9LFxuXG4gIC8qKlxuICAgKiBXZSBsaXN0ZW4gZm9yIGJ1YmJsZWQgdG91Y2ggZXZlbnRzIG9uIHRoZSBkb2N1bWVudCBvYmplY3QuXG4gICAqXG4gICAqIEZpcmVmb3ggdjguMDEgKGFuZCBwb3NzaWJseSBvdGhlcnMpIGV4aGliaXRlZCBzdHJhbmdlIGJlaGF2aW9yIHdoZW5cbiAgICogbW91bnRpbmcgYG9ubW91c2Vtb3ZlYCBldmVudHMgYXQgc29tZSBub2RlIHRoYXQgd2FzIG5vdCB0aGUgZG9jdW1lbnRcbiAgICogZWxlbWVudC4gVGhlIHN5bXB0b21zIHdlcmUgdGhhdCBpZiB5b3VyIG1vdXNlIGlzIG5vdCBtb3Zpbmcgb3ZlciBzb21ldGhpbmdcbiAgICogY29udGFpbmVkIHdpdGhpbiB0aGF0IG1vdW50IHBvaW50IChmb3IgZXhhbXBsZSBvbiB0aGUgYmFja2dyb3VuZCkgdGhlXG4gICAqIHRvcC1sZXZlbCBsaXN0ZW5lcnMgZm9yIGBvbm1vdXNlbW92ZWAgd29uJ3QgYmUgY2FsbGVkLiBIb3dldmVyLCBpZiB5b3VcbiAgICogcmVnaXN0ZXIgdGhlIGBtb3VzZW1vdmVgIG9uIHRoZSBkb2N1bWVudCBvYmplY3QsIHRoZW4gaXQgd2lsbCBvZiBjb3Vyc2VcbiAgICogY2F0Y2ggYWxsIGBtb3VzZW1vdmVgcy4gVGhpcyBhbG9uZyB3aXRoIGlPUyBxdWlya3MsIGp1c3RpZmllcyByZXN0cmljdGluZ1xuICAgKiB0b3AtbGV2ZWwgbGlzdGVuZXJzIHRvIHRoZSBkb2N1bWVudCBvYmplY3Qgb25seSwgYXQgbGVhc3QgZm9yIHRoZXNlXG4gICAqIG1vdmVtZW50IHR5cGVzIG9mIGV2ZW50cyBhbmQgcG9zc2libHkgYWxsIGV2ZW50cy5cbiAgICpcbiAgICogQHNlZSBodHRwOi8vd3d3LnF1aXJrc21vZGUub3JnL2Jsb2cvYXJjaGl2ZXMvMjAxMC8wOS9jbGlja19ldmVudF9kZWwuaHRtbFxuICAgKlxuICAgKiBBbHNvLCBga2V5dXBgL2BrZXlwcmVzc2AvYGtleWRvd25gIGRvIG5vdCBidWJibGUgdG8gdGhlIHdpbmRvdyBvbiBJRSwgYnV0XG4gICAqIHRoZXkgYnViYmxlIHRvIGRvY3VtZW50LlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gcmVnaXN0cmF0aW9uTmFtZSBOYW1lIG9mIGxpc3RlbmVyIChlLmcuIGBvbkNsaWNrYCkuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBjb250ZW50RG9jdW1lbnRIYW5kbGUgRG9jdW1lbnQgd2hpY2ggb3ducyB0aGUgY29udGFpbmVyXG4gICAqL1xuICBsaXN0ZW5UbzogZnVuY3Rpb24ocmVnaXN0cmF0aW9uTmFtZSwgY29udGVudERvY3VtZW50SGFuZGxlKSB7XG4gICAgdmFyIG1vdW50QXQgPSBjb250ZW50RG9jdW1lbnRIYW5kbGU7XG4gICAgdmFyIGlzTGlzdGVuaW5nID0gZ2V0TGlzdGVuaW5nRm9yRG9jdW1lbnQobW91bnRBdCk7XG4gICAgdmFyIGRlcGVuZGVuY2llcyA9IEV2ZW50UGx1Z2luUmVnaXN0cnkuXG4gICAgICByZWdpc3RyYXRpb25OYW1lRGVwZW5kZW5jaWVzW3JlZ2lzdHJhdGlvbk5hbWVdO1xuXG4gICAgdmFyIHRvcExldmVsVHlwZXMgPSBFdmVudENvbnN0YW50cy50b3BMZXZlbFR5cGVzO1xuICAgIGZvciAodmFyIGkgPSAwLCBsID0gZGVwZW5kZW5jaWVzLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgICAgdmFyIGRlcGVuZGVuY3kgPSBkZXBlbmRlbmNpZXNbaV07XG4gICAgICBpZiAoIShcbiAgICAgICAgICAgIGlzTGlzdGVuaW5nLmhhc093blByb3BlcnR5KGRlcGVuZGVuY3kpICYmXG4gICAgICAgICAgICBpc0xpc3RlbmluZ1tkZXBlbmRlbmN5XVxuICAgICAgICAgICkpIHtcbiAgICAgICAgaWYgKGRlcGVuZGVuY3kgPT09IHRvcExldmVsVHlwZXMudG9wV2hlZWwpIHtcbiAgICAgICAgICBpZiAoaXNFdmVudFN1cHBvcnRlZCgnd2hlZWwnKSkge1xuICAgICAgICAgICAgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLlJlYWN0RXZlbnRMaXN0ZW5lci50cmFwQnViYmxlZEV2ZW50KFxuICAgICAgICAgICAgICB0b3BMZXZlbFR5cGVzLnRvcFdoZWVsLFxuICAgICAgICAgICAgICAnd2hlZWwnLFxuICAgICAgICAgICAgICBtb3VudEF0XG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0gZWxzZSBpZiAoaXNFdmVudFN1cHBvcnRlZCgnbW91c2V3aGVlbCcpKSB7XG4gICAgICAgICAgICBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIuUmVhY3RFdmVudExpc3RlbmVyLnRyYXBCdWJibGVkRXZlbnQoXG4gICAgICAgICAgICAgIHRvcExldmVsVHlwZXMudG9wV2hlZWwsXG4gICAgICAgICAgICAgICdtb3VzZXdoZWVsJyxcbiAgICAgICAgICAgICAgbW91bnRBdFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gRmlyZWZveCBuZWVkcyB0byBjYXB0dXJlIGEgZGlmZmVyZW50IG1vdXNlIHNjcm9sbCBldmVudC5cbiAgICAgICAgICAgIC8vIEBzZWUgaHR0cDovL3d3dy5xdWlya3Ntb2RlLm9yZy9kb20vZXZlbnRzL3Rlc3RzL3Njcm9sbC5odG1sXG4gICAgICAgICAgICBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIuUmVhY3RFdmVudExpc3RlbmVyLnRyYXBCdWJibGVkRXZlbnQoXG4gICAgICAgICAgICAgIHRvcExldmVsVHlwZXMudG9wV2hlZWwsXG4gICAgICAgICAgICAgICdET01Nb3VzZVNjcm9sbCcsXG4gICAgICAgICAgICAgIG1vdW50QXRcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKGRlcGVuZGVuY3kgPT09IHRvcExldmVsVHlwZXMudG9wU2Nyb2xsKSB7XG5cbiAgICAgICAgICBpZiAoaXNFdmVudFN1cHBvcnRlZCgnc2Nyb2xsJywgdHJ1ZSkpIHtcbiAgICAgICAgICAgIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5SZWFjdEV2ZW50TGlzdGVuZXIudHJhcENhcHR1cmVkRXZlbnQoXG4gICAgICAgICAgICAgIHRvcExldmVsVHlwZXMudG9wU2Nyb2xsLFxuICAgICAgICAgICAgICAnc2Nyb2xsJyxcbiAgICAgICAgICAgICAgbW91bnRBdFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLlJlYWN0RXZlbnRMaXN0ZW5lci50cmFwQnViYmxlZEV2ZW50KFxuICAgICAgICAgICAgICB0b3BMZXZlbFR5cGVzLnRvcFNjcm9sbCxcbiAgICAgICAgICAgICAgJ3Njcm9sbCcsXG4gICAgICAgICAgICAgIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5SZWFjdEV2ZW50TGlzdGVuZXIuV0lORE9XX0hBTkRMRVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoZGVwZW5kZW5jeSA9PT0gdG9wTGV2ZWxUeXBlcy50b3BGb2N1cyB8fFxuICAgICAgICAgICAgZGVwZW5kZW5jeSA9PT0gdG9wTGV2ZWxUeXBlcy50b3BCbHVyKSB7XG5cbiAgICAgICAgICBpZiAoaXNFdmVudFN1cHBvcnRlZCgnZm9jdXMnLCB0cnVlKSkge1xuICAgICAgICAgICAgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLlJlYWN0RXZlbnRMaXN0ZW5lci50cmFwQ2FwdHVyZWRFdmVudChcbiAgICAgICAgICAgICAgdG9wTGV2ZWxUeXBlcy50b3BGb2N1cyxcbiAgICAgICAgICAgICAgJ2ZvY3VzJyxcbiAgICAgICAgICAgICAgbW91bnRBdFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5SZWFjdEV2ZW50TGlzdGVuZXIudHJhcENhcHR1cmVkRXZlbnQoXG4gICAgICAgICAgICAgIHRvcExldmVsVHlwZXMudG9wQmx1cixcbiAgICAgICAgICAgICAgJ2JsdXInLFxuICAgICAgICAgICAgICBtb3VudEF0XG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0gZWxzZSBpZiAoaXNFdmVudFN1cHBvcnRlZCgnZm9jdXNpbicpKSB7XG4gICAgICAgICAgICAvLyBJRSBoYXMgYGZvY3VzaW5gIGFuZCBgZm9jdXNvdXRgIGV2ZW50cyB3aGljaCBidWJibGUuXG4gICAgICAgICAgICAvLyBAc2VlIGh0dHA6Ly93d3cucXVpcmtzbW9kZS5vcmcvYmxvZy9hcmNoaXZlcy8yMDA4LzA0L2RlbGVnYXRpbmdfdGhlLmh0bWxcbiAgICAgICAgICAgIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5SZWFjdEV2ZW50TGlzdGVuZXIudHJhcEJ1YmJsZWRFdmVudChcbiAgICAgICAgICAgICAgdG9wTGV2ZWxUeXBlcy50b3BGb2N1cyxcbiAgICAgICAgICAgICAgJ2ZvY3VzaW4nLFxuICAgICAgICAgICAgICBtb3VudEF0XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLlJlYWN0RXZlbnRMaXN0ZW5lci50cmFwQnViYmxlZEV2ZW50KFxuICAgICAgICAgICAgICB0b3BMZXZlbFR5cGVzLnRvcEJsdXIsXG4gICAgICAgICAgICAgICdmb2N1c291dCcsXG4gICAgICAgICAgICAgIG1vdW50QXRcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gdG8gbWFrZSBzdXJlIGJsdXIgYW5kIGZvY3VzIGV2ZW50IGxpc3RlbmVycyBhcmUgb25seSBhdHRhY2hlZCBvbmNlXG4gICAgICAgICAgaXNMaXN0ZW5pbmdbdG9wTGV2ZWxUeXBlcy50b3BCbHVyXSA9IHRydWU7XG4gICAgICAgICAgaXNMaXN0ZW5pbmdbdG9wTGV2ZWxUeXBlcy50b3BGb2N1c10gPSB0cnVlO1xuICAgICAgICB9IGVsc2UgaWYgKHRvcEV2ZW50TWFwcGluZy5oYXNPd25Qcm9wZXJ0eShkZXBlbmRlbmN5KSkge1xuICAgICAgICAgIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5SZWFjdEV2ZW50TGlzdGVuZXIudHJhcEJ1YmJsZWRFdmVudChcbiAgICAgICAgICAgIGRlcGVuZGVuY3ksXG4gICAgICAgICAgICB0b3BFdmVudE1hcHBpbmdbZGVwZW5kZW5jeV0sXG4gICAgICAgICAgICBtb3VudEF0XG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlzTGlzdGVuaW5nW2RlcGVuZGVuY3ldID0gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG4gIH0sXG5cbiAgdHJhcEJ1YmJsZWRFdmVudDogZnVuY3Rpb24odG9wTGV2ZWxUeXBlLCBoYW5kbGVyQmFzZU5hbWUsIGhhbmRsZSkge1xuICAgIHJldHVybiBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIuUmVhY3RFdmVudExpc3RlbmVyLnRyYXBCdWJibGVkRXZlbnQoXG4gICAgICB0b3BMZXZlbFR5cGUsXG4gICAgICBoYW5kbGVyQmFzZU5hbWUsXG4gICAgICBoYW5kbGVcbiAgICApO1xuICB9LFxuXG4gIHRyYXBDYXB0dXJlZEV2ZW50OiBmdW5jdGlvbih0b3BMZXZlbFR5cGUsIGhhbmRsZXJCYXNlTmFtZSwgaGFuZGxlKSB7XG4gICAgcmV0dXJuIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5SZWFjdEV2ZW50TGlzdGVuZXIudHJhcENhcHR1cmVkRXZlbnQoXG4gICAgICB0b3BMZXZlbFR5cGUsXG4gICAgICBoYW5kbGVyQmFzZU5hbWUsXG4gICAgICBoYW5kbGVcbiAgICApO1xuICB9LFxuXG4gIC8qKlxuICAgKiBMaXN0ZW5zIHRvIHdpbmRvdyBzY3JvbGwgYW5kIHJlc2l6ZSBldmVudHMuIFdlIGNhY2hlIHNjcm9sbCB2YWx1ZXMgc28gdGhhdFxuICAgKiBhcHBsaWNhdGlvbiBjb2RlIGNhbiBhY2Nlc3MgdGhlbSB3aXRob3V0IHRyaWdnZXJpbmcgcmVmbG93cy5cbiAgICpcbiAgICogTk9URTogU2Nyb2xsIGV2ZW50cyBkbyBub3QgYnViYmxlLlxuICAgKlxuICAgKiBAc2VlIGh0dHA6Ly93d3cucXVpcmtzbW9kZS5vcmcvZG9tL2V2ZW50cy9zY3JvbGwuaHRtbFxuICAgKi9cbiAgZW5zdXJlU2Nyb2xsVmFsdWVNb25pdG9yaW5nOiBmdW5jdGlvbigpe1xuICAgIGlmICghaXNNb25pdG9yaW5nU2Nyb2xsVmFsdWUpIHtcbiAgICAgIHZhciByZWZyZXNoID0gVmlld3BvcnRNZXRyaWNzLnJlZnJlc2hTY3JvbGxWYWx1ZXM7XG4gICAgICBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIuUmVhY3RFdmVudExpc3RlbmVyLm1vbml0b3JTY3JvbGxWYWx1ZShyZWZyZXNoKTtcbiAgICAgIGlzTW9uaXRvcmluZ1Njcm9sbFZhbHVlID0gdHJ1ZTtcbiAgICB9XG4gIH0sXG5cbiAgZXZlbnROYW1lRGlzcGF0Y2hDb25maWdzOiBFdmVudFBsdWdpbkh1Yi5ldmVudE5hbWVEaXNwYXRjaENvbmZpZ3MsXG5cbiAgcmVnaXN0cmF0aW9uTmFtZU1vZHVsZXM6IEV2ZW50UGx1Z2luSHViLnJlZ2lzdHJhdGlvbk5hbWVNb2R1bGVzLFxuXG4gIHB1dExpc3RlbmVyOiBFdmVudFBsdWdpbkh1Yi5wdXRMaXN0ZW5lcixcblxuICBnZXRMaXN0ZW5lcjogRXZlbnRQbHVnaW5IdWIuZ2V0TGlzdGVuZXIsXG5cbiAgZGVsZXRlTGlzdGVuZXI6IEV2ZW50UGx1Z2luSHViLmRlbGV0ZUxpc3RlbmVyLFxuXG4gIGRlbGV0ZUFsbExpc3RlbmVyczogRXZlbnRQbHVnaW5IdWIuZGVsZXRlQWxsTGlzdGVuZXJzXG5cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlcjtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEB0eXBlY2hlY2tzXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RDU1NUcmFuc2l0aW9uR3JvdXBcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFJlYWN0ID0gcmVxdWlyZShcIi4vUmVhY3RcIik7XG5cbnZhciBhc3NpZ24gPSByZXF1aXJlKFwiLi9PYmplY3QuYXNzaWduXCIpO1xuXG52YXIgUmVhY3RUcmFuc2l0aW9uR3JvdXAgPSBSZWFjdC5jcmVhdGVGYWN0b3J5KFxuICByZXF1aXJlKFwiLi9SZWFjdFRyYW5zaXRpb25Hcm91cFwiKVxuKTtcbnZhciBSZWFjdENTU1RyYW5zaXRpb25Hcm91cENoaWxkID0gUmVhY3QuY3JlYXRlRmFjdG9yeShcbiAgcmVxdWlyZShcIi4vUmVhY3RDU1NUcmFuc2l0aW9uR3JvdXBDaGlsZFwiKVxuKTtcblxudmFyIFJlYWN0Q1NTVHJhbnNpdGlvbkdyb3VwID0gUmVhY3QuY3JlYXRlQ2xhc3Moe1xuICBkaXNwbGF5TmFtZTogJ1JlYWN0Q1NTVHJhbnNpdGlvbkdyb3VwJyxcblxuICBwcm9wVHlwZXM6IHtcbiAgICB0cmFuc2l0aW9uTmFtZTogUmVhY3QuUHJvcFR5cGVzLnN0cmluZy5pc1JlcXVpcmVkLFxuICAgIHRyYW5zaXRpb25FbnRlcjogUmVhY3QuUHJvcFR5cGVzLmJvb2wsXG4gICAgdHJhbnNpdGlvbkxlYXZlOiBSZWFjdC5Qcm9wVHlwZXMuYm9vbFxuICB9LFxuXG4gIGdldERlZmF1bHRQcm9wczogZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHRyYW5zaXRpb25FbnRlcjogdHJ1ZSxcbiAgICAgIHRyYW5zaXRpb25MZWF2ZTogdHJ1ZVxuICAgIH07XG4gIH0sXG5cbiAgX3dyYXBDaGlsZDogZnVuY3Rpb24oY2hpbGQpIHtcbiAgICAvLyBXZSBuZWVkIHRvIHByb3ZpZGUgdGhpcyBjaGlsZEZhY3Rvcnkgc28gdGhhdFxuICAgIC8vIFJlYWN0Q1NTVHJhbnNpdGlvbkdyb3VwQ2hpbGQgY2FuIHJlY2VpdmUgdXBkYXRlcyB0byBuYW1lLCBlbnRlciwgYW5kXG4gICAgLy8gbGVhdmUgd2hpbGUgaXQgaXMgbGVhdmluZy5cbiAgICByZXR1cm4gUmVhY3RDU1NUcmFuc2l0aW9uR3JvdXBDaGlsZChcbiAgICAgIHtcbiAgICAgICAgbmFtZTogdGhpcy5wcm9wcy50cmFuc2l0aW9uTmFtZSxcbiAgICAgICAgZW50ZXI6IHRoaXMucHJvcHMudHJhbnNpdGlvbkVudGVyLFxuICAgICAgICBsZWF2ZTogdGhpcy5wcm9wcy50cmFuc2l0aW9uTGVhdmVcbiAgICAgIH0sXG4gICAgICBjaGlsZFxuICAgICk7XG4gIH0sXG5cbiAgcmVuZGVyOiBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gKFxuICAgICAgUmVhY3RUcmFuc2l0aW9uR3JvdXAoXG4gICAgICAgIGFzc2lnbih7fSwgdGhpcy5wcm9wcywge2NoaWxkRmFjdG9yeTogdGhpcy5fd3JhcENoaWxkfSlcbiAgICAgIClcbiAgICApO1xuICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdENTU1RyYW5zaXRpb25Hcm91cDtcbiIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAdHlwZWNoZWNrc1xuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0Q1NTVHJhbnNpdGlvbkdyb3VwQ2hpbGRcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFJlYWN0ID0gcmVxdWlyZShcIi4vUmVhY3RcIik7XG5cbnZhciBDU1NDb3JlID0gcmVxdWlyZShcIi4vQ1NTQ29yZVwiKTtcbnZhciBSZWFjdFRyYW5zaXRpb25FdmVudHMgPSByZXF1aXJlKFwiLi9SZWFjdFRyYW5zaXRpb25FdmVudHNcIik7XG5cbnZhciBvbmx5Q2hpbGQgPSByZXF1aXJlKFwiLi9vbmx5Q2hpbGRcIik7XG5cbi8vIFdlIGRvbid0IHJlbW92ZSB0aGUgZWxlbWVudCBmcm9tIHRoZSBET00gdW50aWwgd2UgcmVjZWl2ZSBhbiBhbmltYXRpb25lbmQgb3Jcbi8vIHRyYW5zaXRpb25lbmQgZXZlbnQuIElmIHRoZSB1c2VyIHNjcmV3cyB1cCBhbmQgZm9yZ2V0cyB0byBhZGQgYW4gYW5pbWF0aW9uXG4vLyB0aGVpciBub2RlIHdpbGwgYmUgc3R1Y2sgaW4gdGhlIERPTSBmb3JldmVyLCBzbyB3ZSBkZXRlY3QgaWYgYW4gYW5pbWF0aW9uXG4vLyBkb2VzIG5vdCBzdGFydCBhbmQgaWYgaXQgZG9lc24ndCwgd2UganVzdCBjYWxsIHRoZSBlbmQgbGlzdGVuZXIgaW1tZWRpYXRlbHkuXG52YXIgVElDSyA9IDE3O1xudmFyIE5PX0VWRU5UX1RJTUVPVVQgPSA1MDAwO1xuXG52YXIgbm9FdmVudExpc3RlbmVyID0gbnVsbDtcblxuXG5pZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gIG5vRXZlbnRMaXN0ZW5lciA9IGZ1bmN0aW9uKCkge1xuICAgIGNvbnNvbGUud2FybihcbiAgICAgICd0cmFuc2l0aW9uKCk6IHRyaWVkIHRvIHBlcmZvcm0gYW4gYW5pbWF0aW9uIHdpdGhvdXQgJyArXG4gICAgICAnYW4gYW5pbWF0aW9uZW5kIG9yIHRyYW5zaXRpb25lbmQgZXZlbnQgYWZ0ZXIgdGltZW91dCAoJyArXG4gICAgICBOT19FVkVOVF9USU1FT1VUICsgJ21zKS4gWW91IHNob3VsZCBlaXRoZXIgZGlzYWJsZSB0aGlzICcgK1xuICAgICAgJ3RyYW5zaXRpb24gaW4gSlMgb3IgYWRkIGEgQ1NTIGFuaW1hdGlvbi90cmFuc2l0aW9uLidcbiAgICApO1xuICB9O1xufVxuXG52YXIgUmVhY3RDU1NUcmFuc2l0aW9uR3JvdXBDaGlsZCA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtcbiAgZGlzcGxheU5hbWU6ICdSZWFjdENTU1RyYW5zaXRpb25Hcm91cENoaWxkJyxcblxuICB0cmFuc2l0aW9uOiBmdW5jdGlvbihhbmltYXRpb25UeXBlLCBmaW5pc2hDYWxsYmFjaykge1xuICAgIHZhciBub2RlID0gdGhpcy5nZXRET01Ob2RlKCk7XG4gICAgdmFyIGNsYXNzTmFtZSA9IHRoaXMucHJvcHMubmFtZSArICctJyArIGFuaW1hdGlvblR5cGU7XG4gICAgdmFyIGFjdGl2ZUNsYXNzTmFtZSA9IGNsYXNzTmFtZSArICctYWN0aXZlJztcbiAgICB2YXIgbm9FdmVudFRpbWVvdXQgPSBudWxsO1xuXG4gICAgdmFyIGVuZExpc3RlbmVyID0gZnVuY3Rpb24oZSkge1xuICAgICAgaWYgKGUgJiYgZS50YXJnZXQgIT09IG5vZGUpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgICBjbGVhclRpbWVvdXQobm9FdmVudFRpbWVvdXQpO1xuICAgICAgfVxuXG4gICAgICBDU1NDb3JlLnJlbW92ZUNsYXNzKG5vZGUsIGNsYXNzTmFtZSk7XG4gICAgICBDU1NDb3JlLnJlbW92ZUNsYXNzKG5vZGUsIGFjdGl2ZUNsYXNzTmFtZSk7XG5cbiAgICAgIFJlYWN0VHJhbnNpdGlvbkV2ZW50cy5yZW1vdmVFbmRFdmVudExpc3RlbmVyKG5vZGUsIGVuZExpc3RlbmVyKTtcblxuICAgICAgLy8gVXN1YWxseSB0aGlzIG9wdGlvbmFsIGNhbGxiYWNrIGlzIHVzZWQgZm9yIGluZm9ybWluZyBhbiBvd25lciBvZlxuICAgICAgLy8gYSBsZWF2ZSBhbmltYXRpb24gYW5kIHRlbGxpbmcgaXQgdG8gcmVtb3ZlIHRoZSBjaGlsZC5cbiAgICAgIGZpbmlzaENhbGxiYWNrICYmIGZpbmlzaENhbGxiYWNrKCk7XG4gICAgfTtcblxuICAgIFJlYWN0VHJhbnNpdGlvbkV2ZW50cy5hZGRFbmRFdmVudExpc3RlbmVyKG5vZGUsIGVuZExpc3RlbmVyKTtcblxuICAgIENTU0NvcmUuYWRkQ2xhc3Mobm9kZSwgY2xhc3NOYW1lKTtcblxuICAgIC8vIE5lZWQgdG8gZG8gdGhpcyB0byBhY3R1YWxseSB0cmlnZ2VyIGEgdHJhbnNpdGlvbi5cbiAgICB0aGlzLnF1ZXVlQ2xhc3MoYWN0aXZlQ2xhc3NOYW1lKTtcblxuICAgIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgIG5vRXZlbnRUaW1lb3V0ID0gc2V0VGltZW91dChub0V2ZW50TGlzdGVuZXIsIE5PX0VWRU5UX1RJTUVPVVQpO1xuICAgIH1cbiAgfSxcblxuICBxdWV1ZUNsYXNzOiBmdW5jdGlvbihjbGFzc05hbWUpIHtcbiAgICB0aGlzLmNsYXNzTmFtZVF1ZXVlLnB1c2goY2xhc3NOYW1lKTtcblxuICAgIGlmICghdGhpcy50aW1lb3V0KSB7XG4gICAgICB0aGlzLnRpbWVvdXQgPSBzZXRUaW1lb3V0KHRoaXMuZmx1c2hDbGFzc05hbWVRdWV1ZSwgVElDSyk7XG4gICAgfVxuICB9LFxuXG4gIGZsdXNoQ2xhc3NOYW1lUXVldWU6IGZ1bmN0aW9uKCkge1xuICAgIGlmICh0aGlzLmlzTW91bnRlZCgpKSB7XG4gICAgICB0aGlzLmNsYXNzTmFtZVF1ZXVlLmZvckVhY2goXG4gICAgICAgIENTU0NvcmUuYWRkQ2xhc3MuYmluZChDU1NDb3JlLCB0aGlzLmdldERPTU5vZGUoKSlcbiAgICAgICk7XG4gICAgfVxuICAgIHRoaXMuY2xhc3NOYW1lUXVldWUubGVuZ3RoID0gMDtcbiAgICB0aGlzLnRpbWVvdXQgPSBudWxsO1xuICB9LFxuXG4gIGNvbXBvbmVudFdpbGxNb3VudDogZnVuY3Rpb24oKSB7XG4gICAgdGhpcy5jbGFzc05hbWVRdWV1ZSA9IFtdO1xuICB9LFxuXG4gIGNvbXBvbmVudFdpbGxVbm1vdW50OiBmdW5jdGlvbigpIHtcbiAgICBpZiAodGhpcy50aW1lb3V0KSB7XG4gICAgICBjbGVhclRpbWVvdXQodGhpcy50aW1lb3V0KTtcbiAgICB9XG4gIH0sXG5cbiAgY29tcG9uZW50V2lsbEVudGVyOiBmdW5jdGlvbihkb25lKSB7XG4gICAgaWYgKHRoaXMucHJvcHMuZW50ZXIpIHtcbiAgICAgIHRoaXMudHJhbnNpdGlvbignZW50ZXInLCBkb25lKTtcbiAgICB9IGVsc2Uge1xuICAgICAgZG9uZSgpO1xuICAgIH1cbiAgfSxcblxuICBjb21wb25lbnRXaWxsTGVhdmU6IGZ1bmN0aW9uKGRvbmUpIHtcbiAgICBpZiAodGhpcy5wcm9wcy5sZWF2ZSkge1xuICAgICAgdGhpcy50cmFuc2l0aW9uKCdsZWF2ZScsIGRvbmUpO1xuICAgIH0gZWxzZSB7XG4gICAgICBkb25lKCk7XG4gICAgfVxuICB9LFxuXG4gIHJlbmRlcjogZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIG9ubHlDaGlsZCh0aGlzLnByb3BzLmNoaWxkcmVuKTtcbiAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RDU1NUcmFuc2l0aW9uR3JvdXBDaGlsZDtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdENoaWxkcmVuXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBQb29sZWRDbGFzcyA9IHJlcXVpcmUoXCIuL1Bvb2xlZENsYXNzXCIpO1xuXG52YXIgdHJhdmVyc2VBbGxDaGlsZHJlbiA9IHJlcXVpcmUoXCIuL3RyYXZlcnNlQWxsQ2hpbGRyZW5cIik7XG52YXIgd2FybmluZyA9IHJlcXVpcmUoXCIuL3dhcm5pbmdcIik7XG5cbnZhciB0d29Bcmd1bWVudFBvb2xlciA9IFBvb2xlZENsYXNzLnR3b0FyZ3VtZW50UG9vbGVyO1xudmFyIHRocmVlQXJndW1lbnRQb29sZXIgPSBQb29sZWRDbGFzcy50aHJlZUFyZ3VtZW50UG9vbGVyO1xuXG4vKipcbiAqIFBvb2xlZENsYXNzIHJlcHJlc2VudGluZyB0aGUgYm9va2tlZXBpbmcgYXNzb2NpYXRlZCB3aXRoIHBlcmZvcm1pbmcgYSBjaGlsZFxuICogdHJhdmVyc2FsLiBBbGxvd3MgYXZvaWRpbmcgYmluZGluZyBjYWxsYmFja3MuXG4gKlxuICogQGNvbnN0cnVjdG9yIEZvckVhY2hCb29rS2VlcGluZ1xuICogQHBhcmFtIHshZnVuY3Rpb259IGZvckVhY2hGdW5jdGlvbiBGdW5jdGlvbiB0byBwZXJmb3JtIHRyYXZlcnNhbCB3aXRoLlxuICogQHBhcmFtIHs/Kn0gZm9yRWFjaENvbnRleHQgQ29udGV4dCB0byBwZXJmb3JtIGNvbnRleHQgd2l0aC5cbiAqL1xuZnVuY3Rpb24gRm9yRWFjaEJvb2tLZWVwaW5nKGZvckVhY2hGdW5jdGlvbiwgZm9yRWFjaENvbnRleHQpIHtcbiAgdGhpcy5mb3JFYWNoRnVuY3Rpb24gPSBmb3JFYWNoRnVuY3Rpb247XG4gIHRoaXMuZm9yRWFjaENvbnRleHQgPSBmb3JFYWNoQ29udGV4dDtcbn1cblBvb2xlZENsYXNzLmFkZFBvb2xpbmdUbyhGb3JFYWNoQm9va0tlZXBpbmcsIHR3b0FyZ3VtZW50UG9vbGVyKTtcblxuZnVuY3Rpb24gZm9yRWFjaFNpbmdsZUNoaWxkKHRyYXZlcnNlQ29udGV4dCwgY2hpbGQsIG5hbWUsIGkpIHtcbiAgdmFyIGZvckVhY2hCb29rS2VlcGluZyA9IHRyYXZlcnNlQ29udGV4dDtcbiAgZm9yRWFjaEJvb2tLZWVwaW5nLmZvckVhY2hGdW5jdGlvbi5jYWxsKFxuICAgIGZvckVhY2hCb29rS2VlcGluZy5mb3JFYWNoQ29udGV4dCwgY2hpbGQsIGkpO1xufVxuXG4vKipcbiAqIEl0ZXJhdGVzIHRocm91Z2ggY2hpbGRyZW4gdGhhdCBhcmUgdHlwaWNhbGx5IHNwZWNpZmllZCBhcyBgcHJvcHMuY2hpbGRyZW5gLlxuICpcbiAqIFRoZSBwcm92aWRlZCBmb3JFYWNoRnVuYyhjaGlsZCwgaW5kZXgpIHdpbGwgYmUgY2FsbGVkIGZvciBlYWNoXG4gKiBsZWFmIGNoaWxkLlxuICpcbiAqIEBwYXJhbSB7Pyp9IGNoaWxkcmVuIENoaWxkcmVuIHRyZWUgY29udGFpbmVyLlxuICogQHBhcmFtIHtmdW5jdGlvbigqLCBpbnQpfSBmb3JFYWNoRnVuYy5cbiAqIEBwYXJhbSB7Kn0gZm9yRWFjaENvbnRleHQgQ29udGV4dCBmb3IgZm9yRWFjaENvbnRleHQuXG4gKi9cbmZ1bmN0aW9uIGZvckVhY2hDaGlsZHJlbihjaGlsZHJlbiwgZm9yRWFjaEZ1bmMsIGZvckVhY2hDb250ZXh0KSB7XG4gIGlmIChjaGlsZHJlbiA9PSBudWxsKSB7XG4gICAgcmV0dXJuIGNoaWxkcmVuO1xuICB9XG5cbiAgdmFyIHRyYXZlcnNlQ29udGV4dCA9XG4gICAgRm9yRWFjaEJvb2tLZWVwaW5nLmdldFBvb2xlZChmb3JFYWNoRnVuYywgZm9yRWFjaENvbnRleHQpO1xuICB0cmF2ZXJzZUFsbENoaWxkcmVuKGNoaWxkcmVuLCBmb3JFYWNoU2luZ2xlQ2hpbGQsIHRyYXZlcnNlQ29udGV4dCk7XG4gIEZvckVhY2hCb29rS2VlcGluZy5yZWxlYXNlKHRyYXZlcnNlQ29udGV4dCk7XG59XG5cbi8qKlxuICogUG9vbGVkQ2xhc3MgcmVwcmVzZW50aW5nIHRoZSBib29ra2VlcGluZyBhc3NvY2lhdGVkIHdpdGggcGVyZm9ybWluZyBhIGNoaWxkXG4gKiBtYXBwaW5nLiBBbGxvd3MgYXZvaWRpbmcgYmluZGluZyBjYWxsYmFja3MuXG4gKlxuICogQGNvbnN0cnVjdG9yIE1hcEJvb2tLZWVwaW5nXG4gKiBAcGFyYW0geyEqfSBtYXBSZXN1bHQgT2JqZWN0IGNvbnRhaW5pbmcgdGhlIG9yZGVyZWQgbWFwIG9mIHJlc3VsdHMuXG4gKiBAcGFyYW0geyFmdW5jdGlvbn0gbWFwRnVuY3Rpb24gRnVuY3Rpb24gdG8gcGVyZm9ybSBtYXBwaW5nIHdpdGguXG4gKiBAcGFyYW0gez8qfSBtYXBDb250ZXh0IENvbnRleHQgdG8gcGVyZm9ybSBtYXBwaW5nIHdpdGguXG4gKi9cbmZ1bmN0aW9uIE1hcEJvb2tLZWVwaW5nKG1hcFJlc3VsdCwgbWFwRnVuY3Rpb24sIG1hcENvbnRleHQpIHtcbiAgdGhpcy5tYXBSZXN1bHQgPSBtYXBSZXN1bHQ7XG4gIHRoaXMubWFwRnVuY3Rpb24gPSBtYXBGdW5jdGlvbjtcbiAgdGhpcy5tYXBDb250ZXh0ID0gbWFwQ29udGV4dDtcbn1cblBvb2xlZENsYXNzLmFkZFBvb2xpbmdUbyhNYXBCb29rS2VlcGluZywgdGhyZWVBcmd1bWVudFBvb2xlcik7XG5cbmZ1bmN0aW9uIG1hcFNpbmdsZUNoaWxkSW50b0NvbnRleHQodHJhdmVyc2VDb250ZXh0LCBjaGlsZCwgbmFtZSwgaSkge1xuICB2YXIgbWFwQm9va0tlZXBpbmcgPSB0cmF2ZXJzZUNvbnRleHQ7XG4gIHZhciBtYXBSZXN1bHQgPSBtYXBCb29rS2VlcGluZy5tYXBSZXN1bHQ7XG5cbiAgdmFyIGtleVVuaXF1ZSA9ICFtYXBSZXN1bHQuaGFzT3duUHJvcGVydHkobmFtZSk7XG4gIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyB3YXJuaW5nKFxuICAgIGtleVVuaXF1ZSxcbiAgICAnUmVhY3RDaGlsZHJlbi5tYXAoLi4uKTogRW5jb3VudGVyZWQgdHdvIGNoaWxkcmVuIHdpdGggdGhlIHNhbWUga2V5LCAnICtcbiAgICAnYCVzYC4gQ2hpbGQga2V5cyBtdXN0IGJlIHVuaXF1ZTsgd2hlbiB0d28gY2hpbGRyZW4gc2hhcmUgYSBrZXksIG9ubHkgJyArXG4gICAgJ3RoZSBmaXJzdCBjaGlsZCB3aWxsIGJlIHVzZWQuJyxcbiAgICBuYW1lXG4gICkgOiBudWxsKTtcblxuICBpZiAoa2V5VW5pcXVlKSB7XG4gICAgdmFyIG1hcHBlZENoaWxkID1cbiAgICAgIG1hcEJvb2tLZWVwaW5nLm1hcEZ1bmN0aW9uLmNhbGwobWFwQm9va0tlZXBpbmcubWFwQ29udGV4dCwgY2hpbGQsIGkpO1xuICAgIG1hcFJlc3VsdFtuYW1lXSA9IG1hcHBlZENoaWxkO1xuICB9XG59XG5cbi8qKlxuICogTWFwcyBjaGlsZHJlbiB0aGF0IGFyZSB0eXBpY2FsbHkgc3BlY2lmaWVkIGFzIGBwcm9wcy5jaGlsZHJlbmAuXG4gKlxuICogVGhlIHByb3ZpZGVkIG1hcEZ1bmN0aW9uKGNoaWxkLCBrZXksIGluZGV4KSB3aWxsIGJlIGNhbGxlZCBmb3IgZWFjaFxuICogbGVhZiBjaGlsZC5cbiAqXG4gKiBUT0RPOiBUaGlzIG1heSBsaWtlbHkgYnJlYWsgYW55IGNhbGxzIHRvIGBSZWFjdENoaWxkcmVuLm1hcGAgdGhhdCB3ZXJlXG4gKiBwcmV2aW91c2x5IHJlbHlpbmcgb24gdGhlIGZhY3QgdGhhdCB3ZSBndWFyZGVkIGFnYWluc3QgbnVsbCBjaGlsZHJlbi5cbiAqXG4gKiBAcGFyYW0gez8qfSBjaGlsZHJlbiBDaGlsZHJlbiB0cmVlIGNvbnRhaW5lci5cbiAqIEBwYXJhbSB7ZnVuY3Rpb24oKiwgaW50KX0gbWFwRnVuY3Rpb24uXG4gKiBAcGFyYW0geyp9IG1hcENvbnRleHQgQ29udGV4dCBmb3IgbWFwRnVuY3Rpb24uXG4gKiBAcmV0dXJuIHtvYmplY3R9IE9iamVjdCBjb250YWluaW5nIHRoZSBvcmRlcmVkIG1hcCBvZiByZXN1bHRzLlxuICovXG5mdW5jdGlvbiBtYXBDaGlsZHJlbihjaGlsZHJlbiwgZnVuYywgY29udGV4dCkge1xuICBpZiAoY2hpbGRyZW4gPT0gbnVsbCkge1xuICAgIHJldHVybiBjaGlsZHJlbjtcbiAgfVxuXG4gIHZhciBtYXBSZXN1bHQgPSB7fTtcbiAgdmFyIHRyYXZlcnNlQ29udGV4dCA9IE1hcEJvb2tLZWVwaW5nLmdldFBvb2xlZChtYXBSZXN1bHQsIGZ1bmMsIGNvbnRleHQpO1xuICB0cmF2ZXJzZUFsbENoaWxkcmVuKGNoaWxkcmVuLCBtYXBTaW5nbGVDaGlsZEludG9Db250ZXh0LCB0cmF2ZXJzZUNvbnRleHQpO1xuICBNYXBCb29rS2VlcGluZy5yZWxlYXNlKHRyYXZlcnNlQ29udGV4dCk7XG4gIHJldHVybiBtYXBSZXN1bHQ7XG59XG5cbmZ1bmN0aW9uIGZvckVhY2hTaW5nbGVDaGlsZER1bW15KHRyYXZlcnNlQ29udGV4dCwgY2hpbGQsIG5hbWUsIGkpIHtcbiAgcmV0dXJuIG51bGw7XG59XG5cbi8qKlxuICogQ291bnQgdGhlIG51bWJlciBvZiBjaGlsZHJlbiB0aGF0IGFyZSB0eXBpY2FsbHkgc3BlY2lmaWVkIGFzXG4gKiBgcHJvcHMuY2hpbGRyZW5gLlxuICpcbiAqIEBwYXJhbSB7Pyp9IGNoaWxkcmVuIENoaWxkcmVuIHRyZWUgY29udGFpbmVyLlxuICogQHJldHVybiB7bnVtYmVyfSBUaGUgbnVtYmVyIG9mIGNoaWxkcmVuLlxuICovXG5mdW5jdGlvbiBjb3VudENoaWxkcmVuKGNoaWxkcmVuLCBjb250ZXh0KSB7XG4gIHJldHVybiB0cmF2ZXJzZUFsbENoaWxkcmVuKGNoaWxkcmVuLCBmb3JFYWNoU2luZ2xlQ2hpbGREdW1teSwgbnVsbCk7XG59XG5cbnZhciBSZWFjdENoaWxkcmVuID0ge1xuICBmb3JFYWNoOiBmb3JFYWNoQ2hpbGRyZW4sXG4gIG1hcDogbWFwQ2hpbGRyZW4sXG4gIGNvdW50OiBjb3VudENoaWxkcmVuXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0Q2hpbGRyZW47XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RDb21wb25lbnRcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFJlYWN0RWxlbWVudCA9IHJlcXVpcmUoXCIuL1JlYWN0RWxlbWVudFwiKTtcbnZhciBSZWFjdE93bmVyID0gcmVxdWlyZShcIi4vUmVhY3RPd25lclwiKTtcbnZhciBSZWFjdFVwZGF0ZXMgPSByZXF1aXJlKFwiLi9SZWFjdFVwZGF0ZXNcIik7XG5cbnZhciBhc3NpZ24gPSByZXF1aXJlKFwiLi9PYmplY3QuYXNzaWduXCIpO1xudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcbnZhciBrZXlNaXJyb3IgPSByZXF1aXJlKFwiLi9rZXlNaXJyb3JcIik7XG5cbi8qKlxuICogRXZlcnkgUmVhY3QgY29tcG9uZW50IGlzIGluIG9uZSBvZiB0aGVzZSBsaWZlIGN5Y2xlcy5cbiAqL1xudmFyIENvbXBvbmVudExpZmVDeWNsZSA9IGtleU1pcnJvcih7XG4gIC8qKlxuICAgKiBNb3VudGVkIGNvbXBvbmVudHMgaGF2ZSBhIERPTSBub2RlIHJlcHJlc2VudGF0aW9uIGFuZCBhcmUgY2FwYWJsZSBvZlxuICAgKiByZWNlaXZpbmcgbmV3IHByb3BzLlxuICAgKi9cbiAgTU9VTlRFRDogbnVsbCxcbiAgLyoqXG4gICAqIFVubW91bnRlZCBjb21wb25lbnRzIGFyZSBpbmFjdGl2ZSBhbmQgY2Fubm90IHJlY2VpdmUgbmV3IHByb3BzLlxuICAgKi9cbiAgVU5NT1VOVEVEOiBudWxsXG59KTtcblxudmFyIGluamVjdGVkID0gZmFsc2U7XG5cbi8qKlxuICogT3B0aW9uYWxseSBpbmplY3RhYmxlIGVudmlyb25tZW50IGRlcGVuZGVudCBjbGVhbnVwIGhvb2suIChzZXJ2ZXIgdnMuXG4gKiBicm93c2VyIGV0YykuIEV4YW1wbGU6IEEgYnJvd3NlciBzeXN0ZW0gY2FjaGVzIERPTSBub2RlcyBiYXNlZCBvbiBjb21wb25lbnRcbiAqIElEIGFuZCBtdXN0IHJlbW92ZSB0aGF0IGNhY2hlIGVudHJ5IHdoZW4gdGhpcyBpbnN0YW5jZSBpcyB1bm1vdW50ZWQuXG4gKlxuICogQHByaXZhdGVcbiAqL1xudmFyIHVubW91bnRJREZyb21FbnZpcm9ubWVudCA9IG51bGw7XG5cbi8qKlxuICogVGhlIFwiaW1hZ2VcIiBvZiBhIGNvbXBvbmVudCB0cmVlLCBpcyB0aGUgcGxhdGZvcm0gc3BlY2lmaWMgKHR5cGljYWxseVxuICogc2VyaWFsaXplZCkgZGF0YSB0aGF0IHJlcHJlc2VudHMgYSB0cmVlIG9mIGxvd2VyIGxldmVsIFVJIGJ1aWxkaW5nIGJsb2Nrcy5cbiAqIE9uIHRoZSB3ZWIsIHRoaXMgXCJpbWFnZVwiIGlzIEhUTUwgbWFya3VwIHdoaWNoIGRlc2NyaWJlcyBhIGNvbnN0cnVjdGlvbiBvZlxuICogbG93IGxldmVsIGBkaXZgIGFuZCBgc3BhbmAgbm9kZXMuIE90aGVyIHBsYXRmb3JtcyBtYXkgaGF2ZSBkaWZmZXJlbnRcbiAqIGVuY29kaW5nIG9mIHRoaXMgXCJpbWFnZVwiLiBUaGlzIG11c3QgYmUgaW5qZWN0ZWQuXG4gKlxuICogQHByaXZhdGVcbiAqL1xudmFyIG1vdW50SW1hZ2VJbnRvTm9kZSA9IG51bGw7XG5cbi8qKlxuICogQ29tcG9uZW50cyBhcmUgdGhlIGJhc2ljIHVuaXRzIG9mIGNvbXBvc2l0aW9uIGluIFJlYWN0LlxuICpcbiAqIEV2ZXJ5IGNvbXBvbmVudCBhY2NlcHRzIGEgc2V0IG9mIGtleWVkIGlucHV0IHBhcmFtZXRlcnMga25vd24gYXMgXCJwcm9wc1wiIHRoYXRcbiAqIGFyZSBpbml0aWFsaXplZCBieSB0aGUgY29uc3RydWN0b3IuIE9uY2UgYSBjb21wb25lbnQgaXMgbW91bnRlZCwgdGhlIHByb3BzXG4gKiBjYW4gYmUgbXV0YXRlZCB1c2luZyBgc2V0UHJvcHNgIG9yIGByZXBsYWNlUHJvcHNgLlxuICpcbiAqIEV2ZXJ5IGNvbXBvbmVudCBpcyBjYXBhYmxlIG9mIHRoZSBmb2xsb3dpbmcgb3BlcmF0aW9uczpcbiAqXG4gKiAgIGBtb3VudENvbXBvbmVudGBcbiAqICAgICBJbml0aWFsaXplcyB0aGUgY29tcG9uZW50LCByZW5kZXJzIG1hcmt1cCwgYW5kIHJlZ2lzdGVycyBldmVudCBsaXN0ZW5lcnMuXG4gKlxuICogICBgcmVjZWl2ZUNvbXBvbmVudGBcbiAqICAgICBVcGRhdGVzIHRoZSByZW5kZXJlZCBET00gbm9kZXMgdG8gbWF0Y2ggdGhlIGdpdmVuIGNvbXBvbmVudC5cbiAqXG4gKiAgIGB1bm1vdW50Q29tcG9uZW50YFxuICogICAgIFJlbGVhc2VzIGFueSByZXNvdXJjZXMgYWxsb2NhdGVkIGJ5IHRoaXMgY29tcG9uZW50LlxuICpcbiAqIENvbXBvbmVudHMgY2FuIGFsc28gYmUgXCJvd25lZFwiIGJ5IG90aGVyIGNvbXBvbmVudHMuIEJlaW5nIG93bmVkIGJ5IGFub3RoZXJcbiAqIGNvbXBvbmVudCBtZWFucyBiZWluZyBjb25zdHJ1Y3RlZCBieSB0aGF0IGNvbXBvbmVudC4gVGhpcyBpcyBkaWZmZXJlbnQgZnJvbVxuICogYmVpbmcgdGhlIGNoaWxkIG9mIGEgY29tcG9uZW50LCB3aGljaCBtZWFucyBoYXZpbmcgYSBET00gcmVwcmVzZW50YXRpb24gdGhhdFxuICogaXMgYSBjaGlsZCBvZiB0aGUgRE9NIHJlcHJlc2VudGF0aW9uIG9mIHRoYXQgY29tcG9uZW50LlxuICpcbiAqIEBjbGFzcyBSZWFjdENvbXBvbmVudFxuICovXG52YXIgUmVhY3RDb21wb25lbnQgPSB7XG5cbiAgaW5qZWN0aW9uOiB7XG4gICAgaW5qZWN0RW52aXJvbm1lbnQ6IGZ1bmN0aW9uKFJlYWN0Q29tcG9uZW50RW52aXJvbm1lbnQpIHtcbiAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgICFpbmplY3RlZCxcbiAgICAgICAgJ1JlYWN0Q29tcG9uZW50OiBpbmplY3RFbnZpcm9ubWVudCgpIGNhbiBvbmx5IGJlIGNhbGxlZCBvbmNlLidcbiAgICAgICkgOiBpbnZhcmlhbnQoIWluamVjdGVkKSk7XG4gICAgICBtb3VudEltYWdlSW50b05vZGUgPSBSZWFjdENvbXBvbmVudEVudmlyb25tZW50Lm1vdW50SW1hZ2VJbnRvTm9kZTtcbiAgICAgIHVubW91bnRJREZyb21FbnZpcm9ubWVudCA9XG4gICAgICAgIFJlYWN0Q29tcG9uZW50RW52aXJvbm1lbnQudW5tb3VudElERnJvbUVudmlyb25tZW50O1xuICAgICAgUmVhY3RDb21wb25lbnQuQmFja2VuZElET3BlcmF0aW9ucyA9XG4gICAgICAgIFJlYWN0Q29tcG9uZW50RW52aXJvbm1lbnQuQmFja2VuZElET3BlcmF0aW9ucztcbiAgICAgIGluamVjdGVkID0gdHJ1ZTtcbiAgICB9XG4gIH0sXG5cbiAgLyoqXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgTGlmZUN5Y2xlOiBDb21wb25lbnRMaWZlQ3ljbGUsXG5cbiAgLyoqXG4gICAqIEluamVjdGVkIG1vZHVsZSB0aGF0IHByb3ZpZGVzIGFiaWxpdHkgdG8gbXV0YXRlIGluZGl2aWR1YWwgcHJvcGVydGllcy5cbiAgICogSW5qZWN0ZWQgaW50byB0aGUgYmFzZSBjbGFzcyBiZWNhdXNlIG1hbnkgZGlmZmVyZW50IHN1YmNsYXNzZXMgbmVlZCBhY2Nlc3NcbiAgICogdG8gdGhpcy5cbiAgICpcbiAgICogQGludGVybmFsXG4gICAqL1xuICBCYWNrZW5kSURPcGVyYXRpb25zOiBudWxsLFxuXG4gIC8qKlxuICAgKiBCYXNlIGZ1bmN0aW9uYWxpdHkgZm9yIGV2ZXJ5IFJlYWN0Q29tcG9uZW50IGNvbnN0cnVjdG9yLiBNaXhlZCBpbnRvIHRoZVxuICAgKiBgUmVhY3RDb21wb25lbnRgIHByb3RvdHlwZSwgYnV0IGV4cG9zZWQgc3RhdGljYWxseSBmb3IgZWFzeSBhY2Nlc3MuXG4gICAqXG4gICAqIEBsZW5kcyB7UmVhY3RDb21wb25lbnQucHJvdG90eXBlfVxuICAgKi9cbiAgTWl4aW46IHtcblxuICAgIC8qKlxuICAgICAqIENoZWNrcyB3aGV0aGVyIG9yIG5vdCB0aGlzIGNvbXBvbmVudCBpcyBtb3VudGVkLlxuICAgICAqXG4gICAgICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiBtb3VudGVkLCBmYWxzZSBvdGhlcndpc2UuXG4gICAgICogQGZpbmFsXG4gICAgICogQHByb3RlY3RlZFxuICAgICAqL1xuICAgIGlzTW91bnRlZDogZnVuY3Rpb24oKSB7XG4gICAgICByZXR1cm4gdGhpcy5fbGlmZUN5Y2xlU3RhdGUgPT09IENvbXBvbmVudExpZmVDeWNsZS5NT1VOVEVEO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBTZXRzIGEgc3Vic2V0IG9mIHRoZSBwcm9wcy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBwYXJ0aWFsUHJvcHMgU3Vic2V0IG9mIHRoZSBuZXh0IHByb3BzLlxuICAgICAqIEBwYXJhbSB7P2Z1bmN0aW9ufSBjYWxsYmFjayBDYWxsZWQgYWZ0ZXIgcHJvcHMgYXJlIHVwZGF0ZWQuXG4gICAgICogQGZpbmFsXG4gICAgICogQHB1YmxpY1xuICAgICAqL1xuICAgIHNldFByb3BzOiBmdW5jdGlvbihwYXJ0aWFsUHJvcHMsIGNhbGxiYWNrKSB7XG4gICAgICAvLyBNZXJnZSB3aXRoIHRoZSBwZW5kaW5nIGVsZW1lbnQgaWYgaXQgZXhpc3RzLCBvdGhlcndpc2Ugd2l0aCBleGlzdGluZ1xuICAgICAgLy8gZWxlbWVudCBwcm9wcy5cbiAgICAgIHZhciBlbGVtZW50ID0gdGhpcy5fcGVuZGluZ0VsZW1lbnQgfHwgdGhpcy5fY3VycmVudEVsZW1lbnQ7XG4gICAgICB0aGlzLnJlcGxhY2VQcm9wcyhcbiAgICAgICAgYXNzaWduKHt9LCBlbGVtZW50LnByb3BzLCBwYXJ0aWFsUHJvcHMpLFxuICAgICAgICBjYWxsYmFja1xuICAgICAgKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmVwbGFjZXMgYWxsIG9mIHRoZSBwcm9wcy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBwcm9wcyBOZXcgcHJvcHMuXG4gICAgICogQHBhcmFtIHs/ZnVuY3Rpb259IGNhbGxiYWNrIENhbGxlZCBhZnRlciBwcm9wcyBhcmUgdXBkYXRlZC5cbiAgICAgKiBAZmluYWxcbiAgICAgKiBAcHVibGljXG4gICAgICovXG4gICAgcmVwbGFjZVByb3BzOiBmdW5jdGlvbihwcm9wcywgY2FsbGJhY2spIHtcbiAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgIHRoaXMuaXNNb3VudGVkKCksXG4gICAgICAgICdyZXBsYWNlUHJvcHMoLi4uKTogQ2FuIG9ubHkgdXBkYXRlIGEgbW91bnRlZCBjb21wb25lbnQuJ1xuICAgICAgKSA6IGludmFyaWFudCh0aGlzLmlzTW91bnRlZCgpKSk7XG4gICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICB0aGlzLl9tb3VudERlcHRoID09PSAwLFxuICAgICAgICAncmVwbGFjZVByb3BzKC4uLik6IFlvdSBjYWxsZWQgYHNldFByb3BzYCBvciBgcmVwbGFjZVByb3BzYCBvbiBhICcgK1xuICAgICAgICAnY29tcG9uZW50IHdpdGggYSBwYXJlbnQuIFRoaXMgaXMgYW4gYW50aS1wYXR0ZXJuIHNpbmNlIHByb3BzIHdpbGwgJyArXG4gICAgICAgICdnZXQgcmVhY3RpdmVseSB1cGRhdGVkIHdoZW4gcmVuZGVyZWQuIEluc3RlYWQsIGNoYW5nZSB0aGUgb3duZXJcXCdzICcgK1xuICAgICAgICAnYHJlbmRlcmAgbWV0aG9kIHRvIHBhc3MgdGhlIGNvcnJlY3QgdmFsdWUgYXMgcHJvcHMgdG8gdGhlIGNvbXBvbmVudCAnICtcbiAgICAgICAgJ3doZXJlIGl0IGlzIGNyZWF0ZWQuJ1xuICAgICAgKSA6IGludmFyaWFudCh0aGlzLl9tb3VudERlcHRoID09PSAwKSk7XG4gICAgICAvLyBUaGlzIGlzIGEgZGVvcHRpbWl6ZWQgcGF0aC4gV2Ugb3B0aW1pemUgZm9yIGFsd2F5cyBoYXZpbmcgYSBlbGVtZW50LlxuICAgICAgLy8gVGhpcyBjcmVhdGVzIGFuIGV4dHJhIGludGVybmFsIGVsZW1lbnQuXG4gICAgICB0aGlzLl9wZW5kaW5nRWxlbWVudCA9IFJlYWN0RWxlbWVudC5jbG9uZUFuZFJlcGxhY2VQcm9wcyhcbiAgICAgICAgdGhpcy5fcGVuZGluZ0VsZW1lbnQgfHwgdGhpcy5fY3VycmVudEVsZW1lbnQsXG4gICAgICAgIHByb3BzXG4gICAgICApO1xuICAgICAgUmVhY3RVcGRhdGVzLmVucXVldWVVcGRhdGUodGhpcywgY2FsbGJhY2spO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBTY2hlZHVsZSBhIHBhcnRpYWwgdXBkYXRlIHRvIHRoZSBwcm9wcy4gT25seSB1c2VkIGZvciBpbnRlcm5hbCB0ZXN0aW5nLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtvYmplY3R9IHBhcnRpYWxQcm9wcyBTdWJzZXQgb2YgdGhlIG5leHQgcHJvcHMuXG4gICAgICogQHBhcmFtIHs/ZnVuY3Rpb259IGNhbGxiYWNrIENhbGxlZCBhZnRlciBwcm9wcyBhcmUgdXBkYXRlZC5cbiAgICAgKiBAZmluYWxcbiAgICAgKiBAaW50ZXJuYWxcbiAgICAgKi9cbiAgICBfc2V0UHJvcHNJbnRlcm5hbDogZnVuY3Rpb24ocGFydGlhbFByb3BzLCBjYWxsYmFjaykge1xuICAgICAgLy8gVGhpcyBpcyBhIGRlb3B0aW1pemVkIHBhdGguIFdlIG9wdGltaXplIGZvciBhbHdheXMgaGF2aW5nIGEgZWxlbWVudC5cbiAgICAgIC8vIFRoaXMgY3JlYXRlcyBhbiBleHRyYSBpbnRlcm5hbCBlbGVtZW50LlxuICAgICAgdmFyIGVsZW1lbnQgPSB0aGlzLl9wZW5kaW5nRWxlbWVudCB8fCB0aGlzLl9jdXJyZW50RWxlbWVudDtcbiAgICAgIHRoaXMuX3BlbmRpbmdFbGVtZW50ID0gUmVhY3RFbGVtZW50LmNsb25lQW5kUmVwbGFjZVByb3BzKFxuICAgICAgICBlbGVtZW50LFxuICAgICAgICBhc3NpZ24oe30sIGVsZW1lbnQucHJvcHMsIHBhcnRpYWxQcm9wcylcbiAgICAgICk7XG4gICAgICBSZWFjdFVwZGF0ZXMuZW5xdWV1ZVVwZGF0ZSh0aGlzLCBjYWxsYmFjayk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEJhc2UgY29uc3RydWN0b3IgZm9yIGFsbCBSZWFjdCBjb21wb25lbnRzLlxuICAgICAqXG4gICAgICogU3ViY2xhc3NlcyB0aGF0IG92ZXJyaWRlIHRoaXMgbWV0aG9kIHNob3VsZCBtYWtlIHN1cmUgdG8gaW52b2tlXG4gICAgICogYFJlYWN0Q29tcG9uZW50Lk1peGluLmNvbnN0cnVjdC5jYWxsKHRoaXMsIC4uLilgLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtSZWFjdEVsZW1lbnR9IGVsZW1lbnRcbiAgICAgKiBAaW50ZXJuYWxcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3Q6IGZ1bmN0aW9uKGVsZW1lbnQpIHtcbiAgICAgIC8vIFRoaXMgaXMgdGhlIHB1YmxpYyBleHBvc2VkIHByb3BzIG9iamVjdCBhZnRlciBpdCBoYXMgYmVlbiBwcm9jZXNzZWRcbiAgICAgIC8vIHdpdGggZGVmYXVsdCBwcm9wcy4gVGhlIGVsZW1lbnQncyBwcm9wcyByZXByZXNlbnRzIHRoZSB0cnVlIGludGVybmFsXG4gICAgICAvLyBzdGF0ZSBvZiB0aGUgcHJvcHMuXG4gICAgICB0aGlzLnByb3BzID0gZWxlbWVudC5wcm9wcztcbiAgICAgIC8vIFJlY29yZCB0aGUgY29tcG9uZW50IHJlc3BvbnNpYmxlIGZvciBjcmVhdGluZyB0aGlzIGNvbXBvbmVudC5cbiAgICAgIC8vIFRoaXMgaXMgYWNjZXNzaWJsZSB0aHJvdWdoIHRoZSBlbGVtZW50IGJ1dCB3ZSBtYWludGFpbiBhbiBleHRyYVxuICAgICAgLy8gZmllbGQgZm9yIGNvbXBhdGliaWxpdHkgd2l0aCBkZXZ0b29scyBhbmQgYXMgYSB3YXkgdG8gbWFrZSBhblxuICAgICAgLy8gaW5jcmVtZW50YWwgdXBkYXRlLiBUT0RPOiBDb25zaWRlciBkZXByZWNhdGluZyB0aGlzIGZpZWxkLlxuICAgICAgdGhpcy5fb3duZXIgPSBlbGVtZW50Ll9vd25lcjtcblxuICAgICAgLy8gQWxsIGNvbXBvbmVudHMgc3RhcnQgdW5tb3VudGVkLlxuICAgICAgdGhpcy5fbGlmZUN5Y2xlU3RhdGUgPSBDb21wb25lbnRMaWZlQ3ljbGUuVU5NT1VOVEVEO1xuXG4gICAgICAvLyBTZWUgUmVhY3RVcGRhdGVzLlxuICAgICAgdGhpcy5fcGVuZGluZ0NhbGxiYWNrcyA9IG51bGw7XG5cbiAgICAgIC8vIFdlIGtlZXAgdGhlIG9sZCBlbGVtZW50IGFuZCBhIHJlZmVyZW5jZSB0byB0aGUgcGVuZGluZyBlbGVtZW50XG4gICAgICAvLyB0byB0cmFjayB1cGRhdGVzLlxuICAgICAgdGhpcy5fY3VycmVudEVsZW1lbnQgPSBlbGVtZW50O1xuICAgICAgdGhpcy5fcGVuZGluZ0VsZW1lbnQgPSBudWxsO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBJbml0aWFsaXplcyB0aGUgY29tcG9uZW50LCByZW5kZXJzIG1hcmt1cCwgYW5kIHJlZ2lzdGVycyBldmVudCBsaXN0ZW5lcnMuXG4gICAgICpcbiAgICAgKiBOT1RFOiBUaGlzIGRvZXMgbm90IGluc2VydCBhbnkgbm9kZXMgaW50byB0aGUgRE9NLlxuICAgICAqXG4gICAgICogU3ViY2xhc3NlcyB0aGF0IG92ZXJyaWRlIHRoaXMgbWV0aG9kIHNob3VsZCBtYWtlIHN1cmUgdG8gaW52b2tlXG4gICAgICogYFJlYWN0Q29tcG9uZW50Lk1peGluLm1vdW50Q29tcG9uZW50LmNhbGwodGhpcywgLi4uKWAuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gcm9vdElEIERPTSBJRCBvZiB0aGUgcm9vdCBub2RlLlxuICAgICAqIEBwYXJhbSB7UmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbnxSZWFjdFNlcnZlclJlbmRlcmluZ1RyYW5zYWN0aW9ufSB0cmFuc2FjdGlvblxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBtb3VudERlcHRoIG51bWJlciBvZiBjb21wb25lbnRzIGluIHRoZSBvd25lciBoaWVyYXJjaHkuXG4gICAgICogQHJldHVybiB7P3N0cmluZ30gUmVuZGVyZWQgbWFya3VwIHRvIGJlIGluc2VydGVkIGludG8gdGhlIERPTS5cbiAgICAgKiBAaW50ZXJuYWxcbiAgICAgKi9cbiAgICBtb3VudENvbXBvbmVudDogZnVuY3Rpb24ocm9vdElELCB0cmFuc2FjdGlvbiwgbW91bnREZXB0aCkge1xuICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgIXRoaXMuaXNNb3VudGVkKCksXG4gICAgICAgICdtb3VudENvbXBvbmVudCglcywgLi4uKTogQ2FuIG9ubHkgbW91bnQgYW4gdW5tb3VudGVkIGNvbXBvbmVudC4gJyArXG4gICAgICAgICdNYWtlIHN1cmUgdG8gYXZvaWQgc3RvcmluZyBjb21wb25lbnRzIGJldHdlZW4gcmVuZGVycyBvciByZXVzaW5nIGEgJyArXG4gICAgICAgICdzaW5nbGUgY29tcG9uZW50IGluc3RhbmNlIGluIG11bHRpcGxlIHBsYWNlcy4nLFxuICAgICAgICByb290SURcbiAgICAgICkgOiBpbnZhcmlhbnQoIXRoaXMuaXNNb3VudGVkKCkpKTtcbiAgICAgIHZhciByZWYgPSB0aGlzLl9jdXJyZW50RWxlbWVudC5yZWY7XG4gICAgICBpZiAocmVmICE9IG51bGwpIHtcbiAgICAgICAgdmFyIG93bmVyID0gdGhpcy5fY3VycmVudEVsZW1lbnQuX293bmVyO1xuICAgICAgICBSZWFjdE93bmVyLmFkZENvbXBvbmVudEFzUmVmVG8odGhpcywgcmVmLCBvd25lcik7XG4gICAgICB9XG4gICAgICB0aGlzLl9yb290Tm9kZUlEID0gcm9vdElEO1xuICAgICAgdGhpcy5fbGlmZUN5Y2xlU3RhdGUgPSBDb21wb25lbnRMaWZlQ3ljbGUuTU9VTlRFRDtcbiAgICAgIHRoaXMuX21vdW50RGVwdGggPSBtb3VudERlcHRoO1xuICAgICAgLy8gRWZmZWN0aXZlbHk6IHJldHVybiAnJztcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmVsZWFzZXMgYW55IHJlc291cmNlcyBhbGxvY2F0ZWQgYnkgYG1vdW50Q29tcG9uZW50YC5cbiAgICAgKlxuICAgICAqIE5PVEU6IFRoaXMgZG9lcyBub3QgcmVtb3ZlIGFueSBub2RlcyBmcm9tIHRoZSBET00uXG4gICAgICpcbiAgICAgKiBTdWJjbGFzc2VzIHRoYXQgb3ZlcnJpZGUgdGhpcyBtZXRob2Qgc2hvdWxkIG1ha2Ugc3VyZSB0byBpbnZva2VcbiAgICAgKiBgUmVhY3RDb21wb25lbnQuTWl4aW4udW5tb3VudENvbXBvbmVudC5jYWxsKHRoaXMpYC5cbiAgICAgKlxuICAgICAqIEBpbnRlcm5hbFxuICAgICAqL1xuICAgIHVubW91bnRDb21wb25lbnQ6IGZ1bmN0aW9uKCkge1xuICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgdGhpcy5pc01vdW50ZWQoKSxcbiAgICAgICAgJ3VubW91bnRDb21wb25lbnQoKTogQ2FuIG9ubHkgdW5tb3VudCBhIG1vdW50ZWQgY29tcG9uZW50LidcbiAgICAgICkgOiBpbnZhcmlhbnQodGhpcy5pc01vdW50ZWQoKSkpO1xuICAgICAgdmFyIHJlZiA9IHRoaXMuX2N1cnJlbnRFbGVtZW50LnJlZjtcbiAgICAgIGlmIChyZWYgIT0gbnVsbCkge1xuICAgICAgICBSZWFjdE93bmVyLnJlbW92ZUNvbXBvbmVudEFzUmVmRnJvbSh0aGlzLCByZWYsIHRoaXMuX293bmVyKTtcbiAgICAgIH1cbiAgICAgIHVubW91bnRJREZyb21FbnZpcm9ubWVudCh0aGlzLl9yb290Tm9kZUlEKTtcbiAgICAgIHRoaXMuX3Jvb3ROb2RlSUQgPSBudWxsO1xuICAgICAgdGhpcy5fbGlmZUN5Y2xlU3RhdGUgPSBDb21wb25lbnRMaWZlQ3ljbGUuVU5NT1VOVEVEO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBHaXZlbiBhIG5ldyBpbnN0YW5jZSBvZiB0aGlzIGNvbXBvbmVudCwgdXBkYXRlcyB0aGUgcmVuZGVyZWQgRE9NIG5vZGVzXG4gICAgICogYXMgaWYgdGhhdCBpbnN0YW5jZSB3YXMgcmVuZGVyZWQgaW5zdGVhZC5cbiAgICAgKlxuICAgICAqIFN1YmNsYXNzZXMgdGhhdCBvdmVycmlkZSB0aGlzIG1ldGhvZCBzaG91bGQgbWFrZSBzdXJlIHRvIGludm9rZVxuICAgICAqIGBSZWFjdENvbXBvbmVudC5NaXhpbi5yZWNlaXZlQ29tcG9uZW50LmNhbGwodGhpcywgLi4uKWAuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge29iamVjdH0gbmV4dENvbXBvbmVudCBOZXh0IHNldCBvZiBwcm9wZXJ0aWVzLlxuICAgICAqIEBwYXJhbSB7UmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbn0gdHJhbnNhY3Rpb25cbiAgICAgKiBAaW50ZXJuYWxcbiAgICAgKi9cbiAgICByZWNlaXZlQ29tcG9uZW50OiBmdW5jdGlvbihuZXh0RWxlbWVudCwgdHJhbnNhY3Rpb24pIHtcbiAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgIHRoaXMuaXNNb3VudGVkKCksXG4gICAgICAgICdyZWNlaXZlQ29tcG9uZW50KC4uLik6IENhbiBvbmx5IHVwZGF0ZSBhIG1vdW50ZWQgY29tcG9uZW50LidcbiAgICAgICkgOiBpbnZhcmlhbnQodGhpcy5pc01vdW50ZWQoKSkpO1xuICAgICAgdGhpcy5fcGVuZGluZ0VsZW1lbnQgPSBuZXh0RWxlbWVudDtcbiAgICAgIHRoaXMucGVyZm9ybVVwZGF0ZUlmTmVjZXNzYXJ5KHRyYW5zYWN0aW9uKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogSWYgYF9wZW5kaW5nRWxlbWVudGAgaXMgc2V0LCB1cGRhdGUgdGhlIGNvbXBvbmVudC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7UmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbn0gdHJhbnNhY3Rpb25cbiAgICAgKiBAaW50ZXJuYWxcbiAgICAgKi9cbiAgICBwZXJmb3JtVXBkYXRlSWZOZWNlc3Nhcnk6IGZ1bmN0aW9uKHRyYW5zYWN0aW9uKSB7XG4gICAgICBpZiAodGhpcy5fcGVuZGluZ0VsZW1lbnQgPT0gbnVsbCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICB2YXIgcHJldkVsZW1lbnQgPSB0aGlzLl9jdXJyZW50RWxlbWVudDtcbiAgICAgIHZhciBuZXh0RWxlbWVudCA9IHRoaXMuX3BlbmRpbmdFbGVtZW50O1xuICAgICAgdGhpcy5fY3VycmVudEVsZW1lbnQgPSBuZXh0RWxlbWVudDtcbiAgICAgIHRoaXMucHJvcHMgPSBuZXh0RWxlbWVudC5wcm9wcztcbiAgICAgIHRoaXMuX293bmVyID0gbmV4dEVsZW1lbnQuX293bmVyO1xuICAgICAgdGhpcy5fcGVuZGluZ0VsZW1lbnQgPSBudWxsO1xuICAgICAgdGhpcy51cGRhdGVDb21wb25lbnQodHJhbnNhY3Rpb24sIHByZXZFbGVtZW50KTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVXBkYXRlcyB0aGUgY29tcG9uZW50J3MgY3VycmVudGx5IG1vdW50ZWQgcmVwcmVzZW50YXRpb24uXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1JlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb259IHRyYW5zYWN0aW9uXG4gICAgICogQHBhcmFtIHtvYmplY3R9IHByZXZFbGVtZW50XG4gICAgICogQGludGVybmFsXG4gICAgICovXG4gICAgdXBkYXRlQ29tcG9uZW50OiBmdW5jdGlvbih0cmFuc2FjdGlvbiwgcHJldkVsZW1lbnQpIHtcbiAgICAgIHZhciBuZXh0RWxlbWVudCA9IHRoaXMuX2N1cnJlbnRFbGVtZW50O1xuXG4gICAgICAvLyBJZiBlaXRoZXIgdGhlIG93bmVyIG9yIGEgYHJlZmAgaGFzIGNoYW5nZWQsIG1ha2Ugc3VyZSB0aGUgbmV3ZXN0IG93bmVyXG4gICAgICAvLyBoYXMgc3RvcmVkIGEgcmVmZXJlbmNlIHRvIGB0aGlzYCwgYW5kIHRoZSBwcmV2aW91cyBvd25lciAoaWYgZGlmZmVyZW50KVxuICAgICAgLy8gaGFzIGZvcmdvdHRlbiB0aGUgcmVmZXJlbmNlIHRvIGB0aGlzYC4gV2UgdXNlIHRoZSBlbGVtZW50IGluc3RlYWRcbiAgICAgIC8vIG9mIHRoZSBwdWJsaWMgdGhpcy5wcm9wcyBiZWNhdXNlIHRoZSBwb3N0IHByb2Nlc3NpbmcgY2Fubm90IGRldGVybWluZVxuICAgICAgLy8gYSByZWYuIFRoZSByZWYgY29uY2VwdHVhbGx5IGxpdmVzIG9uIHRoZSBlbGVtZW50LlxuXG4gICAgICAvLyBUT0RPOiBTaG91bGQgdGhpcyBldmVuIGJlIHBvc3NpYmxlPyBUaGUgb3duZXIgY2Fubm90IGNoYW5nZSBiZWNhdXNlXG4gICAgICAvLyBpdCdzIGZvcmJpZGRlbiBieSBzaG91bGRVcGRhdGVSZWFjdENvbXBvbmVudC4gVGhlIHJlZiBjYW4gY2hhbmdlXG4gICAgICAvLyBpZiB5b3Ugc3dhcCB0aGUga2V5cyBvZiBidXQgbm90IHRoZSByZWZzLiBSZWNvbnNpZGVyIHdoZXJlIHRoaXMgY2hlY2tcbiAgICAgIC8vIGlzIG1hZGUuIEl0IHByb2JhYmx5IGJlbG9uZ3Mgd2hlcmUgdGhlIGtleSBjaGVja2luZyBhbmRcbiAgICAgIC8vIGluc3RhbnRpYXRlUmVhY3RDb21wb25lbnQgaXMgZG9uZS5cblxuICAgICAgaWYgKG5leHRFbGVtZW50Ll9vd25lciAhPT0gcHJldkVsZW1lbnQuX293bmVyIHx8XG4gICAgICAgICAgbmV4dEVsZW1lbnQucmVmICE9PSBwcmV2RWxlbWVudC5yZWYpIHtcbiAgICAgICAgaWYgKHByZXZFbGVtZW50LnJlZiAhPSBudWxsKSB7XG4gICAgICAgICAgUmVhY3RPd25lci5yZW1vdmVDb21wb25lbnRBc1JlZkZyb20oXG4gICAgICAgICAgICB0aGlzLCBwcmV2RWxlbWVudC5yZWYsIHByZXZFbGVtZW50Ll9vd25lclxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gQ29ycmVjdCwgZXZlbiBpZiB0aGUgb3duZXIgaXMgdGhlIHNhbWUsIGFuZCBvbmx5IHRoZSByZWYgaGFzIGNoYW5nZWQuXG4gICAgICAgIGlmIChuZXh0RWxlbWVudC5yZWYgIT0gbnVsbCkge1xuICAgICAgICAgIFJlYWN0T3duZXIuYWRkQ29tcG9uZW50QXNSZWZUbyhcbiAgICAgICAgICAgIHRoaXMsXG4gICAgICAgICAgICBuZXh0RWxlbWVudC5yZWYsXG4gICAgICAgICAgICBuZXh0RWxlbWVudC5fb3duZXJcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIE1vdW50cyB0aGlzIGNvbXBvbmVudCBhbmQgaW5zZXJ0cyBpdCBpbnRvIHRoZSBET00uXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gcm9vdElEIERPTSBJRCBvZiB0aGUgcm9vdCBub2RlLlxuICAgICAqIEBwYXJhbSB7RE9NRWxlbWVudH0gY29udGFpbmVyIERPTSBlbGVtZW50IHRvIG1vdW50IGludG8uXG4gICAgICogQHBhcmFtIHtib29sZWFufSBzaG91bGRSZXVzZU1hcmt1cCBJZiB0cnVlLCBkbyBub3QgaW5zZXJ0IG1hcmt1cFxuICAgICAqIEBmaW5hbFxuICAgICAqIEBpbnRlcm5hbFxuICAgICAqIEBzZWUge1JlYWN0TW91bnQucmVuZGVyfVxuICAgICAqL1xuICAgIG1vdW50Q29tcG9uZW50SW50b05vZGU6IGZ1bmN0aW9uKHJvb3RJRCwgY29udGFpbmVyLCBzaG91bGRSZXVzZU1hcmt1cCkge1xuICAgICAgdmFyIHRyYW5zYWN0aW9uID0gUmVhY3RVcGRhdGVzLlJlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb24uZ2V0UG9vbGVkKCk7XG4gICAgICB0cmFuc2FjdGlvbi5wZXJmb3JtKFxuICAgICAgICB0aGlzLl9tb3VudENvbXBvbmVudEludG9Ob2RlLFxuICAgICAgICB0aGlzLFxuICAgICAgICByb290SUQsXG4gICAgICAgIGNvbnRhaW5lcixcbiAgICAgICAgdHJhbnNhY3Rpb24sXG4gICAgICAgIHNob3VsZFJldXNlTWFya3VwXG4gICAgICApO1xuICAgICAgUmVhY3RVcGRhdGVzLlJlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb24ucmVsZWFzZSh0cmFuc2FjdGlvbik7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSByb290SUQgRE9NIElEIG9mIHRoZSByb290IG5vZGUuXG4gICAgICogQHBhcmFtIHtET01FbGVtZW50fSBjb250YWluZXIgRE9NIGVsZW1lbnQgdG8gbW91bnQgaW50by5cbiAgICAgKiBAcGFyYW0ge1JlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb259IHRyYW5zYWN0aW9uXG4gICAgICogQHBhcmFtIHtib29sZWFufSBzaG91bGRSZXVzZU1hcmt1cCBJZiB0cnVlLCBkbyBub3QgaW5zZXJ0IG1hcmt1cFxuICAgICAqIEBmaW5hbFxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgX21vdW50Q29tcG9uZW50SW50b05vZGU6IGZ1bmN0aW9uKFxuICAgICAgICByb290SUQsXG4gICAgICAgIGNvbnRhaW5lcixcbiAgICAgICAgdHJhbnNhY3Rpb24sXG4gICAgICAgIHNob3VsZFJldXNlTWFya3VwKSB7XG4gICAgICB2YXIgbWFya3VwID0gdGhpcy5tb3VudENvbXBvbmVudChyb290SUQsIHRyYW5zYWN0aW9uLCAwKTtcbiAgICAgIG1vdW50SW1hZ2VJbnRvTm9kZShtYXJrdXAsIGNvbnRhaW5lciwgc2hvdWxkUmV1c2VNYXJrdXApO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDaGVja3MgaWYgdGhpcyBjb21wb25lbnQgaXMgb3duZWQgYnkgdGhlIHN1cHBsaWVkIGBvd25lcmAgY29tcG9uZW50LlxuICAgICAqXG4gICAgICogQHBhcmFtIHtSZWFjdENvbXBvbmVudH0gb3duZXIgQ29tcG9uZW50IHRvIGNoZWNrLlxuICAgICAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgYG93bmVyc2Agb3ducyB0aGlzIGNvbXBvbmVudC5cbiAgICAgKiBAZmluYWxcbiAgICAgKiBAaW50ZXJuYWxcbiAgICAgKi9cbiAgICBpc093bmVkQnk6IGZ1bmN0aW9uKG93bmVyKSB7XG4gICAgICByZXR1cm4gdGhpcy5fb3duZXIgPT09IG93bmVyO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBHZXRzIGFub3RoZXIgY29tcG9uZW50LCB0aGF0IHNoYXJlcyB0aGUgc2FtZSBvd25lciBhcyB0aGlzIG9uZSwgYnkgcmVmLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHJlZiBvZiBhIHNpYmxpbmcgQ29tcG9uZW50LlxuICAgICAqIEByZXR1cm4gez9SZWFjdENvbXBvbmVudH0gdGhlIGFjdHVhbCBzaWJsaW5nIENvbXBvbmVudC5cbiAgICAgKiBAZmluYWxcbiAgICAgKiBAaW50ZXJuYWxcbiAgICAgKi9cbiAgICBnZXRTaWJsaW5nQnlSZWY6IGZ1bmN0aW9uKHJlZikge1xuICAgICAgdmFyIG93bmVyID0gdGhpcy5fb3duZXI7XG4gICAgICBpZiAoIW93bmVyIHx8ICFvd25lci5yZWZzKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG93bmVyLnJlZnNbcmVmXTtcbiAgICB9XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RDb21wb25lbnQ7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RDb21wb25lbnRCcm93c2VyRW52aXJvbm1lbnRcbiAqL1xuXG4vKmpzbGludCBldmlsOiB0cnVlICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgUmVhY3RET01JRE9wZXJhdGlvbnMgPSByZXF1aXJlKFwiLi9SZWFjdERPTUlET3BlcmF0aW9uc1wiKTtcbnZhciBSZWFjdE1hcmt1cENoZWNrc3VtID0gcmVxdWlyZShcIi4vUmVhY3RNYXJrdXBDaGVja3N1bVwiKTtcbnZhciBSZWFjdE1vdW50ID0gcmVxdWlyZShcIi4vUmVhY3RNb3VudFwiKTtcbnZhciBSZWFjdFBlcmYgPSByZXF1aXJlKFwiLi9SZWFjdFBlcmZcIik7XG52YXIgUmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbiA9IHJlcXVpcmUoXCIuL1JlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb25cIik7XG5cbnZhciBnZXRSZWFjdFJvb3RFbGVtZW50SW5Db250YWluZXIgPSByZXF1aXJlKFwiLi9nZXRSZWFjdFJvb3RFbGVtZW50SW5Db250YWluZXJcIik7XG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xudmFyIHNldElubmVySFRNTCA9IHJlcXVpcmUoXCIuL3NldElubmVySFRNTFwiKTtcblxuXG52YXIgRUxFTUVOVF9OT0RFX1RZUEUgPSAxO1xudmFyIERPQ19OT0RFX1RZUEUgPSA5O1xuXG5cbi8qKlxuICogQWJzdHJhY3RzIGF3YXkgYWxsIGZ1bmN0aW9uYWxpdHkgb2YgYFJlYWN0Q29tcG9uZW50YCByZXF1aXJlcyBrbm93bGVkZ2Ugb2ZcbiAqIHRoZSBicm93c2VyIGNvbnRleHQuXG4gKi9cbnZhciBSZWFjdENvbXBvbmVudEJyb3dzZXJFbnZpcm9ubWVudCA9IHtcbiAgUmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbjogUmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbixcblxuICBCYWNrZW5kSURPcGVyYXRpb25zOiBSZWFjdERPTUlET3BlcmF0aW9ucyxcblxuICAvKipcbiAgICogSWYgYSBwYXJ0aWN1bGFyIGVudmlyb25tZW50IHJlcXVpcmVzIHRoYXQgc29tZSByZXNvdXJjZXMgYmUgY2xlYW5lZCB1cCxcbiAgICogc3BlY2lmeSB0aGlzIGluIHRoZSBpbmplY3RlZCBNaXhpbi4gSW4gdGhlIERPTSwgd2Ugd291bGQgbGlrZWx5IHdhbnQgdG9cbiAgICogcHVyZ2UgYW55IGNhY2hlZCBub2RlIElEIGxvb2t1cHMuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICB1bm1vdW50SURGcm9tRW52aXJvbm1lbnQ6IGZ1bmN0aW9uKHJvb3ROb2RlSUQpIHtcbiAgICBSZWFjdE1vdW50LnB1cmdlSUQocm9vdE5vZGVJRCk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtYXJrdXAgTWFya3VwIHN0cmluZyB0byBwbGFjZSBpbnRvIHRoZSBET00gRWxlbWVudC5cbiAgICogQHBhcmFtIHtET01FbGVtZW50fSBjb250YWluZXIgRE9NIEVsZW1lbnQgdG8gaW5zZXJ0IG1hcmt1cCBpbnRvLlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHNob3VsZFJldXNlTWFya3VwIFNob3VsZCByZXVzZSB0aGUgZXhpc3RpbmcgbWFya3VwIGluIHRoZVxuICAgKiBjb250YWluZXIgaWYgcG9zc2libGUuXG4gICAqL1xuICBtb3VudEltYWdlSW50b05vZGU6IFJlYWN0UGVyZi5tZWFzdXJlKFxuICAgICdSZWFjdENvbXBvbmVudEJyb3dzZXJFbnZpcm9ubWVudCcsXG4gICAgJ21vdW50SW1hZ2VJbnRvTm9kZScsXG4gICAgZnVuY3Rpb24obWFya3VwLCBjb250YWluZXIsIHNob3VsZFJldXNlTWFya3VwKSB7XG4gICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICBjb250YWluZXIgJiYgKFxuICAgICAgICAgIGNvbnRhaW5lci5ub2RlVHlwZSA9PT0gRUxFTUVOVF9OT0RFX1RZUEUgfHxcbiAgICAgICAgICAgIGNvbnRhaW5lci5ub2RlVHlwZSA9PT0gRE9DX05PREVfVFlQRVxuICAgICAgICApLFxuICAgICAgICAnbW91bnRDb21wb25lbnRJbnRvTm9kZSguLi4pOiBUYXJnZXQgY29udGFpbmVyIGlzIG5vdCB2YWxpZC4nXG4gICAgICApIDogaW52YXJpYW50KGNvbnRhaW5lciAmJiAoXG4gICAgICAgIGNvbnRhaW5lci5ub2RlVHlwZSA9PT0gRUxFTUVOVF9OT0RFX1RZUEUgfHxcbiAgICAgICAgICBjb250YWluZXIubm9kZVR5cGUgPT09IERPQ19OT0RFX1RZUEVcbiAgICAgICkpKTtcblxuICAgICAgaWYgKHNob3VsZFJldXNlTWFya3VwKSB7XG4gICAgICAgIGlmIChSZWFjdE1hcmt1cENoZWNrc3VtLmNhblJldXNlTWFya3VwKFxuICAgICAgICAgIG1hcmt1cCxcbiAgICAgICAgICBnZXRSZWFjdFJvb3RFbGVtZW50SW5Db250YWluZXIoY29udGFpbmVyKSkpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgICAgIGNvbnRhaW5lci5ub2RlVHlwZSAhPT0gRE9DX05PREVfVFlQRSxcbiAgICAgICAgICAgICdZb3VcXCdyZSB0cnlpbmcgdG8gcmVuZGVyIGEgY29tcG9uZW50IHRvIHRoZSBkb2N1bWVudCB1c2luZyAnICtcbiAgICAgICAgICAgICdzZXJ2ZXIgcmVuZGVyaW5nIGJ1dCB0aGUgY2hlY2tzdW0gd2FzIGludmFsaWQuIFRoaXMgdXN1YWxseSAnICtcbiAgICAgICAgICAgICdtZWFucyB5b3UgcmVuZGVyZWQgYSBkaWZmZXJlbnQgY29tcG9uZW50IHR5cGUgb3IgcHJvcHMgb24gJyArXG4gICAgICAgICAgICAndGhlIGNsaWVudCBmcm9tIHRoZSBvbmUgb24gdGhlIHNlcnZlciwgb3IgeW91ciByZW5kZXIoKSAnICtcbiAgICAgICAgICAgICdtZXRob2RzIGFyZSBpbXB1cmUuIFJlYWN0IGNhbm5vdCBoYW5kbGUgdGhpcyBjYXNlIGR1ZSB0byAnICtcbiAgICAgICAgICAgICdjcm9zcy1icm93c2VyIHF1aXJrcyBieSByZW5kZXJpbmcgYXQgdGhlIGRvY3VtZW50IHJvb3QuIFlvdSAnICtcbiAgICAgICAgICAgICdzaG91bGQgbG9vayBmb3IgZW52aXJvbm1lbnQgZGVwZW5kZW50IGNvZGUgaW4geW91ciBjb21wb25lbnRzICcgK1xuICAgICAgICAgICAgJ2FuZCBlbnN1cmUgdGhlIHByb3BzIGFyZSB0aGUgc2FtZSBjbGllbnQgYW5kIHNlcnZlciBzaWRlLidcbiAgICAgICAgICApIDogaW52YXJpYW50KGNvbnRhaW5lci5ub2RlVHlwZSAhPT0gRE9DX05PREVfVFlQRSkpO1xuXG4gICAgICAgICAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgICAgICAnUmVhY3QgYXR0ZW1wdGVkIHRvIHVzZSByZXVzZSBtYXJrdXAgaW4gYSBjb250YWluZXIgYnV0IHRoZSAnICtcbiAgICAgICAgICAgICAgJ2NoZWNrc3VtIHdhcyBpbnZhbGlkLiBUaGlzIGdlbmVyYWxseSBtZWFucyB0aGF0IHlvdSBhcmUgJyArXG4gICAgICAgICAgICAgICd1c2luZyBzZXJ2ZXIgcmVuZGVyaW5nIGFuZCB0aGUgbWFya3VwIGdlbmVyYXRlZCBvbiB0aGUgJyArXG4gICAgICAgICAgICAgICdzZXJ2ZXIgd2FzIG5vdCB3aGF0IHRoZSBjbGllbnQgd2FzIGV4cGVjdGluZy4gUmVhY3QgaW5qZWN0ZWQgJyArXG4gICAgICAgICAgICAgICduZXcgbWFya3VwIHRvIGNvbXBlbnNhdGUgd2hpY2ggd29ya3MgYnV0IHlvdSBoYXZlIGxvc3QgbWFueSAnICtcbiAgICAgICAgICAgICAgJ29mIHRoZSBiZW5lZml0cyBvZiBzZXJ2ZXIgcmVuZGVyaW5nLiBJbnN0ZWFkLCBmaWd1cmUgb3V0ICcgK1xuICAgICAgICAgICAgICAnd2h5IHRoZSBtYXJrdXAgYmVpbmcgZ2VuZXJhdGVkIGlzIGRpZmZlcmVudCBvbiB0aGUgY2xpZW50ICcgK1xuICAgICAgICAgICAgICAnb3Igc2VydmVyLidcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgIGNvbnRhaW5lci5ub2RlVHlwZSAhPT0gRE9DX05PREVfVFlQRSxcbiAgICAgICAgJ1lvdVxcJ3JlIHRyeWluZyB0byByZW5kZXIgYSBjb21wb25lbnQgdG8gdGhlIGRvY3VtZW50IGJ1dCAnICtcbiAgICAgICAgICAneW91IGRpZG5cXCd0IHVzZSBzZXJ2ZXIgcmVuZGVyaW5nLiBXZSBjYW5cXCd0IGRvIHRoaXMgJyArXG4gICAgICAgICAgJ3dpdGhvdXQgdXNpbmcgc2VydmVyIHJlbmRlcmluZyBkdWUgdG8gY3Jvc3MtYnJvd3NlciBxdWlya3MuICcgK1xuICAgICAgICAgICdTZWUgcmVuZGVyQ29tcG9uZW50VG9TdHJpbmcoKSBmb3Igc2VydmVyIHJlbmRlcmluZy4nXG4gICAgICApIDogaW52YXJpYW50KGNvbnRhaW5lci5ub2RlVHlwZSAhPT0gRE9DX05PREVfVFlQRSkpO1xuXG4gICAgICBzZXRJbm5lckhUTUwoY29udGFpbmVyLCBtYXJrdXApO1xuICAgIH1cbiAgKVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdENvbXBvbmVudEJyb3dzZXJFbnZpcm9ubWVudDtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RDb21wb25lbnRXaXRoUHVyZVJlbmRlck1peGluXG4qL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIHNoYWxsb3dFcXVhbCA9IHJlcXVpcmUoXCIuL3NoYWxsb3dFcXVhbFwiKTtcblxuLyoqXG4gKiBJZiB5b3VyIFJlYWN0IGNvbXBvbmVudCdzIHJlbmRlciBmdW5jdGlvbiBpcyBcInB1cmVcIiwgZS5nLiBpdCB3aWxsIHJlbmRlciB0aGVcbiAqIHNhbWUgcmVzdWx0IGdpdmVuIHRoZSBzYW1lIHByb3BzIGFuZCBzdGF0ZSwgcHJvdmlkZSB0aGlzIE1peGluIGZvciBhXG4gKiBjb25zaWRlcmFibGUgcGVyZm9ybWFuY2UgYm9vc3QuXG4gKlxuICogTW9zdCBSZWFjdCBjb21wb25lbnRzIGhhdmUgcHVyZSByZW5kZXIgZnVuY3Rpb25zLlxuICpcbiAqIEV4YW1wbGU6XG4gKlxuICogICB2YXIgUmVhY3RDb21wb25lbnRXaXRoUHVyZVJlbmRlck1peGluID1cbiAqICAgICByZXF1aXJlKCdSZWFjdENvbXBvbmVudFdpdGhQdXJlUmVuZGVyTWl4aW4nKTtcbiAqICAgUmVhY3QuY3JlYXRlQ2xhc3Moe1xuICogICAgIG1peGluczogW1JlYWN0Q29tcG9uZW50V2l0aFB1cmVSZW5kZXJNaXhpbl0sXG4gKlxuICogICAgIHJlbmRlcjogZnVuY3Rpb24oKSB7XG4gKiAgICAgICByZXR1cm4gPGRpdiBjbGFzc05hbWU9e3RoaXMucHJvcHMuY2xhc3NOYW1lfT5mb288L2Rpdj47XG4gKiAgICAgfVxuICogICB9KTtcbiAqXG4gKiBOb3RlOiBUaGlzIG9ubHkgY2hlY2tzIHNoYWxsb3cgZXF1YWxpdHkgZm9yIHByb3BzIGFuZCBzdGF0ZS4gSWYgdGhlc2UgY29udGFpblxuICogY29tcGxleCBkYXRhIHN0cnVjdHVyZXMgdGhpcyBtaXhpbiBtYXkgaGF2ZSBmYWxzZS1uZWdhdGl2ZXMgZm9yIGRlZXBlclxuICogZGlmZmVyZW5jZXMuIE9ubHkgbWl4aW4gdG8gY29tcG9uZW50cyB3aGljaCBoYXZlIHNpbXBsZSBwcm9wcyBhbmQgc3RhdGUsIG9yXG4gKiB1c2UgYGZvcmNlVXBkYXRlKClgIHdoZW4geW91IGtub3cgZGVlcCBkYXRhIHN0cnVjdHVyZXMgaGF2ZSBjaGFuZ2VkLlxuICovXG52YXIgUmVhY3RDb21wb25lbnRXaXRoUHVyZVJlbmRlck1peGluID0ge1xuICBzaG91bGRDb21wb25lbnRVcGRhdGU6IGZ1bmN0aW9uKG5leHRQcm9wcywgbmV4dFN0YXRlKSB7XG4gICAgcmV0dXJuICFzaGFsbG93RXF1YWwodGhpcy5wcm9wcywgbmV4dFByb3BzKSB8fFxuICAgICAgICAgICAhc2hhbGxvd0VxdWFsKHRoaXMuc3RhdGUsIG5leHRTdGF0ZSk7XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RDb21wb25lbnRXaXRoUHVyZVJlbmRlck1peGluO1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudFxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgUmVhY3RDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdENvbXBvbmVudFwiKTtcbnZhciBSZWFjdENvbnRleHQgPSByZXF1aXJlKFwiLi9SZWFjdENvbnRleHRcIik7XG52YXIgUmVhY3RDdXJyZW50T3duZXIgPSByZXF1aXJlKFwiLi9SZWFjdEN1cnJlbnRPd25lclwiKTtcbnZhciBSZWFjdEVsZW1lbnQgPSByZXF1aXJlKFwiLi9SZWFjdEVsZW1lbnRcIik7XG52YXIgUmVhY3RFbGVtZW50VmFsaWRhdG9yID0gcmVxdWlyZShcIi4vUmVhY3RFbGVtZW50VmFsaWRhdG9yXCIpO1xudmFyIFJlYWN0RW1wdHlDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdEVtcHR5Q29tcG9uZW50XCIpO1xudmFyIFJlYWN0RXJyb3JVdGlscyA9IHJlcXVpcmUoXCIuL1JlYWN0RXJyb3JVdGlsc1wiKTtcbnZhciBSZWFjdExlZ2FjeUVsZW1lbnQgPSByZXF1aXJlKFwiLi9SZWFjdExlZ2FjeUVsZW1lbnRcIik7XG52YXIgUmVhY3RPd25lciA9IHJlcXVpcmUoXCIuL1JlYWN0T3duZXJcIik7XG52YXIgUmVhY3RQZXJmID0gcmVxdWlyZShcIi4vUmVhY3RQZXJmXCIpO1xudmFyIFJlYWN0UHJvcFRyYW5zZmVyZXIgPSByZXF1aXJlKFwiLi9SZWFjdFByb3BUcmFuc2ZlcmVyXCIpO1xudmFyIFJlYWN0UHJvcFR5cGVMb2NhdGlvbnMgPSByZXF1aXJlKFwiLi9SZWFjdFByb3BUeXBlTG9jYXRpb25zXCIpO1xudmFyIFJlYWN0UHJvcFR5cGVMb2NhdGlvbk5hbWVzID0gcmVxdWlyZShcIi4vUmVhY3RQcm9wVHlwZUxvY2F0aW9uTmFtZXNcIik7XG52YXIgUmVhY3RVcGRhdGVzID0gcmVxdWlyZShcIi4vUmVhY3RVcGRhdGVzXCIpO1xuXG52YXIgYXNzaWduID0gcmVxdWlyZShcIi4vT2JqZWN0LmFzc2lnblwiKTtcbnZhciBpbnN0YW50aWF0ZVJlYWN0Q29tcG9uZW50ID0gcmVxdWlyZShcIi4vaW5zdGFudGlhdGVSZWFjdENvbXBvbmVudFwiKTtcbnZhciBpbnZhcmlhbnQgPSByZXF1aXJlKFwiLi9pbnZhcmlhbnRcIik7XG52YXIga2V5TWlycm9yID0gcmVxdWlyZShcIi4va2V5TWlycm9yXCIpO1xudmFyIGtleU9mID0gcmVxdWlyZShcIi4va2V5T2ZcIik7XG52YXIgbW9uaXRvckNvZGVVc2UgPSByZXF1aXJlKFwiLi9tb25pdG9yQ29kZVVzZVwiKTtcbnZhciBtYXBPYmplY3QgPSByZXF1aXJlKFwiLi9tYXBPYmplY3RcIik7XG52YXIgc2hvdWxkVXBkYXRlUmVhY3RDb21wb25lbnQgPSByZXF1aXJlKFwiLi9zaG91bGRVcGRhdGVSZWFjdENvbXBvbmVudFwiKTtcbnZhciB3YXJuaW5nID0gcmVxdWlyZShcIi4vd2FybmluZ1wiKTtcblxudmFyIE1JWElOU19LRVkgPSBrZXlPZih7bWl4aW5zOiBudWxsfSk7XG5cbi8qKlxuICogUG9saWNpZXMgdGhhdCBkZXNjcmliZSBtZXRob2RzIGluIGBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudEludGVyZmFjZWAuXG4gKi9cbnZhciBTcGVjUG9saWN5ID0ga2V5TWlycm9yKHtcbiAgLyoqXG4gICAqIFRoZXNlIG1ldGhvZHMgbWF5IGJlIGRlZmluZWQgb25seSBvbmNlIGJ5IHRoZSBjbGFzcyBzcGVjaWZpY2F0aW9uIG9yIG1peGluLlxuICAgKi9cbiAgREVGSU5FX09OQ0U6IG51bGwsXG4gIC8qKlxuICAgKiBUaGVzZSBtZXRob2RzIG1heSBiZSBkZWZpbmVkIGJ5IGJvdGggdGhlIGNsYXNzIHNwZWNpZmljYXRpb24gYW5kIG1peGlucy5cbiAgICogU3Vic2VxdWVudCBkZWZpbml0aW9ucyB3aWxsIGJlIGNoYWluZWQuIFRoZXNlIG1ldGhvZHMgbXVzdCByZXR1cm4gdm9pZC5cbiAgICovXG4gIERFRklORV9NQU5ZOiBudWxsLFxuICAvKipcbiAgICogVGhlc2UgbWV0aG9kcyBhcmUgb3ZlcnJpZGluZyB0aGUgYmFzZSBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudCBjbGFzcy5cbiAgICovXG4gIE9WRVJSSURFX0JBU0U6IG51bGwsXG4gIC8qKlxuICAgKiBUaGVzZSBtZXRob2RzIGFyZSBzaW1pbGFyIHRvIERFRklORV9NQU5ZLCBleGNlcHQgd2UgYXNzdW1lIHRoZXkgcmV0dXJuXG4gICAqIG9iamVjdHMuIFdlIHRyeSB0byBtZXJnZSB0aGUga2V5cyBvZiB0aGUgcmV0dXJuIHZhbHVlcyBvZiBhbGwgdGhlIG1peGVkIGluXG4gICAqIGZ1bmN0aW9ucy4gSWYgdGhlcmUgaXMgYSBrZXkgY29uZmxpY3Qgd2UgdGhyb3cuXG4gICAqL1xuICBERUZJTkVfTUFOWV9NRVJHRUQ6IG51bGxcbn0pO1xuXG5cbnZhciBpbmplY3RlZE1peGlucyA9IFtdO1xuXG4vKipcbiAqIENvbXBvc2l0ZSBjb21wb25lbnRzIGFyZSBoaWdoZXItbGV2ZWwgY29tcG9uZW50cyB0aGF0IGNvbXBvc2Ugb3RoZXIgY29tcG9zaXRlXG4gKiBvciBuYXRpdmUgY29tcG9uZW50cy5cbiAqXG4gKiBUbyBjcmVhdGUgYSBuZXcgdHlwZSBvZiBgUmVhY3RDb21wb3NpdGVDb21wb25lbnRgLCBwYXNzIGEgc3BlY2lmaWNhdGlvbiBvZlxuICogeW91ciBuZXcgY2xhc3MgdG8gYFJlYWN0LmNyZWF0ZUNsYXNzYC4gVGhlIG9ubHkgcmVxdWlyZW1lbnQgb2YgeW91ciBjbGFzc1xuICogc3BlY2lmaWNhdGlvbiBpcyB0aGF0IHlvdSBpbXBsZW1lbnQgYSBgcmVuZGVyYCBtZXRob2QuXG4gKlxuICogICB2YXIgTXlDb21wb25lbnQgPSBSZWFjdC5jcmVhdGVDbGFzcyh7XG4gKiAgICAgcmVuZGVyOiBmdW5jdGlvbigpIHtcbiAqICAgICAgIHJldHVybiA8ZGl2PkhlbGxvIFdvcmxkPC9kaXY+O1xuICogICAgIH1cbiAqICAgfSk7XG4gKlxuICogVGhlIGNsYXNzIHNwZWNpZmljYXRpb24gc3VwcG9ydHMgYSBzcGVjaWZpYyBwcm90b2NvbCBvZiBtZXRob2RzIHRoYXQgaGF2ZVxuICogc3BlY2lhbCBtZWFuaW5nIChlLmcuIGByZW5kZXJgKS4gU2VlIGBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudEludGVyZmFjZWAgZm9yXG4gKiBtb3JlIHRoZSBjb21wcmVoZW5zaXZlIHByb3RvY29sLiBBbnkgb3RoZXIgcHJvcGVydGllcyBhbmQgbWV0aG9kcyBpbiB0aGVcbiAqIGNsYXNzIHNwZWNpZmljYXRpb24gd2lsbCBhdmFpbGFibGUgb24gdGhlIHByb3RvdHlwZS5cbiAqXG4gKiBAaW50ZXJmYWNlIFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50SW50ZXJmYWNlXG4gKiBAaW50ZXJuYWxcbiAqL1xudmFyIFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50SW50ZXJmYWNlID0ge1xuXG4gIC8qKlxuICAgKiBBbiBhcnJheSBvZiBNaXhpbiBvYmplY3RzIHRvIGluY2x1ZGUgd2hlbiBkZWZpbmluZyB5b3VyIGNvbXBvbmVudC5cbiAgICpcbiAgICogQHR5cGUge2FycmF5fVxuICAgKiBAb3B0aW9uYWxcbiAgICovXG4gIG1peGluczogU3BlY1BvbGljeS5ERUZJTkVfTUFOWSxcblxuICAvKipcbiAgICogQW4gb2JqZWN0IGNvbnRhaW5pbmcgcHJvcGVydGllcyBhbmQgbWV0aG9kcyB0aGF0IHNob3VsZCBiZSBkZWZpbmVkIG9uXG4gICAqIHRoZSBjb21wb25lbnQncyBjb25zdHJ1Y3RvciBpbnN0ZWFkIG9mIGl0cyBwcm90b3R5cGUgKHN0YXRpYyBtZXRob2RzKS5cbiAgICpcbiAgICogQHR5cGUge29iamVjdH1cbiAgICogQG9wdGlvbmFsXG4gICAqL1xuICBzdGF0aWNzOiBTcGVjUG9saWN5LkRFRklORV9NQU5ZLFxuXG4gIC8qKlxuICAgKiBEZWZpbml0aW9uIG9mIHByb3AgdHlwZXMgZm9yIHRoaXMgY29tcG9uZW50LlxuICAgKlxuICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgKiBAb3B0aW9uYWxcbiAgICovXG4gIHByb3BUeXBlczogU3BlY1BvbGljeS5ERUZJTkVfTUFOWSxcblxuICAvKipcbiAgICogRGVmaW5pdGlvbiBvZiBjb250ZXh0IHR5cGVzIGZvciB0aGlzIGNvbXBvbmVudC5cbiAgICpcbiAgICogQHR5cGUge29iamVjdH1cbiAgICogQG9wdGlvbmFsXG4gICAqL1xuICBjb250ZXh0VHlwZXM6IFNwZWNQb2xpY3kuREVGSU5FX01BTlksXG5cbiAgLyoqXG4gICAqIERlZmluaXRpb24gb2YgY29udGV4dCB0eXBlcyB0aGlzIGNvbXBvbmVudCBzZXRzIGZvciBpdHMgY2hpbGRyZW4uXG4gICAqXG4gICAqIEB0eXBlIHtvYmplY3R9XG4gICAqIEBvcHRpb25hbFxuICAgKi9cbiAgY2hpbGRDb250ZXh0VHlwZXM6IFNwZWNQb2xpY3kuREVGSU5FX01BTlksXG5cbiAgLy8gPT09PSBEZWZpbml0aW9uIG1ldGhvZHMgPT09PVxuXG4gIC8qKlxuICAgKiBJbnZva2VkIHdoZW4gdGhlIGNvbXBvbmVudCBpcyBtb3VudGVkLiBWYWx1ZXMgaW4gdGhlIG1hcHBpbmcgd2lsbCBiZSBzZXQgb25cbiAgICogYHRoaXMucHJvcHNgIGlmIHRoYXQgcHJvcCBpcyBub3Qgc3BlY2lmaWVkIChpLmUuIHVzaW5nIGFuIGBpbmAgY2hlY2spLlxuICAgKlxuICAgKiBUaGlzIG1ldGhvZCBpcyBpbnZva2VkIGJlZm9yZSBgZ2V0SW5pdGlhbFN0YXRlYCBhbmQgdGhlcmVmb3JlIGNhbm5vdCByZWx5XG4gICAqIG9uIGB0aGlzLnN0YXRlYCBvciB1c2UgYHRoaXMuc2V0U3RhdGVgLlxuICAgKlxuICAgKiBAcmV0dXJuIHtvYmplY3R9XG4gICAqIEBvcHRpb25hbFxuICAgKi9cbiAgZ2V0RGVmYXVsdFByb3BzOiBTcGVjUG9saWN5LkRFRklORV9NQU5ZX01FUkdFRCxcblxuICAvKipcbiAgICogSW52b2tlZCBvbmNlIGJlZm9yZSB0aGUgY29tcG9uZW50IGlzIG1vdW50ZWQuIFRoZSByZXR1cm4gdmFsdWUgd2lsbCBiZSB1c2VkXG4gICAqIGFzIHRoZSBpbml0aWFsIHZhbHVlIG9mIGB0aGlzLnN0YXRlYC5cbiAgICpcbiAgICogICBnZXRJbml0aWFsU3RhdGU6IGZ1bmN0aW9uKCkge1xuICAgKiAgICAgcmV0dXJuIHtcbiAgICogICAgICAgaXNPbjogZmFsc2UsXG4gICAqICAgICAgIGZvb0JhejogbmV3IEJhekZvbygpXG4gICAqICAgICB9XG4gICAqICAgfVxuICAgKlxuICAgKiBAcmV0dXJuIHtvYmplY3R9XG4gICAqIEBvcHRpb25hbFxuICAgKi9cbiAgZ2V0SW5pdGlhbFN0YXRlOiBTcGVjUG9saWN5LkRFRklORV9NQU5ZX01FUkdFRCxcblxuICAvKipcbiAgICogQHJldHVybiB7b2JqZWN0fVxuICAgKiBAb3B0aW9uYWxcbiAgICovXG4gIGdldENoaWxkQ29udGV4dDogU3BlY1BvbGljeS5ERUZJTkVfTUFOWV9NRVJHRUQsXG5cbiAgLyoqXG4gICAqIFVzZXMgcHJvcHMgZnJvbSBgdGhpcy5wcm9wc2AgYW5kIHN0YXRlIGZyb20gYHRoaXMuc3RhdGVgIHRvIHJlbmRlciB0aGVcbiAgICogc3RydWN0dXJlIG9mIHRoZSBjb21wb25lbnQuXG4gICAqXG4gICAqIE5vIGd1YXJhbnRlZXMgYXJlIG1hZGUgYWJvdXQgd2hlbiBvciBob3cgb2Z0ZW4gdGhpcyBtZXRob2QgaXMgaW52b2tlZCwgc29cbiAgICogaXQgbXVzdCBub3QgaGF2ZSBzaWRlIGVmZmVjdHMuXG4gICAqXG4gICAqICAgcmVuZGVyOiBmdW5jdGlvbigpIHtcbiAgICogICAgIHZhciBuYW1lID0gdGhpcy5wcm9wcy5uYW1lO1xuICAgKiAgICAgcmV0dXJuIDxkaXY+SGVsbG8sIHtuYW1lfSE8L2Rpdj47XG4gICAqICAgfVxuICAgKlxuICAgKiBAcmV0dXJuIHtSZWFjdENvbXBvbmVudH1cbiAgICogQG5vc2lkZWVmZmVjdHNcbiAgICogQHJlcXVpcmVkXG4gICAqL1xuICByZW5kZXI6IFNwZWNQb2xpY3kuREVGSU5FX09OQ0UsXG5cblxuXG4gIC8vID09PT0gRGVsZWdhdGUgbWV0aG9kcyA9PT09XG5cbiAgLyoqXG4gICAqIEludm9rZWQgd2hlbiB0aGUgY29tcG9uZW50IGlzIGluaXRpYWxseSBjcmVhdGVkIGFuZCBhYm91dCB0byBiZSBtb3VudGVkLlxuICAgKiBUaGlzIG1heSBoYXZlIHNpZGUgZWZmZWN0cywgYnV0IGFueSBleHRlcm5hbCBzdWJzY3JpcHRpb25zIG9yIGRhdGEgY3JlYXRlZFxuICAgKiBieSB0aGlzIG1ldGhvZCBtdXN0IGJlIGNsZWFuZWQgdXAgaW4gYGNvbXBvbmVudFdpbGxVbm1vdW50YC5cbiAgICpcbiAgICogQG9wdGlvbmFsXG4gICAqL1xuICBjb21wb25lbnRXaWxsTW91bnQ6IFNwZWNQb2xpY3kuREVGSU5FX01BTlksXG5cbiAgLyoqXG4gICAqIEludm9rZWQgd2hlbiB0aGUgY29tcG9uZW50IGhhcyBiZWVuIG1vdW50ZWQgYW5kIGhhcyBhIERPTSByZXByZXNlbnRhdGlvbi5cbiAgICogSG93ZXZlciwgdGhlcmUgaXMgbm8gZ3VhcmFudGVlIHRoYXQgdGhlIERPTSBub2RlIGlzIGluIHRoZSBkb2N1bWVudC5cbiAgICpcbiAgICogVXNlIHRoaXMgYXMgYW4gb3Bwb3J0dW5pdHkgdG8gb3BlcmF0ZSBvbiB0aGUgRE9NIHdoZW4gdGhlIGNvbXBvbmVudCBoYXNcbiAgICogYmVlbiBtb3VudGVkIChpbml0aWFsaXplZCBhbmQgcmVuZGVyZWQpIGZvciB0aGUgZmlyc3QgdGltZS5cbiAgICpcbiAgICogQHBhcmFtIHtET01FbGVtZW50fSByb290Tm9kZSBET00gZWxlbWVudCByZXByZXNlbnRpbmcgdGhlIGNvbXBvbmVudC5cbiAgICogQG9wdGlvbmFsXG4gICAqL1xuICBjb21wb25lbnREaWRNb3VudDogU3BlY1BvbGljeS5ERUZJTkVfTUFOWSxcblxuICAvKipcbiAgICogSW52b2tlZCBiZWZvcmUgdGhlIGNvbXBvbmVudCByZWNlaXZlcyBuZXcgcHJvcHMuXG4gICAqXG4gICAqIFVzZSB0aGlzIGFzIGFuIG9wcG9ydHVuaXR5IHRvIHJlYWN0IHRvIGEgcHJvcCB0cmFuc2l0aW9uIGJ5IHVwZGF0aW5nIHRoZVxuICAgKiBzdGF0ZSB1c2luZyBgdGhpcy5zZXRTdGF0ZWAuIEN1cnJlbnQgcHJvcHMgYXJlIGFjY2Vzc2VkIHZpYSBgdGhpcy5wcm9wc2AuXG4gICAqXG4gICAqICAgY29tcG9uZW50V2lsbFJlY2VpdmVQcm9wczogZnVuY3Rpb24obmV4dFByb3BzLCBuZXh0Q29udGV4dCkge1xuICAgKiAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAqICAgICAgIGxpa2VzSW5jcmVhc2luZzogbmV4dFByb3BzLmxpa2VDb3VudCA+IHRoaXMucHJvcHMubGlrZUNvdW50XG4gICAqICAgICB9KTtcbiAgICogICB9XG4gICAqXG4gICAqIE5PVEU6IFRoZXJlIGlzIG5vIGVxdWl2YWxlbnQgYGNvbXBvbmVudFdpbGxSZWNlaXZlU3RhdGVgLiBBbiBpbmNvbWluZyBwcm9wXG4gICAqIHRyYW5zaXRpb24gbWF5IGNhdXNlIGEgc3RhdGUgY2hhbmdlLCBidXQgdGhlIG9wcG9zaXRlIGlzIG5vdCB0cnVlLiBJZiB5b3VcbiAgICogbmVlZCBpdCwgeW91IGFyZSBwcm9iYWJseSBsb29raW5nIGZvciBgY29tcG9uZW50V2lsbFVwZGF0ZWAuXG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBuZXh0UHJvcHNcbiAgICogQG9wdGlvbmFsXG4gICAqL1xuICBjb21wb25lbnRXaWxsUmVjZWl2ZVByb3BzOiBTcGVjUG9saWN5LkRFRklORV9NQU5ZLFxuXG4gIC8qKlxuICAgKiBJbnZva2VkIHdoaWxlIGRlY2lkaW5nIGlmIHRoZSBjb21wb25lbnQgc2hvdWxkIGJlIHVwZGF0ZWQgYXMgYSByZXN1bHQgb2ZcbiAgICogcmVjZWl2aW5nIG5ldyBwcm9wcywgc3RhdGUgYW5kL29yIGNvbnRleHQuXG4gICAqXG4gICAqIFVzZSB0aGlzIGFzIGFuIG9wcG9ydHVuaXR5IHRvIGByZXR1cm4gZmFsc2VgIHdoZW4geW91J3JlIGNlcnRhaW4gdGhhdCB0aGVcbiAgICogdHJhbnNpdGlvbiB0byB0aGUgbmV3IHByb3BzL3N0YXRlL2NvbnRleHQgd2lsbCBub3QgcmVxdWlyZSBhIGNvbXBvbmVudFxuICAgKiB1cGRhdGUuXG4gICAqXG4gICAqICAgc2hvdWxkQ29tcG9uZW50VXBkYXRlOiBmdW5jdGlvbihuZXh0UHJvcHMsIG5leHRTdGF0ZSwgbmV4dENvbnRleHQpIHtcbiAgICogICAgIHJldHVybiAhZXF1YWwobmV4dFByb3BzLCB0aGlzLnByb3BzKSB8fFxuICAgKiAgICAgICAhZXF1YWwobmV4dFN0YXRlLCB0aGlzLnN0YXRlKSB8fFxuICAgKiAgICAgICAhZXF1YWwobmV4dENvbnRleHQsIHRoaXMuY29udGV4dCk7XG4gICAqICAgfVxuICAgKlxuICAgKiBAcGFyYW0ge29iamVjdH0gbmV4dFByb3BzXG4gICAqIEBwYXJhbSB7P29iamVjdH0gbmV4dFN0YXRlXG4gICAqIEBwYXJhbSB7P29iamVjdH0gbmV4dENvbnRleHRcbiAgICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgY29tcG9uZW50IHNob3VsZCB1cGRhdGUuXG4gICAqIEBvcHRpb25hbFxuICAgKi9cbiAgc2hvdWxkQ29tcG9uZW50VXBkYXRlOiBTcGVjUG9saWN5LkRFRklORV9PTkNFLFxuXG4gIC8qKlxuICAgKiBJbnZva2VkIHdoZW4gdGhlIGNvbXBvbmVudCBpcyBhYm91dCB0byB1cGRhdGUgZHVlIHRvIGEgdHJhbnNpdGlvbiBmcm9tXG4gICAqIGB0aGlzLnByb3BzYCwgYHRoaXMuc3RhdGVgIGFuZCBgdGhpcy5jb250ZXh0YCB0byBgbmV4dFByb3BzYCwgYG5leHRTdGF0ZWBcbiAgICogYW5kIGBuZXh0Q29udGV4dGAuXG4gICAqXG4gICAqIFVzZSB0aGlzIGFzIGFuIG9wcG9ydHVuaXR5IHRvIHBlcmZvcm0gcHJlcGFyYXRpb24gYmVmb3JlIGFuIHVwZGF0ZSBvY2N1cnMuXG4gICAqXG4gICAqIE5PVEU6IFlvdSAqKmNhbm5vdCoqIHVzZSBgdGhpcy5zZXRTdGF0ZSgpYCBpbiB0aGlzIG1ldGhvZC5cbiAgICpcbiAgICogQHBhcmFtIHtvYmplY3R9IG5leHRQcm9wc1xuICAgKiBAcGFyYW0gez9vYmplY3R9IG5leHRTdGF0ZVxuICAgKiBAcGFyYW0gez9vYmplY3R9IG5leHRDb250ZXh0XG4gICAqIEBwYXJhbSB7UmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbn0gdHJhbnNhY3Rpb25cbiAgICogQG9wdGlvbmFsXG4gICAqL1xuICBjb21wb25lbnRXaWxsVXBkYXRlOiBTcGVjUG9saWN5LkRFRklORV9NQU5ZLFxuXG4gIC8qKlxuICAgKiBJbnZva2VkIHdoZW4gdGhlIGNvbXBvbmVudCdzIERPTSByZXByZXNlbnRhdGlvbiBoYXMgYmVlbiB1cGRhdGVkLlxuICAgKlxuICAgKiBVc2UgdGhpcyBhcyBhbiBvcHBvcnR1bml0eSB0byBvcGVyYXRlIG9uIHRoZSBET00gd2hlbiB0aGUgY29tcG9uZW50IGhhc1xuICAgKiBiZWVuIHVwZGF0ZWQuXG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBwcmV2UHJvcHNcbiAgICogQHBhcmFtIHs/b2JqZWN0fSBwcmV2U3RhdGVcbiAgICogQHBhcmFtIHs/b2JqZWN0fSBwcmV2Q29udGV4dFxuICAgKiBAcGFyYW0ge0RPTUVsZW1lbnR9IHJvb3ROb2RlIERPTSBlbGVtZW50IHJlcHJlc2VudGluZyB0aGUgY29tcG9uZW50LlxuICAgKiBAb3B0aW9uYWxcbiAgICovXG4gIGNvbXBvbmVudERpZFVwZGF0ZTogU3BlY1BvbGljeS5ERUZJTkVfTUFOWSxcblxuICAvKipcbiAgICogSW52b2tlZCB3aGVuIHRoZSBjb21wb25lbnQgaXMgYWJvdXQgdG8gYmUgcmVtb3ZlZCBmcm9tIGl0cyBwYXJlbnQgYW5kIGhhdmVcbiAgICogaXRzIERPTSByZXByZXNlbnRhdGlvbiBkZXN0cm95ZWQuXG4gICAqXG4gICAqIFVzZSB0aGlzIGFzIGFuIG9wcG9ydHVuaXR5IHRvIGRlYWxsb2NhdGUgYW55IGV4dGVybmFsIHJlc291cmNlcy5cbiAgICpcbiAgICogTk9URTogVGhlcmUgaXMgbm8gYGNvbXBvbmVudERpZFVubW91bnRgIHNpbmNlIHlvdXIgY29tcG9uZW50IHdpbGwgaGF2ZSBiZWVuXG4gICAqIGRlc3Ryb3llZCBieSB0aGF0IHBvaW50LlxuICAgKlxuICAgKiBAb3B0aW9uYWxcbiAgICovXG4gIGNvbXBvbmVudFdpbGxVbm1vdW50OiBTcGVjUG9saWN5LkRFRklORV9NQU5ZLFxuXG5cblxuICAvLyA9PT09IEFkdmFuY2VkIG1ldGhvZHMgPT09PVxuXG4gIC8qKlxuICAgKiBVcGRhdGVzIHRoZSBjb21wb25lbnQncyBjdXJyZW50bHkgbW91bnRlZCBET00gcmVwcmVzZW50YXRpb24uXG4gICAqXG4gICAqIEJ5IGRlZmF1bHQsIHRoaXMgaW1wbGVtZW50cyBSZWFjdCdzIHJlbmRlcmluZyBhbmQgcmVjb25jaWxpYXRpb24gYWxnb3JpdGhtLlxuICAgKiBTb3BoaXN0aWNhdGVkIGNsaWVudHMgbWF5IHdpc2ggdG8gb3ZlcnJpZGUgdGhpcy5cbiAgICpcbiAgICogQHBhcmFtIHtSZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9ufSB0cmFuc2FjdGlvblxuICAgKiBAaW50ZXJuYWxcbiAgICogQG92ZXJyaWRhYmxlXG4gICAqL1xuICB1cGRhdGVDb21wb25lbnQ6IFNwZWNQb2xpY3kuT1ZFUlJJREVfQkFTRVxuXG59O1xuXG4vKipcbiAqIE1hcHBpbmcgZnJvbSBjbGFzcyBzcGVjaWZpY2F0aW9uIGtleXMgdG8gc3BlY2lhbCBwcm9jZXNzaW5nIGZ1bmN0aW9ucy5cbiAqXG4gKiBBbHRob3VnaCB0aGVzZSBhcmUgZGVjbGFyZWQgbGlrZSBpbnN0YW5jZSBwcm9wZXJ0aWVzIGluIHRoZSBzcGVjaWZpY2F0aW9uXG4gKiB3aGVuIGRlZmluaW5nIGNsYXNzZXMgdXNpbmcgYFJlYWN0LmNyZWF0ZUNsYXNzYCwgdGhleSBhcmUgYWN0dWFsbHkgc3RhdGljXG4gKiBhbmQgYXJlIGFjY2Vzc2libGUgb24gdGhlIGNvbnN0cnVjdG9yIGluc3RlYWQgb2YgdGhlIHByb3RvdHlwZS4gRGVzcGl0ZVxuICogYmVpbmcgc3RhdGljLCB0aGV5IG11c3QgYmUgZGVmaW5lZCBvdXRzaWRlIG9mIHRoZSBcInN0YXRpY3NcIiBrZXkgdW5kZXJcbiAqIHdoaWNoIGFsbCBvdGhlciBzdGF0aWMgbWV0aG9kcyBhcmUgZGVmaW5lZC5cbiAqL1xudmFyIFJFU0VSVkVEX1NQRUNfS0VZUyA9IHtcbiAgZGlzcGxheU5hbWU6IGZ1bmN0aW9uKENvbnN0cnVjdG9yLCBkaXNwbGF5TmFtZSkge1xuICAgIENvbnN0cnVjdG9yLmRpc3BsYXlOYW1lID0gZGlzcGxheU5hbWU7XG4gIH0sXG4gIG1peGluczogZnVuY3Rpb24oQ29uc3RydWN0b3IsIG1peGlucykge1xuICAgIGlmIChtaXhpbnMpIHtcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbWl4aW5zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIG1peFNwZWNJbnRvQ29tcG9uZW50KENvbnN0cnVjdG9yLCBtaXhpbnNbaV0pO1xuICAgICAgfVxuICAgIH1cbiAgfSxcbiAgY2hpbGRDb250ZXh0VHlwZXM6IGZ1bmN0aW9uKENvbnN0cnVjdG9yLCBjaGlsZENvbnRleHRUeXBlcykge1xuICAgIHZhbGlkYXRlVHlwZURlZihcbiAgICAgIENvbnN0cnVjdG9yLFxuICAgICAgY2hpbGRDb250ZXh0VHlwZXMsXG4gICAgICBSZWFjdFByb3BUeXBlTG9jYXRpb25zLmNoaWxkQ29udGV4dFxuICAgICk7XG4gICAgQ29uc3RydWN0b3IuY2hpbGRDb250ZXh0VHlwZXMgPSBhc3NpZ24oXG4gICAgICB7fSxcbiAgICAgIENvbnN0cnVjdG9yLmNoaWxkQ29udGV4dFR5cGVzLFxuICAgICAgY2hpbGRDb250ZXh0VHlwZXNcbiAgICApO1xuICB9LFxuICBjb250ZXh0VHlwZXM6IGZ1bmN0aW9uKENvbnN0cnVjdG9yLCBjb250ZXh0VHlwZXMpIHtcbiAgICB2YWxpZGF0ZVR5cGVEZWYoXG4gICAgICBDb25zdHJ1Y3RvcixcbiAgICAgIGNvbnRleHRUeXBlcyxcbiAgICAgIFJlYWN0UHJvcFR5cGVMb2NhdGlvbnMuY29udGV4dFxuICAgICk7XG4gICAgQ29uc3RydWN0b3IuY29udGV4dFR5cGVzID0gYXNzaWduKFxuICAgICAge30sXG4gICAgICBDb25zdHJ1Y3Rvci5jb250ZXh0VHlwZXMsXG4gICAgICBjb250ZXh0VHlwZXNcbiAgICApO1xuICB9LFxuICAvKipcbiAgICogU3BlY2lhbCBjYXNlIGdldERlZmF1bHRQcm9wcyB3aGljaCBzaG91bGQgbW92ZSBpbnRvIHN0YXRpY3MgYnV0IHJlcXVpcmVzXG4gICAqIGF1dG9tYXRpYyBtZXJnaW5nLlxuICAgKi9cbiAgZ2V0RGVmYXVsdFByb3BzOiBmdW5jdGlvbihDb25zdHJ1Y3RvciwgZ2V0RGVmYXVsdFByb3BzKSB7XG4gICAgaWYgKENvbnN0cnVjdG9yLmdldERlZmF1bHRQcm9wcykge1xuICAgICAgQ29uc3RydWN0b3IuZ2V0RGVmYXVsdFByb3BzID0gY3JlYXRlTWVyZ2VkUmVzdWx0RnVuY3Rpb24oXG4gICAgICAgIENvbnN0cnVjdG9yLmdldERlZmF1bHRQcm9wcyxcbiAgICAgICAgZ2V0RGVmYXVsdFByb3BzXG4gICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICBDb25zdHJ1Y3Rvci5nZXREZWZhdWx0UHJvcHMgPSBnZXREZWZhdWx0UHJvcHM7XG4gICAgfVxuICB9LFxuICBwcm9wVHlwZXM6IGZ1bmN0aW9uKENvbnN0cnVjdG9yLCBwcm9wVHlwZXMpIHtcbiAgICB2YWxpZGF0ZVR5cGVEZWYoXG4gICAgICBDb25zdHJ1Y3RvcixcbiAgICAgIHByb3BUeXBlcyxcbiAgICAgIFJlYWN0UHJvcFR5cGVMb2NhdGlvbnMucHJvcFxuICAgICk7XG4gICAgQ29uc3RydWN0b3IucHJvcFR5cGVzID0gYXNzaWduKFxuICAgICAge30sXG4gICAgICBDb25zdHJ1Y3Rvci5wcm9wVHlwZXMsXG4gICAgICBwcm9wVHlwZXNcbiAgICApO1xuICB9LFxuICBzdGF0aWNzOiBmdW5jdGlvbihDb25zdHJ1Y3Rvciwgc3RhdGljcykge1xuICAgIG1peFN0YXRpY1NwZWNJbnRvQ29tcG9uZW50KENvbnN0cnVjdG9yLCBzdGF0aWNzKTtcbiAgfVxufTtcblxuZnVuY3Rpb24gZ2V0RGVjbGFyYXRpb25FcnJvckFkZGVuZHVtKGNvbXBvbmVudCkge1xuICB2YXIgb3duZXIgPSBjb21wb25lbnQuX293bmVyIHx8IG51bGw7XG4gIGlmIChvd25lciAmJiBvd25lci5jb25zdHJ1Y3RvciAmJiBvd25lci5jb25zdHJ1Y3Rvci5kaXNwbGF5TmFtZSkge1xuICAgIHJldHVybiAnIENoZWNrIHRoZSByZW5kZXIgbWV0aG9kIG9mIGAnICsgb3duZXIuY29uc3RydWN0b3IuZGlzcGxheU5hbWUgK1xuICAgICAgJ2AuJztcbiAgfVxuICByZXR1cm4gJyc7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlVHlwZURlZihDb25zdHJ1Y3RvciwgdHlwZURlZiwgbG9jYXRpb24pIHtcbiAgZm9yICh2YXIgcHJvcE5hbWUgaW4gdHlwZURlZikge1xuICAgIGlmICh0eXBlRGVmLmhhc093blByb3BlcnR5KHByb3BOYW1lKSkge1xuICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgdHlwZW9mIHR5cGVEZWZbcHJvcE5hbWVdID09ICdmdW5jdGlvbicsXG4gICAgICAgICclczogJXMgdHlwZSBgJXNgIGlzIGludmFsaWQ7IGl0IG11c3QgYmUgYSBmdW5jdGlvbiwgdXN1YWxseSBmcm9tICcgK1xuICAgICAgICAnUmVhY3QuUHJvcFR5cGVzLicsXG4gICAgICAgIENvbnN0cnVjdG9yLmRpc3BsYXlOYW1lIHx8ICdSZWFjdENvbXBvc2l0ZUNvbXBvbmVudCcsXG4gICAgICAgIFJlYWN0UHJvcFR5cGVMb2NhdGlvbk5hbWVzW2xvY2F0aW9uXSxcbiAgICAgICAgcHJvcE5hbWVcbiAgICAgICkgOiBpbnZhcmlhbnQodHlwZW9mIHR5cGVEZWZbcHJvcE5hbWVdID09ICdmdW5jdGlvbicpKTtcbiAgICB9XG4gIH1cbn1cblxuZnVuY3Rpb24gdmFsaWRhdGVNZXRob2RPdmVycmlkZShwcm90bywgbmFtZSkge1xuICB2YXIgc3BlY1BvbGljeSA9IFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50SW50ZXJmYWNlLmhhc093blByb3BlcnR5KG5hbWUpID9cbiAgICBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudEludGVyZmFjZVtuYW1lXSA6XG4gICAgbnVsbDtcblxuICAvLyBEaXNhbGxvdyBvdmVycmlkaW5nIG9mIGJhc2UgY2xhc3MgbWV0aG9kcyB1bmxlc3MgZXhwbGljaXRseSBhbGxvd2VkLlxuICBpZiAoUmVhY3RDb21wb3NpdGVDb21wb25lbnRNaXhpbi5oYXNPd25Qcm9wZXJ0eShuYW1lKSkge1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICBzcGVjUG9saWN5ID09PSBTcGVjUG9saWN5Lk9WRVJSSURFX0JBU0UsXG4gICAgICAnUmVhY3RDb21wb3NpdGVDb21wb25lbnRJbnRlcmZhY2U6IFlvdSBhcmUgYXR0ZW1wdGluZyB0byBvdmVycmlkZSAnICtcbiAgICAgICdgJXNgIGZyb20geW91ciBjbGFzcyBzcGVjaWZpY2F0aW9uLiBFbnN1cmUgdGhhdCB5b3VyIG1ldGhvZCBuYW1lcyAnICtcbiAgICAgICdkbyBub3Qgb3ZlcmxhcCB3aXRoIFJlYWN0IG1ldGhvZHMuJyxcbiAgICAgIG5hbWVcbiAgICApIDogaW52YXJpYW50KHNwZWNQb2xpY3kgPT09IFNwZWNQb2xpY3kuT1ZFUlJJREVfQkFTRSkpO1xuICB9XG5cbiAgLy8gRGlzYWxsb3cgZGVmaW5pbmcgbWV0aG9kcyBtb3JlIHRoYW4gb25jZSB1bmxlc3MgZXhwbGljaXRseSBhbGxvd2VkLlxuICBpZiAocHJvdG8uaGFzT3duUHJvcGVydHkobmFtZSkpIHtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgc3BlY1BvbGljeSA9PT0gU3BlY1BvbGljeS5ERUZJTkVfTUFOWSB8fFxuICAgICAgc3BlY1BvbGljeSA9PT0gU3BlY1BvbGljeS5ERUZJTkVfTUFOWV9NRVJHRUQsXG4gICAgICAnUmVhY3RDb21wb3NpdGVDb21wb25lbnRJbnRlcmZhY2U6IFlvdSBhcmUgYXR0ZW1wdGluZyB0byBkZWZpbmUgJyArXG4gICAgICAnYCVzYCBvbiB5b3VyIGNvbXBvbmVudCBtb3JlIHRoYW4gb25jZS4gVGhpcyBjb25mbGljdCBtYXkgYmUgZHVlICcgK1xuICAgICAgJ3RvIGEgbWl4aW4uJyxcbiAgICAgIG5hbWVcbiAgICApIDogaW52YXJpYW50KHNwZWNQb2xpY3kgPT09IFNwZWNQb2xpY3kuREVGSU5FX01BTlkgfHxcbiAgICBzcGVjUG9saWN5ID09PSBTcGVjUG9saWN5LkRFRklORV9NQU5ZX01FUkdFRCkpO1xuICB9XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlTGlmZUN5Y2xlT25SZXBsYWNlU3RhdGUoaW5zdGFuY2UpIHtcbiAgdmFyIGNvbXBvc2l0ZUxpZmVDeWNsZVN0YXRlID0gaW5zdGFuY2UuX2NvbXBvc2l0ZUxpZmVDeWNsZVN0YXRlO1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgIGluc3RhbmNlLmlzTW91bnRlZCgpIHx8XG4gICAgICBjb21wb3NpdGVMaWZlQ3ljbGVTdGF0ZSA9PT0gQ29tcG9zaXRlTGlmZUN5Y2xlLk1PVU5USU5HLFxuICAgICdyZXBsYWNlU3RhdGUoLi4uKTogQ2FuIG9ubHkgdXBkYXRlIGEgbW91bnRlZCBvciBtb3VudGluZyBjb21wb25lbnQuJ1xuICApIDogaW52YXJpYW50KGluc3RhbmNlLmlzTW91bnRlZCgpIHx8XG4gICAgY29tcG9zaXRlTGlmZUN5Y2xlU3RhdGUgPT09IENvbXBvc2l0ZUxpZmVDeWNsZS5NT1VOVElORykpO1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgIFJlYWN0Q3VycmVudE93bmVyLmN1cnJlbnQgPT0gbnVsbCxcbiAgICAncmVwbGFjZVN0YXRlKC4uLik6IENhbm5vdCB1cGRhdGUgZHVyaW5nIGFuIGV4aXN0aW5nIHN0YXRlIHRyYW5zaXRpb24gJyArXG4gICAgJyhzdWNoIGFzIHdpdGhpbiBgcmVuZGVyYCkuIFJlbmRlciBtZXRob2RzIHNob3VsZCBiZSBhIHB1cmUgZnVuY3Rpb24gJyArXG4gICAgJ29mIHByb3BzIGFuZCBzdGF0ZS4nXG4gICkgOiBpbnZhcmlhbnQoUmVhY3RDdXJyZW50T3duZXIuY3VycmVudCA9PSBudWxsKSk7XG4gIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoY29tcG9zaXRlTGlmZUN5Y2xlU3RhdGUgIT09IENvbXBvc2l0ZUxpZmVDeWNsZS5VTk1PVU5USU5HLFxuICAgICdyZXBsYWNlU3RhdGUoLi4uKTogQ2Fubm90IHVwZGF0ZSB3aGlsZSB1bm1vdW50aW5nIGNvbXBvbmVudC4gVGhpcyAnICtcbiAgICAndXN1YWxseSBtZWFucyB5b3UgY2FsbGVkIHNldFN0YXRlKCkgb24gYW4gdW5tb3VudGVkIGNvbXBvbmVudC4nXG4gICkgOiBpbnZhcmlhbnQoY29tcG9zaXRlTGlmZUN5Y2xlU3RhdGUgIT09IENvbXBvc2l0ZUxpZmVDeWNsZS5VTk1PVU5USU5HKSk7XG59XG5cbi8qKlxuICogTWl4aW4gaGVscGVyIHdoaWNoIGhhbmRsZXMgcG9saWN5IHZhbGlkYXRpb24gYW5kIHJlc2VydmVkXG4gKiBzcGVjaWZpY2F0aW9uIGtleXMgd2hlbiBidWlsZGluZyBgUmVhY3RDb21wb3NpdGVDb21wb25lbnRgIGNsYXNzc2VzLlxuICovXG5mdW5jdGlvbiBtaXhTcGVjSW50b0NvbXBvbmVudChDb25zdHJ1Y3Rvciwgc3BlYykge1xuICBpZiAoIXNwZWMpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICFSZWFjdExlZ2FjeUVsZW1lbnQuaXNWYWxpZEZhY3Rvcnkoc3BlYyksXG4gICAgJ1JlYWN0Q29tcG9zaXRlQ29tcG9uZW50OiBZb3VcXCdyZSBhdHRlbXB0aW5nIHRvICcgK1xuICAgICd1c2UgYSBjb21wb25lbnQgY2xhc3MgYXMgYSBtaXhpbi4gSW5zdGVhZCwganVzdCB1c2UgYSByZWd1bGFyIG9iamVjdC4nXG4gICkgOiBpbnZhcmlhbnQoIVJlYWN0TGVnYWN5RWxlbWVudC5pc1ZhbGlkRmFjdG9yeShzcGVjKSkpO1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICFSZWFjdEVsZW1lbnQuaXNWYWxpZEVsZW1lbnQoc3BlYyksXG4gICAgJ1JlYWN0Q29tcG9zaXRlQ29tcG9uZW50OiBZb3VcXCdyZSBhdHRlbXB0aW5nIHRvICcgK1xuICAgICd1c2UgYSBjb21wb25lbnQgYXMgYSBtaXhpbi4gSW5zdGVhZCwganVzdCB1c2UgYSByZWd1bGFyIG9iamVjdC4nXG4gICkgOiBpbnZhcmlhbnQoIVJlYWN0RWxlbWVudC5pc1ZhbGlkRWxlbWVudChzcGVjKSkpO1xuXG4gIHZhciBwcm90byA9IENvbnN0cnVjdG9yLnByb3RvdHlwZTtcblxuICAvLyBCeSBoYW5kbGluZyBtaXhpbnMgYmVmb3JlIGFueSBvdGhlciBwcm9wZXJ0aWVzLCB3ZSBlbnN1cmUgdGhlIHNhbWVcbiAgLy8gY2hhaW5pbmcgb3JkZXIgaXMgYXBwbGllZCB0byBtZXRob2RzIHdpdGggREVGSU5FX01BTlkgcG9saWN5LCB3aGV0aGVyXG4gIC8vIG1peGlucyBhcmUgbGlzdGVkIGJlZm9yZSBvciBhZnRlciB0aGVzZSBtZXRob2RzIGluIHRoZSBzcGVjLlxuICBpZiAoc3BlYy5oYXNPd25Qcm9wZXJ0eShNSVhJTlNfS0VZKSkge1xuICAgIFJFU0VSVkVEX1NQRUNfS0VZUy5taXhpbnMoQ29uc3RydWN0b3IsIHNwZWMubWl4aW5zKTtcbiAgfVxuXG4gIGZvciAodmFyIG5hbWUgaW4gc3BlYykge1xuICAgIGlmICghc3BlYy5oYXNPd25Qcm9wZXJ0eShuYW1lKSkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgaWYgKG5hbWUgPT09IE1JWElOU19LRVkpIHtcbiAgICAgIC8vIFdlIGhhdmUgYWxyZWFkeSBoYW5kbGVkIG1peGlucyBpbiBhIHNwZWNpYWwgY2FzZSBhYm92ZVxuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgdmFyIHByb3BlcnR5ID0gc3BlY1tuYW1lXTtcbiAgICB2YWxpZGF0ZU1ldGhvZE92ZXJyaWRlKHByb3RvLCBuYW1lKTtcblxuICAgIGlmIChSRVNFUlZFRF9TUEVDX0tFWVMuaGFzT3duUHJvcGVydHkobmFtZSkpIHtcbiAgICAgIFJFU0VSVkVEX1NQRUNfS0VZU1tuYW1lXShDb25zdHJ1Y3RvciwgcHJvcGVydHkpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBTZXR1cCBtZXRob2RzIG9uIHByb3RvdHlwZTpcbiAgICAgIC8vIFRoZSBmb2xsb3dpbmcgbWVtYmVyIG1ldGhvZHMgc2hvdWxkIG5vdCBiZSBhdXRvbWF0aWNhbGx5IGJvdW5kOlxuICAgICAgLy8gMS4gRXhwZWN0ZWQgUmVhY3RDb21wb3NpdGVDb21wb25lbnQgbWV0aG9kcyAoaW4gdGhlIFwiaW50ZXJmYWNlXCIpLlxuICAgICAgLy8gMi4gT3ZlcnJpZGRlbiBtZXRob2RzICh0aGF0IHdlcmUgbWl4ZWQgaW4pLlxuICAgICAgdmFyIGlzQ29tcG9zaXRlQ29tcG9uZW50TWV0aG9kID1cbiAgICAgICAgUmVhY3RDb21wb3NpdGVDb21wb25lbnRJbnRlcmZhY2UuaGFzT3duUHJvcGVydHkobmFtZSk7XG4gICAgICB2YXIgaXNBbHJlYWR5RGVmaW5lZCA9IHByb3RvLmhhc093blByb3BlcnR5KG5hbWUpO1xuICAgICAgdmFyIG1hcmtlZERvbnRCaW5kID0gcHJvcGVydHkgJiYgcHJvcGVydHkuX19yZWFjdERvbnRCaW5kO1xuICAgICAgdmFyIGlzRnVuY3Rpb24gPSB0eXBlb2YgcHJvcGVydHkgPT09ICdmdW5jdGlvbic7XG4gICAgICB2YXIgc2hvdWxkQXV0b0JpbmQgPVxuICAgICAgICBpc0Z1bmN0aW9uICYmXG4gICAgICAgICFpc0NvbXBvc2l0ZUNvbXBvbmVudE1ldGhvZCAmJlxuICAgICAgICAhaXNBbHJlYWR5RGVmaW5lZCAmJlxuICAgICAgICAhbWFya2VkRG9udEJpbmQ7XG5cbiAgICAgIGlmIChzaG91bGRBdXRvQmluZCkge1xuICAgICAgICBpZiAoIXByb3RvLl9fcmVhY3RBdXRvQmluZE1hcCkge1xuICAgICAgICAgIHByb3RvLl9fcmVhY3RBdXRvQmluZE1hcCA9IHt9O1xuICAgICAgICB9XG4gICAgICAgIHByb3RvLl9fcmVhY3RBdXRvQmluZE1hcFtuYW1lXSA9IHByb3BlcnR5O1xuICAgICAgICBwcm90b1tuYW1lXSA9IHByb3BlcnR5O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKGlzQWxyZWFkeURlZmluZWQpIHtcbiAgICAgICAgICB2YXIgc3BlY1BvbGljeSA9IFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50SW50ZXJmYWNlW25hbWVdO1xuXG4gICAgICAgICAgLy8gVGhlc2UgY2FzZXMgc2hvdWxkIGFscmVhZHkgYmUgY2F1Z2h0IGJ5IHZhbGlkYXRlTWV0aG9kT3ZlcnJpZGVcbiAgICAgICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICAgICAgaXNDb21wb3NpdGVDb21wb25lbnRNZXRob2QgJiYgKFxuICAgICAgICAgICAgICBzcGVjUG9saWN5ID09PSBTcGVjUG9saWN5LkRFRklORV9NQU5ZX01FUkdFRCB8fFxuICAgICAgICAgICAgICBzcGVjUG9saWN5ID09PSBTcGVjUG9saWN5LkRFRklORV9NQU5ZXG4gICAgICAgICAgICApLFxuICAgICAgICAgICAgJ1JlYWN0Q29tcG9zaXRlQ29tcG9uZW50OiBVbmV4cGVjdGVkIHNwZWMgcG9saWN5ICVzIGZvciBrZXkgJXMgJyArXG4gICAgICAgICAgICAnd2hlbiBtaXhpbmcgaW4gY29tcG9uZW50IHNwZWNzLicsXG4gICAgICAgICAgICBzcGVjUG9saWN5LFxuICAgICAgICAgICAgbmFtZVxuICAgICAgICAgICkgOiBpbnZhcmlhbnQoaXNDb21wb3NpdGVDb21wb25lbnRNZXRob2QgJiYgKFxuICAgICAgICAgICAgc3BlY1BvbGljeSA9PT0gU3BlY1BvbGljeS5ERUZJTkVfTUFOWV9NRVJHRUQgfHxcbiAgICAgICAgICAgIHNwZWNQb2xpY3kgPT09IFNwZWNQb2xpY3kuREVGSU5FX01BTllcbiAgICAgICAgICApKSk7XG5cbiAgICAgICAgICAvLyBGb3IgbWV0aG9kcyB3aGljaCBhcmUgZGVmaW5lZCBtb3JlIHRoYW4gb25jZSwgY2FsbCB0aGUgZXhpc3RpbmdcbiAgICAgICAgICAvLyBtZXRob2RzIGJlZm9yZSBjYWxsaW5nIHRoZSBuZXcgcHJvcGVydHksIG1lcmdpbmcgaWYgYXBwcm9wcmlhdGUuXG4gICAgICAgICAgaWYgKHNwZWNQb2xpY3kgPT09IFNwZWNQb2xpY3kuREVGSU5FX01BTllfTUVSR0VEKSB7XG4gICAgICAgICAgICBwcm90b1tuYW1lXSA9IGNyZWF0ZU1lcmdlZFJlc3VsdEZ1bmN0aW9uKHByb3RvW25hbWVdLCBwcm9wZXJ0eSk7XG4gICAgICAgICAgfSBlbHNlIGlmIChzcGVjUG9saWN5ID09PSBTcGVjUG9saWN5LkRFRklORV9NQU5ZKSB7XG4gICAgICAgICAgICBwcm90b1tuYW1lXSA9IGNyZWF0ZUNoYWluZWRGdW5jdGlvbihwcm90b1tuYW1lXSwgcHJvcGVydHkpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBwcm90b1tuYW1lXSA9IHByb3BlcnR5O1xuICAgICAgICAgIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgICAgICAgIC8vIEFkZCB2ZXJib3NlIGRpc3BsYXlOYW1lIHRvIHRoZSBmdW5jdGlvbiwgd2hpY2ggaGVscHMgd2hlbiBsb29raW5nXG4gICAgICAgICAgICAvLyBhdCBwcm9maWxpbmcgdG9vbHMuXG4gICAgICAgICAgICBpZiAodHlwZW9mIHByb3BlcnR5ID09PSAnZnVuY3Rpb24nICYmIHNwZWMuZGlzcGxheU5hbWUpIHtcbiAgICAgICAgICAgICAgcHJvdG9bbmFtZV0uZGlzcGxheU5hbWUgPSBzcGVjLmRpc3BsYXlOYW1lICsgJ18nICsgbmFtZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuZnVuY3Rpb24gbWl4U3RhdGljU3BlY0ludG9Db21wb25lbnQoQ29uc3RydWN0b3IsIHN0YXRpY3MpIHtcbiAgaWYgKCFzdGF0aWNzKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIGZvciAodmFyIG5hbWUgaW4gc3RhdGljcykge1xuICAgIHZhciBwcm9wZXJ0eSA9IHN0YXRpY3NbbmFtZV07XG4gICAgaWYgKCFzdGF0aWNzLmhhc093blByb3BlcnR5KG5hbWUpKSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICB2YXIgaXNSZXNlcnZlZCA9IG5hbWUgaW4gUkVTRVJWRURfU1BFQ19LRVlTO1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAhaXNSZXNlcnZlZCxcbiAgICAgICdSZWFjdENvbXBvc2l0ZUNvbXBvbmVudDogWW91IGFyZSBhdHRlbXB0aW5nIHRvIGRlZmluZSBhIHJlc2VydmVkICcgK1xuICAgICAgJ3Byb3BlcnR5LCBgJXNgLCB0aGF0IHNob3VsZG5cXCd0IGJlIG9uIHRoZSBcInN0YXRpY3NcIiBrZXkuIERlZmluZSBpdCAnICtcbiAgICAgICdhcyBhbiBpbnN0YW5jZSBwcm9wZXJ0eSBpbnN0ZWFkOyBpdCB3aWxsIHN0aWxsIGJlIGFjY2Vzc2libGUgb24gdGhlICcgK1xuICAgICAgJ2NvbnN0cnVjdG9yLicsXG4gICAgICBuYW1lXG4gICAgKSA6IGludmFyaWFudCghaXNSZXNlcnZlZCkpO1xuXG4gICAgdmFyIGlzSW5oZXJpdGVkID0gbmFtZSBpbiBDb25zdHJ1Y3RvcjtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgIWlzSW5oZXJpdGVkLFxuICAgICAgJ1JlYWN0Q29tcG9zaXRlQ29tcG9uZW50OiBZb3UgYXJlIGF0dGVtcHRpbmcgdG8gZGVmaW5lICcgK1xuICAgICAgJ2Alc2Agb24geW91ciBjb21wb25lbnQgbW9yZSB0aGFuIG9uY2UuIFRoaXMgY29uZmxpY3QgbWF5IGJlICcgK1xuICAgICAgJ2R1ZSB0byBhIG1peGluLicsXG4gICAgICBuYW1lXG4gICAgKSA6IGludmFyaWFudCghaXNJbmhlcml0ZWQpKTtcbiAgICBDb25zdHJ1Y3RvcltuYW1lXSA9IHByb3BlcnR5O1xuICB9XG59XG5cbi8qKlxuICogTWVyZ2UgdHdvIG9iamVjdHMsIGJ1dCB0aHJvdyBpZiBib3RoIGNvbnRhaW4gdGhlIHNhbWUga2V5LlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBvbmUgVGhlIGZpcnN0IG9iamVjdCwgd2hpY2ggaXMgbXV0YXRlZC5cbiAqIEBwYXJhbSB7b2JqZWN0fSB0d28gVGhlIHNlY29uZCBvYmplY3RcbiAqIEByZXR1cm4ge29iamVjdH0gb25lIGFmdGVyIGl0IGhhcyBiZWVuIG11dGF0ZWQgdG8gY29udGFpbiBldmVyeXRoaW5nIGluIHR3by5cbiAqL1xuZnVuY3Rpb24gbWVyZ2VPYmplY3RzV2l0aE5vRHVwbGljYXRlS2V5cyhvbmUsIHR3bykge1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgIG9uZSAmJiB0d28gJiYgdHlwZW9mIG9uZSA9PT0gJ29iamVjdCcgJiYgdHlwZW9mIHR3byA9PT0gJ29iamVjdCcsXG4gICAgJ21lcmdlT2JqZWN0c1dpdGhOb0R1cGxpY2F0ZUtleXMoKTogQ2Fubm90IG1lcmdlIG5vbi1vYmplY3RzJ1xuICApIDogaW52YXJpYW50KG9uZSAmJiB0d28gJiYgdHlwZW9mIG9uZSA9PT0gJ29iamVjdCcgJiYgdHlwZW9mIHR3byA9PT0gJ29iamVjdCcpKTtcblxuICBtYXBPYmplY3QodHdvLCBmdW5jdGlvbih2YWx1ZSwga2V5KSB7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgIG9uZVtrZXldID09PSB1bmRlZmluZWQsXG4gICAgICAnbWVyZ2VPYmplY3RzV2l0aE5vRHVwbGljYXRlS2V5cygpOiAnICtcbiAgICAgICdUcmllZCB0byBtZXJnZSB0d28gb2JqZWN0cyB3aXRoIHRoZSBzYW1lIGtleTogYCVzYC4gVGhpcyBjb25mbGljdCAnICtcbiAgICAgICdtYXkgYmUgZHVlIHRvIGEgbWl4aW47IGluIHBhcnRpY3VsYXIsIHRoaXMgbWF5IGJlIGNhdXNlZCBieSB0d28gJyArXG4gICAgICAnZ2V0SW5pdGlhbFN0YXRlKCkgb3IgZ2V0RGVmYXVsdFByb3BzKCkgbWV0aG9kcyByZXR1cm5pbmcgb2JqZWN0cyAnICtcbiAgICAgICd3aXRoIGNsYXNoaW5nIGtleXMuJyxcbiAgICAgIGtleVxuICAgICkgOiBpbnZhcmlhbnQob25lW2tleV0gPT09IHVuZGVmaW5lZCkpO1xuICAgIG9uZVtrZXldID0gdmFsdWU7XG4gIH0pO1xuICByZXR1cm4gb25lO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBmdW5jdGlvbiB0aGF0IGludm9rZXMgdHdvIGZ1bmN0aW9ucyBhbmQgbWVyZ2VzIHRoZWlyIHJldHVybiB2YWx1ZXMuXG4gKlxuICogQHBhcmFtIHtmdW5jdGlvbn0gb25lIEZ1bmN0aW9uIHRvIGludm9rZSBmaXJzdC5cbiAqIEBwYXJhbSB7ZnVuY3Rpb259IHR3byBGdW5jdGlvbiB0byBpbnZva2Ugc2Vjb25kLlxuICogQHJldHVybiB7ZnVuY3Rpb259IEZ1bmN0aW9uIHRoYXQgaW52b2tlcyB0aGUgdHdvIGFyZ3VtZW50IGZ1bmN0aW9ucy5cbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZU1lcmdlZFJlc3VsdEZ1bmN0aW9uKG9uZSwgdHdvKSB7XG4gIHJldHVybiBmdW5jdGlvbiBtZXJnZWRSZXN1bHQoKSB7XG4gICAgdmFyIGEgPSBvbmUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB2YXIgYiA9IHR3by5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIGlmIChhID09IG51bGwpIHtcbiAgICAgIHJldHVybiBiO1xuICAgIH0gZWxzZSBpZiAoYiA9PSBudWxsKSB7XG4gICAgICByZXR1cm4gYTtcbiAgICB9XG4gICAgcmV0dXJuIG1lcmdlT2JqZWN0c1dpdGhOb0R1cGxpY2F0ZUtleXMoYSwgYik7XG4gIH07XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIGZ1bmN0aW9uIHRoYXQgaW52b2tlcyB0d28gZnVuY3Rpb25zIGFuZCBpZ25vcmVzIHRoZWlyIHJldHVybiB2YWxlcy5cbiAqXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBvbmUgRnVuY3Rpb24gdG8gaW52b2tlIGZpcnN0LlxuICogQHBhcmFtIHtmdW5jdGlvbn0gdHdvIEZ1bmN0aW9uIHRvIGludm9rZSBzZWNvbmQuXG4gKiBAcmV0dXJuIHtmdW5jdGlvbn0gRnVuY3Rpb24gdGhhdCBpbnZva2VzIHRoZSB0d28gYXJndW1lbnQgZnVuY3Rpb25zLlxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gY3JlYXRlQ2hhaW5lZEZ1bmN0aW9uKG9uZSwgdHdvKSB7XG4gIHJldHVybiBmdW5jdGlvbiBjaGFpbmVkRnVuY3Rpb24oKSB7XG4gICAgb25lLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgdHdvLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gIH07XG59XG5cbi8qKlxuICogYFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50YCBtYWludGFpbnMgYW4gYXV4aWxpYXJ5IGxpZmUgY3ljbGUgc3RhdGUgaW5cbiAqIGB0aGlzLl9jb21wb3NpdGVMaWZlQ3ljbGVTdGF0ZWAgKHdoaWNoIGNhbiBiZSBudWxsKS5cbiAqXG4gKiBUaGlzIGlzIGRpZmZlcmVudCBmcm9tIHRoZSBsaWZlIGN5Y2xlIHN0YXRlIG1haW50YWluZWQgYnkgYFJlYWN0Q29tcG9uZW50YCBpblxuICogYHRoaXMuX2xpZmVDeWNsZVN0YXRlYC4gVGhlIGZvbGxvd2luZyBkaWFncmFtIHNob3dzIGhvdyB0aGUgc3RhdGVzIG92ZXJsYXAgaW5cbiAqIHRpbWUuIFRoZXJlIGFyZSB0aW1lcyB3aGVuIHRoZSBDb21wb3NpdGVMaWZlQ3ljbGUgaXMgbnVsbCAtIGF0IHRob3NlIHRpbWVzIGl0XG4gKiBpcyBvbmx5IG1lYW5pbmdmdWwgdG8gbG9vayBhdCBDb21wb25lbnRMaWZlQ3ljbGUgYWxvbmUuXG4gKlxuICogVG9wIFJvdzogUmVhY3RDb21wb25lbnQuQ29tcG9uZW50TGlmZUN5Y2xlXG4gKiBMb3cgUm93OiBSZWFjdENvbXBvbmVudC5Db21wb3NpdGVMaWZlQ3ljbGVcbiAqXG4gKiArLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0rXG4gKiB8ICBVTiAgIHwgICAgICAgICAgICAgTU9VTlRFRCAgICAgICAgICAgICB8ICAgVU4gICB8XG4gKiB8TU9VTlRFRHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IE1PVU5URUR8XG4gKiArLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0rXG4gKiB8ICAgICAgIF4tLS0tLS0tLSsgICArLS0tLS0tLSsgICArLS0tLS0tLS1eICAgICAgICB8XG4gKiB8ICAgICAgIHwgICAgICAgIHwgICB8ICAgICAgIHwgICB8ICAgICAgICB8ICAgICAgICB8XG4gKiB8ICAgIDAtLXxNT1VOVElOR3wtMC18UkVDRUlWRXwtMC18ICAgVU4gICB8LS0tPjAgICB8XG4gKiB8ICAgICAgIHwgICAgICAgIHwgICB8UFJPUFMgIHwgICB8TU9VTlRJTkd8ICAgICAgICB8XG4gKiB8ICAgICAgIHwgICAgICAgIHwgICB8ICAgICAgIHwgICB8ICAgICAgICB8ICAgICAgICB8XG4gKiB8ICAgICAgIHwgICAgICAgIHwgICB8ICAgICAgIHwgICB8ICAgICAgICB8ICAgICAgICB8XG4gKiB8ICAgICAgICstLS0tLS0tLSsgICArLS0tLS0tLSsgICArLS0tLS0tLS0rICAgICAgICB8XG4gKiB8ICAgICAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICB8XG4gKiArLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0rXG4gKi9cbnZhciBDb21wb3NpdGVMaWZlQ3ljbGUgPSBrZXlNaXJyb3Ioe1xuICAvKipcbiAgICogQ29tcG9uZW50cyBpbiB0aGUgcHJvY2VzcyBvZiBiZWluZyBtb3VudGVkIHJlc3BvbmQgdG8gc3RhdGUgY2hhbmdlc1xuICAgKiBkaWZmZXJlbnRseS5cbiAgICovXG4gIE1PVU5USU5HOiBudWxsLFxuICAvKipcbiAgICogQ29tcG9uZW50cyBpbiB0aGUgcHJvY2VzcyBvZiBiZWluZyB1bm1vdW50ZWQgYXJlIGd1YXJkZWQgYWdhaW5zdCBzdGF0ZVxuICAgKiBjaGFuZ2VzLlxuICAgKi9cbiAgVU5NT1VOVElORzogbnVsbCxcbiAgLyoqXG4gICAqIENvbXBvbmVudHMgdGhhdCBhcmUgbW91bnRlZCBhbmQgcmVjZWl2aW5nIG5ldyBwcm9wcyByZXNwb25kIHRvIHN0YXRlXG4gICAqIGNoYW5nZXMgZGlmZmVyZW50bHkuXG4gICAqL1xuICBSRUNFSVZJTkdfUFJPUFM6IG51bGxcbn0pO1xuXG4vKipcbiAqIEBsZW5kcyB7UmVhY3RDb21wb3NpdGVDb21wb25lbnQucHJvdG90eXBlfVxuICovXG52YXIgUmVhY3RDb21wb3NpdGVDb21wb25lbnRNaXhpbiA9IHtcblxuICAvKipcbiAgICogQmFzZSBjb25zdHJ1Y3RvciBmb3IgYWxsIGNvbXBvc2l0ZSBjb21wb25lbnQuXG4gICAqXG4gICAqIEBwYXJhbSB7UmVhY3RFbGVtZW50fSBlbGVtZW50XG4gICAqIEBmaW5hbFxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIGNvbnN0cnVjdDogZnVuY3Rpb24oZWxlbWVudCkge1xuICAgIC8vIENoaWxkcmVuIGNhbiBiZSBlaXRoZXIgYW4gYXJyYXkgb3IgbW9yZSB0aGFuIG9uZSBhcmd1bWVudFxuICAgIFJlYWN0Q29tcG9uZW50Lk1peGluLmNvbnN0cnVjdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIFJlYWN0T3duZXIuTWl4aW4uY29uc3RydWN0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cbiAgICB0aGlzLnN0YXRlID0gbnVsbDtcbiAgICB0aGlzLl9wZW5kaW5nU3RhdGUgPSBudWxsO1xuXG4gICAgLy8gVGhpcyBpcyB0aGUgcHVibGljIHBvc3QtcHJvY2Vzc2VkIGNvbnRleHQuIFRoZSByZWFsIGNvbnRleHQgYW5kIHBlbmRpbmdcbiAgICAvLyBjb250ZXh0IGxpdmVzIG9uIHRoZSBlbGVtZW50LlxuICAgIHRoaXMuY29udGV4dCA9IG51bGw7XG5cbiAgICB0aGlzLl9jb21wb3NpdGVMaWZlQ3ljbGVTdGF0ZSA9IG51bGw7XG4gIH0sXG5cbiAgLyoqXG4gICAqIENoZWNrcyB3aGV0aGVyIG9yIG5vdCB0aGlzIGNvbXBvc2l0ZSBjb21wb25lbnQgaXMgbW91bnRlZC5cbiAgICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiBtb3VudGVkLCBmYWxzZSBvdGhlcndpc2UuXG4gICAqIEBwcm90ZWN0ZWRcbiAgICogQGZpbmFsXG4gICAqL1xuICBpc01vdW50ZWQ6IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiBSZWFjdENvbXBvbmVudC5NaXhpbi5pc01vdW50ZWQuY2FsbCh0aGlzKSAmJlxuICAgICAgdGhpcy5fY29tcG9zaXRlTGlmZUN5Y2xlU3RhdGUgIT09IENvbXBvc2l0ZUxpZmVDeWNsZS5NT1VOVElORztcbiAgfSxcblxuICAvKipcbiAgICogSW5pdGlhbGl6ZXMgdGhlIGNvbXBvbmVudCwgcmVuZGVycyBtYXJrdXAsIGFuZCByZWdpc3RlcnMgZXZlbnQgbGlzdGVuZXJzLlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gcm9vdElEIERPTSBJRCBvZiB0aGUgcm9vdCBub2RlLlxuICAgKiBAcGFyYW0ge1JlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb258UmVhY3RTZXJ2ZXJSZW5kZXJpbmdUcmFuc2FjdGlvbn0gdHJhbnNhY3Rpb25cbiAgICogQHBhcmFtIHtudW1iZXJ9IG1vdW50RGVwdGggbnVtYmVyIG9mIGNvbXBvbmVudHMgaW4gdGhlIG93bmVyIGhpZXJhcmNoeVxuICAgKiBAcmV0dXJuIHs/c3RyaW5nfSBSZW5kZXJlZCBtYXJrdXAgdG8gYmUgaW5zZXJ0ZWQgaW50byB0aGUgRE9NLlxuICAgKiBAZmluYWxcbiAgICogQGludGVybmFsXG4gICAqL1xuICBtb3VudENvbXBvbmVudDogUmVhY3RQZXJmLm1lYXN1cmUoXG4gICAgJ1JlYWN0Q29tcG9zaXRlQ29tcG9uZW50JyxcbiAgICAnbW91bnRDb21wb25lbnQnLFxuICAgIGZ1bmN0aW9uKHJvb3RJRCwgdHJhbnNhY3Rpb24sIG1vdW50RGVwdGgpIHtcbiAgICAgIFJlYWN0Q29tcG9uZW50Lk1peGluLm1vdW50Q29tcG9uZW50LmNhbGwoXG4gICAgICAgIHRoaXMsXG4gICAgICAgIHJvb3RJRCxcbiAgICAgICAgdHJhbnNhY3Rpb24sXG4gICAgICAgIG1vdW50RGVwdGhcbiAgICAgICk7XG4gICAgICB0aGlzLl9jb21wb3NpdGVMaWZlQ3ljbGVTdGF0ZSA9IENvbXBvc2l0ZUxpZmVDeWNsZS5NT1VOVElORztcblxuICAgICAgaWYgKHRoaXMuX19yZWFjdEF1dG9CaW5kTWFwKSB7XG4gICAgICAgIHRoaXMuX2JpbmRBdXRvQmluZE1ldGhvZHMoKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5jb250ZXh0ID0gdGhpcy5fcHJvY2Vzc0NvbnRleHQodGhpcy5fY3VycmVudEVsZW1lbnQuX2NvbnRleHQpO1xuICAgICAgdGhpcy5wcm9wcyA9IHRoaXMuX3Byb2Nlc3NQcm9wcyh0aGlzLnByb3BzKTtcblxuICAgICAgdGhpcy5zdGF0ZSA9IHRoaXMuZ2V0SW5pdGlhbFN0YXRlID8gdGhpcy5nZXRJbml0aWFsU3RhdGUoKSA6IG51bGw7XG4gICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICB0eXBlb2YgdGhpcy5zdGF0ZSA9PT0gJ29iamVjdCcgJiYgIUFycmF5LmlzQXJyYXkodGhpcy5zdGF0ZSksXG4gICAgICAgICclcy5nZXRJbml0aWFsU3RhdGUoKTogbXVzdCByZXR1cm4gYW4gb2JqZWN0IG9yIG51bGwnLFxuICAgICAgICB0aGlzLmNvbnN0cnVjdG9yLmRpc3BsYXlOYW1lIHx8ICdSZWFjdENvbXBvc2l0ZUNvbXBvbmVudCdcbiAgICAgICkgOiBpbnZhcmlhbnQodHlwZW9mIHRoaXMuc3RhdGUgPT09ICdvYmplY3QnICYmICFBcnJheS5pc0FycmF5KHRoaXMuc3RhdGUpKSk7XG5cbiAgICAgIHRoaXMuX3BlbmRpbmdTdGF0ZSA9IG51bGw7XG4gICAgICB0aGlzLl9wZW5kaW5nRm9yY2VVcGRhdGUgPSBmYWxzZTtcblxuICAgICAgaWYgKHRoaXMuY29tcG9uZW50V2lsbE1vdW50KSB7XG4gICAgICAgIHRoaXMuY29tcG9uZW50V2lsbE1vdW50KCk7XG4gICAgICAgIC8vIFdoZW4gbW91bnRpbmcsIGNhbGxzIHRvIGBzZXRTdGF0ZWAgYnkgYGNvbXBvbmVudFdpbGxNb3VudGAgd2lsbCBzZXRcbiAgICAgICAgLy8gYHRoaXMuX3BlbmRpbmdTdGF0ZWAgd2l0aG91dCB0cmlnZ2VyaW5nIGEgcmUtcmVuZGVyLlxuICAgICAgICBpZiAodGhpcy5fcGVuZGluZ1N0YXRlKSB7XG4gICAgICAgICAgdGhpcy5zdGF0ZSA9IHRoaXMuX3BlbmRpbmdTdGF0ZTtcbiAgICAgICAgICB0aGlzLl9wZW5kaW5nU3RhdGUgPSBudWxsO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHRoaXMuX3JlbmRlcmVkQ29tcG9uZW50ID0gaW5zdGFudGlhdGVSZWFjdENvbXBvbmVudChcbiAgICAgICAgdGhpcy5fcmVuZGVyVmFsaWRhdGVkQ29tcG9uZW50KCksXG4gICAgICAgIHRoaXMuX2N1cnJlbnRFbGVtZW50LnR5cGUgLy8gVGhlIHdyYXBwaW5nIHR5cGVcbiAgICAgICk7XG5cbiAgICAgIC8vIERvbmUgd2l0aCBtb3VudGluZywgYHNldFN0YXRlYCB3aWxsIG5vdyB0cmlnZ2VyIFVJIGNoYW5nZXMuXG4gICAgICB0aGlzLl9jb21wb3NpdGVMaWZlQ3ljbGVTdGF0ZSA9IG51bGw7XG4gICAgICB2YXIgbWFya3VwID0gdGhpcy5fcmVuZGVyZWRDb21wb25lbnQubW91bnRDb21wb25lbnQoXG4gICAgICAgIHJvb3RJRCxcbiAgICAgICAgdHJhbnNhY3Rpb24sXG4gICAgICAgIG1vdW50RGVwdGggKyAxXG4gICAgICApO1xuICAgICAgaWYgKHRoaXMuY29tcG9uZW50RGlkTW91bnQpIHtcbiAgICAgICAgdHJhbnNhY3Rpb24uZ2V0UmVhY3RNb3VudFJlYWR5KCkuZW5xdWV1ZSh0aGlzLmNvbXBvbmVudERpZE1vdW50LCB0aGlzKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBtYXJrdXA7XG4gICAgfVxuICApLFxuXG4gIC8qKlxuICAgKiBSZWxlYXNlcyBhbnkgcmVzb3VyY2VzIGFsbG9jYXRlZCBieSBgbW91bnRDb21wb25lbnRgLlxuICAgKlxuICAgKiBAZmluYWxcbiAgICogQGludGVybmFsXG4gICAqL1xuICB1bm1vdW50Q29tcG9uZW50OiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLl9jb21wb3NpdGVMaWZlQ3ljbGVTdGF0ZSA9IENvbXBvc2l0ZUxpZmVDeWNsZS5VTk1PVU5USU5HO1xuICAgIGlmICh0aGlzLmNvbXBvbmVudFdpbGxVbm1vdW50KSB7XG4gICAgICB0aGlzLmNvbXBvbmVudFdpbGxVbm1vdW50KCk7XG4gICAgfVxuICAgIHRoaXMuX2NvbXBvc2l0ZUxpZmVDeWNsZVN0YXRlID0gbnVsbDtcblxuICAgIHRoaXMuX3JlbmRlcmVkQ29tcG9uZW50LnVubW91bnRDb21wb25lbnQoKTtcbiAgICB0aGlzLl9yZW5kZXJlZENvbXBvbmVudCA9IG51bGw7XG5cbiAgICBSZWFjdENvbXBvbmVudC5NaXhpbi51bm1vdW50Q29tcG9uZW50LmNhbGwodGhpcyk7XG5cbiAgICAvLyBTb21lIGV4aXN0aW5nIGNvbXBvbmVudHMgcmVseSBvbiB0aGlzLnByb3BzIGV2ZW4gYWZ0ZXIgdGhleSd2ZSBiZWVuXG4gICAgLy8gZGVzdHJveWVkIChpbiBldmVudCBoYW5kbGVycykuXG4gICAgLy8gVE9ETzogdGhpcy5wcm9wcyA9IG51bGw7XG4gICAgLy8gVE9ETzogdGhpcy5zdGF0ZSA9IG51bGw7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFNldHMgYSBzdWJzZXQgb2YgdGhlIHN0YXRlLiBBbHdheXMgdXNlIHRoaXMgb3IgYHJlcGxhY2VTdGF0ZWAgdG8gbXV0YXRlXG4gICAqIHN0YXRlLiBZb3Ugc2hvdWxkIHRyZWF0IGB0aGlzLnN0YXRlYCBhcyBpbW11dGFibGUuXG4gICAqXG4gICAqIFRoZXJlIGlzIG5vIGd1YXJhbnRlZSB0aGF0IGB0aGlzLnN0YXRlYCB3aWxsIGJlIGltbWVkaWF0ZWx5IHVwZGF0ZWQsIHNvXG4gICAqIGFjY2Vzc2luZyBgdGhpcy5zdGF0ZWAgYWZ0ZXIgY2FsbGluZyB0aGlzIG1ldGhvZCBtYXkgcmV0dXJuIHRoZSBvbGQgdmFsdWUuXG4gICAqXG4gICAqIFRoZXJlIGlzIG5vIGd1YXJhbnRlZSB0aGF0IGNhbGxzIHRvIGBzZXRTdGF0ZWAgd2lsbCBydW4gc3luY2hyb25vdXNseSxcbiAgICogYXMgdGhleSBtYXkgZXZlbnR1YWxseSBiZSBiYXRjaGVkIHRvZ2V0aGVyLiAgWW91IGNhbiBwcm92aWRlIGFuIG9wdGlvbmFsXG4gICAqIGNhbGxiYWNrIHRoYXQgd2lsbCBiZSBleGVjdXRlZCB3aGVuIHRoZSBjYWxsIHRvIHNldFN0YXRlIGlzIGFjdHVhbGx5XG4gICAqIGNvbXBsZXRlZC5cbiAgICpcbiAgICogQHBhcmFtIHtvYmplY3R9IHBhcnRpYWxTdGF0ZSBOZXh0IHBhcnRpYWwgc3RhdGUgdG8gYmUgbWVyZ2VkIHdpdGggc3RhdGUuXG4gICAqIEBwYXJhbSB7P2Z1bmN0aW9ufSBjYWxsYmFjayBDYWxsZWQgYWZ0ZXIgc3RhdGUgaXMgdXBkYXRlZC5cbiAgICogQGZpbmFsXG4gICAqIEBwcm90ZWN0ZWRcbiAgICovXG4gIHNldFN0YXRlOiBmdW5jdGlvbihwYXJ0aWFsU3RhdGUsIGNhbGxiYWNrKSB7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgIHR5cGVvZiBwYXJ0aWFsU3RhdGUgPT09ICdvYmplY3QnIHx8IHBhcnRpYWxTdGF0ZSA9PSBudWxsLFxuICAgICAgJ3NldFN0YXRlKC4uLik6IHRha2VzIGFuIG9iamVjdCBvZiBzdGF0ZSB2YXJpYWJsZXMgdG8gdXBkYXRlLidcbiAgICApIDogaW52YXJpYW50KHR5cGVvZiBwYXJ0aWFsU3RhdGUgPT09ICdvYmplY3QnIHx8IHBhcnRpYWxTdGF0ZSA9PSBudWxsKSk7XG4gICAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVil7XG4gICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gd2FybmluZyhcbiAgICAgICAgcGFydGlhbFN0YXRlICE9IG51bGwsXG4gICAgICAgICdzZXRTdGF0ZSguLi4pOiBZb3UgcGFzc2VkIGFuIHVuZGVmaW5lZCBvciBudWxsIHN0YXRlIG9iamVjdDsgJyArXG4gICAgICAgICdpbnN0ZWFkLCB1c2UgZm9yY2VVcGRhdGUoKS4nXG4gICAgICApIDogbnVsbCk7XG4gICAgfVxuICAgIC8vIE1lcmdlIHdpdGggYF9wZW5kaW5nU3RhdGVgIGlmIGl0IGV4aXN0cywgb3RoZXJ3aXNlIHdpdGggZXhpc3Rpbmcgc3RhdGUuXG4gICAgdGhpcy5yZXBsYWNlU3RhdGUoXG4gICAgICBhc3NpZ24oe30sIHRoaXMuX3BlbmRpbmdTdGF0ZSB8fCB0aGlzLnN0YXRlLCBwYXJ0aWFsU3RhdGUpLFxuICAgICAgY2FsbGJhY2tcbiAgICApO1xuICB9LFxuXG4gIC8qKlxuICAgKiBSZXBsYWNlcyBhbGwgb2YgdGhlIHN0YXRlLiBBbHdheXMgdXNlIHRoaXMgb3IgYHNldFN0YXRlYCB0byBtdXRhdGUgc3RhdGUuXG4gICAqIFlvdSBzaG91bGQgdHJlYXQgYHRoaXMuc3RhdGVgIGFzIGltbXV0YWJsZS5cbiAgICpcbiAgICogVGhlcmUgaXMgbm8gZ3VhcmFudGVlIHRoYXQgYHRoaXMuc3RhdGVgIHdpbGwgYmUgaW1tZWRpYXRlbHkgdXBkYXRlZCwgc29cbiAgICogYWNjZXNzaW5nIGB0aGlzLnN0YXRlYCBhZnRlciBjYWxsaW5nIHRoaXMgbWV0aG9kIG1heSByZXR1cm4gdGhlIG9sZCB2YWx1ZS5cbiAgICpcbiAgICogQHBhcmFtIHtvYmplY3R9IGNvbXBsZXRlU3RhdGUgTmV4dCBzdGF0ZS5cbiAgICogQHBhcmFtIHs/ZnVuY3Rpb259IGNhbGxiYWNrIENhbGxlZCBhZnRlciBzdGF0ZSBpcyB1cGRhdGVkLlxuICAgKiBAZmluYWxcbiAgICogQHByb3RlY3RlZFxuICAgKi9cbiAgcmVwbGFjZVN0YXRlOiBmdW5jdGlvbihjb21wbGV0ZVN0YXRlLCBjYWxsYmFjaykge1xuICAgIHZhbGlkYXRlTGlmZUN5Y2xlT25SZXBsYWNlU3RhdGUodGhpcyk7XG4gICAgdGhpcy5fcGVuZGluZ1N0YXRlID0gY29tcGxldGVTdGF0ZTtcbiAgICBpZiAodGhpcy5fY29tcG9zaXRlTGlmZUN5Y2xlU3RhdGUgIT09IENvbXBvc2l0ZUxpZmVDeWNsZS5NT1VOVElORykge1xuICAgICAgLy8gSWYgd2UncmUgaW4gYSBjb21wb25lbnRXaWxsTW91bnQgaGFuZGxlciwgZG9uJ3QgZW5xdWV1ZSBhIHJlcmVuZGVyXG4gICAgICAvLyBiZWNhdXNlIFJlYWN0VXBkYXRlcyBhc3N1bWVzIHdlJ3JlIGluIGEgYnJvd3NlciBjb250ZXh0ICh3aGljaCBpcyB3cm9uZ1xuICAgICAgLy8gZm9yIHNlcnZlciByZW5kZXJpbmcpIGFuZCB3ZSdyZSBhYm91dCB0byBkbyBhIHJlbmRlciBhbnl3YXkuXG4gICAgICAvLyBUT0RPOiBUaGUgY2FsbGJhY2sgaGVyZSBpcyBpZ25vcmVkIHdoZW4gc2V0U3RhdGUgaXMgY2FsbGVkIGZyb21cbiAgICAgIC8vIGNvbXBvbmVudFdpbGxNb3VudC4gRWl0aGVyIGZpeCBpdCBvciBkaXNhbGxvdyBkb2luZyBzbyBjb21wbGV0ZWx5IGluXG4gICAgICAvLyBmYXZvciBvZiBnZXRJbml0aWFsU3RhdGUuXG4gICAgICBSZWFjdFVwZGF0ZXMuZW5xdWV1ZVVwZGF0ZSh0aGlzLCBjYWxsYmFjayk7XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBGaWx0ZXJzIHRoZSBjb250ZXh0IG9iamVjdCB0byBvbmx5IGNvbnRhaW4ga2V5cyBzcGVjaWZpZWQgaW5cbiAgICogYGNvbnRleHRUeXBlc2AsIGFuZCBhc3NlcnRzIHRoYXQgdGhleSBhcmUgdmFsaWQuXG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBjb250ZXh0XG4gICAqIEByZXR1cm4gez9vYmplY3R9XG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBfcHJvY2Vzc0NvbnRleHQ6IGZ1bmN0aW9uKGNvbnRleHQpIHtcbiAgICB2YXIgbWFza2VkQ29udGV4dCA9IG51bGw7XG4gICAgdmFyIGNvbnRleHRUeXBlcyA9IHRoaXMuY29uc3RydWN0b3IuY29udGV4dFR5cGVzO1xuICAgIGlmIChjb250ZXh0VHlwZXMpIHtcbiAgICAgIG1hc2tlZENvbnRleHQgPSB7fTtcbiAgICAgIGZvciAodmFyIGNvbnRleHROYW1lIGluIGNvbnRleHRUeXBlcykge1xuICAgICAgICBtYXNrZWRDb250ZXh0W2NvbnRleHROYW1lXSA9IGNvbnRleHRbY29udGV4dE5hbWVdO1xuICAgICAgfVxuICAgICAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgICB0aGlzLl9jaGVja1Byb3BUeXBlcyhcbiAgICAgICAgICBjb250ZXh0VHlwZXMsXG4gICAgICAgICAgbWFza2VkQ29udGV4dCxcbiAgICAgICAgICBSZWFjdFByb3BUeXBlTG9jYXRpb25zLmNvbnRleHRcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG1hc2tlZENvbnRleHQ7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBjdXJyZW50Q29udGV4dFxuICAgKiBAcmV0dXJuIHtvYmplY3R9XG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBfcHJvY2Vzc0NoaWxkQ29udGV4dDogZnVuY3Rpb24oY3VycmVudENvbnRleHQpIHtcbiAgICB2YXIgY2hpbGRDb250ZXh0ID0gdGhpcy5nZXRDaGlsZENvbnRleHQgJiYgdGhpcy5nZXRDaGlsZENvbnRleHQoKTtcbiAgICB2YXIgZGlzcGxheU5hbWUgPSB0aGlzLmNvbnN0cnVjdG9yLmRpc3BsYXlOYW1lIHx8ICdSZWFjdENvbXBvc2l0ZUNvbXBvbmVudCc7XG4gICAgaWYgKGNoaWxkQ29udGV4dCkge1xuICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgdHlwZW9mIHRoaXMuY29uc3RydWN0b3IuY2hpbGRDb250ZXh0VHlwZXMgPT09ICdvYmplY3QnLFxuICAgICAgICAnJXMuZ2V0Q2hpbGRDb250ZXh0KCk6IGNoaWxkQ29udGV4dFR5cGVzIG11c3QgYmUgZGVmaW5lZCBpbiBvcmRlciB0byAnICtcbiAgICAgICAgJ3VzZSBnZXRDaGlsZENvbnRleHQoKS4nLFxuICAgICAgICBkaXNwbGF5TmFtZVxuICAgICAgKSA6IGludmFyaWFudCh0eXBlb2YgdGhpcy5jb25zdHJ1Y3Rvci5jaGlsZENvbnRleHRUeXBlcyA9PT0gJ29iamVjdCcpKTtcbiAgICAgIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgICAgdGhpcy5fY2hlY2tQcm9wVHlwZXMoXG4gICAgICAgICAgdGhpcy5jb25zdHJ1Y3Rvci5jaGlsZENvbnRleHRUeXBlcyxcbiAgICAgICAgICBjaGlsZENvbnRleHQsXG4gICAgICAgICAgUmVhY3RQcm9wVHlwZUxvY2F0aW9ucy5jaGlsZENvbnRleHRcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIGZvciAodmFyIG5hbWUgaW4gY2hpbGRDb250ZXh0KSB7XG4gICAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgICAgbmFtZSBpbiB0aGlzLmNvbnN0cnVjdG9yLmNoaWxkQ29udGV4dFR5cGVzLFxuICAgICAgICAgICclcy5nZXRDaGlsZENvbnRleHQoKToga2V5IFwiJXNcIiBpcyBub3QgZGVmaW5lZCBpbiBjaGlsZENvbnRleHRUeXBlcy4nLFxuICAgICAgICAgIGRpc3BsYXlOYW1lLFxuICAgICAgICAgIG5hbWVcbiAgICAgICAgKSA6IGludmFyaWFudChuYW1lIGluIHRoaXMuY29uc3RydWN0b3IuY2hpbGRDb250ZXh0VHlwZXMpKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBhc3NpZ24oe30sIGN1cnJlbnRDb250ZXh0LCBjaGlsZENvbnRleHQpO1xuICAgIH1cbiAgICByZXR1cm4gY3VycmVudENvbnRleHQ7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFByb2Nlc3NlcyBwcm9wcyBieSBzZXR0aW5nIGRlZmF1bHQgdmFsdWVzIGZvciB1bnNwZWNpZmllZCBwcm9wcyBhbmRcbiAgICogYXNzZXJ0aW5nIHRoYXQgdGhlIHByb3BzIGFyZSB2YWxpZC4gRG9lcyBub3QgbXV0YXRlIGl0cyBhcmd1bWVudDsgcmV0dXJuc1xuICAgKiBhIG5ldyBwcm9wcyBvYmplY3Qgd2l0aCBkZWZhdWx0cyBtZXJnZWQgaW4uXG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBuZXdQcm9wc1xuICAgKiBAcmV0dXJuIHtvYmplY3R9XG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBfcHJvY2Vzc1Byb3BzOiBmdW5jdGlvbihuZXdQcm9wcykge1xuICAgIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgIHZhciBwcm9wVHlwZXMgPSB0aGlzLmNvbnN0cnVjdG9yLnByb3BUeXBlcztcbiAgICAgIGlmIChwcm9wVHlwZXMpIHtcbiAgICAgICAgdGhpcy5fY2hlY2tQcm9wVHlwZXMocHJvcFR5cGVzLCBuZXdQcm9wcywgUmVhY3RQcm9wVHlwZUxvY2F0aW9ucy5wcm9wKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG5ld1Byb3BzO1xuICB9LFxuXG4gIC8qKlxuICAgKiBBc3NlcnQgdGhhdCB0aGUgcHJvcHMgYXJlIHZhbGlkXG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBwcm9wVHlwZXMgTWFwIG9mIHByb3AgbmFtZSB0byBhIFJlYWN0UHJvcFR5cGVcbiAgICogQHBhcmFtIHtvYmplY3R9IHByb3BzXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBsb2NhdGlvbiBlLmcuIFwicHJvcFwiLCBcImNvbnRleHRcIiwgXCJjaGlsZCBjb250ZXh0XCJcbiAgICogQHByaXZhdGVcbiAgICovXG4gIF9jaGVja1Byb3BUeXBlczogZnVuY3Rpb24ocHJvcFR5cGVzLCBwcm9wcywgbG9jYXRpb24pIHtcbiAgICAvLyBUT0RPOiBTdG9wIHZhbGlkYXRpbmcgcHJvcCB0eXBlcyBoZXJlIGFuZCBvbmx5IHVzZSB0aGUgZWxlbWVudFxuICAgIC8vIHZhbGlkYXRpb24uXG4gICAgdmFyIGNvbXBvbmVudE5hbWUgPSB0aGlzLmNvbnN0cnVjdG9yLmRpc3BsYXlOYW1lO1xuICAgIGZvciAodmFyIHByb3BOYW1lIGluIHByb3BUeXBlcykge1xuICAgICAgaWYgKHByb3BUeXBlcy5oYXNPd25Qcm9wZXJ0eShwcm9wTmFtZSkpIHtcbiAgICAgICAgdmFyIGVycm9yID1cbiAgICAgICAgICBwcm9wVHlwZXNbcHJvcE5hbWVdKHByb3BzLCBwcm9wTmFtZSwgY29tcG9uZW50TmFtZSwgbG9jYXRpb24pO1xuICAgICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgICAgIC8vIFdlIG1heSB3YW50IHRvIGV4dGVuZCB0aGlzIGxvZ2ljIGZvciBzaW1pbGFyIGVycm9ycyBpblxuICAgICAgICAgIC8vIHJlbmRlckNvbXBvbmVudCBjYWxscywgc28gSSdtIGFic3RyYWN0aW5nIGl0IGF3YXkgaW50b1xuICAgICAgICAgIC8vIGEgZnVuY3Rpb24gdG8gbWluaW1pemUgcmVmYWN0b3JpbmcgaW4gdGhlIGZ1dHVyZVxuICAgICAgICAgIHZhciBhZGRlbmR1bSA9IGdldERlY2xhcmF0aW9uRXJyb3JBZGRlbmR1bSh0aGlzKTtcbiAgICAgICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gd2FybmluZyhmYWxzZSwgZXJyb3IubWVzc2FnZSArIGFkZGVuZHVtKSA6IG51bGwpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBJZiBhbnkgb2YgYF9wZW5kaW5nRWxlbWVudGAsIGBfcGVuZGluZ1N0YXRlYCwgb3IgYF9wZW5kaW5nRm9yY2VVcGRhdGVgXG4gICAqIGlzIHNldCwgdXBkYXRlIHRoZSBjb21wb25lbnQuXG4gICAqXG4gICAqIEBwYXJhbSB7UmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbn0gdHJhbnNhY3Rpb25cbiAgICogQGludGVybmFsXG4gICAqL1xuICBwZXJmb3JtVXBkYXRlSWZOZWNlc3Nhcnk6IGZ1bmN0aW9uKHRyYW5zYWN0aW9uKSB7XG4gICAgdmFyIGNvbXBvc2l0ZUxpZmVDeWNsZVN0YXRlID0gdGhpcy5fY29tcG9zaXRlTGlmZUN5Y2xlU3RhdGU7XG4gICAgLy8gRG8gbm90IHRyaWdnZXIgYSBzdGF0ZSB0cmFuc2l0aW9uIGlmIHdlIGFyZSBpbiB0aGUgbWlkZGxlIG9mIG1vdW50aW5nIG9yXG4gICAgLy8gcmVjZWl2aW5nIHByb3BzIGJlY2F1c2UgYm90aCBvZiB0aG9zZSB3aWxsIGFscmVhZHkgYmUgZG9pbmcgdGhpcy5cbiAgICBpZiAoY29tcG9zaXRlTGlmZUN5Y2xlU3RhdGUgPT09IENvbXBvc2l0ZUxpZmVDeWNsZS5NT1VOVElORyB8fFxuICAgICAgICBjb21wb3NpdGVMaWZlQ3ljbGVTdGF0ZSA9PT0gQ29tcG9zaXRlTGlmZUN5Y2xlLlJFQ0VJVklOR19QUk9QUykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh0aGlzLl9wZW5kaW5nRWxlbWVudCA9PSBudWxsICYmXG4gICAgICAgIHRoaXMuX3BlbmRpbmdTdGF0ZSA9PSBudWxsICYmXG4gICAgICAgICF0aGlzLl9wZW5kaW5nRm9yY2VVcGRhdGUpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgbmV4dENvbnRleHQgPSB0aGlzLmNvbnRleHQ7XG4gICAgdmFyIG5leHRQcm9wcyA9IHRoaXMucHJvcHM7XG4gICAgdmFyIG5leHRFbGVtZW50ID0gdGhpcy5fY3VycmVudEVsZW1lbnQ7XG4gICAgaWYgKHRoaXMuX3BlbmRpbmdFbGVtZW50ICE9IG51bGwpIHtcbiAgICAgIG5leHRFbGVtZW50ID0gdGhpcy5fcGVuZGluZ0VsZW1lbnQ7XG4gICAgICBuZXh0Q29udGV4dCA9IHRoaXMuX3Byb2Nlc3NDb250ZXh0KG5leHRFbGVtZW50Ll9jb250ZXh0KTtcbiAgICAgIG5leHRQcm9wcyA9IHRoaXMuX3Byb2Nlc3NQcm9wcyhuZXh0RWxlbWVudC5wcm9wcyk7XG4gICAgICB0aGlzLl9wZW5kaW5nRWxlbWVudCA9IG51bGw7XG5cbiAgICAgIHRoaXMuX2NvbXBvc2l0ZUxpZmVDeWNsZVN0YXRlID0gQ29tcG9zaXRlTGlmZUN5Y2xlLlJFQ0VJVklOR19QUk9QUztcbiAgICAgIGlmICh0aGlzLmNvbXBvbmVudFdpbGxSZWNlaXZlUHJvcHMpIHtcbiAgICAgICAgdGhpcy5jb21wb25lbnRXaWxsUmVjZWl2ZVByb3BzKG5leHRQcm9wcywgbmV4dENvbnRleHQpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMuX2NvbXBvc2l0ZUxpZmVDeWNsZVN0YXRlID0gbnVsbDtcblxuICAgIHZhciBuZXh0U3RhdGUgPSB0aGlzLl9wZW5kaW5nU3RhdGUgfHwgdGhpcy5zdGF0ZTtcbiAgICB0aGlzLl9wZW5kaW5nU3RhdGUgPSBudWxsO1xuXG4gICAgdmFyIHNob3VsZFVwZGF0ZSA9XG4gICAgICB0aGlzLl9wZW5kaW5nRm9yY2VVcGRhdGUgfHxcbiAgICAgICF0aGlzLnNob3VsZENvbXBvbmVudFVwZGF0ZSB8fFxuICAgICAgdGhpcy5zaG91bGRDb21wb25lbnRVcGRhdGUobmV4dFByb3BzLCBuZXh0U3RhdGUsIG5leHRDb250ZXh0KTtcblxuICAgIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgIGlmICh0eXBlb2Ygc2hvdWxkVXBkYXRlID09PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgICAodGhpcy5jb25zdHJ1Y3Rvci5kaXNwbGF5TmFtZSB8fCAnUmVhY3RDb21wb3NpdGVDb21wb25lbnQnKSArXG4gICAgICAgICAgJy5zaG91bGRDb21wb25lbnRVcGRhdGUoKTogUmV0dXJuZWQgdW5kZWZpbmVkIGluc3RlYWQgb2YgYSAnICtcbiAgICAgICAgICAnYm9vbGVhbiB2YWx1ZS4gTWFrZSBzdXJlIHRvIHJldHVybiB0cnVlIG9yIGZhbHNlLidcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoc2hvdWxkVXBkYXRlKSB7XG4gICAgICB0aGlzLl9wZW5kaW5nRm9yY2VVcGRhdGUgPSBmYWxzZTtcbiAgICAgIC8vIFdpbGwgc2V0IGB0aGlzLnByb3BzYCwgYHRoaXMuc3RhdGVgIGFuZCBgdGhpcy5jb250ZXh0YC5cbiAgICAgIHRoaXMuX3BlcmZvcm1Db21wb25lbnRVcGRhdGUoXG4gICAgICAgIG5leHRFbGVtZW50LFxuICAgICAgICBuZXh0UHJvcHMsXG4gICAgICAgIG5leHRTdGF0ZSxcbiAgICAgICAgbmV4dENvbnRleHQsXG4gICAgICAgIHRyYW5zYWN0aW9uXG4gICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBJZiBpdCdzIGRldGVybWluZWQgdGhhdCBhIGNvbXBvbmVudCBzaG91bGQgbm90IHVwZGF0ZSwgd2Ugc3RpbGwgd2FudFxuICAgICAgLy8gdG8gc2V0IHByb3BzIGFuZCBzdGF0ZS5cbiAgICAgIHRoaXMuX2N1cnJlbnRFbGVtZW50ID0gbmV4dEVsZW1lbnQ7XG4gICAgICB0aGlzLnByb3BzID0gbmV4dFByb3BzO1xuICAgICAgdGhpcy5zdGF0ZSA9IG5leHRTdGF0ZTtcbiAgICAgIHRoaXMuY29udGV4dCA9IG5leHRDb250ZXh0O1xuXG4gICAgICAvLyBPd25lciBjYW5ub3QgY2hhbmdlIGJlY2F1c2Ugc2hvdWxkVXBkYXRlUmVhY3RDb21wb25lbnQgZG9lc24ndCBhbGxvd1xuICAgICAgLy8gaXQuIFRPRE86IFJlbW92ZSB0aGlzLl9vd25lciBjb21wbGV0ZWx5LlxuICAgICAgdGhpcy5fb3duZXIgPSBuZXh0RWxlbWVudC5fb3duZXI7XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBNZXJnZXMgbmV3IHByb3BzIGFuZCBzdGF0ZSwgbm90aWZpZXMgZGVsZWdhdGUgbWV0aG9kcyBvZiB1cGRhdGUgYW5kXG4gICAqIHBlcmZvcm1zIHVwZGF0ZS5cbiAgICpcbiAgICogQHBhcmFtIHtSZWFjdEVsZW1lbnR9IG5leHRFbGVtZW50IE5leHQgZWxlbWVudFxuICAgKiBAcGFyYW0ge29iamVjdH0gbmV4dFByb3BzIE5leHQgcHVibGljIG9iamVjdCB0byBzZXQgYXMgcHJvcGVydGllcy5cbiAgICogQHBhcmFtIHs/b2JqZWN0fSBuZXh0U3RhdGUgTmV4dCBvYmplY3QgdG8gc2V0IGFzIHN0YXRlLlxuICAgKiBAcGFyYW0gez9vYmplY3R9IG5leHRDb250ZXh0IE5leHQgcHVibGljIG9iamVjdCB0byBzZXQgYXMgY29udGV4dC5cbiAgICogQHBhcmFtIHtSZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9ufSB0cmFuc2FjdGlvblxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgX3BlcmZvcm1Db21wb25lbnRVcGRhdGU6IGZ1bmN0aW9uKFxuICAgIG5leHRFbGVtZW50LFxuICAgIG5leHRQcm9wcyxcbiAgICBuZXh0U3RhdGUsXG4gICAgbmV4dENvbnRleHQsXG4gICAgdHJhbnNhY3Rpb25cbiAgKSB7XG4gICAgdmFyIHByZXZFbGVtZW50ID0gdGhpcy5fY3VycmVudEVsZW1lbnQ7XG4gICAgdmFyIHByZXZQcm9wcyA9IHRoaXMucHJvcHM7XG4gICAgdmFyIHByZXZTdGF0ZSA9IHRoaXMuc3RhdGU7XG4gICAgdmFyIHByZXZDb250ZXh0ID0gdGhpcy5jb250ZXh0O1xuXG4gICAgaWYgKHRoaXMuY29tcG9uZW50V2lsbFVwZGF0ZSkge1xuICAgICAgdGhpcy5jb21wb25lbnRXaWxsVXBkYXRlKG5leHRQcm9wcywgbmV4dFN0YXRlLCBuZXh0Q29udGV4dCk7XG4gICAgfVxuXG4gICAgdGhpcy5fY3VycmVudEVsZW1lbnQgPSBuZXh0RWxlbWVudDtcbiAgICB0aGlzLnByb3BzID0gbmV4dFByb3BzO1xuICAgIHRoaXMuc3RhdGUgPSBuZXh0U3RhdGU7XG4gICAgdGhpcy5jb250ZXh0ID0gbmV4dENvbnRleHQ7XG5cbiAgICAvLyBPd25lciBjYW5ub3QgY2hhbmdlIGJlY2F1c2Ugc2hvdWxkVXBkYXRlUmVhY3RDb21wb25lbnQgZG9lc24ndCBhbGxvd1xuICAgIC8vIGl0LiBUT0RPOiBSZW1vdmUgdGhpcy5fb3duZXIgY29tcGxldGVseS5cbiAgICB0aGlzLl9vd25lciA9IG5leHRFbGVtZW50Ll9vd25lcjtcblxuICAgIHRoaXMudXBkYXRlQ29tcG9uZW50KFxuICAgICAgdHJhbnNhY3Rpb24sXG4gICAgICBwcmV2RWxlbWVudFxuICAgICk7XG5cbiAgICBpZiAodGhpcy5jb21wb25lbnREaWRVcGRhdGUpIHtcbiAgICAgIHRyYW5zYWN0aW9uLmdldFJlYWN0TW91bnRSZWFkeSgpLmVucXVldWUoXG4gICAgICAgIHRoaXMuY29tcG9uZW50RGlkVXBkYXRlLmJpbmQodGhpcywgcHJldlByb3BzLCBwcmV2U3RhdGUsIHByZXZDb250ZXh0KSxcbiAgICAgICAgdGhpc1xuICAgICAgKTtcbiAgICB9XG4gIH0sXG5cbiAgcmVjZWl2ZUNvbXBvbmVudDogZnVuY3Rpb24obmV4dEVsZW1lbnQsIHRyYW5zYWN0aW9uKSB7XG4gICAgaWYgKG5leHRFbGVtZW50ID09PSB0aGlzLl9jdXJyZW50RWxlbWVudCAmJlxuICAgICAgICBuZXh0RWxlbWVudC5fb3duZXIgIT0gbnVsbCkge1xuICAgICAgLy8gU2luY2UgZWxlbWVudHMgYXJlIGltbXV0YWJsZSBhZnRlciB0aGUgb3duZXIgaXMgcmVuZGVyZWQsXG4gICAgICAvLyB3ZSBjYW4gZG8gYSBjaGVhcCBpZGVudGl0eSBjb21wYXJlIGhlcmUgdG8gZGV0ZXJtaW5lIGlmIHRoaXMgaXMgYVxuICAgICAgLy8gc3VwZXJmbHVvdXMgcmVjb25jaWxlLiBJdCdzIHBvc3NpYmxlIGZvciBzdGF0ZSB0byBiZSBtdXRhYmxlIGJ1dCBzdWNoXG4gICAgICAvLyBjaGFuZ2Ugc2hvdWxkIHRyaWdnZXIgYW4gdXBkYXRlIG9mIHRoZSBvd25lciB3aGljaCB3b3VsZCByZWNyZWF0ZVxuICAgICAgLy8gdGhlIGVsZW1lbnQuIFdlIGV4cGxpY2l0bHkgY2hlY2sgZm9yIHRoZSBleGlzdGVuY2Ugb2YgYW4gb3duZXIgc2luY2VcbiAgICAgIC8vIGl0J3MgcG9zc2libGUgZm9yIGEgZWxlbWVudCBjcmVhdGVkIG91dHNpZGUgYSBjb21wb3NpdGUgdG8gYmVcbiAgICAgIC8vIGRlZXBseSBtdXRhdGVkIGFuZCByZXVzZWQuXG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgUmVhY3RDb21wb25lbnQuTWl4aW4ucmVjZWl2ZUNvbXBvbmVudC5jYWxsKFxuICAgICAgdGhpcyxcbiAgICAgIG5leHRFbGVtZW50LFxuICAgICAgdHJhbnNhY3Rpb25cbiAgICApO1xuICB9LFxuXG4gIC8qKlxuICAgKiBVcGRhdGVzIHRoZSBjb21wb25lbnQncyBjdXJyZW50bHkgbW91bnRlZCBET00gcmVwcmVzZW50YXRpb24uXG4gICAqXG4gICAqIEJ5IGRlZmF1bHQsIHRoaXMgaW1wbGVtZW50cyBSZWFjdCdzIHJlbmRlcmluZyBhbmQgcmVjb25jaWxpYXRpb24gYWxnb3JpdGhtLlxuICAgKiBTb3BoaXN0aWNhdGVkIGNsaWVudHMgbWF5IHdpc2ggdG8gb3ZlcnJpZGUgdGhpcy5cbiAgICpcbiAgICogQHBhcmFtIHtSZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9ufSB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge1JlYWN0RWxlbWVudH0gcHJldkVsZW1lbnRcbiAgICogQGludGVybmFsXG4gICAqIEBvdmVycmlkYWJsZVxuICAgKi9cbiAgdXBkYXRlQ29tcG9uZW50OiBSZWFjdFBlcmYubWVhc3VyZShcbiAgICAnUmVhY3RDb21wb3NpdGVDb21wb25lbnQnLFxuICAgICd1cGRhdGVDb21wb25lbnQnLFxuICAgIGZ1bmN0aW9uKHRyYW5zYWN0aW9uLCBwcmV2UGFyZW50RWxlbWVudCkge1xuICAgICAgUmVhY3RDb21wb25lbnQuTWl4aW4udXBkYXRlQ29tcG9uZW50LmNhbGwoXG4gICAgICAgIHRoaXMsXG4gICAgICAgIHRyYW5zYWN0aW9uLFxuICAgICAgICBwcmV2UGFyZW50RWxlbWVudFxuICAgICAgKTtcblxuICAgICAgdmFyIHByZXZDb21wb25lbnRJbnN0YW5jZSA9IHRoaXMuX3JlbmRlcmVkQ29tcG9uZW50O1xuICAgICAgdmFyIHByZXZFbGVtZW50ID0gcHJldkNvbXBvbmVudEluc3RhbmNlLl9jdXJyZW50RWxlbWVudDtcbiAgICAgIHZhciBuZXh0RWxlbWVudCA9IHRoaXMuX3JlbmRlclZhbGlkYXRlZENvbXBvbmVudCgpO1xuICAgICAgaWYgKHNob3VsZFVwZGF0ZVJlYWN0Q29tcG9uZW50KHByZXZFbGVtZW50LCBuZXh0RWxlbWVudCkpIHtcbiAgICAgICAgcHJldkNvbXBvbmVudEluc3RhbmNlLnJlY2VpdmVDb21wb25lbnQobmV4dEVsZW1lbnQsIHRyYW5zYWN0aW9uKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIFRoZXNlIHR3byBJRHMgYXJlIGFjdHVhbGx5IHRoZSBzYW1lISBCdXQgbm90aGluZyBzaG91bGQgcmVseSBvbiB0aGF0LlxuICAgICAgICB2YXIgdGhpc0lEID0gdGhpcy5fcm9vdE5vZGVJRDtcbiAgICAgICAgdmFyIHByZXZDb21wb25lbnRJRCA9IHByZXZDb21wb25lbnRJbnN0YW5jZS5fcm9vdE5vZGVJRDtcbiAgICAgICAgcHJldkNvbXBvbmVudEluc3RhbmNlLnVubW91bnRDb21wb25lbnQoKTtcbiAgICAgICAgdGhpcy5fcmVuZGVyZWRDb21wb25lbnQgPSBpbnN0YW50aWF0ZVJlYWN0Q29tcG9uZW50KFxuICAgICAgICAgIG5leHRFbGVtZW50LFxuICAgICAgICAgIHRoaXMuX2N1cnJlbnRFbGVtZW50LnR5cGVcbiAgICAgICAgKTtcbiAgICAgICAgdmFyIG5leHRNYXJrdXAgPSB0aGlzLl9yZW5kZXJlZENvbXBvbmVudC5tb3VudENvbXBvbmVudChcbiAgICAgICAgICB0aGlzSUQsXG4gICAgICAgICAgdHJhbnNhY3Rpb24sXG4gICAgICAgICAgdGhpcy5fbW91bnREZXB0aCArIDFcbiAgICAgICAgKTtcbiAgICAgICAgUmVhY3RDb21wb25lbnQuQmFja2VuZElET3BlcmF0aW9ucy5kYW5nZXJvdXNseVJlcGxhY2VOb2RlV2l0aE1hcmt1cEJ5SUQoXG4gICAgICAgICAgcHJldkNvbXBvbmVudElELFxuICAgICAgICAgIG5leHRNYXJrdXBcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gICksXG5cbiAgLyoqXG4gICAqIEZvcmNlcyBhbiB1cGRhdGUuIFRoaXMgc2hvdWxkIG9ubHkgYmUgaW52b2tlZCB3aGVuIGl0IGlzIGtub3duIHdpdGhcbiAgICogY2VydGFpbnR5IHRoYXQgd2UgYXJlICoqbm90KiogaW4gYSBET00gdHJhbnNhY3Rpb24uXG4gICAqXG4gICAqIFlvdSBtYXkgd2FudCB0byBjYWxsIHRoaXMgd2hlbiB5b3Uga25vdyB0aGF0IHNvbWUgZGVlcGVyIGFzcGVjdCBvZiB0aGVcbiAgICogY29tcG9uZW50J3Mgc3RhdGUgaGFzIGNoYW5nZWQgYnV0IGBzZXRTdGF0ZWAgd2FzIG5vdCBjYWxsZWQuXG4gICAqXG4gICAqIFRoaXMgd2lsbCBub3QgaW52b2tlIGBzaG91bGRVcGRhdGVDb21wb25lbnRgLCBidXQgaXQgd2lsbCBpbnZva2VcbiAgICogYGNvbXBvbmVudFdpbGxVcGRhdGVgIGFuZCBgY29tcG9uZW50RGlkVXBkYXRlYC5cbiAgICpcbiAgICogQHBhcmFtIHs/ZnVuY3Rpb259IGNhbGxiYWNrIENhbGxlZCBhZnRlciB1cGRhdGUgaXMgY29tcGxldGUuXG4gICAqIEBmaW5hbFxuICAgKiBAcHJvdGVjdGVkXG4gICAqL1xuICBmb3JjZVVwZGF0ZTogZnVuY3Rpb24oY2FsbGJhY2spIHtcbiAgICB2YXIgY29tcG9zaXRlTGlmZUN5Y2xlU3RhdGUgPSB0aGlzLl9jb21wb3NpdGVMaWZlQ3ljbGVTdGF0ZTtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgdGhpcy5pc01vdW50ZWQoKSB8fFxuICAgICAgICBjb21wb3NpdGVMaWZlQ3ljbGVTdGF0ZSA9PT0gQ29tcG9zaXRlTGlmZUN5Y2xlLk1PVU5USU5HLFxuICAgICAgJ2ZvcmNlVXBkYXRlKC4uLik6IENhbiBvbmx5IGZvcmNlIGFuIHVwZGF0ZSBvbiBtb3VudGVkIG9yIG1vdW50aW5nICcgK1xuICAgICAgICAnY29tcG9uZW50cy4nXG4gICAgKSA6IGludmFyaWFudCh0aGlzLmlzTW91bnRlZCgpIHx8XG4gICAgICBjb21wb3NpdGVMaWZlQ3ljbGVTdGF0ZSA9PT0gQ29tcG9zaXRlTGlmZUN5Y2xlLk1PVU5USU5HKSk7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgIGNvbXBvc2l0ZUxpZmVDeWNsZVN0YXRlICE9PSBDb21wb3NpdGVMaWZlQ3ljbGUuVU5NT1VOVElORyAmJlxuICAgICAgUmVhY3RDdXJyZW50T3duZXIuY3VycmVudCA9PSBudWxsLFxuICAgICAgJ2ZvcmNlVXBkYXRlKC4uLik6IENhbm5vdCBmb3JjZSBhbiB1cGRhdGUgd2hpbGUgdW5tb3VudGluZyBjb21wb25lbnQgJyArXG4gICAgICAnb3Igd2l0aGluIGEgYHJlbmRlcmAgZnVuY3Rpb24uJ1xuICAgICkgOiBpbnZhcmlhbnQoY29tcG9zaXRlTGlmZUN5Y2xlU3RhdGUgIT09IENvbXBvc2l0ZUxpZmVDeWNsZS5VTk1PVU5USU5HICYmXG4gICAgUmVhY3RDdXJyZW50T3duZXIuY3VycmVudCA9PSBudWxsKSk7XG4gICAgdGhpcy5fcGVuZGluZ0ZvcmNlVXBkYXRlID0gdHJ1ZTtcbiAgICBSZWFjdFVwZGF0ZXMuZW5xdWV1ZVVwZGF0ZSh0aGlzLCBjYWxsYmFjayk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBfcmVuZGVyVmFsaWRhdGVkQ29tcG9uZW50OiBSZWFjdFBlcmYubWVhc3VyZShcbiAgICAnUmVhY3RDb21wb3NpdGVDb21wb25lbnQnLFxuICAgICdfcmVuZGVyVmFsaWRhdGVkQ29tcG9uZW50JyxcbiAgICBmdW5jdGlvbigpIHtcbiAgICAgIHZhciByZW5kZXJlZENvbXBvbmVudDtcbiAgICAgIHZhciBwcmV2aW91c0NvbnRleHQgPSBSZWFjdENvbnRleHQuY3VycmVudDtcbiAgICAgIFJlYWN0Q29udGV4dC5jdXJyZW50ID0gdGhpcy5fcHJvY2Vzc0NoaWxkQ29udGV4dChcbiAgICAgICAgdGhpcy5fY3VycmVudEVsZW1lbnQuX2NvbnRleHRcbiAgICAgICk7XG4gICAgICBSZWFjdEN1cnJlbnRPd25lci5jdXJyZW50ID0gdGhpcztcbiAgICAgIHRyeSB7XG4gICAgICAgIHJlbmRlcmVkQ29tcG9uZW50ID0gdGhpcy5yZW5kZXIoKTtcbiAgICAgICAgaWYgKHJlbmRlcmVkQ29tcG9uZW50ID09PSBudWxsIHx8IHJlbmRlcmVkQ29tcG9uZW50ID09PSBmYWxzZSkge1xuICAgICAgICAgIHJlbmRlcmVkQ29tcG9uZW50ID0gUmVhY3RFbXB0eUNvbXBvbmVudC5nZXRFbXB0eUNvbXBvbmVudCgpO1xuICAgICAgICAgIFJlYWN0RW1wdHlDb21wb25lbnQucmVnaXN0ZXJOdWxsQ29tcG9uZW50SUQodGhpcy5fcm9vdE5vZGVJRCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgUmVhY3RFbXB0eUNvbXBvbmVudC5kZXJlZ2lzdGVyTnVsbENvbXBvbmVudElEKHRoaXMuX3Jvb3ROb2RlSUQpO1xuICAgICAgICB9XG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICBSZWFjdENvbnRleHQuY3VycmVudCA9IHByZXZpb3VzQ29udGV4dDtcbiAgICAgICAgUmVhY3RDdXJyZW50T3duZXIuY3VycmVudCA9IG51bGw7XG4gICAgICB9XG4gICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICBSZWFjdEVsZW1lbnQuaXNWYWxpZEVsZW1lbnQocmVuZGVyZWRDb21wb25lbnQpLFxuICAgICAgICAnJXMucmVuZGVyKCk6IEEgdmFsaWQgUmVhY3RDb21wb25lbnQgbXVzdCBiZSByZXR1cm5lZC4gWW91IG1heSBoYXZlICcgK1xuICAgICAgICAgICdyZXR1cm5lZCB1bmRlZmluZWQsIGFuIGFycmF5IG9yIHNvbWUgb3RoZXIgaW52YWxpZCBvYmplY3QuJyxcbiAgICAgICAgdGhpcy5jb25zdHJ1Y3Rvci5kaXNwbGF5TmFtZSB8fCAnUmVhY3RDb21wb3NpdGVDb21wb25lbnQnXG4gICAgICApIDogaW52YXJpYW50KFJlYWN0RWxlbWVudC5pc1ZhbGlkRWxlbWVudChyZW5kZXJlZENvbXBvbmVudCkpKTtcbiAgICAgIHJldHVybiByZW5kZXJlZENvbXBvbmVudDtcbiAgICB9XG4gICksXG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBfYmluZEF1dG9CaW5kTWV0aG9kczogZnVuY3Rpb24oKSB7XG4gICAgZm9yICh2YXIgYXV0b0JpbmRLZXkgaW4gdGhpcy5fX3JlYWN0QXV0b0JpbmRNYXApIHtcbiAgICAgIGlmICghdGhpcy5fX3JlYWN0QXV0b0JpbmRNYXAuaGFzT3duUHJvcGVydHkoYXV0b0JpbmRLZXkpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgdmFyIG1ldGhvZCA9IHRoaXMuX19yZWFjdEF1dG9CaW5kTWFwW2F1dG9CaW5kS2V5XTtcbiAgICAgIHRoaXNbYXV0b0JpbmRLZXldID0gdGhpcy5fYmluZEF1dG9CaW5kTWV0aG9kKFJlYWN0RXJyb3JVdGlscy5ndWFyZChcbiAgICAgICAgbWV0aG9kLFxuICAgICAgICB0aGlzLmNvbnN0cnVjdG9yLmRpc3BsYXlOYW1lICsgJy4nICsgYXV0b0JpbmRLZXlcbiAgICAgICkpO1xuICAgIH1cbiAgfSxcblxuICAvKipcbiAgICogQmluZHMgYSBtZXRob2QgdG8gdGhlIGNvbXBvbmVudC5cbiAgICpcbiAgICogQHBhcmFtIHtmdW5jdGlvbn0gbWV0aG9kIE1ldGhvZCB0byBiZSBib3VuZC5cbiAgICogQHByaXZhdGVcbiAgICovXG4gIF9iaW5kQXV0b0JpbmRNZXRob2Q6IGZ1bmN0aW9uKG1ldGhvZCkge1xuICAgIHZhciBjb21wb25lbnQgPSB0aGlzO1xuICAgIHZhciBib3VuZE1ldGhvZCA9IG1ldGhvZC5iaW5kKGNvbXBvbmVudCk7XG4gICAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgYm91bmRNZXRob2QuX19yZWFjdEJvdW5kQ29udGV4dCA9IGNvbXBvbmVudDtcbiAgICAgIGJvdW5kTWV0aG9kLl9fcmVhY3RCb3VuZE1ldGhvZCA9IG1ldGhvZDtcbiAgICAgIGJvdW5kTWV0aG9kLl9fcmVhY3RCb3VuZEFyZ3VtZW50cyA9IG51bGw7XG4gICAgICB2YXIgY29tcG9uZW50TmFtZSA9IGNvbXBvbmVudC5jb25zdHJ1Y3Rvci5kaXNwbGF5TmFtZTtcbiAgICAgIHZhciBfYmluZCA9IGJvdW5kTWV0aG9kLmJpbmQ7XG4gICAgICBib3VuZE1ldGhvZC5iaW5kID0gZnVuY3Rpb24obmV3VGhpcyApIHtmb3IgKHZhciBhcmdzPVtdLCRfXzA9MSwkX18xPWFyZ3VtZW50cy5sZW5ndGg7JF9fMDwkX18xOyRfXzArKykgYXJncy5wdXNoKGFyZ3VtZW50c1skX18wXSk7XG4gICAgICAgIC8vIFVzZXIgaXMgdHJ5aW5nIHRvIGJpbmQoKSBhbiBhdXRvYm91bmQgbWV0aG9kOyB3ZSBlZmZlY3RpdmVseSB3aWxsXG4gICAgICAgIC8vIGlnbm9yZSB0aGUgdmFsdWUgb2YgXCJ0aGlzXCIgdGhhdCB0aGUgdXNlciBpcyB0cnlpbmcgdG8gdXNlLCBzb1xuICAgICAgICAvLyBsZXQncyB3YXJuLlxuICAgICAgICBpZiAobmV3VGhpcyAhPT0gY29tcG9uZW50ICYmIG5ld1RoaXMgIT09IG51bGwpIHtcbiAgICAgICAgICBtb25pdG9yQ29kZVVzZSgncmVhY3RfYmluZF93YXJuaW5nJywgeyBjb21wb25lbnQ6IGNvbXBvbmVudE5hbWUgfSk7XG4gICAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgICAgJ2JpbmQoKTogUmVhY3QgY29tcG9uZW50IG1ldGhvZHMgbWF5IG9ubHkgYmUgYm91bmQgdG8gdGhlICcgK1xuICAgICAgICAgICAgJ2NvbXBvbmVudCBpbnN0YW5jZS4gU2VlICcgKyBjb21wb25lbnROYW1lXG4gICAgICAgICAgKTtcbiAgICAgICAgfSBlbHNlIGlmICghYXJncy5sZW5ndGgpIHtcbiAgICAgICAgICBtb25pdG9yQ29kZVVzZSgncmVhY3RfYmluZF93YXJuaW5nJywgeyBjb21wb25lbnQ6IGNvbXBvbmVudE5hbWUgfSk7XG4gICAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgICAgJ2JpbmQoKTogWW91IGFyZSBiaW5kaW5nIGEgY29tcG9uZW50IG1ldGhvZCB0byB0aGUgY29tcG9uZW50LiAnICtcbiAgICAgICAgICAgICdSZWFjdCBkb2VzIHRoaXMgZm9yIHlvdSBhdXRvbWF0aWNhbGx5IGluIGEgaGlnaC1wZXJmb3JtYW5jZSAnICtcbiAgICAgICAgICAgICd3YXksIHNvIHlvdSBjYW4gc2FmZWx5IHJlbW92ZSB0aGlzIGNhbGwuIFNlZSAnICsgY29tcG9uZW50TmFtZVxuICAgICAgICAgICk7XG4gICAgICAgICAgcmV0dXJuIGJvdW5kTWV0aG9kO1xuICAgICAgICB9XG4gICAgICAgIHZhciByZWJvdW5kTWV0aG9kID0gX2JpbmQuYXBwbHkoYm91bmRNZXRob2QsIGFyZ3VtZW50cyk7XG4gICAgICAgIHJlYm91bmRNZXRob2QuX19yZWFjdEJvdW5kQ29udGV4dCA9IGNvbXBvbmVudDtcbiAgICAgICAgcmVib3VuZE1ldGhvZC5fX3JlYWN0Qm91bmRNZXRob2QgPSBtZXRob2Q7XG4gICAgICAgIHJlYm91bmRNZXRob2QuX19yZWFjdEJvdW5kQXJndW1lbnRzID0gYXJncztcbiAgICAgICAgcmV0dXJuIHJlYm91bmRNZXRob2Q7XG4gICAgICB9O1xuICAgIH1cbiAgICByZXR1cm4gYm91bmRNZXRob2Q7XG4gIH1cbn07XG5cbnZhciBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudEJhc2UgPSBmdW5jdGlvbigpIHt9O1xuYXNzaWduKFxuICBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudEJhc2UucHJvdG90eXBlLFxuICBSZWFjdENvbXBvbmVudC5NaXhpbixcbiAgUmVhY3RPd25lci5NaXhpbixcbiAgUmVhY3RQcm9wVHJhbnNmZXJlci5NaXhpbixcbiAgUmVhY3RDb21wb3NpdGVDb21wb25lbnRNaXhpblxuKTtcblxuLyoqXG4gKiBNb2R1bGUgZm9yIGNyZWF0aW5nIGNvbXBvc2l0ZSBjb21wb25lbnRzLlxuICpcbiAqIEBjbGFzcyBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudFxuICogQGV4dGVuZHMgUmVhY3RDb21wb25lbnRcbiAqIEBleHRlbmRzIFJlYWN0T3duZXJcbiAqIEBleHRlbmRzIFJlYWN0UHJvcFRyYW5zZmVyZXJcbiAqL1xudmFyIFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50ID0ge1xuXG4gIExpZmVDeWNsZTogQ29tcG9zaXRlTGlmZUN5Y2xlLFxuXG4gIEJhc2U6IFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50QmFzZSxcblxuICAvKipcbiAgICogQ3JlYXRlcyBhIGNvbXBvc2l0ZSBjb21wb25lbnQgY2xhc3MgZ2l2ZW4gYSBjbGFzcyBzcGVjaWZpY2F0aW9uLlxuICAgKlxuICAgKiBAcGFyYW0ge29iamVjdH0gc3BlYyBDbGFzcyBzcGVjaWZpY2F0aW9uICh3aGljaCBtdXN0IGRlZmluZSBgcmVuZGVyYCkuXG4gICAqIEByZXR1cm4ge2Z1bmN0aW9ufSBDb21wb25lbnQgY29uc3RydWN0b3IgZnVuY3Rpb24uXG4gICAqIEBwdWJsaWNcbiAgICovXG4gIGNyZWF0ZUNsYXNzOiBmdW5jdGlvbihzcGVjKSB7XG4gICAgdmFyIENvbnN0cnVjdG9yID0gZnVuY3Rpb24ocHJvcHMpIHtcbiAgICAgIC8vIFRoaXMgY29uc3RydWN0b3IgaXMgb3ZlcnJpZGRlbiBieSBtb2Nrcy4gVGhlIGFyZ3VtZW50IGlzIHVzZWRcbiAgICAgIC8vIGJ5IG1vY2tzIHRvIGFzc2VydCBvbiB3aGF0IGdldHMgbW91bnRlZC4gVGhpcyB3aWxsIGxhdGVyIGJlIHVzZWRcbiAgICAgIC8vIGJ5IHRoZSBzdGFuZC1hbG9uZSBjbGFzcyBpbXBsZW1lbnRhdGlvbi5cbiAgICB9O1xuICAgIENvbnN0cnVjdG9yLnByb3RvdHlwZSA9IG5ldyBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudEJhc2UoKTtcbiAgICBDb25zdHJ1Y3Rvci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBDb25zdHJ1Y3RvcjtcblxuICAgIGluamVjdGVkTWl4aW5zLmZvckVhY2goXG4gICAgICBtaXhTcGVjSW50b0NvbXBvbmVudC5iaW5kKG51bGwsIENvbnN0cnVjdG9yKVxuICAgICk7XG5cbiAgICBtaXhTcGVjSW50b0NvbXBvbmVudChDb25zdHJ1Y3Rvciwgc3BlYyk7XG5cbiAgICAvLyBJbml0aWFsaXplIHRoZSBkZWZhdWx0UHJvcHMgcHJvcGVydHkgYWZ0ZXIgYWxsIG1peGlucyBoYXZlIGJlZW4gbWVyZ2VkXG4gICAgaWYgKENvbnN0cnVjdG9yLmdldERlZmF1bHRQcm9wcykge1xuICAgICAgQ29uc3RydWN0b3IuZGVmYXVsdFByb3BzID0gQ29uc3RydWN0b3IuZ2V0RGVmYXVsdFByb3BzKCk7XG4gICAgfVxuXG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgIENvbnN0cnVjdG9yLnByb3RvdHlwZS5yZW5kZXIsXG4gICAgICAnY3JlYXRlQ2xhc3MoLi4uKTogQ2xhc3Mgc3BlY2lmaWNhdGlvbiBtdXN0IGltcGxlbWVudCBhIGByZW5kZXJgIG1ldGhvZC4nXG4gICAgKSA6IGludmFyaWFudChDb25zdHJ1Y3Rvci5wcm90b3R5cGUucmVuZGVyKSk7XG5cbiAgICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgICBpZiAoQ29uc3RydWN0b3IucHJvdG90eXBlLmNvbXBvbmVudFNob3VsZFVwZGF0ZSkge1xuICAgICAgICBtb25pdG9yQ29kZVVzZShcbiAgICAgICAgICAncmVhY3RfY29tcG9uZW50X3Nob3VsZF91cGRhdGVfd2FybmluZycsXG4gICAgICAgICAgeyBjb21wb25lbnQ6IHNwZWMuZGlzcGxheU5hbWUgfVxuICAgICAgICApO1xuICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgKHNwZWMuZGlzcGxheU5hbWUgfHwgJ0EgY29tcG9uZW50JykgKyAnIGhhcyBhIG1ldGhvZCBjYWxsZWQgJyArXG4gICAgICAgICAgJ2NvbXBvbmVudFNob3VsZFVwZGF0ZSgpLiBEaWQgeW91IG1lYW4gc2hvdWxkQ29tcG9uZW50VXBkYXRlKCk/ICcgK1xuICAgICAgICAgICdUaGUgbmFtZSBpcyBwaHJhc2VkIGFzIGEgcXVlc3Rpb24gYmVjYXVzZSB0aGUgZnVuY3Rpb24gaXMgJyArXG4gICAgICAgICAgJ2V4cGVjdGVkIHRvIHJldHVybiBhIHZhbHVlLidcbiAgICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gUmVkdWNlIHRpbWUgc3BlbnQgZG9pbmcgbG9va3VwcyBieSBzZXR0aW5nIHRoZXNlIG9uIHRoZSBwcm90b3R5cGUuXG4gICAgZm9yICh2YXIgbWV0aG9kTmFtZSBpbiBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudEludGVyZmFjZSkge1xuICAgICAgaWYgKCFDb25zdHJ1Y3Rvci5wcm90b3R5cGVbbWV0aG9kTmFtZV0pIHtcbiAgICAgICAgQ29uc3RydWN0b3IucHJvdG90eXBlW21ldGhvZE5hbWVdID0gbnVsbDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgICByZXR1cm4gUmVhY3RMZWdhY3lFbGVtZW50LndyYXBGYWN0b3J5KFxuICAgICAgICBSZWFjdEVsZW1lbnRWYWxpZGF0b3IuY3JlYXRlRmFjdG9yeShDb25zdHJ1Y3RvcilcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBSZWFjdExlZ2FjeUVsZW1lbnQud3JhcEZhY3RvcnkoXG4gICAgICBSZWFjdEVsZW1lbnQuY3JlYXRlRmFjdG9yeShDb25zdHJ1Y3RvcilcbiAgICApO1xuICB9LFxuXG4gIGluamVjdGlvbjoge1xuICAgIGluamVjdE1peGluOiBmdW5jdGlvbihtaXhpbikge1xuICAgICAgaW5qZWN0ZWRNaXhpbnMucHVzaChtaXhpbik7XG4gICAgfVxuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50O1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RDb250ZXh0XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBhc3NpZ24gPSByZXF1aXJlKFwiLi9PYmplY3QuYXNzaWduXCIpO1xuXG4vKipcbiAqIEtlZXBzIHRyYWNrIG9mIHRoZSBjdXJyZW50IGNvbnRleHQuXG4gKlxuICogVGhlIGNvbnRleHQgaXMgYXV0b21hdGljYWxseSBwYXNzZWQgZG93biB0aGUgY29tcG9uZW50IG93bmVyc2hpcCBoaWVyYXJjaHlcbiAqIGFuZCBpcyBhY2Nlc3NpYmxlIHZpYSBgdGhpcy5jb250ZXh0YCBvbiBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudHMuXG4gKi9cbnZhciBSZWFjdENvbnRleHQgPSB7XG5cbiAgLyoqXG4gICAqIEBpbnRlcm5hbFxuICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgKi9cbiAgY3VycmVudDoge30sXG5cbiAgLyoqXG4gICAqIFRlbXBvcmFyaWx5IGV4dGVuZHMgdGhlIGN1cnJlbnQgY29udGV4dCB3aGlsZSBleGVjdXRpbmcgc2NvcGVkQ2FsbGJhY2suXG4gICAqXG4gICAqIEEgdHlwaWNhbCB1c2UgY2FzZSBtaWdodCBsb29rIGxpa2VcbiAgICpcbiAgICogIHJlbmRlcjogZnVuY3Rpb24oKSB7XG4gICAqICAgIHZhciBjaGlsZHJlbiA9IFJlYWN0Q29udGV4dC53aXRoQ29udGV4dCh7Zm9vOiAnZm9vJ30sICgpID0+IChcbiAgICpcbiAgICogICAgKSk7XG4gICAqICAgIHJldHVybiA8ZGl2PntjaGlsZHJlbn08L2Rpdj47XG4gICAqICB9XG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBuZXdDb250ZXh0IE5ldyBjb250ZXh0IHRvIG1lcmdlIGludG8gdGhlIGV4aXN0aW5nIGNvbnRleHRcbiAgICogQHBhcmFtIHtmdW5jdGlvbn0gc2NvcGVkQ2FsbGJhY2sgQ2FsbGJhY2sgdG8gcnVuIHdpdGggdGhlIG5ldyBjb250ZXh0XG4gICAqIEByZXR1cm4ge1JlYWN0Q29tcG9uZW50fGFycmF5PFJlYWN0Q29tcG9uZW50Pn1cbiAgICovXG4gIHdpdGhDb250ZXh0OiBmdW5jdGlvbihuZXdDb250ZXh0LCBzY29wZWRDYWxsYmFjaykge1xuICAgIHZhciByZXN1bHQ7XG4gICAgdmFyIHByZXZpb3VzQ29udGV4dCA9IFJlYWN0Q29udGV4dC5jdXJyZW50O1xuICAgIFJlYWN0Q29udGV4dC5jdXJyZW50ID0gYXNzaWduKHt9LCBwcmV2aW91c0NvbnRleHQsIG5ld0NvbnRleHQpO1xuICAgIHRyeSB7XG4gICAgICByZXN1bHQgPSBzY29wZWRDYWxsYmFjaygpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBSZWFjdENvbnRleHQuY3VycmVudCA9IHByZXZpb3VzQ29udGV4dDtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0Q29udGV4dDtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdEN1cnJlbnRPd25lclxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG4vKipcbiAqIEtlZXBzIHRyYWNrIG9mIHRoZSBjdXJyZW50IG93bmVyLlxuICpcbiAqIFRoZSBjdXJyZW50IG93bmVyIGlzIHRoZSBjb21wb25lbnQgd2hvIHNob3VsZCBvd24gYW55IGNvbXBvbmVudHMgdGhhdCBhcmVcbiAqIGN1cnJlbnRseSBiZWluZyBjb25zdHJ1Y3RlZC5cbiAqXG4gKiBUaGUgZGVwdGggaW5kaWNhdGUgaG93IG1hbnkgY29tcG9zaXRlIGNvbXBvbmVudHMgYXJlIGFib3ZlIHRoaXMgcmVuZGVyIGxldmVsLlxuICovXG52YXIgUmVhY3RDdXJyZW50T3duZXIgPSB7XG5cbiAgLyoqXG4gICAqIEBpbnRlcm5hbFxuICAgKiBAdHlwZSB7UmVhY3RDb21wb25lbnR9XG4gICAqL1xuICBjdXJyZW50OiBudWxsXG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RDdXJyZW50T3duZXI7XG4iLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0RE9NXG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgUmVhY3RFbGVtZW50ID0gcmVxdWlyZShcIi4vUmVhY3RFbGVtZW50XCIpO1xudmFyIFJlYWN0RWxlbWVudFZhbGlkYXRvciA9IHJlcXVpcmUoXCIuL1JlYWN0RWxlbWVudFZhbGlkYXRvclwiKTtcbnZhciBSZWFjdExlZ2FjeUVsZW1lbnQgPSByZXF1aXJlKFwiLi9SZWFjdExlZ2FjeUVsZW1lbnRcIik7XG5cbnZhciBtYXBPYmplY3QgPSByZXF1aXJlKFwiLi9tYXBPYmplY3RcIik7XG5cbi8qKlxuICogQ3JlYXRlIGEgZmFjdG9yeSB0aGF0IGNyZWF0ZXMgSFRNTCB0YWcgZWxlbWVudHMuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHRhZyBUYWcgbmFtZSAoZS5nLiBgZGl2YCkuXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBjcmVhdGVET01GYWN0b3J5KHRhZykge1xuICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgcmV0dXJuIFJlYWN0TGVnYWN5RWxlbWVudC5tYXJrTm9uTGVnYWN5RmFjdG9yeShcbiAgICAgIFJlYWN0RWxlbWVudFZhbGlkYXRvci5jcmVhdGVGYWN0b3J5KHRhZylcbiAgICApO1xuICB9XG4gIHJldHVybiBSZWFjdExlZ2FjeUVsZW1lbnQubWFya05vbkxlZ2FjeUZhY3RvcnkoXG4gICAgUmVhY3RFbGVtZW50LmNyZWF0ZUZhY3RvcnkodGFnKVxuICApO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBtYXBwaW5nIGZyb20gc3VwcG9ydGVkIEhUTUwgdGFncyB0byBgUmVhY3RET01Db21wb25lbnRgIGNsYXNzZXMuXG4gKiBUaGlzIGlzIGFsc28gYWNjZXNzaWJsZSB2aWEgYFJlYWN0LkRPTWAuXG4gKlxuICogQHB1YmxpY1xuICovXG52YXIgUmVhY3RET00gPSBtYXBPYmplY3Qoe1xuICBhOiAnYScsXG4gIGFiYnI6ICdhYmJyJyxcbiAgYWRkcmVzczogJ2FkZHJlc3MnLFxuICBhcmVhOiAnYXJlYScsXG4gIGFydGljbGU6ICdhcnRpY2xlJyxcbiAgYXNpZGU6ICdhc2lkZScsXG4gIGF1ZGlvOiAnYXVkaW8nLFxuICBiOiAnYicsXG4gIGJhc2U6ICdiYXNlJyxcbiAgYmRpOiAnYmRpJyxcbiAgYmRvOiAnYmRvJyxcbiAgYmlnOiAnYmlnJyxcbiAgYmxvY2txdW90ZTogJ2Jsb2NrcXVvdGUnLFxuICBib2R5OiAnYm9keScsXG4gIGJyOiAnYnInLFxuICBidXR0b246ICdidXR0b24nLFxuICBjYW52YXM6ICdjYW52YXMnLFxuICBjYXB0aW9uOiAnY2FwdGlvbicsXG4gIGNpdGU6ICdjaXRlJyxcbiAgY29kZTogJ2NvZGUnLFxuICBjb2w6ICdjb2wnLFxuICBjb2xncm91cDogJ2NvbGdyb3VwJyxcbiAgZGF0YTogJ2RhdGEnLFxuICBkYXRhbGlzdDogJ2RhdGFsaXN0JyxcbiAgZGQ6ICdkZCcsXG4gIGRlbDogJ2RlbCcsXG4gIGRldGFpbHM6ICdkZXRhaWxzJyxcbiAgZGZuOiAnZGZuJyxcbiAgZGlhbG9nOiAnZGlhbG9nJyxcbiAgZGl2OiAnZGl2JyxcbiAgZGw6ICdkbCcsXG4gIGR0OiAnZHQnLFxuICBlbTogJ2VtJyxcbiAgZW1iZWQ6ICdlbWJlZCcsXG4gIGZpZWxkc2V0OiAnZmllbGRzZXQnLFxuICBmaWdjYXB0aW9uOiAnZmlnY2FwdGlvbicsXG4gIGZpZ3VyZTogJ2ZpZ3VyZScsXG4gIGZvb3RlcjogJ2Zvb3RlcicsXG4gIGZvcm06ICdmb3JtJyxcbiAgaDE6ICdoMScsXG4gIGgyOiAnaDInLFxuICBoMzogJ2gzJyxcbiAgaDQ6ICdoNCcsXG4gIGg1OiAnaDUnLFxuICBoNjogJ2g2JyxcbiAgaGVhZDogJ2hlYWQnLFxuICBoZWFkZXI6ICdoZWFkZXInLFxuICBocjogJ2hyJyxcbiAgaHRtbDogJ2h0bWwnLFxuICBpOiAnaScsXG4gIGlmcmFtZTogJ2lmcmFtZScsXG4gIGltZzogJ2ltZycsXG4gIGlucHV0OiAnaW5wdXQnLFxuICBpbnM6ICdpbnMnLFxuICBrYmQ6ICdrYmQnLFxuICBrZXlnZW46ICdrZXlnZW4nLFxuICBsYWJlbDogJ2xhYmVsJyxcbiAgbGVnZW5kOiAnbGVnZW5kJyxcbiAgbGk6ICdsaScsXG4gIGxpbms6ICdsaW5rJyxcbiAgbWFpbjogJ21haW4nLFxuICBtYXA6ICdtYXAnLFxuICBtYXJrOiAnbWFyaycsXG4gIG1lbnU6ICdtZW51JyxcbiAgbWVudWl0ZW06ICdtZW51aXRlbScsXG4gIG1ldGE6ICdtZXRhJyxcbiAgbWV0ZXI6ICdtZXRlcicsXG4gIG5hdjogJ25hdicsXG4gIG5vc2NyaXB0OiAnbm9zY3JpcHQnLFxuICBvYmplY3Q6ICdvYmplY3QnLFxuICBvbDogJ29sJyxcbiAgb3B0Z3JvdXA6ICdvcHRncm91cCcsXG4gIG9wdGlvbjogJ29wdGlvbicsXG4gIG91dHB1dDogJ291dHB1dCcsXG4gIHA6ICdwJyxcbiAgcGFyYW06ICdwYXJhbScsXG4gIHBpY3R1cmU6ICdwaWN0dXJlJyxcbiAgcHJlOiAncHJlJyxcbiAgcHJvZ3Jlc3M6ICdwcm9ncmVzcycsXG4gIHE6ICdxJyxcbiAgcnA6ICdycCcsXG4gIHJ0OiAncnQnLFxuICBydWJ5OiAncnVieScsXG4gIHM6ICdzJyxcbiAgc2FtcDogJ3NhbXAnLFxuICBzY3JpcHQ6ICdzY3JpcHQnLFxuICBzZWN0aW9uOiAnc2VjdGlvbicsXG4gIHNlbGVjdDogJ3NlbGVjdCcsXG4gIHNtYWxsOiAnc21hbGwnLFxuICBzb3VyY2U6ICdzb3VyY2UnLFxuICBzcGFuOiAnc3BhbicsXG4gIHN0cm9uZzogJ3N0cm9uZycsXG4gIHN0eWxlOiAnc3R5bGUnLFxuICBzdWI6ICdzdWInLFxuICBzdW1tYXJ5OiAnc3VtbWFyeScsXG4gIHN1cDogJ3N1cCcsXG4gIHRhYmxlOiAndGFibGUnLFxuICB0Ym9keTogJ3Rib2R5JyxcbiAgdGQ6ICd0ZCcsXG4gIHRleHRhcmVhOiAndGV4dGFyZWEnLFxuICB0Zm9vdDogJ3Rmb290JyxcbiAgdGg6ICd0aCcsXG4gIHRoZWFkOiAndGhlYWQnLFxuICB0aW1lOiAndGltZScsXG4gIHRpdGxlOiAndGl0bGUnLFxuICB0cjogJ3RyJyxcbiAgdHJhY2s6ICd0cmFjaycsXG4gIHU6ICd1JyxcbiAgdWw6ICd1bCcsXG4gICd2YXInOiAndmFyJyxcbiAgdmlkZW86ICd2aWRlbycsXG4gIHdicjogJ3dicicsXG5cbiAgLy8gU1ZHXG4gIGNpcmNsZTogJ2NpcmNsZScsXG4gIGRlZnM6ICdkZWZzJyxcbiAgZWxsaXBzZTogJ2VsbGlwc2UnLFxuICBnOiAnZycsXG4gIGxpbmU6ICdsaW5lJyxcbiAgbGluZWFyR3JhZGllbnQ6ICdsaW5lYXJHcmFkaWVudCcsXG4gIG1hc2s6ICdtYXNrJyxcbiAgcGF0aDogJ3BhdGgnLFxuICBwYXR0ZXJuOiAncGF0dGVybicsXG4gIHBvbHlnb246ICdwb2x5Z29uJyxcbiAgcG9seWxpbmU6ICdwb2x5bGluZScsXG4gIHJhZGlhbEdyYWRpZW50OiAncmFkaWFsR3JhZGllbnQnLFxuICByZWN0OiAncmVjdCcsXG4gIHN0b3A6ICdzdG9wJyxcbiAgc3ZnOiAnc3ZnJyxcbiAgdGV4dDogJ3RleHQnLFxuICB0c3BhbjogJ3RzcGFuJ1xuXG59LCBjcmVhdGVET01GYWN0b3J5KTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdERPTTtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0RE9NQnV0dG9uXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBBdXRvRm9jdXNNaXhpbiA9IHJlcXVpcmUoXCIuL0F1dG9Gb2N1c01peGluXCIpO1xudmFyIFJlYWN0QnJvd3NlckNvbXBvbmVudE1peGluID0gcmVxdWlyZShcIi4vUmVhY3RCcm93c2VyQ29tcG9uZW50TWl4aW5cIik7XG52YXIgUmVhY3RDb21wb3NpdGVDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdENvbXBvc2l0ZUNvbXBvbmVudFwiKTtcbnZhciBSZWFjdEVsZW1lbnQgPSByZXF1aXJlKFwiLi9SZWFjdEVsZW1lbnRcIik7XG52YXIgUmVhY3RET00gPSByZXF1aXJlKFwiLi9SZWFjdERPTVwiKTtcblxudmFyIGtleU1pcnJvciA9IHJlcXVpcmUoXCIuL2tleU1pcnJvclwiKTtcblxuLy8gU3RvcmUgYSByZWZlcmVuY2UgdG8gdGhlIDxidXR0b24+IGBSZWFjdERPTUNvbXBvbmVudGAuIFRPRE86IHVzZSBzdHJpbmdcbnZhciBidXR0b24gPSBSZWFjdEVsZW1lbnQuY3JlYXRlRmFjdG9yeShSZWFjdERPTS5idXR0b24udHlwZSk7XG5cbnZhciBtb3VzZUxpc3RlbmVyTmFtZXMgPSBrZXlNaXJyb3Ioe1xuICBvbkNsaWNrOiB0cnVlLFxuICBvbkRvdWJsZUNsaWNrOiB0cnVlLFxuICBvbk1vdXNlRG93bjogdHJ1ZSxcbiAgb25Nb3VzZU1vdmU6IHRydWUsXG4gIG9uTW91c2VVcDogdHJ1ZSxcbiAgb25DbGlja0NhcHR1cmU6IHRydWUsXG4gIG9uRG91YmxlQ2xpY2tDYXB0dXJlOiB0cnVlLFxuICBvbk1vdXNlRG93bkNhcHR1cmU6IHRydWUsXG4gIG9uTW91c2VNb3ZlQ2FwdHVyZTogdHJ1ZSxcbiAgb25Nb3VzZVVwQ2FwdHVyZTogdHJ1ZVxufSk7XG5cbi8qKlxuICogSW1wbGVtZW50cyBhIDxidXR0b24+IG5hdGl2ZSBjb21wb25lbnQgdGhhdCBkb2VzIG5vdCByZWNlaXZlIG1vdXNlIGV2ZW50c1xuICogd2hlbiBgZGlzYWJsZWRgIGlzIHNldC5cbiAqL1xudmFyIFJlYWN0RE9NQnV0dG9uID0gUmVhY3RDb21wb3NpdGVDb21wb25lbnQuY3JlYXRlQ2xhc3Moe1xuICBkaXNwbGF5TmFtZTogJ1JlYWN0RE9NQnV0dG9uJyxcblxuICBtaXhpbnM6IFtBdXRvRm9jdXNNaXhpbiwgUmVhY3RCcm93c2VyQ29tcG9uZW50TWl4aW5dLFxuXG4gIHJlbmRlcjogZnVuY3Rpb24oKSB7XG4gICAgdmFyIHByb3BzID0ge307XG5cbiAgICAvLyBDb3B5IHRoZSBwcm9wczsgZXhjZXB0IHRoZSBtb3VzZSBsaXN0ZW5lcnMgaWYgd2UncmUgZGlzYWJsZWRcbiAgICBmb3IgKHZhciBrZXkgaW4gdGhpcy5wcm9wcykge1xuICAgICAgaWYgKHRoaXMucHJvcHMuaGFzT3duUHJvcGVydHkoa2V5KSAmJlxuICAgICAgICAgICghdGhpcy5wcm9wcy5kaXNhYmxlZCB8fCAhbW91c2VMaXN0ZW5lck5hbWVzW2tleV0pKSB7XG4gICAgICAgIHByb3BzW2tleV0gPSB0aGlzLnByb3BzW2tleV07XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGJ1dHRvbihwcm9wcywgdGhpcy5wcm9wcy5jaGlsZHJlbik7XG4gIH1cblxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RET01CdXR0b247XG4iLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0RE9NQ29tcG9uZW50XG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgQ1NTUHJvcGVydHlPcGVyYXRpb25zID0gcmVxdWlyZShcIi4vQ1NTUHJvcGVydHlPcGVyYXRpb25zXCIpO1xudmFyIERPTVByb3BlcnR5ID0gcmVxdWlyZShcIi4vRE9NUHJvcGVydHlcIik7XG52YXIgRE9NUHJvcGVydHlPcGVyYXRpb25zID0gcmVxdWlyZShcIi4vRE9NUHJvcGVydHlPcGVyYXRpb25zXCIpO1xudmFyIFJlYWN0QnJvd3NlckNvbXBvbmVudE1peGluID0gcmVxdWlyZShcIi4vUmVhY3RCcm93c2VyQ29tcG9uZW50TWl4aW5cIik7XG52YXIgUmVhY3RDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdENvbXBvbmVudFwiKTtcbnZhciBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIgPSByZXF1aXJlKFwiLi9SZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXJcIik7XG52YXIgUmVhY3RNb3VudCA9IHJlcXVpcmUoXCIuL1JlYWN0TW91bnRcIik7XG52YXIgUmVhY3RNdWx0aUNoaWxkID0gcmVxdWlyZShcIi4vUmVhY3RNdWx0aUNoaWxkXCIpO1xudmFyIFJlYWN0UGVyZiA9IHJlcXVpcmUoXCIuL1JlYWN0UGVyZlwiKTtcblxudmFyIGFzc2lnbiA9IHJlcXVpcmUoXCIuL09iamVjdC5hc3NpZ25cIik7XG52YXIgZXNjYXBlVGV4dEZvckJyb3dzZXIgPSByZXF1aXJlKFwiLi9lc2NhcGVUZXh0Rm9yQnJvd3NlclwiKTtcbnZhciBpbnZhcmlhbnQgPSByZXF1aXJlKFwiLi9pbnZhcmlhbnRcIik7XG52YXIgaXNFdmVudFN1cHBvcnRlZCA9IHJlcXVpcmUoXCIuL2lzRXZlbnRTdXBwb3J0ZWRcIik7XG52YXIga2V5T2YgPSByZXF1aXJlKFwiLi9rZXlPZlwiKTtcbnZhciBtb25pdG9yQ29kZVVzZSA9IHJlcXVpcmUoXCIuL21vbml0b3JDb2RlVXNlXCIpO1xuXG52YXIgZGVsZXRlTGlzdGVuZXIgPSBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIuZGVsZXRlTGlzdGVuZXI7XG52YXIgbGlzdGVuVG8gPSBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIubGlzdGVuVG87XG52YXIgcmVnaXN0cmF0aW9uTmFtZU1vZHVsZXMgPSBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIucmVnaXN0cmF0aW9uTmFtZU1vZHVsZXM7XG5cbi8vIEZvciBxdWlja2x5IG1hdGNoaW5nIGNoaWxkcmVuIHR5cGUsIHRvIHRlc3QgaWYgY2FuIGJlIHRyZWF0ZWQgYXMgY29udGVudC5cbnZhciBDT05URU5UX1RZUEVTID0geydzdHJpbmcnOiB0cnVlLCAnbnVtYmVyJzogdHJ1ZX07XG5cbnZhciBTVFlMRSA9IGtleU9mKHtzdHlsZTogbnVsbH0pO1xuXG52YXIgRUxFTUVOVF9OT0RFX1RZUEUgPSAxO1xuXG4vKipcbiAqIEBwYXJhbSB7P29iamVjdH0gcHJvcHNcbiAqL1xuZnVuY3Rpb24gYXNzZXJ0VmFsaWRQcm9wcyhwcm9wcykge1xuICBpZiAoIXByb3BzKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIC8vIE5vdGUgdGhlIHVzZSBvZiBgPT1gIHdoaWNoIGNoZWNrcyBmb3IgbnVsbCBvciB1bmRlZmluZWQuXG4gIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgcHJvcHMuY2hpbGRyZW4gPT0gbnVsbCB8fCBwcm9wcy5kYW5nZXJvdXNseVNldElubmVySFRNTCA9PSBudWxsLFxuICAgICdDYW4gb25seSBzZXQgb25lIG9mIGBjaGlsZHJlbmAgb3IgYHByb3BzLmRhbmdlcm91c2x5U2V0SW5uZXJIVE1MYC4nXG4gICkgOiBpbnZhcmlhbnQocHJvcHMuY2hpbGRyZW4gPT0gbnVsbCB8fCBwcm9wcy5kYW5nZXJvdXNseVNldElubmVySFRNTCA9PSBudWxsKSk7XG4gIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICBpZiAocHJvcHMuY29udGVudEVkaXRhYmxlICYmIHByb3BzLmNoaWxkcmVuICE9IG51bGwpIHtcbiAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgJ0EgY29tcG9uZW50IGlzIGBjb250ZW50RWRpdGFibGVgIGFuZCBjb250YWlucyBgY2hpbGRyZW5gIG1hbmFnZWQgYnkgJyArXG4gICAgICAgICdSZWFjdC4gSXQgaXMgbm93IHlvdXIgcmVzcG9uc2liaWxpdHkgdG8gZ3VhcmFudGVlIHRoYXQgbm9uZSBvZiB0aG9zZSAnK1xuICAgICAgICAnbm9kZXMgYXJlIHVuZXhwZWN0ZWRseSBtb2RpZmllZCBvciBkdXBsaWNhdGVkLiBUaGlzIGlzIHByb2JhYmx5IG5vdCAnICtcbiAgICAgICAgJ2ludGVudGlvbmFsLidcbiAgICAgICk7XG4gICAgfVxuICB9XG4gIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgcHJvcHMuc3R5bGUgPT0gbnVsbCB8fCB0eXBlb2YgcHJvcHMuc3R5bGUgPT09ICdvYmplY3QnLFxuICAgICdUaGUgYHN0eWxlYCBwcm9wIGV4cGVjdHMgYSBtYXBwaW5nIGZyb20gc3R5bGUgcHJvcGVydGllcyB0byB2YWx1ZXMsICcgK1xuICAgICdub3QgYSBzdHJpbmcuJ1xuICApIDogaW52YXJpYW50KHByb3BzLnN0eWxlID09IG51bGwgfHwgdHlwZW9mIHByb3BzLnN0eWxlID09PSAnb2JqZWN0JykpO1xufVxuXG5mdW5jdGlvbiBwdXRMaXN0ZW5lcihpZCwgcmVnaXN0cmF0aW9uTmFtZSwgbGlzdGVuZXIsIHRyYW5zYWN0aW9uKSB7XG4gIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAvLyBJRTggaGFzIG5vIEFQSSBmb3IgZXZlbnQgY2FwdHVyaW5nIGFuZCB0aGUgYG9uU2Nyb2xsYCBldmVudCBkb2Vzbid0XG4gICAgLy8gYnViYmxlLlxuICAgIGlmIChyZWdpc3RyYXRpb25OYW1lID09PSAnb25TY3JvbGwnICYmXG4gICAgICAgICFpc0V2ZW50U3VwcG9ydGVkKCdzY3JvbGwnLCB0cnVlKSkge1xuICAgICAgbW9uaXRvckNvZGVVc2UoJ3JlYWN0X25vX3Njcm9sbF9ldmVudCcpO1xuICAgICAgY29uc29sZS53YXJuKCdUaGlzIGJyb3dzZXIgZG9lc25cXCd0IHN1cHBvcnQgdGhlIGBvblNjcm9sbGAgZXZlbnQnKTtcbiAgICB9XG4gIH1cbiAgdmFyIGNvbnRhaW5lciA9IFJlYWN0TW91bnQuZmluZFJlYWN0Q29udGFpbmVyRm9ySUQoaWQpO1xuICBpZiAoY29udGFpbmVyKSB7XG4gICAgdmFyIGRvYyA9IGNvbnRhaW5lci5ub2RlVHlwZSA9PT0gRUxFTUVOVF9OT0RFX1RZUEUgP1xuICAgICAgY29udGFpbmVyLm93bmVyRG9jdW1lbnQgOlxuICAgICAgY29udGFpbmVyO1xuICAgIGxpc3RlblRvKHJlZ2lzdHJhdGlvbk5hbWUsIGRvYyk7XG4gIH1cbiAgdHJhbnNhY3Rpb24uZ2V0UHV0TGlzdGVuZXJRdWV1ZSgpLmVucXVldWVQdXRMaXN0ZW5lcihcbiAgICBpZCxcbiAgICByZWdpc3RyYXRpb25OYW1lLFxuICAgIGxpc3RlbmVyXG4gICk7XG59XG5cbi8vIEZvciBIVE1MLCBjZXJ0YWluIHRhZ3Mgc2hvdWxkIG9taXQgdGhlaXIgY2xvc2UgdGFnLiBXZSBrZWVwIGEgd2hpdGVsaXN0IGZvclxuLy8gdGhvc2Ugc3BlY2lhbCBjYXNlZCB0YWdzLlxuXG52YXIgb21pdHRlZENsb3NlVGFncyA9IHtcbiAgJ2FyZWEnOiB0cnVlLFxuICAnYmFzZSc6IHRydWUsXG4gICdicic6IHRydWUsXG4gICdjb2wnOiB0cnVlLFxuICAnZW1iZWQnOiB0cnVlLFxuICAnaHInOiB0cnVlLFxuICAnaW1nJzogdHJ1ZSxcbiAgJ2lucHV0JzogdHJ1ZSxcbiAgJ2tleWdlbic6IHRydWUsXG4gICdsaW5rJzogdHJ1ZSxcbiAgJ21ldGEnOiB0cnVlLFxuICAncGFyYW0nOiB0cnVlLFxuICAnc291cmNlJzogdHJ1ZSxcbiAgJ3RyYWNrJzogdHJ1ZSxcbiAgJ3dicic6IHRydWVcbiAgLy8gTk9URTogbWVudWl0ZW0ncyBjbG9zZSB0YWcgc2hvdWxkIGJlIG9taXR0ZWQsIGJ1dCB0aGF0IGNhdXNlcyBwcm9ibGVtcy5cbn07XG5cbi8vIFdlIGFjY2VwdCBhbnkgdGFnIHRvIGJlIHJlbmRlcmVkIGJ1dCBzaW5jZSB0aGlzIGdldHMgaW5qZWN0ZWQgaW50byBhYml0cmFyeVxuLy8gSFRNTCwgd2Ugd2FudCB0byBtYWtlIHN1cmUgdGhhdCBpdCdzIGEgc2FmZSB0YWcuXG4vLyBodHRwOi8vd3d3LnczLm9yZy9UUi9SRUMteG1sLyNOVC1OYW1lXG5cbnZhciBWQUxJRF9UQUdfUkVHRVggPSAvXlthLXpBLVpdW2EtekEtWjpfXFwuXFwtXFxkXSokLzsgLy8gU2ltcGxpZmllZCBzdWJzZXRcbnZhciB2YWxpZGF0ZWRUYWdDYWNoZSA9IHt9O1xudmFyIGhhc093blByb3BlcnR5ID0ge30uaGFzT3duUHJvcGVydHk7XG5cbmZ1bmN0aW9uIHZhbGlkYXRlRGFuZ2Vyb3VzVGFnKHRhZykge1xuICBpZiAoIWhhc093blByb3BlcnR5LmNhbGwodmFsaWRhdGVkVGFnQ2FjaGUsIHRhZykpIHtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFZBTElEX1RBR19SRUdFWC50ZXN0KHRhZyksICdJbnZhbGlkIHRhZzogJXMnLCB0YWcpIDogaW52YXJpYW50KFZBTElEX1RBR19SRUdFWC50ZXN0KHRhZykpKTtcbiAgICB2YWxpZGF0ZWRUYWdDYWNoZVt0YWddID0gdHJ1ZTtcbiAgfVxufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBuZXcgUmVhY3QgY2xhc3MgdGhhdCBpcyBpZGVtcG90ZW50IGFuZCBjYXBhYmxlIG9mIGNvbnRhaW5pbmcgb3RoZXJcbiAqIFJlYWN0IGNvbXBvbmVudHMuIEl0IGFjY2VwdHMgZXZlbnQgbGlzdGVuZXJzIGFuZCBET00gcHJvcGVydGllcyB0aGF0IGFyZVxuICogdmFsaWQgYWNjb3JkaW5nIHRvIGBET01Qcm9wZXJ0eWAuXG4gKlxuICogIC0gRXZlbnQgbGlzdGVuZXJzOiBgb25DbGlja2AsIGBvbk1vdXNlRG93bmAsIGV0Yy5cbiAqICAtIERPTSBwcm9wZXJ0aWVzOiBgY2xhc3NOYW1lYCwgYG5hbWVgLCBgdGl0bGVgLCBldGMuXG4gKlxuICogVGhlIGBzdHlsZWAgcHJvcGVydHkgZnVuY3Rpb25zIGRpZmZlcmVudGx5IGZyb20gdGhlIERPTSBBUEkuIEl0IGFjY2VwdHMgYW5cbiAqIG9iamVjdCBtYXBwaW5nIG9mIHN0eWxlIHByb3BlcnRpZXMgdG8gdmFsdWVzLlxuICpcbiAqIEBjb25zdHJ1Y3RvciBSZWFjdERPTUNvbXBvbmVudFxuICogQGV4dGVuZHMgUmVhY3RDb21wb25lbnRcbiAqIEBleHRlbmRzIFJlYWN0TXVsdGlDaGlsZFxuICovXG5mdW5jdGlvbiBSZWFjdERPTUNvbXBvbmVudCh0YWcpIHtcbiAgdmFsaWRhdGVEYW5nZXJvdXNUYWcodGFnKTtcbiAgdGhpcy5fdGFnID0gdGFnO1xuICB0aGlzLnRhZ05hbWUgPSB0YWcudG9VcHBlckNhc2UoKTtcbn1cblxuUmVhY3RET01Db21wb25lbnQuZGlzcGxheU5hbWUgPSAnUmVhY3RET01Db21wb25lbnQnO1xuXG5SZWFjdERPTUNvbXBvbmVudC5NaXhpbiA9IHtcblxuICAvKipcbiAgICogR2VuZXJhdGVzIHJvb3QgdGFnIG1hcmt1cCB0aGVuIHJlY3Vyc2VzLiBUaGlzIG1ldGhvZCBoYXMgc2lkZSBlZmZlY3RzIGFuZFxuICAgKiBpcyBub3QgaWRlbXBvdGVudC5cbiAgICpcbiAgICogQGludGVybmFsXG4gICAqIEBwYXJhbSB7c3RyaW5nfSByb290SUQgVGhlIHJvb3QgRE9NIElEIGZvciB0aGlzIG5vZGUuXG4gICAqIEBwYXJhbSB7UmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbnxSZWFjdFNlcnZlclJlbmRlcmluZ1RyYW5zYWN0aW9ufSB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge251bWJlcn0gbW91bnREZXB0aCBudW1iZXIgb2YgY29tcG9uZW50cyBpbiB0aGUgb3duZXIgaGllcmFyY2h5XG4gICAqIEByZXR1cm4ge3N0cmluZ30gVGhlIGNvbXB1dGVkIG1hcmt1cC5cbiAgICovXG4gIG1vdW50Q29tcG9uZW50OiBSZWFjdFBlcmYubWVhc3VyZShcbiAgICAnUmVhY3RET01Db21wb25lbnQnLFxuICAgICdtb3VudENvbXBvbmVudCcsXG4gICAgZnVuY3Rpb24ocm9vdElELCB0cmFuc2FjdGlvbiwgbW91bnREZXB0aCkge1xuICAgICAgUmVhY3RDb21wb25lbnQuTWl4aW4ubW91bnRDb21wb25lbnQuY2FsbChcbiAgICAgICAgdGhpcyxcbiAgICAgICAgcm9vdElELFxuICAgICAgICB0cmFuc2FjdGlvbixcbiAgICAgICAgbW91bnREZXB0aFxuICAgICAgKTtcbiAgICAgIGFzc2VydFZhbGlkUHJvcHModGhpcy5wcm9wcyk7XG4gICAgICB2YXIgY2xvc2VUYWcgPSBvbWl0dGVkQ2xvc2VUYWdzW3RoaXMuX3RhZ10gPyAnJyA6ICc8LycgKyB0aGlzLl90YWcgKyAnPic7XG4gICAgICByZXR1cm4gKFxuICAgICAgICB0aGlzLl9jcmVhdGVPcGVuVGFnTWFya3VwQW5kUHV0TGlzdGVuZXJzKHRyYW5zYWN0aW9uKSArXG4gICAgICAgIHRoaXMuX2NyZWF0ZUNvbnRlbnRNYXJrdXAodHJhbnNhY3Rpb24pICtcbiAgICAgICAgY2xvc2VUYWdcbiAgICAgICk7XG4gICAgfVxuICApLFxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIG1hcmt1cCBmb3IgdGhlIG9wZW4gdGFnIGFuZCBhbGwgYXR0cmlidXRlcy5cbiAgICpcbiAgICogVGhpcyBtZXRob2QgaGFzIHNpZGUgZWZmZWN0cyBiZWNhdXNlIGV2ZW50cyBnZXQgcmVnaXN0ZXJlZC5cbiAgICpcbiAgICogSXRlcmF0aW5nIG92ZXIgb2JqZWN0IHByb3BlcnRpZXMgaXMgZmFzdGVyIHRoYW4gaXRlcmF0aW5nIG92ZXIgYXJyYXlzLlxuICAgKiBAc2VlIGh0dHA6Ly9qc3BlcmYuY29tL29iai12cy1hcnItaXRlcmF0aW9uXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEBwYXJhbSB7UmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbnxSZWFjdFNlcnZlclJlbmRlcmluZ1RyYW5zYWN0aW9ufSB0cmFuc2FjdGlvblxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IE1hcmt1cCBvZiBvcGVuaW5nIHRhZy5cbiAgICovXG4gIF9jcmVhdGVPcGVuVGFnTWFya3VwQW5kUHV0TGlzdGVuZXJzOiBmdW5jdGlvbih0cmFuc2FjdGlvbikge1xuICAgIHZhciBwcm9wcyA9IHRoaXMucHJvcHM7XG4gICAgdmFyIHJldCA9ICc8JyArIHRoaXMuX3RhZztcblxuICAgIGZvciAodmFyIHByb3BLZXkgaW4gcHJvcHMpIHtcbiAgICAgIGlmICghcHJvcHMuaGFzT3duUHJvcGVydHkocHJvcEtleSkpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICB2YXIgcHJvcFZhbHVlID0gcHJvcHNbcHJvcEtleV07XG4gICAgICBpZiAocHJvcFZhbHVlID09IG51bGwpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBpZiAocmVnaXN0cmF0aW9uTmFtZU1vZHVsZXMuaGFzT3duUHJvcGVydHkocHJvcEtleSkpIHtcbiAgICAgICAgcHV0TGlzdGVuZXIodGhpcy5fcm9vdE5vZGVJRCwgcHJvcEtleSwgcHJvcFZhbHVlLCB0cmFuc2FjdGlvbik7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpZiAocHJvcEtleSA9PT0gU1RZTEUpIHtcbiAgICAgICAgICBpZiAocHJvcFZhbHVlKSB7XG4gICAgICAgICAgICBwcm9wVmFsdWUgPSBwcm9wcy5zdHlsZSA9IGFzc2lnbih7fSwgcHJvcHMuc3R5bGUpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBwcm9wVmFsdWUgPSBDU1NQcm9wZXJ0eU9wZXJhdGlvbnMuY3JlYXRlTWFya3VwRm9yU3R5bGVzKHByb3BWYWx1ZSk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIG1hcmt1cCA9XG4gICAgICAgICAgRE9NUHJvcGVydHlPcGVyYXRpb25zLmNyZWF0ZU1hcmt1cEZvclByb3BlcnR5KHByb3BLZXksIHByb3BWYWx1ZSk7XG4gICAgICAgIGlmIChtYXJrdXApIHtcbiAgICAgICAgICByZXQgKz0gJyAnICsgbWFya3VwO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gRm9yIHN0YXRpYyBwYWdlcywgbm8gbmVlZCB0byBwdXQgUmVhY3QgSUQgYW5kIGNoZWNrc3VtLiBTYXZlcyBsb3RzIG9mXG4gICAgLy8gYnl0ZXMuXG4gICAgaWYgKHRyYW5zYWN0aW9uLnJlbmRlclRvU3RhdGljTWFya3VwKSB7XG4gICAgICByZXR1cm4gcmV0ICsgJz4nO1xuICAgIH1cblxuICAgIHZhciBtYXJrdXBGb3JJRCA9IERPTVByb3BlcnR5T3BlcmF0aW9ucy5jcmVhdGVNYXJrdXBGb3JJRCh0aGlzLl9yb290Tm9kZUlEKTtcbiAgICByZXR1cm4gcmV0ICsgJyAnICsgbWFya3VwRm9ySUQgKyAnPic7XG4gIH0sXG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgbWFya3VwIGZvciB0aGUgY29udGVudCBiZXR3ZWVuIHRoZSB0YWdzLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge1JlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb258UmVhY3RTZXJ2ZXJSZW5kZXJpbmdUcmFuc2FjdGlvbn0gdHJhbnNhY3Rpb25cbiAgICogQHJldHVybiB7c3RyaW5nfSBDb250ZW50IG1hcmt1cC5cbiAgICovXG4gIF9jcmVhdGVDb250ZW50TWFya3VwOiBmdW5jdGlvbih0cmFuc2FjdGlvbikge1xuICAgIC8vIEludGVudGlvbmFsIHVzZSBvZiAhPSB0byBhdm9pZCBjYXRjaGluZyB6ZXJvL2ZhbHNlLlxuICAgIHZhciBpbm5lckhUTUwgPSB0aGlzLnByb3BzLmRhbmdlcm91c2x5U2V0SW5uZXJIVE1MO1xuICAgIGlmIChpbm5lckhUTUwgIT0gbnVsbCkge1xuICAgICAgaWYgKGlubmVySFRNTC5fX2h0bWwgIT0gbnVsbCkge1xuICAgICAgICByZXR1cm4gaW5uZXJIVE1MLl9faHRtbDtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdmFyIGNvbnRlbnRUb1VzZSA9XG4gICAgICAgIENPTlRFTlRfVFlQRVNbdHlwZW9mIHRoaXMucHJvcHMuY2hpbGRyZW5dID8gdGhpcy5wcm9wcy5jaGlsZHJlbiA6IG51bGw7XG4gICAgICB2YXIgY2hpbGRyZW5Ub1VzZSA9IGNvbnRlbnRUb1VzZSAhPSBudWxsID8gbnVsbCA6IHRoaXMucHJvcHMuY2hpbGRyZW47XG4gICAgICBpZiAoY29udGVudFRvVXNlICE9IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIGVzY2FwZVRleHRGb3JCcm93c2VyKGNvbnRlbnRUb1VzZSk7XG4gICAgICB9IGVsc2UgaWYgKGNoaWxkcmVuVG9Vc2UgIT0gbnVsbCkge1xuICAgICAgICB2YXIgbW91bnRJbWFnZXMgPSB0aGlzLm1vdW50Q2hpbGRyZW4oXG4gICAgICAgICAgY2hpbGRyZW5Ub1VzZSxcbiAgICAgICAgICB0cmFuc2FjdGlvblxuICAgICAgICApO1xuICAgICAgICByZXR1cm4gbW91bnRJbWFnZXMuam9pbignJyk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiAnJztcbiAgfSxcblxuICByZWNlaXZlQ29tcG9uZW50OiBmdW5jdGlvbihuZXh0RWxlbWVudCwgdHJhbnNhY3Rpb24pIHtcbiAgICBpZiAobmV4dEVsZW1lbnQgPT09IHRoaXMuX2N1cnJlbnRFbGVtZW50ICYmXG4gICAgICAgIG5leHRFbGVtZW50Ll9vd25lciAhPSBudWxsKSB7XG4gICAgICAvLyBTaW5jZSBlbGVtZW50cyBhcmUgaW1tdXRhYmxlIGFmdGVyIHRoZSBvd25lciBpcyByZW5kZXJlZCxcbiAgICAgIC8vIHdlIGNhbiBkbyBhIGNoZWFwIGlkZW50aXR5IGNvbXBhcmUgaGVyZSB0byBkZXRlcm1pbmUgaWYgdGhpcyBpcyBhXG4gICAgICAvLyBzdXBlcmZsdW91cyByZWNvbmNpbGUuIEl0J3MgcG9zc2libGUgZm9yIHN0YXRlIHRvIGJlIG11dGFibGUgYnV0IHN1Y2hcbiAgICAgIC8vIGNoYW5nZSBzaG91bGQgdHJpZ2dlciBhbiB1cGRhdGUgb2YgdGhlIG93bmVyIHdoaWNoIHdvdWxkIHJlY3JlYXRlXG4gICAgICAvLyB0aGUgZWxlbWVudC4gV2UgZXhwbGljaXRseSBjaGVjayBmb3IgdGhlIGV4aXN0ZW5jZSBvZiBhbiBvd25lciBzaW5jZVxuICAgICAgLy8gaXQncyBwb3NzaWJsZSBmb3IgYSBlbGVtZW50IGNyZWF0ZWQgb3V0c2lkZSBhIGNvbXBvc2l0ZSB0byBiZVxuICAgICAgLy8gZGVlcGx5IG11dGF0ZWQgYW5kIHJldXNlZC5cbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBSZWFjdENvbXBvbmVudC5NaXhpbi5yZWNlaXZlQ29tcG9uZW50LmNhbGwoXG4gICAgICB0aGlzLFxuICAgICAgbmV4dEVsZW1lbnQsXG4gICAgICB0cmFuc2FjdGlvblxuICAgICk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFVwZGF0ZXMgYSBuYXRpdmUgRE9NIGNvbXBvbmVudCBhZnRlciBpdCBoYXMgYWxyZWFkeSBiZWVuIGFsbG9jYXRlZCBhbmRcbiAgICogYXR0YWNoZWQgdG8gdGhlIERPTS4gUmVjb25jaWxlcyB0aGUgcm9vdCBET00gbm9kZSwgdGhlbiByZWN1cnNlcy5cbiAgICpcbiAgICogQHBhcmFtIHtSZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9ufSB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge1JlYWN0RWxlbWVudH0gcHJldkVsZW1lbnRcbiAgICogQGludGVybmFsXG4gICAqIEBvdmVycmlkYWJsZVxuICAgKi9cbiAgdXBkYXRlQ29tcG9uZW50OiBSZWFjdFBlcmYubWVhc3VyZShcbiAgICAnUmVhY3RET01Db21wb25lbnQnLFxuICAgICd1cGRhdGVDb21wb25lbnQnLFxuICAgIGZ1bmN0aW9uKHRyYW5zYWN0aW9uLCBwcmV2RWxlbWVudCkge1xuICAgICAgYXNzZXJ0VmFsaWRQcm9wcyh0aGlzLl9jdXJyZW50RWxlbWVudC5wcm9wcyk7XG4gICAgICBSZWFjdENvbXBvbmVudC5NaXhpbi51cGRhdGVDb21wb25lbnQuY2FsbChcbiAgICAgICAgdGhpcyxcbiAgICAgICAgdHJhbnNhY3Rpb24sXG4gICAgICAgIHByZXZFbGVtZW50XG4gICAgICApO1xuICAgICAgdGhpcy5fdXBkYXRlRE9NUHJvcGVydGllcyhwcmV2RWxlbWVudC5wcm9wcywgdHJhbnNhY3Rpb24pO1xuICAgICAgdGhpcy5fdXBkYXRlRE9NQ2hpbGRyZW4ocHJldkVsZW1lbnQucHJvcHMsIHRyYW5zYWN0aW9uKTtcbiAgICB9XG4gICksXG5cbiAgLyoqXG4gICAqIFJlY29uY2lsZXMgdGhlIHByb3BlcnRpZXMgYnkgZGV0ZWN0aW5nIGRpZmZlcmVuY2VzIGluIHByb3BlcnR5IHZhbHVlcyBhbmRcbiAgICogdXBkYXRpbmcgdGhlIERPTSBhcyBuZWNlc3NhcnkuIFRoaXMgZnVuY3Rpb24gaXMgcHJvYmFibHkgdGhlIHNpbmdsZSBtb3N0XG4gICAqIGNyaXRpY2FsIHBhdGggZm9yIHBlcmZvcm1hbmNlIG9wdGltaXphdGlvbi5cbiAgICpcbiAgICogVE9ETzogQmVuY2htYXJrIHdoZXRoZXIgY2hlY2tpbmcgZm9yIGNoYW5nZWQgdmFsdWVzIGluIG1lbW9yeSBhY3R1YWxseVxuICAgKiAgICAgICBpbXByb3ZlcyBwZXJmb3JtYW5jZSAoZXNwZWNpYWxseSBzdGF0aWNhbGx5IHBvc2l0aW9uZWQgZWxlbWVudHMpLlxuICAgKiBUT0RPOiBCZW5jaG1hcmsgdGhlIGVmZmVjdHMgb2YgcHV0dGluZyB0aGlzIGF0IHRoZSB0b3Agc2luY2UgOTklIG9mIHByb3BzXG4gICAqICAgICAgIGRvIG5vdCBjaGFuZ2UgZm9yIGEgZ2l2ZW4gcmVjb25jaWxpYXRpb24uXG4gICAqIFRPRE86IEJlbmNobWFyayBhcmVhcyB0aGF0IGNhbiBiZSBpbXByb3ZlZCB3aXRoIGNhY2hpbmcuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBsYXN0UHJvcHNcbiAgICogQHBhcmFtIHtSZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9ufSB0cmFuc2FjdGlvblxuICAgKi9cbiAgX3VwZGF0ZURPTVByb3BlcnRpZXM6IGZ1bmN0aW9uKGxhc3RQcm9wcywgdHJhbnNhY3Rpb24pIHtcbiAgICB2YXIgbmV4dFByb3BzID0gdGhpcy5wcm9wcztcbiAgICB2YXIgcHJvcEtleTtcbiAgICB2YXIgc3R5bGVOYW1lO1xuICAgIHZhciBzdHlsZVVwZGF0ZXM7XG4gICAgZm9yIChwcm9wS2V5IGluIGxhc3RQcm9wcykge1xuICAgICAgaWYgKG5leHRQcm9wcy5oYXNPd25Qcm9wZXJ0eShwcm9wS2V5KSB8fFxuICAgICAgICAgIWxhc3RQcm9wcy5oYXNPd25Qcm9wZXJ0eShwcm9wS2V5KSkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGlmIChwcm9wS2V5ID09PSBTVFlMRSkge1xuICAgICAgICB2YXIgbGFzdFN0eWxlID0gbGFzdFByb3BzW3Byb3BLZXldO1xuICAgICAgICBmb3IgKHN0eWxlTmFtZSBpbiBsYXN0U3R5bGUpIHtcbiAgICAgICAgICBpZiAobGFzdFN0eWxlLmhhc093blByb3BlcnR5KHN0eWxlTmFtZSkpIHtcbiAgICAgICAgICAgIHN0eWxlVXBkYXRlcyA9IHN0eWxlVXBkYXRlcyB8fCB7fTtcbiAgICAgICAgICAgIHN0eWxlVXBkYXRlc1tzdHlsZU5hbWVdID0gJyc7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHJlZ2lzdHJhdGlvbk5hbWVNb2R1bGVzLmhhc093blByb3BlcnR5KHByb3BLZXkpKSB7XG4gICAgICAgIGRlbGV0ZUxpc3RlbmVyKHRoaXMuX3Jvb3ROb2RlSUQsIHByb3BLZXkpO1xuICAgICAgfSBlbHNlIGlmIChcbiAgICAgICAgICBET01Qcm9wZXJ0eS5pc1N0YW5kYXJkTmFtZVtwcm9wS2V5XSB8fFxuICAgICAgICAgIERPTVByb3BlcnR5LmlzQ3VzdG9tQXR0cmlidXRlKHByb3BLZXkpKSB7XG4gICAgICAgIFJlYWN0Q29tcG9uZW50LkJhY2tlbmRJRE9wZXJhdGlvbnMuZGVsZXRlUHJvcGVydHlCeUlEKFxuICAgICAgICAgIHRoaXMuX3Jvb3ROb2RlSUQsXG4gICAgICAgICAgcHJvcEtleVxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cbiAgICBmb3IgKHByb3BLZXkgaW4gbmV4dFByb3BzKSB7XG4gICAgICB2YXIgbmV4dFByb3AgPSBuZXh0UHJvcHNbcHJvcEtleV07XG4gICAgICB2YXIgbGFzdFByb3AgPSBsYXN0UHJvcHNbcHJvcEtleV07XG4gICAgICBpZiAoIW5leHRQcm9wcy5oYXNPd25Qcm9wZXJ0eShwcm9wS2V5KSB8fCBuZXh0UHJvcCA9PT0gbGFzdFByb3ApIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBpZiAocHJvcEtleSA9PT0gU1RZTEUpIHtcbiAgICAgICAgaWYgKG5leHRQcm9wKSB7XG4gICAgICAgICAgbmV4dFByb3AgPSBuZXh0UHJvcHMuc3R5bGUgPSBhc3NpZ24oe30sIG5leHRQcm9wKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobGFzdFByb3ApIHtcbiAgICAgICAgICAvLyBVbnNldCBzdHlsZXMgb24gYGxhc3RQcm9wYCBidXQgbm90IG9uIGBuZXh0UHJvcGAuXG4gICAgICAgICAgZm9yIChzdHlsZU5hbWUgaW4gbGFzdFByb3ApIHtcbiAgICAgICAgICAgIGlmIChsYXN0UHJvcC5oYXNPd25Qcm9wZXJ0eShzdHlsZU5hbWUpICYmXG4gICAgICAgICAgICAgICAgKCFuZXh0UHJvcCB8fCAhbmV4dFByb3AuaGFzT3duUHJvcGVydHkoc3R5bGVOYW1lKSkpIHtcbiAgICAgICAgICAgICAgc3R5bGVVcGRhdGVzID0gc3R5bGVVcGRhdGVzIHx8IHt9O1xuICAgICAgICAgICAgICBzdHlsZVVwZGF0ZXNbc3R5bGVOYW1lXSA9ICcnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBVcGRhdGUgc3R5bGVzIHRoYXQgY2hhbmdlZCBzaW5jZSBgbGFzdFByb3BgLlxuICAgICAgICAgIGZvciAoc3R5bGVOYW1lIGluIG5leHRQcm9wKSB7XG4gICAgICAgICAgICBpZiAobmV4dFByb3AuaGFzT3duUHJvcGVydHkoc3R5bGVOYW1lKSAmJlxuICAgICAgICAgICAgICAgIGxhc3RQcm9wW3N0eWxlTmFtZV0gIT09IG5leHRQcm9wW3N0eWxlTmFtZV0pIHtcbiAgICAgICAgICAgICAgc3R5bGVVcGRhdGVzID0gc3R5bGVVcGRhdGVzIHx8IHt9O1xuICAgICAgICAgICAgICBzdHlsZVVwZGF0ZXNbc3R5bGVOYW1lXSA9IG5leHRQcm9wW3N0eWxlTmFtZV07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIFJlbGllcyBvbiBgdXBkYXRlU3R5bGVzQnlJRGAgbm90IG11dGF0aW5nIGBzdHlsZVVwZGF0ZXNgLlxuICAgICAgICAgIHN0eWxlVXBkYXRlcyA9IG5leHRQcm9wO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHJlZ2lzdHJhdGlvbk5hbWVNb2R1bGVzLmhhc093blByb3BlcnR5KHByb3BLZXkpKSB7XG4gICAgICAgIHB1dExpc3RlbmVyKHRoaXMuX3Jvb3ROb2RlSUQsIHByb3BLZXksIG5leHRQcm9wLCB0cmFuc2FjdGlvbik7XG4gICAgICB9IGVsc2UgaWYgKFxuICAgICAgICAgIERPTVByb3BlcnR5LmlzU3RhbmRhcmROYW1lW3Byb3BLZXldIHx8XG4gICAgICAgICAgRE9NUHJvcGVydHkuaXNDdXN0b21BdHRyaWJ1dGUocHJvcEtleSkpIHtcbiAgICAgICAgUmVhY3RDb21wb25lbnQuQmFja2VuZElET3BlcmF0aW9ucy51cGRhdGVQcm9wZXJ0eUJ5SUQoXG4gICAgICAgICAgdGhpcy5fcm9vdE5vZGVJRCxcbiAgICAgICAgICBwcm9wS2V5LFxuICAgICAgICAgIG5leHRQcm9wXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChzdHlsZVVwZGF0ZXMpIHtcbiAgICAgIFJlYWN0Q29tcG9uZW50LkJhY2tlbmRJRE9wZXJhdGlvbnMudXBkYXRlU3R5bGVzQnlJRChcbiAgICAgICAgdGhpcy5fcm9vdE5vZGVJRCxcbiAgICAgICAgc3R5bGVVcGRhdGVzXG4gICAgICApO1xuICAgIH1cbiAgfSxcblxuICAvKipcbiAgICogUmVjb25jaWxlcyB0aGUgY2hpbGRyZW4gd2l0aCB0aGUgdmFyaW91cyBwcm9wZXJ0aWVzIHRoYXQgYWZmZWN0IHRoZVxuICAgKiBjaGlsZHJlbiBjb250ZW50LlxuICAgKlxuICAgKiBAcGFyYW0ge29iamVjdH0gbGFzdFByb3BzXG4gICAqIEBwYXJhbSB7UmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbn0gdHJhbnNhY3Rpb25cbiAgICovXG4gIF91cGRhdGVET01DaGlsZHJlbjogZnVuY3Rpb24obGFzdFByb3BzLCB0cmFuc2FjdGlvbikge1xuICAgIHZhciBuZXh0UHJvcHMgPSB0aGlzLnByb3BzO1xuXG4gICAgdmFyIGxhc3RDb250ZW50ID1cbiAgICAgIENPTlRFTlRfVFlQRVNbdHlwZW9mIGxhc3RQcm9wcy5jaGlsZHJlbl0gPyBsYXN0UHJvcHMuY2hpbGRyZW4gOiBudWxsO1xuICAgIHZhciBuZXh0Q29udGVudCA9XG4gICAgICBDT05URU5UX1RZUEVTW3R5cGVvZiBuZXh0UHJvcHMuY2hpbGRyZW5dID8gbmV4dFByb3BzLmNoaWxkcmVuIDogbnVsbDtcblxuICAgIHZhciBsYXN0SHRtbCA9XG4gICAgICBsYXN0UHJvcHMuZGFuZ2Vyb3VzbHlTZXRJbm5lckhUTUwgJiZcbiAgICAgIGxhc3RQcm9wcy5kYW5nZXJvdXNseVNldElubmVySFRNTC5fX2h0bWw7XG4gICAgdmFyIG5leHRIdG1sID1cbiAgICAgIG5leHRQcm9wcy5kYW5nZXJvdXNseVNldElubmVySFRNTCAmJlxuICAgICAgbmV4dFByb3BzLmRhbmdlcm91c2x5U2V0SW5uZXJIVE1MLl9faHRtbDtcblxuICAgIC8vIE5vdGUgdGhlIHVzZSBvZiBgIT1gIHdoaWNoIGNoZWNrcyBmb3IgbnVsbCBvciB1bmRlZmluZWQuXG4gICAgdmFyIGxhc3RDaGlsZHJlbiA9IGxhc3RDb250ZW50ICE9IG51bGwgPyBudWxsIDogbGFzdFByb3BzLmNoaWxkcmVuO1xuICAgIHZhciBuZXh0Q2hpbGRyZW4gPSBuZXh0Q29udGVudCAhPSBudWxsID8gbnVsbCA6IG5leHRQcm9wcy5jaGlsZHJlbjtcblxuICAgIC8vIElmIHdlJ3JlIHN3aXRjaGluZyBmcm9tIGNoaWxkcmVuIHRvIGNvbnRlbnQvaHRtbCBvciB2aWNlIHZlcnNhLCByZW1vdmVcbiAgICAvLyB0aGUgb2xkIGNvbnRlbnRcbiAgICB2YXIgbGFzdEhhc0NvbnRlbnRPckh0bWwgPSBsYXN0Q29udGVudCAhPSBudWxsIHx8IGxhc3RIdG1sICE9IG51bGw7XG4gICAgdmFyIG5leHRIYXNDb250ZW50T3JIdG1sID0gbmV4dENvbnRlbnQgIT0gbnVsbCB8fCBuZXh0SHRtbCAhPSBudWxsO1xuICAgIGlmIChsYXN0Q2hpbGRyZW4gIT0gbnVsbCAmJiBuZXh0Q2hpbGRyZW4gPT0gbnVsbCkge1xuICAgICAgdGhpcy51cGRhdGVDaGlsZHJlbihudWxsLCB0cmFuc2FjdGlvbik7XG4gICAgfSBlbHNlIGlmIChsYXN0SGFzQ29udGVudE9ySHRtbCAmJiAhbmV4dEhhc0NvbnRlbnRPckh0bWwpIHtcbiAgICAgIHRoaXMudXBkYXRlVGV4dENvbnRlbnQoJycpO1xuICAgIH1cblxuICAgIGlmIChuZXh0Q29udGVudCAhPSBudWxsKSB7XG4gICAgICBpZiAobGFzdENvbnRlbnQgIT09IG5leHRDb250ZW50KSB7XG4gICAgICAgIHRoaXMudXBkYXRlVGV4dENvbnRlbnQoJycgKyBuZXh0Q29udGVudCk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChuZXh0SHRtbCAhPSBudWxsKSB7XG4gICAgICBpZiAobGFzdEh0bWwgIT09IG5leHRIdG1sKSB7XG4gICAgICAgIFJlYWN0Q29tcG9uZW50LkJhY2tlbmRJRE9wZXJhdGlvbnMudXBkYXRlSW5uZXJIVE1MQnlJRChcbiAgICAgICAgICB0aGlzLl9yb290Tm9kZUlELFxuICAgICAgICAgIG5leHRIdG1sXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChuZXh0Q2hpbGRyZW4gIT0gbnVsbCkge1xuICAgICAgdGhpcy51cGRhdGVDaGlsZHJlbihuZXh0Q2hpbGRyZW4sIHRyYW5zYWN0aW9uKTtcbiAgICB9XG4gIH0sXG5cbiAgLyoqXG4gICAqIERlc3Ryb3lzIGFsbCBldmVudCByZWdpc3RyYXRpb25zIGZvciB0aGlzIGluc3RhbmNlLiBEb2VzIG5vdCByZW1vdmUgZnJvbVxuICAgKiB0aGUgRE9NLiBUaGF0IG11c3QgYmUgZG9uZSBieSB0aGUgcGFyZW50LlxuICAgKlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHVubW91bnRDb21wb25lbnQ6IGZ1bmN0aW9uKCkge1xuICAgIHRoaXMudW5tb3VudENoaWxkcmVuKCk7XG4gICAgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLmRlbGV0ZUFsbExpc3RlbmVycyh0aGlzLl9yb290Tm9kZUlEKTtcbiAgICBSZWFjdENvbXBvbmVudC5NaXhpbi51bm1vdW50Q29tcG9uZW50LmNhbGwodGhpcyk7XG4gIH1cblxufTtcblxuYXNzaWduKFxuICBSZWFjdERPTUNvbXBvbmVudC5wcm90b3R5cGUsXG4gIFJlYWN0Q29tcG9uZW50Lk1peGluLFxuICBSZWFjdERPTUNvbXBvbmVudC5NaXhpbixcbiAgUmVhY3RNdWx0aUNoaWxkLk1peGluLFxuICBSZWFjdEJyb3dzZXJDb21wb25lbnRNaXhpblxuKTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdERPTUNvbXBvbmVudDtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0RE9NRm9ybVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgRXZlbnRDb25zdGFudHMgPSByZXF1aXJlKFwiLi9FdmVudENvbnN0YW50c1wiKTtcbnZhciBMb2NhbEV2ZW50VHJhcE1peGluID0gcmVxdWlyZShcIi4vTG9jYWxFdmVudFRyYXBNaXhpblwiKTtcbnZhciBSZWFjdEJyb3dzZXJDb21wb25lbnRNaXhpbiA9IHJlcXVpcmUoXCIuL1JlYWN0QnJvd3NlckNvbXBvbmVudE1peGluXCIpO1xudmFyIFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50ID0gcmVxdWlyZShcIi4vUmVhY3RDb21wb3NpdGVDb21wb25lbnRcIik7XG52YXIgUmVhY3RFbGVtZW50ID0gcmVxdWlyZShcIi4vUmVhY3RFbGVtZW50XCIpO1xudmFyIFJlYWN0RE9NID0gcmVxdWlyZShcIi4vUmVhY3RET01cIik7XG5cbi8vIFN0b3JlIGEgcmVmZXJlbmNlIHRvIHRoZSA8Zm9ybT4gYFJlYWN0RE9NQ29tcG9uZW50YC4gVE9ETzogdXNlIHN0cmluZ1xudmFyIGZvcm0gPSBSZWFjdEVsZW1lbnQuY3JlYXRlRmFjdG9yeShSZWFjdERPTS5mb3JtLnR5cGUpO1xuXG4vKipcbiAqIFNpbmNlIG9uU3VibWl0IGRvZXNuJ3QgYnViYmxlIE9SIGNhcHR1cmUgb24gdGhlIHRvcCBsZXZlbCBpbiBJRTgsIHdlIG5lZWRcbiAqIHRvIGNhcHR1cmUgaXQgb24gdGhlIDxmb3JtPiBlbGVtZW50IGl0c2VsZi4gVGhlcmUgYXJlIGxvdHMgb2YgaGFja3Mgd2UgY291bGRcbiAqIGRvIHRvIGFjY29tcGxpc2ggdGhpcywgYnV0IHRoZSBtb3N0IHJlbGlhYmxlIGlzIHRvIG1ha2UgPGZvcm0+IGFcbiAqIGNvbXBvc2l0ZSBjb21wb25lbnQgYW5kIHVzZSBgY29tcG9uZW50RGlkTW91bnRgIHRvIGF0dGFjaCB0aGUgZXZlbnQgaGFuZGxlcnMuXG4gKi9cbnZhciBSZWFjdERPTUZvcm0gPSBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudC5jcmVhdGVDbGFzcyh7XG4gIGRpc3BsYXlOYW1lOiAnUmVhY3RET01Gb3JtJyxcblxuICBtaXhpbnM6IFtSZWFjdEJyb3dzZXJDb21wb25lbnRNaXhpbiwgTG9jYWxFdmVudFRyYXBNaXhpbl0sXG5cbiAgcmVuZGVyOiBmdW5jdGlvbigpIHtcbiAgICAvLyBUT0RPOiBJbnN0ZWFkIG9mIHVzaW5nIGBSZWFjdERPTWAgZGlyZWN0bHksIHdlIHNob3VsZCB1c2UgSlNYLiBIb3dldmVyLFxuICAgIC8vIGBqc2hpbnRgIGZhaWxzIHRvIHBhcnNlIEpTWCBzbyBpbiBvcmRlciBmb3IgbGludGluZyB0byB3b3JrIGluIHRoZSBvcGVuXG4gICAgLy8gc291cmNlIHJlcG8sIHdlIG5lZWQgdG8ganVzdCB1c2UgYFJlYWN0RE9NLmZvcm1gLlxuICAgIHJldHVybiBmb3JtKHRoaXMucHJvcHMpO1xuICB9LFxuXG4gIGNvbXBvbmVudERpZE1vdW50OiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLnRyYXBCdWJibGVkRXZlbnQoRXZlbnRDb25zdGFudHMudG9wTGV2ZWxUeXBlcy50b3BSZXNldCwgJ3Jlc2V0Jyk7XG4gICAgdGhpcy50cmFwQnViYmxlZEV2ZW50KEV2ZW50Q29uc3RhbnRzLnRvcExldmVsVHlwZXMudG9wU3VibWl0LCAnc3VibWl0Jyk7XG4gIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0RE9NRm9ybTtcbiIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RET01JRE9wZXJhdGlvbnNcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuLypqc2xpbnQgZXZpbDogdHJ1ZSAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIENTU1Byb3BlcnR5T3BlcmF0aW9ucyA9IHJlcXVpcmUoXCIuL0NTU1Byb3BlcnR5T3BlcmF0aW9uc1wiKTtcbnZhciBET01DaGlsZHJlbk9wZXJhdGlvbnMgPSByZXF1aXJlKFwiLi9ET01DaGlsZHJlbk9wZXJhdGlvbnNcIik7XG52YXIgRE9NUHJvcGVydHlPcGVyYXRpb25zID0gcmVxdWlyZShcIi4vRE9NUHJvcGVydHlPcGVyYXRpb25zXCIpO1xudmFyIFJlYWN0TW91bnQgPSByZXF1aXJlKFwiLi9SZWFjdE1vdW50XCIpO1xudmFyIFJlYWN0UGVyZiA9IHJlcXVpcmUoXCIuL1JlYWN0UGVyZlwiKTtcblxudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcbnZhciBzZXRJbm5lckhUTUwgPSByZXF1aXJlKFwiLi9zZXRJbm5lckhUTUxcIik7XG5cbi8qKlxuICogRXJyb3JzIGZvciBwcm9wZXJ0aWVzIHRoYXQgc2hvdWxkIG5vdCBiZSB1cGRhdGVkIHdpdGggYHVwZGF0ZVByb3BlcnR5QnlJZCgpYC5cbiAqXG4gKiBAdHlwZSB7b2JqZWN0fVxuICogQHByaXZhdGVcbiAqL1xudmFyIElOVkFMSURfUFJPUEVSVFlfRVJST1JTID0ge1xuICBkYW5nZXJvdXNseVNldElubmVySFRNTDpcbiAgICAnYGRhbmdlcm91c2x5U2V0SW5uZXJIVE1MYCBtdXN0IGJlIHNldCB1c2luZyBgdXBkYXRlSW5uZXJIVE1MQnlJRCgpYC4nLFxuICBzdHlsZTogJ2BzdHlsZWAgbXVzdCBiZSBzZXQgdXNpbmcgYHVwZGF0ZVN0eWxlc0J5SUQoKWAuJ1xufTtcblxuLyoqXG4gKiBPcGVyYXRpb25zIHVzZWQgdG8gcHJvY2VzcyB1cGRhdGVzIHRvIERPTSBub2Rlcy4gVGhpcyBpcyBtYWRlIGluamVjdGFibGUgdmlhXG4gKiBgUmVhY3RDb21wb25lbnQuQmFja2VuZElET3BlcmF0aW9uc2AuXG4gKi9cbnZhciBSZWFjdERPTUlET3BlcmF0aW9ucyA9IHtcblxuICAvKipcbiAgICogVXBkYXRlcyBhIERPTSBub2RlIHdpdGggbmV3IHByb3BlcnR5IHZhbHVlcy4gVGhpcyBzaG91bGQgb25seSBiZSB1c2VkIHRvXG4gICAqIHVwZGF0ZSBET00gcHJvcGVydGllcyBpbiBgRE9NUHJvcGVydHlgLlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gaWQgSUQgb2YgdGhlIG5vZGUgdG8gdXBkYXRlLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSBBIHZhbGlkIHByb3BlcnR5IG5hbWUsIHNlZSBgRE9NUHJvcGVydHlgLlxuICAgKiBAcGFyYW0geyp9IHZhbHVlIE5ldyB2YWx1ZSBvZiB0aGUgcHJvcGVydHkuXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgdXBkYXRlUHJvcGVydHlCeUlEOiBSZWFjdFBlcmYubWVhc3VyZShcbiAgICAnUmVhY3RET01JRE9wZXJhdGlvbnMnLFxuICAgICd1cGRhdGVQcm9wZXJ0eUJ5SUQnLFxuICAgIGZ1bmN0aW9uKGlkLCBuYW1lLCB2YWx1ZSkge1xuICAgICAgdmFyIG5vZGUgPSBSZWFjdE1vdW50LmdldE5vZGUoaWQpO1xuICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgIUlOVkFMSURfUFJPUEVSVFlfRVJST1JTLmhhc093blByb3BlcnR5KG5hbWUpLFxuICAgICAgICAndXBkYXRlUHJvcGVydHlCeUlEKC4uLik6ICVzJyxcbiAgICAgICAgSU5WQUxJRF9QUk9QRVJUWV9FUlJPUlNbbmFtZV1cbiAgICAgICkgOiBpbnZhcmlhbnQoIUlOVkFMSURfUFJPUEVSVFlfRVJST1JTLmhhc093blByb3BlcnR5KG5hbWUpKSk7XG5cbiAgICAgIC8vIElmIHdlJ3JlIHVwZGF0aW5nIHRvIG51bGwgb3IgdW5kZWZpbmVkLCB3ZSBzaG91bGQgcmVtb3ZlIHRoZSBwcm9wZXJ0eVxuICAgICAgLy8gZnJvbSB0aGUgRE9NIG5vZGUgaW5zdGVhZCBvZiBpbmFkdmVydGFudGx5IHNldHRpbmcgdG8gYSBzdHJpbmcuIFRoaXNcbiAgICAgIC8vIGJyaW5ncyB1cyBpbiBsaW5lIHdpdGggdGhlIHNhbWUgYmVoYXZpb3Igd2UgaGF2ZSBvbiBpbml0aWFsIHJlbmRlci5cbiAgICAgIGlmICh2YWx1ZSAhPSBudWxsKSB7XG4gICAgICAgIERPTVByb3BlcnR5T3BlcmF0aW9ucy5zZXRWYWx1ZUZvclByb3BlcnR5KG5vZGUsIG5hbWUsIHZhbHVlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIERPTVByb3BlcnR5T3BlcmF0aW9ucy5kZWxldGVWYWx1ZUZvclByb3BlcnR5KG5vZGUsIG5hbWUpO1xuICAgICAgfVxuICAgIH1cbiAgKSxcblxuICAvKipcbiAgICogVXBkYXRlcyBhIERPTSBub2RlIHRvIHJlbW92ZSBhIHByb3BlcnR5LiBUaGlzIHNob3VsZCBvbmx5IGJlIHVzZWQgdG8gcmVtb3ZlXG4gICAqIERPTSBwcm9wZXJ0aWVzIGluIGBET01Qcm9wZXJ0eWAuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpZCBJRCBvZiB0aGUgbm9kZSB0byB1cGRhdGUuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIEEgcHJvcGVydHkgbmFtZSB0byByZW1vdmUsIHNlZSBgRE9NUHJvcGVydHlgLlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIGRlbGV0ZVByb3BlcnR5QnlJRDogUmVhY3RQZXJmLm1lYXN1cmUoXG4gICAgJ1JlYWN0RE9NSURPcGVyYXRpb25zJyxcbiAgICAnZGVsZXRlUHJvcGVydHlCeUlEJyxcbiAgICBmdW5jdGlvbihpZCwgbmFtZSwgdmFsdWUpIHtcbiAgICAgIHZhciBub2RlID0gUmVhY3RNb3VudC5nZXROb2RlKGlkKTtcbiAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgICFJTlZBTElEX1BST1BFUlRZX0VSUk9SUy5oYXNPd25Qcm9wZXJ0eShuYW1lKSxcbiAgICAgICAgJ3VwZGF0ZVByb3BlcnR5QnlJRCguLi4pOiAlcycsXG4gICAgICAgIElOVkFMSURfUFJPUEVSVFlfRVJST1JTW25hbWVdXG4gICAgICApIDogaW52YXJpYW50KCFJTlZBTElEX1BST1BFUlRZX0VSUk9SUy5oYXNPd25Qcm9wZXJ0eShuYW1lKSkpO1xuICAgICAgRE9NUHJvcGVydHlPcGVyYXRpb25zLmRlbGV0ZVZhbHVlRm9yUHJvcGVydHkobm9kZSwgbmFtZSwgdmFsdWUpO1xuICAgIH1cbiAgKSxcblxuICAvKipcbiAgICogVXBkYXRlcyBhIERPTSBub2RlIHdpdGggbmV3IHN0eWxlIHZhbHVlcy4gSWYgYSB2YWx1ZSBpcyBzcGVjaWZpZWQgYXMgJycsXG4gICAqIHRoZSBjb3JyZXNwb25kaW5nIHN0eWxlIHByb3BlcnR5IHdpbGwgYmUgdW5zZXQuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpZCBJRCBvZiB0aGUgbm9kZSB0byB1cGRhdGUuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBzdHlsZXMgTWFwcGluZyBmcm9tIHN0eWxlcyB0byB2YWx1ZXMuXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgdXBkYXRlU3R5bGVzQnlJRDogUmVhY3RQZXJmLm1lYXN1cmUoXG4gICAgJ1JlYWN0RE9NSURPcGVyYXRpb25zJyxcbiAgICAndXBkYXRlU3R5bGVzQnlJRCcsXG4gICAgZnVuY3Rpb24oaWQsIHN0eWxlcykge1xuICAgICAgdmFyIG5vZGUgPSBSZWFjdE1vdW50LmdldE5vZGUoaWQpO1xuICAgICAgQ1NTUHJvcGVydHlPcGVyYXRpb25zLnNldFZhbHVlRm9yU3R5bGVzKG5vZGUsIHN0eWxlcyk7XG4gICAgfVxuICApLFxuXG4gIC8qKlxuICAgKiBVcGRhdGVzIGEgRE9NIG5vZGUncyBpbm5lckhUTUwuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpZCBJRCBvZiB0aGUgbm9kZSB0byB1cGRhdGUuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBodG1sIEFuIEhUTUwgc3RyaW5nLlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHVwZGF0ZUlubmVySFRNTEJ5SUQ6IFJlYWN0UGVyZi5tZWFzdXJlKFxuICAgICdSZWFjdERPTUlET3BlcmF0aW9ucycsXG4gICAgJ3VwZGF0ZUlubmVySFRNTEJ5SUQnLFxuICAgIGZ1bmN0aW9uKGlkLCBodG1sKSB7XG4gICAgICB2YXIgbm9kZSA9IFJlYWN0TW91bnQuZ2V0Tm9kZShpZCk7XG4gICAgICBzZXRJbm5lckhUTUwobm9kZSwgaHRtbCk7XG4gICAgfVxuICApLFxuXG4gIC8qKlxuICAgKiBVcGRhdGVzIGEgRE9NIG5vZGUncyB0ZXh0IGNvbnRlbnQgc2V0IGJ5IGBwcm9wcy5jb250ZW50YC5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IGlkIElEIG9mIHRoZSBub2RlIHRvIHVwZGF0ZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbnRlbnQgVGV4dCBjb250ZW50LlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHVwZGF0ZVRleHRDb250ZW50QnlJRDogUmVhY3RQZXJmLm1lYXN1cmUoXG4gICAgJ1JlYWN0RE9NSURPcGVyYXRpb25zJyxcbiAgICAndXBkYXRlVGV4dENvbnRlbnRCeUlEJyxcbiAgICBmdW5jdGlvbihpZCwgY29udGVudCkge1xuICAgICAgdmFyIG5vZGUgPSBSZWFjdE1vdW50LmdldE5vZGUoaWQpO1xuICAgICAgRE9NQ2hpbGRyZW5PcGVyYXRpb25zLnVwZGF0ZVRleHRDb250ZW50KG5vZGUsIGNvbnRlbnQpO1xuICAgIH1cbiAgKSxcblxuICAvKipcbiAgICogUmVwbGFjZXMgYSBET00gbm9kZSB0aGF0IGV4aXN0cyBpbiB0aGUgZG9jdW1lbnQgd2l0aCBtYXJrdXAuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpZCBJRCBvZiBjaGlsZCB0byBiZSByZXBsYWNlZC5cbiAgICogQHBhcmFtIHtzdHJpbmd9IG1hcmt1cCBEYW5nZXJvdXMgbWFya3VwIHRvIGluamVjdCBpbiBwbGFjZSBvZiBjaGlsZC5cbiAgICogQGludGVybmFsXG4gICAqIEBzZWUge0Rhbmdlci5kYW5nZXJvdXNseVJlcGxhY2VOb2RlV2l0aE1hcmt1cH1cbiAgICovXG4gIGRhbmdlcm91c2x5UmVwbGFjZU5vZGVXaXRoTWFya3VwQnlJRDogUmVhY3RQZXJmLm1lYXN1cmUoXG4gICAgJ1JlYWN0RE9NSURPcGVyYXRpb25zJyxcbiAgICAnZGFuZ2Vyb3VzbHlSZXBsYWNlTm9kZVdpdGhNYXJrdXBCeUlEJyxcbiAgICBmdW5jdGlvbihpZCwgbWFya3VwKSB7XG4gICAgICB2YXIgbm9kZSA9IFJlYWN0TW91bnQuZ2V0Tm9kZShpZCk7XG4gICAgICBET01DaGlsZHJlbk9wZXJhdGlvbnMuZGFuZ2Vyb3VzbHlSZXBsYWNlTm9kZVdpdGhNYXJrdXAobm9kZSwgbWFya3VwKTtcbiAgICB9XG4gICksXG5cbiAgLyoqXG4gICAqIFVwZGF0ZXMgYSBjb21wb25lbnQncyBjaGlsZHJlbiBieSBwcm9jZXNzaW5nIGEgc2VyaWVzIG9mIHVwZGF0ZXMuXG4gICAqXG4gICAqIEBwYXJhbSB7YXJyYXk8b2JqZWN0Pn0gdXBkYXRlcyBMaXN0IG9mIHVwZGF0ZSBjb25maWd1cmF0aW9ucy5cbiAgICogQHBhcmFtIHthcnJheTxzdHJpbmc+fSBtYXJrdXAgTGlzdCBvZiBtYXJrdXAgc3RyaW5ncy5cbiAgICogQGludGVybmFsXG4gICAqL1xuICBkYW5nZXJvdXNseVByb2Nlc3NDaGlsZHJlblVwZGF0ZXM6IFJlYWN0UGVyZi5tZWFzdXJlKFxuICAgICdSZWFjdERPTUlET3BlcmF0aW9ucycsXG4gICAgJ2Rhbmdlcm91c2x5UHJvY2Vzc0NoaWxkcmVuVXBkYXRlcycsXG4gICAgZnVuY3Rpb24odXBkYXRlcywgbWFya3VwKSB7XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHVwZGF0ZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdXBkYXRlc1tpXS5wYXJlbnROb2RlID0gUmVhY3RNb3VudC5nZXROb2RlKHVwZGF0ZXNbaV0ucGFyZW50SUQpO1xuICAgICAgfVxuICAgICAgRE9NQ2hpbGRyZW5PcGVyYXRpb25zLnByb2Nlc3NVcGRhdGVzKHVwZGF0ZXMsIG1hcmt1cCk7XG4gICAgfVxuICApXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0RE9NSURPcGVyYXRpb25zO1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RET01JbWdcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIEV2ZW50Q29uc3RhbnRzID0gcmVxdWlyZShcIi4vRXZlbnRDb25zdGFudHNcIik7XG52YXIgTG9jYWxFdmVudFRyYXBNaXhpbiA9IHJlcXVpcmUoXCIuL0xvY2FsRXZlbnRUcmFwTWl4aW5cIik7XG52YXIgUmVhY3RCcm93c2VyQ29tcG9uZW50TWl4aW4gPSByZXF1aXJlKFwiLi9SZWFjdEJyb3dzZXJDb21wb25lbnRNaXhpblwiKTtcbnZhciBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudCA9IHJlcXVpcmUoXCIuL1JlYWN0Q29tcG9zaXRlQ29tcG9uZW50XCIpO1xudmFyIFJlYWN0RWxlbWVudCA9IHJlcXVpcmUoXCIuL1JlYWN0RWxlbWVudFwiKTtcbnZhciBSZWFjdERPTSA9IHJlcXVpcmUoXCIuL1JlYWN0RE9NXCIpO1xuXG4vLyBTdG9yZSBhIHJlZmVyZW5jZSB0byB0aGUgPGltZz4gYFJlYWN0RE9NQ29tcG9uZW50YC4gVE9ETzogdXNlIHN0cmluZ1xudmFyIGltZyA9IFJlYWN0RWxlbWVudC5jcmVhdGVGYWN0b3J5KFJlYWN0RE9NLmltZy50eXBlKTtcblxuLyoqXG4gKiBTaW5jZSBvbkxvYWQgZG9lc24ndCBidWJibGUgT1IgY2FwdHVyZSBvbiB0aGUgdG9wIGxldmVsIGluIElFOCwgd2UgbmVlZCB0b1xuICogY2FwdHVyZSBpdCBvbiB0aGUgPGltZz4gZWxlbWVudCBpdHNlbGYuIFRoZXJlIGFyZSBsb3RzIG9mIGhhY2tzIHdlIGNvdWxkIGRvXG4gKiB0byBhY2NvbXBsaXNoIHRoaXMsIGJ1dCB0aGUgbW9zdCByZWxpYWJsZSBpcyB0byBtYWtlIDxpbWc+IGEgY29tcG9zaXRlXG4gKiBjb21wb25lbnQgYW5kIHVzZSBgY29tcG9uZW50RGlkTW91bnRgIHRvIGF0dGFjaCB0aGUgZXZlbnQgaGFuZGxlcnMuXG4gKi9cbnZhciBSZWFjdERPTUltZyA9IFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50LmNyZWF0ZUNsYXNzKHtcbiAgZGlzcGxheU5hbWU6ICdSZWFjdERPTUltZycsXG4gIHRhZ05hbWU6ICdJTUcnLFxuXG4gIG1peGluczogW1JlYWN0QnJvd3NlckNvbXBvbmVudE1peGluLCBMb2NhbEV2ZW50VHJhcE1peGluXSxcblxuICByZW5kZXI6IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiBpbWcodGhpcy5wcm9wcyk7XG4gIH0sXG5cbiAgY29tcG9uZW50RGlkTW91bnQ6IGZ1bmN0aW9uKCkge1xuICAgIHRoaXMudHJhcEJ1YmJsZWRFdmVudChFdmVudENvbnN0YW50cy50b3BMZXZlbFR5cGVzLnRvcExvYWQsICdsb2FkJyk7XG4gICAgdGhpcy50cmFwQnViYmxlZEV2ZW50KEV2ZW50Q29uc3RhbnRzLnRvcExldmVsVHlwZXMudG9wRXJyb3IsICdlcnJvcicpO1xuICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdERPTUltZztcbiIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RET01JbnB1dFxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgQXV0b0ZvY3VzTWl4aW4gPSByZXF1aXJlKFwiLi9BdXRvRm9jdXNNaXhpblwiKTtcbnZhciBET01Qcm9wZXJ0eU9wZXJhdGlvbnMgPSByZXF1aXJlKFwiLi9ET01Qcm9wZXJ0eU9wZXJhdGlvbnNcIik7XG52YXIgTGlua2VkVmFsdWVVdGlscyA9IHJlcXVpcmUoXCIuL0xpbmtlZFZhbHVlVXRpbHNcIik7XG52YXIgUmVhY3RCcm93c2VyQ29tcG9uZW50TWl4aW4gPSByZXF1aXJlKFwiLi9SZWFjdEJyb3dzZXJDb21wb25lbnRNaXhpblwiKTtcbnZhciBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudCA9IHJlcXVpcmUoXCIuL1JlYWN0Q29tcG9zaXRlQ29tcG9uZW50XCIpO1xudmFyIFJlYWN0RWxlbWVudCA9IHJlcXVpcmUoXCIuL1JlYWN0RWxlbWVudFwiKTtcbnZhciBSZWFjdERPTSA9IHJlcXVpcmUoXCIuL1JlYWN0RE9NXCIpO1xudmFyIFJlYWN0TW91bnQgPSByZXF1aXJlKFwiLi9SZWFjdE1vdW50XCIpO1xudmFyIFJlYWN0VXBkYXRlcyA9IHJlcXVpcmUoXCIuL1JlYWN0VXBkYXRlc1wiKTtcblxudmFyIGFzc2lnbiA9IHJlcXVpcmUoXCIuL09iamVjdC5hc3NpZ25cIik7XG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG4vLyBTdG9yZSBhIHJlZmVyZW5jZSB0byB0aGUgPGlucHV0PiBgUmVhY3RET01Db21wb25lbnRgLiBUT0RPOiB1c2Ugc3RyaW5nXG52YXIgaW5wdXQgPSBSZWFjdEVsZW1lbnQuY3JlYXRlRmFjdG9yeShSZWFjdERPTS5pbnB1dC50eXBlKTtcblxudmFyIGluc3RhbmNlc0J5UmVhY3RJRCA9IHt9O1xuXG5mdW5jdGlvbiBmb3JjZVVwZGF0ZUlmTW91bnRlZCgpIHtcbiAgLypqc2hpbnQgdmFsaWR0aGlzOnRydWUgKi9cbiAgaWYgKHRoaXMuaXNNb3VudGVkKCkpIHtcbiAgICB0aGlzLmZvcmNlVXBkYXRlKCk7XG4gIH1cbn1cblxuLyoqXG4gKiBJbXBsZW1lbnRzIGFuIDxpbnB1dD4gbmF0aXZlIGNvbXBvbmVudCB0aGF0IGFsbG93cyBzZXR0aW5nIHRoZXNlIG9wdGlvbmFsXG4gKiBwcm9wczogYGNoZWNrZWRgLCBgdmFsdWVgLCBgZGVmYXVsdENoZWNrZWRgLCBhbmQgYGRlZmF1bHRWYWx1ZWAuXG4gKlxuICogSWYgYGNoZWNrZWRgIG9yIGB2YWx1ZWAgYXJlIG5vdCBzdXBwbGllZCAob3IgbnVsbC91bmRlZmluZWQpLCB1c2VyIGFjdGlvbnNcbiAqIHRoYXQgYWZmZWN0IHRoZSBjaGVja2VkIHN0YXRlIG9yIHZhbHVlIHdpbGwgdHJpZ2dlciB1cGRhdGVzIHRvIHRoZSBlbGVtZW50LlxuICpcbiAqIElmIHRoZXkgYXJlIHN1cHBsaWVkIChhbmQgbm90IG51bGwvdW5kZWZpbmVkKSwgdGhlIHJlbmRlcmVkIGVsZW1lbnQgd2lsbCBub3RcbiAqIHRyaWdnZXIgdXBkYXRlcyB0byB0aGUgZWxlbWVudC4gSW5zdGVhZCwgdGhlIHByb3BzIG11c3QgY2hhbmdlIGluIG9yZGVyIGZvclxuICogdGhlIHJlbmRlcmVkIGVsZW1lbnQgdG8gYmUgdXBkYXRlZC5cbiAqXG4gKiBUaGUgcmVuZGVyZWQgZWxlbWVudCB3aWxsIGJlIGluaXRpYWxpemVkIGFzIHVuY2hlY2tlZCAob3IgYGRlZmF1bHRDaGVja2VkYClcbiAqIHdpdGggYW4gZW1wdHkgdmFsdWUgKG9yIGBkZWZhdWx0VmFsdWVgKS5cbiAqXG4gKiBAc2VlIGh0dHA6Ly93d3cudzMub3JnL1RSLzIwMTIvV0QtaHRtbDUtMjAxMjEwMjUvdGhlLWlucHV0LWVsZW1lbnQuaHRtbFxuICovXG52YXIgUmVhY3RET01JbnB1dCA9IFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50LmNyZWF0ZUNsYXNzKHtcbiAgZGlzcGxheU5hbWU6ICdSZWFjdERPTUlucHV0JyxcblxuICBtaXhpbnM6IFtBdXRvRm9jdXNNaXhpbiwgTGlua2VkVmFsdWVVdGlscy5NaXhpbiwgUmVhY3RCcm93c2VyQ29tcG9uZW50TWl4aW5dLFxuXG4gIGdldEluaXRpYWxTdGF0ZTogZnVuY3Rpb24oKSB7XG4gICAgdmFyIGRlZmF1bHRWYWx1ZSA9IHRoaXMucHJvcHMuZGVmYXVsdFZhbHVlO1xuICAgIHJldHVybiB7XG4gICAgICBpbml0aWFsQ2hlY2tlZDogdGhpcy5wcm9wcy5kZWZhdWx0Q2hlY2tlZCB8fCBmYWxzZSxcbiAgICAgIGluaXRpYWxWYWx1ZTogZGVmYXVsdFZhbHVlICE9IG51bGwgPyBkZWZhdWx0VmFsdWUgOiBudWxsXG4gICAgfTtcbiAgfSxcblxuICByZW5kZXI6IGZ1bmN0aW9uKCkge1xuICAgIC8vIENsb25lIGB0aGlzLnByb3BzYCBzbyB3ZSBkb24ndCBtdXRhdGUgdGhlIGlucHV0LlxuICAgIHZhciBwcm9wcyA9IGFzc2lnbih7fSwgdGhpcy5wcm9wcyk7XG5cbiAgICBwcm9wcy5kZWZhdWx0Q2hlY2tlZCA9IG51bGw7XG4gICAgcHJvcHMuZGVmYXVsdFZhbHVlID0gbnVsbDtcblxuICAgIHZhciB2YWx1ZSA9IExpbmtlZFZhbHVlVXRpbHMuZ2V0VmFsdWUodGhpcyk7XG4gICAgcHJvcHMudmFsdWUgPSB2YWx1ZSAhPSBudWxsID8gdmFsdWUgOiB0aGlzLnN0YXRlLmluaXRpYWxWYWx1ZTtcblxuICAgIHZhciBjaGVja2VkID0gTGlua2VkVmFsdWVVdGlscy5nZXRDaGVja2VkKHRoaXMpO1xuICAgIHByb3BzLmNoZWNrZWQgPSBjaGVja2VkICE9IG51bGwgPyBjaGVja2VkIDogdGhpcy5zdGF0ZS5pbml0aWFsQ2hlY2tlZDtcblxuICAgIHByb3BzLm9uQ2hhbmdlID0gdGhpcy5faGFuZGxlQ2hhbmdlO1xuXG4gICAgcmV0dXJuIGlucHV0KHByb3BzLCB0aGlzLnByb3BzLmNoaWxkcmVuKTtcbiAgfSxcblxuICBjb21wb25lbnREaWRNb3VudDogZnVuY3Rpb24oKSB7XG4gICAgdmFyIGlkID0gUmVhY3RNb3VudC5nZXRJRCh0aGlzLmdldERPTU5vZGUoKSk7XG4gICAgaW5zdGFuY2VzQnlSZWFjdElEW2lkXSA9IHRoaXM7XG4gIH0sXG5cbiAgY29tcG9uZW50V2lsbFVubW91bnQ6IGZ1bmN0aW9uKCkge1xuICAgIHZhciByb290Tm9kZSA9IHRoaXMuZ2V0RE9NTm9kZSgpO1xuICAgIHZhciBpZCA9IFJlYWN0TW91bnQuZ2V0SUQocm9vdE5vZGUpO1xuICAgIGRlbGV0ZSBpbnN0YW5jZXNCeVJlYWN0SURbaWRdO1xuICB9LFxuXG4gIGNvbXBvbmVudERpZFVwZGF0ZTogZnVuY3Rpb24ocHJldlByb3BzLCBwcmV2U3RhdGUsIHByZXZDb250ZXh0KSB7XG4gICAgdmFyIHJvb3ROb2RlID0gdGhpcy5nZXRET01Ob2RlKCk7XG4gICAgaWYgKHRoaXMucHJvcHMuY2hlY2tlZCAhPSBudWxsKSB7XG4gICAgICBET01Qcm9wZXJ0eU9wZXJhdGlvbnMuc2V0VmFsdWVGb3JQcm9wZXJ0eShcbiAgICAgICAgcm9vdE5vZGUsXG4gICAgICAgICdjaGVja2VkJyxcbiAgICAgICAgdGhpcy5wcm9wcy5jaGVja2VkIHx8IGZhbHNlXG4gICAgICApO1xuICAgIH1cblxuICAgIHZhciB2YWx1ZSA9IExpbmtlZFZhbHVlVXRpbHMuZ2V0VmFsdWUodGhpcyk7XG4gICAgaWYgKHZhbHVlICE9IG51bGwpIHtcbiAgICAgIC8vIENhc3QgYHZhbHVlYCB0byBhIHN0cmluZyB0byBlbnN1cmUgdGhlIHZhbHVlIGlzIHNldCBjb3JyZWN0bHkuIFdoaWxlXG4gICAgICAvLyBicm93c2VycyB0eXBpY2FsbHkgZG8gdGhpcyBhcyBuZWNlc3NhcnksIGpzZG9tIGRvZXNuJ3QuXG4gICAgICBET01Qcm9wZXJ0eU9wZXJhdGlvbnMuc2V0VmFsdWVGb3JQcm9wZXJ0eShyb290Tm9kZSwgJ3ZhbHVlJywgJycgKyB2YWx1ZSk7XG4gICAgfVxuICB9LFxuXG4gIF9oYW5kbGVDaGFuZ2U6IGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgdmFyIHJldHVyblZhbHVlO1xuICAgIHZhciBvbkNoYW5nZSA9IExpbmtlZFZhbHVlVXRpbHMuZ2V0T25DaGFuZ2UodGhpcyk7XG4gICAgaWYgKG9uQ2hhbmdlKSB7XG4gICAgICByZXR1cm5WYWx1ZSA9IG9uQ2hhbmdlLmNhbGwodGhpcywgZXZlbnQpO1xuICAgIH1cbiAgICAvLyBIZXJlIHdlIHVzZSBhc2FwIHRvIHdhaXQgdW50aWwgYWxsIHVwZGF0ZXMgaGF2ZSBwcm9wYWdhdGVkLCB3aGljaFxuICAgIC8vIGlzIGltcG9ydGFudCB3aGVuIHVzaW5nIGNvbnRyb2xsZWQgY29tcG9uZW50cyB3aXRoaW4gbGF5ZXJzOlxuICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9mYWNlYm9vay9yZWFjdC9pc3N1ZXMvMTY5OFxuICAgIFJlYWN0VXBkYXRlcy5hc2FwKGZvcmNlVXBkYXRlSWZNb3VudGVkLCB0aGlzKTtcblxuICAgIHZhciBuYW1lID0gdGhpcy5wcm9wcy5uYW1lO1xuICAgIGlmICh0aGlzLnByb3BzLnR5cGUgPT09ICdyYWRpbycgJiYgbmFtZSAhPSBudWxsKSB7XG4gICAgICB2YXIgcm9vdE5vZGUgPSB0aGlzLmdldERPTU5vZGUoKTtcbiAgICAgIHZhciBxdWVyeVJvb3QgPSByb290Tm9kZTtcblxuICAgICAgd2hpbGUgKHF1ZXJ5Um9vdC5wYXJlbnROb2RlKSB7XG4gICAgICAgIHF1ZXJ5Um9vdCA9IHF1ZXJ5Um9vdC5wYXJlbnROb2RlO1xuICAgICAgfVxuXG4gICAgICAvLyBJZiBgcm9vdE5vZGUuZm9ybWAgd2FzIG5vbi1udWxsLCB0aGVuIHdlIGNvdWxkIHRyeSBgZm9ybS5lbGVtZW50c2AsXG4gICAgICAvLyBidXQgdGhhdCBzb21ldGltZXMgYmVoYXZlcyBzdHJhbmdlbHkgaW4gSUU4LiBXZSBjb3VsZCBhbHNvIHRyeSB1c2luZ1xuICAgICAgLy8gYGZvcm0uZ2V0RWxlbWVudHNCeU5hbWVgLCBidXQgdGhhdCB3aWxsIG9ubHkgcmV0dXJuIGRpcmVjdCBjaGlsZHJlblxuICAgICAgLy8gYW5kIHdvbid0IGluY2x1ZGUgaW5wdXRzIHRoYXQgdXNlIHRoZSBIVE1MNSBgZm9ybT1gIGF0dHJpYnV0ZS4gU2luY2VcbiAgICAgIC8vIHRoZSBpbnB1dCBtaWdodCBub3QgZXZlbiBiZSBpbiBhIGZvcm0sIGxldCdzIGp1c3QgdXNlIHRoZSBnbG9iYWxcbiAgICAgIC8vIGBxdWVyeVNlbGVjdG9yQWxsYCB0byBlbnN1cmUgd2UgZG9uJ3QgbWlzcyBhbnl0aGluZy5cbiAgICAgIHZhciBncm91cCA9IHF1ZXJ5Um9vdC5xdWVyeVNlbGVjdG9yQWxsKFxuICAgICAgICAnaW5wdXRbbmFtZT0nICsgSlNPTi5zdHJpbmdpZnkoJycgKyBuYW1lKSArICddW3R5cGU9XCJyYWRpb1wiXScpO1xuXG4gICAgICBmb3IgKHZhciBpID0gMCwgZ3JvdXBMZW4gPSBncm91cC5sZW5ndGg7IGkgPCBncm91cExlbjsgaSsrKSB7XG4gICAgICAgIHZhciBvdGhlck5vZGUgPSBncm91cFtpXTtcbiAgICAgICAgaWYgKG90aGVyTm9kZSA9PT0gcm9vdE5vZGUgfHxcbiAgICAgICAgICAgIG90aGVyTm9kZS5mb3JtICE9PSByb290Tm9kZS5mb3JtKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIG90aGVySUQgPSBSZWFjdE1vdW50LmdldElEKG90aGVyTm9kZSk7XG4gICAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgICAgb3RoZXJJRCxcbiAgICAgICAgICAnUmVhY3RET01JbnB1dDogTWl4aW5nIFJlYWN0IGFuZCBub24tUmVhY3QgcmFkaW8gaW5wdXRzIHdpdGggdGhlICcgK1xuICAgICAgICAgICdzYW1lIGBuYW1lYCBpcyBub3Qgc3VwcG9ydGVkLidcbiAgICAgICAgKSA6IGludmFyaWFudChvdGhlcklEKSk7XG4gICAgICAgIHZhciBvdGhlckluc3RhbmNlID0gaW5zdGFuY2VzQnlSZWFjdElEW290aGVySURdO1xuICAgICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICAgIG90aGVySW5zdGFuY2UsXG4gICAgICAgICAgJ1JlYWN0RE9NSW5wdXQ6IFVua25vd24gcmFkaW8gYnV0dG9uIElEICVzLicsXG4gICAgICAgICAgb3RoZXJJRFxuICAgICAgICApIDogaW52YXJpYW50KG90aGVySW5zdGFuY2UpKTtcbiAgICAgICAgLy8gSWYgdGhpcyBpcyBhIGNvbnRyb2xsZWQgcmFkaW8gYnV0dG9uIGdyb3VwLCBmb3JjaW5nIHRoZSBpbnB1dCB0aGF0XG4gICAgICAgIC8vIHdhcyBwcmV2aW91c2x5IGNoZWNrZWQgdG8gdXBkYXRlIHdpbGwgY2F1c2UgaXQgdG8gYmUgY29tZSByZS1jaGVja2VkXG4gICAgICAgIC8vIGFzIGFwcHJvcHJpYXRlLlxuICAgICAgICBSZWFjdFVwZGF0ZXMuYXNhcChmb3JjZVVwZGF0ZUlmTW91bnRlZCwgb3RoZXJJbnN0YW5jZSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHJldHVyblZhbHVlO1xuICB9XG5cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0RE9NSW5wdXQ7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RET01PcHRpb25cbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFJlYWN0QnJvd3NlckNvbXBvbmVudE1peGluID0gcmVxdWlyZShcIi4vUmVhY3RCcm93c2VyQ29tcG9uZW50TWl4aW5cIik7XG52YXIgUmVhY3RDb21wb3NpdGVDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdENvbXBvc2l0ZUNvbXBvbmVudFwiKTtcbnZhciBSZWFjdEVsZW1lbnQgPSByZXF1aXJlKFwiLi9SZWFjdEVsZW1lbnRcIik7XG52YXIgUmVhY3RET00gPSByZXF1aXJlKFwiLi9SZWFjdERPTVwiKTtcblxudmFyIHdhcm5pbmcgPSByZXF1aXJlKFwiLi93YXJuaW5nXCIpO1xuXG4vLyBTdG9yZSBhIHJlZmVyZW5jZSB0byB0aGUgPG9wdGlvbj4gYFJlYWN0RE9NQ29tcG9uZW50YC4gVE9ETzogdXNlIHN0cmluZ1xudmFyIG9wdGlvbiA9IFJlYWN0RWxlbWVudC5jcmVhdGVGYWN0b3J5KFJlYWN0RE9NLm9wdGlvbi50eXBlKTtcblxuLyoqXG4gKiBJbXBsZW1lbnRzIGFuIDxvcHRpb24+IG5hdGl2ZSBjb21wb25lbnQgdGhhdCB3YXJucyB3aGVuIGBzZWxlY3RlZGAgaXMgc2V0LlxuICovXG52YXIgUmVhY3RET01PcHRpb24gPSBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudC5jcmVhdGVDbGFzcyh7XG4gIGRpc3BsYXlOYW1lOiAnUmVhY3RET01PcHRpb24nLFxuXG4gIG1peGluczogW1JlYWN0QnJvd3NlckNvbXBvbmVudE1peGluXSxcblxuICBjb21wb25lbnRXaWxsTW91bnQ6IGZ1bmN0aW9uKCkge1xuICAgIC8vIFRPRE8gKHl1bmdzdGVycyk6IFJlbW92ZSBzdXBwb3J0IGZvciBgc2VsZWN0ZWRgIGluIDxvcHRpb24+LlxuICAgIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyB3YXJuaW5nKFxuICAgICAgICB0aGlzLnByb3BzLnNlbGVjdGVkID09IG51bGwsXG4gICAgICAgICdVc2UgdGhlIGBkZWZhdWx0VmFsdWVgIG9yIGB2YWx1ZWAgcHJvcHMgb24gPHNlbGVjdD4gaW5zdGVhZCBvZiAnICtcbiAgICAgICAgJ3NldHRpbmcgYHNlbGVjdGVkYCBvbiA8b3B0aW9uPi4nXG4gICAgICApIDogbnVsbCk7XG4gICAgfVxuICB9LFxuXG4gIHJlbmRlcjogZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIG9wdGlvbih0aGlzLnByb3BzLCB0aGlzLnByb3BzLmNoaWxkcmVuKTtcbiAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdERPTU9wdGlvbjtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0RE9NU2VsZWN0XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBBdXRvRm9jdXNNaXhpbiA9IHJlcXVpcmUoXCIuL0F1dG9Gb2N1c01peGluXCIpO1xudmFyIExpbmtlZFZhbHVlVXRpbHMgPSByZXF1aXJlKFwiLi9MaW5rZWRWYWx1ZVV0aWxzXCIpO1xudmFyIFJlYWN0QnJvd3NlckNvbXBvbmVudE1peGluID0gcmVxdWlyZShcIi4vUmVhY3RCcm93c2VyQ29tcG9uZW50TWl4aW5cIik7XG52YXIgUmVhY3RDb21wb3NpdGVDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdENvbXBvc2l0ZUNvbXBvbmVudFwiKTtcbnZhciBSZWFjdEVsZW1lbnQgPSByZXF1aXJlKFwiLi9SZWFjdEVsZW1lbnRcIik7XG52YXIgUmVhY3RET00gPSByZXF1aXJlKFwiLi9SZWFjdERPTVwiKTtcbnZhciBSZWFjdFVwZGF0ZXMgPSByZXF1aXJlKFwiLi9SZWFjdFVwZGF0ZXNcIik7XG5cbnZhciBhc3NpZ24gPSByZXF1aXJlKFwiLi9PYmplY3QuYXNzaWduXCIpO1xuXG4vLyBTdG9yZSBhIHJlZmVyZW5jZSB0byB0aGUgPHNlbGVjdD4gYFJlYWN0RE9NQ29tcG9uZW50YC4gVE9ETzogdXNlIHN0cmluZ1xudmFyIHNlbGVjdCA9IFJlYWN0RWxlbWVudC5jcmVhdGVGYWN0b3J5KFJlYWN0RE9NLnNlbGVjdC50eXBlKTtcblxuZnVuY3Rpb24gdXBkYXRlV2l0aFBlbmRpbmdWYWx1ZUlmTW91bnRlZCgpIHtcbiAgLypqc2hpbnQgdmFsaWR0aGlzOnRydWUgKi9cbiAgaWYgKHRoaXMuaXNNb3VudGVkKCkpIHtcbiAgICB0aGlzLnNldFN0YXRlKHt2YWx1ZTogdGhpcy5fcGVuZGluZ1ZhbHVlfSk7XG4gICAgdGhpcy5fcGVuZGluZ1ZhbHVlID0gMDtcbiAgfVxufVxuXG4vKipcbiAqIFZhbGlkYXRpb24gZnVuY3Rpb24gZm9yIGB2YWx1ZWAgYW5kIGBkZWZhdWx0VmFsdWVgLlxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gc2VsZWN0VmFsdWVUeXBlKHByb3BzLCBwcm9wTmFtZSwgY29tcG9uZW50TmFtZSkge1xuICBpZiAocHJvcHNbcHJvcE5hbWVdID09IG51bGwpIHtcbiAgICByZXR1cm47XG4gIH1cbiAgaWYgKHByb3BzLm11bHRpcGxlKSB7XG4gICAgaWYgKCFBcnJheS5pc0FycmF5KHByb3BzW3Byb3BOYW1lXSkpIHtcbiAgICAgIHJldHVybiBuZXcgRXJyb3IoXG4gICAgICAgIChcIlRoZSBgXCIgKyBwcm9wTmFtZSArIFwiYCBwcm9wIHN1cHBsaWVkIHRvIDxzZWxlY3Q+IG11c3QgYmUgYW4gYXJyYXkgaWYgXCIpICtcbiAgICAgICAgKFwiYG11bHRpcGxlYCBpcyB0cnVlLlwiKVxuICAgICAgKTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgaWYgKEFycmF5LmlzQXJyYXkocHJvcHNbcHJvcE5hbWVdKSkge1xuICAgICAgcmV0dXJuIG5ldyBFcnJvcihcbiAgICAgICAgKFwiVGhlIGBcIiArIHByb3BOYW1lICsgXCJgIHByb3Agc3VwcGxpZWQgdG8gPHNlbGVjdD4gbXVzdCBiZSBhIHNjYWxhciBcIikgK1xuICAgICAgICAoXCJ2YWx1ZSBpZiBgbXVsdGlwbGVgIGlzIGZhbHNlLlwiKVxuICAgICAgKTtcbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBJZiBgdmFsdWVgIGlzIHN1cHBsaWVkLCB1cGRhdGVzIDxvcHRpb24+IGVsZW1lbnRzIG9uIG1vdW50IGFuZCB1cGRhdGUuXG4gKiBAcGFyYW0ge1JlYWN0Q29tcG9uZW50fSBjb21wb25lbnQgSW5zdGFuY2Ugb2YgUmVhY3RET01TZWxlY3RcbiAqIEBwYXJhbSB7Pyp9IHByb3BWYWx1ZSBGb3IgdW5jb250cm9sbGVkIGNvbXBvbmVudHMsIG51bGwvdW5kZWZpbmVkLiBGb3JcbiAqIGNvbnRyb2xsZWQgY29tcG9uZW50cywgYSBzdHJpbmcgKG9yIHdpdGggYG11bHRpcGxlYCwgYSBsaXN0IG9mIHN0cmluZ3MpLlxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gdXBkYXRlT3B0aW9ucyhjb21wb25lbnQsIHByb3BWYWx1ZSkge1xuICB2YXIgbXVsdGlwbGUgPSBjb21wb25lbnQucHJvcHMubXVsdGlwbGU7XG4gIHZhciB2YWx1ZSA9IHByb3BWYWx1ZSAhPSBudWxsID8gcHJvcFZhbHVlIDogY29tcG9uZW50LnN0YXRlLnZhbHVlO1xuICB2YXIgb3B0aW9ucyA9IGNvbXBvbmVudC5nZXRET01Ob2RlKCkub3B0aW9ucztcbiAgdmFyIHNlbGVjdGVkVmFsdWUsIGksIGw7XG4gIGlmIChtdWx0aXBsZSkge1xuICAgIHNlbGVjdGVkVmFsdWUgPSB7fTtcbiAgICBmb3IgKGkgPSAwLCBsID0gdmFsdWUubGVuZ3RoOyBpIDwgbDsgKytpKSB7XG4gICAgICBzZWxlY3RlZFZhbHVlWycnICsgdmFsdWVbaV1dID0gdHJ1ZTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgc2VsZWN0ZWRWYWx1ZSA9ICcnICsgdmFsdWU7XG4gIH1cbiAgZm9yIChpID0gMCwgbCA9IG9wdGlvbnMubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XG4gICAgdmFyIHNlbGVjdGVkID0gbXVsdGlwbGUgP1xuICAgICAgc2VsZWN0ZWRWYWx1ZS5oYXNPd25Qcm9wZXJ0eShvcHRpb25zW2ldLnZhbHVlKSA6XG4gICAgICBvcHRpb25zW2ldLnZhbHVlID09PSBzZWxlY3RlZFZhbHVlO1xuXG4gICAgaWYgKHNlbGVjdGVkICE9PSBvcHRpb25zW2ldLnNlbGVjdGVkKSB7XG4gICAgICBvcHRpb25zW2ldLnNlbGVjdGVkID0gc2VsZWN0ZWQ7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogSW1wbGVtZW50cyBhIDxzZWxlY3Q+IG5hdGl2ZSBjb21wb25lbnQgdGhhdCBhbGxvd3Mgb3B0aW9uYWxseSBzZXR0aW5nIHRoZVxuICogcHJvcHMgYHZhbHVlYCBhbmQgYGRlZmF1bHRWYWx1ZWAuIElmIGBtdWx0aXBsZWAgaXMgZmFsc2UsIHRoZSBwcm9wIG11c3QgYmUgYVxuICogc3RyaW5nLiBJZiBgbXVsdGlwbGVgIGlzIHRydWUsIHRoZSBwcm9wIG11c3QgYmUgYW4gYXJyYXkgb2Ygc3RyaW5ncy5cbiAqXG4gKiBJZiBgdmFsdWVgIGlzIG5vdCBzdXBwbGllZCAob3IgbnVsbC91bmRlZmluZWQpLCB1c2VyIGFjdGlvbnMgdGhhdCBjaGFuZ2UgdGhlXG4gKiBzZWxlY3RlZCBvcHRpb24gd2lsbCB0cmlnZ2VyIHVwZGF0ZXMgdG8gdGhlIHJlbmRlcmVkIG9wdGlvbnMuXG4gKlxuICogSWYgaXQgaXMgc3VwcGxpZWQgKGFuZCBub3QgbnVsbC91bmRlZmluZWQpLCB0aGUgcmVuZGVyZWQgb3B0aW9ucyB3aWxsIG5vdFxuICogdXBkYXRlIGluIHJlc3BvbnNlIHRvIHVzZXIgYWN0aW9ucy4gSW5zdGVhZCwgdGhlIGB2YWx1ZWAgcHJvcCBtdXN0IGNoYW5nZSBpblxuICogb3JkZXIgZm9yIHRoZSByZW5kZXJlZCBvcHRpb25zIHRvIHVwZGF0ZS5cbiAqXG4gKiBJZiBgZGVmYXVsdFZhbHVlYCBpcyBwcm92aWRlZCwgYW55IG9wdGlvbnMgd2l0aCB0aGUgc3VwcGxpZWQgdmFsdWVzIHdpbGwgYmVcbiAqIHNlbGVjdGVkLlxuICovXG52YXIgUmVhY3RET01TZWxlY3QgPSBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudC5jcmVhdGVDbGFzcyh7XG4gIGRpc3BsYXlOYW1lOiAnUmVhY3RET01TZWxlY3QnLFxuXG4gIG1peGluczogW0F1dG9Gb2N1c01peGluLCBMaW5rZWRWYWx1ZVV0aWxzLk1peGluLCBSZWFjdEJyb3dzZXJDb21wb25lbnRNaXhpbl0sXG5cbiAgcHJvcFR5cGVzOiB7XG4gICAgZGVmYXVsdFZhbHVlOiBzZWxlY3RWYWx1ZVR5cGUsXG4gICAgdmFsdWU6IHNlbGVjdFZhbHVlVHlwZVxuICB9LFxuXG4gIGdldEluaXRpYWxTdGF0ZTogZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHt2YWx1ZTogdGhpcy5wcm9wcy5kZWZhdWx0VmFsdWUgfHwgKHRoaXMucHJvcHMubXVsdGlwbGUgPyBbXSA6ICcnKX07XG4gIH0sXG5cbiAgY29tcG9uZW50V2lsbE1vdW50OiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLl9wZW5kaW5nVmFsdWUgPSBudWxsO1xuICB9LFxuXG4gIGNvbXBvbmVudFdpbGxSZWNlaXZlUHJvcHM6IGZ1bmN0aW9uKG5leHRQcm9wcykge1xuICAgIGlmICghdGhpcy5wcm9wcy5tdWx0aXBsZSAmJiBuZXh0UHJvcHMubXVsdGlwbGUpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe3ZhbHVlOiBbdGhpcy5zdGF0ZS52YWx1ZV19KTtcbiAgICB9IGVsc2UgaWYgKHRoaXMucHJvcHMubXVsdGlwbGUgJiYgIW5leHRQcm9wcy5tdWx0aXBsZSkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7dmFsdWU6IHRoaXMuc3RhdGUudmFsdWVbMF19KTtcbiAgICB9XG4gIH0sXG5cbiAgcmVuZGVyOiBmdW5jdGlvbigpIHtcbiAgICAvLyBDbG9uZSBgdGhpcy5wcm9wc2Agc28gd2UgZG9uJ3QgbXV0YXRlIHRoZSBpbnB1dC5cbiAgICB2YXIgcHJvcHMgPSBhc3NpZ24oe30sIHRoaXMucHJvcHMpO1xuXG4gICAgcHJvcHMub25DaGFuZ2UgPSB0aGlzLl9oYW5kbGVDaGFuZ2U7XG4gICAgcHJvcHMudmFsdWUgPSBudWxsO1xuXG4gICAgcmV0dXJuIHNlbGVjdChwcm9wcywgdGhpcy5wcm9wcy5jaGlsZHJlbik7XG4gIH0sXG5cbiAgY29tcG9uZW50RGlkTW91bnQ6IGZ1bmN0aW9uKCkge1xuICAgIHVwZGF0ZU9wdGlvbnModGhpcywgTGlua2VkVmFsdWVVdGlscy5nZXRWYWx1ZSh0aGlzKSk7XG4gIH0sXG5cbiAgY29tcG9uZW50RGlkVXBkYXRlOiBmdW5jdGlvbihwcmV2UHJvcHMpIHtcbiAgICB2YXIgdmFsdWUgPSBMaW5rZWRWYWx1ZVV0aWxzLmdldFZhbHVlKHRoaXMpO1xuICAgIHZhciBwcmV2TXVsdGlwbGUgPSAhIXByZXZQcm9wcy5tdWx0aXBsZTtcbiAgICB2YXIgbXVsdGlwbGUgPSAhIXRoaXMucHJvcHMubXVsdGlwbGU7XG4gICAgaWYgKHZhbHVlICE9IG51bGwgfHwgcHJldk11bHRpcGxlICE9PSBtdWx0aXBsZSkge1xuICAgICAgdXBkYXRlT3B0aW9ucyh0aGlzLCB2YWx1ZSk7XG4gICAgfVxuICB9LFxuXG4gIF9oYW5kbGVDaGFuZ2U6IGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgdmFyIHJldHVyblZhbHVlO1xuICAgIHZhciBvbkNoYW5nZSA9IExpbmtlZFZhbHVlVXRpbHMuZ2V0T25DaGFuZ2UodGhpcyk7XG4gICAgaWYgKG9uQ2hhbmdlKSB7XG4gICAgICByZXR1cm5WYWx1ZSA9IG9uQ2hhbmdlLmNhbGwodGhpcywgZXZlbnQpO1xuICAgIH1cblxuICAgIHZhciBzZWxlY3RlZFZhbHVlO1xuICAgIGlmICh0aGlzLnByb3BzLm11bHRpcGxlKSB7XG4gICAgICBzZWxlY3RlZFZhbHVlID0gW107XG4gICAgICB2YXIgb3B0aW9ucyA9IGV2ZW50LnRhcmdldC5vcHRpb25zO1xuICAgICAgZm9yICh2YXIgaSA9IDAsIGwgPSBvcHRpb25zLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgICAgICBpZiAob3B0aW9uc1tpXS5zZWxlY3RlZCkge1xuICAgICAgICAgIHNlbGVjdGVkVmFsdWUucHVzaChvcHRpb25zW2ldLnZhbHVlKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBzZWxlY3RlZFZhbHVlID0gZXZlbnQudGFyZ2V0LnZhbHVlO1xuICAgIH1cblxuICAgIHRoaXMuX3BlbmRpbmdWYWx1ZSA9IHNlbGVjdGVkVmFsdWU7XG4gICAgUmVhY3RVcGRhdGVzLmFzYXAodXBkYXRlV2l0aFBlbmRpbmdWYWx1ZUlmTW91bnRlZCwgdGhpcyk7XG4gICAgcmV0dXJuIHJldHVyblZhbHVlO1xuICB9XG5cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0RE9NU2VsZWN0O1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0RE9NU2VsZWN0aW9uXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBFeGVjdXRpb25FbnZpcm9ubWVudCA9IHJlcXVpcmUoXCIuL0V4ZWN1dGlvbkVudmlyb25tZW50XCIpO1xuXG52YXIgZ2V0Tm9kZUZvckNoYXJhY3Rlck9mZnNldCA9IHJlcXVpcmUoXCIuL2dldE5vZGVGb3JDaGFyYWN0ZXJPZmZzZXRcIik7XG52YXIgZ2V0VGV4dENvbnRlbnRBY2Nlc3NvciA9IHJlcXVpcmUoXCIuL2dldFRleHRDb250ZW50QWNjZXNzb3JcIik7XG5cbi8qKlxuICogV2hpbGUgYGlzQ29sbGFwc2VkYCBpcyBhdmFpbGFibGUgb24gdGhlIFNlbGVjdGlvbiBvYmplY3QgYW5kIGBjb2xsYXBzZWRgXG4gKiBpcyBhdmFpbGFibGUgb24gdGhlIFJhbmdlIG9iamVjdCwgSUUxMSBzb21ldGltZXMgZ2V0cyB0aGVtIHdyb25nLlxuICogSWYgdGhlIGFuY2hvci9mb2N1cyBub2RlcyBhbmQgb2Zmc2V0cyBhcmUgdGhlIHNhbWUsIHRoZSByYW5nZSBpcyBjb2xsYXBzZWQuXG4gKi9cbmZ1bmN0aW9uIGlzQ29sbGFwc2VkKGFuY2hvck5vZGUsIGFuY2hvck9mZnNldCwgZm9jdXNOb2RlLCBmb2N1c09mZnNldCkge1xuICByZXR1cm4gYW5jaG9yTm9kZSA9PT0gZm9jdXNOb2RlICYmIGFuY2hvck9mZnNldCA9PT0gZm9jdXNPZmZzZXQ7XG59XG5cbi8qKlxuICogR2V0IHRoZSBhcHByb3ByaWF0ZSBhbmNob3IgYW5kIGZvY3VzIG5vZGUvb2Zmc2V0IHBhaXJzIGZvciBJRS5cbiAqXG4gKiBUaGUgY2F0Y2ggaGVyZSBpcyB0aGF0IElFJ3Mgc2VsZWN0aW9uIEFQSSBkb2Vzbid0IHByb3ZpZGUgaW5mb3JtYXRpb25cbiAqIGFib3V0IHdoZXRoZXIgdGhlIHNlbGVjdGlvbiBpcyBmb3J3YXJkIG9yIGJhY2t3YXJkLCBzbyB3ZSBoYXZlIHRvXG4gKiBiZWhhdmUgYXMgdGhvdWdoIGl0J3MgYWx3YXlzIGZvcndhcmQuXG4gKlxuICogSUUgdGV4dCBkaWZmZXJzIGZyb20gbW9kZXJuIHNlbGVjdGlvbiBpbiB0aGF0IGl0IGJlaGF2ZXMgYXMgdGhvdWdoXG4gKiBibG9jayBlbGVtZW50cyBlbmQgd2l0aCBhIG5ldyBsaW5lLiBUaGlzIG1lYW5zIGNoYXJhY3RlciBvZmZzZXRzIHdpbGxcbiAqIGRpZmZlciBiZXR3ZWVuIHRoZSB0d28gQVBJcy5cbiAqXG4gKiBAcGFyYW0ge0RPTUVsZW1lbnR9IG5vZGVcbiAqIEByZXR1cm4ge29iamVjdH1cbiAqL1xuZnVuY3Rpb24gZ2V0SUVPZmZzZXRzKG5vZGUpIHtcbiAgdmFyIHNlbGVjdGlvbiA9IGRvY3VtZW50LnNlbGVjdGlvbjtcbiAgdmFyIHNlbGVjdGVkUmFuZ2UgPSBzZWxlY3Rpb24uY3JlYXRlUmFuZ2UoKTtcbiAgdmFyIHNlbGVjdGVkTGVuZ3RoID0gc2VsZWN0ZWRSYW5nZS50ZXh0Lmxlbmd0aDtcblxuICAvLyBEdXBsaWNhdGUgc2VsZWN0aW9uIHNvIHdlIGNhbiBtb3ZlIHJhbmdlIHdpdGhvdXQgYnJlYWtpbmcgdXNlciBzZWxlY3Rpb24uXG4gIHZhciBmcm9tU3RhcnQgPSBzZWxlY3RlZFJhbmdlLmR1cGxpY2F0ZSgpO1xuICBmcm9tU3RhcnQubW92ZVRvRWxlbWVudFRleHQobm9kZSk7XG4gIGZyb21TdGFydC5zZXRFbmRQb2ludCgnRW5kVG9TdGFydCcsIHNlbGVjdGVkUmFuZ2UpO1xuXG4gIHZhciBzdGFydE9mZnNldCA9IGZyb21TdGFydC50ZXh0Lmxlbmd0aDtcbiAgdmFyIGVuZE9mZnNldCA9IHN0YXJ0T2Zmc2V0ICsgc2VsZWN0ZWRMZW5ndGg7XG5cbiAgcmV0dXJuIHtcbiAgICBzdGFydDogc3RhcnRPZmZzZXQsXG4gICAgZW5kOiBlbmRPZmZzZXRcbiAgfTtcbn1cblxuLyoqXG4gKiBAcGFyYW0ge0RPTUVsZW1lbnR9IG5vZGVcbiAqIEByZXR1cm4gez9vYmplY3R9XG4gKi9cbmZ1bmN0aW9uIGdldE1vZGVybk9mZnNldHMobm9kZSkge1xuICB2YXIgc2VsZWN0aW9uID0gd2luZG93LmdldFNlbGVjdGlvbiAmJiB3aW5kb3cuZ2V0U2VsZWN0aW9uKCk7XG5cbiAgaWYgKCFzZWxlY3Rpb24gfHwgc2VsZWN0aW9uLnJhbmdlQ291bnQgPT09IDApIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIHZhciBhbmNob3JOb2RlID0gc2VsZWN0aW9uLmFuY2hvck5vZGU7XG4gIHZhciBhbmNob3JPZmZzZXQgPSBzZWxlY3Rpb24uYW5jaG9yT2Zmc2V0O1xuICB2YXIgZm9jdXNOb2RlID0gc2VsZWN0aW9uLmZvY3VzTm9kZTtcbiAgdmFyIGZvY3VzT2Zmc2V0ID0gc2VsZWN0aW9uLmZvY3VzT2Zmc2V0O1xuXG4gIHZhciBjdXJyZW50UmFuZ2UgPSBzZWxlY3Rpb24uZ2V0UmFuZ2VBdCgwKTtcblxuICAvLyBJZiB0aGUgbm9kZSBhbmQgb2Zmc2V0IHZhbHVlcyBhcmUgdGhlIHNhbWUsIHRoZSBzZWxlY3Rpb24gaXMgY29sbGFwc2VkLlxuICAvLyBgU2VsZWN0aW9uLmlzQ29sbGFwc2VkYCBpcyBhdmFpbGFibGUgbmF0aXZlbHksIGJ1dCBJRSBzb21ldGltZXMgZ2V0c1xuICAvLyB0aGlzIHZhbHVlIHdyb25nLlxuICB2YXIgaXNTZWxlY3Rpb25Db2xsYXBzZWQgPSBpc0NvbGxhcHNlZChcbiAgICBzZWxlY3Rpb24uYW5jaG9yTm9kZSxcbiAgICBzZWxlY3Rpb24uYW5jaG9yT2Zmc2V0LFxuICAgIHNlbGVjdGlvbi5mb2N1c05vZGUsXG4gICAgc2VsZWN0aW9uLmZvY3VzT2Zmc2V0XG4gICk7XG5cbiAgdmFyIHJhbmdlTGVuZ3RoID0gaXNTZWxlY3Rpb25Db2xsYXBzZWQgPyAwIDogY3VycmVudFJhbmdlLnRvU3RyaW5nKCkubGVuZ3RoO1xuXG4gIHZhciB0ZW1wUmFuZ2UgPSBjdXJyZW50UmFuZ2UuY2xvbmVSYW5nZSgpO1xuICB0ZW1wUmFuZ2Uuc2VsZWN0Tm9kZUNvbnRlbnRzKG5vZGUpO1xuICB0ZW1wUmFuZ2Uuc2V0RW5kKGN1cnJlbnRSYW5nZS5zdGFydENvbnRhaW5lciwgY3VycmVudFJhbmdlLnN0YXJ0T2Zmc2V0KTtcblxuICB2YXIgaXNUZW1wUmFuZ2VDb2xsYXBzZWQgPSBpc0NvbGxhcHNlZChcbiAgICB0ZW1wUmFuZ2Uuc3RhcnRDb250YWluZXIsXG4gICAgdGVtcFJhbmdlLnN0YXJ0T2Zmc2V0LFxuICAgIHRlbXBSYW5nZS5lbmRDb250YWluZXIsXG4gICAgdGVtcFJhbmdlLmVuZE9mZnNldFxuICApO1xuXG4gIHZhciBzdGFydCA9IGlzVGVtcFJhbmdlQ29sbGFwc2VkID8gMCA6IHRlbXBSYW5nZS50b1N0cmluZygpLmxlbmd0aDtcbiAgdmFyIGVuZCA9IHN0YXJ0ICsgcmFuZ2VMZW5ndGg7XG5cbiAgLy8gRGV0ZWN0IHdoZXRoZXIgdGhlIHNlbGVjdGlvbiBpcyBiYWNrd2FyZC5cbiAgdmFyIGRldGVjdGlvblJhbmdlID0gZG9jdW1lbnQuY3JlYXRlUmFuZ2UoKTtcbiAgZGV0ZWN0aW9uUmFuZ2Uuc2V0U3RhcnQoYW5jaG9yTm9kZSwgYW5jaG9yT2Zmc2V0KTtcbiAgZGV0ZWN0aW9uUmFuZ2Uuc2V0RW5kKGZvY3VzTm9kZSwgZm9jdXNPZmZzZXQpO1xuICB2YXIgaXNCYWNrd2FyZCA9IGRldGVjdGlvblJhbmdlLmNvbGxhcHNlZDtcblxuICByZXR1cm4ge1xuICAgIHN0YXJ0OiBpc0JhY2t3YXJkID8gZW5kIDogc3RhcnQsXG4gICAgZW5kOiBpc0JhY2t3YXJkID8gc3RhcnQgOiBlbmRcbiAgfTtcbn1cblxuLyoqXG4gKiBAcGFyYW0ge0RPTUVsZW1lbnR8RE9NVGV4dE5vZGV9IG5vZGVcbiAqIEBwYXJhbSB7b2JqZWN0fSBvZmZzZXRzXG4gKi9cbmZ1bmN0aW9uIHNldElFT2Zmc2V0cyhub2RlLCBvZmZzZXRzKSB7XG4gIHZhciByYW5nZSA9IGRvY3VtZW50LnNlbGVjdGlvbi5jcmVhdGVSYW5nZSgpLmR1cGxpY2F0ZSgpO1xuICB2YXIgc3RhcnQsIGVuZDtcblxuICBpZiAodHlwZW9mIG9mZnNldHMuZW5kID09PSAndW5kZWZpbmVkJykge1xuICAgIHN0YXJ0ID0gb2Zmc2V0cy5zdGFydDtcbiAgICBlbmQgPSBzdGFydDtcbiAgfSBlbHNlIGlmIChvZmZzZXRzLnN0YXJ0ID4gb2Zmc2V0cy5lbmQpIHtcbiAgICBzdGFydCA9IG9mZnNldHMuZW5kO1xuICAgIGVuZCA9IG9mZnNldHMuc3RhcnQ7XG4gIH0gZWxzZSB7XG4gICAgc3RhcnQgPSBvZmZzZXRzLnN0YXJ0O1xuICAgIGVuZCA9IG9mZnNldHMuZW5kO1xuICB9XG5cbiAgcmFuZ2UubW92ZVRvRWxlbWVudFRleHQobm9kZSk7XG4gIHJhbmdlLm1vdmVTdGFydCgnY2hhcmFjdGVyJywgc3RhcnQpO1xuICByYW5nZS5zZXRFbmRQb2ludCgnRW5kVG9TdGFydCcsIHJhbmdlKTtcbiAgcmFuZ2UubW92ZUVuZCgnY2hhcmFjdGVyJywgZW5kIC0gc3RhcnQpO1xuICByYW5nZS5zZWxlY3QoKTtcbn1cblxuLyoqXG4gKiBJbiBtb2Rlcm4gbm9uLUlFIGJyb3dzZXJzLCB3ZSBjYW4gc3VwcG9ydCBib3RoIGZvcndhcmQgYW5kIGJhY2t3YXJkXG4gKiBzZWxlY3Rpb25zLlxuICpcbiAqIE5vdGU6IElFMTArIHN1cHBvcnRzIHRoZSBTZWxlY3Rpb24gb2JqZWN0LCBidXQgaXQgZG9lcyBub3Qgc3VwcG9ydFxuICogdGhlIGBleHRlbmRgIG1ldGhvZCwgd2hpY2ggbWVhbnMgdGhhdCBldmVuIGluIG1vZGVybiBJRSwgaXQncyBub3QgcG9zc2libGVcbiAqIHRvIHByb2dyYW1hdGljYWxseSBjcmVhdGUgYSBiYWNrd2FyZCBzZWxlY3Rpb24uIFRodXMsIGZvciBhbGwgSUVcbiAqIHZlcnNpb25zLCB3ZSB1c2UgdGhlIG9sZCBJRSBBUEkgdG8gY3JlYXRlIG91ciBzZWxlY3Rpb25zLlxuICpcbiAqIEBwYXJhbSB7RE9NRWxlbWVudHxET01UZXh0Tm9kZX0gbm9kZVxuICogQHBhcmFtIHtvYmplY3R9IG9mZnNldHNcbiAqL1xuZnVuY3Rpb24gc2V0TW9kZXJuT2Zmc2V0cyhub2RlLCBvZmZzZXRzKSB7XG4gIGlmICghd2luZG93LmdldFNlbGVjdGlvbikge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIHZhciBzZWxlY3Rpb24gPSB3aW5kb3cuZ2V0U2VsZWN0aW9uKCk7XG4gIHZhciBsZW5ndGggPSBub2RlW2dldFRleHRDb250ZW50QWNjZXNzb3IoKV0ubGVuZ3RoO1xuICB2YXIgc3RhcnQgPSBNYXRoLm1pbihvZmZzZXRzLnN0YXJ0LCBsZW5ndGgpO1xuICB2YXIgZW5kID0gdHlwZW9mIG9mZnNldHMuZW5kID09PSAndW5kZWZpbmVkJyA/XG4gICAgICAgICAgICBzdGFydCA6IE1hdGgubWluKG9mZnNldHMuZW5kLCBsZW5ndGgpO1xuXG4gIC8vIElFIDExIHVzZXMgbW9kZXJuIHNlbGVjdGlvbiwgYnV0IGRvZXNuJ3Qgc3VwcG9ydCB0aGUgZXh0ZW5kIG1ldGhvZC5cbiAgLy8gRmxpcCBiYWNrd2FyZCBzZWxlY3Rpb25zLCBzbyB3ZSBjYW4gc2V0IHdpdGggYSBzaW5nbGUgcmFuZ2UuXG4gIGlmICghc2VsZWN0aW9uLmV4dGVuZCAmJiBzdGFydCA+IGVuZCkge1xuICAgIHZhciB0ZW1wID0gZW5kO1xuICAgIGVuZCA9IHN0YXJ0O1xuICAgIHN0YXJ0ID0gdGVtcDtcbiAgfVxuXG4gIHZhciBzdGFydE1hcmtlciA9IGdldE5vZGVGb3JDaGFyYWN0ZXJPZmZzZXQobm9kZSwgc3RhcnQpO1xuICB2YXIgZW5kTWFya2VyID0gZ2V0Tm9kZUZvckNoYXJhY3Rlck9mZnNldChub2RlLCBlbmQpO1xuXG4gIGlmIChzdGFydE1hcmtlciAmJiBlbmRNYXJrZXIpIHtcbiAgICB2YXIgcmFuZ2UgPSBkb2N1bWVudC5jcmVhdGVSYW5nZSgpO1xuICAgIHJhbmdlLnNldFN0YXJ0KHN0YXJ0TWFya2VyLm5vZGUsIHN0YXJ0TWFya2VyLm9mZnNldCk7XG4gICAgc2VsZWN0aW9uLnJlbW92ZUFsbFJhbmdlcygpO1xuXG4gICAgaWYgKHN0YXJ0ID4gZW5kKSB7XG4gICAgICBzZWxlY3Rpb24uYWRkUmFuZ2UocmFuZ2UpO1xuICAgICAgc2VsZWN0aW9uLmV4dGVuZChlbmRNYXJrZXIubm9kZSwgZW5kTWFya2VyLm9mZnNldCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJhbmdlLnNldEVuZChlbmRNYXJrZXIubm9kZSwgZW5kTWFya2VyLm9mZnNldCk7XG4gICAgICBzZWxlY3Rpb24uYWRkUmFuZ2UocmFuZ2UpO1xuICAgIH1cbiAgfVxufVxuXG52YXIgdXNlSUVPZmZzZXRzID0gRXhlY3V0aW9uRW52aXJvbm1lbnQuY2FuVXNlRE9NICYmIGRvY3VtZW50LnNlbGVjdGlvbjtcblxudmFyIFJlYWN0RE9NU2VsZWN0aW9uID0ge1xuICAvKipcbiAgICogQHBhcmFtIHtET01FbGVtZW50fSBub2RlXG4gICAqL1xuICBnZXRPZmZzZXRzOiB1c2VJRU9mZnNldHMgPyBnZXRJRU9mZnNldHMgOiBnZXRNb2Rlcm5PZmZzZXRzLFxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge0RPTUVsZW1lbnR8RE9NVGV4dE5vZGV9IG5vZGVcbiAgICogQHBhcmFtIHtvYmplY3R9IG9mZnNldHNcbiAgICovXG4gIHNldE9mZnNldHM6IHVzZUlFT2Zmc2V0cyA/IHNldElFT2Zmc2V0cyA6IHNldE1vZGVybk9mZnNldHNcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RET01TZWxlY3Rpb247XG4iLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0RE9NVGV4dGFyZWFcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIEF1dG9Gb2N1c01peGluID0gcmVxdWlyZShcIi4vQXV0b0ZvY3VzTWl4aW5cIik7XG52YXIgRE9NUHJvcGVydHlPcGVyYXRpb25zID0gcmVxdWlyZShcIi4vRE9NUHJvcGVydHlPcGVyYXRpb25zXCIpO1xudmFyIExpbmtlZFZhbHVlVXRpbHMgPSByZXF1aXJlKFwiLi9MaW5rZWRWYWx1ZVV0aWxzXCIpO1xudmFyIFJlYWN0QnJvd3NlckNvbXBvbmVudE1peGluID0gcmVxdWlyZShcIi4vUmVhY3RCcm93c2VyQ29tcG9uZW50TWl4aW5cIik7XG52YXIgUmVhY3RDb21wb3NpdGVDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdENvbXBvc2l0ZUNvbXBvbmVudFwiKTtcbnZhciBSZWFjdEVsZW1lbnQgPSByZXF1aXJlKFwiLi9SZWFjdEVsZW1lbnRcIik7XG52YXIgUmVhY3RET00gPSByZXF1aXJlKFwiLi9SZWFjdERPTVwiKTtcbnZhciBSZWFjdFVwZGF0ZXMgPSByZXF1aXJlKFwiLi9SZWFjdFVwZGF0ZXNcIik7XG5cbnZhciBhc3NpZ24gPSByZXF1aXJlKFwiLi9PYmplY3QuYXNzaWduXCIpO1xudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcblxudmFyIHdhcm5pbmcgPSByZXF1aXJlKFwiLi93YXJuaW5nXCIpO1xuXG4vLyBTdG9yZSBhIHJlZmVyZW5jZSB0byB0aGUgPHRleHRhcmVhPiBgUmVhY3RET01Db21wb25lbnRgLiBUT0RPOiB1c2Ugc3RyaW5nXG52YXIgdGV4dGFyZWEgPSBSZWFjdEVsZW1lbnQuY3JlYXRlRmFjdG9yeShSZWFjdERPTS50ZXh0YXJlYS50eXBlKTtcblxuZnVuY3Rpb24gZm9yY2VVcGRhdGVJZk1vdW50ZWQoKSB7XG4gIC8qanNoaW50IHZhbGlkdGhpczp0cnVlICovXG4gIGlmICh0aGlzLmlzTW91bnRlZCgpKSB7XG4gICAgdGhpcy5mb3JjZVVwZGF0ZSgpO1xuICB9XG59XG5cbi8qKlxuICogSW1wbGVtZW50cyBhIDx0ZXh0YXJlYT4gbmF0aXZlIGNvbXBvbmVudCB0aGF0IGFsbG93cyBzZXR0aW5nIGB2YWx1ZWAsIGFuZFxuICogYGRlZmF1bHRWYWx1ZWAuIFRoaXMgZGlmZmVycyBmcm9tIHRoZSB0cmFkaXRpb25hbCBET00gQVBJIGJlY2F1c2UgdmFsdWUgaXNcbiAqIHVzdWFsbHkgc2V0IGFzIFBDREFUQSBjaGlsZHJlbi5cbiAqXG4gKiBJZiBgdmFsdWVgIGlzIG5vdCBzdXBwbGllZCAob3IgbnVsbC91bmRlZmluZWQpLCB1c2VyIGFjdGlvbnMgdGhhdCBhZmZlY3QgdGhlXG4gKiB2YWx1ZSB3aWxsIHRyaWdnZXIgdXBkYXRlcyB0byB0aGUgZWxlbWVudC5cbiAqXG4gKiBJZiBgdmFsdWVgIGlzIHN1cHBsaWVkIChhbmQgbm90IG51bGwvdW5kZWZpbmVkKSwgdGhlIHJlbmRlcmVkIGVsZW1lbnQgd2lsbFxuICogbm90IHRyaWdnZXIgdXBkYXRlcyB0byB0aGUgZWxlbWVudC4gSW5zdGVhZCwgdGhlIGB2YWx1ZWAgcHJvcCBtdXN0IGNoYW5nZSBpblxuICogb3JkZXIgZm9yIHRoZSByZW5kZXJlZCBlbGVtZW50IHRvIGJlIHVwZGF0ZWQuXG4gKlxuICogVGhlIHJlbmRlcmVkIGVsZW1lbnQgd2lsbCBiZSBpbml0aWFsaXplZCB3aXRoIGFuIGVtcHR5IHZhbHVlLCB0aGUgcHJvcFxuICogYGRlZmF1bHRWYWx1ZWAgaWYgc3BlY2lmaWVkLCBvciB0aGUgY2hpbGRyZW4gY29udGVudCAoZGVwcmVjYXRlZCkuXG4gKi9cbnZhciBSZWFjdERPTVRleHRhcmVhID0gUmVhY3RDb21wb3NpdGVDb21wb25lbnQuY3JlYXRlQ2xhc3Moe1xuICBkaXNwbGF5TmFtZTogJ1JlYWN0RE9NVGV4dGFyZWEnLFxuXG4gIG1peGluczogW0F1dG9Gb2N1c01peGluLCBMaW5rZWRWYWx1ZVV0aWxzLk1peGluLCBSZWFjdEJyb3dzZXJDb21wb25lbnRNaXhpbl0sXG5cbiAgZ2V0SW5pdGlhbFN0YXRlOiBmdW5jdGlvbigpIHtcbiAgICB2YXIgZGVmYXVsdFZhbHVlID0gdGhpcy5wcm9wcy5kZWZhdWx0VmFsdWU7XG4gICAgLy8gVE9ETyAoeXVuZ3N0ZXJzKTogUmVtb3ZlIHN1cHBvcnQgZm9yIGNoaWxkcmVuIGNvbnRlbnQgaW4gPHRleHRhcmVhPi5cbiAgICB2YXIgY2hpbGRyZW4gPSB0aGlzLnByb3BzLmNoaWxkcmVuO1xuICAgIGlmIChjaGlsZHJlbiAhPSBudWxsKSB7XG4gICAgICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyB3YXJuaW5nKFxuICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgICdVc2UgdGhlIGBkZWZhdWx0VmFsdWVgIG9yIGB2YWx1ZWAgcHJvcHMgaW5zdGVhZCBvZiBzZXR0aW5nICcgK1xuICAgICAgICAgICdjaGlsZHJlbiBvbiA8dGV4dGFyZWE+LidcbiAgICAgICAgKSA6IG51bGwpO1xuICAgICAgfVxuICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgZGVmYXVsdFZhbHVlID09IG51bGwsXG4gICAgICAgICdJZiB5b3Ugc3VwcGx5IGBkZWZhdWx0VmFsdWVgIG9uIGEgPHRleHRhcmVhPiwgZG8gbm90IHBhc3MgY2hpbGRyZW4uJ1xuICAgICAgKSA6IGludmFyaWFudChkZWZhdWx0VmFsdWUgPT0gbnVsbCkpO1xuICAgICAgaWYgKEFycmF5LmlzQXJyYXkoY2hpbGRyZW4pKSB7XG4gICAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgICAgY2hpbGRyZW4ubGVuZ3RoIDw9IDEsXG4gICAgICAgICAgJzx0ZXh0YXJlYT4gY2FuIG9ubHkgaGF2ZSBhdCBtb3N0IG9uZSBjaGlsZC4nXG4gICAgICAgICkgOiBpbnZhcmlhbnQoY2hpbGRyZW4ubGVuZ3RoIDw9IDEpKTtcbiAgICAgICAgY2hpbGRyZW4gPSBjaGlsZHJlblswXTtcbiAgICAgIH1cblxuICAgICAgZGVmYXVsdFZhbHVlID0gJycgKyBjaGlsZHJlbjtcbiAgICB9XG4gICAgaWYgKGRlZmF1bHRWYWx1ZSA9PSBudWxsKSB7XG4gICAgICBkZWZhdWx0VmFsdWUgPSAnJztcbiAgICB9XG4gICAgdmFyIHZhbHVlID0gTGlua2VkVmFsdWVVdGlscy5nZXRWYWx1ZSh0aGlzKTtcbiAgICByZXR1cm4ge1xuICAgICAgLy8gV2Ugc2F2ZSB0aGUgaW5pdGlhbCB2YWx1ZSBzbyB0aGF0IGBSZWFjdERPTUNvbXBvbmVudGAgZG9lc24ndCB1cGRhdGVcbiAgICAgIC8vIGB0ZXh0Q29udGVudGAgKHVubmVjZXNzYXJ5IHNpbmNlIHdlIHVwZGF0ZSB2YWx1ZSkuXG4gICAgICAvLyBUaGUgaW5pdGlhbCB2YWx1ZSBjYW4gYmUgYSBib29sZWFuIG9yIG9iamVjdCBzbyB0aGF0J3Mgd2h5IGl0J3NcbiAgICAgIC8vIGZvcmNlZCB0byBiZSBhIHN0cmluZy5cbiAgICAgIGluaXRpYWxWYWx1ZTogJycgKyAodmFsdWUgIT0gbnVsbCA/IHZhbHVlIDogZGVmYXVsdFZhbHVlKVxuICAgIH07XG4gIH0sXG5cbiAgcmVuZGVyOiBmdW5jdGlvbigpIHtcbiAgICAvLyBDbG9uZSBgdGhpcy5wcm9wc2Agc28gd2UgZG9uJ3QgbXV0YXRlIHRoZSBpbnB1dC5cbiAgICB2YXIgcHJvcHMgPSBhc3NpZ24oe30sIHRoaXMucHJvcHMpO1xuXG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgIHByb3BzLmRhbmdlcm91c2x5U2V0SW5uZXJIVE1MID09IG51bGwsXG4gICAgICAnYGRhbmdlcm91c2x5U2V0SW5uZXJIVE1MYCBkb2VzIG5vdCBtYWtlIHNlbnNlIG9uIDx0ZXh0YXJlYT4uJ1xuICAgICkgOiBpbnZhcmlhbnQocHJvcHMuZGFuZ2Vyb3VzbHlTZXRJbm5lckhUTUwgPT0gbnVsbCkpO1xuXG4gICAgcHJvcHMuZGVmYXVsdFZhbHVlID0gbnVsbDtcbiAgICBwcm9wcy52YWx1ZSA9IG51bGw7XG4gICAgcHJvcHMub25DaGFuZ2UgPSB0aGlzLl9oYW5kbGVDaGFuZ2U7XG5cbiAgICAvLyBBbHdheXMgc2V0IGNoaWxkcmVuIHRvIHRoZSBzYW1lIHRoaW5nLiBJbiBJRTksIHRoZSBzZWxlY3Rpb24gcmFuZ2Ugd2lsbFxuICAgIC8vIGdldCByZXNldCBpZiBgdGV4dENvbnRlbnRgIGlzIG11dGF0ZWQuXG4gICAgcmV0dXJuIHRleHRhcmVhKHByb3BzLCB0aGlzLnN0YXRlLmluaXRpYWxWYWx1ZSk7XG4gIH0sXG5cbiAgY29tcG9uZW50RGlkVXBkYXRlOiBmdW5jdGlvbihwcmV2UHJvcHMsIHByZXZTdGF0ZSwgcHJldkNvbnRleHQpIHtcbiAgICB2YXIgdmFsdWUgPSBMaW5rZWRWYWx1ZVV0aWxzLmdldFZhbHVlKHRoaXMpO1xuICAgIGlmICh2YWx1ZSAhPSBudWxsKSB7XG4gICAgICB2YXIgcm9vdE5vZGUgPSB0aGlzLmdldERPTU5vZGUoKTtcbiAgICAgIC8vIENhc3QgYHZhbHVlYCB0byBhIHN0cmluZyB0byBlbnN1cmUgdGhlIHZhbHVlIGlzIHNldCBjb3JyZWN0bHkuIFdoaWxlXG4gICAgICAvLyBicm93c2VycyB0eXBpY2FsbHkgZG8gdGhpcyBhcyBuZWNlc3NhcnksIGpzZG9tIGRvZXNuJ3QuXG4gICAgICBET01Qcm9wZXJ0eU9wZXJhdGlvbnMuc2V0VmFsdWVGb3JQcm9wZXJ0eShyb290Tm9kZSwgJ3ZhbHVlJywgJycgKyB2YWx1ZSk7XG4gICAgfVxuICB9LFxuXG4gIF9oYW5kbGVDaGFuZ2U6IGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgdmFyIHJldHVyblZhbHVlO1xuICAgIHZhciBvbkNoYW5nZSA9IExpbmtlZFZhbHVlVXRpbHMuZ2V0T25DaGFuZ2UodGhpcyk7XG4gICAgaWYgKG9uQ2hhbmdlKSB7XG4gICAgICByZXR1cm5WYWx1ZSA9IG9uQ2hhbmdlLmNhbGwodGhpcywgZXZlbnQpO1xuICAgIH1cbiAgICBSZWFjdFVwZGF0ZXMuYXNhcChmb3JjZVVwZGF0ZUlmTW91bnRlZCwgdGhpcyk7XG4gICAgcmV0dXJuIHJldHVyblZhbHVlO1xuICB9XG5cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0RE9NVGV4dGFyZWE7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdERlZmF1bHRCYXRjaGluZ1N0cmF0ZWd5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBSZWFjdFVwZGF0ZXMgPSByZXF1aXJlKFwiLi9SZWFjdFVwZGF0ZXNcIik7XG52YXIgVHJhbnNhY3Rpb24gPSByZXF1aXJlKFwiLi9UcmFuc2FjdGlvblwiKTtcblxudmFyIGFzc2lnbiA9IHJlcXVpcmUoXCIuL09iamVjdC5hc3NpZ25cIik7XG52YXIgZW1wdHlGdW5jdGlvbiA9IHJlcXVpcmUoXCIuL2VtcHR5RnVuY3Rpb25cIik7XG5cbnZhciBSRVNFVF9CQVRDSEVEX1VQREFURVMgPSB7XG4gIGluaXRpYWxpemU6IGVtcHR5RnVuY3Rpb24sXG4gIGNsb3NlOiBmdW5jdGlvbigpIHtcbiAgICBSZWFjdERlZmF1bHRCYXRjaGluZ1N0cmF0ZWd5LmlzQmF0Y2hpbmdVcGRhdGVzID0gZmFsc2U7XG4gIH1cbn07XG5cbnZhciBGTFVTSF9CQVRDSEVEX1VQREFURVMgPSB7XG4gIGluaXRpYWxpemU6IGVtcHR5RnVuY3Rpb24sXG4gIGNsb3NlOiBSZWFjdFVwZGF0ZXMuZmx1c2hCYXRjaGVkVXBkYXRlcy5iaW5kKFJlYWN0VXBkYXRlcylcbn07XG5cbnZhciBUUkFOU0FDVElPTl9XUkFQUEVSUyA9IFtGTFVTSF9CQVRDSEVEX1VQREFURVMsIFJFU0VUX0JBVENIRURfVVBEQVRFU107XG5cbmZ1bmN0aW9uIFJlYWN0RGVmYXVsdEJhdGNoaW5nU3RyYXRlZ3lUcmFuc2FjdGlvbigpIHtcbiAgdGhpcy5yZWluaXRpYWxpemVUcmFuc2FjdGlvbigpO1xufVxuXG5hc3NpZ24oXG4gIFJlYWN0RGVmYXVsdEJhdGNoaW5nU3RyYXRlZ3lUcmFuc2FjdGlvbi5wcm90b3R5cGUsXG4gIFRyYW5zYWN0aW9uLk1peGluLFxuICB7XG4gICAgZ2V0VHJhbnNhY3Rpb25XcmFwcGVyczogZnVuY3Rpb24oKSB7XG4gICAgICByZXR1cm4gVFJBTlNBQ1RJT05fV1JBUFBFUlM7XG4gICAgfVxuICB9XG4pO1xuXG52YXIgdHJhbnNhY3Rpb24gPSBuZXcgUmVhY3REZWZhdWx0QmF0Y2hpbmdTdHJhdGVneVRyYW5zYWN0aW9uKCk7XG5cbnZhciBSZWFjdERlZmF1bHRCYXRjaGluZ1N0cmF0ZWd5ID0ge1xuICBpc0JhdGNoaW5nVXBkYXRlczogZmFsc2UsXG5cbiAgLyoqXG4gICAqIENhbGwgdGhlIHByb3ZpZGVkIGZ1bmN0aW9uIGluIGEgY29udGV4dCB3aXRoaW4gd2hpY2ggY2FsbHMgdG8gYHNldFN0YXRlYFxuICAgKiBhbmQgZnJpZW5kcyBhcmUgYmF0Y2hlZCBzdWNoIHRoYXQgY29tcG9uZW50cyBhcmVuJ3QgdXBkYXRlZCB1bm5lY2Vzc2FyaWx5LlxuICAgKi9cbiAgYmF0Y2hlZFVwZGF0ZXM6IGZ1bmN0aW9uKGNhbGxiYWNrLCBhLCBiKSB7XG4gICAgdmFyIGFscmVhZHlCYXRjaGluZ1VwZGF0ZXMgPSBSZWFjdERlZmF1bHRCYXRjaGluZ1N0cmF0ZWd5LmlzQmF0Y2hpbmdVcGRhdGVzO1xuXG4gICAgUmVhY3REZWZhdWx0QmF0Y2hpbmdTdHJhdGVneS5pc0JhdGNoaW5nVXBkYXRlcyA9IHRydWU7XG5cbiAgICAvLyBUaGUgY29kZSBpcyB3cml0dGVuIHRoaXMgd2F5IHRvIGF2b2lkIGV4dHJhIGFsbG9jYXRpb25zXG4gICAgaWYgKGFscmVhZHlCYXRjaGluZ1VwZGF0ZXMpIHtcbiAgICAgIGNhbGxiYWNrKGEsIGIpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0cmFuc2FjdGlvbi5wZXJmb3JtKGNhbGxiYWNrLCBudWxsLCBhLCBiKTtcbiAgICB9XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3REZWZhdWx0QmF0Y2hpbmdTdHJhdGVneTtcbiIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3REZWZhdWx0SW5qZWN0aW9uXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBCZWZvcmVJbnB1dEV2ZW50UGx1Z2luID0gcmVxdWlyZShcIi4vQmVmb3JlSW5wdXRFdmVudFBsdWdpblwiKTtcbnZhciBDaGFuZ2VFdmVudFBsdWdpbiA9IHJlcXVpcmUoXCIuL0NoYW5nZUV2ZW50UGx1Z2luXCIpO1xudmFyIENsaWVudFJlYWN0Um9vdEluZGV4ID0gcmVxdWlyZShcIi4vQ2xpZW50UmVhY3RSb290SW5kZXhcIik7XG52YXIgQ29tcG9zaXRpb25FdmVudFBsdWdpbiA9IHJlcXVpcmUoXCIuL0NvbXBvc2l0aW9uRXZlbnRQbHVnaW5cIik7XG52YXIgRGVmYXVsdEV2ZW50UGx1Z2luT3JkZXIgPSByZXF1aXJlKFwiLi9EZWZhdWx0RXZlbnRQbHVnaW5PcmRlclwiKTtcbnZhciBFbnRlckxlYXZlRXZlbnRQbHVnaW4gPSByZXF1aXJlKFwiLi9FbnRlckxlYXZlRXZlbnRQbHVnaW5cIik7XG52YXIgRXhlY3V0aW9uRW52aXJvbm1lbnQgPSByZXF1aXJlKFwiLi9FeGVjdXRpb25FbnZpcm9ubWVudFwiKTtcbnZhciBIVE1MRE9NUHJvcGVydHlDb25maWcgPSByZXF1aXJlKFwiLi9IVE1MRE9NUHJvcGVydHlDb25maWdcIik7XG52YXIgTW9iaWxlU2FmYXJpQ2xpY2tFdmVudFBsdWdpbiA9IHJlcXVpcmUoXCIuL01vYmlsZVNhZmFyaUNsaWNrRXZlbnRQbHVnaW5cIik7XG52YXIgUmVhY3RCcm93c2VyQ29tcG9uZW50TWl4aW4gPSByZXF1aXJlKFwiLi9SZWFjdEJyb3dzZXJDb21wb25lbnRNaXhpblwiKTtcbnZhciBSZWFjdENvbXBvbmVudEJyb3dzZXJFbnZpcm9ubWVudCA9XG4gIHJlcXVpcmUoXCIuL1JlYWN0Q29tcG9uZW50QnJvd3NlckVudmlyb25tZW50XCIpO1xudmFyIFJlYWN0RGVmYXVsdEJhdGNoaW5nU3RyYXRlZ3kgPSByZXF1aXJlKFwiLi9SZWFjdERlZmF1bHRCYXRjaGluZ1N0cmF0ZWd5XCIpO1xudmFyIFJlYWN0RE9NQ29tcG9uZW50ID0gcmVxdWlyZShcIi4vUmVhY3RET01Db21wb25lbnRcIik7XG52YXIgUmVhY3RET01CdXR0b24gPSByZXF1aXJlKFwiLi9SZWFjdERPTUJ1dHRvblwiKTtcbnZhciBSZWFjdERPTUZvcm0gPSByZXF1aXJlKFwiLi9SZWFjdERPTUZvcm1cIik7XG52YXIgUmVhY3RET01JbWcgPSByZXF1aXJlKFwiLi9SZWFjdERPTUltZ1wiKTtcbnZhciBSZWFjdERPTUlucHV0ID0gcmVxdWlyZShcIi4vUmVhY3RET01JbnB1dFwiKTtcbnZhciBSZWFjdERPTU9wdGlvbiA9IHJlcXVpcmUoXCIuL1JlYWN0RE9NT3B0aW9uXCIpO1xudmFyIFJlYWN0RE9NU2VsZWN0ID0gcmVxdWlyZShcIi4vUmVhY3RET01TZWxlY3RcIik7XG52YXIgUmVhY3RET01UZXh0YXJlYSA9IHJlcXVpcmUoXCIuL1JlYWN0RE9NVGV4dGFyZWFcIik7XG52YXIgUmVhY3RFdmVudExpc3RlbmVyID0gcmVxdWlyZShcIi4vUmVhY3RFdmVudExpc3RlbmVyXCIpO1xudmFyIFJlYWN0SW5qZWN0aW9uID0gcmVxdWlyZShcIi4vUmVhY3RJbmplY3Rpb25cIik7XG52YXIgUmVhY3RJbnN0YW5jZUhhbmRsZXMgPSByZXF1aXJlKFwiLi9SZWFjdEluc3RhbmNlSGFuZGxlc1wiKTtcbnZhciBSZWFjdE1vdW50ID0gcmVxdWlyZShcIi4vUmVhY3RNb3VudFwiKTtcbnZhciBTZWxlY3RFdmVudFBsdWdpbiA9IHJlcXVpcmUoXCIuL1NlbGVjdEV2ZW50UGx1Z2luXCIpO1xudmFyIFNlcnZlclJlYWN0Um9vdEluZGV4ID0gcmVxdWlyZShcIi4vU2VydmVyUmVhY3RSb290SW5kZXhcIik7XG52YXIgU2ltcGxlRXZlbnRQbHVnaW4gPSByZXF1aXJlKFwiLi9TaW1wbGVFdmVudFBsdWdpblwiKTtcbnZhciBTVkdET01Qcm9wZXJ0eUNvbmZpZyA9IHJlcXVpcmUoXCIuL1NWR0RPTVByb3BlcnR5Q29uZmlnXCIpO1xuXG52YXIgY3JlYXRlRnVsbFBhZ2VDb21wb25lbnQgPSByZXF1aXJlKFwiLi9jcmVhdGVGdWxsUGFnZUNvbXBvbmVudFwiKTtcblxuZnVuY3Rpb24gaW5qZWN0KCkge1xuICBSZWFjdEluamVjdGlvbi5FdmVudEVtaXR0ZXIuaW5qZWN0UmVhY3RFdmVudExpc3RlbmVyKFxuICAgIFJlYWN0RXZlbnRMaXN0ZW5lclxuICApO1xuXG4gIC8qKlxuICAgKiBJbmplY3QgbW9kdWxlcyBmb3IgcmVzb2x2aW5nIERPTSBoaWVyYXJjaHkgYW5kIHBsdWdpbiBvcmRlcmluZy5cbiAgICovXG4gIFJlYWN0SW5qZWN0aW9uLkV2ZW50UGx1Z2luSHViLmluamVjdEV2ZW50UGx1Z2luT3JkZXIoRGVmYXVsdEV2ZW50UGx1Z2luT3JkZXIpO1xuICBSZWFjdEluamVjdGlvbi5FdmVudFBsdWdpbkh1Yi5pbmplY3RJbnN0YW5jZUhhbmRsZShSZWFjdEluc3RhbmNlSGFuZGxlcyk7XG4gIFJlYWN0SW5qZWN0aW9uLkV2ZW50UGx1Z2luSHViLmluamVjdE1vdW50KFJlYWN0TW91bnQpO1xuXG4gIC8qKlxuICAgKiBTb21lIGltcG9ydGFudCBldmVudCBwbHVnaW5zIGluY2x1ZGVkIGJ5IGRlZmF1bHQgKHdpdGhvdXQgaGF2aW5nIHRvIHJlcXVpcmVcbiAgICogdGhlbSkuXG4gICAqL1xuICBSZWFjdEluamVjdGlvbi5FdmVudFBsdWdpbkh1Yi5pbmplY3RFdmVudFBsdWdpbnNCeU5hbWUoe1xuICAgIFNpbXBsZUV2ZW50UGx1Z2luOiBTaW1wbGVFdmVudFBsdWdpbixcbiAgICBFbnRlckxlYXZlRXZlbnRQbHVnaW46IEVudGVyTGVhdmVFdmVudFBsdWdpbixcbiAgICBDaGFuZ2VFdmVudFBsdWdpbjogQ2hhbmdlRXZlbnRQbHVnaW4sXG4gICAgQ29tcG9zaXRpb25FdmVudFBsdWdpbjogQ29tcG9zaXRpb25FdmVudFBsdWdpbixcbiAgICBNb2JpbGVTYWZhcmlDbGlja0V2ZW50UGx1Z2luOiBNb2JpbGVTYWZhcmlDbGlja0V2ZW50UGx1Z2luLFxuICAgIFNlbGVjdEV2ZW50UGx1Z2luOiBTZWxlY3RFdmVudFBsdWdpbixcbiAgICBCZWZvcmVJbnB1dEV2ZW50UGx1Z2luOiBCZWZvcmVJbnB1dEV2ZW50UGx1Z2luXG4gIH0pO1xuXG4gIFJlYWN0SW5qZWN0aW9uLk5hdGl2ZUNvbXBvbmVudC5pbmplY3RHZW5lcmljQ29tcG9uZW50Q2xhc3MoXG4gICAgUmVhY3RET01Db21wb25lbnRcbiAgKTtcblxuICBSZWFjdEluamVjdGlvbi5OYXRpdmVDb21wb25lbnQuaW5qZWN0Q29tcG9uZW50Q2xhc3Nlcyh7XG4gICAgJ2J1dHRvbic6IFJlYWN0RE9NQnV0dG9uLFxuICAgICdmb3JtJzogUmVhY3RET01Gb3JtLFxuICAgICdpbWcnOiBSZWFjdERPTUltZyxcbiAgICAnaW5wdXQnOiBSZWFjdERPTUlucHV0LFxuICAgICdvcHRpb24nOiBSZWFjdERPTU9wdGlvbixcbiAgICAnc2VsZWN0JzogUmVhY3RET01TZWxlY3QsXG4gICAgJ3RleHRhcmVhJzogUmVhY3RET01UZXh0YXJlYSxcblxuICAgICdodG1sJzogY3JlYXRlRnVsbFBhZ2VDb21wb25lbnQoJ2h0bWwnKSxcbiAgICAnaGVhZCc6IGNyZWF0ZUZ1bGxQYWdlQ29tcG9uZW50KCdoZWFkJyksXG4gICAgJ2JvZHknOiBjcmVhdGVGdWxsUGFnZUNvbXBvbmVudCgnYm9keScpXG4gIH0pO1xuXG4gIC8vIFRoaXMgbmVlZHMgdG8gaGFwcGVuIGFmdGVyIGNyZWF0ZUZ1bGxQYWdlQ29tcG9uZW50KCkgb3RoZXJ3aXNlIHRoZSBtaXhpblxuICAvLyBnZXRzIGRvdWJsZSBpbmplY3RlZC5cbiAgUmVhY3RJbmplY3Rpb24uQ29tcG9zaXRlQ29tcG9uZW50LmluamVjdE1peGluKFJlYWN0QnJvd3NlckNvbXBvbmVudE1peGluKTtcblxuICBSZWFjdEluamVjdGlvbi5ET01Qcm9wZXJ0eS5pbmplY3RET01Qcm9wZXJ0eUNvbmZpZyhIVE1MRE9NUHJvcGVydHlDb25maWcpO1xuICBSZWFjdEluamVjdGlvbi5ET01Qcm9wZXJ0eS5pbmplY3RET01Qcm9wZXJ0eUNvbmZpZyhTVkdET01Qcm9wZXJ0eUNvbmZpZyk7XG5cbiAgUmVhY3RJbmplY3Rpb24uRW1wdHlDb21wb25lbnQuaW5qZWN0RW1wdHlDb21wb25lbnQoJ25vc2NyaXB0Jyk7XG5cbiAgUmVhY3RJbmplY3Rpb24uVXBkYXRlcy5pbmplY3RSZWNvbmNpbGVUcmFuc2FjdGlvbihcbiAgICBSZWFjdENvbXBvbmVudEJyb3dzZXJFbnZpcm9ubWVudC5SZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9uXG4gICk7XG4gIFJlYWN0SW5qZWN0aW9uLlVwZGF0ZXMuaW5qZWN0QmF0Y2hpbmdTdHJhdGVneShcbiAgICBSZWFjdERlZmF1bHRCYXRjaGluZ1N0cmF0ZWd5XG4gICk7XG5cbiAgUmVhY3RJbmplY3Rpb24uUm9vdEluZGV4LmluamVjdENyZWF0ZVJlYWN0Um9vdEluZGV4KFxuICAgIEV4ZWN1dGlvbkVudmlyb25tZW50LmNhblVzZURPTSA/XG4gICAgICBDbGllbnRSZWFjdFJvb3RJbmRleC5jcmVhdGVSZWFjdFJvb3RJbmRleCA6XG4gICAgICBTZXJ2ZXJSZWFjdFJvb3RJbmRleC5jcmVhdGVSZWFjdFJvb3RJbmRleFxuICApO1xuXG4gIFJlYWN0SW5qZWN0aW9uLkNvbXBvbmVudC5pbmplY3RFbnZpcm9ubWVudChSZWFjdENvbXBvbmVudEJyb3dzZXJFbnZpcm9ubWVudCk7XG5cbiAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgIHZhciB1cmwgPSAoRXhlY3V0aW9uRW52aXJvbm1lbnQuY2FuVXNlRE9NICYmIHdpbmRvdy5sb2NhdGlvbi5ocmVmKSB8fCAnJztcbiAgICBpZiAoKC9bPyZdcmVhY3RfcGVyZlxcYi8pLnRlc3QodXJsKSkge1xuICAgICAgdmFyIFJlYWN0RGVmYXVsdFBlcmYgPSByZXF1aXJlKFwiLi9SZWFjdERlZmF1bHRQZXJmXCIpO1xuICAgICAgUmVhY3REZWZhdWx0UGVyZi5zdGFydCgpO1xuICAgIH1cbiAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgaW5qZWN0OiBpbmplY3Rcbn07XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdERlZmF1bHRQZXJmXG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgRE9NUHJvcGVydHkgPSByZXF1aXJlKFwiLi9ET01Qcm9wZXJ0eVwiKTtcbnZhciBSZWFjdERlZmF1bHRQZXJmQW5hbHlzaXMgPSByZXF1aXJlKFwiLi9SZWFjdERlZmF1bHRQZXJmQW5hbHlzaXNcIik7XG52YXIgUmVhY3RNb3VudCA9IHJlcXVpcmUoXCIuL1JlYWN0TW91bnRcIik7XG52YXIgUmVhY3RQZXJmID0gcmVxdWlyZShcIi4vUmVhY3RQZXJmXCIpO1xuXG52YXIgcGVyZm9ybWFuY2VOb3cgPSByZXF1aXJlKFwiLi9wZXJmb3JtYW5jZU5vd1wiKTtcblxuZnVuY3Rpb24gcm91bmRGbG9hdCh2YWwpIHtcbiAgcmV0dXJuIE1hdGguZmxvb3IodmFsICogMTAwKSAvIDEwMDtcbn1cblxuZnVuY3Rpb24gYWRkVmFsdWUob2JqLCBrZXksIHZhbCkge1xuICBvYmpba2V5XSA9IChvYmpba2V5XSB8fCAwKSArIHZhbDtcbn1cblxudmFyIFJlYWN0RGVmYXVsdFBlcmYgPSB7XG4gIF9hbGxNZWFzdXJlbWVudHM6IFtdLCAvLyBsYXN0IGl0ZW0gaW4gdGhlIGxpc3QgaXMgdGhlIGN1cnJlbnQgb25lXG4gIF9tb3VudFN0YWNrOiBbMF0sXG4gIF9pbmplY3RlZDogZmFsc2UsXG5cbiAgc3RhcnQ6IGZ1bmN0aW9uKCkge1xuICAgIGlmICghUmVhY3REZWZhdWx0UGVyZi5faW5qZWN0ZWQpIHtcbiAgICAgIFJlYWN0UGVyZi5pbmplY3Rpb24uaW5qZWN0TWVhc3VyZShSZWFjdERlZmF1bHRQZXJmLm1lYXN1cmUpO1xuICAgIH1cblxuICAgIFJlYWN0RGVmYXVsdFBlcmYuX2FsbE1lYXN1cmVtZW50cy5sZW5ndGggPSAwO1xuICAgIFJlYWN0UGVyZi5lbmFibGVNZWFzdXJlID0gdHJ1ZTtcbiAgfSxcblxuICBzdG9wOiBmdW5jdGlvbigpIHtcbiAgICBSZWFjdFBlcmYuZW5hYmxlTWVhc3VyZSA9IGZhbHNlO1xuICB9LFxuXG4gIGdldExhc3RNZWFzdXJlbWVudHM6IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiBSZWFjdERlZmF1bHRQZXJmLl9hbGxNZWFzdXJlbWVudHM7XG4gIH0sXG5cbiAgcHJpbnRFeGNsdXNpdmU6IGZ1bmN0aW9uKG1lYXN1cmVtZW50cykge1xuICAgIG1lYXN1cmVtZW50cyA9IG1lYXN1cmVtZW50cyB8fCBSZWFjdERlZmF1bHRQZXJmLl9hbGxNZWFzdXJlbWVudHM7XG4gICAgdmFyIHN1bW1hcnkgPSBSZWFjdERlZmF1bHRQZXJmQW5hbHlzaXMuZ2V0RXhjbHVzaXZlU3VtbWFyeShtZWFzdXJlbWVudHMpO1xuICAgIGNvbnNvbGUudGFibGUoc3VtbWFyeS5tYXAoZnVuY3Rpb24oaXRlbSkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgJ0NvbXBvbmVudCBjbGFzcyBuYW1lJzogaXRlbS5jb21wb25lbnROYW1lLFxuICAgICAgICAnVG90YWwgaW5jbHVzaXZlIHRpbWUgKG1zKSc6IHJvdW5kRmxvYXQoaXRlbS5pbmNsdXNpdmUpLFxuICAgICAgICAnRXhjbHVzaXZlIG1vdW50IHRpbWUgKG1zKSc6IHJvdW5kRmxvYXQoaXRlbS5leGNsdXNpdmUpLFxuICAgICAgICAnRXhjbHVzaXZlIHJlbmRlciB0aW1lIChtcyknOiByb3VuZEZsb2F0KGl0ZW0ucmVuZGVyKSxcbiAgICAgICAgJ01vdW50IHRpbWUgcGVyIGluc3RhbmNlIChtcyknOiByb3VuZEZsb2F0KGl0ZW0uZXhjbHVzaXZlIC8gaXRlbS5jb3VudCksXG4gICAgICAgICdSZW5kZXIgdGltZSBwZXIgaW5zdGFuY2UgKG1zKSc6IHJvdW5kRmxvYXQoaXRlbS5yZW5kZXIgLyBpdGVtLmNvdW50KSxcbiAgICAgICAgJ0luc3RhbmNlcyc6IGl0ZW0uY291bnRcbiAgICAgIH07XG4gICAgfSkpO1xuICAgIC8vIFRPRE86IFJlYWN0RGVmYXVsdFBlcmZBbmFseXNpcy5nZXRUb3RhbFRpbWUoKSBkb2VzIG5vdCByZXR1cm4gdGhlIGNvcnJlY3RcbiAgICAvLyBudW1iZXIuXG4gIH0sXG5cbiAgcHJpbnRJbmNsdXNpdmU6IGZ1bmN0aW9uKG1lYXN1cmVtZW50cykge1xuICAgIG1lYXN1cmVtZW50cyA9IG1lYXN1cmVtZW50cyB8fCBSZWFjdERlZmF1bHRQZXJmLl9hbGxNZWFzdXJlbWVudHM7XG4gICAgdmFyIHN1bW1hcnkgPSBSZWFjdERlZmF1bHRQZXJmQW5hbHlzaXMuZ2V0SW5jbHVzaXZlU3VtbWFyeShtZWFzdXJlbWVudHMpO1xuICAgIGNvbnNvbGUudGFibGUoc3VtbWFyeS5tYXAoZnVuY3Rpb24oaXRlbSkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgJ093bmVyID4gY29tcG9uZW50JzogaXRlbS5jb21wb25lbnROYW1lLFxuICAgICAgICAnSW5jbHVzaXZlIHRpbWUgKG1zKSc6IHJvdW5kRmxvYXQoaXRlbS50aW1lKSxcbiAgICAgICAgJ0luc3RhbmNlcyc6IGl0ZW0uY291bnRcbiAgICAgIH07XG4gICAgfSkpO1xuICAgIGNvbnNvbGUubG9nKFxuICAgICAgJ1RvdGFsIHRpbWU6JyxcbiAgICAgIFJlYWN0RGVmYXVsdFBlcmZBbmFseXNpcy5nZXRUb3RhbFRpbWUobWVhc3VyZW1lbnRzKS50b0ZpeGVkKDIpICsgJyBtcydcbiAgICApO1xuICB9LFxuXG4gIGdldE1lYXN1cmVtZW50c1N1bW1hcnlNYXA6IGZ1bmN0aW9uKG1lYXN1cmVtZW50cykge1xuICAgIHZhciBzdW1tYXJ5ID0gUmVhY3REZWZhdWx0UGVyZkFuYWx5c2lzLmdldEluY2x1c2l2ZVN1bW1hcnkoXG4gICAgICBtZWFzdXJlbWVudHMsXG4gICAgICB0cnVlXG4gICAgKTtcbiAgICByZXR1cm4gc3VtbWFyeS5tYXAoZnVuY3Rpb24oaXRlbSkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgJ093bmVyID4gY29tcG9uZW50JzogaXRlbS5jb21wb25lbnROYW1lLFxuICAgICAgICAnV2FzdGVkIHRpbWUgKG1zKSc6IGl0ZW0udGltZSxcbiAgICAgICAgJ0luc3RhbmNlcyc6IGl0ZW0uY291bnRcbiAgICAgIH07XG4gICAgfSk7XG4gIH0sXG5cbiAgcHJpbnRXYXN0ZWQ6IGZ1bmN0aW9uKG1lYXN1cmVtZW50cykge1xuICAgIG1lYXN1cmVtZW50cyA9IG1lYXN1cmVtZW50cyB8fCBSZWFjdERlZmF1bHRQZXJmLl9hbGxNZWFzdXJlbWVudHM7XG4gICAgY29uc29sZS50YWJsZShSZWFjdERlZmF1bHRQZXJmLmdldE1lYXN1cmVtZW50c1N1bW1hcnlNYXAobWVhc3VyZW1lbnRzKSk7XG4gICAgY29uc29sZS5sb2coXG4gICAgICAnVG90YWwgdGltZTonLFxuICAgICAgUmVhY3REZWZhdWx0UGVyZkFuYWx5c2lzLmdldFRvdGFsVGltZShtZWFzdXJlbWVudHMpLnRvRml4ZWQoMikgKyAnIG1zJ1xuICAgICk7XG4gIH0sXG5cbiAgcHJpbnRET006IGZ1bmN0aW9uKG1lYXN1cmVtZW50cykge1xuICAgIG1lYXN1cmVtZW50cyA9IG1lYXN1cmVtZW50cyB8fCBSZWFjdERlZmF1bHRQZXJmLl9hbGxNZWFzdXJlbWVudHM7XG4gICAgdmFyIHN1bW1hcnkgPSBSZWFjdERlZmF1bHRQZXJmQW5hbHlzaXMuZ2V0RE9NU3VtbWFyeShtZWFzdXJlbWVudHMpO1xuICAgIGNvbnNvbGUudGFibGUoc3VtbWFyeS5tYXAoZnVuY3Rpb24oaXRlbSkge1xuICAgICAgdmFyIHJlc3VsdCA9IHt9O1xuICAgICAgcmVzdWx0W0RPTVByb3BlcnR5LklEX0FUVFJJQlVURV9OQU1FXSA9IGl0ZW0uaWQ7XG4gICAgICByZXN1bHRbJ3R5cGUnXSA9IGl0ZW0udHlwZTtcbiAgICAgIHJlc3VsdFsnYXJncyddID0gSlNPTi5zdHJpbmdpZnkoaXRlbS5hcmdzKTtcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfSkpO1xuICAgIGNvbnNvbGUubG9nKFxuICAgICAgJ1RvdGFsIHRpbWU6JyxcbiAgICAgIFJlYWN0RGVmYXVsdFBlcmZBbmFseXNpcy5nZXRUb3RhbFRpbWUobWVhc3VyZW1lbnRzKS50b0ZpeGVkKDIpICsgJyBtcydcbiAgICApO1xuICB9LFxuXG4gIF9yZWNvcmRXcml0ZTogZnVuY3Rpb24oaWQsIGZuTmFtZSwgdG90YWxUaW1lLCBhcmdzKSB7XG4gICAgLy8gVE9ETzogdG90YWxUaW1lIGlzbid0IHRoYXQgdXNlZnVsIHNpbmNlIGl0IGRvZXNuJ3QgY291bnQgcGFpbnRzL3JlZmxvd3NcbiAgICB2YXIgd3JpdGVzID1cbiAgICAgIFJlYWN0RGVmYXVsdFBlcmZcbiAgICAgICAgLl9hbGxNZWFzdXJlbWVudHNbUmVhY3REZWZhdWx0UGVyZi5fYWxsTWVhc3VyZW1lbnRzLmxlbmd0aCAtIDFdXG4gICAgICAgIC53cml0ZXM7XG4gICAgd3JpdGVzW2lkXSA9IHdyaXRlc1tpZF0gfHwgW107XG4gICAgd3JpdGVzW2lkXS5wdXNoKHtcbiAgICAgIHR5cGU6IGZuTmFtZSxcbiAgICAgIHRpbWU6IHRvdGFsVGltZSxcbiAgICAgIGFyZ3M6IGFyZ3NcbiAgICB9KTtcbiAgfSxcblxuICBtZWFzdXJlOiBmdW5jdGlvbihtb2R1bGVOYW1lLCBmbk5hbWUsIGZ1bmMpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24oKSB7Zm9yICh2YXIgYXJncz1bXSwkX18wPTAsJF9fMT1hcmd1bWVudHMubGVuZ3RoOyRfXzA8JF9fMTskX18wKyspIGFyZ3MucHVzaChhcmd1bWVudHNbJF9fMF0pO1xuICAgICAgdmFyIHRvdGFsVGltZTtcbiAgICAgIHZhciBydjtcbiAgICAgIHZhciBzdGFydDtcblxuICAgICAgaWYgKGZuTmFtZSA9PT0gJ19yZW5kZXJOZXdSb290Q29tcG9uZW50JyB8fFxuICAgICAgICAgIGZuTmFtZSA9PT0gJ2ZsdXNoQmF0Y2hlZFVwZGF0ZXMnKSB7XG4gICAgICAgIC8vIEEgXCJtZWFzdXJlbWVudFwiIGlzIGEgc2V0IG9mIG1ldHJpY3MgcmVjb3JkZWQgZm9yIGVhY2ggZmx1c2guIFdlIHdhbnRcbiAgICAgICAgLy8gdG8gZ3JvdXAgdGhlIG1ldHJpY3MgZm9yIGEgZ2l2ZW4gZmx1c2ggdG9nZXRoZXIgc28gd2UgY2FuIGxvb2sgYXQgdGhlXG4gICAgICAgIC8vIGNvbXBvbmVudHMgdGhhdCByZW5kZXJlZCBhbmQgdGhlIERPTSBvcGVyYXRpb25zIHRoYXQgYWN0dWFsbHlcbiAgICAgICAgLy8gaGFwcGVuZWQgdG8gZGV0ZXJtaW5lIHRoZSBhbW91bnQgb2YgXCJ3YXN0ZWQgd29ya1wiIHBlcmZvcm1lZC5cbiAgICAgICAgUmVhY3REZWZhdWx0UGVyZi5fYWxsTWVhc3VyZW1lbnRzLnB1c2goe1xuICAgICAgICAgIGV4Y2x1c2l2ZToge30sXG4gICAgICAgICAgaW5jbHVzaXZlOiB7fSxcbiAgICAgICAgICByZW5kZXI6IHt9LFxuICAgICAgICAgIGNvdW50czoge30sXG4gICAgICAgICAgd3JpdGVzOiB7fSxcbiAgICAgICAgICBkaXNwbGF5TmFtZXM6IHt9LFxuICAgICAgICAgIHRvdGFsVGltZTogMFxuICAgICAgICB9KTtcbiAgICAgICAgc3RhcnQgPSBwZXJmb3JtYW5jZU5vdygpO1xuICAgICAgICBydiA9IGZ1bmMuYXBwbHkodGhpcywgYXJncyk7XG4gICAgICAgIFJlYWN0RGVmYXVsdFBlcmYuX2FsbE1lYXN1cmVtZW50c1tcbiAgICAgICAgICBSZWFjdERlZmF1bHRQZXJmLl9hbGxNZWFzdXJlbWVudHMubGVuZ3RoIC0gMVxuICAgICAgICBdLnRvdGFsVGltZSA9IHBlcmZvcm1hbmNlTm93KCkgLSBzdGFydDtcbiAgICAgICAgcmV0dXJuIHJ2O1xuICAgICAgfSBlbHNlIGlmIChtb2R1bGVOYW1lID09PSAnUmVhY3RET01JRE9wZXJhdGlvbnMnIHx8XG4gICAgICAgIG1vZHVsZU5hbWUgPT09ICdSZWFjdENvbXBvbmVudEJyb3dzZXJFbnZpcm9ubWVudCcpIHtcbiAgICAgICAgc3RhcnQgPSBwZXJmb3JtYW5jZU5vdygpO1xuICAgICAgICBydiA9IGZ1bmMuYXBwbHkodGhpcywgYXJncyk7XG4gICAgICAgIHRvdGFsVGltZSA9IHBlcmZvcm1hbmNlTm93KCkgLSBzdGFydDtcblxuICAgICAgICBpZiAoZm5OYW1lID09PSAnbW91bnRJbWFnZUludG9Ob2RlJykge1xuICAgICAgICAgIHZhciBtb3VudElEID0gUmVhY3RNb3VudC5nZXRJRChhcmdzWzFdKTtcbiAgICAgICAgICBSZWFjdERlZmF1bHRQZXJmLl9yZWNvcmRXcml0ZShtb3VudElELCBmbk5hbWUsIHRvdGFsVGltZSwgYXJnc1swXSk7XG4gICAgICAgIH0gZWxzZSBpZiAoZm5OYW1lID09PSAnZGFuZ2Vyb3VzbHlQcm9jZXNzQ2hpbGRyZW5VcGRhdGVzJykge1xuICAgICAgICAgIC8vIHNwZWNpYWwgZm9ybWF0XG4gICAgICAgICAgYXJnc1swXS5mb3JFYWNoKGZ1bmN0aW9uKHVwZGF0ZSkge1xuICAgICAgICAgICAgdmFyIHdyaXRlQXJncyA9IHt9O1xuICAgICAgICAgICAgaWYgKHVwZGF0ZS5mcm9tSW5kZXggIT09IG51bGwpIHtcbiAgICAgICAgICAgICAgd3JpdGVBcmdzLmZyb21JbmRleCA9IHVwZGF0ZS5mcm9tSW5kZXg7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodXBkYXRlLnRvSW5kZXggIT09IG51bGwpIHtcbiAgICAgICAgICAgICAgd3JpdGVBcmdzLnRvSW5kZXggPSB1cGRhdGUudG9JbmRleDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh1cGRhdGUudGV4dENvbnRlbnQgIT09IG51bGwpIHtcbiAgICAgICAgICAgICAgd3JpdGVBcmdzLnRleHRDb250ZW50ID0gdXBkYXRlLnRleHRDb250ZW50O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHVwZGF0ZS5tYXJrdXBJbmRleCAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICB3cml0ZUFyZ3MubWFya3VwID0gYXJnc1sxXVt1cGRhdGUubWFya3VwSW5kZXhdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgUmVhY3REZWZhdWx0UGVyZi5fcmVjb3JkV3JpdGUoXG4gICAgICAgICAgICAgIHVwZGF0ZS5wYXJlbnRJRCxcbiAgICAgICAgICAgICAgdXBkYXRlLnR5cGUsXG4gICAgICAgICAgICAgIHRvdGFsVGltZSxcbiAgICAgICAgICAgICAgd3JpdGVBcmdzXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIGJhc2ljIGZvcm1hdFxuICAgICAgICAgIFJlYWN0RGVmYXVsdFBlcmYuX3JlY29yZFdyaXRlKFxuICAgICAgICAgICAgYXJnc1swXSxcbiAgICAgICAgICAgIGZuTmFtZSxcbiAgICAgICAgICAgIHRvdGFsVGltZSxcbiAgICAgICAgICAgIEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3MsIDEpXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcnY7XG4gICAgICB9IGVsc2UgaWYgKG1vZHVsZU5hbWUgPT09ICdSZWFjdENvbXBvc2l0ZUNvbXBvbmVudCcgJiYgKFxuICAgICAgICBmbk5hbWUgPT09ICdtb3VudENvbXBvbmVudCcgfHxcbiAgICAgICAgZm5OYW1lID09PSAndXBkYXRlQ29tcG9uZW50JyB8fCAvLyBUT0RPOiByZWNlaXZlQ29tcG9uZW50KCk/XG4gICAgICAgIGZuTmFtZSA9PT0gJ19yZW5kZXJWYWxpZGF0ZWRDb21wb25lbnQnKSkge1xuXG4gICAgICAgIHZhciByb290Tm9kZUlEID0gZm5OYW1lID09PSAnbW91bnRDb21wb25lbnQnID9cbiAgICAgICAgICBhcmdzWzBdIDpcbiAgICAgICAgICB0aGlzLl9yb290Tm9kZUlEO1xuICAgICAgICB2YXIgaXNSZW5kZXIgPSBmbk5hbWUgPT09ICdfcmVuZGVyVmFsaWRhdGVkQ29tcG9uZW50JztcbiAgICAgICAgdmFyIGlzTW91bnQgPSBmbk5hbWUgPT09ICdtb3VudENvbXBvbmVudCc7XG5cbiAgICAgICAgdmFyIG1vdW50U3RhY2sgPSBSZWFjdERlZmF1bHRQZXJmLl9tb3VudFN0YWNrO1xuICAgICAgICB2YXIgZW50cnkgPSBSZWFjdERlZmF1bHRQZXJmLl9hbGxNZWFzdXJlbWVudHNbXG4gICAgICAgICAgUmVhY3REZWZhdWx0UGVyZi5fYWxsTWVhc3VyZW1lbnRzLmxlbmd0aCAtIDFcbiAgICAgICAgXTtcblxuICAgICAgICBpZiAoaXNSZW5kZXIpIHtcbiAgICAgICAgICBhZGRWYWx1ZShlbnRyeS5jb3VudHMsIHJvb3ROb2RlSUQsIDEpO1xuICAgICAgICB9IGVsc2UgaWYgKGlzTW91bnQpIHtcbiAgICAgICAgICBtb3VudFN0YWNrLnB1c2goMCk7XG4gICAgICAgIH1cblxuICAgICAgICBzdGFydCA9IHBlcmZvcm1hbmNlTm93KCk7XG4gICAgICAgIHJ2ID0gZnVuYy5hcHBseSh0aGlzLCBhcmdzKTtcbiAgICAgICAgdG90YWxUaW1lID0gcGVyZm9ybWFuY2VOb3coKSAtIHN0YXJ0O1xuXG4gICAgICAgIGlmIChpc1JlbmRlcikge1xuICAgICAgICAgIGFkZFZhbHVlKGVudHJ5LnJlbmRlciwgcm9vdE5vZGVJRCwgdG90YWxUaW1lKTtcbiAgICAgICAgfSBlbHNlIGlmIChpc01vdW50KSB7XG4gICAgICAgICAgdmFyIHN1Yk1vdW50VGltZSA9IG1vdW50U3RhY2sucG9wKCk7XG4gICAgICAgICAgbW91bnRTdGFja1ttb3VudFN0YWNrLmxlbmd0aCAtIDFdICs9IHRvdGFsVGltZTtcbiAgICAgICAgICBhZGRWYWx1ZShlbnRyeS5leGNsdXNpdmUsIHJvb3ROb2RlSUQsIHRvdGFsVGltZSAtIHN1Yk1vdW50VGltZSk7XG4gICAgICAgICAgYWRkVmFsdWUoZW50cnkuaW5jbHVzaXZlLCByb290Tm9kZUlELCB0b3RhbFRpbWUpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGFkZFZhbHVlKGVudHJ5LmluY2x1c2l2ZSwgcm9vdE5vZGVJRCwgdG90YWxUaW1lKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGVudHJ5LmRpc3BsYXlOYW1lc1tyb290Tm9kZUlEXSA9IHtcbiAgICAgICAgICBjdXJyZW50OiB0aGlzLmNvbnN0cnVjdG9yLmRpc3BsYXlOYW1lLFxuICAgICAgICAgIG93bmVyOiB0aGlzLl9vd25lciA/IHRoaXMuX293bmVyLmNvbnN0cnVjdG9yLmRpc3BsYXlOYW1lIDogJzxyb290PidcbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4gcnY7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gZnVuYy5hcHBseSh0aGlzLCBhcmdzKTtcbiAgICAgIH1cbiAgICB9O1xuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0RGVmYXVsdFBlcmY7XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3REZWZhdWx0UGVyZkFuYWx5c2lzXG4gKi9cblxudmFyIGFzc2lnbiA9IHJlcXVpcmUoXCIuL09iamVjdC5hc3NpZ25cIik7XG5cbi8vIERvbid0IHRyeSB0byBzYXZlIHVzZXJzIGxlc3MgdGhhbiAxLjJtcyAoYSBudW1iZXIgSSBtYWRlIHVwKVxudmFyIERPTlRfQ0FSRV9USFJFU0hPTEQgPSAxLjI7XG52YXIgRE9NX09QRVJBVElPTl9UWVBFUyA9IHtcbiAgJ21vdW50SW1hZ2VJbnRvTm9kZSc6ICdzZXQgaW5uZXJIVE1MJyxcbiAgSU5TRVJUX01BUktVUDogJ3NldCBpbm5lckhUTUwnLFxuICBNT1ZFX0VYSVNUSU5HOiAnbW92ZScsXG4gIFJFTU9WRV9OT0RFOiAncmVtb3ZlJyxcbiAgVEVYVF9DT05URU5UOiAnc2V0IHRleHRDb250ZW50JyxcbiAgJ3VwZGF0ZVByb3BlcnR5QnlJRCc6ICd1cGRhdGUgYXR0cmlidXRlJyxcbiAgJ2RlbGV0ZVByb3BlcnR5QnlJRCc6ICdkZWxldGUgYXR0cmlidXRlJyxcbiAgJ3VwZGF0ZVN0eWxlc0J5SUQnOiAndXBkYXRlIHN0eWxlcycsXG4gICd1cGRhdGVJbm5lckhUTUxCeUlEJzogJ3NldCBpbm5lckhUTUwnLFxuICAnZGFuZ2Vyb3VzbHlSZXBsYWNlTm9kZVdpdGhNYXJrdXBCeUlEJzogJ3JlcGxhY2UnXG59O1xuXG5mdW5jdGlvbiBnZXRUb3RhbFRpbWUobWVhc3VyZW1lbnRzKSB7XG4gIC8vIFRPRE86IHJldHVybiBudW1iZXIgb2YgRE9NIG9wcz8gY291bGQgYmUgbWlzbGVhZGluZy5cbiAgLy8gVE9ETzogbWVhc3VyZSBkcm9wcGVkIGZyYW1lcyBhZnRlciByZWNvbmNpbGU/XG4gIC8vIFRPRE86IGxvZyB0b3RhbCB0aW1lIG9mIGVhY2ggcmVjb25jaWxlIGFuZCB0aGUgdG9wLWxldmVsIGNvbXBvbmVudFxuICAvLyBjbGFzcyB0aGF0IHRyaWdnZXJlZCBpdC5cbiAgdmFyIHRvdGFsVGltZSA9IDA7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbWVhc3VyZW1lbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIG1lYXN1cmVtZW50ID0gbWVhc3VyZW1lbnRzW2ldO1xuICAgIHRvdGFsVGltZSArPSBtZWFzdXJlbWVudC50b3RhbFRpbWU7XG4gIH1cbiAgcmV0dXJuIHRvdGFsVGltZTtcbn1cblxuZnVuY3Rpb24gZ2V0RE9NU3VtbWFyeShtZWFzdXJlbWVudHMpIHtcbiAgdmFyIGl0ZW1zID0gW107XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbWVhc3VyZW1lbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIG1lYXN1cmVtZW50ID0gbWVhc3VyZW1lbnRzW2ldO1xuICAgIHZhciBpZDtcblxuICAgIGZvciAoaWQgaW4gbWVhc3VyZW1lbnQud3JpdGVzKSB7XG4gICAgICBtZWFzdXJlbWVudC53cml0ZXNbaWRdLmZvckVhY2goZnVuY3Rpb24od3JpdGUpIHtcbiAgICAgICAgaXRlbXMucHVzaCh7XG4gICAgICAgICAgaWQ6IGlkLFxuICAgICAgICAgIHR5cGU6IERPTV9PUEVSQVRJT05fVFlQRVNbd3JpdGUudHlwZV0gfHwgd3JpdGUudHlwZSxcbiAgICAgICAgICBhcmdzOiB3cml0ZS5hcmdzXG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfVxuICB9XG4gIHJldHVybiBpdGVtcztcbn1cblxuZnVuY3Rpb24gZ2V0RXhjbHVzaXZlU3VtbWFyeShtZWFzdXJlbWVudHMpIHtcbiAgdmFyIGNhbmRpZGF0ZXMgPSB7fTtcbiAgdmFyIGRpc3BsYXlOYW1lO1xuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbWVhc3VyZW1lbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIG1lYXN1cmVtZW50ID0gbWVhc3VyZW1lbnRzW2ldO1xuICAgIHZhciBhbGxJRHMgPSBhc3NpZ24oXG4gICAgICB7fSxcbiAgICAgIG1lYXN1cmVtZW50LmV4Y2x1c2l2ZSxcbiAgICAgIG1lYXN1cmVtZW50LmluY2x1c2l2ZVxuICAgICk7XG5cbiAgICBmb3IgKHZhciBpZCBpbiBhbGxJRHMpIHtcbiAgICAgIGRpc3BsYXlOYW1lID0gbWVhc3VyZW1lbnQuZGlzcGxheU5hbWVzW2lkXS5jdXJyZW50O1xuXG4gICAgICBjYW5kaWRhdGVzW2Rpc3BsYXlOYW1lXSA9IGNhbmRpZGF0ZXNbZGlzcGxheU5hbWVdIHx8IHtcbiAgICAgICAgY29tcG9uZW50TmFtZTogZGlzcGxheU5hbWUsXG4gICAgICAgIGluY2x1c2l2ZTogMCxcbiAgICAgICAgZXhjbHVzaXZlOiAwLFxuICAgICAgICByZW5kZXI6IDAsXG4gICAgICAgIGNvdW50OiAwXG4gICAgICB9O1xuICAgICAgaWYgKG1lYXN1cmVtZW50LnJlbmRlcltpZF0pIHtcbiAgICAgICAgY2FuZGlkYXRlc1tkaXNwbGF5TmFtZV0ucmVuZGVyICs9IG1lYXN1cmVtZW50LnJlbmRlcltpZF07XG4gICAgICB9XG4gICAgICBpZiAobWVhc3VyZW1lbnQuZXhjbHVzaXZlW2lkXSkge1xuICAgICAgICBjYW5kaWRhdGVzW2Rpc3BsYXlOYW1lXS5leGNsdXNpdmUgKz0gbWVhc3VyZW1lbnQuZXhjbHVzaXZlW2lkXTtcbiAgICAgIH1cbiAgICAgIGlmIChtZWFzdXJlbWVudC5pbmNsdXNpdmVbaWRdKSB7XG4gICAgICAgIGNhbmRpZGF0ZXNbZGlzcGxheU5hbWVdLmluY2x1c2l2ZSArPSBtZWFzdXJlbWVudC5pbmNsdXNpdmVbaWRdO1xuICAgICAgfVxuICAgICAgaWYgKG1lYXN1cmVtZW50LmNvdW50c1tpZF0pIHtcbiAgICAgICAgY2FuZGlkYXRlc1tkaXNwbGF5TmFtZV0uY291bnQgKz0gbWVhc3VyZW1lbnQuY291bnRzW2lkXTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyBOb3cgbWFrZSBhIHNvcnRlZCBhcnJheSB3aXRoIHRoZSByZXN1bHRzLlxuICB2YXIgYXJyID0gW107XG4gIGZvciAoZGlzcGxheU5hbWUgaW4gY2FuZGlkYXRlcykge1xuICAgIGlmIChjYW5kaWRhdGVzW2Rpc3BsYXlOYW1lXS5leGNsdXNpdmUgPj0gRE9OVF9DQVJFX1RIUkVTSE9MRCkge1xuICAgICAgYXJyLnB1c2goY2FuZGlkYXRlc1tkaXNwbGF5TmFtZV0pO1xuICAgIH1cbiAgfVxuXG4gIGFyci5zb3J0KGZ1bmN0aW9uKGEsIGIpIHtcbiAgICByZXR1cm4gYi5leGNsdXNpdmUgLSBhLmV4Y2x1c2l2ZTtcbiAgfSk7XG5cbiAgcmV0dXJuIGFycjtcbn1cblxuZnVuY3Rpb24gZ2V0SW5jbHVzaXZlU3VtbWFyeShtZWFzdXJlbWVudHMsIG9ubHlDbGVhbikge1xuICB2YXIgY2FuZGlkYXRlcyA9IHt9O1xuICB2YXIgaW5jbHVzaXZlS2V5O1xuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbWVhc3VyZW1lbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIG1lYXN1cmVtZW50ID0gbWVhc3VyZW1lbnRzW2ldO1xuICAgIHZhciBhbGxJRHMgPSBhc3NpZ24oXG4gICAgICB7fSxcbiAgICAgIG1lYXN1cmVtZW50LmV4Y2x1c2l2ZSxcbiAgICAgIG1lYXN1cmVtZW50LmluY2x1c2l2ZVxuICAgICk7XG4gICAgdmFyIGNsZWFuQ29tcG9uZW50cztcblxuICAgIGlmIChvbmx5Q2xlYW4pIHtcbiAgICAgIGNsZWFuQ29tcG9uZW50cyA9IGdldFVuY2hhbmdlZENvbXBvbmVudHMobWVhc3VyZW1lbnQpO1xuICAgIH1cblxuICAgIGZvciAodmFyIGlkIGluIGFsbElEcykge1xuICAgICAgaWYgKG9ubHlDbGVhbiAmJiAhY2xlYW5Db21wb25lbnRzW2lkXSkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgdmFyIGRpc3BsYXlOYW1lID0gbWVhc3VyZW1lbnQuZGlzcGxheU5hbWVzW2lkXTtcblxuICAgICAgLy8gSW5jbHVzaXZlIHRpbWUgaXMgbm90IHVzZWZ1bCBmb3IgbWFueSBjb21wb25lbnRzIHdpdGhvdXQga25vd2luZyB3aGVyZVxuICAgICAgLy8gdGhleSBhcmUgaW5zdGFudGlhdGVkLiBTbyB3ZSBhZ2dyZWdhdGUgaW5jbHVzaXZlIHRpbWUgd2l0aCBib3RoIHRoZVxuICAgICAgLy8gb3duZXIgYW5kIGN1cnJlbnQgZGlzcGxheU5hbWUgYXMgdGhlIGtleS5cbiAgICAgIGluY2x1c2l2ZUtleSA9IGRpc3BsYXlOYW1lLm93bmVyICsgJyA+ICcgKyBkaXNwbGF5TmFtZS5jdXJyZW50O1xuXG4gICAgICBjYW5kaWRhdGVzW2luY2x1c2l2ZUtleV0gPSBjYW5kaWRhdGVzW2luY2x1c2l2ZUtleV0gfHwge1xuICAgICAgICBjb21wb25lbnROYW1lOiBpbmNsdXNpdmVLZXksXG4gICAgICAgIHRpbWU6IDAsXG4gICAgICAgIGNvdW50OiAwXG4gICAgICB9O1xuXG4gICAgICBpZiAobWVhc3VyZW1lbnQuaW5jbHVzaXZlW2lkXSkge1xuICAgICAgICBjYW5kaWRhdGVzW2luY2x1c2l2ZUtleV0udGltZSArPSBtZWFzdXJlbWVudC5pbmNsdXNpdmVbaWRdO1xuICAgICAgfVxuICAgICAgaWYgKG1lYXN1cmVtZW50LmNvdW50c1tpZF0pIHtcbiAgICAgICAgY2FuZGlkYXRlc1tpbmNsdXNpdmVLZXldLmNvdW50ICs9IG1lYXN1cmVtZW50LmNvdW50c1tpZF07XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gTm93IG1ha2UgYSBzb3J0ZWQgYXJyYXkgd2l0aCB0aGUgcmVzdWx0cy5cbiAgdmFyIGFyciA9IFtdO1xuICBmb3IgKGluY2x1c2l2ZUtleSBpbiBjYW5kaWRhdGVzKSB7XG4gICAgaWYgKGNhbmRpZGF0ZXNbaW5jbHVzaXZlS2V5XS50aW1lID49IERPTlRfQ0FSRV9USFJFU0hPTEQpIHtcbiAgICAgIGFyci5wdXNoKGNhbmRpZGF0ZXNbaW5jbHVzaXZlS2V5XSk7XG4gICAgfVxuICB9XG5cbiAgYXJyLnNvcnQoZnVuY3Rpb24oYSwgYikge1xuICAgIHJldHVybiBiLnRpbWUgLSBhLnRpbWU7XG4gIH0pO1xuXG4gIHJldHVybiBhcnI7XG59XG5cbmZ1bmN0aW9uIGdldFVuY2hhbmdlZENvbXBvbmVudHMobWVhc3VyZW1lbnQpIHtcbiAgLy8gRm9yIGEgZ2l2ZW4gcmVjb25jaWxlLCBsb29rIGF0IHdoaWNoIGNvbXBvbmVudHMgZGlkIG5vdCBhY3R1YWxseVxuICAvLyByZW5kZXIgYW55dGhpbmcgdG8gdGhlIERPTSBhbmQgcmV0dXJuIGEgbWFwcGluZyBvZiB0aGVpciBJRCB0b1xuICAvLyB0aGUgYW1vdW50IG9mIHRpbWUgaXQgdG9vayB0byByZW5kZXIgdGhlIGVudGlyZSBzdWJ0cmVlLlxuICB2YXIgY2xlYW5Db21wb25lbnRzID0ge307XG4gIHZhciBkaXJ0eUxlYWZJRHMgPSBPYmplY3Qua2V5cyhtZWFzdXJlbWVudC53cml0ZXMpO1xuICB2YXIgYWxsSURzID0gYXNzaWduKHt9LCBtZWFzdXJlbWVudC5leGNsdXNpdmUsIG1lYXN1cmVtZW50LmluY2x1c2l2ZSk7XG5cbiAgZm9yICh2YXIgaWQgaW4gYWxsSURzKSB7XG4gICAgdmFyIGlzRGlydHkgPSBmYWxzZTtcbiAgICAvLyBGb3IgZWFjaCBjb21wb25lbnQgdGhhdCByZW5kZXJlZCwgc2VlIGlmIGEgY29tcG9uZW50IHRoYXQgdHJpZ2dlcmVkXG4gICAgLy8gYSBET00gb3AgaXMgaW4gaXRzIHN1YnRyZWUuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBkaXJ0eUxlYWZJRHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmIChkaXJ0eUxlYWZJRHNbaV0uaW5kZXhPZihpZCkgPT09IDApIHtcbiAgICAgICAgaXNEaXJ0eSA9IHRydWU7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoIWlzRGlydHkgJiYgbWVhc3VyZW1lbnQuY291bnRzW2lkXSA+IDApIHtcbiAgICAgIGNsZWFuQ29tcG9uZW50c1tpZF0gPSB0cnVlO1xuICAgIH1cbiAgfVxuICByZXR1cm4gY2xlYW5Db21wb25lbnRzO1xufVxuXG52YXIgUmVhY3REZWZhdWx0UGVyZkFuYWx5c2lzID0ge1xuICBnZXRFeGNsdXNpdmVTdW1tYXJ5OiBnZXRFeGNsdXNpdmVTdW1tYXJ5LFxuICBnZXRJbmNsdXNpdmVTdW1tYXJ5OiBnZXRJbmNsdXNpdmVTdW1tYXJ5LFxuICBnZXRET01TdW1tYXJ5OiBnZXRET01TdW1tYXJ5LFxuICBnZXRUb3RhbFRpbWU6IGdldFRvdGFsVGltZVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdERlZmF1bHRQZXJmQW5hbHlzaXM7XG4iLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdEVsZW1lbnRcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFJlYWN0Q29udGV4dCA9IHJlcXVpcmUoXCIuL1JlYWN0Q29udGV4dFwiKTtcbnZhciBSZWFjdEN1cnJlbnRPd25lciA9IHJlcXVpcmUoXCIuL1JlYWN0Q3VycmVudE93bmVyXCIpO1xuXG52YXIgd2FybmluZyA9IHJlcXVpcmUoXCIuL3dhcm5pbmdcIik7XG5cbnZhciBSRVNFUlZFRF9QUk9QUyA9IHtcbiAga2V5OiB0cnVlLFxuICByZWY6IHRydWVcbn07XG5cbi8qKlxuICogV2FybiBmb3IgbXV0YXRpb25zLlxuICpcbiAqIEBpbnRlcm5hbFxuICogQHBhcmFtIHtvYmplY3R9IG9iamVjdFxuICogQHBhcmFtIHtzdHJpbmd9IGtleVxuICovXG5mdW5jdGlvbiBkZWZpbmVXYXJuaW5nUHJvcGVydHkob2JqZWN0LCBrZXkpIHtcbiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KG9iamVjdCwga2V5LCB7XG5cbiAgICBjb25maWd1cmFibGU6IGZhbHNlLFxuICAgIGVudW1lcmFibGU6IHRydWUsXG5cbiAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgaWYgKCF0aGlzLl9zdG9yZSkge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0aGlzLl9zdG9yZVtrZXldO1xuICAgIH0sXG5cbiAgICBzZXQ6IGZ1bmN0aW9uKHZhbHVlKSB7XG4gICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gd2FybmluZyhcbiAgICAgICAgZmFsc2UsXG4gICAgICAgICdEb25cXCd0IHNldCB0aGUgJyArIGtleSArICcgcHJvcGVydHkgb2YgdGhlIGNvbXBvbmVudC4gJyArXG4gICAgICAgICdNdXRhdGUgdGhlIGV4aXN0aW5nIHByb3BzIG9iamVjdCBpbnN0ZWFkLidcbiAgICAgICkgOiBudWxsKTtcbiAgICAgIHRoaXMuX3N0b3JlW2tleV0gPSB2YWx1ZTtcbiAgICB9XG5cbiAgfSk7XG59XG5cbi8qKlxuICogVGhpcyBpcyB1cGRhdGVkIHRvIHRydWUgaWYgdGhlIG1lbWJyYW5lIGlzIHN1Y2Nlc3NmdWxseSBjcmVhdGVkLlxuICovXG52YXIgdXNlTXV0YXRpb25NZW1icmFuZSA9IGZhbHNlO1xuXG4vKipcbiAqIFdhcm4gZm9yIG11dGF0aW9ucy5cbiAqXG4gKiBAaW50ZXJuYWxcbiAqIEBwYXJhbSB7b2JqZWN0fSBlbGVtZW50XG4gKi9cbmZ1bmN0aW9uIGRlZmluZU11dGF0aW9uTWVtYnJhbmUocHJvdG90eXBlKSB7XG4gIHRyeSB7XG4gICAgdmFyIHBzZXVkb0Zyb3plblByb3BlcnRpZXMgPSB7XG4gICAgICBwcm9wczogdHJ1ZVxuICAgIH07XG4gICAgZm9yICh2YXIga2V5IGluIHBzZXVkb0Zyb3plblByb3BlcnRpZXMpIHtcbiAgICAgIGRlZmluZVdhcm5pbmdQcm9wZXJ0eShwcm90b3R5cGUsIGtleSk7XG4gICAgfVxuICAgIHVzZU11dGF0aW9uTWVtYnJhbmUgPSB0cnVlO1xuICB9IGNhdGNoICh4KSB7XG4gICAgLy8gSUUgd2lsbCBmYWlsIG9uIGRlZmluZVByb3BlcnR5XG4gIH1cbn1cblxuLyoqXG4gKiBCYXNlIGNvbnN0cnVjdG9yIGZvciBhbGwgUmVhY3QgZWxlbWVudHMuIFRoaXMgaXMgb25seSB1c2VkIHRvIG1ha2UgdGhpc1xuICogd29yayB3aXRoIGEgZHluYW1pYyBpbnN0YW5jZW9mIGNoZWNrLiBOb3RoaW5nIHNob3VsZCBsaXZlIG9uIHRoaXMgcHJvdG90eXBlLlxuICpcbiAqIEBwYXJhbSB7Kn0gdHlwZVxuICogQHBhcmFtIHtzdHJpbmd8b2JqZWN0fSByZWZcbiAqIEBwYXJhbSB7Kn0ga2V5XG4gKiBAcGFyYW0geyp9IHByb3BzXG4gKiBAaW50ZXJuYWxcbiAqL1xudmFyIFJlYWN0RWxlbWVudCA9IGZ1bmN0aW9uKHR5cGUsIGtleSwgcmVmLCBvd25lciwgY29udGV4dCwgcHJvcHMpIHtcbiAgLy8gQnVpbHQtaW4gcHJvcGVydGllcyB0aGF0IGJlbG9uZyBvbiB0aGUgZWxlbWVudFxuICB0aGlzLnR5cGUgPSB0eXBlO1xuICB0aGlzLmtleSA9IGtleTtcbiAgdGhpcy5yZWYgPSByZWY7XG5cbiAgLy8gUmVjb3JkIHRoZSBjb21wb25lbnQgcmVzcG9uc2libGUgZm9yIGNyZWF0aW5nIHRoaXMgZWxlbWVudC5cbiAgdGhpcy5fb3duZXIgPSBvd25lcjtcblxuICAvLyBUT0RPOiBEZXByZWNhdGUgd2l0aENvbnRleHQsIGFuZCB0aGVuIHRoZSBjb250ZXh0IGJlY29tZXMgYWNjZXNzaWJsZVxuICAvLyB0aHJvdWdoIHRoZSBvd25lci5cbiAgdGhpcy5fY29udGV4dCA9IGNvbnRleHQ7XG5cbiAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgIC8vIFRoZSB2YWxpZGF0aW9uIGZsYWcgYW5kIHByb3BzIGFyZSBjdXJyZW50bHkgbXV0YXRpdmUuIFdlIHB1dCB0aGVtIG9uXG4gICAgLy8gYW4gZXh0ZXJuYWwgYmFja2luZyBzdG9yZSBzbyB0aGF0IHdlIGNhbiBmcmVlemUgdGhlIHdob2xlIG9iamVjdC5cbiAgICAvLyBUaGlzIGNhbiBiZSByZXBsYWNlZCB3aXRoIGEgV2Vha01hcCBvbmNlIHRoZXkgYXJlIGltcGxlbWVudGVkIGluXG4gICAgLy8gY29tbW9ubHkgdXNlZCBkZXZlbG9wbWVudCBlbnZpcm9ubWVudHMuXG4gICAgdGhpcy5fc3RvcmUgPSB7IHZhbGlkYXRlZDogZmFsc2UsIHByb3BzOiBwcm9wcyB9O1xuXG4gICAgLy8gV2UncmUgbm90IGFsbG93ZWQgdG8gc2V0IHByb3BzIGRpcmVjdGx5IG9uIHRoZSBvYmplY3Qgc28gd2UgZWFybHlcbiAgICAvLyByZXR1cm4gYW5kIHJlbHkgb24gdGhlIHByb3RvdHlwZSBtZW1icmFuZSB0byBmb3J3YXJkIHRvIHRoZSBiYWNraW5nXG4gICAgLy8gc3RvcmUuXG4gICAgaWYgKHVzZU11dGF0aW9uTWVtYnJhbmUpIHtcbiAgICAgIE9iamVjdC5mcmVlemUodGhpcyk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICB9XG5cbiAgdGhpcy5wcm9wcyA9IHByb3BzO1xufTtcblxuLy8gV2UgaW50ZW50aW9uYWxseSBkb24ndCBleHBvc2UgdGhlIGZ1bmN0aW9uIG9uIHRoZSBjb25zdHJ1Y3RvciBwcm9wZXJ0eS5cbi8vIFJlYWN0RWxlbWVudCBzaG91bGQgYmUgaW5kaXN0aW5ndWlzaGFibGUgZnJvbSBhIHBsYWluIG9iamVjdC5cblJlYWN0RWxlbWVudC5wcm90b3R5cGUgPSB7XG4gIF9pc1JlYWN0RWxlbWVudDogdHJ1ZVxufTtcblxuaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICBkZWZpbmVNdXRhdGlvbk1lbWJyYW5lKFJlYWN0RWxlbWVudC5wcm90b3R5cGUpO1xufVxuXG5SZWFjdEVsZW1lbnQuY3JlYXRlRWxlbWVudCA9IGZ1bmN0aW9uKHR5cGUsIGNvbmZpZywgY2hpbGRyZW4pIHtcbiAgdmFyIHByb3BOYW1lO1xuXG4gIC8vIFJlc2VydmVkIG5hbWVzIGFyZSBleHRyYWN0ZWRcbiAgdmFyIHByb3BzID0ge307XG5cbiAgdmFyIGtleSA9IG51bGw7XG4gIHZhciByZWYgPSBudWxsO1xuXG4gIGlmIChjb25maWcgIT0gbnVsbCkge1xuICAgIHJlZiA9IGNvbmZpZy5yZWYgPT09IHVuZGVmaW5lZCA/IG51bGwgOiBjb25maWcucmVmO1xuICAgIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyB3YXJuaW5nKFxuICAgICAgICBjb25maWcua2V5ICE9PSBudWxsLFxuICAgICAgICAnY3JlYXRlRWxlbWVudCguLi4pOiBFbmNvdW50ZXJlZCBjb21wb25lbnQgd2l0aCBhIGBrZXlgIG9mIG51bGwuIEluICcgK1xuICAgICAgICAnYSBmdXR1cmUgdmVyc2lvbiwgdGhpcyB3aWxsIGJlIHRyZWF0ZWQgYXMgZXF1aXZhbGVudCB0byB0aGUgc3RyaW5nICcgK1xuICAgICAgICAnXFwnbnVsbFxcJzsgaW5zdGVhZCwgcHJvdmlkZSBhbiBleHBsaWNpdCBrZXkgb3IgdXNlIHVuZGVmaW5lZC4nXG4gICAgICApIDogbnVsbCk7XG4gICAgfVxuICAgIC8vIFRPRE86IENoYW5nZSB0aGlzIGJhY2sgdG8gYGNvbmZpZy5rZXkgPT09IHVuZGVmaW5lZGBcbiAgICBrZXkgPSBjb25maWcua2V5ID09IG51bGwgPyBudWxsIDogJycgKyBjb25maWcua2V5O1xuICAgIC8vIFJlbWFpbmluZyBwcm9wZXJ0aWVzIGFyZSBhZGRlZCB0byBhIG5ldyBwcm9wcyBvYmplY3RcbiAgICBmb3IgKHByb3BOYW1lIGluIGNvbmZpZykge1xuICAgICAgaWYgKGNvbmZpZy5oYXNPd25Qcm9wZXJ0eShwcm9wTmFtZSkgJiZcbiAgICAgICAgICAhUkVTRVJWRURfUFJPUFMuaGFzT3duUHJvcGVydHkocHJvcE5hbWUpKSB7XG4gICAgICAgIHByb3BzW3Byb3BOYW1lXSA9IGNvbmZpZ1twcm9wTmFtZV07XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gQ2hpbGRyZW4gY2FuIGJlIG1vcmUgdGhhbiBvbmUgYXJndW1lbnQsIGFuZCB0aG9zZSBhcmUgdHJhbnNmZXJyZWQgb250b1xuICAvLyB0aGUgbmV3bHkgYWxsb2NhdGVkIHByb3BzIG9iamVjdC5cbiAgdmFyIGNoaWxkcmVuTGVuZ3RoID0gYXJndW1lbnRzLmxlbmd0aCAtIDI7XG4gIGlmIChjaGlsZHJlbkxlbmd0aCA9PT0gMSkge1xuICAgIHByb3BzLmNoaWxkcmVuID0gY2hpbGRyZW47XG4gIH0gZWxzZSBpZiAoY2hpbGRyZW5MZW5ndGggPiAxKSB7XG4gICAgdmFyIGNoaWxkQXJyYXkgPSBBcnJheShjaGlsZHJlbkxlbmd0aCk7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjaGlsZHJlbkxlbmd0aDsgaSsrKSB7XG4gICAgICBjaGlsZEFycmF5W2ldID0gYXJndW1lbnRzW2kgKyAyXTtcbiAgICB9XG4gICAgcHJvcHMuY2hpbGRyZW4gPSBjaGlsZEFycmF5O1xuICB9XG5cbiAgLy8gUmVzb2x2ZSBkZWZhdWx0IHByb3BzXG4gIGlmICh0eXBlICYmIHR5cGUuZGVmYXVsdFByb3BzKSB7XG4gICAgdmFyIGRlZmF1bHRQcm9wcyA9IHR5cGUuZGVmYXVsdFByb3BzO1xuICAgIGZvciAocHJvcE5hbWUgaW4gZGVmYXVsdFByb3BzKSB7XG4gICAgICBpZiAodHlwZW9mIHByb3BzW3Byb3BOYW1lXSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgcHJvcHNbcHJvcE5hbWVdID0gZGVmYXVsdFByb3BzW3Byb3BOYW1lXTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gbmV3IFJlYWN0RWxlbWVudChcbiAgICB0eXBlLFxuICAgIGtleSxcbiAgICByZWYsXG4gICAgUmVhY3RDdXJyZW50T3duZXIuY3VycmVudCxcbiAgICBSZWFjdENvbnRleHQuY3VycmVudCxcbiAgICBwcm9wc1xuICApO1xufTtcblxuUmVhY3RFbGVtZW50LmNyZWF0ZUZhY3RvcnkgPSBmdW5jdGlvbih0eXBlKSB7XG4gIHZhciBmYWN0b3J5ID0gUmVhY3RFbGVtZW50LmNyZWF0ZUVsZW1lbnQuYmluZChudWxsLCB0eXBlKTtcbiAgLy8gRXhwb3NlIHRoZSB0eXBlIG9uIHRoZSBmYWN0b3J5IGFuZCB0aGUgcHJvdG90eXBlIHNvIHRoYXQgaXQgY2FuIGJlXG4gIC8vIGVhc2lseSBhY2Nlc3NlZCBvbiBlbGVtZW50cy4gRS5nLiA8Rm9vIC8+LnR5cGUgPT09IEZvby50eXBlLlxuICAvLyBUaGlzIHNob3VsZCBub3QgYmUgbmFtZWQgYGNvbnN0cnVjdG9yYCBzaW5jZSB0aGlzIG1heSBub3QgYmUgdGhlIGZ1bmN0aW9uXG4gIC8vIHRoYXQgY3JlYXRlZCB0aGUgZWxlbWVudCwgYW5kIGl0IG1heSBub3QgZXZlbiBiZSBhIGNvbnN0cnVjdG9yLlxuICBmYWN0b3J5LnR5cGUgPSB0eXBlO1xuICByZXR1cm4gZmFjdG9yeTtcbn07XG5cblJlYWN0RWxlbWVudC5jbG9uZUFuZFJlcGxhY2VQcm9wcyA9IGZ1bmN0aW9uKG9sZEVsZW1lbnQsIG5ld1Byb3BzKSB7XG4gIHZhciBuZXdFbGVtZW50ID0gbmV3IFJlYWN0RWxlbWVudChcbiAgICBvbGRFbGVtZW50LnR5cGUsXG4gICAgb2xkRWxlbWVudC5rZXksXG4gICAgb2xkRWxlbWVudC5yZWYsXG4gICAgb2xkRWxlbWVudC5fb3duZXIsXG4gICAgb2xkRWxlbWVudC5fY29udGV4dCxcbiAgICBuZXdQcm9wc1xuICApO1xuXG4gIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAvLyBJZiB0aGUga2V5IG9uIHRoZSBvcmlnaW5hbCBpcyB2YWxpZCwgdGhlbiB0aGUgY2xvbmUgaXMgdmFsaWRcbiAgICBuZXdFbGVtZW50Ll9zdG9yZS52YWxpZGF0ZWQgPSBvbGRFbGVtZW50Ll9zdG9yZS52YWxpZGF0ZWQ7XG4gIH1cbiAgcmV0dXJuIG5ld0VsZW1lbnQ7XG59O1xuXG4vKipcbiAqIEBwYXJhbSB7P29iamVjdH0gb2JqZWN0XG4gKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIGBvYmplY3RgIGlzIGEgdmFsaWQgY29tcG9uZW50LlxuICogQGZpbmFsXG4gKi9cblJlYWN0RWxlbWVudC5pc1ZhbGlkRWxlbWVudCA9IGZ1bmN0aW9uKG9iamVjdCkge1xuICAvLyBSZWFjdFRlc3RVdGlscyBpcyBvZnRlbiB1c2VkIG91dHNpZGUgb2YgYmVmb3JlRWFjaCB3aGVyZSBhcyBSZWFjdCBpc1xuICAvLyB3aXRoaW4gaXQuIFRoaXMgbGVhZHMgdG8gdHdvIGRpZmZlcmVudCBpbnN0YW5jZXMgb2YgUmVhY3Qgb24gdGhlIHNhbWVcbiAgLy8gcGFnZS4gVG8gaWRlbnRpZnkgYSBlbGVtZW50IGZyb20gYSBkaWZmZXJlbnQgUmVhY3QgaW5zdGFuY2Ugd2UgdXNlXG4gIC8vIGEgZmxhZyBpbnN0ZWFkIG9mIGFuIGluc3RhbmNlb2YgY2hlY2suXG4gIHZhciBpc0VsZW1lbnQgPSAhIShvYmplY3QgJiYgb2JqZWN0Ll9pc1JlYWN0RWxlbWVudCk7XG4gIC8vIGlmIChpc0VsZW1lbnQgJiYgIShvYmplY3QgaW5zdGFuY2VvZiBSZWFjdEVsZW1lbnQpKSB7XG4gIC8vIFRoaXMgaXMgYW4gaW5kaWNhdG9yIHRoYXQgeW91J3JlIHVzaW5nIG11bHRpcGxlIHZlcnNpb25zIG9mIFJlYWN0IGF0IHRoZVxuICAvLyBzYW1lIHRpbWUuIFRoaXMgd2lsbCBzY3JldyB3aXRoIG93bmVyc2hpcCBhbmQgc3R1ZmYuIEZpeCBpdCwgcGxlYXNlLlxuICAvLyBUT0RPOiBXZSBjb3VsZCBwb3NzaWJseSB3YXJuIGhlcmUuXG4gIC8vIH1cbiAgcmV0dXJuIGlzRWxlbWVudDtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RFbGVtZW50O1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdEVsZW1lbnRWYWxpZGF0b3JcbiAqL1xuXG4vKipcbiAqIFJlYWN0RWxlbWVudFZhbGlkYXRvciBwcm92aWRlcyBhIHdyYXBwZXIgYXJvdW5kIGEgZWxlbWVudCBmYWN0b3J5XG4gKiB3aGljaCB2YWxpZGF0ZXMgdGhlIHByb3BzIHBhc3NlZCB0byB0aGUgZWxlbWVudC4gVGhpcyBpcyBpbnRlbmRlZCB0byBiZVxuICogdXNlZCBvbmx5IGluIERFViBhbmQgY291bGQgYmUgcmVwbGFjZWQgYnkgYSBzdGF0aWMgdHlwZSBjaGVja2VyIGZvciBsYW5ndWFnZXNcbiAqIHRoYXQgc3VwcG9ydCBpdC5cbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFJlYWN0RWxlbWVudCA9IHJlcXVpcmUoXCIuL1JlYWN0RWxlbWVudFwiKTtcbnZhciBSZWFjdFByb3BUeXBlTG9jYXRpb25zID0gcmVxdWlyZShcIi4vUmVhY3RQcm9wVHlwZUxvY2F0aW9uc1wiKTtcbnZhciBSZWFjdEN1cnJlbnRPd25lciA9IHJlcXVpcmUoXCIuL1JlYWN0Q3VycmVudE93bmVyXCIpO1xuXG52YXIgbW9uaXRvckNvZGVVc2UgPSByZXF1aXJlKFwiLi9tb25pdG9yQ29kZVVzZVwiKTtcbnZhciB3YXJuaW5nID0gcmVxdWlyZShcIi4vd2FybmluZ1wiKTtcblxuLyoqXG4gKiBXYXJuIGlmIHRoZXJlJ3Mgbm8ga2V5IGV4cGxpY2l0bHkgc2V0IG9uIGR5bmFtaWMgYXJyYXlzIG9mIGNoaWxkcmVuIG9yXG4gKiBvYmplY3Qga2V5cyBhcmUgbm90IHZhbGlkLiBUaGlzIGFsbG93cyB1cyB0byBrZWVwIHRyYWNrIG9mIGNoaWxkcmVuIGJldHdlZW5cbiAqIHVwZGF0ZXMuXG4gKi9cbnZhciBvd25lckhhc0tleVVzZVdhcm5pbmcgPSB7XG4gICdyZWFjdF9rZXlfd2FybmluZyc6IHt9LFxuICAncmVhY3RfbnVtZXJpY19rZXlfd2FybmluZyc6IHt9XG59O1xudmFyIG93bmVySGFzTW9uaXRvcmVkT2JqZWN0TWFwID0ge307XG5cbnZhciBsb2dnZWRUeXBlRmFpbHVyZXMgPSB7fTtcblxudmFyIE5VTUVSSUNfUFJPUEVSVFlfUkVHRVggPSAvXlxcZCskLztcblxuLyoqXG4gKiBHZXRzIHRoZSBjdXJyZW50IG93bmVyJ3MgZGlzcGxheU5hbWUgZm9yIHVzZSBpbiB3YXJuaW5ncy5cbiAqXG4gKiBAaW50ZXJuYWxcbiAqIEByZXR1cm4gez9zdHJpbmd9IERpc3BsYXkgbmFtZSBvciB1bmRlZmluZWRcbiAqL1xuZnVuY3Rpb24gZ2V0Q3VycmVudE93bmVyRGlzcGxheU5hbWUoKSB7XG4gIHZhciBjdXJyZW50ID0gUmVhY3RDdXJyZW50T3duZXIuY3VycmVudDtcbiAgcmV0dXJuIGN1cnJlbnQgJiYgY3VycmVudC5jb25zdHJ1Y3Rvci5kaXNwbGF5TmFtZSB8fCB1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogV2FybiBpZiB0aGUgY29tcG9uZW50IGRvZXNuJ3QgaGF2ZSBhbiBleHBsaWNpdCBrZXkgYXNzaWduZWQgdG8gaXQuXG4gKiBUaGlzIGNvbXBvbmVudCBpcyBpbiBhbiBhcnJheS4gVGhlIGFycmF5IGNvdWxkIGdyb3cgYW5kIHNocmluayBvciBiZVxuICogcmVvcmRlcmVkLiBBbGwgY2hpbGRyZW4gdGhhdCBoYXZlbid0IGFscmVhZHkgYmVlbiB2YWxpZGF0ZWQgYXJlIHJlcXVpcmVkIHRvXG4gKiBoYXZlIGEgXCJrZXlcIiBwcm9wZXJ0eSBhc3NpZ25lZCB0byBpdC5cbiAqXG4gKiBAaW50ZXJuYWxcbiAqIEBwYXJhbSB7UmVhY3RDb21wb25lbnR9IGNvbXBvbmVudCBDb21wb25lbnQgdGhhdCByZXF1aXJlcyBhIGtleS5cbiAqIEBwYXJhbSB7Kn0gcGFyZW50VHlwZSBjb21wb25lbnQncyBwYXJlbnQncyB0eXBlLlxuICovXG5mdW5jdGlvbiB2YWxpZGF0ZUV4cGxpY2l0S2V5KGNvbXBvbmVudCwgcGFyZW50VHlwZSkge1xuICBpZiAoY29tcG9uZW50Ll9zdG9yZS52YWxpZGF0ZWQgfHwgY29tcG9uZW50LmtleSAhPSBudWxsKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIGNvbXBvbmVudC5fc3RvcmUudmFsaWRhdGVkID0gdHJ1ZTtcblxuICB3YXJuQW5kTW9uaXRvckZvcktleVVzZShcbiAgICAncmVhY3Rfa2V5X3dhcm5pbmcnLFxuICAgICdFYWNoIGNoaWxkIGluIGFuIGFycmF5IHNob3VsZCBoYXZlIGEgdW5pcXVlIFwia2V5XCIgcHJvcC4nLFxuICAgIGNvbXBvbmVudCxcbiAgICBwYXJlbnRUeXBlXG4gICk7XG59XG5cbi8qKlxuICogV2FybiBpZiB0aGUga2V5IGlzIGJlaW5nIGRlZmluZWQgYXMgYW4gb2JqZWN0IHByb3BlcnR5IGJ1dCBoYXMgYW4gaW5jb3JyZWN0XG4gKiB2YWx1ZS5cbiAqXG4gKiBAaW50ZXJuYWxcbiAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIFByb3BlcnR5IG5hbWUgb2YgdGhlIGtleS5cbiAqIEBwYXJhbSB7UmVhY3RDb21wb25lbnR9IGNvbXBvbmVudCBDb21wb25lbnQgdGhhdCByZXF1aXJlcyBhIGtleS5cbiAqIEBwYXJhbSB7Kn0gcGFyZW50VHlwZSBjb21wb25lbnQncyBwYXJlbnQncyB0eXBlLlxuICovXG5mdW5jdGlvbiB2YWxpZGF0ZVByb3BlcnR5S2V5KG5hbWUsIGNvbXBvbmVudCwgcGFyZW50VHlwZSkge1xuICBpZiAoIU5VTUVSSUNfUFJPUEVSVFlfUkVHRVgudGVzdChuYW1lKSkge1xuICAgIHJldHVybjtcbiAgfVxuICB3YXJuQW5kTW9uaXRvckZvcktleVVzZShcbiAgICAncmVhY3RfbnVtZXJpY19rZXlfd2FybmluZycsXG4gICAgJ0NoaWxkIG9iamVjdHMgc2hvdWxkIGhhdmUgbm9uLW51bWVyaWMga2V5cyBzbyBvcmRlcmluZyBpcyBwcmVzZXJ2ZWQuJyxcbiAgICBjb21wb25lbnQsXG4gICAgcGFyZW50VHlwZVxuICApO1xufVxuXG4vKipcbiAqIFNoYXJlZCB3YXJuaW5nIGFuZCBtb25pdG9yaW5nIGNvZGUgZm9yIHRoZSBrZXkgd2FybmluZ3MuXG4gKlxuICogQGludGVybmFsXG4gKiBAcGFyYW0ge3N0cmluZ30gd2FybmluZ0lEIFRoZSBpZCB1c2VkIHdoZW4gbG9nZ2luZy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlIFRoZSBiYXNlIHdhcm5pbmcgdGhhdCBnZXRzIG91dHB1dC5cbiAqIEBwYXJhbSB7UmVhY3RDb21wb25lbnR9IGNvbXBvbmVudCBDb21wb25lbnQgdGhhdCByZXF1aXJlcyBhIGtleS5cbiAqIEBwYXJhbSB7Kn0gcGFyZW50VHlwZSBjb21wb25lbnQncyBwYXJlbnQncyB0eXBlLlxuICovXG5mdW5jdGlvbiB3YXJuQW5kTW9uaXRvckZvcktleVVzZSh3YXJuaW5nSUQsIG1lc3NhZ2UsIGNvbXBvbmVudCwgcGFyZW50VHlwZSkge1xuICB2YXIgb3duZXJOYW1lID0gZ2V0Q3VycmVudE93bmVyRGlzcGxheU5hbWUoKTtcbiAgdmFyIHBhcmVudE5hbWUgPSBwYXJlbnRUeXBlLmRpc3BsYXlOYW1lO1xuXG4gIHZhciB1c2VOYW1lID0gb3duZXJOYW1lIHx8IHBhcmVudE5hbWU7XG4gIHZhciBtZW1vaXplciA9IG93bmVySGFzS2V5VXNlV2FybmluZ1t3YXJuaW5nSURdO1xuICBpZiAobWVtb2l6ZXIuaGFzT3duUHJvcGVydHkodXNlTmFtZSkpIHtcbiAgICByZXR1cm47XG4gIH1cbiAgbWVtb2l6ZXJbdXNlTmFtZV0gPSB0cnVlO1xuXG4gIG1lc3NhZ2UgKz0gb3duZXJOYW1lID9cbiAgICAoXCIgQ2hlY2sgdGhlIHJlbmRlciBtZXRob2Qgb2YgXCIgKyBvd25lck5hbWUgKyBcIi5cIikgOlxuICAgIChcIiBDaGVjayB0aGUgcmVuZGVyQ29tcG9uZW50IGNhbGwgdXNpbmcgPFwiICsgcGFyZW50TmFtZSArIFwiPi5cIik7XG5cbiAgLy8gVXN1YWxseSB0aGUgY3VycmVudCBvd25lciBpcyB0aGUgb2ZmZW5kZXIsIGJ1dCBpZiBpdCBhY2NlcHRzIGNoaWxkcmVuIGFzIGFcbiAgLy8gcHJvcGVydHksIGl0IG1heSBiZSB0aGUgY3JlYXRvciBvZiB0aGUgY2hpbGQgdGhhdCdzIHJlc3BvbnNpYmxlIGZvclxuICAvLyBhc3NpZ25pbmcgaXQgYSBrZXkuXG4gIHZhciBjaGlsZE93bmVyTmFtZSA9IG51bGw7XG4gIGlmIChjb21wb25lbnQuX293bmVyICYmIGNvbXBvbmVudC5fb3duZXIgIT09IFJlYWN0Q3VycmVudE93bmVyLmN1cnJlbnQpIHtcbiAgICAvLyBOYW1lIG9mIHRoZSBjb21wb25lbnQgdGhhdCBvcmlnaW5hbGx5IGNyZWF0ZWQgdGhpcyBjaGlsZC5cbiAgICBjaGlsZE93bmVyTmFtZSA9IGNvbXBvbmVudC5fb3duZXIuY29uc3RydWN0b3IuZGlzcGxheU5hbWU7XG5cbiAgICBtZXNzYWdlICs9IChcIiBJdCB3YXMgcGFzc2VkIGEgY2hpbGQgZnJvbSBcIiArIGNoaWxkT3duZXJOYW1lICsgXCIuXCIpO1xuICB9XG5cbiAgbWVzc2FnZSArPSAnIFNlZSBodHRwOi8vZmIubWUvcmVhY3Qtd2FybmluZy1rZXlzIGZvciBtb3JlIGluZm9ybWF0aW9uLic7XG4gIG1vbml0b3JDb2RlVXNlKHdhcm5pbmdJRCwge1xuICAgIGNvbXBvbmVudDogdXNlTmFtZSxcbiAgICBjb21wb25lbnRPd25lcjogY2hpbGRPd25lck5hbWVcbiAgfSk7XG4gIGNvbnNvbGUud2FybihtZXNzYWdlKTtcbn1cblxuLyoqXG4gKiBMb2cgdGhhdCB3ZSdyZSB1c2luZyBhbiBvYmplY3QgbWFwLiBXZSdyZSBjb25zaWRlcmluZyBkZXByZWNhdGluZyB0aGlzXG4gKiBmZWF0dXJlIGFuZCByZXBsYWNlIGl0IHdpdGggcHJvcGVyIE1hcCBhbmQgSW1tdXRhYmxlTWFwIGRhdGEgc3RydWN0dXJlcy5cbiAqXG4gKiBAaW50ZXJuYWxcbiAqL1xuZnVuY3Rpb24gbW9uaXRvclVzZU9mT2JqZWN0TWFwKCkge1xuICB2YXIgY3VycmVudE5hbWUgPSBnZXRDdXJyZW50T3duZXJEaXNwbGF5TmFtZSgpIHx8ICcnO1xuICBpZiAob3duZXJIYXNNb25pdG9yZWRPYmplY3RNYXAuaGFzT3duUHJvcGVydHkoY3VycmVudE5hbWUpKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIG93bmVySGFzTW9uaXRvcmVkT2JqZWN0TWFwW2N1cnJlbnROYW1lXSA9IHRydWU7XG4gIG1vbml0b3JDb2RlVXNlKCdyZWFjdF9vYmplY3RfbWFwX2NoaWxkcmVuJyk7XG59XG5cbi8qKlxuICogRW5zdXJlIHRoYXQgZXZlcnkgY29tcG9uZW50IGVpdGhlciBpcyBwYXNzZWQgaW4gYSBzdGF0aWMgbG9jYXRpb24sIGluIGFuXG4gKiBhcnJheSB3aXRoIGFuIGV4cGxpY2l0IGtleXMgcHJvcGVydHkgZGVmaW5lZCwgb3IgaW4gYW4gb2JqZWN0IGxpdGVyYWxcbiAqIHdpdGggdmFsaWQga2V5IHByb3BlcnR5LlxuICpcbiAqIEBpbnRlcm5hbFxuICogQHBhcmFtIHsqfSBjb21wb25lbnQgU3RhdGljYWxseSBwYXNzZWQgY2hpbGQgb2YgYW55IHR5cGUuXG4gKiBAcGFyYW0geyp9IHBhcmVudFR5cGUgY29tcG9uZW50J3MgcGFyZW50J3MgdHlwZS5cbiAqIEByZXR1cm4ge2Jvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIHZhbGlkYXRlQ2hpbGRLZXlzKGNvbXBvbmVudCwgcGFyZW50VHlwZSkge1xuICBpZiAoQXJyYXkuaXNBcnJheShjb21wb25lbnQpKSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjb21wb25lbnQubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBjaGlsZCA9IGNvbXBvbmVudFtpXTtcbiAgICAgIGlmIChSZWFjdEVsZW1lbnQuaXNWYWxpZEVsZW1lbnQoY2hpbGQpKSB7XG4gICAgICAgIHZhbGlkYXRlRXhwbGljaXRLZXkoY2hpbGQsIHBhcmVudFR5cGUpO1xuICAgICAgfVxuICAgIH1cbiAgfSBlbHNlIGlmIChSZWFjdEVsZW1lbnQuaXNWYWxpZEVsZW1lbnQoY29tcG9uZW50KSkge1xuICAgIC8vIFRoaXMgY29tcG9uZW50IHdhcyBwYXNzZWQgaW4gYSB2YWxpZCBsb2NhdGlvbi5cbiAgICBjb21wb25lbnQuX3N0b3JlLnZhbGlkYXRlZCA9IHRydWU7XG4gIH0gZWxzZSBpZiAoY29tcG9uZW50ICYmIHR5cGVvZiBjb21wb25lbnQgPT09ICdvYmplY3QnKSB7XG4gICAgbW9uaXRvclVzZU9mT2JqZWN0TWFwKCk7XG4gICAgZm9yICh2YXIgbmFtZSBpbiBjb21wb25lbnQpIHtcbiAgICAgIHZhbGlkYXRlUHJvcGVydHlLZXkobmFtZSwgY29tcG9uZW50W25hbWVdLCBwYXJlbnRUeXBlKTtcbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBBc3NlcnQgdGhhdCB0aGUgcHJvcHMgYXJlIHZhbGlkXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGNvbXBvbmVudE5hbWUgTmFtZSBvZiB0aGUgY29tcG9uZW50IGZvciBlcnJvciBtZXNzYWdlcy5cbiAqIEBwYXJhbSB7b2JqZWN0fSBwcm9wVHlwZXMgTWFwIG9mIHByb3AgbmFtZSB0byBhIFJlYWN0UHJvcFR5cGVcbiAqIEBwYXJhbSB7b2JqZWN0fSBwcm9wc1xuICogQHBhcmFtIHtzdHJpbmd9IGxvY2F0aW9uIGUuZy4gXCJwcm9wXCIsIFwiY29udGV4dFwiLCBcImNoaWxkIGNvbnRleHRcIlxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gY2hlY2tQcm9wVHlwZXMoY29tcG9uZW50TmFtZSwgcHJvcFR5cGVzLCBwcm9wcywgbG9jYXRpb24pIHtcbiAgZm9yICh2YXIgcHJvcE5hbWUgaW4gcHJvcFR5cGVzKSB7XG4gICAgaWYgKHByb3BUeXBlcy5oYXNPd25Qcm9wZXJ0eShwcm9wTmFtZSkpIHtcbiAgICAgIHZhciBlcnJvcjtcbiAgICAgIC8vIFByb3AgdHlwZSB2YWxpZGF0aW9uIG1heSB0aHJvdy4gSW4gY2FzZSB0aGV5IGRvLCB3ZSBkb24ndCB3YW50IHRvXG4gICAgICAvLyBmYWlsIHRoZSByZW5kZXIgcGhhc2Ugd2hlcmUgaXQgZGlkbid0IGZhaWwgYmVmb3JlLiBTbyB3ZSBsb2cgaXQuXG4gICAgICAvLyBBZnRlciB0aGVzZSBoYXZlIGJlZW4gY2xlYW5lZCB1cCwgd2UnbGwgbGV0IHRoZW0gdGhyb3cuXG4gICAgICB0cnkge1xuICAgICAgICBlcnJvciA9IHByb3BUeXBlc1twcm9wTmFtZV0ocHJvcHMsIHByb3BOYW1lLCBjb21wb25lbnROYW1lLCBsb2NhdGlvbik7XG4gICAgICB9IGNhdGNoIChleCkge1xuICAgICAgICBlcnJvciA9IGV4O1xuICAgICAgfVxuICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IgJiYgIShlcnJvci5tZXNzYWdlIGluIGxvZ2dlZFR5cGVGYWlsdXJlcykpIHtcbiAgICAgICAgLy8gT25seSBtb25pdG9yIHRoaXMgZmFpbHVyZSBvbmNlIGJlY2F1c2UgdGhlcmUgdGVuZHMgdG8gYmUgYSBsb3Qgb2YgdGhlXG4gICAgICAgIC8vIHNhbWUgZXJyb3IuXG4gICAgICAgIGxvZ2dlZFR5cGVGYWlsdXJlc1tlcnJvci5tZXNzYWdlXSA9IHRydWU7XG4gICAgICAgIC8vIFRoaXMgd2lsbCBzb29uIHVzZSB0aGUgd2FybmluZyBtb2R1bGVcbiAgICAgICAgbW9uaXRvckNvZGVVc2UoXG4gICAgICAgICAgJ3JlYWN0X2ZhaWxlZF9kZXNjcmlwdG9yX3R5cGVfY2hlY2snLFxuICAgICAgICAgIHsgbWVzc2FnZTogZXJyb3IubWVzc2FnZSB9XG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cbnZhciBSZWFjdEVsZW1lbnRWYWxpZGF0b3IgPSB7XG5cbiAgY3JlYXRlRWxlbWVudDogZnVuY3Rpb24odHlwZSwgcHJvcHMsIGNoaWxkcmVuKSB7XG4gICAgLy8gV2Ugd2FybiBpbiB0aGlzIGNhc2UgYnV0IGRvbid0IHRocm93LiBXZSBleHBlY3QgdGhlIGVsZW1lbnQgY3JlYXRpb24gdG9cbiAgICAvLyBzdWNjZWVkIGFuZCB0aGVyZSB3aWxsIGxpa2VseSBiZSBlcnJvcnMgaW4gcmVuZGVyLlxuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyB3YXJuaW5nKFxuICAgICAgdHlwZSAhPSBudWxsLFxuICAgICAgJ1JlYWN0LmNyZWF0ZUVsZW1lbnQ6IHR5cGUgc2hvdWxkIG5vdCBiZSBudWxsIG9yIHVuZGVmaW5lZC4gSXQgc2hvdWxkICcgK1xuICAgICAgICAnYmUgYSBzdHJpbmcgKGZvciBET00gZWxlbWVudHMpIG9yIGEgUmVhY3RDbGFzcyAoZm9yIGNvbXBvc2l0ZSAnICtcbiAgICAgICAgJ2NvbXBvbmVudHMpLidcbiAgICApIDogbnVsbCk7XG5cbiAgICB2YXIgZWxlbWVudCA9IFJlYWN0RWxlbWVudC5jcmVhdGVFbGVtZW50LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cbiAgICAvLyBUaGUgcmVzdWx0IGNhbiBiZSBudWxsaXNoIGlmIGEgbW9jayBvciBhIGN1c3RvbSBmdW5jdGlvbiBpcyB1c2VkLlxuICAgIC8vIFRPRE86IERyb3AgdGhpcyB3aGVuIHRoZXNlIGFyZSBubyBsb25nZXIgYWxsb3dlZCBhcyB0aGUgdHlwZSBhcmd1bWVudC5cbiAgICBpZiAoZWxlbWVudCA9PSBudWxsKSB7XG4gICAgICByZXR1cm4gZWxlbWVudDtcbiAgICB9XG5cbiAgICBmb3IgKHZhciBpID0gMjsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFsaWRhdGVDaGlsZEtleXMoYXJndW1lbnRzW2ldLCB0eXBlKTtcbiAgICB9XG5cbiAgICBpZiAodHlwZSkge1xuICAgICAgdmFyIG5hbWUgPSB0eXBlLmRpc3BsYXlOYW1lO1xuICAgICAgaWYgKHR5cGUucHJvcFR5cGVzKSB7XG4gICAgICAgIGNoZWNrUHJvcFR5cGVzKFxuICAgICAgICAgIG5hbWUsXG4gICAgICAgICAgdHlwZS5wcm9wVHlwZXMsXG4gICAgICAgICAgZWxlbWVudC5wcm9wcyxcbiAgICAgICAgICBSZWFjdFByb3BUeXBlTG9jYXRpb25zLnByb3BcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIGlmICh0eXBlLmNvbnRleHRUeXBlcykge1xuICAgICAgICBjaGVja1Byb3BUeXBlcyhcbiAgICAgICAgICBuYW1lLFxuICAgICAgICAgIHR5cGUuY29udGV4dFR5cGVzLFxuICAgICAgICAgIGVsZW1lbnQuX2NvbnRleHQsXG4gICAgICAgICAgUmVhY3RQcm9wVHlwZUxvY2F0aW9ucy5jb250ZXh0XG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBlbGVtZW50O1xuICB9LFxuXG4gIGNyZWF0ZUZhY3Rvcnk6IGZ1bmN0aW9uKHR5cGUpIHtcbiAgICB2YXIgdmFsaWRhdGVkRmFjdG9yeSA9IFJlYWN0RWxlbWVudFZhbGlkYXRvci5jcmVhdGVFbGVtZW50LmJpbmQoXG4gICAgICBudWxsLFxuICAgICAgdHlwZVxuICAgICk7XG4gICAgdmFsaWRhdGVkRmFjdG9yeS50eXBlID0gdHlwZTtcbiAgICByZXR1cm4gdmFsaWRhdGVkRmFjdG9yeTtcbiAgfVxuXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0RWxlbWVudFZhbGlkYXRvcjtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RFbXB0eUNvbXBvbmVudFxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgUmVhY3RFbGVtZW50ID0gcmVxdWlyZShcIi4vUmVhY3RFbGVtZW50XCIpO1xuXG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG52YXIgY29tcG9uZW50O1xuLy8gVGhpcyByZWdpc3RyeSBrZWVwcyB0cmFjayBvZiB0aGUgUmVhY3QgSURzIG9mIHRoZSBjb21wb25lbnRzIHRoYXQgcmVuZGVyZWQgdG9cbi8vIGBudWxsYCAoaW4gcmVhbGl0eSBhIHBsYWNlaG9sZGVyIHN1Y2ggYXMgYG5vc2NyaXB0YClcbnZhciBudWxsQ29tcG9uZW50SWRzUmVnaXN0cnkgPSB7fTtcblxudmFyIFJlYWN0RW1wdHlDb21wb25lbnRJbmplY3Rpb24gPSB7XG4gIGluamVjdEVtcHR5Q29tcG9uZW50OiBmdW5jdGlvbihlbXB0eUNvbXBvbmVudCkge1xuICAgIGNvbXBvbmVudCA9IFJlYWN0RWxlbWVudC5jcmVhdGVGYWN0b3J5KGVtcHR5Q29tcG9uZW50KTtcbiAgfVxufTtcblxuLyoqXG4gKiBAcmV0dXJuIHtSZWFjdENvbXBvbmVudH0gY29tcG9uZW50IFRoZSBpbmplY3RlZCBlbXB0eSBjb21wb25lbnQuXG4gKi9cbmZ1bmN0aW9uIGdldEVtcHR5Q29tcG9uZW50KCkge1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgIGNvbXBvbmVudCxcbiAgICAnVHJ5aW5nIHRvIHJldHVybiBudWxsIGZyb20gYSByZW5kZXIsIGJ1dCBubyBudWxsIHBsYWNlaG9sZGVyIGNvbXBvbmVudCAnICtcbiAgICAnd2FzIGluamVjdGVkLidcbiAgKSA6IGludmFyaWFudChjb21wb25lbnQpKTtcbiAgcmV0dXJuIGNvbXBvbmVudCgpO1xufVxuXG4vKipcbiAqIE1hcmsgdGhlIGNvbXBvbmVudCBhcyBoYXZpbmcgcmVuZGVyZWQgdG8gbnVsbC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBpZCBDb21wb25lbnQncyBgX3Jvb3ROb2RlSURgLlxuICovXG5mdW5jdGlvbiByZWdpc3Rlck51bGxDb21wb25lbnRJRChpZCkge1xuICBudWxsQ29tcG9uZW50SWRzUmVnaXN0cnlbaWRdID0gdHJ1ZTtcbn1cblxuLyoqXG4gKiBVbm1hcmsgdGhlIGNvbXBvbmVudCBhcyBoYXZpbmcgcmVuZGVyZWQgdG8gbnVsbDogaXQgcmVuZGVycyB0byBzb21ldGhpbmcgbm93LlxuICogQHBhcmFtIHtzdHJpbmd9IGlkIENvbXBvbmVudCdzIGBfcm9vdE5vZGVJRGAuXG4gKi9cbmZ1bmN0aW9uIGRlcmVnaXN0ZXJOdWxsQ29tcG9uZW50SUQoaWQpIHtcbiAgZGVsZXRlIG51bGxDb21wb25lbnRJZHNSZWdpc3RyeVtpZF07XG59XG5cbi8qKlxuICogQHBhcmFtIHtzdHJpbmd9IGlkIENvbXBvbmVudCdzIGBfcm9vdE5vZGVJRGAuXG4gKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIHRoZSBjb21wb25lbnQgaXMgcmVuZGVyZWQgdG8gbnVsbC5cbiAqL1xuZnVuY3Rpb24gaXNOdWxsQ29tcG9uZW50SUQoaWQpIHtcbiAgcmV0dXJuIG51bGxDb21wb25lbnRJZHNSZWdpc3RyeVtpZF07XG59XG5cbnZhciBSZWFjdEVtcHR5Q29tcG9uZW50ID0ge1xuICBkZXJlZ2lzdGVyTnVsbENvbXBvbmVudElEOiBkZXJlZ2lzdGVyTnVsbENvbXBvbmVudElELFxuICBnZXRFbXB0eUNvbXBvbmVudDogZ2V0RW1wdHlDb21wb25lbnQsXG4gIGluamVjdGlvbjogUmVhY3RFbXB0eUNvbXBvbmVudEluamVjdGlvbixcbiAgaXNOdWxsQ29tcG9uZW50SUQ6IGlzTnVsbENvbXBvbmVudElELFxuICByZWdpc3Rlck51bGxDb21wb25lbnRJRDogcmVnaXN0ZXJOdWxsQ29tcG9uZW50SURcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RFbXB0eUNvbXBvbmVudDtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0RXJyb3JVdGlsc1xuICogQHR5cGVjaGVja3NcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFJlYWN0RXJyb3JVdGlscyA9IHtcbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBndWFyZGVkIHZlcnNpb24gb2YgYSBmdW5jdGlvbi4gVGhpcyBpcyBzdXBwb3NlZCB0byBtYWtlIGRlYnVnZ2luZ1xuICAgKiBvZiBldmVudCBoYW5kbGVycyBlYXNpZXIuIFRvIGFpZCBkZWJ1Z2dpbmcgd2l0aCB0aGUgYnJvd3NlcidzIGRlYnVnZ2VyLFxuICAgKiB0aGlzIGN1cnJlbnRseSBzaW1wbHkgcmV0dXJucyB0aGUgb3JpZ2luYWwgZnVuY3Rpb24uXG4gICAqXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IGZ1bmMgRnVuY3Rpb24gdG8gYmUgZXhlY3V0ZWRcbiAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgVGhlIG5hbWUgb2YgdGhlIGd1YXJkXG4gICAqIEByZXR1cm4ge2Z1bmN0aW9ufVxuICAgKi9cbiAgZ3VhcmQ6IGZ1bmN0aW9uKGZ1bmMsIG5hbWUpIHtcbiAgICByZXR1cm4gZnVuYztcbiAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdEVycm9yVXRpbHM7XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RFdmVudEVtaXR0ZXJNaXhpblxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgRXZlbnRQbHVnaW5IdWIgPSByZXF1aXJlKFwiLi9FdmVudFBsdWdpbkh1YlwiKTtcblxuZnVuY3Rpb24gcnVuRXZlbnRRdWV1ZUluQmF0Y2goZXZlbnRzKSB7XG4gIEV2ZW50UGx1Z2luSHViLmVucXVldWVFdmVudHMoZXZlbnRzKTtcbiAgRXZlbnRQbHVnaW5IdWIucHJvY2Vzc0V2ZW50UXVldWUoKTtcbn1cblxudmFyIFJlYWN0RXZlbnRFbWl0dGVyTWl4aW4gPSB7XG5cbiAgLyoqXG4gICAqIFN0cmVhbXMgYSBmaXJlZCB0b3AtbGV2ZWwgZXZlbnQgdG8gYEV2ZW50UGx1Z2luSHViYCB3aGVyZSBwbHVnaW5zIGhhdmUgdGhlXG4gICAqIG9wcG9ydHVuaXR5IHRvIGNyZWF0ZSBgUmVhY3RFdmVudGBzIHRvIGJlIGRpc3BhdGNoZWQuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0b3BMZXZlbFR5cGUgUmVjb3JkIGZyb20gYEV2ZW50Q29uc3RhbnRzYC5cbiAgICogQHBhcmFtIHtvYmplY3R9IHRvcExldmVsVGFyZ2V0IFRoZSBsaXN0ZW5pbmcgY29tcG9uZW50IHJvb3Qgbm9kZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHRvcExldmVsVGFyZ2V0SUQgSUQgb2YgYHRvcExldmVsVGFyZ2V0YC5cbiAgICogQHBhcmFtIHtvYmplY3R9IG5hdGl2ZUV2ZW50IE5hdGl2ZSBlbnZpcm9ubWVudCBldmVudC5cbiAgICovXG4gIGhhbmRsZVRvcExldmVsOiBmdW5jdGlvbihcbiAgICAgIHRvcExldmVsVHlwZSxcbiAgICAgIHRvcExldmVsVGFyZ2V0LFxuICAgICAgdG9wTGV2ZWxUYXJnZXRJRCxcbiAgICAgIG5hdGl2ZUV2ZW50KSB7XG4gICAgdmFyIGV2ZW50cyA9IEV2ZW50UGx1Z2luSHViLmV4dHJhY3RFdmVudHMoXG4gICAgICB0b3BMZXZlbFR5cGUsXG4gICAgICB0b3BMZXZlbFRhcmdldCxcbiAgICAgIHRvcExldmVsVGFyZ2V0SUQsXG4gICAgICBuYXRpdmVFdmVudFxuICAgICk7XG5cbiAgICBydW5FdmVudFF1ZXVlSW5CYXRjaChldmVudHMpO1xuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0RXZlbnRFbWl0dGVyTWl4aW47XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RFdmVudExpc3RlbmVyXG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgRXZlbnRMaXN0ZW5lciA9IHJlcXVpcmUoXCIuL0V2ZW50TGlzdGVuZXJcIik7XG52YXIgRXhlY3V0aW9uRW52aXJvbm1lbnQgPSByZXF1aXJlKFwiLi9FeGVjdXRpb25FbnZpcm9ubWVudFwiKTtcbnZhciBQb29sZWRDbGFzcyA9IHJlcXVpcmUoXCIuL1Bvb2xlZENsYXNzXCIpO1xudmFyIFJlYWN0SW5zdGFuY2VIYW5kbGVzID0gcmVxdWlyZShcIi4vUmVhY3RJbnN0YW5jZUhhbmRsZXNcIik7XG52YXIgUmVhY3RNb3VudCA9IHJlcXVpcmUoXCIuL1JlYWN0TW91bnRcIik7XG52YXIgUmVhY3RVcGRhdGVzID0gcmVxdWlyZShcIi4vUmVhY3RVcGRhdGVzXCIpO1xuXG52YXIgYXNzaWduID0gcmVxdWlyZShcIi4vT2JqZWN0LmFzc2lnblwiKTtcbnZhciBnZXRFdmVudFRhcmdldCA9IHJlcXVpcmUoXCIuL2dldEV2ZW50VGFyZ2V0XCIpO1xudmFyIGdldFVuYm91bmRlZFNjcm9sbFBvc2l0aW9uID0gcmVxdWlyZShcIi4vZ2V0VW5ib3VuZGVkU2Nyb2xsUG9zaXRpb25cIik7XG5cbi8qKlxuICogRmluZHMgdGhlIHBhcmVudCBSZWFjdCBjb21wb25lbnQgb2YgYG5vZGVgLlxuICpcbiAqIEBwYXJhbSB7Kn0gbm9kZVxuICogQHJldHVybiB7P0RPTUV2ZW50VGFyZ2V0fSBQYXJlbnQgY29udGFpbmVyLCBvciBgbnVsbGAgaWYgdGhlIHNwZWNpZmllZCBub2RlXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzIG5vdCBuZXN0ZWQuXG4gKi9cbmZ1bmN0aW9uIGZpbmRQYXJlbnQobm9kZSkge1xuICAvLyBUT0RPOiBJdCBtYXkgYmUgYSBnb29kIGlkZWEgdG8gY2FjaGUgdGhpcyB0byBwcmV2ZW50IHVubmVjZXNzYXJ5IERPTVxuICAvLyB0cmF2ZXJzYWwsIGJ1dCBjYWNoaW5nIGlzIGRpZmZpY3VsdCB0byBkbyBjb3JyZWN0bHkgd2l0aG91dCB1c2luZyBhXG4gIC8vIG11dGF0aW9uIG9ic2VydmVyIHRvIGxpc3RlbiBmb3IgYWxsIERPTSBjaGFuZ2VzLlxuICB2YXIgbm9kZUlEID0gUmVhY3RNb3VudC5nZXRJRChub2RlKTtcbiAgdmFyIHJvb3RJRCA9IFJlYWN0SW5zdGFuY2VIYW5kbGVzLmdldFJlYWN0Um9vdElERnJvbU5vZGVJRChub2RlSUQpO1xuICB2YXIgY29udGFpbmVyID0gUmVhY3RNb3VudC5maW5kUmVhY3RDb250YWluZXJGb3JJRChyb290SUQpO1xuICB2YXIgcGFyZW50ID0gUmVhY3RNb3VudC5nZXRGaXJzdFJlYWN0RE9NKGNvbnRhaW5lcik7XG4gIHJldHVybiBwYXJlbnQ7XG59XG5cbi8vIFVzZWQgdG8gc3RvcmUgYW5jZXN0b3IgaGllcmFyY2h5IGluIHRvcCBsZXZlbCBjYWxsYmFja1xuZnVuY3Rpb24gVG9wTGV2ZWxDYWxsYmFja0Jvb2tLZWVwaW5nKHRvcExldmVsVHlwZSwgbmF0aXZlRXZlbnQpIHtcbiAgdGhpcy50b3BMZXZlbFR5cGUgPSB0b3BMZXZlbFR5cGU7XG4gIHRoaXMubmF0aXZlRXZlbnQgPSBuYXRpdmVFdmVudDtcbiAgdGhpcy5hbmNlc3RvcnMgPSBbXTtcbn1cbmFzc2lnbihUb3BMZXZlbENhbGxiYWNrQm9va0tlZXBpbmcucHJvdG90eXBlLCB7XG4gIGRlc3RydWN0b3I6IGZ1bmN0aW9uKCkge1xuICAgIHRoaXMudG9wTGV2ZWxUeXBlID0gbnVsbDtcbiAgICB0aGlzLm5hdGl2ZUV2ZW50ID0gbnVsbDtcbiAgICB0aGlzLmFuY2VzdG9ycy5sZW5ndGggPSAwO1xuICB9XG59KTtcblBvb2xlZENsYXNzLmFkZFBvb2xpbmdUbyhcbiAgVG9wTGV2ZWxDYWxsYmFja0Jvb2tLZWVwaW5nLFxuICBQb29sZWRDbGFzcy50d29Bcmd1bWVudFBvb2xlclxuKTtcblxuZnVuY3Rpb24gaGFuZGxlVG9wTGV2ZWxJbXBsKGJvb2tLZWVwaW5nKSB7XG4gIHZhciB0b3BMZXZlbFRhcmdldCA9IFJlYWN0TW91bnQuZ2V0Rmlyc3RSZWFjdERPTShcbiAgICBnZXRFdmVudFRhcmdldChib29rS2VlcGluZy5uYXRpdmVFdmVudClcbiAgKSB8fCB3aW5kb3c7XG5cbiAgLy8gTG9vcCB0aHJvdWdoIHRoZSBoaWVyYXJjaHksIGluIGNhc2UgdGhlcmUncyBhbnkgbmVzdGVkIGNvbXBvbmVudHMuXG4gIC8vIEl0J3MgaW1wb3J0YW50IHRoYXQgd2UgYnVpbGQgdGhlIGFycmF5IG9mIGFuY2VzdG9ycyBiZWZvcmUgY2FsbGluZyBhbnlcbiAgLy8gZXZlbnQgaGFuZGxlcnMsIGJlY2F1c2UgZXZlbnQgaGFuZGxlcnMgY2FuIG1vZGlmeSB0aGUgRE9NLCBsZWFkaW5nIHRvXG4gIC8vIGluY29uc2lzdGVuY2llcyB3aXRoIFJlYWN0TW91bnQncyBub2RlIGNhY2hlLiBTZWUgIzExMDUuXG4gIHZhciBhbmNlc3RvciA9IHRvcExldmVsVGFyZ2V0O1xuICB3aGlsZSAoYW5jZXN0b3IpIHtcbiAgICBib29rS2VlcGluZy5hbmNlc3RvcnMucHVzaChhbmNlc3Rvcik7XG4gICAgYW5jZXN0b3IgPSBmaW5kUGFyZW50KGFuY2VzdG9yKTtcbiAgfVxuXG4gIGZvciAodmFyIGkgPSAwLCBsID0gYm9va0tlZXBpbmcuYW5jZXN0b3JzLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgIHRvcExldmVsVGFyZ2V0ID0gYm9va0tlZXBpbmcuYW5jZXN0b3JzW2ldO1xuICAgIHZhciB0b3BMZXZlbFRhcmdldElEID0gUmVhY3RNb3VudC5nZXRJRCh0b3BMZXZlbFRhcmdldCkgfHwgJyc7XG4gICAgUmVhY3RFdmVudExpc3RlbmVyLl9oYW5kbGVUb3BMZXZlbChcbiAgICAgIGJvb2tLZWVwaW5nLnRvcExldmVsVHlwZSxcbiAgICAgIHRvcExldmVsVGFyZ2V0LFxuICAgICAgdG9wTGV2ZWxUYXJnZXRJRCxcbiAgICAgIGJvb2tLZWVwaW5nLm5hdGl2ZUV2ZW50XG4gICAgKTtcbiAgfVxufVxuXG5mdW5jdGlvbiBzY3JvbGxWYWx1ZU1vbml0b3IoY2IpIHtcbiAgdmFyIHNjcm9sbFBvc2l0aW9uID0gZ2V0VW5ib3VuZGVkU2Nyb2xsUG9zaXRpb24od2luZG93KTtcbiAgY2Ioc2Nyb2xsUG9zaXRpb24pO1xufVxuXG52YXIgUmVhY3RFdmVudExpc3RlbmVyID0ge1xuICBfZW5hYmxlZDogdHJ1ZSxcbiAgX2hhbmRsZVRvcExldmVsOiBudWxsLFxuXG4gIFdJTkRPV19IQU5ETEU6IEV4ZWN1dGlvbkVudmlyb25tZW50LmNhblVzZURPTSA/IHdpbmRvdyA6IG51bGwsXG5cbiAgc2V0SGFuZGxlVG9wTGV2ZWw6IGZ1bmN0aW9uKGhhbmRsZVRvcExldmVsKSB7XG4gICAgUmVhY3RFdmVudExpc3RlbmVyLl9oYW5kbGVUb3BMZXZlbCA9IGhhbmRsZVRvcExldmVsO1xuICB9LFxuXG4gIHNldEVuYWJsZWQ6IGZ1bmN0aW9uKGVuYWJsZWQpIHtcbiAgICBSZWFjdEV2ZW50TGlzdGVuZXIuX2VuYWJsZWQgPSAhIWVuYWJsZWQ7XG4gIH0sXG5cbiAgaXNFbmFibGVkOiBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gUmVhY3RFdmVudExpc3RlbmVyLl9lbmFibGVkO1xuICB9LFxuXG5cbiAgLyoqXG4gICAqIFRyYXBzIHRvcC1sZXZlbCBldmVudHMgYnkgdXNpbmcgZXZlbnQgYnViYmxpbmcuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0b3BMZXZlbFR5cGUgUmVjb3JkIGZyb20gYEV2ZW50Q29uc3RhbnRzYC5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGhhbmRsZXJCYXNlTmFtZSBFdmVudCBuYW1lIChlLmcuIFwiY2xpY2tcIikuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBoYW5kbGUgRWxlbWVudCBvbiB3aGljaCB0byBhdHRhY2ggbGlzdGVuZXIuXG4gICAqIEByZXR1cm4ge29iamVjdH0gQW4gb2JqZWN0IHdpdGggYSByZW1vdmUgZnVuY3Rpb24gd2hpY2ggd2lsbCBmb3JjZWZ1bGx5XG4gICAqICAgICAgICAgICAgICAgICAgcmVtb3ZlIHRoZSBsaXN0ZW5lci5cbiAgICogQGludGVybmFsXG4gICAqL1xuICB0cmFwQnViYmxlZEV2ZW50OiBmdW5jdGlvbih0b3BMZXZlbFR5cGUsIGhhbmRsZXJCYXNlTmFtZSwgaGFuZGxlKSB7XG4gICAgdmFyIGVsZW1lbnQgPSBoYW5kbGU7XG4gICAgaWYgKCFlbGVtZW50KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHJldHVybiBFdmVudExpc3RlbmVyLmxpc3RlbihcbiAgICAgIGVsZW1lbnQsXG4gICAgICBoYW5kbGVyQmFzZU5hbWUsXG4gICAgICBSZWFjdEV2ZW50TGlzdGVuZXIuZGlzcGF0Y2hFdmVudC5iaW5kKG51bGwsIHRvcExldmVsVHlwZSlcbiAgICApO1xuICB9LFxuXG4gIC8qKlxuICAgKiBUcmFwcyBhIHRvcC1sZXZlbCBldmVudCBieSB1c2luZyBldmVudCBjYXB0dXJpbmcuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0b3BMZXZlbFR5cGUgUmVjb3JkIGZyb20gYEV2ZW50Q29uc3RhbnRzYC5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGhhbmRsZXJCYXNlTmFtZSBFdmVudCBuYW1lIChlLmcuIFwiY2xpY2tcIikuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBoYW5kbGUgRWxlbWVudCBvbiB3aGljaCB0byBhdHRhY2ggbGlzdGVuZXIuXG4gICAqIEByZXR1cm4ge29iamVjdH0gQW4gb2JqZWN0IHdpdGggYSByZW1vdmUgZnVuY3Rpb24gd2hpY2ggd2lsbCBmb3JjZWZ1bGx5XG4gICAqICAgICAgICAgICAgICAgICAgcmVtb3ZlIHRoZSBsaXN0ZW5lci5cbiAgICogQGludGVybmFsXG4gICAqL1xuICB0cmFwQ2FwdHVyZWRFdmVudDogZnVuY3Rpb24odG9wTGV2ZWxUeXBlLCBoYW5kbGVyQmFzZU5hbWUsIGhhbmRsZSkge1xuICAgIHZhciBlbGVtZW50ID0gaGFuZGxlO1xuICAgIGlmICghZWxlbWVudCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICByZXR1cm4gRXZlbnRMaXN0ZW5lci5jYXB0dXJlKFxuICAgICAgZWxlbWVudCxcbiAgICAgIGhhbmRsZXJCYXNlTmFtZSxcbiAgICAgIFJlYWN0RXZlbnRMaXN0ZW5lci5kaXNwYXRjaEV2ZW50LmJpbmQobnVsbCwgdG9wTGV2ZWxUeXBlKVxuICAgICk7XG4gIH0sXG5cbiAgbW9uaXRvclNjcm9sbFZhbHVlOiBmdW5jdGlvbihyZWZyZXNoKSB7XG4gICAgdmFyIGNhbGxiYWNrID0gc2Nyb2xsVmFsdWVNb25pdG9yLmJpbmQobnVsbCwgcmVmcmVzaCk7XG4gICAgRXZlbnRMaXN0ZW5lci5saXN0ZW4od2luZG93LCAnc2Nyb2xsJywgY2FsbGJhY2spO1xuICAgIEV2ZW50TGlzdGVuZXIubGlzdGVuKHdpbmRvdywgJ3Jlc2l6ZScsIGNhbGxiYWNrKTtcbiAgfSxcblxuICBkaXNwYXRjaEV2ZW50OiBmdW5jdGlvbih0b3BMZXZlbFR5cGUsIG5hdGl2ZUV2ZW50KSB7XG4gICAgaWYgKCFSZWFjdEV2ZW50TGlzdGVuZXIuX2VuYWJsZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgYm9va0tlZXBpbmcgPSBUb3BMZXZlbENhbGxiYWNrQm9va0tlZXBpbmcuZ2V0UG9vbGVkKFxuICAgICAgdG9wTGV2ZWxUeXBlLFxuICAgICAgbmF0aXZlRXZlbnRcbiAgICApO1xuICAgIHRyeSB7XG4gICAgICAvLyBFdmVudCBxdWV1ZSBiZWluZyBwcm9jZXNzZWQgaW4gdGhlIHNhbWUgY3ljbGUgYWxsb3dzXG4gICAgICAvLyBgcHJldmVudERlZmF1bHRgLlxuICAgICAgUmVhY3RVcGRhdGVzLmJhdGNoZWRVcGRhdGVzKGhhbmRsZVRvcExldmVsSW1wbCwgYm9va0tlZXBpbmcpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBUb3BMZXZlbENhbGxiYWNrQm9va0tlZXBpbmcucmVsZWFzZShib29rS2VlcGluZyk7XG4gICAgfVxuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0RXZlbnRMaXN0ZW5lcjtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdEluamVjdGlvblxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgRE9NUHJvcGVydHkgPSByZXF1aXJlKFwiLi9ET01Qcm9wZXJ0eVwiKTtcbnZhciBFdmVudFBsdWdpbkh1YiA9IHJlcXVpcmUoXCIuL0V2ZW50UGx1Z2luSHViXCIpO1xudmFyIFJlYWN0Q29tcG9uZW50ID0gcmVxdWlyZShcIi4vUmVhY3RDb21wb25lbnRcIik7XG52YXIgUmVhY3RDb21wb3NpdGVDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdENvbXBvc2l0ZUNvbXBvbmVudFwiKTtcbnZhciBSZWFjdEVtcHR5Q29tcG9uZW50ID0gcmVxdWlyZShcIi4vUmVhY3RFbXB0eUNvbXBvbmVudFwiKTtcbnZhciBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIgPSByZXF1aXJlKFwiLi9SZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXJcIik7XG52YXIgUmVhY3ROYXRpdmVDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdE5hdGl2ZUNvbXBvbmVudFwiKTtcbnZhciBSZWFjdFBlcmYgPSByZXF1aXJlKFwiLi9SZWFjdFBlcmZcIik7XG52YXIgUmVhY3RSb290SW5kZXggPSByZXF1aXJlKFwiLi9SZWFjdFJvb3RJbmRleFwiKTtcbnZhciBSZWFjdFVwZGF0ZXMgPSByZXF1aXJlKFwiLi9SZWFjdFVwZGF0ZXNcIik7XG5cbnZhciBSZWFjdEluamVjdGlvbiA9IHtcbiAgQ29tcG9uZW50OiBSZWFjdENvbXBvbmVudC5pbmplY3Rpb24sXG4gIENvbXBvc2l0ZUNvbXBvbmVudDogUmVhY3RDb21wb3NpdGVDb21wb25lbnQuaW5qZWN0aW9uLFxuICBET01Qcm9wZXJ0eTogRE9NUHJvcGVydHkuaW5qZWN0aW9uLFxuICBFbXB0eUNvbXBvbmVudDogUmVhY3RFbXB0eUNvbXBvbmVudC5pbmplY3Rpb24sXG4gIEV2ZW50UGx1Z2luSHViOiBFdmVudFBsdWdpbkh1Yi5pbmplY3Rpb24sXG4gIEV2ZW50RW1pdHRlcjogUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLmluamVjdGlvbixcbiAgTmF0aXZlQ29tcG9uZW50OiBSZWFjdE5hdGl2ZUNvbXBvbmVudC5pbmplY3Rpb24sXG4gIFBlcmY6IFJlYWN0UGVyZi5pbmplY3Rpb24sXG4gIFJvb3RJbmRleDogUmVhY3RSb290SW5kZXguaW5qZWN0aW9uLFxuICBVcGRhdGVzOiBSZWFjdFVwZGF0ZXMuaW5qZWN0aW9uXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0SW5qZWN0aW9uO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0SW5wdXRTZWxlY3Rpb25cbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFJlYWN0RE9NU2VsZWN0aW9uID0gcmVxdWlyZShcIi4vUmVhY3RET01TZWxlY3Rpb25cIik7XG5cbnZhciBjb250YWluc05vZGUgPSByZXF1aXJlKFwiLi9jb250YWluc05vZGVcIik7XG52YXIgZm9jdXNOb2RlID0gcmVxdWlyZShcIi4vZm9jdXNOb2RlXCIpO1xudmFyIGdldEFjdGl2ZUVsZW1lbnQgPSByZXF1aXJlKFwiLi9nZXRBY3RpdmVFbGVtZW50XCIpO1xuXG5mdW5jdGlvbiBpc0luRG9jdW1lbnQobm9kZSkge1xuICByZXR1cm4gY29udGFpbnNOb2RlKGRvY3VtZW50LmRvY3VtZW50RWxlbWVudCwgbm9kZSk7XG59XG5cbi8qKlxuICogQFJlYWN0SW5wdXRTZWxlY3Rpb246IFJlYWN0IGlucHV0IHNlbGVjdGlvbiBtb2R1bGUuIEJhc2VkIG9uIFNlbGVjdGlvbi5qcyxcbiAqIGJ1dCBtb2RpZmllZCB0byBiZSBzdWl0YWJsZSBmb3IgcmVhY3QgYW5kIGhhcyBhIGNvdXBsZSBvZiBidWcgZml4ZXMgKGRvZXNuJ3RcbiAqIGFzc3VtZSBidXR0b25zIGhhdmUgcmFuZ2Ugc2VsZWN0aW9ucyBhbGxvd2VkKS5cbiAqIElucHV0IHNlbGVjdGlvbiBtb2R1bGUgZm9yIFJlYWN0LlxuICovXG52YXIgUmVhY3RJbnB1dFNlbGVjdGlvbiA9IHtcblxuICBoYXNTZWxlY3Rpb25DYXBhYmlsaXRpZXM6IGZ1bmN0aW9uKGVsZW0pIHtcbiAgICByZXR1cm4gZWxlbSAmJiAoXG4gICAgICAoZWxlbS5ub2RlTmFtZSA9PT0gJ0lOUFVUJyAmJiBlbGVtLnR5cGUgPT09ICd0ZXh0JykgfHxcbiAgICAgIGVsZW0ubm9kZU5hbWUgPT09ICdURVhUQVJFQScgfHxcbiAgICAgIGVsZW0uY29udGVudEVkaXRhYmxlID09PSAndHJ1ZSdcbiAgICApO1xuICB9LFxuXG4gIGdldFNlbGVjdGlvbkluZm9ybWF0aW9uOiBmdW5jdGlvbigpIHtcbiAgICB2YXIgZm9jdXNlZEVsZW0gPSBnZXRBY3RpdmVFbGVtZW50KCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGZvY3VzZWRFbGVtOiBmb2N1c2VkRWxlbSxcbiAgICAgIHNlbGVjdGlvblJhbmdlOlxuICAgICAgICAgIFJlYWN0SW5wdXRTZWxlY3Rpb24uaGFzU2VsZWN0aW9uQ2FwYWJpbGl0aWVzKGZvY3VzZWRFbGVtKSA/XG4gICAgICAgICAgUmVhY3RJbnB1dFNlbGVjdGlvbi5nZXRTZWxlY3Rpb24oZm9jdXNlZEVsZW0pIDpcbiAgICAgICAgICBudWxsXG4gICAgfTtcbiAgfSxcblxuICAvKipcbiAgICogQHJlc3RvcmVTZWxlY3Rpb246IElmIGFueSBzZWxlY3Rpb24gaW5mb3JtYXRpb24gd2FzIHBvdGVudGlhbGx5IGxvc3QsXG4gICAqIHJlc3RvcmUgaXQuIFRoaXMgaXMgdXNlZnVsIHdoZW4gcGVyZm9ybWluZyBvcGVyYXRpb25zIHRoYXQgY291bGQgcmVtb3ZlIGRvbVxuICAgKiBub2RlcyBhbmQgcGxhY2UgdGhlbSBiYWNrIGluLCByZXN1bHRpbmcgaW4gZm9jdXMgYmVpbmcgbG9zdC5cbiAgICovXG4gIHJlc3RvcmVTZWxlY3Rpb246IGZ1bmN0aW9uKHByaW9yU2VsZWN0aW9uSW5mb3JtYXRpb24pIHtcbiAgICB2YXIgY3VyRm9jdXNlZEVsZW0gPSBnZXRBY3RpdmVFbGVtZW50KCk7XG4gICAgdmFyIHByaW9yRm9jdXNlZEVsZW0gPSBwcmlvclNlbGVjdGlvbkluZm9ybWF0aW9uLmZvY3VzZWRFbGVtO1xuICAgIHZhciBwcmlvclNlbGVjdGlvblJhbmdlID0gcHJpb3JTZWxlY3Rpb25JbmZvcm1hdGlvbi5zZWxlY3Rpb25SYW5nZTtcbiAgICBpZiAoY3VyRm9jdXNlZEVsZW0gIT09IHByaW9yRm9jdXNlZEVsZW0gJiZcbiAgICAgICAgaXNJbkRvY3VtZW50KHByaW9yRm9jdXNlZEVsZW0pKSB7XG4gICAgICBpZiAoUmVhY3RJbnB1dFNlbGVjdGlvbi5oYXNTZWxlY3Rpb25DYXBhYmlsaXRpZXMocHJpb3JGb2N1c2VkRWxlbSkpIHtcbiAgICAgICAgUmVhY3RJbnB1dFNlbGVjdGlvbi5zZXRTZWxlY3Rpb24oXG4gICAgICAgICAgcHJpb3JGb2N1c2VkRWxlbSxcbiAgICAgICAgICBwcmlvclNlbGVjdGlvblJhbmdlXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICBmb2N1c05vZGUocHJpb3JGb2N1c2VkRWxlbSk7XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBAZ2V0U2VsZWN0aW9uOiBHZXRzIHRoZSBzZWxlY3Rpb24gYm91bmRzIG9mIGEgZm9jdXNlZCB0ZXh0YXJlYSwgaW5wdXQgb3JcbiAgICogY29udGVudEVkaXRhYmxlIG5vZGUuXG4gICAqIC1AaW5wdXQ6IExvb2sgdXAgc2VsZWN0aW9uIGJvdW5kcyBvZiB0aGlzIGlucHV0XG4gICAqIC1AcmV0dXJuIHtzdGFydDogc2VsZWN0aW9uU3RhcnQsIGVuZDogc2VsZWN0aW9uRW5kfVxuICAgKi9cbiAgZ2V0U2VsZWN0aW9uOiBmdW5jdGlvbihpbnB1dCkge1xuICAgIHZhciBzZWxlY3Rpb247XG5cbiAgICBpZiAoJ3NlbGVjdGlvblN0YXJ0JyBpbiBpbnB1dCkge1xuICAgICAgLy8gTW9kZXJuIGJyb3dzZXIgd2l0aCBpbnB1dCBvciB0ZXh0YXJlYS5cbiAgICAgIHNlbGVjdGlvbiA9IHtcbiAgICAgICAgc3RhcnQ6IGlucHV0LnNlbGVjdGlvblN0YXJ0LFxuICAgICAgICBlbmQ6IGlucHV0LnNlbGVjdGlvbkVuZFxuICAgICAgfTtcbiAgICB9IGVsc2UgaWYgKGRvY3VtZW50LnNlbGVjdGlvbiAmJiBpbnB1dC5ub2RlTmFtZSA9PT0gJ0lOUFVUJykge1xuICAgICAgLy8gSUU4IGlucHV0LlxuICAgICAgdmFyIHJhbmdlID0gZG9jdW1lbnQuc2VsZWN0aW9uLmNyZWF0ZVJhbmdlKCk7XG4gICAgICAvLyBUaGVyZSBjYW4gb25seSBiZSBvbmUgc2VsZWN0aW9uIHBlciBkb2N1bWVudCBpbiBJRSwgc28gaXQgbXVzdFxuICAgICAgLy8gYmUgaW4gb3VyIGVsZW1lbnQuXG4gICAgICBpZiAocmFuZ2UucGFyZW50RWxlbWVudCgpID09PSBpbnB1dCkge1xuICAgICAgICBzZWxlY3Rpb24gPSB7XG4gICAgICAgICAgc3RhcnQ6IC1yYW5nZS5tb3ZlU3RhcnQoJ2NoYXJhY3RlcicsIC1pbnB1dC52YWx1ZS5sZW5ndGgpLFxuICAgICAgICAgIGVuZDogLXJhbmdlLm1vdmVFbmQoJ2NoYXJhY3RlcicsIC1pbnB1dC52YWx1ZS5sZW5ndGgpXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIENvbnRlbnQgZWRpdGFibGUgb3Igb2xkIElFIHRleHRhcmVhLlxuICAgICAgc2VsZWN0aW9uID0gUmVhY3RET01TZWxlY3Rpb24uZ2V0T2Zmc2V0cyhpbnB1dCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHNlbGVjdGlvbiB8fCB7c3RhcnQ6IDAsIGVuZDogMH07XG4gIH0sXG5cbiAgLyoqXG4gICAqIEBzZXRTZWxlY3Rpb246IFNldHMgdGhlIHNlbGVjdGlvbiBib3VuZHMgb2YgYSB0ZXh0YXJlYSBvciBpbnB1dCBhbmQgZm9jdXNlc1xuICAgKiB0aGUgaW5wdXQuXG4gICAqIC1AaW5wdXQgICAgIFNldCBzZWxlY3Rpb24gYm91bmRzIG9mIHRoaXMgaW5wdXQgb3IgdGV4dGFyZWFcbiAgICogLUBvZmZzZXRzICAgT2JqZWN0IG9mIHNhbWUgZm9ybSB0aGF0IGlzIHJldHVybmVkIGZyb20gZ2V0KlxuICAgKi9cbiAgc2V0U2VsZWN0aW9uOiBmdW5jdGlvbihpbnB1dCwgb2Zmc2V0cykge1xuICAgIHZhciBzdGFydCA9IG9mZnNldHMuc3RhcnQ7XG4gICAgdmFyIGVuZCA9IG9mZnNldHMuZW5kO1xuICAgIGlmICh0eXBlb2YgZW5kID09PSAndW5kZWZpbmVkJykge1xuICAgICAgZW5kID0gc3RhcnQ7XG4gICAgfVxuXG4gICAgaWYgKCdzZWxlY3Rpb25TdGFydCcgaW4gaW5wdXQpIHtcbiAgICAgIGlucHV0LnNlbGVjdGlvblN0YXJ0ID0gc3RhcnQ7XG4gICAgICBpbnB1dC5zZWxlY3Rpb25FbmQgPSBNYXRoLm1pbihlbmQsIGlucHV0LnZhbHVlLmxlbmd0aCk7XG4gICAgfSBlbHNlIGlmIChkb2N1bWVudC5zZWxlY3Rpb24gJiYgaW5wdXQubm9kZU5hbWUgPT09ICdJTlBVVCcpIHtcbiAgICAgIHZhciByYW5nZSA9IGlucHV0LmNyZWF0ZVRleHRSYW5nZSgpO1xuICAgICAgcmFuZ2UuY29sbGFwc2UodHJ1ZSk7XG4gICAgICByYW5nZS5tb3ZlU3RhcnQoJ2NoYXJhY3RlcicsIHN0YXJ0KTtcbiAgICAgIHJhbmdlLm1vdmVFbmQoJ2NoYXJhY3RlcicsIGVuZCAtIHN0YXJ0KTtcbiAgICAgIHJhbmdlLnNlbGVjdCgpO1xuICAgIH0gZWxzZSB7XG4gICAgICBSZWFjdERPTVNlbGVjdGlvbi5zZXRPZmZzZXRzKGlucHV0LCBvZmZzZXRzKTtcbiAgICB9XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RJbnB1dFNlbGVjdGlvbjtcbiIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RJbnN0YW5jZUhhbmRsZXNcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBSZWFjdFJvb3RJbmRleCA9IHJlcXVpcmUoXCIuL1JlYWN0Um9vdEluZGV4XCIpO1xuXG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG52YXIgU0VQQVJBVE9SID0gJy4nO1xudmFyIFNFUEFSQVRPUl9MRU5HVEggPSBTRVBBUkFUT1IubGVuZ3RoO1xuXG4vKipcbiAqIE1heGltdW0gZGVwdGggb2YgdHJhdmVyc2FscyBiZWZvcmUgd2UgY29uc2lkZXIgdGhlIHBvc3NpYmlsaXR5IG9mIGEgYmFkIElELlxuICovXG52YXIgTUFYX1RSRUVfREVQVEggPSAxMDA7XG5cbi8qKlxuICogQ3JlYXRlcyBhIERPTSBJRCBwcmVmaXggdG8gdXNlIHdoZW4gbW91bnRpbmcgUmVhY3QgY29tcG9uZW50cy5cbiAqXG4gKiBAcGFyYW0ge251bWJlcn0gaW5kZXggQSB1bmlxdWUgaW50ZWdlclxuICogQHJldHVybiB7c3RyaW5nfSBSZWFjdCByb290IElELlxuICogQGludGVybmFsXG4gKi9cbmZ1bmN0aW9uIGdldFJlYWN0Um9vdElEU3RyaW5nKGluZGV4KSB7XG4gIHJldHVybiBTRVBBUkFUT1IgKyBpbmRleC50b1N0cmluZygzNik7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIGEgY2hhcmFjdGVyIGluIHRoZSBzdXBwbGllZCBJRCBpcyBhIHNlcGFyYXRvciBvciB0aGUgZW5kLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBpZCBBIFJlYWN0IERPTSBJRC5cbiAqIEBwYXJhbSB7bnVtYmVyfSBpbmRleCBJbmRleCBvZiB0aGUgY2hhcmFjdGVyIHRvIGNoZWNrLlxuICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgY2hhcmFjdGVyIGlzIGEgc2VwYXJhdG9yIG9yIGVuZCBvZiB0aGUgSUQuXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBpc0JvdW5kYXJ5KGlkLCBpbmRleCkge1xuICByZXR1cm4gaWQuY2hhckF0KGluZGV4KSA9PT0gU0VQQVJBVE9SIHx8IGluZGV4ID09PSBpZC5sZW5ndGg7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIHRoZSBzdXBwbGllZCBzdHJpbmcgaXMgYSB2YWxpZCBSZWFjdCBET00gSUQuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGlkIEEgUmVhY3QgRE9NIElELCBtYXliZS5cbiAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgdGhlIHN0cmluZyBpcyBhIHZhbGlkIFJlYWN0IERPTSBJRC5cbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIGlzVmFsaWRJRChpZCkge1xuICByZXR1cm4gaWQgPT09ICcnIHx8IChcbiAgICBpZC5jaGFyQXQoMCkgPT09IFNFUEFSQVRPUiAmJiBpZC5jaGFyQXQoaWQubGVuZ3RoIC0gMSkgIT09IFNFUEFSQVRPUlxuICApO1xufVxuXG4vKipcbiAqIENoZWNrcyBpZiB0aGUgZmlyc3QgSUQgaXMgYW4gYW5jZXN0b3Igb2Ygb3IgZXF1YWwgdG8gdGhlIHNlY29uZCBJRC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gYW5jZXN0b3JJRFxuICogQHBhcmFtIHtzdHJpbmd9IGRlc2NlbmRhbnRJRFxuICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiBgYW5jZXN0b3JJRGAgaXMgYW4gYW5jZXN0b3Igb2YgYGRlc2NlbmRhbnRJRGAuXG4gKiBAaW50ZXJuYWxcbiAqL1xuZnVuY3Rpb24gaXNBbmNlc3RvcklET2YoYW5jZXN0b3JJRCwgZGVzY2VuZGFudElEKSB7XG4gIHJldHVybiAoXG4gICAgZGVzY2VuZGFudElELmluZGV4T2YoYW5jZXN0b3JJRCkgPT09IDAgJiZcbiAgICBpc0JvdW5kYXJ5KGRlc2NlbmRhbnRJRCwgYW5jZXN0b3JJRC5sZW5ndGgpXG4gICk7XG59XG5cbi8qKlxuICogR2V0cyB0aGUgcGFyZW50IElEIG9mIHRoZSBzdXBwbGllZCBSZWFjdCBET00gSUQsIGBpZGAuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGlkIElEIG9mIGEgY29tcG9uZW50LlxuICogQHJldHVybiB7c3RyaW5nfSBJRCBvZiB0aGUgcGFyZW50LCBvciBhbiBlbXB0eSBzdHJpbmcuXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBnZXRQYXJlbnRJRChpZCkge1xuICByZXR1cm4gaWQgPyBpZC5zdWJzdHIoMCwgaWQubGFzdEluZGV4T2YoU0VQQVJBVE9SKSkgOiAnJztcbn1cblxuLyoqXG4gKiBHZXRzIHRoZSBuZXh0IERPTSBJRCBvbiB0aGUgdHJlZSBwYXRoIGZyb20gdGhlIHN1cHBsaWVkIGBhbmNlc3RvcklEYCB0byB0aGVcbiAqIHN1cHBsaWVkIGBkZXN0aW5hdGlvbklEYC4gSWYgdGhleSBhcmUgZXF1YWwsIHRoZSBJRCBpcyByZXR1cm5lZC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gYW5jZXN0b3JJRCBJRCBvZiBhbiBhbmNlc3RvciBub2RlIG9mIGBkZXN0aW5hdGlvbklEYC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBkZXN0aW5hdGlvbklEIElEIG9mIHRoZSBkZXN0aW5hdGlvbiBub2RlLlxuICogQHJldHVybiB7c3RyaW5nfSBOZXh0IElEIG9uIHRoZSBwYXRoIGZyb20gYGFuY2VzdG9ySURgIHRvIGBkZXN0aW5hdGlvbklEYC5cbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIGdldE5leHREZXNjZW5kYW50SUQoYW5jZXN0b3JJRCwgZGVzdGluYXRpb25JRCkge1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgIGlzVmFsaWRJRChhbmNlc3RvcklEKSAmJiBpc1ZhbGlkSUQoZGVzdGluYXRpb25JRCksXG4gICAgJ2dldE5leHREZXNjZW5kYW50SUQoJXMsICVzKTogUmVjZWl2ZWQgYW4gaW52YWxpZCBSZWFjdCBET00gSUQuJyxcbiAgICBhbmNlc3RvcklELFxuICAgIGRlc3RpbmF0aW9uSURcbiAgKSA6IGludmFyaWFudChpc1ZhbGlkSUQoYW5jZXN0b3JJRCkgJiYgaXNWYWxpZElEKGRlc3RpbmF0aW9uSUQpKSk7XG4gIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgaXNBbmNlc3RvcklET2YoYW5jZXN0b3JJRCwgZGVzdGluYXRpb25JRCksXG4gICAgJ2dldE5leHREZXNjZW5kYW50SUQoLi4uKTogUmVhY3QgaGFzIG1hZGUgYW4gaW52YWxpZCBhc3N1bXB0aW9uIGFib3V0ICcgK1xuICAgICd0aGUgRE9NIGhpZXJhcmNoeS4gRXhwZWN0ZWQgYCVzYCB0byBiZSBhbiBhbmNlc3RvciBvZiBgJXNgLicsXG4gICAgYW5jZXN0b3JJRCxcbiAgICBkZXN0aW5hdGlvbklEXG4gICkgOiBpbnZhcmlhbnQoaXNBbmNlc3RvcklET2YoYW5jZXN0b3JJRCwgZGVzdGluYXRpb25JRCkpKTtcbiAgaWYgKGFuY2VzdG9ySUQgPT09IGRlc3RpbmF0aW9uSUQpIHtcbiAgICByZXR1cm4gYW5jZXN0b3JJRDtcbiAgfVxuICAvLyBTa2lwIG92ZXIgdGhlIGFuY2VzdG9yIGFuZCB0aGUgaW1tZWRpYXRlIHNlcGFyYXRvci4gVHJhdmVyc2UgdW50aWwgd2UgaGl0XG4gIC8vIGFub3RoZXIgc2VwYXJhdG9yIG9yIHdlIHJlYWNoIHRoZSBlbmQgb2YgYGRlc3RpbmF0aW9uSURgLlxuICB2YXIgc3RhcnQgPSBhbmNlc3RvcklELmxlbmd0aCArIFNFUEFSQVRPUl9MRU5HVEg7XG4gIGZvciAodmFyIGkgPSBzdGFydDsgaSA8IGRlc3RpbmF0aW9uSUQubGVuZ3RoOyBpKyspIHtcbiAgICBpZiAoaXNCb3VuZGFyeShkZXN0aW5hdGlvbklELCBpKSkge1xuICAgICAgYnJlYWs7XG4gICAgfVxuICB9XG4gIHJldHVybiBkZXN0aW5hdGlvbklELnN1YnN0cigwLCBpKTtcbn1cblxuLyoqXG4gKiBHZXRzIHRoZSBuZWFyZXN0IGNvbW1vbiBhbmNlc3RvciBJRCBvZiB0d28gSURzLlxuICpcbiAqIFVzaW5nIHRoaXMgSUQgc2NoZW1lLCB0aGUgbmVhcmVzdCBjb21tb24gYW5jZXN0b3IgSUQgaXMgdGhlIGxvbmdlc3QgY29tbW9uXG4gKiBwcmVmaXggb2YgdGhlIHR3byBJRHMgdGhhdCBpbW1lZGlhdGVseSBwcmVjZWRlZCBhIFwibWFya2VyXCIgaW4gYm90aCBzdHJpbmdzLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBvbmVJRFxuICogQHBhcmFtIHtzdHJpbmd9IHR3b0lEXG4gKiBAcmV0dXJuIHtzdHJpbmd9IE5lYXJlc3QgY29tbW9uIGFuY2VzdG9yIElELCBvciB0aGUgZW1wdHkgc3RyaW5nIGlmIG5vbmUuXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBnZXRGaXJzdENvbW1vbkFuY2VzdG9ySUQob25lSUQsIHR3b0lEKSB7XG4gIHZhciBtaW5MZW5ndGggPSBNYXRoLm1pbihvbmVJRC5sZW5ndGgsIHR3b0lELmxlbmd0aCk7XG4gIGlmIChtaW5MZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gJyc7XG4gIH1cbiAgdmFyIGxhc3RDb21tb25NYXJrZXJJbmRleCA9IDA7XG4gIC8vIFVzZSBgPD1gIHRvIHRyYXZlcnNlIHVudGlsIHRoZSBcIkVPTFwiIG9mIHRoZSBzaG9ydGVyIHN0cmluZy5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPD0gbWluTGVuZ3RoOyBpKyspIHtcbiAgICBpZiAoaXNCb3VuZGFyeShvbmVJRCwgaSkgJiYgaXNCb3VuZGFyeSh0d29JRCwgaSkpIHtcbiAgICAgIGxhc3RDb21tb25NYXJrZXJJbmRleCA9IGk7XG4gICAgfSBlbHNlIGlmIChvbmVJRC5jaGFyQXQoaSkgIT09IHR3b0lELmNoYXJBdChpKSkge1xuICAgICAgYnJlYWs7XG4gICAgfVxuICB9XG4gIHZhciBsb25nZXN0Q29tbW9uSUQgPSBvbmVJRC5zdWJzdHIoMCwgbGFzdENvbW1vbk1hcmtlckluZGV4KTtcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICBpc1ZhbGlkSUQobG9uZ2VzdENvbW1vbklEKSxcbiAgICAnZ2V0Rmlyc3RDb21tb25BbmNlc3RvcklEKCVzLCAlcyk6IEV4cGVjdGVkIGEgdmFsaWQgUmVhY3QgRE9NIElEOiAlcycsXG4gICAgb25lSUQsXG4gICAgdHdvSUQsXG4gICAgbG9uZ2VzdENvbW1vbklEXG4gICkgOiBpbnZhcmlhbnQoaXNWYWxpZElEKGxvbmdlc3RDb21tb25JRCkpKTtcbiAgcmV0dXJuIGxvbmdlc3RDb21tb25JRDtcbn1cblxuLyoqXG4gKiBUcmF2ZXJzZXMgdGhlIHBhcmVudCBwYXRoIGJldHdlZW4gdHdvIElEcyAoZWl0aGVyIHVwIG9yIGRvd24pLiBUaGUgSURzIG11c3RcbiAqIG5vdCBiZSB0aGUgc2FtZSwgYW5kIHRoZXJlIG11c3QgZXhpc3QgYSBwYXJlbnQgcGF0aCBiZXR3ZWVuIHRoZW0uIElmIHRoZVxuICogY2FsbGJhY2sgcmV0dXJucyBgZmFsc2VgLCB0cmF2ZXJzYWwgaXMgc3RvcHBlZC5cbiAqXG4gKiBAcGFyYW0gez9zdHJpbmd9IHN0YXJ0IElEIGF0IHdoaWNoIHRvIHN0YXJ0IHRyYXZlcnNhbC5cbiAqIEBwYXJhbSB7P3N0cmluZ30gc3RvcCBJRCBhdCB3aGljaCB0byBlbmQgdHJhdmVyc2FsLlxuICogQHBhcmFtIHtmdW5jdGlvbn0gY2IgQ2FsbGJhY2sgdG8gaW52b2tlIGVhY2ggSUQgd2l0aC5cbiAqIEBwYXJhbSB7P2Jvb2xlYW59IHNraXBGaXJzdCBXaGV0aGVyIG9yIG5vdCB0byBza2lwIHRoZSBmaXJzdCBub2RlLlxuICogQHBhcmFtIHs/Ym9vbGVhbn0gc2tpcExhc3QgV2hldGhlciBvciBub3QgdG8gc2tpcCB0aGUgbGFzdCBub2RlLlxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gdHJhdmVyc2VQYXJlbnRQYXRoKHN0YXJ0LCBzdG9wLCBjYiwgYXJnLCBza2lwRmlyc3QsIHNraXBMYXN0KSB7XG4gIHN0YXJ0ID0gc3RhcnQgfHwgJyc7XG4gIHN0b3AgPSBzdG9wIHx8ICcnO1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgIHN0YXJ0ICE9PSBzdG9wLFxuICAgICd0cmF2ZXJzZVBhcmVudFBhdGgoLi4uKTogQ2Fubm90IHRyYXZlcnNlIGZyb20gYW5kIHRvIHRoZSBzYW1lIElELCBgJXNgLicsXG4gICAgc3RhcnRcbiAgKSA6IGludmFyaWFudChzdGFydCAhPT0gc3RvcCkpO1xuICB2YXIgdHJhdmVyc2VVcCA9IGlzQW5jZXN0b3JJRE9mKHN0b3AsIHN0YXJ0KTtcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICB0cmF2ZXJzZVVwIHx8IGlzQW5jZXN0b3JJRE9mKHN0YXJ0LCBzdG9wKSxcbiAgICAndHJhdmVyc2VQYXJlbnRQYXRoKCVzLCAlcywgLi4uKTogQ2Fubm90IHRyYXZlcnNlIGZyb20gdHdvIElEcyB0aGF0IGRvICcgK1xuICAgICdub3QgaGF2ZSBhIHBhcmVudCBwYXRoLicsXG4gICAgc3RhcnQsXG4gICAgc3RvcFxuICApIDogaW52YXJpYW50KHRyYXZlcnNlVXAgfHwgaXNBbmNlc3RvcklET2Yoc3RhcnQsIHN0b3ApKSk7XG4gIC8vIFRyYXZlcnNlIGZyb20gYHN0YXJ0YCB0byBgc3RvcGAgb25lIGRlcHRoIGF0IGEgdGltZS5cbiAgdmFyIGRlcHRoID0gMDtcbiAgdmFyIHRyYXZlcnNlID0gdHJhdmVyc2VVcCA/IGdldFBhcmVudElEIDogZ2V0TmV4dERlc2NlbmRhbnRJRDtcbiAgZm9yICh2YXIgaWQgPSBzdGFydDsgLyogdW50aWwgYnJlYWsgKi87IGlkID0gdHJhdmVyc2UoaWQsIHN0b3ApKSB7XG4gICAgdmFyIHJldDtcbiAgICBpZiAoKCFza2lwRmlyc3QgfHwgaWQgIT09IHN0YXJ0KSAmJiAoIXNraXBMYXN0IHx8IGlkICE9PSBzdG9wKSkge1xuICAgICAgcmV0ID0gY2IoaWQsIHRyYXZlcnNlVXAsIGFyZyk7XG4gICAgfVxuICAgIGlmIChyZXQgPT09IGZhbHNlIHx8IGlkID09PSBzdG9wKSB7XG4gICAgICAvLyBPbmx5IGJyZWFrIC8vYWZ0ZXIvLyB2aXNpdGluZyBgc3RvcGAuXG4gICAgICBicmVhaztcbiAgICB9XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgIGRlcHRoKysgPCBNQVhfVFJFRV9ERVBUSCxcbiAgICAgICd0cmF2ZXJzZVBhcmVudFBhdGgoJXMsICVzLCAuLi4pOiBEZXRlY3RlZCBhbiBpbmZpbml0ZSBsb29wIHdoaWxlICcgK1xuICAgICAgJ3RyYXZlcnNpbmcgdGhlIFJlYWN0IERPTSBJRCB0cmVlLiBUaGlzIG1heSBiZSBkdWUgdG8gbWFsZm9ybWVkIElEczogJXMnLFxuICAgICAgc3RhcnQsIHN0b3BcbiAgICApIDogaW52YXJpYW50KGRlcHRoKysgPCBNQVhfVFJFRV9ERVBUSCkpO1xuICB9XG59XG5cbi8qKlxuICogTWFuYWdlcyB0aGUgSURzIGFzc2lnbmVkIHRvIERPTSByZXByZXNlbnRhdGlvbnMgb2YgUmVhY3QgY29tcG9uZW50cy4gVGhpc1xuICogdXNlcyBhIHNwZWNpZmljIHNjaGVtZSBpbiBvcmRlciB0byB0cmF2ZXJzZSB0aGUgRE9NIGVmZmljaWVudGx5IChlLmcuIGluXG4gKiBvcmRlciB0byBzaW11bGF0ZSBldmVudHMpLlxuICpcbiAqIEBpbnRlcm5hbFxuICovXG52YXIgUmVhY3RJbnN0YW5jZUhhbmRsZXMgPSB7XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgYSBSZWFjdCByb290IElEXG4gICAqIEByZXR1cm4ge3N0cmluZ30gQSBSZWFjdCByb290IElELlxuICAgKi9cbiAgY3JlYXRlUmVhY3RSb290SUQ6IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiBnZXRSZWFjdFJvb3RJRFN0cmluZyhSZWFjdFJvb3RJbmRleC5jcmVhdGVSZWFjdFJvb3RJbmRleCgpKTtcbiAgfSxcblxuICAvKipcbiAgICogQ29uc3RydWN0cyBhIFJlYWN0IElEIGJ5IGpvaW5pbmcgYSByb290IElEIHdpdGggYSBuYW1lLlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gcm9vdElEIFJvb3QgSUQgb2YgYSBwYXJlbnQgY29tcG9uZW50LlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSBBIGNvbXBvbmVudCdzIG5hbWUgKGFzIGZsYXR0ZW5lZCBjaGlsZHJlbikuXG4gICAqIEByZXR1cm4ge3N0cmluZ30gQSBSZWFjdCBJRC5cbiAgICogQGludGVybmFsXG4gICAqL1xuICBjcmVhdGVSZWFjdElEOiBmdW5jdGlvbihyb290SUQsIG5hbWUpIHtcbiAgICByZXR1cm4gcm9vdElEICsgbmFtZTtcbiAgfSxcblxuICAvKipcbiAgICogR2V0cyB0aGUgRE9NIElEIG9mIHRoZSBSZWFjdCBjb21wb25lbnQgdGhhdCBpcyB0aGUgcm9vdCBvZiB0aGUgdHJlZSB0aGF0XG4gICAqIGNvbnRhaW5zIHRoZSBSZWFjdCBjb21wb25lbnQgd2l0aCB0aGUgc3VwcGxpZWQgRE9NIElELlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gaWQgRE9NIElEIG9mIGEgUmVhY3QgY29tcG9uZW50LlxuICAgKiBAcmV0dXJuIHs/c3RyaW5nfSBET00gSUQgb2YgdGhlIFJlYWN0IGNvbXBvbmVudCB0aGF0IGlzIHRoZSByb290LlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIGdldFJlYWN0Um9vdElERnJvbU5vZGVJRDogZnVuY3Rpb24oaWQpIHtcbiAgICBpZiAoaWQgJiYgaWQuY2hhckF0KDApID09PSBTRVBBUkFUT1IgJiYgaWQubGVuZ3RoID4gMSkge1xuICAgICAgdmFyIGluZGV4ID0gaWQuaW5kZXhPZihTRVBBUkFUT1IsIDEpO1xuICAgICAgcmV0dXJuIGluZGV4ID4gLTEgPyBpZC5zdWJzdHIoMCwgaW5kZXgpIDogaWQ7XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9LFxuXG4gIC8qKlxuICAgKiBUcmF2ZXJzZXMgdGhlIElEIGhpZXJhcmNoeSBhbmQgaW52b2tlcyB0aGUgc3VwcGxpZWQgYGNiYCBvbiBhbnkgSURzIHRoYXRcbiAgICogc2hvdWxkIHdvdWxkIHJlY2VpdmUgYSBgbW91c2VFbnRlcmAgb3IgYG1vdXNlTGVhdmVgIGV2ZW50LlxuICAgKlxuICAgKiBOT1RFOiBEb2VzIG5vdCBpbnZva2UgdGhlIGNhbGxiYWNrIG9uIHRoZSBuZWFyZXN0IGNvbW1vbiBhbmNlc3RvciBiZWNhdXNlXG4gICAqIG5vdGhpbmcgXCJlbnRlcmVkXCIgb3IgXCJsZWZ0XCIgdGhhdCBlbGVtZW50LlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbGVhdmVJRCBJRCBiZWluZyBsZWZ0LlxuICAgKiBAcGFyYW0ge3N0cmluZ30gZW50ZXJJRCBJRCBiZWluZyBlbnRlcmVkLlxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBjYiBDYWxsYmFjayB0byBpbnZva2Ugb24gZWFjaCBlbnRlcmVkL2xlZnQgSUQuXG4gICAqIEBwYXJhbSB7Kn0gdXBBcmcgQXJndW1lbnQgdG8gaW52b2tlIHRoZSBjYWxsYmFjayB3aXRoIG9uIGxlZnQgSURzLlxuICAgKiBAcGFyYW0geyp9IGRvd25BcmcgQXJndW1lbnQgdG8gaW52b2tlIHRoZSBjYWxsYmFjayB3aXRoIG9uIGVudGVyZWQgSURzLlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHRyYXZlcnNlRW50ZXJMZWF2ZTogZnVuY3Rpb24obGVhdmVJRCwgZW50ZXJJRCwgY2IsIHVwQXJnLCBkb3duQXJnKSB7XG4gICAgdmFyIGFuY2VzdG9ySUQgPSBnZXRGaXJzdENvbW1vbkFuY2VzdG9ySUQobGVhdmVJRCwgZW50ZXJJRCk7XG4gICAgaWYgKGFuY2VzdG9ySUQgIT09IGxlYXZlSUQpIHtcbiAgICAgIHRyYXZlcnNlUGFyZW50UGF0aChsZWF2ZUlELCBhbmNlc3RvcklELCBjYiwgdXBBcmcsIGZhbHNlLCB0cnVlKTtcbiAgICB9XG4gICAgaWYgKGFuY2VzdG9ySUQgIT09IGVudGVySUQpIHtcbiAgICAgIHRyYXZlcnNlUGFyZW50UGF0aChhbmNlc3RvcklELCBlbnRlcklELCBjYiwgZG93bkFyZywgdHJ1ZSwgZmFsc2UpO1xuICAgIH1cbiAgfSxcblxuICAvKipcbiAgICogU2ltdWxhdGVzIHRoZSB0cmF2ZXJzYWwgb2YgYSB0d28tcGhhc2UsIGNhcHR1cmUvYnViYmxlIGV2ZW50IGRpc3BhdGNoLlxuICAgKlxuICAgKiBOT1RFOiBUaGlzIHRyYXZlcnNhbCBoYXBwZW5zIG9uIElEcyB3aXRob3V0IHRvdWNoaW5nIHRoZSBET00uXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0YXJnZXRJRCBJRCBvZiB0aGUgdGFyZ2V0IG5vZGUuXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IGNiIENhbGxiYWNrIHRvIGludm9rZS5cbiAgICogQHBhcmFtIHsqfSBhcmcgQXJndW1lbnQgdG8gaW52b2tlIHRoZSBjYWxsYmFjayB3aXRoLlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHRyYXZlcnNlVHdvUGhhc2U6IGZ1bmN0aW9uKHRhcmdldElELCBjYiwgYXJnKSB7XG4gICAgaWYgKHRhcmdldElEKSB7XG4gICAgICB0cmF2ZXJzZVBhcmVudFBhdGgoJycsIHRhcmdldElELCBjYiwgYXJnLCB0cnVlLCBmYWxzZSk7XG4gICAgICB0cmF2ZXJzZVBhcmVudFBhdGgodGFyZ2V0SUQsICcnLCBjYiwgYXJnLCBmYWxzZSwgdHJ1ZSk7XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBUcmF2ZXJzZSBhIG5vZGUgSUQsIGNhbGxpbmcgdGhlIHN1cHBsaWVkIGBjYmAgZm9yIGVhY2ggYW5jZXN0b3IgSUQuIEZvclxuICAgKiBleGFtcGxlLCBwYXNzaW5nIGAuMC4kcm93LTAuMWAgd291bGQgcmVzdWx0IGluIGBjYmAgZ2V0dGluZyBjYWxsZWRcbiAgICogd2l0aCBgLjBgLCBgLjAuJHJvdy0wYCwgYW5kIGAuMC4kcm93LTAuMWAuXG4gICAqXG4gICAqIE5PVEU6IFRoaXMgdHJhdmVyc2FsIGhhcHBlbnMgb24gSURzIHdpdGhvdXQgdG91Y2hpbmcgdGhlIERPTS5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhcmdldElEIElEIG9mIHRoZSB0YXJnZXQgbm9kZS5cbiAgICogQHBhcmFtIHtmdW5jdGlvbn0gY2IgQ2FsbGJhY2sgdG8gaW52b2tlLlxuICAgKiBAcGFyYW0geyp9IGFyZyBBcmd1bWVudCB0byBpbnZva2UgdGhlIGNhbGxiYWNrIHdpdGguXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgdHJhdmVyc2VBbmNlc3RvcnM6IGZ1bmN0aW9uKHRhcmdldElELCBjYiwgYXJnKSB7XG4gICAgdHJhdmVyc2VQYXJlbnRQYXRoKCcnLCB0YXJnZXRJRCwgY2IsIGFyZywgdHJ1ZSwgZmFsc2UpO1xuICB9LFxuXG4gIC8qKlxuICAgKiBFeHBvc2VkIGZvciB1bml0IHRlc3RpbmcuXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBfZ2V0Rmlyc3RDb21tb25BbmNlc3RvcklEOiBnZXRGaXJzdENvbW1vbkFuY2VzdG9ySUQsXG5cbiAgLyoqXG4gICAqIEV4cG9zZWQgZm9yIHVuaXQgdGVzdGluZy5cbiAgICogQHByaXZhdGVcbiAgICovXG4gIF9nZXROZXh0RGVzY2VuZGFudElEOiBnZXROZXh0RGVzY2VuZGFudElELFxuXG4gIGlzQW5jZXN0b3JJRE9mOiBpc0FuY2VzdG9ySURPZixcblxuICBTRVBBUkFUT1I6IFNFUEFSQVRPUlxuXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0SW5zdGFuY2VIYW5kbGVzO1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdExlZ2FjeUVsZW1lbnRcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFJlYWN0Q3VycmVudE93bmVyID0gcmVxdWlyZShcIi4vUmVhY3RDdXJyZW50T3duZXJcIik7XG5cbnZhciBpbnZhcmlhbnQgPSByZXF1aXJlKFwiLi9pbnZhcmlhbnRcIik7XG52YXIgbW9uaXRvckNvZGVVc2UgPSByZXF1aXJlKFwiLi9tb25pdG9yQ29kZVVzZVwiKTtcbnZhciB3YXJuaW5nID0gcmVxdWlyZShcIi4vd2FybmluZ1wiKTtcblxudmFyIGxlZ2FjeUZhY3RvcnlMb2dzID0ge307XG5mdW5jdGlvbiB3YXJuRm9yTGVnYWN5RmFjdG9yeUNhbGwoKSB7XG4gIGlmICghUmVhY3RMZWdhY3lFbGVtZW50RmFjdG9yeS5faXNMZWdhY3lDYWxsV2FybmluZ0VuYWJsZWQpIHtcbiAgICByZXR1cm47XG4gIH1cbiAgdmFyIG93bmVyID0gUmVhY3RDdXJyZW50T3duZXIuY3VycmVudDtcbiAgdmFyIG5hbWUgPSBvd25lciAmJiBvd25lci5jb25zdHJ1Y3RvciA/IG93bmVyLmNvbnN0cnVjdG9yLmRpc3BsYXlOYW1lIDogJyc7XG4gIGlmICghbmFtZSkge1xuICAgIG5hbWUgPSAnU29tZXRoaW5nJztcbiAgfVxuICBpZiAobGVnYWN5RmFjdG9yeUxvZ3MuaGFzT3duUHJvcGVydHkobmFtZSkpIHtcbiAgICByZXR1cm47XG4gIH1cbiAgbGVnYWN5RmFjdG9yeUxvZ3NbbmFtZV0gPSB0cnVlO1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gd2FybmluZyhcbiAgICBmYWxzZSxcbiAgICBuYW1lICsgJyBpcyBjYWxsaW5nIGEgUmVhY3QgY29tcG9uZW50IGRpcmVjdGx5LiAnICtcbiAgICAnVXNlIGEgZmFjdG9yeSBvciBKU1ggaW5zdGVhZC4gU2VlOiBodHRwOi8vZmIubWUvcmVhY3QtbGVnYWN5ZmFjdG9yeSdcbiAgKSA6IG51bGwpO1xuICBtb25pdG9yQ29kZVVzZSgncmVhY3RfbGVnYWN5X2ZhY3RvcnlfY2FsbCcsIHsgdmVyc2lvbjogMywgbmFtZTogbmFtZSB9KTtcbn1cblxuZnVuY3Rpb24gd2FybkZvclBsYWluRnVuY3Rpb25UeXBlKHR5cGUpIHtcbiAgdmFyIGlzUmVhY3RDbGFzcyA9XG4gICAgdHlwZS5wcm90b3R5cGUgJiZcbiAgICB0eXBlb2YgdHlwZS5wcm90b3R5cGUubW91bnRDb21wb25lbnQgPT09ICdmdW5jdGlvbicgJiZcbiAgICB0eXBlb2YgdHlwZS5wcm90b3R5cGUucmVjZWl2ZUNvbXBvbmVudCA9PT0gJ2Z1bmN0aW9uJztcbiAgaWYgKGlzUmVhY3RDbGFzcykge1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyB3YXJuaW5nKFxuICAgICAgZmFsc2UsXG4gICAgICAnRGlkIG5vdCBleHBlY3QgdG8gZ2V0IGEgUmVhY3QgY2xhc3MgaGVyZS4gVXNlIGBDb21wb25lbnRgIGluc3RlYWQgJyArXG4gICAgICAnb2YgYENvbXBvbmVudC50eXBlYCBvciBgdGhpcy5jb25zdHJ1Y3RvcmAuJ1xuICAgICkgOiBudWxsKTtcbiAgfSBlbHNlIHtcbiAgICBpZiAoIXR5cGUuX3JlYWN0V2FybmVkRm9yVGhpc1R5cGUpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHR5cGUuX3JlYWN0V2FybmVkRm9yVGhpc1R5cGUgPSB0cnVlO1xuICAgICAgfSBjYXRjaCAoeCkge1xuICAgICAgICAvLyBqdXN0IGluY2FzZSB0aGlzIGlzIGEgZnJvemVuIG9iamVjdCBvciBzb21lIHNwZWNpYWwgb2JqZWN0XG4gICAgICB9XG4gICAgICBtb25pdG9yQ29kZVVzZShcbiAgICAgICAgJ3JlYWN0X25vbl9jb21wb25lbnRfaW5fanN4JyxcbiAgICAgICAgeyB2ZXJzaW9uOiAzLCBuYW1lOiB0eXBlLm5hbWUgfVxuICAgICAgKTtcbiAgICB9XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IHdhcm5pbmcoXG4gICAgICBmYWxzZSxcbiAgICAgICdUaGlzIEpTWCB1c2VzIGEgcGxhaW4gZnVuY3Rpb24uIE9ubHkgUmVhY3QgY29tcG9uZW50cyBhcmUgJyArXG4gICAgICAndmFsaWQgaW4gUmVhY3RcXCdzIEpTWCB0cmFuc2Zvcm0uJ1xuICAgICkgOiBudWxsKTtcbiAgfVxufVxuXG5mdW5jdGlvbiB3YXJuRm9yTm9uTGVnYWN5RmFjdG9yeSh0eXBlKSB7XG4gIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyB3YXJuaW5nKFxuICAgIGZhbHNlLFxuICAgICdEbyBub3QgcGFzcyBSZWFjdC5ET00uJyArIHR5cGUudHlwZSArICcgdG8gSlNYIG9yIGNyZWF0ZUZhY3RvcnkuICcgK1xuICAgICdVc2UgdGhlIHN0cmluZyBcIicgKyB0eXBlLnR5cGUgKyAnXCIgaW5zdGVhZC4nXG4gICkgOiBudWxsKTtcbn1cblxuLyoqXG4gKiBUcmFuc2ZlciBzdGF0aWMgcHJvcGVydGllcyBmcm9tIHRoZSBzb3VyY2UgdG8gdGhlIHRhcmdldC4gRnVuY3Rpb25zIGFyZVxuICogcmVib3VuZCB0byBoYXZlIHRoaXMgcmVmbGVjdCB0aGUgb3JpZ2luYWwgc291cmNlLlxuICovXG5mdW5jdGlvbiBwcm94eVN0YXRpY01ldGhvZHModGFyZ2V0LCBzb3VyY2UpIHtcbiAgaWYgKHR5cGVvZiBzb3VyY2UgIT09ICdmdW5jdGlvbicpIHtcbiAgICByZXR1cm47XG4gIH1cbiAgZm9yICh2YXIga2V5IGluIHNvdXJjZSkge1xuICAgIGlmIChzb3VyY2UuaGFzT3duUHJvcGVydHkoa2V5KSkge1xuICAgICAgdmFyIHZhbHVlID0gc291cmNlW2tleV07XG4gICAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHZhciBib3VuZCA9IHZhbHVlLmJpbmQoc291cmNlKTtcbiAgICAgICAgLy8gQ29weSBhbnkgcHJvcGVydGllcyBkZWZpbmVkIG9uIHRoZSBmdW5jdGlvbiwgc3VjaCBhcyBgaXNSZXF1aXJlZGAgb25cbiAgICAgICAgLy8gYSBQcm9wVHlwZXMgdmFsaWRhdG9yLlxuICAgICAgICBmb3IgKHZhciBrIGluIHZhbHVlKSB7XG4gICAgICAgICAgaWYgKHZhbHVlLmhhc093blByb3BlcnR5KGspKSB7XG4gICAgICAgICAgICBib3VuZFtrXSA9IHZhbHVlW2tdO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB0YXJnZXRba2V5XSA9IGJvdW5kO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGFyZ2V0W2tleV0gPSB2YWx1ZTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuLy8gV2UgdXNlIGFuIG9iamVjdCBpbnN0ZWFkIG9mIGEgYm9vbGVhbiBiZWNhdXNlIGJvb2xlYW5zIGFyZSBpZ25vcmVkIGJ5IG91clxuLy8gbW9ja2luZyBsaWJyYXJpZXMgd2hlbiB0aGVzZSBmYWN0b3JpZXMgZ2V0cyBtb2NrZWQuXG52YXIgTEVHQUNZX01BUktFUiA9IHt9O1xudmFyIE5PTl9MRUdBQ1lfTUFSS0VSID0ge307XG5cbnZhciBSZWFjdExlZ2FjeUVsZW1lbnRGYWN0b3J5ID0ge307XG5cblJlYWN0TGVnYWN5RWxlbWVudEZhY3Rvcnkud3JhcENyZWF0ZUZhY3RvcnkgPSBmdW5jdGlvbihjcmVhdGVGYWN0b3J5KSB7XG4gIHZhciBsZWdhY3lDcmVhdGVGYWN0b3J5ID0gZnVuY3Rpb24odHlwZSkge1xuICAgIGlmICh0eXBlb2YgdHlwZSAhPT0gJ2Z1bmN0aW9uJykge1xuICAgICAgLy8gTm9uLWZ1bmN0aW9uIHR5cGVzIGNhbm5vdCBiZSBsZWdhY3kgZmFjdG9yaWVzXG4gICAgICByZXR1cm4gY3JlYXRlRmFjdG9yeSh0eXBlKTtcbiAgICB9XG5cbiAgICBpZiAodHlwZS5pc1JlYWN0Tm9uTGVnYWN5RmFjdG9yeSkge1xuICAgICAgLy8gVGhpcyBpcyBwcm9iYWJseSBhIGZhY3RvcnkgY3JlYXRlZCBieSBSZWFjdERPTSB3ZSB1bndyYXAgaXQgdG8gZ2V0IHRvXG4gICAgICAvLyB0aGUgdW5kZXJseWluZyBzdHJpbmcgdHlwZS4gSXQgc2hvdWxkbid0IGhhdmUgYmVlbiBwYXNzZWQgaGVyZSBzbyB3ZVxuICAgICAgLy8gd2Fybi5cbiAgICAgIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgICAgd2FybkZvck5vbkxlZ2FjeUZhY3RvcnkodHlwZSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gY3JlYXRlRmFjdG9yeSh0eXBlLnR5cGUpO1xuICAgIH1cblxuICAgIGlmICh0eXBlLmlzUmVhY3RMZWdhY3lGYWN0b3J5KSB7XG4gICAgICAvLyBUaGlzIGlzIHByb2JhYmx5IGEgbGVnYWN5IGZhY3RvcnkgY3JlYXRlZCBieSBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudC5cbiAgICAgIC8vIFdlIHVud3JhcCBpdCB0byBnZXQgdG8gdGhlIHVuZGVybHlpbmcgY2xhc3MuXG4gICAgICByZXR1cm4gY3JlYXRlRmFjdG9yeSh0eXBlLnR5cGUpO1xuICAgIH1cblxuICAgIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgIHdhcm5Gb3JQbGFpbkZ1bmN0aW9uVHlwZSh0eXBlKTtcbiAgICB9XG5cbiAgICAvLyBVbmxlc3MgaXQncyBhIGxlZ2FjeSBmYWN0b3J5LCB0aGVuIHRoaXMgaXMgcHJvYmFibHkgYSBwbGFpbiBmdW5jdGlvbixcbiAgICAvLyB0aGF0IGlzIGV4cGVjdGluZyB0byBiZSBpbnZva2VkIGJ5IEpTWC4gV2UgY2FuIGp1c3QgcmV0dXJuIGl0IGFzIGlzLlxuICAgIHJldHVybiB0eXBlO1xuICB9O1xuICByZXR1cm4gbGVnYWN5Q3JlYXRlRmFjdG9yeTtcbn07XG5cblJlYWN0TGVnYWN5RWxlbWVudEZhY3Rvcnkud3JhcENyZWF0ZUVsZW1lbnQgPSBmdW5jdGlvbihjcmVhdGVFbGVtZW50KSB7XG4gIHZhciBsZWdhY3lDcmVhdGVFbGVtZW50ID0gZnVuY3Rpb24odHlwZSwgcHJvcHMsIGNoaWxkcmVuKSB7XG4gICAgaWYgKHR5cGVvZiB0eXBlICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAvLyBOb24tZnVuY3Rpb24gdHlwZXMgY2Fubm90IGJlIGxlZ2FjeSBmYWN0b3JpZXNcbiAgICAgIHJldHVybiBjcmVhdGVFbGVtZW50LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgfVxuXG4gICAgdmFyIGFyZ3M7XG5cbiAgICBpZiAodHlwZS5pc1JlYWN0Tm9uTGVnYWN5RmFjdG9yeSkge1xuICAgICAgLy8gVGhpcyBpcyBwcm9iYWJseSBhIGZhY3RvcnkgY3JlYXRlZCBieSBSZWFjdERPTSB3ZSB1bndyYXAgaXQgdG8gZ2V0IHRvXG4gICAgICAvLyB0aGUgdW5kZXJseWluZyBzdHJpbmcgdHlwZS4gSXQgc2hvdWxkbid0IGhhdmUgYmVlbiBwYXNzZWQgaGVyZSBzbyB3ZVxuICAgICAgLy8gd2Fybi5cbiAgICAgIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgICAgd2FybkZvck5vbkxlZ2FjeUZhY3RvcnkodHlwZSk7XG4gICAgICB9XG4gICAgICBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAwKTtcbiAgICAgIGFyZ3NbMF0gPSB0eXBlLnR5cGU7XG4gICAgICByZXR1cm4gY3JlYXRlRWxlbWVudC5hcHBseSh0aGlzLCBhcmdzKTtcbiAgICB9XG5cbiAgICBpZiAodHlwZS5pc1JlYWN0TGVnYWN5RmFjdG9yeSkge1xuICAgICAgLy8gVGhpcyBpcyBwcm9iYWJseSBhIGxlZ2FjeSBmYWN0b3J5IGNyZWF0ZWQgYnkgUmVhY3RDb21wb3NpdGVDb21wb25lbnQuXG4gICAgICAvLyBXZSB1bndyYXAgaXQgdG8gZ2V0IHRvIHRoZSB1bmRlcmx5aW5nIGNsYXNzLlxuICAgICAgaWYgKHR5cGUuX2lzTW9ja0Z1bmN0aW9uKSB7XG4gICAgICAgIC8vIElmIHRoaXMgaXMgYSBtb2NrIGZ1bmN0aW9uLCBwZW9wbGUgd2lsbCBleHBlY3QgaXQgdG8gYmUgY2FsbGVkLiBXZVxuICAgICAgICAvLyB3aWxsIGFjdHVhbGx5IGNhbGwgdGhlIG9yaWdpbmFsIG1vY2sgZmFjdG9yeSBmdW5jdGlvbiBpbnN0ZWFkLiBUaGlzXG4gICAgICAgIC8vIGZ1dHVyZSBwcm9vZnMgdW5pdCB0ZXN0aW5nIHRoYXQgYXNzdW1lIHRoYXQgdGhlc2UgYXJlIGNsYXNzZXMuXG4gICAgICAgIHR5cGUudHlwZS5fbW9ja2VkUmVhY3RDbGFzc0NvbnN0cnVjdG9yID0gdHlwZTtcbiAgICAgIH1cbiAgICAgIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDApO1xuICAgICAgYXJnc1swXSA9IHR5cGUudHlwZTtcbiAgICAgIHJldHVybiBjcmVhdGVFbGVtZW50LmFwcGx5KHRoaXMsIGFyZ3MpO1xuICAgIH1cblxuICAgIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgIHdhcm5Gb3JQbGFpbkZ1bmN0aW9uVHlwZSh0eXBlKTtcbiAgICB9XG5cbiAgICAvLyBUaGlzIGlzIGJlaW5nIGNhbGxlZCB3aXRoIGEgcGxhaW4gZnVuY3Rpb24gd2Ugc2hvdWxkIGludm9rZSBpdFxuICAgIC8vIGltbWVkaWF0ZWx5IGFzIGlmIHRoaXMgd2FzIHVzZWQgd2l0aCBsZWdhY3kgSlNYLlxuICAgIHJldHVybiB0eXBlLmFwcGx5KG51bGwsIEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSkpO1xuICB9O1xuICByZXR1cm4gbGVnYWN5Q3JlYXRlRWxlbWVudDtcbn07XG5cblJlYWN0TGVnYWN5RWxlbWVudEZhY3Rvcnkud3JhcEZhY3RvcnkgPSBmdW5jdGlvbihmYWN0b3J5KSB7XG4gIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgdHlwZW9mIGZhY3RvcnkgPT09ICdmdW5jdGlvbicsXG4gICAgJ1RoaXMgaXMgc3VwcG9zZSB0byBhY2NlcHQgYSBlbGVtZW50IGZhY3RvcnknXG4gICkgOiBpbnZhcmlhbnQodHlwZW9mIGZhY3RvcnkgPT09ICdmdW5jdGlvbicpKTtcbiAgdmFyIGxlZ2FjeUVsZW1lbnRGYWN0b3J5ID0gZnVuY3Rpb24oY29uZmlnLCBjaGlsZHJlbikge1xuICAgIC8vIFRoaXMgZmFjdG9yeSBzaG91bGQgbm90IGJlIGNhbGxlZCB3aGVuIEpTWCBpcyB1c2VkLiBVc2UgSlNYIGluc3RlYWQuXG4gICAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgd2FybkZvckxlZ2FjeUZhY3RvcnlDYWxsKCk7XG4gICAgfVxuICAgIHJldHVybiBmYWN0b3J5LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gIH07XG4gIHByb3h5U3RhdGljTWV0aG9kcyhsZWdhY3lFbGVtZW50RmFjdG9yeSwgZmFjdG9yeS50eXBlKTtcbiAgbGVnYWN5RWxlbWVudEZhY3RvcnkuaXNSZWFjdExlZ2FjeUZhY3RvcnkgPSBMRUdBQ1lfTUFSS0VSO1xuICBsZWdhY3lFbGVtZW50RmFjdG9yeS50eXBlID0gZmFjdG9yeS50eXBlO1xuICByZXR1cm4gbGVnYWN5RWxlbWVudEZhY3Rvcnk7XG59O1xuXG4vLyBUaGlzIGlzIHVzZWQgdG8gbWFyayBhIGZhY3RvcnkgdGhhdCB3aWxsIHJlbWFpbi4gRS5nLiB3ZSdyZSBhbGxvd2VkIHRvIGNhbGxcbi8vIGl0IGFzIGEgZnVuY3Rpb24uIEhvd2V2ZXIsIHlvdSdyZSBub3Qgc3VwcG9zZSB0byBwYXNzIGl0IHRvIGNyZWF0ZUVsZW1lbnRcbi8vIG9yIGNyZWF0ZUZhY3RvcnksIHNvIGl0IHdpbGwgd2FybiB5b3UgaWYgeW91IGRvLlxuUmVhY3RMZWdhY3lFbGVtZW50RmFjdG9yeS5tYXJrTm9uTGVnYWN5RmFjdG9yeSA9IGZ1bmN0aW9uKGZhY3RvcnkpIHtcbiAgZmFjdG9yeS5pc1JlYWN0Tm9uTGVnYWN5RmFjdG9yeSA9IE5PTl9MRUdBQ1lfTUFSS0VSO1xuICByZXR1cm4gZmFjdG9yeTtcbn07XG5cbi8vIENoZWNrcyBpZiBhIGZhY3RvcnkgZnVuY3Rpb24gaXMgYWN0dWFsbHkgYSBsZWdhY3kgZmFjdG9yeSBwcmV0ZW5kaW5nIHRvXG4vLyBiZSBhIGNsYXNzLlxuUmVhY3RMZWdhY3lFbGVtZW50RmFjdG9yeS5pc1ZhbGlkRmFjdG9yeSA9IGZ1bmN0aW9uKGZhY3RvcnkpIHtcbiAgLy8gVE9ETzogVGhpcyB3aWxsIGJlIHJlbW92ZWQgYW5kIG1vdmVkIGludG8gYSBjbGFzcyB2YWxpZGF0b3Igb3Igc29tZXRoaW5nLlxuICByZXR1cm4gdHlwZW9mIGZhY3RvcnkgPT09ICdmdW5jdGlvbicgJiZcbiAgICBmYWN0b3J5LmlzUmVhY3RMZWdhY3lGYWN0b3J5ID09PSBMRUdBQ1lfTUFSS0VSO1xufTtcblxuUmVhY3RMZWdhY3lFbGVtZW50RmFjdG9yeS5pc1ZhbGlkQ2xhc3MgPSBmdW5jdGlvbihmYWN0b3J5KSB7XG4gIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gd2FybmluZyhcbiAgICAgIGZhbHNlLFxuICAgICAgJ2lzVmFsaWRDbGFzcyBpcyBkZXByZWNhdGVkIGFuZCB3aWxsIGJlIHJlbW92ZWQgaW4gYSBmdXR1cmUgcmVsZWFzZS4gJyArXG4gICAgICAnVXNlIGEgbW9yZSBzcGVjaWZpYyB2YWxpZGF0b3IgaW5zdGVhZC4nXG4gICAgKSA6IG51bGwpO1xuICB9XG4gIHJldHVybiBSZWFjdExlZ2FjeUVsZW1lbnRGYWN0b3J5LmlzVmFsaWRGYWN0b3J5KGZhY3RvcnkpO1xufTtcblxuUmVhY3RMZWdhY3lFbGVtZW50RmFjdG9yeS5faXNMZWdhY3lDYWxsV2FybmluZ0VuYWJsZWQgPSB0cnVlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0TGVnYWN5RWxlbWVudEZhY3Rvcnk7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdExpbmtcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbi8qKlxuICogUmVhY3RMaW5rIGVuY2Fwc3VsYXRlcyBhIGNvbW1vbiBwYXR0ZXJuIGluIHdoaWNoIGEgY29tcG9uZW50IHdhbnRzIHRvIG1vZGlmeVxuICogYSBwcm9wIHJlY2VpdmVkIGZyb20gaXRzIHBhcmVudC4gUmVhY3RMaW5rIGFsbG93cyB0aGUgcGFyZW50IHRvIHBhc3MgZG93biBhXG4gKiB2YWx1ZSBjb3VwbGVkIHdpdGggYSBjYWxsYmFjayB0aGF0LCB3aGVuIGludm9rZWQsIGV4cHJlc3NlcyBhbiBpbnRlbnQgdG9cbiAqIG1vZGlmeSB0aGF0IHZhbHVlLiBGb3IgZXhhbXBsZTpcbiAqXG4gKiBSZWFjdC5jcmVhdGVDbGFzcyh7XG4gKiAgIGdldEluaXRpYWxTdGF0ZTogZnVuY3Rpb24oKSB7XG4gKiAgICAgcmV0dXJuIHt2YWx1ZTogJyd9O1xuICogICB9LFxuICogICByZW5kZXI6IGZ1bmN0aW9uKCkge1xuICogICAgIHZhciB2YWx1ZUxpbmsgPSBuZXcgUmVhY3RMaW5rKHRoaXMuc3RhdGUudmFsdWUsIHRoaXMuX2hhbmRsZVZhbHVlQ2hhbmdlKTtcbiAqICAgICByZXR1cm4gPGlucHV0IHZhbHVlTGluaz17dmFsdWVMaW5rfSAvPjtcbiAqICAgfSxcbiAqICAgdGhpcy5faGFuZGxlVmFsdWVDaGFuZ2U6IGZ1bmN0aW9uKG5ld1ZhbHVlKSB7XG4gKiAgICAgdGhpcy5zZXRTdGF0ZSh7dmFsdWU6IG5ld1ZhbHVlfSk7XG4gKiAgIH1cbiAqIH0pO1xuICpcbiAqIFdlIGhhdmUgcHJvdmlkZWQgc29tZSBzdWdhcnkgbWl4aW5zIHRvIG1ha2UgdGhlIGNyZWF0aW9uIGFuZFxuICogY29uc3VtcHRpb24gb2YgUmVhY3RMaW5rIGVhc2llcjsgc2VlIExpbmtlZFZhbHVlVXRpbHMgYW5kIExpbmtlZFN0YXRlTWl4aW4uXG4gKi9cblxudmFyIFJlYWN0ID0gcmVxdWlyZShcIi4vUmVhY3RcIik7XG5cbi8qKlxuICogQHBhcmFtIHsqfSB2YWx1ZSBjdXJyZW50IHZhbHVlIG9mIHRoZSBsaW5rXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSByZXF1ZXN0Q2hhbmdlIGNhbGxiYWNrIHRvIHJlcXVlc3QgYSBjaGFuZ2VcbiAqL1xuZnVuY3Rpb24gUmVhY3RMaW5rKHZhbHVlLCByZXF1ZXN0Q2hhbmdlKSB7XG4gIHRoaXMudmFsdWUgPSB2YWx1ZTtcbiAgdGhpcy5yZXF1ZXN0Q2hhbmdlID0gcmVxdWVzdENoYW5nZTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgUHJvcFR5cGUgdGhhdCBlbmZvcmNlcyB0aGUgUmVhY3RMaW5rIEFQSSBhbmQgb3B0aW9uYWxseSBjaGVja3MgdGhlXG4gKiB0eXBlIG9mIHRoZSB2YWx1ZSBiZWluZyBwYXNzZWQgaW5zaWRlIHRoZSBsaW5rLiBFeGFtcGxlOlxuICpcbiAqIE15Q29tcG9uZW50LnByb3BUeXBlcyA9IHtcbiAqICAgdGFiSW5kZXhMaW5rOiBSZWFjdExpbmsuUHJvcFR5cGVzLmxpbmsoUmVhY3QuUHJvcFR5cGVzLm51bWJlcilcbiAqIH1cbiAqL1xuZnVuY3Rpb24gY3JlYXRlTGlua1R5cGVDaGVja2VyKGxpbmtUeXBlKSB7XG4gIHZhciBzaGFwZXMgPSB7XG4gICAgdmFsdWU6IHR5cGVvZiBsaW5rVHlwZSA9PT0gJ3VuZGVmaW5lZCcgP1xuICAgICAgUmVhY3QuUHJvcFR5cGVzLmFueS5pc1JlcXVpcmVkIDpcbiAgICAgIGxpbmtUeXBlLmlzUmVxdWlyZWQsXG4gICAgcmVxdWVzdENoYW5nZTogUmVhY3QuUHJvcFR5cGVzLmZ1bmMuaXNSZXF1aXJlZFxuICB9O1xuICByZXR1cm4gUmVhY3QuUHJvcFR5cGVzLnNoYXBlKHNoYXBlcyk7XG59XG5cblJlYWN0TGluay5Qcm9wVHlwZXMgPSB7XG4gIGxpbms6IGNyZWF0ZUxpbmtUeXBlQ2hlY2tlclxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdExpbms7XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RNYXJrdXBDaGVja3N1bVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgYWRsZXIzMiA9IHJlcXVpcmUoXCIuL2FkbGVyMzJcIik7XG5cbnZhciBSZWFjdE1hcmt1cENoZWNrc3VtID0ge1xuICBDSEVDS1NVTV9BVFRSX05BTUU6ICdkYXRhLXJlYWN0LWNoZWNrc3VtJyxcblxuICAvKipcbiAgICogQHBhcmFtIHtzdHJpbmd9IG1hcmt1cCBNYXJrdXAgc3RyaW5nXG4gICAqIEByZXR1cm4ge3N0cmluZ30gTWFya3VwIHN0cmluZyB3aXRoIGNoZWNrc3VtIGF0dHJpYnV0ZSBhdHRhY2hlZFxuICAgKi9cbiAgYWRkQ2hlY2tzdW1Ub01hcmt1cDogZnVuY3Rpb24obWFya3VwKSB7XG4gICAgdmFyIGNoZWNrc3VtID0gYWRsZXIzMihtYXJrdXApO1xuICAgIHJldHVybiBtYXJrdXAucmVwbGFjZShcbiAgICAgICc+JyxcbiAgICAgICcgJyArIFJlYWN0TWFya3VwQ2hlY2tzdW0uQ0hFQ0tTVU1fQVRUUl9OQU1FICsgJz1cIicgKyBjaGVja3N1bSArICdcIj4nXG4gICAgKTtcbiAgfSxcblxuICAvKipcbiAgICogQHBhcmFtIHtzdHJpbmd9IG1hcmt1cCB0byB1c2VcbiAgICogQHBhcmFtIHtET01FbGVtZW50fSBlbGVtZW50IHJvb3QgUmVhY3QgZWxlbWVudFxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gd2hldGhlciBvciBub3QgdGhlIG1hcmt1cCBpcyB0aGUgc2FtZVxuICAgKi9cbiAgY2FuUmV1c2VNYXJrdXA6IGZ1bmN0aW9uKG1hcmt1cCwgZWxlbWVudCkge1xuICAgIHZhciBleGlzdGluZ0NoZWNrc3VtID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoXG4gICAgICBSZWFjdE1hcmt1cENoZWNrc3VtLkNIRUNLU1VNX0FUVFJfTkFNRVxuICAgICk7XG4gICAgZXhpc3RpbmdDaGVja3N1bSA9IGV4aXN0aW5nQ2hlY2tzdW0gJiYgcGFyc2VJbnQoZXhpc3RpbmdDaGVja3N1bSwgMTApO1xuICAgIHZhciBtYXJrdXBDaGVja3N1bSA9IGFkbGVyMzIobWFya3VwKTtcbiAgICByZXR1cm4gbWFya3VwQ2hlY2tzdW0gPT09IGV4aXN0aW5nQ2hlY2tzdW07XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RNYXJrdXBDaGVja3N1bTtcbiIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RNb3VudFxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgRE9NUHJvcGVydHkgPSByZXF1aXJlKFwiLi9ET01Qcm9wZXJ0eVwiKTtcbnZhciBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIgPSByZXF1aXJlKFwiLi9SZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXJcIik7XG52YXIgUmVhY3RDdXJyZW50T3duZXIgPSByZXF1aXJlKFwiLi9SZWFjdEN1cnJlbnRPd25lclwiKTtcbnZhciBSZWFjdEVsZW1lbnQgPSByZXF1aXJlKFwiLi9SZWFjdEVsZW1lbnRcIik7XG52YXIgUmVhY3RMZWdhY3lFbGVtZW50ID0gcmVxdWlyZShcIi4vUmVhY3RMZWdhY3lFbGVtZW50XCIpO1xudmFyIFJlYWN0SW5zdGFuY2VIYW5kbGVzID0gcmVxdWlyZShcIi4vUmVhY3RJbnN0YW5jZUhhbmRsZXNcIik7XG52YXIgUmVhY3RQZXJmID0gcmVxdWlyZShcIi4vUmVhY3RQZXJmXCIpO1xuXG52YXIgY29udGFpbnNOb2RlID0gcmVxdWlyZShcIi4vY29udGFpbnNOb2RlXCIpO1xudmFyIGRlcHJlY2F0ZWQgPSByZXF1aXJlKFwiLi9kZXByZWNhdGVkXCIpO1xudmFyIGdldFJlYWN0Um9vdEVsZW1lbnRJbkNvbnRhaW5lciA9IHJlcXVpcmUoXCIuL2dldFJlYWN0Um9vdEVsZW1lbnRJbkNvbnRhaW5lclwiKTtcbnZhciBpbnN0YW50aWF0ZVJlYWN0Q29tcG9uZW50ID0gcmVxdWlyZShcIi4vaW5zdGFudGlhdGVSZWFjdENvbXBvbmVudFwiKTtcbnZhciBpbnZhcmlhbnQgPSByZXF1aXJlKFwiLi9pbnZhcmlhbnRcIik7XG52YXIgc2hvdWxkVXBkYXRlUmVhY3RDb21wb25lbnQgPSByZXF1aXJlKFwiLi9zaG91bGRVcGRhdGVSZWFjdENvbXBvbmVudFwiKTtcbnZhciB3YXJuaW5nID0gcmVxdWlyZShcIi4vd2FybmluZ1wiKTtcblxudmFyIGNyZWF0ZUVsZW1lbnQgPSBSZWFjdExlZ2FjeUVsZW1lbnQud3JhcENyZWF0ZUVsZW1lbnQoXG4gIFJlYWN0RWxlbWVudC5jcmVhdGVFbGVtZW50XG4pO1xuXG52YXIgU0VQQVJBVE9SID0gUmVhY3RJbnN0YW5jZUhhbmRsZXMuU0VQQVJBVE9SO1xuXG52YXIgQVRUUl9OQU1FID0gRE9NUHJvcGVydHkuSURfQVRUUklCVVRFX05BTUU7XG52YXIgbm9kZUNhY2hlID0ge307XG5cbnZhciBFTEVNRU5UX05PREVfVFlQRSA9IDE7XG52YXIgRE9DX05PREVfVFlQRSA9IDk7XG5cbi8qKiBNYXBwaW5nIGZyb20gcmVhY3RSb290SUQgdG8gUmVhY3QgY29tcG9uZW50IGluc3RhbmNlLiAqL1xudmFyIGluc3RhbmNlc0J5UmVhY3RSb290SUQgPSB7fTtcblxuLyoqIE1hcHBpbmcgZnJvbSByZWFjdFJvb3RJRCB0byBgY29udGFpbmVyYCBub2Rlcy4gKi9cbnZhciBjb250YWluZXJzQnlSZWFjdFJvb3RJRCA9IHt9O1xuXG5pZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gIC8qKiBfX0RFVl9fLW9ubHkgbWFwcGluZyBmcm9tIHJlYWN0Um9vdElEIHRvIHJvb3QgZWxlbWVudHMuICovXG4gIHZhciByb290RWxlbWVudHNCeVJlYWN0Um9vdElEID0ge307XG59XG5cbi8vIFVzZWQgdG8gc3RvcmUgYnJlYWR0aC1maXJzdCBzZWFyY2ggc3RhdGUgaW4gZmluZENvbXBvbmVudFJvb3QuXG52YXIgZmluZENvbXBvbmVudFJvb3RSZXVzYWJsZUFycmF5ID0gW107XG5cbi8qKlxuICogQHBhcmFtIHtET01FbGVtZW50fSBjb250YWluZXIgRE9NIGVsZW1lbnQgdGhhdCBtYXkgY29udGFpbiBhIFJlYWN0IGNvbXBvbmVudC5cbiAqIEByZXR1cm4gez9zdHJpbmd9IEEgXCJyZWFjdFJvb3RcIiBJRCwgaWYgYSBSZWFjdCBjb21wb25lbnQgaXMgcmVuZGVyZWQuXG4gKi9cbmZ1bmN0aW9uIGdldFJlYWN0Um9vdElEKGNvbnRhaW5lcikge1xuICB2YXIgcm9vdEVsZW1lbnQgPSBnZXRSZWFjdFJvb3RFbGVtZW50SW5Db250YWluZXIoY29udGFpbmVyKTtcbiAgcmV0dXJuIHJvb3RFbGVtZW50ICYmIFJlYWN0TW91bnQuZ2V0SUQocm9vdEVsZW1lbnQpO1xufVxuXG4vKipcbiAqIEFjY2Vzc2luZyBub2RlW0FUVFJfTkFNRV0gb3IgY2FsbGluZyBnZXRBdHRyaWJ1dGUoQVRUUl9OQU1FKSBvbiBhIGZvcm1cbiAqIGVsZW1lbnQgY2FuIHJldHVybiBpdHMgY29udHJvbCB3aG9zZSBuYW1lIG9yIElEIGVxdWFscyBBVFRSX05BTUUuIEFsbFxuICogRE9NIG5vZGVzIHN1cHBvcnQgYGdldEF0dHJpYnV0ZU5vZGVgIGJ1dCB0aGlzIGNhbiBhbHNvIGdldCBjYWxsZWQgb25cbiAqIG90aGVyIG9iamVjdHMgc28ganVzdCByZXR1cm4gJycgaWYgd2UncmUgZ2l2ZW4gc29tZXRoaW5nIG90aGVyIHRoYW4gYVxuICogRE9NIG5vZGUgKHN1Y2ggYXMgd2luZG93KS5cbiAqXG4gKiBAcGFyYW0gez9ET01FbGVtZW50fERPTVdpbmRvd3xET01Eb2N1bWVudHxET01UZXh0Tm9kZX0gbm9kZSBET00gbm9kZS5cbiAqIEByZXR1cm4ge3N0cmluZ30gSUQgb2YgdGhlIHN1cHBsaWVkIGBkb21Ob2RlYC5cbiAqL1xuZnVuY3Rpb24gZ2V0SUQobm9kZSkge1xuICB2YXIgaWQgPSBpbnRlcm5hbEdldElEKG5vZGUpO1xuICBpZiAoaWQpIHtcbiAgICBpZiAobm9kZUNhY2hlLmhhc093blByb3BlcnR5KGlkKSkge1xuICAgICAgdmFyIGNhY2hlZCA9IG5vZGVDYWNoZVtpZF07XG4gICAgICBpZiAoY2FjaGVkICE9PSBub2RlKSB7XG4gICAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgICAgIWlzVmFsaWQoY2FjaGVkLCBpZCksXG4gICAgICAgICAgJ1JlYWN0TW91bnQ6IFR3byB2YWxpZCBidXQgdW5lcXVhbCBub2RlcyB3aXRoIHRoZSBzYW1lIGAlc2A6ICVzJyxcbiAgICAgICAgICBBVFRSX05BTUUsIGlkXG4gICAgICAgICkgOiBpbnZhcmlhbnQoIWlzVmFsaWQoY2FjaGVkLCBpZCkpKTtcblxuICAgICAgICBub2RlQ2FjaGVbaWRdID0gbm9kZTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgbm9kZUNhY2hlW2lkXSA9IG5vZGU7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGlkO1xufVxuXG5mdW5jdGlvbiBpbnRlcm5hbEdldElEKG5vZGUpIHtcbiAgLy8gSWYgbm9kZSBpcyBzb21ldGhpbmcgbGlrZSBhIHdpbmRvdywgZG9jdW1lbnQsIG9yIHRleHQgbm9kZSwgbm9uZSBvZlxuICAvLyB3aGljaCBzdXBwb3J0IGF0dHJpYnV0ZXMgb3IgYSAuZ2V0QXR0cmlidXRlIG1ldGhvZCwgZ3JhY2VmdWxseSByZXR1cm5cbiAgLy8gdGhlIGVtcHR5IHN0cmluZywgYXMgaWYgdGhlIGF0dHJpYnV0ZSB3ZXJlIG1pc3NpbmcuXG4gIHJldHVybiBub2RlICYmIG5vZGUuZ2V0QXR0cmlidXRlICYmIG5vZGUuZ2V0QXR0cmlidXRlKEFUVFJfTkFNRSkgfHwgJyc7XG59XG5cbi8qKlxuICogU2V0cyB0aGUgUmVhY3Qtc3BlY2lmaWMgSUQgb2YgdGhlIGdpdmVuIG5vZGUuXG4gKlxuICogQHBhcmFtIHtET01FbGVtZW50fSBub2RlIFRoZSBET00gbm9kZSB3aG9zZSBJRCB3aWxsIGJlIHNldC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBpZCBUaGUgdmFsdWUgb2YgdGhlIElEIGF0dHJpYnV0ZS5cbiAqL1xuZnVuY3Rpb24gc2V0SUQobm9kZSwgaWQpIHtcbiAgdmFyIG9sZElEID0gaW50ZXJuYWxHZXRJRChub2RlKTtcbiAgaWYgKG9sZElEICE9PSBpZCkge1xuICAgIGRlbGV0ZSBub2RlQ2FjaGVbb2xkSURdO1xuICB9XG4gIG5vZGUuc2V0QXR0cmlidXRlKEFUVFJfTkFNRSwgaWQpO1xuICBub2RlQ2FjaGVbaWRdID0gbm9kZTtcbn1cblxuLyoqXG4gKiBGaW5kcyB0aGUgbm9kZSB3aXRoIHRoZSBzdXBwbGllZCBSZWFjdC1nZW5lcmF0ZWQgRE9NIElELlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBpZCBBIFJlYWN0LWdlbmVyYXRlZCBET00gSUQuXG4gKiBAcmV0dXJuIHtET01FbGVtZW50fSBET00gbm9kZSB3aXRoIHRoZSBzdXBwbGVkIGBpZGAuXG4gKiBAaW50ZXJuYWxcbiAqL1xuZnVuY3Rpb24gZ2V0Tm9kZShpZCkge1xuICBpZiAoIW5vZGVDYWNoZS5oYXNPd25Qcm9wZXJ0eShpZCkgfHwgIWlzVmFsaWQobm9kZUNhY2hlW2lkXSwgaWQpKSB7XG4gICAgbm9kZUNhY2hlW2lkXSA9IFJlYWN0TW91bnQuZmluZFJlYWN0Tm9kZUJ5SUQoaWQpO1xuICB9XG4gIHJldHVybiBub2RlQ2FjaGVbaWRdO1xufVxuXG4vKipcbiAqIEEgbm9kZSBpcyBcInZhbGlkXCIgaWYgaXQgaXMgY29udGFpbmVkIGJ5IGEgY3VycmVudGx5IG1vdW50ZWQgY29udGFpbmVyLlxuICpcbiAqIFRoaXMgbWVhbnMgdGhhdCB0aGUgbm9kZSBkb2VzIG5vdCBoYXZlIHRvIGJlIGNvbnRhaW5lZCBieSBhIGRvY3VtZW50IGluXG4gKiBvcmRlciB0byBiZSBjb25zaWRlcmVkIHZhbGlkLlxuICpcbiAqIEBwYXJhbSB7P0RPTUVsZW1lbnR9IG5vZGUgVGhlIGNhbmRpZGF0ZSBET00gbm9kZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBpZCBUaGUgZXhwZWN0ZWQgSUQgb2YgdGhlIG5vZGUuXG4gKiBAcmV0dXJuIHtib29sZWFufSBXaGV0aGVyIHRoZSBub2RlIGlzIGNvbnRhaW5lZCBieSBhIG1vdW50ZWQgY29udGFpbmVyLlxuICovXG5mdW5jdGlvbiBpc1ZhbGlkKG5vZGUsIGlkKSB7XG4gIGlmIChub2RlKSB7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgIGludGVybmFsR2V0SUQobm9kZSkgPT09IGlkLFxuICAgICAgJ1JlYWN0TW91bnQ6IFVuZXhwZWN0ZWQgbW9kaWZpY2F0aW9uIG9mIGAlc2AnLFxuICAgICAgQVRUUl9OQU1FXG4gICAgKSA6IGludmFyaWFudChpbnRlcm5hbEdldElEKG5vZGUpID09PSBpZCkpO1xuXG4gICAgdmFyIGNvbnRhaW5lciA9IFJlYWN0TW91bnQuZmluZFJlYWN0Q29udGFpbmVyRm9ySUQoaWQpO1xuICAgIGlmIChjb250YWluZXIgJiYgY29udGFpbnNOb2RlKGNvbnRhaW5lciwgbm9kZSkpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBmYWxzZTtcbn1cblxuLyoqXG4gKiBDYXVzZXMgdGhlIGNhY2hlIHRvIGZvcmdldCBhYm91dCBvbmUgUmVhY3Qtc3BlY2lmaWMgSUQuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGlkIFRoZSBJRCB0byBmb3JnZXQuXG4gKi9cbmZ1bmN0aW9uIHB1cmdlSUQoaWQpIHtcbiAgZGVsZXRlIG5vZGVDYWNoZVtpZF07XG59XG5cbnZhciBkZWVwZXN0Tm9kZVNvRmFyID0gbnVsbDtcbmZ1bmN0aW9uIGZpbmREZWVwZXN0Q2FjaGVkQW5jZXN0b3JJbXBsKGFuY2VzdG9ySUQpIHtcbiAgdmFyIGFuY2VzdG9yID0gbm9kZUNhY2hlW2FuY2VzdG9ySURdO1xuICBpZiAoYW5jZXN0b3IgJiYgaXNWYWxpZChhbmNlc3RvciwgYW5jZXN0b3JJRCkpIHtcbiAgICBkZWVwZXN0Tm9kZVNvRmFyID0gYW5jZXN0b3I7XG4gIH0gZWxzZSB7XG4gICAgLy8gVGhpcyBub2RlIGlzbid0IHBvcHVsYXRlZCBpbiB0aGUgY2FjaGUsIHNvIHByZXN1bWFibHkgbm9uZSBvZiBpdHNcbiAgICAvLyBkZXNjZW5kYW50cyBhcmUuIEJyZWFrIG91dCBvZiB0aGUgbG9vcC5cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXR1cm4gdGhlIGRlZXBlc3QgY2FjaGVkIG5vZGUgd2hvc2UgSUQgaXMgYSBwcmVmaXggb2YgYHRhcmdldElEYC5cbiAqL1xuZnVuY3Rpb24gZmluZERlZXBlc3RDYWNoZWRBbmNlc3Rvcih0YXJnZXRJRCkge1xuICBkZWVwZXN0Tm9kZVNvRmFyID0gbnVsbDtcbiAgUmVhY3RJbnN0YW5jZUhhbmRsZXMudHJhdmVyc2VBbmNlc3RvcnMoXG4gICAgdGFyZ2V0SUQsXG4gICAgZmluZERlZXBlc3RDYWNoZWRBbmNlc3RvckltcGxcbiAgKTtcblxuICB2YXIgZm91bmROb2RlID0gZGVlcGVzdE5vZGVTb0ZhcjtcbiAgZGVlcGVzdE5vZGVTb0ZhciA9IG51bGw7XG4gIHJldHVybiBmb3VuZE5vZGU7XG59XG5cbi8qKlxuICogTW91bnRpbmcgaXMgdGhlIHByb2Nlc3Mgb2YgaW5pdGlhbGl6aW5nIGEgUmVhY3QgY29tcG9uZW50IGJ5IGNyZWF0aW5ncyBpdHNcbiAqIHJlcHJlc2VudGF0aXZlIERPTSBlbGVtZW50cyBhbmQgaW5zZXJ0aW5nIHRoZW0gaW50byBhIHN1cHBsaWVkIGBjb250YWluZXJgLlxuICogQW55IHByaW9yIGNvbnRlbnQgaW5zaWRlIGBjb250YWluZXJgIGlzIGRlc3Ryb3llZCBpbiB0aGUgcHJvY2Vzcy5cbiAqXG4gKiAgIFJlYWN0TW91bnQucmVuZGVyKFxuICogICAgIGNvbXBvbmVudCxcbiAqICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnY29udGFpbmVyJylcbiAqICAgKTtcbiAqXG4gKiAgIDxkaXYgaWQ9XCJjb250YWluZXJcIj4gICAgICAgICAgICAgICAgICAgPC0tIFN1cHBsaWVkIGBjb250YWluZXJgLlxuICogICAgIDxkaXYgZGF0YS1yZWFjdGlkPVwiLjNcIj4gICAgICAgICAgICAgIDwtLSBSZW5kZXJlZCByZWFjdFJvb3Qgb2YgUmVhY3RcbiAqICAgICAgIC8vIC4uLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbXBvbmVudC5cbiAqICAgICA8L2Rpdj5cbiAqICAgPC9kaXY+XG4gKlxuICogSW5zaWRlIG9mIGBjb250YWluZXJgLCB0aGUgZmlyc3QgZWxlbWVudCByZW5kZXJlZCBpcyB0aGUgXCJyZWFjdFJvb3RcIi5cbiAqL1xudmFyIFJlYWN0TW91bnQgPSB7XG4gIC8qKiBFeHBvc2VkIGZvciBkZWJ1Z2dpbmcgcHVycG9zZXMgKiovXG4gIF9pbnN0YW5jZXNCeVJlYWN0Um9vdElEOiBpbnN0YW5jZXNCeVJlYWN0Um9vdElELFxuXG4gIC8qKlxuICAgKiBUaGlzIGlzIGEgaG9vayBwcm92aWRlZCB0byBzdXBwb3J0IHJlbmRlcmluZyBSZWFjdCBjb21wb25lbnRzIHdoaWxlXG4gICAqIGVuc3VyaW5nIHRoYXQgdGhlIGFwcGFyZW50IHNjcm9sbCBwb3NpdGlvbiBvZiBpdHMgYGNvbnRhaW5lcmAgZG9lcyBub3RcbiAgICogY2hhbmdlLlxuICAgKlxuICAgKiBAcGFyYW0ge0RPTUVsZW1lbnR9IGNvbnRhaW5lciBUaGUgYGNvbnRhaW5lcmAgYmVpbmcgcmVuZGVyZWQgaW50by5cbiAgICogQHBhcmFtIHtmdW5jdGlvbn0gcmVuZGVyQ2FsbGJhY2sgVGhpcyBtdXN0IGJlIGNhbGxlZCBvbmNlIHRvIGRvIHRoZSByZW5kZXIuXG4gICAqL1xuICBzY3JvbGxNb25pdG9yOiBmdW5jdGlvbihjb250YWluZXIsIHJlbmRlckNhbGxiYWNrKSB7XG4gICAgcmVuZGVyQ2FsbGJhY2soKTtcbiAgfSxcblxuICAvKipcbiAgICogVGFrZSBhIGNvbXBvbmVudCB0aGF0J3MgYWxyZWFkeSBtb3VudGVkIGludG8gdGhlIERPTSBhbmQgcmVwbGFjZSBpdHMgcHJvcHNcbiAgICogQHBhcmFtIHtSZWFjdENvbXBvbmVudH0gcHJldkNvbXBvbmVudCBjb21wb25lbnQgaW5zdGFuY2UgYWxyZWFkeSBpbiB0aGUgRE9NXG4gICAqIEBwYXJhbSB7UmVhY3RDb21wb25lbnR9IG5leHRDb21wb25lbnQgY29tcG9uZW50IGluc3RhbmNlIHRvIHJlbmRlclxuICAgKiBAcGFyYW0ge0RPTUVsZW1lbnR9IGNvbnRhaW5lciBjb250YWluZXIgdG8gcmVuZGVyIGludG9cbiAgICogQHBhcmFtIHs/ZnVuY3Rpb259IGNhbGxiYWNrIGZ1bmN0aW9uIHRyaWdnZXJlZCBvbiBjb21wbGV0aW9uXG4gICAqL1xuICBfdXBkYXRlUm9vdENvbXBvbmVudDogZnVuY3Rpb24oXG4gICAgICBwcmV2Q29tcG9uZW50LFxuICAgICAgbmV4dENvbXBvbmVudCxcbiAgICAgIGNvbnRhaW5lcixcbiAgICAgIGNhbGxiYWNrKSB7XG4gICAgdmFyIG5leHRQcm9wcyA9IG5leHRDb21wb25lbnQucHJvcHM7XG4gICAgUmVhY3RNb3VudC5zY3JvbGxNb25pdG9yKGNvbnRhaW5lciwgZnVuY3Rpb24oKSB7XG4gICAgICBwcmV2Q29tcG9uZW50LnJlcGxhY2VQcm9wcyhuZXh0UHJvcHMsIGNhbGxiYWNrKTtcbiAgICB9KTtcblxuICAgIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgIC8vIFJlY29yZCB0aGUgcm9vdCBlbGVtZW50IGluIGNhc2UgaXQgbGF0ZXIgZ2V0cyB0cmFuc3BsYW50ZWQuXG4gICAgICByb290RWxlbWVudHNCeVJlYWN0Um9vdElEW2dldFJlYWN0Um9vdElEKGNvbnRhaW5lcildID1cbiAgICAgICAgZ2V0UmVhY3RSb290RWxlbWVudEluQ29udGFpbmVyKGNvbnRhaW5lcik7XG4gICAgfVxuXG4gICAgcmV0dXJuIHByZXZDb21wb25lbnQ7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFJlZ2lzdGVyIGEgY29tcG9uZW50IGludG8gdGhlIGluc3RhbmNlIG1hcCBhbmQgc3RhcnRzIHNjcm9sbCB2YWx1ZVxuICAgKiBtb25pdG9yaW5nXG4gICAqIEBwYXJhbSB7UmVhY3RDb21wb25lbnR9IG5leHRDb21wb25lbnQgY29tcG9uZW50IGluc3RhbmNlIHRvIHJlbmRlclxuICAgKiBAcGFyYW0ge0RPTUVsZW1lbnR9IGNvbnRhaW5lciBjb250YWluZXIgdG8gcmVuZGVyIGludG9cbiAgICogQHJldHVybiB7c3RyaW5nfSByZWFjdFJvb3QgSUQgcHJlZml4XG4gICAqL1xuICBfcmVnaXN0ZXJDb21wb25lbnQ6IGZ1bmN0aW9uKG5leHRDb21wb25lbnQsIGNvbnRhaW5lcikge1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICBjb250YWluZXIgJiYgKFxuICAgICAgICBjb250YWluZXIubm9kZVR5cGUgPT09IEVMRU1FTlRfTk9ERV9UWVBFIHx8XG4gICAgICAgIGNvbnRhaW5lci5ub2RlVHlwZSA9PT0gRE9DX05PREVfVFlQRVxuICAgICAgKSxcbiAgICAgICdfcmVnaXN0ZXJDb21wb25lbnQoLi4uKTogVGFyZ2V0IGNvbnRhaW5lciBpcyBub3QgYSBET00gZWxlbWVudC4nXG4gICAgKSA6IGludmFyaWFudChjb250YWluZXIgJiYgKFxuICAgICAgY29udGFpbmVyLm5vZGVUeXBlID09PSBFTEVNRU5UX05PREVfVFlQRSB8fFxuICAgICAgY29udGFpbmVyLm5vZGVUeXBlID09PSBET0NfTk9ERV9UWVBFXG4gICAgKSkpO1xuXG4gICAgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLmVuc3VyZVNjcm9sbFZhbHVlTW9uaXRvcmluZygpO1xuXG4gICAgdmFyIHJlYWN0Um9vdElEID0gUmVhY3RNb3VudC5yZWdpc3RlckNvbnRhaW5lcihjb250YWluZXIpO1xuICAgIGluc3RhbmNlc0J5UmVhY3RSb290SURbcmVhY3RSb290SURdID0gbmV4dENvbXBvbmVudDtcbiAgICByZXR1cm4gcmVhY3RSb290SUQ7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFJlbmRlciBhIG5ldyBjb21wb25lbnQgaW50byB0aGUgRE9NLlxuICAgKiBAcGFyYW0ge1JlYWN0Q29tcG9uZW50fSBuZXh0Q29tcG9uZW50IGNvbXBvbmVudCBpbnN0YW5jZSB0byByZW5kZXJcbiAgICogQHBhcmFtIHtET01FbGVtZW50fSBjb250YWluZXIgY29udGFpbmVyIHRvIHJlbmRlciBpbnRvXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc2hvdWxkUmV1c2VNYXJrdXAgaWYgd2Ugc2hvdWxkIHNraXAgdGhlIG1hcmt1cCBpbnNlcnRpb25cbiAgICogQHJldHVybiB7UmVhY3RDb21wb25lbnR9IG5leHRDb21wb25lbnRcbiAgICovXG4gIF9yZW5kZXJOZXdSb290Q29tcG9uZW50OiBSZWFjdFBlcmYubWVhc3VyZShcbiAgICAnUmVhY3RNb3VudCcsXG4gICAgJ19yZW5kZXJOZXdSb290Q29tcG9uZW50JyxcbiAgICBmdW5jdGlvbihcbiAgICAgICAgbmV4dENvbXBvbmVudCxcbiAgICAgICAgY29udGFpbmVyLFxuICAgICAgICBzaG91bGRSZXVzZU1hcmt1cCkge1xuICAgICAgLy8gVmFyaW91cyBwYXJ0cyBvZiBvdXIgY29kZSAoc3VjaCBhcyBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudCdzXG4gICAgICAvLyBfcmVuZGVyVmFsaWRhdGVkQ29tcG9uZW50KSBhc3N1bWUgdGhhdCBjYWxscyB0byByZW5kZXIgYXJlbid0IG5lc3RlZDtcbiAgICAgIC8vIHZlcmlmeSB0aGF0IHRoYXQncyB0aGUgY2FzZS5cbiAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyB3YXJuaW5nKFxuICAgICAgICBSZWFjdEN1cnJlbnRPd25lci5jdXJyZW50ID09IG51bGwsXG4gICAgICAgICdfcmVuZGVyTmV3Um9vdENvbXBvbmVudCgpOiBSZW5kZXIgbWV0aG9kcyBzaG91bGQgYmUgYSBwdXJlIGZ1bmN0aW9uICcgK1xuICAgICAgICAnb2YgcHJvcHMgYW5kIHN0YXRlOyB0cmlnZ2VyaW5nIG5lc3RlZCBjb21wb25lbnQgdXBkYXRlcyBmcm9tICcgK1xuICAgICAgICAncmVuZGVyIGlzIG5vdCBhbGxvd2VkLiBJZiBuZWNlc3NhcnksIHRyaWdnZXIgbmVzdGVkIHVwZGF0ZXMgaW4gJyArXG4gICAgICAgICdjb21wb25lbnREaWRVcGRhdGUuJ1xuICAgICAgKSA6IG51bGwpO1xuXG4gICAgICB2YXIgY29tcG9uZW50SW5zdGFuY2UgPSBpbnN0YW50aWF0ZVJlYWN0Q29tcG9uZW50KG5leHRDb21wb25lbnQsIG51bGwpO1xuICAgICAgdmFyIHJlYWN0Um9vdElEID0gUmVhY3RNb3VudC5fcmVnaXN0ZXJDb21wb25lbnQoXG4gICAgICAgIGNvbXBvbmVudEluc3RhbmNlLFxuICAgICAgICBjb250YWluZXJcbiAgICAgICk7XG4gICAgICBjb21wb25lbnRJbnN0YW5jZS5tb3VudENvbXBvbmVudEludG9Ob2RlKFxuICAgICAgICByZWFjdFJvb3RJRCxcbiAgICAgICAgY29udGFpbmVyLFxuICAgICAgICBzaG91bGRSZXVzZU1hcmt1cFxuICAgICAgKTtcblxuICAgICAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgICAvLyBSZWNvcmQgdGhlIHJvb3QgZWxlbWVudCBpbiBjYXNlIGl0IGxhdGVyIGdldHMgdHJhbnNwbGFudGVkLlxuICAgICAgICByb290RWxlbWVudHNCeVJlYWN0Um9vdElEW3JlYWN0Um9vdElEXSA9XG4gICAgICAgICAgZ2V0UmVhY3RSb290RWxlbWVudEluQ29udGFpbmVyKGNvbnRhaW5lcik7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBjb21wb25lbnRJbnN0YW5jZTtcbiAgICB9XG4gICksXG5cbiAgLyoqXG4gICAqIFJlbmRlcnMgYSBSZWFjdCBjb21wb25lbnQgaW50byB0aGUgRE9NIGluIHRoZSBzdXBwbGllZCBgY29udGFpbmVyYC5cbiAgICpcbiAgICogSWYgdGhlIFJlYWN0IGNvbXBvbmVudCB3YXMgcHJldmlvdXNseSByZW5kZXJlZCBpbnRvIGBjb250YWluZXJgLCB0aGlzIHdpbGxcbiAgICogcGVyZm9ybSBhbiB1cGRhdGUgb24gaXQgYW5kIG9ubHkgbXV0YXRlIHRoZSBET00gYXMgbmVjZXNzYXJ5IHRvIHJlZmxlY3QgdGhlXG4gICAqIGxhdGVzdCBSZWFjdCBjb21wb25lbnQuXG4gICAqXG4gICAqIEBwYXJhbSB7UmVhY3RFbGVtZW50fSBuZXh0RWxlbWVudCBDb21wb25lbnQgZWxlbWVudCB0byByZW5kZXIuXG4gICAqIEBwYXJhbSB7RE9NRWxlbWVudH0gY29udGFpbmVyIERPTSBlbGVtZW50IHRvIHJlbmRlciBpbnRvLlxuICAgKiBAcGFyYW0gez9mdW5jdGlvbn0gY2FsbGJhY2sgZnVuY3Rpb24gdHJpZ2dlcmVkIG9uIGNvbXBsZXRpb25cbiAgICogQHJldHVybiB7UmVhY3RDb21wb25lbnR9IENvbXBvbmVudCBpbnN0YW5jZSByZW5kZXJlZCBpbiBgY29udGFpbmVyYC5cbiAgICovXG4gIHJlbmRlcjogZnVuY3Rpb24obmV4dEVsZW1lbnQsIGNvbnRhaW5lciwgY2FsbGJhY2spIHtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgUmVhY3RFbGVtZW50LmlzVmFsaWRFbGVtZW50KG5leHRFbGVtZW50KSxcbiAgICAgICdyZW5kZXJDb21wb25lbnQoKTogSW52YWxpZCBjb21wb25lbnQgZWxlbWVudC4lcycsXG4gICAgICAoXG4gICAgICAgIHR5cGVvZiBuZXh0RWxlbWVudCA9PT0gJ3N0cmluZycgP1xuICAgICAgICAgICcgSW5zdGVhZCBvZiBwYXNzaW5nIGFuIGVsZW1lbnQgc3RyaW5nLCBtYWtlIHN1cmUgdG8gaW5zdGFudGlhdGUgJyArXG4gICAgICAgICAgJ2l0IGJ5IHBhc3NpbmcgaXQgdG8gUmVhY3QuY3JlYXRlRWxlbWVudC4nIDpcbiAgICAgICAgUmVhY3RMZWdhY3lFbGVtZW50LmlzVmFsaWRGYWN0b3J5KG5leHRFbGVtZW50KSA/XG4gICAgICAgICAgJyBJbnN0ZWFkIG9mIHBhc3NpbmcgYSBjb21wb25lbnQgY2xhc3MsIG1ha2Ugc3VyZSB0byBpbnN0YW50aWF0ZSAnICtcbiAgICAgICAgICAnaXQgYnkgcGFzc2luZyBpdCB0byBSZWFjdC5jcmVhdGVFbGVtZW50LicgOlxuICAgICAgICAvLyBDaGVjayBpZiBpdCBxdWFja3MgbGlrZSBhIGVsZW1lbnRcbiAgICAgICAgdHlwZW9mIG5leHRFbGVtZW50LnByb3BzICE9PSBcInVuZGVmaW5lZFwiID9cbiAgICAgICAgICAnIFRoaXMgbWF5IGJlIGNhdXNlZCBieSB1bmludGVudGlvbmFsbHkgbG9hZGluZyB0d28gaW5kZXBlbmRlbnQgJyArXG4gICAgICAgICAgJ2NvcGllcyBvZiBSZWFjdC4nIDpcbiAgICAgICAgICAnJ1xuICAgICAgKVxuICAgICkgOiBpbnZhcmlhbnQoUmVhY3RFbGVtZW50LmlzVmFsaWRFbGVtZW50KG5leHRFbGVtZW50KSkpO1xuXG4gICAgdmFyIHByZXZDb21wb25lbnQgPSBpbnN0YW5jZXNCeVJlYWN0Um9vdElEW2dldFJlYWN0Um9vdElEKGNvbnRhaW5lcildO1xuXG4gICAgaWYgKHByZXZDb21wb25lbnQpIHtcbiAgICAgIHZhciBwcmV2RWxlbWVudCA9IHByZXZDb21wb25lbnQuX2N1cnJlbnRFbGVtZW50O1xuICAgICAgaWYgKHNob3VsZFVwZGF0ZVJlYWN0Q29tcG9uZW50KHByZXZFbGVtZW50LCBuZXh0RWxlbWVudCkpIHtcbiAgICAgICAgcmV0dXJuIFJlYWN0TW91bnQuX3VwZGF0ZVJvb3RDb21wb25lbnQoXG4gICAgICAgICAgcHJldkNvbXBvbmVudCxcbiAgICAgICAgICBuZXh0RWxlbWVudCxcbiAgICAgICAgICBjb250YWluZXIsXG4gICAgICAgICAgY2FsbGJhY2tcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIFJlYWN0TW91bnQudW5tb3VudENvbXBvbmVudEF0Tm9kZShjb250YWluZXIpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHZhciByZWFjdFJvb3RFbGVtZW50ID0gZ2V0UmVhY3RSb290RWxlbWVudEluQ29udGFpbmVyKGNvbnRhaW5lcik7XG4gICAgdmFyIGNvbnRhaW5lckhhc1JlYWN0TWFya3VwID1cbiAgICAgIHJlYWN0Um9vdEVsZW1lbnQgJiYgUmVhY3RNb3VudC5pc1JlbmRlcmVkQnlSZWFjdChyZWFjdFJvb3RFbGVtZW50KTtcblxuICAgIHZhciBzaG91bGRSZXVzZU1hcmt1cCA9IGNvbnRhaW5lckhhc1JlYWN0TWFya3VwICYmICFwcmV2Q29tcG9uZW50O1xuXG4gICAgdmFyIGNvbXBvbmVudCA9IFJlYWN0TW91bnQuX3JlbmRlck5ld1Jvb3RDb21wb25lbnQoXG4gICAgICBuZXh0RWxlbWVudCxcbiAgICAgIGNvbnRhaW5lcixcbiAgICAgIHNob3VsZFJldXNlTWFya3VwXG4gICAgKTtcbiAgICBjYWxsYmFjayAmJiBjYWxsYmFjay5jYWxsKGNvbXBvbmVudCk7XG4gICAgcmV0dXJuIGNvbXBvbmVudDtcbiAgfSxcblxuICAvKipcbiAgICogQ29uc3RydWN0cyBhIGNvbXBvbmVudCBpbnN0YW5jZSBvZiBgY29uc3RydWN0b3JgIHdpdGggYGluaXRpYWxQcm9wc2AgYW5kXG4gICAqIHJlbmRlcnMgaXQgaW50byB0aGUgc3VwcGxpZWQgYGNvbnRhaW5lcmAuXG4gICAqXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IGNvbnN0cnVjdG9yIFJlYWN0IGNvbXBvbmVudCBjb25zdHJ1Y3Rvci5cbiAgICogQHBhcmFtIHs/b2JqZWN0fSBwcm9wcyBJbml0aWFsIHByb3BzIG9mIHRoZSBjb21wb25lbnQgaW5zdGFuY2UuXG4gICAqIEBwYXJhbSB7RE9NRWxlbWVudH0gY29udGFpbmVyIERPTSBlbGVtZW50IHRvIHJlbmRlciBpbnRvLlxuICAgKiBAcmV0dXJuIHtSZWFjdENvbXBvbmVudH0gQ29tcG9uZW50IGluc3RhbmNlIHJlbmRlcmVkIGluIGBjb250YWluZXJgLlxuICAgKi9cbiAgY29uc3RydWN0QW5kUmVuZGVyQ29tcG9uZW50OiBmdW5jdGlvbihjb25zdHJ1Y3RvciwgcHJvcHMsIGNvbnRhaW5lcikge1xuICAgIHZhciBlbGVtZW50ID0gY3JlYXRlRWxlbWVudChjb25zdHJ1Y3RvciwgcHJvcHMpO1xuICAgIHJldHVybiBSZWFjdE1vdW50LnJlbmRlcihlbGVtZW50LCBjb250YWluZXIpO1xuICB9LFxuXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3RzIGEgY29tcG9uZW50IGluc3RhbmNlIG9mIGBjb25zdHJ1Y3RvcmAgd2l0aCBgaW5pdGlhbFByb3BzYCBhbmRcbiAgICogcmVuZGVycyBpdCBpbnRvIGEgY29udGFpbmVyIG5vZGUgaWRlbnRpZmllZCBieSBzdXBwbGllZCBgaWRgLlxuICAgKlxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBjb21wb25lbnRDb25zdHJ1Y3RvciBSZWFjdCBjb21wb25lbnQgY29uc3RydWN0b3JcbiAgICogQHBhcmFtIHs/b2JqZWN0fSBwcm9wcyBJbml0aWFsIHByb3BzIG9mIHRoZSBjb21wb25lbnQgaW5zdGFuY2UuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpZCBJRCBvZiB0aGUgRE9NIGVsZW1lbnQgdG8gcmVuZGVyIGludG8uXG4gICAqIEByZXR1cm4ge1JlYWN0Q29tcG9uZW50fSBDb21wb25lbnQgaW5zdGFuY2UgcmVuZGVyZWQgaW4gdGhlIGNvbnRhaW5lciBub2RlLlxuICAgKi9cbiAgY29uc3RydWN0QW5kUmVuZGVyQ29tcG9uZW50QnlJRDogZnVuY3Rpb24oY29uc3RydWN0b3IsIHByb3BzLCBpZCkge1xuICAgIHZhciBkb21Ob2RlID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoaWQpO1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICBkb21Ob2RlLFxuICAgICAgJ1RyaWVkIHRvIGdldCBlbGVtZW50IHdpdGggaWQgb2YgXCIlc1wiIGJ1dCBpdCBpcyBub3QgcHJlc2VudCBvbiB0aGUgcGFnZS4nLFxuICAgICAgaWRcbiAgICApIDogaW52YXJpYW50KGRvbU5vZGUpKTtcbiAgICByZXR1cm4gUmVhY3RNb3VudC5jb25zdHJ1Y3RBbmRSZW5kZXJDb21wb25lbnQoY29uc3RydWN0b3IsIHByb3BzLCBkb21Ob2RlKTtcbiAgfSxcblxuICAvKipcbiAgICogUmVnaXN0ZXJzIGEgY29udGFpbmVyIG5vZGUgaW50byB3aGljaCBSZWFjdCBjb21wb25lbnRzIHdpbGwgYmUgcmVuZGVyZWQuXG4gICAqIFRoaXMgYWxzbyBjcmVhdGVzIHRoZSBcInJlYWN0Um9vdFwiIElEIHRoYXQgd2lsbCBiZSBhc3NpZ25lZCB0byB0aGUgZWxlbWVudFxuICAgKiByZW5kZXJlZCB3aXRoaW4uXG4gICAqXG4gICAqIEBwYXJhbSB7RE9NRWxlbWVudH0gY29udGFpbmVyIERPTSBlbGVtZW50IHRvIHJlZ2lzdGVyIGFzIGEgY29udGFpbmVyLlxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBcInJlYWN0Um9vdFwiIElEIG9mIGVsZW1lbnRzIHJlbmRlcmVkIHdpdGhpbi5cbiAgICovXG4gIHJlZ2lzdGVyQ29udGFpbmVyOiBmdW5jdGlvbihjb250YWluZXIpIHtcbiAgICB2YXIgcmVhY3RSb290SUQgPSBnZXRSZWFjdFJvb3RJRChjb250YWluZXIpO1xuICAgIGlmIChyZWFjdFJvb3RJRCkge1xuICAgICAgLy8gSWYgb25lIGV4aXN0cywgbWFrZSBzdXJlIGl0IGlzIGEgdmFsaWQgXCJyZWFjdFJvb3RcIiBJRC5cbiAgICAgIHJlYWN0Um9vdElEID0gUmVhY3RJbnN0YW5jZUhhbmRsZXMuZ2V0UmVhY3RSb290SURGcm9tTm9kZUlEKHJlYWN0Um9vdElEKTtcbiAgICB9XG4gICAgaWYgKCFyZWFjdFJvb3RJRCkge1xuICAgICAgLy8gTm8gdmFsaWQgXCJyZWFjdFJvb3RcIiBJRCBmb3VuZCwgY3JlYXRlIG9uZS5cbiAgICAgIHJlYWN0Um9vdElEID0gUmVhY3RJbnN0YW5jZUhhbmRsZXMuY3JlYXRlUmVhY3RSb290SUQoKTtcbiAgICB9XG4gICAgY29udGFpbmVyc0J5UmVhY3RSb290SURbcmVhY3RSb290SURdID0gY29udGFpbmVyO1xuICAgIHJldHVybiByZWFjdFJvb3RJRDtcbiAgfSxcblxuICAvKipcbiAgICogVW5tb3VudHMgYW5kIGRlc3Ryb3lzIHRoZSBSZWFjdCBjb21wb25lbnQgcmVuZGVyZWQgaW4gdGhlIGBjb250YWluZXJgLlxuICAgKlxuICAgKiBAcGFyYW0ge0RPTUVsZW1lbnR9IGNvbnRhaW5lciBET00gZWxlbWVudCBjb250YWluaW5nIGEgUmVhY3QgY29tcG9uZW50LlxuICAgKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIGEgY29tcG9uZW50IHdhcyBmb3VuZCBpbiBhbmQgdW5tb3VudGVkIGZyb21cbiAgICogICAgICAgICAgICAgICAgICAgYGNvbnRhaW5lcmBcbiAgICovXG4gIHVubW91bnRDb21wb25lbnRBdE5vZGU6IGZ1bmN0aW9uKGNvbnRhaW5lcikge1xuICAgIC8vIFZhcmlvdXMgcGFydHMgb2Ygb3VyIGNvZGUgKHN1Y2ggYXMgUmVhY3RDb21wb3NpdGVDb21wb25lbnQnc1xuICAgIC8vIF9yZW5kZXJWYWxpZGF0ZWRDb21wb25lbnQpIGFzc3VtZSB0aGF0IGNhbGxzIHRvIHJlbmRlciBhcmVuJ3QgbmVzdGVkO1xuICAgIC8vIHZlcmlmeSB0aGF0IHRoYXQncyB0aGUgY2FzZS4gKFN0cmljdGx5IHNwZWFraW5nLCB1bm1vdW50aW5nIHdvbid0IGNhdXNlIGFcbiAgICAvLyByZW5kZXIgYnV0IHdlIHN0aWxsIGRvbid0IGV4cGVjdCB0byBiZSBpbiBhIHJlbmRlciBjYWxsIGhlcmUuKVxuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyB3YXJuaW5nKFxuICAgICAgUmVhY3RDdXJyZW50T3duZXIuY3VycmVudCA9PSBudWxsLFxuICAgICAgJ3VubW91bnRDb21wb25lbnRBdE5vZGUoKTogUmVuZGVyIG1ldGhvZHMgc2hvdWxkIGJlIGEgcHVyZSBmdW5jdGlvbiBvZiAnICtcbiAgICAgICdwcm9wcyBhbmQgc3RhdGU7IHRyaWdnZXJpbmcgbmVzdGVkIGNvbXBvbmVudCB1cGRhdGVzIGZyb20gcmVuZGVyIGlzICcgK1xuICAgICAgJ25vdCBhbGxvd2VkLiBJZiBuZWNlc3NhcnksIHRyaWdnZXIgbmVzdGVkIHVwZGF0ZXMgaW4gJyArXG4gICAgICAnY29tcG9uZW50RGlkVXBkYXRlLidcbiAgICApIDogbnVsbCk7XG5cbiAgICB2YXIgcmVhY3RSb290SUQgPSBnZXRSZWFjdFJvb3RJRChjb250YWluZXIpO1xuICAgIHZhciBjb21wb25lbnQgPSBpbnN0YW5jZXNCeVJlYWN0Um9vdElEW3JlYWN0Um9vdElEXTtcbiAgICBpZiAoIWNvbXBvbmVudCkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBSZWFjdE1vdW50LnVubW91bnRDb21wb25lbnRGcm9tTm9kZShjb21wb25lbnQsIGNvbnRhaW5lcik7XG4gICAgZGVsZXRlIGluc3RhbmNlc0J5UmVhY3RSb290SURbcmVhY3RSb290SURdO1xuICAgIGRlbGV0ZSBjb250YWluZXJzQnlSZWFjdFJvb3RJRFtyZWFjdFJvb3RJRF07XG4gICAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgZGVsZXRlIHJvb3RFbGVtZW50c0J5UmVhY3RSb290SURbcmVhY3RSb290SURdO1xuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfSxcblxuICAvKipcbiAgICogVW5tb3VudHMgYSBjb21wb25lbnQgYW5kIHJlbW92ZXMgaXQgZnJvbSB0aGUgRE9NLlxuICAgKlxuICAgKiBAcGFyYW0ge1JlYWN0Q29tcG9uZW50fSBpbnN0YW5jZSBSZWFjdCBjb21wb25lbnQgaW5zdGFuY2UuXG4gICAqIEBwYXJhbSB7RE9NRWxlbWVudH0gY29udGFpbmVyIERPTSBlbGVtZW50IHRvIHVubW91bnQgZnJvbS5cbiAgICogQGZpbmFsXG4gICAqIEBpbnRlcm5hbFxuICAgKiBAc2VlIHtSZWFjdE1vdW50LnVubW91bnRDb21wb25lbnRBdE5vZGV9XG4gICAqL1xuICB1bm1vdW50Q29tcG9uZW50RnJvbU5vZGU6IGZ1bmN0aW9uKGluc3RhbmNlLCBjb250YWluZXIpIHtcbiAgICBpbnN0YW5jZS51bm1vdW50Q29tcG9uZW50KCk7XG5cbiAgICBpZiAoY29udGFpbmVyLm5vZGVUeXBlID09PSBET0NfTk9ERV9UWVBFKSB7XG4gICAgICBjb250YWluZXIgPSBjb250YWluZXIuZG9jdW1lbnRFbGVtZW50O1xuICAgIH1cblxuICAgIC8vIGh0dHA6Ly9qc3BlcmYuY29tL2VtcHR5aW5nLWEtbm9kZVxuICAgIHdoaWxlIChjb250YWluZXIubGFzdENoaWxkKSB7XG4gICAgICBjb250YWluZXIucmVtb3ZlQ2hpbGQoY29udGFpbmVyLmxhc3RDaGlsZCk7XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBGaW5kcyB0aGUgY29udGFpbmVyIERPTSBlbGVtZW50IHRoYXQgY29udGFpbnMgUmVhY3QgY29tcG9uZW50IHRvIHdoaWNoIHRoZVxuICAgKiBzdXBwbGllZCBET00gYGlkYCBiZWxvbmdzLlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gaWQgVGhlIElEIG9mIGFuIGVsZW1lbnQgcmVuZGVyZWQgYnkgYSBSZWFjdCBjb21wb25lbnQuXG4gICAqIEByZXR1cm4gez9ET01FbGVtZW50fSBET00gZWxlbWVudCB0aGF0IGNvbnRhaW5zIHRoZSBgaWRgLlxuICAgKi9cbiAgZmluZFJlYWN0Q29udGFpbmVyRm9ySUQ6IGZ1bmN0aW9uKGlkKSB7XG4gICAgdmFyIHJlYWN0Um9vdElEID0gUmVhY3RJbnN0YW5jZUhhbmRsZXMuZ2V0UmVhY3RSb290SURGcm9tTm9kZUlEKGlkKTtcbiAgICB2YXIgY29udGFpbmVyID0gY29udGFpbmVyc0J5UmVhY3RSb290SURbcmVhY3RSb290SURdO1xuXG4gICAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgdmFyIHJvb3RFbGVtZW50ID0gcm9vdEVsZW1lbnRzQnlSZWFjdFJvb3RJRFtyZWFjdFJvb3RJRF07XG4gICAgICBpZiAocm9vdEVsZW1lbnQgJiYgcm9vdEVsZW1lbnQucGFyZW50Tm9kZSAhPT0gY29udGFpbmVyKSB7XG4gICAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgICAgLy8gQ2FsbCBpbnRlcm5hbEdldElEIGhlcmUgYmVjYXVzZSBnZXRJRCBjYWxscyBpc1ZhbGlkIHdoaWNoIGNhbGxzXG4gICAgICAgICAgLy8gZmluZFJlYWN0Q29udGFpbmVyRm9ySUQgKHRoaXMgZnVuY3Rpb24pLlxuICAgICAgICAgIGludGVybmFsR2V0SUQocm9vdEVsZW1lbnQpID09PSByZWFjdFJvb3RJRCxcbiAgICAgICAgICAnUmVhY3RNb3VudDogUm9vdCBlbGVtZW50IElEIGRpZmZlcmVkIGZyb20gcmVhY3RSb290SUQuJ1xuICAgICAgICApIDogaW52YXJpYW50KC8vIENhbGwgaW50ZXJuYWxHZXRJRCBoZXJlIGJlY2F1c2UgZ2V0SUQgY2FsbHMgaXNWYWxpZCB3aGljaCBjYWxsc1xuICAgICAgICAvLyBmaW5kUmVhY3RDb250YWluZXJGb3JJRCAodGhpcyBmdW5jdGlvbikuXG4gICAgICAgIGludGVybmFsR2V0SUQocm9vdEVsZW1lbnQpID09PSByZWFjdFJvb3RJRCkpO1xuXG4gICAgICAgIHZhciBjb250YWluZXJDaGlsZCA9IGNvbnRhaW5lci5maXJzdENoaWxkO1xuICAgICAgICBpZiAoY29udGFpbmVyQ2hpbGQgJiZcbiAgICAgICAgICAgIHJlYWN0Um9vdElEID09PSBpbnRlcm5hbEdldElEKGNvbnRhaW5lckNoaWxkKSkge1xuICAgICAgICAgIC8vIElmIHRoZSBjb250YWluZXIgaGFzIGEgbmV3IGNoaWxkIHdpdGggdGhlIHNhbWUgSUQgYXMgdGhlIG9sZFxuICAgICAgICAgIC8vIHJvb3QgZWxlbWVudCwgdGhlbiByb290RWxlbWVudHNCeVJlYWN0Um9vdElEW3JlYWN0Um9vdElEXSBpc1xuICAgICAgICAgIC8vIGp1c3Qgc3RhbGUgYW5kIG5lZWRzIHRvIGJlIHVwZGF0ZWQuIFRoZSBjYXNlIHRoYXQgZGVzZXJ2ZXMgYVxuICAgICAgICAgIC8vIHdhcm5pbmcgaXMgd2hlbiB0aGUgY29udGFpbmVyIGlzIGVtcHR5LlxuICAgICAgICAgIHJvb3RFbGVtZW50c0J5UmVhY3RSb290SURbcmVhY3RSb290SURdID0gY29udGFpbmVyQ2hpbGQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgICAgJ1JlYWN0TW91bnQ6IFJvb3QgZWxlbWVudCBoYXMgYmVlbiByZW1vdmVkIGZyb20gaXRzIG9yaWdpbmFsICcgK1xuICAgICAgICAgICAgJ2NvbnRhaW5lci4gTmV3IGNvbnRhaW5lcjonLCByb290RWxlbWVudC5wYXJlbnROb2RlXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBjb250YWluZXI7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEZpbmRzIGFuIGVsZW1lbnQgcmVuZGVyZWQgYnkgUmVhY3Qgd2l0aCB0aGUgc3VwcGxpZWQgSUQuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpZCBJRCBvZiBhIERPTSBub2RlIGluIHRoZSBSZWFjdCBjb21wb25lbnQuXG4gICAqIEByZXR1cm4ge0RPTUVsZW1lbnR9IFJvb3QgRE9NIG5vZGUgb2YgdGhlIFJlYWN0IGNvbXBvbmVudC5cbiAgICovXG4gIGZpbmRSZWFjdE5vZGVCeUlEOiBmdW5jdGlvbihpZCkge1xuICAgIHZhciByZWFjdFJvb3QgPSBSZWFjdE1vdW50LmZpbmRSZWFjdENvbnRhaW5lckZvcklEKGlkKTtcbiAgICByZXR1cm4gUmVhY3RNb3VudC5maW5kQ29tcG9uZW50Um9vdChyZWFjdFJvb3QsIGlkKTtcbiAgfSxcblxuICAvKipcbiAgICogVHJ1ZSBpZiB0aGUgc3VwcGxpZWQgYG5vZGVgIGlzIHJlbmRlcmVkIGJ5IFJlYWN0LlxuICAgKlxuICAgKiBAcGFyYW0geyp9IG5vZGUgRE9NIEVsZW1lbnQgdG8gY2hlY2suXG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgdGhlIERPTSBFbGVtZW50IGFwcGVhcnMgdG8gYmUgcmVuZGVyZWQgYnkgUmVhY3QuXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgaXNSZW5kZXJlZEJ5UmVhY3Q6IGZ1bmN0aW9uKG5vZGUpIHtcbiAgICBpZiAobm9kZS5ub2RlVHlwZSAhPT0gMSkge1xuICAgICAgLy8gTm90IGEgRE9NRWxlbWVudCwgdGhlcmVmb3JlIG5vdCBhIFJlYWN0IGNvbXBvbmVudFxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICB2YXIgaWQgPSBSZWFjdE1vdW50LmdldElEKG5vZGUpO1xuICAgIHJldHVybiBpZCA/IGlkLmNoYXJBdCgwKSA9PT0gU0VQQVJBVE9SIDogZmFsc2U7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFRyYXZlcnNlcyB1cCB0aGUgYW5jZXN0b3JzIG9mIHRoZSBzdXBwbGllZCBub2RlIHRvIGZpbmQgYSBub2RlIHRoYXQgaXMgYVxuICAgKiBET00gcmVwcmVzZW50YXRpb24gb2YgYSBSZWFjdCBjb21wb25lbnQuXG4gICAqXG4gICAqIEBwYXJhbSB7Kn0gbm9kZVxuICAgKiBAcmV0dXJuIHs/RE9NRXZlbnRUYXJnZXR9XG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgZ2V0Rmlyc3RSZWFjdERPTTogZnVuY3Rpb24obm9kZSkge1xuICAgIHZhciBjdXJyZW50ID0gbm9kZTtcbiAgICB3aGlsZSAoY3VycmVudCAmJiBjdXJyZW50LnBhcmVudE5vZGUgIT09IGN1cnJlbnQpIHtcbiAgICAgIGlmIChSZWFjdE1vdW50LmlzUmVuZGVyZWRCeVJlYWN0KGN1cnJlbnQpKSB7XG4gICAgICAgIHJldHVybiBjdXJyZW50O1xuICAgICAgfVxuICAgICAgY3VycmVudCA9IGN1cnJlbnQucGFyZW50Tm9kZTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEZpbmRzIGEgbm9kZSB3aXRoIHRoZSBzdXBwbGllZCBgdGFyZ2V0SURgIGluc2lkZSBvZiB0aGUgc3VwcGxpZWRcbiAgICogYGFuY2VzdG9yTm9kZWAuICBFeHBsb2l0cyB0aGUgSUQgbmFtaW5nIHNjaGVtZSB0byBwZXJmb3JtIHRoZSBzZWFyY2hcbiAgICogcXVpY2tseS5cbiAgICpcbiAgICogQHBhcmFtIHtET01FdmVudFRhcmdldH0gYW5jZXN0b3JOb2RlIFNlYXJjaCBmcm9tIHRoaXMgcm9vdC5cbiAgICogQHBhcmFybSB7c3RyaW5nfSB0YXJnZXRJRCBJRCBvZiB0aGUgRE9NIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjb21wb25lbnQuXG4gICAqIEByZXR1cm4ge0RPTUV2ZW50VGFyZ2V0fSBET00gbm9kZSB3aXRoIHRoZSBzdXBwbGllZCBgdGFyZ2V0SURgLlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIGZpbmRDb21wb25lbnRSb290OiBmdW5jdGlvbihhbmNlc3Rvck5vZGUsIHRhcmdldElEKSB7XG4gICAgdmFyIGZpcnN0Q2hpbGRyZW4gPSBmaW5kQ29tcG9uZW50Um9vdFJldXNhYmxlQXJyYXk7XG4gICAgdmFyIGNoaWxkSW5kZXggPSAwO1xuXG4gICAgdmFyIGRlZXBlc3RBbmNlc3RvciA9IGZpbmREZWVwZXN0Q2FjaGVkQW5jZXN0b3IodGFyZ2V0SUQpIHx8IGFuY2VzdG9yTm9kZTtcblxuICAgIGZpcnN0Q2hpbGRyZW5bMF0gPSBkZWVwZXN0QW5jZXN0b3IuZmlyc3RDaGlsZDtcbiAgICBmaXJzdENoaWxkcmVuLmxlbmd0aCA9IDE7XG5cbiAgICB3aGlsZSAoY2hpbGRJbmRleCA8IGZpcnN0Q2hpbGRyZW4ubGVuZ3RoKSB7XG4gICAgICB2YXIgY2hpbGQgPSBmaXJzdENoaWxkcmVuW2NoaWxkSW5kZXgrK107XG4gICAgICB2YXIgdGFyZ2V0Q2hpbGQ7XG5cbiAgICAgIHdoaWxlIChjaGlsZCkge1xuICAgICAgICB2YXIgY2hpbGRJRCA9IFJlYWN0TW91bnQuZ2V0SUQoY2hpbGQpO1xuICAgICAgICBpZiAoY2hpbGRJRCkge1xuICAgICAgICAgIC8vIEV2ZW4gaWYgd2UgZmluZCB0aGUgbm9kZSB3ZSdyZSBsb29raW5nIGZvciwgd2UgZmluaXNoIGxvb3BpbmdcbiAgICAgICAgICAvLyB0aHJvdWdoIGl0cyBzaWJsaW5ncyB0byBlbnN1cmUgdGhleSdyZSBjYWNoZWQgc28gdGhhdCB3ZSBkb24ndCBoYXZlXG4gICAgICAgICAgLy8gdG8gcmV2aXNpdCB0aGlzIG5vZGUgYWdhaW4uIE90aGVyd2lzZSwgd2UgbWFrZSBuXjIgY2FsbHMgdG8gZ2V0SURcbiAgICAgICAgICAvLyB3aGVuIHZpc2l0aW5nIHRoZSBtYW55IGNoaWxkcmVuIG9mIGEgc2luZ2xlIG5vZGUgaW4gb3JkZXIuXG5cbiAgICAgICAgICBpZiAodGFyZ2V0SUQgPT09IGNoaWxkSUQpIHtcbiAgICAgICAgICAgIHRhcmdldENoaWxkID0gY2hpbGQ7XG4gICAgICAgICAgfSBlbHNlIGlmIChSZWFjdEluc3RhbmNlSGFuZGxlcy5pc0FuY2VzdG9ySURPZihjaGlsZElELCB0YXJnZXRJRCkpIHtcbiAgICAgICAgICAgIC8vIElmIHdlIGZpbmQgYSBjaGlsZCB3aG9zZSBJRCBpcyBhbiBhbmNlc3RvciBvZiB0aGUgZ2l2ZW4gSUQsXG4gICAgICAgICAgICAvLyB0aGVuIHdlIGNhbiBiZSBzdXJlIHRoYXQgd2Ugb25seSB3YW50IHRvIHNlYXJjaCB0aGUgc3VidHJlZVxuICAgICAgICAgICAgLy8gcm9vdGVkIGF0IHRoaXMgY2hpbGQsIHNvIHdlIGNhbiB0aHJvdyBvdXQgdGhlIHJlc3Qgb2YgdGhlXG4gICAgICAgICAgICAvLyBzZWFyY2ggc3RhdGUuXG4gICAgICAgICAgICBmaXJzdENoaWxkcmVuLmxlbmd0aCA9IGNoaWxkSW5kZXggPSAwO1xuICAgICAgICAgICAgZmlyc3RDaGlsZHJlbi5wdXNoKGNoaWxkLmZpcnN0Q2hpbGQpO1xuICAgICAgICAgIH1cblxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIElmIHRoaXMgY2hpbGQgaGFkIG5vIElELCB0aGVuIHRoZXJlJ3MgYSBjaGFuY2UgdGhhdCBpdCB3YXNcbiAgICAgICAgICAvLyBpbmplY3RlZCBhdXRvbWF0aWNhbGx5IGJ5IHRoZSBicm93c2VyLCBhcyB3aGVuIGEgYDx0YWJsZT5gXG4gICAgICAgICAgLy8gZWxlbWVudCBzcHJvdXRzIGFuIGV4dHJhIGA8dGJvZHk+YCBjaGlsZCBhcyBhIHNpZGUgZWZmZWN0IG9mXG4gICAgICAgICAgLy8gYC5pbm5lckhUTUxgIHBhcnNpbmcuIE9wdGltaXN0aWNhbGx5IGNvbnRpbnVlIGRvd24gdGhpc1xuICAgICAgICAgIC8vIGJyYW5jaCwgYnV0IG5vdCBiZWZvcmUgZXhhbWluaW5nIHRoZSBvdGhlciBzaWJsaW5ncy5cbiAgICAgICAgICBmaXJzdENoaWxkcmVuLnB1c2goY2hpbGQuZmlyc3RDaGlsZCk7XG4gICAgICAgIH1cblxuICAgICAgICBjaGlsZCA9IGNoaWxkLm5leHRTaWJsaW5nO1xuICAgICAgfVxuXG4gICAgICBpZiAodGFyZ2V0Q2hpbGQpIHtcbiAgICAgICAgLy8gRW1wdHlpbmcgZmlyc3RDaGlsZHJlbi9maW5kQ29tcG9uZW50Um9vdFJldXNhYmxlQXJyYXkgaXNcbiAgICAgICAgLy8gbm90IG5lY2Vzc2FyeSBmb3IgY29ycmVjdG5lc3MsIGJ1dCBpdCBoZWxwcyB0aGUgR0MgcmVjbGFpbVxuICAgICAgICAvLyBhbnkgbm9kZXMgdGhhdCB3ZXJlIGxlZnQgYXQgdGhlIGVuZCBvZiB0aGUgc2VhcmNoLlxuICAgICAgICBmaXJzdENoaWxkcmVuLmxlbmd0aCA9IDA7XG5cbiAgICAgICAgcmV0dXJuIHRhcmdldENoaWxkO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZpcnN0Q2hpbGRyZW4ubGVuZ3RoID0gMDtcblxuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICBmYWxzZSxcbiAgICAgICdmaW5kQ29tcG9uZW50Um9vdCguLi4sICVzKTogVW5hYmxlIHRvIGZpbmQgZWxlbWVudC4gVGhpcyBwcm9iYWJseSAnICtcbiAgICAgICdtZWFucyB0aGUgRE9NIHdhcyB1bmV4cGVjdGVkbHkgbXV0YXRlZCAoZS5nLiwgYnkgdGhlIGJyb3dzZXIpLCAnICtcbiAgICAgICd1c3VhbGx5IGR1ZSB0byBmb3JnZXR0aW5nIGEgPHRib2R5PiB3aGVuIHVzaW5nIHRhYmxlcywgbmVzdGluZyB0YWdzICcgK1xuICAgICAgJ2xpa2UgPGZvcm0+LCA8cD4sIG9yIDxhPiwgb3IgdXNpbmcgbm9uLVNWRyBlbGVtZW50cyBpbiBhbiA8c3ZnPiAnICtcbiAgICAgICdwYXJlbnQuICcgK1xuICAgICAgJ1RyeSBpbnNwZWN0aW5nIHRoZSBjaGlsZCBub2RlcyBvZiB0aGUgZWxlbWVudCB3aXRoIFJlYWN0IElEIGAlc2AuJyxcbiAgICAgIHRhcmdldElELFxuICAgICAgUmVhY3RNb3VudC5nZXRJRChhbmNlc3Rvck5vZGUpXG4gICAgKSA6IGludmFyaWFudChmYWxzZSkpO1xuICB9LFxuXG5cbiAgLyoqXG4gICAqIFJlYWN0IElEIHV0aWxpdGllcy5cbiAgICovXG5cbiAgZ2V0UmVhY3RSb290SUQ6IGdldFJlYWN0Um9vdElELFxuXG4gIGdldElEOiBnZXRJRCxcblxuICBzZXRJRDogc2V0SUQsXG5cbiAgZ2V0Tm9kZTogZ2V0Tm9kZSxcblxuICBwdXJnZUlEOiBwdXJnZUlEXG59O1xuXG4vLyBEZXByZWNhdGlvbnMgKHJlbW92ZSBmb3IgMC4xMylcblJlYWN0TW91bnQucmVuZGVyQ29tcG9uZW50ID0gZGVwcmVjYXRlZChcbiAgJ1JlYWN0TW91bnQnLFxuICAncmVuZGVyQ29tcG9uZW50JyxcbiAgJ3JlbmRlcicsXG4gIHRoaXMsXG4gIFJlYWN0TW91bnQucmVuZGVyXG4pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0TW91bnQ7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdE11bHRpQ2hpbGRcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBSZWFjdENvbXBvbmVudCA9IHJlcXVpcmUoXCIuL1JlYWN0Q29tcG9uZW50XCIpO1xudmFyIFJlYWN0TXVsdGlDaGlsZFVwZGF0ZVR5cGVzID0gcmVxdWlyZShcIi4vUmVhY3RNdWx0aUNoaWxkVXBkYXRlVHlwZXNcIik7XG5cbnZhciBmbGF0dGVuQ2hpbGRyZW4gPSByZXF1aXJlKFwiLi9mbGF0dGVuQ2hpbGRyZW5cIik7XG52YXIgaW5zdGFudGlhdGVSZWFjdENvbXBvbmVudCA9IHJlcXVpcmUoXCIuL2luc3RhbnRpYXRlUmVhY3RDb21wb25lbnRcIik7XG52YXIgc2hvdWxkVXBkYXRlUmVhY3RDb21wb25lbnQgPSByZXF1aXJlKFwiLi9zaG91bGRVcGRhdGVSZWFjdENvbXBvbmVudFwiKTtcblxuLyoqXG4gKiBVcGRhdGluZyBjaGlsZHJlbiBvZiBhIGNvbXBvbmVudCBtYXkgdHJpZ2dlciByZWN1cnNpdmUgdXBkYXRlcy4gVGhlIGRlcHRoIGlzXG4gKiB1c2VkIHRvIGJhdGNoIHJlY3Vyc2l2ZSB1cGRhdGVzIHRvIHJlbmRlciBtYXJrdXAgbW9yZSBlZmZpY2llbnRseS5cbiAqXG4gKiBAdHlwZSB7bnVtYmVyfVxuICogQHByaXZhdGVcbiAqL1xudmFyIHVwZGF0ZURlcHRoID0gMDtcblxuLyoqXG4gKiBRdWV1ZSBvZiB1cGRhdGUgY29uZmlndXJhdGlvbiBvYmplY3RzLlxuICpcbiAqIEVhY2ggb2JqZWN0IGhhcyBhIGB0eXBlYCBwcm9wZXJ0eSB0aGF0IGlzIGluIGBSZWFjdE11bHRpQ2hpbGRVcGRhdGVUeXBlc2AuXG4gKlxuICogQHR5cGUge2FycmF5PG9iamVjdD59XG4gKiBAcHJpdmF0ZVxuICovXG52YXIgdXBkYXRlUXVldWUgPSBbXTtcblxuLyoqXG4gKiBRdWV1ZSBvZiBtYXJrdXAgdG8gYmUgcmVuZGVyZWQuXG4gKlxuICogQHR5cGUge2FycmF5PHN0cmluZz59XG4gKiBAcHJpdmF0ZVxuICovXG52YXIgbWFya3VwUXVldWUgPSBbXTtcblxuLyoqXG4gKiBFbnF1ZXVlcyBtYXJrdXAgdG8gYmUgcmVuZGVyZWQgYW5kIGluc2VydGVkIGF0IGEgc3VwcGxpZWQgaW5kZXguXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHBhcmVudElEIElEIG9mIHRoZSBwYXJlbnQgY29tcG9uZW50LlxuICogQHBhcmFtIHtzdHJpbmd9IG1hcmt1cCBNYXJrdXAgdGhhdCByZW5kZXJzIGludG8gYW4gZWxlbWVudC5cbiAqIEBwYXJhbSB7bnVtYmVyfSB0b0luZGV4IERlc3RpbmF0aW9uIGluZGV4LlxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gZW5xdWV1ZU1hcmt1cChwYXJlbnRJRCwgbWFya3VwLCB0b0luZGV4KSB7XG4gIC8vIE5PVEU6IE51bGwgdmFsdWVzIHJlZHVjZSBoaWRkZW4gY2xhc3Nlcy5cbiAgdXBkYXRlUXVldWUucHVzaCh7XG4gICAgcGFyZW50SUQ6IHBhcmVudElELFxuICAgIHBhcmVudE5vZGU6IG51bGwsXG4gICAgdHlwZTogUmVhY3RNdWx0aUNoaWxkVXBkYXRlVHlwZXMuSU5TRVJUX01BUktVUCxcbiAgICBtYXJrdXBJbmRleDogbWFya3VwUXVldWUucHVzaChtYXJrdXApIC0gMSxcbiAgICB0ZXh0Q29udGVudDogbnVsbCxcbiAgICBmcm9tSW5kZXg6IG51bGwsXG4gICAgdG9JbmRleDogdG9JbmRleFxuICB9KTtcbn1cblxuLyoqXG4gKiBFbnF1ZXVlcyBtb3ZpbmcgYW4gZXhpc3RpbmcgZWxlbWVudCB0byBhbm90aGVyIGluZGV4LlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXJlbnRJRCBJRCBvZiB0aGUgcGFyZW50IGNvbXBvbmVudC5cbiAqIEBwYXJhbSB7bnVtYmVyfSBmcm9tSW5kZXggU291cmNlIGluZGV4IG9mIHRoZSBleGlzdGluZyBlbGVtZW50LlxuICogQHBhcmFtIHtudW1iZXJ9IHRvSW5kZXggRGVzdGluYXRpb24gaW5kZXggb2YgdGhlIGVsZW1lbnQuXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBlbnF1ZXVlTW92ZShwYXJlbnRJRCwgZnJvbUluZGV4LCB0b0luZGV4KSB7XG4gIC8vIE5PVEU6IE51bGwgdmFsdWVzIHJlZHVjZSBoaWRkZW4gY2xhc3Nlcy5cbiAgdXBkYXRlUXVldWUucHVzaCh7XG4gICAgcGFyZW50SUQ6IHBhcmVudElELFxuICAgIHBhcmVudE5vZGU6IG51bGwsXG4gICAgdHlwZTogUmVhY3RNdWx0aUNoaWxkVXBkYXRlVHlwZXMuTU9WRV9FWElTVElORyxcbiAgICBtYXJrdXBJbmRleDogbnVsbCxcbiAgICB0ZXh0Q29udGVudDogbnVsbCxcbiAgICBmcm9tSW5kZXg6IGZyb21JbmRleCxcbiAgICB0b0luZGV4OiB0b0luZGV4XG4gIH0pO1xufVxuXG4vKipcbiAqIEVucXVldWVzIHJlbW92aW5nIGFuIGVsZW1lbnQgYXQgYW4gaW5kZXguXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHBhcmVudElEIElEIG9mIHRoZSBwYXJlbnQgY29tcG9uZW50LlxuICogQHBhcmFtIHtudW1iZXJ9IGZyb21JbmRleCBJbmRleCBvZiB0aGUgZWxlbWVudCB0byByZW1vdmUuXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBlbnF1ZXVlUmVtb3ZlKHBhcmVudElELCBmcm9tSW5kZXgpIHtcbiAgLy8gTk9URTogTnVsbCB2YWx1ZXMgcmVkdWNlIGhpZGRlbiBjbGFzc2VzLlxuICB1cGRhdGVRdWV1ZS5wdXNoKHtcbiAgICBwYXJlbnRJRDogcGFyZW50SUQsXG4gICAgcGFyZW50Tm9kZTogbnVsbCxcbiAgICB0eXBlOiBSZWFjdE11bHRpQ2hpbGRVcGRhdGVUeXBlcy5SRU1PVkVfTk9ERSxcbiAgICBtYXJrdXBJbmRleDogbnVsbCxcbiAgICB0ZXh0Q29udGVudDogbnVsbCxcbiAgICBmcm9tSW5kZXg6IGZyb21JbmRleCxcbiAgICB0b0luZGV4OiBudWxsXG4gIH0pO1xufVxuXG4vKipcbiAqIEVucXVldWVzIHNldHRpbmcgdGhlIHRleHQgY29udGVudC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gcGFyZW50SUQgSUQgb2YgdGhlIHBhcmVudCBjb21wb25lbnQuXG4gKiBAcGFyYW0ge3N0cmluZ30gdGV4dENvbnRlbnQgVGV4dCBjb250ZW50IHRvIHNldC5cbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIGVucXVldWVUZXh0Q29udGVudChwYXJlbnRJRCwgdGV4dENvbnRlbnQpIHtcbiAgLy8gTk9URTogTnVsbCB2YWx1ZXMgcmVkdWNlIGhpZGRlbiBjbGFzc2VzLlxuICB1cGRhdGVRdWV1ZS5wdXNoKHtcbiAgICBwYXJlbnRJRDogcGFyZW50SUQsXG4gICAgcGFyZW50Tm9kZTogbnVsbCxcbiAgICB0eXBlOiBSZWFjdE11bHRpQ2hpbGRVcGRhdGVUeXBlcy5URVhUX0NPTlRFTlQsXG4gICAgbWFya3VwSW5kZXg6IG51bGwsXG4gICAgdGV4dENvbnRlbnQ6IHRleHRDb250ZW50LFxuICAgIGZyb21JbmRleDogbnVsbCxcbiAgICB0b0luZGV4OiBudWxsXG4gIH0pO1xufVxuXG4vKipcbiAqIFByb2Nlc3NlcyBhbnkgZW5xdWV1ZWQgdXBkYXRlcy5cbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBwcm9jZXNzUXVldWUoKSB7XG4gIGlmICh1cGRhdGVRdWV1ZS5sZW5ndGgpIHtcbiAgICBSZWFjdENvbXBvbmVudC5CYWNrZW5kSURPcGVyYXRpb25zLmRhbmdlcm91c2x5UHJvY2Vzc0NoaWxkcmVuVXBkYXRlcyhcbiAgICAgIHVwZGF0ZVF1ZXVlLFxuICAgICAgbWFya3VwUXVldWVcbiAgICApO1xuICAgIGNsZWFyUXVldWUoKTtcbiAgfVxufVxuXG4vKipcbiAqIENsZWFycyBhbnkgZW5xdWV1ZWQgdXBkYXRlcy5cbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBjbGVhclF1ZXVlKCkge1xuICB1cGRhdGVRdWV1ZS5sZW5ndGggPSAwO1xuICBtYXJrdXBRdWV1ZS5sZW5ndGggPSAwO1xufVxuXG4vKipcbiAqIFJlYWN0TXVsdGlDaGlsZCBhcmUgY2FwYWJsZSBvZiByZWNvbmNpbGluZyBtdWx0aXBsZSBjaGlsZHJlbi5cbiAqXG4gKiBAY2xhc3MgUmVhY3RNdWx0aUNoaWxkXG4gKiBAaW50ZXJuYWxcbiAqL1xudmFyIFJlYWN0TXVsdGlDaGlsZCA9IHtcblxuICAvKipcbiAgICogUHJvdmlkZXMgY29tbW9uIGZ1bmN0aW9uYWxpdHkgZm9yIGNvbXBvbmVudHMgdGhhdCBtdXN0IHJlY29uY2lsZSBtdWx0aXBsZVxuICAgKiBjaGlsZHJlbi4gVGhpcyBpcyB1c2VkIGJ5IGBSZWFjdERPTUNvbXBvbmVudGAgdG8gbW91bnQsIHVwZGF0ZSwgYW5kXG4gICAqIHVubW91bnQgY2hpbGQgY29tcG9uZW50cy5cbiAgICpcbiAgICogQGxlbmRzIHtSZWFjdE11bHRpQ2hpbGQucHJvdG90eXBlfVxuICAgKi9cbiAgTWl4aW46IHtcblxuICAgIC8qKlxuICAgICAqIEdlbmVyYXRlcyBhIFwibW91bnQgaW1hZ2VcIiBmb3IgZWFjaCBvZiB0aGUgc3VwcGxpZWQgY2hpbGRyZW4uIEluIHRoZSBjYXNlXG4gICAgICogb2YgYFJlYWN0RE9NQ29tcG9uZW50YCwgYSBtb3VudCBpbWFnZSBpcyBhIHN0cmluZyBvZiBtYXJrdXAuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gez9vYmplY3R9IG5lc3RlZENoaWxkcmVuIE5lc3RlZCBjaGlsZCBtYXBzLlxuICAgICAqIEByZXR1cm4ge2FycmF5fSBBbiBhcnJheSBvZiBtb3VudGVkIHJlcHJlc2VudGF0aW9ucy5cbiAgICAgKiBAaW50ZXJuYWxcbiAgICAgKi9cbiAgICBtb3VudENoaWxkcmVuOiBmdW5jdGlvbihuZXN0ZWRDaGlsZHJlbiwgdHJhbnNhY3Rpb24pIHtcbiAgICAgIHZhciBjaGlsZHJlbiA9IGZsYXR0ZW5DaGlsZHJlbihuZXN0ZWRDaGlsZHJlbik7XG4gICAgICB2YXIgbW91bnRJbWFnZXMgPSBbXTtcbiAgICAgIHZhciBpbmRleCA9IDA7XG4gICAgICB0aGlzLl9yZW5kZXJlZENoaWxkcmVuID0gY2hpbGRyZW47XG4gICAgICBmb3IgKHZhciBuYW1lIGluIGNoaWxkcmVuKSB7XG4gICAgICAgIHZhciBjaGlsZCA9IGNoaWxkcmVuW25hbWVdO1xuICAgICAgICBpZiAoY2hpbGRyZW4uaGFzT3duUHJvcGVydHkobmFtZSkpIHtcbiAgICAgICAgICAvLyBUaGUgcmVuZGVyZWQgY2hpbGRyZW4gbXVzdCBiZSB0dXJuZWQgaW50byBpbnN0YW5jZXMgYXMgdGhleSdyZVxuICAgICAgICAgIC8vIG1vdW50ZWQuXG4gICAgICAgICAgdmFyIGNoaWxkSW5zdGFuY2UgPSBpbnN0YW50aWF0ZVJlYWN0Q29tcG9uZW50KGNoaWxkLCBudWxsKTtcbiAgICAgICAgICBjaGlsZHJlbltuYW1lXSA9IGNoaWxkSW5zdGFuY2U7XG4gICAgICAgICAgLy8gSW5saW5lZCBmb3IgcGVyZm9ybWFuY2UsIHNlZSBgUmVhY3RJbnN0YW5jZUhhbmRsZXMuY3JlYXRlUmVhY3RJRGAuXG4gICAgICAgICAgdmFyIHJvb3RJRCA9IHRoaXMuX3Jvb3ROb2RlSUQgKyBuYW1lO1xuICAgICAgICAgIHZhciBtb3VudEltYWdlID0gY2hpbGRJbnN0YW5jZS5tb3VudENvbXBvbmVudChcbiAgICAgICAgICAgIHJvb3RJRCxcbiAgICAgICAgICAgIHRyYW5zYWN0aW9uLFxuICAgICAgICAgICAgdGhpcy5fbW91bnREZXB0aCArIDFcbiAgICAgICAgICApO1xuICAgICAgICAgIGNoaWxkSW5zdGFuY2UuX21vdW50SW5kZXggPSBpbmRleDtcbiAgICAgICAgICBtb3VudEltYWdlcy5wdXNoKG1vdW50SW1hZ2UpO1xuICAgICAgICAgIGluZGV4Kys7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBtb3VudEltYWdlcztcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmVwbGFjZXMgYW55IHJlbmRlcmVkIGNoaWxkcmVuIHdpdGggYSB0ZXh0IGNvbnRlbnQgc3RyaW5nLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IG5leHRDb250ZW50IFN0cmluZyBvZiBjb250ZW50LlxuICAgICAqIEBpbnRlcm5hbFxuICAgICAqL1xuICAgIHVwZGF0ZVRleHRDb250ZW50OiBmdW5jdGlvbihuZXh0Q29udGVudCkge1xuICAgICAgdXBkYXRlRGVwdGgrKztcbiAgICAgIHZhciBlcnJvclRocm93biA9IHRydWU7XG4gICAgICB0cnkge1xuICAgICAgICB2YXIgcHJldkNoaWxkcmVuID0gdGhpcy5fcmVuZGVyZWRDaGlsZHJlbjtcbiAgICAgICAgLy8gUmVtb3ZlIGFueSByZW5kZXJlZCBjaGlsZHJlbi5cbiAgICAgICAgZm9yICh2YXIgbmFtZSBpbiBwcmV2Q2hpbGRyZW4pIHtcbiAgICAgICAgICBpZiAocHJldkNoaWxkcmVuLmhhc093blByb3BlcnR5KG5hbWUpKSB7XG4gICAgICAgICAgICB0aGlzLl91bm1vdW50Q2hpbGRCeU5hbWUocHJldkNoaWxkcmVuW25hbWVdLCBuYW1lKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgLy8gU2V0IG5ldyB0ZXh0IGNvbnRlbnQuXG4gICAgICAgIHRoaXMuc2V0VGV4dENvbnRlbnQobmV4dENvbnRlbnQpO1xuICAgICAgICBlcnJvclRocm93biA9IGZhbHNlO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgdXBkYXRlRGVwdGgtLTtcbiAgICAgICAgaWYgKCF1cGRhdGVEZXB0aCkge1xuICAgICAgICAgIGVycm9yVGhyb3duID8gY2xlYXJRdWV1ZSgpIDogcHJvY2Vzc1F1ZXVlKCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVXBkYXRlcyB0aGUgcmVuZGVyZWQgY2hpbGRyZW4gd2l0aCBuZXcgY2hpbGRyZW4uXG4gICAgICpcbiAgICAgKiBAcGFyYW0gez9vYmplY3R9IG5leHROZXN0ZWRDaGlsZHJlbiBOZXN0ZWQgY2hpbGQgbWFwcy5cbiAgICAgKiBAcGFyYW0ge1JlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb259IHRyYW5zYWN0aW9uXG4gICAgICogQGludGVybmFsXG4gICAgICovXG4gICAgdXBkYXRlQ2hpbGRyZW46IGZ1bmN0aW9uKG5leHROZXN0ZWRDaGlsZHJlbiwgdHJhbnNhY3Rpb24pIHtcbiAgICAgIHVwZGF0ZURlcHRoKys7XG4gICAgICB2YXIgZXJyb3JUaHJvd24gPSB0cnVlO1xuICAgICAgdHJ5IHtcbiAgICAgICAgdGhpcy5fdXBkYXRlQ2hpbGRyZW4obmV4dE5lc3RlZENoaWxkcmVuLCB0cmFuc2FjdGlvbik7XG4gICAgICAgIGVycm9yVGhyb3duID0gZmFsc2U7XG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICB1cGRhdGVEZXB0aC0tO1xuICAgICAgICBpZiAoIXVwZGF0ZURlcHRoKSB7XG4gICAgICAgICAgZXJyb3JUaHJvd24gPyBjbGVhclF1ZXVlKCkgOiBwcm9jZXNzUXVldWUoKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBJbXByb3ZlIHBlcmZvcm1hbmNlIGJ5IGlzb2xhdGluZyB0aGlzIGhvdCBjb2RlIHBhdGggZnJvbSB0aGUgdHJ5L2NhdGNoXG4gICAgICogYmxvY2sgaW4gYHVwZGF0ZUNoaWxkcmVuYC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7P29iamVjdH0gbmV4dE5lc3RlZENoaWxkcmVuIE5lc3RlZCBjaGlsZCBtYXBzLlxuICAgICAqIEBwYXJhbSB7UmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbn0gdHJhbnNhY3Rpb25cbiAgICAgKiBAZmluYWxcbiAgICAgKiBAcHJvdGVjdGVkXG4gICAgICovXG4gICAgX3VwZGF0ZUNoaWxkcmVuOiBmdW5jdGlvbihuZXh0TmVzdGVkQ2hpbGRyZW4sIHRyYW5zYWN0aW9uKSB7XG4gICAgICB2YXIgbmV4dENoaWxkcmVuID0gZmxhdHRlbkNoaWxkcmVuKG5leHROZXN0ZWRDaGlsZHJlbik7XG4gICAgICB2YXIgcHJldkNoaWxkcmVuID0gdGhpcy5fcmVuZGVyZWRDaGlsZHJlbjtcbiAgICAgIGlmICghbmV4dENoaWxkcmVuICYmICFwcmV2Q2hpbGRyZW4pIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgdmFyIG5hbWU7XG4gICAgICAvLyBgbmV4dEluZGV4YCB3aWxsIGluY3JlbWVudCBmb3IgZWFjaCBjaGlsZCBpbiBgbmV4dENoaWxkcmVuYCwgYnV0XG4gICAgICAvLyBgbGFzdEluZGV4YCB3aWxsIGJlIHRoZSBsYXN0IGluZGV4IHZpc2l0ZWQgaW4gYHByZXZDaGlsZHJlbmAuXG4gICAgICB2YXIgbGFzdEluZGV4ID0gMDtcbiAgICAgIHZhciBuZXh0SW5kZXggPSAwO1xuICAgICAgZm9yIChuYW1lIGluIG5leHRDaGlsZHJlbikge1xuICAgICAgICBpZiAoIW5leHRDaGlsZHJlbi5oYXNPd25Qcm9wZXJ0eShuYW1lKSkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIHZhciBwcmV2Q2hpbGQgPSBwcmV2Q2hpbGRyZW4gJiYgcHJldkNoaWxkcmVuW25hbWVdO1xuICAgICAgICB2YXIgcHJldkVsZW1lbnQgPSBwcmV2Q2hpbGQgJiYgcHJldkNoaWxkLl9jdXJyZW50RWxlbWVudDtcbiAgICAgICAgdmFyIG5leHRFbGVtZW50ID0gbmV4dENoaWxkcmVuW25hbWVdO1xuICAgICAgICBpZiAoc2hvdWxkVXBkYXRlUmVhY3RDb21wb25lbnQocHJldkVsZW1lbnQsIG5leHRFbGVtZW50KSkge1xuICAgICAgICAgIHRoaXMubW92ZUNoaWxkKHByZXZDaGlsZCwgbmV4dEluZGV4LCBsYXN0SW5kZXgpO1xuICAgICAgICAgIGxhc3RJbmRleCA9IE1hdGgubWF4KHByZXZDaGlsZC5fbW91bnRJbmRleCwgbGFzdEluZGV4KTtcbiAgICAgICAgICBwcmV2Q2hpbGQucmVjZWl2ZUNvbXBvbmVudChuZXh0RWxlbWVudCwgdHJhbnNhY3Rpb24pO1xuICAgICAgICAgIHByZXZDaGlsZC5fbW91bnRJbmRleCA9IG5leHRJbmRleDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBpZiAocHJldkNoaWxkKSB7XG4gICAgICAgICAgICAvLyBVcGRhdGUgYGxhc3RJbmRleGAgYmVmb3JlIGBfbW91bnRJbmRleGAgZ2V0cyB1bnNldCBieSB1bm1vdW50aW5nLlxuICAgICAgICAgICAgbGFzdEluZGV4ID0gTWF0aC5tYXgocHJldkNoaWxkLl9tb3VudEluZGV4LCBsYXN0SW5kZXgpO1xuICAgICAgICAgICAgdGhpcy5fdW5tb3VudENoaWxkQnlOYW1lKHByZXZDaGlsZCwgbmFtZSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIC8vIFRoZSBjaGlsZCBtdXN0IGJlIGluc3RhbnRpYXRlZCBiZWZvcmUgaXQncyBtb3VudGVkLlxuICAgICAgICAgIHZhciBuZXh0Q2hpbGRJbnN0YW5jZSA9IGluc3RhbnRpYXRlUmVhY3RDb21wb25lbnQoXG4gICAgICAgICAgICBuZXh0RWxlbWVudCxcbiAgICAgICAgICAgIG51bGxcbiAgICAgICAgICApO1xuICAgICAgICAgIHRoaXMuX21vdW50Q2hpbGRCeU5hbWVBdEluZGV4KFxuICAgICAgICAgICAgbmV4dENoaWxkSW5zdGFuY2UsIG5hbWUsIG5leHRJbmRleCwgdHJhbnNhY3Rpb25cbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIG5leHRJbmRleCsrO1xuICAgICAgfVxuICAgICAgLy8gUmVtb3ZlIGNoaWxkcmVuIHRoYXQgYXJlIG5vIGxvbmdlciBwcmVzZW50LlxuICAgICAgZm9yIChuYW1lIGluIHByZXZDaGlsZHJlbikge1xuICAgICAgICBpZiAocHJldkNoaWxkcmVuLmhhc093blByb3BlcnR5KG5hbWUpICYmXG4gICAgICAgICAgICAhKG5leHRDaGlsZHJlbiAmJiBuZXh0Q2hpbGRyZW5bbmFtZV0pKSB7XG4gICAgICAgICAgdGhpcy5fdW5tb3VudENoaWxkQnlOYW1lKHByZXZDaGlsZHJlbltuYW1lXSwgbmFtZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVW5tb3VudHMgYWxsIHJlbmRlcmVkIGNoaWxkcmVuLiBUaGlzIHNob3VsZCBiZSB1c2VkIHRvIGNsZWFuIHVwIGNoaWxkcmVuXG4gICAgICogd2hlbiB0aGlzIGNvbXBvbmVudCBpcyB1bm1vdW50ZWQuXG4gICAgICpcbiAgICAgKiBAaW50ZXJuYWxcbiAgICAgKi9cbiAgICB1bm1vdW50Q2hpbGRyZW46IGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIHJlbmRlcmVkQ2hpbGRyZW4gPSB0aGlzLl9yZW5kZXJlZENoaWxkcmVuO1xuICAgICAgZm9yICh2YXIgbmFtZSBpbiByZW5kZXJlZENoaWxkcmVuKSB7XG4gICAgICAgIHZhciByZW5kZXJlZENoaWxkID0gcmVuZGVyZWRDaGlsZHJlbltuYW1lXTtcbiAgICAgICAgLy8gVE9ETzogV2hlbiBpcyB0aGlzIG5vdCB0cnVlP1xuICAgICAgICBpZiAocmVuZGVyZWRDaGlsZC51bm1vdW50Q29tcG9uZW50KSB7XG4gICAgICAgICAgcmVuZGVyZWRDaGlsZC51bm1vdW50Q29tcG9uZW50KCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHRoaXMuX3JlbmRlcmVkQ2hpbGRyZW4gPSBudWxsO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBNb3ZlcyBhIGNoaWxkIGNvbXBvbmVudCB0byB0aGUgc3VwcGxpZWQgaW5kZXguXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1JlYWN0Q29tcG9uZW50fSBjaGlsZCBDb21wb25lbnQgdG8gbW92ZS5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gdG9JbmRleCBEZXN0aW5hdGlvbiBpbmRleCBvZiB0aGUgZWxlbWVudC5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gbGFzdEluZGV4IExhc3QgaW5kZXggdmlzaXRlZCBvZiB0aGUgc2libGluZ3Mgb2YgYGNoaWxkYC5cbiAgICAgKiBAcHJvdGVjdGVkXG4gICAgICovXG4gICAgbW92ZUNoaWxkOiBmdW5jdGlvbihjaGlsZCwgdG9JbmRleCwgbGFzdEluZGV4KSB7XG4gICAgICAvLyBJZiB0aGUgaW5kZXggb2YgYGNoaWxkYCBpcyBsZXNzIHRoYW4gYGxhc3RJbmRleGAsIHRoZW4gaXQgbmVlZHMgdG9cbiAgICAgIC8vIGJlIG1vdmVkLiBPdGhlcndpc2UsIHdlIGRvIG5vdCBuZWVkIHRvIG1vdmUgaXQgYmVjYXVzZSBhIGNoaWxkIHdpbGwgYmVcbiAgICAgIC8vIGluc2VydGVkIG9yIG1vdmVkIGJlZm9yZSBgY2hpbGRgLlxuICAgICAgaWYgKGNoaWxkLl9tb3VudEluZGV4IDwgbGFzdEluZGV4KSB7XG4gICAgICAgIGVucXVldWVNb3ZlKHRoaXMuX3Jvb3ROb2RlSUQsIGNoaWxkLl9tb3VudEluZGV4LCB0b0luZGV4KTtcbiAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIGNoaWxkIGNvbXBvbmVudC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7UmVhY3RDb21wb25lbnR9IGNoaWxkIENvbXBvbmVudCB0byBjcmVhdGUuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IG1vdW50SW1hZ2UgTWFya3VwIHRvIGluc2VydC5cbiAgICAgKiBAcHJvdGVjdGVkXG4gICAgICovXG4gICAgY3JlYXRlQ2hpbGQ6IGZ1bmN0aW9uKGNoaWxkLCBtb3VudEltYWdlKSB7XG4gICAgICBlbnF1ZXVlTWFya3VwKHRoaXMuX3Jvb3ROb2RlSUQsIG1vdW50SW1hZ2UsIGNoaWxkLl9tb3VudEluZGV4KTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlcyBhIGNoaWxkIGNvbXBvbmVudC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7UmVhY3RDb21wb25lbnR9IGNoaWxkIENoaWxkIHRvIHJlbW92ZS5cbiAgICAgKiBAcHJvdGVjdGVkXG4gICAgICovXG4gICAgcmVtb3ZlQ2hpbGQ6IGZ1bmN0aW9uKGNoaWxkKSB7XG4gICAgICBlbnF1ZXVlUmVtb3ZlKHRoaXMuX3Jvb3ROb2RlSUQsIGNoaWxkLl9tb3VudEluZGV4KTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU2V0cyB0aGlzIHRleHQgY29udGVudCBzdHJpbmcuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdGV4dENvbnRlbnQgVGV4dCBjb250ZW50IHRvIHNldC5cbiAgICAgKiBAcHJvdGVjdGVkXG4gICAgICovXG4gICAgc2V0VGV4dENvbnRlbnQ6IGZ1bmN0aW9uKHRleHRDb250ZW50KSB7XG4gICAgICBlbnF1ZXVlVGV4dENvbnRlbnQodGhpcy5fcm9vdE5vZGVJRCwgdGV4dENvbnRlbnQpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBNb3VudHMgYSBjaGlsZCB3aXRoIHRoZSBzdXBwbGllZCBuYW1lLlxuICAgICAqXG4gICAgICogTk9URTogVGhpcyBpcyBwYXJ0IG9mIGB1cGRhdGVDaGlsZHJlbmAgYW5kIGlzIGhlcmUgZm9yIHJlYWRhYmlsaXR5LlxuICAgICAqXG4gICAgICogQHBhcmFtIHtSZWFjdENvbXBvbmVudH0gY2hpbGQgQ29tcG9uZW50IHRvIG1vdW50LlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIE5hbWUgb2YgdGhlIGNoaWxkLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBpbmRleCBJbmRleCBhdCB3aGljaCB0byBpbnNlcnQgdGhlIGNoaWxkLlxuICAgICAqIEBwYXJhbSB7UmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbn0gdHJhbnNhY3Rpb25cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIF9tb3VudENoaWxkQnlOYW1lQXRJbmRleDogZnVuY3Rpb24oY2hpbGQsIG5hbWUsIGluZGV4LCB0cmFuc2FjdGlvbikge1xuICAgICAgLy8gSW5saW5lZCBmb3IgcGVyZm9ybWFuY2UsIHNlZSBgUmVhY3RJbnN0YW5jZUhhbmRsZXMuY3JlYXRlUmVhY3RJRGAuXG4gICAgICB2YXIgcm9vdElEID0gdGhpcy5fcm9vdE5vZGVJRCArIG5hbWU7XG4gICAgICB2YXIgbW91bnRJbWFnZSA9IGNoaWxkLm1vdW50Q29tcG9uZW50KFxuICAgICAgICByb290SUQsXG4gICAgICAgIHRyYW5zYWN0aW9uLFxuICAgICAgICB0aGlzLl9tb3VudERlcHRoICsgMVxuICAgICAgKTtcbiAgICAgIGNoaWxkLl9tb3VudEluZGV4ID0gaW5kZXg7XG4gICAgICB0aGlzLmNyZWF0ZUNoaWxkKGNoaWxkLCBtb3VudEltYWdlKTtcbiAgICAgIHRoaXMuX3JlbmRlcmVkQ2hpbGRyZW4gPSB0aGlzLl9yZW5kZXJlZENoaWxkcmVuIHx8IHt9O1xuICAgICAgdGhpcy5fcmVuZGVyZWRDaGlsZHJlbltuYW1lXSA9IGNoaWxkO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBVbm1vdW50cyBhIHJlbmRlcmVkIGNoaWxkIGJ5IG5hbWUuXG4gICAgICpcbiAgICAgKiBOT1RFOiBUaGlzIGlzIHBhcnQgb2YgYHVwZGF0ZUNoaWxkcmVuYCBhbmQgaXMgaGVyZSBmb3IgcmVhZGFiaWxpdHkuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1JlYWN0Q29tcG9uZW50fSBjaGlsZCBDb21wb25lbnQgdG8gdW5tb3VudC5cbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSBOYW1lIG9mIHRoZSBjaGlsZCBpbiBgdGhpcy5fcmVuZGVyZWRDaGlsZHJlbmAuXG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBfdW5tb3VudENoaWxkQnlOYW1lOiBmdW5jdGlvbihjaGlsZCwgbmFtZSkge1xuICAgICAgdGhpcy5yZW1vdmVDaGlsZChjaGlsZCk7XG4gICAgICBjaGlsZC5fbW91bnRJbmRleCA9IG51bGw7XG4gICAgICBjaGlsZC51bm1vdW50Q29tcG9uZW50KCk7XG4gICAgICBkZWxldGUgdGhpcy5fcmVuZGVyZWRDaGlsZHJlbltuYW1lXTtcbiAgICB9XG5cbiAgfVxuXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0TXVsdGlDaGlsZDtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdE11bHRpQ2hpbGRVcGRhdGVUeXBlc1xuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIga2V5TWlycm9yID0gcmVxdWlyZShcIi4va2V5TWlycm9yXCIpO1xuXG4vKipcbiAqIFdoZW4gYSBjb21wb25lbnQncyBjaGlsZHJlbiBhcmUgdXBkYXRlZCwgYSBzZXJpZXMgb2YgdXBkYXRlIGNvbmZpZ3VyYXRpb25cbiAqIG9iamVjdHMgYXJlIGNyZWF0ZWQgaW4gb3JkZXIgdG8gYmF0Y2ggYW5kIHNlcmlhbGl6ZSB0aGUgcmVxdWlyZWQgY2hhbmdlcy5cbiAqXG4gKiBFbnVtZXJhdGVzIGFsbCB0aGUgcG9zc2libGUgdHlwZXMgb2YgdXBkYXRlIGNvbmZpZ3VyYXRpb25zLlxuICpcbiAqIEBpbnRlcm5hbFxuICovXG52YXIgUmVhY3RNdWx0aUNoaWxkVXBkYXRlVHlwZXMgPSBrZXlNaXJyb3Ioe1xuICBJTlNFUlRfTUFSS1VQOiBudWxsLFxuICBNT1ZFX0VYSVNUSU5HOiBudWxsLFxuICBSRU1PVkVfTk9ERTogbnVsbCxcbiAgVEVYVF9DT05URU5UOiBudWxsXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdE11bHRpQ2hpbGRVcGRhdGVUeXBlcztcbiIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0TmF0aXZlQ29tcG9uZW50XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBhc3NpZ24gPSByZXF1aXJlKFwiLi9PYmplY3QuYXNzaWduXCIpO1xudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcblxudmFyIGdlbmVyaWNDb21wb25lbnRDbGFzcyA9IG51bGw7XG4vLyBUaGlzIHJlZ2lzdHJ5IGtlZXBzIHRyYWNrIG9mIHdyYXBwZXIgY2xhc3NlcyBhcm91bmQgbmF0aXZlIHRhZ3NcbnZhciB0YWdUb0NvbXBvbmVudENsYXNzID0ge307XG5cbnZhciBSZWFjdE5hdGl2ZUNvbXBvbmVudEluamVjdGlvbiA9IHtcbiAgLy8gVGhpcyBhY2NlcHRzIGEgY2xhc3MgdGhhdCByZWNlaXZlcyB0aGUgdGFnIHN0cmluZy4gVGhpcyBpcyBhIGNhdGNoIGFsbFxuICAvLyB0aGF0IGNhbiByZW5kZXIgYW55IGtpbmQgb2YgdGFnLlxuICBpbmplY3RHZW5lcmljQ29tcG9uZW50Q2xhc3M6IGZ1bmN0aW9uKGNvbXBvbmVudENsYXNzKSB7XG4gICAgZ2VuZXJpY0NvbXBvbmVudENsYXNzID0gY29tcG9uZW50Q2xhc3M7XG4gIH0sXG4gIC8vIFRoaXMgYWNjZXB0cyBhIGtleWVkIG9iamVjdCB3aXRoIGNsYXNzZXMgYXMgdmFsdWVzLiBFYWNoIGtleSByZXByZXNlbnRzIGFcbiAgLy8gdGFnLiBUaGF0IHBhcnRpY3VsYXIgdGFnIHdpbGwgdXNlIHRoaXMgY2xhc3MgaW5zdGVhZCBvZiB0aGUgZ2VuZXJpYyBvbmUuXG4gIGluamVjdENvbXBvbmVudENsYXNzZXM6IGZ1bmN0aW9uKGNvbXBvbmVudENsYXNzZXMpIHtcbiAgICBhc3NpZ24odGFnVG9Db21wb25lbnRDbGFzcywgY29tcG9uZW50Q2xhc3Nlcyk7XG4gIH1cbn07XG5cbi8qKlxuICogQ3JlYXRlIGFuIGludGVybmFsIGNsYXNzIGZvciBhIHNwZWNpZmljIHRhZy5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gdGFnIFRoZSB0YWcgZm9yIHdoaWNoIHRvIGNyZWF0ZSBhbiBpbnRlcm5hbCBpbnN0YW5jZS5cbiAqIEBwYXJhbSB7YW55fSBwcm9wcyBUaGUgcHJvcHMgcGFzc2VkIHRvIHRoZSBpbnN0YW5jZSBjb25zdHJ1Y3Rvci5cbiAqIEByZXR1cm4ge1JlYWN0Q29tcG9uZW50fSBjb21wb25lbnQgVGhlIGluamVjdGVkIGVtcHR5IGNvbXBvbmVudC5cbiAqL1xuZnVuY3Rpb24gY3JlYXRlSW5zdGFuY2VGb3JUYWcodGFnLCBwcm9wcywgcGFyZW50VHlwZSkge1xuICB2YXIgY29tcG9uZW50Q2xhc3MgPSB0YWdUb0NvbXBvbmVudENsYXNzW3RhZ107XG4gIGlmIChjb21wb25lbnRDbGFzcyA9PSBudWxsKSB7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgIGdlbmVyaWNDb21wb25lbnRDbGFzcyxcbiAgICAgICdUaGVyZSBpcyBubyByZWdpc3RlcmVkIGNvbXBvbmVudCBmb3IgdGhlIHRhZyAlcycsXG4gICAgICB0YWdcbiAgICApIDogaW52YXJpYW50KGdlbmVyaWNDb21wb25lbnRDbGFzcykpO1xuICAgIHJldHVybiBuZXcgZ2VuZXJpY0NvbXBvbmVudENsYXNzKHRhZywgcHJvcHMpO1xuICB9XG4gIGlmIChwYXJlbnRUeXBlID09PSB0YWcpIHtcbiAgICAvLyBBdm9pZCByZWN1cnNpb25cbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgZ2VuZXJpY0NvbXBvbmVudENsYXNzLFxuICAgICAgJ1RoZXJlIGlzIG5vIHJlZ2lzdGVyZWQgY29tcG9uZW50IGZvciB0aGUgdGFnICVzJyxcbiAgICAgIHRhZ1xuICAgICkgOiBpbnZhcmlhbnQoZ2VuZXJpY0NvbXBvbmVudENsYXNzKSk7XG4gICAgcmV0dXJuIG5ldyBnZW5lcmljQ29tcG9uZW50Q2xhc3ModGFnLCBwcm9wcyk7XG4gIH1cbiAgLy8gVW53cmFwIGxlZ2FjeSBmYWN0b3JpZXNcbiAgcmV0dXJuIG5ldyBjb21wb25lbnRDbGFzcy50eXBlKHByb3BzKTtcbn1cblxudmFyIFJlYWN0TmF0aXZlQ29tcG9uZW50ID0ge1xuICBjcmVhdGVJbnN0YW5jZUZvclRhZzogY3JlYXRlSW5zdGFuY2VGb3JUYWcsXG4gIGluamVjdGlvbjogUmVhY3ROYXRpdmVDb21wb25lbnRJbmplY3Rpb25cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3ROYXRpdmVDb21wb25lbnQ7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RPd25lclxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgZW1wdHlPYmplY3QgPSByZXF1aXJlKFwiLi9lbXB0eU9iamVjdFwiKTtcbnZhciBpbnZhcmlhbnQgPSByZXF1aXJlKFwiLi9pbnZhcmlhbnRcIik7XG5cbi8qKlxuICogUmVhY3RPd25lcnMgYXJlIGNhcGFibGUgb2Ygc3RvcmluZyByZWZlcmVuY2VzIHRvIG93bmVkIGNvbXBvbmVudHMuXG4gKlxuICogQWxsIGNvbXBvbmVudHMgYXJlIGNhcGFibGUgb2YgLy9iZWluZy8vIHJlZmVyZW5jZWQgYnkgb3duZXIgY29tcG9uZW50cywgYnV0XG4gKiBvbmx5IFJlYWN0T3duZXIgY29tcG9uZW50cyBhcmUgY2FwYWJsZSBvZiAvL3JlZmVyZW5jaW5nLy8gb3duZWQgY29tcG9uZW50cy5cbiAqIFRoZSBuYW1lZCByZWZlcmVuY2UgaXMga25vd24gYXMgYSBcInJlZlwiLlxuICpcbiAqIFJlZnMgYXJlIGF2YWlsYWJsZSB3aGVuIG1vdW50ZWQgYW5kIHVwZGF0ZWQgZHVyaW5nIHJlY29uY2lsaWF0aW9uLlxuICpcbiAqICAgdmFyIE15Q29tcG9uZW50ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe1xuICogICAgIHJlbmRlcjogZnVuY3Rpb24oKSB7XG4gKiAgICAgICByZXR1cm4gKFxuICogICAgICAgICA8ZGl2IG9uQ2xpY2s9e3RoaXMuaGFuZGxlQ2xpY2t9PlxuICogICAgICAgICAgIDxDdXN0b21Db21wb25lbnQgcmVmPVwiY3VzdG9tXCIgLz5cbiAqICAgICAgICAgPC9kaXY+XG4gKiAgICAgICApO1xuICogICAgIH0sXG4gKiAgICAgaGFuZGxlQ2xpY2s6IGZ1bmN0aW9uKCkge1xuICogICAgICAgdGhpcy5yZWZzLmN1c3RvbS5oYW5kbGVDbGljaygpO1xuICogICAgIH0sXG4gKiAgICAgY29tcG9uZW50RGlkTW91bnQ6IGZ1bmN0aW9uKCkge1xuICogICAgICAgdGhpcy5yZWZzLmN1c3RvbS5pbml0aWFsaXplKCk7XG4gKiAgICAgfVxuICogICB9KTtcbiAqXG4gKiBSZWZzIHNob3VsZCByYXJlbHkgYmUgdXNlZC4gV2hlbiByZWZzIGFyZSB1c2VkLCB0aGV5IHNob3VsZCBvbmx5IGJlIGRvbmUgdG9cbiAqIGNvbnRyb2wgZGF0YSB0aGF0IGlzIG5vdCBoYW5kbGVkIGJ5IFJlYWN0J3MgZGF0YSBmbG93LlxuICpcbiAqIEBjbGFzcyBSZWFjdE93bmVyXG4gKi9cbnZhciBSZWFjdE93bmVyID0ge1xuXG4gIC8qKlxuICAgKiBAcGFyYW0gez9vYmplY3R9IG9iamVjdFxuICAgKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIGBvYmplY3RgIGlzIGEgdmFsaWQgb3duZXIuXG4gICAqIEBmaW5hbFxuICAgKi9cbiAgaXNWYWxpZE93bmVyOiBmdW5jdGlvbihvYmplY3QpIHtcbiAgICByZXR1cm4gISEoXG4gICAgICBvYmplY3QgJiZcbiAgICAgIHR5cGVvZiBvYmplY3QuYXR0YWNoUmVmID09PSAnZnVuY3Rpb24nICYmXG4gICAgICB0eXBlb2Ygb2JqZWN0LmRldGFjaFJlZiA9PT0gJ2Z1bmN0aW9uJ1xuICAgICk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEFkZHMgYSBjb21wb25lbnQgYnkgcmVmIHRvIGFuIG93bmVyIGNvbXBvbmVudC5cbiAgICpcbiAgICogQHBhcmFtIHtSZWFjdENvbXBvbmVudH0gY29tcG9uZW50IENvbXBvbmVudCB0byByZWZlcmVuY2UuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSByZWYgTmFtZSBieSB3aGljaCB0byByZWZlciB0byB0aGUgY29tcG9uZW50LlxuICAgKiBAcGFyYW0ge1JlYWN0T3duZXJ9IG93bmVyIENvbXBvbmVudCBvbiB3aGljaCB0byByZWNvcmQgdGhlIHJlZi5cbiAgICogQGZpbmFsXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgYWRkQ29tcG9uZW50QXNSZWZUbzogZnVuY3Rpb24oY29tcG9uZW50LCByZWYsIG93bmVyKSB7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgIFJlYWN0T3duZXIuaXNWYWxpZE93bmVyKG93bmVyKSxcbiAgICAgICdhZGRDb21wb25lbnRBc1JlZlRvKC4uLik6IE9ubHkgYSBSZWFjdE93bmVyIGNhbiBoYXZlIHJlZnMuIFRoaXMgJyArXG4gICAgICAndXN1YWxseSBtZWFucyB0aGF0IHlvdVxcJ3JlIHRyeWluZyB0byBhZGQgYSByZWYgdG8gYSBjb21wb25lbnQgdGhhdCAnICtcbiAgICAgICdkb2VzblxcJ3QgaGF2ZSBhbiBvd25lciAodGhhdCBpcywgd2FzIG5vdCBjcmVhdGVkIGluc2lkZSBvZiBhbm90aGVyICcgK1xuICAgICAgJ2NvbXBvbmVudFxcJ3MgYHJlbmRlcmAgbWV0aG9kKS4gVHJ5IHJlbmRlcmluZyB0aGlzIGNvbXBvbmVudCBpbnNpZGUgb2YgJyArXG4gICAgICAnYSBuZXcgdG9wLWxldmVsIGNvbXBvbmVudCB3aGljaCB3aWxsIGhvbGQgdGhlIHJlZi4nXG4gICAgKSA6IGludmFyaWFudChSZWFjdE93bmVyLmlzVmFsaWRPd25lcihvd25lcikpKTtcbiAgICBvd25lci5hdHRhY2hSZWYocmVmLCBjb21wb25lbnQpO1xuICB9LFxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIGEgY29tcG9uZW50IGJ5IHJlZiBmcm9tIGFuIG93bmVyIGNvbXBvbmVudC5cbiAgICpcbiAgICogQHBhcmFtIHtSZWFjdENvbXBvbmVudH0gY29tcG9uZW50IENvbXBvbmVudCB0byBkZXJlZmVyZW5jZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHJlZiBOYW1lIG9mIHRoZSByZWYgdG8gcmVtb3ZlLlxuICAgKiBAcGFyYW0ge1JlYWN0T3duZXJ9IG93bmVyIENvbXBvbmVudCBvbiB3aGljaCB0aGUgcmVmIGlzIHJlY29yZGVkLlxuICAgKiBAZmluYWxcbiAgICogQGludGVybmFsXG4gICAqL1xuICByZW1vdmVDb21wb25lbnRBc1JlZkZyb206IGZ1bmN0aW9uKGNvbXBvbmVudCwgcmVmLCBvd25lcikge1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICBSZWFjdE93bmVyLmlzVmFsaWRPd25lcihvd25lciksXG4gICAgICAncmVtb3ZlQ29tcG9uZW50QXNSZWZGcm9tKC4uLik6IE9ubHkgYSBSZWFjdE93bmVyIGNhbiBoYXZlIHJlZnMuIFRoaXMgJyArXG4gICAgICAndXN1YWxseSBtZWFucyB0aGF0IHlvdVxcJ3JlIHRyeWluZyB0byByZW1vdmUgYSByZWYgdG8gYSBjb21wb25lbnQgdGhhdCAnICtcbiAgICAgICdkb2VzblxcJ3QgaGF2ZSBhbiBvd25lciAodGhhdCBpcywgd2FzIG5vdCBjcmVhdGVkIGluc2lkZSBvZiBhbm90aGVyICcgK1xuICAgICAgJ2NvbXBvbmVudFxcJ3MgYHJlbmRlcmAgbWV0aG9kKS4gVHJ5IHJlbmRlcmluZyB0aGlzIGNvbXBvbmVudCBpbnNpZGUgb2YgJyArXG4gICAgICAnYSBuZXcgdG9wLWxldmVsIGNvbXBvbmVudCB3aGljaCB3aWxsIGhvbGQgdGhlIHJlZi4nXG4gICAgKSA6IGludmFyaWFudChSZWFjdE93bmVyLmlzVmFsaWRPd25lcihvd25lcikpKTtcbiAgICAvLyBDaGVjayB0aGF0IGBjb21wb25lbnRgIGlzIHN0aWxsIHRoZSBjdXJyZW50IHJlZiBiZWNhdXNlIHdlIGRvIG5vdCB3YW50IHRvXG4gICAgLy8gZGV0YWNoIHRoZSByZWYgaWYgYW5vdGhlciBjb21wb25lbnQgc3RvbGUgaXQuXG4gICAgaWYgKG93bmVyLnJlZnNbcmVmXSA9PT0gY29tcG9uZW50KSB7XG4gICAgICBvd25lci5kZXRhY2hSZWYocmVmKTtcbiAgICB9XG4gIH0sXG5cbiAgLyoqXG4gICAqIEEgUmVhY3RDb21wb25lbnQgbXVzdCBtaXggdGhpcyBpbiB0byBoYXZlIHJlZnMuXG4gICAqXG4gICAqIEBsZW5kcyB7UmVhY3RPd25lci5wcm90b3R5cGV9XG4gICAqL1xuICBNaXhpbjoge1xuXG4gICAgY29uc3RydWN0OiBmdW5jdGlvbigpIHtcbiAgICAgIHRoaXMucmVmcyA9IGVtcHR5T2JqZWN0O1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBMYXppbHkgYWxsb2NhdGVzIHRoZSByZWZzIG9iamVjdCBhbmQgc3RvcmVzIGBjb21wb25lbnRgIGFzIGByZWZgLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHJlZiBSZWZlcmVuY2UgbmFtZS5cbiAgICAgKiBAcGFyYW0ge2NvbXBvbmVudH0gY29tcG9uZW50IENvbXBvbmVudCB0byBzdG9yZSBhcyBgcmVmYC5cbiAgICAgKiBAZmluYWxcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIGF0dGFjaFJlZjogZnVuY3Rpb24ocmVmLCBjb21wb25lbnQpIHtcbiAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgIGNvbXBvbmVudC5pc093bmVkQnkodGhpcyksXG4gICAgICAgICdhdHRhY2hSZWYoJXMsIC4uLik6IE9ubHkgYSBjb21wb25lbnRcXCdzIG93bmVyIGNhbiBzdG9yZSBhIHJlZiB0byBpdC4nLFxuICAgICAgICByZWZcbiAgICAgICkgOiBpbnZhcmlhbnQoY29tcG9uZW50LmlzT3duZWRCeSh0aGlzKSkpO1xuICAgICAgdmFyIHJlZnMgPSB0aGlzLnJlZnMgPT09IGVtcHR5T2JqZWN0ID8gKHRoaXMucmVmcyA9IHt9KSA6IHRoaXMucmVmcztcbiAgICAgIHJlZnNbcmVmXSA9IGNvbXBvbmVudDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogRGV0YWNoZXMgYSByZWZlcmVuY2UgbmFtZS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSByZWYgTmFtZSB0byBkZXJlZmVyZW5jZS5cbiAgICAgKiBAZmluYWxcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIGRldGFjaFJlZjogZnVuY3Rpb24ocmVmKSB7XG4gICAgICBkZWxldGUgdGhpcy5yZWZzW3JlZl07XG4gICAgfVxuXG4gIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdE93bmVyO1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0UGVyZlxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxuLyoqXG4gKiBSZWFjdFBlcmYgaXMgYSBnZW5lcmFsIEFPUCBzeXN0ZW0gZGVzaWduZWQgdG8gbWVhc3VyZSBwZXJmb3JtYW5jZS4gVGhpc1xuICogbW9kdWxlIG9ubHkgaGFzIHRoZSBob29rczogc2VlIFJlYWN0RGVmYXVsdFBlcmYgZm9yIHRoZSBhbmFseXNpcyB0b29sLlxuICovXG52YXIgUmVhY3RQZXJmID0ge1xuICAvKipcbiAgICogQm9vbGVhbiB0byBlbmFibGUvZGlzYWJsZSBtZWFzdXJlbWVudC4gU2V0IHRvIGZhbHNlIGJ5IGRlZmF1bHQgdG8gcHJldmVudFxuICAgKiBhY2NpZGVudGFsIGxvZ2dpbmcgYW5kIHBlcmYgbG9zcy5cbiAgICovXG4gIGVuYWJsZU1lYXN1cmU6IGZhbHNlLFxuXG4gIC8qKlxuICAgKiBIb2xkcyBvbnRvIHRoZSBtZWFzdXJlIGZ1bmN0aW9uIGluIHVzZS4gQnkgZGVmYXVsdCwgZG9uJ3QgbWVhc3VyZVxuICAgKiBhbnl0aGluZywgYnV0IHdlJ2xsIG92ZXJyaWRlIHRoaXMgaWYgd2UgaW5qZWN0IGEgbWVhc3VyZSBmdW5jdGlvbi5cbiAgICovXG4gIHN0b3JlZE1lYXN1cmU6IF9ub01lYXN1cmUsXG5cbiAgLyoqXG4gICAqIFVzZSB0aGlzIHRvIHdyYXAgbWV0aG9kcyB5b3Ugd2FudCB0byBtZWFzdXJlLiBaZXJvIG92ZXJoZWFkIGluIHByb2R1Y3Rpb24uXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBvYmpOYW1lXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBmbk5hbWVcbiAgICogQHBhcmFtIHtmdW5jdGlvbn0gZnVuY1xuICAgKiBAcmV0dXJuIHtmdW5jdGlvbn1cbiAgICovXG4gIG1lYXN1cmU6IGZ1bmN0aW9uKG9iak5hbWUsIGZuTmFtZSwgZnVuYykge1xuICAgIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgIHZhciBtZWFzdXJlZEZ1bmMgPSBudWxsO1xuICAgICAgdmFyIHdyYXBwZXIgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgaWYgKFJlYWN0UGVyZi5lbmFibGVNZWFzdXJlKSB7XG4gICAgICAgICAgaWYgKCFtZWFzdXJlZEZ1bmMpIHtcbiAgICAgICAgICAgIG1lYXN1cmVkRnVuYyA9IFJlYWN0UGVyZi5zdG9yZWRNZWFzdXJlKG9iak5hbWUsIGZuTmFtZSwgZnVuYyk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiBtZWFzdXJlZEZ1bmMuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZnVuYy5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgfTtcbiAgICAgIHdyYXBwZXIuZGlzcGxheU5hbWUgPSBvYmpOYW1lICsgJ18nICsgZm5OYW1lO1xuICAgICAgcmV0dXJuIHdyYXBwZXI7XG4gICAgfVxuICAgIHJldHVybiBmdW5jO1xuICB9LFxuXG4gIGluamVjdGlvbjoge1xuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7ZnVuY3Rpb259IG1lYXN1cmVcbiAgICAgKi9cbiAgICBpbmplY3RNZWFzdXJlOiBmdW5jdGlvbihtZWFzdXJlKSB7XG4gICAgICBSZWFjdFBlcmYuc3RvcmVkTWVhc3VyZSA9IG1lYXN1cmU7XG4gICAgfVxuICB9XG59O1xuXG4vKipcbiAqIFNpbXBseSBwYXNzZXMgdGhyb3VnaCB0aGUgbWVhc3VyZWQgZnVuY3Rpb24sIHdpdGhvdXQgbWVhc3VyaW5nIGl0LlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBvYmpOYW1lXG4gKiBAcGFyYW0ge3N0cmluZ30gZm5OYW1lXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBmdW5jXG4gKiBAcmV0dXJuIHtmdW5jdGlvbn1cbiAqL1xuZnVuY3Rpb24gX25vTWVhc3VyZShvYmpOYW1lLCBmbk5hbWUsIGZ1bmMpIHtcbiAgcmV0dXJuIGZ1bmM7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RQZXJmO1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0UHJvcFRyYW5zZmVyZXJcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIGFzc2lnbiA9IHJlcXVpcmUoXCIuL09iamVjdC5hc3NpZ25cIik7XG52YXIgZW1wdHlGdW5jdGlvbiA9IHJlcXVpcmUoXCIuL2VtcHR5RnVuY3Rpb25cIik7XG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xudmFyIGpvaW5DbGFzc2VzID0gcmVxdWlyZShcIi4vam9pbkNsYXNzZXNcIik7XG52YXIgd2FybmluZyA9IHJlcXVpcmUoXCIuL3dhcm5pbmdcIik7XG5cbnZhciBkaWRXYXJuID0gZmFsc2U7XG5cbi8qKlxuICogQ3JlYXRlcyBhIHRyYW5zZmVyIHN0cmF0ZWd5IHRoYXQgd2lsbCBtZXJnZSBwcm9wIHZhbHVlcyB1c2luZyB0aGUgc3VwcGxpZWRcbiAqIGBtZXJnZVN0cmF0ZWd5YC4gSWYgYSBwcm9wIHdhcyBwcmV2aW91c2x5IHVuc2V0LCB0aGlzIGp1c3Qgc2V0cyBpdC5cbiAqXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBtZXJnZVN0cmF0ZWd5XG4gKiBAcmV0dXJuIHtmdW5jdGlvbn1cbiAqL1xuZnVuY3Rpb24gY3JlYXRlVHJhbnNmZXJTdHJhdGVneShtZXJnZVN0cmF0ZWd5KSB7XG4gIHJldHVybiBmdW5jdGlvbihwcm9wcywga2V5LCB2YWx1ZSkge1xuICAgIGlmICghcHJvcHMuaGFzT3duUHJvcGVydHkoa2V5KSkge1xuICAgICAgcHJvcHNba2V5XSA9IHZhbHVlO1xuICAgIH0gZWxzZSB7XG4gICAgICBwcm9wc1trZXldID0gbWVyZ2VTdHJhdGVneShwcm9wc1trZXldLCB2YWx1ZSk7XG4gICAgfVxuICB9O1xufVxuXG52YXIgdHJhbnNmZXJTdHJhdGVneU1lcmdlID0gY3JlYXRlVHJhbnNmZXJTdHJhdGVneShmdW5jdGlvbihhLCBiKSB7XG4gIC8vIGBtZXJnZWAgb3ZlcnJpZGVzIHRoZSBmaXJzdCBvYmplY3QncyAoYHByb3BzW2tleV1gIGFib3ZlKSBrZXlzIHVzaW5nIHRoZVxuICAvLyBzZWNvbmQgb2JqZWN0J3MgKGB2YWx1ZWApIGtleXMuIEFuIG9iamVjdCdzIHN0eWxlJ3MgZXhpc3RpbmcgYHByb3BBYCB3b3VsZFxuICAvLyBnZXQgb3ZlcnJpZGRlbi4gRmxpcCB0aGUgb3JkZXIgaGVyZS5cbiAgcmV0dXJuIGFzc2lnbih7fSwgYiwgYSk7XG59KTtcblxuLyoqXG4gKiBUcmFuc2ZlciBzdHJhdGVnaWVzIGRpY3RhdGUgaG93IHByb3BzIGFyZSB0cmFuc2ZlcnJlZCBieSBgdHJhbnNmZXJQcm9wc1RvYC5cbiAqIE5PVEU6IGlmIHlvdSBhZGQgYW55IG1vcmUgZXhjZXB0aW9ucyB0byB0aGlzIGxpc3QgeW91IHNob3VsZCBiZSBzdXJlIHRvXG4gKiB1cGRhdGUgYGNsb25lV2l0aFByb3BzKClgIGFjY29yZGluZ2x5LlxuICovXG52YXIgVHJhbnNmZXJTdHJhdGVnaWVzID0ge1xuICAvKipcbiAgICogTmV2ZXIgdHJhbnNmZXIgYGNoaWxkcmVuYC5cbiAgICovXG4gIGNoaWxkcmVuOiBlbXB0eUZ1bmN0aW9uLFxuICAvKipcbiAgICogVHJhbnNmZXIgdGhlIGBjbGFzc05hbWVgIHByb3AgYnkgbWVyZ2luZyB0aGVtLlxuICAgKi9cbiAgY2xhc3NOYW1lOiBjcmVhdGVUcmFuc2ZlclN0cmF0ZWd5KGpvaW5DbGFzc2VzKSxcbiAgLyoqXG4gICAqIFRyYW5zZmVyIHRoZSBgc3R5bGVgIHByb3AgKHdoaWNoIGlzIGFuIG9iamVjdCkgYnkgbWVyZ2luZyB0aGVtLlxuICAgKi9cbiAgc3R5bGU6IHRyYW5zZmVyU3RyYXRlZ3lNZXJnZVxufTtcblxuLyoqXG4gKiBNdXRhdGVzIHRoZSBmaXJzdCBhcmd1bWVudCBieSB0cmFuc2ZlcnJpbmcgdGhlIHByb3BlcnRpZXMgZnJvbSB0aGUgc2Vjb25kXG4gKiBhcmd1bWVudC5cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gcHJvcHNcbiAqIEBwYXJhbSB7b2JqZWN0fSBuZXdQcm9wc1xuICogQHJldHVybiB7b2JqZWN0fVxuICovXG5mdW5jdGlvbiB0cmFuc2ZlckludG8ocHJvcHMsIG5ld1Byb3BzKSB7XG4gIGZvciAodmFyIHRoaXNLZXkgaW4gbmV3UHJvcHMpIHtcbiAgICBpZiAoIW5ld1Byb3BzLmhhc093blByb3BlcnR5KHRoaXNLZXkpKSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICB2YXIgdHJhbnNmZXJTdHJhdGVneSA9IFRyYW5zZmVyU3RyYXRlZ2llc1t0aGlzS2V5XTtcblxuICAgIGlmICh0cmFuc2ZlclN0cmF0ZWd5ICYmIFRyYW5zZmVyU3RyYXRlZ2llcy5oYXNPd25Qcm9wZXJ0eSh0aGlzS2V5KSkge1xuICAgICAgdHJhbnNmZXJTdHJhdGVneShwcm9wcywgdGhpc0tleSwgbmV3UHJvcHNbdGhpc0tleV0pO1xuICAgIH0gZWxzZSBpZiAoIXByb3BzLmhhc093blByb3BlcnR5KHRoaXNLZXkpKSB7XG4gICAgICBwcm9wc1t0aGlzS2V5XSA9IG5ld1Byb3BzW3RoaXNLZXldO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcHJvcHM7XG59XG5cbi8qKlxuICogUmVhY3RQcm9wVHJhbnNmZXJlciBhcmUgY2FwYWJsZSBvZiB0cmFuc2ZlcnJpbmcgcHJvcHMgdG8gYW5vdGhlciBjb21wb25lbnRcbiAqIHVzaW5nIGEgYHRyYW5zZmVyUHJvcHNUb2AgbWV0aG9kLlxuICpcbiAqIEBjbGFzcyBSZWFjdFByb3BUcmFuc2ZlcmVyXG4gKi9cbnZhciBSZWFjdFByb3BUcmFuc2ZlcmVyID0ge1xuXG4gIFRyYW5zZmVyU3RyYXRlZ2llczogVHJhbnNmZXJTdHJhdGVnaWVzLFxuXG4gIC8qKlxuICAgKiBNZXJnZSB0d28gcHJvcHMgb2JqZWN0cyB1c2luZyBUcmFuc2ZlclN0cmF0ZWdpZXMuXG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBvbGRQcm9wcyBvcmlnaW5hbCBwcm9wcyAodGhleSB0YWtlIHByZWNlZGVuY2UpXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBuZXdQcm9wcyBuZXcgcHJvcHMgdG8gbWVyZ2UgaW5cbiAgICogQHJldHVybiB7b2JqZWN0fSBhIG5ldyBvYmplY3QgY29udGFpbmluZyBib3RoIHNldHMgb2YgcHJvcHMgbWVyZ2VkLlxuICAgKi9cbiAgbWVyZ2VQcm9wczogZnVuY3Rpb24ob2xkUHJvcHMsIG5ld1Byb3BzKSB7XG4gICAgcmV0dXJuIHRyYW5zZmVySW50byhhc3NpZ24oe30sIG9sZFByb3BzKSwgbmV3UHJvcHMpO1xuICB9LFxuXG4gIC8qKlxuICAgKiBAbGVuZHMge1JlYWN0UHJvcFRyYW5zZmVyZXIucHJvdG90eXBlfVxuICAgKi9cbiAgTWl4aW46IHtcblxuICAgIC8qKlxuICAgICAqIFRyYW5zZmVyIHByb3BzIGZyb20gdGhpcyBjb21wb25lbnQgdG8gYSB0YXJnZXQgY29tcG9uZW50LlxuICAgICAqXG4gICAgICogUHJvcHMgdGhhdCBkbyBub3QgaGF2ZSBhbiBleHBsaWNpdCB0cmFuc2ZlciBzdHJhdGVneSB3aWxsIGJlIHRyYW5zZmVycmVkXG4gICAgICogb25seSBpZiB0aGUgdGFyZ2V0IGNvbXBvbmVudCBkb2VzIG5vdCBhbHJlYWR5IGhhdmUgdGhlIHByb3Agc2V0LlxuICAgICAqXG4gICAgICogVGhpcyBpcyB1c3VhbGx5IHVzZWQgdG8gcGFzcyBkb3duIHByb3BzIHRvIGEgcmV0dXJuZWQgcm9vdCBjb21wb25lbnQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1JlYWN0RWxlbWVudH0gZWxlbWVudCBDb21wb25lbnQgcmVjZWl2aW5nIHRoZSBwcm9wZXJ0aWVzLlxuICAgICAqIEByZXR1cm4ge1JlYWN0RWxlbWVudH0gVGhlIHN1cHBsaWVkIGBjb21wb25lbnRgLlxuICAgICAqIEBmaW5hbFxuICAgICAqIEBwcm90ZWN0ZWRcbiAgICAgKi9cbiAgICB0cmFuc2ZlclByb3BzVG86IGZ1bmN0aW9uKGVsZW1lbnQpIHtcbiAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgIGVsZW1lbnQuX293bmVyID09PSB0aGlzLFxuICAgICAgICAnJXM6IFlvdSBjYW5cXCd0IGNhbGwgdHJhbnNmZXJQcm9wc1RvKCkgb24gYSBjb21wb25lbnQgdGhhdCB5b3UgJyArXG4gICAgICAgICdkb25cXCd0IG93biwgJXMuIFRoaXMgdXN1YWxseSBtZWFucyB5b3UgYXJlIGNhbGxpbmcgJyArXG4gICAgICAgICd0cmFuc2ZlclByb3BzVG8oKSBvbiBhIGNvbXBvbmVudCBwYXNzZWQgaW4gYXMgcHJvcHMgb3IgY2hpbGRyZW4uJyxcbiAgICAgICAgdGhpcy5jb25zdHJ1Y3Rvci5kaXNwbGF5TmFtZSxcbiAgICAgICAgdHlwZW9mIGVsZW1lbnQudHlwZSA9PT0gJ3N0cmluZycgP1xuICAgICAgICBlbGVtZW50LnR5cGUgOlxuICAgICAgICBlbGVtZW50LnR5cGUuZGlzcGxheU5hbWVcbiAgICAgICkgOiBpbnZhcmlhbnQoZWxlbWVudC5fb3duZXIgPT09IHRoaXMpKTtcblxuICAgICAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgICBpZiAoIWRpZFdhcm4pIHtcbiAgICAgICAgICBkaWRXYXJuID0gdHJ1ZTtcbiAgICAgICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gd2FybmluZyhcbiAgICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgICAgJ3RyYW5zZmVyUHJvcHNUbyBpcyBkZXByZWNhdGVkLiAnICtcbiAgICAgICAgICAgICdTZWUgaHR0cDovL2ZiLm1lL3JlYWN0LXRyYW5zZmVycHJvcHN0byBmb3IgbW9yZSBpbmZvcm1hdGlvbi4nXG4gICAgICAgICAgKSA6IG51bGwpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIEJlY2F1c2UgZWxlbWVudHMgYXJlIGltbXV0YWJsZSB3ZSBoYXZlIHRvIG1lcmdlIGludG8gdGhlIGV4aXN0aW5nXG4gICAgICAvLyBwcm9wcyBvYmplY3QgcmF0aGVyIHRoYW4gY2xvbmUgaXQuXG4gICAgICB0cmFuc2ZlckludG8oZWxlbWVudC5wcm9wcywgdGhpcy5wcm9wcyk7XG5cbiAgICAgIHJldHVybiBlbGVtZW50O1xuICAgIH1cblxuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0UHJvcFRyYW5zZmVyZXI7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RQcm9wVHlwZUxvY2F0aW9uTmFtZXNcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFJlYWN0UHJvcFR5cGVMb2NhdGlvbk5hbWVzID0ge307XG5cbmlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgUmVhY3RQcm9wVHlwZUxvY2F0aW9uTmFtZXMgPSB7XG4gICAgcHJvcDogJ3Byb3AnLFxuICAgIGNvbnRleHQ6ICdjb250ZXh0JyxcbiAgICBjaGlsZENvbnRleHQ6ICdjaGlsZCBjb250ZXh0J1xuICB9O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0UHJvcFR5cGVMb2NhdGlvbk5hbWVzO1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RQcm9wVHlwZUxvY2F0aW9uc1xuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIga2V5TWlycm9yID0gcmVxdWlyZShcIi4va2V5TWlycm9yXCIpO1xuXG52YXIgUmVhY3RQcm9wVHlwZUxvY2F0aW9ucyA9IGtleU1pcnJvcih7XG4gIHByb3A6IG51bGwsXG4gIGNvbnRleHQ6IG51bGwsXG4gIGNoaWxkQ29udGV4dDogbnVsbFxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RQcm9wVHlwZUxvY2F0aW9ucztcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdFByb3BUeXBlc1xuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgUmVhY3RFbGVtZW50ID0gcmVxdWlyZShcIi4vUmVhY3RFbGVtZW50XCIpO1xudmFyIFJlYWN0UHJvcFR5cGVMb2NhdGlvbk5hbWVzID0gcmVxdWlyZShcIi4vUmVhY3RQcm9wVHlwZUxvY2F0aW9uTmFtZXNcIik7XG5cbnZhciBkZXByZWNhdGVkID0gcmVxdWlyZShcIi4vZGVwcmVjYXRlZFwiKTtcbnZhciBlbXB0eUZ1bmN0aW9uID0gcmVxdWlyZShcIi4vZW1wdHlGdW5jdGlvblwiKTtcblxuLyoqXG4gKiBDb2xsZWN0aW9uIG9mIG1ldGhvZHMgdGhhdCBhbGxvdyBkZWNsYXJhdGlvbiBhbmQgdmFsaWRhdGlvbiBvZiBwcm9wcyB0aGF0IGFyZVxuICogc3VwcGxpZWQgdG8gUmVhY3QgY29tcG9uZW50cy4gRXhhbXBsZSB1c2FnZTpcbiAqXG4gKiAgIHZhciBQcm9wcyA9IHJlcXVpcmUoJ1JlYWN0UHJvcFR5cGVzJyk7XG4gKiAgIHZhciBNeUFydGljbGUgPSBSZWFjdC5jcmVhdGVDbGFzcyh7XG4gKiAgICAgcHJvcFR5cGVzOiB7XG4gKiAgICAgICAvLyBBbiBvcHRpb25hbCBzdHJpbmcgcHJvcCBuYW1lZCBcImRlc2NyaXB0aW9uXCIuXG4gKiAgICAgICBkZXNjcmlwdGlvbjogUHJvcHMuc3RyaW5nLFxuICpcbiAqICAgICAgIC8vIEEgcmVxdWlyZWQgZW51bSBwcm9wIG5hbWVkIFwiY2F0ZWdvcnlcIi5cbiAqICAgICAgIGNhdGVnb3J5OiBQcm9wcy5vbmVPZihbJ05ld3MnLCdQaG90b3MnXSkuaXNSZXF1aXJlZCxcbiAqXG4gKiAgICAgICAvLyBBIHByb3AgbmFtZWQgXCJkaWFsb2dcIiB0aGF0IHJlcXVpcmVzIGFuIGluc3RhbmNlIG9mIERpYWxvZy5cbiAqICAgICAgIGRpYWxvZzogUHJvcHMuaW5zdGFuY2VPZihEaWFsb2cpLmlzUmVxdWlyZWRcbiAqICAgICB9LFxuICogICAgIHJlbmRlcjogZnVuY3Rpb24oKSB7IC4uLiB9XG4gKiAgIH0pO1xuICpcbiAqIEEgbW9yZSBmb3JtYWwgc3BlY2lmaWNhdGlvbiBvZiBob3cgdGhlc2UgbWV0aG9kcyBhcmUgdXNlZDpcbiAqXG4gKiAgIHR5cGUgOj0gYXJyYXl8Ym9vbHxmdW5jfG9iamVjdHxudW1iZXJ8c3RyaW5nfG9uZU9mKFsuLi5dKXxpbnN0YW5jZU9mKC4uLilcbiAqICAgZGVjbCA6PSBSZWFjdFByb3BUeXBlcy57dHlwZX0oLmlzUmVxdWlyZWQpP1xuICpcbiAqIEVhY2ggYW5kIGV2ZXJ5IGRlY2xhcmF0aW9uIHByb2R1Y2VzIGEgZnVuY3Rpb24gd2l0aCB0aGUgc2FtZSBzaWduYXR1cmUuIFRoaXNcbiAqIGFsbG93cyB0aGUgY3JlYXRpb24gb2YgY3VzdG9tIHZhbGlkYXRpb24gZnVuY3Rpb25zLiBGb3IgZXhhbXBsZTpcbiAqXG4gKiAgdmFyIE15TGluayA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtcbiAqICAgIHByb3BUeXBlczoge1xuICogICAgICAvLyBBbiBvcHRpb25hbCBzdHJpbmcgb3IgVVJJIHByb3AgbmFtZWQgXCJocmVmXCIuXG4gKiAgICAgIGhyZWY6IGZ1bmN0aW9uKHByb3BzLCBwcm9wTmFtZSwgY29tcG9uZW50TmFtZSkge1xuICogICAgICAgIHZhciBwcm9wVmFsdWUgPSBwcm9wc1twcm9wTmFtZV07XG4gKiAgICAgICAgaWYgKHByb3BWYWx1ZSAhPSBudWxsICYmIHR5cGVvZiBwcm9wVmFsdWUgIT09ICdzdHJpbmcnICYmXG4gKiAgICAgICAgICAgICEocHJvcFZhbHVlIGluc3RhbmNlb2YgVVJJKSkge1xuICogICAgICAgICAgcmV0dXJuIG5ldyBFcnJvcihcbiAqICAgICAgICAgICAgJ0V4cGVjdGVkIGEgc3RyaW5nIG9yIGFuIFVSSSBmb3IgJyArIHByb3BOYW1lICsgJyBpbiAnICtcbiAqICAgICAgICAgICAgY29tcG9uZW50TmFtZVxuICogICAgICAgICAgKTtcbiAqICAgICAgICB9XG4gKiAgICAgIH1cbiAqICAgIH0sXG4gKiAgICByZW5kZXI6IGZ1bmN0aW9uKCkgey4uLn1cbiAqICB9KTtcbiAqXG4gKiBAaW50ZXJuYWxcbiAqL1xuXG52YXIgQU5PTllNT1VTID0gJzw8YW5vbnltb3VzPj4nO1xuXG52YXIgZWxlbWVudFR5cGVDaGVja2VyID0gY3JlYXRlRWxlbWVudFR5cGVDaGVja2VyKCk7XG52YXIgbm9kZVR5cGVDaGVja2VyID0gY3JlYXRlTm9kZUNoZWNrZXIoKTtcblxudmFyIFJlYWN0UHJvcFR5cGVzID0ge1xuICBhcnJheTogY3JlYXRlUHJpbWl0aXZlVHlwZUNoZWNrZXIoJ2FycmF5JyksXG4gIGJvb2w6IGNyZWF0ZVByaW1pdGl2ZVR5cGVDaGVja2VyKCdib29sZWFuJyksXG4gIGZ1bmM6IGNyZWF0ZVByaW1pdGl2ZVR5cGVDaGVja2VyKCdmdW5jdGlvbicpLFxuICBudW1iZXI6IGNyZWF0ZVByaW1pdGl2ZVR5cGVDaGVja2VyKCdudW1iZXInKSxcbiAgb2JqZWN0OiBjcmVhdGVQcmltaXRpdmVUeXBlQ2hlY2tlcignb2JqZWN0JyksXG4gIHN0cmluZzogY3JlYXRlUHJpbWl0aXZlVHlwZUNoZWNrZXIoJ3N0cmluZycpLFxuXG4gIGFueTogY3JlYXRlQW55VHlwZUNoZWNrZXIoKSxcbiAgYXJyYXlPZjogY3JlYXRlQXJyYXlPZlR5cGVDaGVja2VyLFxuICBlbGVtZW50OiBlbGVtZW50VHlwZUNoZWNrZXIsXG4gIGluc3RhbmNlT2Y6IGNyZWF0ZUluc3RhbmNlVHlwZUNoZWNrZXIsXG4gIG5vZGU6IG5vZGVUeXBlQ2hlY2tlcixcbiAgb2JqZWN0T2Y6IGNyZWF0ZU9iamVjdE9mVHlwZUNoZWNrZXIsXG4gIG9uZU9mOiBjcmVhdGVFbnVtVHlwZUNoZWNrZXIsXG4gIG9uZU9mVHlwZTogY3JlYXRlVW5pb25UeXBlQ2hlY2tlcixcbiAgc2hhcGU6IGNyZWF0ZVNoYXBlVHlwZUNoZWNrZXIsXG5cbiAgY29tcG9uZW50OiBkZXByZWNhdGVkKFxuICAgICdSZWFjdC5Qcm9wVHlwZXMnLFxuICAgICdjb21wb25lbnQnLFxuICAgICdlbGVtZW50JyxcbiAgICB0aGlzLFxuICAgIGVsZW1lbnRUeXBlQ2hlY2tlclxuICApLFxuICByZW5kZXJhYmxlOiBkZXByZWNhdGVkKFxuICAgICdSZWFjdC5Qcm9wVHlwZXMnLFxuICAgICdyZW5kZXJhYmxlJyxcbiAgICAnbm9kZScsXG4gICAgdGhpcyxcbiAgICBub2RlVHlwZUNoZWNrZXJcbiAgKVxufTtcblxuZnVuY3Rpb24gY3JlYXRlQ2hhaW5hYmxlVHlwZUNoZWNrZXIodmFsaWRhdGUpIHtcbiAgZnVuY3Rpb24gY2hlY2tUeXBlKGlzUmVxdWlyZWQsIHByb3BzLCBwcm9wTmFtZSwgY29tcG9uZW50TmFtZSwgbG9jYXRpb24pIHtcbiAgICBjb21wb25lbnROYW1lID0gY29tcG9uZW50TmFtZSB8fCBBTk9OWU1PVVM7XG4gICAgaWYgKHByb3BzW3Byb3BOYW1lXSA9PSBudWxsKSB7XG4gICAgICB2YXIgbG9jYXRpb25OYW1lID0gUmVhY3RQcm9wVHlwZUxvY2F0aW9uTmFtZXNbbG9jYXRpb25dO1xuICAgICAgaWYgKGlzUmVxdWlyZWQpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBFcnJvcihcbiAgICAgICAgICAoXCJSZXF1aXJlZCBcIiArIGxvY2F0aW9uTmFtZSArIFwiIGBcIiArIHByb3BOYW1lICsgXCJgIHdhcyBub3Qgc3BlY2lmaWVkIGluIFwiKStcbiAgICAgICAgICAoXCJgXCIgKyBjb21wb25lbnROYW1lICsgXCJgLlwiKVxuICAgICAgICApO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gdmFsaWRhdGUocHJvcHMsIHByb3BOYW1lLCBjb21wb25lbnROYW1lLCBsb2NhdGlvbik7XG4gICAgfVxuICB9XG5cbiAgdmFyIGNoYWluZWRDaGVja1R5cGUgPSBjaGVja1R5cGUuYmluZChudWxsLCBmYWxzZSk7XG4gIGNoYWluZWRDaGVja1R5cGUuaXNSZXF1aXJlZCA9IGNoZWNrVHlwZS5iaW5kKG51bGwsIHRydWUpO1xuXG4gIHJldHVybiBjaGFpbmVkQ2hlY2tUeXBlO1xufVxuXG5mdW5jdGlvbiBjcmVhdGVQcmltaXRpdmVUeXBlQ2hlY2tlcihleHBlY3RlZFR5cGUpIHtcbiAgZnVuY3Rpb24gdmFsaWRhdGUocHJvcHMsIHByb3BOYW1lLCBjb21wb25lbnROYW1lLCBsb2NhdGlvbikge1xuICAgIHZhciBwcm9wVmFsdWUgPSBwcm9wc1twcm9wTmFtZV07XG4gICAgdmFyIHByb3BUeXBlID0gZ2V0UHJvcFR5cGUocHJvcFZhbHVlKTtcbiAgICBpZiAocHJvcFR5cGUgIT09IGV4cGVjdGVkVHlwZSkge1xuICAgICAgdmFyIGxvY2F0aW9uTmFtZSA9IFJlYWN0UHJvcFR5cGVMb2NhdGlvbk5hbWVzW2xvY2F0aW9uXTtcbiAgICAgIC8vIGBwcm9wVmFsdWVgIGJlaW5nIGluc3RhbmNlIG9mLCBzYXksIGRhdGUvcmVnZXhwLCBwYXNzIHRoZSAnb2JqZWN0J1xuICAgICAgLy8gY2hlY2ssIGJ1dCB3ZSBjYW4gb2ZmZXIgYSBtb3JlIHByZWNpc2UgZXJyb3IgbWVzc2FnZSBoZXJlIHJhdGhlciB0aGFuXG4gICAgICAvLyAnb2YgdHlwZSBgb2JqZWN0YCcuXG4gICAgICB2YXIgcHJlY2lzZVR5cGUgPSBnZXRQcmVjaXNlVHlwZShwcm9wVmFsdWUpO1xuXG4gICAgICByZXR1cm4gbmV3IEVycm9yKFxuICAgICAgICAoXCJJbnZhbGlkIFwiICsgbG9jYXRpb25OYW1lICsgXCIgYFwiICsgcHJvcE5hbWUgKyBcImAgb2YgdHlwZSBgXCIgKyBwcmVjaXNlVHlwZSArIFwiYCBcIikgK1xuICAgICAgICAoXCJzdXBwbGllZCB0byBgXCIgKyBjb21wb25lbnROYW1lICsgXCJgLCBleHBlY3RlZCBgXCIgKyBleHBlY3RlZFR5cGUgKyBcImAuXCIpXG4gICAgICApO1xuICAgIH1cbiAgfVxuICByZXR1cm4gY3JlYXRlQ2hhaW5hYmxlVHlwZUNoZWNrZXIodmFsaWRhdGUpO1xufVxuXG5mdW5jdGlvbiBjcmVhdGVBbnlUeXBlQ2hlY2tlcigpIHtcbiAgcmV0dXJuIGNyZWF0ZUNoYWluYWJsZVR5cGVDaGVja2VyKGVtcHR5RnVuY3Rpb24udGhhdFJldHVybnMoKSk7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZUFycmF5T2ZUeXBlQ2hlY2tlcih0eXBlQ2hlY2tlcikge1xuICBmdW5jdGlvbiB2YWxpZGF0ZShwcm9wcywgcHJvcE5hbWUsIGNvbXBvbmVudE5hbWUsIGxvY2F0aW9uKSB7XG4gICAgdmFyIHByb3BWYWx1ZSA9IHByb3BzW3Byb3BOYW1lXTtcbiAgICBpZiAoIUFycmF5LmlzQXJyYXkocHJvcFZhbHVlKSkge1xuICAgICAgdmFyIGxvY2F0aW9uTmFtZSA9IFJlYWN0UHJvcFR5cGVMb2NhdGlvbk5hbWVzW2xvY2F0aW9uXTtcbiAgICAgIHZhciBwcm9wVHlwZSA9IGdldFByb3BUeXBlKHByb3BWYWx1ZSk7XG4gICAgICByZXR1cm4gbmV3IEVycm9yKFxuICAgICAgICAoXCJJbnZhbGlkIFwiICsgbG9jYXRpb25OYW1lICsgXCIgYFwiICsgcHJvcE5hbWUgKyBcImAgb2YgdHlwZSBcIikgK1xuICAgICAgICAoXCJgXCIgKyBwcm9wVHlwZSArIFwiYCBzdXBwbGllZCB0byBgXCIgKyBjb21wb25lbnROYW1lICsgXCJgLCBleHBlY3RlZCBhbiBhcnJheS5cIilcbiAgICAgICk7XG4gICAgfVxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcHJvcFZhbHVlLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgZXJyb3IgPSB0eXBlQ2hlY2tlcihwcm9wVmFsdWUsIGksIGNvbXBvbmVudE5hbWUsIGxvY2F0aW9uKTtcbiAgICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICAgIHJldHVybiBlcnJvcjtcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgcmV0dXJuIGNyZWF0ZUNoYWluYWJsZVR5cGVDaGVja2VyKHZhbGlkYXRlKTtcbn1cblxuZnVuY3Rpb24gY3JlYXRlRWxlbWVudFR5cGVDaGVja2VyKCkge1xuICBmdW5jdGlvbiB2YWxpZGF0ZShwcm9wcywgcHJvcE5hbWUsIGNvbXBvbmVudE5hbWUsIGxvY2F0aW9uKSB7XG4gICAgaWYgKCFSZWFjdEVsZW1lbnQuaXNWYWxpZEVsZW1lbnQocHJvcHNbcHJvcE5hbWVdKSkge1xuICAgICAgdmFyIGxvY2F0aW9uTmFtZSA9IFJlYWN0UHJvcFR5cGVMb2NhdGlvbk5hbWVzW2xvY2F0aW9uXTtcbiAgICAgIHJldHVybiBuZXcgRXJyb3IoXG4gICAgICAgIChcIkludmFsaWQgXCIgKyBsb2NhdGlvbk5hbWUgKyBcIiBgXCIgKyBwcm9wTmFtZSArIFwiYCBzdXBwbGllZCB0byBcIikgK1xuICAgICAgICAoXCJgXCIgKyBjb21wb25lbnROYW1lICsgXCJgLCBleHBlY3RlZCBhIFJlYWN0RWxlbWVudC5cIilcbiAgICAgICk7XG4gICAgfVxuICB9XG4gIHJldHVybiBjcmVhdGVDaGFpbmFibGVUeXBlQ2hlY2tlcih2YWxpZGF0ZSk7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZUluc3RhbmNlVHlwZUNoZWNrZXIoZXhwZWN0ZWRDbGFzcykge1xuICBmdW5jdGlvbiB2YWxpZGF0ZShwcm9wcywgcHJvcE5hbWUsIGNvbXBvbmVudE5hbWUsIGxvY2F0aW9uKSB7XG4gICAgaWYgKCEocHJvcHNbcHJvcE5hbWVdIGluc3RhbmNlb2YgZXhwZWN0ZWRDbGFzcykpIHtcbiAgICAgIHZhciBsb2NhdGlvbk5hbWUgPSBSZWFjdFByb3BUeXBlTG9jYXRpb25OYW1lc1tsb2NhdGlvbl07XG4gICAgICB2YXIgZXhwZWN0ZWRDbGFzc05hbWUgPSBleHBlY3RlZENsYXNzLm5hbWUgfHwgQU5PTllNT1VTO1xuICAgICAgcmV0dXJuIG5ldyBFcnJvcihcbiAgICAgICAgKFwiSW52YWxpZCBcIiArIGxvY2F0aW9uTmFtZSArIFwiIGBcIiArIHByb3BOYW1lICsgXCJgIHN1cHBsaWVkIHRvIFwiKSArXG4gICAgICAgIChcImBcIiArIGNvbXBvbmVudE5hbWUgKyBcImAsIGV4cGVjdGVkIGluc3RhbmNlIG9mIGBcIiArIGV4cGVjdGVkQ2xhc3NOYW1lICsgXCJgLlwiKVxuICAgICAgKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGNyZWF0ZUNoYWluYWJsZVR5cGVDaGVja2VyKHZhbGlkYXRlKTtcbn1cblxuZnVuY3Rpb24gY3JlYXRlRW51bVR5cGVDaGVja2VyKGV4cGVjdGVkVmFsdWVzKSB7XG4gIGZ1bmN0aW9uIHZhbGlkYXRlKHByb3BzLCBwcm9wTmFtZSwgY29tcG9uZW50TmFtZSwgbG9jYXRpb24pIHtcbiAgICB2YXIgcHJvcFZhbHVlID0gcHJvcHNbcHJvcE5hbWVdO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZXhwZWN0ZWRWYWx1ZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmIChwcm9wVmFsdWUgPT09IGV4cGVjdGVkVmFsdWVzW2ldKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB2YXIgbG9jYXRpb25OYW1lID0gUmVhY3RQcm9wVHlwZUxvY2F0aW9uTmFtZXNbbG9jYXRpb25dO1xuICAgIHZhciB2YWx1ZXNTdHJpbmcgPSBKU09OLnN0cmluZ2lmeShleHBlY3RlZFZhbHVlcyk7XG4gICAgcmV0dXJuIG5ldyBFcnJvcihcbiAgICAgIChcIkludmFsaWQgXCIgKyBsb2NhdGlvbk5hbWUgKyBcIiBgXCIgKyBwcm9wTmFtZSArIFwiYCBvZiB2YWx1ZSBgXCIgKyBwcm9wVmFsdWUgKyBcImAgXCIpICtcbiAgICAgIChcInN1cHBsaWVkIHRvIGBcIiArIGNvbXBvbmVudE5hbWUgKyBcImAsIGV4cGVjdGVkIG9uZSBvZiBcIiArIHZhbHVlc1N0cmluZyArIFwiLlwiKVxuICAgICk7XG4gIH1cbiAgcmV0dXJuIGNyZWF0ZUNoYWluYWJsZVR5cGVDaGVja2VyKHZhbGlkYXRlKTtcbn1cblxuZnVuY3Rpb24gY3JlYXRlT2JqZWN0T2ZUeXBlQ2hlY2tlcih0eXBlQ2hlY2tlcikge1xuICBmdW5jdGlvbiB2YWxpZGF0ZShwcm9wcywgcHJvcE5hbWUsIGNvbXBvbmVudE5hbWUsIGxvY2F0aW9uKSB7XG4gICAgdmFyIHByb3BWYWx1ZSA9IHByb3BzW3Byb3BOYW1lXTtcbiAgICB2YXIgcHJvcFR5cGUgPSBnZXRQcm9wVHlwZShwcm9wVmFsdWUpO1xuICAgIGlmIChwcm9wVHlwZSAhPT0gJ29iamVjdCcpIHtcbiAgICAgIHZhciBsb2NhdGlvbk5hbWUgPSBSZWFjdFByb3BUeXBlTG9jYXRpb25OYW1lc1tsb2NhdGlvbl07XG4gICAgICByZXR1cm4gbmV3IEVycm9yKFxuICAgICAgICAoXCJJbnZhbGlkIFwiICsgbG9jYXRpb25OYW1lICsgXCIgYFwiICsgcHJvcE5hbWUgKyBcImAgb2YgdHlwZSBcIikgK1xuICAgICAgICAoXCJgXCIgKyBwcm9wVHlwZSArIFwiYCBzdXBwbGllZCB0byBgXCIgKyBjb21wb25lbnROYW1lICsgXCJgLCBleHBlY3RlZCBhbiBvYmplY3QuXCIpXG4gICAgICApO1xuICAgIH1cbiAgICBmb3IgKHZhciBrZXkgaW4gcHJvcFZhbHVlKSB7XG4gICAgICBpZiAocHJvcFZhbHVlLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgdmFyIGVycm9yID0gdHlwZUNoZWNrZXIocHJvcFZhbHVlLCBrZXksIGNvbXBvbmVudE5hbWUsIGxvY2F0aW9uKTtcbiAgICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgICByZXR1cm4gZXJyb3I7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgcmV0dXJuIGNyZWF0ZUNoYWluYWJsZVR5cGVDaGVja2VyKHZhbGlkYXRlKTtcbn1cblxuZnVuY3Rpb24gY3JlYXRlVW5pb25UeXBlQ2hlY2tlcihhcnJheU9mVHlwZUNoZWNrZXJzKSB7XG4gIGZ1bmN0aW9uIHZhbGlkYXRlKHByb3BzLCBwcm9wTmFtZSwgY29tcG9uZW50TmFtZSwgbG9jYXRpb24pIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFycmF5T2ZUeXBlQ2hlY2tlcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBjaGVja2VyID0gYXJyYXlPZlR5cGVDaGVja2Vyc1tpXTtcbiAgICAgIGlmIChjaGVja2VyKHByb3BzLCBwcm9wTmFtZSwgY29tcG9uZW50TmFtZSwgbG9jYXRpb24pID09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgIH1cblxuICAgIHZhciBsb2NhdGlvbk5hbWUgPSBSZWFjdFByb3BUeXBlTG9jYXRpb25OYW1lc1tsb2NhdGlvbl07XG4gICAgcmV0dXJuIG5ldyBFcnJvcihcbiAgICAgIChcIkludmFsaWQgXCIgKyBsb2NhdGlvbk5hbWUgKyBcIiBgXCIgKyBwcm9wTmFtZSArIFwiYCBzdXBwbGllZCB0byBcIikgK1xuICAgICAgKFwiYFwiICsgY29tcG9uZW50TmFtZSArIFwiYC5cIilcbiAgICApO1xuICB9XG4gIHJldHVybiBjcmVhdGVDaGFpbmFibGVUeXBlQ2hlY2tlcih2YWxpZGF0ZSk7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZU5vZGVDaGVja2VyKCkge1xuICBmdW5jdGlvbiB2YWxpZGF0ZShwcm9wcywgcHJvcE5hbWUsIGNvbXBvbmVudE5hbWUsIGxvY2F0aW9uKSB7XG4gICAgaWYgKCFpc05vZGUocHJvcHNbcHJvcE5hbWVdKSkge1xuICAgICAgdmFyIGxvY2F0aW9uTmFtZSA9IFJlYWN0UHJvcFR5cGVMb2NhdGlvbk5hbWVzW2xvY2F0aW9uXTtcbiAgICAgIHJldHVybiBuZXcgRXJyb3IoXG4gICAgICAgIChcIkludmFsaWQgXCIgKyBsb2NhdGlvbk5hbWUgKyBcIiBgXCIgKyBwcm9wTmFtZSArIFwiYCBzdXBwbGllZCB0byBcIikgK1xuICAgICAgICAoXCJgXCIgKyBjb21wb25lbnROYW1lICsgXCJgLCBleHBlY3RlZCBhIFJlYWN0Tm9kZS5cIilcbiAgICAgICk7XG4gICAgfVxuICB9XG4gIHJldHVybiBjcmVhdGVDaGFpbmFibGVUeXBlQ2hlY2tlcih2YWxpZGF0ZSk7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZVNoYXBlVHlwZUNoZWNrZXIoc2hhcGVUeXBlcykge1xuICBmdW5jdGlvbiB2YWxpZGF0ZShwcm9wcywgcHJvcE5hbWUsIGNvbXBvbmVudE5hbWUsIGxvY2F0aW9uKSB7XG4gICAgdmFyIHByb3BWYWx1ZSA9IHByb3BzW3Byb3BOYW1lXTtcbiAgICB2YXIgcHJvcFR5cGUgPSBnZXRQcm9wVHlwZShwcm9wVmFsdWUpO1xuICAgIGlmIChwcm9wVHlwZSAhPT0gJ29iamVjdCcpIHtcbiAgICAgIHZhciBsb2NhdGlvbk5hbWUgPSBSZWFjdFByb3BUeXBlTG9jYXRpb25OYW1lc1tsb2NhdGlvbl07XG4gICAgICByZXR1cm4gbmV3IEVycm9yKFxuICAgICAgICAoXCJJbnZhbGlkIFwiICsgbG9jYXRpb25OYW1lICsgXCIgYFwiICsgcHJvcE5hbWUgKyBcImAgb2YgdHlwZSBgXCIgKyBwcm9wVHlwZSArIFwiYCBcIikgK1xuICAgICAgICAoXCJzdXBwbGllZCB0byBgXCIgKyBjb21wb25lbnROYW1lICsgXCJgLCBleHBlY3RlZCBgb2JqZWN0YC5cIilcbiAgICAgICk7XG4gICAgfVxuICAgIGZvciAodmFyIGtleSBpbiBzaGFwZVR5cGVzKSB7XG4gICAgICB2YXIgY2hlY2tlciA9IHNoYXBlVHlwZXNba2V5XTtcbiAgICAgIGlmICghY2hlY2tlcikge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIHZhciBlcnJvciA9IGNoZWNrZXIocHJvcFZhbHVlLCBrZXksIGNvbXBvbmVudE5hbWUsIGxvY2F0aW9uKTtcbiAgICAgIGlmIChlcnJvcikge1xuICAgICAgICByZXR1cm4gZXJyb3I7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHJldHVybiBjcmVhdGVDaGFpbmFibGVUeXBlQ2hlY2tlcih2YWxpZGF0ZSwgJ2V4cGVjdGVkIGBvYmplY3RgJyk7XG59XG5cbmZ1bmN0aW9uIGlzTm9kZShwcm9wVmFsdWUpIHtcbiAgc3dpdGNoKHR5cGVvZiBwcm9wVmFsdWUpIHtcbiAgICBjYXNlICdudW1iZXInOlxuICAgIGNhc2UgJ3N0cmluZyc6XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICBjYXNlICdib29sZWFuJzpcbiAgICAgIHJldHVybiAhcHJvcFZhbHVlO1xuICAgIGNhc2UgJ29iamVjdCc6XG4gICAgICBpZiAoQXJyYXkuaXNBcnJheShwcm9wVmFsdWUpKSB7XG4gICAgICAgIHJldHVybiBwcm9wVmFsdWUuZXZlcnkoaXNOb2RlKTtcbiAgICAgIH1cbiAgICAgIGlmIChSZWFjdEVsZW1lbnQuaXNWYWxpZEVsZW1lbnQocHJvcFZhbHVlKSkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICAgIGZvciAodmFyIGsgaW4gcHJvcFZhbHVlKSB7XG4gICAgICAgIGlmICghaXNOb2RlKHByb3BWYWx1ZVtrXSkpIHtcbiAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiB0cnVlO1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn1cblxuLy8gRXF1aXZhbGVudCBvZiBgdHlwZW9mYCBidXQgd2l0aCBzcGVjaWFsIGhhbmRsaW5nIGZvciBhcnJheSBhbmQgcmVnZXhwLlxuZnVuY3Rpb24gZ2V0UHJvcFR5cGUocHJvcFZhbHVlKSB7XG4gIHZhciBwcm9wVHlwZSA9IHR5cGVvZiBwcm9wVmFsdWU7XG4gIGlmIChBcnJheS5pc0FycmF5KHByb3BWYWx1ZSkpIHtcbiAgICByZXR1cm4gJ2FycmF5JztcbiAgfVxuICBpZiAocHJvcFZhbHVlIGluc3RhbmNlb2YgUmVnRXhwKSB7XG4gICAgLy8gT2xkIHdlYmtpdHMgKGF0IGxlYXN0IHVudGlsIEFuZHJvaWQgNC4wKSByZXR1cm4gJ2Z1bmN0aW9uJyByYXRoZXIgdGhhblxuICAgIC8vICdvYmplY3QnIGZvciB0eXBlb2YgYSBSZWdFeHAuIFdlJ2xsIG5vcm1hbGl6ZSB0aGlzIGhlcmUgc28gdGhhdCAvYmxhL1xuICAgIC8vIHBhc3NlcyBQcm9wVHlwZXMub2JqZWN0LlxuICAgIHJldHVybiAnb2JqZWN0JztcbiAgfVxuICByZXR1cm4gcHJvcFR5cGU7XG59XG5cbi8vIFRoaXMgaGFuZGxlcyBtb3JlIHR5cGVzIHRoYW4gYGdldFByb3BUeXBlYC4gT25seSB1c2VkIGZvciBlcnJvciBtZXNzYWdlcy5cbi8vIFNlZSBgY3JlYXRlUHJpbWl0aXZlVHlwZUNoZWNrZXJgLlxuZnVuY3Rpb24gZ2V0UHJlY2lzZVR5cGUocHJvcFZhbHVlKSB7XG4gIHZhciBwcm9wVHlwZSA9IGdldFByb3BUeXBlKHByb3BWYWx1ZSk7XG4gIGlmIChwcm9wVHlwZSA9PT0gJ29iamVjdCcpIHtcbiAgICBpZiAocHJvcFZhbHVlIGluc3RhbmNlb2YgRGF0ZSkge1xuICAgICAgcmV0dXJuICdkYXRlJztcbiAgICB9IGVsc2UgaWYgKHByb3BWYWx1ZSBpbnN0YW5jZW9mIFJlZ0V4cCkge1xuICAgICAgcmV0dXJuICdyZWdleHAnO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcHJvcFR5cGU7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RQcm9wVHlwZXM7XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RQdXRMaXN0ZW5lclF1ZXVlXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBQb29sZWRDbGFzcyA9IHJlcXVpcmUoXCIuL1Bvb2xlZENsYXNzXCIpO1xudmFyIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlciA9IHJlcXVpcmUoXCIuL1JlYWN0QnJvd3NlckV2ZW50RW1pdHRlclwiKTtcblxudmFyIGFzc2lnbiA9IHJlcXVpcmUoXCIuL09iamVjdC5hc3NpZ25cIik7XG5cbmZ1bmN0aW9uIFJlYWN0UHV0TGlzdGVuZXJRdWV1ZSgpIHtcbiAgdGhpcy5saXN0ZW5lcnNUb1B1dCA9IFtdO1xufVxuXG5hc3NpZ24oUmVhY3RQdXRMaXN0ZW5lclF1ZXVlLnByb3RvdHlwZSwge1xuICBlbnF1ZXVlUHV0TGlzdGVuZXI6IGZ1bmN0aW9uKHJvb3ROb2RlSUQsIHByb3BLZXksIHByb3BWYWx1ZSkge1xuICAgIHRoaXMubGlzdGVuZXJzVG9QdXQucHVzaCh7XG4gICAgICByb290Tm9kZUlEOiByb290Tm9kZUlELFxuICAgICAgcHJvcEtleTogcHJvcEtleSxcbiAgICAgIHByb3BWYWx1ZTogcHJvcFZhbHVlXG4gICAgfSk7XG4gIH0sXG5cbiAgcHV0TGlzdGVuZXJzOiBmdW5jdGlvbigpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMubGlzdGVuZXJzVG9QdXQubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBsaXN0ZW5lclRvUHV0ID0gdGhpcy5saXN0ZW5lcnNUb1B1dFtpXTtcbiAgICAgIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5wdXRMaXN0ZW5lcihcbiAgICAgICAgbGlzdGVuZXJUb1B1dC5yb290Tm9kZUlELFxuICAgICAgICBsaXN0ZW5lclRvUHV0LnByb3BLZXksXG4gICAgICAgIGxpc3RlbmVyVG9QdXQucHJvcFZhbHVlXG4gICAgICApO1xuICAgIH1cbiAgfSxcblxuICByZXNldDogZnVuY3Rpb24oKSB7XG4gICAgdGhpcy5saXN0ZW5lcnNUb1B1dC5sZW5ndGggPSAwO1xuICB9LFxuXG4gIGRlc3RydWN0b3I6IGZ1bmN0aW9uKCkge1xuICAgIHRoaXMucmVzZXQoKTtcbiAgfVxufSk7XG5cblBvb2xlZENsYXNzLmFkZFBvb2xpbmdUbyhSZWFjdFB1dExpc3RlbmVyUXVldWUpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0UHV0TGlzdGVuZXJRdWV1ZTtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9uXG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgQ2FsbGJhY2tRdWV1ZSA9IHJlcXVpcmUoXCIuL0NhbGxiYWNrUXVldWVcIik7XG52YXIgUG9vbGVkQ2xhc3MgPSByZXF1aXJlKFwiLi9Qb29sZWRDbGFzc1wiKTtcbnZhciBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIgPSByZXF1aXJlKFwiLi9SZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXJcIik7XG52YXIgUmVhY3RJbnB1dFNlbGVjdGlvbiA9IHJlcXVpcmUoXCIuL1JlYWN0SW5wdXRTZWxlY3Rpb25cIik7XG52YXIgUmVhY3RQdXRMaXN0ZW5lclF1ZXVlID0gcmVxdWlyZShcIi4vUmVhY3RQdXRMaXN0ZW5lclF1ZXVlXCIpO1xudmFyIFRyYW5zYWN0aW9uID0gcmVxdWlyZShcIi4vVHJhbnNhY3Rpb25cIik7XG5cbnZhciBhc3NpZ24gPSByZXF1aXJlKFwiLi9PYmplY3QuYXNzaWduXCIpO1xuXG4vKipcbiAqIEVuc3VyZXMgdGhhdCwgd2hlbiBwb3NzaWJsZSwgdGhlIHNlbGVjdGlvbiByYW5nZSAoY3VycmVudGx5IHNlbGVjdGVkIHRleHRcbiAqIGlucHV0KSBpcyBub3QgZGlzdHVyYmVkIGJ5IHBlcmZvcm1pbmcgdGhlIHRyYW5zYWN0aW9uLlxuICovXG52YXIgU0VMRUNUSU9OX1JFU1RPUkFUSU9OID0ge1xuICAvKipcbiAgICogQHJldHVybiB7U2VsZWN0aW9ufSBTZWxlY3Rpb24gaW5mb3JtYXRpb24uXG4gICAqL1xuICBpbml0aWFsaXplOiBSZWFjdElucHV0U2VsZWN0aW9uLmdldFNlbGVjdGlvbkluZm9ybWF0aW9uLFxuICAvKipcbiAgICogQHBhcmFtIHtTZWxlY3Rpb259IHNlbCBTZWxlY3Rpb24gaW5mb3JtYXRpb24gcmV0dXJuZWQgZnJvbSBgaW5pdGlhbGl6ZWAuXG4gICAqL1xuICBjbG9zZTogUmVhY3RJbnB1dFNlbGVjdGlvbi5yZXN0b3JlU2VsZWN0aW9uXG59O1xuXG4vKipcbiAqIFN1cHByZXNzZXMgZXZlbnRzIChibHVyL2ZvY3VzKSB0aGF0IGNvdWxkIGJlIGluYWR2ZXJ0ZW50bHkgZGlzcGF0Y2hlZCBkdWUgdG9cbiAqIGhpZ2ggbGV2ZWwgRE9NIG1hbmlwdWxhdGlvbnMgKGxpa2UgdGVtcG9yYXJpbHkgcmVtb3ZpbmcgYSB0ZXh0IGlucHV0IGZyb20gdGhlXG4gKiBET00pLlxuICovXG52YXIgRVZFTlRfU1VQUFJFU1NJT04gPSB7XG4gIC8qKlxuICAgKiBAcmV0dXJuIHtib29sZWFufSBUaGUgZW5hYmxlZCBzdGF0dXMgb2YgYFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlcmAgYmVmb3JlXG4gICAqIHRoZSByZWNvbmNpbGlhdGlvbi5cbiAgICovXG4gIGluaXRpYWxpemU6IGZ1bmN0aW9uKCkge1xuICAgIHZhciBjdXJyZW50bHlFbmFibGVkID0gUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLmlzRW5hYmxlZCgpO1xuICAgIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5zZXRFbmFibGVkKGZhbHNlKTtcbiAgICByZXR1cm4gY3VycmVudGx5RW5hYmxlZDtcbiAgfSxcblxuICAvKipcbiAgICogQHBhcmFtIHtib29sZWFufSBwcmV2aW91c2x5RW5hYmxlZCBFbmFibGVkIHN0YXR1cyBvZlxuICAgKiAgIGBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXJgIGJlZm9yZSB0aGUgcmVjb25jaWxpYXRpb24gb2NjdXJlZC4gYGNsb3NlYFxuICAgKiAgIHJlc3RvcmVzIHRoZSBwcmV2aW91cyB2YWx1ZS5cbiAgICovXG4gIGNsb3NlOiBmdW5jdGlvbihwcmV2aW91c2x5RW5hYmxlZCkge1xuICAgIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5zZXRFbmFibGVkKHByZXZpb3VzbHlFbmFibGVkKTtcbiAgfVxufTtcblxuLyoqXG4gKiBQcm92aWRlcyBhIHF1ZXVlIGZvciBjb2xsZWN0aW5nIGBjb21wb25lbnREaWRNb3VudGAgYW5kXG4gKiBgY29tcG9uZW50RGlkVXBkYXRlYCBjYWxsYmFja3MgZHVyaW5nIHRoZSB0aGUgdHJhbnNhY3Rpb24uXG4gKi9cbnZhciBPTl9ET01fUkVBRFlfUVVFVUVJTkcgPSB7XG4gIC8qKlxuICAgKiBJbml0aWFsaXplcyB0aGUgaW50ZXJuYWwgYG9uRE9NUmVhZHlgIHF1ZXVlLlxuICAgKi9cbiAgaW5pdGlhbGl6ZTogZnVuY3Rpb24oKSB7XG4gICAgdGhpcy5yZWFjdE1vdW50UmVhZHkucmVzZXQoKTtcbiAgfSxcblxuICAvKipcbiAgICogQWZ0ZXIgRE9NIGlzIGZsdXNoZWQsIGludm9rZSBhbGwgcmVnaXN0ZXJlZCBgb25ET01SZWFkeWAgY2FsbGJhY2tzLlxuICAgKi9cbiAgY2xvc2U6IGZ1bmN0aW9uKCkge1xuICAgIHRoaXMucmVhY3RNb3VudFJlYWR5Lm5vdGlmeUFsbCgpO1xuICB9XG59O1xuXG52YXIgUFVUX0xJU1RFTkVSX1FVRVVFSU5HID0ge1xuICBpbml0aWFsaXplOiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLnB1dExpc3RlbmVyUXVldWUucmVzZXQoKTtcbiAgfSxcblxuICBjbG9zZTogZnVuY3Rpb24oKSB7XG4gICAgdGhpcy5wdXRMaXN0ZW5lclF1ZXVlLnB1dExpc3RlbmVycygpO1xuICB9XG59O1xuXG4vKipcbiAqIEV4ZWN1dGVkIHdpdGhpbiB0aGUgc2NvcGUgb2YgdGhlIGBUcmFuc2FjdGlvbmAgaW5zdGFuY2UuIENvbnNpZGVyIHRoZXNlIGFzXG4gKiBiZWluZyBtZW1iZXIgbWV0aG9kcywgYnV0IHdpdGggYW4gaW1wbGllZCBvcmRlcmluZyB3aGlsZSBiZWluZyBpc29sYXRlZCBmcm9tXG4gKiBlYWNoIG90aGVyLlxuICovXG52YXIgVFJBTlNBQ1RJT05fV1JBUFBFUlMgPSBbXG4gIFBVVF9MSVNURU5FUl9RVUVVRUlORyxcbiAgU0VMRUNUSU9OX1JFU1RPUkFUSU9OLFxuICBFVkVOVF9TVVBQUkVTU0lPTixcbiAgT05fRE9NX1JFQURZX1FVRVVFSU5HXG5dO1xuXG4vKipcbiAqIEN1cnJlbnRseTpcbiAqIC0gVGhlIG9yZGVyIHRoYXQgdGhlc2UgYXJlIGxpc3RlZCBpbiB0aGUgdHJhbnNhY3Rpb24gaXMgY3JpdGljYWw6XG4gKiAtIFN1cHByZXNzZXMgZXZlbnRzLlxuICogLSBSZXN0b3JlcyBzZWxlY3Rpb24gcmFuZ2UuXG4gKlxuICogRnV0dXJlOlxuICogLSBSZXN0b3JlIGRvY3VtZW50L292ZXJmbG93IHNjcm9sbCBwb3NpdGlvbnMgdGhhdCB3ZXJlIHVuaW50ZW50aW9uYWxseVxuICogICBtb2RpZmllZCB2aWEgRE9NIGluc2VydGlvbnMgYWJvdmUgdGhlIHRvcCB2aWV3cG9ydCBib3VuZGFyeS5cbiAqIC0gSW1wbGVtZW50L2ludGVncmF0ZSB3aXRoIGN1c3RvbWl6ZWQgY29uc3RyYWludCBiYXNlZCBsYXlvdXQgc3lzdGVtIGFuZCBrZWVwXG4gKiAgIHRyYWNrIG9mIHdoaWNoIGRpbWVuc2lvbnMgbXVzdCBiZSByZW1lYXN1cmVkLlxuICpcbiAqIEBjbGFzcyBSZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9uXG4gKi9cbmZ1bmN0aW9uIFJlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb24oKSB7XG4gIHRoaXMucmVpbml0aWFsaXplVHJhbnNhY3Rpb24oKTtcbiAgLy8gT25seSBzZXJ2ZXItc2lkZSByZW5kZXJpbmcgcmVhbGx5IG5lZWRzIHRoaXMgb3B0aW9uIChzZWVcbiAgLy8gYFJlYWN0U2VydmVyUmVuZGVyaW5nYCksIGJ1dCBzZXJ2ZXItc2lkZSB1c2VzXG4gIC8vIGBSZWFjdFNlcnZlclJlbmRlcmluZ1RyYW5zYWN0aW9uYCBpbnN0ZWFkLiBUaGlzIG9wdGlvbiBpcyBoZXJlIHNvIHRoYXQgaXQnc1xuICAvLyBhY2Nlc3NpYmxlIGFuZCBkZWZhdWx0cyB0byBmYWxzZSB3aGVuIGBSZWFjdERPTUNvbXBvbmVudGAgYW5kXG4gIC8vIGBSZWFjdFRleHRDb21wb25lbnRgIGNoZWNrcyBpdCBpbiBgbW91bnRDb21wb25lbnRgLmBcbiAgdGhpcy5yZW5kZXJUb1N0YXRpY01hcmt1cCA9IGZhbHNlO1xuICB0aGlzLnJlYWN0TW91bnRSZWFkeSA9IENhbGxiYWNrUXVldWUuZ2V0UG9vbGVkKG51bGwpO1xuICB0aGlzLnB1dExpc3RlbmVyUXVldWUgPSBSZWFjdFB1dExpc3RlbmVyUXVldWUuZ2V0UG9vbGVkKCk7XG59XG5cbnZhciBNaXhpbiA9IHtcbiAgLyoqXG4gICAqIEBzZWUgVHJhbnNhY3Rpb25cbiAgICogQGFic3RyYWN0XG4gICAqIEBmaW5hbFxuICAgKiBAcmV0dXJuIHthcnJheTxvYmplY3Q+fSBMaXN0IG9mIG9wZXJhdGlvbiB3cmFwIHByb2NlZWR1cmVzLlxuICAgKiAgIFRPRE86IGNvbnZlcnQgdG8gYXJyYXk8VHJhbnNhY3Rpb25XcmFwcGVyPlxuICAgKi9cbiAgZ2V0VHJhbnNhY3Rpb25XcmFwcGVyczogZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIFRSQU5TQUNUSU9OX1dSQVBQRVJTO1xuICB9LFxuXG4gIC8qKlxuICAgKiBAcmV0dXJuIHtvYmplY3R9IFRoZSBxdWV1ZSB0byBjb2xsZWN0IGBvbkRPTVJlYWR5YCBjYWxsYmFja3Mgd2l0aC5cbiAgICovXG4gIGdldFJlYWN0TW91bnRSZWFkeTogZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMucmVhY3RNb3VudFJlYWR5O1xuICB9LFxuXG4gIGdldFB1dExpc3RlbmVyUXVldWU6IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiB0aGlzLnB1dExpc3RlbmVyUXVldWU7XG4gIH0sXG5cbiAgLyoqXG4gICAqIGBQb29sZWRDbGFzc2AgbG9va3MgZm9yIHRoaXMsIGFuZCB3aWxsIGludm9rZSB0aGlzIGJlZm9yZSBhbGxvd2luZyB0aGlzXG4gICAqIGluc3RhbmNlIHRvIGJlIHJlc3VzZWQuXG4gICAqL1xuICBkZXN0cnVjdG9yOiBmdW5jdGlvbigpIHtcbiAgICBDYWxsYmFja1F1ZXVlLnJlbGVhc2UodGhpcy5yZWFjdE1vdW50UmVhZHkpO1xuICAgIHRoaXMucmVhY3RNb3VudFJlYWR5ID0gbnVsbDtcblxuICAgIFJlYWN0UHV0TGlzdGVuZXJRdWV1ZS5yZWxlYXNlKHRoaXMucHV0TGlzdGVuZXJRdWV1ZSk7XG4gICAgdGhpcy5wdXRMaXN0ZW5lclF1ZXVlID0gbnVsbDtcbiAgfVxufTtcblxuXG5hc3NpZ24oUmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbi5wcm90b3R5cGUsIFRyYW5zYWN0aW9uLk1peGluLCBNaXhpbik7XG5cblBvb2xlZENsYXNzLmFkZFBvb2xpbmdUbyhSZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9uKTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9uO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0Um9vdEluZGV4XG4gKiBAdHlwZWNoZWNrc1xuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgUmVhY3RSb290SW5kZXhJbmplY3Rpb24gPSB7XG4gIC8qKlxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBfY3JlYXRlUmVhY3RSb290SW5kZXhcbiAgICovXG4gIGluamVjdENyZWF0ZVJlYWN0Um9vdEluZGV4OiBmdW5jdGlvbihfY3JlYXRlUmVhY3RSb290SW5kZXgpIHtcbiAgICBSZWFjdFJvb3RJbmRleC5jcmVhdGVSZWFjdFJvb3RJbmRleCA9IF9jcmVhdGVSZWFjdFJvb3RJbmRleDtcbiAgfVxufTtcblxudmFyIFJlYWN0Um9vdEluZGV4ID0ge1xuICBjcmVhdGVSZWFjdFJvb3RJbmRleDogbnVsbCxcbiAgaW5qZWN0aW9uOiBSZWFjdFJvb3RJbmRleEluamVjdGlvblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdFJvb3RJbmRleDtcbiIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0U2VydmVyUmVuZGVyaW5nXG4gKi9cblwidXNlIHN0cmljdFwiO1xuXG52YXIgUmVhY3RFbGVtZW50ID0gcmVxdWlyZShcIi4vUmVhY3RFbGVtZW50XCIpO1xudmFyIFJlYWN0SW5zdGFuY2VIYW5kbGVzID0gcmVxdWlyZShcIi4vUmVhY3RJbnN0YW5jZUhhbmRsZXNcIik7XG52YXIgUmVhY3RNYXJrdXBDaGVja3N1bSA9IHJlcXVpcmUoXCIuL1JlYWN0TWFya3VwQ2hlY2tzdW1cIik7XG52YXIgUmVhY3RTZXJ2ZXJSZW5kZXJpbmdUcmFuc2FjdGlvbiA9XG4gIHJlcXVpcmUoXCIuL1JlYWN0U2VydmVyUmVuZGVyaW5nVHJhbnNhY3Rpb25cIik7XG5cbnZhciBpbnN0YW50aWF0ZVJlYWN0Q29tcG9uZW50ID0gcmVxdWlyZShcIi4vaW5zdGFudGlhdGVSZWFjdENvbXBvbmVudFwiKTtcbnZhciBpbnZhcmlhbnQgPSByZXF1aXJlKFwiLi9pbnZhcmlhbnRcIik7XG5cbi8qKlxuICogQHBhcmFtIHtSZWFjdEVsZW1lbnR9IGVsZW1lbnRcbiAqIEByZXR1cm4ge3N0cmluZ30gdGhlIEhUTUwgbWFya3VwXG4gKi9cbmZ1bmN0aW9uIHJlbmRlclRvU3RyaW5nKGVsZW1lbnQpIHtcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICBSZWFjdEVsZW1lbnQuaXNWYWxpZEVsZW1lbnQoZWxlbWVudCksXG4gICAgJ3JlbmRlclRvU3RyaW5nKCk6IFlvdSBtdXN0IHBhc3MgYSB2YWxpZCBSZWFjdEVsZW1lbnQuJ1xuICApIDogaW52YXJpYW50KFJlYWN0RWxlbWVudC5pc1ZhbGlkRWxlbWVudChlbGVtZW50KSkpO1xuXG4gIHZhciB0cmFuc2FjdGlvbjtcbiAgdHJ5IHtcbiAgICB2YXIgaWQgPSBSZWFjdEluc3RhbmNlSGFuZGxlcy5jcmVhdGVSZWFjdFJvb3RJRCgpO1xuICAgIHRyYW5zYWN0aW9uID0gUmVhY3RTZXJ2ZXJSZW5kZXJpbmdUcmFuc2FjdGlvbi5nZXRQb29sZWQoZmFsc2UpO1xuXG4gICAgcmV0dXJuIHRyYW5zYWN0aW9uLnBlcmZvcm0oZnVuY3Rpb24oKSB7XG4gICAgICB2YXIgY29tcG9uZW50SW5zdGFuY2UgPSBpbnN0YW50aWF0ZVJlYWN0Q29tcG9uZW50KGVsZW1lbnQsIG51bGwpO1xuICAgICAgdmFyIG1hcmt1cCA9IGNvbXBvbmVudEluc3RhbmNlLm1vdW50Q29tcG9uZW50KGlkLCB0cmFuc2FjdGlvbiwgMCk7XG4gICAgICByZXR1cm4gUmVhY3RNYXJrdXBDaGVja3N1bS5hZGRDaGVja3N1bVRvTWFya3VwKG1hcmt1cCk7XG4gICAgfSwgbnVsbCk7XG4gIH0gZmluYWxseSB7XG4gICAgUmVhY3RTZXJ2ZXJSZW5kZXJpbmdUcmFuc2FjdGlvbi5yZWxlYXNlKHRyYW5zYWN0aW9uKTtcbiAgfVxufVxuXG4vKipcbiAqIEBwYXJhbSB7UmVhY3RFbGVtZW50fSBlbGVtZW50XG4gKiBAcmV0dXJuIHtzdHJpbmd9IHRoZSBIVE1MIG1hcmt1cCwgd2l0aG91dCB0aGUgZXh0cmEgUmVhY3QgSUQgYW5kIGNoZWNrc3VtXG4gKiAoZm9yIGdlbmVyYXRpbmcgc3RhdGljIHBhZ2VzKVxuICovXG5mdW5jdGlvbiByZW5kZXJUb1N0YXRpY01hcmt1cChlbGVtZW50KSB7XG4gIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgUmVhY3RFbGVtZW50LmlzVmFsaWRFbGVtZW50KGVsZW1lbnQpLFxuICAgICdyZW5kZXJUb1N0YXRpY01hcmt1cCgpOiBZb3UgbXVzdCBwYXNzIGEgdmFsaWQgUmVhY3RFbGVtZW50LidcbiAgKSA6IGludmFyaWFudChSZWFjdEVsZW1lbnQuaXNWYWxpZEVsZW1lbnQoZWxlbWVudCkpKTtcblxuICB2YXIgdHJhbnNhY3Rpb247XG4gIHRyeSB7XG4gICAgdmFyIGlkID0gUmVhY3RJbnN0YW5jZUhhbmRsZXMuY3JlYXRlUmVhY3RSb290SUQoKTtcbiAgICB0cmFuc2FjdGlvbiA9IFJlYWN0U2VydmVyUmVuZGVyaW5nVHJhbnNhY3Rpb24uZ2V0UG9vbGVkKHRydWUpO1xuXG4gICAgcmV0dXJuIHRyYW5zYWN0aW9uLnBlcmZvcm0oZnVuY3Rpb24oKSB7XG4gICAgICB2YXIgY29tcG9uZW50SW5zdGFuY2UgPSBpbnN0YW50aWF0ZVJlYWN0Q29tcG9uZW50KGVsZW1lbnQsIG51bGwpO1xuICAgICAgcmV0dXJuIGNvbXBvbmVudEluc3RhbmNlLm1vdW50Q29tcG9uZW50KGlkLCB0cmFuc2FjdGlvbiwgMCk7XG4gICAgfSwgbnVsbCk7XG4gIH0gZmluYWxseSB7XG4gICAgUmVhY3RTZXJ2ZXJSZW5kZXJpbmdUcmFuc2FjdGlvbi5yZWxlYXNlKHRyYW5zYWN0aW9uKTtcbiAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgcmVuZGVyVG9TdHJpbmc6IHJlbmRlclRvU3RyaW5nLFxuICByZW5kZXJUb1N0YXRpY01hcmt1cDogcmVuZGVyVG9TdGF0aWNNYXJrdXBcbn07XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RTZXJ2ZXJSZW5kZXJpbmdUcmFuc2FjdGlvblxuICogQHR5cGVjaGVja3NcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFBvb2xlZENsYXNzID0gcmVxdWlyZShcIi4vUG9vbGVkQ2xhc3NcIik7XG52YXIgQ2FsbGJhY2tRdWV1ZSA9IHJlcXVpcmUoXCIuL0NhbGxiYWNrUXVldWVcIik7XG52YXIgUmVhY3RQdXRMaXN0ZW5lclF1ZXVlID0gcmVxdWlyZShcIi4vUmVhY3RQdXRMaXN0ZW5lclF1ZXVlXCIpO1xudmFyIFRyYW5zYWN0aW9uID0gcmVxdWlyZShcIi4vVHJhbnNhY3Rpb25cIik7XG5cbnZhciBhc3NpZ24gPSByZXF1aXJlKFwiLi9PYmplY3QuYXNzaWduXCIpO1xudmFyIGVtcHR5RnVuY3Rpb24gPSByZXF1aXJlKFwiLi9lbXB0eUZ1bmN0aW9uXCIpO1xuXG4vKipcbiAqIFByb3ZpZGVzIGEgYENhbGxiYWNrUXVldWVgIHF1ZXVlIGZvciBjb2xsZWN0aW5nIGBvbkRPTVJlYWR5YCBjYWxsYmFja3NcbiAqIGR1cmluZyB0aGUgcGVyZm9ybWluZyBvZiB0aGUgdHJhbnNhY3Rpb24uXG4gKi9cbnZhciBPTl9ET01fUkVBRFlfUVVFVUVJTkcgPSB7XG4gIC8qKlxuICAgKiBJbml0aWFsaXplcyB0aGUgaW50ZXJuYWwgYG9uRE9NUmVhZHlgIHF1ZXVlLlxuICAgKi9cbiAgaW5pdGlhbGl6ZTogZnVuY3Rpb24oKSB7XG4gICAgdGhpcy5yZWFjdE1vdW50UmVhZHkucmVzZXQoKTtcbiAgfSxcblxuICBjbG9zZTogZW1wdHlGdW5jdGlvblxufTtcblxudmFyIFBVVF9MSVNURU5FUl9RVUVVRUlORyA9IHtcbiAgaW5pdGlhbGl6ZTogZnVuY3Rpb24oKSB7XG4gICAgdGhpcy5wdXRMaXN0ZW5lclF1ZXVlLnJlc2V0KCk7XG4gIH0sXG5cbiAgY2xvc2U6IGVtcHR5RnVuY3Rpb25cbn07XG5cbi8qKlxuICogRXhlY3V0ZWQgd2l0aGluIHRoZSBzY29wZSBvZiB0aGUgYFRyYW5zYWN0aW9uYCBpbnN0YW5jZS4gQ29uc2lkZXIgdGhlc2UgYXNcbiAqIGJlaW5nIG1lbWJlciBtZXRob2RzLCBidXQgd2l0aCBhbiBpbXBsaWVkIG9yZGVyaW5nIHdoaWxlIGJlaW5nIGlzb2xhdGVkIGZyb21cbiAqIGVhY2ggb3RoZXIuXG4gKi9cbnZhciBUUkFOU0FDVElPTl9XUkFQUEVSUyA9IFtcbiAgUFVUX0xJU1RFTkVSX1FVRVVFSU5HLFxuICBPTl9ET01fUkVBRFlfUVVFVUVJTkdcbl07XG5cbi8qKlxuICogQGNsYXNzIFJlYWN0U2VydmVyUmVuZGVyaW5nVHJhbnNhY3Rpb25cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gcmVuZGVyVG9TdGF0aWNNYXJrdXBcbiAqL1xuZnVuY3Rpb24gUmVhY3RTZXJ2ZXJSZW5kZXJpbmdUcmFuc2FjdGlvbihyZW5kZXJUb1N0YXRpY01hcmt1cCkge1xuICB0aGlzLnJlaW5pdGlhbGl6ZVRyYW5zYWN0aW9uKCk7XG4gIHRoaXMucmVuZGVyVG9TdGF0aWNNYXJrdXAgPSByZW5kZXJUb1N0YXRpY01hcmt1cDtcbiAgdGhpcy5yZWFjdE1vdW50UmVhZHkgPSBDYWxsYmFja1F1ZXVlLmdldFBvb2xlZChudWxsKTtcbiAgdGhpcy5wdXRMaXN0ZW5lclF1ZXVlID0gUmVhY3RQdXRMaXN0ZW5lclF1ZXVlLmdldFBvb2xlZCgpO1xufVxuXG52YXIgTWl4aW4gPSB7XG4gIC8qKlxuICAgKiBAc2VlIFRyYW5zYWN0aW9uXG4gICAqIEBhYnN0cmFjdFxuICAgKiBAZmluYWxcbiAgICogQHJldHVybiB7YXJyYXl9IEVtcHR5IGxpc3Qgb2Ygb3BlcmF0aW9uIHdyYXAgcHJvY2VlZHVyZXMuXG4gICAqL1xuICBnZXRUcmFuc2FjdGlvbldyYXBwZXJzOiBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gVFJBTlNBQ1RJT05fV1JBUFBFUlM7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEByZXR1cm4ge29iamVjdH0gVGhlIHF1ZXVlIHRvIGNvbGxlY3QgYG9uRE9NUmVhZHlgIGNhbGxiYWNrcyB3aXRoLlxuICAgKi9cbiAgZ2V0UmVhY3RNb3VudFJlYWR5OiBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gdGhpcy5yZWFjdE1vdW50UmVhZHk7XG4gIH0sXG5cbiAgZ2V0UHV0TGlzdGVuZXJRdWV1ZTogZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMucHV0TGlzdGVuZXJRdWV1ZTtcbiAgfSxcblxuICAvKipcbiAgICogYFBvb2xlZENsYXNzYCBsb29rcyBmb3IgdGhpcywgYW5kIHdpbGwgaW52b2tlIHRoaXMgYmVmb3JlIGFsbG93aW5nIHRoaXNcbiAgICogaW5zdGFuY2UgdG8gYmUgcmVzdXNlZC5cbiAgICovXG4gIGRlc3RydWN0b3I6IGZ1bmN0aW9uKCkge1xuICAgIENhbGxiYWNrUXVldWUucmVsZWFzZSh0aGlzLnJlYWN0TW91bnRSZWFkeSk7XG4gICAgdGhpcy5yZWFjdE1vdW50UmVhZHkgPSBudWxsO1xuXG4gICAgUmVhY3RQdXRMaXN0ZW5lclF1ZXVlLnJlbGVhc2UodGhpcy5wdXRMaXN0ZW5lclF1ZXVlKTtcbiAgICB0aGlzLnB1dExpc3RlbmVyUXVldWUgPSBudWxsO1xuICB9XG59O1xuXG5cbmFzc2lnbihcbiAgUmVhY3RTZXJ2ZXJSZW5kZXJpbmdUcmFuc2FjdGlvbi5wcm90b3R5cGUsXG4gIFRyYW5zYWN0aW9uLk1peGluLFxuICBNaXhpblxuKTtcblxuUG9vbGVkQ2xhc3MuYWRkUG9vbGluZ1RvKFJlYWN0U2VydmVyUmVuZGVyaW5nVHJhbnNhY3Rpb24pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0U2VydmVyUmVuZGVyaW5nVHJhbnNhY3Rpb247XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RTdGF0ZVNldHRlcnNcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFJlYWN0U3RhdGVTZXR0ZXJzID0ge1xuICAvKipcbiAgICogUmV0dXJucyBhIGZ1bmN0aW9uIHRoYXQgY2FsbHMgdGhlIHByb3ZpZGVkIGZ1bmN0aW9uLCBhbmQgdXNlcyB0aGUgcmVzdWx0XG4gICAqIG9mIHRoYXQgdG8gc2V0IHRoZSBjb21wb25lbnQncyBzdGF0ZS5cbiAgICpcbiAgICogQHBhcmFtIHtSZWFjdENvbXBvc2l0ZUNvbXBvbmVudH0gY29tcG9uZW50XG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IGZ1bmNSZXR1cm5pbmdTdGF0ZSBSZXR1cm5lZCBjYWxsYmFjayB1c2VzIHRoaXMgdG9cbiAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRldGVybWluZSBob3cgdG8gdXBkYXRlIHN0YXRlLlxuICAgKiBAcmV0dXJuIHtmdW5jdGlvbn0gY2FsbGJhY2sgdGhhdCB3aGVuIGludm9rZWQgdXNlcyBmdW5jUmV0dXJuaW5nU3RhdGUgdG9cbiAgICogICAgICAgICAgICAgICAgICAgIGRldGVybWluZWQgdGhlIG9iamVjdCBsaXRlcmFsIHRvIHNldFN0YXRlLlxuICAgKi9cbiAgY3JlYXRlU3RhdGVTZXR0ZXI6IGZ1bmN0aW9uKGNvbXBvbmVudCwgZnVuY1JldHVybmluZ1N0YXRlKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKGEsIGIsIGMsIGQsIGUsIGYpIHtcbiAgICAgIHZhciBwYXJ0aWFsU3RhdGUgPSBmdW5jUmV0dXJuaW5nU3RhdGUuY2FsbChjb21wb25lbnQsIGEsIGIsIGMsIGQsIGUsIGYpO1xuICAgICAgaWYgKHBhcnRpYWxTdGF0ZSkge1xuICAgICAgICBjb21wb25lbnQuc2V0U3RhdGUocGFydGlhbFN0YXRlKTtcbiAgICAgIH1cbiAgICB9O1xuICB9LFxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGEgc2luZ2xlLWFyZ3VtZW50IGNhbGxiYWNrIHRoYXQgY2FuIGJlIHVzZWQgdG8gdXBkYXRlIGEgc2luZ2xlXG4gICAqIGtleSBpbiB0aGUgY29tcG9uZW50J3Mgc3RhdGUuXG4gICAqXG4gICAqIE5vdGU6IHRoaXMgaXMgbWVtb2l6ZWQgZnVuY3Rpb24sIHdoaWNoIG1ha2VzIGl0IGluZXhwZW5zaXZlIHRvIGNhbGwuXG4gICAqXG4gICAqIEBwYXJhbSB7UmVhY3RDb21wb3NpdGVDb21wb25lbnR9IGNvbXBvbmVudFxuICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5IFRoZSBrZXkgaW4gdGhlIHN0YXRlIHRoYXQgeW91IHNob3VsZCB1cGRhdGUuXG4gICAqIEByZXR1cm4ge2Z1bmN0aW9ufSBjYWxsYmFjayBvZiAxIGFyZ3VtZW50IHdoaWNoIGNhbGxzIHNldFN0YXRlKCkgd2l0aFxuICAgKiAgICAgICAgICAgICAgICAgICAgdGhlIHByb3ZpZGVkIGtleU5hbWUgYW5kIGNhbGxiYWNrIGFyZ3VtZW50LlxuICAgKi9cbiAgY3JlYXRlU3RhdGVLZXlTZXR0ZXI6IGZ1bmN0aW9uKGNvbXBvbmVudCwga2V5KSB7XG4gICAgLy8gTWVtb2l6ZSB0aGUgc2V0dGVycy5cbiAgICB2YXIgY2FjaGUgPSBjb21wb25lbnQuX19rZXlTZXR0ZXJzIHx8IChjb21wb25lbnQuX19rZXlTZXR0ZXJzID0ge30pO1xuICAgIHJldHVybiBjYWNoZVtrZXldIHx8IChjYWNoZVtrZXldID0gY3JlYXRlU3RhdGVLZXlTZXR0ZXIoY29tcG9uZW50LCBrZXkpKTtcbiAgfVxufTtcblxuZnVuY3Rpb24gY3JlYXRlU3RhdGVLZXlTZXR0ZXIoY29tcG9uZW50LCBrZXkpIHtcbiAgLy8gUGFydGlhbCBzdGF0ZSBpcyBhbGxvY2F0ZWQgb3V0c2lkZSBvZiB0aGUgZnVuY3Rpb24gY2xvc3VyZSBzbyBpdCBjYW4gYmVcbiAgLy8gcmV1c2VkIHdpdGggZXZlcnkgY2FsbCwgYXZvaWRpbmcgbWVtb3J5IGFsbG9jYXRpb24gd2hlbiB0aGlzIGZ1bmN0aW9uXG4gIC8vIGlzIGNhbGxlZC5cbiAgdmFyIHBhcnRpYWxTdGF0ZSA9IHt9O1xuICByZXR1cm4gZnVuY3Rpb24gc3RhdGVLZXlTZXR0ZXIodmFsdWUpIHtcbiAgICBwYXJ0aWFsU3RhdGVba2V5XSA9IHZhbHVlO1xuICAgIGNvbXBvbmVudC5zZXRTdGF0ZShwYXJ0aWFsU3RhdGUpO1xuICB9O1xufVxuXG5SZWFjdFN0YXRlU2V0dGVycy5NaXhpbiA9IHtcbiAgLyoqXG4gICAqIFJldHVybnMgYSBmdW5jdGlvbiB0aGF0IGNhbGxzIHRoZSBwcm92aWRlZCBmdW5jdGlvbiwgYW5kIHVzZXMgdGhlIHJlc3VsdFxuICAgKiBvZiB0aGF0IHRvIHNldCB0aGUgY29tcG9uZW50J3Mgc3RhdGUuXG4gICAqXG4gICAqIEZvciBleGFtcGxlLCB0aGVzZSBzdGF0ZW1lbnRzIGFyZSBlcXVpdmFsZW50OlxuICAgKlxuICAgKiAgIHRoaXMuc2V0U3RhdGUoe3g6IDF9KTtcbiAgICogICB0aGlzLmNyZWF0ZVN0YXRlU2V0dGVyKGZ1bmN0aW9uKHhWYWx1ZSkge1xuICAgKiAgICAgcmV0dXJuIHt4OiB4VmFsdWV9O1xuICAgKiAgIH0pKDEpO1xuICAgKlxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBmdW5jUmV0dXJuaW5nU3RhdGUgUmV0dXJuZWQgY2FsbGJhY2sgdXNlcyB0aGlzIHRvXG4gICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXRlcm1pbmUgaG93IHRvIHVwZGF0ZSBzdGF0ZS5cbiAgICogQHJldHVybiB7ZnVuY3Rpb259IGNhbGxiYWNrIHRoYXQgd2hlbiBpbnZva2VkIHVzZXMgZnVuY1JldHVybmluZ1N0YXRlIHRvXG4gICAqICAgICAgICAgICAgICAgICAgICBkZXRlcm1pbmVkIHRoZSBvYmplY3QgbGl0ZXJhbCB0byBzZXRTdGF0ZS5cbiAgICovXG4gIGNyZWF0ZVN0YXRlU2V0dGVyOiBmdW5jdGlvbihmdW5jUmV0dXJuaW5nU3RhdGUpIHtcbiAgICByZXR1cm4gUmVhY3RTdGF0ZVNldHRlcnMuY3JlYXRlU3RhdGVTZXR0ZXIodGhpcywgZnVuY1JldHVybmluZ1N0YXRlKTtcbiAgfSxcblxuICAvKipcbiAgICogUmV0dXJucyBhIHNpbmdsZS1hcmd1bWVudCBjYWxsYmFjayB0aGF0IGNhbiBiZSB1c2VkIHRvIHVwZGF0ZSBhIHNpbmdsZVxuICAgKiBrZXkgaW4gdGhlIGNvbXBvbmVudCdzIHN0YXRlLlxuICAgKlxuICAgKiBGb3IgZXhhbXBsZSwgdGhlc2Ugc3RhdGVtZW50cyBhcmUgZXF1aXZhbGVudDpcbiAgICpcbiAgICogICB0aGlzLnNldFN0YXRlKHt4OiAxfSk7XG4gICAqICAgdGhpcy5jcmVhdGVTdGF0ZUtleVNldHRlcigneCcpKDEpO1xuICAgKlxuICAgKiBOb3RlOiB0aGlzIGlzIG1lbW9pemVkIGZ1bmN0aW9uLCB3aGljaCBtYWtlcyBpdCBpbmV4cGVuc2l2ZSB0byBjYWxsLlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5IFRoZSBrZXkgaW4gdGhlIHN0YXRlIHRoYXQgeW91IHNob3VsZCB1cGRhdGUuXG4gICAqIEByZXR1cm4ge2Z1bmN0aW9ufSBjYWxsYmFjayBvZiAxIGFyZ3VtZW50IHdoaWNoIGNhbGxzIHNldFN0YXRlKCkgd2l0aFxuICAgKiAgICAgICAgICAgICAgICAgICAgdGhlIHByb3ZpZGVkIGtleU5hbWUgYW5kIGNhbGxiYWNrIGFyZ3VtZW50LlxuICAgKi9cbiAgY3JlYXRlU3RhdGVLZXlTZXR0ZXI6IGZ1bmN0aW9uKGtleSkge1xuICAgIHJldHVybiBSZWFjdFN0YXRlU2V0dGVycy5jcmVhdGVTdGF0ZUtleVNldHRlcih0aGlzLCBrZXkpO1xuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0U3RhdGVTZXR0ZXJzO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0VGVzdFV0aWxzXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBFdmVudENvbnN0YW50cyA9IHJlcXVpcmUoXCIuL0V2ZW50Q29uc3RhbnRzXCIpO1xudmFyIEV2ZW50UGx1Z2luSHViID0gcmVxdWlyZShcIi4vRXZlbnRQbHVnaW5IdWJcIik7XG52YXIgRXZlbnRQcm9wYWdhdG9ycyA9IHJlcXVpcmUoXCIuL0V2ZW50UHJvcGFnYXRvcnNcIik7XG52YXIgUmVhY3QgPSByZXF1aXJlKFwiLi9SZWFjdFwiKTtcbnZhciBSZWFjdEVsZW1lbnQgPSByZXF1aXJlKFwiLi9SZWFjdEVsZW1lbnRcIik7XG52YXIgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyID0gcmVxdWlyZShcIi4vUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyXCIpO1xudmFyIFJlYWN0TW91bnQgPSByZXF1aXJlKFwiLi9SZWFjdE1vdW50XCIpO1xudmFyIFJlYWN0VGV4dENvbXBvbmVudCA9IHJlcXVpcmUoXCIuL1JlYWN0VGV4dENvbXBvbmVudFwiKTtcbnZhciBSZWFjdFVwZGF0ZXMgPSByZXF1aXJlKFwiLi9SZWFjdFVwZGF0ZXNcIik7XG52YXIgU3ludGhldGljRXZlbnQgPSByZXF1aXJlKFwiLi9TeW50aGV0aWNFdmVudFwiKTtcblxudmFyIGFzc2lnbiA9IHJlcXVpcmUoXCIuL09iamVjdC5hc3NpZ25cIik7XG5cbnZhciB0b3BMZXZlbFR5cGVzID0gRXZlbnRDb25zdGFudHMudG9wTGV2ZWxUeXBlcztcblxuZnVuY3Rpb24gRXZlbnQoc3VmZml4KSB7fVxuXG4vKipcbiAqIEBjbGFzcyBSZWFjdFRlc3RVdGlsc1xuICovXG5cbi8qKlxuICogVG9kbzogU3VwcG9ydCB0aGUgZW50aXJlIERPTS5zY3J5IHF1ZXJ5IHN5bnRheC4gRm9yIG5vdywgdGhlc2Ugc2ltcGxlXG4gKiB1dGlsaXRpZXMgd2lsbCBzdWZmaWNlIGZvciB0ZXN0aW5nIHB1cnBvc2VzLlxuICogQGxlbmRzIFJlYWN0VGVzdFV0aWxzXG4gKi9cbnZhciBSZWFjdFRlc3RVdGlscyA9IHtcbiAgcmVuZGVySW50b0RvY3VtZW50OiBmdW5jdGlvbihpbnN0YW5jZSkge1xuICAgIHZhciBkaXYgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICAvLyBOb25lIG9mIG91ciB0ZXN0cyBhY3R1YWxseSByZXF1aXJlIGF0dGFjaGluZyB0aGUgY29udGFpbmVyIHRvIHRoZVxuICAgIC8vIERPTSwgYW5kIGRvaW5nIHNvIGNyZWF0ZXMgYSBtZXNzIHRoYXQgd2UgcmVseSBvbiB0ZXN0IGlzb2xhdGlvbiB0b1xuICAgIC8vIGNsZWFuIHVwLCBzbyB3ZSdyZSBnb2luZyB0byBzdG9wIGhvbm9yaW5nIHRoZSBuYW1lIG9mIHRoaXMgbWV0aG9kXG4gICAgLy8gKGFuZCBwcm9iYWJseSByZW5hbWUgaXQgZXZlbnR1YWxseSkgaWYgbm8gcHJvYmxlbXMgYXJpc2UuXG4gICAgLy8gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmFwcGVuZENoaWxkKGRpdik7XG4gICAgcmV0dXJuIFJlYWN0LnJlbmRlcihpbnN0YW5jZSwgZGl2KTtcbiAgfSxcblxuICBpc0VsZW1lbnQ6IGZ1bmN0aW9uKGVsZW1lbnQpIHtcbiAgICByZXR1cm4gUmVhY3RFbGVtZW50LmlzVmFsaWRFbGVtZW50KGVsZW1lbnQpO1xuICB9LFxuXG4gIGlzRWxlbWVudE9mVHlwZTogZnVuY3Rpb24oaW5zdCwgY29udmVuaWVuY2VDb25zdHJ1Y3Rvcikge1xuICAgIHJldHVybiAoXG4gICAgICBSZWFjdEVsZW1lbnQuaXNWYWxpZEVsZW1lbnQoaW5zdCkgJiZcbiAgICAgIGluc3QudHlwZSA9PT0gY29udmVuaWVuY2VDb25zdHJ1Y3Rvci50eXBlXG4gICAgKTtcbiAgfSxcblxuICBpc0RPTUNvbXBvbmVudDogZnVuY3Rpb24oaW5zdCkge1xuICAgIHJldHVybiAhIShpbnN0ICYmIGluc3QubW91bnRDb21wb25lbnQgJiYgaW5zdC50YWdOYW1lKTtcbiAgfSxcblxuICBpc0RPTUNvbXBvbmVudEVsZW1lbnQ6IGZ1bmN0aW9uKGluc3QpIHtcbiAgICByZXR1cm4gISEoaW5zdCAmJlxuICAgICAgICAgICAgICBSZWFjdEVsZW1lbnQuaXNWYWxpZEVsZW1lbnQoaW5zdCkgJiZcbiAgICAgICAgICAgICAgISFpbnN0LnRhZ05hbWUpO1xuICB9LFxuXG4gIGlzQ29tcG9zaXRlQ29tcG9uZW50OiBmdW5jdGlvbihpbnN0KSB7XG4gICAgcmV0dXJuIHR5cGVvZiBpbnN0LnJlbmRlciA9PT0gJ2Z1bmN0aW9uJyAmJlxuICAgICAgICAgICB0eXBlb2YgaW5zdC5zZXRTdGF0ZSA9PT0gJ2Z1bmN0aW9uJztcbiAgfSxcblxuICBpc0NvbXBvc2l0ZUNvbXBvbmVudFdpdGhUeXBlOiBmdW5jdGlvbihpbnN0LCB0eXBlKSB7XG4gICAgcmV0dXJuICEhKFJlYWN0VGVzdFV0aWxzLmlzQ29tcG9zaXRlQ29tcG9uZW50KGluc3QpICYmXG4gICAgICAgICAgICAgKGluc3QuY29uc3RydWN0b3IgPT09IHR5cGUudHlwZSkpO1xuICB9LFxuXG4gIGlzQ29tcG9zaXRlQ29tcG9uZW50RWxlbWVudDogZnVuY3Rpb24oaW5zdCkge1xuICAgIGlmICghUmVhY3RFbGVtZW50LmlzVmFsaWRFbGVtZW50KGluc3QpKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIC8vIFdlIGNoZWNrIHRoZSBwcm90b3R5cGUgb2YgdGhlIHR5cGUgdGhhdCB3aWxsIGdldCBtb3VudGVkLCBub3QgdGhlXG4gICAgLy8gaW5zdGFuY2UgaXRzZWxmLiBUaGlzIGlzIGEgZnV0dXJlIHByb29mIHdheSBvZiBkdWNrIHR5cGluZy5cbiAgICB2YXIgcHJvdG90eXBlID0gaW5zdC50eXBlLnByb3RvdHlwZTtcbiAgICByZXR1cm4gKFxuICAgICAgdHlwZW9mIHByb3RvdHlwZS5yZW5kZXIgPT09ICdmdW5jdGlvbicgJiZcbiAgICAgIHR5cGVvZiBwcm90b3R5cGUuc2V0U3RhdGUgPT09ICdmdW5jdGlvbidcbiAgICApO1xuICB9LFxuXG4gIGlzQ29tcG9zaXRlQ29tcG9uZW50RWxlbWVudFdpdGhUeXBlOiBmdW5jdGlvbihpbnN0LCB0eXBlKSB7XG4gICAgcmV0dXJuICEhKFJlYWN0VGVzdFV0aWxzLmlzQ29tcG9zaXRlQ29tcG9uZW50RWxlbWVudChpbnN0KSAmJlxuICAgICAgICAgICAgIChpbnN0LmNvbnN0cnVjdG9yID09PSB0eXBlKSk7XG4gIH0sXG5cbiAgaXNUZXh0Q29tcG9uZW50OiBmdW5jdGlvbihpbnN0KSB7XG4gICAgcmV0dXJuIGluc3QgaW5zdGFuY2VvZiBSZWFjdFRleHRDb21wb25lbnQudHlwZTtcbiAgfSxcblxuICBmaW5kQWxsSW5SZW5kZXJlZFRyZWU6IGZ1bmN0aW9uKGluc3QsIHRlc3QpIHtcbiAgICBpZiAoIWluc3QpIHtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG4gICAgdmFyIHJldCA9IHRlc3QoaW5zdCkgPyBbaW5zdF0gOiBbXTtcbiAgICBpZiAoUmVhY3RUZXN0VXRpbHMuaXNET01Db21wb25lbnQoaW5zdCkpIHtcbiAgICAgIHZhciByZW5kZXJlZENoaWxkcmVuID0gaW5zdC5fcmVuZGVyZWRDaGlsZHJlbjtcbiAgICAgIHZhciBrZXk7XG4gICAgICBmb3IgKGtleSBpbiByZW5kZXJlZENoaWxkcmVuKSB7XG4gICAgICAgIGlmICghcmVuZGVyZWRDaGlsZHJlbi5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0ID0gcmV0LmNvbmNhdChcbiAgICAgICAgICBSZWFjdFRlc3RVdGlscy5maW5kQWxsSW5SZW5kZXJlZFRyZWUocmVuZGVyZWRDaGlsZHJlbltrZXldLCB0ZXN0KVxuICAgICAgICApO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoUmVhY3RUZXN0VXRpbHMuaXNDb21wb3NpdGVDb21wb25lbnQoaW5zdCkpIHtcbiAgICAgIHJldCA9IHJldC5jb25jYXQoXG4gICAgICAgIFJlYWN0VGVzdFV0aWxzLmZpbmRBbGxJblJlbmRlcmVkVHJlZShpbnN0Ll9yZW5kZXJlZENvbXBvbmVudCwgdGVzdClcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiByZXQ7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEZpbmRzIGFsbCBpbnN0YW5jZSBvZiBjb21wb25lbnRzIGluIHRoZSByZW5kZXJlZCB0cmVlIHRoYXQgYXJlIERPTVxuICAgKiBjb21wb25lbnRzIHdpdGggdGhlIGNsYXNzIG5hbWUgbWF0Y2hpbmcgYGNsYXNzTmFtZWAuXG4gICAqIEByZXR1cm4gYW4gYXJyYXkgb2YgYWxsIHRoZSBtYXRjaGVzLlxuICAgKi9cbiAgc2NyeVJlbmRlcmVkRE9NQ29tcG9uZW50c1dpdGhDbGFzczogZnVuY3Rpb24ocm9vdCwgY2xhc3NOYW1lKSB7XG4gICAgcmV0dXJuIFJlYWN0VGVzdFV0aWxzLmZpbmRBbGxJblJlbmRlcmVkVHJlZShyb290LCBmdW5jdGlvbihpbnN0KSB7XG4gICAgICB2YXIgaW5zdENsYXNzTmFtZSA9IGluc3QucHJvcHMuY2xhc3NOYW1lO1xuICAgICAgcmV0dXJuIFJlYWN0VGVzdFV0aWxzLmlzRE9NQ29tcG9uZW50KGluc3QpICYmIChcbiAgICAgICAgaW5zdENsYXNzTmFtZSAmJlxuICAgICAgICAoJyAnICsgaW5zdENsYXNzTmFtZSArICcgJykuaW5kZXhPZignICcgKyBjbGFzc05hbWUgKyAnICcpICE9PSAtMVxuICAgICAgKTtcbiAgICB9KTtcbiAgfSxcblxuICAvKipcbiAgICogTGlrZSBzY3J5UmVuZGVyZWRET01Db21wb25lbnRzV2l0aENsYXNzIGJ1dCBleHBlY3RzIHRoZXJlIHRvIGJlIG9uZSByZXN1bHQsXG4gICAqIGFuZCByZXR1cm5zIHRoYXQgb25lIHJlc3VsdCwgb3IgdGhyb3dzIGV4Y2VwdGlvbiBpZiB0aGVyZSBpcyBhbnkgb3RoZXJcbiAgICogbnVtYmVyIG9mIG1hdGNoZXMgYmVzaWRlcyBvbmUuXG4gICAqIEByZXR1cm4geyFSZWFjdERPTUNvbXBvbmVudH0gVGhlIG9uZSBtYXRjaC5cbiAgICovXG4gIGZpbmRSZW5kZXJlZERPTUNvbXBvbmVudFdpdGhDbGFzczogZnVuY3Rpb24ocm9vdCwgY2xhc3NOYW1lKSB7XG4gICAgdmFyIGFsbCA9XG4gICAgICBSZWFjdFRlc3RVdGlscy5zY3J5UmVuZGVyZWRET01Db21wb25lbnRzV2l0aENsYXNzKHJvb3QsIGNsYXNzTmFtZSk7XG4gICAgaWYgKGFsbC5sZW5ndGggIT09IDEpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRGlkIG5vdCBmaW5kIGV4YWN0bHkgb25lIG1hdGNoIGZvciBjbGFzczonICsgY2xhc3NOYW1lKTtcbiAgICB9XG4gICAgcmV0dXJuIGFsbFswXTtcbiAgfSxcblxuXG4gIC8qKlxuICAgKiBGaW5kcyBhbGwgaW5zdGFuY2Ugb2YgY29tcG9uZW50cyBpbiB0aGUgcmVuZGVyZWQgdHJlZSB0aGF0IGFyZSBET01cbiAgICogY29tcG9uZW50cyB3aXRoIHRoZSB0YWcgbmFtZSBtYXRjaGluZyBgdGFnTmFtZWAuXG4gICAqIEByZXR1cm4gYW4gYXJyYXkgb2YgYWxsIHRoZSBtYXRjaGVzLlxuICAgKi9cbiAgc2NyeVJlbmRlcmVkRE9NQ29tcG9uZW50c1dpdGhUYWc6IGZ1bmN0aW9uKHJvb3QsIHRhZ05hbWUpIHtcbiAgICByZXR1cm4gUmVhY3RUZXN0VXRpbHMuZmluZEFsbEluUmVuZGVyZWRUcmVlKHJvb3QsIGZ1bmN0aW9uKGluc3QpIHtcbiAgICAgIHJldHVybiBSZWFjdFRlc3RVdGlscy5pc0RPTUNvbXBvbmVudChpbnN0KSAmJlxuICAgICAgICAgICAgaW5zdC50YWdOYW1lID09PSB0YWdOYW1lLnRvVXBwZXJDYXNlKCk7XG4gICAgfSk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIExpa2Ugc2NyeVJlbmRlcmVkRE9NQ29tcG9uZW50c1dpdGhUYWcgYnV0IGV4cGVjdHMgdGhlcmUgdG8gYmUgb25lIHJlc3VsdCxcbiAgICogYW5kIHJldHVybnMgdGhhdCBvbmUgcmVzdWx0LCBvciB0aHJvd3MgZXhjZXB0aW9uIGlmIHRoZXJlIGlzIGFueSBvdGhlclxuICAgKiBudW1iZXIgb2YgbWF0Y2hlcyBiZXNpZGVzIG9uZS5cbiAgICogQHJldHVybiB7IVJlYWN0RE9NQ29tcG9uZW50fSBUaGUgb25lIG1hdGNoLlxuICAgKi9cbiAgZmluZFJlbmRlcmVkRE9NQ29tcG9uZW50V2l0aFRhZzogZnVuY3Rpb24ocm9vdCwgdGFnTmFtZSkge1xuICAgIHZhciBhbGwgPSBSZWFjdFRlc3RVdGlscy5zY3J5UmVuZGVyZWRET01Db21wb25lbnRzV2l0aFRhZyhyb290LCB0YWdOYW1lKTtcbiAgICBpZiAoYWxsLmxlbmd0aCAhPT0gMSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdEaWQgbm90IGZpbmQgZXhhY3RseSBvbmUgbWF0Y2ggZm9yIHRhZzonICsgdGFnTmFtZSk7XG4gICAgfVxuICAgIHJldHVybiBhbGxbMF07XG4gIH0sXG5cblxuICAvKipcbiAgICogRmluZHMgYWxsIGluc3RhbmNlcyBvZiBjb21wb25lbnRzIHdpdGggdHlwZSBlcXVhbCB0byBgY29tcG9uZW50VHlwZWAuXG4gICAqIEByZXR1cm4gYW4gYXJyYXkgb2YgYWxsIHRoZSBtYXRjaGVzLlxuICAgKi9cbiAgc2NyeVJlbmRlcmVkQ29tcG9uZW50c1dpdGhUeXBlOiBmdW5jdGlvbihyb290LCBjb21wb25lbnRUeXBlKSB7XG4gICAgcmV0dXJuIFJlYWN0VGVzdFV0aWxzLmZpbmRBbGxJblJlbmRlcmVkVHJlZShyb290LCBmdW5jdGlvbihpbnN0KSB7XG4gICAgICByZXR1cm4gUmVhY3RUZXN0VXRpbHMuaXNDb21wb3NpdGVDb21wb25lbnRXaXRoVHlwZShcbiAgICAgICAgaW5zdCxcbiAgICAgICAgY29tcG9uZW50VHlwZVxuICAgICAgKTtcbiAgICB9KTtcbiAgfSxcblxuICAvKipcbiAgICogU2FtZSBhcyBgc2NyeVJlbmRlcmVkQ29tcG9uZW50c1dpdGhUeXBlYCBidXQgZXhwZWN0cyB0aGVyZSB0byBiZSBvbmUgcmVzdWx0XG4gICAqIGFuZCByZXR1cm5zIHRoYXQgb25lIHJlc3VsdCwgb3IgdGhyb3dzIGV4Y2VwdGlvbiBpZiB0aGVyZSBpcyBhbnkgb3RoZXJcbiAgICogbnVtYmVyIG9mIG1hdGNoZXMgYmVzaWRlcyBvbmUuXG4gICAqIEByZXR1cm4geyFSZWFjdENvbXBvbmVudH0gVGhlIG9uZSBtYXRjaC5cbiAgICovXG4gIGZpbmRSZW5kZXJlZENvbXBvbmVudFdpdGhUeXBlOiBmdW5jdGlvbihyb290LCBjb21wb25lbnRUeXBlKSB7XG4gICAgdmFyIGFsbCA9IFJlYWN0VGVzdFV0aWxzLnNjcnlSZW5kZXJlZENvbXBvbmVudHNXaXRoVHlwZShcbiAgICAgIHJvb3QsXG4gICAgICBjb21wb25lbnRUeXBlXG4gICAgKTtcbiAgICBpZiAoYWxsLmxlbmd0aCAhPT0gMSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAnRGlkIG5vdCBmaW5kIGV4YWN0bHkgb25lIG1hdGNoIGZvciBjb21wb25lbnRUeXBlOicgKyBjb21wb25lbnRUeXBlXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gYWxsWzBdO1xuICB9LFxuXG4gIC8qKlxuICAgKiBQYXNzIGEgbW9ja2VkIGNvbXBvbmVudCBtb2R1bGUgdG8gdGhpcyBtZXRob2QgdG8gYXVnbWVudCBpdCB3aXRoXG4gICAqIHVzZWZ1bCBtZXRob2RzIHRoYXQgYWxsb3cgaXQgdG8gYmUgdXNlZCBhcyBhIGR1bW15IFJlYWN0IGNvbXBvbmVudC5cbiAgICogSW5zdGVhZCBvZiByZW5kZXJpbmcgYXMgdXN1YWwsIHRoZSBjb21wb25lbnQgd2lsbCBiZWNvbWUgYSBzaW1wbGVcbiAgICogPGRpdj4gY29udGFpbmluZyBhbnkgcHJvdmlkZWQgY2hpbGRyZW4uXG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBtb2R1bGUgdGhlIG1vY2sgZnVuY3Rpb24gb2JqZWN0IGV4cG9ydGVkIGZyb20gYVxuICAgKiAgICAgICAgICAgICAgICAgICAgICAgIG1vZHVsZSB0aGF0IGRlZmluZXMgdGhlIGNvbXBvbmVudCB0byBiZSBtb2NrZWRcbiAgICogQHBhcmFtIHs/c3RyaW5nfSBtb2NrVGFnTmFtZSBvcHRpb25hbCBkdW1teSByb290IHRhZyBuYW1lIHRvIHJldHVyblxuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZyb20gcmVuZGVyIG1ldGhvZCAob3ZlcnJpZGVzXG4gICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kdWxlLm1vY2tUYWdOYW1lIGlmIHByb3ZpZGVkKVxuICAgKiBAcmV0dXJuIHtvYmplY3R9IHRoZSBSZWFjdFRlc3RVdGlscyBvYmplY3QgKGZvciBjaGFpbmluZylcbiAgICovXG4gIG1vY2tDb21wb25lbnQ6IGZ1bmN0aW9uKG1vZHVsZSwgbW9ja1RhZ05hbWUpIHtcbiAgICBtb2NrVGFnTmFtZSA9IG1vY2tUYWdOYW1lIHx8IG1vZHVsZS5tb2NrVGFnTmFtZSB8fCBcImRpdlwiO1xuXG4gICAgdmFyIENvbnZlbmllbmNlQ29uc3RydWN0b3IgPSBSZWFjdC5jcmVhdGVDbGFzcyh7ZGlzcGxheU5hbWU6IFwiQ29udmVuaWVuY2VDb25zdHJ1Y3RvclwiLFxuICAgICAgcmVuZGVyOiBmdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXG4gICAgICAgICAgbW9ja1RhZ05hbWUsXG4gICAgICAgICAgbnVsbCxcbiAgICAgICAgICB0aGlzLnByb3BzLmNoaWxkcmVuXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBtb2R1bGUubW9ja0ltcGxlbWVudGF0aW9uKENvbnZlbmllbmNlQ29uc3RydWN0b3IpO1xuXG4gICAgbW9kdWxlLnR5cGUgPSBDb252ZW5pZW5jZUNvbnN0cnVjdG9yLnR5cGU7XG4gICAgbW9kdWxlLmlzUmVhY3RMZWdhY3lGYWN0b3J5ID0gdHJ1ZTtcblxuICAgIHJldHVybiB0aGlzO1xuICB9LFxuXG4gIC8qKlxuICAgKiBTaW11bGF0ZXMgYSB0b3AgbGV2ZWwgZXZlbnQgYmVpbmcgZGlzcGF0Y2hlZCBmcm9tIGEgcmF3IGV2ZW50IHRoYXQgb2NjdXJlZFxuICAgKiBvbiBhbiBgRWxlbWVudGAgbm9kZS5cbiAgICogQHBhcmFtIHRvcExldmVsVHlwZSB7T2JqZWN0fSBBIHR5cGUgZnJvbSBgRXZlbnRDb25zdGFudHMudG9wTGV2ZWxUeXBlc2BcbiAgICogQHBhcmFtIHshRWxlbWVudH0gbm9kZSBUaGUgZG9tIHRvIHNpbXVsYXRlIGFuIGV2ZW50IG9jY3VycmluZyBvbi5cbiAgICogQHBhcmFtIHs/RXZlbnR9IGZha2VOYXRpdmVFdmVudCBGYWtlIG5hdGl2ZSBldmVudCB0byB1c2UgaW4gU3ludGhldGljRXZlbnQuXG4gICAqL1xuICBzaW11bGF0ZU5hdGl2ZUV2ZW50T25Ob2RlOiBmdW5jdGlvbih0b3BMZXZlbFR5cGUsIG5vZGUsIGZha2VOYXRpdmVFdmVudCkge1xuICAgIGZha2VOYXRpdmVFdmVudC50YXJnZXQgPSBub2RlO1xuICAgIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5SZWFjdEV2ZW50TGlzdGVuZXIuZGlzcGF0Y2hFdmVudChcbiAgICAgIHRvcExldmVsVHlwZSxcbiAgICAgIGZha2VOYXRpdmVFdmVudFxuICAgICk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFNpbXVsYXRlcyBhIHRvcCBsZXZlbCBldmVudCBiZWluZyBkaXNwYXRjaGVkIGZyb20gYSByYXcgZXZlbnQgdGhhdCBvY2N1cmVkXG4gICAqIG9uIHRoZSBgUmVhY3RET01Db21wb25lbnRgIGBjb21wYC5cbiAgICogQHBhcmFtIHRvcExldmVsVHlwZSB7T2JqZWN0fSBBIHR5cGUgZnJvbSBgRXZlbnRDb25zdGFudHMudG9wTGV2ZWxUeXBlc2AuXG4gICAqIEBwYXJhbSBjb21wIHshUmVhY3RET01Db21wb25lbnR9XG4gICAqIEBwYXJhbSB7P0V2ZW50fSBmYWtlTmF0aXZlRXZlbnQgRmFrZSBuYXRpdmUgZXZlbnQgdG8gdXNlIGluIFN5bnRoZXRpY0V2ZW50LlxuICAgKi9cbiAgc2ltdWxhdGVOYXRpdmVFdmVudE9uRE9NQ29tcG9uZW50OiBmdW5jdGlvbihcbiAgICAgIHRvcExldmVsVHlwZSxcbiAgICAgIGNvbXAsXG4gICAgICBmYWtlTmF0aXZlRXZlbnQpIHtcbiAgICBSZWFjdFRlc3RVdGlscy5zaW11bGF0ZU5hdGl2ZUV2ZW50T25Ob2RlKFxuICAgICAgdG9wTGV2ZWxUeXBlLFxuICAgICAgY29tcC5nZXRET01Ob2RlKCksXG4gICAgICBmYWtlTmF0aXZlRXZlbnRcbiAgICApO1xuICB9LFxuXG4gIG5hdGl2ZVRvdWNoRGF0YTogZnVuY3Rpb24oeCwgeSkge1xuICAgIHJldHVybiB7XG4gICAgICB0b3VjaGVzOiBbXG4gICAgICAgIHtwYWdlWDogeCwgcGFnZVk6IHl9XG4gICAgICBdXG4gICAgfTtcbiAgfSxcblxuICBTaW11bGF0ZTogbnVsbCxcbiAgU2ltdWxhdGVOYXRpdmU6IHt9XG59O1xuXG4vKipcbiAqIEV4cG9ydHM6XG4gKlxuICogLSBgUmVhY3RUZXN0VXRpbHMuU2ltdWxhdGUuY2xpY2soRWxlbWVudC9SZWFjdERPTUNvbXBvbmVudClgXG4gKiAtIGBSZWFjdFRlc3RVdGlscy5TaW11bGF0ZS5tb3VzZU1vdmUoRWxlbWVudC9SZWFjdERPTUNvbXBvbmVudClgXG4gKiAtIGBSZWFjdFRlc3RVdGlscy5TaW11bGF0ZS5jaGFuZ2UoRWxlbWVudC9SZWFjdERPTUNvbXBvbmVudClgXG4gKiAtIC4uLiAoQWxsIGtleXMgZnJvbSBldmVudCBwbHVnaW4gYGV2ZW50VHlwZXNgIG9iamVjdHMpXG4gKi9cbmZ1bmN0aW9uIG1ha2VTaW11bGF0b3IoZXZlbnRUeXBlKSB7XG4gIHJldHVybiBmdW5jdGlvbihkb21Db21wb25lbnRPck5vZGUsIGV2ZW50RGF0YSkge1xuICAgIHZhciBub2RlO1xuICAgIGlmIChSZWFjdFRlc3RVdGlscy5pc0RPTUNvbXBvbmVudChkb21Db21wb25lbnRPck5vZGUpKSB7XG4gICAgICBub2RlID0gZG9tQ29tcG9uZW50T3JOb2RlLmdldERPTU5vZGUoKTtcbiAgICB9IGVsc2UgaWYgKGRvbUNvbXBvbmVudE9yTm9kZS50YWdOYW1lKSB7XG4gICAgICBub2RlID0gZG9tQ29tcG9uZW50T3JOb2RlO1xuICAgIH1cblxuICAgIHZhciBmYWtlTmF0aXZlRXZlbnQgPSBuZXcgRXZlbnQoKTtcbiAgICBmYWtlTmF0aXZlRXZlbnQudGFyZ2V0ID0gbm9kZTtcbiAgICAvLyBXZSBkb24ndCB1c2UgU3ludGhldGljRXZlbnQuZ2V0UG9vbGVkIGluIG9yZGVyIHRvIG5vdCBoYXZlIHRvIHdvcnJ5IGFib3V0XG4gICAgLy8gcHJvcGVybHkgZGVzdHJveWluZyBhbnkgcHJvcGVydGllcyBhc3NpZ25lZCBmcm9tIGBldmVudERhdGFgIHVwb24gcmVsZWFzZVxuICAgIHZhciBldmVudCA9IG5ldyBTeW50aGV0aWNFdmVudChcbiAgICAgIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5ldmVudE5hbWVEaXNwYXRjaENvbmZpZ3NbZXZlbnRUeXBlXSxcbiAgICAgIFJlYWN0TW91bnQuZ2V0SUQobm9kZSksXG4gICAgICBmYWtlTmF0aXZlRXZlbnRcbiAgICApO1xuICAgIGFzc2lnbihldmVudCwgZXZlbnREYXRhKTtcbiAgICBFdmVudFByb3BhZ2F0b3JzLmFjY3VtdWxhdGVUd29QaGFzZURpc3BhdGNoZXMoZXZlbnQpO1xuXG4gICAgUmVhY3RVcGRhdGVzLmJhdGNoZWRVcGRhdGVzKGZ1bmN0aW9uKCkge1xuICAgICAgRXZlbnRQbHVnaW5IdWIuZW5xdWV1ZUV2ZW50cyhldmVudCk7XG4gICAgICBFdmVudFBsdWdpbkh1Yi5wcm9jZXNzRXZlbnRRdWV1ZSgpO1xuICAgIH0pO1xuICB9O1xufVxuXG5mdW5jdGlvbiBidWlsZFNpbXVsYXRvcnMoKSB7XG4gIFJlYWN0VGVzdFV0aWxzLlNpbXVsYXRlID0ge307XG5cbiAgdmFyIGV2ZW50VHlwZTtcbiAgZm9yIChldmVudFR5cGUgaW4gUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLmV2ZW50TmFtZURpc3BhdGNoQ29uZmlncykge1xuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7IUVsZW1lbnQgfHwgUmVhY3RET01Db21wb25lbnR9IGRvbUNvbXBvbmVudE9yTm9kZVxuICAgICAqIEBwYXJhbSB7P29iamVjdH0gZXZlbnREYXRhIEZha2UgZXZlbnQgZGF0YSB0byB1c2UgaW4gU3ludGhldGljRXZlbnQuXG4gICAgICovXG4gICAgUmVhY3RUZXN0VXRpbHMuU2ltdWxhdGVbZXZlbnRUeXBlXSA9IG1ha2VTaW11bGF0b3IoZXZlbnRUeXBlKTtcbiAgfVxufVxuXG4vLyBSZWJ1aWxkIFJlYWN0VGVzdFV0aWxzLlNpbXVsYXRlIHdoZW5ldmVyIGV2ZW50IHBsdWdpbnMgYXJlIGluamVjdGVkXG52YXIgb2xkSW5qZWN0RXZlbnRQbHVnaW5PcmRlciA9IEV2ZW50UGx1Z2luSHViLmluamVjdGlvbi5pbmplY3RFdmVudFBsdWdpbk9yZGVyO1xuRXZlbnRQbHVnaW5IdWIuaW5qZWN0aW9uLmluamVjdEV2ZW50UGx1Z2luT3JkZXIgPSBmdW5jdGlvbigpIHtcbiAgb2xkSW5qZWN0RXZlbnRQbHVnaW5PcmRlci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICBidWlsZFNpbXVsYXRvcnMoKTtcbn07XG52YXIgb2xkSW5qZWN0RXZlbnRQbHVnaW5zID0gRXZlbnRQbHVnaW5IdWIuaW5qZWN0aW9uLmluamVjdEV2ZW50UGx1Z2luc0J5TmFtZTtcbkV2ZW50UGx1Z2luSHViLmluamVjdGlvbi5pbmplY3RFdmVudFBsdWdpbnNCeU5hbWUgPSBmdW5jdGlvbigpIHtcbiAgb2xkSW5qZWN0RXZlbnRQbHVnaW5zLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gIGJ1aWxkU2ltdWxhdG9ycygpO1xufTtcblxuYnVpbGRTaW11bGF0b3JzKCk7XG5cbi8qKlxuICogRXhwb3J0czpcbiAqXG4gKiAtIGBSZWFjdFRlc3RVdGlscy5TaW11bGF0ZU5hdGl2ZS5jbGljayhFbGVtZW50L1JlYWN0RE9NQ29tcG9uZW50KWBcbiAqIC0gYFJlYWN0VGVzdFV0aWxzLlNpbXVsYXRlTmF0aXZlLm1vdXNlTW92ZShFbGVtZW50L1JlYWN0RE9NQ29tcG9uZW50KWBcbiAqIC0gYFJlYWN0VGVzdFV0aWxzLlNpbXVsYXRlTmF0aXZlLm1vdXNlSW4vUmVhY3RET01Db21wb25lbnQpYFxuICogLSBgUmVhY3RUZXN0VXRpbHMuU2ltdWxhdGVOYXRpdmUubW91c2VPdXQoRWxlbWVudC9SZWFjdERPTUNvbXBvbmVudClgXG4gKiAtIC4uLiAoQWxsIGtleXMgZnJvbSBgRXZlbnRDb25zdGFudHMudG9wTGV2ZWxUeXBlc2ApXG4gKlxuICogTm90ZTogVG9wIGxldmVsIGV2ZW50IHR5cGVzIGFyZSBhIHN1YnNldCBvZiB0aGUgZW50aXJlIHNldCBvZiBoYW5kbGVyIHR5cGVzXG4gKiAod2hpY2ggaW5jbHVkZSBhIGJyb2FkZXIgc2V0IG9mIFwic3ludGhldGljXCIgZXZlbnRzKS4gRm9yIGV4YW1wbGUsIG9uRHJhZ0RvbmVcbiAqIGlzIGEgc3ludGhldGljIGV2ZW50LiBFeGNlcHQgd2hlbiB0ZXN0aW5nIGFuIGV2ZW50IHBsdWdpbiBvciBSZWFjdCdzIGV2ZW50XG4gKiBoYW5kbGluZyBjb2RlIHNwZWNpZmljYWxseSwgeW91IHByb2JhYmx5IHdhbnQgdG8gdXNlIFJlYWN0VGVzdFV0aWxzLlNpbXVsYXRlXG4gKiB0byBkaXNwYXRjaCBzeW50aGV0aWMgZXZlbnRzLlxuICovXG5cbmZ1bmN0aW9uIG1ha2VOYXRpdmVTaW11bGF0b3IoZXZlbnRUeXBlKSB7XG4gIHJldHVybiBmdW5jdGlvbihkb21Db21wb25lbnRPck5vZGUsIG5hdGl2ZUV2ZW50RGF0YSkge1xuICAgIHZhciBmYWtlTmF0aXZlRXZlbnQgPSBuZXcgRXZlbnQoZXZlbnRUeXBlKTtcbiAgICBhc3NpZ24oZmFrZU5hdGl2ZUV2ZW50LCBuYXRpdmVFdmVudERhdGEpO1xuICAgIGlmIChSZWFjdFRlc3RVdGlscy5pc0RPTUNvbXBvbmVudChkb21Db21wb25lbnRPck5vZGUpKSB7XG4gICAgICBSZWFjdFRlc3RVdGlscy5zaW11bGF0ZU5hdGl2ZUV2ZW50T25ET01Db21wb25lbnQoXG4gICAgICAgIGV2ZW50VHlwZSxcbiAgICAgICAgZG9tQ29tcG9uZW50T3JOb2RlLFxuICAgICAgICBmYWtlTmF0aXZlRXZlbnRcbiAgICAgICk7XG4gICAgfSBlbHNlIGlmICghIWRvbUNvbXBvbmVudE9yTm9kZS50YWdOYW1lKSB7XG4gICAgICAvLyBXaWxsIGFsbG93IG9uIGFjdHVhbCBkb20gbm9kZXMuXG4gICAgICBSZWFjdFRlc3RVdGlscy5zaW11bGF0ZU5hdGl2ZUV2ZW50T25Ob2RlKFxuICAgICAgICBldmVudFR5cGUsXG4gICAgICAgIGRvbUNvbXBvbmVudE9yTm9kZSxcbiAgICAgICAgZmFrZU5hdGl2ZUV2ZW50XG4gICAgICApO1xuICAgIH1cbiAgfTtcbn1cblxudmFyIGV2ZW50VHlwZTtcbmZvciAoZXZlbnRUeXBlIGluIHRvcExldmVsVHlwZXMpIHtcbiAgLy8gRXZlbnQgdHlwZSBpcyBzdG9yZWQgYXMgJ3RvcENsaWNrJyAtIHdlIHRyYW5zZm9ybSB0aGF0IHRvICdjbGljaydcbiAgdmFyIGNvbnZlbmllbmNlTmFtZSA9IGV2ZW50VHlwZS5pbmRleE9mKCd0b3AnKSA9PT0gMCA/XG4gICAgZXZlbnRUeXBlLmNoYXJBdCgzKS50b0xvd2VyQ2FzZSgpICsgZXZlbnRUeXBlLnN1YnN0cig0KSA6IGV2ZW50VHlwZTtcbiAgLyoqXG4gICAqIEBwYXJhbSB7IUVsZW1lbnQgfHwgUmVhY3RET01Db21wb25lbnR9IGRvbUNvbXBvbmVudE9yTm9kZVxuICAgKiBAcGFyYW0gez9FdmVudH0gbmF0aXZlRXZlbnREYXRhIEZha2UgbmF0aXZlIGV2ZW50IHRvIHVzZSBpbiBTeW50aGV0aWNFdmVudC5cbiAgICovXG4gIFJlYWN0VGVzdFV0aWxzLlNpbXVsYXRlTmF0aXZlW2NvbnZlbmllbmNlTmFtZV0gPVxuICAgIG1ha2VOYXRpdmVTaW11bGF0b3IoZXZlbnRUeXBlKTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdFRlc3RVdGlscztcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdFRleHRDb21wb25lbnRcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBET01Qcm9wZXJ0eU9wZXJhdGlvbnMgPSByZXF1aXJlKFwiLi9ET01Qcm9wZXJ0eU9wZXJhdGlvbnNcIik7XG52YXIgUmVhY3RDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdENvbXBvbmVudFwiKTtcbnZhciBSZWFjdEVsZW1lbnQgPSByZXF1aXJlKFwiLi9SZWFjdEVsZW1lbnRcIik7XG5cbnZhciBhc3NpZ24gPSByZXF1aXJlKFwiLi9PYmplY3QuYXNzaWduXCIpO1xudmFyIGVzY2FwZVRleHRGb3JCcm93c2VyID0gcmVxdWlyZShcIi4vZXNjYXBlVGV4dEZvckJyb3dzZXJcIik7XG5cbi8qKlxuICogVGV4dCBub2RlcyB2aW9sYXRlIGEgY291cGxlIGFzc3VtcHRpb25zIHRoYXQgUmVhY3QgbWFrZXMgYWJvdXQgY29tcG9uZW50czpcbiAqXG4gKiAgLSBXaGVuIG1vdW50aW5nIHRleHQgaW50byB0aGUgRE9NLCBhZGphY2VudCB0ZXh0IG5vZGVzIGFyZSBtZXJnZWQuXG4gKiAgLSBUZXh0IG5vZGVzIGNhbm5vdCBiZSBhc3NpZ25lZCBhIFJlYWN0IHJvb3QgSUQuXG4gKlxuICogVGhpcyBjb21wb25lbnQgaXMgdXNlZCB0byB3cmFwIHN0cmluZ3MgaW4gZWxlbWVudHMgc28gdGhhdCB0aGV5IGNhbiB1bmRlcmdvXG4gKiB0aGUgc2FtZSByZWNvbmNpbGlhdGlvbiB0aGF0IGlzIGFwcGxpZWQgdG8gZWxlbWVudHMuXG4gKlxuICogVE9ETzogSW52ZXN0aWdhdGUgcmVwcmVzZW50aW5nIFJlYWN0IGNvbXBvbmVudHMgaW4gdGhlIERPTSB3aXRoIHRleHQgbm9kZXMuXG4gKlxuICogQGNsYXNzIFJlYWN0VGV4dENvbXBvbmVudFxuICogQGV4dGVuZHMgUmVhY3RDb21wb25lbnRcbiAqIEBpbnRlcm5hbFxuICovXG52YXIgUmVhY3RUZXh0Q29tcG9uZW50ID0gZnVuY3Rpb24ocHJvcHMpIHtcbiAgLy8gVGhpcyBjb25zdHJ1Y3RvciBhbmQgaXQncyBhcmd1bWVudCBpcyBjdXJyZW50bHkgdXNlZCBieSBtb2Nrcy5cbn07XG5cbmFzc2lnbihSZWFjdFRleHRDb21wb25lbnQucHJvdG90eXBlLCBSZWFjdENvbXBvbmVudC5NaXhpbiwge1xuXG4gIC8qKlxuICAgKiBDcmVhdGVzIHRoZSBtYXJrdXAgZm9yIHRoaXMgdGV4dCBub2RlLiBUaGlzIG5vZGUgaXMgbm90IGludGVuZGVkIHRvIGhhdmVcbiAgICogYW55IGZlYXR1cmVzIGJlc2lkZXMgY29udGFpbmluZyB0ZXh0IGNvbnRlbnQuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSByb290SUQgRE9NIElEIG9mIHRoZSByb290IG5vZGUuXG4gICAqIEBwYXJhbSB7UmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbnxSZWFjdFNlcnZlclJlbmRlcmluZ1RyYW5zYWN0aW9ufSB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge251bWJlcn0gbW91bnREZXB0aCBudW1iZXIgb2YgY29tcG9uZW50cyBpbiB0aGUgb3duZXIgaGllcmFyY2h5XG4gICAqIEByZXR1cm4ge3N0cmluZ30gTWFya3VwIGZvciB0aGlzIHRleHQgbm9kZS5cbiAgICogQGludGVybmFsXG4gICAqL1xuICBtb3VudENvbXBvbmVudDogZnVuY3Rpb24ocm9vdElELCB0cmFuc2FjdGlvbiwgbW91bnREZXB0aCkge1xuICAgIFJlYWN0Q29tcG9uZW50Lk1peGluLm1vdW50Q29tcG9uZW50LmNhbGwoXG4gICAgICB0aGlzLFxuICAgICAgcm9vdElELFxuICAgICAgdHJhbnNhY3Rpb24sXG4gICAgICBtb3VudERlcHRoXG4gICAgKTtcblxuICAgIHZhciBlc2NhcGVkVGV4dCA9IGVzY2FwZVRleHRGb3JCcm93c2VyKHRoaXMucHJvcHMpO1xuXG4gICAgaWYgKHRyYW5zYWN0aW9uLnJlbmRlclRvU3RhdGljTWFya3VwKSB7XG4gICAgICAvLyBOb3JtYWxseSB3ZSdkIHdyYXAgdGhpcyBpbiBhIGBzcGFuYCBmb3IgdGhlIHJlYXNvbnMgc3RhdGVkIGFib3ZlLCBidXRcbiAgICAgIC8vIHNpbmNlIHRoaXMgaXMgYSBzaXR1YXRpb24gd2hlcmUgUmVhY3Qgd29uJ3QgdGFrZSBvdmVyIChzdGF0aWMgcGFnZXMpLFxuICAgICAgLy8gd2UgY2FuIHNpbXBseSByZXR1cm4gdGhlIHRleHQgYXMgaXQgaXMuXG4gICAgICByZXR1cm4gZXNjYXBlZFRleHQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIChcbiAgICAgICc8c3BhbiAnICsgRE9NUHJvcGVydHlPcGVyYXRpb25zLmNyZWF0ZU1hcmt1cEZvcklEKHJvb3RJRCkgKyAnPicgK1xuICAgICAgICBlc2NhcGVkVGV4dCArXG4gICAgICAnPC9zcGFuPidcbiAgICApO1xuICB9LFxuXG4gIC8qKlxuICAgKiBVcGRhdGVzIHRoaXMgY29tcG9uZW50IGJ5IHVwZGF0aW5nIHRoZSB0ZXh0IGNvbnRlbnQuXG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBuZXh0Q29tcG9uZW50IENvbnRhaW5zIHRoZSBuZXh0IHRleHQgY29udGVudC5cbiAgICogQHBhcmFtIHtSZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9ufSB0cmFuc2FjdGlvblxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHJlY2VpdmVDb21wb25lbnQ6IGZ1bmN0aW9uKG5leHRDb21wb25lbnQsIHRyYW5zYWN0aW9uKSB7XG4gICAgdmFyIG5leHRQcm9wcyA9IG5leHRDb21wb25lbnQucHJvcHM7XG4gICAgaWYgKG5leHRQcm9wcyAhPT0gdGhpcy5wcm9wcykge1xuICAgICAgdGhpcy5wcm9wcyA9IG5leHRQcm9wcztcbiAgICAgIFJlYWN0Q29tcG9uZW50LkJhY2tlbmRJRE9wZXJhdGlvbnMudXBkYXRlVGV4dENvbnRlbnRCeUlEKFxuICAgICAgICB0aGlzLl9yb290Tm9kZUlELFxuICAgICAgICBuZXh0UHJvcHNcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbn0pO1xuXG52YXIgUmVhY3RUZXh0Q29tcG9uZW50RmFjdG9yeSA9IGZ1bmN0aW9uKHRleHQpIHtcbiAgLy8gQnlwYXNzIHZhbGlkYXRpb24gYW5kIGNvbmZpZ3VyYXRpb25cbiAgcmV0dXJuIG5ldyBSZWFjdEVsZW1lbnQoUmVhY3RUZXh0Q29tcG9uZW50LCBudWxsLCBudWxsLCBudWxsLCBudWxsLCB0ZXh0KTtcbn07XG5cblJlYWN0VGV4dENvbXBvbmVudEZhY3RvcnkudHlwZSA9IFJlYWN0VGV4dENvbXBvbmVudDtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdFRleHRDb21wb25lbnRGYWN0b3J5O1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdFRyYW5zaXRpb25DaGlsZE1hcHBpbmdcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFJlYWN0Q2hpbGRyZW4gPSByZXF1aXJlKFwiLi9SZWFjdENoaWxkcmVuXCIpO1xuXG52YXIgUmVhY3RUcmFuc2l0aW9uQ2hpbGRNYXBwaW5nID0ge1xuICAvKipcbiAgICogR2l2ZW4gYHRoaXMucHJvcHMuY2hpbGRyZW5gLCByZXR1cm4gYW4gb2JqZWN0IG1hcHBpbmcga2V5IHRvIGNoaWxkLiBKdXN0XG4gICAqIHNpbXBsZSBzeW50YWN0aWMgc3VnYXIgYXJvdW5kIFJlYWN0Q2hpbGRyZW4ubWFwKCkuXG4gICAqXG4gICAqIEBwYXJhbSB7Kn0gY2hpbGRyZW4gYHRoaXMucHJvcHMuY2hpbGRyZW5gXG4gICAqIEByZXR1cm4ge29iamVjdH0gTWFwcGluZyBvZiBrZXkgdG8gY2hpbGRcbiAgICovXG4gIGdldENoaWxkTWFwcGluZzogZnVuY3Rpb24oY2hpbGRyZW4pIHtcbiAgICByZXR1cm4gUmVhY3RDaGlsZHJlbi5tYXAoY2hpbGRyZW4sIGZ1bmN0aW9uKGNoaWxkKSB7XG4gICAgICByZXR1cm4gY2hpbGQ7XG4gICAgfSk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFdoZW4geW91J3JlIGFkZGluZyBvciByZW1vdmluZyBjaGlsZHJlbiBzb21lIG1heSBiZSBhZGRlZCBvciByZW1vdmVkIGluIHRoZVxuICAgKiBzYW1lIHJlbmRlciBwYXNzLiBXZSB3YW50IHRvIHNob3cgKmJvdGgqIHNpbmNlIHdlIHdhbnQgdG8gc2ltdWx0YW5lb3VzbHlcbiAgICogYW5pbWF0ZSBlbGVtZW50cyBpbiBhbmQgb3V0LiBUaGlzIGZ1bmN0aW9uIHRha2VzIGEgcHJldmlvdXMgc2V0IG9mIGtleXNcbiAgICogYW5kIGEgbmV3IHNldCBvZiBrZXlzIGFuZCBtZXJnZXMgdGhlbSB3aXRoIGl0cyBiZXN0IGd1ZXNzIG9mIHRoZSBjb3JyZWN0XG4gICAqIG9yZGVyaW5nLiBJbiB0aGUgZnV0dXJlIHdlIG1heSBleHBvc2Ugc29tZSBvZiB0aGUgdXRpbGl0aWVzIGluXG4gICAqIFJlYWN0TXVsdGlDaGlsZCB0byBtYWtlIHRoaXMgZWFzeSwgYnV0IGZvciBub3cgUmVhY3QgaXRzZWxmIGRvZXMgbm90XG4gICAqIGRpcmVjdGx5IGhhdmUgdGhpcyBjb25jZXB0IG9mIHRoZSB1bmlvbiBvZiBwcmV2Q2hpbGRyZW4gYW5kIG5leHRDaGlsZHJlblxuICAgKiBzbyB3ZSBpbXBsZW1lbnQgaXQgaGVyZS5cbiAgICpcbiAgICogQHBhcmFtIHtvYmplY3R9IHByZXYgcHJldiBjaGlsZHJlbiBhcyByZXR1cm5lZCBmcm9tXG4gICAqIGBSZWFjdFRyYW5zaXRpb25DaGlsZE1hcHBpbmcuZ2V0Q2hpbGRNYXBwaW5nKClgLlxuICAgKiBAcGFyYW0ge29iamVjdH0gbmV4dCBuZXh0IGNoaWxkcmVuIGFzIHJldHVybmVkIGZyb21cbiAgICogYFJlYWN0VHJhbnNpdGlvbkNoaWxkTWFwcGluZy5nZXRDaGlsZE1hcHBpbmcoKWAuXG4gICAqIEByZXR1cm4ge29iamVjdH0gYSBrZXkgc2V0IHRoYXQgY29udGFpbnMgYWxsIGtleXMgaW4gYHByZXZgIGFuZCBhbGwga2V5c1xuICAgKiBpbiBgbmV4dGAgaW4gYSByZWFzb25hYmxlIG9yZGVyLlxuICAgKi9cbiAgbWVyZ2VDaGlsZE1hcHBpbmdzOiBmdW5jdGlvbihwcmV2LCBuZXh0KSB7XG4gICAgcHJldiA9IHByZXYgfHwge307XG4gICAgbmV4dCA9IG5leHQgfHwge307XG5cbiAgICBmdW5jdGlvbiBnZXRWYWx1ZUZvcktleShrZXkpIHtcbiAgICAgIGlmIChuZXh0Lmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgcmV0dXJuIG5leHRba2V5XTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBwcmV2W2tleV07XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gRm9yIGVhY2gga2V5IG9mIGBuZXh0YCwgdGhlIGxpc3Qgb2Yga2V5cyB0byBpbnNlcnQgYmVmb3JlIHRoYXQga2V5IGluXG4gICAgLy8gdGhlIGNvbWJpbmVkIGxpc3RcbiAgICB2YXIgbmV4dEtleXNQZW5kaW5nID0ge307XG5cbiAgICB2YXIgcGVuZGluZ0tleXMgPSBbXTtcbiAgICBmb3IgKHZhciBwcmV2S2V5IGluIHByZXYpIHtcbiAgICAgIGlmIChuZXh0Lmhhc093blByb3BlcnR5KHByZXZLZXkpKSB7XG4gICAgICAgIGlmIChwZW5kaW5nS2V5cy5sZW5ndGgpIHtcbiAgICAgICAgICBuZXh0S2V5c1BlbmRpbmdbcHJldktleV0gPSBwZW5kaW5nS2V5cztcbiAgICAgICAgICBwZW5kaW5nS2V5cyA9IFtdO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBwZW5kaW5nS2V5cy5wdXNoKHByZXZLZXkpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHZhciBpO1xuICAgIHZhciBjaGlsZE1hcHBpbmcgPSB7fTtcbiAgICBmb3IgKHZhciBuZXh0S2V5IGluIG5leHQpIHtcbiAgICAgIGlmIChuZXh0S2V5c1BlbmRpbmcuaGFzT3duUHJvcGVydHkobmV4dEtleSkpIHtcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IG5leHRLZXlzUGVuZGluZ1tuZXh0S2V5XS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIHZhciBwZW5kaW5nTmV4dEtleSA9IG5leHRLZXlzUGVuZGluZ1tuZXh0S2V5XVtpXTtcbiAgICAgICAgICBjaGlsZE1hcHBpbmdbbmV4dEtleXNQZW5kaW5nW25leHRLZXldW2ldXSA9IGdldFZhbHVlRm9yS2V5KFxuICAgICAgICAgICAgcGVuZGluZ05leHRLZXlcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBjaGlsZE1hcHBpbmdbbmV4dEtleV0gPSBnZXRWYWx1ZUZvcktleShuZXh0S2V5KTtcbiAgICB9XG5cbiAgICAvLyBGaW5hbGx5LCBhZGQgdGhlIGtleXMgd2hpY2ggZGlkbid0IGFwcGVhciBiZWZvcmUgYW55IGtleSBpbiBgbmV4dGBcbiAgICBmb3IgKGkgPSAwOyBpIDwgcGVuZGluZ0tleXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNoaWxkTWFwcGluZ1twZW5kaW5nS2V5c1tpXV0gPSBnZXRWYWx1ZUZvcktleShwZW5kaW5nS2V5c1tpXSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGNoaWxkTWFwcGluZztcbiAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdFRyYW5zaXRpb25DaGlsZE1hcHBpbmc7XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RUcmFuc2l0aW9uRXZlbnRzXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBFeGVjdXRpb25FbnZpcm9ubWVudCA9IHJlcXVpcmUoXCIuL0V4ZWN1dGlvbkVudmlyb25tZW50XCIpO1xuXG4vKipcbiAqIEVWRU5UX05BTUVfTUFQIGlzIHVzZWQgdG8gZGV0ZXJtaW5lIHdoaWNoIGV2ZW50IGZpcmVkIHdoZW4gYVxuICogdHJhbnNpdGlvbi9hbmltYXRpb24gZW5kcywgYmFzZWQgb24gdGhlIHN0eWxlIHByb3BlcnR5IHVzZWQgdG9cbiAqIGRlZmluZSB0aGF0IGV2ZW50LlxuICovXG52YXIgRVZFTlRfTkFNRV9NQVAgPSB7XG4gIHRyYW5zaXRpb25lbmQ6IHtcbiAgICAndHJhbnNpdGlvbic6ICd0cmFuc2l0aW9uZW5kJyxcbiAgICAnV2Via2l0VHJhbnNpdGlvbic6ICd3ZWJraXRUcmFuc2l0aW9uRW5kJyxcbiAgICAnTW96VHJhbnNpdGlvbic6ICdtb3pUcmFuc2l0aW9uRW5kJyxcbiAgICAnT1RyYW5zaXRpb24nOiAnb1RyYW5zaXRpb25FbmQnLFxuICAgICdtc1RyYW5zaXRpb24nOiAnTVNUcmFuc2l0aW9uRW5kJ1xuICB9LFxuXG4gIGFuaW1hdGlvbmVuZDoge1xuICAgICdhbmltYXRpb24nOiAnYW5pbWF0aW9uZW5kJyxcbiAgICAnV2Via2l0QW5pbWF0aW9uJzogJ3dlYmtpdEFuaW1hdGlvbkVuZCcsXG4gICAgJ01vekFuaW1hdGlvbic6ICdtb3pBbmltYXRpb25FbmQnLFxuICAgICdPQW5pbWF0aW9uJzogJ29BbmltYXRpb25FbmQnLFxuICAgICdtc0FuaW1hdGlvbic6ICdNU0FuaW1hdGlvbkVuZCdcbiAgfVxufTtcblxudmFyIGVuZEV2ZW50cyA9IFtdO1xuXG5mdW5jdGlvbiBkZXRlY3RFdmVudHMoKSB7XG4gIHZhciB0ZXN0RWwgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgdmFyIHN0eWxlID0gdGVzdEVsLnN0eWxlO1xuXG4gIC8vIE9uIHNvbWUgcGxhdGZvcm1zLCBpbiBwYXJ0aWN1bGFyIHNvbWUgcmVsZWFzZXMgb2YgQW5kcm9pZCA0LngsXG4gIC8vIHRoZSB1bi1wcmVmaXhlZCBcImFuaW1hdGlvblwiIGFuZCBcInRyYW5zaXRpb25cIiBwcm9wZXJ0aWVzIGFyZSBkZWZpbmVkIG9uIHRoZVxuICAvLyBzdHlsZSBvYmplY3QgYnV0IHRoZSBldmVudHMgdGhhdCBmaXJlIHdpbGwgc3RpbGwgYmUgcHJlZml4ZWQsIHNvIHdlIG5lZWRcbiAgLy8gdG8gY2hlY2sgaWYgdGhlIHVuLXByZWZpeGVkIGV2ZW50cyBhcmUgdXNlYWJsZSwgYW5kIGlmIG5vdCByZW1vdmUgdGhlbVxuICAvLyBmcm9tIHRoZSBtYXBcbiAgaWYgKCEoJ0FuaW1hdGlvbkV2ZW50JyBpbiB3aW5kb3cpKSB7XG4gICAgZGVsZXRlIEVWRU5UX05BTUVfTUFQLmFuaW1hdGlvbmVuZC5hbmltYXRpb247XG4gIH1cblxuICBpZiAoISgnVHJhbnNpdGlvbkV2ZW50JyBpbiB3aW5kb3cpKSB7XG4gICAgZGVsZXRlIEVWRU5UX05BTUVfTUFQLnRyYW5zaXRpb25lbmQudHJhbnNpdGlvbjtcbiAgfVxuXG4gIGZvciAodmFyIGJhc2VFdmVudE5hbWUgaW4gRVZFTlRfTkFNRV9NQVApIHtcbiAgICB2YXIgYmFzZUV2ZW50cyA9IEVWRU5UX05BTUVfTUFQW2Jhc2VFdmVudE5hbWVdO1xuICAgIGZvciAodmFyIHN0eWxlTmFtZSBpbiBiYXNlRXZlbnRzKSB7XG4gICAgICBpZiAoc3R5bGVOYW1lIGluIHN0eWxlKSB7XG4gICAgICAgIGVuZEV2ZW50cy5wdXNoKGJhc2VFdmVudHNbc3R5bGVOYW1lXSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuXG5pZiAoRXhlY3V0aW9uRW52aXJvbm1lbnQuY2FuVXNlRE9NKSB7XG4gIGRldGVjdEV2ZW50cygpO1xufVxuXG4vLyBXZSB1c2UgdGhlIHJhdyB7YWRkfHJlbW92ZX1FdmVudExpc3RlbmVyKCkgY2FsbCBiZWNhdXNlIEV2ZW50TGlzdGVuZXJcbi8vIGRvZXMgbm90IGtub3cgaG93IHRvIHJlbW92ZSBldmVudCBsaXN0ZW5lcnMgYW5kIHdlIHJlYWxseSBzaG91bGRcbi8vIGNsZWFuIHVwLiBBbHNvLCB0aGVzZSBldmVudHMgYXJlIG5vdCB0cmlnZ2VyZWQgaW4gb2xkZXIgYnJvd3NlcnNcbi8vIHNvIHdlIHNob3VsZCBiZSBBLU9LIGhlcmUuXG5cbmZ1bmN0aW9uIGFkZEV2ZW50TGlzdGVuZXIobm9kZSwgZXZlbnROYW1lLCBldmVudExpc3RlbmVyKSB7XG4gIG5vZGUuYWRkRXZlbnRMaXN0ZW5lcihldmVudE5hbWUsIGV2ZW50TGlzdGVuZXIsIGZhbHNlKTtcbn1cblxuZnVuY3Rpb24gcmVtb3ZlRXZlbnRMaXN0ZW5lcihub2RlLCBldmVudE5hbWUsIGV2ZW50TGlzdGVuZXIpIHtcbiAgbm9kZS5yZW1vdmVFdmVudExpc3RlbmVyKGV2ZW50TmFtZSwgZXZlbnRMaXN0ZW5lciwgZmFsc2UpO1xufVxuXG52YXIgUmVhY3RUcmFuc2l0aW9uRXZlbnRzID0ge1xuICBhZGRFbmRFdmVudExpc3RlbmVyOiBmdW5jdGlvbihub2RlLCBldmVudExpc3RlbmVyKSB7XG4gICAgaWYgKGVuZEV2ZW50cy5sZW5ndGggPT09IDApIHtcbiAgICAgIC8vIElmIENTUyB0cmFuc2l0aW9ucyBhcmUgbm90IHN1cHBvcnRlZCwgdHJpZ2dlciBhbiBcImVuZCBhbmltYXRpb25cIlxuICAgICAgLy8gZXZlbnQgaW1tZWRpYXRlbHkuXG4gICAgICB3aW5kb3cuc2V0VGltZW91dChldmVudExpc3RlbmVyLCAwKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgZW5kRXZlbnRzLmZvckVhY2goZnVuY3Rpb24oZW5kRXZlbnQpIHtcbiAgICAgIGFkZEV2ZW50TGlzdGVuZXIobm9kZSwgZW5kRXZlbnQsIGV2ZW50TGlzdGVuZXIpO1xuICAgIH0pO1xuICB9LFxuXG4gIHJlbW92ZUVuZEV2ZW50TGlzdGVuZXI6IGZ1bmN0aW9uKG5vZGUsIGV2ZW50TGlzdGVuZXIpIHtcbiAgICBpZiAoZW5kRXZlbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBlbmRFdmVudHMuZm9yRWFjaChmdW5jdGlvbihlbmRFdmVudCkge1xuICAgICAgcmVtb3ZlRXZlbnRMaXN0ZW5lcihub2RlLCBlbmRFdmVudCwgZXZlbnRMaXN0ZW5lcik7XG4gICAgfSk7XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RUcmFuc2l0aW9uRXZlbnRzO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0VHJhbnNpdGlvbkdyb3VwXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBSZWFjdCA9IHJlcXVpcmUoXCIuL1JlYWN0XCIpO1xudmFyIFJlYWN0VHJhbnNpdGlvbkNoaWxkTWFwcGluZyA9IHJlcXVpcmUoXCIuL1JlYWN0VHJhbnNpdGlvbkNoaWxkTWFwcGluZ1wiKTtcblxudmFyIGFzc2lnbiA9IHJlcXVpcmUoXCIuL09iamVjdC5hc3NpZ25cIik7XG52YXIgY2xvbmVXaXRoUHJvcHMgPSByZXF1aXJlKFwiLi9jbG9uZVdpdGhQcm9wc1wiKTtcbnZhciBlbXB0eUZ1bmN0aW9uID0gcmVxdWlyZShcIi4vZW1wdHlGdW5jdGlvblwiKTtcblxudmFyIFJlYWN0VHJhbnNpdGlvbkdyb3VwID0gUmVhY3QuY3JlYXRlQ2xhc3Moe1xuICBkaXNwbGF5TmFtZTogJ1JlYWN0VHJhbnNpdGlvbkdyb3VwJyxcblxuICBwcm9wVHlwZXM6IHtcbiAgICBjb21wb25lbnQ6IFJlYWN0LlByb3BUeXBlcy5hbnksXG4gICAgY2hpbGRGYWN0b3J5OiBSZWFjdC5Qcm9wVHlwZXMuZnVuY1xuICB9LFxuXG4gIGdldERlZmF1bHRQcm9wczogZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGNvbXBvbmVudDogJ3NwYW4nLFxuICAgICAgY2hpbGRGYWN0b3J5OiBlbXB0eUZ1bmN0aW9uLnRoYXRSZXR1cm5zQXJndW1lbnRcbiAgICB9O1xuICB9LFxuXG4gIGdldEluaXRpYWxTdGF0ZTogZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGNoaWxkcmVuOiBSZWFjdFRyYW5zaXRpb25DaGlsZE1hcHBpbmcuZ2V0Q2hpbGRNYXBwaW5nKHRoaXMucHJvcHMuY2hpbGRyZW4pXG4gICAgfTtcbiAgfSxcblxuICBjb21wb25lbnRXaWxsUmVjZWl2ZVByb3BzOiBmdW5jdGlvbihuZXh0UHJvcHMpIHtcbiAgICB2YXIgbmV4dENoaWxkTWFwcGluZyA9IFJlYWN0VHJhbnNpdGlvbkNoaWxkTWFwcGluZy5nZXRDaGlsZE1hcHBpbmcoXG4gICAgICBuZXh0UHJvcHMuY2hpbGRyZW5cbiAgICApO1xuICAgIHZhciBwcmV2Q2hpbGRNYXBwaW5nID0gdGhpcy5zdGF0ZS5jaGlsZHJlbjtcblxuICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgY2hpbGRyZW46IFJlYWN0VHJhbnNpdGlvbkNoaWxkTWFwcGluZy5tZXJnZUNoaWxkTWFwcGluZ3MoXG4gICAgICAgIHByZXZDaGlsZE1hcHBpbmcsXG4gICAgICAgIG5leHRDaGlsZE1hcHBpbmdcbiAgICAgIClcbiAgICB9KTtcblxuICAgIHZhciBrZXk7XG5cbiAgICBmb3IgKGtleSBpbiBuZXh0Q2hpbGRNYXBwaW5nKSB7XG4gICAgICB2YXIgaGFzUHJldiA9IHByZXZDaGlsZE1hcHBpbmcgJiYgcHJldkNoaWxkTWFwcGluZy5oYXNPd25Qcm9wZXJ0eShrZXkpO1xuICAgICAgaWYgKG5leHRDaGlsZE1hcHBpbmdba2V5XSAmJiAhaGFzUHJldiAmJlxuICAgICAgICAgICF0aGlzLmN1cnJlbnRseVRyYW5zaXRpb25pbmdLZXlzW2tleV0pIHtcbiAgICAgICAgdGhpcy5rZXlzVG9FbnRlci5wdXNoKGtleSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgZm9yIChrZXkgaW4gcHJldkNoaWxkTWFwcGluZykge1xuICAgICAgdmFyIGhhc05leHQgPSBuZXh0Q2hpbGRNYXBwaW5nICYmIG5leHRDaGlsZE1hcHBpbmcuaGFzT3duUHJvcGVydHkoa2V5KTtcbiAgICAgIGlmIChwcmV2Q2hpbGRNYXBwaW5nW2tleV0gJiYgIWhhc05leHQgJiZcbiAgICAgICAgICAhdGhpcy5jdXJyZW50bHlUcmFuc2l0aW9uaW5nS2V5c1trZXldKSB7XG4gICAgICAgIHRoaXMua2V5c1RvTGVhdmUucHVzaChrZXkpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIElmIHdlIHdhbnQgdG8gc29tZWRheSBjaGVjayBmb3IgcmVvcmRlcmluZywgd2UgY291bGQgZG8gaXQgaGVyZS5cbiAgfSxcblxuICBjb21wb25lbnRXaWxsTW91bnQ6IGZ1bmN0aW9uKCkge1xuICAgIHRoaXMuY3VycmVudGx5VHJhbnNpdGlvbmluZ0tleXMgPSB7fTtcbiAgICB0aGlzLmtleXNUb0VudGVyID0gW107XG4gICAgdGhpcy5rZXlzVG9MZWF2ZSA9IFtdO1xuICB9LFxuXG4gIGNvbXBvbmVudERpZFVwZGF0ZTogZnVuY3Rpb24oKSB7XG4gICAgdmFyIGtleXNUb0VudGVyID0gdGhpcy5rZXlzVG9FbnRlcjtcbiAgICB0aGlzLmtleXNUb0VudGVyID0gW107XG4gICAga2V5c1RvRW50ZXIuZm9yRWFjaCh0aGlzLnBlcmZvcm1FbnRlcik7XG5cbiAgICB2YXIga2V5c1RvTGVhdmUgPSB0aGlzLmtleXNUb0xlYXZlO1xuICAgIHRoaXMua2V5c1RvTGVhdmUgPSBbXTtcbiAgICBrZXlzVG9MZWF2ZS5mb3JFYWNoKHRoaXMucGVyZm9ybUxlYXZlKTtcbiAgfSxcblxuICBwZXJmb3JtRW50ZXI6IGZ1bmN0aW9uKGtleSkge1xuICAgIHRoaXMuY3VycmVudGx5VHJhbnNpdGlvbmluZ0tleXNba2V5XSA9IHRydWU7XG5cbiAgICB2YXIgY29tcG9uZW50ID0gdGhpcy5yZWZzW2tleV07XG5cbiAgICBpZiAoY29tcG9uZW50LmNvbXBvbmVudFdpbGxFbnRlcikge1xuICAgICAgY29tcG9uZW50LmNvbXBvbmVudFdpbGxFbnRlcihcbiAgICAgICAgdGhpcy5faGFuZGxlRG9uZUVudGVyaW5nLmJpbmQodGhpcywga2V5KVxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5faGFuZGxlRG9uZUVudGVyaW5nKGtleSk7XG4gICAgfVxuICB9LFxuXG4gIF9oYW5kbGVEb25lRW50ZXJpbmc6IGZ1bmN0aW9uKGtleSkge1xuICAgIHZhciBjb21wb25lbnQgPSB0aGlzLnJlZnNba2V5XTtcbiAgICBpZiAoY29tcG9uZW50LmNvbXBvbmVudERpZEVudGVyKSB7XG4gICAgICBjb21wb25lbnQuY29tcG9uZW50RGlkRW50ZXIoKTtcbiAgICB9XG5cbiAgICBkZWxldGUgdGhpcy5jdXJyZW50bHlUcmFuc2l0aW9uaW5nS2V5c1trZXldO1xuXG4gICAgdmFyIGN1cnJlbnRDaGlsZE1hcHBpbmcgPSBSZWFjdFRyYW5zaXRpb25DaGlsZE1hcHBpbmcuZ2V0Q2hpbGRNYXBwaW5nKFxuICAgICAgdGhpcy5wcm9wcy5jaGlsZHJlblxuICAgICk7XG5cbiAgICBpZiAoIWN1cnJlbnRDaGlsZE1hcHBpbmcgfHwgIWN1cnJlbnRDaGlsZE1hcHBpbmcuaGFzT3duUHJvcGVydHkoa2V5KSkge1xuICAgICAgLy8gVGhpcyB3YXMgcmVtb3ZlZCBiZWZvcmUgaXQgaGFkIGZ1bGx5IGVudGVyZWQuIFJlbW92ZSBpdC5cbiAgICAgIHRoaXMucGVyZm9ybUxlYXZlKGtleSk7XG4gICAgfVxuICB9LFxuXG4gIHBlcmZvcm1MZWF2ZTogZnVuY3Rpb24oa2V5KSB7XG4gICAgdGhpcy5jdXJyZW50bHlUcmFuc2l0aW9uaW5nS2V5c1trZXldID0gdHJ1ZTtcblxuICAgIHZhciBjb21wb25lbnQgPSB0aGlzLnJlZnNba2V5XTtcbiAgICBpZiAoY29tcG9uZW50LmNvbXBvbmVudFdpbGxMZWF2ZSkge1xuICAgICAgY29tcG9uZW50LmNvbXBvbmVudFdpbGxMZWF2ZSh0aGlzLl9oYW5kbGVEb25lTGVhdmluZy5iaW5kKHRoaXMsIGtleSkpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBOb3RlIHRoYXQgdGhpcyBpcyBzb21ld2hhdCBkYW5nZXJvdXMgYi9jIGl0IGNhbGxzIHNldFN0YXRlKClcbiAgICAgIC8vIGFnYWluLCBlZmZlY3RpdmVseSBtdXRhdGluZyB0aGUgY29tcG9uZW50IGJlZm9yZSBhbGwgdGhlIHdvcmtcbiAgICAgIC8vIGlzIGRvbmUuXG4gICAgICB0aGlzLl9oYW5kbGVEb25lTGVhdmluZyhrZXkpO1xuICAgIH1cbiAgfSxcblxuICBfaGFuZGxlRG9uZUxlYXZpbmc6IGZ1bmN0aW9uKGtleSkge1xuICAgIHZhciBjb21wb25lbnQgPSB0aGlzLnJlZnNba2V5XTtcblxuICAgIGlmIChjb21wb25lbnQuY29tcG9uZW50RGlkTGVhdmUpIHtcbiAgICAgIGNvbXBvbmVudC5jb21wb25lbnREaWRMZWF2ZSgpO1xuICAgIH1cblxuICAgIGRlbGV0ZSB0aGlzLmN1cnJlbnRseVRyYW5zaXRpb25pbmdLZXlzW2tleV07XG5cbiAgICB2YXIgY3VycmVudENoaWxkTWFwcGluZyA9IFJlYWN0VHJhbnNpdGlvbkNoaWxkTWFwcGluZy5nZXRDaGlsZE1hcHBpbmcoXG4gICAgICB0aGlzLnByb3BzLmNoaWxkcmVuXG4gICAgKTtcblxuICAgIGlmIChjdXJyZW50Q2hpbGRNYXBwaW5nICYmIGN1cnJlbnRDaGlsZE1hcHBpbmcuaGFzT3duUHJvcGVydHkoa2V5KSkge1xuICAgICAgLy8gVGhpcyBlbnRlcmVkIGFnYWluIGJlZm9yZSBpdCBmdWxseSBsZWZ0LiBBZGQgaXQgYWdhaW4uXG4gICAgICB0aGlzLnBlcmZvcm1FbnRlcihrZXkpO1xuICAgIH0gZWxzZSB7XG4gICAgICB2YXIgbmV3Q2hpbGRyZW4gPSBhc3NpZ24oe30sIHRoaXMuc3RhdGUuY2hpbGRyZW4pO1xuICAgICAgZGVsZXRlIG5ld0NoaWxkcmVuW2tleV07XG4gICAgICB0aGlzLnNldFN0YXRlKHtjaGlsZHJlbjogbmV3Q2hpbGRyZW59KTtcbiAgICB9XG4gIH0sXG5cbiAgcmVuZGVyOiBmdW5jdGlvbigpIHtcbiAgICAvLyBUT0RPOiB3ZSBjb3VsZCBnZXQgcmlkIG9mIHRoZSBuZWVkIGZvciB0aGUgd3JhcHBlciBub2RlXG4gICAgLy8gYnkgY2xvbmluZyBhIHNpbmdsZSBjaGlsZFxuICAgIHZhciBjaGlsZHJlblRvUmVuZGVyID0ge307XG4gICAgZm9yICh2YXIga2V5IGluIHRoaXMuc3RhdGUuY2hpbGRyZW4pIHtcbiAgICAgIHZhciBjaGlsZCA9IHRoaXMuc3RhdGUuY2hpbGRyZW5ba2V5XTtcbiAgICAgIGlmIChjaGlsZCkge1xuICAgICAgICAvLyBZb3UgbWF5IG5lZWQgdG8gYXBwbHkgcmVhY3RpdmUgdXBkYXRlcyB0byBhIGNoaWxkIGFzIGl0IGlzIGxlYXZpbmcuXG4gICAgICAgIC8vIFRoZSBub3JtYWwgUmVhY3Qgd2F5IHRvIGRvIGl0IHdvbid0IHdvcmsgc2luY2UgdGhlIGNoaWxkIHdpbGwgaGF2ZVxuICAgICAgICAvLyBhbHJlYWR5IGJlZW4gcmVtb3ZlZC4gSW4gY2FzZSB5b3UgbmVlZCB0aGlzIGJlaGF2aW9yIHlvdSBjYW4gcHJvdmlkZVxuICAgICAgICAvLyBhIGNoaWxkRmFjdG9yeSBmdW5jdGlvbiB0byB3cmFwIGV2ZXJ5IGNoaWxkLCBldmVuIHRoZSBvbmVzIHRoYXQgYXJlXG4gICAgICAgIC8vIGxlYXZpbmcuXG4gICAgICAgIGNoaWxkcmVuVG9SZW5kZXJba2V5XSA9IGNsb25lV2l0aFByb3BzKFxuICAgICAgICAgIHRoaXMucHJvcHMuY2hpbGRGYWN0b3J5KGNoaWxkKSxcbiAgICAgICAgICB7cmVmOiBrZXl9XG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBSZWFjdC5jcmVhdGVFbGVtZW50KFxuICAgICAgdGhpcy5wcm9wcy5jb21wb25lbnQsXG4gICAgICB0aGlzLnByb3BzLFxuICAgICAgY2hpbGRyZW5Ub1JlbmRlclxuICAgICk7XG4gIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0VHJhbnNpdGlvbkdyb3VwO1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdFVwZGF0ZXNcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIENhbGxiYWNrUXVldWUgPSByZXF1aXJlKFwiLi9DYWxsYmFja1F1ZXVlXCIpO1xudmFyIFBvb2xlZENsYXNzID0gcmVxdWlyZShcIi4vUG9vbGVkQ2xhc3NcIik7XG52YXIgUmVhY3RDdXJyZW50T3duZXIgPSByZXF1aXJlKFwiLi9SZWFjdEN1cnJlbnRPd25lclwiKTtcbnZhciBSZWFjdFBlcmYgPSByZXF1aXJlKFwiLi9SZWFjdFBlcmZcIik7XG52YXIgVHJhbnNhY3Rpb24gPSByZXF1aXJlKFwiLi9UcmFuc2FjdGlvblwiKTtcblxudmFyIGFzc2lnbiA9IHJlcXVpcmUoXCIuL09iamVjdC5hc3NpZ25cIik7XG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xudmFyIHdhcm5pbmcgPSByZXF1aXJlKFwiLi93YXJuaW5nXCIpO1xuXG52YXIgZGlydHlDb21wb25lbnRzID0gW107XG52YXIgYXNhcENhbGxiYWNrUXVldWUgPSBDYWxsYmFja1F1ZXVlLmdldFBvb2xlZCgpO1xudmFyIGFzYXBFbnF1ZXVlZCA9IGZhbHNlO1xuXG52YXIgYmF0Y2hpbmdTdHJhdGVneSA9IG51bGw7XG5cbmZ1bmN0aW9uIGVuc3VyZUluamVjdGVkKCkge1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgIFJlYWN0VXBkYXRlcy5SZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9uICYmIGJhdGNoaW5nU3RyYXRlZ3ksXG4gICAgJ1JlYWN0VXBkYXRlczogbXVzdCBpbmplY3QgYSByZWNvbmNpbGUgdHJhbnNhY3Rpb24gY2xhc3MgYW5kIGJhdGNoaW5nICcgK1xuICAgICdzdHJhdGVneSdcbiAgKSA6IGludmFyaWFudChSZWFjdFVwZGF0ZXMuUmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbiAmJiBiYXRjaGluZ1N0cmF0ZWd5KSk7XG59XG5cbnZhciBORVNURURfVVBEQVRFUyA9IHtcbiAgaW5pdGlhbGl6ZTogZnVuY3Rpb24oKSB7XG4gICAgdGhpcy5kaXJ0eUNvbXBvbmVudHNMZW5ndGggPSBkaXJ0eUNvbXBvbmVudHMubGVuZ3RoO1xuICB9LFxuICBjbG9zZTogZnVuY3Rpb24oKSB7XG4gICAgaWYgKHRoaXMuZGlydHlDb21wb25lbnRzTGVuZ3RoICE9PSBkaXJ0eUNvbXBvbmVudHMubGVuZ3RoKSB7XG4gICAgICAvLyBBZGRpdGlvbmFsIHVwZGF0ZXMgd2VyZSBlbnF1ZXVlZCBieSBjb21wb25lbnREaWRVcGRhdGUgaGFuZGxlcnMgb3JcbiAgICAgIC8vIHNpbWlsYXI7IGJlZm9yZSBvdXIgb3duIFVQREFURV9RVUVVRUlORyB3cmFwcGVyIGNsb3Nlcywgd2Ugd2FudCB0byBydW5cbiAgICAgIC8vIHRoZXNlIG5ldyB1cGRhdGVzIHNvIHRoYXQgaWYgQSdzIGNvbXBvbmVudERpZFVwZGF0ZSBjYWxscyBzZXRTdGF0ZSBvblxuICAgICAgLy8gQiwgQiB3aWxsIHVwZGF0ZSBiZWZvcmUgdGhlIGNhbGxiYWNrIEEncyB1cGRhdGVyIHByb3ZpZGVkIHdoZW4gY2FsbGluZ1xuICAgICAgLy8gc2V0U3RhdGUuXG4gICAgICBkaXJ0eUNvbXBvbmVudHMuc3BsaWNlKDAsIHRoaXMuZGlydHlDb21wb25lbnRzTGVuZ3RoKTtcbiAgICAgIGZsdXNoQmF0Y2hlZFVwZGF0ZXMoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgZGlydHlDb21wb25lbnRzLmxlbmd0aCA9IDA7XG4gICAgfVxuICB9XG59O1xuXG52YXIgVVBEQVRFX1FVRVVFSU5HID0ge1xuICBpbml0aWFsaXplOiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLmNhbGxiYWNrUXVldWUucmVzZXQoKTtcbiAgfSxcbiAgY2xvc2U6IGZ1bmN0aW9uKCkge1xuICAgIHRoaXMuY2FsbGJhY2tRdWV1ZS5ub3RpZnlBbGwoKTtcbiAgfVxufTtcblxudmFyIFRSQU5TQUNUSU9OX1dSQVBQRVJTID0gW05FU1RFRF9VUERBVEVTLCBVUERBVEVfUVVFVUVJTkddO1xuXG5mdW5jdGlvbiBSZWFjdFVwZGF0ZXNGbHVzaFRyYW5zYWN0aW9uKCkge1xuICB0aGlzLnJlaW5pdGlhbGl6ZVRyYW5zYWN0aW9uKCk7XG4gIHRoaXMuZGlydHlDb21wb25lbnRzTGVuZ3RoID0gbnVsbDtcbiAgdGhpcy5jYWxsYmFja1F1ZXVlID0gQ2FsbGJhY2tRdWV1ZS5nZXRQb29sZWQoKTtcbiAgdGhpcy5yZWNvbmNpbGVUcmFuc2FjdGlvbiA9XG4gICAgUmVhY3RVcGRhdGVzLlJlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb24uZ2V0UG9vbGVkKCk7XG59XG5cbmFzc2lnbihcbiAgUmVhY3RVcGRhdGVzRmx1c2hUcmFuc2FjdGlvbi5wcm90b3R5cGUsXG4gIFRyYW5zYWN0aW9uLk1peGluLCB7XG4gIGdldFRyYW5zYWN0aW9uV3JhcHBlcnM6IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiBUUkFOU0FDVElPTl9XUkFQUEVSUztcbiAgfSxcblxuICBkZXN0cnVjdG9yOiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLmRpcnR5Q29tcG9uZW50c0xlbmd0aCA9IG51bGw7XG4gICAgQ2FsbGJhY2tRdWV1ZS5yZWxlYXNlKHRoaXMuY2FsbGJhY2tRdWV1ZSk7XG4gICAgdGhpcy5jYWxsYmFja1F1ZXVlID0gbnVsbDtcbiAgICBSZWFjdFVwZGF0ZXMuUmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbi5yZWxlYXNlKHRoaXMucmVjb25jaWxlVHJhbnNhY3Rpb24pO1xuICAgIHRoaXMucmVjb25jaWxlVHJhbnNhY3Rpb24gPSBudWxsO1xuICB9LFxuXG4gIHBlcmZvcm06IGZ1bmN0aW9uKG1ldGhvZCwgc2NvcGUsIGEpIHtcbiAgICAvLyBFc3NlbnRpYWxseSBjYWxscyBgdGhpcy5yZWNvbmNpbGVUcmFuc2FjdGlvbi5wZXJmb3JtKG1ldGhvZCwgc2NvcGUsIGEpYFxuICAgIC8vIHdpdGggdGhpcyB0cmFuc2FjdGlvbidzIHdyYXBwZXJzIGFyb3VuZCBpdC5cbiAgICByZXR1cm4gVHJhbnNhY3Rpb24uTWl4aW4ucGVyZm9ybS5jYWxsKFxuICAgICAgdGhpcyxcbiAgICAgIHRoaXMucmVjb25jaWxlVHJhbnNhY3Rpb24ucGVyZm9ybSxcbiAgICAgIHRoaXMucmVjb25jaWxlVHJhbnNhY3Rpb24sXG4gICAgICBtZXRob2QsXG4gICAgICBzY29wZSxcbiAgICAgIGFcbiAgICApO1xuICB9XG59KTtcblxuUG9vbGVkQ2xhc3MuYWRkUG9vbGluZ1RvKFJlYWN0VXBkYXRlc0ZsdXNoVHJhbnNhY3Rpb24pO1xuXG5mdW5jdGlvbiBiYXRjaGVkVXBkYXRlcyhjYWxsYmFjaywgYSwgYikge1xuICBlbnN1cmVJbmplY3RlZCgpO1xuICBiYXRjaGluZ1N0cmF0ZWd5LmJhdGNoZWRVcGRhdGVzKGNhbGxiYWNrLCBhLCBiKTtcbn1cblxuLyoqXG4gKiBBcnJheSBjb21wYXJhdG9yIGZvciBSZWFjdENvbXBvbmVudHMgYnkgb3duZXIgZGVwdGhcbiAqXG4gKiBAcGFyYW0ge1JlYWN0Q29tcG9uZW50fSBjMSBmaXJzdCBjb21wb25lbnQgeW91J3JlIGNvbXBhcmluZ1xuICogQHBhcmFtIHtSZWFjdENvbXBvbmVudH0gYzIgc2Vjb25kIGNvbXBvbmVudCB5b3UncmUgY29tcGFyaW5nXG4gKiBAcmV0dXJuIHtudW1iZXJ9IFJldHVybiB2YWx1ZSB1c2FibGUgYnkgQXJyYXkucHJvdG90eXBlLnNvcnQoKS5cbiAqL1xuZnVuY3Rpb24gbW91bnREZXB0aENvbXBhcmF0b3IoYzEsIGMyKSB7XG4gIHJldHVybiBjMS5fbW91bnREZXB0aCAtIGMyLl9tb3VudERlcHRoO1xufVxuXG5mdW5jdGlvbiBydW5CYXRjaGVkVXBkYXRlcyh0cmFuc2FjdGlvbikge1xuICB2YXIgbGVuID0gdHJhbnNhY3Rpb24uZGlydHlDb21wb25lbnRzTGVuZ3RoO1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgIGxlbiA9PT0gZGlydHlDb21wb25lbnRzLmxlbmd0aCxcbiAgICAnRXhwZWN0ZWQgZmx1c2ggdHJhbnNhY3Rpb25cXCdzIHN0b3JlZCBkaXJ0eS1jb21wb25lbnRzIGxlbmd0aCAoJXMpIHRvICcgK1xuICAgICdtYXRjaCBkaXJ0eS1jb21wb25lbnRzIGFycmF5IGxlbmd0aCAoJXMpLicsXG4gICAgbGVuLFxuICAgIGRpcnR5Q29tcG9uZW50cy5sZW5ndGhcbiAgKSA6IGludmFyaWFudChsZW4gPT09IGRpcnR5Q29tcG9uZW50cy5sZW5ndGgpKTtcblxuICAvLyBTaW5jZSByZWNvbmNpbGluZyBhIGNvbXBvbmVudCBoaWdoZXIgaW4gdGhlIG93bmVyIGhpZXJhcmNoeSB1c3VhbGx5IChub3RcbiAgLy8gYWx3YXlzIC0tIHNlZSBzaG91bGRDb21wb25lbnRVcGRhdGUoKSkgd2lsbCByZWNvbmNpbGUgY2hpbGRyZW4sIHJlY29uY2lsZVxuICAvLyB0aGVtIGJlZm9yZSB0aGVpciBjaGlsZHJlbiBieSBzb3J0aW5nIHRoZSBhcnJheS5cbiAgZGlydHlDb21wb25lbnRzLnNvcnQobW91bnREZXB0aENvbXBhcmF0b3IpO1xuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuOyBpKyspIHtcbiAgICAvLyBJZiBhIGNvbXBvbmVudCBpcyB1bm1vdW50ZWQgYmVmb3JlIHBlbmRpbmcgY2hhbmdlcyBhcHBseSwgaWdub3JlIHRoZW1cbiAgICAvLyBUT0RPOiBRdWV1ZSB1bm1vdW50cyBpbiB0aGUgc2FtZSBsaXN0IHRvIGF2b2lkIHRoaXMgaGFwcGVuaW5nIGF0IGFsbFxuICAgIHZhciBjb21wb25lbnQgPSBkaXJ0eUNvbXBvbmVudHNbaV07XG4gICAgaWYgKGNvbXBvbmVudC5pc01vdW50ZWQoKSkge1xuICAgICAgLy8gSWYgcGVyZm9ybVVwZGF0ZUlmTmVjZXNzYXJ5IGhhcHBlbnMgdG8gZW5xdWV1ZSBhbnkgbmV3IHVwZGF0ZXMsIHdlXG4gICAgICAvLyBzaG91bGRuJ3QgZXhlY3V0ZSB0aGUgY2FsbGJhY2tzIHVudGlsIHRoZSBuZXh0IHJlbmRlciBoYXBwZW5zLCBzb1xuICAgICAgLy8gc3Rhc2ggdGhlIGNhbGxiYWNrcyBmaXJzdFxuICAgICAgdmFyIGNhbGxiYWNrcyA9IGNvbXBvbmVudC5fcGVuZGluZ0NhbGxiYWNrcztcbiAgICAgIGNvbXBvbmVudC5fcGVuZGluZ0NhbGxiYWNrcyA9IG51bGw7XG4gICAgICBjb21wb25lbnQucGVyZm9ybVVwZGF0ZUlmTmVjZXNzYXJ5KHRyYW5zYWN0aW9uLnJlY29uY2lsZVRyYW5zYWN0aW9uKTtcblxuICAgICAgaWYgKGNhbGxiYWNrcykge1xuICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IGNhbGxiYWNrcy5sZW5ndGg7IGorKykge1xuICAgICAgICAgIHRyYW5zYWN0aW9uLmNhbGxiYWNrUXVldWUuZW5xdWV1ZShcbiAgICAgICAgICAgIGNhbGxiYWNrc1tqXSxcbiAgICAgICAgICAgIGNvbXBvbmVudFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxudmFyIGZsdXNoQmF0Y2hlZFVwZGF0ZXMgPSBSZWFjdFBlcmYubWVhc3VyZShcbiAgJ1JlYWN0VXBkYXRlcycsXG4gICdmbHVzaEJhdGNoZWRVcGRhdGVzJyxcbiAgZnVuY3Rpb24oKSB7XG4gICAgLy8gUmVhY3RVcGRhdGVzRmx1c2hUcmFuc2FjdGlvbidzIHdyYXBwZXJzIHdpbGwgY2xlYXIgdGhlIGRpcnR5Q29tcG9uZW50c1xuICAgIC8vIGFycmF5IGFuZCBwZXJmb3JtIGFueSB1cGRhdGVzIGVucXVldWVkIGJ5IG1vdW50LXJlYWR5IGhhbmRsZXJzIChpLmUuLFxuICAgIC8vIGNvbXBvbmVudERpZFVwZGF0ZSkgYnV0IHdlIG5lZWQgdG8gY2hlY2sgaGVyZSB0b28gaW4gb3JkZXIgdG8gY2F0Y2hcbiAgICAvLyB1cGRhdGVzIGVucXVldWVkIGJ5IHNldFN0YXRlIGNhbGxiYWNrcyBhbmQgYXNhcCBjYWxscy5cbiAgICB3aGlsZSAoZGlydHlDb21wb25lbnRzLmxlbmd0aCB8fCBhc2FwRW5xdWV1ZWQpIHtcbiAgICAgIGlmIChkaXJ0eUNvbXBvbmVudHMubGVuZ3RoKSB7XG4gICAgICAgIHZhciB0cmFuc2FjdGlvbiA9IFJlYWN0VXBkYXRlc0ZsdXNoVHJhbnNhY3Rpb24uZ2V0UG9vbGVkKCk7XG4gICAgICAgIHRyYW5zYWN0aW9uLnBlcmZvcm0ocnVuQmF0Y2hlZFVwZGF0ZXMsIG51bGwsIHRyYW5zYWN0aW9uKTtcbiAgICAgICAgUmVhY3RVcGRhdGVzRmx1c2hUcmFuc2FjdGlvbi5yZWxlYXNlKHRyYW5zYWN0aW9uKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGFzYXBFbnF1ZXVlZCkge1xuICAgICAgICBhc2FwRW5xdWV1ZWQgPSBmYWxzZTtcbiAgICAgICAgdmFyIHF1ZXVlID0gYXNhcENhbGxiYWNrUXVldWU7XG4gICAgICAgIGFzYXBDYWxsYmFja1F1ZXVlID0gQ2FsbGJhY2tRdWV1ZS5nZXRQb29sZWQoKTtcbiAgICAgICAgcXVldWUubm90aWZ5QWxsKCk7XG4gICAgICAgIENhbGxiYWNrUXVldWUucmVsZWFzZShxdWV1ZSk7XG4gICAgICB9XG4gICAgfVxuICB9XG4pO1xuXG4vKipcbiAqIE1hcmsgYSBjb21wb25lbnQgYXMgbmVlZGluZyBhIHJlcmVuZGVyLCBhZGRpbmcgYW4gb3B0aW9uYWwgY2FsbGJhY2sgdG8gYVxuICogbGlzdCBvZiBmdW5jdGlvbnMgd2hpY2ggd2lsbCBiZSBleGVjdXRlZCBvbmNlIHRoZSByZXJlbmRlciBvY2N1cnMuXG4gKi9cbmZ1bmN0aW9uIGVucXVldWVVcGRhdGUoY29tcG9uZW50LCBjYWxsYmFjaykge1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICFjYWxsYmFjayB8fCB0eXBlb2YgY2FsbGJhY2sgPT09IFwiZnVuY3Rpb25cIixcbiAgICAnZW5xdWV1ZVVwZGF0ZSguLi4pOiBZb3UgY2FsbGVkIGBzZXRQcm9wc2AsIGByZXBsYWNlUHJvcHNgLCAnICtcbiAgICAnYHNldFN0YXRlYCwgYHJlcGxhY2VTdGF0ZWAsIG9yIGBmb3JjZVVwZGF0ZWAgd2l0aCBhIGNhbGxiYWNrIHRoYXQgJyArXG4gICAgJ2lzblxcJ3QgY2FsbGFibGUuJ1xuICApIDogaW52YXJpYW50KCFjYWxsYmFjayB8fCB0eXBlb2YgY2FsbGJhY2sgPT09IFwiZnVuY3Rpb25cIikpO1xuICBlbnN1cmVJbmplY3RlZCgpO1xuXG4gIC8vIFZhcmlvdXMgcGFydHMgb2Ygb3VyIGNvZGUgKHN1Y2ggYXMgUmVhY3RDb21wb3NpdGVDb21wb25lbnQnc1xuICAvLyBfcmVuZGVyVmFsaWRhdGVkQ29tcG9uZW50KSBhc3N1bWUgdGhhdCBjYWxscyB0byByZW5kZXIgYXJlbid0IG5lc3RlZDtcbiAgLy8gdmVyaWZ5IHRoYXQgdGhhdCdzIHRoZSBjYXNlLiAoVGhpcyBpcyBjYWxsZWQgYnkgZWFjaCB0b3AtbGV2ZWwgdXBkYXRlXG4gIC8vIGZ1bmN0aW9uLCBsaWtlIHNldFByb3BzLCBzZXRTdGF0ZSwgZm9yY2VVcGRhdGUsIGV0Yy47IGNyZWF0aW9uIGFuZFxuICAvLyBkZXN0cnVjdGlvbiBvZiB0b3AtbGV2ZWwgY29tcG9uZW50cyBpcyBndWFyZGVkIGluIFJlYWN0TW91bnQuKVxuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gd2FybmluZyhcbiAgICBSZWFjdEN1cnJlbnRPd25lci5jdXJyZW50ID09IG51bGwsXG4gICAgJ2VucXVldWVVcGRhdGUoKTogUmVuZGVyIG1ldGhvZHMgc2hvdWxkIGJlIGEgcHVyZSBmdW5jdGlvbiBvZiBwcm9wcyAnICtcbiAgICAnYW5kIHN0YXRlOyB0cmlnZ2VyaW5nIG5lc3RlZCBjb21wb25lbnQgdXBkYXRlcyBmcm9tIHJlbmRlciBpcyBub3QgJyArXG4gICAgJ2FsbG93ZWQuIElmIG5lY2Vzc2FyeSwgdHJpZ2dlciBuZXN0ZWQgdXBkYXRlcyBpbiAnICtcbiAgICAnY29tcG9uZW50RGlkVXBkYXRlLidcbiAgKSA6IG51bGwpO1xuXG4gIGlmICghYmF0Y2hpbmdTdHJhdGVneS5pc0JhdGNoaW5nVXBkYXRlcykge1xuICAgIGJhdGNoaW5nU3RyYXRlZ3kuYmF0Y2hlZFVwZGF0ZXMoZW5xdWV1ZVVwZGF0ZSwgY29tcG9uZW50LCBjYWxsYmFjayk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgZGlydHlDb21wb25lbnRzLnB1c2goY29tcG9uZW50KTtcblxuICBpZiAoY2FsbGJhY2spIHtcbiAgICBpZiAoY29tcG9uZW50Ll9wZW5kaW5nQ2FsbGJhY2tzKSB7XG4gICAgICBjb21wb25lbnQuX3BlbmRpbmdDYWxsYmFja3MucHVzaChjYWxsYmFjayk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbXBvbmVudC5fcGVuZGluZ0NhbGxiYWNrcyA9IFtjYWxsYmFja107XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogRW5xdWV1ZSBhIGNhbGxiYWNrIHRvIGJlIHJ1biBhdCB0aGUgZW5kIG9mIHRoZSBjdXJyZW50IGJhdGNoaW5nIGN5Y2xlLiBUaHJvd3NcbiAqIGlmIG5vIHVwZGF0ZXMgYXJlIGN1cnJlbnRseSBiZWluZyBwZXJmb3JtZWQuXG4gKi9cbmZ1bmN0aW9uIGFzYXAoY2FsbGJhY2ssIGNvbnRleHQpIHtcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICBiYXRjaGluZ1N0cmF0ZWd5LmlzQmF0Y2hpbmdVcGRhdGVzLFxuICAgICdSZWFjdFVwZGF0ZXMuYXNhcDogQ2FuXFwndCBlbnF1ZXVlIGFuIGFzYXAgY2FsbGJhY2sgaW4gYSBjb250ZXh0IHdoZXJlJyArXG4gICAgJ3VwZGF0ZXMgYXJlIG5vdCBiZWluZyBiYXRjaGVkLidcbiAgKSA6IGludmFyaWFudChiYXRjaGluZ1N0cmF0ZWd5LmlzQmF0Y2hpbmdVcGRhdGVzKSk7XG4gIGFzYXBDYWxsYmFja1F1ZXVlLmVucXVldWUoY2FsbGJhY2ssIGNvbnRleHQpO1xuICBhc2FwRW5xdWV1ZWQgPSB0cnVlO1xufVxuXG52YXIgUmVhY3RVcGRhdGVzSW5qZWN0aW9uID0ge1xuICBpbmplY3RSZWNvbmNpbGVUcmFuc2FjdGlvbjogZnVuY3Rpb24oUmVjb25jaWxlVHJhbnNhY3Rpb24pIHtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgUmVjb25jaWxlVHJhbnNhY3Rpb24sXG4gICAgICAnUmVhY3RVcGRhdGVzOiBtdXN0IHByb3ZpZGUgYSByZWNvbmNpbGUgdHJhbnNhY3Rpb24gY2xhc3MnXG4gICAgKSA6IGludmFyaWFudChSZWNvbmNpbGVUcmFuc2FjdGlvbikpO1xuICAgIFJlYWN0VXBkYXRlcy5SZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9uID0gUmVjb25jaWxlVHJhbnNhY3Rpb247XG4gIH0sXG5cbiAgaW5qZWN0QmF0Y2hpbmdTdHJhdGVneTogZnVuY3Rpb24oX2JhdGNoaW5nU3RyYXRlZ3kpIHtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgX2JhdGNoaW5nU3RyYXRlZ3ksXG4gICAgICAnUmVhY3RVcGRhdGVzOiBtdXN0IHByb3ZpZGUgYSBiYXRjaGluZyBzdHJhdGVneSdcbiAgICApIDogaW52YXJpYW50KF9iYXRjaGluZ1N0cmF0ZWd5KSk7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgIHR5cGVvZiBfYmF0Y2hpbmdTdHJhdGVneS5iYXRjaGVkVXBkYXRlcyA9PT0gJ2Z1bmN0aW9uJyxcbiAgICAgICdSZWFjdFVwZGF0ZXM6IG11c3QgcHJvdmlkZSBhIGJhdGNoZWRVcGRhdGVzKCkgZnVuY3Rpb24nXG4gICAgKSA6IGludmFyaWFudCh0eXBlb2YgX2JhdGNoaW5nU3RyYXRlZ3kuYmF0Y2hlZFVwZGF0ZXMgPT09ICdmdW5jdGlvbicpKTtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgdHlwZW9mIF9iYXRjaGluZ1N0cmF0ZWd5LmlzQmF0Y2hpbmdVcGRhdGVzID09PSAnYm9vbGVhbicsXG4gICAgICAnUmVhY3RVcGRhdGVzOiBtdXN0IHByb3ZpZGUgYW4gaXNCYXRjaGluZ1VwZGF0ZXMgYm9vbGVhbiBhdHRyaWJ1dGUnXG4gICAgKSA6IGludmFyaWFudCh0eXBlb2YgX2JhdGNoaW5nU3RyYXRlZ3kuaXNCYXRjaGluZ1VwZGF0ZXMgPT09ICdib29sZWFuJykpO1xuICAgIGJhdGNoaW5nU3RyYXRlZ3kgPSBfYmF0Y2hpbmdTdHJhdGVneTtcbiAgfVxufTtcblxudmFyIFJlYWN0VXBkYXRlcyA9IHtcbiAgLyoqXG4gICAqIFJlYWN0IHJlZmVyZW5jZXMgYFJlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb25gIHVzaW5nIHRoaXMgcHJvcGVydHkgaW4gb3JkZXJcbiAgICogdG8gYWxsb3cgZGVwZW5kZW5jeSBpbmplY3Rpb24uXG4gICAqXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgUmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbjogbnVsbCxcblxuICBiYXRjaGVkVXBkYXRlczogYmF0Y2hlZFVwZGF0ZXMsXG4gIGVucXVldWVVcGRhdGU6IGVucXVldWVVcGRhdGUsXG4gIGZsdXNoQmF0Y2hlZFVwZGF0ZXM6IGZsdXNoQmF0Y2hlZFVwZGF0ZXMsXG4gIGluamVjdGlvbjogUmVhY3RVcGRhdGVzSW5qZWN0aW9uLFxuICBhc2FwOiBhc2FwXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0VXBkYXRlcztcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdFdpdGhBZGRvbnNcbiAqL1xuXG4vKipcbiAqIFRoaXMgbW9kdWxlIGV4aXN0cyBwdXJlbHkgaW4gdGhlIG9wZW4gc291cmNlIHByb2plY3QsIGFuZCBpcyBtZWFudCBhcyBhIHdheVxuICogdG8gY3JlYXRlIGEgc2VwYXJhdGUgc3RhbmRhbG9uZSBidWlsZCBvZiBSZWFjdC4gVGhpcyBidWlsZCBoYXMgXCJhZGRvbnNcIiwgb3JcbiAqIGZ1bmN0aW9uYWxpdHkgd2UndmUgYnVpbHQgYW5kIHRoaW5rIG1pZ2h0IGJlIHVzZWZ1bCBidXQgZG9lc24ndCBoYXZlIGEgZ29vZFxuICogcGxhY2UgdG8gbGl2ZSBpbnNpZGUgUmVhY3QgY29yZS5cbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIExpbmtlZFN0YXRlTWl4aW4gPSByZXF1aXJlKFwiLi9MaW5rZWRTdGF0ZU1peGluXCIpO1xudmFyIFJlYWN0ID0gcmVxdWlyZShcIi4vUmVhY3RcIik7XG52YXIgUmVhY3RDb21wb25lbnRXaXRoUHVyZVJlbmRlck1peGluID1cbiAgcmVxdWlyZShcIi4vUmVhY3RDb21wb25lbnRXaXRoUHVyZVJlbmRlck1peGluXCIpO1xudmFyIFJlYWN0Q1NTVHJhbnNpdGlvbkdyb3VwID0gcmVxdWlyZShcIi4vUmVhY3RDU1NUcmFuc2l0aW9uR3JvdXBcIik7XG52YXIgUmVhY3RUcmFuc2l0aW9uR3JvdXAgPSByZXF1aXJlKFwiLi9SZWFjdFRyYW5zaXRpb25Hcm91cFwiKTtcbnZhciBSZWFjdFVwZGF0ZXMgPSByZXF1aXJlKFwiLi9SZWFjdFVwZGF0ZXNcIik7XG5cbnZhciBjeCA9IHJlcXVpcmUoXCIuL2N4XCIpO1xudmFyIGNsb25lV2l0aFByb3BzID0gcmVxdWlyZShcIi4vY2xvbmVXaXRoUHJvcHNcIik7XG52YXIgdXBkYXRlID0gcmVxdWlyZShcIi4vdXBkYXRlXCIpO1xuXG5SZWFjdC5hZGRvbnMgPSB7XG4gIENTU1RyYW5zaXRpb25Hcm91cDogUmVhY3RDU1NUcmFuc2l0aW9uR3JvdXAsXG4gIExpbmtlZFN0YXRlTWl4aW46IExpbmtlZFN0YXRlTWl4aW4sXG4gIFB1cmVSZW5kZXJNaXhpbjogUmVhY3RDb21wb25lbnRXaXRoUHVyZVJlbmRlck1peGluLFxuICBUcmFuc2l0aW9uR3JvdXA6IFJlYWN0VHJhbnNpdGlvbkdyb3VwLFxuXG4gIGJhdGNoZWRVcGRhdGVzOiBSZWFjdFVwZGF0ZXMuYmF0Y2hlZFVwZGF0ZXMsXG4gIGNsYXNzU2V0OiBjeCxcbiAgY2xvbmVXaXRoUHJvcHM6IGNsb25lV2l0aFByb3BzLFxuICB1cGRhdGU6IHVwZGF0ZVxufTtcblxuaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICBSZWFjdC5hZGRvbnMuUGVyZiA9IHJlcXVpcmUoXCIuL1JlYWN0RGVmYXVsdFBlcmZcIik7XG4gIFJlYWN0LmFkZG9ucy5UZXN0VXRpbHMgPSByZXF1aXJlKFwiLi9SZWFjdFRlc3RVdGlsc1wiKTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdDtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFNWR0RPTVByb3BlcnR5Q29uZmlnXG4gKi9cblxuLypqc2xpbnQgYml0d2lzZTogdHJ1ZSovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgRE9NUHJvcGVydHkgPSByZXF1aXJlKFwiLi9ET01Qcm9wZXJ0eVwiKTtcblxudmFyIE1VU1RfVVNFX0FUVFJJQlVURSA9IERPTVByb3BlcnR5LmluamVjdGlvbi5NVVNUX1VTRV9BVFRSSUJVVEU7XG5cbnZhciBTVkdET01Qcm9wZXJ0eUNvbmZpZyA9IHtcbiAgUHJvcGVydGllczoge1xuICAgIGN4OiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgY3k6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBkOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgZHg6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBkeTogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIGZpbGw6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBmaWxsT3BhY2l0eTogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIGZvbnRGYW1pbHk6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBmb250U2l6ZTogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIGZ4OiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgZnk6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBncmFkaWVudFRyYW5zZm9ybTogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIGdyYWRpZW50VW5pdHM6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBtYXJrZXJFbmQ6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBtYXJrZXJNaWQ6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBtYXJrZXJTdGFydDogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIG9mZnNldDogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIG9wYWNpdHk6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBwYXR0ZXJuQ29udGVudFVuaXRzOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgcGF0dGVyblVuaXRzOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgcG9pbnRzOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgcHJlc2VydmVBc3BlY3RSYXRpbzogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIHI6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICByeDogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIHJ5OiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgc3ByZWFkTWV0aG9kOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgc3RvcENvbG9yOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgc3RvcE9wYWNpdHk6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBzdHJva2U6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBzdHJva2VEYXNoYXJyYXk6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBzdHJva2VMaW5lY2FwOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgc3Ryb2tlT3BhY2l0eTogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIHN0cm9rZVdpZHRoOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgdGV4dEFuY2hvcjogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIHRyYW5zZm9ybTogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIHZlcnNpb246IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICB2aWV3Qm94OiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgeDE6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICB4MjogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIHg6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICB5MTogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIHkyOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgeTogTVVTVF9VU0VfQVRUUklCVVRFXG4gIH0sXG4gIERPTUF0dHJpYnV0ZU5hbWVzOiB7XG4gICAgZmlsbE9wYWNpdHk6ICdmaWxsLW9wYWNpdHknLFxuICAgIGZvbnRGYW1pbHk6ICdmb250LWZhbWlseScsXG4gICAgZm9udFNpemU6ICdmb250LXNpemUnLFxuICAgIGdyYWRpZW50VHJhbnNmb3JtOiAnZ3JhZGllbnRUcmFuc2Zvcm0nLFxuICAgIGdyYWRpZW50VW5pdHM6ICdncmFkaWVudFVuaXRzJyxcbiAgICBtYXJrZXJFbmQ6ICdtYXJrZXItZW5kJyxcbiAgICBtYXJrZXJNaWQ6ICdtYXJrZXItbWlkJyxcbiAgICBtYXJrZXJTdGFydDogJ21hcmtlci1zdGFydCcsXG4gICAgcGF0dGVybkNvbnRlbnRVbml0czogJ3BhdHRlcm5Db250ZW50VW5pdHMnLFxuICAgIHBhdHRlcm5Vbml0czogJ3BhdHRlcm5Vbml0cycsXG4gICAgcHJlc2VydmVBc3BlY3RSYXRpbzogJ3ByZXNlcnZlQXNwZWN0UmF0aW8nLFxuICAgIHNwcmVhZE1ldGhvZDogJ3NwcmVhZE1ldGhvZCcsXG4gICAgc3RvcENvbG9yOiAnc3RvcC1jb2xvcicsXG4gICAgc3RvcE9wYWNpdHk6ICdzdG9wLW9wYWNpdHknLFxuICAgIHN0cm9rZURhc2hhcnJheTogJ3N0cm9rZS1kYXNoYXJyYXknLFxuICAgIHN0cm9rZUxpbmVjYXA6ICdzdHJva2UtbGluZWNhcCcsXG4gICAgc3Ryb2tlT3BhY2l0eTogJ3N0cm9rZS1vcGFjaXR5JyxcbiAgICBzdHJva2VXaWR0aDogJ3N0cm9rZS13aWR0aCcsXG4gICAgdGV4dEFuY2hvcjogJ3RleHQtYW5jaG9yJyxcbiAgICB2aWV3Qm94OiAndmlld0JveCdcbiAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTVkdET01Qcm9wZXJ0eUNvbmZpZztcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBTZWxlY3RFdmVudFBsdWdpblxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgRXZlbnRDb25zdGFudHMgPSByZXF1aXJlKFwiLi9FdmVudENvbnN0YW50c1wiKTtcbnZhciBFdmVudFByb3BhZ2F0b3JzID0gcmVxdWlyZShcIi4vRXZlbnRQcm9wYWdhdG9yc1wiKTtcbnZhciBSZWFjdElucHV0U2VsZWN0aW9uID0gcmVxdWlyZShcIi4vUmVhY3RJbnB1dFNlbGVjdGlvblwiKTtcbnZhciBTeW50aGV0aWNFdmVudCA9IHJlcXVpcmUoXCIuL1N5bnRoZXRpY0V2ZW50XCIpO1xuXG52YXIgZ2V0QWN0aXZlRWxlbWVudCA9IHJlcXVpcmUoXCIuL2dldEFjdGl2ZUVsZW1lbnRcIik7XG52YXIgaXNUZXh0SW5wdXRFbGVtZW50ID0gcmVxdWlyZShcIi4vaXNUZXh0SW5wdXRFbGVtZW50XCIpO1xudmFyIGtleU9mID0gcmVxdWlyZShcIi4va2V5T2ZcIik7XG52YXIgc2hhbGxvd0VxdWFsID0gcmVxdWlyZShcIi4vc2hhbGxvd0VxdWFsXCIpO1xuXG52YXIgdG9wTGV2ZWxUeXBlcyA9IEV2ZW50Q29uc3RhbnRzLnRvcExldmVsVHlwZXM7XG5cbnZhciBldmVudFR5cGVzID0ge1xuICBzZWxlY3Q6IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uU2VsZWN0OiBudWxsfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uU2VsZWN0Q2FwdHVyZTogbnVsbH0pXG4gICAgfSxcbiAgICBkZXBlbmRlbmNpZXM6IFtcbiAgICAgIHRvcExldmVsVHlwZXMudG9wQmx1cixcbiAgICAgIHRvcExldmVsVHlwZXMudG9wQ29udGV4dE1lbnUsXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcEZvY3VzLFxuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BLZXlEb3duLFxuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BNb3VzZURvd24sXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcE1vdXNlVXAsXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcFNlbGVjdGlvbkNoYW5nZVxuICAgIF1cbiAgfVxufTtcblxudmFyIGFjdGl2ZUVsZW1lbnQgPSBudWxsO1xudmFyIGFjdGl2ZUVsZW1lbnRJRCA9IG51bGw7XG52YXIgbGFzdFNlbGVjdGlvbiA9IG51bGw7XG52YXIgbW91c2VEb3duID0gZmFsc2U7XG5cbi8qKlxuICogR2V0IGFuIG9iamVjdCB3aGljaCBpcyBhIHVuaXF1ZSByZXByZXNlbnRhdGlvbiBvZiB0aGUgY3VycmVudCBzZWxlY3Rpb24uXG4gKlxuICogVGhlIHJldHVybiB2YWx1ZSB3aWxsIG5vdCBiZSBjb25zaXN0ZW50IGFjcm9zcyBub2RlcyBvciBicm93c2VycywgYnV0XG4gKiB0d28gaWRlbnRpY2FsIHNlbGVjdGlvbnMgb24gdGhlIHNhbWUgbm9kZSB3aWxsIHJldHVybiBpZGVudGljYWwgb2JqZWN0cy5cbiAqXG4gKiBAcGFyYW0ge0RPTUVsZW1lbnR9IG5vZGVcbiAqIEBwYXJhbSB7b2JqZWN0fVxuICovXG5mdW5jdGlvbiBnZXRTZWxlY3Rpb24obm9kZSkge1xuICBpZiAoJ3NlbGVjdGlvblN0YXJ0JyBpbiBub2RlICYmXG4gICAgICBSZWFjdElucHV0U2VsZWN0aW9uLmhhc1NlbGVjdGlvbkNhcGFiaWxpdGllcyhub2RlKSkge1xuICAgIHJldHVybiB7XG4gICAgICBzdGFydDogbm9kZS5zZWxlY3Rpb25TdGFydCxcbiAgICAgIGVuZDogbm9kZS5zZWxlY3Rpb25FbmRcbiAgICB9O1xuICB9IGVsc2UgaWYgKHdpbmRvdy5nZXRTZWxlY3Rpb24pIHtcbiAgICB2YXIgc2VsZWN0aW9uID0gd2luZG93LmdldFNlbGVjdGlvbigpO1xuICAgIHJldHVybiB7XG4gICAgICBhbmNob3JOb2RlOiBzZWxlY3Rpb24uYW5jaG9yTm9kZSxcbiAgICAgIGFuY2hvck9mZnNldDogc2VsZWN0aW9uLmFuY2hvck9mZnNldCxcbiAgICAgIGZvY3VzTm9kZTogc2VsZWN0aW9uLmZvY3VzTm9kZSxcbiAgICAgIGZvY3VzT2Zmc2V0OiBzZWxlY3Rpb24uZm9jdXNPZmZzZXRcbiAgICB9O1xuICB9IGVsc2UgaWYgKGRvY3VtZW50LnNlbGVjdGlvbikge1xuICAgIHZhciByYW5nZSA9IGRvY3VtZW50LnNlbGVjdGlvbi5jcmVhdGVSYW5nZSgpO1xuICAgIHJldHVybiB7XG4gICAgICBwYXJlbnRFbGVtZW50OiByYW5nZS5wYXJlbnRFbGVtZW50KCksXG4gICAgICB0ZXh0OiByYW5nZS50ZXh0LFxuICAgICAgdG9wOiByYW5nZS5ib3VuZGluZ1RvcCxcbiAgICAgIGxlZnQ6IHJhbmdlLmJvdW5kaW5nTGVmdFxuICAgIH07XG4gIH1cbn1cblxuLyoqXG4gKiBQb2xsIHNlbGVjdGlvbiB0byBzZWUgd2hldGhlciBpdCdzIGNoYW5nZWQuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IG5hdGl2ZUV2ZW50XG4gKiBAcmV0dXJuIHs/U3ludGhldGljRXZlbnR9XG4gKi9cbmZ1bmN0aW9uIGNvbnN0cnVjdFNlbGVjdEV2ZW50KG5hdGl2ZUV2ZW50KSB7XG4gIC8vIEVuc3VyZSB3ZSBoYXZlIHRoZSByaWdodCBlbGVtZW50LCBhbmQgdGhhdCB0aGUgdXNlciBpcyBub3QgZHJhZ2dpbmcgYVxuICAvLyBzZWxlY3Rpb24gKHRoaXMgbWF0Y2hlcyBuYXRpdmUgYHNlbGVjdGAgZXZlbnQgYmVoYXZpb3IpLiBJbiBIVE1MNSwgc2VsZWN0XG4gIC8vIGZpcmVzIG9ubHkgb24gaW5wdXQgYW5kIHRleHRhcmVhIHRodXMgaWYgdGhlcmUncyBubyBmb2N1c2VkIGVsZW1lbnQgd2VcbiAgLy8gd29uJ3QgZGlzcGF0Y2guXG4gIGlmIChtb3VzZURvd24gfHxcbiAgICAgIGFjdGl2ZUVsZW1lbnQgPT0gbnVsbCB8fFxuICAgICAgYWN0aXZlRWxlbWVudCAhPSBnZXRBY3RpdmVFbGVtZW50KCkpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICAvLyBPbmx5IGZpcmUgd2hlbiBzZWxlY3Rpb24gaGFzIGFjdHVhbGx5IGNoYW5nZWQuXG4gIHZhciBjdXJyZW50U2VsZWN0aW9uID0gZ2V0U2VsZWN0aW9uKGFjdGl2ZUVsZW1lbnQpO1xuICBpZiAoIWxhc3RTZWxlY3Rpb24gfHwgIXNoYWxsb3dFcXVhbChsYXN0U2VsZWN0aW9uLCBjdXJyZW50U2VsZWN0aW9uKSkge1xuICAgIGxhc3RTZWxlY3Rpb24gPSBjdXJyZW50U2VsZWN0aW9uO1xuXG4gICAgdmFyIHN5bnRoZXRpY0V2ZW50ID0gU3ludGhldGljRXZlbnQuZ2V0UG9vbGVkKFxuICAgICAgZXZlbnRUeXBlcy5zZWxlY3QsXG4gICAgICBhY3RpdmVFbGVtZW50SUQsXG4gICAgICBuYXRpdmVFdmVudFxuICAgICk7XG5cbiAgICBzeW50aGV0aWNFdmVudC50eXBlID0gJ3NlbGVjdCc7XG4gICAgc3ludGhldGljRXZlbnQudGFyZ2V0ID0gYWN0aXZlRWxlbWVudDtcblxuICAgIEV2ZW50UHJvcGFnYXRvcnMuYWNjdW11bGF0ZVR3b1BoYXNlRGlzcGF0Y2hlcyhzeW50aGV0aWNFdmVudCk7XG5cbiAgICByZXR1cm4gc3ludGhldGljRXZlbnQ7XG4gIH1cbn1cblxuLyoqXG4gKiBUaGlzIHBsdWdpbiBjcmVhdGVzIGFuIGBvblNlbGVjdGAgZXZlbnQgdGhhdCBub3JtYWxpemVzIHNlbGVjdCBldmVudHNcbiAqIGFjcm9zcyBmb3JtIGVsZW1lbnRzLlxuICpcbiAqIFN1cHBvcnRlZCBlbGVtZW50cyBhcmU6XG4gKiAtIGlucHV0IChzZWUgYGlzVGV4dElucHV0RWxlbWVudGApXG4gKiAtIHRleHRhcmVhXG4gKiAtIGNvbnRlbnRFZGl0YWJsZVxuICpcbiAqIFRoaXMgZGlmZmVycyBmcm9tIG5hdGl2ZSBicm93c2VyIGltcGxlbWVudGF0aW9ucyBpbiB0aGUgZm9sbG93aW5nIHdheXM6XG4gKiAtIEZpcmVzIG9uIGNvbnRlbnRFZGl0YWJsZSBmaWVsZHMgYXMgd2VsbCBhcyBpbnB1dHMuXG4gKiAtIEZpcmVzIGZvciBjb2xsYXBzZWQgc2VsZWN0aW9uLlxuICogLSBGaXJlcyBhZnRlciB1c2VyIGlucHV0LlxuICovXG52YXIgU2VsZWN0RXZlbnRQbHVnaW4gPSB7XG5cbiAgZXZlbnRUeXBlczogZXZlbnRUeXBlcyxcblxuICAvKipcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRvcExldmVsVHlwZSBSZWNvcmQgZnJvbSBgRXZlbnRDb25zdGFudHNgLlxuICAgKiBAcGFyYW0ge0RPTUV2ZW50VGFyZ2V0fSB0b3BMZXZlbFRhcmdldCBUaGUgbGlzdGVuaW5nIGNvbXBvbmVudCByb290IG5vZGUuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0b3BMZXZlbFRhcmdldElEIElEIG9mIGB0b3BMZXZlbFRhcmdldGAuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudCBOYXRpdmUgYnJvd3NlciBldmVudC5cbiAgICogQHJldHVybiB7Kn0gQW4gYWNjdW11bGF0aW9uIG9mIHN5bnRoZXRpYyBldmVudHMuXG4gICAqIEBzZWUge0V2ZW50UGx1Z2luSHViLmV4dHJhY3RFdmVudHN9XG4gICAqL1xuICBleHRyYWN0RXZlbnRzOiBmdW5jdGlvbihcbiAgICAgIHRvcExldmVsVHlwZSxcbiAgICAgIHRvcExldmVsVGFyZ2V0LFxuICAgICAgdG9wTGV2ZWxUYXJnZXRJRCxcbiAgICAgIG5hdGl2ZUV2ZW50KSB7XG5cbiAgICBzd2l0Y2ggKHRvcExldmVsVHlwZSkge1xuICAgICAgLy8gVHJhY2sgdGhlIGlucHV0IG5vZGUgdGhhdCBoYXMgZm9jdXMuXG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wRm9jdXM6XG4gICAgICAgIGlmIChpc1RleHRJbnB1dEVsZW1lbnQodG9wTGV2ZWxUYXJnZXQpIHx8XG4gICAgICAgICAgICB0b3BMZXZlbFRhcmdldC5jb250ZW50RWRpdGFibGUgPT09ICd0cnVlJykge1xuICAgICAgICAgIGFjdGl2ZUVsZW1lbnQgPSB0b3BMZXZlbFRhcmdldDtcbiAgICAgICAgICBhY3RpdmVFbGVtZW50SUQgPSB0b3BMZXZlbFRhcmdldElEO1xuICAgICAgICAgIGxhc3RTZWxlY3Rpb24gPSBudWxsO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcEJsdXI6XG4gICAgICAgIGFjdGl2ZUVsZW1lbnQgPSBudWxsO1xuICAgICAgICBhY3RpdmVFbGVtZW50SUQgPSBudWxsO1xuICAgICAgICBsYXN0U2VsZWN0aW9uID0gbnVsbDtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIC8vIERvbid0IGZpcmUgdGhlIGV2ZW50IHdoaWxlIHRoZSB1c2VyIGlzIGRyYWdnaW5nLiBUaGlzIG1hdGNoZXMgdGhlXG4gICAgICAvLyBzZW1hbnRpY3Mgb2YgdGhlIG5hdGl2ZSBzZWxlY3QgZXZlbnQuXG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wTW91c2VEb3duOlxuICAgICAgICBtb3VzZURvd24gPSB0cnVlO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BDb250ZXh0TWVudTpcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BNb3VzZVVwOlxuICAgICAgICBtb3VzZURvd24gPSBmYWxzZTtcbiAgICAgICAgcmV0dXJuIGNvbnN0cnVjdFNlbGVjdEV2ZW50KG5hdGl2ZUV2ZW50KTtcblxuICAgICAgLy8gQ2hyb21lIGFuZCBJRSBmaXJlIG5vbi1zdGFuZGFyZCBldmVudCB3aGVuIHNlbGVjdGlvbiBpcyBjaGFuZ2VkIChhbmRcbiAgICAgIC8vIHNvbWV0aW1lcyB3aGVuIGl0IGhhc24ndCkuXG4gICAgICAvLyBGaXJlZm94IGRvZXNuJ3Qgc3VwcG9ydCBzZWxlY3Rpb25jaGFuZ2UsIHNvIGNoZWNrIHNlbGVjdGlvbiBzdGF0dXNcbiAgICAgIC8vIGFmdGVyIGVhY2gga2V5IGVudHJ5LiBUaGUgc2VsZWN0aW9uIGNoYW5nZXMgYWZ0ZXIga2V5ZG93biBhbmQgYmVmb3JlXG4gICAgICAvLyBrZXl1cCwgYnV0IHdlIGNoZWNrIG9uIGtleWRvd24gYXMgd2VsbCBpbiB0aGUgY2FzZSBvZiBob2xkaW5nIGRvd24gYVxuICAgICAgLy8ga2V5LCB3aGVuIG11bHRpcGxlIGtleWRvd24gZXZlbnRzIGFyZSBmaXJlZCBidXQgb25seSBvbmUga2V5dXAgaXMuXG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wU2VsZWN0aW9uQ2hhbmdlOlxuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcEtleURvd246XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wS2V5VXA6XG4gICAgICAgIHJldHVybiBjb25zdHJ1Y3RTZWxlY3RFdmVudChuYXRpdmVFdmVudCk7XG4gICAgfVxuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFNlbGVjdEV2ZW50UGx1Z2luO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFNlcnZlclJlYWN0Um9vdEluZGV4XG4gKiBAdHlwZWNoZWNrc1xuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG4vKipcbiAqIFNpemUgb2YgdGhlIHJlYWN0Um9vdCBJRCBzcGFjZS4gV2UgZ2VuZXJhdGUgcmFuZG9tIG51bWJlcnMgZm9yIFJlYWN0IHJvb3RcbiAqIElEcyBhbmQgaWYgdGhlcmUncyBhIGNvbGxpc2lvbiB0aGUgZXZlbnRzIGFuZCBET00gdXBkYXRlIHN5c3RlbSB3aWxsXG4gKiBnZXQgY29uZnVzZWQuIEluIHRoZSBmdXR1cmUgd2UgbmVlZCBhIHdheSB0byBnZW5lcmF0ZSBHVUlEcyBidXQgZm9yXG4gKiBub3cgdGhpcyB3aWxsIHdvcmsgb24gYSBzbWFsbGVyIHNjYWxlLlxuICovXG52YXIgR0xPQkFMX01PVU5UX1BPSU5UX01BWCA9IE1hdGgucG93KDIsIDUzKTtcblxudmFyIFNlcnZlclJlYWN0Um9vdEluZGV4ID0ge1xuICBjcmVhdGVSZWFjdFJvb3RJbmRleDogZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIE1hdGguY2VpbChNYXRoLnJhbmRvbSgpICogR0xPQkFMX01PVU5UX1BPSU5UX01BWCk7XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gU2VydmVyUmVhY3RSb290SW5kZXg7XG4iLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFNpbXBsZUV2ZW50UGx1Z2luXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBFdmVudENvbnN0YW50cyA9IHJlcXVpcmUoXCIuL0V2ZW50Q29uc3RhbnRzXCIpO1xudmFyIEV2ZW50UGx1Z2luVXRpbHMgPSByZXF1aXJlKFwiLi9FdmVudFBsdWdpblV0aWxzXCIpO1xudmFyIEV2ZW50UHJvcGFnYXRvcnMgPSByZXF1aXJlKFwiLi9FdmVudFByb3BhZ2F0b3JzXCIpO1xudmFyIFN5bnRoZXRpY0NsaXBib2FyZEV2ZW50ID0gcmVxdWlyZShcIi4vU3ludGhldGljQ2xpcGJvYXJkRXZlbnRcIik7XG52YXIgU3ludGhldGljRXZlbnQgPSByZXF1aXJlKFwiLi9TeW50aGV0aWNFdmVudFwiKTtcbnZhciBTeW50aGV0aWNGb2N1c0V2ZW50ID0gcmVxdWlyZShcIi4vU3ludGhldGljRm9jdXNFdmVudFwiKTtcbnZhciBTeW50aGV0aWNLZXlib2FyZEV2ZW50ID0gcmVxdWlyZShcIi4vU3ludGhldGljS2V5Ym9hcmRFdmVudFwiKTtcbnZhciBTeW50aGV0aWNNb3VzZUV2ZW50ID0gcmVxdWlyZShcIi4vU3ludGhldGljTW91c2VFdmVudFwiKTtcbnZhciBTeW50aGV0aWNEcmFnRXZlbnQgPSByZXF1aXJlKFwiLi9TeW50aGV0aWNEcmFnRXZlbnRcIik7XG52YXIgU3ludGhldGljVG91Y2hFdmVudCA9IHJlcXVpcmUoXCIuL1N5bnRoZXRpY1RvdWNoRXZlbnRcIik7XG52YXIgU3ludGhldGljVUlFdmVudCA9IHJlcXVpcmUoXCIuL1N5bnRoZXRpY1VJRXZlbnRcIik7XG52YXIgU3ludGhldGljV2hlZWxFdmVudCA9IHJlcXVpcmUoXCIuL1N5bnRoZXRpY1doZWVsRXZlbnRcIik7XG5cbnZhciBnZXRFdmVudENoYXJDb2RlID0gcmVxdWlyZShcIi4vZ2V0RXZlbnRDaGFyQ29kZVwiKTtcblxudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcbnZhciBrZXlPZiA9IHJlcXVpcmUoXCIuL2tleU9mXCIpO1xudmFyIHdhcm5pbmcgPSByZXF1aXJlKFwiLi93YXJuaW5nXCIpO1xuXG52YXIgdG9wTGV2ZWxUeXBlcyA9IEV2ZW50Q29uc3RhbnRzLnRvcExldmVsVHlwZXM7XG5cbnZhciBldmVudFR5cGVzID0ge1xuICBibHVyOiB7XG4gICAgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXM6IHtcbiAgICAgIGJ1YmJsZWQ6IGtleU9mKHtvbkJsdXI6IHRydWV9KSxcbiAgICAgIGNhcHR1cmVkOiBrZXlPZih7b25CbHVyQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBjbGljazoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25DbGljazogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbkNsaWNrQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBjb250ZXh0TWVudToge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25Db250ZXh0TWVudTogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbkNvbnRleHRNZW51Q2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBjb3B5OiB7XG4gICAgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXM6IHtcbiAgICAgIGJ1YmJsZWQ6IGtleU9mKHtvbkNvcHk6IHRydWV9KSxcbiAgICAgIGNhcHR1cmVkOiBrZXlPZih7b25Db3B5Q2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBjdXQ6IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uQ3V0OiB0cnVlfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uQ3V0Q2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBkb3VibGVDbGljazoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25Eb3VibGVDbGljazogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbkRvdWJsZUNsaWNrQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBkcmFnOiB7XG4gICAgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXM6IHtcbiAgICAgIGJ1YmJsZWQ6IGtleU9mKHtvbkRyYWc6IHRydWV9KSxcbiAgICAgIGNhcHR1cmVkOiBrZXlPZih7b25EcmFnQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBkcmFnRW5kOiB7XG4gICAgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXM6IHtcbiAgICAgIGJ1YmJsZWQ6IGtleU9mKHtvbkRyYWdFbmQ6IHRydWV9KSxcbiAgICAgIGNhcHR1cmVkOiBrZXlPZih7b25EcmFnRW5kQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBkcmFnRW50ZXI6IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uRHJhZ0VudGVyOiB0cnVlfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uRHJhZ0VudGVyQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBkcmFnRXhpdDoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25EcmFnRXhpdDogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbkRyYWdFeGl0Q2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBkcmFnTGVhdmU6IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uRHJhZ0xlYXZlOiB0cnVlfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uRHJhZ0xlYXZlQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBkcmFnT3Zlcjoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25EcmFnT3ZlcjogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbkRyYWdPdmVyQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBkcmFnU3RhcnQ6IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uRHJhZ1N0YXJ0OiB0cnVlfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uRHJhZ1N0YXJ0Q2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBkcm9wOiB7XG4gICAgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXM6IHtcbiAgICAgIGJ1YmJsZWQ6IGtleU9mKHtvbkRyb3A6IHRydWV9KSxcbiAgICAgIGNhcHR1cmVkOiBrZXlPZih7b25Ecm9wQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBmb2N1czoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25Gb2N1czogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbkZvY3VzQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBpbnB1dDoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25JbnB1dDogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbklucHV0Q2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBrZXlEb3duOiB7XG4gICAgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXM6IHtcbiAgICAgIGJ1YmJsZWQ6IGtleU9mKHtvbktleURvd246IHRydWV9KSxcbiAgICAgIGNhcHR1cmVkOiBrZXlPZih7b25LZXlEb3duQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBrZXlQcmVzczoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25LZXlQcmVzczogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbktleVByZXNzQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBrZXlVcDoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25LZXlVcDogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbktleVVwQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBsb2FkOiB7XG4gICAgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXM6IHtcbiAgICAgIGJ1YmJsZWQ6IGtleU9mKHtvbkxvYWQ6IHRydWV9KSxcbiAgICAgIGNhcHR1cmVkOiBrZXlPZih7b25Mb2FkQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBlcnJvcjoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25FcnJvcjogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbkVycm9yQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICAvLyBOb3RlOiBXZSBkbyBub3QgYWxsb3cgbGlzdGVuaW5nIHRvIG1vdXNlT3ZlciBldmVudHMuIEluc3RlYWQsIHVzZSB0aGVcbiAgLy8gb25Nb3VzZUVudGVyL29uTW91c2VMZWF2ZSBjcmVhdGVkIGJ5IGBFbnRlckxlYXZlRXZlbnRQbHVnaW5gLlxuICBtb3VzZURvd246IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uTW91c2VEb3duOiB0cnVlfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uTW91c2VEb3duQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBtb3VzZU1vdmU6IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uTW91c2VNb3ZlOiB0cnVlfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uTW91c2VNb3ZlQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBtb3VzZU91dDoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25Nb3VzZU91dDogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbk1vdXNlT3V0Q2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBtb3VzZU92ZXI6IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uTW91c2VPdmVyOiB0cnVlfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uTW91c2VPdmVyQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBtb3VzZVVwOiB7XG4gICAgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXM6IHtcbiAgICAgIGJ1YmJsZWQ6IGtleU9mKHtvbk1vdXNlVXA6IHRydWV9KSxcbiAgICAgIGNhcHR1cmVkOiBrZXlPZih7b25Nb3VzZVVwQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBwYXN0ZToge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25QYXN0ZTogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvblBhc3RlQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICByZXNldDoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25SZXNldDogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvblJlc2V0Q2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBzY3JvbGw6IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uU2Nyb2xsOiB0cnVlfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uU2Nyb2xsQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBzdWJtaXQ6IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uU3VibWl0OiB0cnVlfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uU3VibWl0Q2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICB0b3VjaENhbmNlbDoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25Ub3VjaENhbmNlbDogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvblRvdWNoQ2FuY2VsQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICB0b3VjaEVuZDoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25Ub3VjaEVuZDogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvblRvdWNoRW5kQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICB0b3VjaE1vdmU6IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uVG91Y2hNb3ZlOiB0cnVlfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uVG91Y2hNb3ZlQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICB0b3VjaFN0YXJ0OiB7XG4gICAgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXM6IHtcbiAgICAgIGJ1YmJsZWQ6IGtleU9mKHtvblRvdWNoU3RhcnQ6IHRydWV9KSxcbiAgICAgIGNhcHR1cmVkOiBrZXlPZih7b25Ub3VjaFN0YXJ0Q2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICB3aGVlbDoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25XaGVlbDogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbldoZWVsQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9XG59O1xuXG52YXIgdG9wTGV2ZWxFdmVudHNUb0Rpc3BhdGNoQ29uZmlnID0ge1xuICB0b3BCbHVyOiAgICAgICAgZXZlbnRUeXBlcy5ibHVyLFxuICB0b3BDbGljazogICAgICAgZXZlbnRUeXBlcy5jbGljayxcbiAgdG9wQ29udGV4dE1lbnU6IGV2ZW50VHlwZXMuY29udGV4dE1lbnUsXG4gIHRvcENvcHk6ICAgICAgICBldmVudFR5cGVzLmNvcHksXG4gIHRvcEN1dDogICAgICAgICBldmVudFR5cGVzLmN1dCxcbiAgdG9wRG91YmxlQ2xpY2s6IGV2ZW50VHlwZXMuZG91YmxlQ2xpY2ssXG4gIHRvcERyYWc6ICAgICAgICBldmVudFR5cGVzLmRyYWcsXG4gIHRvcERyYWdFbmQ6ICAgICBldmVudFR5cGVzLmRyYWdFbmQsXG4gIHRvcERyYWdFbnRlcjogICBldmVudFR5cGVzLmRyYWdFbnRlcixcbiAgdG9wRHJhZ0V4aXQ6ICAgIGV2ZW50VHlwZXMuZHJhZ0V4aXQsXG4gIHRvcERyYWdMZWF2ZTogICBldmVudFR5cGVzLmRyYWdMZWF2ZSxcbiAgdG9wRHJhZ092ZXI6ICAgIGV2ZW50VHlwZXMuZHJhZ092ZXIsXG4gIHRvcERyYWdTdGFydDogICBldmVudFR5cGVzLmRyYWdTdGFydCxcbiAgdG9wRHJvcDogICAgICAgIGV2ZW50VHlwZXMuZHJvcCxcbiAgdG9wRXJyb3I6ICAgICAgIGV2ZW50VHlwZXMuZXJyb3IsXG4gIHRvcEZvY3VzOiAgICAgICBldmVudFR5cGVzLmZvY3VzLFxuICB0b3BJbnB1dDogICAgICAgZXZlbnRUeXBlcy5pbnB1dCxcbiAgdG9wS2V5RG93bjogICAgIGV2ZW50VHlwZXMua2V5RG93bixcbiAgdG9wS2V5UHJlc3M6ICAgIGV2ZW50VHlwZXMua2V5UHJlc3MsXG4gIHRvcEtleVVwOiAgICAgICBldmVudFR5cGVzLmtleVVwLFxuICB0b3BMb2FkOiAgICAgICAgZXZlbnRUeXBlcy5sb2FkLFxuICB0b3BNb3VzZURvd246ICAgZXZlbnRUeXBlcy5tb3VzZURvd24sXG4gIHRvcE1vdXNlTW92ZTogICBldmVudFR5cGVzLm1vdXNlTW92ZSxcbiAgdG9wTW91c2VPdXQ6ICAgIGV2ZW50VHlwZXMubW91c2VPdXQsXG4gIHRvcE1vdXNlT3ZlcjogICBldmVudFR5cGVzLm1vdXNlT3ZlcixcbiAgdG9wTW91c2VVcDogICAgIGV2ZW50VHlwZXMubW91c2VVcCxcbiAgdG9wUGFzdGU6ICAgICAgIGV2ZW50VHlwZXMucGFzdGUsXG4gIHRvcFJlc2V0OiAgICAgICBldmVudFR5cGVzLnJlc2V0LFxuICB0b3BTY3JvbGw6ICAgICAgZXZlbnRUeXBlcy5zY3JvbGwsXG4gIHRvcFN1Ym1pdDogICAgICBldmVudFR5cGVzLnN1Ym1pdCxcbiAgdG9wVG91Y2hDYW5jZWw6IGV2ZW50VHlwZXMudG91Y2hDYW5jZWwsXG4gIHRvcFRvdWNoRW5kOiAgICBldmVudFR5cGVzLnRvdWNoRW5kLFxuICB0b3BUb3VjaE1vdmU6ICAgZXZlbnRUeXBlcy50b3VjaE1vdmUsXG4gIHRvcFRvdWNoU3RhcnQ6ICBldmVudFR5cGVzLnRvdWNoU3RhcnQsXG4gIHRvcFdoZWVsOiAgICAgICBldmVudFR5cGVzLndoZWVsXG59O1xuXG5mb3IgKHZhciB0b3BMZXZlbFR5cGUgaW4gdG9wTGV2ZWxFdmVudHNUb0Rpc3BhdGNoQ29uZmlnKSB7XG4gIHRvcExldmVsRXZlbnRzVG9EaXNwYXRjaENvbmZpZ1t0b3BMZXZlbFR5cGVdLmRlcGVuZGVuY2llcyA9IFt0b3BMZXZlbFR5cGVdO1xufVxuXG52YXIgU2ltcGxlRXZlbnRQbHVnaW4gPSB7XG5cbiAgZXZlbnRUeXBlczogZXZlbnRUeXBlcyxcblxuICAvKipcbiAgICogU2FtZSBhcyB0aGUgZGVmYXVsdCBpbXBsZW1lbnRhdGlvbiwgZXhjZXB0IGNhbmNlbHMgdGhlIGV2ZW50IHdoZW4gcmV0dXJuXG4gICAqIHZhbHVlIGlzIGZhbHNlLiBUaGlzIGJlaGF2aW9yIHdpbGwgYmUgZGlzYWJsZWQgaW4gYSBmdXR1cmUgcmVsZWFzZS5cbiAgICpcbiAgICogQHBhcmFtIHtvYmplY3R9IEV2ZW50IHRvIGJlIGRpc3BhdGNoZWQuXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IEFwcGxpY2F0aW9uLWxldmVsIGNhbGxiYWNrLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gZG9tSUQgRE9NIElEIHRvIHBhc3MgdG8gdGhlIGNhbGxiYWNrLlxuICAgKi9cbiAgZXhlY3V0ZURpc3BhdGNoOiBmdW5jdGlvbihldmVudCwgbGlzdGVuZXIsIGRvbUlEKSB7XG4gICAgdmFyIHJldHVyblZhbHVlID0gRXZlbnRQbHVnaW5VdGlscy5leGVjdXRlRGlzcGF0Y2goZXZlbnQsIGxpc3RlbmVyLCBkb21JRCk7XG5cbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gd2FybmluZyhcbiAgICAgIHR5cGVvZiByZXR1cm5WYWx1ZSAhPT0gJ2Jvb2xlYW4nLFxuICAgICAgJ1JldHVybmluZyBgZmFsc2VgIGZyb20gYW4gZXZlbnQgaGFuZGxlciBpcyBkZXByZWNhdGVkIGFuZCB3aWxsIGJlICcgK1xuICAgICAgJ2lnbm9yZWQgaW4gYSBmdXR1cmUgcmVsZWFzZS4gSW5zdGVhZCwgbWFudWFsbHkgY2FsbCAnICtcbiAgICAgICdlLnN0b3BQcm9wYWdhdGlvbigpIG9yIGUucHJldmVudERlZmF1bHQoKSwgYXMgYXBwcm9wcmlhdGUuJ1xuICAgICkgOiBudWxsKTtcblxuICAgIGlmIChyZXR1cm5WYWx1ZSA9PT0gZmFsc2UpIHtcbiAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB9XG4gIH0sXG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0b3BMZXZlbFR5cGUgUmVjb3JkIGZyb20gYEV2ZW50Q29uc3RhbnRzYC5cbiAgICogQHBhcmFtIHtET01FdmVudFRhcmdldH0gdG9wTGV2ZWxUYXJnZXQgVGhlIGxpc3RlbmluZyBjb21wb25lbnQgcm9vdCBub2RlLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gdG9wTGV2ZWxUYXJnZXRJRCBJRCBvZiBgdG9wTGV2ZWxUYXJnZXRgLlxuICAgKiBAcGFyYW0ge29iamVjdH0gbmF0aXZlRXZlbnQgTmF0aXZlIGJyb3dzZXIgZXZlbnQuXG4gICAqIEByZXR1cm4geyp9IEFuIGFjY3VtdWxhdGlvbiBvZiBzeW50aGV0aWMgZXZlbnRzLlxuICAgKiBAc2VlIHtFdmVudFBsdWdpbkh1Yi5leHRyYWN0RXZlbnRzfVxuICAgKi9cbiAgZXh0cmFjdEV2ZW50czogZnVuY3Rpb24oXG4gICAgICB0b3BMZXZlbFR5cGUsXG4gICAgICB0b3BMZXZlbFRhcmdldCxcbiAgICAgIHRvcExldmVsVGFyZ2V0SUQsXG4gICAgICBuYXRpdmVFdmVudCkge1xuICAgIHZhciBkaXNwYXRjaENvbmZpZyA9IHRvcExldmVsRXZlbnRzVG9EaXNwYXRjaENvbmZpZ1t0b3BMZXZlbFR5cGVdO1xuICAgIGlmICghZGlzcGF0Y2hDb25maWcpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICB2YXIgRXZlbnRDb25zdHJ1Y3RvcjtcbiAgICBzd2l0Y2ggKHRvcExldmVsVHlwZSkge1xuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcElucHV0OlxuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcExvYWQ6XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wRXJyb3I6XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wUmVzZXQ6XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wU3VibWl0OlxuICAgICAgICAvLyBIVE1MIEV2ZW50c1xuICAgICAgICAvLyBAc2VlIGh0dHA6Ly93d3cudzMub3JnL1RSL2h0bWw1L2luZGV4Lmh0bWwjZXZlbnRzLTBcbiAgICAgICAgRXZlbnRDb25zdHJ1Y3RvciA9IFN5bnRoZXRpY0V2ZW50O1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BLZXlQcmVzczpcbiAgICAgICAgLy8gRmlyZUZveCBjcmVhdGVzIGEga2V5cHJlc3MgZXZlbnQgZm9yIGZ1bmN0aW9uIGtleXMgdG9vLiBUaGlzIHJlbW92ZXNcbiAgICAgICAgLy8gdGhlIHVud2FudGVkIGtleXByZXNzIGV2ZW50cy4gRW50ZXIgaXMgaG93ZXZlciBib3RoIHByaW50YWJsZSBhbmRcbiAgICAgICAgLy8gbm9uLXByaW50YWJsZS4gT25lIHdvdWxkIGV4cGVjdCBUYWIgdG8gYmUgYXMgd2VsbCAoYnV0IGl0IGlzbid0KS5cbiAgICAgICAgaWYgKGdldEV2ZW50Q2hhckNvZGUobmF0aXZlRXZlbnQpID09PSAwKSB7XG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgLyogZmFsbHMgdGhyb3VnaCAqL1xuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcEtleURvd246XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wS2V5VXA6XG4gICAgICAgIEV2ZW50Q29uc3RydWN0b3IgPSBTeW50aGV0aWNLZXlib2FyZEV2ZW50O1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BCbHVyOlxuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcEZvY3VzOlxuICAgICAgICBFdmVudENvbnN0cnVjdG9yID0gU3ludGhldGljRm9jdXNFdmVudDtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wQ2xpY2s6XG4gICAgICAgIC8vIEZpcmVmb3ggY3JlYXRlcyBhIGNsaWNrIGV2ZW50IG9uIHJpZ2h0IG1vdXNlIGNsaWNrcy4gVGhpcyByZW1vdmVzIHRoZVxuICAgICAgICAvLyB1bndhbnRlZCBjbGljayBldmVudHMuXG4gICAgICAgIGlmIChuYXRpdmVFdmVudC5idXR0b24gPT09IDIpIHtcbiAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICAvKiBmYWxscyB0aHJvdWdoICovXG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wQ29udGV4dE1lbnU6XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wRG91YmxlQ2xpY2s6XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wTW91c2VEb3duOlxuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcE1vdXNlTW92ZTpcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BNb3VzZU91dDpcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BNb3VzZU92ZXI6XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wTW91c2VVcDpcbiAgICAgICAgRXZlbnRDb25zdHJ1Y3RvciA9IFN5bnRoZXRpY01vdXNlRXZlbnQ7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcERyYWc6XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wRHJhZ0VuZDpcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BEcmFnRW50ZXI6XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wRHJhZ0V4aXQ6XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wRHJhZ0xlYXZlOlxuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcERyYWdPdmVyOlxuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcERyYWdTdGFydDpcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BEcm9wOlxuICAgICAgICBFdmVudENvbnN0cnVjdG9yID0gU3ludGhldGljRHJhZ0V2ZW50O1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BUb3VjaENhbmNlbDpcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BUb3VjaEVuZDpcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BUb3VjaE1vdmU6XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wVG91Y2hTdGFydDpcbiAgICAgICAgRXZlbnRDb25zdHJ1Y3RvciA9IFN5bnRoZXRpY1RvdWNoRXZlbnQ7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcFNjcm9sbDpcbiAgICAgICAgRXZlbnRDb25zdHJ1Y3RvciA9IFN5bnRoZXRpY1VJRXZlbnQ7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcFdoZWVsOlxuICAgICAgICBFdmVudENvbnN0cnVjdG9yID0gU3ludGhldGljV2hlZWxFdmVudDtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wQ29weTpcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BDdXQ6XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wUGFzdGU6XG4gICAgICAgIEV2ZW50Q29uc3RydWN0b3IgPSBTeW50aGV0aWNDbGlwYm9hcmRFdmVudDtcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICBFdmVudENvbnN0cnVjdG9yLFxuICAgICAgJ1NpbXBsZUV2ZW50UGx1Z2luOiBVbmhhbmRsZWQgZXZlbnQgdHlwZSwgYCVzYC4nLFxuICAgICAgdG9wTGV2ZWxUeXBlXG4gICAgKSA6IGludmFyaWFudChFdmVudENvbnN0cnVjdG9yKSk7XG4gICAgdmFyIGV2ZW50ID0gRXZlbnRDb25zdHJ1Y3Rvci5nZXRQb29sZWQoXG4gICAgICBkaXNwYXRjaENvbmZpZyxcbiAgICAgIHRvcExldmVsVGFyZ2V0SUQsXG4gICAgICBuYXRpdmVFdmVudFxuICAgICk7XG4gICAgRXZlbnRQcm9wYWdhdG9ycy5hY2N1bXVsYXRlVHdvUGhhc2VEaXNwYXRjaGVzKGV2ZW50KTtcbiAgICByZXR1cm4gZXZlbnQ7XG4gIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTaW1wbGVFdmVudFBsdWdpbjtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFN5bnRoZXRpY0NsaXBib2FyZEV2ZW50XG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgU3ludGhldGljRXZlbnQgPSByZXF1aXJlKFwiLi9TeW50aGV0aWNFdmVudFwiKTtcblxuLyoqXG4gKiBAaW50ZXJmYWNlIEV2ZW50XG4gKiBAc2VlIGh0dHA6Ly93d3cudzMub3JnL1RSL2NsaXBib2FyZC1hcGlzL1xuICovXG52YXIgQ2xpcGJvYXJkRXZlbnRJbnRlcmZhY2UgPSB7XG4gIGNsaXBib2FyZERhdGE6IGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgcmV0dXJuIChcbiAgICAgICdjbGlwYm9hcmREYXRhJyBpbiBldmVudCA/XG4gICAgICAgIGV2ZW50LmNsaXBib2FyZERhdGEgOlxuICAgICAgICB3aW5kb3cuY2xpcGJvYXJkRGF0YVxuICAgICk7XG4gIH1cbn07XG5cbi8qKlxuICogQHBhcmFtIHtvYmplY3R9IGRpc3BhdGNoQ29uZmlnIENvbmZpZ3VyYXRpb24gdXNlZCB0byBkaXNwYXRjaCB0aGlzIGV2ZW50LlxuICogQHBhcmFtIHtzdHJpbmd9IGRpc3BhdGNoTWFya2VyIE1hcmtlciBpZGVudGlmeWluZyB0aGUgZXZlbnQgdGFyZ2V0LlxuICogQHBhcmFtIHtvYmplY3R9IG5hdGl2ZUV2ZW50IE5hdGl2ZSBicm93c2VyIGV2ZW50LlxuICogQGV4dGVuZHMge1N5bnRoZXRpY1VJRXZlbnR9XG4gKi9cbmZ1bmN0aW9uIFN5bnRoZXRpY0NsaXBib2FyZEV2ZW50KGRpc3BhdGNoQ29uZmlnLCBkaXNwYXRjaE1hcmtlciwgbmF0aXZlRXZlbnQpIHtcbiAgU3ludGhldGljRXZlbnQuY2FsbCh0aGlzLCBkaXNwYXRjaENvbmZpZywgZGlzcGF0Y2hNYXJrZXIsIG5hdGl2ZUV2ZW50KTtcbn1cblxuU3ludGhldGljRXZlbnQuYXVnbWVudENsYXNzKFN5bnRoZXRpY0NsaXBib2FyZEV2ZW50LCBDbGlwYm9hcmRFdmVudEludGVyZmFjZSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3ludGhldGljQ2xpcGJvYXJkRXZlbnQ7XG5cbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBTeW50aGV0aWNDb21wb3NpdGlvbkV2ZW50XG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgU3ludGhldGljRXZlbnQgPSByZXF1aXJlKFwiLi9TeW50aGV0aWNFdmVudFwiKTtcblxuLyoqXG4gKiBAaW50ZXJmYWNlIEV2ZW50XG4gKiBAc2VlIGh0dHA6Ly93d3cudzMub3JnL1RSL0RPTS1MZXZlbC0zLUV2ZW50cy8jZXZlbnRzLWNvbXBvc2l0aW9uZXZlbnRzXG4gKi9cbnZhciBDb21wb3NpdGlvbkV2ZW50SW50ZXJmYWNlID0ge1xuICBkYXRhOiBudWxsXG59O1xuXG4vKipcbiAqIEBwYXJhbSB7b2JqZWN0fSBkaXNwYXRjaENvbmZpZyBDb25maWd1cmF0aW9uIHVzZWQgdG8gZGlzcGF0Y2ggdGhpcyBldmVudC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBkaXNwYXRjaE1hcmtlciBNYXJrZXIgaWRlbnRpZnlpbmcgdGhlIGV2ZW50IHRhcmdldC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudCBOYXRpdmUgYnJvd3NlciBldmVudC5cbiAqIEBleHRlbmRzIHtTeW50aGV0aWNVSUV2ZW50fVxuICovXG5mdW5jdGlvbiBTeW50aGV0aWNDb21wb3NpdGlvbkV2ZW50KFxuICBkaXNwYXRjaENvbmZpZyxcbiAgZGlzcGF0Y2hNYXJrZXIsXG4gIG5hdGl2ZUV2ZW50KSB7XG4gIFN5bnRoZXRpY0V2ZW50LmNhbGwodGhpcywgZGlzcGF0Y2hDb25maWcsIGRpc3BhdGNoTWFya2VyLCBuYXRpdmVFdmVudCk7XG59XG5cblN5bnRoZXRpY0V2ZW50LmF1Z21lbnRDbGFzcyhcbiAgU3ludGhldGljQ29tcG9zaXRpb25FdmVudCxcbiAgQ29tcG9zaXRpb25FdmVudEludGVyZmFjZVxuKTtcblxubW9kdWxlLmV4cG9ydHMgPSBTeW50aGV0aWNDb21wb3NpdGlvbkV2ZW50O1xuXG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgU3ludGhldGljRHJhZ0V2ZW50XG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgU3ludGhldGljTW91c2VFdmVudCA9IHJlcXVpcmUoXCIuL1N5bnRoZXRpY01vdXNlRXZlbnRcIik7XG5cbi8qKlxuICogQGludGVyZmFjZSBEcmFnRXZlbnRcbiAqIEBzZWUgaHR0cDovL3d3dy53My5vcmcvVFIvRE9NLUxldmVsLTMtRXZlbnRzL1xuICovXG52YXIgRHJhZ0V2ZW50SW50ZXJmYWNlID0ge1xuICBkYXRhVHJhbnNmZXI6IG51bGxcbn07XG5cbi8qKlxuICogQHBhcmFtIHtvYmplY3R9IGRpc3BhdGNoQ29uZmlnIENvbmZpZ3VyYXRpb24gdXNlZCB0byBkaXNwYXRjaCB0aGlzIGV2ZW50LlxuICogQHBhcmFtIHtzdHJpbmd9IGRpc3BhdGNoTWFya2VyIE1hcmtlciBpZGVudGlmeWluZyB0aGUgZXZlbnQgdGFyZ2V0LlxuICogQHBhcmFtIHtvYmplY3R9IG5hdGl2ZUV2ZW50IE5hdGl2ZSBicm93c2VyIGV2ZW50LlxuICogQGV4dGVuZHMge1N5bnRoZXRpY1VJRXZlbnR9XG4gKi9cbmZ1bmN0aW9uIFN5bnRoZXRpY0RyYWdFdmVudChkaXNwYXRjaENvbmZpZywgZGlzcGF0Y2hNYXJrZXIsIG5hdGl2ZUV2ZW50KSB7XG4gIFN5bnRoZXRpY01vdXNlRXZlbnQuY2FsbCh0aGlzLCBkaXNwYXRjaENvbmZpZywgZGlzcGF0Y2hNYXJrZXIsIG5hdGl2ZUV2ZW50KTtcbn1cblxuU3ludGhldGljTW91c2VFdmVudC5hdWdtZW50Q2xhc3MoU3ludGhldGljRHJhZ0V2ZW50LCBEcmFnRXZlbnRJbnRlcmZhY2UpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN5bnRoZXRpY0RyYWdFdmVudDtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBTeW50aGV0aWNFdmVudFxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFBvb2xlZENsYXNzID0gcmVxdWlyZShcIi4vUG9vbGVkQ2xhc3NcIik7XG5cbnZhciBhc3NpZ24gPSByZXF1aXJlKFwiLi9PYmplY3QuYXNzaWduXCIpO1xudmFyIGVtcHR5RnVuY3Rpb24gPSByZXF1aXJlKFwiLi9lbXB0eUZ1bmN0aW9uXCIpO1xudmFyIGdldEV2ZW50VGFyZ2V0ID0gcmVxdWlyZShcIi4vZ2V0RXZlbnRUYXJnZXRcIik7XG5cbi8qKlxuICogQGludGVyZmFjZSBFdmVudFxuICogQHNlZSBodHRwOi8vd3d3LnczLm9yZy9UUi9ET00tTGV2ZWwtMy1FdmVudHMvXG4gKi9cbnZhciBFdmVudEludGVyZmFjZSA9IHtcbiAgdHlwZTogbnVsbCxcbiAgdGFyZ2V0OiBnZXRFdmVudFRhcmdldCxcbiAgLy8gY3VycmVudFRhcmdldCBpcyBzZXQgd2hlbiBkaXNwYXRjaGluZzsgbm8gdXNlIGluIGNvcHlpbmcgaXQgaGVyZVxuICBjdXJyZW50VGFyZ2V0OiBlbXB0eUZ1bmN0aW9uLnRoYXRSZXR1cm5zTnVsbCxcbiAgZXZlbnRQaGFzZTogbnVsbCxcbiAgYnViYmxlczogbnVsbCxcbiAgY2FuY2VsYWJsZTogbnVsbCxcbiAgdGltZVN0YW1wOiBmdW5jdGlvbihldmVudCkge1xuICAgIHJldHVybiBldmVudC50aW1lU3RhbXAgfHwgRGF0ZS5ub3coKTtcbiAgfSxcbiAgZGVmYXVsdFByZXZlbnRlZDogbnVsbCxcbiAgaXNUcnVzdGVkOiBudWxsXG59O1xuXG4vKipcbiAqIFN5bnRoZXRpYyBldmVudHMgYXJlIGRpc3BhdGNoZWQgYnkgZXZlbnQgcGx1Z2lucywgdHlwaWNhbGx5IGluIHJlc3BvbnNlIHRvIGFcbiAqIHRvcC1sZXZlbCBldmVudCBkZWxlZ2F0aW9uIGhhbmRsZXIuXG4gKlxuICogVGhlc2Ugc3lzdGVtcyBzaG91bGQgZ2VuZXJhbGx5IHVzZSBwb29saW5nIHRvIHJlZHVjZSB0aGUgZnJlcXVlbmN5IG9mIGdhcmJhZ2VcbiAqIGNvbGxlY3Rpb24uIFRoZSBzeXN0ZW0gc2hvdWxkIGNoZWNrIGBpc1BlcnNpc3RlbnRgIHRvIGRldGVybWluZSB3aGV0aGVyIHRoZVxuICogZXZlbnQgc2hvdWxkIGJlIHJlbGVhc2VkIGludG8gdGhlIHBvb2wgYWZ0ZXIgYmVpbmcgZGlzcGF0Y2hlZC4gVXNlcnMgdGhhdFxuICogbmVlZCBhIHBlcnNpc3RlZCBldmVudCBzaG91bGQgaW52b2tlIGBwZXJzaXN0YC5cbiAqXG4gKiBTeW50aGV0aWMgZXZlbnRzIChhbmQgc3ViY2xhc3NlcykgaW1wbGVtZW50IHRoZSBET00gTGV2ZWwgMyBFdmVudHMgQVBJIGJ5XG4gKiBub3JtYWxpemluZyBicm93c2VyIHF1aXJrcy4gU3ViY2xhc3NlcyBkbyBub3QgbmVjZXNzYXJpbHkgaGF2ZSB0byBpbXBsZW1lbnQgYVxuICogRE9NIGludGVyZmFjZTsgY3VzdG9tIGFwcGxpY2F0aW9uLXNwZWNpZmljIGV2ZW50cyBjYW4gYWxzbyBzdWJjbGFzcyB0aGlzLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBkaXNwYXRjaENvbmZpZyBDb25maWd1cmF0aW9uIHVzZWQgdG8gZGlzcGF0Y2ggdGhpcyBldmVudC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBkaXNwYXRjaE1hcmtlciBNYXJrZXIgaWRlbnRpZnlpbmcgdGhlIGV2ZW50IHRhcmdldC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudCBOYXRpdmUgYnJvd3NlciBldmVudC5cbiAqL1xuZnVuY3Rpb24gU3ludGhldGljRXZlbnQoZGlzcGF0Y2hDb25maWcsIGRpc3BhdGNoTWFya2VyLCBuYXRpdmVFdmVudCkge1xuICB0aGlzLmRpc3BhdGNoQ29uZmlnID0gZGlzcGF0Y2hDb25maWc7XG4gIHRoaXMuZGlzcGF0Y2hNYXJrZXIgPSBkaXNwYXRjaE1hcmtlcjtcbiAgdGhpcy5uYXRpdmVFdmVudCA9IG5hdGl2ZUV2ZW50O1xuXG4gIHZhciBJbnRlcmZhY2UgPSB0aGlzLmNvbnN0cnVjdG9yLkludGVyZmFjZTtcbiAgZm9yICh2YXIgcHJvcE5hbWUgaW4gSW50ZXJmYWNlKSB7XG4gICAgaWYgKCFJbnRlcmZhY2UuaGFzT3duUHJvcGVydHkocHJvcE5hbWUpKSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgdmFyIG5vcm1hbGl6ZSA9IEludGVyZmFjZVtwcm9wTmFtZV07XG4gICAgaWYgKG5vcm1hbGl6ZSkge1xuICAgICAgdGhpc1twcm9wTmFtZV0gPSBub3JtYWxpemUobmF0aXZlRXZlbnQpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzW3Byb3BOYW1lXSA9IG5hdGl2ZUV2ZW50W3Byb3BOYW1lXTtcbiAgICB9XG4gIH1cblxuICB2YXIgZGVmYXVsdFByZXZlbnRlZCA9IG5hdGl2ZUV2ZW50LmRlZmF1bHRQcmV2ZW50ZWQgIT0gbnVsbCA/XG4gICAgbmF0aXZlRXZlbnQuZGVmYXVsdFByZXZlbnRlZCA6XG4gICAgbmF0aXZlRXZlbnQucmV0dXJuVmFsdWUgPT09IGZhbHNlO1xuICBpZiAoZGVmYXVsdFByZXZlbnRlZCkge1xuICAgIHRoaXMuaXNEZWZhdWx0UHJldmVudGVkID0gZW1wdHlGdW5jdGlvbi50aGF0UmV0dXJuc1RydWU7XG4gIH0gZWxzZSB7XG4gICAgdGhpcy5pc0RlZmF1bHRQcmV2ZW50ZWQgPSBlbXB0eUZ1bmN0aW9uLnRoYXRSZXR1cm5zRmFsc2U7XG4gIH1cbiAgdGhpcy5pc1Byb3BhZ2F0aW9uU3RvcHBlZCA9IGVtcHR5RnVuY3Rpb24udGhhdFJldHVybnNGYWxzZTtcbn1cblxuYXNzaWduKFN5bnRoZXRpY0V2ZW50LnByb3RvdHlwZSwge1xuXG4gIHByZXZlbnREZWZhdWx0OiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLmRlZmF1bHRQcmV2ZW50ZWQgPSB0cnVlO1xuICAgIHZhciBldmVudCA9IHRoaXMubmF0aXZlRXZlbnQ7XG4gICAgZXZlbnQucHJldmVudERlZmF1bHQgPyBldmVudC5wcmV2ZW50RGVmYXVsdCgpIDogZXZlbnQucmV0dXJuVmFsdWUgPSBmYWxzZTtcbiAgICB0aGlzLmlzRGVmYXVsdFByZXZlbnRlZCA9IGVtcHR5RnVuY3Rpb24udGhhdFJldHVybnNUcnVlO1xuICB9LFxuXG4gIHN0b3BQcm9wYWdhdGlvbjogZnVuY3Rpb24oKSB7XG4gICAgdmFyIGV2ZW50ID0gdGhpcy5uYXRpdmVFdmVudDtcbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24gPyBldmVudC5zdG9wUHJvcGFnYXRpb24oKSA6IGV2ZW50LmNhbmNlbEJ1YmJsZSA9IHRydWU7XG4gICAgdGhpcy5pc1Byb3BhZ2F0aW9uU3RvcHBlZCA9IGVtcHR5RnVuY3Rpb24udGhhdFJldHVybnNUcnVlO1xuICB9LFxuXG4gIC8qKlxuICAgKiBXZSByZWxlYXNlIGFsbCBkaXNwYXRjaGVkIGBTeW50aGV0aWNFdmVudGBzIGFmdGVyIGVhY2ggZXZlbnQgbG9vcCwgYWRkaW5nXG4gICAqIHRoZW0gYmFjayBpbnRvIHRoZSBwb29sLiBUaGlzIGFsbG93cyBhIHdheSB0byBob2xkIG9udG8gYSByZWZlcmVuY2UgdGhhdFxuICAgKiB3b24ndCBiZSBhZGRlZCBiYWNrIGludG8gdGhlIHBvb2wuXG4gICAqL1xuICBwZXJzaXN0OiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLmlzUGVyc2lzdGVudCA9IGVtcHR5RnVuY3Rpb24udGhhdFJldHVybnNUcnVlO1xuICB9LFxuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgdGhpcyBldmVudCBzaG91bGQgYmUgcmVsZWFzZWQgYmFjayBpbnRvIHRoZSBwb29sLlxuICAgKlxuICAgKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIHRoaXMgc2hvdWxkIG5vdCBiZSByZWxlYXNlZCwgZmFsc2Ugb3RoZXJ3aXNlLlxuICAgKi9cbiAgaXNQZXJzaXN0ZW50OiBlbXB0eUZ1bmN0aW9uLnRoYXRSZXR1cm5zRmFsc2UsXG5cbiAgLyoqXG4gICAqIGBQb29sZWRDbGFzc2AgbG9va3MgZm9yIGBkZXN0cnVjdG9yYCBvbiBlYWNoIGluc3RhbmNlIGl0IHJlbGVhc2VzLlxuICAgKi9cbiAgZGVzdHJ1Y3RvcjogZnVuY3Rpb24oKSB7XG4gICAgdmFyIEludGVyZmFjZSA9IHRoaXMuY29uc3RydWN0b3IuSW50ZXJmYWNlO1xuICAgIGZvciAodmFyIHByb3BOYW1lIGluIEludGVyZmFjZSkge1xuICAgICAgdGhpc1twcm9wTmFtZV0gPSBudWxsO1xuICAgIH1cbiAgICB0aGlzLmRpc3BhdGNoQ29uZmlnID0gbnVsbDtcbiAgICB0aGlzLmRpc3BhdGNoTWFya2VyID0gbnVsbDtcbiAgICB0aGlzLm5hdGl2ZUV2ZW50ID0gbnVsbDtcbiAgfVxuXG59KTtcblxuU3ludGhldGljRXZlbnQuSW50ZXJmYWNlID0gRXZlbnRJbnRlcmZhY2U7XG5cbi8qKlxuICogSGVscGVyIHRvIHJlZHVjZSBib2lsZXJwbGF0ZSB3aGVuIGNyZWF0aW5nIHN1YmNsYXNzZXMuXG4gKlxuICogQHBhcmFtIHtmdW5jdGlvbn0gQ2xhc3NcbiAqIEBwYXJhbSB7P29iamVjdH0gSW50ZXJmYWNlXG4gKi9cblN5bnRoZXRpY0V2ZW50LmF1Z21lbnRDbGFzcyA9IGZ1bmN0aW9uKENsYXNzLCBJbnRlcmZhY2UpIHtcbiAgdmFyIFN1cGVyID0gdGhpcztcblxuICB2YXIgcHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShTdXBlci5wcm90b3R5cGUpO1xuICBhc3NpZ24ocHJvdG90eXBlLCBDbGFzcy5wcm90b3R5cGUpO1xuICBDbGFzcy5wcm90b3R5cGUgPSBwcm90b3R5cGU7XG4gIENsYXNzLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IENsYXNzO1xuXG4gIENsYXNzLkludGVyZmFjZSA9IGFzc2lnbih7fSwgU3VwZXIuSW50ZXJmYWNlLCBJbnRlcmZhY2UpO1xuICBDbGFzcy5hdWdtZW50Q2xhc3MgPSBTdXBlci5hdWdtZW50Q2xhc3M7XG5cbiAgUG9vbGVkQ2xhc3MuYWRkUG9vbGluZ1RvKENsYXNzLCBQb29sZWRDbGFzcy50aHJlZUFyZ3VtZW50UG9vbGVyKTtcbn07XG5cblBvb2xlZENsYXNzLmFkZFBvb2xpbmdUbyhTeW50aGV0aWNFdmVudCwgUG9vbGVkQ2xhc3MudGhyZWVBcmd1bWVudFBvb2xlcik7XG5cbm1vZHVsZS5leHBvcnRzID0gU3ludGhldGljRXZlbnQ7XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgU3ludGhldGljRm9jdXNFdmVudFxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFN5bnRoZXRpY1VJRXZlbnQgPSByZXF1aXJlKFwiLi9TeW50aGV0aWNVSUV2ZW50XCIpO1xuXG4vKipcbiAqIEBpbnRlcmZhY2UgRm9jdXNFdmVudFxuICogQHNlZSBodHRwOi8vd3d3LnczLm9yZy9UUi9ET00tTGV2ZWwtMy1FdmVudHMvXG4gKi9cbnZhciBGb2N1c0V2ZW50SW50ZXJmYWNlID0ge1xuICByZWxhdGVkVGFyZ2V0OiBudWxsXG59O1xuXG4vKipcbiAqIEBwYXJhbSB7b2JqZWN0fSBkaXNwYXRjaENvbmZpZyBDb25maWd1cmF0aW9uIHVzZWQgdG8gZGlzcGF0Y2ggdGhpcyBldmVudC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBkaXNwYXRjaE1hcmtlciBNYXJrZXIgaWRlbnRpZnlpbmcgdGhlIGV2ZW50IHRhcmdldC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudCBOYXRpdmUgYnJvd3NlciBldmVudC5cbiAqIEBleHRlbmRzIHtTeW50aGV0aWNVSUV2ZW50fVxuICovXG5mdW5jdGlvbiBTeW50aGV0aWNGb2N1c0V2ZW50KGRpc3BhdGNoQ29uZmlnLCBkaXNwYXRjaE1hcmtlciwgbmF0aXZlRXZlbnQpIHtcbiAgU3ludGhldGljVUlFdmVudC5jYWxsKHRoaXMsIGRpc3BhdGNoQ29uZmlnLCBkaXNwYXRjaE1hcmtlciwgbmF0aXZlRXZlbnQpO1xufVxuXG5TeW50aGV0aWNVSUV2ZW50LmF1Z21lbnRDbGFzcyhTeW50aGV0aWNGb2N1c0V2ZW50LCBGb2N1c0V2ZW50SW50ZXJmYWNlKTtcblxubW9kdWxlLmV4cG9ydHMgPSBTeW50aGV0aWNGb2N1c0V2ZW50O1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMyBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFN5bnRoZXRpY0lucHV0RXZlbnRcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBTeW50aGV0aWNFdmVudCA9IHJlcXVpcmUoXCIuL1N5bnRoZXRpY0V2ZW50XCIpO1xuXG4vKipcbiAqIEBpbnRlcmZhY2UgRXZlbnRcbiAqIEBzZWUgaHR0cDovL3d3dy53My5vcmcvVFIvMjAxMy9XRC1ET00tTGV2ZWwtMy1FdmVudHMtMjAxMzExMDVcbiAqICAgICAgLyNldmVudHMtaW5wdXRldmVudHNcbiAqL1xudmFyIElucHV0RXZlbnRJbnRlcmZhY2UgPSB7XG4gIGRhdGE6IG51bGxcbn07XG5cbi8qKlxuICogQHBhcmFtIHtvYmplY3R9IGRpc3BhdGNoQ29uZmlnIENvbmZpZ3VyYXRpb24gdXNlZCB0byBkaXNwYXRjaCB0aGlzIGV2ZW50LlxuICogQHBhcmFtIHtzdHJpbmd9IGRpc3BhdGNoTWFya2VyIE1hcmtlciBpZGVudGlmeWluZyB0aGUgZXZlbnQgdGFyZ2V0LlxuICogQHBhcmFtIHtvYmplY3R9IG5hdGl2ZUV2ZW50IE5hdGl2ZSBicm93c2VyIGV2ZW50LlxuICogQGV4dGVuZHMge1N5bnRoZXRpY1VJRXZlbnR9XG4gKi9cbmZ1bmN0aW9uIFN5bnRoZXRpY0lucHV0RXZlbnQoXG4gIGRpc3BhdGNoQ29uZmlnLFxuICBkaXNwYXRjaE1hcmtlcixcbiAgbmF0aXZlRXZlbnQpIHtcbiAgU3ludGhldGljRXZlbnQuY2FsbCh0aGlzLCBkaXNwYXRjaENvbmZpZywgZGlzcGF0Y2hNYXJrZXIsIG5hdGl2ZUV2ZW50KTtcbn1cblxuU3ludGhldGljRXZlbnQuYXVnbWVudENsYXNzKFxuICBTeW50aGV0aWNJbnB1dEV2ZW50LFxuICBJbnB1dEV2ZW50SW50ZXJmYWNlXG4pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN5bnRoZXRpY0lucHV0RXZlbnQ7XG5cbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBTeW50aGV0aWNLZXlib2FyZEV2ZW50XG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgU3ludGhldGljVUlFdmVudCA9IHJlcXVpcmUoXCIuL1N5bnRoZXRpY1VJRXZlbnRcIik7XG5cbnZhciBnZXRFdmVudENoYXJDb2RlID0gcmVxdWlyZShcIi4vZ2V0RXZlbnRDaGFyQ29kZVwiKTtcbnZhciBnZXRFdmVudEtleSA9IHJlcXVpcmUoXCIuL2dldEV2ZW50S2V5XCIpO1xudmFyIGdldEV2ZW50TW9kaWZpZXJTdGF0ZSA9IHJlcXVpcmUoXCIuL2dldEV2ZW50TW9kaWZpZXJTdGF0ZVwiKTtcblxuLyoqXG4gKiBAaW50ZXJmYWNlIEtleWJvYXJkRXZlbnRcbiAqIEBzZWUgaHR0cDovL3d3dy53My5vcmcvVFIvRE9NLUxldmVsLTMtRXZlbnRzL1xuICovXG52YXIgS2V5Ym9hcmRFdmVudEludGVyZmFjZSA9IHtcbiAga2V5OiBnZXRFdmVudEtleSxcbiAgbG9jYXRpb246IG51bGwsXG4gIGN0cmxLZXk6IG51bGwsXG4gIHNoaWZ0S2V5OiBudWxsLFxuICBhbHRLZXk6IG51bGwsXG4gIG1ldGFLZXk6IG51bGwsXG4gIHJlcGVhdDogbnVsbCxcbiAgbG9jYWxlOiBudWxsLFxuICBnZXRNb2RpZmllclN0YXRlOiBnZXRFdmVudE1vZGlmaWVyU3RhdGUsXG4gIC8vIExlZ2FjeSBJbnRlcmZhY2VcbiAgY2hhckNvZGU6IGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgLy8gYGNoYXJDb2RlYCBpcyB0aGUgcmVzdWx0IG9mIGEgS2V5UHJlc3MgZXZlbnQgYW5kIHJlcHJlc2VudHMgdGhlIHZhbHVlIG9mXG4gICAgLy8gdGhlIGFjdHVhbCBwcmludGFibGUgY2hhcmFjdGVyLlxuXG4gICAgLy8gS2V5UHJlc3MgaXMgZGVwcmVjYXRlZCwgYnV0IGl0cyByZXBsYWNlbWVudCBpcyBub3QgeWV0IGZpbmFsIGFuZCBub3RcbiAgICAvLyBpbXBsZW1lbnRlZCBpbiBhbnkgbWFqb3IgYnJvd3Nlci4gT25seSBLZXlQcmVzcyBoYXMgY2hhckNvZGUuXG4gICAgaWYgKGV2ZW50LnR5cGUgPT09ICdrZXlwcmVzcycpIHtcbiAgICAgIHJldHVybiBnZXRFdmVudENoYXJDb2RlKGV2ZW50KTtcbiAgICB9XG4gICAgcmV0dXJuIDA7XG4gIH0sXG4gIGtleUNvZGU6IGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgLy8gYGtleUNvZGVgIGlzIHRoZSByZXN1bHQgb2YgYSBLZXlEb3duL1VwIGV2ZW50IGFuZCByZXByZXNlbnRzIHRoZSB2YWx1ZSBvZlxuICAgIC8vIHBoeXNpY2FsIGtleWJvYXJkIGtleS5cblxuICAgIC8vIFRoZSBhY3R1YWwgbWVhbmluZyBvZiB0aGUgdmFsdWUgZGVwZW5kcyBvbiB0aGUgdXNlcnMnIGtleWJvYXJkIGxheW91dFxuICAgIC8vIHdoaWNoIGNhbm5vdCBiZSBkZXRlY3RlZC4gQXNzdW1pbmcgdGhhdCBpdCBpcyBhIFVTIGtleWJvYXJkIGxheW91dFxuICAgIC8vIHByb3ZpZGVzIGEgc3VycHJpc2luZ2x5IGFjY3VyYXRlIG1hcHBpbmcgZm9yIFVTIGFuZCBFdXJvcGVhbiB1c2Vycy5cbiAgICAvLyBEdWUgdG8gdGhpcywgaXQgaXMgbGVmdCB0byB0aGUgdXNlciB0byBpbXBsZW1lbnQgYXQgdGhpcyB0aW1lLlxuICAgIGlmIChldmVudC50eXBlID09PSAna2V5ZG93bicgfHwgZXZlbnQudHlwZSA9PT0gJ2tleXVwJykge1xuICAgICAgcmV0dXJuIGV2ZW50LmtleUNvZGU7XG4gICAgfVxuICAgIHJldHVybiAwO1xuICB9LFxuICB3aGljaDogZnVuY3Rpb24oZXZlbnQpIHtcbiAgICAvLyBgd2hpY2hgIGlzIGFuIGFsaWFzIGZvciBlaXRoZXIgYGtleUNvZGVgIG9yIGBjaGFyQ29kZWAgZGVwZW5kaW5nIG9uIHRoZVxuICAgIC8vIHR5cGUgb2YgdGhlIGV2ZW50LlxuICAgIGlmIChldmVudC50eXBlID09PSAna2V5cHJlc3MnKSB7XG4gICAgICByZXR1cm4gZ2V0RXZlbnRDaGFyQ29kZShldmVudCk7XG4gICAgfVxuICAgIGlmIChldmVudC50eXBlID09PSAna2V5ZG93bicgfHwgZXZlbnQudHlwZSA9PT0gJ2tleXVwJykge1xuICAgICAgcmV0dXJuIGV2ZW50LmtleUNvZGU7XG4gICAgfVxuICAgIHJldHVybiAwO1xuICB9XG59O1xuXG4vKipcbiAqIEBwYXJhbSB7b2JqZWN0fSBkaXNwYXRjaENvbmZpZyBDb25maWd1cmF0aW9uIHVzZWQgdG8gZGlzcGF0Y2ggdGhpcyBldmVudC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBkaXNwYXRjaE1hcmtlciBNYXJrZXIgaWRlbnRpZnlpbmcgdGhlIGV2ZW50IHRhcmdldC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudCBOYXRpdmUgYnJvd3NlciBldmVudC5cbiAqIEBleHRlbmRzIHtTeW50aGV0aWNVSUV2ZW50fVxuICovXG5mdW5jdGlvbiBTeW50aGV0aWNLZXlib2FyZEV2ZW50KGRpc3BhdGNoQ29uZmlnLCBkaXNwYXRjaE1hcmtlciwgbmF0aXZlRXZlbnQpIHtcbiAgU3ludGhldGljVUlFdmVudC5jYWxsKHRoaXMsIGRpc3BhdGNoQ29uZmlnLCBkaXNwYXRjaE1hcmtlciwgbmF0aXZlRXZlbnQpO1xufVxuXG5TeW50aGV0aWNVSUV2ZW50LmF1Z21lbnRDbGFzcyhTeW50aGV0aWNLZXlib2FyZEV2ZW50LCBLZXlib2FyZEV2ZW50SW50ZXJmYWNlKTtcblxubW9kdWxlLmV4cG9ydHMgPSBTeW50aGV0aWNLZXlib2FyZEV2ZW50O1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFN5bnRoZXRpY01vdXNlRXZlbnRcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBTeW50aGV0aWNVSUV2ZW50ID0gcmVxdWlyZShcIi4vU3ludGhldGljVUlFdmVudFwiKTtcbnZhciBWaWV3cG9ydE1ldHJpY3MgPSByZXF1aXJlKFwiLi9WaWV3cG9ydE1ldHJpY3NcIik7XG5cbnZhciBnZXRFdmVudE1vZGlmaWVyU3RhdGUgPSByZXF1aXJlKFwiLi9nZXRFdmVudE1vZGlmaWVyU3RhdGVcIik7XG5cbi8qKlxuICogQGludGVyZmFjZSBNb3VzZUV2ZW50XG4gKiBAc2VlIGh0dHA6Ly93d3cudzMub3JnL1RSL0RPTS1MZXZlbC0zLUV2ZW50cy9cbiAqL1xudmFyIE1vdXNlRXZlbnRJbnRlcmZhY2UgPSB7XG4gIHNjcmVlblg6IG51bGwsXG4gIHNjcmVlblk6IG51bGwsXG4gIGNsaWVudFg6IG51bGwsXG4gIGNsaWVudFk6IG51bGwsXG4gIGN0cmxLZXk6IG51bGwsXG4gIHNoaWZ0S2V5OiBudWxsLFxuICBhbHRLZXk6IG51bGwsXG4gIG1ldGFLZXk6IG51bGwsXG4gIGdldE1vZGlmaWVyU3RhdGU6IGdldEV2ZW50TW9kaWZpZXJTdGF0ZSxcbiAgYnV0dG9uOiBmdW5jdGlvbihldmVudCkge1xuICAgIC8vIFdlYmtpdCwgRmlyZWZveCwgSUU5K1xuICAgIC8vIHdoaWNoOiAgMSAyIDNcbiAgICAvLyBidXR0b246IDAgMSAyIChzdGFuZGFyZClcbiAgICB2YXIgYnV0dG9uID0gZXZlbnQuYnV0dG9uO1xuICAgIGlmICgnd2hpY2gnIGluIGV2ZW50KSB7XG4gICAgICByZXR1cm4gYnV0dG9uO1xuICAgIH1cbiAgICAvLyBJRTw5XG4gICAgLy8gd2hpY2g6ICB1bmRlZmluZWRcbiAgICAvLyBidXR0b246IDAgMCAwXG4gICAgLy8gYnV0dG9uOiAxIDQgMiAob25tb3VzZXVwKVxuICAgIHJldHVybiBidXR0b24gPT09IDIgPyAyIDogYnV0dG9uID09PSA0ID8gMSA6IDA7XG4gIH0sXG4gIGJ1dHRvbnM6IG51bGwsXG4gIHJlbGF0ZWRUYXJnZXQ6IGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgcmV0dXJuIGV2ZW50LnJlbGF0ZWRUYXJnZXQgfHwgKFxuICAgICAgZXZlbnQuZnJvbUVsZW1lbnQgPT09IGV2ZW50LnNyY0VsZW1lbnQgP1xuICAgICAgICBldmVudC50b0VsZW1lbnQgOlxuICAgICAgICBldmVudC5mcm9tRWxlbWVudFxuICAgICk7XG4gIH0sXG4gIC8vIFwiUHJvcHJpZXRhcnlcIiBJbnRlcmZhY2UuXG4gIHBhZ2VYOiBmdW5jdGlvbihldmVudCkge1xuICAgIHJldHVybiAncGFnZVgnIGluIGV2ZW50ID9cbiAgICAgIGV2ZW50LnBhZ2VYIDpcbiAgICAgIGV2ZW50LmNsaWVudFggKyBWaWV3cG9ydE1ldHJpY3MuY3VycmVudFNjcm9sbExlZnQ7XG4gIH0sXG4gIHBhZ2VZOiBmdW5jdGlvbihldmVudCkge1xuICAgIHJldHVybiAncGFnZVknIGluIGV2ZW50ID9cbiAgICAgIGV2ZW50LnBhZ2VZIDpcbiAgICAgIGV2ZW50LmNsaWVudFkgKyBWaWV3cG9ydE1ldHJpY3MuY3VycmVudFNjcm9sbFRvcDtcbiAgfVxufTtcblxuLyoqXG4gKiBAcGFyYW0ge29iamVjdH0gZGlzcGF0Y2hDb25maWcgQ29uZmlndXJhdGlvbiB1c2VkIHRvIGRpc3BhdGNoIHRoaXMgZXZlbnQuXG4gKiBAcGFyYW0ge3N0cmluZ30gZGlzcGF0Y2hNYXJrZXIgTWFya2VyIGlkZW50aWZ5aW5nIHRoZSBldmVudCB0YXJnZXQuXG4gKiBAcGFyYW0ge29iamVjdH0gbmF0aXZlRXZlbnQgTmF0aXZlIGJyb3dzZXIgZXZlbnQuXG4gKiBAZXh0ZW5kcyB7U3ludGhldGljVUlFdmVudH1cbiAqL1xuZnVuY3Rpb24gU3ludGhldGljTW91c2VFdmVudChkaXNwYXRjaENvbmZpZywgZGlzcGF0Y2hNYXJrZXIsIG5hdGl2ZUV2ZW50KSB7XG4gIFN5bnRoZXRpY1VJRXZlbnQuY2FsbCh0aGlzLCBkaXNwYXRjaENvbmZpZywgZGlzcGF0Y2hNYXJrZXIsIG5hdGl2ZUV2ZW50KTtcbn1cblxuU3ludGhldGljVUlFdmVudC5hdWdtZW50Q2xhc3MoU3ludGhldGljTW91c2VFdmVudCwgTW91c2VFdmVudEludGVyZmFjZSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3ludGhldGljTW91c2VFdmVudDtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBTeW50aGV0aWNUb3VjaEV2ZW50XG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgU3ludGhldGljVUlFdmVudCA9IHJlcXVpcmUoXCIuL1N5bnRoZXRpY1VJRXZlbnRcIik7XG5cbnZhciBnZXRFdmVudE1vZGlmaWVyU3RhdGUgPSByZXF1aXJlKFwiLi9nZXRFdmVudE1vZGlmaWVyU3RhdGVcIik7XG5cbi8qKlxuICogQGludGVyZmFjZSBUb3VjaEV2ZW50XG4gKiBAc2VlIGh0dHA6Ly93d3cudzMub3JnL1RSL3RvdWNoLWV2ZW50cy9cbiAqL1xudmFyIFRvdWNoRXZlbnRJbnRlcmZhY2UgPSB7XG4gIHRvdWNoZXM6IG51bGwsXG4gIHRhcmdldFRvdWNoZXM6IG51bGwsXG4gIGNoYW5nZWRUb3VjaGVzOiBudWxsLFxuICBhbHRLZXk6IG51bGwsXG4gIG1ldGFLZXk6IG51bGwsXG4gIGN0cmxLZXk6IG51bGwsXG4gIHNoaWZ0S2V5OiBudWxsLFxuICBnZXRNb2RpZmllclN0YXRlOiBnZXRFdmVudE1vZGlmaWVyU3RhdGVcbn07XG5cbi8qKlxuICogQHBhcmFtIHtvYmplY3R9IGRpc3BhdGNoQ29uZmlnIENvbmZpZ3VyYXRpb24gdXNlZCB0byBkaXNwYXRjaCB0aGlzIGV2ZW50LlxuICogQHBhcmFtIHtzdHJpbmd9IGRpc3BhdGNoTWFya2VyIE1hcmtlciBpZGVudGlmeWluZyB0aGUgZXZlbnQgdGFyZ2V0LlxuICogQHBhcmFtIHtvYmplY3R9IG5hdGl2ZUV2ZW50IE5hdGl2ZSBicm93c2VyIGV2ZW50LlxuICogQGV4dGVuZHMge1N5bnRoZXRpY1VJRXZlbnR9XG4gKi9cbmZ1bmN0aW9uIFN5bnRoZXRpY1RvdWNoRXZlbnQoZGlzcGF0Y2hDb25maWcsIGRpc3BhdGNoTWFya2VyLCBuYXRpdmVFdmVudCkge1xuICBTeW50aGV0aWNVSUV2ZW50LmNhbGwodGhpcywgZGlzcGF0Y2hDb25maWcsIGRpc3BhdGNoTWFya2VyLCBuYXRpdmVFdmVudCk7XG59XG5cblN5bnRoZXRpY1VJRXZlbnQuYXVnbWVudENsYXNzKFN5bnRoZXRpY1RvdWNoRXZlbnQsIFRvdWNoRXZlbnRJbnRlcmZhY2UpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN5bnRoZXRpY1RvdWNoRXZlbnQ7XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgU3ludGhldGljVUlFdmVudFxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFN5bnRoZXRpY0V2ZW50ID0gcmVxdWlyZShcIi4vU3ludGhldGljRXZlbnRcIik7XG5cbnZhciBnZXRFdmVudFRhcmdldCA9IHJlcXVpcmUoXCIuL2dldEV2ZW50VGFyZ2V0XCIpO1xuXG4vKipcbiAqIEBpbnRlcmZhY2UgVUlFdmVudFxuICogQHNlZSBodHRwOi8vd3d3LnczLm9yZy9UUi9ET00tTGV2ZWwtMy1FdmVudHMvXG4gKi9cbnZhciBVSUV2ZW50SW50ZXJmYWNlID0ge1xuICB2aWV3OiBmdW5jdGlvbihldmVudCkge1xuICAgIGlmIChldmVudC52aWV3KSB7XG4gICAgICByZXR1cm4gZXZlbnQudmlldztcbiAgICB9XG5cbiAgICB2YXIgdGFyZ2V0ID0gZ2V0RXZlbnRUYXJnZXQoZXZlbnQpO1xuICAgIGlmICh0YXJnZXQgIT0gbnVsbCAmJiB0YXJnZXQud2luZG93ID09PSB0YXJnZXQpIHtcbiAgICAgIC8vIHRhcmdldCBpcyBhIHdpbmRvdyBvYmplY3RcbiAgICAgIHJldHVybiB0YXJnZXQ7XG4gICAgfVxuXG4gICAgdmFyIGRvYyA9IHRhcmdldC5vd25lckRvY3VtZW50O1xuICAgIC8vIFRPRE86IEZpZ3VyZSBvdXQgd2h5IGBvd25lckRvY3VtZW50YCBpcyBzb21ldGltZXMgdW5kZWZpbmVkIGluIElFOC5cbiAgICBpZiAoZG9jKSB7XG4gICAgICByZXR1cm4gZG9jLmRlZmF1bHRWaWV3IHx8IGRvYy5wYXJlbnRXaW5kb3c7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiB3aW5kb3c7XG4gICAgfVxuICB9LFxuICBkZXRhaWw6IGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgcmV0dXJuIGV2ZW50LmRldGFpbCB8fCAwO1xuICB9XG59O1xuXG4vKipcbiAqIEBwYXJhbSB7b2JqZWN0fSBkaXNwYXRjaENvbmZpZyBDb25maWd1cmF0aW9uIHVzZWQgdG8gZGlzcGF0Y2ggdGhpcyBldmVudC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBkaXNwYXRjaE1hcmtlciBNYXJrZXIgaWRlbnRpZnlpbmcgdGhlIGV2ZW50IHRhcmdldC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudCBOYXRpdmUgYnJvd3NlciBldmVudC5cbiAqIEBleHRlbmRzIHtTeW50aGV0aWNFdmVudH1cbiAqL1xuZnVuY3Rpb24gU3ludGhldGljVUlFdmVudChkaXNwYXRjaENvbmZpZywgZGlzcGF0Y2hNYXJrZXIsIG5hdGl2ZUV2ZW50KSB7XG4gIFN5bnRoZXRpY0V2ZW50LmNhbGwodGhpcywgZGlzcGF0Y2hDb25maWcsIGRpc3BhdGNoTWFya2VyLCBuYXRpdmVFdmVudCk7XG59XG5cblN5bnRoZXRpY0V2ZW50LmF1Z21lbnRDbGFzcyhTeW50aGV0aWNVSUV2ZW50LCBVSUV2ZW50SW50ZXJmYWNlKTtcblxubW9kdWxlLmV4cG9ydHMgPSBTeW50aGV0aWNVSUV2ZW50O1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFN5bnRoZXRpY1doZWVsRXZlbnRcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBTeW50aGV0aWNNb3VzZUV2ZW50ID0gcmVxdWlyZShcIi4vU3ludGhldGljTW91c2VFdmVudFwiKTtcblxuLyoqXG4gKiBAaW50ZXJmYWNlIFdoZWVsRXZlbnRcbiAqIEBzZWUgaHR0cDovL3d3dy53My5vcmcvVFIvRE9NLUxldmVsLTMtRXZlbnRzL1xuICovXG52YXIgV2hlZWxFdmVudEludGVyZmFjZSA9IHtcbiAgZGVsdGFYOiBmdW5jdGlvbihldmVudCkge1xuICAgIHJldHVybiAoXG4gICAgICAnZGVsdGFYJyBpbiBldmVudCA/IGV2ZW50LmRlbHRhWCA6XG4gICAgICAvLyBGYWxsYmFjayB0byBgd2hlZWxEZWx0YVhgIGZvciBXZWJraXQgYW5kIG5vcm1hbGl6ZSAocmlnaHQgaXMgcG9zaXRpdmUpLlxuICAgICAgJ3doZWVsRGVsdGFYJyBpbiBldmVudCA/IC1ldmVudC53aGVlbERlbHRhWCA6IDBcbiAgICApO1xuICB9LFxuICBkZWx0YVk6IGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgcmV0dXJuIChcbiAgICAgICdkZWx0YVknIGluIGV2ZW50ID8gZXZlbnQuZGVsdGFZIDpcbiAgICAgIC8vIEZhbGxiYWNrIHRvIGB3aGVlbERlbHRhWWAgZm9yIFdlYmtpdCBhbmQgbm9ybWFsaXplIChkb3duIGlzIHBvc2l0aXZlKS5cbiAgICAgICd3aGVlbERlbHRhWScgaW4gZXZlbnQgPyAtZXZlbnQud2hlZWxEZWx0YVkgOlxuICAgICAgLy8gRmFsbGJhY2sgdG8gYHdoZWVsRGVsdGFgIGZvciBJRTw5IGFuZCBub3JtYWxpemUgKGRvd24gaXMgcG9zaXRpdmUpLlxuICAgICAgJ3doZWVsRGVsdGEnIGluIGV2ZW50ID8gLWV2ZW50LndoZWVsRGVsdGEgOiAwXG4gICAgKTtcbiAgfSxcbiAgZGVsdGFaOiBudWxsLFxuXG4gIC8vIEJyb3dzZXJzIHdpdGhvdXQgXCJkZWx0YU1vZGVcIiBpcyByZXBvcnRpbmcgaW4gcmF3IHdoZWVsIGRlbHRhIHdoZXJlIG9uZVxuICAvLyBub3RjaCBvbiB0aGUgc2Nyb2xsIGlzIGFsd2F5cyArLy0gMTIwLCByb3VnaGx5IGVxdWl2YWxlbnQgdG8gcGl4ZWxzLlxuICAvLyBBIGdvb2QgYXBwcm94aW1hdGlvbiBvZiBET01fREVMVEFfTElORSAoMSkgaXMgNSUgb2Ygdmlld3BvcnQgc2l6ZSBvclxuICAvLyB+NDAgcGl4ZWxzLCBmb3IgRE9NX0RFTFRBX1NDUkVFTiAoMikgaXQgaXMgODcuNSUgb2Ygdmlld3BvcnQgc2l6ZS5cbiAgZGVsdGFNb2RlOiBudWxsXG59O1xuXG4vKipcbiAqIEBwYXJhbSB7b2JqZWN0fSBkaXNwYXRjaENvbmZpZyBDb25maWd1cmF0aW9uIHVzZWQgdG8gZGlzcGF0Y2ggdGhpcyBldmVudC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBkaXNwYXRjaE1hcmtlciBNYXJrZXIgaWRlbnRpZnlpbmcgdGhlIGV2ZW50IHRhcmdldC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudCBOYXRpdmUgYnJvd3NlciBldmVudC5cbiAqIEBleHRlbmRzIHtTeW50aGV0aWNNb3VzZUV2ZW50fVxuICovXG5mdW5jdGlvbiBTeW50aGV0aWNXaGVlbEV2ZW50KGRpc3BhdGNoQ29uZmlnLCBkaXNwYXRjaE1hcmtlciwgbmF0aXZlRXZlbnQpIHtcbiAgU3ludGhldGljTW91c2VFdmVudC5jYWxsKHRoaXMsIGRpc3BhdGNoQ29uZmlnLCBkaXNwYXRjaE1hcmtlciwgbmF0aXZlRXZlbnQpO1xufVxuXG5TeW50aGV0aWNNb3VzZUV2ZW50LmF1Z21lbnRDbGFzcyhTeW50aGV0aWNXaGVlbEV2ZW50LCBXaGVlbEV2ZW50SW50ZXJmYWNlKTtcblxubW9kdWxlLmV4cG9ydHMgPSBTeW50aGV0aWNXaGVlbEV2ZW50O1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBUcmFuc2FjdGlvblxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG4vKipcbiAqIGBUcmFuc2FjdGlvbmAgY3JlYXRlcyBhIGJsYWNrIGJveCB0aGF0IGlzIGFibGUgdG8gd3JhcCBhbnkgbWV0aG9kIHN1Y2ggdGhhdFxuICogY2VydGFpbiBpbnZhcmlhbnRzIGFyZSBtYWludGFpbmVkIGJlZm9yZSBhbmQgYWZ0ZXIgdGhlIG1ldGhvZCBpcyBpbnZva2VkXG4gKiAoRXZlbiBpZiBhbiBleGNlcHRpb24gaXMgdGhyb3duIHdoaWxlIGludm9raW5nIHRoZSB3cmFwcGVkIG1ldGhvZCkuIFdob2V2ZXJcbiAqIGluc3RhbnRpYXRlcyBhIHRyYW5zYWN0aW9uIGNhbiBwcm92aWRlIGVuZm9yY2VycyBvZiB0aGUgaW52YXJpYW50cyBhdFxuICogY3JlYXRpb24gdGltZS4gVGhlIGBUcmFuc2FjdGlvbmAgY2xhc3MgaXRzZWxmIHdpbGwgc3VwcGx5IG9uZSBhZGRpdGlvbmFsXG4gKiBhdXRvbWF0aWMgaW52YXJpYW50IGZvciB5b3UgLSB0aGUgaW52YXJpYW50IHRoYXQgYW55IHRyYW5zYWN0aW9uIGluc3RhbmNlXG4gKiBzaG91bGQgbm90IGJlIHJ1biB3aGlsZSBpdCBpcyBhbHJlYWR5IGJlaW5nIHJ1bi4gWW91IHdvdWxkIHR5cGljYWxseSBjcmVhdGUgYVxuICogc2luZ2xlIGluc3RhbmNlIG9mIGEgYFRyYW5zYWN0aW9uYCBmb3IgcmV1c2UgbXVsdGlwbGUgdGltZXMsIHRoYXQgcG90ZW50aWFsbHlcbiAqIGlzIHVzZWQgdG8gd3JhcCBzZXZlcmFsIGRpZmZlcmVudCBtZXRob2RzLiBXcmFwcGVycyBhcmUgZXh0cmVtZWx5IHNpbXBsZSAtXG4gKiB0aGV5IG9ubHkgcmVxdWlyZSBpbXBsZW1lbnRpbmcgdHdvIG1ldGhvZHMuXG4gKlxuICogPHByZT5cbiAqICAgICAgICAgICAgICAgICAgICAgICB3cmFwcGVycyAoaW5qZWN0ZWQgYXQgY3JlYXRpb24gdGltZSlcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICArICAgICAgICArXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgfFxuICogICAgICAgICAgICAgICAgICAgICstLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLXwtLS0tLS0tLS0tLS0tLStcbiAqICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICB2ICAgICAgICB8ICAgICAgICAgICAgICB8XG4gKiAgICAgICAgICAgICAgICAgICAgfCAgICAgICstLS0tLS0tLS0tLS0tLS0rICAgfCAgICAgICAgICAgICAgfFxuICogICAgICAgICAgICAgICAgICAgIHwgICArLS18ICAgIHdyYXBwZXIxICAgfC0tLXwtLS0tKyAgICAgICAgIHxcbiAqICAgICAgICAgICAgICAgICAgICB8ICAgfCAgKy0tLS0tLS0tLS0tLS0tLSsgICB2ICAgIHwgICAgICAgICB8XG4gKiAgICAgICAgICAgICAgICAgICAgfCAgIHwgICAgICAgICAgKy0tLS0tLS0tLS0tLS0rICB8ICAgICAgICAgfFxuICogICAgICAgICAgICAgICAgICAgIHwgICB8ICAgICArLS0tLXwgICB3cmFwcGVyMiAgfC0tLS0tLS0tKyAgIHxcbiAqICAgICAgICAgICAgICAgICAgICB8ICAgfCAgICAgfCAgICArLS0tLS0tLS0tLS0tLSsgIHwgICAgIHwgICB8XG4gKiAgICAgICAgICAgICAgICAgICAgfCAgIHwgICAgIHwgICAgICAgICAgICAgICAgICAgICB8ICAgICB8ICAgfFxuICogICAgICAgICAgICAgICAgICAgIHwgICB2ICAgICB2ICAgICAgICAgICAgICAgICAgICAgdiAgICAgdiAgIHwgd3JhcHBlclxuICogICAgICAgICAgICAgICAgICAgIHwgKy0tLSsgKy0tLSsgICArLS0tLS0tLS0tKyAgICstLS0rICstLS0rIHwgaW52YXJpYW50c1xuICogcGVyZm9ybShhbnlNZXRob2QpIHwgfCAgIHwgfCAgIHwgICB8ICAgICAgICAgfCAgIHwgICB8IHwgICB8IHwgbWFpbnRhaW5lZFxuICogKy0tLS0tLS0tLS0tLS0tLS0tPnwtfC0tLXwtfC0tLXwtLT58YW55TWV0aG9kfC0tLXwtLS18LXwtLS18LXwtLS0tLS0tLT5cbiAqICAgICAgICAgICAgICAgICAgICB8IHwgICB8IHwgICB8ICAgfCAgICAgICAgIHwgICB8ICAgfCB8ICAgfCB8XG4gKiAgICAgICAgICAgICAgICAgICAgfCB8ICAgfCB8ICAgfCAgIHwgICAgICAgICB8ICAgfCAgIHwgfCAgIHwgfFxuICogICAgICAgICAgICAgICAgICAgIHwgfCAgIHwgfCAgIHwgICB8ICAgICAgICAgfCAgIHwgICB8IHwgICB8IHxcbiAqICAgICAgICAgICAgICAgICAgICB8ICstLS0rICstLS0rICAgKy0tLS0tLS0tLSsgICArLS0tKyArLS0tKyB8XG4gKiAgICAgICAgICAgICAgICAgICAgfCAgaW5pdGlhbGl6ZSAgICAgICAgICAgICAgICAgICAgY2xvc2UgICAgfFxuICogICAgICAgICAgICAgICAgICAgICstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLStcbiAqIDwvcHJlPlxuICpcbiAqIFVzZSBjYXNlczpcbiAqIC0gUHJlc2VydmluZyB0aGUgaW5wdXQgc2VsZWN0aW9uIHJhbmdlcyBiZWZvcmUvYWZ0ZXIgcmVjb25jaWxpYXRpb24uXG4gKiAgIFJlc3RvcmluZyBzZWxlY3Rpb24gZXZlbiBpbiB0aGUgZXZlbnQgb2YgYW4gdW5leHBlY3RlZCBlcnJvci5cbiAqIC0gRGVhY3RpdmF0aW5nIGV2ZW50cyB3aGlsZSByZWFycmFuZ2luZyB0aGUgRE9NLCBwcmV2ZW50aW5nIGJsdXJzL2ZvY3VzZXMsXG4gKiAgIHdoaWxlIGd1YXJhbnRlZWluZyB0aGF0IGFmdGVyd2FyZHMsIHRoZSBldmVudCBzeXN0ZW0gaXMgcmVhY3RpdmF0ZWQuXG4gKiAtIEZsdXNoaW5nIGEgcXVldWUgb2YgY29sbGVjdGVkIERPTSBtdXRhdGlvbnMgdG8gdGhlIG1haW4gVUkgdGhyZWFkIGFmdGVyIGFcbiAqICAgcmVjb25jaWxpYXRpb24gdGFrZXMgcGxhY2UgaW4gYSB3b3JrZXIgdGhyZWFkLlxuICogLSBJbnZva2luZyBhbnkgY29sbGVjdGVkIGBjb21wb25lbnREaWRVcGRhdGVgIGNhbGxiYWNrcyBhZnRlciByZW5kZXJpbmcgbmV3XG4gKiAgIGNvbnRlbnQuXG4gKiAtIChGdXR1cmUgdXNlIGNhc2UpOiBXcmFwcGluZyBwYXJ0aWN1bGFyIGZsdXNoZXMgb2YgdGhlIGBSZWFjdFdvcmtlcmAgcXVldWVcbiAqICAgdG8gcHJlc2VydmUgdGhlIGBzY3JvbGxUb3BgIChhbiBhdXRvbWF0aWMgc2Nyb2xsIGF3YXJlIERPTSkuXG4gKiAtIChGdXR1cmUgdXNlIGNhc2UpOiBMYXlvdXQgY2FsY3VsYXRpb25zIGJlZm9yZSBhbmQgYWZ0ZXIgRE9NIHVwYXRlcy5cbiAqXG4gKiBUcmFuc2FjdGlvbmFsIHBsdWdpbiBBUEk6XG4gKiAtIEEgbW9kdWxlIHRoYXQgaGFzIGFuIGBpbml0aWFsaXplYCBtZXRob2QgdGhhdCByZXR1cm5zIGFueSBwcmVjb21wdXRhdGlvbi5cbiAqIC0gYW5kIGEgYGNsb3NlYCBtZXRob2QgdGhhdCBhY2NlcHRzIHRoZSBwcmVjb21wdXRhdGlvbi4gYGNsb3NlYCBpcyBpbnZva2VkXG4gKiAgIHdoZW4gdGhlIHdyYXBwZWQgcHJvY2VzcyBpcyBjb21wbGV0ZWQsIG9yIGhhcyBmYWlsZWQuXG4gKlxuICogQHBhcmFtIHtBcnJheTxUcmFuc2FjdGlvbmFsV3JhcHBlcj59IHRyYW5zYWN0aW9uV3JhcHBlciBXcmFwcGVyIG1vZHVsZXNcbiAqIHRoYXQgaW1wbGVtZW50IGBpbml0aWFsaXplYCBhbmQgYGNsb3NlYC5cbiAqIEByZXR1cm4ge1RyYW5zYWN0aW9ufSBTaW5nbGUgdHJhbnNhY3Rpb24gZm9yIHJldXNlIGluIHRocmVhZC5cbiAqXG4gKiBAY2xhc3MgVHJhbnNhY3Rpb25cbiAqL1xudmFyIE1peGluID0ge1xuICAvKipcbiAgICogU2V0cyB1cCB0aGlzIGluc3RhbmNlIHNvIHRoYXQgaXQgaXMgcHJlcGFyZWQgZm9yIGNvbGxlY3RpbmcgbWV0cmljcy4gRG9lc1xuICAgKiBzbyBzdWNoIHRoYXQgdGhpcyBzZXR1cCBtZXRob2QgbWF5IGJlIHVzZWQgb24gYW4gaW5zdGFuY2UgdGhhdCBpcyBhbHJlYWR5XG4gICAqIGluaXRpYWxpemVkLCBpbiBhIHdheSB0aGF0IGRvZXMgbm90IGNvbnN1bWUgYWRkaXRpb25hbCBtZW1vcnkgdXBvbiByZXVzZS5cbiAgICogVGhhdCBjYW4gYmUgdXNlZnVsIGlmIHlvdSBkZWNpZGUgdG8gbWFrZSB5b3VyIHN1YmNsYXNzIG9mIHRoaXMgbWl4aW4gYVxuICAgKiBcIlBvb2xlZENsYXNzXCIuXG4gICAqL1xuICByZWluaXRpYWxpemVUcmFuc2FjdGlvbjogZnVuY3Rpb24oKSB7XG4gICAgdGhpcy50cmFuc2FjdGlvbldyYXBwZXJzID0gdGhpcy5nZXRUcmFuc2FjdGlvbldyYXBwZXJzKCk7XG4gICAgaWYgKCF0aGlzLndyYXBwZXJJbml0RGF0YSkge1xuICAgICAgdGhpcy53cmFwcGVySW5pdERhdGEgPSBbXTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy53cmFwcGVySW5pdERhdGEubGVuZ3RoID0gMDtcbiAgICB9XG4gICAgdGhpcy5faXNJblRyYW5zYWN0aW9uID0gZmFsc2U7XG4gIH0sXG5cbiAgX2lzSW5UcmFuc2FjdGlvbjogZmFsc2UsXG5cbiAgLyoqXG4gICAqIEBhYnN0cmFjdFxuICAgKiBAcmV0dXJuIHtBcnJheTxUcmFuc2FjdGlvbldyYXBwZXI+fSBBcnJheSBvZiB0cmFuc2FjdGlvbiB3cmFwcGVycy5cbiAgICovXG4gIGdldFRyYW5zYWN0aW9uV3JhcHBlcnM6IG51bGwsXG5cbiAgaXNJblRyYW5zYWN0aW9uOiBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gISF0aGlzLl9pc0luVHJhbnNhY3Rpb247XG4gIH0sXG5cbiAgLyoqXG4gICAqIEV4ZWN1dGVzIHRoZSBmdW5jdGlvbiB3aXRoaW4gYSBzYWZldHkgd2luZG93LiBVc2UgdGhpcyBmb3IgdGhlIHRvcCBsZXZlbFxuICAgKiBtZXRob2RzIHRoYXQgcmVzdWx0IGluIGxhcmdlIGFtb3VudHMgb2YgY29tcHV0YXRpb24vbXV0YXRpb25zIHRoYXQgd291bGRcbiAgICogbmVlZCB0byBiZSBzYWZldHkgY2hlY2tlZC5cbiAgICpcbiAgICogQHBhcmFtIHtmdW5jdGlvbn0gbWV0aG9kIE1lbWJlciBvZiBzY29wZSB0byBjYWxsLlxuICAgKiBAcGFyYW0ge09iamVjdH0gc2NvcGUgU2NvcGUgdG8gaW52b2tlIGZyb20uXG4gICAqIEBwYXJhbSB7T2JqZWN0Pz19IGFyZ3MuLi4gQXJndW1lbnRzIHRvIHBhc3MgdG8gdGhlIG1ldGhvZCAob3B0aW9uYWwpLlxuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgIEhlbHBzIHByZXZlbnQgbmVlZCB0byBiaW5kIGluIG1hbnkgY2FzZXMuXG4gICAqIEByZXR1cm4gUmV0dXJuIHZhbHVlIGZyb20gYG1ldGhvZGAuXG4gICAqL1xuICBwZXJmb3JtOiBmdW5jdGlvbihtZXRob2QsIHNjb3BlLCBhLCBiLCBjLCBkLCBlLCBmKSB7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICF0aGlzLmlzSW5UcmFuc2FjdGlvbigpLFxuICAgICAgJ1RyYW5zYWN0aW9uLnBlcmZvcm0oLi4uKTogQ2Fubm90IGluaXRpYWxpemUgYSB0cmFuc2FjdGlvbiB3aGVuIHRoZXJlICcgK1xuICAgICAgJ2lzIGFscmVhZHkgYW4gb3V0c3RhbmRpbmcgdHJhbnNhY3Rpb24uJ1xuICAgICkgOiBpbnZhcmlhbnQoIXRoaXMuaXNJblRyYW5zYWN0aW9uKCkpKTtcbiAgICB2YXIgZXJyb3JUaHJvd247XG4gICAgdmFyIHJldDtcbiAgICB0cnkge1xuICAgICAgdGhpcy5faXNJblRyYW5zYWN0aW9uID0gdHJ1ZTtcbiAgICAgIC8vIENhdGNoaW5nIGVycm9ycyBtYWtlcyBkZWJ1Z2dpbmcgbW9yZSBkaWZmaWN1bHQsIHNvIHdlIHN0YXJ0IHdpdGhcbiAgICAgIC8vIGVycm9yVGhyb3duIHNldCB0byB0cnVlIGJlZm9yZSBzZXR0aW5nIGl0IHRvIGZhbHNlIGFmdGVyIGNhbGxpbmdcbiAgICAgIC8vIGNsb3NlIC0tIGlmIGl0J3Mgc3RpbGwgc2V0IHRvIHRydWUgaW4gdGhlIGZpbmFsbHkgYmxvY2ssIGl0IG1lYW5zXG4gICAgICAvLyBvbmUgb2YgdGhlc2UgY2FsbHMgdGhyZXcuXG4gICAgICBlcnJvclRocm93biA9IHRydWU7XG4gICAgICB0aGlzLmluaXRpYWxpemVBbGwoMCk7XG4gICAgICByZXQgPSBtZXRob2QuY2FsbChzY29wZSwgYSwgYiwgYywgZCwgZSwgZik7XG4gICAgICBlcnJvclRocm93biA9IGZhbHNlO1xuICAgIH0gZmluYWxseSB7XG4gICAgICB0cnkge1xuICAgICAgICBpZiAoZXJyb3JUaHJvd24pIHtcbiAgICAgICAgICAvLyBJZiBgbWV0aG9kYCB0aHJvd3MsIHByZWZlciB0byBzaG93IHRoYXQgc3RhY2sgdHJhY2Ugb3ZlciBhbnkgdGhyb3duXG4gICAgICAgICAgLy8gYnkgaW52b2tpbmcgYGNsb3NlQWxsYC5cbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgdGhpcy5jbG9zZUFsbCgwKTtcbiAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gU2luY2UgYG1ldGhvZGAgZGlkbid0IHRocm93LCB3ZSBkb24ndCB3YW50IHRvIHNpbGVuY2UgdGhlIGV4Y2VwdGlvblxuICAgICAgICAgIC8vIGhlcmUuXG4gICAgICAgICAgdGhpcy5jbG9zZUFsbCgwKTtcbiAgICAgICAgfVxuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgdGhpcy5faXNJblRyYW5zYWN0aW9uID0gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZXQ7XG4gIH0sXG5cbiAgaW5pdGlhbGl6ZUFsbDogZnVuY3Rpb24oc3RhcnRJbmRleCkge1xuICAgIHZhciB0cmFuc2FjdGlvbldyYXBwZXJzID0gdGhpcy50cmFuc2FjdGlvbldyYXBwZXJzO1xuICAgIGZvciAodmFyIGkgPSBzdGFydEluZGV4OyBpIDwgdHJhbnNhY3Rpb25XcmFwcGVycy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIHdyYXBwZXIgPSB0cmFuc2FjdGlvbldyYXBwZXJzW2ldO1xuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gQ2F0Y2hpbmcgZXJyb3JzIG1ha2VzIGRlYnVnZ2luZyBtb3JlIGRpZmZpY3VsdCwgc28gd2Ugc3RhcnQgd2l0aCB0aGVcbiAgICAgICAgLy8gT0JTRVJWRURfRVJST1Igc3RhdGUgYmVmb3JlIG92ZXJ3cml0aW5nIGl0IHdpdGggdGhlIHJlYWwgcmV0dXJuIHZhbHVlXG4gICAgICAgIC8vIG9mIGluaXRpYWxpemUgLS0gaWYgaXQncyBzdGlsbCBzZXQgdG8gT0JTRVJWRURfRVJST1IgaW4gdGhlIGZpbmFsbHlcbiAgICAgICAgLy8gYmxvY2ssIGl0IG1lYW5zIHdyYXBwZXIuaW5pdGlhbGl6ZSB0aHJldy5cbiAgICAgICAgdGhpcy53cmFwcGVySW5pdERhdGFbaV0gPSBUcmFuc2FjdGlvbi5PQlNFUlZFRF9FUlJPUjtcbiAgICAgICAgdGhpcy53cmFwcGVySW5pdERhdGFbaV0gPSB3cmFwcGVyLmluaXRpYWxpemUgP1xuICAgICAgICAgIHdyYXBwZXIuaW5pdGlhbGl6ZS5jYWxsKHRoaXMpIDpcbiAgICAgICAgICBudWxsO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgaWYgKHRoaXMud3JhcHBlckluaXREYXRhW2ldID09PSBUcmFuc2FjdGlvbi5PQlNFUlZFRF9FUlJPUikge1xuICAgICAgICAgIC8vIFRoZSBpbml0aWFsaXplciBmb3Igd3JhcHBlciBpIHRocmV3IGFuIGVycm9yOyBpbml0aWFsaXplIHRoZVxuICAgICAgICAgIC8vIHJlbWFpbmluZyB3cmFwcGVycyBidXQgc2lsZW5jZSBhbnkgZXhjZXB0aW9ucyBmcm9tIHRoZW0gdG8gZW5zdXJlXG4gICAgICAgICAgLy8gdGhhdCB0aGUgZmlyc3QgZXJyb3IgaXMgdGhlIG9uZSB0byBidWJibGUgdXAuXG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHRoaXMuaW5pdGlhbGl6ZUFsbChpICsgMSk7XG4gICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBJbnZva2VzIGVhY2ggb2YgYHRoaXMudHJhbnNhY3Rpb25XcmFwcGVycy5jbG9zZVtpXWAgZnVuY3Rpb25zLCBwYXNzaW5nIGludG9cbiAgICogdGhlbSB0aGUgcmVzcGVjdGl2ZSByZXR1cm4gdmFsdWVzIG9mIGB0aGlzLnRyYW5zYWN0aW9uV3JhcHBlcnMuaW5pdFtpXWBcbiAgICogKGBjbG9zZWBycyB0aGF0IGNvcnJlc3BvbmQgdG8gaW5pdGlhbGl6ZXJzIHRoYXQgZmFpbGVkIHdpbGwgbm90IGJlXG4gICAqIGludm9rZWQpLlxuICAgKi9cbiAgY2xvc2VBbGw6IGZ1bmN0aW9uKHN0YXJ0SW5kZXgpIHtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgdGhpcy5pc0luVHJhbnNhY3Rpb24oKSxcbiAgICAgICdUcmFuc2FjdGlvbi5jbG9zZUFsbCgpOiBDYW5ub3QgY2xvc2UgdHJhbnNhY3Rpb24gd2hlbiBub25lIGFyZSBvcGVuLidcbiAgICApIDogaW52YXJpYW50KHRoaXMuaXNJblRyYW5zYWN0aW9uKCkpKTtcbiAgICB2YXIgdHJhbnNhY3Rpb25XcmFwcGVycyA9IHRoaXMudHJhbnNhY3Rpb25XcmFwcGVycztcbiAgICBmb3IgKHZhciBpID0gc3RhcnRJbmRleDsgaSA8IHRyYW5zYWN0aW9uV3JhcHBlcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciB3cmFwcGVyID0gdHJhbnNhY3Rpb25XcmFwcGVyc1tpXTtcbiAgICAgIHZhciBpbml0RGF0YSA9IHRoaXMud3JhcHBlckluaXREYXRhW2ldO1xuICAgICAgdmFyIGVycm9yVGhyb3duO1xuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gQ2F0Y2hpbmcgZXJyb3JzIG1ha2VzIGRlYnVnZ2luZyBtb3JlIGRpZmZpY3VsdCwgc28gd2Ugc3RhcnQgd2l0aFxuICAgICAgICAvLyBlcnJvclRocm93biBzZXQgdG8gdHJ1ZSBiZWZvcmUgc2V0dGluZyBpdCB0byBmYWxzZSBhZnRlciBjYWxsaW5nXG4gICAgICAgIC8vIGNsb3NlIC0tIGlmIGl0J3Mgc3RpbGwgc2V0IHRvIHRydWUgaW4gdGhlIGZpbmFsbHkgYmxvY2ssIGl0IG1lYW5zXG4gICAgICAgIC8vIHdyYXBwZXIuY2xvc2UgdGhyZXcuXG4gICAgICAgIGVycm9yVGhyb3duID0gdHJ1ZTtcbiAgICAgICAgaWYgKGluaXREYXRhICE9PSBUcmFuc2FjdGlvbi5PQlNFUlZFRF9FUlJPUikge1xuICAgICAgICAgIHdyYXBwZXIuY2xvc2UgJiYgd3JhcHBlci5jbG9zZS5jYWxsKHRoaXMsIGluaXREYXRhKTtcbiAgICAgICAgfVxuICAgICAgICBlcnJvclRocm93biA9IGZhbHNlO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgaWYgKGVycm9yVGhyb3duKSB7XG4gICAgICAgICAgLy8gVGhlIGNsb3NlciBmb3Igd3JhcHBlciBpIHRocmV3IGFuIGVycm9yOyBjbG9zZSB0aGUgcmVtYWluaW5nXG4gICAgICAgICAgLy8gd3JhcHBlcnMgYnV0IHNpbGVuY2UgYW55IGV4Y2VwdGlvbnMgZnJvbSB0aGVtIHRvIGVuc3VyZSB0aGF0IHRoZVxuICAgICAgICAgIC8vIGZpcnN0IGVycm9yIGlzIHRoZSBvbmUgdG8gYnViYmxlIHVwLlxuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICB0aGlzLmNsb3NlQWxsKGkgKyAxKTtcbiAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMud3JhcHBlckluaXREYXRhLmxlbmd0aCA9IDA7XG4gIH1cbn07XG5cbnZhciBUcmFuc2FjdGlvbiA9IHtcblxuICBNaXhpbjogTWl4aW4sXG5cbiAgLyoqXG4gICAqIFRva2VuIHRvIGxvb2sgZm9yIHRvIGRldGVybWluZSBpZiBhbiBlcnJvciBvY2N1cmVkLlxuICAgKi9cbiAgT0JTRVJWRURfRVJST1I6IHt9XG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gVHJhbnNhY3Rpb247XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBWaWV3cG9ydE1ldHJpY3NcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIGdldFVuYm91bmRlZFNjcm9sbFBvc2l0aW9uID0gcmVxdWlyZShcIi4vZ2V0VW5ib3VuZGVkU2Nyb2xsUG9zaXRpb25cIik7XG5cbnZhciBWaWV3cG9ydE1ldHJpY3MgPSB7XG5cbiAgY3VycmVudFNjcm9sbExlZnQ6IDAsXG5cbiAgY3VycmVudFNjcm9sbFRvcDogMCxcblxuICByZWZyZXNoU2Nyb2xsVmFsdWVzOiBmdW5jdGlvbigpIHtcbiAgICB2YXIgc2Nyb2xsUG9zaXRpb24gPSBnZXRVbmJvdW5kZWRTY3JvbGxQb3NpdGlvbih3aW5kb3cpO1xuICAgIFZpZXdwb3J0TWV0cmljcy5jdXJyZW50U2Nyb2xsTGVmdCA9IHNjcm9sbFBvc2l0aW9uLng7XG4gICAgVmlld3BvcnRNZXRyaWNzLmN1cnJlbnRTY3JvbGxUb3AgPSBzY3JvbGxQb3NpdGlvbi55O1xuICB9XG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gVmlld3BvcnRNZXRyaWNzO1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgYWNjdW11bGF0ZUludG9cbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcblxuLyoqXG4gKlxuICogQWNjdW11bGF0ZXMgaXRlbXMgdGhhdCBtdXN0IG5vdCBiZSBudWxsIG9yIHVuZGVmaW5lZCBpbnRvIHRoZSBmaXJzdCBvbmUuIFRoaXNcbiAqIGlzIHVzZWQgdG8gY29uc2VydmUgbWVtb3J5IGJ5IGF2b2lkaW5nIGFycmF5IGFsbG9jYXRpb25zLCBhbmQgdGh1cyBzYWNyaWZpY2VzXG4gKiBBUEkgY2xlYW5uZXNzLiBTaW5jZSBgY3VycmVudGAgY2FuIGJlIG51bGwgYmVmb3JlIGJlaW5nIHBhc3NlZCBpbiBhbmQgbm90XG4gKiBudWxsIGFmdGVyIHRoaXMgZnVuY3Rpb24sIG1ha2Ugc3VyZSB0byBhc3NpZ24gaXQgYmFjayB0byBgY3VycmVudGA6XG4gKlxuICogYGEgPSBhY2N1bXVsYXRlSW50byhhLCBiKTtgXG4gKlxuICogVGhpcyBBUEkgc2hvdWxkIGJlIHNwYXJpbmdseSB1c2VkLiBUcnkgYGFjY3VtdWxhdGVgIGZvciBzb21ldGhpbmcgY2xlYW5lci5cbiAqXG4gKiBAcmV0dXJuIHsqfGFycmF5PCo+fSBBbiBhY2N1bXVsYXRpb24gb2YgaXRlbXMuXG4gKi9cblxuZnVuY3Rpb24gYWNjdW11bGF0ZUludG8oY3VycmVudCwgbmV4dCkge1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgIG5leHQgIT0gbnVsbCxcbiAgICAnYWNjdW11bGF0ZUludG8oLi4uKTogQWNjdW11bGF0ZWQgaXRlbXMgbXVzdCBub3QgYmUgbnVsbCBvciB1bmRlZmluZWQuJ1xuICApIDogaW52YXJpYW50KG5leHQgIT0gbnVsbCkpO1xuICBpZiAoY3VycmVudCA9PSBudWxsKSB7XG4gICAgcmV0dXJuIG5leHQ7XG4gIH1cblxuICAvLyBCb3RoIGFyZSBub3QgZW1wdHkuIFdhcm5pbmc6IE5ldmVyIGNhbGwgeC5jb25jYXQoeSkgd2hlbiB5b3UgYXJlIG5vdFxuICAvLyBjZXJ0YWluIHRoYXQgeCBpcyBhbiBBcnJheSAoeCBjb3VsZCBiZSBhIHN0cmluZyB3aXRoIGNvbmNhdCBtZXRob2QpLlxuICB2YXIgY3VycmVudElzQXJyYXkgPSBBcnJheS5pc0FycmF5KGN1cnJlbnQpO1xuICB2YXIgbmV4dElzQXJyYXkgPSBBcnJheS5pc0FycmF5KG5leHQpO1xuXG4gIGlmIChjdXJyZW50SXNBcnJheSAmJiBuZXh0SXNBcnJheSkge1xuICAgIGN1cnJlbnQucHVzaC5hcHBseShjdXJyZW50LCBuZXh0KTtcbiAgICByZXR1cm4gY3VycmVudDtcbiAgfVxuXG4gIGlmIChjdXJyZW50SXNBcnJheSkge1xuICAgIGN1cnJlbnQucHVzaChuZXh0KTtcbiAgICByZXR1cm4gY3VycmVudDtcbiAgfVxuXG4gIGlmIChuZXh0SXNBcnJheSkge1xuICAgIC8vIEEgYml0IHRvbyBkYW5nZXJvdXMgdG8gbXV0YXRlIGBuZXh0YC5cbiAgICByZXR1cm4gW2N1cnJlbnRdLmNvbmNhdChuZXh0KTtcbiAgfVxuXG4gIHJldHVybiBbY3VycmVudCwgbmV4dF07XG59XG5cbm1vZHVsZS5leHBvcnRzID0gYWNjdW11bGF0ZUludG87XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBhZGxlcjMyXG4gKi9cblxuLyoganNsaW50IGJpdHdpc2U6dHJ1ZSAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIE1PRCA9IDY1NTIxO1xuXG4vLyBUaGlzIGlzIGEgY2xlYW4tcm9vbSBpbXBsZW1lbnRhdGlvbiBvZiBhZGxlcjMyIGRlc2lnbmVkIGZvciBkZXRlY3Rpbmdcbi8vIGlmIG1hcmt1cCBpcyBub3Qgd2hhdCB3ZSBleHBlY3QgaXQgdG8gYmUuIEl0IGRvZXMgbm90IG5lZWQgdG8gYmVcbi8vIGNyeXB0b2dyYXBoaWNhbGx5IHN0cm9uZywgb25seSByZWFzb25hYmx5IGdvb2QgYXQgZGV0ZWN0aW5nIGlmIG1hcmt1cFxuLy8gZ2VuZXJhdGVkIG9uIHRoZSBzZXJ2ZXIgaXMgZGlmZmVyZW50IHRoYW4gdGhhdCBvbiB0aGUgY2xpZW50LlxuZnVuY3Rpb24gYWRsZXIzMihkYXRhKSB7XG4gIHZhciBhID0gMTtcbiAgdmFyIGIgPSAwO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IGRhdGEubGVuZ3RoOyBpKyspIHtcbiAgICBhID0gKGEgKyBkYXRhLmNoYXJDb2RlQXQoaSkpICUgTU9EO1xuICAgIGIgPSAoYiArIGEpICUgTU9EO1xuICB9XG4gIHJldHVybiBhIHwgKGIgPDwgMTYpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGFkbGVyMzI7XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgY2FtZWxpemVcbiAqIEB0eXBlY2hlY2tzXG4gKi9cblxudmFyIF9oeXBoZW5QYXR0ZXJuID0gLy0oLikvZztcblxuLyoqXG4gKiBDYW1lbGNhc2VzIGEgaHlwaGVuYXRlZCBzdHJpbmcsIGZvciBleGFtcGxlOlxuICpcbiAqICAgPiBjYW1lbGl6ZSgnYmFja2dyb3VuZC1jb2xvcicpXG4gKiAgIDwgXCJiYWNrZ3JvdW5kQ29sb3JcIlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdHJpbmdcbiAqIEByZXR1cm4ge3N0cmluZ31cbiAqL1xuZnVuY3Rpb24gY2FtZWxpemUoc3RyaW5nKSB7XG4gIHJldHVybiBzdHJpbmcucmVwbGFjZShfaHlwaGVuUGF0dGVybiwgZnVuY3Rpb24oXywgY2hhcmFjdGVyKSB7XG4gICAgcmV0dXJuIGNoYXJhY3Rlci50b1VwcGVyQ2FzZSgpO1xuICB9KTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBjYW1lbGl6ZTtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgY2FtZWxpemVTdHlsZU5hbWVcbiAqIEB0eXBlY2hlY2tzXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBjYW1lbGl6ZSA9IHJlcXVpcmUoXCIuL2NhbWVsaXplXCIpO1xuXG52YXIgbXNQYXR0ZXJuID0gL14tbXMtLztcblxuLyoqXG4gKiBDYW1lbGNhc2VzIGEgaHlwaGVuYXRlZCBDU1MgcHJvcGVydHkgbmFtZSwgZm9yIGV4YW1wbGU6XG4gKlxuICogICA+IGNhbWVsaXplU3R5bGVOYW1lKCdiYWNrZ3JvdW5kLWNvbG9yJylcbiAqICAgPCBcImJhY2tncm91bmRDb2xvclwiXG4gKiAgID4gY2FtZWxpemVTdHlsZU5hbWUoJy1tb3otdHJhbnNpdGlvbicpXG4gKiAgIDwgXCJNb3pUcmFuc2l0aW9uXCJcbiAqICAgPiBjYW1lbGl6ZVN0eWxlTmFtZSgnLW1zLXRyYW5zaXRpb24nKVxuICogICA8IFwibXNUcmFuc2l0aW9uXCJcbiAqXG4gKiBBcyBBbmRpIFNtaXRoIHN1Z2dlc3RzXG4gKiAoaHR0cDovL3d3dy5hbmRpc21pdGguY29tL2Jsb2cvMjAxMi8wMi9tb2Rlcm5penItcHJlZml4ZWQvKSwgYW4gYC1tc2AgcHJlZml4XG4gKiBpcyBjb252ZXJ0ZWQgdG8gbG93ZXJjYXNlIGBtc2AuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHN0cmluZ1xuICogQHJldHVybiB7c3RyaW5nfVxuICovXG5mdW5jdGlvbiBjYW1lbGl6ZVN0eWxlTmFtZShzdHJpbmcpIHtcbiAgcmV0dXJuIGNhbWVsaXplKHN0cmluZy5yZXBsYWNlKG1zUGF0dGVybiwgJ21zLScpKTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBjYW1lbGl6ZVN0eWxlTmFtZTtcbiIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAdHlwZWNoZWNrc1xuICogQHByb3ZpZGVzTW9kdWxlIGNsb25lV2l0aFByb3BzXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBSZWFjdEVsZW1lbnQgPSByZXF1aXJlKFwiLi9SZWFjdEVsZW1lbnRcIik7XG52YXIgUmVhY3RQcm9wVHJhbnNmZXJlciA9IHJlcXVpcmUoXCIuL1JlYWN0UHJvcFRyYW5zZmVyZXJcIik7XG5cbnZhciBrZXlPZiA9IHJlcXVpcmUoXCIuL2tleU9mXCIpO1xudmFyIHdhcm5pbmcgPSByZXF1aXJlKFwiLi93YXJuaW5nXCIpO1xuXG52YXIgQ0hJTERSRU5fUFJPUCA9IGtleU9mKHtjaGlsZHJlbjogbnVsbH0pO1xuXG4vKipcbiAqIFNvbWV0aW1lcyB5b3Ugd2FudCB0byBjaGFuZ2UgdGhlIHByb3BzIG9mIGEgY2hpbGQgcGFzc2VkIHRvIHlvdS4gVXN1YWxseVxuICogdGhpcyBpcyB0byBhZGQgYSBDU1MgY2xhc3MuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IGNoaWxkIGNoaWxkIGNvbXBvbmVudCB5b3UnZCBsaWtlIHRvIGNsb25lXG4gKiBAcGFyYW0ge29iamVjdH0gcHJvcHMgcHJvcHMgeW91J2QgbGlrZSB0byBtb2RpZnkuIFRoZXkgd2lsbCBiZSBtZXJnZWRcbiAqIGFzIGlmIHlvdSB1c2VkIGB0cmFuc2ZlclByb3BzVG8oKWAuXG4gKiBAcmV0dXJuIHtvYmplY3R9IGEgY2xvbmUgb2YgY2hpbGQgd2l0aCBwcm9wcyBtZXJnZWQgaW4uXG4gKi9cbmZ1bmN0aW9uIGNsb25lV2l0aFByb3BzKGNoaWxkLCBwcm9wcykge1xuICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IHdhcm5pbmcoXG4gICAgICAhY2hpbGQucmVmLFxuICAgICAgJ1lvdSBhcmUgY2FsbGluZyBjbG9uZVdpdGhQcm9wcygpIG9uIGEgY2hpbGQgd2l0aCBhIHJlZi4gVGhpcyBpcyAnICtcbiAgICAgICdkYW5nZXJvdXMgYmVjYXVzZSB5b3VcXCdyZSBjcmVhdGluZyBhIG5ldyBjaGlsZCB3aGljaCB3aWxsIG5vdCBiZSAnICtcbiAgICAgICdhZGRlZCBhcyBhIHJlZiB0byBpdHMgcGFyZW50LidcbiAgICApIDogbnVsbCk7XG4gIH1cblxuICB2YXIgbmV3UHJvcHMgPSBSZWFjdFByb3BUcmFuc2ZlcmVyLm1lcmdlUHJvcHMocHJvcHMsIGNoaWxkLnByb3BzKTtcblxuICAvLyBVc2UgYGNoaWxkLnByb3BzLmNoaWxkcmVuYCBpZiBpdCBpcyBwcm92aWRlZC5cbiAgaWYgKCFuZXdQcm9wcy5oYXNPd25Qcm9wZXJ0eShDSElMRFJFTl9QUk9QKSAmJlxuICAgICAgY2hpbGQucHJvcHMuaGFzT3duUHJvcGVydHkoQ0hJTERSRU5fUFJPUCkpIHtcbiAgICBuZXdQcm9wcy5jaGlsZHJlbiA9IGNoaWxkLnByb3BzLmNoaWxkcmVuO1xuICB9XG5cbiAgLy8gVGhlIGN1cnJlbnQgQVBJIGRvZXNuJ3QgcmV0YWluIF9vd25lciBhbmQgX2NvbnRleHQsIHdoaWNoIGlzIHdoeSB0aGlzXG4gIC8vIGRvZXNuJ3QgdXNlIFJlYWN0RWxlbWVudC5jbG9uZUFuZFJlcGxhY2VQcm9wcy5cbiAgcmV0dXJuIFJlYWN0RWxlbWVudC5jcmVhdGVFbGVtZW50KGNoaWxkLnR5cGUsIG5ld1Byb3BzKTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBjbG9uZVdpdGhQcm9wcztcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGNvbnRhaW5zTm9kZVxuICogQHR5cGVjaGVja3NcbiAqL1xuXG52YXIgaXNUZXh0Tm9kZSA9IHJlcXVpcmUoXCIuL2lzVGV4dE5vZGVcIik7XG5cbi8qanNsaW50IGJpdHdpc2U6dHJ1ZSAqL1xuXG4vKipcbiAqIENoZWNrcyBpZiBhIGdpdmVuIERPTSBub2RlIGNvbnRhaW5zIG9yIGlzIGFub3RoZXIgRE9NIG5vZGUuXG4gKlxuICogQHBhcmFtIHs/RE9NTm9kZX0gb3V0ZXJOb2RlIE91dGVyIERPTSBub2RlLlxuICogQHBhcmFtIHs/RE9NTm9kZX0gaW5uZXJOb2RlIElubmVyIERPTSBub2RlLlxuICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiBgb3V0ZXJOb2RlYCBjb250YWlucyBvciBpcyBgaW5uZXJOb2RlYC5cbiAqL1xuZnVuY3Rpb24gY29udGFpbnNOb2RlKG91dGVyTm9kZSwgaW5uZXJOb2RlKSB7XG4gIGlmICghb3V0ZXJOb2RlIHx8ICFpbm5lck5vZGUpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH0gZWxzZSBpZiAob3V0ZXJOb2RlID09PSBpbm5lck5vZGUpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfSBlbHNlIGlmIChpc1RleHROb2RlKG91dGVyTm9kZSkpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH0gZWxzZSBpZiAoaXNUZXh0Tm9kZShpbm5lck5vZGUpKSB7XG4gICAgcmV0dXJuIGNvbnRhaW5zTm9kZShvdXRlck5vZGUsIGlubmVyTm9kZS5wYXJlbnROb2RlKTtcbiAgfSBlbHNlIGlmIChvdXRlck5vZGUuY29udGFpbnMpIHtcbiAgICByZXR1cm4gb3V0ZXJOb2RlLmNvbnRhaW5zKGlubmVyTm9kZSk7XG4gIH0gZWxzZSBpZiAob3V0ZXJOb2RlLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uKSB7XG4gICAgcmV0dXJuICEhKG91dGVyTm9kZS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbihpbm5lck5vZGUpICYgMTYpO1xuICB9IGVsc2Uge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGNvbnRhaW5zTm9kZTtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBjcmVhdGVBcnJheUZyb21cbiAqIEB0eXBlY2hlY2tzXG4gKi9cblxudmFyIHRvQXJyYXkgPSByZXF1aXJlKFwiLi90b0FycmF5XCIpO1xuXG4vKipcbiAqIFBlcmZvcm0gYSBoZXVyaXN0aWMgdGVzdCB0byBkZXRlcm1pbmUgaWYgYW4gb2JqZWN0IGlzIFwiYXJyYXktbGlrZVwiLlxuICpcbiAqICAgQSBtb25rIGFza2VkIEpvc2h1LCBhIFplbiBtYXN0ZXIsIFwiSGFzIGEgZG9nIEJ1ZGRoYSBuYXR1cmU/XCJcbiAqICAgSm9zaHUgcmVwbGllZDogXCJNdS5cIlxuICpcbiAqIFRoaXMgZnVuY3Rpb24gZGV0ZXJtaW5lcyBpZiBpdHMgYXJndW1lbnQgaGFzIFwiYXJyYXkgbmF0dXJlXCI6IGl0IHJldHVybnNcbiAqIHRydWUgaWYgdGhlIGFyZ3VtZW50IGlzIGFuIGFjdHVhbCBhcnJheSwgYW4gYGFyZ3VtZW50cycgb2JqZWN0LCBvciBhblxuICogSFRNTENvbGxlY3Rpb24gKGUuZy4gbm9kZS5jaGlsZE5vZGVzIG9yIG5vZGUuZ2V0RWxlbWVudHNCeVRhZ05hbWUoKSkuXG4gKlxuICogSXQgd2lsbCByZXR1cm4gZmFsc2UgZm9yIG90aGVyIGFycmF5LWxpa2Ugb2JqZWN0cyBsaWtlIEZpbGVsaXN0LlxuICpcbiAqIEBwYXJhbSB7Kn0gb2JqXG4gKiBAcmV0dXJuIHtib29sZWFufVxuICovXG5mdW5jdGlvbiBoYXNBcnJheU5hdHVyZShvYmopIHtcbiAgcmV0dXJuIChcbiAgICAvLyBub3QgbnVsbC9mYWxzZVxuICAgICEhb2JqICYmXG4gICAgLy8gYXJyYXlzIGFyZSBvYmplY3RzLCBOb2RlTGlzdHMgYXJlIGZ1bmN0aW9ucyBpbiBTYWZhcmlcbiAgICAodHlwZW9mIG9iaiA9PSAnb2JqZWN0JyB8fCB0eXBlb2Ygb2JqID09ICdmdW5jdGlvbicpICYmXG4gICAgLy8gcXVhY2tzIGxpa2UgYW4gYXJyYXlcbiAgICAoJ2xlbmd0aCcgaW4gb2JqKSAmJlxuICAgIC8vIG5vdCB3aW5kb3dcbiAgICAhKCdzZXRJbnRlcnZhbCcgaW4gb2JqKSAmJlxuICAgIC8vIG5vIERPTSBub2RlIHNob3VsZCBiZSBjb25zaWRlcmVkIGFuIGFycmF5LWxpa2VcbiAgICAvLyBhICdzZWxlY3QnIGVsZW1lbnQgaGFzICdsZW5ndGgnIGFuZCAnaXRlbScgcHJvcGVydGllcyBvbiBJRThcbiAgICAodHlwZW9mIG9iai5ub2RlVHlwZSAhPSAnbnVtYmVyJykgJiZcbiAgICAoXG4gICAgICAvLyBhIHJlYWwgYXJyYXlcbiAgICAgICgvLyBIVE1MQ29sbGVjdGlvbi9Ob2RlTGlzdFxuICAgICAgKEFycmF5LmlzQXJyYXkob2JqKSB8fFxuICAgICAgLy8gYXJndW1lbnRzXG4gICAgICAoJ2NhbGxlZScgaW4gb2JqKSB8fCAnaXRlbScgaW4gb2JqKSlcbiAgICApXG4gICk7XG59XG5cbi8qKlxuICogRW5zdXJlIHRoYXQgdGhlIGFyZ3VtZW50IGlzIGFuIGFycmF5IGJ5IHdyYXBwaW5nIGl0IGluIGFuIGFycmF5IGlmIGl0IGlzIG5vdC5cbiAqIENyZWF0ZXMgYSBjb3B5IG9mIHRoZSBhcmd1bWVudCBpZiBpdCBpcyBhbHJlYWR5IGFuIGFycmF5LlxuICpcbiAqIFRoaXMgaXMgbW9zdGx5IHVzZWZ1bCBpZGlvbWF0aWNhbGx5OlxuICpcbiAqICAgdmFyIGNyZWF0ZUFycmF5RnJvbSA9IHJlcXVpcmUoJ2NyZWF0ZUFycmF5RnJvbScpO1xuICpcbiAqICAgZnVuY3Rpb24gdGFrZXNPbmVPck1vcmVUaGluZ3ModGhpbmdzKSB7XG4gKiAgICAgdGhpbmdzID0gY3JlYXRlQXJyYXlGcm9tKHRoaW5ncyk7XG4gKiAgICAgLi4uXG4gKiAgIH1cbiAqXG4gKiBUaGlzIGFsbG93cyB5b3UgdG8gdHJlYXQgYHRoaW5ncycgYXMgYW4gYXJyYXksIGJ1dCBhY2NlcHQgc2NhbGFycyBpbiB0aGUgQVBJLlxuICpcbiAqIElmIHlvdSBuZWVkIHRvIGNvbnZlcnQgYW4gYXJyYXktbGlrZSBvYmplY3QsIGxpa2UgYGFyZ3VtZW50c2AsIGludG8gYW4gYXJyYXlcbiAqIHVzZSB0b0FycmF5IGluc3RlYWQuXG4gKlxuICogQHBhcmFtIHsqfSBvYmpcbiAqIEByZXR1cm4ge2FycmF5fVxuICovXG5mdW5jdGlvbiBjcmVhdGVBcnJheUZyb20ob2JqKSB7XG4gIGlmICghaGFzQXJyYXlOYXR1cmUob2JqKSkge1xuICAgIHJldHVybiBbb2JqXTtcbiAgfSBlbHNlIGlmIChBcnJheS5pc0FycmF5KG9iaikpIHtcbiAgICByZXR1cm4gb2JqLnNsaWNlKCk7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIHRvQXJyYXkob2JqKTtcbiAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGNyZWF0ZUFycmF5RnJvbTtcbiIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgY3JlYXRlRnVsbFBhZ2VDb21wb25lbnRcbiAqIEB0eXBlY2hlY2tzXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbi8vIERlZmVhdCBjaXJjdWxhciByZWZlcmVuY2VzIGJ5IHJlcXVpcmluZyB0aGlzIGRpcmVjdGx5LlxudmFyIFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50ID0gcmVxdWlyZShcIi4vUmVhY3RDb21wb3NpdGVDb21wb25lbnRcIik7XG52YXIgUmVhY3RFbGVtZW50ID0gcmVxdWlyZShcIi4vUmVhY3RFbGVtZW50XCIpO1xuXG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG4vKipcbiAqIENyZWF0ZSBhIGNvbXBvbmVudCB0aGF0IHdpbGwgdGhyb3cgYW4gZXhjZXB0aW9uIHdoZW4gdW5tb3VudGVkLlxuICpcbiAqIENvbXBvbmVudHMgbGlrZSA8aHRtbD4gPGhlYWQ+IGFuZCA8Ym9keT4gY2FuJ3QgYmUgcmVtb3ZlZCBvciBhZGRlZFxuICogZWFzaWx5IGluIGEgY3Jvc3MtYnJvd3NlciB3YXksIGhvd2V2ZXIgaXQncyB2YWx1YWJsZSB0byBiZSBhYmxlIHRvXG4gKiB0YWtlIGFkdmFudGFnZSBvZiBSZWFjdCdzIHJlY29uY2lsaWF0aW9uIGZvciBzdHlsaW5nIGFuZCA8dGl0bGU+XG4gKiBtYW5hZ2VtZW50LiBTbyB3ZSBqdXN0IGRvY3VtZW50IGl0IGFuZCB0aHJvdyBpbiBkYW5nZXJvdXMgY2FzZXMuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHRhZyBUaGUgdGFnIHRvIHdyYXBcbiAqIEByZXR1cm4ge2Z1bmN0aW9ufSBjb252ZW5pZW5jZSBjb25zdHJ1Y3RvciBvZiBuZXcgY29tcG9uZW50XG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZUZ1bGxQYWdlQ29tcG9uZW50KHRhZykge1xuICB2YXIgZWxlbWVudEZhY3RvcnkgPSBSZWFjdEVsZW1lbnQuY3JlYXRlRmFjdG9yeSh0YWcpO1xuXG4gIHZhciBGdWxsUGFnZUNvbXBvbmVudCA9IFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50LmNyZWF0ZUNsYXNzKHtcbiAgICBkaXNwbGF5TmFtZTogJ1JlYWN0RnVsbFBhZ2VDb21wb25lbnQnICsgdGFnLFxuXG4gICAgY29tcG9uZW50V2lsbFVubW91bnQ6IGZ1bmN0aW9uKCkge1xuICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgZmFsc2UsXG4gICAgICAgICclcyB0cmllZCB0byB1bm1vdW50LiBCZWNhdXNlIG9mIGNyb3NzLWJyb3dzZXIgcXVpcmtzIGl0IGlzICcgK1xuICAgICAgICAnaW1wb3NzaWJsZSB0byB1bm1vdW50IHNvbWUgdG9wLWxldmVsIGNvbXBvbmVudHMgKGVnIDxodG1sPiwgPGhlYWQ+LCAnICtcbiAgICAgICAgJ2FuZCA8Ym9keT4pIHJlbGlhYmx5IGFuZCBlZmZpY2llbnRseS4gVG8gZml4IHRoaXMsIGhhdmUgYSBzaW5nbGUgJyArXG4gICAgICAgICd0b3AtbGV2ZWwgY29tcG9uZW50IHRoYXQgbmV2ZXIgdW5tb3VudHMgcmVuZGVyIHRoZXNlIGVsZW1lbnRzLicsXG4gICAgICAgIHRoaXMuY29uc3RydWN0b3IuZGlzcGxheU5hbWVcbiAgICAgICkgOiBpbnZhcmlhbnQoZmFsc2UpKTtcbiAgICB9LFxuXG4gICAgcmVuZGVyOiBmdW5jdGlvbigpIHtcbiAgICAgIHJldHVybiBlbGVtZW50RmFjdG9yeSh0aGlzLnByb3BzKTtcbiAgICB9XG4gIH0pO1xuXG4gIHJldHVybiBGdWxsUGFnZUNvbXBvbmVudDtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBjcmVhdGVGdWxsUGFnZUNvbXBvbmVudDtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBjcmVhdGVOb2Rlc0Zyb21NYXJrdXBcbiAqIEB0eXBlY2hlY2tzXG4gKi9cblxuLypqc2xpbnQgZXZpbDogdHJ1ZSwgc3ViOiB0cnVlICovXG5cbnZhciBFeGVjdXRpb25FbnZpcm9ubWVudCA9IHJlcXVpcmUoXCIuL0V4ZWN1dGlvbkVudmlyb25tZW50XCIpO1xuXG52YXIgY3JlYXRlQXJyYXlGcm9tID0gcmVxdWlyZShcIi4vY3JlYXRlQXJyYXlGcm9tXCIpO1xudmFyIGdldE1hcmt1cFdyYXAgPSByZXF1aXJlKFwiLi9nZXRNYXJrdXBXcmFwXCIpO1xudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcblxuLyoqXG4gKiBEdW1teSBjb250YWluZXIgdXNlZCB0byByZW5kZXIgYWxsIG1hcmt1cC5cbiAqL1xudmFyIGR1bW15Tm9kZSA9XG4gIEV4ZWN1dGlvbkVudmlyb25tZW50LmNhblVzZURPTSA/IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpIDogbnVsbDtcblxuLyoqXG4gKiBQYXR0ZXJuIHVzZWQgYnkgYGdldE5vZGVOYW1lYC5cbiAqL1xudmFyIG5vZGVOYW1lUGF0dGVybiA9IC9eXFxzKjwoXFx3KykvO1xuXG4vKipcbiAqIEV4dHJhY3RzIHRoZSBgbm9kZU5hbWVgIG9mIHRoZSBmaXJzdCBlbGVtZW50IGluIGEgc3RyaW5nIG9mIG1hcmt1cC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gbWFya3VwIFN0cmluZyBvZiBtYXJrdXAuXG4gKiBAcmV0dXJuIHs/c3RyaW5nfSBOb2RlIG5hbWUgb2YgdGhlIHN1cHBsaWVkIG1hcmt1cC5cbiAqL1xuZnVuY3Rpb24gZ2V0Tm9kZU5hbWUobWFya3VwKSB7XG4gIHZhciBub2RlTmFtZU1hdGNoID0gbWFya3VwLm1hdGNoKG5vZGVOYW1lUGF0dGVybik7XG4gIHJldHVybiBub2RlTmFtZU1hdGNoICYmIG5vZGVOYW1lTWF0Y2hbMV0udG9Mb3dlckNhc2UoKTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGFuIGFycmF5IGNvbnRhaW5pbmcgdGhlIG5vZGVzIHJlbmRlcmVkIGZyb20gdGhlIHN1cHBsaWVkIG1hcmt1cC4gVGhlXG4gKiBvcHRpb25hbGx5IHN1cHBsaWVkIGBoYW5kbGVTY3JpcHRgIGZ1bmN0aW9uIHdpbGwgYmUgaW52b2tlZCBvbmNlIGZvciBlYWNoXG4gKiA8c2NyaXB0PiBlbGVtZW50IHRoYXQgaXMgcmVuZGVyZWQuIElmIG5vIGBoYW5kbGVTY3JpcHRgIGZ1bmN0aW9uIGlzIHN1cHBsaWVkLFxuICogYW4gZXhjZXB0aW9uIGlzIHRocm93biBpZiBhbnkgPHNjcmlwdD4gZWxlbWVudHMgYXJlIHJlbmRlcmVkLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBtYXJrdXAgQSBzdHJpbmcgb2YgdmFsaWQgSFRNTCBtYXJrdXAuXG4gKiBAcGFyYW0gez9mdW5jdGlvbn0gaGFuZGxlU2NyaXB0IEludm9rZWQgb25jZSBmb3IgZWFjaCByZW5kZXJlZCA8c2NyaXB0Pi5cbiAqIEByZXR1cm4ge2FycmF5PERPTUVsZW1lbnR8RE9NVGV4dE5vZGU+fSBBbiBhcnJheSBvZiByZW5kZXJlZCBub2Rlcy5cbiAqL1xuZnVuY3Rpb24gY3JlYXRlTm9kZXNGcm9tTWFya3VwKG1hcmt1cCwgaGFuZGxlU2NyaXB0KSB7XG4gIHZhciBub2RlID0gZHVtbXlOb2RlO1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KCEhZHVtbXlOb2RlLCAnY3JlYXRlTm9kZXNGcm9tTWFya3VwIGR1bW15IG5vdCBpbml0aWFsaXplZCcpIDogaW52YXJpYW50KCEhZHVtbXlOb2RlKSk7XG4gIHZhciBub2RlTmFtZSA9IGdldE5vZGVOYW1lKG1hcmt1cCk7XG5cbiAgdmFyIHdyYXAgPSBub2RlTmFtZSAmJiBnZXRNYXJrdXBXcmFwKG5vZGVOYW1lKTtcbiAgaWYgKHdyYXApIHtcbiAgICBub2RlLmlubmVySFRNTCA9IHdyYXBbMV0gKyBtYXJrdXAgKyB3cmFwWzJdO1xuXG4gICAgdmFyIHdyYXBEZXB0aCA9IHdyYXBbMF07XG4gICAgd2hpbGUgKHdyYXBEZXB0aC0tKSB7XG4gICAgICBub2RlID0gbm9kZS5sYXN0Q2hpbGQ7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIG5vZGUuaW5uZXJIVE1MID0gbWFya3VwO1xuICB9XG5cbiAgdmFyIHNjcmlwdHMgPSBub2RlLmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzY3JpcHQnKTtcbiAgaWYgKHNjcmlwdHMubGVuZ3RoKSB7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgIGhhbmRsZVNjcmlwdCxcbiAgICAgICdjcmVhdGVOb2Rlc0Zyb21NYXJrdXAoLi4uKTogVW5leHBlY3RlZCA8c2NyaXB0PiBlbGVtZW50IHJlbmRlcmVkLidcbiAgICApIDogaW52YXJpYW50KGhhbmRsZVNjcmlwdCkpO1xuICAgIGNyZWF0ZUFycmF5RnJvbShzY3JpcHRzKS5mb3JFYWNoKGhhbmRsZVNjcmlwdCk7XG4gIH1cblxuICB2YXIgbm9kZXMgPSBjcmVhdGVBcnJheUZyb20obm9kZS5jaGlsZE5vZGVzKTtcbiAgd2hpbGUgKG5vZGUubGFzdENoaWxkKSB7XG4gICAgbm9kZS5yZW1vdmVDaGlsZChub2RlLmxhc3RDaGlsZCk7XG4gIH1cbiAgcmV0dXJuIG5vZGVzO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGNyZWF0ZU5vZGVzRnJvbU1hcmt1cDtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGN4XG4gKi9cblxuLyoqXG4gKiBUaGlzIGZ1bmN0aW9uIGlzIHVzZWQgdG8gbWFyayBzdHJpbmcgbGl0ZXJhbHMgcmVwcmVzZW50aW5nIENTUyBjbGFzcyBuYW1lc1xuICogc28gdGhhdCB0aGV5IGNhbiBiZSB0cmFuc2Zvcm1lZCBzdGF0aWNhbGx5LiBUaGlzIGFsbG93cyBmb3IgbW9kdWxhcml6YXRpb25cbiAqIGFuZCBtaW5pZmljYXRpb24gb2YgQ1NTIGNsYXNzIG5hbWVzLlxuICpcbiAqIEluIHN0YXRpY191cHN0cmVhbSwgdGhpcyBmdW5jdGlvbiBpcyBhY3R1YWxseSBpbXBsZW1lbnRlZCwgYnV0IGl0IHNob3VsZFxuICogZXZlbnR1YWxseSBiZSByZXBsYWNlZCB3aXRoIHNvbWV0aGluZyBtb3JlIGRlc2NyaXB0aXZlLCBhbmQgdGhlIHRyYW5zZm9ybVxuICogdGhhdCBpcyB1c2VkIGluIHRoZSBtYWluIHN0YWNrIHNob3VsZCBiZSBwb3J0ZWQgZm9yIHVzZSBlbHNld2hlcmUuXG4gKlxuICogQHBhcmFtIHN0cmluZ3xvYmplY3QgY2xhc3NOYW1lIHRvIG1vZHVsYXJpemUsIG9yIGFuIG9iamVjdCBvZiBrZXkvdmFsdWVzLlxuICogICAgICAgICAgICAgICAgICAgICAgSW4gdGhlIG9iamVjdCBjYXNlLCB0aGUgdmFsdWVzIGFyZSBjb25kaXRpb25zIHRoYXRcbiAqICAgICAgICAgICAgICAgICAgICAgIGRldGVybWluZSBpZiB0aGUgY2xhc3NOYW1lIGtleXMgc2hvdWxkIGJlIGluY2x1ZGVkLlxuICogQHBhcmFtIFtzdHJpbmcgLi4uXSAgVmFyaWFibGUgbGlzdCBvZiBjbGFzc05hbWVzIGluIHRoZSBzdHJpbmcgY2FzZS5cbiAqIEByZXR1cm4gc3RyaW5nICAgICAgIFJlbmRlcmFibGUgc3BhY2Utc2VwYXJhdGVkIENTUyBjbGFzc05hbWUuXG4gKi9cbmZ1bmN0aW9uIGN4KGNsYXNzTmFtZXMpIHtcbiAgaWYgKHR5cGVvZiBjbGFzc05hbWVzID09ICdvYmplY3QnKSB7XG4gICAgcmV0dXJuIE9iamVjdC5rZXlzKGNsYXNzTmFtZXMpLmZpbHRlcihmdW5jdGlvbihjbGFzc05hbWUpIHtcbiAgICAgIHJldHVybiBjbGFzc05hbWVzW2NsYXNzTmFtZV07XG4gICAgfSkuam9pbignICcpO1xuICB9IGVsc2Uge1xuICAgIHJldHVybiBBcnJheS5wcm90b3R5cGUuam9pbi5jYWxsKGFyZ3VtZW50cywgJyAnKTtcbiAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGN4O1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGRhbmdlcm91c1N0eWxlVmFsdWVcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBDU1NQcm9wZXJ0eSA9IHJlcXVpcmUoXCIuL0NTU1Byb3BlcnR5XCIpO1xuXG52YXIgaXNVbml0bGVzc051bWJlciA9IENTU1Byb3BlcnR5LmlzVW5pdGxlc3NOdW1iZXI7XG5cbi8qKlxuICogQ29udmVydCBhIHZhbHVlIGludG8gdGhlIHByb3BlciBjc3Mgd3JpdGFibGUgdmFsdWUuIFRoZSBzdHlsZSBuYW1lIGBuYW1lYFxuICogc2hvdWxkIGJlIGxvZ2ljYWwgKG5vIGh5cGhlbnMpLCBhcyBzcGVjaWZpZWRcbiAqIGluIGBDU1NQcm9wZXJ0eS5pc1VuaXRsZXNzTnVtYmVyYC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gbmFtZSBDU1MgcHJvcGVydHkgbmFtZSBzdWNoIGFzIGB0b3BNYXJnaW5gLlxuICogQHBhcmFtIHsqfSB2YWx1ZSBDU1MgcHJvcGVydHkgdmFsdWUgc3VjaCBhcyBgMTBweGAuXG4gKiBAcmV0dXJuIHtzdHJpbmd9IE5vcm1hbGl6ZWQgc3R5bGUgdmFsdWUgd2l0aCBkaW1lbnNpb25zIGFwcGxpZWQuXG4gKi9cbmZ1bmN0aW9uIGRhbmdlcm91c1N0eWxlVmFsdWUobmFtZSwgdmFsdWUpIHtcbiAgLy8gTm90ZSB0aGF0IHdlJ3ZlIHJlbW92ZWQgZXNjYXBlVGV4dEZvckJyb3dzZXIoKSBjYWxscyBoZXJlIHNpbmNlIHRoZVxuICAvLyB3aG9sZSBzdHJpbmcgd2lsbCBiZSBlc2NhcGVkIHdoZW4gdGhlIGF0dHJpYnV0ZSBpcyBpbmplY3RlZCBpbnRvXG4gIC8vIHRoZSBtYXJrdXAuIElmIHlvdSBwcm92aWRlIHVuc2FmZSB1c2VyIGRhdGEgaGVyZSB0aGV5IGNhbiBpbmplY3RcbiAgLy8gYXJiaXRyYXJ5IENTUyB3aGljaCBtYXkgYmUgcHJvYmxlbWF0aWMgKEkgY291bGRuJ3QgcmVwcm8gdGhpcyk6XG4gIC8vIGh0dHBzOi8vd3d3Lm93YXNwLm9yZy9pbmRleC5waHAvWFNTX0ZpbHRlcl9FdmFzaW9uX0NoZWF0X1NoZWV0XG4gIC8vIGh0dHA6Ly93d3cudGhlc3Bhbm5lci5jby51ay8yMDA3LzExLzI2L3VsdGltYXRlLXhzcy1jc3MtaW5qZWN0aW9uL1xuICAvLyBUaGlzIGlzIG5vdCBhbiBYU1MgaG9sZSBidXQgaW5zdGVhZCBhIHBvdGVudGlhbCBDU1MgaW5qZWN0aW9uIGlzc3VlXG4gIC8vIHdoaWNoIGhhcyBsZWFkIHRvIGEgZ3JlYXRlciBkaXNjdXNzaW9uIGFib3V0IGhvdyB3ZSdyZSBnb2luZyB0b1xuICAvLyB0cnVzdCBVUkxzIG1vdmluZyBmb3J3YXJkLiBTZWUgIzIxMTU5MDFcblxuICB2YXIgaXNFbXB0eSA9IHZhbHVlID09IG51bGwgfHwgdHlwZW9mIHZhbHVlID09PSAnYm9vbGVhbicgfHwgdmFsdWUgPT09ICcnO1xuICBpZiAoaXNFbXB0eSkge1xuICAgIHJldHVybiAnJztcbiAgfVxuXG4gIHZhciBpc05vbk51bWVyaWMgPSBpc05hTih2YWx1ZSk7XG4gIGlmIChpc05vbk51bWVyaWMgfHwgdmFsdWUgPT09IDAgfHxcbiAgICAgIGlzVW5pdGxlc3NOdW1iZXIuaGFzT3duUHJvcGVydHkobmFtZSkgJiYgaXNVbml0bGVzc051bWJlcltuYW1lXSkge1xuICAgIHJldHVybiAnJyArIHZhbHVlOyAvLyBjYXN0IHRvIHN0cmluZ1xuICB9XG5cbiAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycpIHtcbiAgICB2YWx1ZSA9IHZhbHVlLnRyaW0oKTtcbiAgfVxuICByZXR1cm4gdmFsdWUgKyAncHgnO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGRhbmdlcm91c1N0eWxlVmFsdWU7XG4iLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGRlcHJlY2F0ZWRcbiAqL1xuXG52YXIgYXNzaWduID0gcmVxdWlyZShcIi4vT2JqZWN0LmFzc2lnblwiKTtcbnZhciB3YXJuaW5nID0gcmVxdWlyZShcIi4vd2FybmluZ1wiKTtcblxuLyoqXG4gKiBUaGlzIHdpbGwgbG9nIGEgc2luZ2xlIGRlcHJlY2F0aW9uIG5vdGljZSBwZXIgZnVuY3Rpb24gYW5kIGZvcndhcmQgdGhlIGNhbGxcbiAqIG9uIHRvIHRoZSBuZXcgQVBJLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lc3BhY2UgVGhlIG5hbWVzcGFjZSBvZiB0aGUgY2FsbCwgZWcgJ1JlYWN0J1xuICogQHBhcmFtIHtzdHJpbmd9IG9sZE5hbWUgVGhlIG9sZCBmdW5jdGlvbiBuYW1lLCBlZyAncmVuZGVyQ29tcG9uZW50J1xuICogQHBhcmFtIHtzdHJpbmd9IG5ld05hbWUgVGhlIG5ldyBmdW5jdGlvbiBuYW1lLCBlZyAncmVuZGVyJ1xuICogQHBhcmFtIHsqfSBjdHggVGhlIGNvbnRleHQgdGhpcyBmb3J3YXJkZWQgY2FsbCBzaG91bGQgcnVuIGluXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBmbiBUaGUgZnVuY3Rpb24gdG8gZm9yd2FyZCBvbiB0b1xuICogQHJldHVybiB7Kn0gV2lsbCBiZSB0aGUgdmFsdWUgYXMgcmV0dXJuZWQgZnJvbSBgZm5gXG4gKi9cbmZ1bmN0aW9uIGRlcHJlY2F0ZWQobmFtZXNwYWNlLCBvbGROYW1lLCBuZXdOYW1lLCBjdHgsIGZuKSB7XG4gIHZhciB3YXJuZWQgPSBmYWxzZTtcbiAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgIHZhciBuZXdGbiA9IGZ1bmN0aW9uKCkge1xuICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IHdhcm5pbmcoXG4gICAgICAgIHdhcm5lZCxcbiAgICAgICAgKG5hbWVzcGFjZSArIFwiLlwiICsgb2xkTmFtZSArIFwiIHdpbGwgYmUgZGVwcmVjYXRlZCBpbiBhIGZ1dHVyZSB2ZXJzaW9uLiBcIikgK1xuICAgICAgICAoXCJVc2UgXCIgKyBuYW1lc3BhY2UgKyBcIi5cIiArIG5ld05hbWUgKyBcIiBpbnN0ZWFkLlwiKVxuICAgICAgKSA6IG51bGwpO1xuICAgICAgd2FybmVkID0gdHJ1ZTtcbiAgICAgIHJldHVybiBmbi5hcHBseShjdHgsIGFyZ3VtZW50cyk7XG4gICAgfTtcbiAgICBuZXdGbi5kaXNwbGF5TmFtZSA9IChuYW1lc3BhY2UgKyBcIl9cIiArIG9sZE5hbWUpO1xuICAgIC8vIFdlIG5lZWQgdG8gbWFrZSBzdXJlIGFsbCBwcm9wZXJ0aWVzIG9mIHRoZSBvcmlnaW5hbCBmbiBhcmUgY29waWVkIG92ZXIuXG4gICAgLy8gSW4gcGFydGljdWxhciwgdGhpcyBpcyBuZWVkZWQgdG8gc3VwcG9ydCBQcm9wVHlwZXNcbiAgICByZXR1cm4gYXNzaWduKG5ld0ZuLCBmbik7XG4gIH1cblxuICByZXR1cm4gZm47XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZGVwcmVjYXRlZDtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGVtcHR5RnVuY3Rpb25cbiAqL1xuXG5mdW5jdGlvbiBtYWtlRW1wdHlGdW5jdGlvbihhcmcpIHtcbiAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiBhcmc7XG4gIH07XG59XG5cbi8qKlxuICogVGhpcyBmdW5jdGlvbiBhY2NlcHRzIGFuZCBkaXNjYXJkcyBpbnB1dHM7IGl0IGhhcyBubyBzaWRlIGVmZmVjdHMuIFRoaXMgaXNcbiAqIHByaW1hcmlseSB1c2VmdWwgaWRpb21hdGljYWxseSBmb3Igb3ZlcnJpZGFibGUgZnVuY3Rpb24gZW5kcG9pbnRzIHdoaWNoXG4gKiBhbHdheXMgbmVlZCB0byBiZSBjYWxsYWJsZSwgc2luY2UgSlMgbGFja3MgYSBudWxsLWNhbGwgaWRpb20gYWxhIENvY29hLlxuICovXG5mdW5jdGlvbiBlbXB0eUZ1bmN0aW9uKCkge31cblxuZW1wdHlGdW5jdGlvbi50aGF0UmV0dXJucyA9IG1ha2VFbXB0eUZ1bmN0aW9uO1xuZW1wdHlGdW5jdGlvbi50aGF0UmV0dXJuc0ZhbHNlID0gbWFrZUVtcHR5RnVuY3Rpb24oZmFsc2UpO1xuZW1wdHlGdW5jdGlvbi50aGF0UmV0dXJuc1RydWUgPSBtYWtlRW1wdHlGdW5jdGlvbih0cnVlKTtcbmVtcHR5RnVuY3Rpb24udGhhdFJldHVybnNOdWxsID0gbWFrZUVtcHR5RnVuY3Rpb24obnVsbCk7XG5lbXB0eUZ1bmN0aW9uLnRoYXRSZXR1cm5zVGhpcyA9IGZ1bmN0aW9uKCkgeyByZXR1cm4gdGhpczsgfTtcbmVtcHR5RnVuY3Rpb24udGhhdFJldHVybnNBcmd1bWVudCA9IGZ1bmN0aW9uKGFyZykgeyByZXR1cm4gYXJnOyB9O1xuXG5tb2R1bGUuZXhwb3J0cyA9IGVtcHR5RnVuY3Rpb247XG4iLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGVtcHR5T2JqZWN0XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBlbXB0eU9iamVjdCA9IHt9O1xuXG5pZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gIE9iamVjdC5mcmVlemUoZW1wdHlPYmplY3QpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGVtcHR5T2JqZWN0O1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgZXNjYXBlVGV4dEZvckJyb3dzZXJcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBFU0NBUEVfTE9PS1VQID0ge1xuICBcIiZcIjogXCImYW1wO1wiLFxuICBcIj5cIjogXCImZ3Q7XCIsXG4gIFwiPFwiOiBcIiZsdDtcIixcbiAgXCJcXFwiXCI6IFwiJnF1b3Q7XCIsXG4gIFwiJ1wiOiBcIiYjeDI3O1wiXG59O1xuXG52YXIgRVNDQVBFX1JFR0VYID0gL1smPjxcIiddL2c7XG5cbmZ1bmN0aW9uIGVzY2FwZXIobWF0Y2gpIHtcbiAgcmV0dXJuIEVTQ0FQRV9MT09LVVBbbWF0Y2hdO1xufVxuXG4vKipcbiAqIEVzY2FwZXMgdGV4dCB0byBwcmV2ZW50IHNjcmlwdGluZyBhdHRhY2tzLlxuICpcbiAqIEBwYXJhbSB7Kn0gdGV4dCBUZXh0IHZhbHVlIHRvIGVzY2FwZS5cbiAqIEByZXR1cm4ge3N0cmluZ30gQW4gZXNjYXBlZCBzdHJpbmcuXG4gKi9cbmZ1bmN0aW9uIGVzY2FwZVRleHRGb3JCcm93c2VyKHRleHQpIHtcbiAgcmV0dXJuICgnJyArIHRleHQpLnJlcGxhY2UoRVNDQVBFX1JFR0VYLCBlc2NhcGVyKTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBlc2NhcGVUZXh0Rm9yQnJvd3NlcjtcbiIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgZmxhdHRlbkNoaWxkcmVuXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBSZWFjdFRleHRDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdFRleHRDb21wb25lbnRcIik7XG5cbnZhciB0cmF2ZXJzZUFsbENoaWxkcmVuID0gcmVxdWlyZShcIi4vdHJhdmVyc2VBbGxDaGlsZHJlblwiKTtcbnZhciB3YXJuaW5nID0gcmVxdWlyZShcIi4vd2FybmluZ1wiKTtcblxuLyoqXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSB0cmF2ZXJzZUNvbnRleHQgQ29udGV4dCBwYXNzZWQgdGhyb3VnaCB0cmF2ZXJzYWwuXG4gKiBAcGFyYW0gez9SZWFjdENvbXBvbmVudH0gY2hpbGQgUmVhY3QgY2hpbGQgY29tcG9uZW50LlxuICogQHBhcmFtIHshc3RyaW5nfSBuYW1lIFN0cmluZyBuYW1lIG9mIGtleSBwYXRoIHRvIGNoaWxkLlxuICovXG5mdW5jdGlvbiBmbGF0dGVuU2luZ2xlQ2hpbGRJbnRvQ29udGV4dCh0cmF2ZXJzZUNvbnRleHQsIGNoaWxkLCBuYW1lKSB7XG4gIC8vIFdlIGZvdW5kIGEgY29tcG9uZW50IGluc3RhbmNlLlxuICB2YXIgcmVzdWx0ID0gdHJhdmVyc2VDb250ZXh0O1xuICB2YXIga2V5VW5pcXVlID0gIXJlc3VsdC5oYXNPd25Qcm9wZXJ0eShuYW1lKTtcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IHdhcm5pbmcoXG4gICAga2V5VW5pcXVlLFxuICAgICdmbGF0dGVuQ2hpbGRyZW4oLi4uKTogRW5jb3VudGVyZWQgdHdvIGNoaWxkcmVuIHdpdGggdGhlIHNhbWUga2V5LCAnICtcbiAgICAnYCVzYC4gQ2hpbGQga2V5cyBtdXN0IGJlIHVuaXF1ZTsgd2hlbiB0d28gY2hpbGRyZW4gc2hhcmUgYSBrZXksIG9ubHkgJyArXG4gICAgJ3RoZSBmaXJzdCBjaGlsZCB3aWxsIGJlIHVzZWQuJyxcbiAgICBuYW1lXG4gICkgOiBudWxsKTtcbiAgaWYgKGtleVVuaXF1ZSAmJiBjaGlsZCAhPSBudWxsKSB7XG4gICAgdmFyIHR5cGUgPSB0eXBlb2YgY2hpbGQ7XG4gICAgdmFyIG5vcm1hbGl6ZWRWYWx1ZTtcblxuICAgIGlmICh0eXBlID09PSAnc3RyaW5nJykge1xuICAgICAgbm9ybWFsaXplZFZhbHVlID0gUmVhY3RUZXh0Q29tcG9uZW50KGNoaWxkKTtcbiAgICB9IGVsc2UgaWYgKHR5cGUgPT09ICdudW1iZXInKSB7XG4gICAgICBub3JtYWxpemVkVmFsdWUgPSBSZWFjdFRleHRDb21wb25lbnQoJycgKyBjaGlsZCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIG5vcm1hbGl6ZWRWYWx1ZSA9IGNoaWxkO1xuICAgIH1cblxuICAgIHJlc3VsdFtuYW1lXSA9IG5vcm1hbGl6ZWRWYWx1ZTtcbiAgfVxufVxuXG4vKipcbiAqIEZsYXR0ZW5zIGNoaWxkcmVuIHRoYXQgYXJlIHR5cGljYWxseSBzcGVjaWZpZWQgYXMgYHByb3BzLmNoaWxkcmVuYC4gQW55IG51bGxcbiAqIGNoaWxkcmVuIHdpbGwgbm90IGJlIGluY2x1ZGVkIGluIHRoZSByZXN1bHRpbmcgb2JqZWN0LlxuICogQHJldHVybiB7IW9iamVjdH0gZmxhdHRlbmVkIGNoaWxkcmVuIGtleWVkIGJ5IG5hbWUuXG4gKi9cbmZ1bmN0aW9uIGZsYXR0ZW5DaGlsZHJlbihjaGlsZHJlbikge1xuICBpZiAoY2hpbGRyZW4gPT0gbnVsbCkge1xuICAgIHJldHVybiBjaGlsZHJlbjtcbiAgfVxuICB2YXIgcmVzdWx0ID0ge307XG4gIHRyYXZlcnNlQWxsQ2hpbGRyZW4oY2hpbGRyZW4sIGZsYXR0ZW5TaW5nbGVDaGlsZEludG9Db250ZXh0LCByZXN1bHQpO1xuICByZXR1cm4gcmVzdWx0O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGZsYXR0ZW5DaGlsZHJlbjtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBmb2N1c05vZGVcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxuLyoqXG4gKiBAcGFyYW0ge0RPTUVsZW1lbnR9IG5vZGUgaW5wdXQvdGV4dGFyZWEgdG8gZm9jdXNcbiAqL1xuZnVuY3Rpb24gZm9jdXNOb2RlKG5vZGUpIHtcbiAgLy8gSUU4IGNhbiB0aHJvdyBcIkNhbid0IG1vdmUgZm9jdXMgdG8gdGhlIGNvbnRyb2wgYmVjYXVzZSBpdCBpcyBpbnZpc2libGUsXG4gIC8vIG5vdCBlbmFibGVkLCBvciBvZiBhIHR5cGUgdGhhdCBkb2VzIG5vdCBhY2NlcHQgdGhlIGZvY3VzLlwiIGZvciBhbGwga2luZHMgb2ZcbiAgLy8gcmVhc29ucyB0aGF0IGFyZSB0b28gZXhwZW5zaXZlIGFuZCBmcmFnaWxlIHRvIHRlc3QuXG4gIHRyeSB7XG4gICAgbm9kZS5mb2N1cygpO1xuICB9IGNhdGNoKGUpIHtcbiAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGZvY3VzTm9kZTtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBmb3JFYWNoQWNjdW11bGF0ZWRcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxuLyoqXG4gKiBAcGFyYW0ge2FycmF5fSBhbiBcImFjY3VtdWxhdGlvblwiIG9mIGl0ZW1zIHdoaWNoIGlzIGVpdGhlciBhbiBBcnJheSBvclxuICogYSBzaW5nbGUgaXRlbS4gVXNlZnVsIHdoZW4gcGFpcmVkIHdpdGggdGhlIGBhY2N1bXVsYXRlYCBtb2R1bGUuIFRoaXMgaXMgYVxuICogc2ltcGxlIHV0aWxpdHkgdGhhdCBhbGxvd3MgdXMgdG8gcmVhc29uIGFib3V0IGEgY29sbGVjdGlvbiBvZiBpdGVtcywgYnV0XG4gKiBoYW5kbGluZyB0aGUgY2FzZSB3aGVuIHRoZXJlIGlzIGV4YWN0bHkgb25lIGl0ZW0gKGFuZCB3ZSBkbyBub3QgbmVlZCB0b1xuICogYWxsb2NhdGUgYW4gYXJyYXkpLlxuICovXG52YXIgZm9yRWFjaEFjY3VtdWxhdGVkID0gZnVuY3Rpb24oYXJyLCBjYiwgc2NvcGUpIHtcbiAgaWYgKEFycmF5LmlzQXJyYXkoYXJyKSkge1xuICAgIGFyci5mb3JFYWNoKGNiLCBzY29wZSk7XG4gIH0gZWxzZSBpZiAoYXJyKSB7XG4gICAgY2IuY2FsbChzY29wZSwgYXJyKTtcbiAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBmb3JFYWNoQWNjdW11bGF0ZWQ7XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgZ2V0QWN0aXZlRWxlbWVudFxuICogQHR5cGVjaGVja3NcbiAqL1xuXG4vKipcbiAqIFNhbWUgYXMgZG9jdW1lbnQuYWN0aXZlRWxlbWVudCBidXQgd3JhcHMgaW4gYSB0cnktY2F0Y2ggYmxvY2suIEluIElFIGl0IGlzXG4gKiBub3Qgc2FmZSB0byBjYWxsIGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQgaWYgdGhlcmUgaXMgbm90aGluZyBmb2N1c2VkLlxuICpcbiAqIFRoZSBhY3RpdmVFbGVtZW50IHdpbGwgYmUgbnVsbCBvbmx5IGlmIHRoZSBkb2N1bWVudCBib2R5IGlzIG5vdCB5ZXQgZGVmaW5lZC5cbiAqL1xuZnVuY3Rpb24gZ2V0QWN0aXZlRWxlbWVudCgpIC8qP0RPTUVsZW1lbnQqLyB7XG4gIHRyeSB7XG4gICAgcmV0dXJuIGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQgfHwgZG9jdW1lbnQuYm9keTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIHJldHVybiBkb2N1bWVudC5ib2R5O1xuICB9XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZ2V0QWN0aXZlRWxlbWVudDtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBnZXRFdmVudENoYXJDb2RlXG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG4vKipcbiAqIGBjaGFyQ29kZWAgcmVwcmVzZW50cyB0aGUgYWN0dWFsIFwiY2hhcmFjdGVyIGNvZGVcIiBhbmQgaXMgc2FmZSB0byB1c2Ugd2l0aFxuICogYFN0cmluZy5mcm9tQ2hhckNvZGVgLiBBcyBzdWNoLCBvbmx5IGtleXMgdGhhdCBjb3JyZXNwb25kIHRvIHByaW50YWJsZVxuICogY2hhcmFjdGVycyBwcm9kdWNlIGEgdmFsaWQgYGNoYXJDb2RlYCwgdGhlIG9ubHkgZXhjZXB0aW9uIHRvIHRoaXMgaXMgRW50ZXIuXG4gKiBUaGUgVGFiLWtleSBpcyBjb25zaWRlcmVkIG5vbi1wcmludGFibGUgYW5kIGRvZXMgbm90IGhhdmUgYSBgY2hhckNvZGVgLFxuICogcHJlc3VtYWJseSBiZWNhdXNlIGl0IGRvZXMgbm90IHByb2R1Y2UgYSB0YWItY2hhcmFjdGVyIGluIGJyb3dzZXJzLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudCBOYXRpdmUgYnJvd3NlciBldmVudC5cbiAqIEByZXR1cm4ge3N0cmluZ30gTm9ybWFsaXplZCBgY2hhckNvZGVgIHByb3BlcnR5LlxuICovXG5mdW5jdGlvbiBnZXRFdmVudENoYXJDb2RlKG5hdGl2ZUV2ZW50KSB7XG4gIHZhciBjaGFyQ29kZTtcbiAgdmFyIGtleUNvZGUgPSBuYXRpdmVFdmVudC5rZXlDb2RlO1xuXG4gIGlmICgnY2hhckNvZGUnIGluIG5hdGl2ZUV2ZW50KSB7XG4gICAgY2hhckNvZGUgPSBuYXRpdmVFdmVudC5jaGFyQ29kZTtcblxuICAgIC8vIEZGIGRvZXMgbm90IHNldCBgY2hhckNvZGVgIGZvciB0aGUgRW50ZXIta2V5LCBjaGVjayBhZ2FpbnN0IGBrZXlDb2RlYC5cbiAgICBpZiAoY2hhckNvZGUgPT09IDAgJiYga2V5Q29kZSA9PT0gMTMpIHtcbiAgICAgIGNoYXJDb2RlID0gMTM7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIC8vIElFOCBkb2VzIG5vdCBpbXBsZW1lbnQgYGNoYXJDb2RlYCwgYnV0IGBrZXlDb2RlYCBoYXMgdGhlIGNvcnJlY3QgdmFsdWUuXG4gICAgY2hhckNvZGUgPSBrZXlDb2RlO1xuICB9XG5cbiAgLy8gU29tZSBub24tcHJpbnRhYmxlIGtleXMgYXJlIHJlcG9ydGVkIGluIGBjaGFyQ29kZWAvYGtleUNvZGVgLCBkaXNjYXJkIHRoZW0uXG4gIC8vIE11c3Qgbm90IGRpc2NhcmQgdGhlIChub24tKXByaW50YWJsZSBFbnRlci1rZXkuXG4gIGlmIChjaGFyQ29kZSA+PSAzMiB8fCBjaGFyQ29kZSA9PT0gMTMpIHtcbiAgICByZXR1cm4gY2hhckNvZGU7XG4gIH1cblxuICByZXR1cm4gMDtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBnZXRFdmVudENoYXJDb2RlO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGdldEV2ZW50S2V5XG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgZ2V0RXZlbnRDaGFyQ29kZSA9IHJlcXVpcmUoXCIuL2dldEV2ZW50Q2hhckNvZGVcIik7XG5cbi8qKlxuICogTm9ybWFsaXphdGlvbiBvZiBkZXByZWNhdGVkIEhUTUw1IGBrZXlgIHZhbHVlc1xuICogQHNlZSBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9BUEkvS2V5Ym9hcmRFdmVudCNLZXlfbmFtZXNcbiAqL1xudmFyIG5vcm1hbGl6ZUtleSA9IHtcbiAgJ0VzYyc6ICdFc2NhcGUnLFxuICAnU3BhY2ViYXInOiAnICcsXG4gICdMZWZ0JzogJ0Fycm93TGVmdCcsXG4gICdVcCc6ICdBcnJvd1VwJyxcbiAgJ1JpZ2h0JzogJ0Fycm93UmlnaHQnLFxuICAnRG93bic6ICdBcnJvd0Rvd24nLFxuICAnRGVsJzogJ0RlbGV0ZScsXG4gICdXaW4nOiAnT1MnLFxuICAnTWVudSc6ICdDb250ZXh0TWVudScsXG4gICdBcHBzJzogJ0NvbnRleHRNZW51JyxcbiAgJ1Njcm9sbCc6ICdTY3JvbGxMb2NrJyxcbiAgJ01velByaW50YWJsZUtleSc6ICdVbmlkZW50aWZpZWQnXG59O1xuXG4vKipcbiAqIFRyYW5zbGF0aW9uIGZyb20gbGVnYWN5IGBrZXlDb2RlYCB0byBIVE1MNSBga2V5YFxuICogT25seSBzcGVjaWFsIGtleXMgc3VwcG9ydGVkLCBhbGwgb3RoZXJzIGRlcGVuZCBvbiBrZXlib2FyZCBsYXlvdXQgb3IgYnJvd3NlclxuICogQHNlZSBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9BUEkvS2V5Ym9hcmRFdmVudCNLZXlfbmFtZXNcbiAqL1xudmFyIHRyYW5zbGF0ZVRvS2V5ID0ge1xuICA4OiAnQmFja3NwYWNlJyxcbiAgOTogJ1RhYicsXG4gIDEyOiAnQ2xlYXInLFxuICAxMzogJ0VudGVyJyxcbiAgMTY6ICdTaGlmdCcsXG4gIDE3OiAnQ29udHJvbCcsXG4gIDE4OiAnQWx0JyxcbiAgMTk6ICdQYXVzZScsXG4gIDIwOiAnQ2Fwc0xvY2snLFxuICAyNzogJ0VzY2FwZScsXG4gIDMyOiAnICcsXG4gIDMzOiAnUGFnZVVwJyxcbiAgMzQ6ICdQYWdlRG93bicsXG4gIDM1OiAnRW5kJyxcbiAgMzY6ICdIb21lJyxcbiAgMzc6ICdBcnJvd0xlZnQnLFxuICAzODogJ0Fycm93VXAnLFxuICAzOTogJ0Fycm93UmlnaHQnLFxuICA0MDogJ0Fycm93RG93bicsXG4gIDQ1OiAnSW5zZXJ0JyxcbiAgNDY6ICdEZWxldGUnLFxuICAxMTI6ICdGMScsIDExMzogJ0YyJywgMTE0OiAnRjMnLCAxMTU6ICdGNCcsIDExNjogJ0Y1JywgMTE3OiAnRjYnLFxuICAxMTg6ICdGNycsIDExOTogJ0Y4JywgMTIwOiAnRjknLCAxMjE6ICdGMTAnLCAxMjI6ICdGMTEnLCAxMjM6ICdGMTInLFxuICAxNDQ6ICdOdW1Mb2NrJyxcbiAgMTQ1OiAnU2Nyb2xsTG9jaycsXG4gIDIyNDogJ01ldGEnXG59O1xuXG4vKipcbiAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudCBOYXRpdmUgYnJvd3NlciBldmVudC5cbiAqIEByZXR1cm4ge3N0cmluZ30gTm9ybWFsaXplZCBga2V5YCBwcm9wZXJ0eS5cbiAqL1xuZnVuY3Rpb24gZ2V0RXZlbnRLZXkobmF0aXZlRXZlbnQpIHtcbiAgaWYgKG5hdGl2ZUV2ZW50LmtleSkge1xuICAgIC8vIE5vcm1hbGl6ZSBpbmNvbnNpc3RlbnQgdmFsdWVzIHJlcG9ydGVkIGJ5IGJyb3dzZXJzIGR1ZSB0b1xuICAgIC8vIGltcGxlbWVudGF0aW9ucyBvZiBhIHdvcmtpbmcgZHJhZnQgc3BlY2lmaWNhdGlvbi5cblxuICAgIC8vIEZpcmVGb3ggaW1wbGVtZW50cyBga2V5YCBidXQgcmV0dXJucyBgTW96UHJpbnRhYmxlS2V5YCBmb3IgYWxsXG4gICAgLy8gcHJpbnRhYmxlIGNoYXJhY3RlcnMgKG5vcm1hbGl6ZWQgdG8gYFVuaWRlbnRpZmllZGApLCBpZ25vcmUgaXQuXG4gICAgdmFyIGtleSA9IG5vcm1hbGl6ZUtleVtuYXRpdmVFdmVudC5rZXldIHx8IG5hdGl2ZUV2ZW50LmtleTtcbiAgICBpZiAoa2V5ICE9PSAnVW5pZGVudGlmaWVkJykge1xuICAgICAgcmV0dXJuIGtleTtcbiAgICB9XG4gIH1cblxuICAvLyBCcm93c2VyIGRvZXMgbm90IGltcGxlbWVudCBga2V5YCwgcG9seWZpbGwgYXMgbXVjaCBvZiBpdCBhcyB3ZSBjYW4uXG4gIGlmIChuYXRpdmVFdmVudC50eXBlID09PSAna2V5cHJlc3MnKSB7XG4gICAgdmFyIGNoYXJDb2RlID0gZ2V0RXZlbnRDaGFyQ29kZShuYXRpdmVFdmVudCk7XG5cbiAgICAvLyBUaGUgZW50ZXIta2V5IGlzIHRlY2huaWNhbGx5IGJvdGggcHJpbnRhYmxlIGFuZCBub24tcHJpbnRhYmxlIGFuZCBjYW5cbiAgICAvLyB0aHVzIGJlIGNhcHR1cmVkIGJ5IGBrZXlwcmVzc2AsIG5vIG90aGVyIG5vbi1wcmludGFibGUga2V5IHNob3VsZC5cbiAgICByZXR1cm4gY2hhckNvZGUgPT09IDEzID8gJ0VudGVyJyA6IFN0cmluZy5mcm9tQ2hhckNvZGUoY2hhckNvZGUpO1xuICB9XG4gIGlmIChuYXRpdmVFdmVudC50eXBlID09PSAna2V5ZG93bicgfHwgbmF0aXZlRXZlbnQudHlwZSA9PT0gJ2tleXVwJykge1xuICAgIC8vIFdoaWxlIHVzZXIga2V5Ym9hcmQgbGF5b3V0IGRldGVybWluZXMgdGhlIGFjdHVhbCBtZWFuaW5nIG9mIGVhY2hcbiAgICAvLyBga2V5Q29kZWAgdmFsdWUsIGFsbW9zdCBhbGwgZnVuY3Rpb24ga2V5cyBoYXZlIGEgdW5pdmVyc2FsIHZhbHVlLlxuICAgIHJldHVybiB0cmFuc2xhdGVUb0tleVtuYXRpdmVFdmVudC5rZXlDb2RlXSB8fCAnVW5pZGVudGlmaWVkJztcbiAgfVxuICByZXR1cm4gJyc7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZ2V0RXZlbnRLZXk7XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgZ2V0RXZlbnRNb2RpZmllclN0YXRlXG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG4vKipcbiAqIFRyYW5zbGF0aW9uIGZyb20gbW9kaWZpZXIga2V5IHRvIHRoZSBhc3NvY2lhdGVkIHByb3BlcnR5IGluIHRoZSBldmVudC5cbiAqIEBzZWUgaHR0cDovL3d3dy53My5vcmcvVFIvRE9NLUxldmVsLTMtRXZlbnRzLyNrZXlzLU1vZGlmaWVyc1xuICovXG5cbnZhciBtb2RpZmllcktleVRvUHJvcCA9IHtcbiAgJ0FsdCc6ICdhbHRLZXknLFxuICAnQ29udHJvbCc6ICdjdHJsS2V5JyxcbiAgJ01ldGEnOiAnbWV0YUtleScsXG4gICdTaGlmdCc6ICdzaGlmdEtleSdcbn07XG5cbi8vIElFOCBkb2VzIG5vdCBpbXBsZW1lbnQgZ2V0TW9kaWZpZXJTdGF0ZSBzbyB3ZSBzaW1wbHkgbWFwIGl0IHRvIHRoZSBvbmx5XG4vLyBtb2RpZmllciBrZXlzIGV4cG9zZWQgYnkgdGhlIGV2ZW50IGl0c2VsZiwgZG9lcyBub3Qgc3VwcG9ydCBMb2NrLWtleXMuXG4vLyBDdXJyZW50bHksIGFsbCBtYWpvciBicm93c2VycyBleGNlcHQgQ2hyb21lIHNlZW1zIHRvIHN1cHBvcnQgTG9jay1rZXlzLlxuZnVuY3Rpb24gbW9kaWZpZXJTdGF0ZUdldHRlcihrZXlBcmcpIHtcbiAgLypqc2hpbnQgdmFsaWR0aGlzOnRydWUgKi9cbiAgdmFyIHN5bnRoZXRpY0V2ZW50ID0gdGhpcztcbiAgdmFyIG5hdGl2ZUV2ZW50ID0gc3ludGhldGljRXZlbnQubmF0aXZlRXZlbnQ7XG4gIGlmIChuYXRpdmVFdmVudC5nZXRNb2RpZmllclN0YXRlKSB7XG4gICAgcmV0dXJuIG5hdGl2ZUV2ZW50LmdldE1vZGlmaWVyU3RhdGUoa2V5QXJnKTtcbiAgfVxuICB2YXIga2V5UHJvcCA9IG1vZGlmaWVyS2V5VG9Qcm9wW2tleUFyZ107XG4gIHJldHVybiBrZXlQcm9wID8gISFuYXRpdmVFdmVudFtrZXlQcm9wXSA6IGZhbHNlO1xufVxuXG5mdW5jdGlvbiBnZXRFdmVudE1vZGlmaWVyU3RhdGUobmF0aXZlRXZlbnQpIHtcbiAgcmV0dXJuIG1vZGlmaWVyU3RhdGVHZXR0ZXI7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZ2V0RXZlbnRNb2RpZmllclN0YXRlO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGdldEV2ZW50VGFyZ2V0XG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG4vKipcbiAqIEdldHMgdGhlIHRhcmdldCBub2RlIGZyb20gYSBuYXRpdmUgYnJvd3NlciBldmVudCBieSBhY2NvdW50aW5nIGZvclxuICogaW5jb25zaXN0ZW5jaWVzIGluIGJyb3dzZXIgRE9NIEFQSXMuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IG5hdGl2ZUV2ZW50IE5hdGl2ZSBicm93c2VyIGV2ZW50LlxuICogQHJldHVybiB7RE9NRXZlbnRUYXJnZXR9IFRhcmdldCBub2RlLlxuICovXG5mdW5jdGlvbiBnZXRFdmVudFRhcmdldChuYXRpdmVFdmVudCkge1xuICB2YXIgdGFyZ2V0ID0gbmF0aXZlRXZlbnQudGFyZ2V0IHx8IG5hdGl2ZUV2ZW50LnNyY0VsZW1lbnQgfHwgd2luZG93O1xuICAvLyBTYWZhcmkgbWF5IGZpcmUgZXZlbnRzIG9uIHRleHQgbm9kZXMgKE5vZGUuVEVYVF9OT0RFIGlzIDMpLlxuICAvLyBAc2VlIGh0dHA6Ly93d3cucXVpcmtzbW9kZS5vcmcvanMvZXZlbnRzX3Byb3BlcnRpZXMuaHRtbFxuICByZXR1cm4gdGFyZ2V0Lm5vZGVUeXBlID09PSAzID8gdGFyZ2V0LnBhcmVudE5vZGUgOiB0YXJnZXQ7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZ2V0RXZlbnRUYXJnZXQ7XG4iLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGdldE1hcmt1cFdyYXBcbiAqL1xuXG52YXIgRXhlY3V0aW9uRW52aXJvbm1lbnQgPSByZXF1aXJlKFwiLi9FeGVjdXRpb25FbnZpcm9ubWVudFwiKTtcblxudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcblxuLyoqXG4gKiBEdW1teSBjb250YWluZXIgdXNlZCB0byBkZXRlY3Qgd2hpY2ggd3JhcHMgYXJlIG5lY2Vzc2FyeS5cbiAqL1xudmFyIGR1bW15Tm9kZSA9XG4gIEV4ZWN1dGlvbkVudmlyb25tZW50LmNhblVzZURPTSA/IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpIDogbnVsbDtcblxuLyoqXG4gKiBTb21lIGJyb3dzZXJzIGNhbm5vdCB1c2UgYGlubmVySFRNTGAgdG8gcmVuZGVyIGNlcnRhaW4gZWxlbWVudHMgc3RhbmRhbG9uZSxcbiAqIHNvIHdlIHdyYXAgdGhlbSwgcmVuZGVyIHRoZSB3cmFwcGVkIG5vZGVzLCB0aGVuIGV4dHJhY3QgdGhlIGRlc2lyZWQgbm9kZS5cbiAqXG4gKiBJbiBJRTgsIGNlcnRhaW4gZWxlbWVudHMgY2Fubm90IHJlbmRlciBhbG9uZSwgc28gd3JhcCBhbGwgZWxlbWVudHMgKCcqJykuXG4gKi9cbnZhciBzaG91bGRXcmFwID0ge1xuICAvLyBGb3JjZSB3cmFwcGluZyBmb3IgU1ZHIGVsZW1lbnRzIGJlY2F1c2UgaWYgdGhleSBnZXQgY3JlYXRlZCBpbnNpZGUgYSA8ZGl2PixcbiAgLy8gdGhleSB3aWxsIGJlIGluaXRpYWxpemVkIGluIHRoZSB3cm9uZyBuYW1lc3BhY2UgKGFuZCB3aWxsIG5vdCBkaXNwbGF5KS5cbiAgJ2NpcmNsZSc6IHRydWUsXG4gICdkZWZzJzogdHJ1ZSxcbiAgJ2VsbGlwc2UnOiB0cnVlLFxuICAnZyc6IHRydWUsXG4gICdsaW5lJzogdHJ1ZSxcbiAgJ2xpbmVhckdyYWRpZW50JzogdHJ1ZSxcbiAgJ3BhdGgnOiB0cnVlLFxuICAncG9seWdvbic6IHRydWUsXG4gICdwb2x5bGluZSc6IHRydWUsXG4gICdyYWRpYWxHcmFkaWVudCc6IHRydWUsXG4gICdyZWN0JzogdHJ1ZSxcbiAgJ3N0b3AnOiB0cnVlLFxuICAndGV4dCc6IHRydWVcbn07XG5cbnZhciBzZWxlY3RXcmFwID0gWzEsICc8c2VsZWN0IG11bHRpcGxlPVwidHJ1ZVwiPicsICc8L3NlbGVjdD4nXTtcbnZhciB0YWJsZVdyYXAgPSBbMSwgJzx0YWJsZT4nLCAnPC90YWJsZT4nXTtcbnZhciB0cldyYXAgPSBbMywgJzx0YWJsZT48dGJvZHk+PHRyPicsICc8L3RyPjwvdGJvZHk+PC90YWJsZT4nXTtcblxudmFyIHN2Z1dyYXAgPSBbMSwgJzxzdmc+JywgJzwvc3ZnPiddO1xuXG52YXIgbWFya3VwV3JhcCA9IHtcbiAgJyonOiBbMSwgJz88ZGl2PicsICc8L2Rpdj4nXSxcblxuICAnYXJlYSc6IFsxLCAnPG1hcD4nLCAnPC9tYXA+J10sXG4gICdjb2wnOiBbMiwgJzx0YWJsZT48dGJvZHk+PC90Ym9keT48Y29sZ3JvdXA+JywgJzwvY29sZ3JvdXA+PC90YWJsZT4nXSxcbiAgJ2xlZ2VuZCc6IFsxLCAnPGZpZWxkc2V0PicsICc8L2ZpZWxkc2V0PiddLFxuICAncGFyYW0nOiBbMSwgJzxvYmplY3Q+JywgJzwvb2JqZWN0PiddLFxuICAndHInOiBbMiwgJzx0YWJsZT48dGJvZHk+JywgJzwvdGJvZHk+PC90YWJsZT4nXSxcblxuICAnb3B0Z3JvdXAnOiBzZWxlY3RXcmFwLFxuICAnb3B0aW9uJzogc2VsZWN0V3JhcCxcblxuICAnY2FwdGlvbic6IHRhYmxlV3JhcCxcbiAgJ2NvbGdyb3VwJzogdGFibGVXcmFwLFxuICAndGJvZHknOiB0YWJsZVdyYXAsXG4gICd0Zm9vdCc6IHRhYmxlV3JhcCxcbiAgJ3RoZWFkJzogdGFibGVXcmFwLFxuXG4gICd0ZCc6IHRyV3JhcCxcbiAgJ3RoJzogdHJXcmFwLFxuXG4gICdjaXJjbGUnOiBzdmdXcmFwLFxuICAnZGVmcyc6IHN2Z1dyYXAsXG4gICdlbGxpcHNlJzogc3ZnV3JhcCxcbiAgJ2cnOiBzdmdXcmFwLFxuICAnbGluZSc6IHN2Z1dyYXAsXG4gICdsaW5lYXJHcmFkaWVudCc6IHN2Z1dyYXAsXG4gICdwYXRoJzogc3ZnV3JhcCxcbiAgJ3BvbHlnb24nOiBzdmdXcmFwLFxuICAncG9seWxpbmUnOiBzdmdXcmFwLFxuICAncmFkaWFsR3JhZGllbnQnOiBzdmdXcmFwLFxuICAncmVjdCc6IHN2Z1dyYXAsXG4gICdzdG9wJzogc3ZnV3JhcCxcbiAgJ3RleHQnOiBzdmdXcmFwXG59O1xuXG4vKipcbiAqIEdldHMgdGhlIG1hcmt1cCB3cmFwIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBzdXBwbGllZCBgbm9kZU5hbWVgLlxuICpcbiAqIE5PVEU6IFRoaXMgbGF6aWx5IGRldGVjdHMgd2hpY2ggd3JhcHMgYXJlIG5lY2Vzc2FyeSBmb3IgdGhlIGN1cnJlbnQgYnJvd3Nlci5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gbm9kZU5hbWUgTG93ZXJjYXNlIGBub2RlTmFtZWAuXG4gKiBAcmV0dXJuIHs/YXJyYXl9IE1hcmt1cCB3cmFwIGNvbmZpZ3VyYXRpb24sIGlmIGFwcGxpY2FibGUuXG4gKi9cbmZ1bmN0aW9uIGdldE1hcmt1cFdyYXAobm9kZU5hbWUpIHtcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudCghIWR1bW15Tm9kZSwgJ01hcmt1cCB3cmFwcGluZyBub2RlIG5vdCBpbml0aWFsaXplZCcpIDogaW52YXJpYW50KCEhZHVtbXlOb2RlKSk7XG4gIGlmICghbWFya3VwV3JhcC5oYXNPd25Qcm9wZXJ0eShub2RlTmFtZSkpIHtcbiAgICBub2RlTmFtZSA9ICcqJztcbiAgfVxuICBpZiAoIXNob3VsZFdyYXAuaGFzT3duUHJvcGVydHkobm9kZU5hbWUpKSB7XG4gICAgaWYgKG5vZGVOYW1lID09PSAnKicpIHtcbiAgICAgIGR1bW15Tm9kZS5pbm5lckhUTUwgPSAnPGxpbmsgLz4nO1xuICAgIH0gZWxzZSB7XG4gICAgICBkdW1teU5vZGUuaW5uZXJIVE1MID0gJzwnICsgbm9kZU5hbWUgKyAnPjwvJyArIG5vZGVOYW1lICsgJz4nO1xuICAgIH1cbiAgICBzaG91bGRXcmFwW25vZGVOYW1lXSA9ICFkdW1teU5vZGUuZmlyc3RDaGlsZDtcbiAgfVxuICByZXR1cm4gc2hvdWxkV3JhcFtub2RlTmFtZV0gPyBtYXJrdXBXcmFwW25vZGVOYW1lXSA6IG51bGw7XG59XG5cblxubW9kdWxlLmV4cG9ydHMgPSBnZXRNYXJrdXBXcmFwO1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgZ2V0Tm9kZUZvckNoYXJhY3Rlck9mZnNldFxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG4vKipcbiAqIEdpdmVuIGFueSBub2RlIHJldHVybiB0aGUgZmlyc3QgbGVhZiBub2RlIHdpdGhvdXQgY2hpbGRyZW4uXG4gKlxuICogQHBhcmFtIHtET01FbGVtZW50fERPTVRleHROb2RlfSBub2RlXG4gKiBAcmV0dXJuIHtET01FbGVtZW50fERPTVRleHROb2RlfVxuICovXG5mdW5jdGlvbiBnZXRMZWFmTm9kZShub2RlKSB7XG4gIHdoaWxlIChub2RlICYmIG5vZGUuZmlyc3RDaGlsZCkge1xuICAgIG5vZGUgPSBub2RlLmZpcnN0Q2hpbGQ7XG4gIH1cbiAgcmV0dXJuIG5vZGU7XG59XG5cbi8qKlxuICogR2V0IHRoZSBuZXh0IHNpYmxpbmcgd2l0aGluIGEgY29udGFpbmVyLiBUaGlzIHdpbGwgd2FsayB1cCB0aGVcbiAqIERPTSBpZiBhIG5vZGUncyBzaWJsaW5ncyBoYXZlIGJlZW4gZXhoYXVzdGVkLlxuICpcbiAqIEBwYXJhbSB7RE9NRWxlbWVudHxET01UZXh0Tm9kZX0gbm9kZVxuICogQHJldHVybiB7P0RPTUVsZW1lbnR8RE9NVGV4dE5vZGV9XG4gKi9cbmZ1bmN0aW9uIGdldFNpYmxpbmdOb2RlKG5vZGUpIHtcbiAgd2hpbGUgKG5vZGUpIHtcbiAgICBpZiAobm9kZS5uZXh0U2libGluZykge1xuICAgICAgcmV0dXJuIG5vZGUubmV4dFNpYmxpbmc7XG4gICAgfVxuICAgIG5vZGUgPSBub2RlLnBhcmVudE5vZGU7XG4gIH1cbn1cblxuLyoqXG4gKiBHZXQgb2JqZWN0IGRlc2NyaWJpbmcgdGhlIG5vZGVzIHdoaWNoIGNvbnRhaW4gY2hhcmFjdGVycyBhdCBvZmZzZXQuXG4gKlxuICogQHBhcmFtIHtET01FbGVtZW50fERPTVRleHROb2RlfSByb290XG4gKiBAcGFyYW0ge251bWJlcn0gb2Zmc2V0XG4gKiBAcmV0dXJuIHs/b2JqZWN0fVxuICovXG5mdW5jdGlvbiBnZXROb2RlRm9yQ2hhcmFjdGVyT2Zmc2V0KHJvb3QsIG9mZnNldCkge1xuICB2YXIgbm9kZSA9IGdldExlYWZOb2RlKHJvb3QpO1xuICB2YXIgbm9kZVN0YXJ0ID0gMDtcbiAgdmFyIG5vZGVFbmQgPSAwO1xuXG4gIHdoaWxlIChub2RlKSB7XG4gICAgaWYgKG5vZGUubm9kZVR5cGUgPT0gMykge1xuICAgICAgbm9kZUVuZCA9IG5vZGVTdGFydCArIG5vZGUudGV4dENvbnRlbnQubGVuZ3RoO1xuXG4gICAgICBpZiAobm9kZVN0YXJ0IDw9IG9mZnNldCAmJiBub2RlRW5kID49IG9mZnNldCkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIG5vZGU6IG5vZGUsXG4gICAgICAgICAgb2Zmc2V0OiBvZmZzZXQgLSBub2RlU3RhcnRcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgbm9kZVN0YXJ0ID0gbm9kZUVuZDtcbiAgICB9XG5cbiAgICBub2RlID0gZ2V0TGVhZk5vZGUoZ2V0U2libGluZ05vZGUobm9kZSkpO1xuICB9XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZ2V0Tm9kZUZvckNoYXJhY3Rlck9mZnNldDtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBnZXRSZWFjdFJvb3RFbGVtZW50SW5Db250YWluZXJcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIERPQ19OT0RFX1RZUEUgPSA5O1xuXG4vKipcbiAqIEBwYXJhbSB7RE9NRWxlbWVudHxET01Eb2N1bWVudH0gY29udGFpbmVyIERPTSBlbGVtZW50IHRoYXQgbWF5IGNvbnRhaW5cbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGEgUmVhY3QgY29tcG9uZW50XG4gKiBAcmV0dXJuIHs/Kn0gRE9NIGVsZW1lbnQgdGhhdCBtYXkgaGF2ZSB0aGUgcmVhY3RSb290IElELCBvciBudWxsLlxuICovXG5mdW5jdGlvbiBnZXRSZWFjdFJvb3RFbGVtZW50SW5Db250YWluZXIoY29udGFpbmVyKSB7XG4gIGlmICghY29udGFpbmVyKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBpZiAoY29udGFpbmVyLm5vZGVUeXBlID09PSBET0NfTk9ERV9UWVBFKSB7XG4gICAgcmV0dXJuIGNvbnRhaW5lci5kb2N1bWVudEVsZW1lbnQ7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIGNvbnRhaW5lci5maXJzdENoaWxkO1xuICB9XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZ2V0UmVhY3RSb290RWxlbWVudEluQ29udGFpbmVyO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGdldFRleHRDb250ZW50QWNjZXNzb3JcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIEV4ZWN1dGlvbkVudmlyb25tZW50ID0gcmVxdWlyZShcIi4vRXhlY3V0aW9uRW52aXJvbm1lbnRcIik7XG5cbnZhciBjb250ZW50S2V5ID0gbnVsbDtcblxuLyoqXG4gKiBHZXRzIHRoZSBrZXkgdXNlZCB0byBhY2Nlc3MgdGV4dCBjb250ZW50IG9uIGEgRE9NIG5vZGUuXG4gKlxuICogQHJldHVybiB7P3N0cmluZ30gS2V5IHVzZWQgdG8gYWNjZXNzIHRleHQgY29udGVudC5cbiAqIEBpbnRlcm5hbFxuICovXG5mdW5jdGlvbiBnZXRUZXh0Q29udGVudEFjY2Vzc29yKCkge1xuICBpZiAoIWNvbnRlbnRLZXkgJiYgRXhlY3V0aW9uRW52aXJvbm1lbnQuY2FuVXNlRE9NKSB7XG4gICAgLy8gUHJlZmVyIHRleHRDb250ZW50IHRvIGlubmVyVGV4dCBiZWNhdXNlIG1hbnkgYnJvd3NlcnMgc3VwcG9ydCBib3RoIGJ1dFxuICAgIC8vIFNWRyA8dGV4dD4gZWxlbWVudHMgZG9uJ3Qgc3VwcG9ydCBpbm5lclRleHQgZXZlbiB3aGVuIDxkaXY+IGRvZXMuXG4gICAgY29udGVudEtleSA9ICd0ZXh0Q29udGVudCcgaW4gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50ID9cbiAgICAgICd0ZXh0Q29udGVudCcgOlxuICAgICAgJ2lubmVyVGV4dCc7XG4gIH1cbiAgcmV0dXJuIGNvbnRlbnRLZXk7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZ2V0VGV4dENvbnRlbnRBY2Nlc3NvcjtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBnZXRVbmJvdW5kZWRTY3JvbGxQb3NpdGlvblxuICogQHR5cGVjaGVja3NcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxuLyoqXG4gKiBHZXRzIHRoZSBzY3JvbGwgcG9zaXRpb24gb2YgdGhlIHN1cHBsaWVkIGVsZW1lbnQgb3Igd2luZG93LlxuICpcbiAqIFRoZSByZXR1cm4gdmFsdWVzIGFyZSB1bmJvdW5kZWQsIHVubGlrZSBgZ2V0U2Nyb2xsUG9zaXRpb25gLiBUaGlzIG1lYW5zIHRoZXlcbiAqIG1heSBiZSBuZWdhdGl2ZSBvciBleGNlZWQgdGhlIGVsZW1lbnQgYm91bmRhcmllcyAod2hpY2ggaXMgcG9zc2libGUgdXNpbmdcbiAqIGluZXJ0aWFsIHNjcm9sbGluZykuXG4gKlxuICogQHBhcmFtIHtET01XaW5kb3d8RE9NRWxlbWVudH0gc2Nyb2xsYWJsZVxuICogQHJldHVybiB7b2JqZWN0fSBNYXAgd2l0aCBgeGAgYW5kIGB5YCBrZXlzLlxuICovXG5mdW5jdGlvbiBnZXRVbmJvdW5kZWRTY3JvbGxQb3NpdGlvbihzY3JvbGxhYmxlKSB7XG4gIGlmIChzY3JvbGxhYmxlID09PSB3aW5kb3cpIHtcbiAgICByZXR1cm4ge1xuICAgICAgeDogd2luZG93LnBhZ2VYT2Zmc2V0IHx8IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zY3JvbGxMZWZ0LFxuICAgICAgeTogd2luZG93LnBhZ2VZT2Zmc2V0IHx8IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zY3JvbGxUb3BcbiAgICB9O1xuICB9XG4gIHJldHVybiB7XG4gICAgeDogc2Nyb2xsYWJsZS5zY3JvbGxMZWZ0LFxuICAgIHk6IHNjcm9sbGFibGUuc2Nyb2xsVG9wXG4gIH07XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZ2V0VW5ib3VuZGVkU2Nyb2xsUG9zaXRpb247XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgaHlwaGVuYXRlXG4gKiBAdHlwZWNoZWNrc1xuICovXG5cbnZhciBfdXBwZXJjYXNlUGF0dGVybiA9IC8oW0EtWl0pL2c7XG5cbi8qKlxuICogSHlwaGVuYXRlcyBhIGNhbWVsY2FzZWQgc3RyaW5nLCBmb3IgZXhhbXBsZTpcbiAqXG4gKiAgID4gaHlwaGVuYXRlKCdiYWNrZ3JvdW5kQ29sb3InKVxuICogICA8IFwiYmFja2dyb3VuZC1jb2xvclwiXG4gKlxuICogRm9yIENTUyBzdHlsZSBuYW1lcywgdXNlIGBoeXBoZW5hdGVTdHlsZU5hbWVgIGluc3RlYWQgd2hpY2ggd29ya3MgcHJvcGVybHlcbiAqIHdpdGggYWxsIHZlbmRvciBwcmVmaXhlcywgaW5jbHVkaW5nIGBtc2AuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHN0cmluZ1xuICogQHJldHVybiB7c3RyaW5nfVxuICovXG5mdW5jdGlvbiBoeXBoZW5hdGUoc3RyaW5nKSB7XG4gIHJldHVybiBzdHJpbmcucmVwbGFjZShfdXBwZXJjYXNlUGF0dGVybiwgJy0kMScpLnRvTG93ZXJDYXNlKCk7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gaHlwaGVuYXRlO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGh5cGhlbmF0ZVN0eWxlTmFtZVxuICogQHR5cGVjaGVja3NcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIGh5cGhlbmF0ZSA9IHJlcXVpcmUoXCIuL2h5cGhlbmF0ZVwiKTtcblxudmFyIG1zUGF0dGVybiA9IC9ebXMtLztcblxuLyoqXG4gKiBIeXBoZW5hdGVzIGEgY2FtZWxjYXNlZCBDU1MgcHJvcGVydHkgbmFtZSwgZm9yIGV4YW1wbGU6XG4gKlxuICogICA+IGh5cGhlbmF0ZVN0eWxlTmFtZSgnYmFja2dyb3VuZENvbG9yJylcbiAqICAgPCBcImJhY2tncm91bmQtY29sb3JcIlxuICogICA+IGh5cGhlbmF0ZVN0eWxlTmFtZSgnTW96VHJhbnNpdGlvbicpXG4gKiAgIDwgXCItbW96LXRyYW5zaXRpb25cIlxuICogICA+IGh5cGhlbmF0ZVN0eWxlTmFtZSgnbXNUcmFuc2l0aW9uJylcbiAqICAgPCBcIi1tcy10cmFuc2l0aW9uXCJcbiAqXG4gKiBBcyBNb2Rlcm5penIgc3VnZ2VzdHMgKGh0dHA6Ly9tb2Rlcm5penIuY29tL2RvY3MvI3ByZWZpeGVkKSwgYW4gYG1zYCBwcmVmaXhcbiAqIGlzIGNvbnZlcnRlZCB0byBgLW1zLWAuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHN0cmluZ1xuICogQHJldHVybiB7c3RyaW5nfVxuICovXG5mdW5jdGlvbiBoeXBoZW5hdGVTdHlsZU5hbWUoc3RyaW5nKSB7XG4gIHJldHVybiBoeXBoZW5hdGUoc3RyaW5nKS5yZXBsYWNlKG1zUGF0dGVybiwgJy1tcy0nKTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBoeXBoZW5hdGVTdHlsZU5hbWU7XG4iLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGluc3RhbnRpYXRlUmVhY3RDb21wb25lbnRcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciB3YXJuaW5nID0gcmVxdWlyZShcIi4vd2FybmluZ1wiKTtcblxudmFyIFJlYWN0RWxlbWVudCA9IHJlcXVpcmUoXCIuL1JlYWN0RWxlbWVudFwiKTtcbnZhciBSZWFjdExlZ2FjeUVsZW1lbnQgPSByZXF1aXJlKFwiLi9SZWFjdExlZ2FjeUVsZW1lbnRcIik7XG52YXIgUmVhY3ROYXRpdmVDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdE5hdGl2ZUNvbXBvbmVudFwiKTtcbnZhciBSZWFjdEVtcHR5Q29tcG9uZW50ID0gcmVxdWlyZShcIi4vUmVhY3RFbXB0eUNvbXBvbmVudFwiKTtcblxuLyoqXG4gKiBHaXZlbiBhbiBgZWxlbWVudGAgY3JlYXRlIGFuIGluc3RhbmNlIHRoYXQgd2lsbCBhY3R1YWxseSBiZSBtb3VudGVkLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBlbGVtZW50XG4gKiBAcGFyYW0geyp9IHBhcmVudENvbXBvc2l0ZVR5cGUgVGhlIGNvbXBvc2l0ZSB0eXBlIHRoYXQgcmVzb2x2ZWQgdGhpcy5cbiAqIEByZXR1cm4ge29iamVjdH0gQSBuZXcgaW5zdGFuY2Ugb2YgdGhlIGVsZW1lbnQncyBjb25zdHJ1Y3Rvci5cbiAqIEBwcm90ZWN0ZWRcbiAqL1xuZnVuY3Rpb24gaW5zdGFudGlhdGVSZWFjdENvbXBvbmVudChlbGVtZW50LCBwYXJlbnRDb21wb3NpdGVUeXBlKSB7XG4gIHZhciBpbnN0YW5jZTtcblxuICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IHdhcm5pbmcoXG4gICAgICBlbGVtZW50ICYmICh0eXBlb2YgZWxlbWVudC50eXBlID09PSAnZnVuY3Rpb24nIHx8XG4gICAgICAgICAgICAgICAgICAgICB0eXBlb2YgZWxlbWVudC50eXBlID09PSAnc3RyaW5nJyksXG4gICAgICAnT25seSBmdW5jdGlvbnMgb3Igc3RyaW5ncyBjYW4gYmUgbW91bnRlZCBhcyBSZWFjdCBjb21wb25lbnRzLidcbiAgICApIDogbnVsbCk7XG5cbiAgICAvLyBSZXNvbHZlIG1vY2sgaW5zdGFuY2VzXG4gICAgaWYgKGVsZW1lbnQudHlwZS5fbW9ja2VkUmVhY3RDbGFzc0NvbnN0cnVjdG9yKSB7XG4gICAgICAvLyBJZiB0aGlzIGlzIGEgbW9ja2VkIGNsYXNzLCB3ZSB0cmVhdCB0aGUgbGVnYWN5IGZhY3RvcnkgYXMgaWYgaXQgd2FzIHRoZVxuICAgICAgLy8gY2xhc3MgY29uc3RydWN0b3IgZm9yIGZ1dHVyZSBwcm9vZmluZyB1bml0IHRlc3RzLiBCZWNhdXNlIHRoaXMgbWlnaHRcbiAgICAgIC8vIGJlIG1vY2tlZCBhcyBhIGxlZ2FjeSBmYWN0b3J5LCB3ZSBpZ25vcmUgYW55IHdhcm5pbmdzIHRyaWdnZXJkIGJ5XG4gICAgICAvLyB0aGlzIHRlbXBvcmFyeSBoYWNrLlxuICAgICAgUmVhY3RMZWdhY3lFbGVtZW50Ll9pc0xlZ2FjeUNhbGxXYXJuaW5nRW5hYmxlZCA9IGZhbHNlO1xuICAgICAgdHJ5IHtcbiAgICAgICAgaW5zdGFuY2UgPSBuZXcgZWxlbWVudC50eXBlLl9tb2NrZWRSZWFjdENsYXNzQ29uc3RydWN0b3IoXG4gICAgICAgICAgZWxlbWVudC5wcm9wc1xuICAgICAgICApO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgUmVhY3RMZWdhY3lFbGVtZW50Ll9pc0xlZ2FjeUNhbGxXYXJuaW5nRW5hYmxlZCA9IHRydWU7XG4gICAgICB9XG5cbiAgICAgIC8vIElmIHRoZSBtb2NrIGltcGxlbWVudGF0aW9uIHdhcyBhIGxlZ2FjeSBmYWN0b3J5LCB0aGVuIGl0IHJldHVybnMgYVxuICAgICAgLy8gZWxlbWVudC4gV2UgbmVlZCB0byB0dXJuIHRoaXMgaW50byBhIHJlYWwgY29tcG9uZW50IGluc3RhbmNlLlxuICAgICAgaWYgKFJlYWN0RWxlbWVudC5pc1ZhbGlkRWxlbWVudChpbnN0YW5jZSkpIHtcbiAgICAgICAgaW5zdGFuY2UgPSBuZXcgaW5zdGFuY2UudHlwZShpbnN0YW5jZS5wcm9wcyk7XG4gICAgICB9XG5cbiAgICAgIHZhciByZW5kZXIgPSBpbnN0YW5jZS5yZW5kZXI7XG4gICAgICBpZiAoIXJlbmRlcikge1xuICAgICAgICAvLyBGb3IgYXV0by1tb2NrZWQgZmFjdG9yaWVzLCB0aGUgcHJvdG90eXBlIGlzbid0IHNoaW1tZWQgYW5kIHRoZXJlZm9yZVxuICAgICAgICAvLyB0aGVyZSBpcyBubyByZW5kZXIgZnVuY3Rpb24gb24gdGhlIGluc3RhbmNlLiBXZSByZXBsYWNlIHRoZSB3aG9sZVxuICAgICAgICAvLyBjb21wb25lbnQgd2l0aCBhbiBlbXB0eSBjb21wb25lbnQgaW5zdGFuY2UgaW5zdGVhZC5cbiAgICAgICAgZWxlbWVudCA9IFJlYWN0RW1wdHlDb21wb25lbnQuZ2V0RW1wdHlDb21wb25lbnQoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmIChyZW5kZXIuX2lzTW9ja0Z1bmN0aW9uICYmICFyZW5kZXIuX2dldE1vY2tJbXBsZW1lbnRhdGlvbigpKSB7XG4gICAgICAgICAgLy8gQXV0by1tb2NrZWQgY29tcG9uZW50cyBtYXkgaGF2ZSBhIHByb3RvdHlwZSB3aXRoIGEgbW9ja2VkIHJlbmRlclxuICAgICAgICAgIC8vIGZ1bmN0aW9uLiBGb3IgdGhvc2UsIHdlJ2xsIG5lZWQgdG8gbW9jayB0aGUgcmVzdWx0IG9mIHRoZSByZW5kZXJcbiAgICAgICAgICAvLyBzaW5jZSB3ZSBjb25zaWRlciB1bmRlZmluZWQgdG8gYmUgaW52YWxpZCByZXN1bHRzIGZyb20gcmVuZGVyLlxuICAgICAgICAgIHJlbmRlci5tb2NrSW1wbGVtZW50YXRpb24oXG4gICAgICAgICAgICBSZWFjdEVtcHR5Q29tcG9uZW50LmdldEVtcHR5Q29tcG9uZW50XG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBpbnN0YW5jZS5jb25zdHJ1Y3QoZWxlbWVudCk7XG4gICAgICAgIHJldHVybiBpbnN0YW5jZTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyBTcGVjaWFsIGNhc2Ugc3RyaW5nIHZhbHVlc1xuICBpZiAodHlwZW9mIGVsZW1lbnQudHlwZSA9PT0gJ3N0cmluZycpIHtcbiAgICBpbnN0YW5jZSA9IFJlYWN0TmF0aXZlQ29tcG9uZW50LmNyZWF0ZUluc3RhbmNlRm9yVGFnKFxuICAgICAgZWxlbWVudC50eXBlLFxuICAgICAgZWxlbWVudC5wcm9wcyxcbiAgICAgIHBhcmVudENvbXBvc2l0ZVR5cGVcbiAgICApO1xuICB9IGVsc2Uge1xuICAgIC8vIE5vcm1hbCBjYXNlIGZvciBub24tbW9ja3MgYW5kIG5vbi1zdHJpbmdzXG4gICAgaW5zdGFuY2UgPSBuZXcgZWxlbWVudC50eXBlKGVsZW1lbnQucHJvcHMpO1xuICB9XG5cbiAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyB3YXJuaW5nKFxuICAgICAgdHlwZW9mIGluc3RhbmNlLmNvbnN0cnVjdCA9PT0gJ2Z1bmN0aW9uJyAmJlxuICAgICAgdHlwZW9mIGluc3RhbmNlLm1vdW50Q29tcG9uZW50ID09PSAnZnVuY3Rpb24nICYmXG4gICAgICB0eXBlb2YgaW5zdGFuY2UucmVjZWl2ZUNvbXBvbmVudCA9PT0gJ2Z1bmN0aW9uJyxcbiAgICAgICdPbmx5IFJlYWN0IENvbXBvbmVudHMgY2FuIGJlIG1vdW50ZWQuJ1xuICAgICkgOiBudWxsKTtcbiAgfVxuXG4gIC8vIFRoaXMgYWN0dWFsbHkgc2V0cyB1cCB0aGUgaW50ZXJuYWwgaW5zdGFuY2UuIFRoaXMgd2lsbCBiZWNvbWUgZGVjb3VwbGVkXG4gIC8vIGZyb20gdGhlIHB1YmxpYyBpbnN0YW5jZSBpbiBhIGZ1dHVyZSBkaWZmLlxuICBpbnN0YW5jZS5jb25zdHJ1Y3QoZWxlbWVudCk7XG5cbiAgcmV0dXJuIGluc3RhbmNlO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGluc3RhbnRpYXRlUmVhY3RDb21wb25lbnQ7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgaW52YXJpYW50XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbi8qKlxuICogVXNlIGludmFyaWFudCgpIHRvIGFzc2VydCBzdGF0ZSB3aGljaCB5b3VyIHByb2dyYW0gYXNzdW1lcyB0byBiZSB0cnVlLlxuICpcbiAqIFByb3ZpZGUgc3ByaW50Zi1zdHlsZSBmb3JtYXQgKG9ubHkgJXMgaXMgc3VwcG9ydGVkKSBhbmQgYXJndW1lbnRzXG4gKiB0byBwcm92aWRlIGluZm9ybWF0aW9uIGFib3V0IHdoYXQgYnJva2UgYW5kIHdoYXQgeW91IHdlcmVcbiAqIGV4cGVjdGluZy5cbiAqXG4gKiBUaGUgaW52YXJpYW50IG1lc3NhZ2Ugd2lsbCBiZSBzdHJpcHBlZCBpbiBwcm9kdWN0aW9uLCBidXQgdGhlIGludmFyaWFudFxuICogd2lsbCByZW1haW4gdG8gZW5zdXJlIGxvZ2ljIGRvZXMgbm90IGRpZmZlciBpbiBwcm9kdWN0aW9uLlxuICovXG5cbnZhciBpbnZhcmlhbnQgPSBmdW5jdGlvbihjb25kaXRpb24sIGZvcm1hdCwgYSwgYiwgYywgZCwgZSwgZikge1xuICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgaWYgKGZvcm1hdCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFyaWFudCByZXF1aXJlcyBhbiBlcnJvciBtZXNzYWdlIGFyZ3VtZW50Jyk7XG4gICAgfVxuICB9XG5cbiAgaWYgKCFjb25kaXRpb24pIHtcbiAgICB2YXIgZXJyb3I7XG4gICAgaWYgKGZvcm1hdCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBlcnJvciA9IG5ldyBFcnJvcihcbiAgICAgICAgJ01pbmlmaWVkIGV4Y2VwdGlvbiBvY2N1cnJlZDsgdXNlIHRoZSBub24tbWluaWZpZWQgZGV2IGVudmlyb25tZW50ICcgK1xuICAgICAgICAnZm9yIHRoZSBmdWxsIGVycm9yIG1lc3NhZ2UgYW5kIGFkZGl0aW9uYWwgaGVscGZ1bCB3YXJuaW5ncy4nXG4gICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICB2YXIgYXJncyA9IFthLCBiLCBjLCBkLCBlLCBmXTtcbiAgICAgIHZhciBhcmdJbmRleCA9IDA7XG4gICAgICBlcnJvciA9IG5ldyBFcnJvcihcbiAgICAgICAgJ0ludmFyaWFudCBWaW9sYXRpb246ICcgK1xuICAgICAgICBmb3JtYXQucmVwbGFjZSgvJXMvZywgZnVuY3Rpb24oKSB7IHJldHVybiBhcmdzW2FyZ0luZGV4KytdOyB9KVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBlcnJvci5mcmFtZXNUb1BvcCA9IDE7IC8vIHdlIGRvbid0IGNhcmUgYWJvdXQgaW52YXJpYW50J3Mgb3duIGZyYW1lXG4gICAgdGhyb3cgZXJyb3I7XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gaW52YXJpYW50O1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgaXNFdmVudFN1cHBvcnRlZFxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgRXhlY3V0aW9uRW52aXJvbm1lbnQgPSByZXF1aXJlKFwiLi9FeGVjdXRpb25FbnZpcm9ubWVudFwiKTtcblxudmFyIHVzZUhhc0ZlYXR1cmU7XG5pZiAoRXhlY3V0aW9uRW52aXJvbm1lbnQuY2FuVXNlRE9NKSB7XG4gIHVzZUhhc0ZlYXR1cmUgPVxuICAgIGRvY3VtZW50LmltcGxlbWVudGF0aW9uICYmXG4gICAgZG9jdW1lbnQuaW1wbGVtZW50YXRpb24uaGFzRmVhdHVyZSAmJlxuICAgIC8vIGFsd2F5cyByZXR1cm5zIHRydWUgaW4gbmV3ZXIgYnJvd3NlcnMgYXMgcGVyIHRoZSBzdGFuZGFyZC5cbiAgICAvLyBAc2VlIGh0dHA6Ly9kb20uc3BlYy53aGF0d2cub3JnLyNkb20tZG9taW1wbGVtZW50YXRpb24taGFzZmVhdHVyZVxuICAgIGRvY3VtZW50LmltcGxlbWVudGF0aW9uLmhhc0ZlYXR1cmUoJycsICcnKSAhPT0gdHJ1ZTtcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgYW4gZXZlbnQgaXMgc3VwcG9ydGVkIGluIHRoZSBjdXJyZW50IGV4ZWN1dGlvbiBlbnZpcm9ubWVudC5cbiAqXG4gKiBOT1RFOiBUaGlzIHdpbGwgbm90IHdvcmsgY29ycmVjdGx5IGZvciBub24tZ2VuZXJpYyBldmVudHMgc3VjaCBhcyBgY2hhbmdlYCxcbiAqIGByZXNldGAsIGBsb2FkYCwgYGVycm9yYCwgYW5kIGBzZWxlY3RgLlxuICpcbiAqIEJvcnJvd3MgZnJvbSBNb2Rlcm5penIuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZVN1ZmZpeCBFdmVudCBuYW1lLCBlLmcuIFwiY2xpY2tcIi5cbiAqIEBwYXJhbSB7P2Jvb2xlYW59IGNhcHR1cmUgQ2hlY2sgaWYgdGhlIGNhcHR1cmUgcGhhc2UgaXMgc3VwcG9ydGVkLlxuICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgZXZlbnQgaXMgc3VwcG9ydGVkLlxuICogQGludGVybmFsXG4gKiBAbGljZW5zZSBNb2Rlcm5penIgMy4wLjBwcmUgKEN1c3RvbSBCdWlsZCkgfCBNSVRcbiAqL1xuZnVuY3Rpb24gaXNFdmVudFN1cHBvcnRlZChldmVudE5hbWVTdWZmaXgsIGNhcHR1cmUpIHtcbiAgaWYgKCFFeGVjdXRpb25FbnZpcm9ubWVudC5jYW5Vc2VET00gfHxcbiAgICAgIGNhcHR1cmUgJiYgISgnYWRkRXZlbnRMaXN0ZW5lcicgaW4gZG9jdW1lbnQpKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgdmFyIGV2ZW50TmFtZSA9ICdvbicgKyBldmVudE5hbWVTdWZmaXg7XG4gIHZhciBpc1N1cHBvcnRlZCA9IGV2ZW50TmFtZSBpbiBkb2N1bWVudDtcblxuICBpZiAoIWlzU3VwcG9ydGVkKSB7XG4gICAgdmFyIGVsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICBlbGVtZW50LnNldEF0dHJpYnV0ZShldmVudE5hbWUsICdyZXR1cm47Jyk7XG4gICAgaXNTdXBwb3J0ZWQgPSB0eXBlb2YgZWxlbWVudFtldmVudE5hbWVdID09PSAnZnVuY3Rpb24nO1xuICB9XG5cbiAgaWYgKCFpc1N1cHBvcnRlZCAmJiB1c2VIYXNGZWF0dXJlICYmIGV2ZW50TmFtZVN1ZmZpeCA9PT0gJ3doZWVsJykge1xuICAgIC8vIFRoaXMgaXMgdGhlIG9ubHkgd2F5IHRvIHRlc3Qgc3VwcG9ydCBmb3IgdGhlIGB3aGVlbGAgZXZlbnQgaW4gSUU5Ky5cbiAgICBpc1N1cHBvcnRlZCA9IGRvY3VtZW50LmltcGxlbWVudGF0aW9uLmhhc0ZlYXR1cmUoJ0V2ZW50cy53aGVlbCcsICczLjAnKTtcbiAgfVxuXG4gIHJldHVybiBpc1N1cHBvcnRlZDtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBpc0V2ZW50U3VwcG9ydGVkO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGlzTm9kZVxuICogQHR5cGVjaGVja3NcbiAqL1xuXG4vKipcbiAqIEBwYXJhbSB7Kn0gb2JqZWN0IFRoZSBvYmplY3QgdG8gY2hlY2suXG4gKiBAcmV0dXJuIHtib29sZWFufSBXaGV0aGVyIG9yIG5vdCB0aGUgb2JqZWN0IGlzIGEgRE9NIG5vZGUuXG4gKi9cbmZ1bmN0aW9uIGlzTm9kZShvYmplY3QpIHtcbiAgcmV0dXJuICEhKG9iamVjdCAmJiAoXG4gICAgdHlwZW9mIE5vZGUgPT09ICdmdW5jdGlvbicgPyBvYmplY3QgaW5zdGFuY2VvZiBOb2RlIDpcbiAgICAgIHR5cGVvZiBvYmplY3QgPT09ICdvYmplY3QnICYmXG4gICAgICB0eXBlb2Ygb2JqZWN0Lm5vZGVUeXBlID09PSAnbnVtYmVyJyAmJlxuICAgICAgdHlwZW9mIG9iamVjdC5ub2RlTmFtZSA9PT0gJ3N0cmluZydcbiAgKSk7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gaXNOb2RlO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGlzVGV4dElucHV0RWxlbWVudFxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG4vKipcbiAqIEBzZWUgaHR0cDovL3d3dy53aGF0d2cub3JnL3NwZWNzL3dlYi1hcHBzL2N1cnJlbnQtd29yay9tdWx0aXBhZ2UvdGhlLWlucHV0LWVsZW1lbnQuaHRtbCNpbnB1dC10eXBlLWF0dHItc3VtbWFyeVxuICovXG52YXIgc3VwcG9ydGVkSW5wdXRUeXBlcyA9IHtcbiAgJ2NvbG9yJzogdHJ1ZSxcbiAgJ2RhdGUnOiB0cnVlLFxuICAnZGF0ZXRpbWUnOiB0cnVlLFxuICAnZGF0ZXRpbWUtbG9jYWwnOiB0cnVlLFxuICAnZW1haWwnOiB0cnVlLFxuICAnbW9udGgnOiB0cnVlLFxuICAnbnVtYmVyJzogdHJ1ZSxcbiAgJ3Bhc3N3b3JkJzogdHJ1ZSxcbiAgJ3JhbmdlJzogdHJ1ZSxcbiAgJ3NlYXJjaCc6IHRydWUsXG4gICd0ZWwnOiB0cnVlLFxuICAndGV4dCc6IHRydWUsXG4gICd0aW1lJzogdHJ1ZSxcbiAgJ3VybCc6IHRydWUsXG4gICd3ZWVrJzogdHJ1ZVxufTtcblxuZnVuY3Rpb24gaXNUZXh0SW5wdXRFbGVtZW50KGVsZW0pIHtcbiAgcmV0dXJuIGVsZW0gJiYgKFxuICAgIChlbGVtLm5vZGVOYW1lID09PSAnSU5QVVQnICYmIHN1cHBvcnRlZElucHV0VHlwZXNbZWxlbS50eXBlXSkgfHxcbiAgICBlbGVtLm5vZGVOYW1lID09PSAnVEVYVEFSRUEnXG4gICk7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gaXNUZXh0SW5wdXRFbGVtZW50O1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGlzVGV4dE5vZGVcbiAqIEB0eXBlY2hlY2tzXG4gKi9cblxudmFyIGlzTm9kZSA9IHJlcXVpcmUoXCIuL2lzTm9kZVwiKTtcblxuLyoqXG4gKiBAcGFyYW0geyp9IG9iamVjdCBUaGUgb2JqZWN0IHRvIGNoZWNrLlxuICogQHJldHVybiB7Ym9vbGVhbn0gV2hldGhlciBvciBub3QgdGhlIG9iamVjdCBpcyBhIERPTSB0ZXh0IG5vZGUuXG4gKi9cbmZ1bmN0aW9uIGlzVGV4dE5vZGUob2JqZWN0KSB7XG4gIHJldHVybiBpc05vZGUob2JqZWN0KSAmJiBvYmplY3Qubm9kZVR5cGUgPT0gMztcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBpc1RleHROb2RlO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGpvaW5DbGFzc2VzXG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG4vKipcbiAqIENvbWJpbmVzIG11bHRpcGxlIGNsYXNzTmFtZSBzdHJpbmdzIGludG8gb25lLlxuICogaHR0cDovL2pzcGVyZi5jb20vam9pbmNsYXNzZXMtYXJncy12cy1hcnJheVxuICpcbiAqIEBwYXJhbSB7Li4uP3N0cmluZ30gY2xhc3Nlc1xuICogQHJldHVybiB7c3RyaW5nfVxuICovXG5mdW5jdGlvbiBqb2luQ2xhc3NlcyhjbGFzc05hbWUvKiwgLi4uICovKSB7XG4gIGlmICghY2xhc3NOYW1lKSB7XG4gICAgY2xhc3NOYW1lID0gJyc7XG4gIH1cbiAgdmFyIG5leHRDbGFzcztcbiAgdmFyIGFyZ0xlbmd0aCA9IGFyZ3VtZW50cy5sZW5ndGg7XG4gIGlmIChhcmdMZW5ndGggPiAxKSB7XG4gICAgZm9yICh2YXIgaWkgPSAxOyBpaSA8IGFyZ0xlbmd0aDsgaWkrKykge1xuICAgICAgbmV4dENsYXNzID0gYXJndW1lbnRzW2lpXTtcbiAgICAgIGlmIChuZXh0Q2xhc3MpIHtcbiAgICAgICAgY2xhc3NOYW1lID0gKGNsYXNzTmFtZSA/IGNsYXNzTmFtZSArICcgJyA6ICcnKSArIG5leHRDbGFzcztcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgcmV0dXJuIGNsYXNzTmFtZTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBqb2luQ2xhc3NlcztcbiIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUga2V5TWlycm9yXG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG4vKipcbiAqIENvbnN0cnVjdHMgYW4gZW51bWVyYXRpb24gd2l0aCBrZXlzIGVxdWFsIHRvIHRoZWlyIHZhbHVlLlxuICpcbiAqIEZvciBleGFtcGxlOlxuICpcbiAqICAgdmFyIENPTE9SUyA9IGtleU1pcnJvcih7Ymx1ZTogbnVsbCwgcmVkOiBudWxsfSk7XG4gKiAgIHZhciBteUNvbG9yID0gQ09MT1JTLmJsdWU7XG4gKiAgIHZhciBpc0NvbG9yVmFsaWQgPSAhIUNPTE9SU1tteUNvbG9yXTtcbiAqXG4gKiBUaGUgbGFzdCBsaW5lIGNvdWxkIG5vdCBiZSBwZXJmb3JtZWQgaWYgdGhlIHZhbHVlcyBvZiB0aGUgZ2VuZXJhdGVkIGVudW0gd2VyZVxuICogbm90IGVxdWFsIHRvIHRoZWlyIGtleXMuXG4gKlxuICogICBJbnB1dDogIHtrZXkxOiB2YWwxLCBrZXkyOiB2YWwyfVxuICogICBPdXRwdXQ6IHtrZXkxOiBrZXkxLCBrZXkyOiBrZXkyfVxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBvYmpcbiAqIEByZXR1cm4ge29iamVjdH1cbiAqL1xudmFyIGtleU1pcnJvciA9IGZ1bmN0aW9uKG9iaikge1xuICB2YXIgcmV0ID0ge307XG4gIHZhciBrZXk7XG4gIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgb2JqIGluc3RhbmNlb2YgT2JqZWN0ICYmICFBcnJheS5pc0FycmF5KG9iaiksXG4gICAgJ2tleU1pcnJvciguLi4pOiBBcmd1bWVudCBtdXN0IGJlIGFuIG9iamVjdC4nXG4gICkgOiBpbnZhcmlhbnQob2JqIGluc3RhbmNlb2YgT2JqZWN0ICYmICFBcnJheS5pc0FycmF5KG9iaikpKTtcbiAgZm9yIChrZXkgaW4gb2JqKSB7XG4gICAgaWYgKCFvYmouaGFzT3duUHJvcGVydHkoa2V5KSkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIHJldFtrZXldID0ga2V5O1xuICB9XG4gIHJldHVybiByZXQ7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IGtleU1pcnJvcjtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGtleU9mXG4gKi9cblxuLyoqXG4gKiBBbGxvd3MgZXh0cmFjdGlvbiBvZiBhIG1pbmlmaWVkIGtleS4gTGV0J3MgdGhlIGJ1aWxkIHN5c3RlbSBtaW5pZnkga2V5c1xuICogd2l0aG91dCBsb29zaW5nIHRoZSBhYmlsaXR5IHRvIGR5bmFtaWNhbGx5IHVzZSBrZXkgc3RyaW5ncyBhcyB2YWx1ZXNcbiAqIHRoZW1zZWx2ZXMuIFBhc3MgaW4gYW4gb2JqZWN0IHdpdGggYSBzaW5nbGUga2V5L3ZhbCBwYWlyIGFuZCBpdCB3aWxsIHJldHVyblxuICogeW91IHRoZSBzdHJpbmcga2V5IG9mIHRoYXQgc2luZ2xlIHJlY29yZC4gU3VwcG9zZSB5b3Ugd2FudCB0byBncmFiIHRoZVxuICogdmFsdWUgZm9yIGEga2V5ICdjbGFzc05hbWUnIGluc2lkZSBvZiBhbiBvYmplY3QuIEtleS92YWwgbWluaWZpY2F0aW9uIG1heVxuICogaGF2ZSBhbGlhc2VkIHRoYXQga2V5IHRvIGJlICd4YTEyJy4ga2V5T2Yoe2NsYXNzTmFtZTogbnVsbH0pIHdpbGwgcmV0dXJuXG4gKiAneGExMicgaW4gdGhhdCBjYXNlLiBSZXNvbHZlIGtleXMgeW91IHdhbnQgdG8gdXNlIG9uY2UgYXQgc3RhcnR1cCB0aW1lLCB0aGVuXG4gKiByZXVzZSB0aG9zZSByZXNvbHV0aW9ucy5cbiAqL1xudmFyIGtleU9mID0gZnVuY3Rpb24ob25lS2V5T2JqKSB7XG4gIHZhciBrZXk7XG4gIGZvciAoa2V5IGluIG9uZUtleU9iaikge1xuICAgIGlmICghb25lS2V5T2JqLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICByZXR1cm4ga2V5O1xuICB9XG4gIHJldHVybiBudWxsO1xufTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IGtleU9mO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIG1hcE9iamVjdFxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIGhhc093blByb3BlcnR5ID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eTtcblxuLyoqXG4gKiBFeGVjdXRlcyB0aGUgcHJvdmlkZWQgYGNhbGxiYWNrYCBvbmNlIGZvciBlYWNoIGVudW1lcmFibGUgb3duIHByb3BlcnR5IGluIHRoZVxuICogb2JqZWN0IGFuZCBjb25zdHJ1Y3RzIGEgbmV3IG9iamVjdCBmcm9tIHRoZSByZXN1bHRzLiBUaGUgYGNhbGxiYWNrYCBpc1xuICogaW52b2tlZCB3aXRoIHRocmVlIGFyZ3VtZW50czpcbiAqXG4gKiAgLSB0aGUgcHJvcGVydHkgdmFsdWVcbiAqICAtIHRoZSBwcm9wZXJ0eSBuYW1lXG4gKiAgLSB0aGUgb2JqZWN0IGJlaW5nIHRyYXZlcnNlZFxuICpcbiAqIFByb3BlcnRpZXMgdGhhdCBhcmUgYWRkZWQgYWZ0ZXIgdGhlIGNhbGwgdG8gYG1hcE9iamVjdGAgd2lsbCBub3QgYmUgdmlzaXRlZFxuICogYnkgYGNhbGxiYWNrYC4gSWYgdGhlIHZhbHVlcyBvZiBleGlzdGluZyBwcm9wZXJ0aWVzIGFyZSBjaGFuZ2VkLCB0aGUgdmFsdWVcbiAqIHBhc3NlZCB0byBgY2FsbGJhY2tgIHdpbGwgYmUgdGhlIHZhbHVlIGF0IHRoZSB0aW1lIGBtYXBPYmplY3RgIHZpc2l0cyB0aGVtLlxuICogUHJvcGVydGllcyB0aGF0IGFyZSBkZWxldGVkIGJlZm9yZSBiZWluZyB2aXNpdGVkIGFyZSBub3QgdmlzaXRlZC5cbiAqXG4gKiBAZ3JlcCBmdW5jdGlvbiBvYmplY3RNYXAoKVxuICogQGdyZXAgZnVuY3Rpb24gb2JqTWFwKClcbiAqXG4gKiBAcGFyYW0gez9vYmplY3R9IG9iamVjdFxuICogQHBhcmFtIHtmdW5jdGlvbn0gY2FsbGJhY2tcbiAqIEBwYXJhbSB7Kn0gY29udGV4dFxuICogQHJldHVybiB7P29iamVjdH1cbiAqL1xuZnVuY3Rpb24gbWFwT2JqZWN0KG9iamVjdCwgY2FsbGJhY2ssIGNvbnRleHQpIHtcbiAgaWYgKCFvYmplY3QpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuICB2YXIgcmVzdWx0ID0ge307XG4gIGZvciAodmFyIG5hbWUgaW4gb2JqZWN0KSB7XG4gICAgaWYgKGhhc093blByb3BlcnR5LmNhbGwob2JqZWN0LCBuYW1lKSkge1xuICAgICAgcmVzdWx0W25hbWVdID0gY2FsbGJhY2suY2FsbChjb250ZXh0LCBvYmplY3RbbmFtZV0sIG5hbWUsIG9iamVjdCk7XG4gICAgfVxuICB9XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gbWFwT2JqZWN0O1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIG1lbW9pemVTdHJpbmdPbmx5XG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG4vKipcbiAqIE1lbW9pemVzIHRoZSByZXR1cm4gdmFsdWUgb2YgYSBmdW5jdGlvbiB0aGF0IGFjY2VwdHMgb25lIHN0cmluZyBhcmd1bWVudC5cbiAqXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBjYWxsYmFja1xuICogQHJldHVybiB7ZnVuY3Rpb259XG4gKi9cbmZ1bmN0aW9uIG1lbW9pemVTdHJpbmdPbmx5KGNhbGxiYWNrKSB7XG4gIHZhciBjYWNoZSA9IHt9O1xuICByZXR1cm4gZnVuY3Rpb24oc3RyaW5nKSB7XG4gICAgaWYgKGNhY2hlLmhhc093blByb3BlcnR5KHN0cmluZykpIHtcbiAgICAgIHJldHVybiBjYWNoZVtzdHJpbmddO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gY2FjaGVbc3RyaW5nXSA9IGNhbGxiYWNrLmNhbGwodGhpcywgc3RyaW5nKTtcbiAgICB9XG4gIH07XG59XG5cbm1vZHVsZS5leHBvcnRzID0gbWVtb2l6ZVN0cmluZ09ubHk7XG4iLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBtb25pdG9yQ29kZVVzZVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG4vKipcbiAqIFByb3ZpZGVzIG9wZW4tc291cmNlIGNvbXBhdGlibGUgaW5zdHJ1bWVudGF0aW9uIGZvciBtb25pdG9yaW5nIGNlcnRhaW4gQVBJXG4gKiB1c2VzIGJlZm9yZSB3ZSdyZSByZWFkeSB0byBpc3N1ZSBhIHdhcm5pbmcgb3IgcmVmYWN0b3IuIEl0IGFjY2VwdHMgYW4gZXZlbnRcbiAqIG5hbWUgd2hpY2ggbWF5IG9ubHkgY29udGFpbiB0aGUgY2hhcmFjdGVycyBbYS16MC05X10gYW5kIGFuIG9wdGlvbmFsIGRhdGFcbiAqIG9iamVjdCB3aXRoIGZ1cnRoZXIgaW5mb3JtYXRpb24uXG4gKi9cblxuZnVuY3Rpb24gbW9uaXRvckNvZGVVc2UoZXZlbnROYW1lLCBkYXRhKSB7XG4gIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgZXZlbnROYW1lICYmICEvW15hLXowLTlfXS8udGVzdChldmVudE5hbWUpLFxuICAgICdZb3UgbXVzdCBwcm92aWRlIGFuIGV2ZW50TmFtZSB1c2luZyBvbmx5IHRoZSBjaGFyYWN0ZXJzIFthLXowLTlfXSdcbiAgKSA6IGludmFyaWFudChldmVudE5hbWUgJiYgIS9bXmEtejAtOV9dLy50ZXN0KGV2ZW50TmFtZSkpKTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBtb25pdG9yQ29kZVVzZTtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBvbmx5Q2hpbGRcbiAqL1xuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBSZWFjdEVsZW1lbnQgPSByZXF1aXJlKFwiLi9SZWFjdEVsZW1lbnRcIik7XG5cbnZhciBpbnZhcmlhbnQgPSByZXF1aXJlKFwiLi9pbnZhcmlhbnRcIik7XG5cbi8qKlxuICogUmV0dXJucyB0aGUgZmlyc3QgY2hpbGQgaW4gYSBjb2xsZWN0aW9uIG9mIGNoaWxkcmVuIGFuZCB2ZXJpZmllcyB0aGF0IHRoZXJlXG4gKiBpcyBvbmx5IG9uZSBjaGlsZCBpbiB0aGUgY29sbGVjdGlvbi4gVGhlIGN1cnJlbnQgaW1wbGVtZW50YXRpb24gb2YgdGhpc1xuICogZnVuY3Rpb24gYXNzdW1lcyB0aGF0IGEgc2luZ2xlIGNoaWxkIGdldHMgcGFzc2VkIHdpdGhvdXQgYSB3cmFwcGVyLCBidXQgdGhlXG4gKiBwdXJwb3NlIG9mIHRoaXMgaGVscGVyIGZ1bmN0aW9uIGlzIHRvIGFic3RyYWN0IGF3YXkgdGhlIHBhcnRpY3VsYXIgc3RydWN0dXJlXG4gKiBvZiBjaGlsZHJlbi5cbiAqXG4gKiBAcGFyYW0gez9vYmplY3R9IGNoaWxkcmVuIENoaWxkIGNvbGxlY3Rpb24gc3RydWN0dXJlLlxuICogQHJldHVybiB7UmVhY3RDb21wb25lbnR9IFRoZSBmaXJzdCBhbmQgb25seSBgUmVhY3RDb21wb25lbnRgIGNvbnRhaW5lZCBpbiB0aGVcbiAqIHN0cnVjdHVyZS5cbiAqL1xuZnVuY3Rpb24gb25seUNoaWxkKGNoaWxkcmVuKSB7XG4gIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgUmVhY3RFbGVtZW50LmlzVmFsaWRFbGVtZW50KGNoaWxkcmVuKSxcbiAgICAnb25seUNoaWxkIG11c3QgYmUgcGFzc2VkIGEgY2hpbGRyZW4gd2l0aCBleGFjdGx5IG9uZSBjaGlsZC4nXG4gICkgOiBpbnZhcmlhbnQoUmVhY3RFbGVtZW50LmlzVmFsaWRFbGVtZW50KGNoaWxkcmVuKSkpO1xuICByZXR1cm4gY2hpbGRyZW47XG59XG5cbm1vZHVsZS5leHBvcnRzID0gb25seUNoaWxkO1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgcGVyZm9ybWFuY2VcbiAqIEB0eXBlY2hlY2tzXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBFeGVjdXRpb25FbnZpcm9ubWVudCA9IHJlcXVpcmUoXCIuL0V4ZWN1dGlvbkVudmlyb25tZW50XCIpO1xuXG52YXIgcGVyZm9ybWFuY2U7XG5cbmlmIChFeGVjdXRpb25FbnZpcm9ubWVudC5jYW5Vc2VET00pIHtcbiAgcGVyZm9ybWFuY2UgPVxuICAgIHdpbmRvdy5wZXJmb3JtYW5jZSB8fFxuICAgIHdpbmRvdy5tc1BlcmZvcm1hbmNlIHx8XG4gICAgd2luZG93LndlYmtpdFBlcmZvcm1hbmNlO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHBlcmZvcm1hbmNlIHx8IHt9O1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIHBlcmZvcm1hbmNlTm93XG4gKiBAdHlwZWNoZWNrc1xuICovXG5cbnZhciBwZXJmb3JtYW5jZSA9IHJlcXVpcmUoXCIuL3BlcmZvcm1hbmNlXCIpO1xuXG4vKipcbiAqIERldGVjdCBpZiB3ZSBjYW4gdXNlIGB3aW5kb3cucGVyZm9ybWFuY2Uubm93KClgIGFuZCBncmFjZWZ1bGx5IGZhbGxiYWNrIHRvXG4gKiBgRGF0ZS5ub3coKWAgaWYgaXQgZG9lc24ndCBleGlzdC4gV2UgbmVlZCB0byBzdXBwb3J0IEZpcmVmb3ggPCAxNSBmb3Igbm93XG4gKiBiZWNhdXNlIG9mIEZhY2Vib29rJ3MgdGVzdGluZyBpbmZyYXN0cnVjdHVyZS5cbiAqL1xuaWYgKCFwZXJmb3JtYW5jZSB8fCAhcGVyZm9ybWFuY2Uubm93KSB7XG4gIHBlcmZvcm1hbmNlID0gRGF0ZTtcbn1cblxudmFyIHBlcmZvcm1hbmNlTm93ID0gcGVyZm9ybWFuY2Uubm93LmJpbmQocGVyZm9ybWFuY2UpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHBlcmZvcm1hbmNlTm93O1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIHNldElubmVySFRNTFxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgRXhlY3V0aW9uRW52aXJvbm1lbnQgPSByZXF1aXJlKFwiLi9FeGVjdXRpb25FbnZpcm9ubWVudFwiKTtcblxudmFyIFdISVRFU1BBQ0VfVEVTVCA9IC9eWyBcXHJcXG5cXHRcXGZdLztcbnZhciBOT05WSVNJQkxFX1RFU1QgPSAvPCghLS18bGlua3xub3NjcmlwdHxtZXRhfHNjcmlwdHxzdHlsZSlbIFxcclxcblxcdFxcZlxcLz5dLztcblxuLyoqXG4gKiBTZXQgdGhlIGlubmVySFRNTCBwcm9wZXJ0eSBvZiBhIG5vZGUsIGVuc3VyaW5nIHRoYXQgd2hpdGVzcGFjZSBpcyBwcmVzZXJ2ZWRcbiAqIGV2ZW4gaW4gSUU4LlxuICpcbiAqIEBwYXJhbSB7RE9NRWxlbWVudH0gbm9kZVxuICogQHBhcmFtIHtzdHJpbmd9IGh0bWxcbiAqIEBpbnRlcm5hbFxuICovXG52YXIgc2V0SW5uZXJIVE1MID0gZnVuY3Rpb24obm9kZSwgaHRtbCkge1xuICBub2RlLmlubmVySFRNTCA9IGh0bWw7XG59O1xuXG5pZiAoRXhlY3V0aW9uRW52aXJvbm1lbnQuY2FuVXNlRE9NKSB7XG4gIC8vIElFODogV2hlbiB1cGRhdGluZyBhIGp1c3QgY3JlYXRlZCBub2RlIHdpdGggaW5uZXJIVE1MIG9ubHkgbGVhZGluZ1xuICAvLyB3aGl0ZXNwYWNlIGlzIHJlbW92ZWQuIFdoZW4gdXBkYXRpbmcgYW4gZXhpc3Rpbmcgbm9kZSB3aXRoIGlubmVySFRNTFxuICAvLyB3aGl0ZXNwYWNlIGluIHJvb3QgVGV4dE5vZGVzIGlzIGFsc28gY29sbGFwc2VkLlxuICAvLyBAc2VlIHF1aXJrc21vZGUub3JnL2J1Z3JlcG9ydHMvYXJjaGl2ZXMvMjAwNC8xMS9pbm5lcmh0bWxfYW5kX3QuaHRtbFxuXG4gIC8vIEZlYXR1cmUgZGV0ZWN0aW9uOyBvbmx5IElFOCBpcyBrbm93biB0byBiZWhhdmUgaW1wcm9wZXJseSBsaWtlIHRoaXMuXG4gIHZhciB0ZXN0RWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICB0ZXN0RWxlbWVudC5pbm5lckhUTUwgPSAnICc7XG4gIGlmICh0ZXN0RWxlbWVudC5pbm5lckhUTUwgPT09ICcnKSB7XG4gICAgc2V0SW5uZXJIVE1MID0gZnVuY3Rpb24obm9kZSwgaHRtbCkge1xuICAgICAgLy8gTWFnaWMgdGhlb3J5OiBJRTggc3VwcG9zZWRseSBkaWZmZXJlbnRpYXRlcyBiZXR3ZWVuIGFkZGVkIGFuZCB1cGRhdGVkXG4gICAgICAvLyBub2RlcyB3aGVuIHByb2Nlc3NpbmcgaW5uZXJIVE1MLCBpbm5lckhUTUwgb24gdXBkYXRlZCBub2RlcyBzdWZmZXJzXG4gICAgICAvLyBmcm9tIHdvcnNlIHdoaXRlc3BhY2UgYmVoYXZpb3IuIFJlLWFkZGluZyBhIG5vZGUgbGlrZSB0aGlzIHRyaWdnZXJzXG4gICAgICAvLyB0aGUgaW5pdGlhbCBhbmQgbW9yZSBmYXZvcmFibGUgd2hpdGVzcGFjZSBiZWhhdmlvci5cbiAgICAgIC8vIFRPRE86IFdoYXQgdG8gZG8gb24gYSBkZXRhY2hlZCBub2RlP1xuICAgICAgaWYgKG5vZGUucGFyZW50Tm9kZSkge1xuICAgICAgICBub2RlLnBhcmVudE5vZGUucmVwbGFjZUNoaWxkKG5vZGUsIG5vZGUpO1xuICAgICAgfVxuXG4gICAgICAvLyBXZSBhbHNvIGltcGxlbWVudCBhIHdvcmthcm91bmQgZm9yIG5vbi12aXNpYmxlIHRhZ3MgZGlzYXBwZWFyaW5nIGludG9cbiAgICAgIC8vIHRoaW4gYWlyIG9uIElFOCwgdGhpcyBvbmx5IGhhcHBlbnMgaWYgdGhlcmUgaXMgbm8gdmlzaWJsZSB0ZXh0XG4gICAgICAvLyBpbi1mcm9udCBvZiB0aGUgbm9uLXZpc2libGUgdGFncy4gUGlnZ3liYWNrIG9uIHRoZSB3aGl0ZXNwYWNlIGZpeFxuICAgICAgLy8gYW5kIHNpbXBseSBjaGVjayBpZiBhbnkgbm9uLXZpc2libGUgdGFncyBhcHBlYXIgaW4gdGhlIHNvdXJjZS5cbiAgICAgIGlmIChXSElURVNQQUNFX1RFU1QudGVzdChodG1sKSB8fFxuICAgICAgICAgIGh0bWxbMF0gPT09ICc8JyAmJiBOT05WSVNJQkxFX1RFU1QudGVzdChodG1sKSkge1xuICAgICAgICAvLyBSZWNvdmVyIGxlYWRpbmcgd2hpdGVzcGFjZSBieSB0ZW1wb3JhcmlseSBwcmVwZW5kaW5nIGFueSBjaGFyYWN0ZXIuXG4gICAgICAgIC8vIFxcdUZFRkYgaGFzIHRoZSBwb3RlbnRpYWwgYWR2YW50YWdlIG9mIGJlaW5nIHplcm8td2lkdGgvaW52aXNpYmxlLlxuICAgICAgICBub2RlLmlubmVySFRNTCA9ICdcXHVGRUZGJyArIGh0bWw7XG5cbiAgICAgICAgLy8gZGVsZXRlRGF0YSBsZWF2ZXMgYW4gZW1wdHkgYFRleHROb2RlYCB3aGljaCBvZmZzZXRzIHRoZSBpbmRleCBvZiBhbGxcbiAgICAgICAgLy8gY2hpbGRyZW4uIERlZmluaXRlbHkgd2FudCB0byBhdm9pZCB0aGlzLlxuICAgICAgICB2YXIgdGV4dE5vZGUgPSBub2RlLmZpcnN0Q2hpbGQ7XG4gICAgICAgIGlmICh0ZXh0Tm9kZS5kYXRhLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgIG5vZGUucmVtb3ZlQ2hpbGQodGV4dE5vZGUpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRleHROb2RlLmRlbGV0ZURhdGEoMCwgMSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG5vZGUuaW5uZXJIVE1MID0gaHRtbDtcbiAgICAgIH1cbiAgICB9O1xuICB9XG59XG5cbm1vZHVsZS5leHBvcnRzID0gc2V0SW5uZXJIVE1MO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIHNoYWxsb3dFcXVhbFxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG4vKipcbiAqIFBlcmZvcm1zIGVxdWFsaXR5IGJ5IGl0ZXJhdGluZyB0aHJvdWdoIGtleXMgb24gYW4gb2JqZWN0IGFuZCByZXR1cm5pbmdcbiAqIGZhbHNlIHdoZW4gYW55IGtleSBoYXMgdmFsdWVzIHdoaWNoIGFyZSBub3Qgc3RyaWN0bHkgZXF1YWwgYmV0d2VlblxuICogb2JqQSBhbmQgb2JqQi4gUmV0dXJucyB0cnVlIHdoZW4gdGhlIHZhbHVlcyBvZiBhbGwga2V5cyBhcmUgc3RyaWN0bHkgZXF1YWwuXG4gKlxuICogQHJldHVybiB7Ym9vbGVhbn1cbiAqL1xuZnVuY3Rpb24gc2hhbGxvd0VxdWFsKG9iakEsIG9iakIpIHtcbiAgaWYgKG9iakEgPT09IG9iakIpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuICB2YXIga2V5O1xuICAvLyBUZXN0IGZvciBBJ3Mga2V5cyBkaWZmZXJlbnQgZnJvbSBCLlxuICBmb3IgKGtleSBpbiBvYmpBKSB7XG4gICAgaWYgKG9iakEuaGFzT3duUHJvcGVydHkoa2V5KSAmJlxuICAgICAgICAoIW9iakIuaGFzT3duUHJvcGVydHkoa2V5KSB8fCBvYmpBW2tleV0gIT09IG9iakJba2V5XSkpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cbiAgLy8gVGVzdCBmb3IgQidzIGtleXMgbWlzc2luZyBmcm9tIEEuXG4gIGZvciAoa2V5IGluIG9iakIpIHtcbiAgICBpZiAob2JqQi5oYXNPd25Qcm9wZXJ0eShrZXkpICYmICFvYmpBLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHRydWU7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gc2hhbGxvd0VxdWFsO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIHNob3VsZFVwZGF0ZVJlYWN0Q29tcG9uZW50XG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG4vKipcbiAqIEdpdmVuIGEgYHByZXZFbGVtZW50YCBhbmQgYG5leHRFbGVtZW50YCwgZGV0ZXJtaW5lcyBpZiB0aGUgZXhpc3RpbmdcbiAqIGluc3RhbmNlIHNob3VsZCBiZSB1cGRhdGVkIGFzIG9wcG9zZWQgdG8gYmVpbmcgZGVzdHJveWVkIG9yIHJlcGxhY2VkIGJ5IGEgbmV3XG4gKiBpbnN0YW5jZS4gQm90aCBhcmd1bWVudHMgYXJlIGVsZW1lbnRzLiBUaGlzIGVuc3VyZXMgdGhhdCB0aGlzIGxvZ2ljIGNhblxuICogb3BlcmF0ZSBvbiBzdGF0ZWxlc3MgdHJlZXMgd2l0aG91dCBhbnkgYmFja2luZyBpbnN0YW5jZS5cbiAqXG4gKiBAcGFyYW0gez9vYmplY3R9IHByZXZFbGVtZW50XG4gKiBAcGFyYW0gez9vYmplY3R9IG5leHRFbGVtZW50XG4gKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIHRoZSBleGlzdGluZyBpbnN0YW5jZSBzaG91bGQgYmUgdXBkYXRlZC5cbiAqIEBwcm90ZWN0ZWRcbiAqL1xuZnVuY3Rpb24gc2hvdWxkVXBkYXRlUmVhY3RDb21wb25lbnQocHJldkVsZW1lbnQsIG5leHRFbGVtZW50KSB7XG4gIGlmIChwcmV2RWxlbWVudCAmJiBuZXh0RWxlbWVudCAmJlxuICAgICAgcHJldkVsZW1lbnQudHlwZSA9PT0gbmV4dEVsZW1lbnQudHlwZSAmJlxuICAgICAgcHJldkVsZW1lbnQua2V5ID09PSBuZXh0RWxlbWVudC5rZXkgJiZcbiAgICAgIHByZXZFbGVtZW50Ll9vd25lciA9PT0gbmV4dEVsZW1lbnQuX293bmVyKSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbiAgcmV0dXJuIGZhbHNlO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHNob3VsZFVwZGF0ZVJlYWN0Q29tcG9uZW50O1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgdG9BcnJheVxuICogQHR5cGVjaGVja3NcbiAqL1xuXG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG4vKipcbiAqIENvbnZlcnQgYXJyYXktbGlrZSBvYmplY3RzIHRvIGFycmF5cy5cbiAqXG4gKiBUaGlzIEFQSSBhc3N1bWVzIHRoZSBjYWxsZXIga25vd3MgdGhlIGNvbnRlbnRzIG9mIHRoZSBkYXRhIHR5cGUuIEZvciBsZXNzXG4gKiB3ZWxsIGRlZmluZWQgaW5wdXRzIHVzZSBjcmVhdGVBcnJheUZyb20uXG4gKlxuICogQHBhcmFtIHtvYmplY3R8ZnVuY3Rpb258ZmlsZWxpc3R9IG9ialxuICogQHJldHVybiB7YXJyYXl9XG4gKi9cbmZ1bmN0aW9uIHRvQXJyYXkob2JqKSB7XG4gIHZhciBsZW5ndGggPSBvYmoubGVuZ3RoO1xuXG4gIC8vIFNvbWUgYnJvd3NlIGJ1aWx0aW4gb2JqZWN0cyBjYW4gcmVwb3J0IHR5cGVvZiAnZnVuY3Rpb24nIChlLmcuIE5vZGVMaXN0IGluXG4gIC8vIG9sZCB2ZXJzaW9ucyBvZiBTYWZhcmkpLlxuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICFBcnJheS5pc0FycmF5KG9iaikgJiZcbiAgICAodHlwZW9mIG9iaiA9PT0gJ29iamVjdCcgfHwgdHlwZW9mIG9iaiA9PT0gJ2Z1bmN0aW9uJyksXG4gICAgJ3RvQXJyYXk6IEFycmF5LWxpa2Ugb2JqZWN0IGV4cGVjdGVkJ1xuICApIDogaW52YXJpYW50KCFBcnJheS5pc0FycmF5KG9iaikgJiZcbiAgKHR5cGVvZiBvYmogPT09ICdvYmplY3QnIHx8IHR5cGVvZiBvYmogPT09ICdmdW5jdGlvbicpKSk7XG5cbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICB0eXBlb2YgbGVuZ3RoID09PSAnbnVtYmVyJyxcbiAgICAndG9BcnJheTogT2JqZWN0IG5lZWRzIGEgbGVuZ3RoIHByb3BlcnR5J1xuICApIDogaW52YXJpYW50KHR5cGVvZiBsZW5ndGggPT09ICdudW1iZXInKSk7XG5cbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICBsZW5ndGggPT09IDAgfHxcbiAgICAobGVuZ3RoIC0gMSkgaW4gb2JqLFxuICAgICd0b0FycmF5OiBPYmplY3Qgc2hvdWxkIGhhdmUga2V5cyBmb3IgaW5kaWNlcydcbiAgKSA6IGludmFyaWFudChsZW5ndGggPT09IDAgfHxcbiAgKGxlbmd0aCAtIDEpIGluIG9iaikpO1xuXG4gIC8vIE9sZCBJRSBkb2Vzbid0IGdpdmUgY29sbGVjdGlvbnMgYWNjZXNzIHRvIGhhc093blByb3BlcnR5LiBBc3N1bWUgaW5wdXRzXG4gIC8vIHdpdGhvdXQgbWV0aG9kIHdpbGwgdGhyb3cgZHVyaW5nIHRoZSBzbGljZSBjYWxsIGFuZCBza2lwIHN0cmFpZ2h0IHRvIHRoZVxuICAvLyBmYWxsYmFjay5cbiAgaWYgKG9iai5oYXNPd25Qcm9wZXJ0eSkge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwob2JqKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAvLyBJRSA8IDkgZG9lcyBub3Qgc3VwcG9ydCBBcnJheSNzbGljZSBvbiBjb2xsZWN0aW9ucyBvYmplY3RzXG4gICAgfVxuICB9XG5cbiAgLy8gRmFsbCBiYWNrIHRvIGNvcHlpbmcga2V5IGJ5IGtleS4gVGhpcyBhc3N1bWVzIGFsbCBrZXlzIGhhdmUgYSB2YWx1ZSxcbiAgLy8gc28gd2lsbCBub3QgcHJlc2VydmUgc3BhcnNlbHkgcG9wdWxhdGVkIGlucHV0cy5cbiAgdmFyIHJldCA9IEFycmF5KGxlbmd0aCk7XG4gIGZvciAodmFyIGlpID0gMDsgaWkgPCBsZW5ndGg7IGlpKyspIHtcbiAgICByZXRbaWldID0gb2JqW2lpXTtcbiAgfVxuICByZXR1cm4gcmV0O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHRvQXJyYXk7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgdHJhdmVyc2VBbGxDaGlsZHJlblxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgUmVhY3RFbGVtZW50ID0gcmVxdWlyZShcIi4vUmVhY3RFbGVtZW50XCIpO1xudmFyIFJlYWN0SW5zdGFuY2VIYW5kbGVzID0gcmVxdWlyZShcIi4vUmVhY3RJbnN0YW5jZUhhbmRsZXNcIik7XG5cbnZhciBpbnZhcmlhbnQgPSByZXF1aXJlKFwiLi9pbnZhcmlhbnRcIik7XG5cbnZhciBTRVBBUkFUT1IgPSBSZWFjdEluc3RhbmNlSGFuZGxlcy5TRVBBUkFUT1I7XG52YXIgU1VCU0VQQVJBVE9SID0gJzonO1xuXG4vKipcbiAqIFRPRE86IFRlc3QgdGhhdDpcbiAqIDEuIGBtYXBDaGlsZHJlbmAgdHJhbnNmb3JtcyBzdHJpbmdzIGFuZCBudW1iZXJzIGludG8gYFJlYWN0VGV4dENvbXBvbmVudGAuXG4gKiAyLiBpdCgnc2hvdWxkIGZhaWwgd2hlbiBzdXBwbGllZCBkdXBsaWNhdGUga2V5JywgZnVuY3Rpb24oKSB7XG4gKiAzLiBUaGF0IGEgc2luZ2xlIGNoaWxkIGFuZCBhbiBhcnJheSB3aXRoIG9uZSBpdGVtIGhhdmUgdGhlIHNhbWUga2V5IHBhdHRlcm4uXG4gKiB9KTtcbiAqL1xuXG52YXIgdXNlclByb3ZpZGVkS2V5RXNjYXBlckxvb2t1cCA9IHtcbiAgJz0nOiAnPTAnLFxuICAnLic6ICc9MScsXG4gICc6JzogJz0yJ1xufTtcblxudmFyIHVzZXJQcm92aWRlZEtleUVzY2FwZVJlZ2V4ID0gL1s9LjpdL2c7XG5cbmZ1bmN0aW9uIHVzZXJQcm92aWRlZEtleUVzY2FwZXIobWF0Y2gpIHtcbiAgcmV0dXJuIHVzZXJQcm92aWRlZEtleUVzY2FwZXJMb29rdXBbbWF0Y2hdO1xufVxuXG4vKipcbiAqIEdlbmVyYXRlIGEga2V5IHN0cmluZyB0aGF0IGlkZW50aWZpZXMgYSBjb21wb25lbnQgd2l0aGluIGEgc2V0LlxuICpcbiAqIEBwYXJhbSB7Kn0gY29tcG9uZW50IEEgY29tcG9uZW50IHRoYXQgY291bGQgY29udGFpbiBhIG1hbnVhbCBrZXkuXG4gKiBAcGFyYW0ge251bWJlcn0gaW5kZXggSW5kZXggdGhhdCBpcyB1c2VkIGlmIGEgbWFudWFsIGtleSBpcyBub3QgcHJvdmlkZWQuXG4gKiBAcmV0dXJuIHtzdHJpbmd9XG4gKi9cbmZ1bmN0aW9uIGdldENvbXBvbmVudEtleShjb21wb25lbnQsIGluZGV4KSB7XG4gIGlmIChjb21wb25lbnQgJiYgY29tcG9uZW50LmtleSAhPSBudWxsKSB7XG4gICAgLy8gRXhwbGljaXQga2V5XG4gICAgcmV0dXJuIHdyYXBVc2VyUHJvdmlkZWRLZXkoY29tcG9uZW50LmtleSk7XG4gIH1cbiAgLy8gSW1wbGljaXQga2V5IGRldGVybWluZWQgYnkgdGhlIGluZGV4IGluIHRoZSBzZXRcbiAgcmV0dXJuIGluZGV4LnRvU3RyaW5nKDM2KTtcbn1cblxuLyoqXG4gKiBFc2NhcGUgYSBjb21wb25lbnQga2V5IHNvIHRoYXQgaXQgaXMgc2FmZSB0byB1c2UgaW4gYSByZWFjdGlkLlxuICpcbiAqIEBwYXJhbSB7Kn0ga2V5IENvbXBvbmVudCBrZXkgdG8gYmUgZXNjYXBlZC5cbiAqIEByZXR1cm4ge3N0cmluZ30gQW4gZXNjYXBlZCBzdHJpbmcuXG4gKi9cbmZ1bmN0aW9uIGVzY2FwZVVzZXJQcm92aWRlZEtleSh0ZXh0KSB7XG4gIHJldHVybiAoJycgKyB0ZXh0KS5yZXBsYWNlKFxuICAgIHVzZXJQcm92aWRlZEtleUVzY2FwZVJlZ2V4LFxuICAgIHVzZXJQcm92aWRlZEtleUVzY2FwZXJcbiAgKTtcbn1cblxuLyoqXG4gKiBXcmFwIGEgYGtleWAgdmFsdWUgZXhwbGljaXRseSBwcm92aWRlZCBieSB0aGUgdXNlciB0byBkaXN0aW5ndWlzaCBpdCBmcm9tXG4gKiBpbXBsaWNpdGx5LWdlbmVyYXRlZCBrZXlzIGdlbmVyYXRlZCBieSBhIGNvbXBvbmVudCdzIGluZGV4IGluIGl0cyBwYXJlbnQuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGtleSBWYWx1ZSBvZiBhIHVzZXItcHJvdmlkZWQgYGtleWAgYXR0cmlidXRlXG4gKiBAcmV0dXJuIHtzdHJpbmd9XG4gKi9cbmZ1bmN0aW9uIHdyYXBVc2VyUHJvdmlkZWRLZXkoa2V5KSB7XG4gIHJldHVybiAnJCcgKyBlc2NhcGVVc2VyUHJvdmlkZWRLZXkoa2V5KTtcbn1cblxuLyoqXG4gKiBAcGFyYW0gez8qfSBjaGlsZHJlbiBDaGlsZHJlbiB0cmVlIGNvbnRhaW5lci5cbiAqIEBwYXJhbSB7IXN0cmluZ30gbmFtZVNvRmFyIE5hbWUgb2YgdGhlIGtleSBwYXRoIHNvIGZhci5cbiAqIEBwYXJhbSB7IW51bWJlcn0gaW5kZXhTb0ZhciBOdW1iZXIgb2YgY2hpbGRyZW4gZW5jb3VudGVyZWQgdW50aWwgdGhpcyBwb2ludC5cbiAqIEBwYXJhbSB7IWZ1bmN0aW9ufSBjYWxsYmFjayBDYWxsYmFjayB0byBpbnZva2Ugd2l0aCBlYWNoIGNoaWxkIGZvdW5kLlxuICogQHBhcmFtIHs/Kn0gdHJhdmVyc2VDb250ZXh0IFVzZWQgdG8gcGFzcyBpbmZvcm1hdGlvbiB0aHJvdWdob3V0IHRoZSB0cmF2ZXJzYWxcbiAqIHByb2Nlc3MuXG4gKiBAcmV0dXJuIHshbnVtYmVyfSBUaGUgbnVtYmVyIG9mIGNoaWxkcmVuIGluIHRoaXMgc3VidHJlZS5cbiAqL1xudmFyIHRyYXZlcnNlQWxsQ2hpbGRyZW5JbXBsID1cbiAgZnVuY3Rpb24oY2hpbGRyZW4sIG5hbWVTb0ZhciwgaW5kZXhTb0ZhciwgY2FsbGJhY2ssIHRyYXZlcnNlQ29udGV4dCkge1xuICAgIHZhciBuZXh0TmFtZSwgbmV4dEluZGV4O1xuICAgIHZhciBzdWJ0cmVlQ291bnQgPSAwOyAgLy8gQ291bnQgb2YgY2hpbGRyZW4gZm91bmQgaW4gdGhlIGN1cnJlbnQgc3VidHJlZS5cbiAgICBpZiAoQXJyYXkuaXNBcnJheShjaGlsZHJlbikpIHtcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY2hpbGRyZW4ubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGNoaWxkID0gY2hpbGRyZW5baV07XG4gICAgICAgIG5leHROYW1lID0gKFxuICAgICAgICAgIG5hbWVTb0ZhciArXG4gICAgICAgICAgKG5hbWVTb0ZhciA/IFNVQlNFUEFSQVRPUiA6IFNFUEFSQVRPUikgK1xuICAgICAgICAgIGdldENvbXBvbmVudEtleShjaGlsZCwgaSlcbiAgICAgICAgKTtcbiAgICAgICAgbmV4dEluZGV4ID0gaW5kZXhTb0ZhciArIHN1YnRyZWVDb3VudDtcbiAgICAgICAgc3VidHJlZUNvdW50ICs9IHRyYXZlcnNlQWxsQ2hpbGRyZW5JbXBsKFxuICAgICAgICAgIGNoaWxkLFxuICAgICAgICAgIG5leHROYW1lLFxuICAgICAgICAgIG5leHRJbmRleCxcbiAgICAgICAgICBjYWxsYmFjayxcbiAgICAgICAgICB0cmF2ZXJzZUNvbnRleHRcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdmFyIHR5cGUgPSB0eXBlb2YgY2hpbGRyZW47XG4gICAgICB2YXIgaXNPbmx5Q2hpbGQgPSBuYW1lU29GYXIgPT09ICcnO1xuICAgICAgLy8gSWYgaXQncyB0aGUgb25seSBjaGlsZCwgdHJlYXQgdGhlIG5hbWUgYXMgaWYgaXQgd2FzIHdyYXBwZWQgaW4gYW4gYXJyYXlcbiAgICAgIC8vIHNvIHRoYXQgaXQncyBjb25zaXN0ZW50IGlmIHRoZSBudW1iZXIgb2YgY2hpbGRyZW4gZ3Jvd3NcbiAgICAgIHZhciBzdG9yYWdlTmFtZSA9XG4gICAgICAgIGlzT25seUNoaWxkID8gU0VQQVJBVE9SICsgZ2V0Q29tcG9uZW50S2V5KGNoaWxkcmVuLCAwKSA6IG5hbWVTb0ZhcjtcbiAgICAgIGlmIChjaGlsZHJlbiA9PSBudWxsIHx8IHR5cGUgPT09ICdib29sZWFuJykge1xuICAgICAgICAvLyBBbGwgb2YgdGhlIGFib3ZlIGFyZSBwZXJjZWl2ZWQgYXMgbnVsbC5cbiAgICAgICAgY2FsbGJhY2sodHJhdmVyc2VDb250ZXh0LCBudWxsLCBzdG9yYWdlTmFtZSwgaW5kZXhTb0Zhcik7XG4gICAgICAgIHN1YnRyZWVDb3VudCA9IDE7XG4gICAgICB9IGVsc2UgaWYgKHR5cGUgPT09ICdzdHJpbmcnIHx8IHR5cGUgPT09ICdudW1iZXInIHx8XG4gICAgICAgICAgICAgICAgIFJlYWN0RWxlbWVudC5pc1ZhbGlkRWxlbWVudChjaGlsZHJlbikpIHtcbiAgICAgICAgY2FsbGJhY2sodHJhdmVyc2VDb250ZXh0LCBjaGlsZHJlbiwgc3RvcmFnZU5hbWUsIGluZGV4U29GYXIpO1xuICAgICAgICBzdWJ0cmVlQ291bnQgPSAxO1xuICAgICAgfSBlbHNlIGlmICh0eXBlID09PSAnb2JqZWN0Jykge1xuICAgICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICAgICFjaGlsZHJlbiB8fCBjaGlsZHJlbi5ub2RlVHlwZSAhPT0gMSxcbiAgICAgICAgICAndHJhdmVyc2VBbGxDaGlsZHJlbiguLi4pOiBFbmNvdW50ZXJlZCBhbiBpbnZhbGlkIGNoaWxkOyBET00gJyArXG4gICAgICAgICAgJ2VsZW1lbnRzIGFyZSBub3QgdmFsaWQgY2hpbGRyZW4gb2YgUmVhY3QgY29tcG9uZW50cy4nXG4gICAgICAgICkgOiBpbnZhcmlhbnQoIWNoaWxkcmVuIHx8IGNoaWxkcmVuLm5vZGVUeXBlICE9PSAxKSk7XG4gICAgICAgIGZvciAodmFyIGtleSBpbiBjaGlsZHJlbikge1xuICAgICAgICAgIGlmIChjaGlsZHJlbi5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7XG4gICAgICAgICAgICBuZXh0TmFtZSA9IChcbiAgICAgICAgICAgICAgbmFtZVNvRmFyICsgKG5hbWVTb0ZhciA/IFNVQlNFUEFSQVRPUiA6IFNFUEFSQVRPUikgK1xuICAgICAgICAgICAgICB3cmFwVXNlclByb3ZpZGVkS2V5KGtleSkgKyBTVUJTRVBBUkFUT1IgK1xuICAgICAgICAgICAgICBnZXRDb21wb25lbnRLZXkoY2hpbGRyZW5ba2V5XSwgMClcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBuZXh0SW5kZXggPSBpbmRleFNvRmFyICsgc3VidHJlZUNvdW50O1xuICAgICAgICAgICAgc3VidHJlZUNvdW50ICs9IHRyYXZlcnNlQWxsQ2hpbGRyZW5JbXBsKFxuICAgICAgICAgICAgICBjaGlsZHJlbltrZXldLFxuICAgICAgICAgICAgICBuZXh0TmFtZSxcbiAgICAgICAgICAgICAgbmV4dEluZGV4LFxuICAgICAgICAgICAgICBjYWxsYmFjayxcbiAgICAgICAgICAgICAgdHJhdmVyc2VDb250ZXh0XG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gc3VidHJlZUNvdW50O1xuICB9O1xuXG4vKipcbiAqIFRyYXZlcnNlcyBjaGlsZHJlbiB0aGF0IGFyZSB0eXBpY2FsbHkgc3BlY2lmaWVkIGFzIGBwcm9wcy5jaGlsZHJlbmAsIGJ1dFxuICogbWlnaHQgYWxzbyBiZSBzcGVjaWZpZWQgdGhyb3VnaCBhdHRyaWJ1dGVzOlxuICpcbiAqIC0gYHRyYXZlcnNlQWxsQ2hpbGRyZW4odGhpcy5wcm9wcy5jaGlsZHJlbiwgLi4uKWBcbiAqIC0gYHRyYXZlcnNlQWxsQ2hpbGRyZW4odGhpcy5wcm9wcy5sZWZ0UGFuZWxDaGlsZHJlbiwgLi4uKWBcbiAqXG4gKiBUaGUgYHRyYXZlcnNlQ29udGV4dGAgaXMgYW4gb3B0aW9uYWwgYXJndW1lbnQgdGhhdCBpcyBwYXNzZWQgdGhyb3VnaCB0aGVcbiAqIGVudGlyZSB0cmF2ZXJzYWwuIEl0IGNhbiBiZSB1c2VkIHRvIHN0b3JlIGFjY3VtdWxhdGlvbnMgb3IgYW55dGhpbmcgZWxzZSB0aGF0XG4gKiB0aGUgY2FsbGJhY2sgbWlnaHQgZmluZCByZWxldmFudC5cbiAqXG4gKiBAcGFyYW0gez8qfSBjaGlsZHJlbiBDaGlsZHJlbiB0cmVlIG9iamVjdC5cbiAqIEBwYXJhbSB7IWZ1bmN0aW9ufSBjYWxsYmFjayBUbyBpbnZva2UgdXBvbiB0cmF2ZXJzaW5nIGVhY2ggY2hpbGQuXG4gKiBAcGFyYW0gez8qfSB0cmF2ZXJzZUNvbnRleHQgQ29udGV4dCBmb3IgdHJhdmVyc2FsLlxuICogQHJldHVybiB7IW51bWJlcn0gVGhlIG51bWJlciBvZiBjaGlsZHJlbiBpbiB0aGlzIHN1YnRyZWUuXG4gKi9cbmZ1bmN0aW9uIHRyYXZlcnNlQWxsQ2hpbGRyZW4oY2hpbGRyZW4sIGNhbGxiYWNrLCB0cmF2ZXJzZUNvbnRleHQpIHtcbiAgaWYgKGNoaWxkcmVuID09IG51bGwpIHtcbiAgICByZXR1cm4gMDtcbiAgfVxuXG4gIHJldHVybiB0cmF2ZXJzZUFsbENoaWxkcmVuSW1wbChjaGlsZHJlbiwgJycsIDAsIGNhbGxiYWNrLCB0cmF2ZXJzZUNvbnRleHQpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHRyYXZlcnNlQWxsQ2hpbGRyZW47XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgdXBkYXRlXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBhc3NpZ24gPSByZXF1aXJlKFwiLi9PYmplY3QuYXNzaWduXCIpO1xudmFyIGtleU9mID0gcmVxdWlyZShcIi4va2V5T2ZcIik7XG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG5mdW5jdGlvbiBzaGFsbG93Q29weSh4KSB7XG4gIGlmIChBcnJheS5pc0FycmF5KHgpKSB7XG4gICAgcmV0dXJuIHguY29uY2F0KCk7XG4gIH0gZWxzZSBpZiAoeCAmJiB0eXBlb2YgeCA9PT0gJ29iamVjdCcpIHtcbiAgICByZXR1cm4gYXNzaWduKG5ldyB4LmNvbnN0cnVjdG9yKCksIHgpO1xuICB9IGVsc2Uge1xuICAgIHJldHVybiB4O1xuICB9XG59XG5cbnZhciBDT01NQU5EX1BVU0ggPSBrZXlPZih7JHB1c2g6IG51bGx9KTtcbnZhciBDT01NQU5EX1VOU0hJRlQgPSBrZXlPZih7JHVuc2hpZnQ6IG51bGx9KTtcbnZhciBDT01NQU5EX1NQTElDRSA9IGtleU9mKHskc3BsaWNlOiBudWxsfSk7XG52YXIgQ09NTUFORF9TRVQgPSBrZXlPZih7JHNldDogbnVsbH0pO1xudmFyIENPTU1BTkRfTUVSR0UgPSBrZXlPZih7JG1lcmdlOiBudWxsfSk7XG52YXIgQ09NTUFORF9BUFBMWSA9IGtleU9mKHskYXBwbHk6IG51bGx9KTtcblxudmFyIEFMTF9DT01NQU5EU19MSVNUID0gW1xuICBDT01NQU5EX1BVU0gsXG4gIENPTU1BTkRfVU5TSElGVCxcbiAgQ09NTUFORF9TUExJQ0UsXG4gIENPTU1BTkRfU0VULFxuICBDT01NQU5EX01FUkdFLFxuICBDT01NQU5EX0FQUExZXG5dO1xuXG52YXIgQUxMX0NPTU1BTkRTX1NFVCA9IHt9O1xuXG5BTExfQ09NTUFORFNfTElTVC5mb3JFYWNoKGZ1bmN0aW9uKGNvbW1hbmQpIHtcbiAgQUxMX0NPTU1BTkRTX1NFVFtjb21tYW5kXSA9IHRydWU7XG59KTtcblxuZnVuY3Rpb24gaW52YXJpYW50QXJyYXlDYXNlKHZhbHVlLCBzcGVjLCBjb21tYW5kKSB7XG4gIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgQXJyYXkuaXNBcnJheSh2YWx1ZSksXG4gICAgJ3VwZGF0ZSgpOiBleHBlY3RlZCB0YXJnZXQgb2YgJXMgdG8gYmUgYW4gYXJyYXk7IGdvdCAlcy4nLFxuICAgIGNvbW1hbmQsXG4gICAgdmFsdWVcbiAgKSA6IGludmFyaWFudChBcnJheS5pc0FycmF5KHZhbHVlKSkpO1xuICB2YXIgc3BlY1ZhbHVlID0gc3BlY1tjb21tYW5kXTtcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICBBcnJheS5pc0FycmF5KHNwZWNWYWx1ZSksXG4gICAgJ3VwZGF0ZSgpOiBleHBlY3RlZCBzcGVjIG9mICVzIHRvIGJlIGFuIGFycmF5OyBnb3QgJXMuICcgK1xuICAgICdEaWQgeW91IGZvcmdldCB0byB3cmFwIHlvdXIgcGFyYW1ldGVyIGluIGFuIGFycmF5PycsXG4gICAgY29tbWFuZCxcbiAgICBzcGVjVmFsdWVcbiAgKSA6IGludmFyaWFudChBcnJheS5pc0FycmF5KHNwZWNWYWx1ZSkpKTtcbn1cblxuZnVuY3Rpb24gdXBkYXRlKHZhbHVlLCBzcGVjKSB7XG4gIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgdHlwZW9mIHNwZWMgPT09ICdvYmplY3QnLFxuICAgICd1cGRhdGUoKTogWW91IHByb3ZpZGVkIGEga2V5IHBhdGggdG8gdXBkYXRlKCkgdGhhdCBkaWQgbm90IGNvbnRhaW4gb25lICcgK1xuICAgICdvZiAlcy4gRGlkIHlvdSBmb3JnZXQgdG8gaW5jbHVkZSB7JXM6IC4uLn0/JyxcbiAgICBBTExfQ09NTUFORFNfTElTVC5qb2luKCcsICcpLFxuICAgIENPTU1BTkRfU0VUXG4gICkgOiBpbnZhcmlhbnQodHlwZW9mIHNwZWMgPT09ICdvYmplY3QnKSk7XG5cbiAgaWYgKHNwZWMuaGFzT3duUHJvcGVydHkoQ09NTUFORF9TRVQpKSB7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgIE9iamVjdC5rZXlzKHNwZWMpLmxlbmd0aCA9PT0gMSxcbiAgICAgICdDYW5ub3QgaGF2ZSBtb3JlIHRoYW4gb25lIGtleSBpbiBhbiBvYmplY3Qgd2l0aCAlcycsXG4gICAgICBDT01NQU5EX1NFVFxuICAgICkgOiBpbnZhcmlhbnQoT2JqZWN0LmtleXMoc3BlYykubGVuZ3RoID09PSAxKSk7XG5cbiAgICByZXR1cm4gc3BlY1tDT01NQU5EX1NFVF07XG4gIH1cblxuICB2YXIgbmV4dFZhbHVlID0gc2hhbGxvd0NvcHkodmFsdWUpO1xuXG4gIGlmIChzcGVjLmhhc093blByb3BlcnR5KENPTU1BTkRfTUVSR0UpKSB7XG4gICAgdmFyIG1lcmdlT2JqID0gc3BlY1tDT01NQU5EX01FUkdFXTtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgbWVyZ2VPYmogJiYgdHlwZW9mIG1lcmdlT2JqID09PSAnb2JqZWN0JyxcbiAgICAgICd1cGRhdGUoKTogJXMgZXhwZWN0cyBhIHNwZWMgb2YgdHlwZSBcXCdvYmplY3RcXCc7IGdvdCAlcycsXG4gICAgICBDT01NQU5EX01FUkdFLFxuICAgICAgbWVyZ2VPYmpcbiAgICApIDogaW52YXJpYW50KG1lcmdlT2JqICYmIHR5cGVvZiBtZXJnZU9iaiA9PT0gJ29iamVjdCcpKTtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgbmV4dFZhbHVlICYmIHR5cGVvZiBuZXh0VmFsdWUgPT09ICdvYmplY3QnLFxuICAgICAgJ3VwZGF0ZSgpOiAlcyBleHBlY3RzIGEgdGFyZ2V0IG9mIHR5cGUgXFwnb2JqZWN0XFwnOyBnb3QgJXMnLFxuICAgICAgQ09NTUFORF9NRVJHRSxcbiAgICAgIG5leHRWYWx1ZVxuICAgICkgOiBpbnZhcmlhbnQobmV4dFZhbHVlICYmIHR5cGVvZiBuZXh0VmFsdWUgPT09ICdvYmplY3QnKSk7XG4gICAgYXNzaWduKG5leHRWYWx1ZSwgc3BlY1tDT01NQU5EX01FUkdFXSk7XG4gIH1cblxuICBpZiAoc3BlYy5oYXNPd25Qcm9wZXJ0eShDT01NQU5EX1BVU0gpKSB7XG4gICAgaW52YXJpYW50QXJyYXlDYXNlKHZhbHVlLCBzcGVjLCBDT01NQU5EX1BVU0gpO1xuICAgIHNwZWNbQ09NTUFORF9QVVNIXS5mb3JFYWNoKGZ1bmN0aW9uKGl0ZW0pIHtcbiAgICAgIG5leHRWYWx1ZS5wdXNoKGl0ZW0pO1xuICAgIH0pO1xuICB9XG5cbiAgaWYgKHNwZWMuaGFzT3duUHJvcGVydHkoQ09NTUFORF9VTlNISUZUKSkge1xuICAgIGludmFyaWFudEFycmF5Q2FzZSh2YWx1ZSwgc3BlYywgQ09NTUFORF9VTlNISUZUKTtcbiAgICBzcGVjW0NPTU1BTkRfVU5TSElGVF0uZm9yRWFjaChmdW5jdGlvbihpdGVtKSB7XG4gICAgICBuZXh0VmFsdWUudW5zaGlmdChpdGVtKTtcbiAgICB9KTtcbiAgfVxuXG4gIGlmIChzcGVjLmhhc093blByb3BlcnR5KENPTU1BTkRfU1BMSUNFKSkge1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICBBcnJheS5pc0FycmF5KHZhbHVlKSxcbiAgICAgICdFeHBlY3RlZCAlcyB0YXJnZXQgdG8gYmUgYW4gYXJyYXk7IGdvdCAlcycsXG4gICAgICBDT01NQU5EX1NQTElDRSxcbiAgICAgIHZhbHVlXG4gICAgKSA6IGludmFyaWFudChBcnJheS5pc0FycmF5KHZhbHVlKSkpO1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICBBcnJheS5pc0FycmF5KHNwZWNbQ09NTUFORF9TUExJQ0VdKSxcbiAgICAgICd1cGRhdGUoKTogZXhwZWN0ZWQgc3BlYyBvZiAlcyB0byBiZSBhbiBhcnJheSBvZiBhcnJheXM7IGdvdCAlcy4gJyArXG4gICAgICAnRGlkIHlvdSBmb3JnZXQgdG8gd3JhcCB5b3VyIHBhcmFtZXRlcnMgaW4gYW4gYXJyYXk/JyxcbiAgICAgIENPTU1BTkRfU1BMSUNFLFxuICAgICAgc3BlY1tDT01NQU5EX1NQTElDRV1cbiAgICApIDogaW52YXJpYW50KEFycmF5LmlzQXJyYXkoc3BlY1tDT01NQU5EX1NQTElDRV0pKSk7XG4gICAgc3BlY1tDT01NQU5EX1NQTElDRV0uZm9yRWFjaChmdW5jdGlvbihhcmdzKSB7XG4gICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICBBcnJheS5pc0FycmF5KGFyZ3MpLFxuICAgICAgICAndXBkYXRlKCk6IGV4cGVjdGVkIHNwZWMgb2YgJXMgdG8gYmUgYW4gYXJyYXkgb2YgYXJyYXlzOyBnb3QgJXMuICcgK1xuICAgICAgICAnRGlkIHlvdSBmb3JnZXQgdG8gd3JhcCB5b3VyIHBhcmFtZXRlcnMgaW4gYW4gYXJyYXk/JyxcbiAgICAgICAgQ09NTUFORF9TUExJQ0UsXG4gICAgICAgIHNwZWNbQ09NTUFORF9TUExJQ0VdXG4gICAgICApIDogaW52YXJpYW50KEFycmF5LmlzQXJyYXkoYXJncykpKTtcbiAgICAgIG5leHRWYWx1ZS5zcGxpY2UuYXBwbHkobmV4dFZhbHVlLCBhcmdzKTtcbiAgICB9KTtcbiAgfVxuXG4gIGlmIChzcGVjLmhhc093blByb3BlcnR5KENPTU1BTkRfQVBQTFkpKSB7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgIHR5cGVvZiBzcGVjW0NPTU1BTkRfQVBQTFldID09PSAnZnVuY3Rpb24nLFxuICAgICAgJ3VwZGF0ZSgpOiBleHBlY3RlZCBzcGVjIG9mICVzIHRvIGJlIGEgZnVuY3Rpb247IGdvdCAlcy4nLFxuICAgICAgQ09NTUFORF9BUFBMWSxcbiAgICAgIHNwZWNbQ09NTUFORF9BUFBMWV1cbiAgICApIDogaW52YXJpYW50KHR5cGVvZiBzcGVjW0NPTU1BTkRfQVBQTFldID09PSAnZnVuY3Rpb24nKSk7XG4gICAgbmV4dFZhbHVlID0gc3BlY1tDT01NQU5EX0FQUExZXShuZXh0VmFsdWUpO1xuICB9XG5cbiAgZm9yICh2YXIgayBpbiBzcGVjKSB7XG4gICAgaWYgKCEoQUxMX0NPTU1BTkRTX1NFVC5oYXNPd25Qcm9wZXJ0eShrKSAmJiBBTExfQ09NTUFORFNfU0VUW2tdKSkge1xuICAgICAgbmV4dFZhbHVlW2tdID0gdXBkYXRlKHZhbHVlW2tdLCBzcGVjW2tdKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gbmV4dFZhbHVlO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHVwZGF0ZTtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgd2FybmluZ1xuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgZW1wdHlGdW5jdGlvbiA9IHJlcXVpcmUoXCIuL2VtcHR5RnVuY3Rpb25cIik7XG5cbi8qKlxuICogU2ltaWxhciB0byBpbnZhcmlhbnQgYnV0IG9ubHkgbG9ncyBhIHdhcm5pbmcgaWYgdGhlIGNvbmRpdGlvbiBpcyBub3QgbWV0LlxuICogVGhpcyBjYW4gYmUgdXNlZCB0byBsb2cgaXNzdWVzIGluIGRldmVsb3BtZW50IGVudmlyb25tZW50cyBpbiBjcml0aWNhbFxuICogcGF0aHMuIFJlbW92aW5nIHRoZSBsb2dnaW5nIGNvZGUgZm9yIHByb2R1Y3Rpb24gZW52aXJvbm1lbnRzIHdpbGwga2VlcCB0aGVcbiAqIHNhbWUgbG9naWMgYW5kIGZvbGxvdyB0aGUgc2FtZSBjb2RlIHBhdGhzLlxuICovXG5cbnZhciB3YXJuaW5nID0gZW1wdHlGdW5jdGlvbjtcblxuaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICB3YXJuaW5nID0gZnVuY3Rpb24oY29uZGl0aW9uLCBmb3JtYXQgKSB7Zm9yICh2YXIgYXJncz1bXSwkX18wPTIsJF9fMT1hcmd1bWVudHMubGVuZ3RoOyRfXzA8JF9fMTskX18wKyspIGFyZ3MucHVzaChhcmd1bWVudHNbJF9fMF0pO1xuICAgIGlmIChmb3JtYXQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAnYHdhcm5pbmcoY29uZGl0aW9uLCBmb3JtYXQsIC4uLmFyZ3MpYCByZXF1aXJlcyBhIHdhcm5pbmcgJyArXG4gICAgICAgICdtZXNzYWdlIGFyZ3VtZW50J1xuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAoIWNvbmRpdGlvbikge1xuICAgICAgdmFyIGFyZ0luZGV4ID0gMDtcbiAgICAgIGNvbnNvbGUud2FybignV2FybmluZzogJyArIGZvcm1hdC5yZXBsYWNlKC8lcy9nLCBmdW5jdGlvbigpICB7cmV0dXJuIGFyZ3NbYXJnSW5kZXgrK107fSkpO1xuICAgIH1cbiAgfTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB3YXJuaW5nO1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIvKiFcbiAqIGpRdWVyeSBKYXZhU2NyaXB0IExpYnJhcnkgdjIuMS4zXG4gKiBodHRwOi8vanF1ZXJ5LmNvbS9cbiAqXG4gKiBJbmNsdWRlcyBTaXp6bGUuanNcbiAqIGh0dHA6Ly9zaXp6bGVqcy5jb20vXG4gKlxuICogQ29weXJpZ2h0IDIwMDUsIDIwMTQgalF1ZXJ5IEZvdW5kYXRpb24sIEluYy4gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKlxuICogRGF0ZTogMjAxNC0xMi0xOFQxNToxMVpcbiAqL1xuXG4oZnVuY3Rpb24oIGdsb2JhbCwgZmFjdG9yeSApIHtcblxuXHRpZiAoIHR5cGVvZiBtb2R1bGUgPT09IFwib2JqZWN0XCIgJiYgdHlwZW9mIG1vZHVsZS5leHBvcnRzID09PSBcIm9iamVjdFwiICkge1xuXHRcdC8vIEZvciBDb21tb25KUyBhbmQgQ29tbW9uSlMtbGlrZSBlbnZpcm9ubWVudHMgd2hlcmUgYSBwcm9wZXIgYHdpbmRvd2Bcblx0XHQvLyBpcyBwcmVzZW50LCBleGVjdXRlIHRoZSBmYWN0b3J5IGFuZCBnZXQgalF1ZXJ5LlxuXHRcdC8vIEZvciBlbnZpcm9ubWVudHMgdGhhdCBkbyBub3QgaGF2ZSBhIGB3aW5kb3dgIHdpdGggYSBgZG9jdW1lbnRgXG5cdFx0Ly8gKHN1Y2ggYXMgTm9kZS5qcyksIGV4cG9zZSBhIGZhY3RvcnkgYXMgbW9kdWxlLmV4cG9ydHMuXG5cdFx0Ly8gVGhpcyBhY2NlbnR1YXRlcyB0aGUgbmVlZCBmb3IgdGhlIGNyZWF0aW9uIG9mIGEgcmVhbCBgd2luZG93YC5cblx0XHQvLyBlLmcuIHZhciBqUXVlcnkgPSByZXF1aXJlKFwianF1ZXJ5XCIpKHdpbmRvdyk7XG5cdFx0Ly8gU2VlIHRpY2tldCAjMTQ1NDkgZm9yIG1vcmUgaW5mby5cblx0XHRtb2R1bGUuZXhwb3J0cyA9IGdsb2JhbC5kb2N1bWVudCA/XG5cdFx0XHRmYWN0b3J5KCBnbG9iYWwsIHRydWUgKSA6XG5cdFx0XHRmdW5jdGlvbiggdyApIHtcblx0XHRcdFx0aWYgKCAhdy5kb2N1bWVudCApIHtcblx0XHRcdFx0XHR0aHJvdyBuZXcgRXJyb3IoIFwialF1ZXJ5IHJlcXVpcmVzIGEgd2luZG93IHdpdGggYSBkb2N1bWVudFwiICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIGZhY3RvcnkoIHcgKTtcblx0XHRcdH07XG5cdH0gZWxzZSB7XG5cdFx0ZmFjdG9yeSggZ2xvYmFsICk7XG5cdH1cblxuLy8gUGFzcyB0aGlzIGlmIHdpbmRvdyBpcyBub3QgZGVmaW5lZCB5ZXRcbn0odHlwZW9mIHdpbmRvdyAhPT0gXCJ1bmRlZmluZWRcIiA/IHdpbmRvdyA6IHRoaXMsIGZ1bmN0aW9uKCB3aW5kb3csIG5vR2xvYmFsICkge1xuXG4vLyBTdXBwb3J0OiBGaXJlZm94IDE4K1xuLy8gQ2FuJ3QgYmUgaW4gc3RyaWN0IG1vZGUsIHNldmVyYWwgbGlicyBpbmNsdWRpbmcgQVNQLk5FVCB0cmFjZVxuLy8gdGhlIHN0YWNrIHZpYSBhcmd1bWVudHMuY2FsbGVyLmNhbGxlZSBhbmQgRmlyZWZveCBkaWVzIGlmXG4vLyB5b3UgdHJ5IHRvIHRyYWNlIHRocm91Z2ggXCJ1c2Ugc3RyaWN0XCIgY2FsbCBjaGFpbnMuICgjMTMzMzUpXG4vL1xuXG52YXIgYXJyID0gW107XG5cbnZhciBzbGljZSA9IGFyci5zbGljZTtcblxudmFyIGNvbmNhdCA9IGFyci5jb25jYXQ7XG5cbnZhciBwdXNoID0gYXJyLnB1c2g7XG5cbnZhciBpbmRleE9mID0gYXJyLmluZGV4T2Y7XG5cbnZhciBjbGFzczJ0eXBlID0ge307XG5cbnZhciB0b1N0cmluZyA9IGNsYXNzMnR5cGUudG9TdHJpbmc7XG5cbnZhciBoYXNPd24gPSBjbGFzczJ0eXBlLmhhc093blByb3BlcnR5O1xuXG52YXIgc3VwcG9ydCA9IHt9O1xuXG5cblxudmFyXG5cdC8vIFVzZSB0aGUgY29ycmVjdCBkb2N1bWVudCBhY2NvcmRpbmdseSB3aXRoIHdpbmRvdyBhcmd1bWVudCAoc2FuZGJveClcblx0ZG9jdW1lbnQgPSB3aW5kb3cuZG9jdW1lbnQsXG5cblx0dmVyc2lvbiA9IFwiMi4xLjNcIixcblxuXHQvLyBEZWZpbmUgYSBsb2NhbCBjb3B5IG9mIGpRdWVyeVxuXHRqUXVlcnkgPSBmdW5jdGlvbiggc2VsZWN0b3IsIGNvbnRleHQgKSB7XG5cdFx0Ly8gVGhlIGpRdWVyeSBvYmplY3QgaXMgYWN0dWFsbHkganVzdCB0aGUgaW5pdCBjb25zdHJ1Y3RvciAnZW5oYW5jZWQnXG5cdFx0Ly8gTmVlZCBpbml0IGlmIGpRdWVyeSBpcyBjYWxsZWQgKGp1c3QgYWxsb3cgZXJyb3IgdG8gYmUgdGhyb3duIGlmIG5vdCBpbmNsdWRlZClcblx0XHRyZXR1cm4gbmV3IGpRdWVyeS5mbi5pbml0KCBzZWxlY3RvciwgY29udGV4dCApO1xuXHR9LFxuXG5cdC8vIFN1cHBvcnQ6IEFuZHJvaWQ8NC4xXG5cdC8vIE1ha2Ugc3VyZSB3ZSB0cmltIEJPTSBhbmQgTkJTUFxuXHRydHJpbSA9IC9eW1xcc1xcdUZFRkZcXHhBMF0rfFtcXHNcXHVGRUZGXFx4QTBdKyQvZyxcblxuXHQvLyBNYXRjaGVzIGRhc2hlZCBzdHJpbmcgZm9yIGNhbWVsaXppbmdcblx0cm1zUHJlZml4ID0gL14tbXMtLyxcblx0cmRhc2hBbHBoYSA9IC8tKFtcXGRhLXpdKS9naSxcblxuXHQvLyBVc2VkIGJ5IGpRdWVyeS5jYW1lbENhc2UgYXMgY2FsbGJhY2sgdG8gcmVwbGFjZSgpXG5cdGZjYW1lbENhc2UgPSBmdW5jdGlvbiggYWxsLCBsZXR0ZXIgKSB7XG5cdFx0cmV0dXJuIGxldHRlci50b1VwcGVyQ2FzZSgpO1xuXHR9O1xuXG5qUXVlcnkuZm4gPSBqUXVlcnkucHJvdG90eXBlID0ge1xuXHQvLyBUaGUgY3VycmVudCB2ZXJzaW9uIG9mIGpRdWVyeSBiZWluZyB1c2VkXG5cdGpxdWVyeTogdmVyc2lvbixcblxuXHRjb25zdHJ1Y3RvcjogalF1ZXJ5LFxuXG5cdC8vIFN0YXJ0IHdpdGggYW4gZW1wdHkgc2VsZWN0b3Jcblx0c2VsZWN0b3I6IFwiXCIsXG5cblx0Ly8gVGhlIGRlZmF1bHQgbGVuZ3RoIG9mIGEgalF1ZXJ5IG9iamVjdCBpcyAwXG5cdGxlbmd0aDogMCxcblxuXHR0b0FycmF5OiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gc2xpY2UuY2FsbCggdGhpcyApO1xuXHR9LFxuXG5cdC8vIEdldCB0aGUgTnRoIGVsZW1lbnQgaW4gdGhlIG1hdGNoZWQgZWxlbWVudCBzZXQgT1Jcblx0Ly8gR2V0IHRoZSB3aG9sZSBtYXRjaGVkIGVsZW1lbnQgc2V0IGFzIGEgY2xlYW4gYXJyYXlcblx0Z2V0OiBmdW5jdGlvbiggbnVtICkge1xuXHRcdHJldHVybiBudW0gIT0gbnVsbCA/XG5cblx0XHRcdC8vIFJldHVybiBqdXN0IHRoZSBvbmUgZWxlbWVudCBmcm9tIHRoZSBzZXRcblx0XHRcdCggbnVtIDwgMCA/IHRoaXNbIG51bSArIHRoaXMubGVuZ3RoIF0gOiB0aGlzWyBudW0gXSApIDpcblxuXHRcdFx0Ly8gUmV0dXJuIGFsbCB0aGUgZWxlbWVudHMgaW4gYSBjbGVhbiBhcnJheVxuXHRcdFx0c2xpY2UuY2FsbCggdGhpcyApO1xuXHR9LFxuXG5cdC8vIFRha2UgYW4gYXJyYXkgb2YgZWxlbWVudHMgYW5kIHB1c2ggaXQgb250byB0aGUgc3RhY2tcblx0Ly8gKHJldHVybmluZyB0aGUgbmV3IG1hdGNoZWQgZWxlbWVudCBzZXQpXG5cdHB1c2hTdGFjazogZnVuY3Rpb24oIGVsZW1zICkge1xuXG5cdFx0Ly8gQnVpbGQgYSBuZXcgalF1ZXJ5IG1hdGNoZWQgZWxlbWVudCBzZXRcblx0XHR2YXIgcmV0ID0galF1ZXJ5Lm1lcmdlKCB0aGlzLmNvbnN0cnVjdG9yKCksIGVsZW1zICk7XG5cblx0XHQvLyBBZGQgdGhlIG9sZCBvYmplY3Qgb250byB0aGUgc3RhY2sgKGFzIGEgcmVmZXJlbmNlKVxuXHRcdHJldC5wcmV2T2JqZWN0ID0gdGhpcztcblx0XHRyZXQuY29udGV4dCA9IHRoaXMuY29udGV4dDtcblxuXHRcdC8vIFJldHVybiB0aGUgbmV3bHktZm9ybWVkIGVsZW1lbnQgc2V0XG5cdFx0cmV0dXJuIHJldDtcblx0fSxcblxuXHQvLyBFeGVjdXRlIGEgY2FsbGJhY2sgZm9yIGV2ZXJ5IGVsZW1lbnQgaW4gdGhlIG1hdGNoZWQgc2V0LlxuXHQvLyAoWW91IGNhbiBzZWVkIHRoZSBhcmd1bWVudHMgd2l0aCBhbiBhcnJheSBvZiBhcmdzLCBidXQgdGhpcyBpc1xuXHQvLyBvbmx5IHVzZWQgaW50ZXJuYWxseS4pXG5cdGVhY2g6IGZ1bmN0aW9uKCBjYWxsYmFjaywgYXJncyApIHtcblx0XHRyZXR1cm4galF1ZXJ5LmVhY2goIHRoaXMsIGNhbGxiYWNrLCBhcmdzICk7XG5cdH0sXG5cblx0bWFwOiBmdW5jdGlvbiggY2FsbGJhY2sgKSB7XG5cdFx0cmV0dXJuIHRoaXMucHVzaFN0YWNrKCBqUXVlcnkubWFwKHRoaXMsIGZ1bmN0aW9uKCBlbGVtLCBpICkge1xuXHRcdFx0cmV0dXJuIGNhbGxiYWNrLmNhbGwoIGVsZW0sIGksIGVsZW0gKTtcblx0XHR9KSk7XG5cdH0sXG5cblx0c2xpY2U6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLnB1c2hTdGFjayggc2xpY2UuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApICk7XG5cdH0sXG5cblx0Zmlyc3Q6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLmVxKCAwICk7XG5cdH0sXG5cblx0bGFzdDogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMuZXEoIC0xICk7XG5cdH0sXG5cblx0ZXE6IGZ1bmN0aW9uKCBpICkge1xuXHRcdHZhciBsZW4gPSB0aGlzLmxlbmd0aCxcblx0XHRcdGogPSAraSArICggaSA8IDAgPyBsZW4gOiAwICk7XG5cdFx0cmV0dXJuIHRoaXMucHVzaFN0YWNrKCBqID49IDAgJiYgaiA8IGxlbiA/IFsgdGhpc1tqXSBdIDogW10gKTtcblx0fSxcblxuXHRlbmQ6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLnByZXZPYmplY3QgfHwgdGhpcy5jb25zdHJ1Y3RvcihudWxsKTtcblx0fSxcblxuXHQvLyBGb3IgaW50ZXJuYWwgdXNlIG9ubHkuXG5cdC8vIEJlaGF2ZXMgbGlrZSBhbiBBcnJheSdzIG1ldGhvZCwgbm90IGxpa2UgYSBqUXVlcnkgbWV0aG9kLlxuXHRwdXNoOiBwdXNoLFxuXHRzb3J0OiBhcnIuc29ydCxcblx0c3BsaWNlOiBhcnIuc3BsaWNlXG59O1xuXG5qUXVlcnkuZXh0ZW5kID0galF1ZXJ5LmZuLmV4dGVuZCA9IGZ1bmN0aW9uKCkge1xuXHR2YXIgb3B0aW9ucywgbmFtZSwgc3JjLCBjb3B5LCBjb3B5SXNBcnJheSwgY2xvbmUsXG5cdFx0dGFyZ2V0ID0gYXJndW1lbnRzWzBdIHx8IHt9LFxuXHRcdGkgPSAxLFxuXHRcdGxlbmd0aCA9IGFyZ3VtZW50cy5sZW5ndGgsXG5cdFx0ZGVlcCA9IGZhbHNlO1xuXG5cdC8vIEhhbmRsZSBhIGRlZXAgY29weSBzaXR1YXRpb25cblx0aWYgKCB0eXBlb2YgdGFyZ2V0ID09PSBcImJvb2xlYW5cIiApIHtcblx0XHRkZWVwID0gdGFyZ2V0O1xuXG5cdFx0Ly8gU2tpcCB0aGUgYm9vbGVhbiBhbmQgdGhlIHRhcmdldFxuXHRcdHRhcmdldCA9IGFyZ3VtZW50c1sgaSBdIHx8IHt9O1xuXHRcdGkrKztcblx0fVxuXG5cdC8vIEhhbmRsZSBjYXNlIHdoZW4gdGFyZ2V0IGlzIGEgc3RyaW5nIG9yIHNvbWV0aGluZyAocG9zc2libGUgaW4gZGVlcCBjb3B5KVxuXHRpZiAoIHR5cGVvZiB0YXJnZXQgIT09IFwib2JqZWN0XCIgJiYgIWpRdWVyeS5pc0Z1bmN0aW9uKHRhcmdldCkgKSB7XG5cdFx0dGFyZ2V0ID0ge307XG5cdH1cblxuXHQvLyBFeHRlbmQgalF1ZXJ5IGl0c2VsZiBpZiBvbmx5IG9uZSBhcmd1bWVudCBpcyBwYXNzZWRcblx0aWYgKCBpID09PSBsZW5ndGggKSB7XG5cdFx0dGFyZ2V0ID0gdGhpcztcblx0XHRpLS07XG5cdH1cblxuXHRmb3IgKCA7IGkgPCBsZW5ndGg7IGkrKyApIHtcblx0XHQvLyBPbmx5IGRlYWwgd2l0aCBub24tbnVsbC91bmRlZmluZWQgdmFsdWVzXG5cdFx0aWYgKCAob3B0aW9ucyA9IGFyZ3VtZW50c1sgaSBdKSAhPSBudWxsICkge1xuXHRcdFx0Ly8gRXh0ZW5kIHRoZSBiYXNlIG9iamVjdFxuXHRcdFx0Zm9yICggbmFtZSBpbiBvcHRpb25zICkge1xuXHRcdFx0XHRzcmMgPSB0YXJnZXRbIG5hbWUgXTtcblx0XHRcdFx0Y29weSA9IG9wdGlvbnNbIG5hbWUgXTtcblxuXHRcdFx0XHQvLyBQcmV2ZW50IG5ldmVyLWVuZGluZyBsb29wXG5cdFx0XHRcdGlmICggdGFyZ2V0ID09PSBjb3B5ICkge1xuXHRcdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gUmVjdXJzZSBpZiB3ZSdyZSBtZXJnaW5nIHBsYWluIG9iamVjdHMgb3IgYXJyYXlzXG5cdFx0XHRcdGlmICggZGVlcCAmJiBjb3B5ICYmICggalF1ZXJ5LmlzUGxhaW5PYmplY3QoY29weSkgfHwgKGNvcHlJc0FycmF5ID0galF1ZXJ5LmlzQXJyYXkoY29weSkpICkgKSB7XG5cdFx0XHRcdFx0aWYgKCBjb3B5SXNBcnJheSApIHtcblx0XHRcdFx0XHRcdGNvcHlJc0FycmF5ID0gZmFsc2U7XG5cdFx0XHRcdFx0XHRjbG9uZSA9IHNyYyAmJiBqUXVlcnkuaXNBcnJheShzcmMpID8gc3JjIDogW107XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0Y2xvbmUgPSBzcmMgJiYgalF1ZXJ5LmlzUGxhaW5PYmplY3Qoc3JjKSA/IHNyYyA6IHt9O1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIE5ldmVyIG1vdmUgb3JpZ2luYWwgb2JqZWN0cywgY2xvbmUgdGhlbVxuXHRcdFx0XHRcdHRhcmdldFsgbmFtZSBdID0galF1ZXJ5LmV4dGVuZCggZGVlcCwgY2xvbmUsIGNvcHkgKTtcblxuXHRcdFx0XHQvLyBEb24ndCBicmluZyBpbiB1bmRlZmluZWQgdmFsdWVzXG5cdFx0XHRcdH0gZWxzZSBpZiAoIGNvcHkgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0XHR0YXJnZXRbIG5hbWUgXSA9IGNvcHk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHQvLyBSZXR1cm4gdGhlIG1vZGlmaWVkIG9iamVjdFxuXHRyZXR1cm4gdGFyZ2V0O1xufTtcblxualF1ZXJ5LmV4dGVuZCh7XG5cdC8vIFVuaXF1ZSBmb3IgZWFjaCBjb3B5IG9mIGpRdWVyeSBvbiB0aGUgcGFnZVxuXHRleHBhbmRvOiBcImpRdWVyeVwiICsgKCB2ZXJzaW9uICsgTWF0aC5yYW5kb20oKSApLnJlcGxhY2UoIC9cXEQvZywgXCJcIiApLFxuXG5cdC8vIEFzc3VtZSBqUXVlcnkgaXMgcmVhZHkgd2l0aG91dCB0aGUgcmVhZHkgbW9kdWxlXG5cdGlzUmVhZHk6IHRydWUsXG5cblx0ZXJyb3I6IGZ1bmN0aW9uKCBtc2cgKSB7XG5cdFx0dGhyb3cgbmV3IEVycm9yKCBtc2cgKTtcblx0fSxcblxuXHRub29wOiBmdW5jdGlvbigpIHt9LFxuXG5cdGlzRnVuY3Rpb246IGZ1bmN0aW9uKCBvYmogKSB7XG5cdFx0cmV0dXJuIGpRdWVyeS50eXBlKG9iaikgPT09IFwiZnVuY3Rpb25cIjtcblx0fSxcblxuXHRpc0FycmF5OiBBcnJheS5pc0FycmF5LFxuXG5cdGlzV2luZG93OiBmdW5jdGlvbiggb2JqICkge1xuXHRcdHJldHVybiBvYmogIT0gbnVsbCAmJiBvYmogPT09IG9iai53aW5kb3c7XG5cdH0sXG5cblx0aXNOdW1lcmljOiBmdW5jdGlvbiggb2JqICkge1xuXHRcdC8vIHBhcnNlRmxvYXQgTmFOcyBudW1lcmljLWNhc3QgZmFsc2UgcG9zaXRpdmVzIChudWxsfHRydWV8ZmFsc2V8XCJcIilcblx0XHQvLyAuLi5idXQgbWlzaW50ZXJwcmV0cyBsZWFkaW5nLW51bWJlciBzdHJpbmdzLCBwYXJ0aWN1bGFybHkgaGV4IGxpdGVyYWxzIChcIjB4Li4uXCIpXG5cdFx0Ly8gc3VidHJhY3Rpb24gZm9yY2VzIGluZmluaXRpZXMgdG8gTmFOXG5cdFx0Ly8gYWRkaW5nIDEgY29ycmVjdHMgbG9zcyBvZiBwcmVjaXNpb24gZnJvbSBwYXJzZUZsb2F0ICgjMTUxMDApXG5cdFx0cmV0dXJuICFqUXVlcnkuaXNBcnJheSggb2JqICkgJiYgKG9iaiAtIHBhcnNlRmxvYXQoIG9iaiApICsgMSkgPj0gMDtcblx0fSxcblxuXHRpc1BsYWluT2JqZWN0OiBmdW5jdGlvbiggb2JqICkge1xuXHRcdC8vIE5vdCBwbGFpbiBvYmplY3RzOlxuXHRcdC8vIC0gQW55IG9iamVjdCBvciB2YWx1ZSB3aG9zZSBpbnRlcm5hbCBbW0NsYXNzXV0gcHJvcGVydHkgaXMgbm90IFwiW29iamVjdCBPYmplY3RdXCJcblx0XHQvLyAtIERPTSBub2Rlc1xuXHRcdC8vIC0gd2luZG93XG5cdFx0aWYgKCBqUXVlcnkudHlwZSggb2JqICkgIT09IFwib2JqZWN0XCIgfHwgb2JqLm5vZGVUeXBlIHx8IGpRdWVyeS5pc1dpbmRvdyggb2JqICkgKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0aWYgKCBvYmouY29uc3RydWN0b3IgJiZcblx0XHRcdFx0IWhhc093bi5jYWxsKCBvYmouY29uc3RydWN0b3IucHJvdG90eXBlLCBcImlzUHJvdG90eXBlT2ZcIiApICkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdC8vIElmIHRoZSBmdW5jdGlvbiBoYXNuJ3QgcmV0dXJuZWQgYWxyZWFkeSwgd2UncmUgY29uZmlkZW50IHRoYXRcblx0XHQvLyB8b2JqfCBpcyBhIHBsYWluIG9iamVjdCwgY3JlYXRlZCBieSB7fSBvciBjb25zdHJ1Y3RlZCB3aXRoIG5ldyBPYmplY3Rcblx0XHRyZXR1cm4gdHJ1ZTtcblx0fSxcblxuXHRpc0VtcHR5T2JqZWN0OiBmdW5jdGlvbiggb2JqICkge1xuXHRcdHZhciBuYW1lO1xuXHRcdGZvciAoIG5hbWUgaW4gb2JqICkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblx0XHRyZXR1cm4gdHJ1ZTtcblx0fSxcblxuXHR0eXBlOiBmdW5jdGlvbiggb2JqICkge1xuXHRcdGlmICggb2JqID09IG51bGwgKSB7XG5cdFx0XHRyZXR1cm4gb2JqICsgXCJcIjtcblx0XHR9XG5cdFx0Ly8gU3VwcG9ydDogQW5kcm9pZDw0LjAsIGlPUzw2IChmdW5jdGlvbmlzaCBSZWdFeHApXG5cdFx0cmV0dXJuIHR5cGVvZiBvYmogPT09IFwib2JqZWN0XCIgfHwgdHlwZW9mIG9iaiA9PT0gXCJmdW5jdGlvblwiID9cblx0XHRcdGNsYXNzMnR5cGVbIHRvU3RyaW5nLmNhbGwob2JqKSBdIHx8IFwib2JqZWN0XCIgOlxuXHRcdFx0dHlwZW9mIG9iajtcblx0fSxcblxuXHQvLyBFdmFsdWF0ZXMgYSBzY3JpcHQgaW4gYSBnbG9iYWwgY29udGV4dFxuXHRnbG9iYWxFdmFsOiBmdW5jdGlvbiggY29kZSApIHtcblx0XHR2YXIgc2NyaXB0LFxuXHRcdFx0aW5kaXJlY3QgPSBldmFsO1xuXG5cdFx0Y29kZSA9IGpRdWVyeS50cmltKCBjb2RlICk7XG5cblx0XHRpZiAoIGNvZGUgKSB7XG5cdFx0XHQvLyBJZiB0aGUgY29kZSBpbmNsdWRlcyBhIHZhbGlkLCBwcm9sb2d1ZSBwb3NpdGlvblxuXHRcdFx0Ly8gc3RyaWN0IG1vZGUgcHJhZ21hLCBleGVjdXRlIGNvZGUgYnkgaW5qZWN0aW5nIGFcblx0XHRcdC8vIHNjcmlwdCB0YWcgaW50byB0aGUgZG9jdW1lbnQuXG5cdFx0XHRpZiAoIGNvZGUuaW5kZXhPZihcInVzZSBzdHJpY3RcIikgPT09IDEgKSB7XG5cdFx0XHRcdHNjcmlwdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJzY3JpcHRcIik7XG5cdFx0XHRcdHNjcmlwdC50ZXh0ID0gY29kZTtcblx0XHRcdFx0ZG9jdW1lbnQuaGVhZC5hcHBlbmRDaGlsZCggc2NyaXB0ICkucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCggc2NyaXB0ICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0Ly8gT3RoZXJ3aXNlLCBhdm9pZCB0aGUgRE9NIG5vZGUgY3JlYXRpb24sIGluc2VydGlvblxuXHRcdFx0Ly8gYW5kIHJlbW92YWwgYnkgdXNpbmcgYW4gaW5kaXJlY3QgZ2xvYmFsIGV2YWxcblx0XHRcdFx0aW5kaXJlY3QoIGNvZGUgKTtcblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cblx0Ly8gQ29udmVydCBkYXNoZWQgdG8gY2FtZWxDYXNlOyB1c2VkIGJ5IHRoZSBjc3MgYW5kIGRhdGEgbW9kdWxlc1xuXHQvLyBTdXBwb3J0OiBJRTktMTErXG5cdC8vIE1pY3Jvc29mdCBmb3Jnb3QgdG8gaHVtcCB0aGVpciB2ZW5kb3IgcHJlZml4ICgjOTU3Milcblx0Y2FtZWxDYXNlOiBmdW5jdGlvbiggc3RyaW5nICkge1xuXHRcdHJldHVybiBzdHJpbmcucmVwbGFjZSggcm1zUHJlZml4LCBcIm1zLVwiICkucmVwbGFjZSggcmRhc2hBbHBoYSwgZmNhbWVsQ2FzZSApO1xuXHR9LFxuXG5cdG5vZGVOYW1lOiBmdW5jdGlvbiggZWxlbSwgbmFtZSApIHtcblx0XHRyZXR1cm4gZWxlbS5ub2RlTmFtZSAmJiBlbGVtLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09IG5hbWUudG9Mb3dlckNhc2UoKTtcblx0fSxcblxuXHQvLyBhcmdzIGlzIGZvciBpbnRlcm5hbCB1c2FnZSBvbmx5XG5cdGVhY2g6IGZ1bmN0aW9uKCBvYmosIGNhbGxiYWNrLCBhcmdzICkge1xuXHRcdHZhciB2YWx1ZSxcblx0XHRcdGkgPSAwLFxuXHRcdFx0bGVuZ3RoID0gb2JqLmxlbmd0aCxcblx0XHRcdGlzQXJyYXkgPSBpc0FycmF5bGlrZSggb2JqICk7XG5cblx0XHRpZiAoIGFyZ3MgKSB7XG5cdFx0XHRpZiAoIGlzQXJyYXkgKSB7XG5cdFx0XHRcdGZvciAoIDsgaSA8IGxlbmd0aDsgaSsrICkge1xuXHRcdFx0XHRcdHZhbHVlID0gY2FsbGJhY2suYXBwbHkoIG9ialsgaSBdLCBhcmdzICk7XG5cblx0XHRcdFx0XHRpZiAoIHZhbHVlID09PSBmYWxzZSApIHtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Zm9yICggaSBpbiBvYmogKSB7XG5cdFx0XHRcdFx0dmFsdWUgPSBjYWxsYmFjay5hcHBseSggb2JqWyBpIF0sIGFyZ3MgKTtcblxuXHRcdFx0XHRcdGlmICggdmFsdWUgPT09IGZhbHNlICkge1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHQvLyBBIHNwZWNpYWwsIGZhc3QsIGNhc2UgZm9yIHRoZSBtb3N0IGNvbW1vbiB1c2Ugb2YgZWFjaFxuXHRcdH0gZWxzZSB7XG5cdFx0XHRpZiAoIGlzQXJyYXkgKSB7XG5cdFx0XHRcdGZvciAoIDsgaSA8IGxlbmd0aDsgaSsrICkge1xuXHRcdFx0XHRcdHZhbHVlID0gY2FsbGJhY2suY2FsbCggb2JqWyBpIF0sIGksIG9ialsgaSBdICk7XG5cblx0XHRcdFx0XHRpZiAoIHZhbHVlID09PSBmYWxzZSApIHtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Zm9yICggaSBpbiBvYmogKSB7XG5cdFx0XHRcdFx0dmFsdWUgPSBjYWxsYmFjay5jYWxsKCBvYmpbIGkgXSwgaSwgb2JqWyBpIF0gKTtcblxuXHRcdFx0XHRcdGlmICggdmFsdWUgPT09IGZhbHNlICkge1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIG9iajtcblx0fSxcblxuXHQvLyBTdXBwb3J0OiBBbmRyb2lkPDQuMVxuXHR0cmltOiBmdW5jdGlvbiggdGV4dCApIHtcblx0XHRyZXR1cm4gdGV4dCA9PSBudWxsID9cblx0XHRcdFwiXCIgOlxuXHRcdFx0KCB0ZXh0ICsgXCJcIiApLnJlcGxhY2UoIHJ0cmltLCBcIlwiICk7XG5cdH0sXG5cblx0Ly8gcmVzdWx0cyBpcyBmb3IgaW50ZXJuYWwgdXNhZ2Ugb25seVxuXHRtYWtlQXJyYXk6IGZ1bmN0aW9uKCBhcnIsIHJlc3VsdHMgKSB7XG5cdFx0dmFyIHJldCA9IHJlc3VsdHMgfHwgW107XG5cblx0XHRpZiAoIGFyciAhPSBudWxsICkge1xuXHRcdFx0aWYgKCBpc0FycmF5bGlrZSggT2JqZWN0KGFycikgKSApIHtcblx0XHRcdFx0alF1ZXJ5Lm1lcmdlKCByZXQsXG5cdFx0XHRcdFx0dHlwZW9mIGFyciA9PT0gXCJzdHJpbmdcIiA/XG5cdFx0XHRcdFx0WyBhcnIgXSA6IGFyclxuXHRcdFx0XHQpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0cHVzaC5jYWxsKCByZXQsIGFyciApO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiByZXQ7XG5cdH0sXG5cblx0aW5BcnJheTogZnVuY3Rpb24oIGVsZW0sIGFyciwgaSApIHtcblx0XHRyZXR1cm4gYXJyID09IG51bGwgPyAtMSA6IGluZGV4T2YuY2FsbCggYXJyLCBlbGVtLCBpICk7XG5cdH0sXG5cblx0bWVyZ2U6IGZ1bmN0aW9uKCBmaXJzdCwgc2Vjb25kICkge1xuXHRcdHZhciBsZW4gPSArc2Vjb25kLmxlbmd0aCxcblx0XHRcdGogPSAwLFxuXHRcdFx0aSA9IGZpcnN0Lmxlbmd0aDtcblxuXHRcdGZvciAoIDsgaiA8IGxlbjsgaisrICkge1xuXHRcdFx0Zmlyc3RbIGkrKyBdID0gc2Vjb25kWyBqIF07XG5cdFx0fVxuXG5cdFx0Zmlyc3QubGVuZ3RoID0gaTtcblxuXHRcdHJldHVybiBmaXJzdDtcblx0fSxcblxuXHRncmVwOiBmdW5jdGlvbiggZWxlbXMsIGNhbGxiYWNrLCBpbnZlcnQgKSB7XG5cdFx0dmFyIGNhbGxiYWNrSW52ZXJzZSxcblx0XHRcdG1hdGNoZXMgPSBbXSxcblx0XHRcdGkgPSAwLFxuXHRcdFx0bGVuZ3RoID0gZWxlbXMubGVuZ3RoLFxuXHRcdFx0Y2FsbGJhY2tFeHBlY3QgPSAhaW52ZXJ0O1xuXG5cdFx0Ly8gR28gdGhyb3VnaCB0aGUgYXJyYXksIG9ubHkgc2F2aW5nIHRoZSBpdGVtc1xuXHRcdC8vIHRoYXQgcGFzcyB0aGUgdmFsaWRhdG9yIGZ1bmN0aW9uXG5cdFx0Zm9yICggOyBpIDwgbGVuZ3RoOyBpKysgKSB7XG5cdFx0XHRjYWxsYmFja0ludmVyc2UgPSAhY2FsbGJhY2soIGVsZW1zWyBpIF0sIGkgKTtcblx0XHRcdGlmICggY2FsbGJhY2tJbnZlcnNlICE9PSBjYWxsYmFja0V4cGVjdCApIHtcblx0XHRcdFx0bWF0Y2hlcy5wdXNoKCBlbGVtc1sgaSBdICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIG1hdGNoZXM7XG5cdH0sXG5cblx0Ly8gYXJnIGlzIGZvciBpbnRlcm5hbCB1c2FnZSBvbmx5XG5cdG1hcDogZnVuY3Rpb24oIGVsZW1zLCBjYWxsYmFjaywgYXJnICkge1xuXHRcdHZhciB2YWx1ZSxcblx0XHRcdGkgPSAwLFxuXHRcdFx0bGVuZ3RoID0gZWxlbXMubGVuZ3RoLFxuXHRcdFx0aXNBcnJheSA9IGlzQXJyYXlsaWtlKCBlbGVtcyApLFxuXHRcdFx0cmV0ID0gW107XG5cblx0XHQvLyBHbyB0aHJvdWdoIHRoZSBhcnJheSwgdHJhbnNsYXRpbmcgZWFjaCBvZiB0aGUgaXRlbXMgdG8gdGhlaXIgbmV3IHZhbHVlc1xuXHRcdGlmICggaXNBcnJheSApIHtcblx0XHRcdGZvciAoIDsgaSA8IGxlbmd0aDsgaSsrICkge1xuXHRcdFx0XHR2YWx1ZSA9IGNhbGxiYWNrKCBlbGVtc1sgaSBdLCBpLCBhcmcgKTtcblxuXHRcdFx0XHRpZiAoIHZhbHVlICE9IG51bGwgKSB7XG5cdFx0XHRcdFx0cmV0LnB1c2goIHZhbHVlICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdC8vIEdvIHRocm91Z2ggZXZlcnkga2V5IG9uIHRoZSBvYmplY3QsXG5cdFx0fSBlbHNlIHtcblx0XHRcdGZvciAoIGkgaW4gZWxlbXMgKSB7XG5cdFx0XHRcdHZhbHVlID0gY2FsbGJhY2soIGVsZW1zWyBpIF0sIGksIGFyZyApO1xuXG5cdFx0XHRcdGlmICggdmFsdWUgIT0gbnVsbCApIHtcblx0XHRcdFx0XHRyZXQucHVzaCggdmFsdWUgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIEZsYXR0ZW4gYW55IG5lc3RlZCBhcnJheXNcblx0XHRyZXR1cm4gY29uY2F0LmFwcGx5KCBbXSwgcmV0ICk7XG5cdH0sXG5cblx0Ly8gQSBnbG9iYWwgR1VJRCBjb3VudGVyIGZvciBvYmplY3RzXG5cdGd1aWQ6IDEsXG5cblx0Ly8gQmluZCBhIGZ1bmN0aW9uIHRvIGEgY29udGV4dCwgb3B0aW9uYWxseSBwYXJ0aWFsbHkgYXBwbHlpbmcgYW55XG5cdC8vIGFyZ3VtZW50cy5cblx0cHJveHk6IGZ1bmN0aW9uKCBmbiwgY29udGV4dCApIHtcblx0XHR2YXIgdG1wLCBhcmdzLCBwcm94eTtcblxuXHRcdGlmICggdHlwZW9mIGNvbnRleHQgPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHR0bXAgPSBmblsgY29udGV4dCBdO1xuXHRcdFx0Y29udGV4dCA9IGZuO1xuXHRcdFx0Zm4gPSB0bXA7XG5cdFx0fVxuXG5cdFx0Ly8gUXVpY2sgY2hlY2sgdG8gZGV0ZXJtaW5lIGlmIHRhcmdldCBpcyBjYWxsYWJsZSwgaW4gdGhlIHNwZWNcblx0XHQvLyB0aGlzIHRocm93cyBhIFR5cGVFcnJvciwgYnV0IHdlIHdpbGwganVzdCByZXR1cm4gdW5kZWZpbmVkLlxuXHRcdGlmICggIWpRdWVyeS5pc0Z1bmN0aW9uKCBmbiApICkge1xuXHRcdFx0cmV0dXJuIHVuZGVmaW5lZDtcblx0XHR9XG5cblx0XHQvLyBTaW11bGF0ZWQgYmluZFxuXHRcdGFyZ3MgPSBzbGljZS5jYWxsKCBhcmd1bWVudHMsIDIgKTtcblx0XHRwcm94eSA9IGZ1bmN0aW9uKCkge1xuXHRcdFx0cmV0dXJuIGZuLmFwcGx5KCBjb250ZXh0IHx8IHRoaXMsIGFyZ3MuY29uY2F0KCBzbGljZS5jYWxsKCBhcmd1bWVudHMgKSApICk7XG5cdFx0fTtcblxuXHRcdC8vIFNldCB0aGUgZ3VpZCBvZiB1bmlxdWUgaGFuZGxlciB0byB0aGUgc2FtZSBvZiBvcmlnaW5hbCBoYW5kbGVyLCBzbyBpdCBjYW4gYmUgcmVtb3ZlZFxuXHRcdHByb3h5Lmd1aWQgPSBmbi5ndWlkID0gZm4uZ3VpZCB8fCBqUXVlcnkuZ3VpZCsrO1xuXG5cdFx0cmV0dXJuIHByb3h5O1xuXHR9LFxuXG5cdG5vdzogRGF0ZS5ub3csXG5cblx0Ly8galF1ZXJ5LnN1cHBvcnQgaXMgbm90IHVzZWQgaW4gQ29yZSBidXQgb3RoZXIgcHJvamVjdHMgYXR0YWNoIHRoZWlyXG5cdC8vIHByb3BlcnRpZXMgdG8gaXQgc28gaXQgbmVlZHMgdG8gZXhpc3QuXG5cdHN1cHBvcnQ6IHN1cHBvcnRcbn0pO1xuXG4vLyBQb3B1bGF0ZSB0aGUgY2xhc3MydHlwZSBtYXBcbmpRdWVyeS5lYWNoKFwiQm9vbGVhbiBOdW1iZXIgU3RyaW5nIEZ1bmN0aW9uIEFycmF5IERhdGUgUmVnRXhwIE9iamVjdCBFcnJvclwiLnNwbGl0KFwiIFwiKSwgZnVuY3Rpb24oaSwgbmFtZSkge1xuXHRjbGFzczJ0eXBlWyBcIltvYmplY3QgXCIgKyBuYW1lICsgXCJdXCIgXSA9IG5hbWUudG9Mb3dlckNhc2UoKTtcbn0pO1xuXG5mdW5jdGlvbiBpc0FycmF5bGlrZSggb2JqICkge1xuXHR2YXIgbGVuZ3RoID0gb2JqLmxlbmd0aCxcblx0XHR0eXBlID0galF1ZXJ5LnR5cGUoIG9iaiApO1xuXG5cdGlmICggdHlwZSA9PT0gXCJmdW5jdGlvblwiIHx8IGpRdWVyeS5pc1dpbmRvdyggb2JqICkgKSB7XG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9XG5cblx0aWYgKCBvYmoubm9kZVR5cGUgPT09IDEgJiYgbGVuZ3RoICkge1xuXHRcdHJldHVybiB0cnVlO1xuXHR9XG5cblx0cmV0dXJuIHR5cGUgPT09IFwiYXJyYXlcIiB8fCBsZW5ndGggPT09IDAgfHxcblx0XHR0eXBlb2YgbGVuZ3RoID09PSBcIm51bWJlclwiICYmIGxlbmd0aCA+IDAgJiYgKCBsZW5ndGggLSAxICkgaW4gb2JqO1xufVxudmFyIFNpenpsZSA9XG4vKiFcbiAqIFNpenpsZSBDU1MgU2VsZWN0b3IgRW5naW5lIHYyLjIuMC1wcmVcbiAqIGh0dHA6Ly9zaXp6bGVqcy5jb20vXG4gKlxuICogQ29weXJpZ2h0IDIwMDgsIDIwMTQgalF1ZXJ5IEZvdW5kYXRpb24sIEluYy4gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKlxuICogRGF0ZTogMjAxNC0xMi0xNlxuICovXG4oZnVuY3Rpb24oIHdpbmRvdyApIHtcblxudmFyIGksXG5cdHN1cHBvcnQsXG5cdEV4cHIsXG5cdGdldFRleHQsXG5cdGlzWE1MLFxuXHR0b2tlbml6ZSxcblx0Y29tcGlsZSxcblx0c2VsZWN0LFxuXHRvdXRlcm1vc3RDb250ZXh0LFxuXHRzb3J0SW5wdXQsXG5cdGhhc0R1cGxpY2F0ZSxcblxuXHQvLyBMb2NhbCBkb2N1bWVudCB2YXJzXG5cdHNldERvY3VtZW50LFxuXHRkb2N1bWVudCxcblx0ZG9jRWxlbSxcblx0ZG9jdW1lbnRJc0hUTUwsXG5cdHJidWdneVFTQSxcblx0cmJ1Z2d5TWF0Y2hlcyxcblx0bWF0Y2hlcyxcblx0Y29udGFpbnMsXG5cblx0Ly8gSW5zdGFuY2Utc3BlY2lmaWMgZGF0YVxuXHRleHBhbmRvID0gXCJzaXp6bGVcIiArIDEgKiBuZXcgRGF0ZSgpLFxuXHRwcmVmZXJyZWREb2MgPSB3aW5kb3cuZG9jdW1lbnQsXG5cdGRpcnJ1bnMgPSAwLFxuXHRkb25lID0gMCxcblx0Y2xhc3NDYWNoZSA9IGNyZWF0ZUNhY2hlKCksXG5cdHRva2VuQ2FjaGUgPSBjcmVhdGVDYWNoZSgpLFxuXHRjb21waWxlckNhY2hlID0gY3JlYXRlQ2FjaGUoKSxcblx0c29ydE9yZGVyID0gZnVuY3Rpb24oIGEsIGIgKSB7XG5cdFx0aWYgKCBhID09PSBiICkge1xuXHRcdFx0aGFzRHVwbGljYXRlID0gdHJ1ZTtcblx0XHR9XG5cdFx0cmV0dXJuIDA7XG5cdH0sXG5cblx0Ly8gR2VuZXJhbC1wdXJwb3NlIGNvbnN0YW50c1xuXHRNQVhfTkVHQVRJVkUgPSAxIDw8IDMxLFxuXG5cdC8vIEluc3RhbmNlIG1ldGhvZHNcblx0aGFzT3duID0gKHt9KS5oYXNPd25Qcm9wZXJ0eSxcblx0YXJyID0gW10sXG5cdHBvcCA9IGFyci5wb3AsXG5cdHB1c2hfbmF0aXZlID0gYXJyLnB1c2gsXG5cdHB1c2ggPSBhcnIucHVzaCxcblx0c2xpY2UgPSBhcnIuc2xpY2UsXG5cdC8vIFVzZSBhIHN0cmlwcGVkLWRvd24gaW5kZXhPZiBhcyBpdCdzIGZhc3RlciB0aGFuIG5hdGl2ZVxuXHQvLyBodHRwOi8vanNwZXJmLmNvbS90aG9yLWluZGV4b2YtdnMtZm9yLzVcblx0aW5kZXhPZiA9IGZ1bmN0aW9uKCBsaXN0LCBlbGVtICkge1xuXHRcdHZhciBpID0gMCxcblx0XHRcdGxlbiA9IGxpc3QubGVuZ3RoO1xuXHRcdGZvciAoIDsgaSA8IGxlbjsgaSsrICkge1xuXHRcdFx0aWYgKCBsaXN0W2ldID09PSBlbGVtICkge1xuXHRcdFx0XHRyZXR1cm4gaTtcblx0XHRcdH1cblx0XHR9XG5cdFx0cmV0dXJuIC0xO1xuXHR9LFxuXG5cdGJvb2xlYW5zID0gXCJjaGVja2VkfHNlbGVjdGVkfGFzeW5jfGF1dG9mb2N1c3xhdXRvcGxheXxjb250cm9sc3xkZWZlcnxkaXNhYmxlZHxoaWRkZW58aXNtYXB8bG9vcHxtdWx0aXBsZXxvcGVufHJlYWRvbmx5fHJlcXVpcmVkfHNjb3BlZFwiLFxuXG5cdC8vIFJlZ3VsYXIgZXhwcmVzc2lvbnNcblxuXHQvLyBXaGl0ZXNwYWNlIGNoYXJhY3RlcnMgaHR0cDovL3d3dy53My5vcmcvVFIvY3NzMy1zZWxlY3RvcnMvI3doaXRlc3BhY2Vcblx0d2hpdGVzcGFjZSA9IFwiW1xcXFx4MjBcXFxcdFxcXFxyXFxcXG5cXFxcZl1cIixcblx0Ly8gaHR0cDovL3d3dy53My5vcmcvVFIvY3NzMy1zeW50YXgvI2NoYXJhY3RlcnNcblx0Y2hhcmFjdGVyRW5jb2RpbmcgPSBcIig/OlxcXFxcXFxcLnxbXFxcXHctXXxbXlxcXFx4MDAtXFxcXHhhMF0pK1wiLFxuXG5cdC8vIExvb3NlbHkgbW9kZWxlZCBvbiBDU1MgaWRlbnRpZmllciBjaGFyYWN0ZXJzXG5cdC8vIEFuIHVucXVvdGVkIHZhbHVlIHNob3VsZCBiZSBhIENTUyBpZGVudGlmaWVyIGh0dHA6Ly93d3cudzMub3JnL1RSL2NzczMtc2VsZWN0b3JzLyNhdHRyaWJ1dGUtc2VsZWN0b3JzXG5cdC8vIFByb3BlciBzeW50YXg6IGh0dHA6Ly93d3cudzMub3JnL1RSL0NTUzIxL3N5bmRhdGEuaHRtbCN2YWx1ZS1kZWYtaWRlbnRpZmllclxuXHRpZGVudGlmaWVyID0gY2hhcmFjdGVyRW5jb2RpbmcucmVwbGFjZSggXCJ3XCIsIFwidyNcIiApLFxuXG5cdC8vIEF0dHJpYnV0ZSBzZWxlY3RvcnM6IGh0dHA6Ly93d3cudzMub3JnL1RSL3NlbGVjdG9ycy8jYXR0cmlidXRlLXNlbGVjdG9yc1xuXHRhdHRyaWJ1dGVzID0gXCJcXFxcW1wiICsgd2hpdGVzcGFjZSArIFwiKihcIiArIGNoYXJhY3RlckVuY29kaW5nICsgXCIpKD86XCIgKyB3aGl0ZXNwYWNlICtcblx0XHQvLyBPcGVyYXRvciAoY2FwdHVyZSAyKVxuXHRcdFwiKihbKl4kfCF+XT89KVwiICsgd2hpdGVzcGFjZSArXG5cdFx0Ly8gXCJBdHRyaWJ1dGUgdmFsdWVzIG11c3QgYmUgQ1NTIGlkZW50aWZpZXJzIFtjYXB0dXJlIDVdIG9yIHN0cmluZ3MgW2NhcHR1cmUgMyBvciBjYXB0dXJlIDRdXCJcblx0XHRcIiooPzonKCg/OlxcXFxcXFxcLnxbXlxcXFxcXFxcJ10pKiknfFxcXCIoKD86XFxcXFxcXFwufFteXFxcXFxcXFxcXFwiXSkqKVxcXCJ8KFwiICsgaWRlbnRpZmllciArIFwiKSl8KVwiICsgd2hpdGVzcGFjZSArXG5cdFx0XCIqXFxcXF1cIixcblxuXHRwc2V1ZG9zID0gXCI6KFwiICsgY2hhcmFjdGVyRW5jb2RpbmcgKyBcIikoPzpcXFxcKChcIiArXG5cdFx0Ly8gVG8gcmVkdWNlIHRoZSBudW1iZXIgb2Ygc2VsZWN0b3JzIG5lZWRpbmcgdG9rZW5pemUgaW4gdGhlIHByZUZpbHRlciwgcHJlZmVyIGFyZ3VtZW50czpcblx0XHQvLyAxLiBxdW90ZWQgKGNhcHR1cmUgMzsgY2FwdHVyZSA0IG9yIGNhcHR1cmUgNSlcblx0XHRcIignKCg/OlxcXFxcXFxcLnxbXlxcXFxcXFxcJ10pKiknfFxcXCIoKD86XFxcXFxcXFwufFteXFxcXFxcXFxcXFwiXSkqKVxcXCIpfFwiICtcblx0XHQvLyAyLiBzaW1wbGUgKGNhcHR1cmUgNilcblx0XHRcIigoPzpcXFxcXFxcXC58W15cXFxcXFxcXCgpW1xcXFxdXXxcIiArIGF0dHJpYnV0ZXMgKyBcIikqKXxcIiArXG5cdFx0Ly8gMy4gYW55dGhpbmcgZWxzZSAoY2FwdHVyZSAyKVxuXHRcdFwiLipcIiArXG5cdFx0XCIpXFxcXCl8KVwiLFxuXG5cdC8vIExlYWRpbmcgYW5kIG5vbi1lc2NhcGVkIHRyYWlsaW5nIHdoaXRlc3BhY2UsIGNhcHR1cmluZyBzb21lIG5vbi13aGl0ZXNwYWNlIGNoYXJhY3RlcnMgcHJlY2VkaW5nIHRoZSBsYXR0ZXJcblx0cndoaXRlc3BhY2UgPSBuZXcgUmVnRXhwKCB3aGl0ZXNwYWNlICsgXCIrXCIsIFwiZ1wiICksXG5cdHJ0cmltID0gbmV3IFJlZ0V4cCggXCJeXCIgKyB3aGl0ZXNwYWNlICsgXCIrfCgoPzpefFteXFxcXFxcXFxdKSg/OlxcXFxcXFxcLikqKVwiICsgd2hpdGVzcGFjZSArIFwiKyRcIiwgXCJnXCIgKSxcblxuXHRyY29tbWEgPSBuZXcgUmVnRXhwKCBcIl5cIiArIHdoaXRlc3BhY2UgKyBcIiosXCIgKyB3aGl0ZXNwYWNlICsgXCIqXCIgKSxcblx0cmNvbWJpbmF0b3JzID0gbmV3IFJlZ0V4cCggXCJeXCIgKyB3aGl0ZXNwYWNlICsgXCIqKFs+K35dfFwiICsgd2hpdGVzcGFjZSArIFwiKVwiICsgd2hpdGVzcGFjZSArIFwiKlwiICksXG5cblx0cmF0dHJpYnV0ZVF1b3RlcyA9IG5ldyBSZWdFeHAoIFwiPVwiICsgd2hpdGVzcGFjZSArIFwiKihbXlxcXFxdJ1xcXCJdKj8pXCIgKyB3aGl0ZXNwYWNlICsgXCIqXFxcXF1cIiwgXCJnXCIgKSxcblxuXHRycHNldWRvID0gbmV3IFJlZ0V4cCggcHNldWRvcyApLFxuXHRyaWRlbnRpZmllciA9IG5ldyBSZWdFeHAoIFwiXlwiICsgaWRlbnRpZmllciArIFwiJFwiICksXG5cblx0bWF0Y2hFeHByID0ge1xuXHRcdFwiSURcIjogbmV3IFJlZ0V4cCggXCJeIyhcIiArIGNoYXJhY3RlckVuY29kaW5nICsgXCIpXCIgKSxcblx0XHRcIkNMQVNTXCI6IG5ldyBSZWdFeHAoIFwiXlxcXFwuKFwiICsgY2hhcmFjdGVyRW5jb2RpbmcgKyBcIilcIiApLFxuXHRcdFwiVEFHXCI6IG5ldyBSZWdFeHAoIFwiXihcIiArIGNoYXJhY3RlckVuY29kaW5nLnJlcGxhY2UoIFwid1wiLCBcIncqXCIgKSArIFwiKVwiICksXG5cdFx0XCJBVFRSXCI6IG5ldyBSZWdFeHAoIFwiXlwiICsgYXR0cmlidXRlcyApLFxuXHRcdFwiUFNFVURPXCI6IG5ldyBSZWdFeHAoIFwiXlwiICsgcHNldWRvcyApLFxuXHRcdFwiQ0hJTERcIjogbmV3IFJlZ0V4cCggXCJeOihvbmx5fGZpcnN0fGxhc3R8bnRofG50aC1sYXN0KS0oY2hpbGR8b2YtdHlwZSkoPzpcXFxcKFwiICsgd2hpdGVzcGFjZSArXG5cdFx0XHRcIiooZXZlbnxvZGR8KChbKy1dfCkoXFxcXGQqKW58KVwiICsgd2hpdGVzcGFjZSArIFwiKig/OihbKy1dfClcIiArIHdoaXRlc3BhY2UgK1xuXHRcdFx0XCIqKFxcXFxkKyl8KSlcIiArIHdoaXRlc3BhY2UgKyBcIipcXFxcKXwpXCIsIFwiaVwiICksXG5cdFx0XCJib29sXCI6IG5ldyBSZWdFeHAoIFwiXig/OlwiICsgYm9vbGVhbnMgKyBcIikkXCIsIFwiaVwiICksXG5cdFx0Ly8gRm9yIHVzZSBpbiBsaWJyYXJpZXMgaW1wbGVtZW50aW5nIC5pcygpXG5cdFx0Ly8gV2UgdXNlIHRoaXMgZm9yIFBPUyBtYXRjaGluZyBpbiBgc2VsZWN0YFxuXHRcdFwibmVlZHNDb250ZXh0XCI6IG5ldyBSZWdFeHAoIFwiXlwiICsgd2hpdGVzcGFjZSArIFwiKls+K35dfDooZXZlbnxvZGR8ZXF8Z3R8bHR8bnRofGZpcnN0fGxhc3QpKD86XFxcXChcIiArXG5cdFx0XHR3aGl0ZXNwYWNlICsgXCIqKCg/Oi1cXFxcZCk/XFxcXGQqKVwiICsgd2hpdGVzcGFjZSArIFwiKlxcXFwpfCkoPz1bXi1dfCQpXCIsIFwiaVwiIClcblx0fSxcblxuXHRyaW5wdXRzID0gL14oPzppbnB1dHxzZWxlY3R8dGV4dGFyZWF8YnV0dG9uKSQvaSxcblx0cmhlYWRlciA9IC9eaFxcZCQvaSxcblxuXHRybmF0aXZlID0gL15bXntdK1xce1xccypcXFtuYXRpdmUgXFx3LyxcblxuXHQvLyBFYXNpbHktcGFyc2VhYmxlL3JldHJpZXZhYmxlIElEIG9yIFRBRyBvciBDTEFTUyBzZWxlY3RvcnNcblx0cnF1aWNrRXhwciA9IC9eKD86IyhbXFx3LV0rKXwoXFx3Kyl8XFwuKFtcXHctXSspKSQvLFxuXG5cdHJzaWJsaW5nID0gL1srfl0vLFxuXHRyZXNjYXBlID0gLyd8XFxcXC9nLFxuXG5cdC8vIENTUyBlc2NhcGVzIGh0dHA6Ly93d3cudzMub3JnL1RSL0NTUzIxL3N5bmRhdGEuaHRtbCNlc2NhcGVkLWNoYXJhY3RlcnNcblx0cnVuZXNjYXBlID0gbmV3IFJlZ0V4cCggXCJcXFxcXFxcXChbXFxcXGRhLWZdezEsNn1cIiArIHdoaXRlc3BhY2UgKyBcIj98KFwiICsgd2hpdGVzcGFjZSArIFwiKXwuKVwiLCBcImlnXCIgKSxcblx0ZnVuZXNjYXBlID0gZnVuY3Rpb24oIF8sIGVzY2FwZWQsIGVzY2FwZWRXaGl0ZXNwYWNlICkge1xuXHRcdHZhciBoaWdoID0gXCIweFwiICsgZXNjYXBlZCAtIDB4MTAwMDA7XG5cdFx0Ly8gTmFOIG1lYW5zIG5vbi1jb2RlcG9pbnRcblx0XHQvLyBTdXBwb3J0OiBGaXJlZm94PDI0XG5cdFx0Ly8gV29ya2Fyb3VuZCBlcnJvbmVvdXMgbnVtZXJpYyBpbnRlcnByZXRhdGlvbiBvZiArXCIweFwiXG5cdFx0cmV0dXJuIGhpZ2ggIT09IGhpZ2ggfHwgZXNjYXBlZFdoaXRlc3BhY2UgP1xuXHRcdFx0ZXNjYXBlZCA6XG5cdFx0XHRoaWdoIDwgMCA/XG5cdFx0XHRcdC8vIEJNUCBjb2RlcG9pbnRcblx0XHRcdFx0U3RyaW5nLmZyb21DaGFyQ29kZSggaGlnaCArIDB4MTAwMDAgKSA6XG5cdFx0XHRcdC8vIFN1cHBsZW1lbnRhbCBQbGFuZSBjb2RlcG9pbnQgKHN1cnJvZ2F0ZSBwYWlyKVxuXHRcdFx0XHRTdHJpbmcuZnJvbUNoYXJDb2RlKCBoaWdoID4+IDEwIHwgMHhEODAwLCBoaWdoICYgMHgzRkYgfCAweERDMDAgKTtcblx0fSxcblxuXHQvLyBVc2VkIGZvciBpZnJhbWVzXG5cdC8vIFNlZSBzZXREb2N1bWVudCgpXG5cdC8vIFJlbW92aW5nIHRoZSBmdW5jdGlvbiB3cmFwcGVyIGNhdXNlcyBhIFwiUGVybWlzc2lvbiBEZW5pZWRcIlxuXHQvLyBlcnJvciBpbiBJRVxuXHR1bmxvYWRIYW5kbGVyID0gZnVuY3Rpb24oKSB7XG5cdFx0c2V0RG9jdW1lbnQoKTtcblx0fTtcblxuLy8gT3B0aW1pemUgZm9yIHB1c2guYXBwbHkoIF8sIE5vZGVMaXN0IClcbnRyeSB7XG5cdHB1c2guYXBwbHkoXG5cdFx0KGFyciA9IHNsaWNlLmNhbGwoIHByZWZlcnJlZERvYy5jaGlsZE5vZGVzICkpLFxuXHRcdHByZWZlcnJlZERvYy5jaGlsZE5vZGVzXG5cdCk7XG5cdC8vIFN1cHBvcnQ6IEFuZHJvaWQ8NC4wXG5cdC8vIERldGVjdCBzaWxlbnRseSBmYWlsaW5nIHB1c2guYXBwbHlcblx0YXJyWyBwcmVmZXJyZWREb2MuY2hpbGROb2Rlcy5sZW5ndGggXS5ub2RlVHlwZTtcbn0gY2F0Y2ggKCBlICkge1xuXHRwdXNoID0geyBhcHBseTogYXJyLmxlbmd0aCA/XG5cblx0XHQvLyBMZXZlcmFnZSBzbGljZSBpZiBwb3NzaWJsZVxuXHRcdGZ1bmN0aW9uKCB0YXJnZXQsIGVscyApIHtcblx0XHRcdHB1c2hfbmF0aXZlLmFwcGx5KCB0YXJnZXQsIHNsaWNlLmNhbGwoZWxzKSApO1xuXHRcdH0gOlxuXG5cdFx0Ly8gU3VwcG9ydDogSUU8OVxuXHRcdC8vIE90aGVyd2lzZSBhcHBlbmQgZGlyZWN0bHlcblx0XHRmdW5jdGlvbiggdGFyZ2V0LCBlbHMgKSB7XG5cdFx0XHR2YXIgaiA9IHRhcmdldC5sZW5ndGgsXG5cdFx0XHRcdGkgPSAwO1xuXHRcdFx0Ly8gQ2FuJ3QgdHJ1c3QgTm9kZUxpc3QubGVuZ3RoXG5cdFx0XHR3aGlsZSAoICh0YXJnZXRbaisrXSA9IGVsc1tpKytdKSApIHt9XG5cdFx0XHR0YXJnZXQubGVuZ3RoID0gaiAtIDE7XG5cdFx0fVxuXHR9O1xufVxuXG5mdW5jdGlvbiBTaXp6bGUoIHNlbGVjdG9yLCBjb250ZXh0LCByZXN1bHRzLCBzZWVkICkge1xuXHR2YXIgbWF0Y2gsIGVsZW0sIG0sIG5vZGVUeXBlLFxuXHRcdC8vIFFTQSB2YXJzXG5cdFx0aSwgZ3JvdXBzLCBvbGQsIG5pZCwgbmV3Q29udGV4dCwgbmV3U2VsZWN0b3I7XG5cblx0aWYgKCAoIGNvbnRleHQgPyBjb250ZXh0Lm93bmVyRG9jdW1lbnQgfHwgY29udGV4dCA6IHByZWZlcnJlZERvYyApICE9PSBkb2N1bWVudCApIHtcblx0XHRzZXREb2N1bWVudCggY29udGV4dCApO1xuXHR9XG5cblx0Y29udGV4dCA9IGNvbnRleHQgfHwgZG9jdW1lbnQ7XG5cdHJlc3VsdHMgPSByZXN1bHRzIHx8IFtdO1xuXHRub2RlVHlwZSA9IGNvbnRleHQubm9kZVR5cGU7XG5cblx0aWYgKCB0eXBlb2Ygc2VsZWN0b3IgIT09IFwic3RyaW5nXCIgfHwgIXNlbGVjdG9yIHx8XG5cdFx0bm9kZVR5cGUgIT09IDEgJiYgbm9kZVR5cGUgIT09IDkgJiYgbm9kZVR5cGUgIT09IDExICkge1xuXG5cdFx0cmV0dXJuIHJlc3VsdHM7XG5cdH1cblxuXHRpZiAoICFzZWVkICYmIGRvY3VtZW50SXNIVE1MICkge1xuXG5cdFx0Ly8gVHJ5IHRvIHNob3J0Y3V0IGZpbmQgb3BlcmF0aW9ucyB3aGVuIHBvc3NpYmxlIChlLmcuLCBub3QgdW5kZXIgRG9jdW1lbnRGcmFnbWVudClcblx0XHRpZiAoIG5vZGVUeXBlICE9PSAxMSAmJiAobWF0Y2ggPSBycXVpY2tFeHByLmV4ZWMoIHNlbGVjdG9yICkpICkge1xuXHRcdFx0Ly8gU3BlZWQtdXA6IFNpenpsZShcIiNJRFwiKVxuXHRcdFx0aWYgKCAobSA9IG1hdGNoWzFdKSApIHtcblx0XHRcdFx0aWYgKCBub2RlVHlwZSA9PT0gOSApIHtcblx0XHRcdFx0XHRlbGVtID0gY29udGV4dC5nZXRFbGVtZW50QnlJZCggbSApO1xuXHRcdFx0XHRcdC8vIENoZWNrIHBhcmVudE5vZGUgdG8gY2F0Y2ggd2hlbiBCbGFja2JlcnJ5IDQuNiByZXR1cm5zXG5cdFx0XHRcdFx0Ly8gbm9kZXMgdGhhdCBhcmUgbm8gbG9uZ2VyIGluIHRoZSBkb2N1bWVudCAoalF1ZXJ5ICM2OTYzKVxuXHRcdFx0XHRcdGlmICggZWxlbSAmJiBlbGVtLnBhcmVudE5vZGUgKSB7XG5cdFx0XHRcdFx0XHQvLyBIYW5kbGUgdGhlIGNhc2Ugd2hlcmUgSUUsIE9wZXJhLCBhbmQgV2Via2l0IHJldHVybiBpdGVtc1xuXHRcdFx0XHRcdFx0Ly8gYnkgbmFtZSBpbnN0ZWFkIG9mIElEXG5cdFx0XHRcdFx0XHRpZiAoIGVsZW0uaWQgPT09IG0gKSB7XG5cdFx0XHRcdFx0XHRcdHJlc3VsdHMucHVzaCggZWxlbSApO1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4gcmVzdWx0cztcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0cmV0dXJuIHJlc3VsdHM7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdC8vIENvbnRleHQgaXMgbm90IGEgZG9jdW1lbnRcblx0XHRcdFx0XHRpZiAoIGNvbnRleHQub3duZXJEb2N1bWVudCAmJiAoZWxlbSA9IGNvbnRleHQub3duZXJEb2N1bWVudC5nZXRFbGVtZW50QnlJZCggbSApKSAmJlxuXHRcdFx0XHRcdFx0Y29udGFpbnMoIGNvbnRleHQsIGVsZW0gKSAmJiBlbGVtLmlkID09PSBtICkge1xuXHRcdFx0XHRcdFx0cmVzdWx0cy5wdXNoKCBlbGVtICk7XG5cdFx0XHRcdFx0XHRyZXR1cm4gcmVzdWx0cztcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblxuXHRcdFx0Ly8gU3BlZWQtdXA6IFNpenpsZShcIlRBR1wiKVxuXHRcdFx0fSBlbHNlIGlmICggbWF0Y2hbMl0gKSB7XG5cdFx0XHRcdHB1c2guYXBwbHkoIHJlc3VsdHMsIGNvbnRleHQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoIHNlbGVjdG9yICkgKTtcblx0XHRcdFx0cmV0dXJuIHJlc3VsdHM7XG5cblx0XHRcdC8vIFNwZWVkLXVwOiBTaXp6bGUoXCIuQ0xBU1NcIilcblx0XHRcdH0gZWxzZSBpZiAoIChtID0gbWF0Y2hbM10pICYmIHN1cHBvcnQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSApIHtcblx0XHRcdFx0cHVzaC5hcHBseSggcmVzdWx0cywgY29udGV4dC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKCBtICkgKTtcblx0XHRcdFx0cmV0dXJuIHJlc3VsdHM7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gUVNBIHBhdGhcblx0XHRpZiAoIHN1cHBvcnQucXNhICYmICghcmJ1Z2d5UVNBIHx8ICFyYnVnZ3lRU0EudGVzdCggc2VsZWN0b3IgKSkgKSB7XG5cdFx0XHRuaWQgPSBvbGQgPSBleHBhbmRvO1xuXHRcdFx0bmV3Q29udGV4dCA9IGNvbnRleHQ7XG5cdFx0XHRuZXdTZWxlY3RvciA9IG5vZGVUeXBlICE9PSAxICYmIHNlbGVjdG9yO1xuXG5cdFx0XHQvLyBxU0Egd29ya3Mgc3RyYW5nZWx5IG9uIEVsZW1lbnQtcm9vdGVkIHF1ZXJpZXNcblx0XHRcdC8vIFdlIGNhbiB3b3JrIGFyb3VuZCB0aGlzIGJ5IHNwZWNpZnlpbmcgYW4gZXh0cmEgSUQgb24gdGhlIHJvb3Rcblx0XHRcdC8vIGFuZCB3b3JraW5nIHVwIGZyb20gdGhlcmUgKFRoYW5rcyB0byBBbmRyZXcgRHVwb250IGZvciB0aGUgdGVjaG5pcXVlKVxuXHRcdFx0Ly8gSUUgOCBkb2Vzbid0IHdvcmsgb24gb2JqZWN0IGVsZW1lbnRzXG5cdFx0XHRpZiAoIG5vZGVUeXBlID09PSAxICYmIGNvbnRleHQubm9kZU5hbWUudG9Mb3dlckNhc2UoKSAhPT0gXCJvYmplY3RcIiApIHtcblx0XHRcdFx0Z3JvdXBzID0gdG9rZW5pemUoIHNlbGVjdG9yICk7XG5cblx0XHRcdFx0aWYgKCAob2xkID0gY29udGV4dC5nZXRBdHRyaWJ1dGUoXCJpZFwiKSkgKSB7XG5cdFx0XHRcdFx0bmlkID0gb2xkLnJlcGxhY2UoIHJlc2NhcGUsIFwiXFxcXCQmXCIgKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRjb250ZXh0LnNldEF0dHJpYnV0ZSggXCJpZFwiLCBuaWQgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRuaWQgPSBcIltpZD0nXCIgKyBuaWQgKyBcIiddIFwiO1xuXG5cdFx0XHRcdGkgPSBncm91cHMubGVuZ3RoO1xuXHRcdFx0XHR3aGlsZSAoIGktLSApIHtcblx0XHRcdFx0XHRncm91cHNbaV0gPSBuaWQgKyB0b1NlbGVjdG9yKCBncm91cHNbaV0gKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRuZXdDb250ZXh0ID0gcnNpYmxpbmcudGVzdCggc2VsZWN0b3IgKSAmJiB0ZXN0Q29udGV4dCggY29udGV4dC5wYXJlbnROb2RlICkgfHwgY29udGV4dDtcblx0XHRcdFx0bmV3U2VsZWN0b3IgPSBncm91cHMuam9pbihcIixcIik7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggbmV3U2VsZWN0b3IgKSB7XG5cdFx0XHRcdHRyeSB7XG5cdFx0XHRcdFx0cHVzaC5hcHBseSggcmVzdWx0cyxcblx0XHRcdFx0XHRcdG5ld0NvbnRleHQucXVlcnlTZWxlY3RvckFsbCggbmV3U2VsZWN0b3IgKVxuXHRcdFx0XHRcdCk7XG5cdFx0XHRcdFx0cmV0dXJuIHJlc3VsdHM7XG5cdFx0XHRcdH0gY2F0Y2gocXNhRXJyb3IpIHtcblx0XHRcdFx0fSBmaW5hbGx5IHtcblx0XHRcdFx0XHRpZiAoICFvbGQgKSB7XG5cdFx0XHRcdFx0XHRjb250ZXh0LnJlbW92ZUF0dHJpYnV0ZShcImlkXCIpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdC8vIEFsbCBvdGhlcnNcblx0cmV0dXJuIHNlbGVjdCggc2VsZWN0b3IucmVwbGFjZSggcnRyaW0sIFwiJDFcIiApLCBjb250ZXh0LCByZXN1bHRzLCBzZWVkICk7XG59XG5cbi8qKlxuICogQ3JlYXRlIGtleS12YWx1ZSBjYWNoZXMgb2YgbGltaXRlZCBzaXplXG4gKiBAcmV0dXJucyB7RnVuY3Rpb24oc3RyaW5nLCBPYmplY3QpfSBSZXR1cm5zIHRoZSBPYmplY3QgZGF0YSBhZnRlciBzdG9yaW5nIGl0IG9uIGl0c2VsZiB3aXRoXG4gKlx0cHJvcGVydHkgbmFtZSB0aGUgKHNwYWNlLXN1ZmZpeGVkKSBzdHJpbmcgYW5kIChpZiB0aGUgY2FjaGUgaXMgbGFyZ2VyIHRoYW4gRXhwci5jYWNoZUxlbmd0aClcbiAqXHRkZWxldGluZyB0aGUgb2xkZXN0IGVudHJ5XG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZUNhY2hlKCkge1xuXHR2YXIga2V5cyA9IFtdO1xuXG5cdGZ1bmN0aW9uIGNhY2hlKCBrZXksIHZhbHVlICkge1xuXHRcdC8vIFVzZSAoa2V5ICsgXCIgXCIpIHRvIGF2b2lkIGNvbGxpc2lvbiB3aXRoIG5hdGl2ZSBwcm90b3R5cGUgcHJvcGVydGllcyAoc2VlIElzc3VlICMxNTcpXG5cdFx0aWYgKCBrZXlzLnB1c2goIGtleSArIFwiIFwiICkgPiBFeHByLmNhY2hlTGVuZ3RoICkge1xuXHRcdFx0Ly8gT25seSBrZWVwIHRoZSBtb3N0IHJlY2VudCBlbnRyaWVzXG5cdFx0XHRkZWxldGUgY2FjaGVbIGtleXMuc2hpZnQoKSBdO1xuXHRcdH1cblx0XHRyZXR1cm4gKGNhY2hlWyBrZXkgKyBcIiBcIiBdID0gdmFsdWUpO1xuXHR9XG5cdHJldHVybiBjYWNoZTtcbn1cblxuLyoqXG4gKiBNYXJrIGEgZnVuY3Rpb24gZm9yIHNwZWNpYWwgdXNlIGJ5IFNpenpsZVxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gVGhlIGZ1bmN0aW9uIHRvIG1hcmtcbiAqL1xuZnVuY3Rpb24gbWFya0Z1bmN0aW9uKCBmbiApIHtcblx0Zm5bIGV4cGFuZG8gXSA9IHRydWU7XG5cdHJldHVybiBmbjtcbn1cblxuLyoqXG4gKiBTdXBwb3J0IHRlc3RpbmcgdXNpbmcgYW4gZWxlbWVudFxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gUGFzc2VkIHRoZSBjcmVhdGVkIGRpdiBhbmQgZXhwZWN0cyBhIGJvb2xlYW4gcmVzdWx0XG4gKi9cbmZ1bmN0aW9uIGFzc2VydCggZm4gKSB7XG5cdHZhciBkaXYgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwiZGl2XCIpO1xuXG5cdHRyeSB7XG5cdFx0cmV0dXJuICEhZm4oIGRpdiApO1xuXHR9IGNhdGNoIChlKSB7XG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9IGZpbmFsbHkge1xuXHRcdC8vIFJlbW92ZSBmcm9tIGl0cyBwYXJlbnQgYnkgZGVmYXVsdFxuXHRcdGlmICggZGl2LnBhcmVudE5vZGUgKSB7XG5cdFx0XHRkaXYucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCggZGl2ICk7XG5cdFx0fVxuXHRcdC8vIHJlbGVhc2UgbWVtb3J5IGluIElFXG5cdFx0ZGl2ID0gbnVsbDtcblx0fVxufVxuXG4vKipcbiAqIEFkZHMgdGhlIHNhbWUgaGFuZGxlciBmb3IgYWxsIG9mIHRoZSBzcGVjaWZpZWQgYXR0cnNcbiAqIEBwYXJhbSB7U3RyaW5nfSBhdHRycyBQaXBlLXNlcGFyYXRlZCBsaXN0IG9mIGF0dHJpYnV0ZXNcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGhhbmRsZXIgVGhlIG1ldGhvZCB0aGF0IHdpbGwgYmUgYXBwbGllZFxuICovXG5mdW5jdGlvbiBhZGRIYW5kbGUoIGF0dHJzLCBoYW5kbGVyICkge1xuXHR2YXIgYXJyID0gYXR0cnMuc3BsaXQoXCJ8XCIpLFxuXHRcdGkgPSBhdHRycy5sZW5ndGg7XG5cblx0d2hpbGUgKCBpLS0gKSB7XG5cdFx0RXhwci5hdHRySGFuZGxlWyBhcnJbaV0gXSA9IGhhbmRsZXI7XG5cdH1cbn1cblxuLyoqXG4gKiBDaGVja3MgZG9jdW1lbnQgb3JkZXIgb2YgdHdvIHNpYmxpbmdzXG4gKiBAcGFyYW0ge0VsZW1lbnR9IGFcbiAqIEBwYXJhbSB7RWxlbWVudH0gYlxuICogQHJldHVybnMge051bWJlcn0gUmV0dXJucyBsZXNzIHRoYW4gMCBpZiBhIHByZWNlZGVzIGIsIGdyZWF0ZXIgdGhhbiAwIGlmIGEgZm9sbG93cyBiXG4gKi9cbmZ1bmN0aW9uIHNpYmxpbmdDaGVjayggYSwgYiApIHtcblx0dmFyIGN1ciA9IGIgJiYgYSxcblx0XHRkaWZmID0gY3VyICYmIGEubm9kZVR5cGUgPT09IDEgJiYgYi5ub2RlVHlwZSA9PT0gMSAmJlxuXHRcdFx0KCB+Yi5zb3VyY2VJbmRleCB8fCBNQVhfTkVHQVRJVkUgKSAtXG5cdFx0XHQoIH5hLnNvdXJjZUluZGV4IHx8IE1BWF9ORUdBVElWRSApO1xuXG5cdC8vIFVzZSBJRSBzb3VyY2VJbmRleCBpZiBhdmFpbGFibGUgb24gYm90aCBub2Rlc1xuXHRpZiAoIGRpZmYgKSB7XG5cdFx0cmV0dXJuIGRpZmY7XG5cdH1cblxuXHQvLyBDaGVjayBpZiBiIGZvbGxvd3MgYVxuXHRpZiAoIGN1ciApIHtcblx0XHR3aGlsZSAoIChjdXIgPSBjdXIubmV4dFNpYmxpbmcpICkge1xuXHRcdFx0aWYgKCBjdXIgPT09IGIgKSB7XG5cdFx0XHRcdHJldHVybiAtMTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHRyZXR1cm4gYSA/IDEgOiAtMTtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIGEgZnVuY3Rpb24gdG8gdXNlIGluIHBzZXVkb3MgZm9yIGlucHV0IHR5cGVzXG4gKiBAcGFyYW0ge1N0cmluZ30gdHlwZVxuICovXG5mdW5jdGlvbiBjcmVhdGVJbnB1dFBzZXVkbyggdHlwZSApIHtcblx0cmV0dXJuIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdHZhciBuYW1lID0gZWxlbS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpO1xuXHRcdHJldHVybiBuYW1lID09PSBcImlucHV0XCIgJiYgZWxlbS50eXBlID09PSB0eXBlO1xuXHR9O1xufVxuXG4vKipcbiAqIFJldHVybnMgYSBmdW5jdGlvbiB0byB1c2UgaW4gcHNldWRvcyBmb3IgYnV0dG9uc1xuICogQHBhcmFtIHtTdHJpbmd9IHR5cGVcbiAqL1xuZnVuY3Rpb24gY3JlYXRlQnV0dG9uUHNldWRvKCB0eXBlICkge1xuXHRyZXR1cm4gZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0dmFyIG5hbWUgPSBlbGVtLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk7XG5cdFx0cmV0dXJuIChuYW1lID09PSBcImlucHV0XCIgfHwgbmFtZSA9PT0gXCJidXR0b25cIikgJiYgZWxlbS50eXBlID09PSB0eXBlO1xuXHR9O1xufVxuXG4vKipcbiAqIFJldHVybnMgYSBmdW5jdGlvbiB0byB1c2UgaW4gcHNldWRvcyBmb3IgcG9zaXRpb25hbHNcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZuXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZVBvc2l0aW9uYWxQc2V1ZG8oIGZuICkge1xuXHRyZXR1cm4gbWFya0Z1bmN0aW9uKGZ1bmN0aW9uKCBhcmd1bWVudCApIHtcblx0XHRhcmd1bWVudCA9ICthcmd1bWVudDtcblx0XHRyZXR1cm4gbWFya0Z1bmN0aW9uKGZ1bmN0aW9uKCBzZWVkLCBtYXRjaGVzICkge1xuXHRcdFx0dmFyIGosXG5cdFx0XHRcdG1hdGNoSW5kZXhlcyA9IGZuKCBbXSwgc2VlZC5sZW5ndGgsIGFyZ3VtZW50ICksXG5cdFx0XHRcdGkgPSBtYXRjaEluZGV4ZXMubGVuZ3RoO1xuXG5cdFx0XHQvLyBNYXRjaCBlbGVtZW50cyBmb3VuZCBhdCB0aGUgc3BlY2lmaWVkIGluZGV4ZXNcblx0XHRcdHdoaWxlICggaS0tICkge1xuXHRcdFx0XHRpZiAoIHNlZWRbIChqID0gbWF0Y2hJbmRleGVzW2ldKSBdICkge1xuXHRcdFx0XHRcdHNlZWRbal0gPSAhKG1hdGNoZXNbal0gPSBzZWVkW2pdKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0pO1xuXHR9KTtcbn1cblxuLyoqXG4gKiBDaGVja3MgYSBub2RlIGZvciB2YWxpZGl0eSBhcyBhIFNpenpsZSBjb250ZXh0XG4gKiBAcGFyYW0ge0VsZW1lbnR8T2JqZWN0PX0gY29udGV4dFxuICogQHJldHVybnMge0VsZW1lbnR8T2JqZWN0fEJvb2xlYW59IFRoZSBpbnB1dCBub2RlIGlmIGFjY2VwdGFibGUsIG90aGVyd2lzZSBhIGZhbHN5IHZhbHVlXG4gKi9cbmZ1bmN0aW9uIHRlc3RDb250ZXh0KCBjb250ZXh0ICkge1xuXHRyZXR1cm4gY29udGV4dCAmJiB0eXBlb2YgY29udGV4dC5nZXRFbGVtZW50c0J5VGFnTmFtZSAhPT0gXCJ1bmRlZmluZWRcIiAmJiBjb250ZXh0O1xufVxuXG4vLyBFeHBvc2Ugc3VwcG9ydCB2YXJzIGZvciBjb252ZW5pZW5jZVxuc3VwcG9ydCA9IFNpenpsZS5zdXBwb3J0ID0ge307XG5cbi8qKlxuICogRGV0ZWN0cyBYTUwgbm9kZXNcbiAqIEBwYXJhbSB7RWxlbWVudHxPYmplY3R9IGVsZW0gQW4gZWxlbWVudCBvciBhIGRvY3VtZW50XG4gKiBAcmV0dXJucyB7Qm9vbGVhbn0gVHJ1ZSBpZmYgZWxlbSBpcyBhIG5vbi1IVE1MIFhNTCBub2RlXG4gKi9cbmlzWE1MID0gU2l6emxlLmlzWE1MID0gZnVuY3Rpb24oIGVsZW0gKSB7XG5cdC8vIGRvY3VtZW50RWxlbWVudCBpcyB2ZXJpZmllZCBmb3IgY2FzZXMgd2hlcmUgaXQgZG9lc24ndCB5ZXQgZXhpc3Rcblx0Ly8gKHN1Y2ggYXMgbG9hZGluZyBpZnJhbWVzIGluIElFIC0gIzQ4MzMpXG5cdHZhciBkb2N1bWVudEVsZW1lbnQgPSBlbGVtICYmIChlbGVtLm93bmVyRG9jdW1lbnQgfHwgZWxlbSkuZG9jdW1lbnRFbGVtZW50O1xuXHRyZXR1cm4gZG9jdW1lbnRFbGVtZW50ID8gZG9jdW1lbnRFbGVtZW50Lm5vZGVOYW1lICE9PSBcIkhUTUxcIiA6IGZhbHNlO1xufTtcblxuLyoqXG4gKiBTZXRzIGRvY3VtZW50LXJlbGF0ZWQgdmFyaWFibGVzIG9uY2UgYmFzZWQgb24gdGhlIGN1cnJlbnQgZG9jdW1lbnRcbiAqIEBwYXJhbSB7RWxlbWVudHxPYmplY3R9IFtkb2NdIEFuIGVsZW1lbnQgb3IgZG9jdW1lbnQgb2JqZWN0IHRvIHVzZSB0byBzZXQgdGhlIGRvY3VtZW50XG4gKiBAcmV0dXJucyB7T2JqZWN0fSBSZXR1cm5zIHRoZSBjdXJyZW50IGRvY3VtZW50XG4gKi9cbnNldERvY3VtZW50ID0gU2l6emxlLnNldERvY3VtZW50ID0gZnVuY3Rpb24oIG5vZGUgKSB7XG5cdHZhciBoYXNDb21wYXJlLCBwYXJlbnQsXG5cdFx0ZG9jID0gbm9kZSA/IG5vZGUub3duZXJEb2N1bWVudCB8fCBub2RlIDogcHJlZmVycmVkRG9jO1xuXG5cdC8vIElmIG5vIGRvY3VtZW50IGFuZCBkb2N1bWVudEVsZW1lbnQgaXMgYXZhaWxhYmxlLCByZXR1cm5cblx0aWYgKCBkb2MgPT09IGRvY3VtZW50IHx8IGRvYy5ub2RlVHlwZSAhPT0gOSB8fCAhZG9jLmRvY3VtZW50RWxlbWVudCApIHtcblx0XHRyZXR1cm4gZG9jdW1lbnQ7XG5cdH1cblxuXHQvLyBTZXQgb3VyIGRvY3VtZW50XG5cdGRvY3VtZW50ID0gZG9jO1xuXHRkb2NFbGVtID0gZG9jLmRvY3VtZW50RWxlbWVudDtcblx0cGFyZW50ID0gZG9jLmRlZmF1bHRWaWV3O1xuXG5cdC8vIFN1cHBvcnQ6IElFPjhcblx0Ly8gSWYgaWZyYW1lIGRvY3VtZW50IGlzIGFzc2lnbmVkIHRvIFwiZG9jdW1lbnRcIiB2YXJpYWJsZSBhbmQgaWYgaWZyYW1lIGhhcyBiZWVuIHJlbG9hZGVkLFxuXHQvLyBJRSB3aWxsIHRocm93IFwicGVybWlzc2lvbiBkZW5pZWRcIiBlcnJvciB3aGVuIGFjY2Vzc2luZyBcImRvY3VtZW50XCIgdmFyaWFibGUsIHNlZSBqUXVlcnkgIzEzOTM2XG5cdC8vIElFNi04IGRvIG5vdCBzdXBwb3J0IHRoZSBkZWZhdWx0VmlldyBwcm9wZXJ0eSBzbyBwYXJlbnQgd2lsbCBiZSB1bmRlZmluZWRcblx0aWYgKCBwYXJlbnQgJiYgcGFyZW50ICE9PSBwYXJlbnQudG9wICkge1xuXHRcdC8vIElFMTEgZG9lcyBub3QgaGF2ZSBhdHRhY2hFdmVudCwgc28gYWxsIG11c3Qgc3VmZmVyXG5cdFx0aWYgKCBwYXJlbnQuYWRkRXZlbnRMaXN0ZW5lciApIHtcblx0XHRcdHBhcmVudC5hZGRFdmVudExpc3RlbmVyKCBcInVubG9hZFwiLCB1bmxvYWRIYW5kbGVyLCBmYWxzZSApO1xuXHRcdH0gZWxzZSBpZiAoIHBhcmVudC5hdHRhY2hFdmVudCApIHtcblx0XHRcdHBhcmVudC5hdHRhY2hFdmVudCggXCJvbnVubG9hZFwiLCB1bmxvYWRIYW5kbGVyICk7XG5cdFx0fVxuXHR9XG5cblx0LyogU3VwcG9ydCB0ZXN0c1xuXHQtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG5cdGRvY3VtZW50SXNIVE1MID0gIWlzWE1MKCBkb2MgKTtcblxuXHQvKiBBdHRyaWJ1dGVzXG5cdC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cblxuXHQvLyBTdXBwb3J0OiBJRTw4XG5cdC8vIFZlcmlmeSB0aGF0IGdldEF0dHJpYnV0ZSByZWFsbHkgcmV0dXJucyBhdHRyaWJ1dGVzIGFuZCBub3QgcHJvcGVydGllc1xuXHQvLyAoZXhjZXB0aW5nIElFOCBib29sZWFucylcblx0c3VwcG9ydC5hdHRyaWJ1dGVzID0gYXNzZXJ0KGZ1bmN0aW9uKCBkaXYgKSB7XG5cdFx0ZGl2LmNsYXNzTmFtZSA9IFwiaVwiO1xuXHRcdHJldHVybiAhZGl2LmdldEF0dHJpYnV0ZShcImNsYXNzTmFtZVwiKTtcblx0fSk7XG5cblx0LyogZ2V0RWxlbWVudChzKUJ5KlxuXHQtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG5cblx0Ly8gQ2hlY2sgaWYgZ2V0RWxlbWVudHNCeVRhZ05hbWUoXCIqXCIpIHJldHVybnMgb25seSBlbGVtZW50c1xuXHRzdXBwb3J0LmdldEVsZW1lbnRzQnlUYWdOYW1lID0gYXNzZXJ0KGZ1bmN0aW9uKCBkaXYgKSB7XG5cdFx0ZGl2LmFwcGVuZENoaWxkKCBkb2MuY3JlYXRlQ29tbWVudChcIlwiKSApO1xuXHRcdHJldHVybiAhZGl2LmdldEVsZW1lbnRzQnlUYWdOYW1lKFwiKlwiKS5sZW5ndGg7XG5cdH0pO1xuXG5cdC8vIFN1cHBvcnQ6IElFPDlcblx0c3VwcG9ydC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lID0gcm5hdGl2ZS50ZXN0KCBkb2MuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSApO1xuXG5cdC8vIFN1cHBvcnQ6IElFPDEwXG5cdC8vIENoZWNrIGlmIGdldEVsZW1lbnRCeUlkIHJldHVybnMgZWxlbWVudHMgYnkgbmFtZVxuXHQvLyBUaGUgYnJva2VuIGdldEVsZW1lbnRCeUlkIG1ldGhvZHMgZG9uJ3QgcGljayB1cCBwcm9ncmFtYXRpY2FsbHktc2V0IG5hbWVzLFxuXHQvLyBzbyB1c2UgYSByb3VuZGFib3V0IGdldEVsZW1lbnRzQnlOYW1lIHRlc3Rcblx0c3VwcG9ydC5nZXRCeUlkID0gYXNzZXJ0KGZ1bmN0aW9uKCBkaXYgKSB7XG5cdFx0ZG9jRWxlbS5hcHBlbmRDaGlsZCggZGl2ICkuaWQgPSBleHBhbmRvO1xuXHRcdHJldHVybiAhZG9jLmdldEVsZW1lbnRzQnlOYW1lIHx8ICFkb2MuZ2V0RWxlbWVudHNCeU5hbWUoIGV4cGFuZG8gKS5sZW5ndGg7XG5cdH0pO1xuXG5cdC8vIElEIGZpbmQgYW5kIGZpbHRlclxuXHRpZiAoIHN1cHBvcnQuZ2V0QnlJZCApIHtcblx0XHRFeHByLmZpbmRbXCJJRFwiXSA9IGZ1bmN0aW9uKCBpZCwgY29udGV4dCApIHtcblx0XHRcdGlmICggdHlwZW9mIGNvbnRleHQuZ2V0RWxlbWVudEJ5SWQgIT09IFwidW5kZWZpbmVkXCIgJiYgZG9jdW1lbnRJc0hUTUwgKSB7XG5cdFx0XHRcdHZhciBtID0gY29udGV4dC5nZXRFbGVtZW50QnlJZCggaWQgKTtcblx0XHRcdFx0Ly8gQ2hlY2sgcGFyZW50Tm9kZSB0byBjYXRjaCB3aGVuIEJsYWNrYmVycnkgNC42IHJldHVybnNcblx0XHRcdFx0Ly8gbm9kZXMgdGhhdCBhcmUgbm8gbG9uZ2VyIGluIHRoZSBkb2N1bWVudCAjNjk2M1xuXHRcdFx0XHRyZXR1cm4gbSAmJiBtLnBhcmVudE5vZGUgPyBbIG0gXSA6IFtdO1xuXHRcdFx0fVxuXHRcdH07XG5cdFx0RXhwci5maWx0ZXJbXCJJRFwiXSA9IGZ1bmN0aW9uKCBpZCApIHtcblx0XHRcdHZhciBhdHRySWQgPSBpZC5yZXBsYWNlKCBydW5lc2NhcGUsIGZ1bmVzY2FwZSApO1xuXHRcdFx0cmV0dXJuIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0XHRyZXR1cm4gZWxlbS5nZXRBdHRyaWJ1dGUoXCJpZFwiKSA9PT0gYXR0cklkO1xuXHRcdFx0fTtcblx0XHR9O1xuXHR9IGVsc2Uge1xuXHRcdC8vIFN1cHBvcnQ6IElFNi83XG5cdFx0Ly8gZ2V0RWxlbWVudEJ5SWQgaXMgbm90IHJlbGlhYmxlIGFzIGEgZmluZCBzaG9ydGN1dFxuXHRcdGRlbGV0ZSBFeHByLmZpbmRbXCJJRFwiXTtcblxuXHRcdEV4cHIuZmlsdGVyW1wiSURcIl0gPSAgZnVuY3Rpb24oIGlkICkge1xuXHRcdFx0dmFyIGF0dHJJZCA9IGlkLnJlcGxhY2UoIHJ1bmVzY2FwZSwgZnVuZXNjYXBlICk7XG5cdFx0XHRyZXR1cm4gZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRcdHZhciBub2RlID0gdHlwZW9mIGVsZW0uZ2V0QXR0cmlidXRlTm9kZSAhPT0gXCJ1bmRlZmluZWRcIiAmJiBlbGVtLmdldEF0dHJpYnV0ZU5vZGUoXCJpZFwiKTtcblx0XHRcdFx0cmV0dXJuIG5vZGUgJiYgbm9kZS52YWx1ZSA9PT0gYXR0cklkO1xuXHRcdFx0fTtcblx0XHR9O1xuXHR9XG5cblx0Ly8gVGFnXG5cdEV4cHIuZmluZFtcIlRBR1wiXSA9IHN1cHBvcnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUgP1xuXHRcdGZ1bmN0aW9uKCB0YWcsIGNvbnRleHQgKSB7XG5cdFx0XHRpZiAoIHR5cGVvZiBjb250ZXh0LmdldEVsZW1lbnRzQnlUYWdOYW1lICE9PSBcInVuZGVmaW5lZFwiICkge1xuXHRcdFx0XHRyZXR1cm4gY29udGV4dC5nZXRFbGVtZW50c0J5VGFnTmFtZSggdGFnICk7XG5cblx0XHRcdC8vIERvY3VtZW50RnJhZ21lbnQgbm9kZXMgZG9uJ3QgaGF2ZSBnRUJUTlxuXHRcdFx0fSBlbHNlIGlmICggc3VwcG9ydC5xc2EgKSB7XG5cdFx0XHRcdHJldHVybiBjb250ZXh0LnF1ZXJ5U2VsZWN0b3JBbGwoIHRhZyApO1xuXHRcdFx0fVxuXHRcdH0gOlxuXG5cdFx0ZnVuY3Rpb24oIHRhZywgY29udGV4dCApIHtcblx0XHRcdHZhciBlbGVtLFxuXHRcdFx0XHR0bXAgPSBbXSxcblx0XHRcdFx0aSA9IDAsXG5cdFx0XHRcdC8vIEJ5IGhhcHB5IGNvaW5jaWRlbmNlLCBhIChicm9rZW4pIGdFQlROIGFwcGVhcnMgb24gRG9jdW1lbnRGcmFnbWVudCBub2RlcyB0b29cblx0XHRcdFx0cmVzdWx0cyA9IGNvbnRleHQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoIHRhZyApO1xuXG5cdFx0XHQvLyBGaWx0ZXIgb3V0IHBvc3NpYmxlIGNvbW1lbnRzXG5cdFx0XHRpZiAoIHRhZyA9PT0gXCIqXCIgKSB7XG5cdFx0XHRcdHdoaWxlICggKGVsZW0gPSByZXN1bHRzW2krK10pICkge1xuXHRcdFx0XHRcdGlmICggZWxlbS5ub2RlVHlwZSA9PT0gMSApIHtcblx0XHRcdFx0XHRcdHRtcC5wdXNoKCBlbGVtICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cblx0XHRcdFx0cmV0dXJuIHRtcDtcblx0XHRcdH1cblx0XHRcdHJldHVybiByZXN1bHRzO1xuXHRcdH07XG5cblx0Ly8gQ2xhc3Ncblx0RXhwci5maW5kW1wiQ0xBU1NcIl0gPSBzdXBwb3J0LmdldEVsZW1lbnRzQnlDbGFzc05hbWUgJiYgZnVuY3Rpb24oIGNsYXNzTmFtZSwgY29udGV4dCApIHtcblx0XHRpZiAoIGRvY3VtZW50SXNIVE1MICkge1xuXHRcdFx0cmV0dXJuIGNvbnRleHQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSggY2xhc3NOYW1lICk7XG5cdFx0fVxuXHR9O1xuXG5cdC8qIFFTQS9tYXRjaGVzU2VsZWN0b3Jcblx0LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xuXG5cdC8vIFFTQSBhbmQgbWF0Y2hlc1NlbGVjdG9yIHN1cHBvcnRcblxuXHQvLyBtYXRjaGVzU2VsZWN0b3IoOmFjdGl2ZSkgcmVwb3J0cyBmYWxzZSB3aGVuIHRydWUgKElFOS9PcGVyYSAxMS41KVxuXHRyYnVnZ3lNYXRjaGVzID0gW107XG5cblx0Ly8gcVNhKDpmb2N1cykgcmVwb3J0cyBmYWxzZSB3aGVuIHRydWUgKENocm9tZSAyMSlcblx0Ly8gV2UgYWxsb3cgdGhpcyBiZWNhdXNlIG9mIGEgYnVnIGluIElFOC85IHRoYXQgdGhyb3dzIGFuIGVycm9yXG5cdC8vIHdoZW5ldmVyIGBkb2N1bWVudC5hY3RpdmVFbGVtZW50YCBpcyBhY2Nlc3NlZCBvbiBhbiBpZnJhbWVcblx0Ly8gU28sIHdlIGFsbG93IDpmb2N1cyB0byBwYXNzIHRocm91Z2ggUVNBIGFsbCB0aGUgdGltZSB0byBhdm9pZCB0aGUgSUUgZXJyb3Jcblx0Ly8gU2VlIGh0dHA6Ly9idWdzLmpxdWVyeS5jb20vdGlja2V0LzEzMzc4XG5cdHJidWdneVFTQSA9IFtdO1xuXG5cdGlmICggKHN1cHBvcnQucXNhID0gcm5hdGl2ZS50ZXN0KCBkb2MucXVlcnlTZWxlY3RvckFsbCApKSApIHtcblx0XHQvLyBCdWlsZCBRU0EgcmVnZXhcblx0XHQvLyBSZWdleCBzdHJhdGVneSBhZG9wdGVkIGZyb20gRGllZ28gUGVyaW5pXG5cdFx0YXNzZXJ0KGZ1bmN0aW9uKCBkaXYgKSB7XG5cdFx0XHQvLyBTZWxlY3QgaXMgc2V0IHRvIGVtcHR5IHN0cmluZyBvbiBwdXJwb3NlXG5cdFx0XHQvLyBUaGlzIGlzIHRvIHRlc3QgSUUncyB0cmVhdG1lbnQgb2Ygbm90IGV4cGxpY2l0bHlcblx0XHRcdC8vIHNldHRpbmcgYSBib29sZWFuIGNvbnRlbnQgYXR0cmlidXRlLFxuXHRcdFx0Ly8gc2luY2UgaXRzIHByZXNlbmNlIHNob3VsZCBiZSBlbm91Z2hcblx0XHRcdC8vIGh0dHA6Ly9idWdzLmpxdWVyeS5jb20vdGlja2V0LzEyMzU5XG5cdFx0XHRkb2NFbGVtLmFwcGVuZENoaWxkKCBkaXYgKS5pbm5lckhUTUwgPSBcIjxhIGlkPSdcIiArIGV4cGFuZG8gKyBcIic+PC9hPlwiICtcblx0XHRcdFx0XCI8c2VsZWN0IGlkPSdcIiArIGV4cGFuZG8gKyBcIi1cXGZdJyBtc2FsbG93Y2FwdHVyZT0nJz5cIiArXG5cdFx0XHRcdFwiPG9wdGlvbiBzZWxlY3RlZD0nJz48L29wdGlvbj48L3NlbGVjdD5cIjtcblxuXHRcdFx0Ly8gU3VwcG9ydDogSUU4LCBPcGVyYSAxMS0xMi4xNlxuXHRcdFx0Ly8gTm90aGluZyBzaG91bGQgYmUgc2VsZWN0ZWQgd2hlbiBlbXB0eSBzdHJpbmdzIGZvbGxvdyBePSBvciAkPSBvciAqPVxuXHRcdFx0Ly8gVGhlIHRlc3QgYXR0cmlidXRlIG11c3QgYmUgdW5rbm93biBpbiBPcGVyYSBidXQgXCJzYWZlXCIgZm9yIFdpblJUXG5cdFx0XHQvLyBodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tL2VuLXVzL2xpYnJhcnkvaWUvaGg0NjUzODguYXNweCNhdHRyaWJ1dGVfc2VjdGlvblxuXHRcdFx0aWYgKCBkaXYucXVlcnlTZWxlY3RvckFsbChcIlttc2FsbG93Y2FwdHVyZV49JyddXCIpLmxlbmd0aCApIHtcblx0XHRcdFx0cmJ1Z2d5UVNBLnB1c2goIFwiWypeJF09XCIgKyB3aGl0ZXNwYWNlICsgXCIqKD86Jyd8XFxcIlxcXCIpXCIgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gU3VwcG9ydDogSUU4XG5cdFx0XHQvLyBCb29sZWFuIGF0dHJpYnV0ZXMgYW5kIFwidmFsdWVcIiBhcmUgbm90IHRyZWF0ZWQgY29ycmVjdGx5XG5cdFx0XHRpZiAoICFkaXYucXVlcnlTZWxlY3RvckFsbChcIltzZWxlY3RlZF1cIikubGVuZ3RoICkge1xuXHRcdFx0XHRyYnVnZ3lRU0EucHVzaCggXCJcXFxcW1wiICsgd2hpdGVzcGFjZSArIFwiKig/OnZhbHVlfFwiICsgYm9vbGVhbnMgKyBcIilcIiApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBTdXBwb3J0OiBDaHJvbWU8MjksIEFuZHJvaWQ8NC4yKywgU2FmYXJpPDcuMCssIGlPUzw3LjArLCBQaGFudG9tSlM8MS45LjcrXG5cdFx0XHRpZiAoICFkaXYucXVlcnlTZWxlY3RvckFsbCggXCJbaWR+PVwiICsgZXhwYW5kbyArIFwiLV1cIiApLmxlbmd0aCApIHtcblx0XHRcdFx0cmJ1Z2d5UVNBLnB1c2goXCJ+PVwiKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gV2Via2l0L09wZXJhIC0gOmNoZWNrZWQgc2hvdWxkIHJldHVybiBzZWxlY3RlZCBvcHRpb24gZWxlbWVudHNcblx0XHRcdC8vIGh0dHA6Ly93d3cudzMub3JnL1RSLzIwMTEvUkVDLWNzczMtc2VsZWN0b3JzLTIwMTEwOTI5LyNjaGVja2VkXG5cdFx0XHQvLyBJRTggdGhyb3dzIGVycm9yIGhlcmUgYW5kIHdpbGwgbm90IHNlZSBsYXRlciB0ZXN0c1xuXHRcdFx0aWYgKCAhZGl2LnF1ZXJ5U2VsZWN0b3JBbGwoXCI6Y2hlY2tlZFwiKS5sZW5ndGggKSB7XG5cdFx0XHRcdHJidWdneVFTQS5wdXNoKFwiOmNoZWNrZWRcIik7XG5cdFx0XHR9XG5cblx0XHRcdC8vIFN1cHBvcnQ6IFNhZmFyaSA4KywgaU9TIDgrXG5cdFx0XHQvLyBodHRwczovL2J1Z3Mud2Via2l0Lm9yZy9zaG93X2J1Zy5jZ2k/aWQ9MTM2ODUxXG5cdFx0XHQvLyBJbi1wYWdlIGBzZWxlY3RvciNpZCBzaWJpbmctY29tYmluYXRvciBzZWxlY3RvcmAgZmFpbHNcblx0XHRcdGlmICggIWRpdi5xdWVyeVNlbGVjdG9yQWxsKCBcImEjXCIgKyBleHBhbmRvICsgXCIrKlwiICkubGVuZ3RoICkge1xuXHRcdFx0XHRyYnVnZ3lRU0EucHVzaChcIi4jLitbK35dXCIpO1xuXHRcdFx0fVxuXHRcdH0pO1xuXG5cdFx0YXNzZXJ0KGZ1bmN0aW9uKCBkaXYgKSB7XG5cdFx0XHQvLyBTdXBwb3J0OiBXaW5kb3dzIDggTmF0aXZlIEFwcHNcblx0XHRcdC8vIFRoZSB0eXBlIGFuZCBuYW1lIGF0dHJpYnV0ZXMgYXJlIHJlc3RyaWN0ZWQgZHVyaW5nIC5pbm5lckhUTUwgYXNzaWdubWVudFxuXHRcdFx0dmFyIGlucHV0ID0gZG9jLmNyZWF0ZUVsZW1lbnQoXCJpbnB1dFwiKTtcblx0XHRcdGlucHV0LnNldEF0dHJpYnV0ZSggXCJ0eXBlXCIsIFwiaGlkZGVuXCIgKTtcblx0XHRcdGRpdi5hcHBlbmRDaGlsZCggaW5wdXQgKS5zZXRBdHRyaWJ1dGUoIFwibmFtZVwiLCBcIkRcIiApO1xuXG5cdFx0XHQvLyBTdXBwb3J0OiBJRThcblx0XHRcdC8vIEVuZm9yY2UgY2FzZS1zZW5zaXRpdml0eSBvZiBuYW1lIGF0dHJpYnV0ZVxuXHRcdFx0aWYgKCBkaXYucXVlcnlTZWxlY3RvckFsbChcIltuYW1lPWRdXCIpLmxlbmd0aCApIHtcblx0XHRcdFx0cmJ1Z2d5UVNBLnB1c2goIFwibmFtZVwiICsgd2hpdGVzcGFjZSArIFwiKlsqXiR8IX5dPz1cIiApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBGRiAzLjUgLSA6ZW5hYmxlZC86ZGlzYWJsZWQgYW5kIGhpZGRlbiBlbGVtZW50cyAoaGlkZGVuIGVsZW1lbnRzIGFyZSBzdGlsbCBlbmFibGVkKVxuXHRcdFx0Ly8gSUU4IHRocm93cyBlcnJvciBoZXJlIGFuZCB3aWxsIG5vdCBzZWUgbGF0ZXIgdGVzdHNcblx0XHRcdGlmICggIWRpdi5xdWVyeVNlbGVjdG9yQWxsKFwiOmVuYWJsZWRcIikubGVuZ3RoICkge1xuXHRcdFx0XHRyYnVnZ3lRU0EucHVzaCggXCI6ZW5hYmxlZFwiLCBcIjpkaXNhYmxlZFwiICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIE9wZXJhIDEwLTExIGRvZXMgbm90IHRocm93IG9uIHBvc3QtY29tbWEgaW52YWxpZCBwc2V1ZG9zXG5cdFx0XHRkaXYucXVlcnlTZWxlY3RvckFsbChcIiosOnhcIik7XG5cdFx0XHRyYnVnZ3lRU0EucHVzaChcIiwuKjpcIik7XG5cdFx0fSk7XG5cdH1cblxuXHRpZiAoIChzdXBwb3J0Lm1hdGNoZXNTZWxlY3RvciA9IHJuYXRpdmUudGVzdCggKG1hdGNoZXMgPSBkb2NFbGVtLm1hdGNoZXMgfHxcblx0XHRkb2NFbGVtLndlYmtpdE1hdGNoZXNTZWxlY3RvciB8fFxuXHRcdGRvY0VsZW0ubW96TWF0Y2hlc1NlbGVjdG9yIHx8XG5cdFx0ZG9jRWxlbS5vTWF0Y2hlc1NlbGVjdG9yIHx8XG5cdFx0ZG9jRWxlbS5tc01hdGNoZXNTZWxlY3RvcikgKSkgKSB7XG5cblx0XHRhc3NlcnQoZnVuY3Rpb24oIGRpdiApIHtcblx0XHRcdC8vIENoZWNrIHRvIHNlZSBpZiBpdCdzIHBvc3NpYmxlIHRvIGRvIG1hdGNoZXNTZWxlY3RvclxuXHRcdFx0Ly8gb24gYSBkaXNjb25uZWN0ZWQgbm9kZSAoSUUgOSlcblx0XHRcdHN1cHBvcnQuZGlzY29ubmVjdGVkTWF0Y2ggPSBtYXRjaGVzLmNhbGwoIGRpdiwgXCJkaXZcIiApO1xuXG5cdFx0XHQvLyBUaGlzIHNob3VsZCBmYWlsIHdpdGggYW4gZXhjZXB0aW9uXG5cdFx0XHQvLyBHZWNrbyBkb2VzIG5vdCBlcnJvciwgcmV0dXJucyBmYWxzZSBpbnN0ZWFkXG5cdFx0XHRtYXRjaGVzLmNhbGwoIGRpdiwgXCJbcyE9JyddOnhcIiApO1xuXHRcdFx0cmJ1Z2d5TWF0Y2hlcy5wdXNoKCBcIiE9XCIsIHBzZXVkb3MgKTtcblx0XHR9KTtcblx0fVxuXG5cdHJidWdneVFTQSA9IHJidWdneVFTQS5sZW5ndGggJiYgbmV3IFJlZ0V4cCggcmJ1Z2d5UVNBLmpvaW4oXCJ8XCIpICk7XG5cdHJidWdneU1hdGNoZXMgPSByYnVnZ3lNYXRjaGVzLmxlbmd0aCAmJiBuZXcgUmVnRXhwKCByYnVnZ3lNYXRjaGVzLmpvaW4oXCJ8XCIpICk7XG5cblx0LyogQ29udGFpbnNcblx0LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xuXHRoYXNDb21wYXJlID0gcm5hdGl2ZS50ZXN0KCBkb2NFbGVtLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uICk7XG5cblx0Ly8gRWxlbWVudCBjb250YWlucyBhbm90aGVyXG5cdC8vIFB1cnBvc2VmdWxseSBkb2VzIG5vdCBpbXBsZW1lbnQgaW5jbHVzaXZlIGRlc2NlbmRlbnRcblx0Ly8gQXMgaW4sIGFuIGVsZW1lbnQgZG9lcyBub3QgY29udGFpbiBpdHNlbGZcblx0Y29udGFpbnMgPSBoYXNDb21wYXJlIHx8IHJuYXRpdmUudGVzdCggZG9jRWxlbS5jb250YWlucyApID9cblx0XHRmdW5jdGlvbiggYSwgYiApIHtcblx0XHRcdHZhciBhZG93biA9IGEubm9kZVR5cGUgPT09IDkgPyBhLmRvY3VtZW50RWxlbWVudCA6IGEsXG5cdFx0XHRcdGJ1cCA9IGIgJiYgYi5wYXJlbnROb2RlO1xuXHRcdFx0cmV0dXJuIGEgPT09IGJ1cCB8fCAhISggYnVwICYmIGJ1cC5ub2RlVHlwZSA9PT0gMSAmJiAoXG5cdFx0XHRcdGFkb3duLmNvbnRhaW5zID9cblx0XHRcdFx0XHRhZG93bi5jb250YWlucyggYnVwICkgOlxuXHRcdFx0XHRcdGEuY29tcGFyZURvY3VtZW50UG9zaXRpb24gJiYgYS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbiggYnVwICkgJiAxNlxuXHRcdFx0KSk7XG5cdFx0fSA6XG5cdFx0ZnVuY3Rpb24oIGEsIGIgKSB7XG5cdFx0XHRpZiAoIGIgKSB7XG5cdFx0XHRcdHdoaWxlICggKGIgPSBiLnBhcmVudE5vZGUpICkge1xuXHRcdFx0XHRcdGlmICggYiA9PT0gYSApIHtcblx0XHRcdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH07XG5cblx0LyogU29ydGluZ1xuXHQtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG5cblx0Ly8gRG9jdW1lbnQgb3JkZXIgc29ydGluZ1xuXHRzb3J0T3JkZXIgPSBoYXNDb21wYXJlID9cblx0ZnVuY3Rpb24oIGEsIGIgKSB7XG5cblx0XHQvLyBGbGFnIGZvciBkdXBsaWNhdGUgcmVtb3ZhbFxuXHRcdGlmICggYSA9PT0gYiApIHtcblx0XHRcdGhhc0R1cGxpY2F0ZSA9IHRydWU7XG5cdFx0XHRyZXR1cm4gMDtcblx0XHR9XG5cblx0XHQvLyBTb3J0IG9uIG1ldGhvZCBleGlzdGVuY2UgaWYgb25seSBvbmUgaW5wdXQgaGFzIGNvbXBhcmVEb2N1bWVudFBvc2l0aW9uXG5cdFx0dmFyIGNvbXBhcmUgPSAhYS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbiAtICFiLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uO1xuXHRcdGlmICggY29tcGFyZSApIHtcblx0XHRcdHJldHVybiBjb21wYXJlO1xuXHRcdH1cblxuXHRcdC8vIENhbGN1bGF0ZSBwb3NpdGlvbiBpZiBib3RoIGlucHV0cyBiZWxvbmcgdG8gdGhlIHNhbWUgZG9jdW1lbnRcblx0XHRjb21wYXJlID0gKCBhLm93bmVyRG9jdW1lbnQgfHwgYSApID09PSAoIGIub3duZXJEb2N1bWVudCB8fCBiICkgP1xuXHRcdFx0YS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbiggYiApIDpcblxuXHRcdFx0Ly8gT3RoZXJ3aXNlIHdlIGtub3cgdGhleSBhcmUgZGlzY29ubmVjdGVkXG5cdFx0XHQxO1xuXG5cdFx0Ly8gRGlzY29ubmVjdGVkIG5vZGVzXG5cdFx0aWYgKCBjb21wYXJlICYgMSB8fFxuXHRcdFx0KCFzdXBwb3J0LnNvcnREZXRhY2hlZCAmJiBiLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uKCBhICkgPT09IGNvbXBhcmUpICkge1xuXG5cdFx0XHQvLyBDaG9vc2UgdGhlIGZpcnN0IGVsZW1lbnQgdGhhdCBpcyByZWxhdGVkIHRvIG91ciBwcmVmZXJyZWQgZG9jdW1lbnRcblx0XHRcdGlmICggYSA9PT0gZG9jIHx8IGEub3duZXJEb2N1bWVudCA9PT0gcHJlZmVycmVkRG9jICYmIGNvbnRhaW5zKHByZWZlcnJlZERvYywgYSkgKSB7XG5cdFx0XHRcdHJldHVybiAtMTtcblx0XHRcdH1cblx0XHRcdGlmICggYiA9PT0gZG9jIHx8IGIub3duZXJEb2N1bWVudCA9PT0gcHJlZmVycmVkRG9jICYmIGNvbnRhaW5zKHByZWZlcnJlZERvYywgYikgKSB7XG5cdFx0XHRcdHJldHVybiAxO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBNYWludGFpbiBvcmlnaW5hbCBvcmRlclxuXHRcdFx0cmV0dXJuIHNvcnRJbnB1dCA/XG5cdFx0XHRcdCggaW5kZXhPZiggc29ydElucHV0LCBhICkgLSBpbmRleE9mKCBzb3J0SW5wdXQsIGIgKSApIDpcblx0XHRcdFx0MDtcblx0XHR9XG5cblx0XHRyZXR1cm4gY29tcGFyZSAmIDQgPyAtMSA6IDE7XG5cdH0gOlxuXHRmdW5jdGlvbiggYSwgYiApIHtcblx0XHQvLyBFeGl0IGVhcmx5IGlmIHRoZSBub2RlcyBhcmUgaWRlbnRpY2FsXG5cdFx0aWYgKCBhID09PSBiICkge1xuXHRcdFx0aGFzRHVwbGljYXRlID0gdHJ1ZTtcblx0XHRcdHJldHVybiAwO1xuXHRcdH1cblxuXHRcdHZhciBjdXIsXG5cdFx0XHRpID0gMCxcblx0XHRcdGF1cCA9IGEucGFyZW50Tm9kZSxcblx0XHRcdGJ1cCA9IGIucGFyZW50Tm9kZSxcblx0XHRcdGFwID0gWyBhIF0sXG5cdFx0XHRicCA9IFsgYiBdO1xuXG5cdFx0Ly8gUGFyZW50bGVzcyBub2RlcyBhcmUgZWl0aGVyIGRvY3VtZW50cyBvciBkaXNjb25uZWN0ZWRcblx0XHRpZiAoICFhdXAgfHwgIWJ1cCApIHtcblx0XHRcdHJldHVybiBhID09PSBkb2MgPyAtMSA6XG5cdFx0XHRcdGIgPT09IGRvYyA/IDEgOlxuXHRcdFx0XHRhdXAgPyAtMSA6XG5cdFx0XHRcdGJ1cCA/IDEgOlxuXHRcdFx0XHRzb3J0SW5wdXQgP1xuXHRcdFx0XHQoIGluZGV4T2YoIHNvcnRJbnB1dCwgYSApIC0gaW5kZXhPZiggc29ydElucHV0LCBiICkgKSA6XG5cdFx0XHRcdDA7XG5cblx0XHQvLyBJZiB0aGUgbm9kZXMgYXJlIHNpYmxpbmdzLCB3ZSBjYW4gZG8gYSBxdWljayBjaGVja1xuXHRcdH0gZWxzZSBpZiAoIGF1cCA9PT0gYnVwICkge1xuXHRcdFx0cmV0dXJuIHNpYmxpbmdDaGVjayggYSwgYiApO1xuXHRcdH1cblxuXHRcdC8vIE90aGVyd2lzZSB3ZSBuZWVkIGZ1bGwgbGlzdHMgb2YgdGhlaXIgYW5jZXN0b3JzIGZvciBjb21wYXJpc29uXG5cdFx0Y3VyID0gYTtcblx0XHR3aGlsZSAoIChjdXIgPSBjdXIucGFyZW50Tm9kZSkgKSB7XG5cdFx0XHRhcC51bnNoaWZ0KCBjdXIgKTtcblx0XHR9XG5cdFx0Y3VyID0gYjtcblx0XHR3aGlsZSAoIChjdXIgPSBjdXIucGFyZW50Tm9kZSkgKSB7XG5cdFx0XHRicC51bnNoaWZ0KCBjdXIgKTtcblx0XHR9XG5cblx0XHQvLyBXYWxrIGRvd24gdGhlIHRyZWUgbG9va2luZyBmb3IgYSBkaXNjcmVwYW5jeVxuXHRcdHdoaWxlICggYXBbaV0gPT09IGJwW2ldICkge1xuXHRcdFx0aSsrO1xuXHRcdH1cblxuXHRcdHJldHVybiBpID9cblx0XHRcdC8vIERvIGEgc2libGluZyBjaGVjayBpZiB0aGUgbm9kZXMgaGF2ZSBhIGNvbW1vbiBhbmNlc3RvclxuXHRcdFx0c2libGluZ0NoZWNrKCBhcFtpXSwgYnBbaV0gKSA6XG5cblx0XHRcdC8vIE90aGVyd2lzZSBub2RlcyBpbiBvdXIgZG9jdW1lbnQgc29ydCBmaXJzdFxuXHRcdFx0YXBbaV0gPT09IHByZWZlcnJlZERvYyA/IC0xIDpcblx0XHRcdGJwW2ldID09PSBwcmVmZXJyZWREb2MgPyAxIDpcblx0XHRcdDA7XG5cdH07XG5cblx0cmV0dXJuIGRvYztcbn07XG5cblNpenpsZS5tYXRjaGVzID0gZnVuY3Rpb24oIGV4cHIsIGVsZW1lbnRzICkge1xuXHRyZXR1cm4gU2l6emxlKCBleHByLCBudWxsLCBudWxsLCBlbGVtZW50cyApO1xufTtcblxuU2l6emxlLm1hdGNoZXNTZWxlY3RvciA9IGZ1bmN0aW9uKCBlbGVtLCBleHByICkge1xuXHQvLyBTZXQgZG9jdW1lbnQgdmFycyBpZiBuZWVkZWRcblx0aWYgKCAoIGVsZW0ub3duZXJEb2N1bWVudCB8fCBlbGVtICkgIT09IGRvY3VtZW50ICkge1xuXHRcdHNldERvY3VtZW50KCBlbGVtICk7XG5cdH1cblxuXHQvLyBNYWtlIHN1cmUgdGhhdCBhdHRyaWJ1dGUgc2VsZWN0b3JzIGFyZSBxdW90ZWRcblx0ZXhwciA9IGV4cHIucmVwbGFjZSggcmF0dHJpYnV0ZVF1b3RlcywgXCI9JyQxJ11cIiApO1xuXG5cdGlmICggc3VwcG9ydC5tYXRjaGVzU2VsZWN0b3IgJiYgZG9jdW1lbnRJc0hUTUwgJiZcblx0XHQoICFyYnVnZ3lNYXRjaGVzIHx8ICFyYnVnZ3lNYXRjaGVzLnRlc3QoIGV4cHIgKSApICYmXG5cdFx0KCAhcmJ1Z2d5UVNBICAgICB8fCAhcmJ1Z2d5UVNBLnRlc3QoIGV4cHIgKSApICkge1xuXG5cdFx0dHJ5IHtcblx0XHRcdHZhciByZXQgPSBtYXRjaGVzLmNhbGwoIGVsZW0sIGV4cHIgKTtcblxuXHRcdFx0Ly8gSUUgOSdzIG1hdGNoZXNTZWxlY3RvciByZXR1cm5zIGZhbHNlIG9uIGRpc2Nvbm5lY3RlZCBub2Rlc1xuXHRcdFx0aWYgKCByZXQgfHwgc3VwcG9ydC5kaXNjb25uZWN0ZWRNYXRjaCB8fFxuXHRcdFx0XHRcdC8vIEFzIHdlbGwsIGRpc2Nvbm5lY3RlZCBub2RlcyBhcmUgc2FpZCB0byBiZSBpbiBhIGRvY3VtZW50XG5cdFx0XHRcdFx0Ly8gZnJhZ21lbnQgaW4gSUUgOVxuXHRcdFx0XHRcdGVsZW0uZG9jdW1lbnQgJiYgZWxlbS5kb2N1bWVudC5ub2RlVHlwZSAhPT0gMTEgKSB7XG5cdFx0XHRcdHJldHVybiByZXQ7XG5cdFx0XHR9XG5cdFx0fSBjYXRjaCAoZSkge31cblx0fVxuXG5cdHJldHVybiBTaXp6bGUoIGV4cHIsIGRvY3VtZW50LCBudWxsLCBbIGVsZW0gXSApLmxlbmd0aCA+IDA7XG59O1xuXG5TaXp6bGUuY29udGFpbnMgPSBmdW5jdGlvbiggY29udGV4dCwgZWxlbSApIHtcblx0Ly8gU2V0IGRvY3VtZW50IHZhcnMgaWYgbmVlZGVkXG5cdGlmICggKCBjb250ZXh0Lm93bmVyRG9jdW1lbnQgfHwgY29udGV4dCApICE9PSBkb2N1bWVudCApIHtcblx0XHRzZXREb2N1bWVudCggY29udGV4dCApO1xuXHR9XG5cdHJldHVybiBjb250YWlucyggY29udGV4dCwgZWxlbSApO1xufTtcblxuU2l6emxlLmF0dHIgPSBmdW5jdGlvbiggZWxlbSwgbmFtZSApIHtcblx0Ly8gU2V0IGRvY3VtZW50IHZhcnMgaWYgbmVlZGVkXG5cdGlmICggKCBlbGVtLm93bmVyRG9jdW1lbnQgfHwgZWxlbSApICE9PSBkb2N1bWVudCApIHtcblx0XHRzZXREb2N1bWVudCggZWxlbSApO1xuXHR9XG5cblx0dmFyIGZuID0gRXhwci5hdHRySGFuZGxlWyBuYW1lLnRvTG93ZXJDYXNlKCkgXSxcblx0XHQvLyBEb24ndCBnZXQgZm9vbGVkIGJ5IE9iamVjdC5wcm90b3R5cGUgcHJvcGVydGllcyAoalF1ZXJ5ICMxMzgwNylcblx0XHR2YWwgPSBmbiAmJiBoYXNPd24uY2FsbCggRXhwci5hdHRySGFuZGxlLCBuYW1lLnRvTG93ZXJDYXNlKCkgKSA/XG5cdFx0XHRmbiggZWxlbSwgbmFtZSwgIWRvY3VtZW50SXNIVE1MICkgOlxuXHRcdFx0dW5kZWZpbmVkO1xuXG5cdHJldHVybiB2YWwgIT09IHVuZGVmaW5lZCA/XG5cdFx0dmFsIDpcblx0XHRzdXBwb3J0LmF0dHJpYnV0ZXMgfHwgIWRvY3VtZW50SXNIVE1MID9cblx0XHRcdGVsZW0uZ2V0QXR0cmlidXRlKCBuYW1lICkgOlxuXHRcdFx0KHZhbCA9IGVsZW0uZ2V0QXR0cmlidXRlTm9kZShuYW1lKSkgJiYgdmFsLnNwZWNpZmllZCA/XG5cdFx0XHRcdHZhbC52YWx1ZSA6XG5cdFx0XHRcdG51bGw7XG59O1xuXG5TaXp6bGUuZXJyb3IgPSBmdW5jdGlvbiggbXNnICkge1xuXHR0aHJvdyBuZXcgRXJyb3IoIFwiU3ludGF4IGVycm9yLCB1bnJlY29nbml6ZWQgZXhwcmVzc2lvbjogXCIgKyBtc2cgKTtcbn07XG5cbi8qKlxuICogRG9jdW1lbnQgc29ydGluZyBhbmQgcmVtb3ZpbmcgZHVwbGljYXRlc1xuICogQHBhcmFtIHtBcnJheUxpa2V9IHJlc3VsdHNcbiAqL1xuU2l6emxlLnVuaXF1ZVNvcnQgPSBmdW5jdGlvbiggcmVzdWx0cyApIHtcblx0dmFyIGVsZW0sXG5cdFx0ZHVwbGljYXRlcyA9IFtdLFxuXHRcdGogPSAwLFxuXHRcdGkgPSAwO1xuXG5cdC8vIFVubGVzcyB3ZSAqa25vdyogd2UgY2FuIGRldGVjdCBkdXBsaWNhdGVzLCBhc3N1bWUgdGhlaXIgcHJlc2VuY2Vcblx0aGFzRHVwbGljYXRlID0gIXN1cHBvcnQuZGV0ZWN0RHVwbGljYXRlcztcblx0c29ydElucHV0ID0gIXN1cHBvcnQuc29ydFN0YWJsZSAmJiByZXN1bHRzLnNsaWNlKCAwICk7XG5cdHJlc3VsdHMuc29ydCggc29ydE9yZGVyICk7XG5cblx0aWYgKCBoYXNEdXBsaWNhdGUgKSB7XG5cdFx0d2hpbGUgKCAoZWxlbSA9IHJlc3VsdHNbaSsrXSkgKSB7XG5cdFx0XHRpZiAoIGVsZW0gPT09IHJlc3VsdHNbIGkgXSApIHtcblx0XHRcdFx0aiA9IGR1cGxpY2F0ZXMucHVzaCggaSApO1xuXHRcdFx0fVxuXHRcdH1cblx0XHR3aGlsZSAoIGotLSApIHtcblx0XHRcdHJlc3VsdHMuc3BsaWNlKCBkdXBsaWNhdGVzWyBqIF0sIDEgKTtcblx0XHR9XG5cdH1cblxuXHQvLyBDbGVhciBpbnB1dCBhZnRlciBzb3J0aW5nIHRvIHJlbGVhc2Ugb2JqZWN0c1xuXHQvLyBTZWUgaHR0cHM6Ly9naXRodWIuY29tL2pxdWVyeS9zaXp6bGUvcHVsbC8yMjVcblx0c29ydElucHV0ID0gbnVsbDtcblxuXHRyZXR1cm4gcmVzdWx0cztcbn07XG5cbi8qKlxuICogVXRpbGl0eSBmdW5jdGlvbiBmb3IgcmV0cmlldmluZyB0aGUgdGV4dCB2YWx1ZSBvZiBhbiBhcnJheSBvZiBET00gbm9kZXNcbiAqIEBwYXJhbSB7QXJyYXl8RWxlbWVudH0gZWxlbVxuICovXG5nZXRUZXh0ID0gU2l6emxlLmdldFRleHQgPSBmdW5jdGlvbiggZWxlbSApIHtcblx0dmFyIG5vZGUsXG5cdFx0cmV0ID0gXCJcIixcblx0XHRpID0gMCxcblx0XHRub2RlVHlwZSA9IGVsZW0ubm9kZVR5cGU7XG5cblx0aWYgKCAhbm9kZVR5cGUgKSB7XG5cdFx0Ly8gSWYgbm8gbm9kZVR5cGUsIHRoaXMgaXMgZXhwZWN0ZWQgdG8gYmUgYW4gYXJyYXlcblx0XHR3aGlsZSAoIChub2RlID0gZWxlbVtpKytdKSApIHtcblx0XHRcdC8vIERvIG5vdCB0cmF2ZXJzZSBjb21tZW50IG5vZGVzXG5cdFx0XHRyZXQgKz0gZ2V0VGV4dCggbm9kZSApO1xuXHRcdH1cblx0fSBlbHNlIGlmICggbm9kZVR5cGUgPT09IDEgfHwgbm9kZVR5cGUgPT09IDkgfHwgbm9kZVR5cGUgPT09IDExICkge1xuXHRcdC8vIFVzZSB0ZXh0Q29udGVudCBmb3IgZWxlbWVudHNcblx0XHQvLyBpbm5lclRleHQgdXNhZ2UgcmVtb3ZlZCBmb3IgY29uc2lzdGVuY3kgb2YgbmV3IGxpbmVzIChqUXVlcnkgIzExMTUzKVxuXHRcdGlmICggdHlwZW9mIGVsZW0udGV4dENvbnRlbnQgPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRyZXR1cm4gZWxlbS50ZXh0Q29udGVudDtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Ly8gVHJhdmVyc2UgaXRzIGNoaWxkcmVuXG5cdFx0XHRmb3IgKCBlbGVtID0gZWxlbS5maXJzdENoaWxkOyBlbGVtOyBlbGVtID0gZWxlbS5uZXh0U2libGluZyApIHtcblx0XHRcdFx0cmV0ICs9IGdldFRleHQoIGVsZW0gKTtcblx0XHRcdH1cblx0XHR9XG5cdH0gZWxzZSBpZiAoIG5vZGVUeXBlID09PSAzIHx8IG5vZGVUeXBlID09PSA0ICkge1xuXHRcdHJldHVybiBlbGVtLm5vZGVWYWx1ZTtcblx0fVxuXHQvLyBEbyBub3QgaW5jbHVkZSBjb21tZW50IG9yIHByb2Nlc3NpbmcgaW5zdHJ1Y3Rpb24gbm9kZXNcblxuXHRyZXR1cm4gcmV0O1xufTtcblxuRXhwciA9IFNpenpsZS5zZWxlY3RvcnMgPSB7XG5cblx0Ly8gQ2FuIGJlIGFkanVzdGVkIGJ5IHRoZSB1c2VyXG5cdGNhY2hlTGVuZ3RoOiA1MCxcblxuXHRjcmVhdGVQc2V1ZG86IG1hcmtGdW5jdGlvbixcblxuXHRtYXRjaDogbWF0Y2hFeHByLFxuXG5cdGF0dHJIYW5kbGU6IHt9LFxuXG5cdGZpbmQ6IHt9LFxuXG5cdHJlbGF0aXZlOiB7XG5cdFx0XCI+XCI6IHsgZGlyOiBcInBhcmVudE5vZGVcIiwgZmlyc3Q6IHRydWUgfSxcblx0XHRcIiBcIjogeyBkaXI6IFwicGFyZW50Tm9kZVwiIH0sXG5cdFx0XCIrXCI6IHsgZGlyOiBcInByZXZpb3VzU2libGluZ1wiLCBmaXJzdDogdHJ1ZSB9LFxuXHRcdFwiflwiOiB7IGRpcjogXCJwcmV2aW91c1NpYmxpbmdcIiB9XG5cdH0sXG5cblx0cHJlRmlsdGVyOiB7XG5cdFx0XCJBVFRSXCI6IGZ1bmN0aW9uKCBtYXRjaCApIHtcblx0XHRcdG1hdGNoWzFdID0gbWF0Y2hbMV0ucmVwbGFjZSggcnVuZXNjYXBlLCBmdW5lc2NhcGUgKTtcblxuXHRcdFx0Ly8gTW92ZSB0aGUgZ2l2ZW4gdmFsdWUgdG8gbWF0Y2hbM10gd2hldGhlciBxdW90ZWQgb3IgdW5xdW90ZWRcblx0XHRcdG1hdGNoWzNdID0gKCBtYXRjaFszXSB8fCBtYXRjaFs0XSB8fCBtYXRjaFs1XSB8fCBcIlwiICkucmVwbGFjZSggcnVuZXNjYXBlLCBmdW5lc2NhcGUgKTtcblxuXHRcdFx0aWYgKCBtYXRjaFsyXSA9PT0gXCJ+PVwiICkge1xuXHRcdFx0XHRtYXRjaFszXSA9IFwiIFwiICsgbWF0Y2hbM10gKyBcIiBcIjtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIG1hdGNoLnNsaWNlKCAwLCA0ICk7XG5cdFx0fSxcblxuXHRcdFwiQ0hJTERcIjogZnVuY3Rpb24oIG1hdGNoICkge1xuXHRcdFx0LyogbWF0Y2hlcyBmcm9tIG1hdGNoRXhwcltcIkNISUxEXCJdXG5cdFx0XHRcdDEgdHlwZSAob25seXxudGh8Li4uKVxuXHRcdFx0XHQyIHdoYXQgKGNoaWxkfG9mLXR5cGUpXG5cdFx0XHRcdDMgYXJndW1lbnQgKGV2ZW58b2RkfFxcZCp8XFxkKm4oWystXVxcZCspP3wuLi4pXG5cdFx0XHRcdDQgeG4tY29tcG9uZW50IG9mIHhuK3kgYXJndW1lbnQgKFsrLV0/XFxkKm58KVxuXHRcdFx0XHQ1IHNpZ24gb2YgeG4tY29tcG9uZW50XG5cdFx0XHRcdDYgeCBvZiB4bi1jb21wb25lbnRcblx0XHRcdFx0NyBzaWduIG9mIHktY29tcG9uZW50XG5cdFx0XHRcdDggeSBvZiB5LWNvbXBvbmVudFxuXHRcdFx0Ki9cblx0XHRcdG1hdGNoWzFdID0gbWF0Y2hbMV0udG9Mb3dlckNhc2UoKTtcblxuXHRcdFx0aWYgKCBtYXRjaFsxXS5zbGljZSggMCwgMyApID09PSBcIm50aFwiICkge1xuXHRcdFx0XHQvLyBudGgtKiByZXF1aXJlcyBhcmd1bWVudFxuXHRcdFx0XHRpZiAoICFtYXRjaFszXSApIHtcblx0XHRcdFx0XHRTaXp6bGUuZXJyb3IoIG1hdGNoWzBdICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBudW1lcmljIHggYW5kIHkgcGFyYW1ldGVycyBmb3IgRXhwci5maWx0ZXIuQ0hJTERcblx0XHRcdFx0Ly8gcmVtZW1iZXIgdGhhdCBmYWxzZS90cnVlIGNhc3QgcmVzcGVjdGl2ZWx5IHRvIDAvMVxuXHRcdFx0XHRtYXRjaFs0XSA9ICsoIG1hdGNoWzRdID8gbWF0Y2hbNV0gKyAobWF0Y2hbNl0gfHwgMSkgOiAyICogKCBtYXRjaFszXSA9PT0gXCJldmVuXCIgfHwgbWF0Y2hbM10gPT09IFwib2RkXCIgKSApO1xuXHRcdFx0XHRtYXRjaFs1XSA9ICsoICggbWF0Y2hbN10gKyBtYXRjaFs4XSApIHx8IG1hdGNoWzNdID09PSBcIm9kZFwiICk7XG5cblx0XHRcdC8vIG90aGVyIHR5cGVzIHByb2hpYml0IGFyZ3VtZW50c1xuXHRcdFx0fSBlbHNlIGlmICggbWF0Y2hbM10gKSB7XG5cdFx0XHRcdFNpenpsZS5lcnJvciggbWF0Y2hbMF0gKTtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIG1hdGNoO1xuXHRcdH0sXG5cblx0XHRcIlBTRVVET1wiOiBmdW5jdGlvbiggbWF0Y2ggKSB7XG5cdFx0XHR2YXIgZXhjZXNzLFxuXHRcdFx0XHR1bnF1b3RlZCA9ICFtYXRjaFs2XSAmJiBtYXRjaFsyXTtcblxuXHRcdFx0aWYgKCBtYXRjaEV4cHJbXCJDSElMRFwiXS50ZXN0KCBtYXRjaFswXSApICkge1xuXHRcdFx0XHRyZXR1cm4gbnVsbDtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQWNjZXB0IHF1b3RlZCBhcmd1bWVudHMgYXMtaXNcblx0XHRcdGlmICggbWF0Y2hbM10gKSB7XG5cdFx0XHRcdG1hdGNoWzJdID0gbWF0Y2hbNF0gfHwgbWF0Y2hbNV0gfHwgXCJcIjtcblxuXHRcdFx0Ly8gU3RyaXAgZXhjZXNzIGNoYXJhY3RlcnMgZnJvbSB1bnF1b3RlZCBhcmd1bWVudHNcblx0XHRcdH0gZWxzZSBpZiAoIHVucXVvdGVkICYmIHJwc2V1ZG8udGVzdCggdW5xdW90ZWQgKSAmJlxuXHRcdFx0XHQvLyBHZXQgZXhjZXNzIGZyb20gdG9rZW5pemUgKHJlY3Vyc2l2ZWx5KVxuXHRcdFx0XHQoZXhjZXNzID0gdG9rZW5pemUoIHVucXVvdGVkLCB0cnVlICkpICYmXG5cdFx0XHRcdC8vIGFkdmFuY2UgdG8gdGhlIG5leHQgY2xvc2luZyBwYXJlbnRoZXNpc1xuXHRcdFx0XHQoZXhjZXNzID0gdW5xdW90ZWQuaW5kZXhPZiggXCIpXCIsIHVucXVvdGVkLmxlbmd0aCAtIGV4Y2VzcyApIC0gdW5xdW90ZWQubGVuZ3RoKSApIHtcblxuXHRcdFx0XHQvLyBleGNlc3MgaXMgYSBuZWdhdGl2ZSBpbmRleFxuXHRcdFx0XHRtYXRjaFswXSA9IG1hdGNoWzBdLnNsaWNlKCAwLCBleGNlc3MgKTtcblx0XHRcdFx0bWF0Y2hbMl0gPSB1bnF1b3RlZC5zbGljZSggMCwgZXhjZXNzICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIFJldHVybiBvbmx5IGNhcHR1cmVzIG5lZWRlZCBieSB0aGUgcHNldWRvIGZpbHRlciBtZXRob2QgKHR5cGUgYW5kIGFyZ3VtZW50KVxuXHRcdFx0cmV0dXJuIG1hdGNoLnNsaWNlKCAwLCAzICk7XG5cdFx0fVxuXHR9LFxuXG5cdGZpbHRlcjoge1xuXG5cdFx0XCJUQUdcIjogZnVuY3Rpb24oIG5vZGVOYW1lU2VsZWN0b3IgKSB7XG5cdFx0XHR2YXIgbm9kZU5hbWUgPSBub2RlTmFtZVNlbGVjdG9yLnJlcGxhY2UoIHJ1bmVzY2FwZSwgZnVuZXNjYXBlICkudG9Mb3dlckNhc2UoKTtcblx0XHRcdHJldHVybiBub2RlTmFtZVNlbGVjdG9yID09PSBcIipcIiA/XG5cdFx0XHRcdGZ1bmN0aW9uKCkgeyByZXR1cm4gdHJ1ZTsgfSA6XG5cdFx0XHRcdGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0XHRcdHJldHVybiBlbGVtLm5vZGVOYW1lICYmIGVsZW0ubm9kZU5hbWUudG9Mb3dlckNhc2UoKSA9PT0gbm9kZU5hbWU7XG5cdFx0XHRcdH07XG5cdFx0fSxcblxuXHRcdFwiQ0xBU1NcIjogZnVuY3Rpb24oIGNsYXNzTmFtZSApIHtcblx0XHRcdHZhciBwYXR0ZXJuID0gY2xhc3NDYWNoZVsgY2xhc3NOYW1lICsgXCIgXCIgXTtcblxuXHRcdFx0cmV0dXJuIHBhdHRlcm4gfHxcblx0XHRcdFx0KHBhdHRlcm4gPSBuZXcgUmVnRXhwKCBcIihefFwiICsgd2hpdGVzcGFjZSArIFwiKVwiICsgY2xhc3NOYW1lICsgXCIoXCIgKyB3aGl0ZXNwYWNlICsgXCJ8JClcIiApKSAmJlxuXHRcdFx0XHRjbGFzc0NhY2hlKCBjbGFzc05hbWUsIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0XHRcdHJldHVybiBwYXR0ZXJuLnRlc3QoIHR5cGVvZiBlbGVtLmNsYXNzTmFtZSA9PT0gXCJzdHJpbmdcIiAmJiBlbGVtLmNsYXNzTmFtZSB8fCB0eXBlb2YgZWxlbS5nZXRBdHRyaWJ1dGUgIT09IFwidW5kZWZpbmVkXCIgJiYgZWxlbS5nZXRBdHRyaWJ1dGUoXCJjbGFzc1wiKSB8fCBcIlwiICk7XG5cdFx0XHRcdH0pO1xuXHRcdH0sXG5cblx0XHRcIkFUVFJcIjogZnVuY3Rpb24oIG5hbWUsIG9wZXJhdG9yLCBjaGVjayApIHtcblx0XHRcdHJldHVybiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdFx0dmFyIHJlc3VsdCA9IFNpenpsZS5hdHRyKCBlbGVtLCBuYW1lICk7XG5cblx0XHRcdFx0aWYgKCByZXN1bHQgPT0gbnVsbCApIHtcblx0XHRcdFx0XHRyZXR1cm4gb3BlcmF0b3IgPT09IFwiIT1cIjtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoICFvcGVyYXRvciApIHtcblx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHJlc3VsdCArPSBcIlwiO1xuXG5cdFx0XHRcdHJldHVybiBvcGVyYXRvciA9PT0gXCI9XCIgPyByZXN1bHQgPT09IGNoZWNrIDpcblx0XHRcdFx0XHRvcGVyYXRvciA9PT0gXCIhPVwiID8gcmVzdWx0ICE9PSBjaGVjayA6XG5cdFx0XHRcdFx0b3BlcmF0b3IgPT09IFwiXj1cIiA/IGNoZWNrICYmIHJlc3VsdC5pbmRleE9mKCBjaGVjayApID09PSAwIDpcblx0XHRcdFx0XHRvcGVyYXRvciA9PT0gXCIqPVwiID8gY2hlY2sgJiYgcmVzdWx0LmluZGV4T2YoIGNoZWNrICkgPiAtMSA6XG5cdFx0XHRcdFx0b3BlcmF0b3IgPT09IFwiJD1cIiA/IGNoZWNrICYmIHJlc3VsdC5zbGljZSggLWNoZWNrLmxlbmd0aCApID09PSBjaGVjayA6XG5cdFx0XHRcdFx0b3BlcmF0b3IgPT09IFwifj1cIiA/ICggXCIgXCIgKyByZXN1bHQucmVwbGFjZSggcndoaXRlc3BhY2UsIFwiIFwiICkgKyBcIiBcIiApLmluZGV4T2YoIGNoZWNrICkgPiAtMSA6XG5cdFx0XHRcdFx0b3BlcmF0b3IgPT09IFwifD1cIiA/IHJlc3VsdCA9PT0gY2hlY2sgfHwgcmVzdWx0LnNsaWNlKCAwLCBjaGVjay5sZW5ndGggKyAxICkgPT09IGNoZWNrICsgXCItXCIgOlxuXHRcdFx0XHRcdGZhbHNlO1xuXHRcdFx0fTtcblx0XHR9LFxuXG5cdFx0XCJDSElMRFwiOiBmdW5jdGlvbiggdHlwZSwgd2hhdCwgYXJndW1lbnQsIGZpcnN0LCBsYXN0ICkge1xuXHRcdFx0dmFyIHNpbXBsZSA9IHR5cGUuc2xpY2UoIDAsIDMgKSAhPT0gXCJudGhcIixcblx0XHRcdFx0Zm9yd2FyZCA9IHR5cGUuc2xpY2UoIC00ICkgIT09IFwibGFzdFwiLFxuXHRcdFx0XHRvZlR5cGUgPSB3aGF0ID09PSBcIm9mLXR5cGVcIjtcblxuXHRcdFx0cmV0dXJuIGZpcnN0ID09PSAxICYmIGxhc3QgPT09IDAgP1xuXG5cdFx0XHRcdC8vIFNob3J0Y3V0IGZvciA6bnRoLSoobilcblx0XHRcdFx0ZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRcdFx0cmV0dXJuICEhZWxlbS5wYXJlbnROb2RlO1xuXHRcdFx0XHR9IDpcblxuXHRcdFx0XHRmdW5jdGlvbiggZWxlbSwgY29udGV4dCwgeG1sICkge1xuXHRcdFx0XHRcdHZhciBjYWNoZSwgb3V0ZXJDYWNoZSwgbm9kZSwgZGlmZiwgbm9kZUluZGV4LCBzdGFydCxcblx0XHRcdFx0XHRcdGRpciA9IHNpbXBsZSAhPT0gZm9yd2FyZCA/IFwibmV4dFNpYmxpbmdcIiA6IFwicHJldmlvdXNTaWJsaW5nXCIsXG5cdFx0XHRcdFx0XHRwYXJlbnQgPSBlbGVtLnBhcmVudE5vZGUsXG5cdFx0XHRcdFx0XHRuYW1lID0gb2ZUeXBlICYmIGVsZW0ubm9kZU5hbWUudG9Mb3dlckNhc2UoKSxcblx0XHRcdFx0XHRcdHVzZUNhY2hlID0gIXhtbCAmJiAhb2ZUeXBlO1xuXG5cdFx0XHRcdFx0aWYgKCBwYXJlbnQgKSB7XG5cblx0XHRcdFx0XHRcdC8vIDooZmlyc3R8bGFzdHxvbmx5KS0oY2hpbGR8b2YtdHlwZSlcblx0XHRcdFx0XHRcdGlmICggc2ltcGxlICkge1xuXHRcdFx0XHRcdFx0XHR3aGlsZSAoIGRpciApIHtcblx0XHRcdFx0XHRcdFx0XHRub2RlID0gZWxlbTtcblx0XHRcdFx0XHRcdFx0XHR3aGlsZSAoIChub2RlID0gbm9kZVsgZGlyIF0pICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0aWYgKCBvZlR5cGUgPyBub2RlLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09IG5hbWUgOiBub2RlLm5vZGVUeXBlID09PSAxICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdC8vIFJldmVyc2UgZGlyZWN0aW9uIGZvciA6b25seS0qIChpZiB3ZSBoYXZlbid0IHlldCBkb25lIHNvKVxuXHRcdFx0XHRcdFx0XHRcdHN0YXJ0ID0gZGlyID0gdHlwZSA9PT0gXCJvbmx5XCIgJiYgIXN0YXJ0ICYmIFwibmV4dFNpYmxpbmdcIjtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0c3RhcnQgPSBbIGZvcndhcmQgPyBwYXJlbnQuZmlyc3RDaGlsZCA6IHBhcmVudC5sYXN0Q2hpbGQgXTtcblxuXHRcdFx0XHRcdFx0Ly8gbm9uLXhtbCA6bnRoLWNoaWxkKC4uLikgc3RvcmVzIGNhY2hlIGRhdGEgb24gYHBhcmVudGBcblx0XHRcdFx0XHRcdGlmICggZm9yd2FyZCAmJiB1c2VDYWNoZSApIHtcblx0XHRcdFx0XHRcdFx0Ly8gU2VlayBgZWxlbWAgZnJvbSBhIHByZXZpb3VzbHktY2FjaGVkIGluZGV4XG5cdFx0XHRcdFx0XHRcdG91dGVyQ2FjaGUgPSBwYXJlbnRbIGV4cGFuZG8gXSB8fCAocGFyZW50WyBleHBhbmRvIF0gPSB7fSk7XG5cdFx0XHRcdFx0XHRcdGNhY2hlID0gb3V0ZXJDYWNoZVsgdHlwZSBdIHx8IFtdO1xuXHRcdFx0XHRcdFx0XHRub2RlSW5kZXggPSBjYWNoZVswXSA9PT0gZGlycnVucyAmJiBjYWNoZVsxXTtcblx0XHRcdFx0XHRcdFx0ZGlmZiA9IGNhY2hlWzBdID09PSBkaXJydW5zICYmIGNhY2hlWzJdO1xuXHRcdFx0XHRcdFx0XHRub2RlID0gbm9kZUluZGV4ICYmIHBhcmVudC5jaGlsZE5vZGVzWyBub2RlSW5kZXggXTtcblxuXHRcdFx0XHRcdFx0XHR3aGlsZSAoIChub2RlID0gKytub2RlSW5kZXggJiYgbm9kZSAmJiBub2RlWyBkaXIgXSB8fFxuXG5cdFx0XHRcdFx0XHRcdFx0Ly8gRmFsbGJhY2sgdG8gc2Vla2luZyBgZWxlbWAgZnJvbSB0aGUgc3RhcnRcblx0XHRcdFx0XHRcdFx0XHQoZGlmZiA9IG5vZGVJbmRleCA9IDApIHx8IHN0YXJ0LnBvcCgpKSApIHtcblxuXHRcdFx0XHRcdFx0XHRcdC8vIFdoZW4gZm91bmQsIGNhY2hlIGluZGV4ZXMgb24gYHBhcmVudGAgYW5kIGJyZWFrXG5cdFx0XHRcdFx0XHRcdFx0aWYgKCBub2RlLm5vZGVUeXBlID09PSAxICYmICsrZGlmZiAmJiBub2RlID09PSBlbGVtICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0b3V0ZXJDYWNoZVsgdHlwZSBdID0gWyBkaXJydW5zLCBub2RlSW5kZXgsIGRpZmYgXTtcblx0XHRcdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHQvLyBVc2UgcHJldmlvdXNseS1jYWNoZWQgZWxlbWVudCBpbmRleCBpZiBhdmFpbGFibGVcblx0XHRcdFx0XHRcdH0gZWxzZSBpZiAoIHVzZUNhY2hlICYmIChjYWNoZSA9IChlbGVtWyBleHBhbmRvIF0gfHwgKGVsZW1bIGV4cGFuZG8gXSA9IHt9KSlbIHR5cGUgXSkgJiYgY2FjaGVbMF0gPT09IGRpcnJ1bnMgKSB7XG5cdFx0XHRcdFx0XHRcdGRpZmYgPSBjYWNoZVsxXTtcblxuXHRcdFx0XHRcdFx0Ly8geG1sIDpudGgtY2hpbGQoLi4uKSBvciA6bnRoLWxhc3QtY2hpbGQoLi4uKSBvciA6bnRoKC1sYXN0KT8tb2YtdHlwZSguLi4pXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHQvLyBVc2UgdGhlIHNhbWUgbG9vcCBhcyBhYm92ZSB0byBzZWVrIGBlbGVtYCBmcm9tIHRoZSBzdGFydFxuXHRcdFx0XHRcdFx0XHR3aGlsZSAoIChub2RlID0gKytub2RlSW5kZXggJiYgbm9kZSAmJiBub2RlWyBkaXIgXSB8fFxuXHRcdFx0XHRcdFx0XHRcdChkaWZmID0gbm9kZUluZGV4ID0gMCkgfHwgc3RhcnQucG9wKCkpICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0aWYgKCAoIG9mVHlwZSA/IG5vZGUubm9kZU5hbWUudG9Mb3dlckNhc2UoKSA9PT0gbmFtZSA6IG5vZGUubm9kZVR5cGUgPT09IDEgKSAmJiArK2RpZmYgKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHQvLyBDYWNoZSB0aGUgaW5kZXggb2YgZWFjaCBlbmNvdW50ZXJlZCBlbGVtZW50XG5cdFx0XHRcdFx0XHRcdFx0XHRpZiAoIHVzZUNhY2hlICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHQobm9kZVsgZXhwYW5kbyBdIHx8IChub2RlWyBleHBhbmRvIF0gPSB7fSkpWyB0eXBlIF0gPSBbIGRpcnJ1bnMsIGRpZmYgXTtcblx0XHRcdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0XHRcdFx0aWYgKCBub2RlID09PSBlbGVtICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0Ly8gSW5jb3Jwb3JhdGUgdGhlIG9mZnNldCwgdGhlbiBjaGVjayBhZ2FpbnN0IGN5Y2xlIHNpemVcblx0XHRcdFx0XHRcdGRpZmYgLT0gbGFzdDtcblx0XHRcdFx0XHRcdHJldHVybiBkaWZmID09PSBmaXJzdCB8fCAoIGRpZmYgJSBmaXJzdCA9PT0gMCAmJiBkaWZmIC8gZmlyc3QgPj0gMCApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fTtcblx0XHR9LFxuXG5cdFx0XCJQU0VVRE9cIjogZnVuY3Rpb24oIHBzZXVkbywgYXJndW1lbnQgKSB7XG5cdFx0XHQvLyBwc2V1ZG8tY2xhc3MgbmFtZXMgYXJlIGNhc2UtaW5zZW5zaXRpdmVcblx0XHRcdC8vIGh0dHA6Ly93d3cudzMub3JnL1RSL3NlbGVjdG9ycy8jcHNldWRvLWNsYXNzZXNcblx0XHRcdC8vIFByaW9yaXRpemUgYnkgY2FzZSBzZW5zaXRpdml0eSBpbiBjYXNlIGN1c3RvbSBwc2V1ZG9zIGFyZSBhZGRlZCB3aXRoIHVwcGVyY2FzZSBsZXR0ZXJzXG5cdFx0XHQvLyBSZW1lbWJlciB0aGF0IHNldEZpbHRlcnMgaW5oZXJpdHMgZnJvbSBwc2V1ZG9zXG5cdFx0XHR2YXIgYXJncyxcblx0XHRcdFx0Zm4gPSBFeHByLnBzZXVkb3NbIHBzZXVkbyBdIHx8IEV4cHIuc2V0RmlsdGVyc1sgcHNldWRvLnRvTG93ZXJDYXNlKCkgXSB8fFxuXHRcdFx0XHRcdFNpenpsZS5lcnJvciggXCJ1bnN1cHBvcnRlZCBwc2V1ZG86IFwiICsgcHNldWRvICk7XG5cblx0XHRcdC8vIFRoZSB1c2VyIG1heSB1c2UgY3JlYXRlUHNldWRvIHRvIGluZGljYXRlIHRoYXRcblx0XHRcdC8vIGFyZ3VtZW50cyBhcmUgbmVlZGVkIHRvIGNyZWF0ZSB0aGUgZmlsdGVyIGZ1bmN0aW9uXG5cdFx0XHQvLyBqdXN0IGFzIFNpenpsZSBkb2VzXG5cdFx0XHRpZiAoIGZuWyBleHBhbmRvIF0gKSB7XG5cdFx0XHRcdHJldHVybiBmbiggYXJndW1lbnQgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQnV0IG1haW50YWluIHN1cHBvcnQgZm9yIG9sZCBzaWduYXR1cmVzXG5cdFx0XHRpZiAoIGZuLmxlbmd0aCA+IDEgKSB7XG5cdFx0XHRcdGFyZ3MgPSBbIHBzZXVkbywgcHNldWRvLCBcIlwiLCBhcmd1bWVudCBdO1xuXHRcdFx0XHRyZXR1cm4gRXhwci5zZXRGaWx0ZXJzLmhhc093blByb3BlcnR5KCBwc2V1ZG8udG9Mb3dlckNhc2UoKSApID9cblx0XHRcdFx0XHRtYXJrRnVuY3Rpb24oZnVuY3Rpb24oIHNlZWQsIG1hdGNoZXMgKSB7XG5cdFx0XHRcdFx0XHR2YXIgaWR4LFxuXHRcdFx0XHRcdFx0XHRtYXRjaGVkID0gZm4oIHNlZWQsIGFyZ3VtZW50ICksXG5cdFx0XHRcdFx0XHRcdGkgPSBtYXRjaGVkLmxlbmd0aDtcblx0XHRcdFx0XHRcdHdoaWxlICggaS0tICkge1xuXHRcdFx0XHRcdFx0XHRpZHggPSBpbmRleE9mKCBzZWVkLCBtYXRjaGVkW2ldICk7XG5cdFx0XHRcdFx0XHRcdHNlZWRbIGlkeCBdID0gISggbWF0Y2hlc1sgaWR4IF0gPSBtYXRjaGVkW2ldICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fSkgOlxuXHRcdFx0XHRcdGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0XHRcdFx0cmV0dXJuIGZuKCBlbGVtLCAwLCBhcmdzICk7XG5cdFx0XHRcdFx0fTtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGZuO1xuXHRcdH1cblx0fSxcblxuXHRwc2V1ZG9zOiB7XG5cdFx0Ly8gUG90ZW50aWFsbHkgY29tcGxleCBwc2V1ZG9zXG5cdFx0XCJub3RcIjogbWFya0Z1bmN0aW9uKGZ1bmN0aW9uKCBzZWxlY3RvciApIHtcblx0XHRcdC8vIFRyaW0gdGhlIHNlbGVjdG9yIHBhc3NlZCB0byBjb21waWxlXG5cdFx0XHQvLyB0byBhdm9pZCB0cmVhdGluZyBsZWFkaW5nIGFuZCB0cmFpbGluZ1xuXHRcdFx0Ly8gc3BhY2VzIGFzIGNvbWJpbmF0b3JzXG5cdFx0XHR2YXIgaW5wdXQgPSBbXSxcblx0XHRcdFx0cmVzdWx0cyA9IFtdLFxuXHRcdFx0XHRtYXRjaGVyID0gY29tcGlsZSggc2VsZWN0b3IucmVwbGFjZSggcnRyaW0sIFwiJDFcIiApICk7XG5cblx0XHRcdHJldHVybiBtYXRjaGVyWyBleHBhbmRvIF0gP1xuXHRcdFx0XHRtYXJrRnVuY3Rpb24oZnVuY3Rpb24oIHNlZWQsIG1hdGNoZXMsIGNvbnRleHQsIHhtbCApIHtcblx0XHRcdFx0XHR2YXIgZWxlbSxcblx0XHRcdFx0XHRcdHVubWF0Y2hlZCA9IG1hdGNoZXIoIHNlZWQsIG51bGwsIHhtbCwgW10gKSxcblx0XHRcdFx0XHRcdGkgPSBzZWVkLmxlbmd0aDtcblxuXHRcdFx0XHRcdC8vIE1hdGNoIGVsZW1lbnRzIHVubWF0Y2hlZCBieSBgbWF0Y2hlcmBcblx0XHRcdFx0XHR3aGlsZSAoIGktLSApIHtcblx0XHRcdFx0XHRcdGlmICggKGVsZW0gPSB1bm1hdGNoZWRbaV0pICkge1xuXHRcdFx0XHRcdFx0XHRzZWVkW2ldID0gIShtYXRjaGVzW2ldID0gZWxlbSk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9KSA6XG5cdFx0XHRcdGZ1bmN0aW9uKCBlbGVtLCBjb250ZXh0LCB4bWwgKSB7XG5cdFx0XHRcdFx0aW5wdXRbMF0gPSBlbGVtO1xuXHRcdFx0XHRcdG1hdGNoZXIoIGlucHV0LCBudWxsLCB4bWwsIHJlc3VsdHMgKTtcblx0XHRcdFx0XHQvLyBEb24ndCBrZWVwIHRoZSBlbGVtZW50IChpc3N1ZSAjMjk5KVxuXHRcdFx0XHRcdGlucHV0WzBdID0gbnVsbDtcblx0XHRcdFx0XHRyZXR1cm4gIXJlc3VsdHMucG9wKCk7XG5cdFx0XHRcdH07XG5cdFx0fSksXG5cblx0XHRcImhhc1wiOiBtYXJrRnVuY3Rpb24oZnVuY3Rpb24oIHNlbGVjdG9yICkge1xuXHRcdFx0cmV0dXJuIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0XHRyZXR1cm4gU2l6emxlKCBzZWxlY3RvciwgZWxlbSApLmxlbmd0aCA+IDA7XG5cdFx0XHR9O1xuXHRcdH0pLFxuXG5cdFx0XCJjb250YWluc1wiOiBtYXJrRnVuY3Rpb24oZnVuY3Rpb24oIHRleHQgKSB7XG5cdFx0XHR0ZXh0ID0gdGV4dC5yZXBsYWNlKCBydW5lc2NhcGUsIGZ1bmVzY2FwZSApO1xuXHRcdFx0cmV0dXJuIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0XHRyZXR1cm4gKCBlbGVtLnRleHRDb250ZW50IHx8IGVsZW0uaW5uZXJUZXh0IHx8IGdldFRleHQoIGVsZW0gKSApLmluZGV4T2YoIHRleHQgKSA+IC0xO1xuXHRcdFx0fTtcblx0XHR9KSxcblxuXHRcdC8vIFwiV2hldGhlciBhbiBlbGVtZW50IGlzIHJlcHJlc2VudGVkIGJ5IGEgOmxhbmcoKSBzZWxlY3RvclxuXHRcdC8vIGlzIGJhc2VkIHNvbGVseSBvbiB0aGUgZWxlbWVudCdzIGxhbmd1YWdlIHZhbHVlXG5cdFx0Ly8gYmVpbmcgZXF1YWwgdG8gdGhlIGlkZW50aWZpZXIgQyxcblx0XHQvLyBvciBiZWdpbm5pbmcgd2l0aCB0aGUgaWRlbnRpZmllciBDIGltbWVkaWF0ZWx5IGZvbGxvd2VkIGJ5IFwiLVwiLlxuXHRcdC8vIFRoZSBtYXRjaGluZyBvZiBDIGFnYWluc3QgdGhlIGVsZW1lbnQncyBsYW5ndWFnZSB2YWx1ZSBpcyBwZXJmb3JtZWQgY2FzZS1pbnNlbnNpdGl2ZWx5LlxuXHRcdC8vIFRoZSBpZGVudGlmaWVyIEMgZG9lcyBub3QgaGF2ZSB0byBiZSBhIHZhbGlkIGxhbmd1YWdlIG5hbWUuXCJcblx0XHQvLyBodHRwOi8vd3d3LnczLm9yZy9UUi9zZWxlY3RvcnMvI2xhbmctcHNldWRvXG5cdFx0XCJsYW5nXCI6IG1hcmtGdW5jdGlvbiggZnVuY3Rpb24oIGxhbmcgKSB7XG5cdFx0XHQvLyBsYW5nIHZhbHVlIG11c3QgYmUgYSB2YWxpZCBpZGVudGlmaWVyXG5cdFx0XHRpZiAoICFyaWRlbnRpZmllci50ZXN0KGxhbmcgfHwgXCJcIikgKSB7XG5cdFx0XHRcdFNpenpsZS5lcnJvciggXCJ1bnN1cHBvcnRlZCBsYW5nOiBcIiArIGxhbmcgKTtcblx0XHRcdH1cblx0XHRcdGxhbmcgPSBsYW5nLnJlcGxhY2UoIHJ1bmVzY2FwZSwgZnVuZXNjYXBlICkudG9Mb3dlckNhc2UoKTtcblx0XHRcdHJldHVybiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdFx0dmFyIGVsZW1MYW5nO1xuXHRcdFx0XHRkbyB7XG5cdFx0XHRcdFx0aWYgKCAoZWxlbUxhbmcgPSBkb2N1bWVudElzSFRNTCA/XG5cdFx0XHRcdFx0XHRlbGVtLmxhbmcgOlxuXHRcdFx0XHRcdFx0ZWxlbS5nZXRBdHRyaWJ1dGUoXCJ4bWw6bGFuZ1wiKSB8fCBlbGVtLmdldEF0dHJpYnV0ZShcImxhbmdcIikpICkge1xuXG5cdFx0XHRcdFx0XHRlbGVtTGFuZyA9IGVsZW1MYW5nLnRvTG93ZXJDYXNlKCk7XG5cdFx0XHRcdFx0XHRyZXR1cm4gZWxlbUxhbmcgPT09IGxhbmcgfHwgZWxlbUxhbmcuaW5kZXhPZiggbGFuZyArIFwiLVwiICkgPT09IDA7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9IHdoaWxlICggKGVsZW0gPSBlbGVtLnBhcmVudE5vZGUpICYmIGVsZW0ubm9kZVR5cGUgPT09IDEgKTtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fTtcblx0XHR9KSxcblxuXHRcdC8vIE1pc2NlbGxhbmVvdXNcblx0XHRcInRhcmdldFwiOiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdHZhciBoYXNoID0gd2luZG93LmxvY2F0aW9uICYmIHdpbmRvdy5sb2NhdGlvbi5oYXNoO1xuXHRcdFx0cmV0dXJuIGhhc2ggJiYgaGFzaC5zbGljZSggMSApID09PSBlbGVtLmlkO1xuXHRcdH0sXG5cblx0XHRcInJvb3RcIjogZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRyZXR1cm4gZWxlbSA9PT0gZG9jRWxlbTtcblx0XHR9LFxuXG5cdFx0XCJmb2N1c1wiOiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdHJldHVybiBlbGVtID09PSBkb2N1bWVudC5hY3RpdmVFbGVtZW50ICYmICghZG9jdW1lbnQuaGFzRm9jdXMgfHwgZG9jdW1lbnQuaGFzRm9jdXMoKSkgJiYgISEoZWxlbS50eXBlIHx8IGVsZW0uaHJlZiB8fCB+ZWxlbS50YWJJbmRleCk7XG5cdFx0fSxcblxuXHRcdC8vIEJvb2xlYW4gcHJvcGVydGllc1xuXHRcdFwiZW5hYmxlZFwiOiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdHJldHVybiBlbGVtLmRpc2FibGVkID09PSBmYWxzZTtcblx0XHR9LFxuXG5cdFx0XCJkaXNhYmxlZFwiOiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdHJldHVybiBlbGVtLmRpc2FibGVkID09PSB0cnVlO1xuXHRcdH0sXG5cblx0XHRcImNoZWNrZWRcIjogZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHQvLyBJbiBDU1MzLCA6Y2hlY2tlZCBzaG91bGQgcmV0dXJuIGJvdGggY2hlY2tlZCBhbmQgc2VsZWN0ZWQgZWxlbWVudHNcblx0XHRcdC8vIGh0dHA6Ly93d3cudzMub3JnL1RSLzIwMTEvUkVDLWNzczMtc2VsZWN0b3JzLTIwMTEwOTI5LyNjaGVja2VkXG5cdFx0XHR2YXIgbm9kZU5hbWUgPSBlbGVtLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk7XG5cdFx0XHRyZXR1cm4gKG5vZGVOYW1lID09PSBcImlucHV0XCIgJiYgISFlbGVtLmNoZWNrZWQpIHx8IChub2RlTmFtZSA9PT0gXCJvcHRpb25cIiAmJiAhIWVsZW0uc2VsZWN0ZWQpO1xuXHRcdH0sXG5cblx0XHRcInNlbGVjdGVkXCI6IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0Ly8gQWNjZXNzaW5nIHRoaXMgcHJvcGVydHkgbWFrZXMgc2VsZWN0ZWQtYnktZGVmYXVsdFxuXHRcdFx0Ly8gb3B0aW9ucyBpbiBTYWZhcmkgd29yayBwcm9wZXJseVxuXHRcdFx0aWYgKCBlbGVtLnBhcmVudE5vZGUgKSB7XG5cdFx0XHRcdGVsZW0ucGFyZW50Tm9kZS5zZWxlY3RlZEluZGV4O1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gZWxlbS5zZWxlY3RlZCA9PT0gdHJ1ZTtcblx0XHR9LFxuXG5cdFx0Ly8gQ29udGVudHNcblx0XHRcImVtcHR5XCI6IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0Ly8gaHR0cDovL3d3dy53My5vcmcvVFIvc2VsZWN0b3JzLyNlbXB0eS1wc2V1ZG9cblx0XHRcdC8vIDplbXB0eSBpcyBuZWdhdGVkIGJ5IGVsZW1lbnQgKDEpIG9yIGNvbnRlbnQgbm9kZXMgKHRleHQ6IDM7IGNkYXRhOiA0OyBlbnRpdHkgcmVmOiA1KSxcblx0XHRcdC8vICAgYnV0IG5vdCBieSBvdGhlcnMgKGNvbW1lbnQ6IDg7IHByb2Nlc3NpbmcgaW5zdHJ1Y3Rpb246IDc7IGV0Yy4pXG5cdFx0XHQvLyBub2RlVHlwZSA8IDYgd29ya3MgYmVjYXVzZSBhdHRyaWJ1dGVzICgyKSBkbyBub3QgYXBwZWFyIGFzIGNoaWxkcmVuXG5cdFx0XHRmb3IgKCBlbGVtID0gZWxlbS5maXJzdENoaWxkOyBlbGVtOyBlbGVtID0gZWxlbS5uZXh0U2libGluZyApIHtcblx0XHRcdFx0aWYgKCBlbGVtLm5vZGVUeXBlIDwgNiApIHtcblx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHJldHVybiB0cnVlO1xuXHRcdH0sXG5cblx0XHRcInBhcmVudFwiOiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdHJldHVybiAhRXhwci5wc2V1ZG9zW1wiZW1wdHlcIl0oIGVsZW0gKTtcblx0XHR9LFxuXG5cdFx0Ly8gRWxlbWVudC9pbnB1dCB0eXBlc1xuXHRcdFwiaGVhZGVyXCI6IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0cmV0dXJuIHJoZWFkZXIudGVzdCggZWxlbS5ub2RlTmFtZSApO1xuXHRcdH0sXG5cblx0XHRcImlucHV0XCI6IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0cmV0dXJuIHJpbnB1dHMudGVzdCggZWxlbS5ub2RlTmFtZSApO1xuXHRcdH0sXG5cblx0XHRcImJ1dHRvblwiOiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdHZhciBuYW1lID0gZWxlbS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpO1xuXHRcdFx0cmV0dXJuIG5hbWUgPT09IFwiaW5wdXRcIiAmJiBlbGVtLnR5cGUgPT09IFwiYnV0dG9uXCIgfHwgbmFtZSA9PT0gXCJidXR0b25cIjtcblx0XHR9LFxuXG5cdFx0XCJ0ZXh0XCI6IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0dmFyIGF0dHI7XG5cdFx0XHRyZXR1cm4gZWxlbS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpID09PSBcImlucHV0XCIgJiZcblx0XHRcdFx0ZWxlbS50eXBlID09PSBcInRleHRcIiAmJlxuXG5cdFx0XHRcdC8vIFN1cHBvcnQ6IElFPDhcblx0XHRcdFx0Ly8gTmV3IEhUTUw1IGF0dHJpYnV0ZSB2YWx1ZXMgKGUuZy4sIFwic2VhcmNoXCIpIGFwcGVhciB3aXRoIGVsZW0udHlwZSA9PT0gXCJ0ZXh0XCJcblx0XHRcdFx0KCAoYXR0ciA9IGVsZW0uZ2V0QXR0cmlidXRlKFwidHlwZVwiKSkgPT0gbnVsbCB8fCBhdHRyLnRvTG93ZXJDYXNlKCkgPT09IFwidGV4dFwiICk7XG5cdFx0fSxcblxuXHRcdC8vIFBvc2l0aW9uLWluLWNvbGxlY3Rpb25cblx0XHRcImZpcnN0XCI6IGNyZWF0ZVBvc2l0aW9uYWxQc2V1ZG8oZnVuY3Rpb24oKSB7XG5cdFx0XHRyZXR1cm4gWyAwIF07XG5cdFx0fSksXG5cblx0XHRcImxhc3RcIjogY3JlYXRlUG9zaXRpb25hbFBzZXVkbyhmdW5jdGlvbiggbWF0Y2hJbmRleGVzLCBsZW5ndGggKSB7XG5cdFx0XHRyZXR1cm4gWyBsZW5ndGggLSAxIF07XG5cdFx0fSksXG5cblx0XHRcImVxXCI6IGNyZWF0ZVBvc2l0aW9uYWxQc2V1ZG8oZnVuY3Rpb24oIG1hdGNoSW5kZXhlcywgbGVuZ3RoLCBhcmd1bWVudCApIHtcblx0XHRcdHJldHVybiBbIGFyZ3VtZW50IDwgMCA/IGFyZ3VtZW50ICsgbGVuZ3RoIDogYXJndW1lbnQgXTtcblx0XHR9KSxcblxuXHRcdFwiZXZlblwiOiBjcmVhdGVQb3NpdGlvbmFsUHNldWRvKGZ1bmN0aW9uKCBtYXRjaEluZGV4ZXMsIGxlbmd0aCApIHtcblx0XHRcdHZhciBpID0gMDtcblx0XHRcdGZvciAoIDsgaSA8IGxlbmd0aDsgaSArPSAyICkge1xuXHRcdFx0XHRtYXRjaEluZGV4ZXMucHVzaCggaSApO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIG1hdGNoSW5kZXhlcztcblx0XHR9KSxcblxuXHRcdFwib2RkXCI6IGNyZWF0ZVBvc2l0aW9uYWxQc2V1ZG8oZnVuY3Rpb24oIG1hdGNoSW5kZXhlcywgbGVuZ3RoICkge1xuXHRcdFx0dmFyIGkgPSAxO1xuXHRcdFx0Zm9yICggOyBpIDwgbGVuZ3RoOyBpICs9IDIgKSB7XG5cdFx0XHRcdG1hdGNoSW5kZXhlcy5wdXNoKCBpICk7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gbWF0Y2hJbmRleGVzO1xuXHRcdH0pLFxuXG5cdFx0XCJsdFwiOiBjcmVhdGVQb3NpdGlvbmFsUHNldWRvKGZ1bmN0aW9uKCBtYXRjaEluZGV4ZXMsIGxlbmd0aCwgYXJndW1lbnQgKSB7XG5cdFx0XHR2YXIgaSA9IGFyZ3VtZW50IDwgMCA/IGFyZ3VtZW50ICsgbGVuZ3RoIDogYXJndW1lbnQ7XG5cdFx0XHRmb3IgKCA7IC0taSA+PSAwOyApIHtcblx0XHRcdFx0bWF0Y2hJbmRleGVzLnB1c2goIGkgKTtcblx0XHRcdH1cblx0XHRcdHJldHVybiBtYXRjaEluZGV4ZXM7XG5cdFx0fSksXG5cblx0XHRcImd0XCI6IGNyZWF0ZVBvc2l0aW9uYWxQc2V1ZG8oZnVuY3Rpb24oIG1hdGNoSW5kZXhlcywgbGVuZ3RoLCBhcmd1bWVudCApIHtcblx0XHRcdHZhciBpID0gYXJndW1lbnQgPCAwID8gYXJndW1lbnQgKyBsZW5ndGggOiBhcmd1bWVudDtcblx0XHRcdGZvciAoIDsgKytpIDwgbGVuZ3RoOyApIHtcblx0XHRcdFx0bWF0Y2hJbmRleGVzLnB1c2goIGkgKTtcblx0XHRcdH1cblx0XHRcdHJldHVybiBtYXRjaEluZGV4ZXM7XG5cdFx0fSlcblx0fVxufTtcblxuRXhwci5wc2V1ZG9zW1wibnRoXCJdID0gRXhwci5wc2V1ZG9zW1wiZXFcIl07XG5cbi8vIEFkZCBidXR0b24vaW5wdXQgdHlwZSBwc2V1ZG9zXG5mb3IgKCBpIGluIHsgcmFkaW86IHRydWUsIGNoZWNrYm94OiB0cnVlLCBmaWxlOiB0cnVlLCBwYXNzd29yZDogdHJ1ZSwgaW1hZ2U6IHRydWUgfSApIHtcblx0RXhwci5wc2V1ZG9zWyBpIF0gPSBjcmVhdGVJbnB1dFBzZXVkbyggaSApO1xufVxuZm9yICggaSBpbiB7IHN1Ym1pdDogdHJ1ZSwgcmVzZXQ6IHRydWUgfSApIHtcblx0RXhwci5wc2V1ZG9zWyBpIF0gPSBjcmVhdGVCdXR0b25Qc2V1ZG8oIGkgKTtcbn1cblxuLy8gRWFzeSBBUEkgZm9yIGNyZWF0aW5nIG5ldyBzZXRGaWx0ZXJzXG5mdW5jdGlvbiBzZXRGaWx0ZXJzKCkge31cbnNldEZpbHRlcnMucHJvdG90eXBlID0gRXhwci5maWx0ZXJzID0gRXhwci5wc2V1ZG9zO1xuRXhwci5zZXRGaWx0ZXJzID0gbmV3IHNldEZpbHRlcnMoKTtcblxudG9rZW5pemUgPSBTaXp6bGUudG9rZW5pemUgPSBmdW5jdGlvbiggc2VsZWN0b3IsIHBhcnNlT25seSApIHtcblx0dmFyIG1hdGNoZWQsIG1hdGNoLCB0b2tlbnMsIHR5cGUsXG5cdFx0c29GYXIsIGdyb3VwcywgcHJlRmlsdGVycyxcblx0XHRjYWNoZWQgPSB0b2tlbkNhY2hlWyBzZWxlY3RvciArIFwiIFwiIF07XG5cblx0aWYgKCBjYWNoZWQgKSB7XG5cdFx0cmV0dXJuIHBhcnNlT25seSA/IDAgOiBjYWNoZWQuc2xpY2UoIDAgKTtcblx0fVxuXG5cdHNvRmFyID0gc2VsZWN0b3I7XG5cdGdyb3VwcyA9IFtdO1xuXHRwcmVGaWx0ZXJzID0gRXhwci5wcmVGaWx0ZXI7XG5cblx0d2hpbGUgKCBzb0ZhciApIHtcblxuXHRcdC8vIENvbW1hIGFuZCBmaXJzdCBydW5cblx0XHRpZiAoICFtYXRjaGVkIHx8IChtYXRjaCA9IHJjb21tYS5leGVjKCBzb0ZhciApKSApIHtcblx0XHRcdGlmICggbWF0Y2ggKSB7XG5cdFx0XHRcdC8vIERvbid0IGNvbnN1bWUgdHJhaWxpbmcgY29tbWFzIGFzIHZhbGlkXG5cdFx0XHRcdHNvRmFyID0gc29GYXIuc2xpY2UoIG1hdGNoWzBdLmxlbmd0aCApIHx8IHNvRmFyO1xuXHRcdFx0fVxuXHRcdFx0Z3JvdXBzLnB1c2goICh0b2tlbnMgPSBbXSkgKTtcblx0XHR9XG5cblx0XHRtYXRjaGVkID0gZmFsc2U7XG5cblx0XHQvLyBDb21iaW5hdG9yc1xuXHRcdGlmICggKG1hdGNoID0gcmNvbWJpbmF0b3JzLmV4ZWMoIHNvRmFyICkpICkge1xuXHRcdFx0bWF0Y2hlZCA9IG1hdGNoLnNoaWZ0KCk7XG5cdFx0XHR0b2tlbnMucHVzaCh7XG5cdFx0XHRcdHZhbHVlOiBtYXRjaGVkLFxuXHRcdFx0XHQvLyBDYXN0IGRlc2NlbmRhbnQgY29tYmluYXRvcnMgdG8gc3BhY2Vcblx0XHRcdFx0dHlwZTogbWF0Y2hbMF0ucmVwbGFjZSggcnRyaW0sIFwiIFwiIClcblx0XHRcdH0pO1xuXHRcdFx0c29GYXIgPSBzb0Zhci5zbGljZSggbWF0Y2hlZC5sZW5ndGggKTtcblx0XHR9XG5cblx0XHQvLyBGaWx0ZXJzXG5cdFx0Zm9yICggdHlwZSBpbiBFeHByLmZpbHRlciApIHtcblx0XHRcdGlmICggKG1hdGNoID0gbWF0Y2hFeHByWyB0eXBlIF0uZXhlYyggc29GYXIgKSkgJiYgKCFwcmVGaWx0ZXJzWyB0eXBlIF0gfHxcblx0XHRcdFx0KG1hdGNoID0gcHJlRmlsdGVyc1sgdHlwZSBdKCBtYXRjaCApKSkgKSB7XG5cdFx0XHRcdG1hdGNoZWQgPSBtYXRjaC5zaGlmdCgpO1xuXHRcdFx0XHR0b2tlbnMucHVzaCh7XG5cdFx0XHRcdFx0dmFsdWU6IG1hdGNoZWQsXG5cdFx0XHRcdFx0dHlwZTogdHlwZSxcblx0XHRcdFx0XHRtYXRjaGVzOiBtYXRjaFxuXHRcdFx0XHR9KTtcblx0XHRcdFx0c29GYXIgPSBzb0Zhci5zbGljZSggbWF0Y2hlZC5sZW5ndGggKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAoICFtYXRjaGVkICkge1xuXHRcdFx0YnJlYWs7XG5cdFx0fVxuXHR9XG5cblx0Ly8gUmV0dXJuIHRoZSBsZW5ndGggb2YgdGhlIGludmFsaWQgZXhjZXNzXG5cdC8vIGlmIHdlJ3JlIGp1c3QgcGFyc2luZ1xuXHQvLyBPdGhlcndpc2UsIHRocm93IGFuIGVycm9yIG9yIHJldHVybiB0b2tlbnNcblx0cmV0dXJuIHBhcnNlT25seSA/XG5cdFx0c29GYXIubGVuZ3RoIDpcblx0XHRzb0ZhciA/XG5cdFx0XHRTaXp6bGUuZXJyb3IoIHNlbGVjdG9yICkgOlxuXHRcdFx0Ly8gQ2FjaGUgdGhlIHRva2Vuc1xuXHRcdFx0dG9rZW5DYWNoZSggc2VsZWN0b3IsIGdyb3VwcyApLnNsaWNlKCAwICk7XG59O1xuXG5mdW5jdGlvbiB0b1NlbGVjdG9yKCB0b2tlbnMgKSB7XG5cdHZhciBpID0gMCxcblx0XHRsZW4gPSB0b2tlbnMubGVuZ3RoLFxuXHRcdHNlbGVjdG9yID0gXCJcIjtcblx0Zm9yICggOyBpIDwgbGVuOyBpKysgKSB7XG5cdFx0c2VsZWN0b3IgKz0gdG9rZW5zW2ldLnZhbHVlO1xuXHR9XG5cdHJldHVybiBzZWxlY3Rvcjtcbn1cblxuZnVuY3Rpb24gYWRkQ29tYmluYXRvciggbWF0Y2hlciwgY29tYmluYXRvciwgYmFzZSApIHtcblx0dmFyIGRpciA9IGNvbWJpbmF0b3IuZGlyLFxuXHRcdGNoZWNrTm9uRWxlbWVudHMgPSBiYXNlICYmIGRpciA9PT0gXCJwYXJlbnROb2RlXCIsXG5cdFx0ZG9uZU5hbWUgPSBkb25lKys7XG5cblx0cmV0dXJuIGNvbWJpbmF0b3IuZmlyc3QgP1xuXHRcdC8vIENoZWNrIGFnYWluc3QgY2xvc2VzdCBhbmNlc3Rvci9wcmVjZWRpbmcgZWxlbWVudFxuXHRcdGZ1bmN0aW9uKCBlbGVtLCBjb250ZXh0LCB4bWwgKSB7XG5cdFx0XHR3aGlsZSAoIChlbGVtID0gZWxlbVsgZGlyIF0pICkge1xuXHRcdFx0XHRpZiAoIGVsZW0ubm9kZVR5cGUgPT09IDEgfHwgY2hlY2tOb25FbGVtZW50cyApIHtcblx0XHRcdFx0XHRyZXR1cm4gbWF0Y2hlciggZWxlbSwgY29udGV4dCwgeG1sICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9IDpcblxuXHRcdC8vIENoZWNrIGFnYWluc3QgYWxsIGFuY2VzdG9yL3ByZWNlZGluZyBlbGVtZW50c1xuXHRcdGZ1bmN0aW9uKCBlbGVtLCBjb250ZXh0LCB4bWwgKSB7XG5cdFx0XHR2YXIgb2xkQ2FjaGUsIG91dGVyQ2FjaGUsXG5cdFx0XHRcdG5ld0NhY2hlID0gWyBkaXJydW5zLCBkb25lTmFtZSBdO1xuXG5cdFx0XHQvLyBXZSBjYW4ndCBzZXQgYXJiaXRyYXJ5IGRhdGEgb24gWE1MIG5vZGVzLCBzbyB0aGV5IGRvbid0IGJlbmVmaXQgZnJvbSBkaXIgY2FjaGluZ1xuXHRcdFx0aWYgKCB4bWwgKSB7XG5cdFx0XHRcdHdoaWxlICggKGVsZW0gPSBlbGVtWyBkaXIgXSkgKSB7XG5cdFx0XHRcdFx0aWYgKCBlbGVtLm5vZGVUeXBlID09PSAxIHx8IGNoZWNrTm9uRWxlbWVudHMgKSB7XG5cdFx0XHRcdFx0XHRpZiAoIG1hdGNoZXIoIGVsZW0sIGNvbnRleHQsIHhtbCApICkge1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHdoaWxlICggKGVsZW0gPSBlbGVtWyBkaXIgXSkgKSB7XG5cdFx0XHRcdFx0aWYgKCBlbGVtLm5vZGVUeXBlID09PSAxIHx8IGNoZWNrTm9uRWxlbWVudHMgKSB7XG5cdFx0XHRcdFx0XHRvdXRlckNhY2hlID0gZWxlbVsgZXhwYW5kbyBdIHx8IChlbGVtWyBleHBhbmRvIF0gPSB7fSk7XG5cdFx0XHRcdFx0XHRpZiAoIChvbGRDYWNoZSA9IG91dGVyQ2FjaGVbIGRpciBdKSAmJlxuXHRcdFx0XHRcdFx0XHRvbGRDYWNoZVsgMCBdID09PSBkaXJydW5zICYmIG9sZENhY2hlWyAxIF0gPT09IGRvbmVOYW1lICkge1xuXG5cdFx0XHRcdFx0XHRcdC8vIEFzc2lnbiB0byBuZXdDYWNoZSBzbyByZXN1bHRzIGJhY2stcHJvcGFnYXRlIHRvIHByZXZpb3VzIGVsZW1lbnRzXG5cdFx0XHRcdFx0XHRcdHJldHVybiAobmV3Q2FjaGVbIDIgXSA9IG9sZENhY2hlWyAyIF0pO1xuXHRcdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdFx0Ly8gUmV1c2UgbmV3Y2FjaGUgc28gcmVzdWx0cyBiYWNrLXByb3BhZ2F0ZSB0byBwcmV2aW91cyBlbGVtZW50c1xuXHRcdFx0XHRcdFx0XHRvdXRlckNhY2hlWyBkaXIgXSA9IG5ld0NhY2hlO1xuXG5cdFx0XHRcdFx0XHRcdC8vIEEgbWF0Y2ggbWVhbnMgd2UncmUgZG9uZTsgYSBmYWlsIG1lYW5zIHdlIGhhdmUgdG8ga2VlcCBjaGVja2luZ1xuXHRcdFx0XHRcdFx0XHRpZiAoIChuZXdDYWNoZVsgMiBdID0gbWF0Y2hlciggZWxlbSwgY29udGV4dCwgeG1sICkpICkge1xuXHRcdFx0XHRcdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fTtcbn1cblxuZnVuY3Rpb24gZWxlbWVudE1hdGNoZXIoIG1hdGNoZXJzICkge1xuXHRyZXR1cm4gbWF0Y2hlcnMubGVuZ3RoID4gMSA/XG5cdFx0ZnVuY3Rpb24oIGVsZW0sIGNvbnRleHQsIHhtbCApIHtcblx0XHRcdHZhciBpID0gbWF0Y2hlcnMubGVuZ3RoO1xuXHRcdFx0d2hpbGUgKCBpLS0gKSB7XG5cdFx0XHRcdGlmICggIW1hdGNoZXJzW2ldKCBlbGVtLCBjb250ZXh0LCB4bWwgKSApIHtcblx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHJldHVybiB0cnVlO1xuXHRcdH0gOlxuXHRcdG1hdGNoZXJzWzBdO1xufVxuXG5mdW5jdGlvbiBtdWx0aXBsZUNvbnRleHRzKCBzZWxlY3RvciwgY29udGV4dHMsIHJlc3VsdHMgKSB7XG5cdHZhciBpID0gMCxcblx0XHRsZW4gPSBjb250ZXh0cy5sZW5ndGg7XG5cdGZvciAoIDsgaSA8IGxlbjsgaSsrICkge1xuXHRcdFNpenpsZSggc2VsZWN0b3IsIGNvbnRleHRzW2ldLCByZXN1bHRzICk7XG5cdH1cblx0cmV0dXJuIHJlc3VsdHM7XG59XG5cbmZ1bmN0aW9uIGNvbmRlbnNlKCB1bm1hdGNoZWQsIG1hcCwgZmlsdGVyLCBjb250ZXh0LCB4bWwgKSB7XG5cdHZhciBlbGVtLFxuXHRcdG5ld1VubWF0Y2hlZCA9IFtdLFxuXHRcdGkgPSAwLFxuXHRcdGxlbiA9IHVubWF0Y2hlZC5sZW5ndGgsXG5cdFx0bWFwcGVkID0gbWFwICE9IG51bGw7XG5cblx0Zm9yICggOyBpIDwgbGVuOyBpKysgKSB7XG5cdFx0aWYgKCAoZWxlbSA9IHVubWF0Y2hlZFtpXSkgKSB7XG5cdFx0XHRpZiAoICFmaWx0ZXIgfHwgZmlsdGVyKCBlbGVtLCBjb250ZXh0LCB4bWwgKSApIHtcblx0XHRcdFx0bmV3VW5tYXRjaGVkLnB1c2goIGVsZW0gKTtcblx0XHRcdFx0aWYgKCBtYXBwZWQgKSB7XG5cdFx0XHRcdFx0bWFwLnB1c2goIGkgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdHJldHVybiBuZXdVbm1hdGNoZWQ7XG59XG5cbmZ1bmN0aW9uIHNldE1hdGNoZXIoIHByZUZpbHRlciwgc2VsZWN0b3IsIG1hdGNoZXIsIHBvc3RGaWx0ZXIsIHBvc3RGaW5kZXIsIHBvc3RTZWxlY3RvciApIHtcblx0aWYgKCBwb3N0RmlsdGVyICYmICFwb3N0RmlsdGVyWyBleHBhbmRvIF0gKSB7XG5cdFx0cG9zdEZpbHRlciA9IHNldE1hdGNoZXIoIHBvc3RGaWx0ZXIgKTtcblx0fVxuXHRpZiAoIHBvc3RGaW5kZXIgJiYgIXBvc3RGaW5kZXJbIGV4cGFuZG8gXSApIHtcblx0XHRwb3N0RmluZGVyID0gc2V0TWF0Y2hlciggcG9zdEZpbmRlciwgcG9zdFNlbGVjdG9yICk7XG5cdH1cblx0cmV0dXJuIG1hcmtGdW5jdGlvbihmdW5jdGlvbiggc2VlZCwgcmVzdWx0cywgY29udGV4dCwgeG1sICkge1xuXHRcdHZhciB0ZW1wLCBpLCBlbGVtLFxuXHRcdFx0cHJlTWFwID0gW10sXG5cdFx0XHRwb3N0TWFwID0gW10sXG5cdFx0XHRwcmVleGlzdGluZyA9IHJlc3VsdHMubGVuZ3RoLFxuXG5cdFx0XHQvLyBHZXQgaW5pdGlhbCBlbGVtZW50cyBmcm9tIHNlZWQgb3IgY29udGV4dFxuXHRcdFx0ZWxlbXMgPSBzZWVkIHx8IG11bHRpcGxlQ29udGV4dHMoIHNlbGVjdG9yIHx8IFwiKlwiLCBjb250ZXh0Lm5vZGVUeXBlID8gWyBjb250ZXh0IF0gOiBjb250ZXh0LCBbXSApLFxuXG5cdFx0XHQvLyBQcmVmaWx0ZXIgdG8gZ2V0IG1hdGNoZXIgaW5wdXQsIHByZXNlcnZpbmcgYSBtYXAgZm9yIHNlZWQtcmVzdWx0cyBzeW5jaHJvbml6YXRpb25cblx0XHRcdG1hdGNoZXJJbiA9IHByZUZpbHRlciAmJiAoIHNlZWQgfHwgIXNlbGVjdG9yICkgP1xuXHRcdFx0XHRjb25kZW5zZSggZWxlbXMsIHByZU1hcCwgcHJlRmlsdGVyLCBjb250ZXh0LCB4bWwgKSA6XG5cdFx0XHRcdGVsZW1zLFxuXG5cdFx0XHRtYXRjaGVyT3V0ID0gbWF0Y2hlciA/XG5cdFx0XHRcdC8vIElmIHdlIGhhdmUgYSBwb3N0RmluZGVyLCBvciBmaWx0ZXJlZCBzZWVkLCBvciBub24tc2VlZCBwb3N0RmlsdGVyIG9yIHByZWV4aXN0aW5nIHJlc3VsdHMsXG5cdFx0XHRcdHBvc3RGaW5kZXIgfHwgKCBzZWVkID8gcHJlRmlsdGVyIDogcHJlZXhpc3RpbmcgfHwgcG9zdEZpbHRlciApID9cblxuXHRcdFx0XHRcdC8vIC4uLmludGVybWVkaWF0ZSBwcm9jZXNzaW5nIGlzIG5lY2Vzc2FyeVxuXHRcdFx0XHRcdFtdIDpcblxuXHRcdFx0XHRcdC8vIC4uLm90aGVyd2lzZSB1c2UgcmVzdWx0cyBkaXJlY3RseVxuXHRcdFx0XHRcdHJlc3VsdHMgOlxuXHRcdFx0XHRtYXRjaGVySW47XG5cblx0XHQvLyBGaW5kIHByaW1hcnkgbWF0Y2hlc1xuXHRcdGlmICggbWF0Y2hlciApIHtcblx0XHRcdG1hdGNoZXIoIG1hdGNoZXJJbiwgbWF0Y2hlck91dCwgY29udGV4dCwgeG1sICk7XG5cdFx0fVxuXG5cdFx0Ly8gQXBwbHkgcG9zdEZpbHRlclxuXHRcdGlmICggcG9zdEZpbHRlciApIHtcblx0XHRcdHRlbXAgPSBjb25kZW5zZSggbWF0Y2hlck91dCwgcG9zdE1hcCApO1xuXHRcdFx0cG9zdEZpbHRlciggdGVtcCwgW10sIGNvbnRleHQsIHhtbCApO1xuXG5cdFx0XHQvLyBVbi1tYXRjaCBmYWlsaW5nIGVsZW1lbnRzIGJ5IG1vdmluZyB0aGVtIGJhY2sgdG8gbWF0Y2hlckluXG5cdFx0XHRpID0gdGVtcC5sZW5ndGg7XG5cdFx0XHR3aGlsZSAoIGktLSApIHtcblx0XHRcdFx0aWYgKCAoZWxlbSA9IHRlbXBbaV0pICkge1xuXHRcdFx0XHRcdG1hdGNoZXJPdXRbIHBvc3RNYXBbaV0gXSA9ICEobWF0Y2hlckluWyBwb3N0TWFwW2ldIF0gPSBlbGVtKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGlmICggc2VlZCApIHtcblx0XHRcdGlmICggcG9zdEZpbmRlciB8fCBwcmVGaWx0ZXIgKSB7XG5cdFx0XHRcdGlmICggcG9zdEZpbmRlciApIHtcblx0XHRcdFx0XHQvLyBHZXQgdGhlIGZpbmFsIG1hdGNoZXJPdXQgYnkgY29uZGVuc2luZyB0aGlzIGludGVybWVkaWF0ZSBpbnRvIHBvc3RGaW5kZXIgY29udGV4dHNcblx0XHRcdFx0XHR0ZW1wID0gW107XG5cdFx0XHRcdFx0aSA9IG1hdGNoZXJPdXQubGVuZ3RoO1xuXHRcdFx0XHRcdHdoaWxlICggaS0tICkge1xuXHRcdFx0XHRcdFx0aWYgKCAoZWxlbSA9IG1hdGNoZXJPdXRbaV0pICkge1xuXHRcdFx0XHRcdFx0XHQvLyBSZXN0b3JlIG1hdGNoZXJJbiBzaW5jZSBlbGVtIGlzIG5vdCB5ZXQgYSBmaW5hbCBtYXRjaFxuXHRcdFx0XHRcdFx0XHR0ZW1wLnB1c2goIChtYXRjaGVySW5baV0gPSBlbGVtKSApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRwb3N0RmluZGVyKCBudWxsLCAobWF0Y2hlck91dCA9IFtdKSwgdGVtcCwgeG1sICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBNb3ZlIG1hdGNoZWQgZWxlbWVudHMgZnJvbSBzZWVkIHRvIHJlc3VsdHMgdG8ga2VlcCB0aGVtIHN5bmNocm9uaXplZFxuXHRcdFx0XHRpID0gbWF0Y2hlck91dC5sZW5ndGg7XG5cdFx0XHRcdHdoaWxlICggaS0tICkge1xuXHRcdFx0XHRcdGlmICggKGVsZW0gPSBtYXRjaGVyT3V0W2ldKSAmJlxuXHRcdFx0XHRcdFx0KHRlbXAgPSBwb3N0RmluZGVyID8gaW5kZXhPZiggc2VlZCwgZWxlbSApIDogcHJlTWFwW2ldKSA+IC0xICkge1xuXG5cdFx0XHRcdFx0XHRzZWVkW3RlbXBdID0gIShyZXN1bHRzW3RlbXBdID0gZWxlbSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHQvLyBBZGQgZWxlbWVudHMgdG8gcmVzdWx0cywgdGhyb3VnaCBwb3N0RmluZGVyIGlmIGRlZmluZWRcblx0XHR9IGVsc2Uge1xuXHRcdFx0bWF0Y2hlck91dCA9IGNvbmRlbnNlKFxuXHRcdFx0XHRtYXRjaGVyT3V0ID09PSByZXN1bHRzID9cblx0XHRcdFx0XHRtYXRjaGVyT3V0LnNwbGljZSggcHJlZXhpc3RpbmcsIG1hdGNoZXJPdXQubGVuZ3RoICkgOlxuXHRcdFx0XHRcdG1hdGNoZXJPdXRcblx0XHRcdCk7XG5cdFx0XHRpZiAoIHBvc3RGaW5kZXIgKSB7XG5cdFx0XHRcdHBvc3RGaW5kZXIoIG51bGwsIHJlc3VsdHMsIG1hdGNoZXJPdXQsIHhtbCApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0cHVzaC5hcHBseSggcmVzdWx0cywgbWF0Y2hlck91dCApO1xuXHRcdFx0fVxuXHRcdH1cblx0fSk7XG59XG5cbmZ1bmN0aW9uIG1hdGNoZXJGcm9tVG9rZW5zKCB0b2tlbnMgKSB7XG5cdHZhciBjaGVja0NvbnRleHQsIG1hdGNoZXIsIGosXG5cdFx0bGVuID0gdG9rZW5zLmxlbmd0aCxcblx0XHRsZWFkaW5nUmVsYXRpdmUgPSBFeHByLnJlbGF0aXZlWyB0b2tlbnNbMF0udHlwZSBdLFxuXHRcdGltcGxpY2l0UmVsYXRpdmUgPSBsZWFkaW5nUmVsYXRpdmUgfHwgRXhwci5yZWxhdGl2ZVtcIiBcIl0sXG5cdFx0aSA9IGxlYWRpbmdSZWxhdGl2ZSA/IDEgOiAwLFxuXG5cdFx0Ly8gVGhlIGZvdW5kYXRpb25hbCBtYXRjaGVyIGVuc3VyZXMgdGhhdCBlbGVtZW50cyBhcmUgcmVhY2hhYmxlIGZyb20gdG9wLWxldmVsIGNvbnRleHQocylcblx0XHRtYXRjaENvbnRleHQgPSBhZGRDb21iaW5hdG9yKCBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdHJldHVybiBlbGVtID09PSBjaGVja0NvbnRleHQ7XG5cdFx0fSwgaW1wbGljaXRSZWxhdGl2ZSwgdHJ1ZSApLFxuXHRcdG1hdGNoQW55Q29udGV4dCA9IGFkZENvbWJpbmF0b3IoIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0cmV0dXJuIGluZGV4T2YoIGNoZWNrQ29udGV4dCwgZWxlbSApID4gLTE7XG5cdFx0fSwgaW1wbGljaXRSZWxhdGl2ZSwgdHJ1ZSApLFxuXHRcdG1hdGNoZXJzID0gWyBmdW5jdGlvbiggZWxlbSwgY29udGV4dCwgeG1sICkge1xuXHRcdFx0dmFyIHJldCA9ICggIWxlYWRpbmdSZWxhdGl2ZSAmJiAoIHhtbCB8fCBjb250ZXh0ICE9PSBvdXRlcm1vc3RDb250ZXh0ICkgKSB8fCAoXG5cdFx0XHRcdChjaGVja0NvbnRleHQgPSBjb250ZXh0KS5ub2RlVHlwZSA/XG5cdFx0XHRcdFx0bWF0Y2hDb250ZXh0KCBlbGVtLCBjb250ZXh0LCB4bWwgKSA6XG5cdFx0XHRcdFx0bWF0Y2hBbnlDb250ZXh0KCBlbGVtLCBjb250ZXh0LCB4bWwgKSApO1xuXHRcdFx0Ly8gQXZvaWQgaGFuZ2luZyBvbnRvIGVsZW1lbnQgKGlzc3VlICMyOTkpXG5cdFx0XHRjaGVja0NvbnRleHQgPSBudWxsO1xuXHRcdFx0cmV0dXJuIHJldDtcblx0XHR9IF07XG5cblx0Zm9yICggOyBpIDwgbGVuOyBpKysgKSB7XG5cdFx0aWYgKCAobWF0Y2hlciA9IEV4cHIucmVsYXRpdmVbIHRva2Vuc1tpXS50eXBlIF0pICkge1xuXHRcdFx0bWF0Y2hlcnMgPSBbIGFkZENvbWJpbmF0b3IoZWxlbWVudE1hdGNoZXIoIG1hdGNoZXJzICksIG1hdGNoZXIpIF07XG5cdFx0fSBlbHNlIHtcblx0XHRcdG1hdGNoZXIgPSBFeHByLmZpbHRlclsgdG9rZW5zW2ldLnR5cGUgXS5hcHBseSggbnVsbCwgdG9rZW5zW2ldLm1hdGNoZXMgKTtcblxuXHRcdFx0Ly8gUmV0dXJuIHNwZWNpYWwgdXBvbiBzZWVpbmcgYSBwb3NpdGlvbmFsIG1hdGNoZXJcblx0XHRcdGlmICggbWF0Y2hlclsgZXhwYW5kbyBdICkge1xuXHRcdFx0XHQvLyBGaW5kIHRoZSBuZXh0IHJlbGF0aXZlIG9wZXJhdG9yIChpZiBhbnkpIGZvciBwcm9wZXIgaGFuZGxpbmdcblx0XHRcdFx0aiA9ICsraTtcblx0XHRcdFx0Zm9yICggOyBqIDwgbGVuOyBqKysgKSB7XG5cdFx0XHRcdFx0aWYgKCBFeHByLnJlbGF0aXZlWyB0b2tlbnNbal0udHlwZSBdICkge1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiBzZXRNYXRjaGVyKFxuXHRcdFx0XHRcdGkgPiAxICYmIGVsZW1lbnRNYXRjaGVyKCBtYXRjaGVycyApLFxuXHRcdFx0XHRcdGkgPiAxICYmIHRvU2VsZWN0b3IoXG5cdFx0XHRcdFx0XHQvLyBJZiB0aGUgcHJlY2VkaW5nIHRva2VuIHdhcyBhIGRlc2NlbmRhbnQgY29tYmluYXRvciwgaW5zZXJ0IGFuIGltcGxpY2l0IGFueS1lbGVtZW50IGAqYFxuXHRcdFx0XHRcdFx0dG9rZW5zLnNsaWNlKCAwLCBpIC0gMSApLmNvbmNhdCh7IHZhbHVlOiB0b2tlbnNbIGkgLSAyIF0udHlwZSA9PT0gXCIgXCIgPyBcIipcIiA6IFwiXCIgfSlcblx0XHRcdFx0XHQpLnJlcGxhY2UoIHJ0cmltLCBcIiQxXCIgKSxcblx0XHRcdFx0XHRtYXRjaGVyLFxuXHRcdFx0XHRcdGkgPCBqICYmIG1hdGNoZXJGcm9tVG9rZW5zKCB0b2tlbnMuc2xpY2UoIGksIGogKSApLFxuXHRcdFx0XHRcdGogPCBsZW4gJiYgbWF0Y2hlckZyb21Ub2tlbnMoICh0b2tlbnMgPSB0b2tlbnMuc2xpY2UoIGogKSkgKSxcblx0XHRcdFx0XHRqIDwgbGVuICYmIHRvU2VsZWN0b3IoIHRva2VucyApXG5cdFx0XHRcdCk7XG5cdFx0XHR9XG5cdFx0XHRtYXRjaGVycy5wdXNoKCBtYXRjaGVyICk7XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIGVsZW1lbnRNYXRjaGVyKCBtYXRjaGVycyApO1xufVxuXG5mdW5jdGlvbiBtYXRjaGVyRnJvbUdyb3VwTWF0Y2hlcnMoIGVsZW1lbnRNYXRjaGVycywgc2V0TWF0Y2hlcnMgKSB7XG5cdHZhciBieVNldCA9IHNldE1hdGNoZXJzLmxlbmd0aCA+IDAsXG5cdFx0YnlFbGVtZW50ID0gZWxlbWVudE1hdGNoZXJzLmxlbmd0aCA+IDAsXG5cdFx0c3VwZXJNYXRjaGVyID0gZnVuY3Rpb24oIHNlZWQsIGNvbnRleHQsIHhtbCwgcmVzdWx0cywgb3V0ZXJtb3N0ICkge1xuXHRcdFx0dmFyIGVsZW0sIGosIG1hdGNoZXIsXG5cdFx0XHRcdG1hdGNoZWRDb3VudCA9IDAsXG5cdFx0XHRcdGkgPSBcIjBcIixcblx0XHRcdFx0dW5tYXRjaGVkID0gc2VlZCAmJiBbXSxcblx0XHRcdFx0c2V0TWF0Y2hlZCA9IFtdLFxuXHRcdFx0XHRjb250ZXh0QmFja3VwID0gb3V0ZXJtb3N0Q29udGV4dCxcblx0XHRcdFx0Ly8gV2UgbXVzdCBhbHdheXMgaGF2ZSBlaXRoZXIgc2VlZCBlbGVtZW50cyBvciBvdXRlcm1vc3QgY29udGV4dFxuXHRcdFx0XHRlbGVtcyA9IHNlZWQgfHwgYnlFbGVtZW50ICYmIEV4cHIuZmluZFtcIlRBR1wiXSggXCIqXCIsIG91dGVybW9zdCApLFxuXHRcdFx0XHQvLyBVc2UgaW50ZWdlciBkaXJydW5zIGlmZiB0aGlzIGlzIHRoZSBvdXRlcm1vc3QgbWF0Y2hlclxuXHRcdFx0XHRkaXJydW5zVW5pcXVlID0gKGRpcnJ1bnMgKz0gY29udGV4dEJhY2t1cCA9PSBudWxsID8gMSA6IE1hdGgucmFuZG9tKCkgfHwgMC4xKSxcblx0XHRcdFx0bGVuID0gZWxlbXMubGVuZ3RoO1xuXG5cdFx0XHRpZiAoIG91dGVybW9zdCApIHtcblx0XHRcdFx0b3V0ZXJtb3N0Q29udGV4dCA9IGNvbnRleHQgIT09IGRvY3VtZW50ICYmIGNvbnRleHQ7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEFkZCBlbGVtZW50cyBwYXNzaW5nIGVsZW1lbnRNYXRjaGVycyBkaXJlY3RseSB0byByZXN1bHRzXG5cdFx0XHQvLyBLZWVwIGBpYCBhIHN0cmluZyBpZiB0aGVyZSBhcmUgbm8gZWxlbWVudHMgc28gYG1hdGNoZWRDb3VudGAgd2lsbCBiZSBcIjAwXCIgYmVsb3dcblx0XHRcdC8vIFN1cHBvcnQ6IElFPDksIFNhZmFyaVxuXHRcdFx0Ly8gVG9sZXJhdGUgTm9kZUxpc3QgcHJvcGVydGllcyAoSUU6IFwibGVuZ3RoXCI7IFNhZmFyaTogPG51bWJlcj4pIG1hdGNoaW5nIGVsZW1lbnRzIGJ5IGlkXG5cdFx0XHRmb3IgKCA7IGkgIT09IGxlbiAmJiAoZWxlbSA9IGVsZW1zW2ldKSAhPSBudWxsOyBpKysgKSB7XG5cdFx0XHRcdGlmICggYnlFbGVtZW50ICYmIGVsZW0gKSB7XG5cdFx0XHRcdFx0aiA9IDA7XG5cdFx0XHRcdFx0d2hpbGUgKCAobWF0Y2hlciA9IGVsZW1lbnRNYXRjaGVyc1tqKytdKSApIHtcblx0XHRcdFx0XHRcdGlmICggbWF0Y2hlciggZWxlbSwgY29udGV4dCwgeG1sICkgKSB7XG5cdFx0XHRcdFx0XHRcdHJlc3VsdHMucHVzaCggZWxlbSApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aWYgKCBvdXRlcm1vc3QgKSB7XG5cdFx0XHRcdFx0XHRkaXJydW5zID0gZGlycnVuc1VuaXF1ZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBUcmFjayB1bm1hdGNoZWQgZWxlbWVudHMgZm9yIHNldCBmaWx0ZXJzXG5cdFx0XHRcdGlmICggYnlTZXQgKSB7XG5cdFx0XHRcdFx0Ly8gVGhleSB3aWxsIGhhdmUgZ29uZSB0aHJvdWdoIGFsbCBwb3NzaWJsZSBtYXRjaGVyc1xuXHRcdFx0XHRcdGlmICggKGVsZW0gPSAhbWF0Y2hlciAmJiBlbGVtKSApIHtcblx0XHRcdFx0XHRcdG1hdGNoZWRDb3VudC0tO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIExlbmd0aGVuIHRoZSBhcnJheSBmb3IgZXZlcnkgZWxlbWVudCwgbWF0Y2hlZCBvciBub3Rcblx0XHRcdFx0XHRpZiAoIHNlZWQgKSB7XG5cdFx0XHRcdFx0XHR1bm1hdGNoZWQucHVzaCggZWxlbSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHQvLyBBcHBseSBzZXQgZmlsdGVycyB0byB1bm1hdGNoZWQgZWxlbWVudHNcblx0XHRcdG1hdGNoZWRDb3VudCArPSBpO1xuXHRcdFx0aWYgKCBieVNldCAmJiBpICE9PSBtYXRjaGVkQ291bnQgKSB7XG5cdFx0XHRcdGogPSAwO1xuXHRcdFx0XHR3aGlsZSAoIChtYXRjaGVyID0gc2V0TWF0Y2hlcnNbaisrXSkgKSB7XG5cdFx0XHRcdFx0bWF0Y2hlciggdW5tYXRjaGVkLCBzZXRNYXRjaGVkLCBjb250ZXh0LCB4bWwgKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggc2VlZCApIHtcblx0XHRcdFx0XHQvLyBSZWludGVncmF0ZSBlbGVtZW50IG1hdGNoZXMgdG8gZWxpbWluYXRlIHRoZSBuZWVkIGZvciBzb3J0aW5nXG5cdFx0XHRcdFx0aWYgKCBtYXRjaGVkQ291bnQgPiAwICkge1xuXHRcdFx0XHRcdFx0d2hpbGUgKCBpLS0gKSB7XG5cdFx0XHRcdFx0XHRcdGlmICggISh1bm1hdGNoZWRbaV0gfHwgc2V0TWF0Y2hlZFtpXSkgKSB7XG5cdFx0XHRcdFx0XHRcdFx0c2V0TWF0Y2hlZFtpXSA9IHBvcC5jYWxsKCByZXN1bHRzICk7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvLyBEaXNjYXJkIGluZGV4IHBsYWNlaG9sZGVyIHZhbHVlcyB0byBnZXQgb25seSBhY3R1YWwgbWF0Y2hlc1xuXHRcdFx0XHRcdHNldE1hdGNoZWQgPSBjb25kZW5zZSggc2V0TWF0Y2hlZCApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gQWRkIG1hdGNoZXMgdG8gcmVzdWx0c1xuXHRcdFx0XHRwdXNoLmFwcGx5KCByZXN1bHRzLCBzZXRNYXRjaGVkICk7XG5cblx0XHRcdFx0Ly8gU2VlZGxlc3Mgc2V0IG1hdGNoZXMgc3VjY2VlZGluZyBtdWx0aXBsZSBzdWNjZXNzZnVsIG1hdGNoZXJzIHN0aXB1bGF0ZSBzb3J0aW5nXG5cdFx0XHRcdGlmICggb3V0ZXJtb3N0ICYmICFzZWVkICYmIHNldE1hdGNoZWQubGVuZ3RoID4gMCAmJlxuXHRcdFx0XHRcdCggbWF0Y2hlZENvdW50ICsgc2V0TWF0Y2hlcnMubGVuZ3RoICkgPiAxICkge1xuXG5cdFx0XHRcdFx0U2l6emxlLnVuaXF1ZVNvcnQoIHJlc3VsdHMgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHQvLyBPdmVycmlkZSBtYW5pcHVsYXRpb24gb2YgZ2xvYmFscyBieSBuZXN0ZWQgbWF0Y2hlcnNcblx0XHRcdGlmICggb3V0ZXJtb3N0ICkge1xuXHRcdFx0XHRkaXJydW5zID0gZGlycnVuc1VuaXF1ZTtcblx0XHRcdFx0b3V0ZXJtb3N0Q29udGV4dCA9IGNvbnRleHRCYWNrdXA7XG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiB1bm1hdGNoZWQ7XG5cdFx0fTtcblxuXHRyZXR1cm4gYnlTZXQgP1xuXHRcdG1hcmtGdW5jdGlvbiggc3VwZXJNYXRjaGVyICkgOlxuXHRcdHN1cGVyTWF0Y2hlcjtcbn1cblxuY29tcGlsZSA9IFNpenpsZS5jb21waWxlID0gZnVuY3Rpb24oIHNlbGVjdG9yLCBtYXRjaCAvKiBJbnRlcm5hbCBVc2UgT25seSAqLyApIHtcblx0dmFyIGksXG5cdFx0c2V0TWF0Y2hlcnMgPSBbXSxcblx0XHRlbGVtZW50TWF0Y2hlcnMgPSBbXSxcblx0XHRjYWNoZWQgPSBjb21waWxlckNhY2hlWyBzZWxlY3RvciArIFwiIFwiIF07XG5cblx0aWYgKCAhY2FjaGVkICkge1xuXHRcdC8vIEdlbmVyYXRlIGEgZnVuY3Rpb24gb2YgcmVjdXJzaXZlIGZ1bmN0aW9ucyB0aGF0IGNhbiBiZSB1c2VkIHRvIGNoZWNrIGVhY2ggZWxlbWVudFxuXHRcdGlmICggIW1hdGNoICkge1xuXHRcdFx0bWF0Y2ggPSB0b2tlbml6ZSggc2VsZWN0b3IgKTtcblx0XHR9XG5cdFx0aSA9IG1hdGNoLmxlbmd0aDtcblx0XHR3aGlsZSAoIGktLSApIHtcblx0XHRcdGNhY2hlZCA9IG1hdGNoZXJGcm9tVG9rZW5zKCBtYXRjaFtpXSApO1xuXHRcdFx0aWYgKCBjYWNoZWRbIGV4cGFuZG8gXSApIHtcblx0XHRcdFx0c2V0TWF0Y2hlcnMucHVzaCggY2FjaGVkICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRlbGVtZW50TWF0Y2hlcnMucHVzaCggY2FjaGVkICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gQ2FjaGUgdGhlIGNvbXBpbGVkIGZ1bmN0aW9uXG5cdFx0Y2FjaGVkID0gY29tcGlsZXJDYWNoZSggc2VsZWN0b3IsIG1hdGNoZXJGcm9tR3JvdXBNYXRjaGVycyggZWxlbWVudE1hdGNoZXJzLCBzZXRNYXRjaGVycyApICk7XG5cblx0XHQvLyBTYXZlIHNlbGVjdG9yIGFuZCB0b2tlbml6YXRpb25cblx0XHRjYWNoZWQuc2VsZWN0b3IgPSBzZWxlY3Rvcjtcblx0fVxuXHRyZXR1cm4gY2FjaGVkO1xufTtcblxuLyoqXG4gKiBBIGxvdy1sZXZlbCBzZWxlY3Rpb24gZnVuY3Rpb24gdGhhdCB3b3JrcyB3aXRoIFNpenpsZSdzIGNvbXBpbGVkXG4gKiAgc2VsZWN0b3IgZnVuY3Rpb25zXG4gKiBAcGFyYW0ge1N0cmluZ3xGdW5jdGlvbn0gc2VsZWN0b3IgQSBzZWxlY3RvciBvciBhIHByZS1jb21waWxlZFxuICogIHNlbGVjdG9yIGZ1bmN0aW9uIGJ1aWx0IHdpdGggU2l6emxlLmNvbXBpbGVcbiAqIEBwYXJhbSB7RWxlbWVudH0gY29udGV4dFxuICogQHBhcmFtIHtBcnJheX0gW3Jlc3VsdHNdXG4gKiBAcGFyYW0ge0FycmF5fSBbc2VlZF0gQSBzZXQgb2YgZWxlbWVudHMgdG8gbWF0Y2ggYWdhaW5zdFxuICovXG5zZWxlY3QgPSBTaXp6bGUuc2VsZWN0ID0gZnVuY3Rpb24oIHNlbGVjdG9yLCBjb250ZXh0LCByZXN1bHRzLCBzZWVkICkge1xuXHR2YXIgaSwgdG9rZW5zLCB0b2tlbiwgdHlwZSwgZmluZCxcblx0XHRjb21waWxlZCA9IHR5cGVvZiBzZWxlY3RvciA9PT0gXCJmdW5jdGlvblwiICYmIHNlbGVjdG9yLFxuXHRcdG1hdGNoID0gIXNlZWQgJiYgdG9rZW5pemUoIChzZWxlY3RvciA9IGNvbXBpbGVkLnNlbGVjdG9yIHx8IHNlbGVjdG9yKSApO1xuXG5cdHJlc3VsdHMgPSByZXN1bHRzIHx8IFtdO1xuXG5cdC8vIFRyeSB0byBtaW5pbWl6ZSBvcGVyYXRpb25zIGlmIHRoZXJlIGlzIG5vIHNlZWQgYW5kIG9ubHkgb25lIGdyb3VwXG5cdGlmICggbWF0Y2gubGVuZ3RoID09PSAxICkge1xuXG5cdFx0Ly8gVGFrZSBhIHNob3J0Y3V0IGFuZCBzZXQgdGhlIGNvbnRleHQgaWYgdGhlIHJvb3Qgc2VsZWN0b3IgaXMgYW4gSURcblx0XHR0b2tlbnMgPSBtYXRjaFswXSA9IG1hdGNoWzBdLnNsaWNlKCAwICk7XG5cdFx0aWYgKCB0b2tlbnMubGVuZ3RoID4gMiAmJiAodG9rZW4gPSB0b2tlbnNbMF0pLnR5cGUgPT09IFwiSURcIiAmJlxuXHRcdFx0XHRzdXBwb3J0LmdldEJ5SWQgJiYgY29udGV4dC5ub2RlVHlwZSA9PT0gOSAmJiBkb2N1bWVudElzSFRNTCAmJlxuXHRcdFx0XHRFeHByLnJlbGF0aXZlWyB0b2tlbnNbMV0udHlwZSBdICkge1xuXG5cdFx0XHRjb250ZXh0ID0gKCBFeHByLmZpbmRbXCJJRFwiXSggdG9rZW4ubWF0Y2hlc1swXS5yZXBsYWNlKHJ1bmVzY2FwZSwgZnVuZXNjYXBlKSwgY29udGV4dCApIHx8IFtdIClbMF07XG5cdFx0XHRpZiAoICFjb250ZXh0ICkge1xuXHRcdFx0XHRyZXR1cm4gcmVzdWx0cztcblxuXHRcdFx0Ly8gUHJlY29tcGlsZWQgbWF0Y2hlcnMgd2lsbCBzdGlsbCB2ZXJpZnkgYW5jZXN0cnksIHNvIHN0ZXAgdXAgYSBsZXZlbFxuXHRcdFx0fSBlbHNlIGlmICggY29tcGlsZWQgKSB7XG5cdFx0XHRcdGNvbnRleHQgPSBjb250ZXh0LnBhcmVudE5vZGU7XG5cdFx0XHR9XG5cblx0XHRcdHNlbGVjdG9yID0gc2VsZWN0b3Iuc2xpY2UoIHRva2Vucy5zaGlmdCgpLnZhbHVlLmxlbmd0aCApO1xuXHRcdH1cblxuXHRcdC8vIEZldGNoIGEgc2VlZCBzZXQgZm9yIHJpZ2h0LXRvLWxlZnQgbWF0Y2hpbmdcblx0XHRpID0gbWF0Y2hFeHByW1wibmVlZHNDb250ZXh0XCJdLnRlc3QoIHNlbGVjdG9yICkgPyAwIDogdG9rZW5zLmxlbmd0aDtcblx0XHR3aGlsZSAoIGktLSApIHtcblx0XHRcdHRva2VuID0gdG9rZW5zW2ldO1xuXG5cdFx0XHQvLyBBYm9ydCBpZiB3ZSBoaXQgYSBjb21iaW5hdG9yXG5cdFx0XHRpZiAoIEV4cHIucmVsYXRpdmVbICh0eXBlID0gdG9rZW4udHlwZSkgXSApIHtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIChmaW5kID0gRXhwci5maW5kWyB0eXBlIF0pICkge1xuXHRcdFx0XHQvLyBTZWFyY2gsIGV4cGFuZGluZyBjb250ZXh0IGZvciBsZWFkaW5nIHNpYmxpbmcgY29tYmluYXRvcnNcblx0XHRcdFx0aWYgKCAoc2VlZCA9IGZpbmQoXG5cdFx0XHRcdFx0dG9rZW4ubWF0Y2hlc1swXS5yZXBsYWNlKCBydW5lc2NhcGUsIGZ1bmVzY2FwZSApLFxuXHRcdFx0XHRcdHJzaWJsaW5nLnRlc3QoIHRva2Vuc1swXS50eXBlICkgJiYgdGVzdENvbnRleHQoIGNvbnRleHQucGFyZW50Tm9kZSApIHx8IGNvbnRleHRcblx0XHRcdFx0KSkgKSB7XG5cblx0XHRcdFx0XHQvLyBJZiBzZWVkIGlzIGVtcHR5IG9yIG5vIHRva2VucyByZW1haW4sIHdlIGNhbiByZXR1cm4gZWFybHlcblx0XHRcdFx0XHR0b2tlbnMuc3BsaWNlKCBpLCAxICk7XG5cdFx0XHRcdFx0c2VsZWN0b3IgPSBzZWVkLmxlbmd0aCAmJiB0b1NlbGVjdG9yKCB0b2tlbnMgKTtcblx0XHRcdFx0XHRpZiAoICFzZWxlY3RvciApIHtcblx0XHRcdFx0XHRcdHB1c2guYXBwbHkoIHJlc3VsdHMsIHNlZWQgKTtcblx0XHRcdFx0XHRcdHJldHVybiByZXN1bHRzO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0Ly8gQ29tcGlsZSBhbmQgZXhlY3V0ZSBhIGZpbHRlcmluZyBmdW5jdGlvbiBpZiBvbmUgaXMgbm90IHByb3ZpZGVkXG5cdC8vIFByb3ZpZGUgYG1hdGNoYCB0byBhdm9pZCByZXRva2VuaXphdGlvbiBpZiB3ZSBtb2RpZmllZCB0aGUgc2VsZWN0b3IgYWJvdmVcblx0KCBjb21waWxlZCB8fCBjb21waWxlKCBzZWxlY3RvciwgbWF0Y2ggKSApKFxuXHRcdHNlZWQsXG5cdFx0Y29udGV4dCxcblx0XHQhZG9jdW1lbnRJc0hUTUwsXG5cdFx0cmVzdWx0cyxcblx0XHRyc2libGluZy50ZXN0KCBzZWxlY3RvciApICYmIHRlc3RDb250ZXh0KCBjb250ZXh0LnBhcmVudE5vZGUgKSB8fCBjb250ZXh0XG5cdCk7XG5cdHJldHVybiByZXN1bHRzO1xufTtcblxuLy8gT25lLXRpbWUgYXNzaWdubWVudHNcblxuLy8gU29ydCBzdGFiaWxpdHlcbnN1cHBvcnQuc29ydFN0YWJsZSA9IGV4cGFuZG8uc3BsaXQoXCJcIikuc29ydCggc29ydE9yZGVyICkuam9pbihcIlwiKSA9PT0gZXhwYW5kbztcblxuLy8gU3VwcG9ydDogQ2hyb21lIDE0LTM1K1xuLy8gQWx3YXlzIGFzc3VtZSBkdXBsaWNhdGVzIGlmIHRoZXkgYXJlbid0IHBhc3NlZCB0byB0aGUgY29tcGFyaXNvbiBmdW5jdGlvblxuc3VwcG9ydC5kZXRlY3REdXBsaWNhdGVzID0gISFoYXNEdXBsaWNhdGU7XG5cbi8vIEluaXRpYWxpemUgYWdhaW5zdCB0aGUgZGVmYXVsdCBkb2N1bWVudFxuc2V0RG9jdW1lbnQoKTtcblxuLy8gU3VwcG9ydDogV2Via2l0PDUzNy4zMiAtIFNhZmFyaSA2LjAuMy9DaHJvbWUgMjUgKGZpeGVkIGluIENocm9tZSAyNylcbi8vIERldGFjaGVkIG5vZGVzIGNvbmZvdW5kaW5nbHkgZm9sbG93ICplYWNoIG90aGVyKlxuc3VwcG9ydC5zb3J0RGV0YWNoZWQgPSBhc3NlcnQoZnVuY3Rpb24oIGRpdjEgKSB7XG5cdC8vIFNob3VsZCByZXR1cm4gMSwgYnV0IHJldHVybnMgNCAoZm9sbG93aW5nKVxuXHRyZXR1cm4gZGl2MS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbiggZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImRpdlwiKSApICYgMTtcbn0pO1xuXG4vLyBTdXBwb3J0OiBJRTw4XG4vLyBQcmV2ZW50IGF0dHJpYnV0ZS9wcm9wZXJ0eSBcImludGVycG9sYXRpb25cIlxuLy8gaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbS9lbi11cy9saWJyYXJ5L21zNTM2NDI5JTI4VlMuODUlMjkuYXNweFxuaWYgKCAhYXNzZXJ0KGZ1bmN0aW9uKCBkaXYgKSB7XG5cdGRpdi5pbm5lckhUTUwgPSBcIjxhIGhyZWY9JyMnPjwvYT5cIjtcblx0cmV0dXJuIGRpdi5maXJzdENoaWxkLmdldEF0dHJpYnV0ZShcImhyZWZcIikgPT09IFwiI1wiIDtcbn0pICkge1xuXHRhZGRIYW5kbGUoIFwidHlwZXxocmVmfGhlaWdodHx3aWR0aFwiLCBmdW5jdGlvbiggZWxlbSwgbmFtZSwgaXNYTUwgKSB7XG5cdFx0aWYgKCAhaXNYTUwgKSB7XG5cdFx0XHRyZXR1cm4gZWxlbS5nZXRBdHRyaWJ1dGUoIG5hbWUsIG5hbWUudG9Mb3dlckNhc2UoKSA9PT0gXCJ0eXBlXCIgPyAxIDogMiApO1xuXHRcdH1cblx0fSk7XG59XG5cbi8vIFN1cHBvcnQ6IElFPDlcbi8vIFVzZSBkZWZhdWx0VmFsdWUgaW4gcGxhY2Ugb2YgZ2V0QXR0cmlidXRlKFwidmFsdWVcIilcbmlmICggIXN1cHBvcnQuYXR0cmlidXRlcyB8fCAhYXNzZXJ0KGZ1bmN0aW9uKCBkaXYgKSB7XG5cdGRpdi5pbm5lckhUTUwgPSBcIjxpbnB1dC8+XCI7XG5cdGRpdi5maXJzdENoaWxkLnNldEF0dHJpYnV0ZSggXCJ2YWx1ZVwiLCBcIlwiICk7XG5cdHJldHVybiBkaXYuZmlyc3RDaGlsZC5nZXRBdHRyaWJ1dGUoIFwidmFsdWVcIiApID09PSBcIlwiO1xufSkgKSB7XG5cdGFkZEhhbmRsZSggXCJ2YWx1ZVwiLCBmdW5jdGlvbiggZWxlbSwgbmFtZSwgaXNYTUwgKSB7XG5cdFx0aWYgKCAhaXNYTUwgJiYgZWxlbS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpID09PSBcImlucHV0XCIgKSB7XG5cdFx0XHRyZXR1cm4gZWxlbS5kZWZhdWx0VmFsdWU7XG5cdFx0fVxuXHR9KTtcbn1cblxuLy8gU3VwcG9ydDogSUU8OVxuLy8gVXNlIGdldEF0dHJpYnV0ZU5vZGUgdG8gZmV0Y2ggYm9vbGVhbnMgd2hlbiBnZXRBdHRyaWJ1dGUgbGllc1xuaWYgKCAhYXNzZXJ0KGZ1bmN0aW9uKCBkaXYgKSB7XG5cdHJldHVybiBkaXYuZ2V0QXR0cmlidXRlKFwiZGlzYWJsZWRcIikgPT0gbnVsbDtcbn0pICkge1xuXHRhZGRIYW5kbGUoIGJvb2xlYW5zLCBmdW5jdGlvbiggZWxlbSwgbmFtZSwgaXNYTUwgKSB7XG5cdFx0dmFyIHZhbDtcblx0XHRpZiAoICFpc1hNTCApIHtcblx0XHRcdHJldHVybiBlbGVtWyBuYW1lIF0gPT09IHRydWUgPyBuYW1lLnRvTG93ZXJDYXNlKCkgOlxuXHRcdFx0XHRcdCh2YWwgPSBlbGVtLmdldEF0dHJpYnV0ZU5vZGUoIG5hbWUgKSkgJiYgdmFsLnNwZWNpZmllZCA/XG5cdFx0XHRcdFx0dmFsLnZhbHVlIDpcblx0XHRcdFx0bnVsbDtcblx0XHR9XG5cdH0pO1xufVxuXG5yZXR1cm4gU2l6emxlO1xuXG59KSggd2luZG93ICk7XG5cblxuXG5qUXVlcnkuZmluZCA9IFNpenpsZTtcbmpRdWVyeS5leHByID0gU2l6emxlLnNlbGVjdG9ycztcbmpRdWVyeS5leHByW1wiOlwiXSA9IGpRdWVyeS5leHByLnBzZXVkb3M7XG5qUXVlcnkudW5pcXVlID0gU2l6emxlLnVuaXF1ZVNvcnQ7XG5qUXVlcnkudGV4dCA9IFNpenpsZS5nZXRUZXh0O1xualF1ZXJ5LmlzWE1MRG9jID0gU2l6emxlLmlzWE1MO1xualF1ZXJ5LmNvbnRhaW5zID0gU2l6emxlLmNvbnRhaW5zO1xuXG5cblxudmFyIHJuZWVkc0NvbnRleHQgPSBqUXVlcnkuZXhwci5tYXRjaC5uZWVkc0NvbnRleHQ7XG5cbnZhciByc2luZ2xlVGFnID0gKC9ePChcXHcrKVxccypcXC8/Pig/OjxcXC9cXDE+fCkkLyk7XG5cblxuXG52YXIgcmlzU2ltcGxlID0gL14uW146I1xcW1xcLixdKiQvO1xuXG4vLyBJbXBsZW1lbnQgdGhlIGlkZW50aWNhbCBmdW5jdGlvbmFsaXR5IGZvciBmaWx0ZXIgYW5kIG5vdFxuZnVuY3Rpb24gd2lubm93KCBlbGVtZW50cywgcXVhbGlmaWVyLCBub3QgKSB7XG5cdGlmICggalF1ZXJ5LmlzRnVuY3Rpb24oIHF1YWxpZmllciApICkge1xuXHRcdHJldHVybiBqUXVlcnkuZ3JlcCggZWxlbWVudHMsIGZ1bmN0aW9uKCBlbGVtLCBpICkge1xuXHRcdFx0LyoganNoaW50IC1XMDE4ICovXG5cdFx0XHRyZXR1cm4gISFxdWFsaWZpZXIuY2FsbCggZWxlbSwgaSwgZWxlbSApICE9PSBub3Q7XG5cdFx0fSk7XG5cblx0fVxuXG5cdGlmICggcXVhbGlmaWVyLm5vZGVUeXBlICkge1xuXHRcdHJldHVybiBqUXVlcnkuZ3JlcCggZWxlbWVudHMsIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0cmV0dXJuICggZWxlbSA9PT0gcXVhbGlmaWVyICkgIT09IG5vdDtcblx0XHR9KTtcblxuXHR9XG5cblx0aWYgKCB0eXBlb2YgcXVhbGlmaWVyID09PSBcInN0cmluZ1wiICkge1xuXHRcdGlmICggcmlzU2ltcGxlLnRlc3QoIHF1YWxpZmllciApICkge1xuXHRcdFx0cmV0dXJuIGpRdWVyeS5maWx0ZXIoIHF1YWxpZmllciwgZWxlbWVudHMsIG5vdCApO1xuXHRcdH1cblxuXHRcdHF1YWxpZmllciA9IGpRdWVyeS5maWx0ZXIoIHF1YWxpZmllciwgZWxlbWVudHMgKTtcblx0fVxuXG5cdHJldHVybiBqUXVlcnkuZ3JlcCggZWxlbWVudHMsIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdHJldHVybiAoIGluZGV4T2YuY2FsbCggcXVhbGlmaWVyLCBlbGVtICkgPj0gMCApICE9PSBub3Q7XG5cdH0pO1xufVxuXG5qUXVlcnkuZmlsdGVyID0gZnVuY3Rpb24oIGV4cHIsIGVsZW1zLCBub3QgKSB7XG5cdHZhciBlbGVtID0gZWxlbXNbIDAgXTtcblxuXHRpZiAoIG5vdCApIHtcblx0XHRleHByID0gXCI6bm90KFwiICsgZXhwciArIFwiKVwiO1xuXHR9XG5cblx0cmV0dXJuIGVsZW1zLmxlbmd0aCA9PT0gMSAmJiBlbGVtLm5vZGVUeXBlID09PSAxID9cblx0XHRqUXVlcnkuZmluZC5tYXRjaGVzU2VsZWN0b3IoIGVsZW0sIGV4cHIgKSA/IFsgZWxlbSBdIDogW10gOlxuXHRcdGpRdWVyeS5maW5kLm1hdGNoZXMoIGV4cHIsIGpRdWVyeS5ncmVwKCBlbGVtcywgZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRyZXR1cm4gZWxlbS5ub2RlVHlwZSA9PT0gMTtcblx0XHR9KSk7XG59O1xuXG5qUXVlcnkuZm4uZXh0ZW5kKHtcblx0ZmluZDogZnVuY3Rpb24oIHNlbGVjdG9yICkge1xuXHRcdHZhciBpLFxuXHRcdFx0bGVuID0gdGhpcy5sZW5ndGgsXG5cdFx0XHRyZXQgPSBbXSxcblx0XHRcdHNlbGYgPSB0aGlzO1xuXG5cdFx0aWYgKCB0eXBlb2Ygc2VsZWN0b3IgIT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5wdXNoU3RhY2soIGpRdWVyeSggc2VsZWN0b3IgKS5maWx0ZXIoZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGZvciAoIGkgPSAwOyBpIDwgbGVuOyBpKysgKSB7XG5cdFx0XHRcdFx0aWYgKCBqUXVlcnkuY29udGFpbnMoIHNlbGZbIGkgXSwgdGhpcyApICkge1xuXHRcdFx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9KSApO1xuXHRcdH1cblxuXHRcdGZvciAoIGkgPSAwOyBpIDwgbGVuOyBpKysgKSB7XG5cdFx0XHRqUXVlcnkuZmluZCggc2VsZWN0b3IsIHNlbGZbIGkgXSwgcmV0ICk7XG5cdFx0fVxuXG5cdFx0Ly8gTmVlZGVkIGJlY2F1c2UgJCggc2VsZWN0b3IsIGNvbnRleHQgKSBiZWNvbWVzICQoIGNvbnRleHQgKS5maW5kKCBzZWxlY3RvciApXG5cdFx0cmV0ID0gdGhpcy5wdXNoU3RhY2soIGxlbiA+IDEgPyBqUXVlcnkudW5pcXVlKCByZXQgKSA6IHJldCApO1xuXHRcdHJldC5zZWxlY3RvciA9IHRoaXMuc2VsZWN0b3IgPyB0aGlzLnNlbGVjdG9yICsgXCIgXCIgKyBzZWxlY3RvciA6IHNlbGVjdG9yO1xuXHRcdHJldHVybiByZXQ7XG5cdH0sXG5cdGZpbHRlcjogZnVuY3Rpb24oIHNlbGVjdG9yICkge1xuXHRcdHJldHVybiB0aGlzLnB1c2hTdGFjayggd2lubm93KHRoaXMsIHNlbGVjdG9yIHx8IFtdLCBmYWxzZSkgKTtcblx0fSxcblx0bm90OiBmdW5jdGlvbiggc2VsZWN0b3IgKSB7XG5cdFx0cmV0dXJuIHRoaXMucHVzaFN0YWNrKCB3aW5ub3codGhpcywgc2VsZWN0b3IgfHwgW10sIHRydWUpICk7XG5cdH0sXG5cdGlzOiBmdW5jdGlvbiggc2VsZWN0b3IgKSB7XG5cdFx0cmV0dXJuICEhd2lubm93KFxuXHRcdFx0dGhpcyxcblxuXHRcdFx0Ly8gSWYgdGhpcyBpcyBhIHBvc2l0aW9uYWwvcmVsYXRpdmUgc2VsZWN0b3IsIGNoZWNrIG1lbWJlcnNoaXAgaW4gdGhlIHJldHVybmVkIHNldFxuXHRcdFx0Ly8gc28gJChcInA6Zmlyc3RcIikuaXMoXCJwOmxhc3RcIikgd29uJ3QgcmV0dXJuIHRydWUgZm9yIGEgZG9jIHdpdGggdHdvIFwicFwiLlxuXHRcdFx0dHlwZW9mIHNlbGVjdG9yID09PSBcInN0cmluZ1wiICYmIHJuZWVkc0NvbnRleHQudGVzdCggc2VsZWN0b3IgKSA/XG5cdFx0XHRcdGpRdWVyeSggc2VsZWN0b3IgKSA6XG5cdFx0XHRcdHNlbGVjdG9yIHx8IFtdLFxuXHRcdFx0ZmFsc2Vcblx0XHQpLmxlbmd0aDtcblx0fVxufSk7XG5cblxuLy8gSW5pdGlhbGl6ZSBhIGpRdWVyeSBvYmplY3RcblxuXG4vLyBBIGNlbnRyYWwgcmVmZXJlbmNlIHRvIHRoZSByb290IGpRdWVyeShkb2N1bWVudClcbnZhciByb290alF1ZXJ5LFxuXG5cdC8vIEEgc2ltcGxlIHdheSB0byBjaGVjayBmb3IgSFRNTCBzdHJpbmdzXG5cdC8vIFByaW9yaXRpemUgI2lkIG92ZXIgPHRhZz4gdG8gYXZvaWQgWFNTIHZpYSBsb2NhdGlvbi5oYXNoICgjOTUyMSlcblx0Ly8gU3RyaWN0IEhUTUwgcmVjb2duaXRpb24gKCMxMTI5MDogbXVzdCBzdGFydCB3aXRoIDwpXG5cdHJxdWlja0V4cHIgPSAvXig/OlxccyooPFtcXHdcXFddKz4pW14+XSp8IyhbXFx3LV0qKSkkLyxcblxuXHRpbml0ID0galF1ZXJ5LmZuLmluaXQgPSBmdW5jdGlvbiggc2VsZWN0b3IsIGNvbnRleHQgKSB7XG5cdFx0dmFyIG1hdGNoLCBlbGVtO1xuXG5cdFx0Ly8gSEFORExFOiAkKFwiXCIpLCAkKG51bGwpLCAkKHVuZGVmaW5lZCksICQoZmFsc2UpXG5cdFx0aWYgKCAhc2VsZWN0b3IgKSB7XG5cdFx0XHRyZXR1cm4gdGhpcztcblx0XHR9XG5cblx0XHQvLyBIYW5kbGUgSFRNTCBzdHJpbmdzXG5cdFx0aWYgKCB0eXBlb2Ygc2VsZWN0b3IgPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRpZiAoIHNlbGVjdG9yWzBdID09PSBcIjxcIiAmJiBzZWxlY3Rvclsgc2VsZWN0b3IubGVuZ3RoIC0gMSBdID09PSBcIj5cIiAmJiBzZWxlY3Rvci5sZW5ndGggPj0gMyApIHtcblx0XHRcdFx0Ly8gQXNzdW1lIHRoYXQgc3RyaW5ncyB0aGF0IHN0YXJ0IGFuZCBlbmQgd2l0aCA8PiBhcmUgSFRNTCBhbmQgc2tpcCB0aGUgcmVnZXggY2hlY2tcblx0XHRcdFx0bWF0Y2ggPSBbIG51bGwsIHNlbGVjdG9yLCBudWxsIF07XG5cblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdG1hdGNoID0gcnF1aWNrRXhwci5leGVjKCBzZWxlY3RvciApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBNYXRjaCBodG1sIG9yIG1ha2Ugc3VyZSBubyBjb250ZXh0IGlzIHNwZWNpZmllZCBmb3IgI2lkXG5cdFx0XHRpZiAoIG1hdGNoICYmIChtYXRjaFsxXSB8fCAhY29udGV4dCkgKSB7XG5cblx0XHRcdFx0Ly8gSEFORExFOiAkKGh0bWwpIC0+ICQoYXJyYXkpXG5cdFx0XHRcdGlmICggbWF0Y2hbMV0gKSB7XG5cdFx0XHRcdFx0Y29udGV4dCA9IGNvbnRleHQgaW5zdGFuY2VvZiBqUXVlcnkgPyBjb250ZXh0WzBdIDogY29udGV4dDtcblxuXHRcdFx0XHRcdC8vIE9wdGlvbiB0byBydW4gc2NyaXB0cyBpcyB0cnVlIGZvciBiYWNrLWNvbXBhdFxuXHRcdFx0XHRcdC8vIEludGVudGlvbmFsbHkgbGV0IHRoZSBlcnJvciBiZSB0aHJvd24gaWYgcGFyc2VIVE1MIGlzIG5vdCBwcmVzZW50XG5cdFx0XHRcdFx0alF1ZXJ5Lm1lcmdlKCB0aGlzLCBqUXVlcnkucGFyc2VIVE1MKFxuXHRcdFx0XHRcdFx0bWF0Y2hbMV0sXG5cdFx0XHRcdFx0XHRjb250ZXh0ICYmIGNvbnRleHQubm9kZVR5cGUgPyBjb250ZXh0Lm93bmVyRG9jdW1lbnQgfHwgY29udGV4dCA6IGRvY3VtZW50LFxuXHRcdFx0XHRcdFx0dHJ1ZVxuXHRcdFx0XHRcdCkgKTtcblxuXHRcdFx0XHRcdC8vIEhBTkRMRTogJChodG1sLCBwcm9wcylcblx0XHRcdFx0XHRpZiAoIHJzaW5nbGVUYWcudGVzdCggbWF0Y2hbMV0gKSAmJiBqUXVlcnkuaXNQbGFpbk9iamVjdCggY29udGV4dCApICkge1xuXHRcdFx0XHRcdFx0Zm9yICggbWF0Y2ggaW4gY29udGV4dCApIHtcblx0XHRcdFx0XHRcdFx0Ly8gUHJvcGVydGllcyBvZiBjb250ZXh0IGFyZSBjYWxsZWQgYXMgbWV0aG9kcyBpZiBwb3NzaWJsZVxuXHRcdFx0XHRcdFx0XHRpZiAoIGpRdWVyeS5pc0Z1bmN0aW9uKCB0aGlzWyBtYXRjaCBdICkgKSB7XG5cdFx0XHRcdFx0XHRcdFx0dGhpc1sgbWF0Y2ggXSggY29udGV4dFsgbWF0Y2ggXSApO1xuXG5cdFx0XHRcdFx0XHRcdC8vIC4uLmFuZCBvdGhlcndpc2Ugc2V0IGFzIGF0dHJpYnV0ZXNcblx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdFx0XHR0aGlzLmF0dHIoIG1hdGNoLCBjb250ZXh0WyBtYXRjaCBdICk7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRyZXR1cm4gdGhpcztcblxuXHRcdFx0XHQvLyBIQU5ETEU6ICQoI2lkKVxuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGVsZW0gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCggbWF0Y2hbMl0gKTtcblxuXHRcdFx0XHRcdC8vIFN1cHBvcnQ6IEJsYWNrYmVycnkgNC42XG5cdFx0XHRcdFx0Ly8gZ0VCSUQgcmV0dXJucyBub2RlcyBubyBsb25nZXIgaW4gdGhlIGRvY3VtZW50ICgjNjk2Mylcblx0XHRcdFx0XHRpZiAoIGVsZW0gJiYgZWxlbS5wYXJlbnROb2RlICkge1xuXHRcdFx0XHRcdFx0Ly8gSW5qZWN0IHRoZSBlbGVtZW50IGRpcmVjdGx5IGludG8gdGhlIGpRdWVyeSBvYmplY3Rcblx0XHRcdFx0XHRcdHRoaXMubGVuZ3RoID0gMTtcblx0XHRcdFx0XHRcdHRoaXNbMF0gPSBlbGVtO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdHRoaXMuY29udGV4dCA9IGRvY3VtZW50O1xuXHRcdFx0XHRcdHRoaXMuc2VsZWN0b3IgPSBzZWxlY3Rvcjtcblx0XHRcdFx0XHRyZXR1cm4gdGhpcztcblx0XHRcdFx0fVxuXG5cdFx0XHQvLyBIQU5ETEU6ICQoZXhwciwgJCguLi4pKVxuXHRcdFx0fSBlbHNlIGlmICggIWNvbnRleHQgfHwgY29udGV4dC5qcXVlcnkgKSB7XG5cdFx0XHRcdHJldHVybiAoIGNvbnRleHQgfHwgcm9vdGpRdWVyeSApLmZpbmQoIHNlbGVjdG9yICk7XG5cblx0XHRcdC8vIEhBTkRMRTogJChleHByLCBjb250ZXh0KVxuXHRcdFx0Ly8gKHdoaWNoIGlzIGp1c3QgZXF1aXZhbGVudCB0bzogJChjb250ZXh0KS5maW5kKGV4cHIpXG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRyZXR1cm4gdGhpcy5jb25zdHJ1Y3RvciggY29udGV4dCApLmZpbmQoIHNlbGVjdG9yICk7XG5cdFx0XHR9XG5cblx0XHQvLyBIQU5ETEU6ICQoRE9NRWxlbWVudClcblx0XHR9IGVsc2UgaWYgKCBzZWxlY3Rvci5ub2RlVHlwZSApIHtcblx0XHRcdHRoaXMuY29udGV4dCA9IHRoaXNbMF0gPSBzZWxlY3Rvcjtcblx0XHRcdHRoaXMubGVuZ3RoID0gMTtcblx0XHRcdHJldHVybiB0aGlzO1xuXG5cdFx0Ly8gSEFORExFOiAkKGZ1bmN0aW9uKVxuXHRcdC8vIFNob3J0Y3V0IGZvciBkb2N1bWVudCByZWFkeVxuXHRcdH0gZWxzZSBpZiAoIGpRdWVyeS5pc0Z1bmN0aW9uKCBzZWxlY3RvciApICkge1xuXHRcdFx0cmV0dXJuIHR5cGVvZiByb290alF1ZXJ5LnJlYWR5ICE9PSBcInVuZGVmaW5lZFwiID9cblx0XHRcdFx0cm9vdGpRdWVyeS5yZWFkeSggc2VsZWN0b3IgKSA6XG5cdFx0XHRcdC8vIEV4ZWN1dGUgaW1tZWRpYXRlbHkgaWYgcmVhZHkgaXMgbm90IHByZXNlbnRcblx0XHRcdFx0c2VsZWN0b3IoIGpRdWVyeSApO1xuXHRcdH1cblxuXHRcdGlmICggc2VsZWN0b3Iuc2VsZWN0b3IgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdHRoaXMuc2VsZWN0b3IgPSBzZWxlY3Rvci5zZWxlY3Rvcjtcblx0XHRcdHRoaXMuY29udGV4dCA9IHNlbGVjdG9yLmNvbnRleHQ7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGpRdWVyeS5tYWtlQXJyYXkoIHNlbGVjdG9yLCB0aGlzICk7XG5cdH07XG5cbi8vIEdpdmUgdGhlIGluaXQgZnVuY3Rpb24gdGhlIGpRdWVyeSBwcm90b3R5cGUgZm9yIGxhdGVyIGluc3RhbnRpYXRpb25cbmluaXQucHJvdG90eXBlID0galF1ZXJ5LmZuO1xuXG4vLyBJbml0aWFsaXplIGNlbnRyYWwgcmVmZXJlbmNlXG5yb290alF1ZXJ5ID0galF1ZXJ5KCBkb2N1bWVudCApO1xuXG5cbnZhciBycGFyZW50c3ByZXYgPSAvXig/OnBhcmVudHN8cHJldig/OlVudGlsfEFsbCkpLyxcblx0Ly8gTWV0aG9kcyBndWFyYW50ZWVkIHRvIHByb2R1Y2UgYSB1bmlxdWUgc2V0IHdoZW4gc3RhcnRpbmcgZnJvbSBhIHVuaXF1ZSBzZXRcblx0Z3VhcmFudGVlZFVuaXF1ZSA9IHtcblx0XHRjaGlsZHJlbjogdHJ1ZSxcblx0XHRjb250ZW50czogdHJ1ZSxcblx0XHRuZXh0OiB0cnVlLFxuXHRcdHByZXY6IHRydWVcblx0fTtcblxualF1ZXJ5LmV4dGVuZCh7XG5cdGRpcjogZnVuY3Rpb24oIGVsZW0sIGRpciwgdW50aWwgKSB7XG5cdFx0dmFyIG1hdGNoZWQgPSBbXSxcblx0XHRcdHRydW5jYXRlID0gdW50aWwgIT09IHVuZGVmaW5lZDtcblxuXHRcdHdoaWxlICggKGVsZW0gPSBlbGVtWyBkaXIgXSkgJiYgZWxlbS5ub2RlVHlwZSAhPT0gOSApIHtcblx0XHRcdGlmICggZWxlbS5ub2RlVHlwZSA9PT0gMSApIHtcblx0XHRcdFx0aWYgKCB0cnVuY2F0ZSAmJiBqUXVlcnkoIGVsZW0gKS5pcyggdW50aWwgKSApIHtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0fVxuXHRcdFx0XHRtYXRjaGVkLnB1c2goIGVsZW0gKTtcblx0XHRcdH1cblx0XHR9XG5cdFx0cmV0dXJuIG1hdGNoZWQ7XG5cdH0sXG5cblx0c2libGluZzogZnVuY3Rpb24oIG4sIGVsZW0gKSB7XG5cdFx0dmFyIG1hdGNoZWQgPSBbXTtcblxuXHRcdGZvciAoIDsgbjsgbiA9IG4ubmV4dFNpYmxpbmcgKSB7XG5cdFx0XHRpZiAoIG4ubm9kZVR5cGUgPT09IDEgJiYgbiAhPT0gZWxlbSApIHtcblx0XHRcdFx0bWF0Y2hlZC5wdXNoKCBuICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIG1hdGNoZWQ7XG5cdH1cbn0pO1xuXG5qUXVlcnkuZm4uZXh0ZW5kKHtcblx0aGFzOiBmdW5jdGlvbiggdGFyZ2V0ICkge1xuXHRcdHZhciB0YXJnZXRzID0galF1ZXJ5KCB0YXJnZXQsIHRoaXMgKSxcblx0XHRcdGwgPSB0YXJnZXRzLmxlbmd0aDtcblxuXHRcdHJldHVybiB0aGlzLmZpbHRlcihmdW5jdGlvbigpIHtcblx0XHRcdHZhciBpID0gMDtcblx0XHRcdGZvciAoIDsgaSA8IGw7IGkrKyApIHtcblx0XHRcdFx0aWYgKCBqUXVlcnkuY29udGFpbnMoIHRoaXMsIHRhcmdldHNbaV0gKSApIHtcblx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0pO1xuXHR9LFxuXG5cdGNsb3Nlc3Q6IGZ1bmN0aW9uKCBzZWxlY3RvcnMsIGNvbnRleHQgKSB7XG5cdFx0dmFyIGN1cixcblx0XHRcdGkgPSAwLFxuXHRcdFx0bCA9IHRoaXMubGVuZ3RoLFxuXHRcdFx0bWF0Y2hlZCA9IFtdLFxuXHRcdFx0cG9zID0gcm5lZWRzQ29udGV4dC50ZXN0KCBzZWxlY3RvcnMgKSB8fCB0eXBlb2Ygc2VsZWN0b3JzICE9PSBcInN0cmluZ1wiID9cblx0XHRcdFx0alF1ZXJ5KCBzZWxlY3RvcnMsIGNvbnRleHQgfHwgdGhpcy5jb250ZXh0ICkgOlxuXHRcdFx0XHQwO1xuXG5cdFx0Zm9yICggOyBpIDwgbDsgaSsrICkge1xuXHRcdFx0Zm9yICggY3VyID0gdGhpc1tpXTsgY3VyICYmIGN1ciAhPT0gY29udGV4dDsgY3VyID0gY3VyLnBhcmVudE5vZGUgKSB7XG5cdFx0XHRcdC8vIEFsd2F5cyBza2lwIGRvY3VtZW50IGZyYWdtZW50c1xuXHRcdFx0XHRpZiAoIGN1ci5ub2RlVHlwZSA8IDExICYmIChwb3MgP1xuXHRcdFx0XHRcdHBvcy5pbmRleChjdXIpID4gLTEgOlxuXG5cdFx0XHRcdFx0Ly8gRG9uJ3QgcGFzcyBub24tZWxlbWVudHMgdG8gU2l6emxlXG5cdFx0XHRcdFx0Y3VyLm5vZGVUeXBlID09PSAxICYmXG5cdFx0XHRcdFx0XHRqUXVlcnkuZmluZC5tYXRjaGVzU2VsZWN0b3IoY3VyLCBzZWxlY3RvcnMpKSApIHtcblxuXHRcdFx0XHRcdG1hdGNoZWQucHVzaCggY3VyICk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcy5wdXNoU3RhY2soIG1hdGNoZWQubGVuZ3RoID4gMSA/IGpRdWVyeS51bmlxdWUoIG1hdGNoZWQgKSA6IG1hdGNoZWQgKTtcblx0fSxcblxuXHQvLyBEZXRlcm1pbmUgdGhlIHBvc2l0aW9uIG9mIGFuIGVsZW1lbnQgd2l0aGluIHRoZSBzZXRcblx0aW5kZXg6IGZ1bmN0aW9uKCBlbGVtICkge1xuXG5cdFx0Ly8gTm8gYXJndW1lbnQsIHJldHVybiBpbmRleCBpbiBwYXJlbnRcblx0XHRpZiAoICFlbGVtICkge1xuXHRcdFx0cmV0dXJuICggdGhpc1sgMCBdICYmIHRoaXNbIDAgXS5wYXJlbnROb2RlICkgPyB0aGlzLmZpcnN0KCkucHJldkFsbCgpLmxlbmd0aCA6IC0xO1xuXHRcdH1cblxuXHRcdC8vIEluZGV4IGluIHNlbGVjdG9yXG5cdFx0aWYgKCB0eXBlb2YgZWxlbSA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdHJldHVybiBpbmRleE9mLmNhbGwoIGpRdWVyeSggZWxlbSApLCB0aGlzWyAwIF0gKTtcblx0XHR9XG5cblx0XHQvLyBMb2NhdGUgdGhlIHBvc2l0aW9uIG9mIHRoZSBkZXNpcmVkIGVsZW1lbnRcblx0XHRyZXR1cm4gaW5kZXhPZi5jYWxsKCB0aGlzLFxuXG5cdFx0XHQvLyBJZiBpdCByZWNlaXZlcyBhIGpRdWVyeSBvYmplY3QsIHRoZSBmaXJzdCBlbGVtZW50IGlzIHVzZWRcblx0XHRcdGVsZW0uanF1ZXJ5ID8gZWxlbVsgMCBdIDogZWxlbVxuXHRcdCk7XG5cdH0sXG5cblx0YWRkOiBmdW5jdGlvbiggc2VsZWN0b3IsIGNvbnRleHQgKSB7XG5cdFx0cmV0dXJuIHRoaXMucHVzaFN0YWNrKFxuXHRcdFx0alF1ZXJ5LnVuaXF1ZShcblx0XHRcdFx0alF1ZXJ5Lm1lcmdlKCB0aGlzLmdldCgpLCBqUXVlcnkoIHNlbGVjdG9yLCBjb250ZXh0ICkgKVxuXHRcdFx0KVxuXHRcdCk7XG5cdH0sXG5cblx0YWRkQmFjazogZnVuY3Rpb24oIHNlbGVjdG9yICkge1xuXHRcdHJldHVybiB0aGlzLmFkZCggc2VsZWN0b3IgPT0gbnVsbCA/XG5cdFx0XHR0aGlzLnByZXZPYmplY3QgOiB0aGlzLnByZXZPYmplY3QuZmlsdGVyKHNlbGVjdG9yKVxuXHRcdCk7XG5cdH1cbn0pO1xuXG5mdW5jdGlvbiBzaWJsaW5nKCBjdXIsIGRpciApIHtcblx0d2hpbGUgKCAoY3VyID0gY3VyW2Rpcl0pICYmIGN1ci5ub2RlVHlwZSAhPT0gMSApIHt9XG5cdHJldHVybiBjdXI7XG59XG5cbmpRdWVyeS5lYWNoKHtcblx0cGFyZW50OiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHR2YXIgcGFyZW50ID0gZWxlbS5wYXJlbnROb2RlO1xuXHRcdHJldHVybiBwYXJlbnQgJiYgcGFyZW50Lm5vZGVUeXBlICE9PSAxMSA/IHBhcmVudCA6IG51bGw7XG5cdH0sXG5cdHBhcmVudHM6IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdHJldHVybiBqUXVlcnkuZGlyKCBlbGVtLCBcInBhcmVudE5vZGVcIiApO1xuXHR9LFxuXHRwYXJlbnRzVW50aWw6IGZ1bmN0aW9uKCBlbGVtLCBpLCB1bnRpbCApIHtcblx0XHRyZXR1cm4galF1ZXJ5LmRpciggZWxlbSwgXCJwYXJlbnROb2RlXCIsIHVudGlsICk7XG5cdH0sXG5cdG5leHQ6IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdHJldHVybiBzaWJsaW5nKCBlbGVtLCBcIm5leHRTaWJsaW5nXCIgKTtcblx0fSxcblx0cHJldjogZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0cmV0dXJuIHNpYmxpbmcoIGVsZW0sIFwicHJldmlvdXNTaWJsaW5nXCIgKTtcblx0fSxcblx0bmV4dEFsbDogZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0cmV0dXJuIGpRdWVyeS5kaXIoIGVsZW0sIFwibmV4dFNpYmxpbmdcIiApO1xuXHR9LFxuXHRwcmV2QWxsOiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRyZXR1cm4galF1ZXJ5LmRpciggZWxlbSwgXCJwcmV2aW91c1NpYmxpbmdcIiApO1xuXHR9LFxuXHRuZXh0VW50aWw6IGZ1bmN0aW9uKCBlbGVtLCBpLCB1bnRpbCApIHtcblx0XHRyZXR1cm4galF1ZXJ5LmRpciggZWxlbSwgXCJuZXh0U2libGluZ1wiLCB1bnRpbCApO1xuXHR9LFxuXHRwcmV2VW50aWw6IGZ1bmN0aW9uKCBlbGVtLCBpLCB1bnRpbCApIHtcblx0XHRyZXR1cm4galF1ZXJ5LmRpciggZWxlbSwgXCJwcmV2aW91c1NpYmxpbmdcIiwgdW50aWwgKTtcblx0fSxcblx0c2libGluZ3M6IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdHJldHVybiBqUXVlcnkuc2libGluZyggKCBlbGVtLnBhcmVudE5vZGUgfHwge30gKS5maXJzdENoaWxkLCBlbGVtICk7XG5cdH0sXG5cdGNoaWxkcmVuOiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRyZXR1cm4galF1ZXJ5LnNpYmxpbmcoIGVsZW0uZmlyc3RDaGlsZCApO1xuXHR9LFxuXHRjb250ZW50czogZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0cmV0dXJuIGVsZW0uY29udGVudERvY3VtZW50IHx8IGpRdWVyeS5tZXJnZSggW10sIGVsZW0uY2hpbGROb2RlcyApO1xuXHR9XG59LCBmdW5jdGlvbiggbmFtZSwgZm4gKSB7XG5cdGpRdWVyeS5mblsgbmFtZSBdID0gZnVuY3Rpb24oIHVudGlsLCBzZWxlY3RvciApIHtcblx0XHR2YXIgbWF0Y2hlZCA9IGpRdWVyeS5tYXAoIHRoaXMsIGZuLCB1bnRpbCApO1xuXG5cdFx0aWYgKCBuYW1lLnNsaWNlKCAtNSApICE9PSBcIlVudGlsXCIgKSB7XG5cdFx0XHRzZWxlY3RvciA9IHVudGlsO1xuXHRcdH1cblxuXHRcdGlmICggc2VsZWN0b3IgJiYgdHlwZW9mIHNlbGVjdG9yID09PSBcInN0cmluZ1wiICkge1xuXHRcdFx0bWF0Y2hlZCA9IGpRdWVyeS5maWx0ZXIoIHNlbGVjdG9yLCBtYXRjaGVkICk7XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmxlbmd0aCA+IDEgKSB7XG5cdFx0XHQvLyBSZW1vdmUgZHVwbGljYXRlc1xuXHRcdFx0aWYgKCAhZ3VhcmFudGVlZFVuaXF1ZVsgbmFtZSBdICkge1xuXHRcdFx0XHRqUXVlcnkudW5pcXVlKCBtYXRjaGVkICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIFJldmVyc2Ugb3JkZXIgZm9yIHBhcmVudHMqIGFuZCBwcmV2LWRlcml2YXRpdmVzXG5cdFx0XHRpZiAoIHJwYXJlbnRzcHJldi50ZXN0KCBuYW1lICkgKSB7XG5cdFx0XHRcdG1hdGNoZWQucmV2ZXJzZSgpO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLnB1c2hTdGFjayggbWF0Y2hlZCApO1xuXHR9O1xufSk7XG52YXIgcm5vdHdoaXRlID0gKC9cXFMrL2cpO1xuXG5cblxuLy8gU3RyaW5nIHRvIE9iamVjdCBvcHRpb25zIGZvcm1hdCBjYWNoZVxudmFyIG9wdGlvbnNDYWNoZSA9IHt9O1xuXG4vLyBDb252ZXJ0IFN0cmluZy1mb3JtYXR0ZWQgb3B0aW9ucyBpbnRvIE9iamVjdC1mb3JtYXR0ZWQgb25lcyBhbmQgc3RvcmUgaW4gY2FjaGVcbmZ1bmN0aW9uIGNyZWF0ZU9wdGlvbnMoIG9wdGlvbnMgKSB7XG5cdHZhciBvYmplY3QgPSBvcHRpb25zQ2FjaGVbIG9wdGlvbnMgXSA9IHt9O1xuXHRqUXVlcnkuZWFjaCggb3B0aW9ucy5tYXRjaCggcm5vdHdoaXRlICkgfHwgW10sIGZ1bmN0aW9uKCBfLCBmbGFnICkge1xuXHRcdG9iamVjdFsgZmxhZyBdID0gdHJ1ZTtcblx0fSk7XG5cdHJldHVybiBvYmplY3Q7XG59XG5cbi8qXG4gKiBDcmVhdGUgYSBjYWxsYmFjayBsaXN0IHVzaW5nIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVyczpcbiAqXG4gKlx0b3B0aW9uczogYW4gb3B0aW9uYWwgbGlzdCBvZiBzcGFjZS1zZXBhcmF0ZWQgb3B0aW9ucyB0aGF0IHdpbGwgY2hhbmdlIGhvd1xuICpcdFx0XHR0aGUgY2FsbGJhY2sgbGlzdCBiZWhhdmVzIG9yIGEgbW9yZSB0cmFkaXRpb25hbCBvcHRpb24gb2JqZWN0XG4gKlxuICogQnkgZGVmYXVsdCBhIGNhbGxiYWNrIGxpc3Qgd2lsbCBhY3QgbGlrZSBhbiBldmVudCBjYWxsYmFjayBsaXN0IGFuZCBjYW4gYmVcbiAqIFwiZmlyZWRcIiBtdWx0aXBsZSB0aW1lcy5cbiAqXG4gKiBQb3NzaWJsZSBvcHRpb25zOlxuICpcbiAqXHRvbmNlOlx0XHRcdHdpbGwgZW5zdXJlIHRoZSBjYWxsYmFjayBsaXN0IGNhbiBvbmx5IGJlIGZpcmVkIG9uY2UgKGxpa2UgYSBEZWZlcnJlZClcbiAqXG4gKlx0bWVtb3J5Olx0XHRcdHdpbGwga2VlcCB0cmFjayBvZiBwcmV2aW91cyB2YWx1ZXMgYW5kIHdpbGwgY2FsbCBhbnkgY2FsbGJhY2sgYWRkZWRcbiAqXHRcdFx0XHRcdGFmdGVyIHRoZSBsaXN0IGhhcyBiZWVuIGZpcmVkIHJpZ2h0IGF3YXkgd2l0aCB0aGUgbGF0ZXN0IFwibWVtb3JpemVkXCJcbiAqXHRcdFx0XHRcdHZhbHVlcyAobGlrZSBhIERlZmVycmVkKVxuICpcbiAqXHR1bmlxdWU6XHRcdFx0d2lsbCBlbnN1cmUgYSBjYWxsYmFjayBjYW4gb25seSBiZSBhZGRlZCBvbmNlIChubyBkdXBsaWNhdGUgaW4gdGhlIGxpc3QpXG4gKlxuICpcdHN0b3BPbkZhbHNlOlx0aW50ZXJydXB0IGNhbGxpbmdzIHdoZW4gYSBjYWxsYmFjayByZXR1cm5zIGZhbHNlXG4gKlxuICovXG5qUXVlcnkuQ2FsbGJhY2tzID0gZnVuY3Rpb24oIG9wdGlvbnMgKSB7XG5cblx0Ly8gQ29udmVydCBvcHRpb25zIGZyb20gU3RyaW5nLWZvcm1hdHRlZCB0byBPYmplY3QtZm9ybWF0dGVkIGlmIG5lZWRlZFxuXHQvLyAod2UgY2hlY2sgaW4gY2FjaGUgZmlyc3QpXG5cdG9wdGlvbnMgPSB0eXBlb2Ygb3B0aW9ucyA9PT0gXCJzdHJpbmdcIiA/XG5cdFx0KCBvcHRpb25zQ2FjaGVbIG9wdGlvbnMgXSB8fCBjcmVhdGVPcHRpb25zKCBvcHRpb25zICkgKSA6XG5cdFx0alF1ZXJ5LmV4dGVuZCgge30sIG9wdGlvbnMgKTtcblxuXHR2YXIgLy8gTGFzdCBmaXJlIHZhbHVlIChmb3Igbm9uLWZvcmdldHRhYmxlIGxpc3RzKVxuXHRcdG1lbW9yeSxcblx0XHQvLyBGbGFnIHRvIGtub3cgaWYgbGlzdCB3YXMgYWxyZWFkeSBmaXJlZFxuXHRcdGZpcmVkLFxuXHRcdC8vIEZsYWcgdG8ga25vdyBpZiBsaXN0IGlzIGN1cnJlbnRseSBmaXJpbmdcblx0XHRmaXJpbmcsXG5cdFx0Ly8gRmlyc3QgY2FsbGJhY2sgdG8gZmlyZSAodXNlZCBpbnRlcm5hbGx5IGJ5IGFkZCBhbmQgZmlyZVdpdGgpXG5cdFx0ZmlyaW5nU3RhcnQsXG5cdFx0Ly8gRW5kIG9mIHRoZSBsb29wIHdoZW4gZmlyaW5nXG5cdFx0ZmlyaW5nTGVuZ3RoLFxuXHRcdC8vIEluZGV4IG9mIGN1cnJlbnRseSBmaXJpbmcgY2FsbGJhY2sgKG1vZGlmaWVkIGJ5IHJlbW92ZSBpZiBuZWVkZWQpXG5cdFx0ZmlyaW5nSW5kZXgsXG5cdFx0Ly8gQWN0dWFsIGNhbGxiYWNrIGxpc3Rcblx0XHRsaXN0ID0gW10sXG5cdFx0Ly8gU3RhY2sgb2YgZmlyZSBjYWxscyBmb3IgcmVwZWF0YWJsZSBsaXN0c1xuXHRcdHN0YWNrID0gIW9wdGlvbnMub25jZSAmJiBbXSxcblx0XHQvLyBGaXJlIGNhbGxiYWNrc1xuXHRcdGZpcmUgPSBmdW5jdGlvbiggZGF0YSApIHtcblx0XHRcdG1lbW9yeSA9IG9wdGlvbnMubWVtb3J5ICYmIGRhdGE7XG5cdFx0XHRmaXJlZCA9IHRydWU7XG5cdFx0XHRmaXJpbmdJbmRleCA9IGZpcmluZ1N0YXJ0IHx8IDA7XG5cdFx0XHRmaXJpbmdTdGFydCA9IDA7XG5cdFx0XHRmaXJpbmdMZW5ndGggPSBsaXN0Lmxlbmd0aDtcblx0XHRcdGZpcmluZyA9IHRydWU7XG5cdFx0XHRmb3IgKCA7IGxpc3QgJiYgZmlyaW5nSW5kZXggPCBmaXJpbmdMZW5ndGg7IGZpcmluZ0luZGV4KysgKSB7XG5cdFx0XHRcdGlmICggbGlzdFsgZmlyaW5nSW5kZXggXS5hcHBseSggZGF0YVsgMCBdLCBkYXRhWyAxIF0gKSA9PT0gZmFsc2UgJiYgb3B0aW9ucy5zdG9wT25GYWxzZSApIHtcblx0XHRcdFx0XHRtZW1vcnkgPSBmYWxzZTsgLy8gVG8gcHJldmVudCBmdXJ0aGVyIGNhbGxzIHVzaW5nIGFkZFxuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRmaXJpbmcgPSBmYWxzZTtcblx0XHRcdGlmICggbGlzdCApIHtcblx0XHRcdFx0aWYgKCBzdGFjayApIHtcblx0XHRcdFx0XHRpZiAoIHN0YWNrLmxlbmd0aCApIHtcblx0XHRcdFx0XHRcdGZpcmUoIHN0YWNrLnNoaWZ0KCkgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gZWxzZSBpZiAoIG1lbW9yeSApIHtcblx0XHRcdFx0XHRsaXN0ID0gW107XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0c2VsZi5kaXNhYmxlKCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9LFxuXHRcdC8vIEFjdHVhbCBDYWxsYmFja3Mgb2JqZWN0XG5cdFx0c2VsZiA9IHtcblx0XHRcdC8vIEFkZCBhIGNhbGxiYWNrIG9yIGEgY29sbGVjdGlvbiBvZiBjYWxsYmFja3MgdG8gdGhlIGxpc3Rcblx0XHRcdGFkZDogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGlmICggbGlzdCApIHtcblx0XHRcdFx0XHQvLyBGaXJzdCwgd2Ugc2F2ZSB0aGUgY3VycmVudCBsZW5ndGhcblx0XHRcdFx0XHR2YXIgc3RhcnQgPSBsaXN0Lmxlbmd0aDtcblx0XHRcdFx0XHQoZnVuY3Rpb24gYWRkKCBhcmdzICkge1xuXHRcdFx0XHRcdFx0alF1ZXJ5LmVhY2goIGFyZ3MsIGZ1bmN0aW9uKCBfLCBhcmcgKSB7XG5cdFx0XHRcdFx0XHRcdHZhciB0eXBlID0galF1ZXJ5LnR5cGUoIGFyZyApO1xuXHRcdFx0XHRcdFx0XHRpZiAoIHR5cGUgPT09IFwiZnVuY3Rpb25cIiApIHtcblx0XHRcdFx0XHRcdFx0XHRpZiAoICFvcHRpb25zLnVuaXF1ZSB8fCAhc2VsZi5oYXMoIGFyZyApICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0bGlzdC5wdXNoKCBhcmcgKTtcblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdH0gZWxzZSBpZiAoIGFyZyAmJiBhcmcubGVuZ3RoICYmIHR5cGUgIT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRcdFx0XHRcdFx0Ly8gSW5zcGVjdCByZWN1cnNpdmVseVxuXHRcdFx0XHRcdFx0XHRcdGFkZCggYXJnICk7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH0pO1xuXHRcdFx0XHRcdH0pKCBhcmd1bWVudHMgKTtcblx0XHRcdFx0XHQvLyBEbyB3ZSBuZWVkIHRvIGFkZCB0aGUgY2FsbGJhY2tzIHRvIHRoZVxuXHRcdFx0XHRcdC8vIGN1cnJlbnQgZmlyaW5nIGJhdGNoP1xuXHRcdFx0XHRcdGlmICggZmlyaW5nICkge1xuXHRcdFx0XHRcdFx0ZmlyaW5nTGVuZ3RoID0gbGlzdC5sZW5ndGg7XG5cdFx0XHRcdFx0Ly8gV2l0aCBtZW1vcnksIGlmIHdlJ3JlIG5vdCBmaXJpbmcgdGhlblxuXHRcdFx0XHRcdC8vIHdlIHNob3VsZCBjYWxsIHJpZ2h0IGF3YXlcblx0XHRcdFx0XHR9IGVsc2UgaWYgKCBtZW1vcnkgKSB7XG5cdFx0XHRcdFx0XHRmaXJpbmdTdGFydCA9IHN0YXJ0O1xuXHRcdFx0XHRcdFx0ZmlyZSggbWVtb3J5ICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiB0aGlzO1xuXHRcdFx0fSxcblx0XHRcdC8vIFJlbW92ZSBhIGNhbGxiYWNrIGZyb20gdGhlIGxpc3Rcblx0XHRcdHJlbW92ZTogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGlmICggbGlzdCApIHtcblx0XHRcdFx0XHRqUXVlcnkuZWFjaCggYXJndW1lbnRzLCBmdW5jdGlvbiggXywgYXJnICkge1xuXHRcdFx0XHRcdFx0dmFyIGluZGV4O1xuXHRcdFx0XHRcdFx0d2hpbGUgKCAoIGluZGV4ID0galF1ZXJ5LmluQXJyYXkoIGFyZywgbGlzdCwgaW5kZXggKSApID4gLTEgKSB7XG5cdFx0XHRcdFx0XHRcdGxpc3Quc3BsaWNlKCBpbmRleCwgMSApO1xuXHRcdFx0XHRcdFx0XHQvLyBIYW5kbGUgZmlyaW5nIGluZGV4ZXNcblx0XHRcdFx0XHRcdFx0aWYgKCBmaXJpbmcgKSB7XG5cdFx0XHRcdFx0XHRcdFx0aWYgKCBpbmRleCA8PSBmaXJpbmdMZW5ndGggKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRmaXJpbmdMZW5ndGgtLTtcblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0aWYgKCBpbmRleCA8PSBmaXJpbmdJbmRleCApIHtcblx0XHRcdFx0XHRcdFx0XHRcdGZpcmluZ0luZGV4LS07XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHR9LFxuXHRcdFx0Ly8gQ2hlY2sgaWYgYSBnaXZlbiBjYWxsYmFjayBpcyBpbiB0aGUgbGlzdC5cblx0XHRcdC8vIElmIG5vIGFyZ3VtZW50IGlzIGdpdmVuLCByZXR1cm4gd2hldGhlciBvciBub3QgbGlzdCBoYXMgY2FsbGJhY2tzIGF0dGFjaGVkLlxuXHRcdFx0aGFzOiBmdW5jdGlvbiggZm4gKSB7XG5cdFx0XHRcdHJldHVybiBmbiA/IGpRdWVyeS5pbkFycmF5KCBmbiwgbGlzdCApID4gLTEgOiAhISggbGlzdCAmJiBsaXN0Lmxlbmd0aCApO1xuXHRcdFx0fSxcblx0XHRcdC8vIFJlbW92ZSBhbGwgY2FsbGJhY2tzIGZyb20gdGhlIGxpc3Rcblx0XHRcdGVtcHR5OiBmdW5jdGlvbigpIHtcblx0XHRcdFx0bGlzdCA9IFtdO1xuXHRcdFx0XHRmaXJpbmdMZW5ndGggPSAwO1xuXHRcdFx0XHRyZXR1cm4gdGhpcztcblx0XHRcdH0sXG5cdFx0XHQvLyBIYXZlIHRoZSBsaXN0IGRvIG5vdGhpbmcgYW55bW9yZVxuXHRcdFx0ZGlzYWJsZTogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGxpc3QgPSBzdGFjayA9IG1lbW9yeSA9IHVuZGVmaW5lZDtcblx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHR9LFxuXHRcdFx0Ly8gSXMgaXQgZGlzYWJsZWQ/XG5cdFx0XHRkaXNhYmxlZDogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHJldHVybiAhbGlzdDtcblx0XHRcdH0sXG5cdFx0XHQvLyBMb2NrIHRoZSBsaXN0IGluIGl0cyBjdXJyZW50IHN0YXRlXG5cdFx0XHRsb2NrOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0c3RhY2sgPSB1bmRlZmluZWQ7XG5cdFx0XHRcdGlmICggIW1lbW9yeSApIHtcblx0XHRcdFx0XHRzZWxmLmRpc2FibGUoKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gdGhpcztcblx0XHRcdH0sXG5cdFx0XHQvLyBJcyBpdCBsb2NrZWQ/XG5cdFx0XHRsb2NrZWQ6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRyZXR1cm4gIXN0YWNrO1xuXHRcdFx0fSxcblx0XHRcdC8vIENhbGwgYWxsIGNhbGxiYWNrcyB3aXRoIHRoZSBnaXZlbiBjb250ZXh0IGFuZCBhcmd1bWVudHNcblx0XHRcdGZpcmVXaXRoOiBmdW5jdGlvbiggY29udGV4dCwgYXJncyApIHtcblx0XHRcdFx0aWYgKCBsaXN0ICYmICggIWZpcmVkIHx8IHN0YWNrICkgKSB7XG5cdFx0XHRcdFx0YXJncyA9IGFyZ3MgfHwgW107XG5cdFx0XHRcdFx0YXJncyA9IFsgY29udGV4dCwgYXJncy5zbGljZSA/IGFyZ3Muc2xpY2UoKSA6IGFyZ3MgXTtcblx0XHRcdFx0XHRpZiAoIGZpcmluZyApIHtcblx0XHRcdFx0XHRcdHN0YWNrLnB1c2goIGFyZ3MgKTtcblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0ZmlyZSggYXJncyApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gdGhpcztcblx0XHRcdH0sXG5cdFx0XHQvLyBDYWxsIGFsbCB0aGUgY2FsbGJhY2tzIHdpdGggdGhlIGdpdmVuIGFyZ3VtZW50c1xuXHRcdFx0ZmlyZTogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHNlbGYuZmlyZVdpdGgoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdFx0XHRyZXR1cm4gdGhpcztcblx0XHRcdH0sXG5cdFx0XHQvLyBUbyBrbm93IGlmIHRoZSBjYWxsYmFja3MgaGF2ZSBhbHJlYWR5IGJlZW4gY2FsbGVkIGF0IGxlYXN0IG9uY2Vcblx0XHRcdGZpcmVkOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0cmV0dXJuICEhZmlyZWQ7XG5cdFx0XHR9XG5cdFx0fTtcblxuXHRyZXR1cm4gc2VsZjtcbn07XG5cblxualF1ZXJ5LmV4dGVuZCh7XG5cblx0RGVmZXJyZWQ6IGZ1bmN0aW9uKCBmdW5jICkge1xuXHRcdHZhciB0dXBsZXMgPSBbXG5cdFx0XHRcdC8vIGFjdGlvbiwgYWRkIGxpc3RlbmVyLCBsaXN0ZW5lciBsaXN0LCBmaW5hbCBzdGF0ZVxuXHRcdFx0XHRbIFwicmVzb2x2ZVwiLCBcImRvbmVcIiwgalF1ZXJ5LkNhbGxiYWNrcyhcIm9uY2UgbWVtb3J5XCIpLCBcInJlc29sdmVkXCIgXSxcblx0XHRcdFx0WyBcInJlamVjdFwiLCBcImZhaWxcIiwgalF1ZXJ5LkNhbGxiYWNrcyhcIm9uY2UgbWVtb3J5XCIpLCBcInJlamVjdGVkXCIgXSxcblx0XHRcdFx0WyBcIm5vdGlmeVwiLCBcInByb2dyZXNzXCIsIGpRdWVyeS5DYWxsYmFja3MoXCJtZW1vcnlcIikgXVxuXHRcdFx0XSxcblx0XHRcdHN0YXRlID0gXCJwZW5kaW5nXCIsXG5cdFx0XHRwcm9taXNlID0ge1xuXHRcdFx0XHRzdGF0ZTogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHN0YXRlO1xuXHRcdFx0XHR9LFxuXHRcdFx0XHRhbHdheXM6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdGRlZmVycmVkLmRvbmUoIGFyZ3VtZW50cyApLmZhaWwoIGFyZ3VtZW50cyApO1xuXHRcdFx0XHRcdHJldHVybiB0aGlzO1xuXHRcdFx0XHR9LFxuXHRcdFx0XHR0aGVuOiBmdW5jdGlvbiggLyogZm5Eb25lLCBmbkZhaWwsIGZuUHJvZ3Jlc3MgKi8gKSB7XG5cdFx0XHRcdFx0dmFyIGZucyA9IGFyZ3VtZW50cztcblx0XHRcdFx0XHRyZXR1cm4galF1ZXJ5LkRlZmVycmVkKGZ1bmN0aW9uKCBuZXdEZWZlciApIHtcblx0XHRcdFx0XHRcdGpRdWVyeS5lYWNoKCB0dXBsZXMsIGZ1bmN0aW9uKCBpLCB0dXBsZSApIHtcblx0XHRcdFx0XHRcdFx0dmFyIGZuID0galF1ZXJ5LmlzRnVuY3Rpb24oIGZuc1sgaSBdICkgJiYgZm5zWyBpIF07XG5cdFx0XHRcdFx0XHRcdC8vIGRlZmVycmVkWyBkb25lIHwgZmFpbCB8IHByb2dyZXNzIF0gZm9yIGZvcndhcmRpbmcgYWN0aW9ucyB0byBuZXdEZWZlclxuXHRcdFx0XHRcdFx0XHRkZWZlcnJlZFsgdHVwbGVbMV0gXShmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdFx0XHR2YXIgcmV0dXJuZWQgPSBmbiAmJiBmbi5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0XHRcdFx0XHRcdFx0aWYgKCByZXR1cm5lZCAmJiBqUXVlcnkuaXNGdW5jdGlvbiggcmV0dXJuZWQucHJvbWlzZSApICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0cmV0dXJuZWQucHJvbWlzZSgpXG5cdFx0XHRcdFx0XHRcdFx0XHRcdC5kb25lKCBuZXdEZWZlci5yZXNvbHZlIClcblx0XHRcdFx0XHRcdFx0XHRcdFx0LmZhaWwoIG5ld0RlZmVyLnJlamVjdCApXG5cdFx0XHRcdFx0XHRcdFx0XHRcdC5wcm9ncmVzcyggbmV3RGVmZXIubm90aWZ5ICk7XG5cdFx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdFx0XHRcdG5ld0RlZmVyWyB0dXBsZVsgMCBdICsgXCJXaXRoXCIgXSggdGhpcyA9PT0gcHJvbWlzZSA/IG5ld0RlZmVyLnByb21pc2UoKSA6IHRoaXMsIGZuID8gWyByZXR1cm5lZCBdIDogYXJndW1lbnRzICk7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR9KTtcblx0XHRcdFx0XHRcdH0pO1xuXHRcdFx0XHRcdFx0Zm5zID0gbnVsbDtcblx0XHRcdFx0XHR9KS5wcm9taXNlKCk7XG5cdFx0XHRcdH0sXG5cdFx0XHRcdC8vIEdldCBhIHByb21pc2UgZm9yIHRoaXMgZGVmZXJyZWRcblx0XHRcdFx0Ly8gSWYgb2JqIGlzIHByb3ZpZGVkLCB0aGUgcHJvbWlzZSBhc3BlY3QgaXMgYWRkZWQgdG8gdGhlIG9iamVjdFxuXHRcdFx0XHRwcm9taXNlOiBmdW5jdGlvbiggb2JqICkge1xuXHRcdFx0XHRcdHJldHVybiBvYmogIT0gbnVsbCA/IGpRdWVyeS5leHRlbmQoIG9iaiwgcHJvbWlzZSApIDogcHJvbWlzZTtcblx0XHRcdFx0fVxuXHRcdFx0fSxcblx0XHRcdGRlZmVycmVkID0ge307XG5cblx0XHQvLyBLZWVwIHBpcGUgZm9yIGJhY2stY29tcGF0XG5cdFx0cHJvbWlzZS5waXBlID0gcHJvbWlzZS50aGVuO1xuXG5cdFx0Ly8gQWRkIGxpc3Qtc3BlY2lmaWMgbWV0aG9kc1xuXHRcdGpRdWVyeS5lYWNoKCB0dXBsZXMsIGZ1bmN0aW9uKCBpLCB0dXBsZSApIHtcblx0XHRcdHZhciBsaXN0ID0gdHVwbGVbIDIgXSxcblx0XHRcdFx0c3RhdGVTdHJpbmcgPSB0dXBsZVsgMyBdO1xuXG5cdFx0XHQvLyBwcm9taXNlWyBkb25lIHwgZmFpbCB8IHByb2dyZXNzIF0gPSBsaXN0LmFkZFxuXHRcdFx0cHJvbWlzZVsgdHVwbGVbMV0gXSA9IGxpc3QuYWRkO1xuXG5cdFx0XHQvLyBIYW5kbGUgc3RhdGVcblx0XHRcdGlmICggc3RhdGVTdHJpbmcgKSB7XG5cdFx0XHRcdGxpc3QuYWRkKGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdC8vIHN0YXRlID0gWyByZXNvbHZlZCB8IHJlamVjdGVkIF1cblx0XHRcdFx0XHRzdGF0ZSA9IHN0YXRlU3RyaW5nO1xuXG5cdFx0XHRcdC8vIFsgcmVqZWN0X2xpc3QgfCByZXNvbHZlX2xpc3QgXS5kaXNhYmxlOyBwcm9ncmVzc19saXN0LmxvY2tcblx0XHRcdFx0fSwgdHVwbGVzWyBpIF4gMSBdWyAyIF0uZGlzYWJsZSwgdHVwbGVzWyAyIF1bIDIgXS5sb2NrICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIGRlZmVycmVkWyByZXNvbHZlIHwgcmVqZWN0IHwgbm90aWZ5IF1cblx0XHRcdGRlZmVycmVkWyB0dXBsZVswXSBdID0gZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGRlZmVycmVkWyB0dXBsZVswXSArIFwiV2l0aFwiIF0oIHRoaXMgPT09IGRlZmVycmVkID8gcHJvbWlzZSA6IHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdFx0XHRyZXR1cm4gdGhpcztcblx0XHRcdH07XG5cdFx0XHRkZWZlcnJlZFsgdHVwbGVbMF0gKyBcIldpdGhcIiBdID0gbGlzdC5maXJlV2l0aDtcblx0XHR9KTtcblxuXHRcdC8vIE1ha2UgdGhlIGRlZmVycmVkIGEgcHJvbWlzZVxuXHRcdHByb21pc2UucHJvbWlzZSggZGVmZXJyZWQgKTtcblxuXHRcdC8vIENhbGwgZ2l2ZW4gZnVuYyBpZiBhbnlcblx0XHRpZiAoIGZ1bmMgKSB7XG5cdFx0XHRmdW5jLmNhbGwoIGRlZmVycmVkLCBkZWZlcnJlZCApO1xuXHRcdH1cblxuXHRcdC8vIEFsbCBkb25lIVxuXHRcdHJldHVybiBkZWZlcnJlZDtcblx0fSxcblxuXHQvLyBEZWZlcnJlZCBoZWxwZXJcblx0d2hlbjogZnVuY3Rpb24oIHN1Ym9yZGluYXRlIC8qICwgLi4uLCBzdWJvcmRpbmF0ZU4gKi8gKSB7XG5cdFx0dmFyIGkgPSAwLFxuXHRcdFx0cmVzb2x2ZVZhbHVlcyA9IHNsaWNlLmNhbGwoIGFyZ3VtZW50cyApLFxuXHRcdFx0bGVuZ3RoID0gcmVzb2x2ZVZhbHVlcy5sZW5ndGgsXG5cblx0XHRcdC8vIHRoZSBjb3VudCBvZiB1bmNvbXBsZXRlZCBzdWJvcmRpbmF0ZXNcblx0XHRcdHJlbWFpbmluZyA9IGxlbmd0aCAhPT0gMSB8fCAoIHN1Ym9yZGluYXRlICYmIGpRdWVyeS5pc0Z1bmN0aW9uKCBzdWJvcmRpbmF0ZS5wcm9taXNlICkgKSA/IGxlbmd0aCA6IDAsXG5cblx0XHRcdC8vIHRoZSBtYXN0ZXIgRGVmZXJyZWQuIElmIHJlc29sdmVWYWx1ZXMgY29uc2lzdCBvZiBvbmx5IGEgc2luZ2xlIERlZmVycmVkLCBqdXN0IHVzZSB0aGF0LlxuXHRcdFx0ZGVmZXJyZWQgPSByZW1haW5pbmcgPT09IDEgPyBzdWJvcmRpbmF0ZSA6IGpRdWVyeS5EZWZlcnJlZCgpLFxuXG5cdFx0XHQvLyBVcGRhdGUgZnVuY3Rpb24gZm9yIGJvdGggcmVzb2x2ZSBhbmQgcHJvZ3Jlc3MgdmFsdWVzXG5cdFx0XHR1cGRhdGVGdW5jID0gZnVuY3Rpb24oIGksIGNvbnRleHRzLCB2YWx1ZXMgKSB7XG5cdFx0XHRcdHJldHVybiBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0XHRcdFx0Y29udGV4dHNbIGkgXSA9IHRoaXM7XG5cdFx0XHRcdFx0dmFsdWVzWyBpIF0gPSBhcmd1bWVudHMubGVuZ3RoID4gMSA/IHNsaWNlLmNhbGwoIGFyZ3VtZW50cyApIDogdmFsdWU7XG5cdFx0XHRcdFx0aWYgKCB2YWx1ZXMgPT09IHByb2dyZXNzVmFsdWVzICkge1xuXHRcdFx0XHRcdFx0ZGVmZXJyZWQubm90aWZ5V2l0aCggY29udGV4dHMsIHZhbHVlcyApO1xuXHRcdFx0XHRcdH0gZWxzZSBpZiAoICEoIC0tcmVtYWluaW5nICkgKSB7XG5cdFx0XHRcdFx0XHRkZWZlcnJlZC5yZXNvbHZlV2l0aCggY29udGV4dHMsIHZhbHVlcyApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fTtcblx0XHRcdH0sXG5cblx0XHRcdHByb2dyZXNzVmFsdWVzLCBwcm9ncmVzc0NvbnRleHRzLCByZXNvbHZlQ29udGV4dHM7XG5cblx0XHQvLyBBZGQgbGlzdGVuZXJzIHRvIERlZmVycmVkIHN1Ym9yZGluYXRlczsgdHJlYXQgb3RoZXJzIGFzIHJlc29sdmVkXG5cdFx0aWYgKCBsZW5ndGggPiAxICkge1xuXHRcdFx0cHJvZ3Jlc3NWYWx1ZXMgPSBuZXcgQXJyYXkoIGxlbmd0aCApO1xuXHRcdFx0cHJvZ3Jlc3NDb250ZXh0cyA9IG5ldyBBcnJheSggbGVuZ3RoICk7XG5cdFx0XHRyZXNvbHZlQ29udGV4dHMgPSBuZXcgQXJyYXkoIGxlbmd0aCApO1xuXHRcdFx0Zm9yICggOyBpIDwgbGVuZ3RoOyBpKysgKSB7XG5cdFx0XHRcdGlmICggcmVzb2x2ZVZhbHVlc1sgaSBdICYmIGpRdWVyeS5pc0Z1bmN0aW9uKCByZXNvbHZlVmFsdWVzWyBpIF0ucHJvbWlzZSApICkge1xuXHRcdFx0XHRcdHJlc29sdmVWYWx1ZXNbIGkgXS5wcm9taXNlKClcblx0XHRcdFx0XHRcdC5kb25lKCB1cGRhdGVGdW5jKCBpLCByZXNvbHZlQ29udGV4dHMsIHJlc29sdmVWYWx1ZXMgKSApXG5cdFx0XHRcdFx0XHQuZmFpbCggZGVmZXJyZWQucmVqZWN0IClcblx0XHRcdFx0XHRcdC5wcm9ncmVzcyggdXBkYXRlRnVuYyggaSwgcHJvZ3Jlc3NDb250ZXh0cywgcHJvZ3Jlc3NWYWx1ZXMgKSApO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdC0tcmVtYWluaW5nO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gSWYgd2UncmUgbm90IHdhaXRpbmcgb24gYW55dGhpbmcsIHJlc29sdmUgdGhlIG1hc3RlclxuXHRcdGlmICggIXJlbWFpbmluZyApIHtcblx0XHRcdGRlZmVycmVkLnJlc29sdmVXaXRoKCByZXNvbHZlQ29udGV4dHMsIHJlc29sdmVWYWx1ZXMgKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gZGVmZXJyZWQucHJvbWlzZSgpO1xuXHR9XG59KTtcblxuXG4vLyBUaGUgZGVmZXJyZWQgdXNlZCBvbiBET00gcmVhZHlcbnZhciByZWFkeUxpc3Q7XG5cbmpRdWVyeS5mbi5yZWFkeSA9IGZ1bmN0aW9uKCBmbiApIHtcblx0Ly8gQWRkIHRoZSBjYWxsYmFja1xuXHRqUXVlcnkucmVhZHkucHJvbWlzZSgpLmRvbmUoIGZuICk7XG5cblx0cmV0dXJuIHRoaXM7XG59O1xuXG5qUXVlcnkuZXh0ZW5kKHtcblx0Ly8gSXMgdGhlIERPTSByZWFkeSB0byBiZSB1c2VkPyBTZXQgdG8gdHJ1ZSBvbmNlIGl0IG9jY3Vycy5cblx0aXNSZWFkeTogZmFsc2UsXG5cblx0Ly8gQSBjb3VudGVyIHRvIHRyYWNrIGhvdyBtYW55IGl0ZW1zIHRvIHdhaXQgZm9yIGJlZm9yZVxuXHQvLyB0aGUgcmVhZHkgZXZlbnQgZmlyZXMuIFNlZSAjNjc4MVxuXHRyZWFkeVdhaXQ6IDEsXG5cblx0Ly8gSG9sZCAob3IgcmVsZWFzZSkgdGhlIHJlYWR5IGV2ZW50XG5cdGhvbGRSZWFkeTogZnVuY3Rpb24oIGhvbGQgKSB7XG5cdFx0aWYgKCBob2xkICkge1xuXHRcdFx0alF1ZXJ5LnJlYWR5V2FpdCsrO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRqUXVlcnkucmVhZHkoIHRydWUgKTtcblx0XHR9XG5cdH0sXG5cblx0Ly8gSGFuZGxlIHdoZW4gdGhlIERPTSBpcyByZWFkeVxuXHRyZWFkeTogZnVuY3Rpb24oIHdhaXQgKSB7XG5cblx0XHQvLyBBYm9ydCBpZiB0aGVyZSBhcmUgcGVuZGluZyBob2xkcyBvciB3ZSdyZSBhbHJlYWR5IHJlYWR5XG5cdFx0aWYgKCB3YWl0ID09PSB0cnVlID8gLS1qUXVlcnkucmVhZHlXYWl0IDogalF1ZXJ5LmlzUmVhZHkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gUmVtZW1iZXIgdGhhdCB0aGUgRE9NIGlzIHJlYWR5XG5cdFx0alF1ZXJ5LmlzUmVhZHkgPSB0cnVlO1xuXG5cdFx0Ly8gSWYgYSBub3JtYWwgRE9NIFJlYWR5IGV2ZW50IGZpcmVkLCBkZWNyZW1lbnQsIGFuZCB3YWl0IGlmIG5lZWQgYmVcblx0XHRpZiAoIHdhaXQgIT09IHRydWUgJiYgLS1qUXVlcnkucmVhZHlXYWl0ID4gMCApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBJZiB0aGVyZSBhcmUgZnVuY3Rpb25zIGJvdW5kLCB0byBleGVjdXRlXG5cdFx0cmVhZHlMaXN0LnJlc29sdmVXaXRoKCBkb2N1bWVudCwgWyBqUXVlcnkgXSApO1xuXG5cdFx0Ly8gVHJpZ2dlciBhbnkgYm91bmQgcmVhZHkgZXZlbnRzXG5cdFx0aWYgKCBqUXVlcnkuZm4udHJpZ2dlckhhbmRsZXIgKSB7XG5cdFx0XHRqUXVlcnkoIGRvY3VtZW50ICkudHJpZ2dlckhhbmRsZXIoIFwicmVhZHlcIiApO1xuXHRcdFx0alF1ZXJ5KCBkb2N1bWVudCApLm9mZiggXCJyZWFkeVwiICk7XG5cdFx0fVxuXHR9XG59KTtcblxuLyoqXG4gKiBUaGUgcmVhZHkgZXZlbnQgaGFuZGxlciBhbmQgc2VsZiBjbGVhbnVwIG1ldGhvZFxuICovXG5mdW5jdGlvbiBjb21wbGV0ZWQoKSB7XG5cdGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoIFwiRE9NQ29udGVudExvYWRlZFwiLCBjb21wbGV0ZWQsIGZhbHNlICk7XG5cdHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCBcImxvYWRcIiwgY29tcGxldGVkLCBmYWxzZSApO1xuXHRqUXVlcnkucmVhZHkoKTtcbn1cblxualF1ZXJ5LnJlYWR5LnByb21pc2UgPSBmdW5jdGlvbiggb2JqICkge1xuXHRpZiAoICFyZWFkeUxpc3QgKSB7XG5cblx0XHRyZWFkeUxpc3QgPSBqUXVlcnkuRGVmZXJyZWQoKTtcblxuXHRcdC8vIENhdGNoIGNhc2VzIHdoZXJlICQoZG9jdW1lbnQpLnJlYWR5KCkgaXMgY2FsbGVkIGFmdGVyIHRoZSBicm93c2VyIGV2ZW50IGhhcyBhbHJlYWR5IG9jY3VycmVkLlxuXHRcdC8vIFdlIG9uY2UgdHJpZWQgdG8gdXNlIHJlYWR5U3RhdGUgXCJpbnRlcmFjdGl2ZVwiIGhlcmUsIGJ1dCBpdCBjYXVzZWQgaXNzdWVzIGxpa2UgdGhlIG9uZVxuXHRcdC8vIGRpc2NvdmVyZWQgYnkgQ2hyaXNTIGhlcmU6IGh0dHA6Ly9idWdzLmpxdWVyeS5jb20vdGlja2V0LzEyMjgyI2NvbW1lbnQ6MTVcblx0XHRpZiAoIGRvY3VtZW50LnJlYWR5U3RhdGUgPT09IFwiY29tcGxldGVcIiApIHtcblx0XHRcdC8vIEhhbmRsZSBpdCBhc3luY2hyb25vdXNseSB0byBhbGxvdyBzY3JpcHRzIHRoZSBvcHBvcnR1bml0eSB0byBkZWxheSByZWFkeVxuXHRcdFx0c2V0VGltZW91dCggalF1ZXJ5LnJlYWR5ICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHQvLyBVc2UgdGhlIGhhbmR5IGV2ZW50IGNhbGxiYWNrXG5cdFx0XHRkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCBcIkRPTUNvbnRlbnRMb2FkZWRcIiwgY29tcGxldGVkLCBmYWxzZSApO1xuXG5cdFx0XHQvLyBBIGZhbGxiYWNrIHRvIHdpbmRvdy5vbmxvYWQsIHRoYXQgd2lsbCBhbHdheXMgd29ya1xuXHRcdFx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoIFwibG9hZFwiLCBjb21wbGV0ZWQsIGZhbHNlICk7XG5cdFx0fVxuXHR9XG5cdHJldHVybiByZWFkeUxpc3QucHJvbWlzZSggb2JqICk7XG59O1xuXG4vLyBLaWNrIG9mZiB0aGUgRE9NIHJlYWR5IGNoZWNrIGV2ZW4gaWYgdGhlIHVzZXIgZG9lcyBub3RcbmpRdWVyeS5yZWFkeS5wcm9taXNlKCk7XG5cblxuXG5cbi8vIE11bHRpZnVuY3Rpb25hbCBtZXRob2QgdG8gZ2V0IGFuZCBzZXQgdmFsdWVzIG9mIGEgY29sbGVjdGlvblxuLy8gVGhlIHZhbHVlL3MgY2FuIG9wdGlvbmFsbHkgYmUgZXhlY3V0ZWQgaWYgaXQncyBhIGZ1bmN0aW9uXG52YXIgYWNjZXNzID0galF1ZXJ5LmFjY2VzcyA9IGZ1bmN0aW9uKCBlbGVtcywgZm4sIGtleSwgdmFsdWUsIGNoYWluYWJsZSwgZW1wdHlHZXQsIHJhdyApIHtcblx0dmFyIGkgPSAwLFxuXHRcdGxlbiA9IGVsZW1zLmxlbmd0aCxcblx0XHRidWxrID0ga2V5ID09IG51bGw7XG5cblx0Ly8gU2V0cyBtYW55IHZhbHVlc1xuXHRpZiAoIGpRdWVyeS50eXBlKCBrZXkgKSA9PT0gXCJvYmplY3RcIiApIHtcblx0XHRjaGFpbmFibGUgPSB0cnVlO1xuXHRcdGZvciAoIGkgaW4ga2V5ICkge1xuXHRcdFx0alF1ZXJ5LmFjY2VzcyggZWxlbXMsIGZuLCBpLCBrZXlbaV0sIHRydWUsIGVtcHR5R2V0LCByYXcgKTtcblx0XHR9XG5cblx0Ly8gU2V0cyBvbmUgdmFsdWVcblx0fSBlbHNlIGlmICggdmFsdWUgIT09IHVuZGVmaW5lZCApIHtcblx0XHRjaGFpbmFibGUgPSB0cnVlO1xuXG5cdFx0aWYgKCAhalF1ZXJ5LmlzRnVuY3Rpb24oIHZhbHVlICkgKSB7XG5cdFx0XHRyYXcgPSB0cnVlO1xuXHRcdH1cblxuXHRcdGlmICggYnVsayApIHtcblx0XHRcdC8vIEJ1bGsgb3BlcmF0aW9ucyBydW4gYWdhaW5zdCB0aGUgZW50aXJlIHNldFxuXHRcdFx0aWYgKCByYXcgKSB7XG5cdFx0XHRcdGZuLmNhbGwoIGVsZW1zLCB2YWx1ZSApO1xuXHRcdFx0XHRmbiA9IG51bGw7XG5cblx0XHRcdC8vIC4uLmV4Y2VwdCB3aGVuIGV4ZWN1dGluZyBmdW5jdGlvbiB2YWx1ZXNcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGJ1bGsgPSBmbjtcblx0XHRcdFx0Zm4gPSBmdW5jdGlvbiggZWxlbSwga2V5LCB2YWx1ZSApIHtcblx0XHRcdFx0XHRyZXR1cm4gYnVsay5jYWxsKCBqUXVlcnkoIGVsZW0gKSwgdmFsdWUgKTtcblx0XHRcdFx0fTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAoIGZuICkge1xuXHRcdFx0Zm9yICggOyBpIDwgbGVuOyBpKysgKSB7XG5cdFx0XHRcdGZuKCBlbGVtc1tpXSwga2V5LCByYXcgPyB2YWx1ZSA6IHZhbHVlLmNhbGwoIGVsZW1zW2ldLCBpLCBmbiggZWxlbXNbaV0sIGtleSApICkgKTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHRyZXR1cm4gY2hhaW5hYmxlID9cblx0XHRlbGVtcyA6XG5cblx0XHQvLyBHZXRzXG5cdFx0YnVsayA/XG5cdFx0XHRmbi5jYWxsKCBlbGVtcyApIDpcblx0XHRcdGxlbiA/IGZuKCBlbGVtc1swXSwga2V5ICkgOiBlbXB0eUdldDtcbn07XG5cblxuLyoqXG4gKiBEZXRlcm1pbmVzIHdoZXRoZXIgYW4gb2JqZWN0IGNhbiBoYXZlIGRhdGFcbiAqL1xualF1ZXJ5LmFjY2VwdERhdGEgPSBmdW5jdGlvbiggb3duZXIgKSB7XG5cdC8vIEFjY2VwdHMgb25seTpcblx0Ly8gIC0gTm9kZVxuXHQvLyAgICAtIE5vZGUuRUxFTUVOVF9OT0RFXG5cdC8vICAgIC0gTm9kZS5ET0NVTUVOVF9OT0RFXG5cdC8vICAtIE9iamVjdFxuXHQvLyAgICAtIEFueVxuXHQvKiBqc2hpbnQgLVcwMTggKi9cblx0cmV0dXJuIG93bmVyLm5vZGVUeXBlID09PSAxIHx8IG93bmVyLm5vZGVUeXBlID09PSA5IHx8ICEoICtvd25lci5ub2RlVHlwZSApO1xufTtcblxuXG5mdW5jdGlvbiBEYXRhKCkge1xuXHQvLyBTdXBwb3J0OiBBbmRyb2lkPDQsXG5cdC8vIE9sZCBXZWJLaXQgZG9lcyBub3QgaGF2ZSBPYmplY3QucHJldmVudEV4dGVuc2lvbnMvZnJlZXplIG1ldGhvZCxcblx0Ly8gcmV0dXJuIG5ldyBlbXB0eSBvYmplY3QgaW5zdGVhZCB3aXRoIG5vIFtbc2V0XV0gYWNjZXNzb3Jcblx0T2JqZWN0LmRlZmluZVByb3BlcnR5KCB0aGlzLmNhY2hlID0ge30sIDAsIHtcblx0XHRnZXQ6IGZ1bmN0aW9uKCkge1xuXHRcdFx0cmV0dXJuIHt9O1xuXHRcdH1cblx0fSk7XG5cblx0dGhpcy5leHBhbmRvID0galF1ZXJ5LmV4cGFuZG8gKyBEYXRhLnVpZCsrO1xufVxuXG5EYXRhLnVpZCA9IDE7XG5EYXRhLmFjY2VwdHMgPSBqUXVlcnkuYWNjZXB0RGF0YTtcblxuRGF0YS5wcm90b3R5cGUgPSB7XG5cdGtleTogZnVuY3Rpb24oIG93bmVyICkge1xuXHRcdC8vIFdlIGNhbiBhY2NlcHQgZGF0YSBmb3Igbm9uLWVsZW1lbnQgbm9kZXMgaW4gbW9kZXJuIGJyb3dzZXJzLFxuXHRcdC8vIGJ1dCB3ZSBzaG91bGQgbm90LCBzZWUgIzgzMzUuXG5cdFx0Ly8gQWx3YXlzIHJldHVybiB0aGUga2V5IGZvciBhIGZyb3plbiBvYmplY3QuXG5cdFx0aWYgKCAhRGF0YS5hY2NlcHRzKCBvd25lciApICkge1xuXHRcdFx0cmV0dXJuIDA7XG5cdFx0fVxuXG5cdFx0dmFyIGRlc2NyaXB0b3IgPSB7fSxcblx0XHRcdC8vIENoZWNrIGlmIHRoZSBvd25lciBvYmplY3QgYWxyZWFkeSBoYXMgYSBjYWNoZSBrZXlcblx0XHRcdHVubG9jayA9IG93bmVyWyB0aGlzLmV4cGFuZG8gXTtcblxuXHRcdC8vIElmIG5vdCwgY3JlYXRlIG9uZVxuXHRcdGlmICggIXVubG9jayApIHtcblx0XHRcdHVubG9jayA9IERhdGEudWlkKys7XG5cblx0XHRcdC8vIFNlY3VyZSBpdCBpbiBhIG5vbi1lbnVtZXJhYmxlLCBub24td3JpdGFibGUgcHJvcGVydHlcblx0XHRcdHRyeSB7XG5cdFx0XHRcdGRlc2NyaXB0b3JbIHRoaXMuZXhwYW5kbyBdID0geyB2YWx1ZTogdW5sb2NrIH07XG5cdFx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKCBvd25lciwgZGVzY3JpcHRvciApO1xuXG5cdFx0XHQvLyBTdXBwb3J0OiBBbmRyb2lkPDRcblx0XHRcdC8vIEZhbGxiYWNrIHRvIGEgbGVzcyBzZWN1cmUgZGVmaW5pdGlvblxuXHRcdFx0fSBjYXRjaCAoIGUgKSB7XG5cdFx0XHRcdGRlc2NyaXB0b3JbIHRoaXMuZXhwYW5kbyBdID0gdW5sb2NrO1xuXHRcdFx0XHRqUXVlcnkuZXh0ZW5kKCBvd25lciwgZGVzY3JpcHRvciApO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIEVuc3VyZSB0aGUgY2FjaGUgb2JqZWN0XG5cdFx0aWYgKCAhdGhpcy5jYWNoZVsgdW5sb2NrIF0gKSB7XG5cdFx0XHR0aGlzLmNhY2hlWyB1bmxvY2sgXSA9IHt9O1xuXHRcdH1cblxuXHRcdHJldHVybiB1bmxvY2s7XG5cdH0sXG5cdHNldDogZnVuY3Rpb24oIG93bmVyLCBkYXRhLCB2YWx1ZSApIHtcblx0XHR2YXIgcHJvcCxcblx0XHRcdC8vIFRoZXJlIG1heSBiZSBhbiB1bmxvY2sgYXNzaWduZWQgdG8gdGhpcyBub2RlLFxuXHRcdFx0Ly8gaWYgdGhlcmUgaXMgbm8gZW50cnkgZm9yIHRoaXMgXCJvd25lclwiLCBjcmVhdGUgb25lIGlubGluZVxuXHRcdFx0Ly8gYW5kIHNldCB0aGUgdW5sb2NrIGFzIHRob3VnaCBhbiBvd25lciBlbnRyeSBoYWQgYWx3YXlzIGV4aXN0ZWRcblx0XHRcdHVubG9jayA9IHRoaXMua2V5KCBvd25lciApLFxuXHRcdFx0Y2FjaGUgPSB0aGlzLmNhY2hlWyB1bmxvY2sgXTtcblxuXHRcdC8vIEhhbmRsZTogWyBvd25lciwga2V5LCB2YWx1ZSBdIGFyZ3Ncblx0XHRpZiAoIHR5cGVvZiBkYXRhID09PSBcInN0cmluZ1wiICkge1xuXHRcdFx0Y2FjaGVbIGRhdGEgXSA9IHZhbHVlO1xuXG5cdFx0Ly8gSGFuZGxlOiBbIG93bmVyLCB7IHByb3BlcnRpZXMgfSBdIGFyZ3Ncblx0XHR9IGVsc2Uge1xuXHRcdFx0Ly8gRnJlc2ggYXNzaWdubWVudHMgYnkgb2JqZWN0IGFyZSBzaGFsbG93IGNvcGllZFxuXHRcdFx0aWYgKCBqUXVlcnkuaXNFbXB0eU9iamVjdCggY2FjaGUgKSApIHtcblx0XHRcdFx0alF1ZXJ5LmV4dGVuZCggdGhpcy5jYWNoZVsgdW5sb2NrIF0sIGRhdGEgKTtcblx0XHRcdC8vIE90aGVyd2lzZSwgY29weSB0aGUgcHJvcGVydGllcyBvbmUtYnktb25lIHRvIHRoZSBjYWNoZSBvYmplY3Rcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGZvciAoIHByb3AgaW4gZGF0YSApIHtcblx0XHRcdFx0XHRjYWNoZVsgcHJvcCBdID0gZGF0YVsgcHJvcCBdO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHJldHVybiBjYWNoZTtcblx0fSxcblx0Z2V0OiBmdW5jdGlvbiggb3duZXIsIGtleSApIHtcblx0XHQvLyBFaXRoZXIgYSB2YWxpZCBjYWNoZSBpcyBmb3VuZCwgb3Igd2lsbCBiZSBjcmVhdGVkLlxuXHRcdC8vIE5ldyBjYWNoZXMgd2lsbCBiZSBjcmVhdGVkIGFuZCB0aGUgdW5sb2NrIHJldHVybmVkLFxuXHRcdC8vIGFsbG93aW5nIGRpcmVjdCBhY2Nlc3MgdG8gdGhlIG5ld2x5IGNyZWF0ZWRcblx0XHQvLyBlbXB0eSBkYXRhIG9iamVjdC4gQSB2YWxpZCBvd25lciBvYmplY3QgbXVzdCBiZSBwcm92aWRlZC5cblx0XHR2YXIgY2FjaGUgPSB0aGlzLmNhY2hlWyB0aGlzLmtleSggb3duZXIgKSBdO1xuXG5cdFx0cmV0dXJuIGtleSA9PT0gdW5kZWZpbmVkID9cblx0XHRcdGNhY2hlIDogY2FjaGVbIGtleSBdO1xuXHR9LFxuXHRhY2Nlc3M6IGZ1bmN0aW9uKCBvd25lciwga2V5LCB2YWx1ZSApIHtcblx0XHR2YXIgc3RvcmVkO1xuXHRcdC8vIEluIGNhc2VzIHdoZXJlIGVpdGhlcjpcblx0XHQvL1xuXHRcdC8vICAgMS4gTm8ga2V5IHdhcyBzcGVjaWZpZWRcblx0XHQvLyAgIDIuIEEgc3RyaW5nIGtleSB3YXMgc3BlY2lmaWVkLCBidXQgbm8gdmFsdWUgcHJvdmlkZWRcblx0XHQvL1xuXHRcdC8vIFRha2UgdGhlIFwicmVhZFwiIHBhdGggYW5kIGFsbG93IHRoZSBnZXQgbWV0aG9kIHRvIGRldGVybWluZVxuXHRcdC8vIHdoaWNoIHZhbHVlIHRvIHJldHVybiwgcmVzcGVjdGl2ZWx5IGVpdGhlcjpcblx0XHQvL1xuXHRcdC8vICAgMS4gVGhlIGVudGlyZSBjYWNoZSBvYmplY3Rcblx0XHQvLyAgIDIuIFRoZSBkYXRhIHN0b3JlZCBhdCB0aGUga2V5XG5cdFx0Ly9cblx0XHRpZiAoIGtleSA9PT0gdW5kZWZpbmVkIHx8XG5cdFx0XHRcdCgoa2V5ICYmIHR5cGVvZiBrZXkgPT09IFwic3RyaW5nXCIpICYmIHZhbHVlID09PSB1bmRlZmluZWQpICkge1xuXG5cdFx0XHRzdG9yZWQgPSB0aGlzLmdldCggb3duZXIsIGtleSApO1xuXG5cdFx0XHRyZXR1cm4gc3RvcmVkICE9PSB1bmRlZmluZWQgP1xuXHRcdFx0XHRzdG9yZWQgOiB0aGlzLmdldCggb3duZXIsIGpRdWVyeS5jYW1lbENhc2Uoa2V5KSApO1xuXHRcdH1cblxuXHRcdC8vIFsqXVdoZW4gdGhlIGtleSBpcyBub3QgYSBzdHJpbmcsIG9yIGJvdGggYSBrZXkgYW5kIHZhbHVlXG5cdFx0Ly8gYXJlIHNwZWNpZmllZCwgc2V0IG9yIGV4dGVuZCAoZXhpc3Rpbmcgb2JqZWN0cykgd2l0aCBlaXRoZXI6XG5cdFx0Ly9cblx0XHQvLyAgIDEuIEFuIG9iamVjdCBvZiBwcm9wZXJ0aWVzXG5cdFx0Ly8gICAyLiBBIGtleSBhbmQgdmFsdWVcblx0XHQvL1xuXHRcdHRoaXMuc2V0KCBvd25lciwga2V5LCB2YWx1ZSApO1xuXG5cdFx0Ly8gU2luY2UgdGhlIFwic2V0XCIgcGF0aCBjYW4gaGF2ZSB0d28gcG9zc2libGUgZW50cnkgcG9pbnRzXG5cdFx0Ly8gcmV0dXJuIHRoZSBleHBlY3RlZCBkYXRhIGJhc2VkIG9uIHdoaWNoIHBhdGggd2FzIHRha2VuWypdXG5cdFx0cmV0dXJuIHZhbHVlICE9PSB1bmRlZmluZWQgPyB2YWx1ZSA6IGtleTtcblx0fSxcblx0cmVtb3ZlOiBmdW5jdGlvbiggb3duZXIsIGtleSApIHtcblx0XHR2YXIgaSwgbmFtZSwgY2FtZWwsXG5cdFx0XHR1bmxvY2sgPSB0aGlzLmtleSggb3duZXIgKSxcblx0XHRcdGNhY2hlID0gdGhpcy5jYWNoZVsgdW5sb2NrIF07XG5cblx0XHRpZiAoIGtleSA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0dGhpcy5jYWNoZVsgdW5sb2NrIF0gPSB7fTtcblxuXHRcdH0gZWxzZSB7XG5cdFx0XHQvLyBTdXBwb3J0IGFycmF5IG9yIHNwYWNlIHNlcGFyYXRlZCBzdHJpbmcgb2Yga2V5c1xuXHRcdFx0aWYgKCBqUXVlcnkuaXNBcnJheSgga2V5ICkgKSB7XG5cdFx0XHRcdC8vIElmIFwibmFtZVwiIGlzIGFuIGFycmF5IG9mIGtleXMuLi5cblx0XHRcdFx0Ly8gV2hlbiBkYXRhIGlzIGluaXRpYWxseSBjcmVhdGVkLCB2aWEgKFwia2V5XCIsIFwidmFsXCIpIHNpZ25hdHVyZSxcblx0XHRcdFx0Ly8ga2V5cyB3aWxsIGJlIGNvbnZlcnRlZCB0byBjYW1lbENhc2UuXG5cdFx0XHRcdC8vIFNpbmNlIHRoZXJlIGlzIG5vIHdheSB0byB0ZWxsIF9ob3dfIGEga2V5IHdhcyBhZGRlZCwgcmVtb3ZlXG5cdFx0XHRcdC8vIGJvdGggcGxhaW4ga2V5IGFuZCBjYW1lbENhc2Uga2V5LiAjMTI3ODZcblx0XHRcdFx0Ly8gVGhpcyB3aWxsIG9ubHkgcGVuYWxpemUgdGhlIGFycmF5IGFyZ3VtZW50IHBhdGguXG5cdFx0XHRcdG5hbWUgPSBrZXkuY29uY2F0KCBrZXkubWFwKCBqUXVlcnkuY2FtZWxDYXNlICkgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGNhbWVsID0galF1ZXJ5LmNhbWVsQ2FzZSgga2V5ICk7XG5cdFx0XHRcdC8vIFRyeSB0aGUgc3RyaW5nIGFzIGEga2V5IGJlZm9yZSBhbnkgbWFuaXB1bGF0aW9uXG5cdFx0XHRcdGlmICgga2V5IGluIGNhY2hlICkge1xuXHRcdFx0XHRcdG5hbWUgPSBbIGtleSwgY2FtZWwgXTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHQvLyBJZiBhIGtleSB3aXRoIHRoZSBzcGFjZXMgZXhpc3RzLCB1c2UgaXQuXG5cdFx0XHRcdFx0Ly8gT3RoZXJ3aXNlLCBjcmVhdGUgYW4gYXJyYXkgYnkgbWF0Y2hpbmcgbm9uLXdoaXRlc3BhY2Vcblx0XHRcdFx0XHRuYW1lID0gY2FtZWw7XG5cdFx0XHRcdFx0bmFtZSA9IG5hbWUgaW4gY2FjaGUgP1xuXHRcdFx0XHRcdFx0WyBuYW1lIF0gOiAoIG5hbWUubWF0Y2goIHJub3R3aGl0ZSApIHx8IFtdICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0aSA9IG5hbWUubGVuZ3RoO1xuXHRcdFx0d2hpbGUgKCBpLS0gKSB7XG5cdFx0XHRcdGRlbGV0ZSBjYWNoZVsgbmFtZVsgaSBdIF07XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXHRoYXNEYXRhOiBmdW5jdGlvbiggb3duZXIgKSB7XG5cdFx0cmV0dXJuICFqUXVlcnkuaXNFbXB0eU9iamVjdChcblx0XHRcdHRoaXMuY2FjaGVbIG93bmVyWyB0aGlzLmV4cGFuZG8gXSBdIHx8IHt9XG5cdFx0KTtcblx0fSxcblx0ZGlzY2FyZDogZnVuY3Rpb24oIG93bmVyICkge1xuXHRcdGlmICggb3duZXJbIHRoaXMuZXhwYW5kbyBdICkge1xuXHRcdFx0ZGVsZXRlIHRoaXMuY2FjaGVbIG93bmVyWyB0aGlzLmV4cGFuZG8gXSBdO1xuXHRcdH1cblx0fVxufTtcbnZhciBkYXRhX3ByaXYgPSBuZXcgRGF0YSgpO1xuXG52YXIgZGF0YV91c2VyID0gbmV3IERhdGEoKTtcblxuXG5cbi8vXHRJbXBsZW1lbnRhdGlvbiBTdW1tYXJ5XG4vL1xuLy9cdDEuIEVuZm9yY2UgQVBJIHN1cmZhY2UgYW5kIHNlbWFudGljIGNvbXBhdGliaWxpdHkgd2l0aCAxLjkueCBicmFuY2hcbi8vXHQyLiBJbXByb3ZlIHRoZSBtb2R1bGUncyBtYWludGFpbmFiaWxpdHkgYnkgcmVkdWNpbmcgdGhlIHN0b3JhZ2Vcbi8vXHRcdHBhdGhzIHRvIGEgc2luZ2xlIG1lY2hhbmlzbS5cbi8vXHQzLiBVc2UgdGhlIHNhbWUgc2luZ2xlIG1lY2hhbmlzbSB0byBzdXBwb3J0IFwicHJpdmF0ZVwiIGFuZCBcInVzZXJcIiBkYXRhLlxuLy9cdDQuIF9OZXZlcl8gZXhwb3NlIFwicHJpdmF0ZVwiIGRhdGEgdG8gdXNlciBjb2RlIChUT0RPOiBEcm9wIF9kYXRhLCBfcmVtb3ZlRGF0YSlcbi8vXHQ1LiBBdm9pZCBleHBvc2luZyBpbXBsZW1lbnRhdGlvbiBkZXRhaWxzIG9uIHVzZXIgb2JqZWN0cyAoZWcuIGV4cGFuZG8gcHJvcGVydGllcylcbi8vXHQ2LiBQcm92aWRlIGEgY2xlYXIgcGF0aCBmb3IgaW1wbGVtZW50YXRpb24gdXBncmFkZSB0byBXZWFrTWFwIGluIDIwMTRcblxudmFyIHJicmFjZSA9IC9eKD86XFx7W1xcd1xcV10qXFx9fFxcW1tcXHdcXFddKlxcXSkkLyxcblx0cm11bHRpRGFzaCA9IC8oW0EtWl0pL2c7XG5cbmZ1bmN0aW9uIGRhdGFBdHRyKCBlbGVtLCBrZXksIGRhdGEgKSB7XG5cdHZhciBuYW1lO1xuXG5cdC8vIElmIG5vdGhpbmcgd2FzIGZvdW5kIGludGVybmFsbHksIHRyeSB0byBmZXRjaCBhbnlcblx0Ly8gZGF0YSBmcm9tIHRoZSBIVE1MNSBkYXRhLSogYXR0cmlidXRlXG5cdGlmICggZGF0YSA9PT0gdW5kZWZpbmVkICYmIGVsZW0ubm9kZVR5cGUgPT09IDEgKSB7XG5cdFx0bmFtZSA9IFwiZGF0YS1cIiArIGtleS5yZXBsYWNlKCBybXVsdGlEYXNoLCBcIi0kMVwiICkudG9Mb3dlckNhc2UoKTtcblx0XHRkYXRhID0gZWxlbS5nZXRBdHRyaWJ1dGUoIG5hbWUgKTtcblxuXHRcdGlmICggdHlwZW9mIGRhdGEgPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHR0cnkge1xuXHRcdFx0XHRkYXRhID0gZGF0YSA9PT0gXCJ0cnVlXCIgPyB0cnVlIDpcblx0XHRcdFx0XHRkYXRhID09PSBcImZhbHNlXCIgPyBmYWxzZSA6XG5cdFx0XHRcdFx0ZGF0YSA9PT0gXCJudWxsXCIgPyBudWxsIDpcblx0XHRcdFx0XHQvLyBPbmx5IGNvbnZlcnQgdG8gYSBudW1iZXIgaWYgaXQgZG9lc24ndCBjaGFuZ2UgdGhlIHN0cmluZ1xuXHRcdFx0XHRcdCtkYXRhICsgXCJcIiA9PT0gZGF0YSA/ICtkYXRhIDpcblx0XHRcdFx0XHRyYnJhY2UudGVzdCggZGF0YSApID8galF1ZXJ5LnBhcnNlSlNPTiggZGF0YSApIDpcblx0XHRcdFx0XHRkYXRhO1xuXHRcdFx0fSBjYXRjaCggZSApIHt9XG5cblx0XHRcdC8vIE1ha2Ugc3VyZSB3ZSBzZXQgdGhlIGRhdGEgc28gaXQgaXNuJ3QgY2hhbmdlZCBsYXRlclxuXHRcdFx0ZGF0YV91c2VyLnNldCggZWxlbSwga2V5LCBkYXRhICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGRhdGEgPSB1bmRlZmluZWQ7XG5cdFx0fVxuXHR9XG5cdHJldHVybiBkYXRhO1xufVxuXG5qUXVlcnkuZXh0ZW5kKHtcblx0aGFzRGF0YTogZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0cmV0dXJuIGRhdGFfdXNlci5oYXNEYXRhKCBlbGVtICkgfHwgZGF0YV9wcml2Lmhhc0RhdGEoIGVsZW0gKTtcblx0fSxcblxuXHRkYXRhOiBmdW5jdGlvbiggZWxlbSwgbmFtZSwgZGF0YSApIHtcblx0XHRyZXR1cm4gZGF0YV91c2VyLmFjY2VzcyggZWxlbSwgbmFtZSwgZGF0YSApO1xuXHR9LFxuXG5cdHJlbW92ZURhdGE6IGZ1bmN0aW9uKCBlbGVtLCBuYW1lICkge1xuXHRcdGRhdGFfdXNlci5yZW1vdmUoIGVsZW0sIG5hbWUgKTtcblx0fSxcblxuXHQvLyBUT0RPOiBOb3cgdGhhdCBhbGwgY2FsbHMgdG8gX2RhdGEgYW5kIF9yZW1vdmVEYXRhIGhhdmUgYmVlbiByZXBsYWNlZFxuXHQvLyB3aXRoIGRpcmVjdCBjYWxscyB0byBkYXRhX3ByaXYgbWV0aG9kcywgdGhlc2UgY2FuIGJlIGRlcHJlY2F0ZWQuXG5cdF9kYXRhOiBmdW5jdGlvbiggZWxlbSwgbmFtZSwgZGF0YSApIHtcblx0XHRyZXR1cm4gZGF0YV9wcml2LmFjY2VzcyggZWxlbSwgbmFtZSwgZGF0YSApO1xuXHR9LFxuXG5cdF9yZW1vdmVEYXRhOiBmdW5jdGlvbiggZWxlbSwgbmFtZSApIHtcblx0XHRkYXRhX3ByaXYucmVtb3ZlKCBlbGVtLCBuYW1lICk7XG5cdH1cbn0pO1xuXG5qUXVlcnkuZm4uZXh0ZW5kKHtcblx0ZGF0YTogZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cdFx0dmFyIGksIG5hbWUsIGRhdGEsXG5cdFx0XHRlbGVtID0gdGhpc1sgMCBdLFxuXHRcdFx0YXR0cnMgPSBlbGVtICYmIGVsZW0uYXR0cmlidXRlcztcblxuXHRcdC8vIEdldHMgYWxsIHZhbHVlc1xuXHRcdGlmICgga2V5ID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRpZiAoIHRoaXMubGVuZ3RoICkge1xuXHRcdFx0XHRkYXRhID0gZGF0YV91c2VyLmdldCggZWxlbSApO1xuXG5cdFx0XHRcdGlmICggZWxlbS5ub2RlVHlwZSA9PT0gMSAmJiAhZGF0YV9wcml2LmdldCggZWxlbSwgXCJoYXNEYXRhQXR0cnNcIiApICkge1xuXHRcdFx0XHRcdGkgPSBhdHRycy5sZW5ndGg7XG5cdFx0XHRcdFx0d2hpbGUgKCBpLS0gKSB7XG5cblx0XHRcdFx0XHRcdC8vIFN1cHBvcnQ6IElFMTErXG5cdFx0XHRcdFx0XHQvLyBUaGUgYXR0cnMgZWxlbWVudHMgY2FuIGJlIG51bGwgKCMxNDg5NClcblx0XHRcdFx0XHRcdGlmICggYXR0cnNbIGkgXSApIHtcblx0XHRcdFx0XHRcdFx0bmFtZSA9IGF0dHJzWyBpIF0ubmFtZTtcblx0XHRcdFx0XHRcdFx0aWYgKCBuYW1lLmluZGV4T2YoIFwiZGF0YS1cIiApID09PSAwICkge1xuXHRcdFx0XHRcdFx0XHRcdG5hbWUgPSBqUXVlcnkuY2FtZWxDYXNlKCBuYW1lLnNsaWNlKDUpICk7XG5cdFx0XHRcdFx0XHRcdFx0ZGF0YUF0dHIoIGVsZW0sIG5hbWUsIGRhdGFbIG5hbWUgXSApO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGRhdGFfcHJpdi5zZXQoIGVsZW0sIFwiaGFzRGF0YUF0dHJzXCIsIHRydWUgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gZGF0YTtcblx0XHR9XG5cblx0XHQvLyBTZXRzIG11bHRpcGxlIHZhbHVlc1xuXHRcdGlmICggdHlwZW9mIGtleSA9PT0gXCJvYmplY3RcIiApIHtcblx0XHRcdHJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGRhdGFfdXNlci5zZXQoIHRoaXMsIGtleSApO1xuXHRcdFx0fSk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGFjY2VzcyggdGhpcywgZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdFx0dmFyIGRhdGEsXG5cdFx0XHRcdGNhbWVsS2V5ID0galF1ZXJ5LmNhbWVsQ2FzZSgga2V5ICk7XG5cblx0XHRcdC8vIFRoZSBjYWxsaW5nIGpRdWVyeSBvYmplY3QgKGVsZW1lbnQgbWF0Y2hlcykgaXMgbm90IGVtcHR5XG5cdFx0XHQvLyAoYW5kIHRoZXJlZm9yZSBoYXMgYW4gZWxlbWVudCBhcHBlYXJzIGF0IHRoaXNbIDAgXSkgYW5kIHRoZVxuXHRcdFx0Ly8gYHZhbHVlYCBwYXJhbWV0ZXIgd2FzIG5vdCB1bmRlZmluZWQuIEFuIGVtcHR5IGpRdWVyeSBvYmplY3Rcblx0XHRcdC8vIHdpbGwgcmVzdWx0IGluIGB1bmRlZmluZWRgIGZvciBlbGVtID0gdGhpc1sgMCBdIHdoaWNoIHdpbGxcblx0XHRcdC8vIHRocm93IGFuIGV4Y2VwdGlvbiBpZiBhbiBhdHRlbXB0IHRvIHJlYWQgYSBkYXRhIGNhY2hlIGlzIG1hZGUuXG5cdFx0XHRpZiAoIGVsZW0gJiYgdmFsdWUgPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0Ly8gQXR0ZW1wdCB0byBnZXQgZGF0YSBmcm9tIHRoZSBjYWNoZVxuXHRcdFx0XHQvLyB3aXRoIHRoZSBrZXkgYXMtaXNcblx0XHRcdFx0ZGF0YSA9IGRhdGFfdXNlci5nZXQoIGVsZW0sIGtleSApO1xuXHRcdFx0XHRpZiAoIGRhdGEgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0XHRyZXR1cm4gZGF0YTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIEF0dGVtcHQgdG8gZ2V0IGRhdGEgZnJvbSB0aGUgY2FjaGVcblx0XHRcdFx0Ly8gd2l0aCB0aGUga2V5IGNhbWVsaXplZFxuXHRcdFx0XHRkYXRhID0gZGF0YV91c2VyLmdldCggZWxlbSwgY2FtZWxLZXkgKTtcblx0XHRcdFx0aWYgKCBkYXRhICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdFx0cmV0dXJuIGRhdGE7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBBdHRlbXB0IHRvIFwiZGlzY292ZXJcIiB0aGUgZGF0YSBpblxuXHRcdFx0XHQvLyBIVE1MNSBjdXN0b20gZGF0YS0qIGF0dHJzXG5cdFx0XHRcdGRhdGEgPSBkYXRhQXR0ciggZWxlbSwgY2FtZWxLZXksIHVuZGVmaW5lZCApO1xuXHRcdFx0XHRpZiAoIGRhdGEgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0XHRyZXR1cm4gZGF0YTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIFdlIHRyaWVkIHJlYWxseSBoYXJkLCBidXQgdGhlIGRhdGEgZG9lc24ndCBleGlzdC5cblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBTZXQgdGhlIGRhdGEuLi5cblx0XHRcdHRoaXMuZWFjaChmdW5jdGlvbigpIHtcblx0XHRcdFx0Ly8gRmlyc3QsIGF0dGVtcHQgdG8gc3RvcmUgYSBjb3B5IG9yIHJlZmVyZW5jZSBvZiBhbnlcblx0XHRcdFx0Ly8gZGF0YSB0aGF0IG1pZ2h0J3ZlIGJlZW4gc3RvcmUgd2l0aCBhIGNhbWVsQ2FzZWQga2V5LlxuXHRcdFx0XHR2YXIgZGF0YSA9IGRhdGFfdXNlci5nZXQoIHRoaXMsIGNhbWVsS2V5ICk7XG5cblx0XHRcdFx0Ly8gRm9yIEhUTUw1IGRhdGEtKiBhdHRyaWJ1dGUgaW50ZXJvcCwgd2UgaGF2ZSB0b1xuXHRcdFx0XHQvLyBzdG9yZSBwcm9wZXJ0eSBuYW1lcyB3aXRoIGRhc2hlcyBpbiBhIGNhbWVsQ2FzZSBmb3JtLlxuXHRcdFx0XHQvLyBUaGlzIG1pZ2h0IG5vdCBhcHBseSB0byBhbGwgcHJvcGVydGllcy4uLipcblx0XHRcdFx0ZGF0YV91c2VyLnNldCggdGhpcywgY2FtZWxLZXksIHZhbHVlICk7XG5cblx0XHRcdFx0Ly8gKi4uLiBJbiB0aGUgY2FzZSBvZiBwcm9wZXJ0aWVzIHRoYXQgbWlnaHQgX2FjdHVhbGx5X1xuXHRcdFx0XHQvLyBoYXZlIGRhc2hlcywgd2UgbmVlZCB0byBhbHNvIHN0b3JlIGEgY29weSBvZiB0aGF0XG5cdFx0XHRcdC8vIHVuY2hhbmdlZCBwcm9wZXJ0eS5cblx0XHRcdFx0aWYgKCBrZXkuaW5kZXhPZihcIi1cIikgIT09IC0xICYmIGRhdGEgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0XHRkYXRhX3VzZXIuc2V0KCB0aGlzLCBrZXksIHZhbHVlICk7XG5cdFx0XHRcdH1cblx0XHRcdH0pO1xuXHRcdH0sIG51bGwsIHZhbHVlLCBhcmd1bWVudHMubGVuZ3RoID4gMSwgbnVsbCwgdHJ1ZSApO1xuXHR9LFxuXG5cdHJlbW92ZURhdGE6IGZ1bmN0aW9uKCBrZXkgKSB7XG5cdFx0cmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpIHtcblx0XHRcdGRhdGFfdXNlci5yZW1vdmUoIHRoaXMsIGtleSApO1xuXHRcdH0pO1xuXHR9XG59KTtcblxuXG5qUXVlcnkuZXh0ZW5kKHtcblx0cXVldWU6IGZ1bmN0aW9uKCBlbGVtLCB0eXBlLCBkYXRhICkge1xuXHRcdHZhciBxdWV1ZTtcblxuXHRcdGlmICggZWxlbSApIHtcblx0XHRcdHR5cGUgPSAoIHR5cGUgfHwgXCJmeFwiICkgKyBcInF1ZXVlXCI7XG5cdFx0XHRxdWV1ZSA9IGRhdGFfcHJpdi5nZXQoIGVsZW0sIHR5cGUgKTtcblxuXHRcdFx0Ly8gU3BlZWQgdXAgZGVxdWV1ZSBieSBnZXR0aW5nIG91dCBxdWlja2x5IGlmIHRoaXMgaXMganVzdCBhIGxvb2t1cFxuXHRcdFx0aWYgKCBkYXRhICkge1xuXHRcdFx0XHRpZiAoICFxdWV1ZSB8fCBqUXVlcnkuaXNBcnJheSggZGF0YSApICkge1xuXHRcdFx0XHRcdHF1ZXVlID0gZGF0YV9wcml2LmFjY2VzcyggZWxlbSwgdHlwZSwgalF1ZXJ5Lm1ha2VBcnJheShkYXRhKSApO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHF1ZXVlLnB1c2goIGRhdGEgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHF1ZXVlIHx8IFtdO1xuXHRcdH1cblx0fSxcblxuXHRkZXF1ZXVlOiBmdW5jdGlvbiggZWxlbSwgdHlwZSApIHtcblx0XHR0eXBlID0gdHlwZSB8fCBcImZ4XCI7XG5cblx0XHR2YXIgcXVldWUgPSBqUXVlcnkucXVldWUoIGVsZW0sIHR5cGUgKSxcblx0XHRcdHN0YXJ0TGVuZ3RoID0gcXVldWUubGVuZ3RoLFxuXHRcdFx0Zm4gPSBxdWV1ZS5zaGlmdCgpLFxuXHRcdFx0aG9va3MgPSBqUXVlcnkuX3F1ZXVlSG9va3MoIGVsZW0sIHR5cGUgKSxcblx0XHRcdG5leHQgPSBmdW5jdGlvbigpIHtcblx0XHRcdFx0alF1ZXJ5LmRlcXVldWUoIGVsZW0sIHR5cGUgKTtcblx0XHRcdH07XG5cblx0XHQvLyBJZiB0aGUgZnggcXVldWUgaXMgZGVxdWV1ZWQsIGFsd2F5cyByZW1vdmUgdGhlIHByb2dyZXNzIHNlbnRpbmVsXG5cdFx0aWYgKCBmbiA9PT0gXCJpbnByb2dyZXNzXCIgKSB7XG5cdFx0XHRmbiA9IHF1ZXVlLnNoaWZ0KCk7XG5cdFx0XHRzdGFydExlbmd0aC0tO1xuXHRcdH1cblxuXHRcdGlmICggZm4gKSB7XG5cblx0XHRcdC8vIEFkZCBhIHByb2dyZXNzIHNlbnRpbmVsIHRvIHByZXZlbnQgdGhlIGZ4IHF1ZXVlIGZyb20gYmVpbmdcblx0XHRcdC8vIGF1dG9tYXRpY2FsbHkgZGVxdWV1ZWRcblx0XHRcdGlmICggdHlwZSA9PT0gXCJmeFwiICkge1xuXHRcdFx0XHRxdWV1ZS51bnNoaWZ0KCBcImlucHJvZ3Jlc3NcIiApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBDbGVhciB1cCB0aGUgbGFzdCBxdWV1ZSBzdG9wIGZ1bmN0aW9uXG5cdFx0XHRkZWxldGUgaG9va3Muc3RvcDtcblx0XHRcdGZuLmNhbGwoIGVsZW0sIG5leHQsIGhvb2tzICk7XG5cdFx0fVxuXG5cdFx0aWYgKCAhc3RhcnRMZW5ndGggJiYgaG9va3MgKSB7XG5cdFx0XHRob29rcy5lbXB0eS5maXJlKCk7XG5cdFx0fVxuXHR9LFxuXG5cdC8vIE5vdCBwdWJsaWMgLSBnZW5lcmF0ZSBhIHF1ZXVlSG9va3Mgb2JqZWN0LCBvciByZXR1cm4gdGhlIGN1cnJlbnQgb25lXG5cdF9xdWV1ZUhvb2tzOiBmdW5jdGlvbiggZWxlbSwgdHlwZSApIHtcblx0XHR2YXIga2V5ID0gdHlwZSArIFwicXVldWVIb29rc1wiO1xuXHRcdHJldHVybiBkYXRhX3ByaXYuZ2V0KCBlbGVtLCBrZXkgKSB8fCBkYXRhX3ByaXYuYWNjZXNzKCBlbGVtLCBrZXksIHtcblx0XHRcdGVtcHR5OiBqUXVlcnkuQ2FsbGJhY2tzKFwib25jZSBtZW1vcnlcIikuYWRkKGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRkYXRhX3ByaXYucmVtb3ZlKCBlbGVtLCBbIHR5cGUgKyBcInF1ZXVlXCIsIGtleSBdICk7XG5cdFx0XHR9KVxuXHRcdH0pO1xuXHR9XG59KTtcblxualF1ZXJ5LmZuLmV4dGVuZCh7XG5cdHF1ZXVlOiBmdW5jdGlvbiggdHlwZSwgZGF0YSApIHtcblx0XHR2YXIgc2V0dGVyID0gMjtcblxuXHRcdGlmICggdHlwZW9mIHR5cGUgIT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRkYXRhID0gdHlwZTtcblx0XHRcdHR5cGUgPSBcImZ4XCI7XG5cdFx0XHRzZXR0ZXItLTtcblx0XHR9XG5cblx0XHRpZiAoIGFyZ3VtZW50cy5sZW5ndGggPCBzZXR0ZXIgKSB7XG5cdFx0XHRyZXR1cm4galF1ZXJ5LnF1ZXVlKCB0aGlzWzBdLCB0eXBlICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGRhdGEgPT09IHVuZGVmaW5lZCA/XG5cdFx0XHR0aGlzIDpcblx0XHRcdHRoaXMuZWFjaChmdW5jdGlvbigpIHtcblx0XHRcdFx0dmFyIHF1ZXVlID0galF1ZXJ5LnF1ZXVlKCB0aGlzLCB0eXBlLCBkYXRhICk7XG5cblx0XHRcdFx0Ly8gRW5zdXJlIGEgaG9va3MgZm9yIHRoaXMgcXVldWVcblx0XHRcdFx0alF1ZXJ5Ll9xdWV1ZUhvb2tzKCB0aGlzLCB0eXBlICk7XG5cblx0XHRcdFx0aWYgKCB0eXBlID09PSBcImZ4XCIgJiYgcXVldWVbMF0gIT09IFwiaW5wcm9ncmVzc1wiICkge1xuXHRcdFx0XHRcdGpRdWVyeS5kZXF1ZXVlKCB0aGlzLCB0eXBlICk7XG5cdFx0XHRcdH1cblx0XHRcdH0pO1xuXHR9LFxuXHRkZXF1ZXVlOiBmdW5jdGlvbiggdHlwZSApIHtcblx0XHRyZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKCkge1xuXHRcdFx0alF1ZXJ5LmRlcXVldWUoIHRoaXMsIHR5cGUgKTtcblx0XHR9KTtcblx0fSxcblx0Y2xlYXJRdWV1ZTogZnVuY3Rpb24oIHR5cGUgKSB7XG5cdFx0cmV0dXJuIHRoaXMucXVldWUoIHR5cGUgfHwgXCJmeFwiLCBbXSApO1xuXHR9LFxuXHQvLyBHZXQgYSBwcm9taXNlIHJlc29sdmVkIHdoZW4gcXVldWVzIG9mIGEgY2VydGFpbiB0eXBlXG5cdC8vIGFyZSBlbXB0aWVkIChmeCBpcyB0aGUgdHlwZSBieSBkZWZhdWx0KVxuXHRwcm9taXNlOiBmdW5jdGlvbiggdHlwZSwgb2JqICkge1xuXHRcdHZhciB0bXAsXG5cdFx0XHRjb3VudCA9IDEsXG5cdFx0XHRkZWZlciA9IGpRdWVyeS5EZWZlcnJlZCgpLFxuXHRcdFx0ZWxlbWVudHMgPSB0aGlzLFxuXHRcdFx0aSA9IHRoaXMubGVuZ3RoLFxuXHRcdFx0cmVzb2x2ZSA9IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRpZiAoICEoIC0tY291bnQgKSApIHtcblx0XHRcdFx0XHRkZWZlci5yZXNvbHZlV2l0aCggZWxlbWVudHMsIFsgZWxlbWVudHMgXSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9O1xuXG5cdFx0aWYgKCB0eXBlb2YgdHlwZSAhPT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdG9iaiA9IHR5cGU7XG5cdFx0XHR0eXBlID0gdW5kZWZpbmVkO1xuXHRcdH1cblx0XHR0eXBlID0gdHlwZSB8fCBcImZ4XCI7XG5cblx0XHR3aGlsZSAoIGktLSApIHtcblx0XHRcdHRtcCA9IGRhdGFfcHJpdi5nZXQoIGVsZW1lbnRzWyBpIF0sIHR5cGUgKyBcInF1ZXVlSG9va3NcIiApO1xuXHRcdFx0aWYgKCB0bXAgJiYgdG1wLmVtcHR5ICkge1xuXHRcdFx0XHRjb3VudCsrO1xuXHRcdFx0XHR0bXAuZW1wdHkuYWRkKCByZXNvbHZlICk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHJlc29sdmUoKTtcblx0XHRyZXR1cm4gZGVmZXIucHJvbWlzZSggb2JqICk7XG5cdH1cbn0pO1xudmFyIHBudW0gPSAoL1srLV0/KD86XFxkKlxcLnwpXFxkKyg/OltlRV1bKy1dP1xcZCt8KS8pLnNvdXJjZTtcblxudmFyIGNzc0V4cGFuZCA9IFsgXCJUb3BcIiwgXCJSaWdodFwiLCBcIkJvdHRvbVwiLCBcIkxlZnRcIiBdO1xuXG52YXIgaXNIaWRkZW4gPSBmdW5jdGlvbiggZWxlbSwgZWwgKSB7XG5cdFx0Ly8gaXNIaWRkZW4gbWlnaHQgYmUgY2FsbGVkIGZyb20galF1ZXJ5I2ZpbHRlciBmdW5jdGlvbjtcblx0XHQvLyBpbiB0aGF0IGNhc2UsIGVsZW1lbnQgd2lsbCBiZSBzZWNvbmQgYXJndW1lbnRcblx0XHRlbGVtID0gZWwgfHwgZWxlbTtcblx0XHRyZXR1cm4galF1ZXJ5LmNzcyggZWxlbSwgXCJkaXNwbGF5XCIgKSA9PT0gXCJub25lXCIgfHwgIWpRdWVyeS5jb250YWlucyggZWxlbS5vd25lckRvY3VtZW50LCBlbGVtICk7XG5cdH07XG5cbnZhciByY2hlY2thYmxlVHlwZSA9ICgvXig/OmNoZWNrYm94fHJhZGlvKSQvaSk7XG5cblxuXG4oZnVuY3Rpb24oKSB7XG5cdHZhciBmcmFnbWVudCA9IGRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKSxcblx0XHRkaXYgPSBmcmFnbWVudC5hcHBlbmRDaGlsZCggZG9jdW1lbnQuY3JlYXRlRWxlbWVudCggXCJkaXZcIiApICksXG5cdFx0aW5wdXQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCBcImlucHV0XCIgKTtcblxuXHQvLyBTdXBwb3J0OiBTYWZhcmk8PTUuMVxuXHQvLyBDaGVjayBzdGF0ZSBsb3N0IGlmIHRoZSBuYW1lIGlzIHNldCAoIzExMjE3KVxuXHQvLyBTdXBwb3J0OiBXaW5kb3dzIFdlYiBBcHBzIChXV0EpXG5cdC8vIGBuYW1lYCBhbmQgYHR5cGVgIG11c3QgdXNlIC5zZXRBdHRyaWJ1dGUgZm9yIFdXQSAoIzE0OTAxKVxuXHRpbnB1dC5zZXRBdHRyaWJ1dGUoIFwidHlwZVwiLCBcInJhZGlvXCIgKTtcblx0aW5wdXQuc2V0QXR0cmlidXRlKCBcImNoZWNrZWRcIiwgXCJjaGVja2VkXCIgKTtcblx0aW5wdXQuc2V0QXR0cmlidXRlKCBcIm5hbWVcIiwgXCJ0XCIgKTtcblxuXHRkaXYuYXBwZW5kQ2hpbGQoIGlucHV0ICk7XG5cblx0Ly8gU3VwcG9ydDogU2FmYXJpPD01LjEsIEFuZHJvaWQ8NC4yXG5cdC8vIE9sZGVyIFdlYktpdCBkb2Vzbid0IGNsb25lIGNoZWNrZWQgc3RhdGUgY29ycmVjdGx5IGluIGZyYWdtZW50c1xuXHRzdXBwb3J0LmNoZWNrQ2xvbmUgPSBkaXYuY2xvbmVOb2RlKCB0cnVlICkuY2xvbmVOb2RlKCB0cnVlICkubGFzdENoaWxkLmNoZWNrZWQ7XG5cblx0Ly8gU3VwcG9ydDogSUU8PTExK1xuXHQvLyBNYWtlIHN1cmUgdGV4dGFyZWEgKGFuZCBjaGVja2JveCkgZGVmYXVsdFZhbHVlIGlzIHByb3Blcmx5IGNsb25lZFxuXHRkaXYuaW5uZXJIVE1MID0gXCI8dGV4dGFyZWE+eDwvdGV4dGFyZWE+XCI7XG5cdHN1cHBvcnQubm9DbG9uZUNoZWNrZWQgPSAhIWRpdi5jbG9uZU5vZGUoIHRydWUgKS5sYXN0Q2hpbGQuZGVmYXVsdFZhbHVlO1xufSkoKTtcbnZhciBzdHJ1bmRlZmluZWQgPSB0eXBlb2YgdW5kZWZpbmVkO1xuXG5cblxuc3VwcG9ydC5mb2N1c2luQnViYmxlcyA9IFwib25mb2N1c2luXCIgaW4gd2luZG93O1xuXG5cbnZhclxuXHRya2V5RXZlbnQgPSAvXmtleS8sXG5cdHJtb3VzZUV2ZW50ID0gL14oPzptb3VzZXxwb2ludGVyfGNvbnRleHRtZW51KXxjbGljay8sXG5cdHJmb2N1c01vcnBoID0gL14oPzpmb2N1c2luZm9jdXN8Zm9jdXNvdXRibHVyKSQvLFxuXHRydHlwZW5hbWVzcGFjZSA9IC9eKFteLl0qKSg/OlxcLiguKyl8KSQvO1xuXG5mdW5jdGlvbiByZXR1cm5UcnVlKCkge1xuXHRyZXR1cm4gdHJ1ZTtcbn1cblxuZnVuY3Rpb24gcmV0dXJuRmFsc2UoKSB7XG5cdHJldHVybiBmYWxzZTtcbn1cblxuZnVuY3Rpb24gc2FmZUFjdGl2ZUVsZW1lbnQoKSB7XG5cdHRyeSB7XG5cdFx0cmV0dXJuIGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQ7XG5cdH0gY2F0Y2ggKCBlcnIgKSB7IH1cbn1cblxuLypcbiAqIEhlbHBlciBmdW5jdGlvbnMgZm9yIG1hbmFnaW5nIGV2ZW50cyAtLSBub3QgcGFydCBvZiB0aGUgcHVibGljIGludGVyZmFjZS5cbiAqIFByb3BzIHRvIERlYW4gRWR3YXJkcycgYWRkRXZlbnQgbGlicmFyeSBmb3IgbWFueSBvZiB0aGUgaWRlYXMuXG4gKi9cbmpRdWVyeS5ldmVudCA9IHtcblxuXHRnbG9iYWw6IHt9LFxuXG5cdGFkZDogZnVuY3Rpb24oIGVsZW0sIHR5cGVzLCBoYW5kbGVyLCBkYXRhLCBzZWxlY3RvciApIHtcblxuXHRcdHZhciBoYW5kbGVPYmpJbiwgZXZlbnRIYW5kbGUsIHRtcCxcblx0XHRcdGV2ZW50cywgdCwgaGFuZGxlT2JqLFxuXHRcdFx0c3BlY2lhbCwgaGFuZGxlcnMsIHR5cGUsIG5hbWVzcGFjZXMsIG9yaWdUeXBlLFxuXHRcdFx0ZWxlbURhdGEgPSBkYXRhX3ByaXYuZ2V0KCBlbGVtICk7XG5cblx0XHQvLyBEb24ndCBhdHRhY2ggZXZlbnRzIHRvIG5vRGF0YSBvciB0ZXh0L2NvbW1lbnQgbm9kZXMgKGJ1dCBhbGxvdyBwbGFpbiBvYmplY3RzKVxuXHRcdGlmICggIWVsZW1EYXRhICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIENhbGxlciBjYW4gcGFzcyBpbiBhbiBvYmplY3Qgb2YgY3VzdG9tIGRhdGEgaW4gbGlldSBvZiB0aGUgaGFuZGxlclxuXHRcdGlmICggaGFuZGxlci5oYW5kbGVyICkge1xuXHRcdFx0aGFuZGxlT2JqSW4gPSBoYW5kbGVyO1xuXHRcdFx0aGFuZGxlciA9IGhhbmRsZU9iakluLmhhbmRsZXI7XG5cdFx0XHRzZWxlY3RvciA9IGhhbmRsZU9iakluLnNlbGVjdG9yO1xuXHRcdH1cblxuXHRcdC8vIE1ha2Ugc3VyZSB0aGF0IHRoZSBoYW5kbGVyIGhhcyBhIHVuaXF1ZSBJRCwgdXNlZCB0byBmaW5kL3JlbW92ZSBpdCBsYXRlclxuXHRcdGlmICggIWhhbmRsZXIuZ3VpZCApIHtcblx0XHRcdGhhbmRsZXIuZ3VpZCA9IGpRdWVyeS5ndWlkKys7XG5cdFx0fVxuXG5cdFx0Ly8gSW5pdCB0aGUgZWxlbWVudCdzIGV2ZW50IHN0cnVjdHVyZSBhbmQgbWFpbiBoYW5kbGVyLCBpZiB0aGlzIGlzIHRoZSBmaXJzdFxuXHRcdGlmICggIShldmVudHMgPSBlbGVtRGF0YS5ldmVudHMpICkge1xuXHRcdFx0ZXZlbnRzID0gZWxlbURhdGEuZXZlbnRzID0ge307XG5cdFx0fVxuXHRcdGlmICggIShldmVudEhhbmRsZSA9IGVsZW1EYXRhLmhhbmRsZSkgKSB7XG5cdFx0XHRldmVudEhhbmRsZSA9IGVsZW1EYXRhLmhhbmRsZSA9IGZ1bmN0aW9uKCBlICkge1xuXHRcdFx0XHQvLyBEaXNjYXJkIHRoZSBzZWNvbmQgZXZlbnQgb2YgYSBqUXVlcnkuZXZlbnQudHJpZ2dlcigpIGFuZFxuXHRcdFx0XHQvLyB3aGVuIGFuIGV2ZW50IGlzIGNhbGxlZCBhZnRlciBhIHBhZ2UgaGFzIHVubG9hZGVkXG5cdFx0XHRcdHJldHVybiB0eXBlb2YgalF1ZXJ5ICE9PSBzdHJ1bmRlZmluZWQgJiYgalF1ZXJ5LmV2ZW50LnRyaWdnZXJlZCAhPT0gZS50eXBlID9cblx0XHRcdFx0XHRqUXVlcnkuZXZlbnQuZGlzcGF0Y2guYXBwbHkoIGVsZW0sIGFyZ3VtZW50cyApIDogdW5kZWZpbmVkO1xuXHRcdFx0fTtcblx0XHR9XG5cblx0XHQvLyBIYW5kbGUgbXVsdGlwbGUgZXZlbnRzIHNlcGFyYXRlZCBieSBhIHNwYWNlXG5cdFx0dHlwZXMgPSAoIHR5cGVzIHx8IFwiXCIgKS5tYXRjaCggcm5vdHdoaXRlICkgfHwgWyBcIlwiIF07XG5cdFx0dCA9IHR5cGVzLmxlbmd0aDtcblx0XHR3aGlsZSAoIHQtLSApIHtcblx0XHRcdHRtcCA9IHJ0eXBlbmFtZXNwYWNlLmV4ZWMoIHR5cGVzW3RdICkgfHwgW107XG5cdFx0XHR0eXBlID0gb3JpZ1R5cGUgPSB0bXBbMV07XG5cdFx0XHRuYW1lc3BhY2VzID0gKCB0bXBbMl0gfHwgXCJcIiApLnNwbGl0KCBcIi5cIiApLnNvcnQoKTtcblxuXHRcdFx0Ly8gVGhlcmUgKm11c3QqIGJlIGEgdHlwZSwgbm8gYXR0YWNoaW5nIG5hbWVzcGFjZS1vbmx5IGhhbmRsZXJzXG5cdFx0XHRpZiAoICF0eXBlICkge1xuXHRcdFx0XHRjb250aW51ZTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gSWYgZXZlbnQgY2hhbmdlcyBpdHMgdHlwZSwgdXNlIHRoZSBzcGVjaWFsIGV2ZW50IGhhbmRsZXJzIGZvciB0aGUgY2hhbmdlZCB0eXBlXG5cdFx0XHRzcGVjaWFsID0galF1ZXJ5LmV2ZW50LnNwZWNpYWxbIHR5cGUgXSB8fCB7fTtcblxuXHRcdFx0Ly8gSWYgc2VsZWN0b3IgZGVmaW5lZCwgZGV0ZXJtaW5lIHNwZWNpYWwgZXZlbnQgYXBpIHR5cGUsIG90aGVyd2lzZSBnaXZlbiB0eXBlXG5cdFx0XHR0eXBlID0gKCBzZWxlY3RvciA/IHNwZWNpYWwuZGVsZWdhdGVUeXBlIDogc3BlY2lhbC5iaW5kVHlwZSApIHx8IHR5cGU7XG5cblx0XHRcdC8vIFVwZGF0ZSBzcGVjaWFsIGJhc2VkIG9uIG5ld2x5IHJlc2V0IHR5cGVcblx0XHRcdHNwZWNpYWwgPSBqUXVlcnkuZXZlbnQuc3BlY2lhbFsgdHlwZSBdIHx8IHt9O1xuXG5cdFx0XHQvLyBoYW5kbGVPYmogaXMgcGFzc2VkIHRvIGFsbCBldmVudCBoYW5kbGVyc1xuXHRcdFx0aGFuZGxlT2JqID0galF1ZXJ5LmV4dGVuZCh7XG5cdFx0XHRcdHR5cGU6IHR5cGUsXG5cdFx0XHRcdG9yaWdUeXBlOiBvcmlnVHlwZSxcblx0XHRcdFx0ZGF0YTogZGF0YSxcblx0XHRcdFx0aGFuZGxlcjogaGFuZGxlcixcblx0XHRcdFx0Z3VpZDogaGFuZGxlci5ndWlkLFxuXHRcdFx0XHRzZWxlY3Rvcjogc2VsZWN0b3IsXG5cdFx0XHRcdG5lZWRzQ29udGV4dDogc2VsZWN0b3IgJiYgalF1ZXJ5LmV4cHIubWF0Y2gubmVlZHNDb250ZXh0LnRlc3QoIHNlbGVjdG9yICksXG5cdFx0XHRcdG5hbWVzcGFjZTogbmFtZXNwYWNlcy5qb2luKFwiLlwiKVxuXHRcdFx0fSwgaGFuZGxlT2JqSW4gKTtcblxuXHRcdFx0Ly8gSW5pdCB0aGUgZXZlbnQgaGFuZGxlciBxdWV1ZSBpZiB3ZSdyZSB0aGUgZmlyc3Rcblx0XHRcdGlmICggIShoYW5kbGVycyA9IGV2ZW50c1sgdHlwZSBdKSApIHtcblx0XHRcdFx0aGFuZGxlcnMgPSBldmVudHNbIHR5cGUgXSA9IFtdO1xuXHRcdFx0XHRoYW5kbGVycy5kZWxlZ2F0ZUNvdW50ID0gMDtcblxuXHRcdFx0XHQvLyBPbmx5IHVzZSBhZGRFdmVudExpc3RlbmVyIGlmIHRoZSBzcGVjaWFsIGV2ZW50cyBoYW5kbGVyIHJldHVybnMgZmFsc2Vcblx0XHRcdFx0aWYgKCAhc3BlY2lhbC5zZXR1cCB8fCBzcGVjaWFsLnNldHVwLmNhbGwoIGVsZW0sIGRhdGEsIG5hbWVzcGFjZXMsIGV2ZW50SGFuZGxlICkgPT09IGZhbHNlICkge1xuXHRcdFx0XHRcdGlmICggZWxlbS5hZGRFdmVudExpc3RlbmVyICkge1xuXHRcdFx0XHRcdFx0ZWxlbS5hZGRFdmVudExpc3RlbmVyKCB0eXBlLCBldmVudEhhbmRsZSwgZmFsc2UgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBzcGVjaWFsLmFkZCApIHtcblx0XHRcdFx0c3BlY2lhbC5hZGQuY2FsbCggZWxlbSwgaGFuZGxlT2JqICk7XG5cblx0XHRcdFx0aWYgKCAhaGFuZGxlT2JqLmhhbmRsZXIuZ3VpZCApIHtcblx0XHRcdFx0XHRoYW5kbGVPYmouaGFuZGxlci5ndWlkID0gaGFuZGxlci5ndWlkO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdC8vIEFkZCB0byB0aGUgZWxlbWVudCdzIGhhbmRsZXIgbGlzdCwgZGVsZWdhdGVzIGluIGZyb250XG5cdFx0XHRpZiAoIHNlbGVjdG9yICkge1xuXHRcdFx0XHRoYW5kbGVycy5zcGxpY2UoIGhhbmRsZXJzLmRlbGVnYXRlQ291bnQrKywgMCwgaGFuZGxlT2JqICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRoYW5kbGVycy5wdXNoKCBoYW5kbGVPYmogKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gS2VlcCB0cmFjayBvZiB3aGljaCBldmVudHMgaGF2ZSBldmVyIGJlZW4gdXNlZCwgZm9yIGV2ZW50IG9wdGltaXphdGlvblxuXHRcdFx0alF1ZXJ5LmV2ZW50Lmdsb2JhbFsgdHlwZSBdID0gdHJ1ZTtcblx0XHR9XG5cblx0fSxcblxuXHQvLyBEZXRhY2ggYW4gZXZlbnQgb3Igc2V0IG9mIGV2ZW50cyBmcm9tIGFuIGVsZW1lbnRcblx0cmVtb3ZlOiBmdW5jdGlvbiggZWxlbSwgdHlwZXMsIGhhbmRsZXIsIHNlbGVjdG9yLCBtYXBwZWRUeXBlcyApIHtcblxuXHRcdHZhciBqLCBvcmlnQ291bnQsIHRtcCxcblx0XHRcdGV2ZW50cywgdCwgaGFuZGxlT2JqLFxuXHRcdFx0c3BlY2lhbCwgaGFuZGxlcnMsIHR5cGUsIG5hbWVzcGFjZXMsIG9yaWdUeXBlLFxuXHRcdFx0ZWxlbURhdGEgPSBkYXRhX3ByaXYuaGFzRGF0YSggZWxlbSApICYmIGRhdGFfcHJpdi5nZXQoIGVsZW0gKTtcblxuXHRcdGlmICggIWVsZW1EYXRhIHx8ICEoZXZlbnRzID0gZWxlbURhdGEuZXZlbnRzKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBPbmNlIGZvciBlYWNoIHR5cGUubmFtZXNwYWNlIGluIHR5cGVzOyB0eXBlIG1heSBiZSBvbWl0dGVkXG5cdFx0dHlwZXMgPSAoIHR5cGVzIHx8IFwiXCIgKS5tYXRjaCggcm5vdHdoaXRlICkgfHwgWyBcIlwiIF07XG5cdFx0dCA9IHR5cGVzLmxlbmd0aDtcblx0XHR3aGlsZSAoIHQtLSApIHtcblx0XHRcdHRtcCA9IHJ0eXBlbmFtZXNwYWNlLmV4ZWMoIHR5cGVzW3RdICkgfHwgW107XG5cdFx0XHR0eXBlID0gb3JpZ1R5cGUgPSB0bXBbMV07XG5cdFx0XHRuYW1lc3BhY2VzID0gKCB0bXBbMl0gfHwgXCJcIiApLnNwbGl0KCBcIi5cIiApLnNvcnQoKTtcblxuXHRcdFx0Ly8gVW5iaW5kIGFsbCBldmVudHMgKG9uIHRoaXMgbmFtZXNwYWNlLCBpZiBwcm92aWRlZCkgZm9yIHRoZSBlbGVtZW50XG5cdFx0XHRpZiAoICF0eXBlICkge1xuXHRcdFx0XHRmb3IgKCB0eXBlIGluIGV2ZW50cyApIHtcblx0XHRcdFx0XHRqUXVlcnkuZXZlbnQucmVtb3ZlKCBlbGVtLCB0eXBlICsgdHlwZXNbIHQgXSwgaGFuZGxlciwgc2VsZWN0b3IsIHRydWUgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRjb250aW51ZTtcblx0XHRcdH1cblxuXHRcdFx0c3BlY2lhbCA9IGpRdWVyeS5ldmVudC5zcGVjaWFsWyB0eXBlIF0gfHwge307XG5cdFx0XHR0eXBlID0gKCBzZWxlY3RvciA/IHNwZWNpYWwuZGVsZWdhdGVUeXBlIDogc3BlY2lhbC5iaW5kVHlwZSApIHx8IHR5cGU7XG5cdFx0XHRoYW5kbGVycyA9IGV2ZW50c1sgdHlwZSBdIHx8IFtdO1xuXHRcdFx0dG1wID0gdG1wWzJdICYmIG5ldyBSZWdFeHAoIFwiKF58XFxcXC4pXCIgKyBuYW1lc3BhY2VzLmpvaW4oXCJcXFxcLig/Oi4qXFxcXC58KVwiKSArIFwiKFxcXFwufCQpXCIgKTtcblxuXHRcdFx0Ly8gUmVtb3ZlIG1hdGNoaW5nIGV2ZW50c1xuXHRcdFx0b3JpZ0NvdW50ID0gaiA9IGhhbmRsZXJzLmxlbmd0aDtcblx0XHRcdHdoaWxlICggai0tICkge1xuXHRcdFx0XHRoYW5kbGVPYmogPSBoYW5kbGVyc1sgaiBdO1xuXG5cdFx0XHRcdGlmICggKCBtYXBwZWRUeXBlcyB8fCBvcmlnVHlwZSA9PT0gaGFuZGxlT2JqLm9yaWdUeXBlICkgJiZcblx0XHRcdFx0XHQoICFoYW5kbGVyIHx8IGhhbmRsZXIuZ3VpZCA9PT0gaGFuZGxlT2JqLmd1aWQgKSAmJlxuXHRcdFx0XHRcdCggIXRtcCB8fCB0bXAudGVzdCggaGFuZGxlT2JqLm5hbWVzcGFjZSApICkgJiZcblx0XHRcdFx0XHQoICFzZWxlY3RvciB8fCBzZWxlY3RvciA9PT0gaGFuZGxlT2JqLnNlbGVjdG9yIHx8IHNlbGVjdG9yID09PSBcIioqXCIgJiYgaGFuZGxlT2JqLnNlbGVjdG9yICkgKSB7XG5cdFx0XHRcdFx0aGFuZGxlcnMuc3BsaWNlKCBqLCAxICk7XG5cblx0XHRcdFx0XHRpZiAoIGhhbmRsZU9iai5zZWxlY3RvciApIHtcblx0XHRcdFx0XHRcdGhhbmRsZXJzLmRlbGVnYXRlQ291bnQtLTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aWYgKCBzcGVjaWFsLnJlbW92ZSApIHtcblx0XHRcdFx0XHRcdHNwZWNpYWwucmVtb3ZlLmNhbGwoIGVsZW0sIGhhbmRsZU9iaiApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHQvLyBSZW1vdmUgZ2VuZXJpYyBldmVudCBoYW5kbGVyIGlmIHdlIHJlbW92ZWQgc29tZXRoaW5nIGFuZCBubyBtb3JlIGhhbmRsZXJzIGV4aXN0XG5cdFx0XHQvLyAoYXZvaWRzIHBvdGVudGlhbCBmb3IgZW5kbGVzcyByZWN1cnNpb24gZHVyaW5nIHJlbW92YWwgb2Ygc3BlY2lhbCBldmVudCBoYW5kbGVycylcblx0XHRcdGlmICggb3JpZ0NvdW50ICYmICFoYW5kbGVycy5sZW5ndGggKSB7XG5cdFx0XHRcdGlmICggIXNwZWNpYWwudGVhcmRvd24gfHwgc3BlY2lhbC50ZWFyZG93bi5jYWxsKCBlbGVtLCBuYW1lc3BhY2VzLCBlbGVtRGF0YS5oYW5kbGUgKSA9PT0gZmFsc2UgKSB7XG5cdFx0XHRcdFx0alF1ZXJ5LnJlbW92ZUV2ZW50KCBlbGVtLCB0eXBlLCBlbGVtRGF0YS5oYW5kbGUgKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGRlbGV0ZSBldmVudHNbIHR5cGUgXTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBSZW1vdmUgdGhlIGV4cGFuZG8gaWYgaXQncyBubyBsb25nZXIgdXNlZFxuXHRcdGlmICggalF1ZXJ5LmlzRW1wdHlPYmplY3QoIGV2ZW50cyApICkge1xuXHRcdFx0ZGVsZXRlIGVsZW1EYXRhLmhhbmRsZTtcblx0XHRcdGRhdGFfcHJpdi5yZW1vdmUoIGVsZW0sIFwiZXZlbnRzXCIgKTtcblx0XHR9XG5cdH0sXG5cblx0dHJpZ2dlcjogZnVuY3Rpb24oIGV2ZW50LCBkYXRhLCBlbGVtLCBvbmx5SGFuZGxlcnMgKSB7XG5cblx0XHR2YXIgaSwgY3VyLCB0bXAsIGJ1YmJsZVR5cGUsIG9udHlwZSwgaGFuZGxlLCBzcGVjaWFsLFxuXHRcdFx0ZXZlbnRQYXRoID0gWyBlbGVtIHx8IGRvY3VtZW50IF0sXG5cdFx0XHR0eXBlID0gaGFzT3duLmNhbGwoIGV2ZW50LCBcInR5cGVcIiApID8gZXZlbnQudHlwZSA6IGV2ZW50LFxuXHRcdFx0bmFtZXNwYWNlcyA9IGhhc093bi5jYWxsKCBldmVudCwgXCJuYW1lc3BhY2VcIiApID8gZXZlbnQubmFtZXNwYWNlLnNwbGl0KFwiLlwiKSA6IFtdO1xuXG5cdFx0Y3VyID0gdG1wID0gZWxlbSA9IGVsZW0gfHwgZG9jdW1lbnQ7XG5cblx0XHQvLyBEb24ndCBkbyBldmVudHMgb24gdGV4dCBhbmQgY29tbWVudCBub2Rlc1xuXHRcdGlmICggZWxlbS5ub2RlVHlwZSA9PT0gMyB8fCBlbGVtLm5vZGVUeXBlID09PSA4ICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIGZvY3VzL2JsdXIgbW9ycGhzIHRvIGZvY3VzaW4vb3V0OyBlbnN1cmUgd2UncmUgbm90IGZpcmluZyB0aGVtIHJpZ2h0IG5vd1xuXHRcdGlmICggcmZvY3VzTW9ycGgudGVzdCggdHlwZSArIGpRdWVyeS5ldmVudC50cmlnZ2VyZWQgKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAoIHR5cGUuaW5kZXhPZihcIi5cIikgPj0gMCApIHtcblx0XHRcdC8vIE5hbWVzcGFjZWQgdHJpZ2dlcjsgY3JlYXRlIGEgcmVnZXhwIHRvIG1hdGNoIGV2ZW50IHR5cGUgaW4gaGFuZGxlKClcblx0XHRcdG5hbWVzcGFjZXMgPSB0eXBlLnNwbGl0KFwiLlwiKTtcblx0XHRcdHR5cGUgPSBuYW1lc3BhY2VzLnNoaWZ0KCk7XG5cdFx0XHRuYW1lc3BhY2VzLnNvcnQoKTtcblx0XHR9XG5cdFx0b250eXBlID0gdHlwZS5pbmRleE9mKFwiOlwiKSA8IDAgJiYgXCJvblwiICsgdHlwZTtcblxuXHRcdC8vIENhbGxlciBjYW4gcGFzcyBpbiBhIGpRdWVyeS5FdmVudCBvYmplY3QsIE9iamVjdCwgb3IganVzdCBhbiBldmVudCB0eXBlIHN0cmluZ1xuXHRcdGV2ZW50ID0gZXZlbnRbIGpRdWVyeS5leHBhbmRvIF0gP1xuXHRcdFx0ZXZlbnQgOlxuXHRcdFx0bmV3IGpRdWVyeS5FdmVudCggdHlwZSwgdHlwZW9mIGV2ZW50ID09PSBcIm9iamVjdFwiICYmIGV2ZW50ICk7XG5cblx0XHQvLyBUcmlnZ2VyIGJpdG1hc2s6ICYgMSBmb3IgbmF0aXZlIGhhbmRsZXJzOyAmIDIgZm9yIGpRdWVyeSAoYWx3YXlzIHRydWUpXG5cdFx0ZXZlbnQuaXNUcmlnZ2VyID0gb25seUhhbmRsZXJzID8gMiA6IDM7XG5cdFx0ZXZlbnQubmFtZXNwYWNlID0gbmFtZXNwYWNlcy5qb2luKFwiLlwiKTtcblx0XHRldmVudC5uYW1lc3BhY2VfcmUgPSBldmVudC5uYW1lc3BhY2UgP1xuXHRcdFx0bmV3IFJlZ0V4cCggXCIoXnxcXFxcLilcIiArIG5hbWVzcGFjZXMuam9pbihcIlxcXFwuKD86LipcXFxcLnwpXCIpICsgXCIoXFxcXC58JClcIiApIDpcblx0XHRcdG51bGw7XG5cblx0XHQvLyBDbGVhbiB1cCB0aGUgZXZlbnQgaW4gY2FzZSBpdCBpcyBiZWluZyByZXVzZWRcblx0XHRldmVudC5yZXN1bHQgPSB1bmRlZmluZWQ7XG5cdFx0aWYgKCAhZXZlbnQudGFyZ2V0ICkge1xuXHRcdFx0ZXZlbnQudGFyZ2V0ID0gZWxlbTtcblx0XHR9XG5cblx0XHQvLyBDbG9uZSBhbnkgaW5jb21pbmcgZGF0YSBhbmQgcHJlcGVuZCB0aGUgZXZlbnQsIGNyZWF0aW5nIHRoZSBoYW5kbGVyIGFyZyBsaXN0XG5cdFx0ZGF0YSA9IGRhdGEgPT0gbnVsbCA/XG5cdFx0XHRbIGV2ZW50IF0gOlxuXHRcdFx0alF1ZXJ5Lm1ha2VBcnJheSggZGF0YSwgWyBldmVudCBdICk7XG5cblx0XHQvLyBBbGxvdyBzcGVjaWFsIGV2ZW50cyB0byBkcmF3IG91dHNpZGUgdGhlIGxpbmVzXG5cdFx0c3BlY2lhbCA9IGpRdWVyeS5ldmVudC5zcGVjaWFsWyB0eXBlIF0gfHwge307XG5cdFx0aWYgKCAhb25seUhhbmRsZXJzICYmIHNwZWNpYWwudHJpZ2dlciAmJiBzcGVjaWFsLnRyaWdnZXIuYXBwbHkoIGVsZW0sIGRhdGEgKSA9PT0gZmFsc2UgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gRGV0ZXJtaW5lIGV2ZW50IHByb3BhZ2F0aW9uIHBhdGggaW4gYWR2YW5jZSwgcGVyIFczQyBldmVudHMgc3BlYyAoIzk5NTEpXG5cdFx0Ly8gQnViYmxlIHVwIHRvIGRvY3VtZW50LCB0aGVuIHRvIHdpbmRvdzsgd2F0Y2ggZm9yIGEgZ2xvYmFsIG93bmVyRG9jdW1lbnQgdmFyICgjOTcyNClcblx0XHRpZiAoICFvbmx5SGFuZGxlcnMgJiYgIXNwZWNpYWwubm9CdWJibGUgJiYgIWpRdWVyeS5pc1dpbmRvdyggZWxlbSApICkge1xuXG5cdFx0XHRidWJibGVUeXBlID0gc3BlY2lhbC5kZWxlZ2F0ZVR5cGUgfHwgdHlwZTtcblx0XHRcdGlmICggIXJmb2N1c01vcnBoLnRlc3QoIGJ1YmJsZVR5cGUgKyB0eXBlICkgKSB7XG5cdFx0XHRcdGN1ciA9IGN1ci5wYXJlbnROb2RlO1xuXHRcdFx0fVxuXHRcdFx0Zm9yICggOyBjdXI7IGN1ciA9IGN1ci5wYXJlbnROb2RlICkge1xuXHRcdFx0XHRldmVudFBhdGgucHVzaCggY3VyICk7XG5cdFx0XHRcdHRtcCA9IGN1cjtcblx0XHRcdH1cblxuXHRcdFx0Ly8gT25seSBhZGQgd2luZG93IGlmIHdlIGdvdCB0byBkb2N1bWVudCAoZS5nLiwgbm90IHBsYWluIG9iaiBvciBkZXRhY2hlZCBET00pXG5cdFx0XHRpZiAoIHRtcCA9PT0gKGVsZW0ub3duZXJEb2N1bWVudCB8fCBkb2N1bWVudCkgKSB7XG5cdFx0XHRcdGV2ZW50UGF0aC5wdXNoKCB0bXAuZGVmYXVsdFZpZXcgfHwgdG1wLnBhcmVudFdpbmRvdyB8fCB3aW5kb3cgKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBGaXJlIGhhbmRsZXJzIG9uIHRoZSBldmVudCBwYXRoXG5cdFx0aSA9IDA7XG5cdFx0d2hpbGUgKCAoY3VyID0gZXZlbnRQYXRoW2krK10pICYmICFldmVudC5pc1Byb3BhZ2F0aW9uU3RvcHBlZCgpICkge1xuXG5cdFx0XHRldmVudC50eXBlID0gaSA+IDEgP1xuXHRcdFx0XHRidWJibGVUeXBlIDpcblx0XHRcdFx0c3BlY2lhbC5iaW5kVHlwZSB8fCB0eXBlO1xuXG5cdFx0XHQvLyBqUXVlcnkgaGFuZGxlclxuXHRcdFx0aGFuZGxlID0gKCBkYXRhX3ByaXYuZ2V0KCBjdXIsIFwiZXZlbnRzXCIgKSB8fCB7fSApWyBldmVudC50eXBlIF0gJiYgZGF0YV9wcml2LmdldCggY3VyLCBcImhhbmRsZVwiICk7XG5cdFx0XHRpZiAoIGhhbmRsZSApIHtcblx0XHRcdFx0aGFuZGxlLmFwcGx5KCBjdXIsIGRhdGEgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gTmF0aXZlIGhhbmRsZXJcblx0XHRcdGhhbmRsZSA9IG9udHlwZSAmJiBjdXJbIG9udHlwZSBdO1xuXHRcdFx0aWYgKCBoYW5kbGUgJiYgaGFuZGxlLmFwcGx5ICYmIGpRdWVyeS5hY2NlcHREYXRhKCBjdXIgKSApIHtcblx0XHRcdFx0ZXZlbnQucmVzdWx0ID0gaGFuZGxlLmFwcGx5KCBjdXIsIGRhdGEgKTtcblx0XHRcdFx0aWYgKCBldmVudC5yZXN1bHQgPT09IGZhbHNlICkge1xuXHRcdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdFx0ZXZlbnQudHlwZSA9IHR5cGU7XG5cblx0XHQvLyBJZiBub2JvZHkgcHJldmVudGVkIHRoZSBkZWZhdWx0IGFjdGlvbiwgZG8gaXQgbm93XG5cdFx0aWYgKCAhb25seUhhbmRsZXJzICYmICFldmVudC5pc0RlZmF1bHRQcmV2ZW50ZWQoKSApIHtcblxuXHRcdFx0aWYgKCAoIXNwZWNpYWwuX2RlZmF1bHQgfHwgc3BlY2lhbC5fZGVmYXVsdC5hcHBseSggZXZlbnRQYXRoLnBvcCgpLCBkYXRhICkgPT09IGZhbHNlKSAmJlxuXHRcdFx0XHRqUXVlcnkuYWNjZXB0RGF0YSggZWxlbSApICkge1xuXG5cdFx0XHRcdC8vIENhbGwgYSBuYXRpdmUgRE9NIG1ldGhvZCBvbiB0aGUgdGFyZ2V0IHdpdGggdGhlIHNhbWUgbmFtZSBuYW1lIGFzIHRoZSBldmVudC5cblx0XHRcdFx0Ly8gRG9uJ3QgZG8gZGVmYXVsdCBhY3Rpb25zIG9uIHdpbmRvdywgdGhhdCdzIHdoZXJlIGdsb2JhbCB2YXJpYWJsZXMgYmUgKCM2MTcwKVxuXHRcdFx0XHRpZiAoIG9udHlwZSAmJiBqUXVlcnkuaXNGdW5jdGlvbiggZWxlbVsgdHlwZSBdICkgJiYgIWpRdWVyeS5pc1dpbmRvdyggZWxlbSApICkge1xuXG5cdFx0XHRcdFx0Ly8gRG9uJ3QgcmUtdHJpZ2dlciBhbiBvbkZPTyBldmVudCB3aGVuIHdlIGNhbGwgaXRzIEZPTygpIG1ldGhvZFxuXHRcdFx0XHRcdHRtcCA9IGVsZW1bIG9udHlwZSBdO1xuXG5cdFx0XHRcdFx0aWYgKCB0bXAgKSB7XG5cdFx0XHRcdFx0XHRlbGVtWyBvbnR5cGUgXSA9IG51bGw7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Ly8gUHJldmVudCByZS10cmlnZ2VyaW5nIG9mIHRoZSBzYW1lIGV2ZW50LCBzaW5jZSB3ZSBhbHJlYWR5IGJ1YmJsZWQgaXQgYWJvdmVcblx0XHRcdFx0XHRqUXVlcnkuZXZlbnQudHJpZ2dlcmVkID0gdHlwZTtcblx0XHRcdFx0XHRlbGVtWyB0eXBlIF0oKTtcblx0XHRcdFx0XHRqUXVlcnkuZXZlbnQudHJpZ2dlcmVkID0gdW5kZWZpbmVkO1xuXG5cdFx0XHRcdFx0aWYgKCB0bXAgKSB7XG5cdFx0XHRcdFx0XHRlbGVtWyBvbnR5cGUgXSA9IHRtcDtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4gZXZlbnQucmVzdWx0O1xuXHR9LFxuXG5cdGRpc3BhdGNoOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cblx0XHQvLyBNYWtlIGEgd3JpdGFibGUgalF1ZXJ5LkV2ZW50IGZyb20gdGhlIG5hdGl2ZSBldmVudCBvYmplY3Rcblx0XHRldmVudCA9IGpRdWVyeS5ldmVudC5maXgoIGV2ZW50ICk7XG5cblx0XHR2YXIgaSwgaiwgcmV0LCBtYXRjaGVkLCBoYW5kbGVPYmosXG5cdFx0XHRoYW5kbGVyUXVldWUgPSBbXSxcblx0XHRcdGFyZ3MgPSBzbGljZS5jYWxsKCBhcmd1bWVudHMgKSxcblx0XHRcdGhhbmRsZXJzID0gKCBkYXRhX3ByaXYuZ2V0KCB0aGlzLCBcImV2ZW50c1wiICkgfHwge30gKVsgZXZlbnQudHlwZSBdIHx8IFtdLFxuXHRcdFx0c3BlY2lhbCA9IGpRdWVyeS5ldmVudC5zcGVjaWFsWyBldmVudC50eXBlIF0gfHwge307XG5cblx0XHQvLyBVc2UgdGhlIGZpeC1lZCBqUXVlcnkuRXZlbnQgcmF0aGVyIHRoYW4gdGhlIChyZWFkLW9ubHkpIG5hdGl2ZSBldmVudFxuXHRcdGFyZ3NbMF0gPSBldmVudDtcblx0XHRldmVudC5kZWxlZ2F0ZVRhcmdldCA9IHRoaXM7XG5cblx0XHQvLyBDYWxsIHRoZSBwcmVEaXNwYXRjaCBob29rIGZvciB0aGUgbWFwcGVkIHR5cGUsIGFuZCBsZXQgaXQgYmFpbCBpZiBkZXNpcmVkXG5cdFx0aWYgKCBzcGVjaWFsLnByZURpc3BhdGNoICYmIHNwZWNpYWwucHJlRGlzcGF0Y2guY2FsbCggdGhpcywgZXZlbnQgKSA9PT0gZmFsc2UgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gRGV0ZXJtaW5lIGhhbmRsZXJzXG5cdFx0aGFuZGxlclF1ZXVlID0galF1ZXJ5LmV2ZW50LmhhbmRsZXJzLmNhbGwoIHRoaXMsIGV2ZW50LCBoYW5kbGVycyApO1xuXG5cdFx0Ly8gUnVuIGRlbGVnYXRlcyBmaXJzdDsgdGhleSBtYXkgd2FudCB0byBzdG9wIHByb3BhZ2F0aW9uIGJlbmVhdGggdXNcblx0XHRpID0gMDtcblx0XHR3aGlsZSAoIChtYXRjaGVkID0gaGFuZGxlclF1ZXVlWyBpKysgXSkgJiYgIWV2ZW50LmlzUHJvcGFnYXRpb25TdG9wcGVkKCkgKSB7XG5cdFx0XHRldmVudC5jdXJyZW50VGFyZ2V0ID0gbWF0Y2hlZC5lbGVtO1xuXG5cdFx0XHRqID0gMDtcblx0XHRcdHdoaWxlICggKGhhbmRsZU9iaiA9IG1hdGNoZWQuaGFuZGxlcnNbIGorKyBdKSAmJiAhZXZlbnQuaXNJbW1lZGlhdGVQcm9wYWdhdGlvblN0b3BwZWQoKSApIHtcblxuXHRcdFx0XHQvLyBUcmlnZ2VyZWQgZXZlbnQgbXVzdCBlaXRoZXIgMSkgaGF2ZSBubyBuYW1lc3BhY2UsIG9yIDIpIGhhdmUgbmFtZXNwYWNlKHMpXG5cdFx0XHRcdC8vIGEgc3Vic2V0IG9yIGVxdWFsIHRvIHRob3NlIGluIHRoZSBib3VuZCBldmVudCAoYm90aCBjYW4gaGF2ZSBubyBuYW1lc3BhY2UpLlxuXHRcdFx0XHRpZiAoICFldmVudC5uYW1lc3BhY2VfcmUgfHwgZXZlbnQubmFtZXNwYWNlX3JlLnRlc3QoIGhhbmRsZU9iai5uYW1lc3BhY2UgKSApIHtcblxuXHRcdFx0XHRcdGV2ZW50LmhhbmRsZU9iaiA9IGhhbmRsZU9iajtcblx0XHRcdFx0XHRldmVudC5kYXRhID0gaGFuZGxlT2JqLmRhdGE7XG5cblx0XHRcdFx0XHRyZXQgPSAoIChqUXVlcnkuZXZlbnQuc3BlY2lhbFsgaGFuZGxlT2JqLm9yaWdUeXBlIF0gfHwge30pLmhhbmRsZSB8fCBoYW5kbGVPYmouaGFuZGxlciApXG5cdFx0XHRcdFx0XHRcdC5hcHBseSggbWF0Y2hlZC5lbGVtLCBhcmdzICk7XG5cblx0XHRcdFx0XHRpZiAoIHJldCAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRcdFx0aWYgKCAoZXZlbnQucmVzdWx0ID0gcmV0KSA9PT0gZmFsc2UgKSB7XG5cdFx0XHRcdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdFx0XHRcdGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIENhbGwgdGhlIHBvc3REaXNwYXRjaCBob29rIGZvciB0aGUgbWFwcGVkIHR5cGVcblx0XHRpZiAoIHNwZWNpYWwucG9zdERpc3BhdGNoICkge1xuXHRcdFx0c3BlY2lhbC5wb3N0RGlzcGF0Y2guY2FsbCggdGhpcywgZXZlbnQgKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gZXZlbnQucmVzdWx0O1xuXHR9LFxuXG5cdGhhbmRsZXJzOiBmdW5jdGlvbiggZXZlbnQsIGhhbmRsZXJzICkge1xuXHRcdHZhciBpLCBtYXRjaGVzLCBzZWwsIGhhbmRsZU9iaixcblx0XHRcdGhhbmRsZXJRdWV1ZSA9IFtdLFxuXHRcdFx0ZGVsZWdhdGVDb3VudCA9IGhhbmRsZXJzLmRlbGVnYXRlQ291bnQsXG5cdFx0XHRjdXIgPSBldmVudC50YXJnZXQ7XG5cblx0XHQvLyBGaW5kIGRlbGVnYXRlIGhhbmRsZXJzXG5cdFx0Ly8gQmxhY2staG9sZSBTVkcgPHVzZT4gaW5zdGFuY2UgdHJlZXMgKCMxMzE4MClcblx0XHQvLyBBdm9pZCBub24tbGVmdC1jbGljayBidWJibGluZyBpbiBGaXJlZm94ICgjMzg2MSlcblx0XHRpZiAoIGRlbGVnYXRlQ291bnQgJiYgY3VyLm5vZGVUeXBlICYmICghZXZlbnQuYnV0dG9uIHx8IGV2ZW50LnR5cGUgIT09IFwiY2xpY2tcIikgKSB7XG5cblx0XHRcdGZvciAoIDsgY3VyICE9PSB0aGlzOyBjdXIgPSBjdXIucGFyZW50Tm9kZSB8fCB0aGlzICkge1xuXG5cdFx0XHRcdC8vIERvbid0IHByb2Nlc3MgY2xpY2tzIG9uIGRpc2FibGVkIGVsZW1lbnRzICgjNjkxMSwgIzgxNjUsICMxMTM4MiwgIzExNzY0KVxuXHRcdFx0XHRpZiAoIGN1ci5kaXNhYmxlZCAhPT0gdHJ1ZSB8fCBldmVudC50eXBlICE9PSBcImNsaWNrXCIgKSB7XG5cdFx0XHRcdFx0bWF0Y2hlcyA9IFtdO1xuXHRcdFx0XHRcdGZvciAoIGkgPSAwOyBpIDwgZGVsZWdhdGVDb3VudDsgaSsrICkge1xuXHRcdFx0XHRcdFx0aGFuZGxlT2JqID0gaGFuZGxlcnNbIGkgXTtcblxuXHRcdFx0XHRcdFx0Ly8gRG9uJ3QgY29uZmxpY3Qgd2l0aCBPYmplY3QucHJvdG90eXBlIHByb3BlcnRpZXMgKCMxMzIwMylcblx0XHRcdFx0XHRcdHNlbCA9IGhhbmRsZU9iai5zZWxlY3RvciArIFwiIFwiO1xuXG5cdFx0XHRcdFx0XHRpZiAoIG1hdGNoZXNbIHNlbCBdID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdFx0XHRcdG1hdGNoZXNbIHNlbCBdID0gaGFuZGxlT2JqLm5lZWRzQ29udGV4dCA/XG5cdFx0XHRcdFx0XHRcdFx0alF1ZXJ5KCBzZWwsIHRoaXMgKS5pbmRleCggY3VyICkgPj0gMCA6XG5cdFx0XHRcdFx0XHRcdFx0alF1ZXJ5LmZpbmQoIHNlbCwgdGhpcywgbnVsbCwgWyBjdXIgXSApLmxlbmd0aDtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGlmICggbWF0Y2hlc1sgc2VsIF0gKSB7XG5cdFx0XHRcdFx0XHRcdG1hdGNoZXMucHVzaCggaGFuZGxlT2JqICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGlmICggbWF0Y2hlcy5sZW5ndGggKSB7XG5cdFx0XHRcdFx0XHRoYW5kbGVyUXVldWUucHVzaCh7IGVsZW06IGN1ciwgaGFuZGxlcnM6IG1hdGNoZXMgfSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gQWRkIHRoZSByZW1haW5pbmcgKGRpcmVjdGx5LWJvdW5kKSBoYW5kbGVyc1xuXHRcdGlmICggZGVsZWdhdGVDb3VudCA8IGhhbmRsZXJzLmxlbmd0aCApIHtcblx0XHRcdGhhbmRsZXJRdWV1ZS5wdXNoKHsgZWxlbTogdGhpcywgaGFuZGxlcnM6IGhhbmRsZXJzLnNsaWNlKCBkZWxlZ2F0ZUNvdW50ICkgfSk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGhhbmRsZXJRdWV1ZTtcblx0fSxcblxuXHQvLyBJbmNsdWRlcyBzb21lIGV2ZW50IHByb3BzIHNoYXJlZCBieSBLZXlFdmVudCBhbmQgTW91c2VFdmVudFxuXHRwcm9wczogXCJhbHRLZXkgYnViYmxlcyBjYW5jZWxhYmxlIGN0cmxLZXkgY3VycmVudFRhcmdldCBldmVudFBoYXNlIG1ldGFLZXkgcmVsYXRlZFRhcmdldCBzaGlmdEtleSB0YXJnZXQgdGltZVN0YW1wIHZpZXcgd2hpY2hcIi5zcGxpdChcIiBcIiksXG5cblx0Zml4SG9va3M6IHt9LFxuXG5cdGtleUhvb2tzOiB7XG5cdFx0cHJvcHM6IFwiY2hhciBjaGFyQ29kZSBrZXkga2V5Q29kZVwiLnNwbGl0KFwiIFwiKSxcblx0XHRmaWx0ZXI6IGZ1bmN0aW9uKCBldmVudCwgb3JpZ2luYWwgKSB7XG5cblx0XHRcdC8vIEFkZCB3aGljaCBmb3Iga2V5IGV2ZW50c1xuXHRcdFx0aWYgKCBldmVudC53aGljaCA9PSBudWxsICkge1xuXHRcdFx0XHRldmVudC53aGljaCA9IG9yaWdpbmFsLmNoYXJDb2RlICE9IG51bGwgPyBvcmlnaW5hbC5jaGFyQ29kZSA6IG9yaWdpbmFsLmtleUNvZGU7XG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiBldmVudDtcblx0XHR9XG5cdH0sXG5cblx0bW91c2VIb29rczoge1xuXHRcdHByb3BzOiBcImJ1dHRvbiBidXR0b25zIGNsaWVudFggY2xpZW50WSBvZmZzZXRYIG9mZnNldFkgcGFnZVggcGFnZVkgc2NyZWVuWCBzY3JlZW5ZIHRvRWxlbWVudFwiLnNwbGl0KFwiIFwiKSxcblx0XHRmaWx0ZXI6IGZ1bmN0aW9uKCBldmVudCwgb3JpZ2luYWwgKSB7XG5cdFx0XHR2YXIgZXZlbnREb2MsIGRvYywgYm9keSxcblx0XHRcdFx0YnV0dG9uID0gb3JpZ2luYWwuYnV0dG9uO1xuXG5cdFx0XHQvLyBDYWxjdWxhdGUgcGFnZVgvWSBpZiBtaXNzaW5nIGFuZCBjbGllbnRYL1kgYXZhaWxhYmxlXG5cdFx0XHRpZiAoIGV2ZW50LnBhZ2VYID09IG51bGwgJiYgb3JpZ2luYWwuY2xpZW50WCAhPSBudWxsICkge1xuXHRcdFx0XHRldmVudERvYyA9IGV2ZW50LnRhcmdldC5vd25lckRvY3VtZW50IHx8IGRvY3VtZW50O1xuXHRcdFx0XHRkb2MgPSBldmVudERvYy5kb2N1bWVudEVsZW1lbnQ7XG5cdFx0XHRcdGJvZHkgPSBldmVudERvYy5ib2R5O1xuXG5cdFx0XHRcdGV2ZW50LnBhZ2VYID0gb3JpZ2luYWwuY2xpZW50WCArICggZG9jICYmIGRvYy5zY3JvbGxMZWZ0IHx8IGJvZHkgJiYgYm9keS5zY3JvbGxMZWZ0IHx8IDAgKSAtICggZG9jICYmIGRvYy5jbGllbnRMZWZ0IHx8IGJvZHkgJiYgYm9keS5jbGllbnRMZWZ0IHx8IDAgKTtcblx0XHRcdFx0ZXZlbnQucGFnZVkgPSBvcmlnaW5hbC5jbGllbnRZICsgKCBkb2MgJiYgZG9jLnNjcm9sbFRvcCAgfHwgYm9keSAmJiBib2R5LnNjcm9sbFRvcCAgfHwgMCApIC0gKCBkb2MgJiYgZG9jLmNsaWVudFRvcCAgfHwgYm9keSAmJiBib2R5LmNsaWVudFRvcCAgfHwgMCApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBBZGQgd2hpY2ggZm9yIGNsaWNrOiAxID09PSBsZWZ0OyAyID09PSBtaWRkbGU7IDMgPT09IHJpZ2h0XG5cdFx0XHQvLyBOb3RlOiBidXR0b24gaXMgbm90IG5vcm1hbGl6ZWQsIHNvIGRvbid0IHVzZSBpdFxuXHRcdFx0aWYgKCAhZXZlbnQud2hpY2ggJiYgYnV0dG9uICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdGV2ZW50LndoaWNoID0gKCBidXR0b24gJiAxID8gMSA6ICggYnV0dG9uICYgMiA/IDMgOiAoIGJ1dHRvbiAmIDQgPyAyIDogMCApICkgKTtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGV2ZW50O1xuXHRcdH1cblx0fSxcblxuXHRmaXg6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRpZiAoIGV2ZW50WyBqUXVlcnkuZXhwYW5kbyBdICkge1xuXHRcdFx0cmV0dXJuIGV2ZW50O1xuXHRcdH1cblxuXHRcdC8vIENyZWF0ZSBhIHdyaXRhYmxlIGNvcHkgb2YgdGhlIGV2ZW50IG9iamVjdCBhbmQgbm9ybWFsaXplIHNvbWUgcHJvcGVydGllc1xuXHRcdHZhciBpLCBwcm9wLCBjb3B5LFxuXHRcdFx0dHlwZSA9IGV2ZW50LnR5cGUsXG5cdFx0XHRvcmlnaW5hbEV2ZW50ID0gZXZlbnQsXG5cdFx0XHRmaXhIb29rID0gdGhpcy5maXhIb29rc1sgdHlwZSBdO1xuXG5cdFx0aWYgKCAhZml4SG9vayApIHtcblx0XHRcdHRoaXMuZml4SG9va3NbIHR5cGUgXSA9IGZpeEhvb2sgPVxuXHRcdFx0XHRybW91c2VFdmVudC50ZXN0KCB0eXBlICkgPyB0aGlzLm1vdXNlSG9va3MgOlxuXHRcdFx0XHRya2V5RXZlbnQudGVzdCggdHlwZSApID8gdGhpcy5rZXlIb29rcyA6XG5cdFx0XHRcdHt9O1xuXHRcdH1cblx0XHRjb3B5ID0gZml4SG9vay5wcm9wcyA/IHRoaXMucHJvcHMuY29uY2F0KCBmaXhIb29rLnByb3BzICkgOiB0aGlzLnByb3BzO1xuXG5cdFx0ZXZlbnQgPSBuZXcgalF1ZXJ5LkV2ZW50KCBvcmlnaW5hbEV2ZW50ICk7XG5cblx0XHRpID0gY29weS5sZW5ndGg7XG5cdFx0d2hpbGUgKCBpLS0gKSB7XG5cdFx0XHRwcm9wID0gY29weVsgaSBdO1xuXHRcdFx0ZXZlbnRbIHByb3AgXSA9IG9yaWdpbmFsRXZlbnRbIHByb3AgXTtcblx0XHR9XG5cblx0XHQvLyBTdXBwb3J0OiBDb3Jkb3ZhIDIuNSAoV2ViS2l0KSAoIzEzMjU1KVxuXHRcdC8vIEFsbCBldmVudHMgc2hvdWxkIGhhdmUgYSB0YXJnZXQ7IENvcmRvdmEgZGV2aWNlcmVhZHkgZG9lc24ndFxuXHRcdGlmICggIWV2ZW50LnRhcmdldCApIHtcblx0XHRcdGV2ZW50LnRhcmdldCA9IGRvY3VtZW50O1xuXHRcdH1cblxuXHRcdC8vIFN1cHBvcnQ6IFNhZmFyaSA2LjArLCBDaHJvbWU8Mjhcblx0XHQvLyBUYXJnZXQgc2hvdWxkIG5vdCBiZSBhIHRleHQgbm9kZSAoIzUwNCwgIzEzMTQzKVxuXHRcdGlmICggZXZlbnQudGFyZ2V0Lm5vZGVUeXBlID09PSAzICkge1xuXHRcdFx0ZXZlbnQudGFyZ2V0ID0gZXZlbnQudGFyZ2V0LnBhcmVudE5vZGU7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGZpeEhvb2suZmlsdGVyID8gZml4SG9vay5maWx0ZXIoIGV2ZW50LCBvcmlnaW5hbEV2ZW50ICkgOiBldmVudDtcblx0fSxcblxuXHRzcGVjaWFsOiB7XG5cdFx0bG9hZDoge1xuXHRcdFx0Ly8gUHJldmVudCB0cmlnZ2VyZWQgaW1hZ2UubG9hZCBldmVudHMgZnJvbSBidWJibGluZyB0byB3aW5kb3cubG9hZFxuXHRcdFx0bm9CdWJibGU6IHRydWVcblx0XHR9LFxuXHRcdGZvY3VzOiB7XG5cdFx0XHQvLyBGaXJlIG5hdGl2ZSBldmVudCBpZiBwb3NzaWJsZSBzbyBibHVyL2ZvY3VzIHNlcXVlbmNlIGlzIGNvcnJlY3Rcblx0XHRcdHRyaWdnZXI6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRpZiAoIHRoaXMgIT09IHNhZmVBY3RpdmVFbGVtZW50KCkgJiYgdGhpcy5mb2N1cyApIHtcblx0XHRcdFx0XHR0aGlzLmZvY3VzKCk7XG5cdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHR9XG5cdFx0XHR9LFxuXHRcdFx0ZGVsZWdhdGVUeXBlOiBcImZvY3VzaW5cIlxuXHRcdH0sXG5cdFx0Ymx1cjoge1xuXHRcdFx0dHJpZ2dlcjogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGlmICggdGhpcyA9PT0gc2FmZUFjdGl2ZUVsZW1lbnQoKSAmJiB0aGlzLmJsdXIgKSB7XG5cdFx0XHRcdFx0dGhpcy5ibHVyKCk7XG5cdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHR9XG5cdFx0XHR9LFxuXHRcdFx0ZGVsZWdhdGVUeXBlOiBcImZvY3Vzb3V0XCJcblx0XHR9LFxuXHRcdGNsaWNrOiB7XG5cdFx0XHQvLyBGb3IgY2hlY2tib3gsIGZpcmUgbmF0aXZlIGV2ZW50IHNvIGNoZWNrZWQgc3RhdGUgd2lsbCBiZSByaWdodFxuXHRcdFx0dHJpZ2dlcjogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGlmICggdGhpcy50eXBlID09PSBcImNoZWNrYm94XCIgJiYgdGhpcy5jbGljayAmJiBqUXVlcnkubm9kZU5hbWUoIHRoaXMsIFwiaW5wdXRcIiApICkge1xuXHRcdFx0XHRcdHRoaXMuY2xpY2soKTtcblx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdH1cblx0XHRcdH0sXG5cblx0XHRcdC8vIEZvciBjcm9zcy1icm93c2VyIGNvbnNpc3RlbmN5LCBkb24ndCBmaXJlIG5hdGl2ZSAuY2xpY2soKSBvbiBsaW5rc1xuXHRcdFx0X2RlZmF1bHQ6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0cmV0dXJuIGpRdWVyeS5ub2RlTmFtZSggZXZlbnQudGFyZ2V0LCBcImFcIiApO1xuXHRcdFx0fVxuXHRcdH0sXG5cblx0XHRiZWZvcmV1bmxvYWQ6IHtcblx0XHRcdHBvc3REaXNwYXRjaDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXG5cdFx0XHRcdC8vIFN1cHBvcnQ6IEZpcmVmb3ggMjArXG5cdFx0XHRcdC8vIEZpcmVmb3ggZG9lc24ndCBhbGVydCBpZiB0aGUgcmV0dXJuVmFsdWUgZmllbGQgaXMgbm90IHNldC5cblx0XHRcdFx0aWYgKCBldmVudC5yZXN1bHQgIT09IHVuZGVmaW5lZCAmJiBldmVudC5vcmlnaW5hbEV2ZW50ICkge1xuXHRcdFx0XHRcdGV2ZW50Lm9yaWdpbmFsRXZlbnQucmV0dXJuVmFsdWUgPSBldmVudC5yZXN1bHQ7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cblx0c2ltdWxhdGU6IGZ1bmN0aW9uKCB0eXBlLCBlbGVtLCBldmVudCwgYnViYmxlICkge1xuXHRcdC8vIFBpZ2d5YmFjayBvbiBhIGRvbm9yIGV2ZW50IHRvIHNpbXVsYXRlIGEgZGlmZmVyZW50IG9uZS5cblx0XHQvLyBGYWtlIG9yaWdpbmFsRXZlbnQgdG8gYXZvaWQgZG9ub3IncyBzdG9wUHJvcGFnYXRpb24sIGJ1dCBpZiB0aGVcblx0XHQvLyBzaW11bGF0ZWQgZXZlbnQgcHJldmVudHMgZGVmYXVsdCB0aGVuIHdlIGRvIHRoZSBzYW1lIG9uIHRoZSBkb25vci5cblx0XHR2YXIgZSA9IGpRdWVyeS5leHRlbmQoXG5cdFx0XHRuZXcgalF1ZXJ5LkV2ZW50KCksXG5cdFx0XHRldmVudCxcblx0XHRcdHtcblx0XHRcdFx0dHlwZTogdHlwZSxcblx0XHRcdFx0aXNTaW11bGF0ZWQ6IHRydWUsXG5cdFx0XHRcdG9yaWdpbmFsRXZlbnQ6IHt9XG5cdFx0XHR9XG5cdFx0KTtcblx0XHRpZiAoIGJ1YmJsZSApIHtcblx0XHRcdGpRdWVyeS5ldmVudC50cmlnZ2VyKCBlLCBudWxsLCBlbGVtICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGpRdWVyeS5ldmVudC5kaXNwYXRjaC5jYWxsKCBlbGVtLCBlICk7XG5cdFx0fVxuXHRcdGlmICggZS5pc0RlZmF1bHRQcmV2ZW50ZWQoKSApIHtcblx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0fVxuXHR9XG59O1xuXG5qUXVlcnkucmVtb3ZlRXZlbnQgPSBmdW5jdGlvbiggZWxlbSwgdHlwZSwgaGFuZGxlICkge1xuXHRpZiAoIGVsZW0ucmVtb3ZlRXZlbnRMaXN0ZW5lciApIHtcblx0XHRlbGVtLnJlbW92ZUV2ZW50TGlzdGVuZXIoIHR5cGUsIGhhbmRsZSwgZmFsc2UgKTtcblx0fVxufTtcblxualF1ZXJ5LkV2ZW50ID0gZnVuY3Rpb24oIHNyYywgcHJvcHMgKSB7XG5cdC8vIEFsbG93IGluc3RhbnRpYXRpb24gd2l0aG91dCB0aGUgJ25ldycga2V5d29yZFxuXHRpZiAoICEodGhpcyBpbnN0YW5jZW9mIGpRdWVyeS5FdmVudCkgKSB7XG5cdFx0cmV0dXJuIG5ldyBqUXVlcnkuRXZlbnQoIHNyYywgcHJvcHMgKTtcblx0fVxuXG5cdC8vIEV2ZW50IG9iamVjdFxuXHRpZiAoIHNyYyAmJiBzcmMudHlwZSApIHtcblx0XHR0aGlzLm9yaWdpbmFsRXZlbnQgPSBzcmM7XG5cdFx0dGhpcy50eXBlID0gc3JjLnR5cGU7XG5cblx0XHQvLyBFdmVudHMgYnViYmxpbmcgdXAgdGhlIGRvY3VtZW50IG1heSBoYXZlIGJlZW4gbWFya2VkIGFzIHByZXZlbnRlZFxuXHRcdC8vIGJ5IGEgaGFuZGxlciBsb3dlciBkb3duIHRoZSB0cmVlOyByZWZsZWN0IHRoZSBjb3JyZWN0IHZhbHVlLlxuXHRcdHRoaXMuaXNEZWZhdWx0UHJldmVudGVkID0gc3JjLmRlZmF1bHRQcmV2ZW50ZWQgfHxcblx0XHRcdFx0c3JjLmRlZmF1bHRQcmV2ZW50ZWQgPT09IHVuZGVmaW5lZCAmJlxuXHRcdFx0XHQvLyBTdXBwb3J0OiBBbmRyb2lkPDQuMFxuXHRcdFx0XHRzcmMucmV0dXJuVmFsdWUgPT09IGZhbHNlID9cblx0XHRcdHJldHVyblRydWUgOlxuXHRcdFx0cmV0dXJuRmFsc2U7XG5cblx0Ly8gRXZlbnQgdHlwZVxuXHR9IGVsc2Uge1xuXHRcdHRoaXMudHlwZSA9IHNyYztcblx0fVxuXG5cdC8vIFB1dCBleHBsaWNpdGx5IHByb3ZpZGVkIHByb3BlcnRpZXMgb250byB0aGUgZXZlbnQgb2JqZWN0XG5cdGlmICggcHJvcHMgKSB7XG5cdFx0alF1ZXJ5LmV4dGVuZCggdGhpcywgcHJvcHMgKTtcblx0fVxuXG5cdC8vIENyZWF0ZSBhIHRpbWVzdGFtcCBpZiBpbmNvbWluZyBldmVudCBkb2Vzbid0IGhhdmUgb25lXG5cdHRoaXMudGltZVN0YW1wID0gc3JjICYmIHNyYy50aW1lU3RhbXAgfHwgalF1ZXJ5Lm5vdygpO1xuXG5cdC8vIE1hcmsgaXQgYXMgZml4ZWRcblx0dGhpc1sgalF1ZXJ5LmV4cGFuZG8gXSA9IHRydWU7XG59O1xuXG4vLyBqUXVlcnkuRXZlbnQgaXMgYmFzZWQgb24gRE9NMyBFdmVudHMgYXMgc3BlY2lmaWVkIGJ5IHRoZSBFQ01BU2NyaXB0IExhbmd1YWdlIEJpbmRpbmdcbi8vIGh0dHA6Ly93d3cudzMub3JnL1RSLzIwMDMvV0QtRE9NLUxldmVsLTMtRXZlbnRzLTIwMDMwMzMxL2VjbWEtc2NyaXB0LWJpbmRpbmcuaHRtbFxualF1ZXJ5LkV2ZW50LnByb3RvdHlwZSA9IHtcblx0aXNEZWZhdWx0UHJldmVudGVkOiByZXR1cm5GYWxzZSxcblx0aXNQcm9wYWdhdGlvblN0b3BwZWQ6IHJldHVybkZhbHNlLFxuXHRpc0ltbWVkaWF0ZVByb3BhZ2F0aW9uU3RvcHBlZDogcmV0dXJuRmFsc2UsXG5cblx0cHJldmVudERlZmF1bHQ6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBlID0gdGhpcy5vcmlnaW5hbEV2ZW50O1xuXG5cdFx0dGhpcy5pc0RlZmF1bHRQcmV2ZW50ZWQgPSByZXR1cm5UcnVlO1xuXG5cdFx0aWYgKCBlICYmIGUucHJldmVudERlZmF1bHQgKSB7XG5cdFx0XHRlLnByZXZlbnREZWZhdWx0KCk7XG5cdFx0fVxuXHR9LFxuXHRzdG9wUHJvcGFnYXRpb246IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBlID0gdGhpcy5vcmlnaW5hbEV2ZW50O1xuXG5cdFx0dGhpcy5pc1Byb3BhZ2F0aW9uU3RvcHBlZCA9IHJldHVyblRydWU7XG5cblx0XHRpZiAoIGUgJiYgZS5zdG9wUHJvcGFnYXRpb24gKSB7XG5cdFx0XHRlLnN0b3BQcm9wYWdhdGlvbigpO1xuXHRcdH1cblx0fSxcblx0c3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgZSA9IHRoaXMub3JpZ2luYWxFdmVudDtcblxuXHRcdHRoaXMuaXNJbW1lZGlhdGVQcm9wYWdhdGlvblN0b3BwZWQgPSByZXR1cm5UcnVlO1xuXG5cdFx0aWYgKCBlICYmIGUuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uICkge1xuXHRcdFx0ZS5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKTtcblx0XHR9XG5cblx0XHR0aGlzLnN0b3BQcm9wYWdhdGlvbigpO1xuXHR9XG59O1xuXG4vLyBDcmVhdGUgbW91c2VlbnRlci9sZWF2ZSBldmVudHMgdXNpbmcgbW91c2VvdmVyL291dCBhbmQgZXZlbnQtdGltZSBjaGVja3Ncbi8vIFN1cHBvcnQ6IENocm9tZSAxNStcbmpRdWVyeS5lYWNoKHtcblx0bW91c2VlbnRlcjogXCJtb3VzZW92ZXJcIixcblx0bW91c2VsZWF2ZTogXCJtb3VzZW91dFwiLFxuXHRwb2ludGVyZW50ZXI6IFwicG9pbnRlcm92ZXJcIixcblx0cG9pbnRlcmxlYXZlOiBcInBvaW50ZXJvdXRcIlxufSwgZnVuY3Rpb24oIG9yaWcsIGZpeCApIHtcblx0alF1ZXJ5LmV2ZW50LnNwZWNpYWxbIG9yaWcgXSA9IHtcblx0XHRkZWxlZ2F0ZVR5cGU6IGZpeCxcblx0XHRiaW5kVHlwZTogZml4LFxuXG5cdFx0aGFuZGxlOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHR2YXIgcmV0LFxuXHRcdFx0XHR0YXJnZXQgPSB0aGlzLFxuXHRcdFx0XHRyZWxhdGVkID0gZXZlbnQucmVsYXRlZFRhcmdldCxcblx0XHRcdFx0aGFuZGxlT2JqID0gZXZlbnQuaGFuZGxlT2JqO1xuXG5cdFx0XHQvLyBGb3IgbW91c2VudGVyL2xlYXZlIGNhbGwgdGhlIGhhbmRsZXIgaWYgcmVsYXRlZCBpcyBvdXRzaWRlIHRoZSB0YXJnZXQuXG5cdFx0XHQvLyBOQjogTm8gcmVsYXRlZFRhcmdldCBpZiB0aGUgbW91c2UgbGVmdC9lbnRlcmVkIHRoZSBicm93c2VyIHdpbmRvd1xuXHRcdFx0aWYgKCAhcmVsYXRlZCB8fCAocmVsYXRlZCAhPT0gdGFyZ2V0ICYmICFqUXVlcnkuY29udGFpbnMoIHRhcmdldCwgcmVsYXRlZCApKSApIHtcblx0XHRcdFx0ZXZlbnQudHlwZSA9IGhhbmRsZU9iai5vcmlnVHlwZTtcblx0XHRcdFx0cmV0ID0gaGFuZGxlT2JqLmhhbmRsZXIuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdFx0XHRldmVudC50eXBlID0gZml4O1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHJldDtcblx0XHR9XG5cdH07XG59KTtcblxuLy8gU3VwcG9ydDogRmlyZWZveCwgQ2hyb21lLCBTYWZhcmlcbi8vIENyZWF0ZSBcImJ1YmJsaW5nXCIgZm9jdXMgYW5kIGJsdXIgZXZlbnRzXG5pZiAoICFzdXBwb3J0LmZvY3VzaW5CdWJibGVzICkge1xuXHRqUXVlcnkuZWFjaCh7IGZvY3VzOiBcImZvY3VzaW5cIiwgYmx1cjogXCJmb2N1c291dFwiIH0sIGZ1bmN0aW9uKCBvcmlnLCBmaXggKSB7XG5cblx0XHQvLyBBdHRhY2ggYSBzaW5nbGUgY2FwdHVyaW5nIGhhbmRsZXIgb24gdGhlIGRvY3VtZW50IHdoaWxlIHNvbWVvbmUgd2FudHMgZm9jdXNpbi9mb2N1c291dFxuXHRcdHZhciBoYW5kbGVyID0gZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHRqUXVlcnkuZXZlbnQuc2ltdWxhdGUoIGZpeCwgZXZlbnQudGFyZ2V0LCBqUXVlcnkuZXZlbnQuZml4KCBldmVudCApLCB0cnVlICk7XG5cdFx0XHR9O1xuXG5cdFx0alF1ZXJ5LmV2ZW50LnNwZWNpYWxbIGZpeCBdID0ge1xuXHRcdFx0c2V0dXA6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR2YXIgZG9jID0gdGhpcy5vd25lckRvY3VtZW50IHx8IHRoaXMsXG5cdFx0XHRcdFx0YXR0YWNoZXMgPSBkYXRhX3ByaXYuYWNjZXNzKCBkb2MsIGZpeCApO1xuXG5cdFx0XHRcdGlmICggIWF0dGFjaGVzICkge1xuXHRcdFx0XHRcdGRvYy5hZGRFdmVudExpc3RlbmVyKCBvcmlnLCBoYW5kbGVyLCB0cnVlICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0ZGF0YV9wcml2LmFjY2VzcyggZG9jLCBmaXgsICggYXR0YWNoZXMgfHwgMCApICsgMSApO1xuXHRcdFx0fSxcblx0XHRcdHRlYXJkb3duOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0dmFyIGRvYyA9IHRoaXMub3duZXJEb2N1bWVudCB8fCB0aGlzLFxuXHRcdFx0XHRcdGF0dGFjaGVzID0gZGF0YV9wcml2LmFjY2VzcyggZG9jLCBmaXggKSAtIDE7XG5cblx0XHRcdFx0aWYgKCAhYXR0YWNoZXMgKSB7XG5cdFx0XHRcdFx0ZG9jLnJlbW92ZUV2ZW50TGlzdGVuZXIoIG9yaWcsIGhhbmRsZXIsIHRydWUgKTtcblx0XHRcdFx0XHRkYXRhX3ByaXYucmVtb3ZlKCBkb2MsIGZpeCApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0ZGF0YV9wcml2LmFjY2VzcyggZG9jLCBmaXgsIGF0dGFjaGVzICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9O1xuXHR9KTtcbn1cblxualF1ZXJ5LmZuLmV4dGVuZCh7XG5cblx0b246IGZ1bmN0aW9uKCB0eXBlcywgc2VsZWN0b3IsIGRhdGEsIGZuLCAvKklOVEVSTkFMKi8gb25lICkge1xuXHRcdHZhciBvcmlnRm4sIHR5cGU7XG5cblx0XHQvLyBUeXBlcyBjYW4gYmUgYSBtYXAgb2YgdHlwZXMvaGFuZGxlcnNcblx0XHRpZiAoIHR5cGVvZiB0eXBlcyA9PT0gXCJvYmplY3RcIiApIHtcblx0XHRcdC8vICggdHlwZXMtT2JqZWN0LCBzZWxlY3RvciwgZGF0YSApXG5cdFx0XHRpZiAoIHR5cGVvZiBzZWxlY3RvciAhPT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdFx0Ly8gKCB0eXBlcy1PYmplY3QsIGRhdGEgKVxuXHRcdFx0XHRkYXRhID0gZGF0YSB8fCBzZWxlY3Rvcjtcblx0XHRcdFx0c2VsZWN0b3IgPSB1bmRlZmluZWQ7XG5cdFx0XHR9XG5cdFx0XHRmb3IgKCB0eXBlIGluIHR5cGVzICkge1xuXHRcdFx0XHR0aGlzLm9uKCB0eXBlLCBzZWxlY3RvciwgZGF0YSwgdHlwZXNbIHR5cGUgXSwgb25lICk7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gdGhpcztcblx0XHR9XG5cblx0XHRpZiAoIGRhdGEgPT0gbnVsbCAmJiBmbiA9PSBudWxsICkge1xuXHRcdFx0Ly8gKCB0eXBlcywgZm4gKVxuXHRcdFx0Zm4gPSBzZWxlY3Rvcjtcblx0XHRcdGRhdGEgPSBzZWxlY3RvciA9IHVuZGVmaW5lZDtcblx0XHR9IGVsc2UgaWYgKCBmbiA9PSBudWxsICkge1xuXHRcdFx0aWYgKCB0eXBlb2Ygc2VsZWN0b3IgPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRcdC8vICggdHlwZXMsIHNlbGVjdG9yLCBmbiApXG5cdFx0XHRcdGZuID0gZGF0YTtcblx0XHRcdFx0ZGF0YSA9IHVuZGVmaW5lZDtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdC8vICggdHlwZXMsIGRhdGEsIGZuIClcblx0XHRcdFx0Zm4gPSBkYXRhO1xuXHRcdFx0XHRkYXRhID0gc2VsZWN0b3I7XG5cdFx0XHRcdHNlbGVjdG9yID0gdW5kZWZpbmVkO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRpZiAoIGZuID09PSBmYWxzZSApIHtcblx0XHRcdGZuID0gcmV0dXJuRmFsc2U7XG5cdFx0fSBlbHNlIGlmICggIWZuICkge1xuXHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0fVxuXG5cdFx0aWYgKCBvbmUgPT09IDEgKSB7XG5cdFx0XHRvcmlnRm4gPSBmbjtcblx0XHRcdGZuID0gZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHQvLyBDYW4gdXNlIGFuIGVtcHR5IHNldCwgc2luY2UgZXZlbnQgY29udGFpbnMgdGhlIGluZm9cblx0XHRcdFx0alF1ZXJ5KCkub2ZmKCBldmVudCApO1xuXHRcdFx0XHRyZXR1cm4gb3JpZ0ZuLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0XHRcdH07XG5cdFx0XHQvLyBVc2Ugc2FtZSBndWlkIHNvIGNhbGxlciBjYW4gcmVtb3ZlIHVzaW5nIG9yaWdGblxuXHRcdFx0Zm4uZ3VpZCA9IG9yaWdGbi5ndWlkIHx8ICggb3JpZ0ZuLmd1aWQgPSBqUXVlcnkuZ3VpZCsrICk7XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0alF1ZXJ5LmV2ZW50LmFkZCggdGhpcywgdHlwZXMsIGZuLCBkYXRhLCBzZWxlY3RvciApO1xuXHRcdH0pO1xuXHR9LFxuXHRvbmU6IGZ1bmN0aW9uKCB0eXBlcywgc2VsZWN0b3IsIGRhdGEsIGZuICkge1xuXHRcdHJldHVybiB0aGlzLm9uKCB0eXBlcywgc2VsZWN0b3IsIGRhdGEsIGZuLCAxICk7XG5cdH0sXG5cdG9mZjogZnVuY3Rpb24oIHR5cGVzLCBzZWxlY3RvciwgZm4gKSB7XG5cdFx0dmFyIGhhbmRsZU9iaiwgdHlwZTtcblx0XHRpZiAoIHR5cGVzICYmIHR5cGVzLnByZXZlbnREZWZhdWx0ICYmIHR5cGVzLmhhbmRsZU9iaiApIHtcblx0XHRcdC8vICggZXZlbnQgKSAgZGlzcGF0Y2hlZCBqUXVlcnkuRXZlbnRcblx0XHRcdGhhbmRsZU9iaiA9IHR5cGVzLmhhbmRsZU9iajtcblx0XHRcdGpRdWVyeSggdHlwZXMuZGVsZWdhdGVUYXJnZXQgKS5vZmYoXG5cdFx0XHRcdGhhbmRsZU9iai5uYW1lc3BhY2UgPyBoYW5kbGVPYmoub3JpZ1R5cGUgKyBcIi5cIiArIGhhbmRsZU9iai5uYW1lc3BhY2UgOiBoYW5kbGVPYmoub3JpZ1R5cGUsXG5cdFx0XHRcdGhhbmRsZU9iai5zZWxlY3Rvcixcblx0XHRcdFx0aGFuZGxlT2JqLmhhbmRsZXJcblx0XHRcdCk7XG5cdFx0XHRyZXR1cm4gdGhpcztcblx0XHR9XG5cdFx0aWYgKCB0eXBlb2YgdHlwZXMgPT09IFwib2JqZWN0XCIgKSB7XG5cdFx0XHQvLyAoIHR5cGVzLW9iamVjdCBbLCBzZWxlY3Rvcl0gKVxuXHRcdFx0Zm9yICggdHlwZSBpbiB0eXBlcyApIHtcblx0XHRcdFx0dGhpcy5vZmYoIHR5cGUsIHNlbGVjdG9yLCB0eXBlc1sgdHlwZSBdICk7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gdGhpcztcblx0XHR9XG5cdFx0aWYgKCBzZWxlY3RvciA9PT0gZmFsc2UgfHwgdHlwZW9mIHNlbGVjdG9yID09PSBcImZ1bmN0aW9uXCIgKSB7XG5cdFx0XHQvLyAoIHR5cGVzIFssIGZuXSApXG5cdFx0XHRmbiA9IHNlbGVjdG9yO1xuXHRcdFx0c2VsZWN0b3IgPSB1bmRlZmluZWQ7XG5cdFx0fVxuXHRcdGlmICggZm4gPT09IGZhbHNlICkge1xuXHRcdFx0Zm4gPSByZXR1cm5GYWxzZTtcblx0XHR9XG5cdFx0cmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpIHtcblx0XHRcdGpRdWVyeS5ldmVudC5yZW1vdmUoIHRoaXMsIHR5cGVzLCBmbiwgc2VsZWN0b3IgKTtcblx0XHR9KTtcblx0fSxcblxuXHR0cmlnZ2VyOiBmdW5jdGlvbiggdHlwZSwgZGF0YSApIHtcblx0XHRyZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKCkge1xuXHRcdFx0alF1ZXJ5LmV2ZW50LnRyaWdnZXIoIHR5cGUsIGRhdGEsIHRoaXMgKTtcblx0XHR9KTtcblx0fSxcblx0dHJpZ2dlckhhbmRsZXI6IGZ1bmN0aW9uKCB0eXBlLCBkYXRhICkge1xuXHRcdHZhciBlbGVtID0gdGhpc1swXTtcblx0XHRpZiAoIGVsZW0gKSB7XG5cdFx0XHRyZXR1cm4galF1ZXJ5LmV2ZW50LnRyaWdnZXIoIHR5cGUsIGRhdGEsIGVsZW0sIHRydWUgKTtcblx0XHR9XG5cdH1cbn0pO1xuXG5cbnZhclxuXHRyeGh0bWxUYWcgPSAvPCg/IWFyZWF8YnJ8Y29sfGVtYmVkfGhyfGltZ3xpbnB1dHxsaW5rfG1ldGF8cGFyYW0pKChbXFx3Ol0rKVtePl0qKVxcLz4vZ2ksXG5cdHJ0YWdOYW1lID0gLzwoW1xcdzpdKykvLFxuXHRyaHRtbCA9IC88fCYjP1xcdys7Lyxcblx0cm5vSW5uZXJodG1sID0gLzwoPzpzY3JpcHR8c3R5bGV8bGluaykvaSxcblx0Ly8gY2hlY2tlZD1cImNoZWNrZWRcIiBvciBjaGVja2VkXG5cdHJjaGVja2VkID0gL2NoZWNrZWRcXHMqKD86W149XXw9XFxzKi5jaGVja2VkLikvaSxcblx0cnNjcmlwdFR5cGUgPSAvXiR8XFwvKD86amF2YXxlY21hKXNjcmlwdC9pLFxuXHRyc2NyaXB0VHlwZU1hc2tlZCA9IC9edHJ1ZVxcLyguKikvLFxuXHRyY2xlYW5TY3JpcHQgPSAvXlxccyo8ISg/OlxcW0NEQVRBXFxbfC0tKXwoPzpcXF1cXF18LS0pPlxccyokL2csXG5cblx0Ly8gV2UgaGF2ZSB0byBjbG9zZSB0aGVzZSB0YWdzIHRvIHN1cHBvcnQgWEhUTUwgKCMxMzIwMClcblx0d3JhcE1hcCA9IHtcblxuXHRcdC8vIFN1cHBvcnQ6IElFOVxuXHRcdG9wdGlvbjogWyAxLCBcIjxzZWxlY3QgbXVsdGlwbGU9J211bHRpcGxlJz5cIiwgXCI8L3NlbGVjdD5cIiBdLFxuXG5cdFx0dGhlYWQ6IFsgMSwgXCI8dGFibGU+XCIsIFwiPC90YWJsZT5cIiBdLFxuXHRcdGNvbDogWyAyLCBcIjx0YWJsZT48Y29sZ3JvdXA+XCIsIFwiPC9jb2xncm91cD48L3RhYmxlPlwiIF0sXG5cdFx0dHI6IFsgMiwgXCI8dGFibGU+PHRib2R5PlwiLCBcIjwvdGJvZHk+PC90YWJsZT5cIiBdLFxuXHRcdHRkOiBbIDMsIFwiPHRhYmxlPjx0Ym9keT48dHI+XCIsIFwiPC90cj48L3Rib2R5PjwvdGFibGU+XCIgXSxcblxuXHRcdF9kZWZhdWx0OiBbIDAsIFwiXCIsIFwiXCIgXVxuXHR9O1xuXG4vLyBTdXBwb3J0OiBJRTlcbndyYXBNYXAub3B0Z3JvdXAgPSB3cmFwTWFwLm9wdGlvbjtcblxud3JhcE1hcC50Ym9keSA9IHdyYXBNYXAudGZvb3QgPSB3cmFwTWFwLmNvbGdyb3VwID0gd3JhcE1hcC5jYXB0aW9uID0gd3JhcE1hcC50aGVhZDtcbndyYXBNYXAudGggPSB3cmFwTWFwLnRkO1xuXG4vLyBTdXBwb3J0OiAxLnggY29tcGF0aWJpbGl0eVxuLy8gTWFuaXB1bGF0aW5nIHRhYmxlcyByZXF1aXJlcyBhIHRib2R5XG5mdW5jdGlvbiBtYW5pcHVsYXRpb25UYXJnZXQoIGVsZW0sIGNvbnRlbnQgKSB7XG5cdHJldHVybiBqUXVlcnkubm9kZU5hbWUoIGVsZW0sIFwidGFibGVcIiApICYmXG5cdFx0alF1ZXJ5Lm5vZGVOYW1lKCBjb250ZW50Lm5vZGVUeXBlICE9PSAxMSA/IGNvbnRlbnQgOiBjb250ZW50LmZpcnN0Q2hpbGQsIFwidHJcIiApID9cblxuXHRcdGVsZW0uZ2V0RWxlbWVudHNCeVRhZ05hbWUoXCJ0Ym9keVwiKVswXSB8fFxuXHRcdFx0ZWxlbS5hcHBlbmRDaGlsZCggZWxlbS5vd25lckRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJ0Ym9keVwiKSApIDpcblx0XHRlbGVtO1xufVxuXG4vLyBSZXBsYWNlL3Jlc3RvcmUgdGhlIHR5cGUgYXR0cmlidXRlIG9mIHNjcmlwdCBlbGVtZW50cyBmb3Igc2FmZSBET00gbWFuaXB1bGF0aW9uXG5mdW5jdGlvbiBkaXNhYmxlU2NyaXB0KCBlbGVtICkge1xuXHRlbGVtLnR5cGUgPSAoZWxlbS5nZXRBdHRyaWJ1dGUoXCJ0eXBlXCIpICE9PSBudWxsKSArIFwiL1wiICsgZWxlbS50eXBlO1xuXHRyZXR1cm4gZWxlbTtcbn1cbmZ1bmN0aW9uIHJlc3RvcmVTY3JpcHQoIGVsZW0gKSB7XG5cdHZhciBtYXRjaCA9IHJzY3JpcHRUeXBlTWFza2VkLmV4ZWMoIGVsZW0udHlwZSApO1xuXG5cdGlmICggbWF0Y2ggKSB7XG5cdFx0ZWxlbS50eXBlID0gbWF0Y2hbIDEgXTtcblx0fSBlbHNlIHtcblx0XHRlbGVtLnJlbW92ZUF0dHJpYnV0ZShcInR5cGVcIik7XG5cdH1cblxuXHRyZXR1cm4gZWxlbTtcbn1cblxuLy8gTWFyayBzY3JpcHRzIGFzIGhhdmluZyBhbHJlYWR5IGJlZW4gZXZhbHVhdGVkXG5mdW5jdGlvbiBzZXRHbG9iYWxFdmFsKCBlbGVtcywgcmVmRWxlbWVudHMgKSB7XG5cdHZhciBpID0gMCxcblx0XHRsID0gZWxlbXMubGVuZ3RoO1xuXG5cdGZvciAoIDsgaSA8IGw7IGkrKyApIHtcblx0XHRkYXRhX3ByaXYuc2V0KFxuXHRcdFx0ZWxlbXNbIGkgXSwgXCJnbG9iYWxFdmFsXCIsICFyZWZFbGVtZW50cyB8fCBkYXRhX3ByaXYuZ2V0KCByZWZFbGVtZW50c1sgaSBdLCBcImdsb2JhbEV2YWxcIiApXG5cdFx0KTtcblx0fVxufVxuXG5mdW5jdGlvbiBjbG9uZUNvcHlFdmVudCggc3JjLCBkZXN0ICkge1xuXHR2YXIgaSwgbCwgdHlwZSwgcGRhdGFPbGQsIHBkYXRhQ3VyLCB1ZGF0YU9sZCwgdWRhdGFDdXIsIGV2ZW50cztcblxuXHRpZiAoIGRlc3Qubm9kZVR5cGUgIT09IDEgKSB7XG5cdFx0cmV0dXJuO1xuXHR9XG5cblx0Ly8gMS4gQ29weSBwcml2YXRlIGRhdGE6IGV2ZW50cywgaGFuZGxlcnMsIGV0Yy5cblx0aWYgKCBkYXRhX3ByaXYuaGFzRGF0YSggc3JjICkgKSB7XG5cdFx0cGRhdGFPbGQgPSBkYXRhX3ByaXYuYWNjZXNzKCBzcmMgKTtcblx0XHRwZGF0YUN1ciA9IGRhdGFfcHJpdi5zZXQoIGRlc3QsIHBkYXRhT2xkICk7XG5cdFx0ZXZlbnRzID0gcGRhdGFPbGQuZXZlbnRzO1xuXG5cdFx0aWYgKCBldmVudHMgKSB7XG5cdFx0XHRkZWxldGUgcGRhdGFDdXIuaGFuZGxlO1xuXHRcdFx0cGRhdGFDdXIuZXZlbnRzID0ge307XG5cblx0XHRcdGZvciAoIHR5cGUgaW4gZXZlbnRzICkge1xuXHRcdFx0XHRmb3IgKCBpID0gMCwgbCA9IGV2ZW50c1sgdHlwZSBdLmxlbmd0aDsgaSA8IGw7IGkrKyApIHtcblx0XHRcdFx0XHRqUXVlcnkuZXZlbnQuYWRkKCBkZXN0LCB0eXBlLCBldmVudHNbIHR5cGUgXVsgaSBdICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHQvLyAyLiBDb3B5IHVzZXIgZGF0YVxuXHRpZiAoIGRhdGFfdXNlci5oYXNEYXRhKCBzcmMgKSApIHtcblx0XHR1ZGF0YU9sZCA9IGRhdGFfdXNlci5hY2Nlc3MoIHNyYyApO1xuXHRcdHVkYXRhQ3VyID0galF1ZXJ5LmV4dGVuZCgge30sIHVkYXRhT2xkICk7XG5cblx0XHRkYXRhX3VzZXIuc2V0KCBkZXN0LCB1ZGF0YUN1ciApO1xuXHR9XG59XG5cbmZ1bmN0aW9uIGdldEFsbCggY29udGV4dCwgdGFnICkge1xuXHR2YXIgcmV0ID0gY29udGV4dC5nZXRFbGVtZW50c0J5VGFnTmFtZSA/IGNvbnRleHQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoIHRhZyB8fCBcIipcIiApIDpcblx0XHRcdGNvbnRleHQucXVlcnlTZWxlY3RvckFsbCA/IGNvbnRleHQucXVlcnlTZWxlY3RvckFsbCggdGFnIHx8IFwiKlwiICkgOlxuXHRcdFx0W107XG5cblx0cmV0dXJuIHRhZyA9PT0gdW5kZWZpbmVkIHx8IHRhZyAmJiBqUXVlcnkubm9kZU5hbWUoIGNvbnRleHQsIHRhZyApID9cblx0XHRqUXVlcnkubWVyZ2UoIFsgY29udGV4dCBdLCByZXQgKSA6XG5cdFx0cmV0O1xufVxuXG4vLyBGaXggSUUgYnVncywgc2VlIHN1cHBvcnQgdGVzdHNcbmZ1bmN0aW9uIGZpeElucHV0KCBzcmMsIGRlc3QgKSB7XG5cdHZhciBub2RlTmFtZSA9IGRlc3Qubm9kZU5hbWUudG9Mb3dlckNhc2UoKTtcblxuXHQvLyBGYWlscyB0byBwZXJzaXN0IHRoZSBjaGVja2VkIHN0YXRlIG9mIGEgY2xvbmVkIGNoZWNrYm94IG9yIHJhZGlvIGJ1dHRvbi5cblx0aWYgKCBub2RlTmFtZSA9PT0gXCJpbnB1dFwiICYmIHJjaGVja2FibGVUeXBlLnRlc3QoIHNyYy50eXBlICkgKSB7XG5cdFx0ZGVzdC5jaGVja2VkID0gc3JjLmNoZWNrZWQ7XG5cblx0Ly8gRmFpbHMgdG8gcmV0dXJuIHRoZSBzZWxlY3RlZCBvcHRpb24gdG8gdGhlIGRlZmF1bHQgc2VsZWN0ZWQgc3RhdGUgd2hlbiBjbG9uaW5nIG9wdGlvbnNcblx0fSBlbHNlIGlmICggbm9kZU5hbWUgPT09IFwiaW5wdXRcIiB8fCBub2RlTmFtZSA9PT0gXCJ0ZXh0YXJlYVwiICkge1xuXHRcdGRlc3QuZGVmYXVsdFZhbHVlID0gc3JjLmRlZmF1bHRWYWx1ZTtcblx0fVxufVxuXG5qUXVlcnkuZXh0ZW5kKHtcblx0Y2xvbmU6IGZ1bmN0aW9uKCBlbGVtLCBkYXRhQW5kRXZlbnRzLCBkZWVwRGF0YUFuZEV2ZW50cyApIHtcblx0XHR2YXIgaSwgbCwgc3JjRWxlbWVudHMsIGRlc3RFbGVtZW50cyxcblx0XHRcdGNsb25lID0gZWxlbS5jbG9uZU5vZGUoIHRydWUgKSxcblx0XHRcdGluUGFnZSA9IGpRdWVyeS5jb250YWlucyggZWxlbS5vd25lckRvY3VtZW50LCBlbGVtICk7XG5cblx0XHQvLyBGaXggSUUgY2xvbmluZyBpc3N1ZXNcblx0XHRpZiAoICFzdXBwb3J0Lm5vQ2xvbmVDaGVja2VkICYmICggZWxlbS5ub2RlVHlwZSA9PT0gMSB8fCBlbGVtLm5vZGVUeXBlID09PSAxMSApICYmXG5cdFx0XHRcdCFqUXVlcnkuaXNYTUxEb2MoIGVsZW0gKSApIHtcblxuXHRcdFx0Ly8gV2UgZXNjaGV3IFNpenpsZSBoZXJlIGZvciBwZXJmb3JtYW5jZSByZWFzb25zOiBodHRwOi8vanNwZXJmLmNvbS9nZXRhbGwtdnMtc2l6emxlLzJcblx0XHRcdGRlc3RFbGVtZW50cyA9IGdldEFsbCggY2xvbmUgKTtcblx0XHRcdHNyY0VsZW1lbnRzID0gZ2V0QWxsKCBlbGVtICk7XG5cblx0XHRcdGZvciAoIGkgPSAwLCBsID0gc3JjRWxlbWVudHMubGVuZ3RoOyBpIDwgbDsgaSsrICkge1xuXHRcdFx0XHRmaXhJbnB1dCggc3JjRWxlbWVudHNbIGkgXSwgZGVzdEVsZW1lbnRzWyBpIF0gKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBDb3B5IHRoZSBldmVudHMgZnJvbSB0aGUgb3JpZ2luYWwgdG8gdGhlIGNsb25lXG5cdFx0aWYgKCBkYXRhQW5kRXZlbnRzICkge1xuXHRcdFx0aWYgKCBkZWVwRGF0YUFuZEV2ZW50cyApIHtcblx0XHRcdFx0c3JjRWxlbWVudHMgPSBzcmNFbGVtZW50cyB8fCBnZXRBbGwoIGVsZW0gKTtcblx0XHRcdFx0ZGVzdEVsZW1lbnRzID0gZGVzdEVsZW1lbnRzIHx8IGdldEFsbCggY2xvbmUgKTtcblxuXHRcdFx0XHRmb3IgKCBpID0gMCwgbCA9IHNyY0VsZW1lbnRzLmxlbmd0aDsgaSA8IGw7IGkrKyApIHtcblx0XHRcdFx0XHRjbG9uZUNvcHlFdmVudCggc3JjRWxlbWVudHNbIGkgXSwgZGVzdEVsZW1lbnRzWyBpIF0gKTtcblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Y2xvbmVDb3B5RXZlbnQoIGVsZW0sIGNsb25lICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gUHJlc2VydmUgc2NyaXB0IGV2YWx1YXRpb24gaGlzdG9yeVxuXHRcdGRlc3RFbGVtZW50cyA9IGdldEFsbCggY2xvbmUsIFwic2NyaXB0XCIgKTtcblx0XHRpZiAoIGRlc3RFbGVtZW50cy5sZW5ndGggPiAwICkge1xuXHRcdFx0c2V0R2xvYmFsRXZhbCggZGVzdEVsZW1lbnRzLCAhaW5QYWdlICYmIGdldEFsbCggZWxlbSwgXCJzY3JpcHRcIiApICk7XG5cdFx0fVxuXG5cdFx0Ly8gUmV0dXJuIHRoZSBjbG9uZWQgc2V0XG5cdFx0cmV0dXJuIGNsb25lO1xuXHR9LFxuXG5cdGJ1aWxkRnJhZ21lbnQ6IGZ1bmN0aW9uKCBlbGVtcywgY29udGV4dCwgc2NyaXB0cywgc2VsZWN0aW9uICkge1xuXHRcdHZhciBlbGVtLCB0bXAsIHRhZywgd3JhcCwgY29udGFpbnMsIGosXG5cdFx0XHRmcmFnbWVudCA9IGNvbnRleHQuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpLFxuXHRcdFx0bm9kZXMgPSBbXSxcblx0XHRcdGkgPSAwLFxuXHRcdFx0bCA9IGVsZW1zLmxlbmd0aDtcblxuXHRcdGZvciAoIDsgaSA8IGw7IGkrKyApIHtcblx0XHRcdGVsZW0gPSBlbGVtc1sgaSBdO1xuXG5cdFx0XHRpZiAoIGVsZW0gfHwgZWxlbSA9PT0gMCApIHtcblxuXHRcdFx0XHQvLyBBZGQgbm9kZXMgZGlyZWN0bHlcblx0XHRcdFx0aWYgKCBqUXVlcnkudHlwZSggZWxlbSApID09PSBcIm9iamVjdFwiICkge1xuXHRcdFx0XHRcdC8vIFN1cHBvcnQ6IFF0V2ViS2l0LCBQaGFudG9tSlNcblx0XHRcdFx0XHQvLyBwdXNoLmFwcGx5KF8sIGFycmF5bGlrZSkgdGhyb3dzIG9uIGFuY2llbnQgV2ViS2l0XG5cdFx0XHRcdFx0alF1ZXJ5Lm1lcmdlKCBub2RlcywgZWxlbS5ub2RlVHlwZSA/IFsgZWxlbSBdIDogZWxlbSApO1xuXG5cdFx0XHRcdC8vIENvbnZlcnQgbm9uLWh0bWwgaW50byBhIHRleHQgbm9kZVxuXHRcdFx0XHR9IGVsc2UgaWYgKCAhcmh0bWwudGVzdCggZWxlbSApICkge1xuXHRcdFx0XHRcdG5vZGVzLnB1c2goIGNvbnRleHQuY3JlYXRlVGV4dE5vZGUoIGVsZW0gKSApO1xuXG5cdFx0XHRcdC8vIENvbnZlcnQgaHRtbCBpbnRvIERPTSBub2Rlc1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHRtcCA9IHRtcCB8fCBmcmFnbWVudC5hcHBlbmRDaGlsZCggY29udGV4dC5jcmVhdGVFbGVtZW50KFwiZGl2XCIpICk7XG5cblx0XHRcdFx0XHQvLyBEZXNlcmlhbGl6ZSBhIHN0YW5kYXJkIHJlcHJlc2VudGF0aW9uXG5cdFx0XHRcdFx0dGFnID0gKCBydGFnTmFtZS5leGVjKCBlbGVtICkgfHwgWyBcIlwiLCBcIlwiIF0gKVsgMSBdLnRvTG93ZXJDYXNlKCk7XG5cdFx0XHRcdFx0d3JhcCA9IHdyYXBNYXBbIHRhZyBdIHx8IHdyYXBNYXAuX2RlZmF1bHQ7XG5cdFx0XHRcdFx0dG1wLmlubmVySFRNTCA9IHdyYXBbIDEgXSArIGVsZW0ucmVwbGFjZSggcnhodG1sVGFnLCBcIjwkMT48LyQyPlwiICkgKyB3cmFwWyAyIF07XG5cblx0XHRcdFx0XHQvLyBEZXNjZW5kIHRocm91Z2ggd3JhcHBlcnMgdG8gdGhlIHJpZ2h0IGNvbnRlbnRcblx0XHRcdFx0XHRqID0gd3JhcFsgMCBdO1xuXHRcdFx0XHRcdHdoaWxlICggai0tICkge1xuXHRcdFx0XHRcdFx0dG1wID0gdG1wLmxhc3RDaGlsZDtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvLyBTdXBwb3J0OiBRdFdlYktpdCwgUGhhbnRvbUpTXG5cdFx0XHRcdFx0Ly8gcHVzaC5hcHBseShfLCBhcnJheWxpa2UpIHRocm93cyBvbiBhbmNpZW50IFdlYktpdFxuXHRcdFx0XHRcdGpRdWVyeS5tZXJnZSggbm9kZXMsIHRtcC5jaGlsZE5vZGVzICk7XG5cblx0XHRcdFx0XHQvLyBSZW1lbWJlciB0aGUgdG9wLWxldmVsIGNvbnRhaW5lclxuXHRcdFx0XHRcdHRtcCA9IGZyYWdtZW50LmZpcnN0Q2hpbGQ7XG5cblx0XHRcdFx0XHQvLyBFbnN1cmUgdGhlIGNyZWF0ZWQgbm9kZXMgYXJlIG9ycGhhbmVkICgjMTIzOTIpXG5cdFx0XHRcdFx0dG1wLnRleHRDb250ZW50ID0gXCJcIjtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIFJlbW92ZSB3cmFwcGVyIGZyb20gZnJhZ21lbnRcblx0XHRmcmFnbWVudC50ZXh0Q29udGVudCA9IFwiXCI7XG5cblx0XHRpID0gMDtcblx0XHR3aGlsZSAoIChlbGVtID0gbm9kZXNbIGkrKyBdKSApIHtcblxuXHRcdFx0Ly8gIzQwODcgLSBJZiBvcmlnaW4gYW5kIGRlc3RpbmF0aW9uIGVsZW1lbnRzIGFyZSB0aGUgc2FtZSwgYW5kIHRoaXMgaXNcblx0XHRcdC8vIHRoYXQgZWxlbWVudCwgZG8gbm90IGRvIGFueXRoaW5nXG5cdFx0XHRpZiAoIHNlbGVjdGlvbiAmJiBqUXVlcnkuaW5BcnJheSggZWxlbSwgc2VsZWN0aW9uICkgIT09IC0xICkge1xuXHRcdFx0XHRjb250aW51ZTtcblx0XHRcdH1cblxuXHRcdFx0Y29udGFpbnMgPSBqUXVlcnkuY29udGFpbnMoIGVsZW0ub3duZXJEb2N1bWVudCwgZWxlbSApO1xuXG5cdFx0XHQvLyBBcHBlbmQgdG8gZnJhZ21lbnRcblx0XHRcdHRtcCA9IGdldEFsbCggZnJhZ21lbnQuYXBwZW5kQ2hpbGQoIGVsZW0gKSwgXCJzY3JpcHRcIiApO1xuXG5cdFx0XHQvLyBQcmVzZXJ2ZSBzY3JpcHQgZXZhbHVhdGlvbiBoaXN0b3J5XG5cdFx0XHRpZiAoIGNvbnRhaW5zICkge1xuXHRcdFx0XHRzZXRHbG9iYWxFdmFsKCB0bXAgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQ2FwdHVyZSBleGVjdXRhYmxlc1xuXHRcdFx0aWYgKCBzY3JpcHRzICkge1xuXHRcdFx0XHRqID0gMDtcblx0XHRcdFx0d2hpbGUgKCAoZWxlbSA9IHRtcFsgaisrIF0pICkge1xuXHRcdFx0XHRcdGlmICggcnNjcmlwdFR5cGUudGVzdCggZWxlbS50eXBlIHx8IFwiXCIgKSApIHtcblx0XHRcdFx0XHRcdHNjcmlwdHMucHVzaCggZWxlbSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiBmcmFnbWVudDtcblx0fSxcblxuXHRjbGVhbkRhdGE6IGZ1bmN0aW9uKCBlbGVtcyApIHtcblx0XHR2YXIgZGF0YSwgZWxlbSwgdHlwZSwga2V5LFxuXHRcdFx0c3BlY2lhbCA9IGpRdWVyeS5ldmVudC5zcGVjaWFsLFxuXHRcdFx0aSA9IDA7XG5cblx0XHRmb3IgKCA7IChlbGVtID0gZWxlbXNbIGkgXSkgIT09IHVuZGVmaW5lZDsgaSsrICkge1xuXHRcdFx0aWYgKCBqUXVlcnkuYWNjZXB0RGF0YSggZWxlbSApICkge1xuXHRcdFx0XHRrZXkgPSBlbGVtWyBkYXRhX3ByaXYuZXhwYW5kbyBdO1xuXG5cdFx0XHRcdGlmICgga2V5ICYmIChkYXRhID0gZGF0YV9wcml2LmNhY2hlWyBrZXkgXSkgKSB7XG5cdFx0XHRcdFx0aWYgKCBkYXRhLmV2ZW50cyApIHtcblx0XHRcdFx0XHRcdGZvciAoIHR5cGUgaW4gZGF0YS5ldmVudHMgKSB7XG5cdFx0XHRcdFx0XHRcdGlmICggc3BlY2lhbFsgdHlwZSBdICkge1xuXHRcdFx0XHRcdFx0XHRcdGpRdWVyeS5ldmVudC5yZW1vdmUoIGVsZW0sIHR5cGUgKTtcblxuXHRcdFx0XHRcdFx0XHQvLyBUaGlzIGlzIGEgc2hvcnRjdXQgdG8gYXZvaWQgalF1ZXJ5LmV2ZW50LnJlbW92ZSdzIG92ZXJoZWFkXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdFx0alF1ZXJ5LnJlbW92ZUV2ZW50KCBlbGVtLCB0eXBlLCBkYXRhLmhhbmRsZSApO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGlmICggZGF0YV9wcml2LmNhY2hlWyBrZXkgXSApIHtcblx0XHRcdFx0XHRcdC8vIERpc2NhcmQgYW55IHJlbWFpbmluZyBgcHJpdmF0ZWAgZGF0YVxuXHRcdFx0XHRcdFx0ZGVsZXRlIGRhdGFfcHJpdi5jYWNoZVsga2V5IF07XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHQvLyBEaXNjYXJkIGFueSByZW1haW5pbmcgYHVzZXJgIGRhdGFcblx0XHRcdGRlbGV0ZSBkYXRhX3VzZXIuY2FjaGVbIGVsZW1bIGRhdGFfdXNlci5leHBhbmRvIF0gXTtcblx0XHR9XG5cdH1cbn0pO1xuXG5qUXVlcnkuZm4uZXh0ZW5kKHtcblx0dGV4dDogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdHJldHVybiBhY2Nlc3MoIHRoaXMsIGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHRcdHJldHVybiB2YWx1ZSA9PT0gdW5kZWZpbmVkID9cblx0XHRcdFx0alF1ZXJ5LnRleHQoIHRoaXMgKSA6XG5cdFx0XHRcdHRoaXMuZW1wdHkoKS5lYWNoKGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdGlmICggdGhpcy5ub2RlVHlwZSA9PT0gMSB8fCB0aGlzLm5vZGVUeXBlID09PSAxMSB8fCB0aGlzLm5vZGVUeXBlID09PSA5ICkge1xuXHRcdFx0XHRcdFx0dGhpcy50ZXh0Q29udGVudCA9IHZhbHVlO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSk7XG5cdFx0fSwgbnVsbCwgdmFsdWUsIGFyZ3VtZW50cy5sZW5ndGggKTtcblx0fSxcblxuXHRhcHBlbmQ6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLmRvbU1hbmlwKCBhcmd1bWVudHMsIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0aWYgKCB0aGlzLm5vZGVUeXBlID09PSAxIHx8IHRoaXMubm9kZVR5cGUgPT09IDExIHx8IHRoaXMubm9kZVR5cGUgPT09IDkgKSB7XG5cdFx0XHRcdHZhciB0YXJnZXQgPSBtYW5pcHVsYXRpb25UYXJnZXQoIHRoaXMsIGVsZW0gKTtcblx0XHRcdFx0dGFyZ2V0LmFwcGVuZENoaWxkKCBlbGVtICk7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH0sXG5cblx0cHJlcGVuZDogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMuZG9tTWFuaXAoIGFyZ3VtZW50cywgZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRpZiAoIHRoaXMubm9kZVR5cGUgPT09IDEgfHwgdGhpcy5ub2RlVHlwZSA9PT0gMTEgfHwgdGhpcy5ub2RlVHlwZSA9PT0gOSApIHtcblx0XHRcdFx0dmFyIHRhcmdldCA9IG1hbmlwdWxhdGlvblRhcmdldCggdGhpcywgZWxlbSApO1xuXHRcdFx0XHR0YXJnZXQuaW5zZXJ0QmVmb3JlKCBlbGVtLCB0YXJnZXQuZmlyc3RDaGlsZCApO1xuXHRcdFx0fVxuXHRcdH0pO1xuXHR9LFxuXG5cdGJlZm9yZTogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMuZG9tTWFuaXAoIGFyZ3VtZW50cywgZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRpZiAoIHRoaXMucGFyZW50Tm9kZSApIHtcblx0XHRcdFx0dGhpcy5wYXJlbnROb2RlLmluc2VydEJlZm9yZSggZWxlbSwgdGhpcyApO1xuXHRcdFx0fVxuXHRcdH0pO1xuXHR9LFxuXG5cdGFmdGVyOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5kb21NYW5pcCggYXJndW1lbnRzLCBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdGlmICggdGhpcy5wYXJlbnROb2RlICkge1xuXHRcdFx0XHR0aGlzLnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKCBlbGVtLCB0aGlzLm5leHRTaWJsaW5nICk7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH0sXG5cblx0cmVtb3ZlOiBmdW5jdGlvbiggc2VsZWN0b3IsIGtlZXBEYXRhIC8qIEludGVybmFsIFVzZSBPbmx5ICovICkge1xuXHRcdHZhciBlbGVtLFxuXHRcdFx0ZWxlbXMgPSBzZWxlY3RvciA/IGpRdWVyeS5maWx0ZXIoIHNlbGVjdG9yLCB0aGlzICkgOiB0aGlzLFxuXHRcdFx0aSA9IDA7XG5cblx0XHRmb3IgKCA7IChlbGVtID0gZWxlbXNbaV0pICE9IG51bGw7IGkrKyApIHtcblx0XHRcdGlmICggIWtlZXBEYXRhICYmIGVsZW0ubm9kZVR5cGUgPT09IDEgKSB7XG5cdFx0XHRcdGpRdWVyeS5jbGVhbkRhdGEoIGdldEFsbCggZWxlbSApICk7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggZWxlbS5wYXJlbnROb2RlICkge1xuXHRcdFx0XHRpZiAoIGtlZXBEYXRhICYmIGpRdWVyeS5jb250YWlucyggZWxlbS5vd25lckRvY3VtZW50LCBlbGVtICkgKSB7XG5cdFx0XHRcdFx0c2V0R2xvYmFsRXZhbCggZ2V0QWxsKCBlbGVtLCBcInNjcmlwdFwiICkgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbGVtLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoIGVsZW0gKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHRlbXB0eTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGVsZW0sXG5cdFx0XHRpID0gMDtcblxuXHRcdGZvciAoIDsgKGVsZW0gPSB0aGlzW2ldKSAhPSBudWxsOyBpKysgKSB7XG5cdFx0XHRpZiAoIGVsZW0ubm9kZVR5cGUgPT09IDEgKSB7XG5cblx0XHRcdFx0Ly8gUHJldmVudCBtZW1vcnkgbGVha3Ncblx0XHRcdFx0alF1ZXJ5LmNsZWFuRGF0YSggZ2V0QWxsKCBlbGVtLCBmYWxzZSApICk7XG5cblx0XHRcdFx0Ly8gUmVtb3ZlIGFueSByZW1haW5pbmcgbm9kZXNcblx0XHRcdFx0ZWxlbS50ZXh0Q29udGVudCA9IFwiXCI7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0Y2xvbmU6IGZ1bmN0aW9uKCBkYXRhQW5kRXZlbnRzLCBkZWVwRGF0YUFuZEV2ZW50cyApIHtcblx0XHRkYXRhQW5kRXZlbnRzID0gZGF0YUFuZEV2ZW50cyA9PSBudWxsID8gZmFsc2UgOiBkYXRhQW5kRXZlbnRzO1xuXHRcdGRlZXBEYXRhQW5kRXZlbnRzID0gZGVlcERhdGFBbmRFdmVudHMgPT0gbnVsbCA/IGRhdGFBbmRFdmVudHMgOiBkZWVwRGF0YUFuZEV2ZW50cztcblxuXHRcdHJldHVybiB0aGlzLm1hcChmdW5jdGlvbigpIHtcblx0XHRcdHJldHVybiBqUXVlcnkuY2xvbmUoIHRoaXMsIGRhdGFBbmRFdmVudHMsIGRlZXBEYXRhQW5kRXZlbnRzICk7XG5cdFx0fSk7XG5cdH0sXG5cblx0aHRtbDogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdHJldHVybiBhY2Nlc3MoIHRoaXMsIGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHRcdHZhciBlbGVtID0gdGhpc1sgMCBdIHx8IHt9LFxuXHRcdFx0XHRpID0gMCxcblx0XHRcdFx0bCA9IHRoaXMubGVuZ3RoO1xuXG5cdFx0XHRpZiAoIHZhbHVlID09PSB1bmRlZmluZWQgJiYgZWxlbS5ub2RlVHlwZSA9PT0gMSApIHtcblx0XHRcdFx0cmV0dXJuIGVsZW0uaW5uZXJIVE1MO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBTZWUgaWYgd2UgY2FuIHRha2UgYSBzaG9ydGN1dCBhbmQganVzdCB1c2UgaW5uZXJIVE1MXG5cdFx0XHRpZiAoIHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIiAmJiAhcm5vSW5uZXJodG1sLnRlc3QoIHZhbHVlICkgJiZcblx0XHRcdFx0IXdyYXBNYXBbICggcnRhZ05hbWUuZXhlYyggdmFsdWUgKSB8fCBbIFwiXCIsIFwiXCIgXSApWyAxIF0udG9Mb3dlckNhc2UoKSBdICkge1xuXG5cdFx0XHRcdHZhbHVlID0gdmFsdWUucmVwbGFjZSggcnhodG1sVGFnLCBcIjwkMT48LyQyPlwiICk7XG5cblx0XHRcdFx0dHJ5IHtcblx0XHRcdFx0XHRmb3IgKCA7IGkgPCBsOyBpKysgKSB7XG5cdFx0XHRcdFx0XHRlbGVtID0gdGhpc1sgaSBdIHx8IHt9O1xuXG5cdFx0XHRcdFx0XHQvLyBSZW1vdmUgZWxlbWVudCBub2RlcyBhbmQgcHJldmVudCBtZW1vcnkgbGVha3Ncblx0XHRcdFx0XHRcdGlmICggZWxlbS5ub2RlVHlwZSA9PT0gMSApIHtcblx0XHRcdFx0XHRcdFx0alF1ZXJ5LmNsZWFuRGF0YSggZ2V0QWxsKCBlbGVtLCBmYWxzZSApICk7XG5cdFx0XHRcdFx0XHRcdGVsZW0uaW5uZXJIVE1MID0gdmFsdWU7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0ZWxlbSA9IDA7XG5cblx0XHRcdFx0Ly8gSWYgdXNpbmcgaW5uZXJIVE1MIHRocm93cyBhbiBleGNlcHRpb24sIHVzZSB0aGUgZmFsbGJhY2sgbWV0aG9kXG5cdFx0XHRcdH0gY2F0Y2goIGUgKSB7fVxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIGVsZW0gKSB7XG5cdFx0XHRcdHRoaXMuZW1wdHkoKS5hcHBlbmQoIHZhbHVlICk7XG5cdFx0XHR9XG5cdFx0fSwgbnVsbCwgdmFsdWUsIGFyZ3VtZW50cy5sZW5ndGggKTtcblx0fSxcblxuXHRyZXBsYWNlV2l0aDogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGFyZyA9IGFyZ3VtZW50c1sgMCBdO1xuXG5cdFx0Ly8gTWFrZSB0aGUgY2hhbmdlcywgcmVwbGFjaW5nIGVhY2ggY29udGV4dCBlbGVtZW50IHdpdGggdGhlIG5ldyBjb250ZW50XG5cdFx0dGhpcy5kb21NYW5pcCggYXJndW1lbnRzLCBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdGFyZyA9IHRoaXMucGFyZW50Tm9kZTtcblxuXHRcdFx0alF1ZXJ5LmNsZWFuRGF0YSggZ2V0QWxsKCB0aGlzICkgKTtcblxuXHRcdFx0aWYgKCBhcmcgKSB7XG5cdFx0XHRcdGFyZy5yZXBsYWNlQ2hpbGQoIGVsZW0sIHRoaXMgKTtcblx0XHRcdH1cblx0XHR9KTtcblxuXHRcdC8vIEZvcmNlIHJlbW92YWwgaWYgdGhlcmUgd2FzIG5vIG5ldyBjb250ZW50IChlLmcuLCBmcm9tIGVtcHR5IGFyZ3VtZW50cylcblx0XHRyZXR1cm4gYXJnICYmIChhcmcubGVuZ3RoIHx8IGFyZy5ub2RlVHlwZSkgPyB0aGlzIDogdGhpcy5yZW1vdmUoKTtcblx0fSxcblxuXHRkZXRhY2g6IGZ1bmN0aW9uKCBzZWxlY3RvciApIHtcblx0XHRyZXR1cm4gdGhpcy5yZW1vdmUoIHNlbGVjdG9yLCB0cnVlICk7XG5cdH0sXG5cblx0ZG9tTWFuaXA6IGZ1bmN0aW9uKCBhcmdzLCBjYWxsYmFjayApIHtcblxuXHRcdC8vIEZsYXR0ZW4gYW55IG5lc3RlZCBhcnJheXNcblx0XHRhcmdzID0gY29uY2F0LmFwcGx5KCBbXSwgYXJncyApO1xuXG5cdFx0dmFyIGZyYWdtZW50LCBmaXJzdCwgc2NyaXB0cywgaGFzU2NyaXB0cywgbm9kZSwgZG9jLFxuXHRcdFx0aSA9IDAsXG5cdFx0XHRsID0gdGhpcy5sZW5ndGgsXG5cdFx0XHRzZXQgPSB0aGlzLFxuXHRcdFx0aU5vQ2xvbmUgPSBsIC0gMSxcblx0XHRcdHZhbHVlID0gYXJnc1sgMCBdLFxuXHRcdFx0aXNGdW5jdGlvbiA9IGpRdWVyeS5pc0Z1bmN0aW9uKCB2YWx1ZSApO1xuXG5cdFx0Ly8gV2UgY2FuJ3QgY2xvbmVOb2RlIGZyYWdtZW50cyB0aGF0IGNvbnRhaW4gY2hlY2tlZCwgaW4gV2ViS2l0XG5cdFx0aWYgKCBpc0Z1bmN0aW9uIHx8XG5cdFx0XHRcdCggbCA+IDEgJiYgdHlwZW9mIHZhbHVlID09PSBcInN0cmluZ1wiICYmXG5cdFx0XHRcdFx0IXN1cHBvcnQuY2hlY2tDbG9uZSAmJiByY2hlY2tlZC50ZXN0KCB2YWx1ZSApICkgKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKCBpbmRleCApIHtcblx0XHRcdFx0dmFyIHNlbGYgPSBzZXQuZXEoIGluZGV4ICk7XG5cdFx0XHRcdGlmICggaXNGdW5jdGlvbiApIHtcblx0XHRcdFx0XHRhcmdzWyAwIF0gPSB2YWx1ZS5jYWxsKCB0aGlzLCBpbmRleCwgc2VsZi5odG1sKCkgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRzZWxmLmRvbU1hbmlwKCBhcmdzLCBjYWxsYmFjayApO1xuXHRcdFx0fSk7XG5cdFx0fVxuXG5cdFx0aWYgKCBsICkge1xuXHRcdFx0ZnJhZ21lbnQgPSBqUXVlcnkuYnVpbGRGcmFnbWVudCggYXJncywgdGhpc1sgMCBdLm93bmVyRG9jdW1lbnQsIGZhbHNlLCB0aGlzICk7XG5cdFx0XHRmaXJzdCA9IGZyYWdtZW50LmZpcnN0Q2hpbGQ7XG5cblx0XHRcdGlmICggZnJhZ21lbnQuY2hpbGROb2Rlcy5sZW5ndGggPT09IDEgKSB7XG5cdFx0XHRcdGZyYWdtZW50ID0gZmlyc3Q7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggZmlyc3QgKSB7XG5cdFx0XHRcdHNjcmlwdHMgPSBqUXVlcnkubWFwKCBnZXRBbGwoIGZyYWdtZW50LCBcInNjcmlwdFwiICksIGRpc2FibGVTY3JpcHQgKTtcblx0XHRcdFx0aGFzU2NyaXB0cyA9IHNjcmlwdHMubGVuZ3RoO1xuXG5cdFx0XHRcdC8vIFVzZSB0aGUgb3JpZ2luYWwgZnJhZ21lbnQgZm9yIHRoZSBsYXN0IGl0ZW0gaW5zdGVhZCBvZiB0aGUgZmlyc3QgYmVjYXVzZSBpdCBjYW4gZW5kIHVwXG5cdFx0XHRcdC8vIGJlaW5nIGVtcHRpZWQgaW5jb3JyZWN0bHkgaW4gY2VydGFpbiBzaXR1YXRpb25zICgjODA3MCkuXG5cdFx0XHRcdGZvciAoIDsgaSA8IGw7IGkrKyApIHtcblx0XHRcdFx0XHRub2RlID0gZnJhZ21lbnQ7XG5cblx0XHRcdFx0XHRpZiAoIGkgIT09IGlOb0Nsb25lICkge1xuXHRcdFx0XHRcdFx0bm9kZSA9IGpRdWVyeS5jbG9uZSggbm9kZSwgdHJ1ZSwgdHJ1ZSApO1xuXG5cdFx0XHRcdFx0XHQvLyBLZWVwIHJlZmVyZW5jZXMgdG8gY2xvbmVkIHNjcmlwdHMgZm9yIGxhdGVyIHJlc3RvcmF0aW9uXG5cdFx0XHRcdFx0XHRpZiAoIGhhc1NjcmlwdHMgKSB7XG5cdFx0XHRcdFx0XHRcdC8vIFN1cHBvcnQ6IFF0V2ViS2l0XG5cdFx0XHRcdFx0XHRcdC8vIGpRdWVyeS5tZXJnZSBiZWNhdXNlIHB1c2guYXBwbHkoXywgYXJyYXlsaWtlKSB0aHJvd3Ncblx0XHRcdFx0XHRcdFx0alF1ZXJ5Lm1lcmdlKCBzY3JpcHRzLCBnZXRBbGwoIG5vZGUsIFwic2NyaXB0XCIgKSApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGNhbGxiYWNrLmNhbGwoIHRoaXNbIGkgXSwgbm9kZSwgaSApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCBoYXNTY3JpcHRzICkge1xuXHRcdFx0XHRcdGRvYyA9IHNjcmlwdHNbIHNjcmlwdHMubGVuZ3RoIC0gMSBdLm93bmVyRG9jdW1lbnQ7XG5cblx0XHRcdFx0XHQvLyBSZWVuYWJsZSBzY3JpcHRzXG5cdFx0XHRcdFx0alF1ZXJ5Lm1hcCggc2NyaXB0cywgcmVzdG9yZVNjcmlwdCApO1xuXG5cdFx0XHRcdFx0Ly8gRXZhbHVhdGUgZXhlY3V0YWJsZSBzY3JpcHRzIG9uIGZpcnN0IGRvY3VtZW50IGluc2VydGlvblxuXHRcdFx0XHRcdGZvciAoIGkgPSAwOyBpIDwgaGFzU2NyaXB0czsgaSsrICkge1xuXHRcdFx0XHRcdFx0bm9kZSA9IHNjcmlwdHNbIGkgXTtcblx0XHRcdFx0XHRcdGlmICggcnNjcmlwdFR5cGUudGVzdCggbm9kZS50eXBlIHx8IFwiXCIgKSAmJlxuXHRcdFx0XHRcdFx0XHQhZGF0YV9wcml2LmFjY2Vzcyggbm9kZSwgXCJnbG9iYWxFdmFsXCIgKSAmJiBqUXVlcnkuY29udGFpbnMoIGRvYywgbm9kZSApICkge1xuXG5cdFx0XHRcdFx0XHRcdGlmICggbm9kZS5zcmMgKSB7XG5cdFx0XHRcdFx0XHRcdFx0Ly8gT3B0aW9uYWwgQUpBWCBkZXBlbmRlbmN5LCBidXQgd29uJ3QgcnVuIHNjcmlwdHMgaWYgbm90IHByZXNlbnRcblx0XHRcdFx0XHRcdFx0XHRpZiAoIGpRdWVyeS5fZXZhbFVybCApIHtcblx0XHRcdFx0XHRcdFx0XHRcdGpRdWVyeS5fZXZhbFVybCggbm9kZS5zcmMgKTtcblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdFx0alF1ZXJ5Lmdsb2JhbEV2YWwoIG5vZGUudGV4dENvbnRlbnQucmVwbGFjZSggcmNsZWFuU2NyaXB0LCBcIlwiICkgKTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXHR9XG59KTtcblxualF1ZXJ5LmVhY2goe1xuXHRhcHBlbmRUbzogXCJhcHBlbmRcIixcblx0cHJlcGVuZFRvOiBcInByZXBlbmRcIixcblx0aW5zZXJ0QmVmb3JlOiBcImJlZm9yZVwiLFxuXHRpbnNlcnRBZnRlcjogXCJhZnRlclwiLFxuXHRyZXBsYWNlQWxsOiBcInJlcGxhY2VXaXRoXCJcbn0sIGZ1bmN0aW9uKCBuYW1lLCBvcmlnaW5hbCApIHtcblx0alF1ZXJ5LmZuWyBuYW1lIF0gPSBmdW5jdGlvbiggc2VsZWN0b3IgKSB7XG5cdFx0dmFyIGVsZW1zLFxuXHRcdFx0cmV0ID0gW10sXG5cdFx0XHRpbnNlcnQgPSBqUXVlcnkoIHNlbGVjdG9yICksXG5cdFx0XHRsYXN0ID0gaW5zZXJ0Lmxlbmd0aCAtIDEsXG5cdFx0XHRpID0gMDtcblxuXHRcdGZvciAoIDsgaSA8PSBsYXN0OyBpKysgKSB7XG5cdFx0XHRlbGVtcyA9IGkgPT09IGxhc3QgPyB0aGlzIDogdGhpcy5jbG9uZSggdHJ1ZSApO1xuXHRcdFx0alF1ZXJ5KCBpbnNlcnRbIGkgXSApWyBvcmlnaW5hbCBdKCBlbGVtcyApO1xuXG5cdFx0XHQvLyBTdXBwb3J0OiBRdFdlYktpdFxuXHRcdFx0Ly8gLmdldCgpIGJlY2F1c2UgcHVzaC5hcHBseShfLCBhcnJheWxpa2UpIHRocm93c1xuXHRcdFx0cHVzaC5hcHBseSggcmV0LCBlbGVtcy5nZXQoKSApO1xuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLnB1c2hTdGFjayggcmV0ICk7XG5cdH07XG59KTtcblxuXG52YXIgaWZyYW1lLFxuXHRlbGVtZGlzcGxheSA9IHt9O1xuXG4vKipcbiAqIFJldHJpZXZlIHRoZSBhY3R1YWwgZGlzcGxheSBvZiBhIGVsZW1lbnRcbiAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lIG5vZGVOYW1lIG9mIHRoZSBlbGVtZW50XG4gKiBAcGFyYW0ge09iamVjdH0gZG9jIERvY3VtZW50IG9iamVjdFxuICovXG4vLyBDYWxsZWQgb25seSBmcm9tIHdpdGhpbiBkZWZhdWx0RGlzcGxheVxuZnVuY3Rpb24gYWN0dWFsRGlzcGxheSggbmFtZSwgZG9jICkge1xuXHR2YXIgc3R5bGUsXG5cdFx0ZWxlbSA9IGpRdWVyeSggZG9jLmNyZWF0ZUVsZW1lbnQoIG5hbWUgKSApLmFwcGVuZFRvKCBkb2MuYm9keSApLFxuXG5cdFx0Ly8gZ2V0RGVmYXVsdENvbXB1dGVkU3R5bGUgbWlnaHQgYmUgcmVsaWFibHkgdXNlZCBvbmx5IG9uIGF0dGFjaGVkIGVsZW1lbnRcblx0XHRkaXNwbGF5ID0gd2luZG93LmdldERlZmF1bHRDb21wdXRlZFN0eWxlICYmICggc3R5bGUgPSB3aW5kb3cuZ2V0RGVmYXVsdENvbXB1dGVkU3R5bGUoIGVsZW1bIDAgXSApICkgP1xuXG5cdFx0XHQvLyBVc2Ugb2YgdGhpcyBtZXRob2QgaXMgYSB0ZW1wb3JhcnkgZml4IChtb3JlIGxpa2Ugb3B0aW1pemF0aW9uKSB1bnRpbCBzb21ldGhpbmcgYmV0dGVyIGNvbWVzIGFsb25nLFxuXHRcdFx0Ly8gc2luY2UgaXQgd2FzIHJlbW92ZWQgZnJvbSBzcGVjaWZpY2F0aW9uIGFuZCBzdXBwb3J0ZWQgb25seSBpbiBGRlxuXHRcdFx0c3R5bGUuZGlzcGxheSA6IGpRdWVyeS5jc3MoIGVsZW1bIDAgXSwgXCJkaXNwbGF5XCIgKTtcblxuXHQvLyBXZSBkb24ndCBoYXZlIGFueSBkYXRhIHN0b3JlZCBvbiB0aGUgZWxlbWVudCxcblx0Ly8gc28gdXNlIFwiZGV0YWNoXCIgbWV0aG9kIGFzIGZhc3Qgd2F5IHRvIGdldCByaWQgb2YgdGhlIGVsZW1lbnRcblx0ZWxlbS5kZXRhY2goKTtcblxuXHRyZXR1cm4gZGlzcGxheTtcbn1cblxuLyoqXG4gKiBUcnkgdG8gZGV0ZXJtaW5lIHRoZSBkZWZhdWx0IGRpc3BsYXkgdmFsdWUgb2YgYW4gZWxlbWVudFxuICogQHBhcmFtIHtTdHJpbmd9IG5vZGVOYW1lXG4gKi9cbmZ1bmN0aW9uIGRlZmF1bHREaXNwbGF5KCBub2RlTmFtZSApIHtcblx0dmFyIGRvYyA9IGRvY3VtZW50LFxuXHRcdGRpc3BsYXkgPSBlbGVtZGlzcGxheVsgbm9kZU5hbWUgXTtcblxuXHRpZiAoICFkaXNwbGF5ICkge1xuXHRcdGRpc3BsYXkgPSBhY3R1YWxEaXNwbGF5KCBub2RlTmFtZSwgZG9jICk7XG5cblx0XHQvLyBJZiB0aGUgc2ltcGxlIHdheSBmYWlscywgcmVhZCBmcm9tIGluc2lkZSBhbiBpZnJhbWVcblx0XHRpZiAoIGRpc3BsYXkgPT09IFwibm9uZVwiIHx8ICFkaXNwbGF5ICkge1xuXG5cdFx0XHQvLyBVc2UgdGhlIGFscmVhZHktY3JlYXRlZCBpZnJhbWUgaWYgcG9zc2libGVcblx0XHRcdGlmcmFtZSA9IChpZnJhbWUgfHwgalF1ZXJ5KCBcIjxpZnJhbWUgZnJhbWVib3JkZXI9JzAnIHdpZHRoPScwJyBoZWlnaHQ9JzAnLz5cIiApKS5hcHBlbmRUbyggZG9jLmRvY3VtZW50RWxlbWVudCApO1xuXG5cdFx0XHQvLyBBbHdheXMgd3JpdGUgYSBuZXcgSFRNTCBza2VsZXRvbiBzbyBXZWJraXQgYW5kIEZpcmVmb3ggZG9uJ3QgY2hva2Ugb24gcmV1c2Vcblx0XHRcdGRvYyA9IGlmcmFtZVsgMCBdLmNvbnRlbnREb2N1bWVudDtcblxuXHRcdFx0Ly8gU3VwcG9ydDogSUVcblx0XHRcdGRvYy53cml0ZSgpO1xuXHRcdFx0ZG9jLmNsb3NlKCk7XG5cblx0XHRcdGRpc3BsYXkgPSBhY3R1YWxEaXNwbGF5KCBub2RlTmFtZSwgZG9jICk7XG5cdFx0XHRpZnJhbWUuZGV0YWNoKCk7XG5cdFx0fVxuXG5cdFx0Ly8gU3RvcmUgdGhlIGNvcnJlY3QgZGVmYXVsdCBkaXNwbGF5XG5cdFx0ZWxlbWRpc3BsYXlbIG5vZGVOYW1lIF0gPSBkaXNwbGF5O1xuXHR9XG5cblx0cmV0dXJuIGRpc3BsYXk7XG59XG52YXIgcm1hcmdpbiA9ICgvXm1hcmdpbi8pO1xuXG52YXIgcm51bW5vbnB4ID0gbmV3IFJlZ0V4cCggXCJeKFwiICsgcG51bSArIFwiKSg/IXB4KVthLXolXSskXCIsIFwiaVwiICk7XG5cbnZhciBnZXRTdHlsZXMgPSBmdW5jdGlvbiggZWxlbSApIHtcblx0XHQvLyBTdXBwb3J0OiBJRTw9MTErLCBGaXJlZm94PD0zMCsgKCMxNTA5OCwgIzE0MTUwKVxuXHRcdC8vIElFIHRocm93cyBvbiBlbGVtZW50cyBjcmVhdGVkIGluIHBvcHVwc1xuXHRcdC8vIEZGIG1lYW53aGlsZSB0aHJvd3Mgb24gZnJhbWUgZWxlbWVudHMgdGhyb3VnaCBcImRlZmF1bHRWaWV3LmdldENvbXB1dGVkU3R5bGVcIlxuXHRcdGlmICggZWxlbS5vd25lckRvY3VtZW50LmRlZmF1bHRWaWV3Lm9wZW5lciApIHtcblx0XHRcdHJldHVybiBlbGVtLm93bmVyRG9jdW1lbnQuZGVmYXVsdFZpZXcuZ2V0Q29tcHV0ZWRTdHlsZSggZWxlbSwgbnVsbCApO1xuXHRcdH1cblxuXHRcdHJldHVybiB3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZSggZWxlbSwgbnVsbCApO1xuXHR9O1xuXG5cblxuZnVuY3Rpb24gY3VyQ1NTKCBlbGVtLCBuYW1lLCBjb21wdXRlZCApIHtcblx0dmFyIHdpZHRoLCBtaW5XaWR0aCwgbWF4V2lkdGgsIHJldCxcblx0XHRzdHlsZSA9IGVsZW0uc3R5bGU7XG5cblx0Y29tcHV0ZWQgPSBjb21wdXRlZCB8fCBnZXRTdHlsZXMoIGVsZW0gKTtcblxuXHQvLyBTdXBwb3J0OiBJRTlcblx0Ly8gZ2V0UHJvcGVydHlWYWx1ZSBpcyBvbmx5IG5lZWRlZCBmb3IgLmNzcygnZmlsdGVyJykgKCMxMjUzNylcblx0aWYgKCBjb21wdXRlZCApIHtcblx0XHRyZXQgPSBjb21wdXRlZC5nZXRQcm9wZXJ0eVZhbHVlKCBuYW1lICkgfHwgY29tcHV0ZWRbIG5hbWUgXTtcblx0fVxuXG5cdGlmICggY29tcHV0ZWQgKSB7XG5cblx0XHRpZiAoIHJldCA9PT0gXCJcIiAmJiAhalF1ZXJ5LmNvbnRhaW5zKCBlbGVtLm93bmVyRG9jdW1lbnQsIGVsZW0gKSApIHtcblx0XHRcdHJldCA9IGpRdWVyeS5zdHlsZSggZWxlbSwgbmFtZSApO1xuXHRcdH1cblxuXHRcdC8vIFN1cHBvcnQ6IGlPUyA8IDZcblx0XHQvLyBBIHRyaWJ1dGUgdG8gdGhlIFwiYXdlc29tZSBoYWNrIGJ5IERlYW4gRWR3YXJkc1wiXG5cdFx0Ly8gaU9TIDwgNiAoYXQgbGVhc3QpIHJldHVybnMgcGVyY2VudGFnZSBmb3IgYSBsYXJnZXIgc2V0IG9mIHZhbHVlcywgYnV0IHdpZHRoIHNlZW1zIHRvIGJlIHJlbGlhYmx5IHBpeGVsc1xuXHRcdC8vIHRoaXMgaXMgYWdhaW5zdCB0aGUgQ1NTT00gZHJhZnQgc3BlYzogaHR0cDovL2Rldi53My5vcmcvY3Nzd2cvY3Nzb20vI3Jlc29sdmVkLXZhbHVlc1xuXHRcdGlmICggcm51bW5vbnB4LnRlc3QoIHJldCApICYmIHJtYXJnaW4udGVzdCggbmFtZSApICkge1xuXG5cdFx0XHQvLyBSZW1lbWJlciB0aGUgb3JpZ2luYWwgdmFsdWVzXG5cdFx0XHR3aWR0aCA9IHN0eWxlLndpZHRoO1xuXHRcdFx0bWluV2lkdGggPSBzdHlsZS5taW5XaWR0aDtcblx0XHRcdG1heFdpZHRoID0gc3R5bGUubWF4V2lkdGg7XG5cblx0XHRcdC8vIFB1dCBpbiB0aGUgbmV3IHZhbHVlcyB0byBnZXQgYSBjb21wdXRlZCB2YWx1ZSBvdXRcblx0XHRcdHN0eWxlLm1pbldpZHRoID0gc3R5bGUubWF4V2lkdGggPSBzdHlsZS53aWR0aCA9IHJldDtcblx0XHRcdHJldCA9IGNvbXB1dGVkLndpZHRoO1xuXG5cdFx0XHQvLyBSZXZlcnQgdGhlIGNoYW5nZWQgdmFsdWVzXG5cdFx0XHRzdHlsZS53aWR0aCA9IHdpZHRoO1xuXHRcdFx0c3R5bGUubWluV2lkdGggPSBtaW5XaWR0aDtcblx0XHRcdHN0eWxlLm1heFdpZHRoID0gbWF4V2lkdGg7XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIHJldCAhPT0gdW5kZWZpbmVkID9cblx0XHQvLyBTdXBwb3J0OiBJRVxuXHRcdC8vIElFIHJldHVybnMgekluZGV4IHZhbHVlIGFzIGFuIGludGVnZXIuXG5cdFx0cmV0ICsgXCJcIiA6XG5cdFx0cmV0O1xufVxuXG5cbmZ1bmN0aW9uIGFkZEdldEhvb2tJZiggY29uZGl0aW9uRm4sIGhvb2tGbiApIHtcblx0Ly8gRGVmaW5lIHRoZSBob29rLCB3ZSdsbCBjaGVjayBvbiB0aGUgZmlyc3QgcnVuIGlmIGl0J3MgcmVhbGx5IG5lZWRlZC5cblx0cmV0dXJuIHtcblx0XHRnZXQ6IGZ1bmN0aW9uKCkge1xuXHRcdFx0aWYgKCBjb25kaXRpb25GbigpICkge1xuXHRcdFx0XHQvLyBIb29rIG5vdCBuZWVkZWQgKG9yIGl0J3Mgbm90IHBvc3NpYmxlIHRvIHVzZSBpdCBkdWVcblx0XHRcdFx0Ly8gdG8gbWlzc2luZyBkZXBlbmRlbmN5KSwgcmVtb3ZlIGl0LlxuXHRcdFx0XHRkZWxldGUgdGhpcy5nZXQ7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0Ly8gSG9vayBuZWVkZWQ7IHJlZGVmaW5lIGl0IHNvIHRoYXQgdGhlIHN1cHBvcnQgdGVzdCBpcyBub3QgZXhlY3V0ZWQgYWdhaW4uXG5cdFx0XHRyZXR1cm4gKHRoaXMuZ2V0ID0gaG9va0ZuKS5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0fVxuXHR9O1xufVxuXG5cbihmdW5jdGlvbigpIHtcblx0dmFyIHBpeGVsUG9zaXRpb25WYWwsIGJveFNpemluZ1JlbGlhYmxlVmFsLFxuXHRcdGRvY0VsZW0gPSBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQsXG5cdFx0Y29udGFpbmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCggXCJkaXZcIiApLFxuXHRcdGRpdiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoIFwiZGl2XCIgKTtcblxuXHRpZiAoICFkaXYuc3R5bGUgKSB7XG5cdFx0cmV0dXJuO1xuXHR9XG5cblx0Ly8gU3VwcG9ydDogSUU5LTExK1xuXHQvLyBTdHlsZSBvZiBjbG9uZWQgZWxlbWVudCBhZmZlY3RzIHNvdXJjZSBlbGVtZW50IGNsb25lZCAoIzg5MDgpXG5cdGRpdi5zdHlsZS5iYWNrZ3JvdW5kQ2xpcCA9IFwiY29udGVudC1ib3hcIjtcblx0ZGl2LmNsb25lTm9kZSggdHJ1ZSApLnN0eWxlLmJhY2tncm91bmRDbGlwID0gXCJcIjtcblx0c3VwcG9ydC5jbGVhckNsb25lU3R5bGUgPSBkaXYuc3R5bGUuYmFja2dyb3VuZENsaXAgPT09IFwiY29udGVudC1ib3hcIjtcblxuXHRjb250YWluZXIuc3R5bGUuY3NzVGV4dCA9IFwiYm9yZGVyOjA7d2lkdGg6MDtoZWlnaHQ6MDt0b3A6MDtsZWZ0Oi05OTk5cHg7bWFyZ2luLXRvcDoxcHg7XCIgK1xuXHRcdFwicG9zaXRpb246YWJzb2x1dGVcIjtcblx0Y29udGFpbmVyLmFwcGVuZENoaWxkKCBkaXYgKTtcblxuXHQvLyBFeGVjdXRpbmcgYm90aCBwaXhlbFBvc2l0aW9uICYgYm94U2l6aW5nUmVsaWFibGUgdGVzdHMgcmVxdWlyZSBvbmx5IG9uZSBsYXlvdXRcblx0Ly8gc28gdGhleSdyZSBleGVjdXRlZCBhdCB0aGUgc2FtZSB0aW1lIHRvIHNhdmUgdGhlIHNlY29uZCBjb21wdXRhdGlvbi5cblx0ZnVuY3Rpb24gY29tcHV0ZVBpeGVsUG9zaXRpb25BbmRCb3hTaXppbmdSZWxpYWJsZSgpIHtcblx0XHRkaXYuc3R5bGUuY3NzVGV4dCA9XG5cdFx0XHQvLyBTdXBwb3J0OiBGaXJlZm94PDI5LCBBbmRyb2lkIDIuM1xuXHRcdFx0Ly8gVmVuZG9yLXByZWZpeCBib3gtc2l6aW5nXG5cdFx0XHRcIi13ZWJraXQtYm94LXNpemluZzpib3JkZXItYm94Oy1tb3otYm94LXNpemluZzpib3JkZXItYm94O1wiICtcblx0XHRcdFwiYm94LXNpemluZzpib3JkZXItYm94O2Rpc3BsYXk6YmxvY2s7bWFyZ2luLXRvcDoxJTt0b3A6MSU7XCIgK1xuXHRcdFx0XCJib3JkZXI6MXB4O3BhZGRpbmc6MXB4O3dpZHRoOjRweDtwb3NpdGlvbjphYnNvbHV0ZVwiO1xuXHRcdGRpdi5pbm5lckhUTUwgPSBcIlwiO1xuXHRcdGRvY0VsZW0uYXBwZW5kQ2hpbGQoIGNvbnRhaW5lciApO1xuXG5cdFx0dmFyIGRpdlN0eWxlID0gd2luZG93LmdldENvbXB1dGVkU3R5bGUoIGRpdiwgbnVsbCApO1xuXHRcdHBpeGVsUG9zaXRpb25WYWwgPSBkaXZTdHlsZS50b3AgIT09IFwiMSVcIjtcblx0XHRib3hTaXppbmdSZWxpYWJsZVZhbCA9IGRpdlN0eWxlLndpZHRoID09PSBcIjRweFwiO1xuXG5cdFx0ZG9jRWxlbS5yZW1vdmVDaGlsZCggY29udGFpbmVyICk7XG5cdH1cblxuXHQvLyBTdXBwb3J0OiBub2RlLmpzIGpzZG9tXG5cdC8vIERvbid0IGFzc3VtZSB0aGF0IGdldENvbXB1dGVkU3R5bGUgaXMgYSBwcm9wZXJ0eSBvZiB0aGUgZ2xvYmFsIG9iamVjdFxuXHRpZiAoIHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlICkge1xuXHRcdGpRdWVyeS5leHRlbmQoIHN1cHBvcnQsIHtcblx0XHRcdHBpeGVsUG9zaXRpb246IGZ1bmN0aW9uKCkge1xuXG5cdFx0XHRcdC8vIFRoaXMgdGVzdCBpcyBleGVjdXRlZCBvbmx5IG9uY2UgYnV0IHdlIHN0aWxsIGRvIG1lbW9pemluZ1xuXHRcdFx0XHQvLyBzaW5jZSB3ZSBjYW4gdXNlIHRoZSBib3hTaXppbmdSZWxpYWJsZSBwcmUtY29tcHV0aW5nLlxuXHRcdFx0XHQvLyBObyBuZWVkIHRvIGNoZWNrIGlmIHRoZSB0ZXN0IHdhcyBhbHJlYWR5IHBlcmZvcm1lZCwgdGhvdWdoLlxuXHRcdFx0XHRjb21wdXRlUGl4ZWxQb3NpdGlvbkFuZEJveFNpemluZ1JlbGlhYmxlKCk7XG5cdFx0XHRcdHJldHVybiBwaXhlbFBvc2l0aW9uVmFsO1xuXHRcdFx0fSxcblx0XHRcdGJveFNpemluZ1JlbGlhYmxlOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0aWYgKCBib3hTaXppbmdSZWxpYWJsZVZhbCA9PSBudWxsICkge1xuXHRcdFx0XHRcdGNvbXB1dGVQaXhlbFBvc2l0aW9uQW5kQm94U2l6aW5nUmVsaWFibGUoKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gYm94U2l6aW5nUmVsaWFibGVWYWw7XG5cdFx0XHR9LFxuXHRcdFx0cmVsaWFibGVNYXJnaW5SaWdodDogZnVuY3Rpb24oKSB7XG5cblx0XHRcdFx0Ly8gU3VwcG9ydDogQW5kcm9pZCAyLjNcblx0XHRcdFx0Ly8gQ2hlY2sgaWYgZGl2IHdpdGggZXhwbGljaXQgd2lkdGggYW5kIG5vIG1hcmdpbi1yaWdodCBpbmNvcnJlY3RseVxuXHRcdFx0XHQvLyBnZXRzIGNvbXB1dGVkIG1hcmdpbi1yaWdodCBiYXNlZCBvbiB3aWR0aCBvZiBjb250YWluZXIuICgjMzMzMylcblx0XHRcdFx0Ly8gV2ViS2l0IEJ1ZyAxMzM0MyAtIGdldENvbXB1dGVkU3R5bGUgcmV0dXJucyB3cm9uZyB2YWx1ZSBmb3IgbWFyZ2luLXJpZ2h0XG5cdFx0XHRcdC8vIFRoaXMgc3VwcG9ydCBmdW5jdGlvbiBpcyBvbmx5IGV4ZWN1dGVkIG9uY2Ugc28gbm8gbWVtb2l6aW5nIGlzIG5lZWRlZC5cblx0XHRcdFx0dmFyIHJldCxcblx0XHRcdFx0XHRtYXJnaW5EaXYgPSBkaXYuYXBwZW5kQ2hpbGQoIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoIFwiZGl2XCIgKSApO1xuXG5cdFx0XHRcdC8vIFJlc2V0IENTUzogYm94LXNpemluZzsgZGlzcGxheTsgbWFyZ2luOyBib3JkZXI7IHBhZGRpbmdcblx0XHRcdFx0bWFyZ2luRGl2LnN0eWxlLmNzc1RleHQgPSBkaXYuc3R5bGUuY3NzVGV4dCA9XG5cdFx0XHRcdFx0Ly8gU3VwcG9ydDogRmlyZWZveDwyOSwgQW5kcm9pZCAyLjNcblx0XHRcdFx0XHQvLyBWZW5kb3ItcHJlZml4IGJveC1zaXppbmdcblx0XHRcdFx0XHRcIi13ZWJraXQtYm94LXNpemluZzpjb250ZW50LWJveDstbW96LWJveC1zaXppbmc6Y29udGVudC1ib3g7XCIgK1xuXHRcdFx0XHRcdFwiYm94LXNpemluZzpjb250ZW50LWJveDtkaXNwbGF5OmJsb2NrO21hcmdpbjowO2JvcmRlcjowO3BhZGRpbmc6MFwiO1xuXHRcdFx0XHRtYXJnaW5EaXYuc3R5bGUubWFyZ2luUmlnaHQgPSBtYXJnaW5EaXYuc3R5bGUud2lkdGggPSBcIjBcIjtcblx0XHRcdFx0ZGl2LnN0eWxlLndpZHRoID0gXCIxcHhcIjtcblx0XHRcdFx0ZG9jRWxlbS5hcHBlbmRDaGlsZCggY29udGFpbmVyICk7XG5cblx0XHRcdFx0cmV0ID0gIXBhcnNlRmxvYXQoIHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKCBtYXJnaW5EaXYsIG51bGwgKS5tYXJnaW5SaWdodCApO1xuXG5cdFx0XHRcdGRvY0VsZW0ucmVtb3ZlQ2hpbGQoIGNvbnRhaW5lciApO1xuXHRcdFx0XHRkaXYucmVtb3ZlQ2hpbGQoIG1hcmdpbkRpdiApO1xuXG5cdFx0XHRcdHJldHVybiByZXQ7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH1cbn0pKCk7XG5cblxuLy8gQSBtZXRob2QgZm9yIHF1aWNrbHkgc3dhcHBpbmcgaW4vb3V0IENTUyBwcm9wZXJ0aWVzIHRvIGdldCBjb3JyZWN0IGNhbGN1bGF0aW9ucy5cbmpRdWVyeS5zd2FwID0gZnVuY3Rpb24oIGVsZW0sIG9wdGlvbnMsIGNhbGxiYWNrLCBhcmdzICkge1xuXHR2YXIgcmV0LCBuYW1lLFxuXHRcdG9sZCA9IHt9O1xuXG5cdC8vIFJlbWVtYmVyIHRoZSBvbGQgdmFsdWVzLCBhbmQgaW5zZXJ0IHRoZSBuZXcgb25lc1xuXHRmb3IgKCBuYW1lIGluIG9wdGlvbnMgKSB7XG5cdFx0b2xkWyBuYW1lIF0gPSBlbGVtLnN0eWxlWyBuYW1lIF07XG5cdFx0ZWxlbS5zdHlsZVsgbmFtZSBdID0gb3B0aW9uc1sgbmFtZSBdO1xuXHR9XG5cblx0cmV0ID0gY2FsbGJhY2suYXBwbHkoIGVsZW0sIGFyZ3MgfHwgW10gKTtcblxuXHQvLyBSZXZlcnQgdGhlIG9sZCB2YWx1ZXNcblx0Zm9yICggbmFtZSBpbiBvcHRpb25zICkge1xuXHRcdGVsZW0uc3R5bGVbIG5hbWUgXSA9IG9sZFsgbmFtZSBdO1xuXHR9XG5cblx0cmV0dXJuIHJldDtcbn07XG5cblxudmFyXG5cdC8vIFN3YXBwYWJsZSBpZiBkaXNwbGF5IGlzIG5vbmUgb3Igc3RhcnRzIHdpdGggdGFibGUgZXhjZXB0IFwidGFibGVcIiwgXCJ0YWJsZS1jZWxsXCIsIG9yIFwidGFibGUtY2FwdGlvblwiXG5cdC8vIFNlZSBoZXJlIGZvciBkaXNwbGF5IHZhbHVlczogaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9DU1MvZGlzcGxheVxuXHRyZGlzcGxheXN3YXAgPSAvXihub25lfHRhYmxlKD8hLWNbZWFdKS4rKS8sXG5cdHJudW1zcGxpdCA9IG5ldyBSZWdFeHAoIFwiXihcIiArIHBudW0gKyBcIikoLiopJFwiLCBcImlcIiApLFxuXHRycmVsTnVtID0gbmV3IFJlZ0V4cCggXCJeKFsrLV0pPShcIiArIHBudW0gKyBcIilcIiwgXCJpXCIgKSxcblxuXHRjc3NTaG93ID0geyBwb3NpdGlvbjogXCJhYnNvbHV0ZVwiLCB2aXNpYmlsaXR5OiBcImhpZGRlblwiLCBkaXNwbGF5OiBcImJsb2NrXCIgfSxcblx0Y3NzTm9ybWFsVHJhbnNmb3JtID0ge1xuXHRcdGxldHRlclNwYWNpbmc6IFwiMFwiLFxuXHRcdGZvbnRXZWlnaHQ6IFwiNDAwXCJcblx0fSxcblxuXHRjc3NQcmVmaXhlcyA9IFsgXCJXZWJraXRcIiwgXCJPXCIsIFwiTW96XCIsIFwibXNcIiBdO1xuXG4vLyBSZXR1cm4gYSBjc3MgcHJvcGVydHkgbWFwcGVkIHRvIGEgcG90ZW50aWFsbHkgdmVuZG9yIHByZWZpeGVkIHByb3BlcnR5XG5mdW5jdGlvbiB2ZW5kb3JQcm9wTmFtZSggc3R5bGUsIG5hbWUgKSB7XG5cblx0Ly8gU2hvcnRjdXQgZm9yIG5hbWVzIHRoYXQgYXJlIG5vdCB2ZW5kb3IgcHJlZml4ZWRcblx0aWYgKCBuYW1lIGluIHN0eWxlICkge1xuXHRcdHJldHVybiBuYW1lO1xuXHR9XG5cblx0Ly8gQ2hlY2sgZm9yIHZlbmRvciBwcmVmaXhlZCBuYW1lc1xuXHR2YXIgY2FwTmFtZSA9IG5hbWVbMF0udG9VcHBlckNhc2UoKSArIG5hbWUuc2xpY2UoMSksXG5cdFx0b3JpZ05hbWUgPSBuYW1lLFxuXHRcdGkgPSBjc3NQcmVmaXhlcy5sZW5ndGg7XG5cblx0d2hpbGUgKCBpLS0gKSB7XG5cdFx0bmFtZSA9IGNzc1ByZWZpeGVzWyBpIF0gKyBjYXBOYW1lO1xuXHRcdGlmICggbmFtZSBpbiBzdHlsZSApIHtcblx0XHRcdHJldHVybiBuYW1lO1xuXHRcdH1cblx0fVxuXG5cdHJldHVybiBvcmlnTmFtZTtcbn1cblxuZnVuY3Rpb24gc2V0UG9zaXRpdmVOdW1iZXIoIGVsZW0sIHZhbHVlLCBzdWJ0cmFjdCApIHtcblx0dmFyIG1hdGNoZXMgPSBybnVtc3BsaXQuZXhlYyggdmFsdWUgKTtcblx0cmV0dXJuIG1hdGNoZXMgP1xuXHRcdC8vIEd1YXJkIGFnYWluc3QgdW5kZWZpbmVkIFwic3VidHJhY3RcIiwgZS5nLiwgd2hlbiB1c2VkIGFzIGluIGNzc0hvb2tzXG5cdFx0TWF0aC5tYXgoIDAsIG1hdGNoZXNbIDEgXSAtICggc3VidHJhY3QgfHwgMCApICkgKyAoIG1hdGNoZXNbIDIgXSB8fCBcInB4XCIgKSA6XG5cdFx0dmFsdWU7XG59XG5cbmZ1bmN0aW9uIGF1Z21lbnRXaWR0aE9ySGVpZ2h0KCBlbGVtLCBuYW1lLCBleHRyYSwgaXNCb3JkZXJCb3gsIHN0eWxlcyApIHtcblx0dmFyIGkgPSBleHRyYSA9PT0gKCBpc0JvcmRlckJveCA/IFwiYm9yZGVyXCIgOiBcImNvbnRlbnRcIiApID9cblx0XHQvLyBJZiB3ZSBhbHJlYWR5IGhhdmUgdGhlIHJpZ2h0IG1lYXN1cmVtZW50LCBhdm9pZCBhdWdtZW50YXRpb25cblx0XHQ0IDpcblx0XHQvLyBPdGhlcndpc2UgaW5pdGlhbGl6ZSBmb3IgaG9yaXpvbnRhbCBvciB2ZXJ0aWNhbCBwcm9wZXJ0aWVzXG5cdFx0bmFtZSA9PT0gXCJ3aWR0aFwiID8gMSA6IDAsXG5cblx0XHR2YWwgPSAwO1xuXG5cdGZvciAoIDsgaSA8IDQ7IGkgKz0gMiApIHtcblx0XHQvLyBCb3RoIGJveCBtb2RlbHMgZXhjbHVkZSBtYXJnaW4sIHNvIGFkZCBpdCBpZiB3ZSB3YW50IGl0XG5cdFx0aWYgKCBleHRyYSA9PT0gXCJtYXJnaW5cIiApIHtcblx0XHRcdHZhbCArPSBqUXVlcnkuY3NzKCBlbGVtLCBleHRyYSArIGNzc0V4cGFuZFsgaSBdLCB0cnVlLCBzdHlsZXMgKTtcblx0XHR9XG5cblx0XHRpZiAoIGlzQm9yZGVyQm94ICkge1xuXHRcdFx0Ly8gYm9yZGVyLWJveCBpbmNsdWRlcyBwYWRkaW5nLCBzbyByZW1vdmUgaXQgaWYgd2Ugd2FudCBjb250ZW50XG5cdFx0XHRpZiAoIGV4dHJhID09PSBcImNvbnRlbnRcIiApIHtcblx0XHRcdFx0dmFsIC09IGpRdWVyeS5jc3MoIGVsZW0sIFwicGFkZGluZ1wiICsgY3NzRXhwYW5kWyBpIF0sIHRydWUsIHN0eWxlcyApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBBdCB0aGlzIHBvaW50LCBleHRyYSBpc24ndCBib3JkZXIgbm9yIG1hcmdpbiwgc28gcmVtb3ZlIGJvcmRlclxuXHRcdFx0aWYgKCBleHRyYSAhPT0gXCJtYXJnaW5cIiApIHtcblx0XHRcdFx0dmFsIC09IGpRdWVyeS5jc3MoIGVsZW0sIFwiYm9yZGVyXCIgKyBjc3NFeHBhbmRbIGkgXSArIFwiV2lkdGhcIiwgdHJ1ZSwgc3R5bGVzICk7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdC8vIEF0IHRoaXMgcG9pbnQsIGV4dHJhIGlzbid0IGNvbnRlbnQsIHNvIGFkZCBwYWRkaW5nXG5cdFx0XHR2YWwgKz0galF1ZXJ5LmNzcyggZWxlbSwgXCJwYWRkaW5nXCIgKyBjc3NFeHBhbmRbIGkgXSwgdHJ1ZSwgc3R5bGVzICk7XG5cblx0XHRcdC8vIEF0IHRoaXMgcG9pbnQsIGV4dHJhIGlzbid0IGNvbnRlbnQgbm9yIHBhZGRpbmcsIHNvIGFkZCBib3JkZXJcblx0XHRcdGlmICggZXh0cmEgIT09IFwicGFkZGluZ1wiICkge1xuXHRcdFx0XHR2YWwgKz0galF1ZXJ5LmNzcyggZWxlbSwgXCJib3JkZXJcIiArIGNzc0V4cGFuZFsgaSBdICsgXCJXaWR0aFwiLCB0cnVlLCBzdHlsZXMgKTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHRyZXR1cm4gdmFsO1xufVxuXG5mdW5jdGlvbiBnZXRXaWR0aE9ySGVpZ2h0KCBlbGVtLCBuYW1lLCBleHRyYSApIHtcblxuXHQvLyBTdGFydCB3aXRoIG9mZnNldCBwcm9wZXJ0eSwgd2hpY2ggaXMgZXF1aXZhbGVudCB0byB0aGUgYm9yZGVyLWJveCB2YWx1ZVxuXHR2YXIgdmFsdWVJc0JvcmRlckJveCA9IHRydWUsXG5cdFx0dmFsID0gbmFtZSA9PT0gXCJ3aWR0aFwiID8gZWxlbS5vZmZzZXRXaWR0aCA6IGVsZW0ub2Zmc2V0SGVpZ2h0LFxuXHRcdHN0eWxlcyA9IGdldFN0eWxlcyggZWxlbSApLFxuXHRcdGlzQm9yZGVyQm94ID0galF1ZXJ5LmNzcyggZWxlbSwgXCJib3hTaXppbmdcIiwgZmFsc2UsIHN0eWxlcyApID09PSBcImJvcmRlci1ib3hcIjtcblxuXHQvLyBTb21lIG5vbi1odG1sIGVsZW1lbnRzIHJldHVybiB1bmRlZmluZWQgZm9yIG9mZnNldFdpZHRoLCBzbyBjaGVjayBmb3IgbnVsbC91bmRlZmluZWRcblx0Ly8gc3ZnIC0gaHR0cHM6Ly9idWd6aWxsYS5tb3ppbGxhLm9yZy9zaG93X2J1Zy5jZ2k/aWQ9NjQ5Mjg1XG5cdC8vIE1hdGhNTCAtIGh0dHBzOi8vYnVnemlsbGEubW96aWxsYS5vcmcvc2hvd19idWcuY2dpP2lkPTQ5MTY2OFxuXHRpZiAoIHZhbCA8PSAwIHx8IHZhbCA9PSBudWxsICkge1xuXHRcdC8vIEZhbGwgYmFjayB0byBjb21wdXRlZCB0aGVuIHVuY29tcHV0ZWQgY3NzIGlmIG5lY2Vzc2FyeVxuXHRcdHZhbCA9IGN1ckNTUyggZWxlbSwgbmFtZSwgc3R5bGVzICk7XG5cdFx0aWYgKCB2YWwgPCAwIHx8IHZhbCA9PSBudWxsICkge1xuXHRcdFx0dmFsID0gZWxlbS5zdHlsZVsgbmFtZSBdO1xuXHRcdH1cblxuXHRcdC8vIENvbXB1dGVkIHVuaXQgaXMgbm90IHBpeGVscy4gU3RvcCBoZXJlIGFuZCByZXR1cm4uXG5cdFx0aWYgKCBybnVtbm9ucHgudGVzdCh2YWwpICkge1xuXHRcdFx0cmV0dXJuIHZhbDtcblx0XHR9XG5cblx0XHQvLyBDaGVjayBmb3Igc3R5bGUgaW4gY2FzZSBhIGJyb3dzZXIgd2hpY2ggcmV0dXJucyB1bnJlbGlhYmxlIHZhbHVlc1xuXHRcdC8vIGZvciBnZXRDb21wdXRlZFN0eWxlIHNpbGVudGx5IGZhbGxzIGJhY2sgdG8gdGhlIHJlbGlhYmxlIGVsZW0uc3R5bGVcblx0XHR2YWx1ZUlzQm9yZGVyQm94ID0gaXNCb3JkZXJCb3ggJiZcblx0XHRcdCggc3VwcG9ydC5ib3hTaXppbmdSZWxpYWJsZSgpIHx8IHZhbCA9PT0gZWxlbS5zdHlsZVsgbmFtZSBdICk7XG5cblx0XHQvLyBOb3JtYWxpemUgXCJcIiwgYXV0bywgYW5kIHByZXBhcmUgZm9yIGV4dHJhXG5cdFx0dmFsID0gcGFyc2VGbG9hdCggdmFsICkgfHwgMDtcblx0fVxuXG5cdC8vIFVzZSB0aGUgYWN0aXZlIGJveC1zaXppbmcgbW9kZWwgdG8gYWRkL3N1YnRyYWN0IGlycmVsZXZhbnQgc3R5bGVzXG5cdHJldHVybiAoIHZhbCArXG5cdFx0YXVnbWVudFdpZHRoT3JIZWlnaHQoXG5cdFx0XHRlbGVtLFxuXHRcdFx0bmFtZSxcblx0XHRcdGV4dHJhIHx8ICggaXNCb3JkZXJCb3ggPyBcImJvcmRlclwiIDogXCJjb250ZW50XCIgKSxcblx0XHRcdHZhbHVlSXNCb3JkZXJCb3gsXG5cdFx0XHRzdHlsZXNcblx0XHQpXG5cdCkgKyBcInB4XCI7XG59XG5cbmZ1bmN0aW9uIHNob3dIaWRlKCBlbGVtZW50cywgc2hvdyApIHtcblx0dmFyIGRpc3BsYXksIGVsZW0sIGhpZGRlbixcblx0XHR2YWx1ZXMgPSBbXSxcblx0XHRpbmRleCA9IDAsXG5cdFx0bGVuZ3RoID0gZWxlbWVudHMubGVuZ3RoO1xuXG5cdGZvciAoIDsgaW5kZXggPCBsZW5ndGg7IGluZGV4KysgKSB7XG5cdFx0ZWxlbSA9IGVsZW1lbnRzWyBpbmRleCBdO1xuXHRcdGlmICggIWVsZW0uc3R5bGUgKSB7XG5cdFx0XHRjb250aW51ZTtcblx0XHR9XG5cblx0XHR2YWx1ZXNbIGluZGV4IF0gPSBkYXRhX3ByaXYuZ2V0KCBlbGVtLCBcIm9sZGRpc3BsYXlcIiApO1xuXHRcdGRpc3BsYXkgPSBlbGVtLnN0eWxlLmRpc3BsYXk7XG5cdFx0aWYgKCBzaG93ICkge1xuXHRcdFx0Ly8gUmVzZXQgdGhlIGlubGluZSBkaXNwbGF5IG9mIHRoaXMgZWxlbWVudCB0byBsZWFybiBpZiBpdCBpc1xuXHRcdFx0Ly8gYmVpbmcgaGlkZGVuIGJ5IGNhc2NhZGVkIHJ1bGVzIG9yIG5vdFxuXHRcdFx0aWYgKCAhdmFsdWVzWyBpbmRleCBdICYmIGRpc3BsYXkgPT09IFwibm9uZVwiICkge1xuXHRcdFx0XHRlbGVtLnN0eWxlLmRpc3BsYXkgPSBcIlwiO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBTZXQgZWxlbWVudHMgd2hpY2ggaGF2ZSBiZWVuIG92ZXJyaWRkZW4gd2l0aCBkaXNwbGF5OiBub25lXG5cdFx0XHQvLyBpbiBhIHN0eWxlc2hlZXQgdG8gd2hhdGV2ZXIgdGhlIGRlZmF1bHQgYnJvd3NlciBzdHlsZSBpc1xuXHRcdFx0Ly8gZm9yIHN1Y2ggYW4gZWxlbWVudFxuXHRcdFx0aWYgKCBlbGVtLnN0eWxlLmRpc3BsYXkgPT09IFwiXCIgJiYgaXNIaWRkZW4oIGVsZW0gKSApIHtcblx0XHRcdFx0dmFsdWVzWyBpbmRleCBdID0gZGF0YV9wcml2LmFjY2VzcyggZWxlbSwgXCJvbGRkaXNwbGF5XCIsIGRlZmF1bHREaXNwbGF5KGVsZW0ubm9kZU5hbWUpICk7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdGhpZGRlbiA9IGlzSGlkZGVuKCBlbGVtICk7XG5cblx0XHRcdGlmICggZGlzcGxheSAhPT0gXCJub25lXCIgfHwgIWhpZGRlbiApIHtcblx0XHRcdFx0ZGF0YV9wcml2LnNldCggZWxlbSwgXCJvbGRkaXNwbGF5XCIsIGhpZGRlbiA/IGRpc3BsYXkgOiBqUXVlcnkuY3NzKCBlbGVtLCBcImRpc3BsYXlcIiApICk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0Ly8gU2V0IHRoZSBkaXNwbGF5IG9mIG1vc3Qgb2YgdGhlIGVsZW1lbnRzIGluIGEgc2Vjb25kIGxvb3Bcblx0Ly8gdG8gYXZvaWQgdGhlIGNvbnN0YW50IHJlZmxvd1xuXHRmb3IgKCBpbmRleCA9IDA7IGluZGV4IDwgbGVuZ3RoOyBpbmRleCsrICkge1xuXHRcdGVsZW0gPSBlbGVtZW50c1sgaW5kZXggXTtcblx0XHRpZiAoICFlbGVtLnN0eWxlICkge1xuXHRcdFx0Y29udGludWU7XG5cdFx0fVxuXHRcdGlmICggIXNob3cgfHwgZWxlbS5zdHlsZS5kaXNwbGF5ID09PSBcIm5vbmVcIiB8fCBlbGVtLnN0eWxlLmRpc3BsYXkgPT09IFwiXCIgKSB7XG5cdFx0XHRlbGVtLnN0eWxlLmRpc3BsYXkgPSBzaG93ID8gdmFsdWVzWyBpbmRleCBdIHx8IFwiXCIgOiBcIm5vbmVcIjtcblx0XHR9XG5cdH1cblxuXHRyZXR1cm4gZWxlbWVudHM7XG59XG5cbmpRdWVyeS5leHRlbmQoe1xuXG5cdC8vIEFkZCBpbiBzdHlsZSBwcm9wZXJ0eSBob29rcyBmb3Igb3ZlcnJpZGluZyB0aGUgZGVmYXVsdFxuXHQvLyBiZWhhdmlvciBvZiBnZXR0aW5nIGFuZCBzZXR0aW5nIGEgc3R5bGUgcHJvcGVydHlcblx0Y3NzSG9va3M6IHtcblx0XHRvcGFjaXR5OiB7XG5cdFx0XHRnZXQ6IGZ1bmN0aW9uKCBlbGVtLCBjb21wdXRlZCApIHtcblx0XHRcdFx0aWYgKCBjb21wdXRlZCApIHtcblxuXHRcdFx0XHRcdC8vIFdlIHNob3VsZCBhbHdheXMgZ2V0IGEgbnVtYmVyIGJhY2sgZnJvbSBvcGFjaXR5XG5cdFx0XHRcdFx0dmFyIHJldCA9IGN1ckNTUyggZWxlbSwgXCJvcGFjaXR5XCIgKTtcblx0XHRcdFx0XHRyZXR1cm4gcmV0ID09PSBcIlwiID8gXCIxXCIgOiByZXQ7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cblx0Ly8gRG9uJ3QgYXV0b21hdGljYWxseSBhZGQgXCJweFwiIHRvIHRoZXNlIHBvc3NpYmx5LXVuaXRsZXNzIHByb3BlcnRpZXNcblx0Y3NzTnVtYmVyOiB7XG5cdFx0XCJjb2x1bW5Db3VudFwiOiB0cnVlLFxuXHRcdFwiZmlsbE9wYWNpdHlcIjogdHJ1ZSxcblx0XHRcImZsZXhHcm93XCI6IHRydWUsXG5cdFx0XCJmbGV4U2hyaW5rXCI6IHRydWUsXG5cdFx0XCJmb250V2VpZ2h0XCI6IHRydWUsXG5cdFx0XCJsaW5lSGVpZ2h0XCI6IHRydWUsXG5cdFx0XCJvcGFjaXR5XCI6IHRydWUsXG5cdFx0XCJvcmRlclwiOiB0cnVlLFxuXHRcdFwib3JwaGFuc1wiOiB0cnVlLFxuXHRcdFwid2lkb3dzXCI6IHRydWUsXG5cdFx0XCJ6SW5kZXhcIjogdHJ1ZSxcblx0XHRcInpvb21cIjogdHJ1ZVxuXHR9LFxuXG5cdC8vIEFkZCBpbiBwcm9wZXJ0aWVzIHdob3NlIG5hbWVzIHlvdSB3aXNoIHRvIGZpeCBiZWZvcmVcblx0Ly8gc2V0dGluZyBvciBnZXR0aW5nIHRoZSB2YWx1ZVxuXHRjc3NQcm9wczoge1xuXHRcdFwiZmxvYXRcIjogXCJjc3NGbG9hdFwiXG5cdH0sXG5cblx0Ly8gR2V0IGFuZCBzZXQgdGhlIHN0eWxlIHByb3BlcnR5IG9uIGEgRE9NIE5vZGVcblx0c3R5bGU6IGZ1bmN0aW9uKCBlbGVtLCBuYW1lLCB2YWx1ZSwgZXh0cmEgKSB7XG5cblx0XHQvLyBEb24ndCBzZXQgc3R5bGVzIG9uIHRleHQgYW5kIGNvbW1lbnQgbm9kZXNcblx0XHRpZiAoICFlbGVtIHx8IGVsZW0ubm9kZVR5cGUgPT09IDMgfHwgZWxlbS5ub2RlVHlwZSA9PT0gOCB8fCAhZWxlbS5zdHlsZSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBNYWtlIHN1cmUgdGhhdCB3ZSdyZSB3b3JraW5nIHdpdGggdGhlIHJpZ2h0IG5hbWVcblx0XHR2YXIgcmV0LCB0eXBlLCBob29rcyxcblx0XHRcdG9yaWdOYW1lID0galF1ZXJ5LmNhbWVsQ2FzZSggbmFtZSApLFxuXHRcdFx0c3R5bGUgPSBlbGVtLnN0eWxlO1xuXG5cdFx0bmFtZSA9IGpRdWVyeS5jc3NQcm9wc1sgb3JpZ05hbWUgXSB8fCAoIGpRdWVyeS5jc3NQcm9wc1sgb3JpZ05hbWUgXSA9IHZlbmRvclByb3BOYW1lKCBzdHlsZSwgb3JpZ05hbWUgKSApO1xuXG5cdFx0Ly8gR2V0cyBob29rIGZvciB0aGUgcHJlZml4ZWQgdmVyc2lvbiwgdGhlbiB1bnByZWZpeGVkIHZlcnNpb25cblx0XHRob29rcyA9IGpRdWVyeS5jc3NIb29rc1sgbmFtZSBdIHx8IGpRdWVyeS5jc3NIb29rc1sgb3JpZ05hbWUgXTtcblxuXHRcdC8vIENoZWNrIGlmIHdlJ3JlIHNldHRpbmcgYSB2YWx1ZVxuXHRcdGlmICggdmFsdWUgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdHR5cGUgPSB0eXBlb2YgdmFsdWU7XG5cblx0XHRcdC8vIENvbnZlcnQgXCIrPVwiIG9yIFwiLT1cIiB0byByZWxhdGl2ZSBudW1iZXJzICgjNzM0NSlcblx0XHRcdGlmICggdHlwZSA9PT0gXCJzdHJpbmdcIiAmJiAocmV0ID0gcnJlbE51bS5leGVjKCB2YWx1ZSApKSApIHtcblx0XHRcdFx0dmFsdWUgPSAoIHJldFsxXSArIDEgKSAqIHJldFsyXSArIHBhcnNlRmxvYXQoIGpRdWVyeS5jc3MoIGVsZW0sIG5hbWUgKSApO1xuXHRcdFx0XHQvLyBGaXhlcyBidWcgIzkyMzdcblx0XHRcdFx0dHlwZSA9IFwibnVtYmVyXCI7XG5cdFx0XHR9XG5cblx0XHRcdC8vIE1ha2Ugc3VyZSB0aGF0IG51bGwgYW5kIE5hTiB2YWx1ZXMgYXJlbid0IHNldCAoIzcxMTYpXG5cdFx0XHRpZiAoIHZhbHVlID09IG51bGwgfHwgdmFsdWUgIT09IHZhbHVlICkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdC8vIElmIGEgbnVtYmVyLCBhZGQgJ3B4JyB0byB0aGUgKGV4Y2VwdCBmb3IgY2VydGFpbiBDU1MgcHJvcGVydGllcylcblx0XHRcdGlmICggdHlwZSA9PT0gXCJudW1iZXJcIiAmJiAhalF1ZXJ5LmNzc051bWJlclsgb3JpZ05hbWUgXSApIHtcblx0XHRcdFx0dmFsdWUgKz0gXCJweFwiO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBTdXBwb3J0OiBJRTktMTErXG5cdFx0XHQvLyBiYWNrZ3JvdW5kLSogcHJvcHMgYWZmZWN0IG9yaWdpbmFsIGNsb25lJ3MgdmFsdWVzXG5cdFx0XHRpZiAoICFzdXBwb3J0LmNsZWFyQ2xvbmVTdHlsZSAmJiB2YWx1ZSA9PT0gXCJcIiAmJiBuYW1lLmluZGV4T2YoIFwiYmFja2dyb3VuZFwiICkgPT09IDAgKSB7XG5cdFx0XHRcdHN0eWxlWyBuYW1lIF0gPSBcImluaGVyaXRcIjtcblx0XHRcdH1cblxuXHRcdFx0Ly8gSWYgYSBob29rIHdhcyBwcm92aWRlZCwgdXNlIHRoYXQgdmFsdWUsIG90aGVyd2lzZSBqdXN0IHNldCB0aGUgc3BlY2lmaWVkIHZhbHVlXG5cdFx0XHRpZiAoICFob29rcyB8fCAhKFwic2V0XCIgaW4gaG9va3MpIHx8ICh2YWx1ZSA9IGhvb2tzLnNldCggZWxlbSwgdmFsdWUsIGV4dHJhICkpICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdHN0eWxlWyBuYW1lIF0gPSB2YWx1ZTtcblx0XHRcdH1cblxuXHRcdH0gZWxzZSB7XG5cdFx0XHQvLyBJZiBhIGhvb2sgd2FzIHByb3ZpZGVkIGdldCB0aGUgbm9uLWNvbXB1dGVkIHZhbHVlIGZyb20gdGhlcmVcblx0XHRcdGlmICggaG9va3MgJiYgXCJnZXRcIiBpbiBob29rcyAmJiAocmV0ID0gaG9va3MuZ2V0KCBlbGVtLCBmYWxzZSwgZXh0cmEgKSkgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0cmV0dXJuIHJldDtcblx0XHRcdH1cblxuXHRcdFx0Ly8gT3RoZXJ3aXNlIGp1c3QgZ2V0IHRoZSB2YWx1ZSBmcm9tIHRoZSBzdHlsZSBvYmplY3Rcblx0XHRcdHJldHVybiBzdHlsZVsgbmFtZSBdO1xuXHRcdH1cblx0fSxcblxuXHRjc3M6IGZ1bmN0aW9uKCBlbGVtLCBuYW1lLCBleHRyYSwgc3R5bGVzICkge1xuXHRcdHZhciB2YWwsIG51bSwgaG9va3MsXG5cdFx0XHRvcmlnTmFtZSA9IGpRdWVyeS5jYW1lbENhc2UoIG5hbWUgKTtcblxuXHRcdC8vIE1ha2Ugc3VyZSB0aGF0IHdlJ3JlIHdvcmtpbmcgd2l0aCB0aGUgcmlnaHQgbmFtZVxuXHRcdG5hbWUgPSBqUXVlcnkuY3NzUHJvcHNbIG9yaWdOYW1lIF0gfHwgKCBqUXVlcnkuY3NzUHJvcHNbIG9yaWdOYW1lIF0gPSB2ZW5kb3JQcm9wTmFtZSggZWxlbS5zdHlsZSwgb3JpZ05hbWUgKSApO1xuXG5cdFx0Ly8gVHJ5IHByZWZpeGVkIG5hbWUgZm9sbG93ZWQgYnkgdGhlIHVucHJlZml4ZWQgbmFtZVxuXHRcdGhvb2tzID0galF1ZXJ5LmNzc0hvb2tzWyBuYW1lIF0gfHwgalF1ZXJ5LmNzc0hvb2tzWyBvcmlnTmFtZSBdO1xuXG5cdFx0Ly8gSWYgYSBob29rIHdhcyBwcm92aWRlZCBnZXQgdGhlIGNvbXB1dGVkIHZhbHVlIGZyb20gdGhlcmVcblx0XHRpZiAoIGhvb2tzICYmIFwiZ2V0XCIgaW4gaG9va3MgKSB7XG5cdFx0XHR2YWwgPSBob29rcy5nZXQoIGVsZW0sIHRydWUsIGV4dHJhICk7XG5cdFx0fVxuXG5cdFx0Ly8gT3RoZXJ3aXNlLCBpZiBhIHdheSB0byBnZXQgdGhlIGNvbXB1dGVkIHZhbHVlIGV4aXN0cywgdXNlIHRoYXRcblx0XHRpZiAoIHZhbCA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0dmFsID0gY3VyQ1NTKCBlbGVtLCBuYW1lLCBzdHlsZXMgKTtcblx0XHR9XG5cblx0XHQvLyBDb252ZXJ0IFwibm9ybWFsXCIgdG8gY29tcHV0ZWQgdmFsdWVcblx0XHRpZiAoIHZhbCA9PT0gXCJub3JtYWxcIiAmJiBuYW1lIGluIGNzc05vcm1hbFRyYW5zZm9ybSApIHtcblx0XHRcdHZhbCA9IGNzc05vcm1hbFRyYW5zZm9ybVsgbmFtZSBdO1xuXHRcdH1cblxuXHRcdC8vIE1ha2UgbnVtZXJpYyBpZiBmb3JjZWQgb3IgYSBxdWFsaWZpZXIgd2FzIHByb3ZpZGVkIGFuZCB2YWwgbG9va3MgbnVtZXJpY1xuXHRcdGlmICggZXh0cmEgPT09IFwiXCIgfHwgZXh0cmEgKSB7XG5cdFx0XHRudW0gPSBwYXJzZUZsb2F0KCB2YWwgKTtcblx0XHRcdHJldHVybiBleHRyYSA9PT0gdHJ1ZSB8fCBqUXVlcnkuaXNOdW1lcmljKCBudW0gKSA/IG51bSB8fCAwIDogdmFsO1xuXHRcdH1cblx0XHRyZXR1cm4gdmFsO1xuXHR9XG59KTtcblxualF1ZXJ5LmVhY2goWyBcImhlaWdodFwiLCBcIndpZHRoXCIgXSwgZnVuY3Rpb24oIGksIG5hbWUgKSB7XG5cdGpRdWVyeS5jc3NIb29rc1sgbmFtZSBdID0ge1xuXHRcdGdldDogZnVuY3Rpb24oIGVsZW0sIGNvbXB1dGVkLCBleHRyYSApIHtcblx0XHRcdGlmICggY29tcHV0ZWQgKSB7XG5cblx0XHRcdFx0Ly8gQ2VydGFpbiBlbGVtZW50cyBjYW4gaGF2ZSBkaW1lbnNpb24gaW5mbyBpZiB3ZSBpbnZpc2libHkgc2hvdyB0aGVtXG5cdFx0XHRcdC8vIGJ1dCBpdCBtdXN0IGhhdmUgYSBjdXJyZW50IGRpc3BsYXkgc3R5bGUgdGhhdCB3b3VsZCBiZW5lZml0XG5cdFx0XHRcdHJldHVybiByZGlzcGxheXN3YXAudGVzdCggalF1ZXJ5LmNzcyggZWxlbSwgXCJkaXNwbGF5XCIgKSApICYmIGVsZW0ub2Zmc2V0V2lkdGggPT09IDAgP1xuXHRcdFx0XHRcdGpRdWVyeS5zd2FwKCBlbGVtLCBjc3NTaG93LCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdHJldHVybiBnZXRXaWR0aE9ySGVpZ2h0KCBlbGVtLCBuYW1lLCBleHRyYSApO1xuXHRcdFx0XHRcdH0pIDpcblx0XHRcdFx0XHRnZXRXaWR0aE9ySGVpZ2h0KCBlbGVtLCBuYW1lLCBleHRyYSApO1xuXHRcdFx0fVxuXHRcdH0sXG5cblx0XHRzZXQ6IGZ1bmN0aW9uKCBlbGVtLCB2YWx1ZSwgZXh0cmEgKSB7XG5cdFx0XHR2YXIgc3R5bGVzID0gZXh0cmEgJiYgZ2V0U3R5bGVzKCBlbGVtICk7XG5cdFx0XHRyZXR1cm4gc2V0UG9zaXRpdmVOdW1iZXIoIGVsZW0sIHZhbHVlLCBleHRyYSA/XG5cdFx0XHRcdGF1Z21lbnRXaWR0aE9ySGVpZ2h0KFxuXHRcdFx0XHRcdGVsZW0sXG5cdFx0XHRcdFx0bmFtZSxcblx0XHRcdFx0XHRleHRyYSxcblx0XHRcdFx0XHRqUXVlcnkuY3NzKCBlbGVtLCBcImJveFNpemluZ1wiLCBmYWxzZSwgc3R5bGVzICkgPT09IFwiYm9yZGVyLWJveFwiLFxuXHRcdFx0XHRcdHN0eWxlc1xuXHRcdFx0XHQpIDogMFxuXHRcdFx0KTtcblx0XHR9XG5cdH07XG59KTtcblxuLy8gU3VwcG9ydDogQW5kcm9pZCAyLjNcbmpRdWVyeS5jc3NIb29rcy5tYXJnaW5SaWdodCA9IGFkZEdldEhvb2tJZiggc3VwcG9ydC5yZWxpYWJsZU1hcmdpblJpZ2h0LFxuXHRmdW5jdGlvbiggZWxlbSwgY29tcHV0ZWQgKSB7XG5cdFx0aWYgKCBjb21wdXRlZCApIHtcblx0XHRcdHJldHVybiBqUXVlcnkuc3dhcCggZWxlbSwgeyBcImRpc3BsYXlcIjogXCJpbmxpbmUtYmxvY2tcIiB9LFxuXHRcdFx0XHRjdXJDU1MsIFsgZWxlbSwgXCJtYXJnaW5SaWdodFwiIF0gKTtcblx0XHR9XG5cdH1cbik7XG5cbi8vIFRoZXNlIGhvb2tzIGFyZSB1c2VkIGJ5IGFuaW1hdGUgdG8gZXhwYW5kIHByb3BlcnRpZXNcbmpRdWVyeS5lYWNoKHtcblx0bWFyZ2luOiBcIlwiLFxuXHRwYWRkaW5nOiBcIlwiLFxuXHRib3JkZXI6IFwiV2lkdGhcIlxufSwgZnVuY3Rpb24oIHByZWZpeCwgc3VmZml4ICkge1xuXHRqUXVlcnkuY3NzSG9va3NbIHByZWZpeCArIHN1ZmZpeCBdID0ge1xuXHRcdGV4cGFuZDogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdFx0dmFyIGkgPSAwLFxuXHRcdFx0XHRleHBhbmRlZCA9IHt9LFxuXG5cdFx0XHRcdC8vIEFzc3VtZXMgYSBzaW5nbGUgbnVtYmVyIGlmIG5vdCBhIHN0cmluZ1xuXHRcdFx0XHRwYXJ0cyA9IHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIiA/IHZhbHVlLnNwbGl0KFwiIFwiKSA6IFsgdmFsdWUgXTtcblxuXHRcdFx0Zm9yICggOyBpIDwgNDsgaSsrICkge1xuXHRcdFx0XHRleHBhbmRlZFsgcHJlZml4ICsgY3NzRXhwYW5kWyBpIF0gKyBzdWZmaXggXSA9XG5cdFx0XHRcdFx0cGFydHNbIGkgXSB8fCBwYXJ0c1sgaSAtIDIgXSB8fCBwYXJ0c1sgMCBdO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gZXhwYW5kZWQ7XG5cdFx0fVxuXHR9O1xuXG5cdGlmICggIXJtYXJnaW4udGVzdCggcHJlZml4ICkgKSB7XG5cdFx0alF1ZXJ5LmNzc0hvb2tzWyBwcmVmaXggKyBzdWZmaXggXS5zZXQgPSBzZXRQb3NpdGl2ZU51bWJlcjtcblx0fVxufSk7XG5cbmpRdWVyeS5mbi5leHRlbmQoe1xuXHRjc3M6IGZ1bmN0aW9uKCBuYW1lLCB2YWx1ZSApIHtcblx0XHRyZXR1cm4gYWNjZXNzKCB0aGlzLCBmdW5jdGlvbiggZWxlbSwgbmFtZSwgdmFsdWUgKSB7XG5cdFx0XHR2YXIgc3R5bGVzLCBsZW4sXG5cdFx0XHRcdG1hcCA9IHt9LFxuXHRcdFx0XHRpID0gMDtcblxuXHRcdFx0aWYgKCBqUXVlcnkuaXNBcnJheSggbmFtZSApICkge1xuXHRcdFx0XHRzdHlsZXMgPSBnZXRTdHlsZXMoIGVsZW0gKTtcblx0XHRcdFx0bGVuID0gbmFtZS5sZW5ndGg7XG5cblx0XHRcdFx0Zm9yICggOyBpIDwgbGVuOyBpKysgKSB7XG5cdFx0XHRcdFx0bWFwWyBuYW1lWyBpIF0gXSA9IGpRdWVyeS5jc3MoIGVsZW0sIG5hbWVbIGkgXSwgZmFsc2UsIHN0eWxlcyApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0cmV0dXJuIG1hcDtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHZhbHVlICE9PSB1bmRlZmluZWQgP1xuXHRcdFx0XHRqUXVlcnkuc3R5bGUoIGVsZW0sIG5hbWUsIHZhbHVlICkgOlxuXHRcdFx0XHRqUXVlcnkuY3NzKCBlbGVtLCBuYW1lICk7XG5cdFx0fSwgbmFtZSwgdmFsdWUsIGFyZ3VtZW50cy5sZW5ndGggPiAxICk7XG5cdH0sXG5cdHNob3c6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiBzaG93SGlkZSggdGhpcywgdHJ1ZSApO1xuXHR9LFxuXHRoaWRlOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gc2hvd0hpZGUoIHRoaXMgKTtcblx0fSxcblx0dG9nZ2xlOiBmdW5jdGlvbiggc3RhdGUgKSB7XG5cdFx0aWYgKCB0eXBlb2Ygc3RhdGUgPT09IFwiYm9vbGVhblwiICkge1xuXHRcdFx0cmV0dXJuIHN0YXRlID8gdGhpcy5zaG93KCkgOiB0aGlzLmhpZGUoKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKCkge1xuXHRcdFx0aWYgKCBpc0hpZGRlbiggdGhpcyApICkge1xuXHRcdFx0XHRqUXVlcnkoIHRoaXMgKS5zaG93KCk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRqUXVlcnkoIHRoaXMgKS5oaWRlKCk7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH1cbn0pO1xuXG5cbmZ1bmN0aW9uIFR3ZWVuKCBlbGVtLCBvcHRpb25zLCBwcm9wLCBlbmQsIGVhc2luZyApIHtcblx0cmV0dXJuIG5ldyBUd2Vlbi5wcm90b3R5cGUuaW5pdCggZWxlbSwgb3B0aW9ucywgcHJvcCwgZW5kLCBlYXNpbmcgKTtcbn1cbmpRdWVyeS5Ud2VlbiA9IFR3ZWVuO1xuXG5Ud2Vlbi5wcm90b3R5cGUgPSB7XG5cdGNvbnN0cnVjdG9yOiBUd2Vlbixcblx0aW5pdDogZnVuY3Rpb24oIGVsZW0sIG9wdGlvbnMsIHByb3AsIGVuZCwgZWFzaW5nLCB1bml0ICkge1xuXHRcdHRoaXMuZWxlbSA9IGVsZW07XG5cdFx0dGhpcy5wcm9wID0gcHJvcDtcblx0XHR0aGlzLmVhc2luZyA9IGVhc2luZyB8fCBcInN3aW5nXCI7XG5cdFx0dGhpcy5vcHRpb25zID0gb3B0aW9ucztcblx0XHR0aGlzLnN0YXJ0ID0gdGhpcy5ub3cgPSB0aGlzLmN1cigpO1xuXHRcdHRoaXMuZW5kID0gZW5kO1xuXHRcdHRoaXMudW5pdCA9IHVuaXQgfHwgKCBqUXVlcnkuY3NzTnVtYmVyWyBwcm9wIF0gPyBcIlwiIDogXCJweFwiICk7XG5cdH0sXG5cdGN1cjogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGhvb2tzID0gVHdlZW4ucHJvcEhvb2tzWyB0aGlzLnByb3AgXTtcblxuXHRcdHJldHVybiBob29rcyAmJiBob29rcy5nZXQgP1xuXHRcdFx0aG9va3MuZ2V0KCB0aGlzICkgOlxuXHRcdFx0VHdlZW4ucHJvcEhvb2tzLl9kZWZhdWx0LmdldCggdGhpcyApO1xuXHR9LFxuXHRydW46IGZ1bmN0aW9uKCBwZXJjZW50ICkge1xuXHRcdHZhciBlYXNlZCxcblx0XHRcdGhvb2tzID0gVHdlZW4ucHJvcEhvb2tzWyB0aGlzLnByb3AgXTtcblxuXHRcdGlmICggdGhpcy5vcHRpb25zLmR1cmF0aW9uICkge1xuXHRcdFx0dGhpcy5wb3MgPSBlYXNlZCA9IGpRdWVyeS5lYXNpbmdbIHRoaXMuZWFzaW5nIF0oXG5cdFx0XHRcdHBlcmNlbnQsIHRoaXMub3B0aW9ucy5kdXJhdGlvbiAqIHBlcmNlbnQsIDAsIDEsIHRoaXMub3B0aW9ucy5kdXJhdGlvblxuXHRcdFx0KTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5wb3MgPSBlYXNlZCA9IHBlcmNlbnQ7XG5cdFx0fVxuXHRcdHRoaXMubm93ID0gKCB0aGlzLmVuZCAtIHRoaXMuc3RhcnQgKSAqIGVhc2VkICsgdGhpcy5zdGFydDtcblxuXHRcdGlmICggdGhpcy5vcHRpb25zLnN0ZXAgKSB7XG5cdFx0XHR0aGlzLm9wdGlvbnMuc3RlcC5jYWxsKCB0aGlzLmVsZW0sIHRoaXMubm93LCB0aGlzICk7XG5cdFx0fVxuXG5cdFx0aWYgKCBob29rcyAmJiBob29rcy5zZXQgKSB7XG5cdFx0XHRob29rcy5zZXQoIHRoaXMgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0VHdlZW4ucHJvcEhvb2tzLl9kZWZhdWx0LnNldCggdGhpcyApO1xuXHRcdH1cblx0XHRyZXR1cm4gdGhpcztcblx0fVxufTtcblxuVHdlZW4ucHJvdG90eXBlLmluaXQucHJvdG90eXBlID0gVHdlZW4ucHJvdG90eXBlO1xuXG5Ud2Vlbi5wcm9wSG9va3MgPSB7XG5cdF9kZWZhdWx0OiB7XG5cdFx0Z2V0OiBmdW5jdGlvbiggdHdlZW4gKSB7XG5cdFx0XHR2YXIgcmVzdWx0O1xuXG5cdFx0XHRpZiAoIHR3ZWVuLmVsZW1bIHR3ZWVuLnByb3AgXSAhPSBudWxsICYmXG5cdFx0XHRcdCghdHdlZW4uZWxlbS5zdHlsZSB8fCB0d2Vlbi5lbGVtLnN0eWxlWyB0d2Vlbi5wcm9wIF0gPT0gbnVsbCkgKSB7XG5cdFx0XHRcdHJldHVybiB0d2Vlbi5lbGVtWyB0d2Vlbi5wcm9wIF07XG5cdFx0XHR9XG5cblx0XHRcdC8vIFBhc3NpbmcgYW4gZW1wdHkgc3RyaW5nIGFzIGEgM3JkIHBhcmFtZXRlciB0byAuY3NzIHdpbGwgYXV0b21hdGljYWxseVxuXHRcdFx0Ly8gYXR0ZW1wdCBhIHBhcnNlRmxvYXQgYW5kIGZhbGxiYWNrIHRvIGEgc3RyaW5nIGlmIHRoZSBwYXJzZSBmYWlscy5cblx0XHRcdC8vIFNpbXBsZSB2YWx1ZXMgc3VjaCBhcyBcIjEwcHhcIiBhcmUgcGFyc2VkIHRvIEZsb2F0O1xuXHRcdFx0Ly8gY29tcGxleCB2YWx1ZXMgc3VjaCBhcyBcInJvdGF0ZSgxcmFkKVwiIGFyZSByZXR1cm5lZCBhcy1pcy5cblx0XHRcdHJlc3VsdCA9IGpRdWVyeS5jc3MoIHR3ZWVuLmVsZW0sIHR3ZWVuLnByb3AsIFwiXCIgKTtcblx0XHRcdC8vIEVtcHR5IHN0cmluZ3MsIG51bGwsIHVuZGVmaW5lZCBhbmQgXCJhdXRvXCIgYXJlIGNvbnZlcnRlZCB0byAwLlxuXHRcdFx0cmV0dXJuICFyZXN1bHQgfHwgcmVzdWx0ID09PSBcImF1dG9cIiA/IDAgOiByZXN1bHQ7XG5cdFx0fSxcblx0XHRzZXQ6IGZ1bmN0aW9uKCB0d2VlbiApIHtcblx0XHRcdC8vIFVzZSBzdGVwIGhvb2sgZm9yIGJhY2sgY29tcGF0LlxuXHRcdFx0Ly8gVXNlIGNzc0hvb2sgaWYgaXRzIHRoZXJlLlxuXHRcdFx0Ly8gVXNlIC5zdHlsZSBpZiBhdmFpbGFibGUgYW5kIHVzZSBwbGFpbiBwcm9wZXJ0aWVzIHdoZXJlIGF2YWlsYWJsZS5cblx0XHRcdGlmICggalF1ZXJ5LmZ4LnN0ZXBbIHR3ZWVuLnByb3AgXSApIHtcblx0XHRcdFx0alF1ZXJ5LmZ4LnN0ZXBbIHR3ZWVuLnByb3AgXSggdHdlZW4gKTtcblx0XHRcdH0gZWxzZSBpZiAoIHR3ZWVuLmVsZW0uc3R5bGUgJiYgKCB0d2Vlbi5lbGVtLnN0eWxlWyBqUXVlcnkuY3NzUHJvcHNbIHR3ZWVuLnByb3AgXSBdICE9IG51bGwgfHwgalF1ZXJ5LmNzc0hvb2tzWyB0d2Vlbi5wcm9wIF0gKSApIHtcblx0XHRcdFx0alF1ZXJ5LnN0eWxlKCB0d2Vlbi5lbGVtLCB0d2Vlbi5wcm9wLCB0d2Vlbi5ub3cgKyB0d2Vlbi51bml0ICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0d2Vlbi5lbGVtWyB0d2Vlbi5wcm9wIF0gPSB0d2Vlbi5ub3c7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG59O1xuXG4vLyBTdXBwb3J0OiBJRTlcbi8vIFBhbmljIGJhc2VkIGFwcHJvYWNoIHRvIHNldHRpbmcgdGhpbmdzIG9uIGRpc2Nvbm5lY3RlZCBub2Rlc1xuVHdlZW4ucHJvcEhvb2tzLnNjcm9sbFRvcCA9IFR3ZWVuLnByb3BIb29rcy5zY3JvbGxMZWZ0ID0ge1xuXHRzZXQ6IGZ1bmN0aW9uKCB0d2VlbiApIHtcblx0XHRpZiAoIHR3ZWVuLmVsZW0ubm9kZVR5cGUgJiYgdHdlZW4uZWxlbS5wYXJlbnROb2RlICkge1xuXHRcdFx0dHdlZW4uZWxlbVsgdHdlZW4ucHJvcCBdID0gdHdlZW4ubm93O1xuXHRcdH1cblx0fVxufTtcblxualF1ZXJ5LmVhc2luZyA9IHtcblx0bGluZWFyOiBmdW5jdGlvbiggcCApIHtcblx0XHRyZXR1cm4gcDtcblx0fSxcblx0c3dpbmc6IGZ1bmN0aW9uKCBwICkge1xuXHRcdHJldHVybiAwLjUgLSBNYXRoLmNvcyggcCAqIE1hdGguUEkgKSAvIDI7XG5cdH1cbn07XG5cbmpRdWVyeS5meCA9IFR3ZWVuLnByb3RvdHlwZS5pbml0O1xuXG4vLyBCYWNrIENvbXBhdCA8MS44IGV4dGVuc2lvbiBwb2ludFxualF1ZXJ5LmZ4LnN0ZXAgPSB7fTtcblxuXG5cblxudmFyXG5cdGZ4Tm93LCB0aW1lcklkLFxuXHRyZnh0eXBlcyA9IC9eKD86dG9nZ2xlfHNob3d8aGlkZSkkLyxcblx0cmZ4bnVtID0gbmV3IFJlZ0V4cCggXCJeKD86KFsrLV0pPXwpKFwiICsgcG51bSArIFwiKShbYS16JV0qKSRcIiwgXCJpXCIgKSxcblx0cnJ1biA9IC9xdWV1ZUhvb2tzJC8sXG5cdGFuaW1hdGlvblByZWZpbHRlcnMgPSBbIGRlZmF1bHRQcmVmaWx0ZXIgXSxcblx0dHdlZW5lcnMgPSB7XG5cdFx0XCIqXCI6IFsgZnVuY3Rpb24oIHByb3AsIHZhbHVlICkge1xuXHRcdFx0dmFyIHR3ZWVuID0gdGhpcy5jcmVhdGVUd2VlbiggcHJvcCwgdmFsdWUgKSxcblx0XHRcdFx0dGFyZ2V0ID0gdHdlZW4uY3VyKCksXG5cdFx0XHRcdHBhcnRzID0gcmZ4bnVtLmV4ZWMoIHZhbHVlICksXG5cdFx0XHRcdHVuaXQgPSBwYXJ0cyAmJiBwYXJ0c1sgMyBdIHx8ICggalF1ZXJ5LmNzc051bWJlclsgcHJvcCBdID8gXCJcIiA6IFwicHhcIiApLFxuXG5cdFx0XHRcdC8vIFN0YXJ0aW5nIHZhbHVlIGNvbXB1dGF0aW9uIGlzIHJlcXVpcmVkIGZvciBwb3RlbnRpYWwgdW5pdCBtaXNtYXRjaGVzXG5cdFx0XHRcdHN0YXJ0ID0gKCBqUXVlcnkuY3NzTnVtYmVyWyBwcm9wIF0gfHwgdW5pdCAhPT0gXCJweFwiICYmICt0YXJnZXQgKSAmJlxuXHRcdFx0XHRcdHJmeG51bS5leGVjKCBqUXVlcnkuY3NzKCB0d2Vlbi5lbGVtLCBwcm9wICkgKSxcblx0XHRcdFx0c2NhbGUgPSAxLFxuXHRcdFx0XHRtYXhJdGVyYXRpb25zID0gMjA7XG5cblx0XHRcdGlmICggc3RhcnQgJiYgc3RhcnRbIDMgXSAhPT0gdW5pdCApIHtcblx0XHRcdFx0Ly8gVHJ1c3QgdW5pdHMgcmVwb3J0ZWQgYnkgalF1ZXJ5LmNzc1xuXHRcdFx0XHR1bml0ID0gdW5pdCB8fCBzdGFydFsgMyBdO1xuXG5cdFx0XHRcdC8vIE1ha2Ugc3VyZSB3ZSB1cGRhdGUgdGhlIHR3ZWVuIHByb3BlcnRpZXMgbGF0ZXIgb25cblx0XHRcdFx0cGFydHMgPSBwYXJ0cyB8fCBbXTtcblxuXHRcdFx0XHQvLyBJdGVyYXRpdmVseSBhcHByb3hpbWF0ZSBmcm9tIGEgbm9uemVybyBzdGFydGluZyBwb2ludFxuXHRcdFx0XHRzdGFydCA9ICt0YXJnZXQgfHwgMTtcblxuXHRcdFx0XHRkbyB7XG5cdFx0XHRcdFx0Ly8gSWYgcHJldmlvdXMgaXRlcmF0aW9uIHplcm9lZCBvdXQsIGRvdWJsZSB1bnRpbCB3ZSBnZXQgKnNvbWV0aGluZyouXG5cdFx0XHRcdFx0Ly8gVXNlIHN0cmluZyBmb3IgZG91Ymxpbmcgc28gd2UgZG9uJ3QgYWNjaWRlbnRhbGx5IHNlZSBzY2FsZSBhcyB1bmNoYW5nZWQgYmVsb3dcblx0XHRcdFx0XHRzY2FsZSA9IHNjYWxlIHx8IFwiLjVcIjtcblxuXHRcdFx0XHRcdC8vIEFkanVzdCBhbmQgYXBwbHlcblx0XHRcdFx0XHRzdGFydCA9IHN0YXJ0IC8gc2NhbGU7XG5cdFx0XHRcdFx0alF1ZXJ5LnN0eWxlKCB0d2Vlbi5lbGVtLCBwcm9wLCBzdGFydCArIHVuaXQgKTtcblxuXHRcdFx0XHQvLyBVcGRhdGUgc2NhbGUsIHRvbGVyYXRpbmcgemVybyBvciBOYU4gZnJvbSB0d2Vlbi5jdXIoKSxcblx0XHRcdFx0Ly8gYnJlYWsgdGhlIGxvb3AgaWYgc2NhbGUgaXMgdW5jaGFuZ2VkIG9yIHBlcmZlY3QsIG9yIGlmIHdlJ3ZlIGp1c3QgaGFkIGVub3VnaFxuXHRcdFx0XHR9IHdoaWxlICggc2NhbGUgIT09IChzY2FsZSA9IHR3ZWVuLmN1cigpIC8gdGFyZ2V0KSAmJiBzY2FsZSAhPT0gMSAmJiAtLW1heEl0ZXJhdGlvbnMgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gVXBkYXRlIHR3ZWVuIHByb3BlcnRpZXNcblx0XHRcdGlmICggcGFydHMgKSB7XG5cdFx0XHRcdHN0YXJ0ID0gdHdlZW4uc3RhcnQgPSArc3RhcnQgfHwgK3RhcmdldCB8fCAwO1xuXHRcdFx0XHR0d2Vlbi51bml0ID0gdW5pdDtcblx0XHRcdFx0Ly8gSWYgYSArPS8tPSB0b2tlbiB3YXMgcHJvdmlkZWQsIHdlJ3JlIGRvaW5nIGEgcmVsYXRpdmUgYW5pbWF0aW9uXG5cdFx0XHRcdHR3ZWVuLmVuZCA9IHBhcnRzWyAxIF0gP1xuXHRcdFx0XHRcdHN0YXJ0ICsgKCBwYXJ0c1sgMSBdICsgMSApICogcGFydHNbIDIgXSA6XG5cdFx0XHRcdFx0K3BhcnRzWyAyIF07XG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiB0d2Vlbjtcblx0XHR9IF1cblx0fTtcblxuLy8gQW5pbWF0aW9ucyBjcmVhdGVkIHN5bmNocm9ub3VzbHkgd2lsbCBydW4gc3luY2hyb25vdXNseVxuZnVuY3Rpb24gY3JlYXRlRnhOb3coKSB7XG5cdHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG5cdFx0ZnhOb3cgPSB1bmRlZmluZWQ7XG5cdH0pO1xuXHRyZXR1cm4gKCBmeE5vdyA9IGpRdWVyeS5ub3coKSApO1xufVxuXG4vLyBHZW5lcmF0ZSBwYXJhbWV0ZXJzIHRvIGNyZWF0ZSBhIHN0YW5kYXJkIGFuaW1hdGlvblxuZnVuY3Rpb24gZ2VuRngoIHR5cGUsIGluY2x1ZGVXaWR0aCApIHtcblx0dmFyIHdoaWNoLFxuXHRcdGkgPSAwLFxuXHRcdGF0dHJzID0geyBoZWlnaHQ6IHR5cGUgfTtcblxuXHQvLyBJZiB3ZSBpbmNsdWRlIHdpZHRoLCBzdGVwIHZhbHVlIGlzIDEgdG8gZG8gYWxsIGNzc0V4cGFuZCB2YWx1ZXMsXG5cdC8vIG90aGVyd2lzZSBzdGVwIHZhbHVlIGlzIDIgdG8gc2tpcCBvdmVyIExlZnQgYW5kIFJpZ2h0XG5cdGluY2x1ZGVXaWR0aCA9IGluY2x1ZGVXaWR0aCA/IDEgOiAwO1xuXHRmb3IgKCA7IGkgPCA0IDsgaSArPSAyIC0gaW5jbHVkZVdpZHRoICkge1xuXHRcdHdoaWNoID0gY3NzRXhwYW5kWyBpIF07XG5cdFx0YXR0cnNbIFwibWFyZ2luXCIgKyB3aGljaCBdID0gYXR0cnNbIFwicGFkZGluZ1wiICsgd2hpY2ggXSA9IHR5cGU7XG5cdH1cblxuXHRpZiAoIGluY2x1ZGVXaWR0aCApIHtcblx0XHRhdHRycy5vcGFjaXR5ID0gYXR0cnMud2lkdGggPSB0eXBlO1xuXHR9XG5cblx0cmV0dXJuIGF0dHJzO1xufVxuXG5mdW5jdGlvbiBjcmVhdGVUd2VlbiggdmFsdWUsIHByb3AsIGFuaW1hdGlvbiApIHtcblx0dmFyIHR3ZWVuLFxuXHRcdGNvbGxlY3Rpb24gPSAoIHR3ZWVuZXJzWyBwcm9wIF0gfHwgW10gKS5jb25jYXQoIHR3ZWVuZXJzWyBcIipcIiBdICksXG5cdFx0aW5kZXggPSAwLFxuXHRcdGxlbmd0aCA9IGNvbGxlY3Rpb24ubGVuZ3RoO1xuXHRmb3IgKCA7IGluZGV4IDwgbGVuZ3RoOyBpbmRleCsrICkge1xuXHRcdGlmICggKHR3ZWVuID0gY29sbGVjdGlvblsgaW5kZXggXS5jYWxsKCBhbmltYXRpb24sIHByb3AsIHZhbHVlICkpICkge1xuXG5cdFx0XHQvLyBXZSdyZSBkb25lIHdpdGggdGhpcyBwcm9wZXJ0eVxuXHRcdFx0cmV0dXJuIHR3ZWVuO1xuXHRcdH1cblx0fVxufVxuXG5mdW5jdGlvbiBkZWZhdWx0UHJlZmlsdGVyKCBlbGVtLCBwcm9wcywgb3B0cyApIHtcblx0LyoganNoaW50IHZhbGlkdGhpczogdHJ1ZSAqL1xuXHR2YXIgcHJvcCwgdmFsdWUsIHRvZ2dsZSwgdHdlZW4sIGhvb2tzLCBvbGRmaXJlLCBkaXNwbGF5LCBjaGVja0Rpc3BsYXksXG5cdFx0YW5pbSA9IHRoaXMsXG5cdFx0b3JpZyA9IHt9LFxuXHRcdHN0eWxlID0gZWxlbS5zdHlsZSxcblx0XHRoaWRkZW4gPSBlbGVtLm5vZGVUeXBlICYmIGlzSGlkZGVuKCBlbGVtICksXG5cdFx0ZGF0YVNob3cgPSBkYXRhX3ByaXYuZ2V0KCBlbGVtLCBcImZ4c2hvd1wiICk7XG5cblx0Ly8gSGFuZGxlIHF1ZXVlOiBmYWxzZSBwcm9taXNlc1xuXHRpZiAoICFvcHRzLnF1ZXVlICkge1xuXHRcdGhvb2tzID0galF1ZXJ5Ll9xdWV1ZUhvb2tzKCBlbGVtLCBcImZ4XCIgKTtcblx0XHRpZiAoIGhvb2tzLnVucXVldWVkID09IG51bGwgKSB7XG5cdFx0XHRob29rcy51bnF1ZXVlZCA9IDA7XG5cdFx0XHRvbGRmaXJlID0gaG9va3MuZW1wdHkuZmlyZTtcblx0XHRcdGhvb2tzLmVtcHR5LmZpcmUgPSBmdW5jdGlvbigpIHtcblx0XHRcdFx0aWYgKCAhaG9va3MudW5xdWV1ZWQgKSB7XG5cdFx0XHRcdFx0b2xkZmlyZSgpO1xuXHRcdFx0XHR9XG5cdFx0XHR9O1xuXHRcdH1cblx0XHRob29rcy51bnF1ZXVlZCsrO1xuXG5cdFx0YW5pbS5hbHdheXMoZnVuY3Rpb24oKSB7XG5cdFx0XHQvLyBFbnN1cmUgdGhlIGNvbXBsZXRlIGhhbmRsZXIgaXMgY2FsbGVkIGJlZm9yZSB0aGlzIGNvbXBsZXRlc1xuXHRcdFx0YW5pbS5hbHdheXMoZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGhvb2tzLnVucXVldWVkLS07XG5cdFx0XHRcdGlmICggIWpRdWVyeS5xdWV1ZSggZWxlbSwgXCJmeFwiICkubGVuZ3RoICkge1xuXHRcdFx0XHRcdGhvb2tzLmVtcHR5LmZpcmUoKTtcblx0XHRcdFx0fVxuXHRcdFx0fSk7XG5cdFx0fSk7XG5cdH1cblxuXHQvLyBIZWlnaHQvd2lkdGggb3ZlcmZsb3cgcGFzc1xuXHRpZiAoIGVsZW0ubm9kZVR5cGUgPT09IDEgJiYgKCBcImhlaWdodFwiIGluIHByb3BzIHx8IFwid2lkdGhcIiBpbiBwcm9wcyApICkge1xuXHRcdC8vIE1ha2Ugc3VyZSB0aGF0IG5vdGhpbmcgc25lYWtzIG91dFxuXHRcdC8vIFJlY29yZCBhbGwgMyBvdmVyZmxvdyBhdHRyaWJ1dGVzIGJlY2F1c2UgSUU5LTEwIGRvIG5vdFxuXHRcdC8vIGNoYW5nZSB0aGUgb3ZlcmZsb3cgYXR0cmlidXRlIHdoZW4gb3ZlcmZsb3dYIGFuZFxuXHRcdC8vIG92ZXJmbG93WSBhcmUgc2V0IHRvIHRoZSBzYW1lIHZhbHVlXG5cdFx0b3B0cy5vdmVyZmxvdyA9IFsgc3R5bGUub3ZlcmZsb3csIHN0eWxlLm92ZXJmbG93WCwgc3R5bGUub3ZlcmZsb3dZIF07XG5cblx0XHQvLyBTZXQgZGlzcGxheSBwcm9wZXJ0eSB0byBpbmxpbmUtYmxvY2sgZm9yIGhlaWdodC93aWR0aFxuXHRcdC8vIGFuaW1hdGlvbnMgb24gaW5saW5lIGVsZW1lbnRzIHRoYXQgYXJlIGhhdmluZyB3aWR0aC9oZWlnaHQgYW5pbWF0ZWRcblx0XHRkaXNwbGF5ID0galF1ZXJ5LmNzcyggZWxlbSwgXCJkaXNwbGF5XCIgKTtcblxuXHRcdC8vIFRlc3QgZGVmYXVsdCBkaXNwbGF5IGlmIGRpc3BsYXkgaXMgY3VycmVudGx5IFwibm9uZVwiXG5cdFx0Y2hlY2tEaXNwbGF5ID0gZGlzcGxheSA9PT0gXCJub25lXCIgP1xuXHRcdFx0ZGF0YV9wcml2LmdldCggZWxlbSwgXCJvbGRkaXNwbGF5XCIgKSB8fCBkZWZhdWx0RGlzcGxheSggZWxlbS5ub2RlTmFtZSApIDogZGlzcGxheTtcblxuXHRcdGlmICggY2hlY2tEaXNwbGF5ID09PSBcImlubGluZVwiICYmIGpRdWVyeS5jc3MoIGVsZW0sIFwiZmxvYXRcIiApID09PSBcIm5vbmVcIiApIHtcblx0XHRcdHN0eWxlLmRpc3BsYXkgPSBcImlubGluZS1ibG9ja1wiO1xuXHRcdH1cblx0fVxuXG5cdGlmICggb3B0cy5vdmVyZmxvdyApIHtcblx0XHRzdHlsZS5vdmVyZmxvdyA9IFwiaGlkZGVuXCI7XG5cdFx0YW5pbS5hbHdheXMoZnVuY3Rpb24oKSB7XG5cdFx0XHRzdHlsZS5vdmVyZmxvdyA9IG9wdHMub3ZlcmZsb3dbIDAgXTtcblx0XHRcdHN0eWxlLm92ZXJmbG93WCA9IG9wdHMub3ZlcmZsb3dbIDEgXTtcblx0XHRcdHN0eWxlLm92ZXJmbG93WSA9IG9wdHMub3ZlcmZsb3dbIDIgXTtcblx0XHR9KTtcblx0fVxuXG5cdC8vIHNob3cvaGlkZSBwYXNzXG5cdGZvciAoIHByb3AgaW4gcHJvcHMgKSB7XG5cdFx0dmFsdWUgPSBwcm9wc1sgcHJvcCBdO1xuXHRcdGlmICggcmZ4dHlwZXMuZXhlYyggdmFsdWUgKSApIHtcblx0XHRcdGRlbGV0ZSBwcm9wc1sgcHJvcCBdO1xuXHRcdFx0dG9nZ2xlID0gdG9nZ2xlIHx8IHZhbHVlID09PSBcInRvZ2dsZVwiO1xuXHRcdFx0aWYgKCB2YWx1ZSA9PT0gKCBoaWRkZW4gPyBcImhpZGVcIiA6IFwic2hvd1wiICkgKSB7XG5cblx0XHRcdFx0Ly8gSWYgdGhlcmUgaXMgZGF0YVNob3cgbGVmdCBvdmVyIGZyb20gYSBzdG9wcGVkIGhpZGUgb3Igc2hvdyBhbmQgd2UgYXJlIGdvaW5nIHRvIHByb2NlZWQgd2l0aCBzaG93LCB3ZSBzaG91bGQgcHJldGVuZCB0byBiZSBoaWRkZW5cblx0XHRcdFx0aWYgKCB2YWx1ZSA9PT0gXCJzaG93XCIgJiYgZGF0YVNob3cgJiYgZGF0YVNob3dbIHByb3AgXSAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRcdGhpZGRlbiA9IHRydWU7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0Y29udGludWU7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdG9yaWdbIHByb3AgXSA9IGRhdGFTaG93ICYmIGRhdGFTaG93WyBwcm9wIF0gfHwgalF1ZXJ5LnN0eWxlKCBlbGVtLCBwcm9wICk7XG5cblx0XHQvLyBBbnkgbm9uLWZ4IHZhbHVlIHN0b3BzIHVzIGZyb20gcmVzdG9yaW5nIHRoZSBvcmlnaW5hbCBkaXNwbGF5IHZhbHVlXG5cdFx0fSBlbHNlIHtcblx0XHRcdGRpc3BsYXkgPSB1bmRlZmluZWQ7XG5cdFx0fVxuXHR9XG5cblx0aWYgKCAhalF1ZXJ5LmlzRW1wdHlPYmplY3QoIG9yaWcgKSApIHtcblx0XHRpZiAoIGRhdGFTaG93ICkge1xuXHRcdFx0aWYgKCBcImhpZGRlblwiIGluIGRhdGFTaG93ICkge1xuXHRcdFx0XHRoaWRkZW4gPSBkYXRhU2hvdy5oaWRkZW47XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdGRhdGFTaG93ID0gZGF0YV9wcml2LmFjY2VzcyggZWxlbSwgXCJmeHNob3dcIiwge30gKTtcblx0XHR9XG5cblx0XHQvLyBTdG9yZSBzdGF0ZSBpZiBpdHMgdG9nZ2xlIC0gZW5hYmxlcyAuc3RvcCgpLnRvZ2dsZSgpIHRvIFwicmV2ZXJzZVwiXG5cdFx0aWYgKCB0b2dnbGUgKSB7XG5cdFx0XHRkYXRhU2hvdy5oaWRkZW4gPSAhaGlkZGVuO1xuXHRcdH1cblx0XHRpZiAoIGhpZGRlbiApIHtcblx0XHRcdGpRdWVyeSggZWxlbSApLnNob3coKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0YW5pbS5kb25lKGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRqUXVlcnkoIGVsZW0gKS5oaWRlKCk7XG5cdFx0XHR9KTtcblx0XHR9XG5cdFx0YW5pbS5kb25lKGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIHByb3A7XG5cblx0XHRcdGRhdGFfcHJpdi5yZW1vdmUoIGVsZW0sIFwiZnhzaG93XCIgKTtcblx0XHRcdGZvciAoIHByb3AgaW4gb3JpZyApIHtcblx0XHRcdFx0alF1ZXJ5LnN0eWxlKCBlbGVtLCBwcm9wLCBvcmlnWyBwcm9wIF0gKTtcblx0XHRcdH1cblx0XHR9KTtcblx0XHRmb3IgKCBwcm9wIGluIG9yaWcgKSB7XG5cdFx0XHR0d2VlbiA9IGNyZWF0ZVR3ZWVuKCBoaWRkZW4gPyBkYXRhU2hvd1sgcHJvcCBdIDogMCwgcHJvcCwgYW5pbSApO1xuXG5cdFx0XHRpZiAoICEoIHByb3AgaW4gZGF0YVNob3cgKSApIHtcblx0XHRcdFx0ZGF0YVNob3dbIHByb3AgXSA9IHR3ZWVuLnN0YXJ0O1xuXHRcdFx0XHRpZiAoIGhpZGRlbiApIHtcblx0XHRcdFx0XHR0d2Vlbi5lbmQgPSB0d2Vlbi5zdGFydDtcblx0XHRcdFx0XHR0d2Vlbi5zdGFydCA9IHByb3AgPT09IFwid2lkdGhcIiB8fCBwcm9wID09PSBcImhlaWdodFwiID8gMSA6IDA7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0Ly8gSWYgdGhpcyBpcyBhIG5vb3AgbGlrZSAuaGlkZSgpLmhpZGUoKSwgcmVzdG9yZSBhbiBvdmVyd3JpdHRlbiBkaXNwbGF5IHZhbHVlXG5cdH0gZWxzZSBpZiAoIChkaXNwbGF5ID09PSBcIm5vbmVcIiA/IGRlZmF1bHREaXNwbGF5KCBlbGVtLm5vZGVOYW1lICkgOiBkaXNwbGF5KSA9PT0gXCJpbmxpbmVcIiApIHtcblx0XHRzdHlsZS5kaXNwbGF5ID0gZGlzcGxheTtcblx0fVxufVxuXG5mdW5jdGlvbiBwcm9wRmlsdGVyKCBwcm9wcywgc3BlY2lhbEVhc2luZyApIHtcblx0dmFyIGluZGV4LCBuYW1lLCBlYXNpbmcsIHZhbHVlLCBob29rcztcblxuXHQvLyBjYW1lbENhc2UsIHNwZWNpYWxFYXNpbmcgYW5kIGV4cGFuZCBjc3NIb29rIHBhc3Ncblx0Zm9yICggaW5kZXggaW4gcHJvcHMgKSB7XG5cdFx0bmFtZSA9IGpRdWVyeS5jYW1lbENhc2UoIGluZGV4ICk7XG5cdFx0ZWFzaW5nID0gc3BlY2lhbEVhc2luZ1sgbmFtZSBdO1xuXHRcdHZhbHVlID0gcHJvcHNbIGluZGV4IF07XG5cdFx0aWYgKCBqUXVlcnkuaXNBcnJheSggdmFsdWUgKSApIHtcblx0XHRcdGVhc2luZyA9IHZhbHVlWyAxIF07XG5cdFx0XHR2YWx1ZSA9IHByb3BzWyBpbmRleCBdID0gdmFsdWVbIDAgXTtcblx0XHR9XG5cblx0XHRpZiAoIGluZGV4ICE9PSBuYW1lICkge1xuXHRcdFx0cHJvcHNbIG5hbWUgXSA9IHZhbHVlO1xuXHRcdFx0ZGVsZXRlIHByb3BzWyBpbmRleCBdO1xuXHRcdH1cblxuXHRcdGhvb2tzID0galF1ZXJ5LmNzc0hvb2tzWyBuYW1lIF07XG5cdFx0aWYgKCBob29rcyAmJiBcImV4cGFuZFwiIGluIGhvb2tzICkge1xuXHRcdFx0dmFsdWUgPSBob29rcy5leHBhbmQoIHZhbHVlICk7XG5cdFx0XHRkZWxldGUgcHJvcHNbIG5hbWUgXTtcblxuXHRcdFx0Ly8gTm90IHF1aXRlICQuZXh0ZW5kLCB0aGlzIHdvbid0IG92ZXJ3cml0ZSBleGlzdGluZyBrZXlzLlxuXHRcdFx0Ly8gUmV1c2luZyAnaW5kZXgnIGJlY2F1c2Ugd2UgaGF2ZSB0aGUgY29ycmVjdCBcIm5hbWVcIlxuXHRcdFx0Zm9yICggaW5kZXggaW4gdmFsdWUgKSB7XG5cdFx0XHRcdGlmICggISggaW5kZXggaW4gcHJvcHMgKSApIHtcblx0XHRcdFx0XHRwcm9wc1sgaW5kZXggXSA9IHZhbHVlWyBpbmRleCBdO1xuXHRcdFx0XHRcdHNwZWNpYWxFYXNpbmdbIGluZGV4IF0gPSBlYXNpbmc7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9IGVsc2Uge1xuXHRcdFx0c3BlY2lhbEVhc2luZ1sgbmFtZSBdID0gZWFzaW5nO1xuXHRcdH1cblx0fVxufVxuXG5mdW5jdGlvbiBBbmltYXRpb24oIGVsZW0sIHByb3BlcnRpZXMsIG9wdGlvbnMgKSB7XG5cdHZhciByZXN1bHQsXG5cdFx0c3RvcHBlZCxcblx0XHRpbmRleCA9IDAsXG5cdFx0bGVuZ3RoID0gYW5pbWF0aW9uUHJlZmlsdGVycy5sZW5ndGgsXG5cdFx0ZGVmZXJyZWQgPSBqUXVlcnkuRGVmZXJyZWQoKS5hbHdheXMoIGZ1bmN0aW9uKCkge1xuXHRcdFx0Ly8gRG9uJ3QgbWF0Y2ggZWxlbSBpbiB0aGUgOmFuaW1hdGVkIHNlbGVjdG9yXG5cdFx0XHRkZWxldGUgdGljay5lbGVtO1xuXHRcdH0pLFxuXHRcdHRpY2sgPSBmdW5jdGlvbigpIHtcblx0XHRcdGlmICggc3RvcHBlZCApIHtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0dmFyIGN1cnJlbnRUaW1lID0gZnhOb3cgfHwgY3JlYXRlRnhOb3coKSxcblx0XHRcdFx0cmVtYWluaW5nID0gTWF0aC5tYXgoIDAsIGFuaW1hdGlvbi5zdGFydFRpbWUgKyBhbmltYXRpb24uZHVyYXRpb24gLSBjdXJyZW50VGltZSApLFxuXHRcdFx0XHQvLyBTdXBwb3J0OiBBbmRyb2lkIDIuM1xuXHRcdFx0XHQvLyBBcmNoYWljIGNyYXNoIGJ1ZyB3b24ndCBhbGxvdyB1cyB0byB1c2UgYDEgLSAoIDAuNSB8fCAwIClgICgjMTI0OTcpXG5cdFx0XHRcdHRlbXAgPSByZW1haW5pbmcgLyBhbmltYXRpb24uZHVyYXRpb24gfHwgMCxcblx0XHRcdFx0cGVyY2VudCA9IDEgLSB0ZW1wLFxuXHRcdFx0XHRpbmRleCA9IDAsXG5cdFx0XHRcdGxlbmd0aCA9IGFuaW1hdGlvbi50d2VlbnMubGVuZ3RoO1xuXG5cdFx0XHRmb3IgKCA7IGluZGV4IDwgbGVuZ3RoIDsgaW5kZXgrKyApIHtcblx0XHRcdFx0YW5pbWF0aW9uLnR3ZWVuc1sgaW5kZXggXS5ydW4oIHBlcmNlbnQgKTtcblx0XHRcdH1cblxuXHRcdFx0ZGVmZXJyZWQubm90aWZ5V2l0aCggZWxlbSwgWyBhbmltYXRpb24sIHBlcmNlbnQsIHJlbWFpbmluZyBdKTtcblxuXHRcdFx0aWYgKCBwZXJjZW50IDwgMSAmJiBsZW5ndGggKSB7XG5cdFx0XHRcdHJldHVybiByZW1haW5pbmc7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRkZWZlcnJlZC5yZXNvbHZlV2l0aCggZWxlbSwgWyBhbmltYXRpb24gXSApO1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0fSxcblx0XHRhbmltYXRpb24gPSBkZWZlcnJlZC5wcm9taXNlKHtcblx0XHRcdGVsZW06IGVsZW0sXG5cdFx0XHRwcm9wczogalF1ZXJ5LmV4dGVuZCgge30sIHByb3BlcnRpZXMgKSxcblx0XHRcdG9wdHM6IGpRdWVyeS5leHRlbmQoIHRydWUsIHsgc3BlY2lhbEVhc2luZzoge30gfSwgb3B0aW9ucyApLFxuXHRcdFx0b3JpZ2luYWxQcm9wZXJ0aWVzOiBwcm9wZXJ0aWVzLFxuXHRcdFx0b3JpZ2luYWxPcHRpb25zOiBvcHRpb25zLFxuXHRcdFx0c3RhcnRUaW1lOiBmeE5vdyB8fCBjcmVhdGVGeE5vdygpLFxuXHRcdFx0ZHVyYXRpb246IG9wdGlvbnMuZHVyYXRpb24sXG5cdFx0XHR0d2VlbnM6IFtdLFxuXHRcdFx0Y3JlYXRlVHdlZW46IGZ1bmN0aW9uKCBwcm9wLCBlbmQgKSB7XG5cdFx0XHRcdHZhciB0d2VlbiA9IGpRdWVyeS5Ud2VlbiggZWxlbSwgYW5pbWF0aW9uLm9wdHMsIHByb3AsIGVuZCxcblx0XHRcdFx0XHRcdGFuaW1hdGlvbi5vcHRzLnNwZWNpYWxFYXNpbmdbIHByb3AgXSB8fCBhbmltYXRpb24ub3B0cy5lYXNpbmcgKTtcblx0XHRcdFx0YW5pbWF0aW9uLnR3ZWVucy5wdXNoKCB0d2VlbiApO1xuXHRcdFx0XHRyZXR1cm4gdHdlZW47XG5cdFx0XHR9LFxuXHRcdFx0c3RvcDogZnVuY3Rpb24oIGdvdG9FbmQgKSB7XG5cdFx0XHRcdHZhciBpbmRleCA9IDAsXG5cdFx0XHRcdFx0Ly8gSWYgd2UgYXJlIGdvaW5nIHRvIHRoZSBlbmQsIHdlIHdhbnQgdG8gcnVuIGFsbCB0aGUgdHdlZW5zXG5cdFx0XHRcdFx0Ly8gb3RoZXJ3aXNlIHdlIHNraXAgdGhpcyBwYXJ0XG5cdFx0XHRcdFx0bGVuZ3RoID0gZ290b0VuZCA/IGFuaW1hdGlvbi50d2VlbnMubGVuZ3RoIDogMDtcblx0XHRcdFx0aWYgKCBzdG9wcGVkICkge1xuXHRcdFx0XHRcdHJldHVybiB0aGlzO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHN0b3BwZWQgPSB0cnVlO1xuXHRcdFx0XHRmb3IgKCA7IGluZGV4IDwgbGVuZ3RoIDsgaW5kZXgrKyApIHtcblx0XHRcdFx0XHRhbmltYXRpb24udHdlZW5zWyBpbmRleCBdLnJ1biggMSApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gUmVzb2x2ZSB3aGVuIHdlIHBsYXllZCB0aGUgbGFzdCBmcmFtZTsgb3RoZXJ3aXNlLCByZWplY3Rcblx0XHRcdFx0aWYgKCBnb3RvRW5kICkge1xuXHRcdFx0XHRcdGRlZmVycmVkLnJlc29sdmVXaXRoKCBlbGVtLCBbIGFuaW1hdGlvbiwgZ290b0VuZCBdICk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0ZGVmZXJyZWQucmVqZWN0V2l0aCggZWxlbSwgWyBhbmltYXRpb24sIGdvdG9FbmQgXSApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiB0aGlzO1xuXHRcdFx0fVxuXHRcdH0pLFxuXHRcdHByb3BzID0gYW5pbWF0aW9uLnByb3BzO1xuXG5cdHByb3BGaWx0ZXIoIHByb3BzLCBhbmltYXRpb24ub3B0cy5zcGVjaWFsRWFzaW5nICk7XG5cblx0Zm9yICggOyBpbmRleCA8IGxlbmd0aCA7IGluZGV4KysgKSB7XG5cdFx0cmVzdWx0ID0gYW5pbWF0aW9uUHJlZmlsdGVyc1sgaW5kZXggXS5jYWxsKCBhbmltYXRpb24sIGVsZW0sIHByb3BzLCBhbmltYXRpb24ub3B0cyApO1xuXHRcdGlmICggcmVzdWx0ICkge1xuXHRcdFx0cmV0dXJuIHJlc3VsdDtcblx0XHR9XG5cdH1cblxuXHRqUXVlcnkubWFwKCBwcm9wcywgY3JlYXRlVHdlZW4sIGFuaW1hdGlvbiApO1xuXG5cdGlmICggalF1ZXJ5LmlzRnVuY3Rpb24oIGFuaW1hdGlvbi5vcHRzLnN0YXJ0ICkgKSB7XG5cdFx0YW5pbWF0aW9uLm9wdHMuc3RhcnQuY2FsbCggZWxlbSwgYW5pbWF0aW9uICk7XG5cdH1cblxuXHRqUXVlcnkuZngudGltZXIoXG5cdFx0alF1ZXJ5LmV4dGVuZCggdGljaywge1xuXHRcdFx0ZWxlbTogZWxlbSxcblx0XHRcdGFuaW06IGFuaW1hdGlvbixcblx0XHRcdHF1ZXVlOiBhbmltYXRpb24ub3B0cy5xdWV1ZVxuXHRcdH0pXG5cdCk7XG5cblx0Ly8gYXR0YWNoIGNhbGxiYWNrcyBmcm9tIG9wdGlvbnNcblx0cmV0dXJuIGFuaW1hdGlvbi5wcm9ncmVzcyggYW5pbWF0aW9uLm9wdHMucHJvZ3Jlc3MgKVxuXHRcdC5kb25lKCBhbmltYXRpb24ub3B0cy5kb25lLCBhbmltYXRpb24ub3B0cy5jb21wbGV0ZSApXG5cdFx0LmZhaWwoIGFuaW1hdGlvbi5vcHRzLmZhaWwgKVxuXHRcdC5hbHdheXMoIGFuaW1hdGlvbi5vcHRzLmFsd2F5cyApO1xufVxuXG5qUXVlcnkuQW5pbWF0aW9uID0galF1ZXJ5LmV4dGVuZCggQW5pbWF0aW9uLCB7XG5cblx0dHdlZW5lcjogZnVuY3Rpb24oIHByb3BzLCBjYWxsYmFjayApIHtcblx0XHRpZiAoIGpRdWVyeS5pc0Z1bmN0aW9uKCBwcm9wcyApICkge1xuXHRcdFx0Y2FsbGJhY2sgPSBwcm9wcztcblx0XHRcdHByb3BzID0gWyBcIipcIiBdO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRwcm9wcyA9IHByb3BzLnNwbGl0KFwiIFwiKTtcblx0XHR9XG5cblx0XHR2YXIgcHJvcCxcblx0XHRcdGluZGV4ID0gMCxcblx0XHRcdGxlbmd0aCA9IHByb3BzLmxlbmd0aDtcblxuXHRcdGZvciAoIDsgaW5kZXggPCBsZW5ndGggOyBpbmRleCsrICkge1xuXHRcdFx0cHJvcCA9IHByb3BzWyBpbmRleCBdO1xuXHRcdFx0dHdlZW5lcnNbIHByb3AgXSA9IHR3ZWVuZXJzWyBwcm9wIF0gfHwgW107XG5cdFx0XHR0d2VlbmVyc1sgcHJvcCBdLnVuc2hpZnQoIGNhbGxiYWNrICk7XG5cdFx0fVxuXHR9LFxuXG5cdHByZWZpbHRlcjogZnVuY3Rpb24oIGNhbGxiYWNrLCBwcmVwZW5kICkge1xuXHRcdGlmICggcHJlcGVuZCApIHtcblx0XHRcdGFuaW1hdGlvblByZWZpbHRlcnMudW5zaGlmdCggY2FsbGJhY2sgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0YW5pbWF0aW9uUHJlZmlsdGVycy5wdXNoKCBjYWxsYmFjayApO1xuXHRcdH1cblx0fVxufSk7XG5cbmpRdWVyeS5zcGVlZCA9IGZ1bmN0aW9uKCBzcGVlZCwgZWFzaW5nLCBmbiApIHtcblx0dmFyIG9wdCA9IHNwZWVkICYmIHR5cGVvZiBzcGVlZCA9PT0gXCJvYmplY3RcIiA/IGpRdWVyeS5leHRlbmQoIHt9LCBzcGVlZCApIDoge1xuXHRcdGNvbXBsZXRlOiBmbiB8fCAhZm4gJiYgZWFzaW5nIHx8XG5cdFx0XHRqUXVlcnkuaXNGdW5jdGlvbiggc3BlZWQgKSAmJiBzcGVlZCxcblx0XHRkdXJhdGlvbjogc3BlZWQsXG5cdFx0ZWFzaW5nOiBmbiAmJiBlYXNpbmcgfHwgZWFzaW5nICYmICFqUXVlcnkuaXNGdW5jdGlvbiggZWFzaW5nICkgJiYgZWFzaW5nXG5cdH07XG5cblx0b3B0LmR1cmF0aW9uID0galF1ZXJ5LmZ4Lm9mZiA/IDAgOiB0eXBlb2Ygb3B0LmR1cmF0aW9uID09PSBcIm51bWJlclwiID8gb3B0LmR1cmF0aW9uIDpcblx0XHRvcHQuZHVyYXRpb24gaW4galF1ZXJ5LmZ4LnNwZWVkcyA/IGpRdWVyeS5meC5zcGVlZHNbIG9wdC5kdXJhdGlvbiBdIDogalF1ZXJ5LmZ4LnNwZWVkcy5fZGVmYXVsdDtcblxuXHQvLyBOb3JtYWxpemUgb3B0LnF1ZXVlIC0gdHJ1ZS91bmRlZmluZWQvbnVsbCAtPiBcImZ4XCJcblx0aWYgKCBvcHQucXVldWUgPT0gbnVsbCB8fCBvcHQucXVldWUgPT09IHRydWUgKSB7XG5cdFx0b3B0LnF1ZXVlID0gXCJmeFwiO1xuXHR9XG5cblx0Ly8gUXVldWVpbmdcblx0b3B0Lm9sZCA9IG9wdC5jb21wbGV0ZTtcblxuXHRvcHQuY29tcGxldGUgPSBmdW5jdGlvbigpIHtcblx0XHRpZiAoIGpRdWVyeS5pc0Z1bmN0aW9uKCBvcHQub2xkICkgKSB7XG5cdFx0XHRvcHQub2xkLmNhbGwoIHRoaXMgKTtcblx0XHR9XG5cblx0XHRpZiAoIG9wdC5xdWV1ZSApIHtcblx0XHRcdGpRdWVyeS5kZXF1ZXVlKCB0aGlzLCBvcHQucXVldWUgKTtcblx0XHR9XG5cdH07XG5cblx0cmV0dXJuIG9wdDtcbn07XG5cbmpRdWVyeS5mbi5leHRlbmQoe1xuXHRmYWRlVG86IGZ1bmN0aW9uKCBzcGVlZCwgdG8sIGVhc2luZywgY2FsbGJhY2sgKSB7XG5cblx0XHQvLyBTaG93IGFueSBoaWRkZW4gZWxlbWVudHMgYWZ0ZXIgc2V0dGluZyBvcGFjaXR5IHRvIDBcblx0XHRyZXR1cm4gdGhpcy5maWx0ZXIoIGlzSGlkZGVuICkuY3NzKCBcIm9wYWNpdHlcIiwgMCApLnNob3coKVxuXG5cdFx0XHQvLyBBbmltYXRlIHRvIHRoZSB2YWx1ZSBzcGVjaWZpZWRcblx0XHRcdC5lbmQoKS5hbmltYXRlKHsgb3BhY2l0eTogdG8gfSwgc3BlZWQsIGVhc2luZywgY2FsbGJhY2sgKTtcblx0fSxcblx0YW5pbWF0ZTogZnVuY3Rpb24oIHByb3AsIHNwZWVkLCBlYXNpbmcsIGNhbGxiYWNrICkge1xuXHRcdHZhciBlbXB0eSA9IGpRdWVyeS5pc0VtcHR5T2JqZWN0KCBwcm9wICksXG5cdFx0XHRvcHRhbGwgPSBqUXVlcnkuc3BlZWQoIHNwZWVkLCBlYXNpbmcsIGNhbGxiYWNrICksXG5cdFx0XHRkb0FuaW1hdGlvbiA9IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHQvLyBPcGVyYXRlIG9uIGEgY29weSBvZiBwcm9wIHNvIHBlci1wcm9wZXJ0eSBlYXNpbmcgd29uJ3QgYmUgbG9zdFxuXHRcdFx0XHR2YXIgYW5pbSA9IEFuaW1hdGlvbiggdGhpcywgalF1ZXJ5LmV4dGVuZCgge30sIHByb3AgKSwgb3B0YWxsICk7XG5cblx0XHRcdFx0Ly8gRW1wdHkgYW5pbWF0aW9ucywgb3IgZmluaXNoaW5nIHJlc29sdmVzIGltbWVkaWF0ZWx5XG5cdFx0XHRcdGlmICggZW1wdHkgfHwgZGF0YV9wcml2LmdldCggdGhpcywgXCJmaW5pc2hcIiApICkge1xuXHRcdFx0XHRcdGFuaW0uc3RvcCggdHJ1ZSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9O1xuXHRcdFx0ZG9BbmltYXRpb24uZmluaXNoID0gZG9BbmltYXRpb247XG5cblx0XHRyZXR1cm4gZW1wdHkgfHwgb3B0YWxsLnF1ZXVlID09PSBmYWxzZSA/XG5cdFx0XHR0aGlzLmVhY2goIGRvQW5pbWF0aW9uICkgOlxuXHRcdFx0dGhpcy5xdWV1ZSggb3B0YWxsLnF1ZXVlLCBkb0FuaW1hdGlvbiApO1xuXHR9LFxuXHRzdG9wOiBmdW5jdGlvbiggdHlwZSwgY2xlYXJRdWV1ZSwgZ290b0VuZCApIHtcblx0XHR2YXIgc3RvcFF1ZXVlID0gZnVuY3Rpb24oIGhvb2tzICkge1xuXHRcdFx0dmFyIHN0b3AgPSBob29rcy5zdG9wO1xuXHRcdFx0ZGVsZXRlIGhvb2tzLnN0b3A7XG5cdFx0XHRzdG9wKCBnb3RvRW5kICk7XG5cdFx0fTtcblxuXHRcdGlmICggdHlwZW9mIHR5cGUgIT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRnb3RvRW5kID0gY2xlYXJRdWV1ZTtcblx0XHRcdGNsZWFyUXVldWUgPSB0eXBlO1xuXHRcdFx0dHlwZSA9IHVuZGVmaW5lZDtcblx0XHR9XG5cdFx0aWYgKCBjbGVhclF1ZXVlICYmIHR5cGUgIT09IGZhbHNlICkge1xuXHRcdFx0dGhpcy5xdWV1ZSggdHlwZSB8fCBcImZ4XCIsIFtdICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpIHtcblx0XHRcdHZhciBkZXF1ZXVlID0gdHJ1ZSxcblx0XHRcdFx0aW5kZXggPSB0eXBlICE9IG51bGwgJiYgdHlwZSArIFwicXVldWVIb29rc1wiLFxuXHRcdFx0XHR0aW1lcnMgPSBqUXVlcnkudGltZXJzLFxuXHRcdFx0XHRkYXRhID0gZGF0YV9wcml2LmdldCggdGhpcyApO1xuXG5cdFx0XHRpZiAoIGluZGV4ICkge1xuXHRcdFx0XHRpZiAoIGRhdGFbIGluZGV4IF0gJiYgZGF0YVsgaW5kZXggXS5zdG9wICkge1xuXHRcdFx0XHRcdHN0b3BRdWV1ZSggZGF0YVsgaW5kZXggXSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRmb3IgKCBpbmRleCBpbiBkYXRhICkge1xuXHRcdFx0XHRcdGlmICggZGF0YVsgaW5kZXggXSAmJiBkYXRhWyBpbmRleCBdLnN0b3AgJiYgcnJ1bi50ZXN0KCBpbmRleCApICkge1xuXHRcdFx0XHRcdFx0c3RvcFF1ZXVlKCBkYXRhWyBpbmRleCBdICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdGZvciAoIGluZGV4ID0gdGltZXJzLmxlbmd0aDsgaW5kZXgtLTsgKSB7XG5cdFx0XHRcdGlmICggdGltZXJzWyBpbmRleCBdLmVsZW0gPT09IHRoaXMgJiYgKHR5cGUgPT0gbnVsbCB8fCB0aW1lcnNbIGluZGV4IF0ucXVldWUgPT09IHR5cGUpICkge1xuXHRcdFx0XHRcdHRpbWVyc1sgaW5kZXggXS5hbmltLnN0b3AoIGdvdG9FbmQgKTtcblx0XHRcdFx0XHRkZXF1ZXVlID0gZmFsc2U7XG5cdFx0XHRcdFx0dGltZXJzLnNwbGljZSggaW5kZXgsIDEgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHQvLyBTdGFydCB0aGUgbmV4dCBpbiB0aGUgcXVldWUgaWYgdGhlIGxhc3Qgc3RlcCB3YXNuJ3QgZm9yY2VkLlxuXHRcdFx0Ly8gVGltZXJzIGN1cnJlbnRseSB3aWxsIGNhbGwgdGhlaXIgY29tcGxldGUgY2FsbGJhY2tzLCB3aGljaFxuXHRcdFx0Ly8gd2lsbCBkZXF1ZXVlIGJ1dCBvbmx5IGlmIHRoZXkgd2VyZSBnb3RvRW5kLlxuXHRcdFx0aWYgKCBkZXF1ZXVlIHx8ICFnb3RvRW5kICkge1xuXHRcdFx0XHRqUXVlcnkuZGVxdWV1ZSggdGhpcywgdHlwZSApO1xuXHRcdFx0fVxuXHRcdH0pO1xuXHR9LFxuXHRmaW5pc2g6IGZ1bmN0aW9uKCB0eXBlICkge1xuXHRcdGlmICggdHlwZSAhPT0gZmFsc2UgKSB7XG5cdFx0XHR0eXBlID0gdHlwZSB8fCBcImZ4XCI7XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgaW5kZXgsXG5cdFx0XHRcdGRhdGEgPSBkYXRhX3ByaXYuZ2V0KCB0aGlzICksXG5cdFx0XHRcdHF1ZXVlID0gZGF0YVsgdHlwZSArIFwicXVldWVcIiBdLFxuXHRcdFx0XHRob29rcyA9IGRhdGFbIHR5cGUgKyBcInF1ZXVlSG9va3NcIiBdLFxuXHRcdFx0XHR0aW1lcnMgPSBqUXVlcnkudGltZXJzLFxuXHRcdFx0XHRsZW5ndGggPSBxdWV1ZSA/IHF1ZXVlLmxlbmd0aCA6IDA7XG5cblx0XHRcdC8vIEVuYWJsZSBmaW5pc2hpbmcgZmxhZyBvbiBwcml2YXRlIGRhdGFcblx0XHRcdGRhdGEuZmluaXNoID0gdHJ1ZTtcblxuXHRcdFx0Ly8gRW1wdHkgdGhlIHF1ZXVlIGZpcnN0XG5cdFx0XHRqUXVlcnkucXVldWUoIHRoaXMsIHR5cGUsIFtdICk7XG5cblx0XHRcdGlmICggaG9va3MgJiYgaG9va3Muc3RvcCApIHtcblx0XHRcdFx0aG9va3Muc3RvcC5jYWxsKCB0aGlzLCB0cnVlICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIExvb2sgZm9yIGFueSBhY3RpdmUgYW5pbWF0aW9ucywgYW5kIGZpbmlzaCB0aGVtXG5cdFx0XHRmb3IgKCBpbmRleCA9IHRpbWVycy5sZW5ndGg7IGluZGV4LS07ICkge1xuXHRcdFx0XHRpZiAoIHRpbWVyc1sgaW5kZXggXS5lbGVtID09PSB0aGlzICYmIHRpbWVyc1sgaW5kZXggXS5xdWV1ZSA9PT0gdHlwZSApIHtcblx0XHRcdFx0XHR0aW1lcnNbIGluZGV4IF0uYW5pbS5zdG9wKCB0cnVlICk7XG5cdFx0XHRcdFx0dGltZXJzLnNwbGljZSggaW5kZXgsIDEgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHQvLyBMb29rIGZvciBhbnkgYW5pbWF0aW9ucyBpbiB0aGUgb2xkIHF1ZXVlIGFuZCBmaW5pc2ggdGhlbVxuXHRcdFx0Zm9yICggaW5kZXggPSAwOyBpbmRleCA8IGxlbmd0aDsgaW5kZXgrKyApIHtcblx0XHRcdFx0aWYgKCBxdWV1ZVsgaW5kZXggXSAmJiBxdWV1ZVsgaW5kZXggXS5maW5pc2ggKSB7XG5cdFx0XHRcdFx0cXVldWVbIGluZGV4IF0uZmluaXNoLmNhbGwoIHRoaXMgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHQvLyBUdXJuIG9mZiBmaW5pc2hpbmcgZmxhZ1xuXHRcdFx0ZGVsZXRlIGRhdGEuZmluaXNoO1xuXHRcdH0pO1xuXHR9XG59KTtcblxualF1ZXJ5LmVhY2goWyBcInRvZ2dsZVwiLCBcInNob3dcIiwgXCJoaWRlXCIgXSwgZnVuY3Rpb24oIGksIG5hbWUgKSB7XG5cdHZhciBjc3NGbiA9IGpRdWVyeS5mblsgbmFtZSBdO1xuXHRqUXVlcnkuZm5bIG5hbWUgXSA9IGZ1bmN0aW9uKCBzcGVlZCwgZWFzaW5nLCBjYWxsYmFjayApIHtcblx0XHRyZXR1cm4gc3BlZWQgPT0gbnVsbCB8fCB0eXBlb2Ygc3BlZWQgPT09IFwiYm9vbGVhblwiID9cblx0XHRcdGNzc0ZuLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKSA6XG5cdFx0XHR0aGlzLmFuaW1hdGUoIGdlbkZ4KCBuYW1lLCB0cnVlICksIHNwZWVkLCBlYXNpbmcsIGNhbGxiYWNrICk7XG5cdH07XG59KTtcblxuLy8gR2VuZXJhdGUgc2hvcnRjdXRzIGZvciBjdXN0b20gYW5pbWF0aW9uc1xualF1ZXJ5LmVhY2goe1xuXHRzbGlkZURvd246IGdlbkZ4KFwic2hvd1wiKSxcblx0c2xpZGVVcDogZ2VuRngoXCJoaWRlXCIpLFxuXHRzbGlkZVRvZ2dsZTogZ2VuRngoXCJ0b2dnbGVcIiksXG5cdGZhZGVJbjogeyBvcGFjaXR5OiBcInNob3dcIiB9LFxuXHRmYWRlT3V0OiB7IG9wYWNpdHk6IFwiaGlkZVwiIH0sXG5cdGZhZGVUb2dnbGU6IHsgb3BhY2l0eTogXCJ0b2dnbGVcIiB9XG59LCBmdW5jdGlvbiggbmFtZSwgcHJvcHMgKSB7XG5cdGpRdWVyeS5mblsgbmFtZSBdID0gZnVuY3Rpb24oIHNwZWVkLCBlYXNpbmcsIGNhbGxiYWNrICkge1xuXHRcdHJldHVybiB0aGlzLmFuaW1hdGUoIHByb3BzLCBzcGVlZCwgZWFzaW5nLCBjYWxsYmFjayApO1xuXHR9O1xufSk7XG5cbmpRdWVyeS50aW1lcnMgPSBbXTtcbmpRdWVyeS5meC50aWNrID0gZnVuY3Rpb24oKSB7XG5cdHZhciB0aW1lcixcblx0XHRpID0gMCxcblx0XHR0aW1lcnMgPSBqUXVlcnkudGltZXJzO1xuXG5cdGZ4Tm93ID0galF1ZXJ5Lm5vdygpO1xuXG5cdGZvciAoIDsgaSA8IHRpbWVycy5sZW5ndGg7IGkrKyApIHtcblx0XHR0aW1lciA9IHRpbWVyc1sgaSBdO1xuXHRcdC8vIENoZWNrcyB0aGUgdGltZXIgaGFzIG5vdCBhbHJlYWR5IGJlZW4gcmVtb3ZlZFxuXHRcdGlmICggIXRpbWVyKCkgJiYgdGltZXJzWyBpIF0gPT09IHRpbWVyICkge1xuXHRcdFx0dGltZXJzLnNwbGljZSggaS0tLCAxICk7XG5cdFx0fVxuXHR9XG5cblx0aWYgKCAhdGltZXJzLmxlbmd0aCApIHtcblx0XHRqUXVlcnkuZnguc3RvcCgpO1xuXHR9XG5cdGZ4Tm93ID0gdW5kZWZpbmVkO1xufTtcblxualF1ZXJ5LmZ4LnRpbWVyID0gZnVuY3Rpb24oIHRpbWVyICkge1xuXHRqUXVlcnkudGltZXJzLnB1c2goIHRpbWVyICk7XG5cdGlmICggdGltZXIoKSApIHtcblx0XHRqUXVlcnkuZnguc3RhcnQoKTtcblx0fSBlbHNlIHtcblx0XHRqUXVlcnkudGltZXJzLnBvcCgpO1xuXHR9XG59O1xuXG5qUXVlcnkuZnguaW50ZXJ2YWwgPSAxMztcblxualF1ZXJ5LmZ4LnN0YXJ0ID0gZnVuY3Rpb24oKSB7XG5cdGlmICggIXRpbWVySWQgKSB7XG5cdFx0dGltZXJJZCA9IHNldEludGVydmFsKCBqUXVlcnkuZngudGljaywgalF1ZXJ5LmZ4LmludGVydmFsICk7XG5cdH1cbn07XG5cbmpRdWVyeS5meC5zdG9wID0gZnVuY3Rpb24oKSB7XG5cdGNsZWFySW50ZXJ2YWwoIHRpbWVySWQgKTtcblx0dGltZXJJZCA9IG51bGw7XG59O1xuXG5qUXVlcnkuZnguc3BlZWRzID0ge1xuXHRzbG93OiA2MDAsXG5cdGZhc3Q6IDIwMCxcblx0Ly8gRGVmYXVsdCBzcGVlZFxuXHRfZGVmYXVsdDogNDAwXG59O1xuXG5cbi8vIEJhc2VkIG9mZiBvZiB0aGUgcGx1Z2luIGJ5IENsaW50IEhlbGZlcnMsIHdpdGggcGVybWlzc2lvbi5cbi8vIGh0dHA6Ly9ibGluZHNpZ25hbHMuY29tL2luZGV4LnBocC8yMDA5LzA3L2pxdWVyeS1kZWxheS9cbmpRdWVyeS5mbi5kZWxheSA9IGZ1bmN0aW9uKCB0aW1lLCB0eXBlICkge1xuXHR0aW1lID0galF1ZXJ5LmZ4ID8galF1ZXJ5LmZ4LnNwZWVkc1sgdGltZSBdIHx8IHRpbWUgOiB0aW1lO1xuXHR0eXBlID0gdHlwZSB8fCBcImZ4XCI7XG5cblx0cmV0dXJuIHRoaXMucXVldWUoIHR5cGUsIGZ1bmN0aW9uKCBuZXh0LCBob29rcyApIHtcblx0XHR2YXIgdGltZW91dCA9IHNldFRpbWVvdXQoIG5leHQsIHRpbWUgKTtcblx0XHRob29rcy5zdG9wID0gZnVuY3Rpb24oKSB7XG5cdFx0XHRjbGVhclRpbWVvdXQoIHRpbWVvdXQgKTtcblx0XHR9O1xuXHR9KTtcbn07XG5cblxuKGZ1bmN0aW9uKCkge1xuXHR2YXIgaW5wdXQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCBcImlucHV0XCIgKSxcblx0XHRzZWxlY3QgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCBcInNlbGVjdFwiICksXG5cdFx0b3B0ID0gc2VsZWN0LmFwcGVuZENoaWxkKCBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCBcIm9wdGlvblwiICkgKTtcblxuXHRpbnB1dC50eXBlID0gXCJjaGVja2JveFwiO1xuXG5cdC8vIFN1cHBvcnQ6IGlPUzw9NS4xLCBBbmRyb2lkPD00LjIrXG5cdC8vIERlZmF1bHQgdmFsdWUgZm9yIGEgY2hlY2tib3ggc2hvdWxkIGJlIFwib25cIlxuXHRzdXBwb3J0LmNoZWNrT24gPSBpbnB1dC52YWx1ZSAhPT0gXCJcIjtcblxuXHQvLyBTdXBwb3J0OiBJRTw9MTErXG5cdC8vIE11c3QgYWNjZXNzIHNlbGVjdGVkSW5kZXggdG8gbWFrZSBkZWZhdWx0IG9wdGlvbnMgc2VsZWN0XG5cdHN1cHBvcnQub3B0U2VsZWN0ZWQgPSBvcHQuc2VsZWN0ZWQ7XG5cblx0Ly8gU3VwcG9ydDogQW5kcm9pZDw9Mi4zXG5cdC8vIE9wdGlvbnMgaW5zaWRlIGRpc2FibGVkIHNlbGVjdHMgYXJlIGluY29ycmVjdGx5IG1hcmtlZCBhcyBkaXNhYmxlZFxuXHRzZWxlY3QuZGlzYWJsZWQgPSB0cnVlO1xuXHRzdXBwb3J0Lm9wdERpc2FibGVkID0gIW9wdC5kaXNhYmxlZDtcblxuXHQvLyBTdXBwb3J0OiBJRTw9MTErXG5cdC8vIEFuIGlucHV0IGxvc2VzIGl0cyB2YWx1ZSBhZnRlciBiZWNvbWluZyBhIHJhZGlvXG5cdGlucHV0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCggXCJpbnB1dFwiICk7XG5cdGlucHV0LnZhbHVlID0gXCJ0XCI7XG5cdGlucHV0LnR5cGUgPSBcInJhZGlvXCI7XG5cdHN1cHBvcnQucmFkaW9WYWx1ZSA9IGlucHV0LnZhbHVlID09PSBcInRcIjtcbn0pKCk7XG5cblxudmFyIG5vZGVIb29rLCBib29sSG9vayxcblx0YXR0ckhhbmRsZSA9IGpRdWVyeS5leHByLmF0dHJIYW5kbGU7XG5cbmpRdWVyeS5mbi5leHRlbmQoe1xuXHRhdHRyOiBmdW5jdGlvbiggbmFtZSwgdmFsdWUgKSB7XG5cdFx0cmV0dXJuIGFjY2VzcyggdGhpcywgalF1ZXJ5LmF0dHIsIG5hbWUsIHZhbHVlLCBhcmd1bWVudHMubGVuZ3RoID4gMSApO1xuXHR9LFxuXG5cdHJlbW92ZUF0dHI6IGZ1bmN0aW9uKCBuYW1lICkge1xuXHRcdHJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oKSB7XG5cdFx0XHRqUXVlcnkucmVtb3ZlQXR0ciggdGhpcywgbmFtZSApO1xuXHRcdH0pO1xuXHR9XG59KTtcblxualF1ZXJ5LmV4dGVuZCh7XG5cdGF0dHI6IGZ1bmN0aW9uKCBlbGVtLCBuYW1lLCB2YWx1ZSApIHtcblx0XHR2YXIgaG9va3MsIHJldCxcblx0XHRcdG5UeXBlID0gZWxlbS5ub2RlVHlwZTtcblxuXHRcdC8vIGRvbid0IGdldC9zZXQgYXR0cmlidXRlcyBvbiB0ZXh0LCBjb21tZW50IGFuZCBhdHRyaWJ1dGUgbm9kZXNcblx0XHRpZiAoICFlbGVtIHx8IG5UeXBlID09PSAzIHx8IG5UeXBlID09PSA4IHx8IG5UeXBlID09PSAyICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIEZhbGxiYWNrIHRvIHByb3Agd2hlbiBhdHRyaWJ1dGVzIGFyZSBub3Qgc3VwcG9ydGVkXG5cdFx0aWYgKCB0eXBlb2YgZWxlbS5nZXRBdHRyaWJ1dGUgPT09IHN0cnVuZGVmaW5lZCApIHtcblx0XHRcdHJldHVybiBqUXVlcnkucHJvcCggZWxlbSwgbmFtZSwgdmFsdWUgKTtcblx0XHR9XG5cblx0XHQvLyBBbGwgYXR0cmlidXRlcyBhcmUgbG93ZXJjYXNlXG5cdFx0Ly8gR3JhYiBuZWNlc3NhcnkgaG9vayBpZiBvbmUgaXMgZGVmaW5lZFxuXHRcdGlmICggblR5cGUgIT09IDEgfHwgIWpRdWVyeS5pc1hNTERvYyggZWxlbSApICkge1xuXHRcdFx0bmFtZSA9IG5hbWUudG9Mb3dlckNhc2UoKTtcblx0XHRcdGhvb2tzID0galF1ZXJ5LmF0dHJIb29rc1sgbmFtZSBdIHx8XG5cdFx0XHRcdCggalF1ZXJ5LmV4cHIubWF0Y2guYm9vbC50ZXN0KCBuYW1lICkgPyBib29sSG9vayA6IG5vZGVIb29rICk7XG5cdFx0fVxuXG5cdFx0aWYgKCB2YWx1ZSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRpZiAoIHZhbHVlID09PSBudWxsICkge1xuXHRcdFx0XHRqUXVlcnkucmVtb3ZlQXR0ciggZWxlbSwgbmFtZSApO1xuXG5cdFx0XHR9IGVsc2UgaWYgKCBob29rcyAmJiBcInNldFwiIGluIGhvb2tzICYmIChyZXQgPSBob29rcy5zZXQoIGVsZW0sIHZhbHVlLCBuYW1lICkpICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdHJldHVybiByZXQ7XG5cblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGVsZW0uc2V0QXR0cmlidXRlKCBuYW1lLCB2YWx1ZSArIFwiXCIgKTtcblx0XHRcdFx0cmV0dXJuIHZhbHVlO1xuXHRcdFx0fVxuXG5cdFx0fSBlbHNlIGlmICggaG9va3MgJiYgXCJnZXRcIiBpbiBob29rcyAmJiAocmV0ID0gaG9va3MuZ2V0KCBlbGVtLCBuYW1lICkpICE9PSBudWxsICkge1xuXHRcdFx0cmV0dXJuIHJldDtcblxuXHRcdH0gZWxzZSB7XG5cdFx0XHRyZXQgPSBqUXVlcnkuZmluZC5hdHRyKCBlbGVtLCBuYW1lICk7XG5cblx0XHRcdC8vIE5vbi1leGlzdGVudCBhdHRyaWJ1dGVzIHJldHVybiBudWxsLCB3ZSBub3JtYWxpemUgdG8gdW5kZWZpbmVkXG5cdFx0XHRyZXR1cm4gcmV0ID09IG51bGwgP1xuXHRcdFx0XHR1bmRlZmluZWQgOlxuXHRcdFx0XHRyZXQ7XG5cdFx0fVxuXHR9LFxuXG5cdHJlbW92ZUF0dHI6IGZ1bmN0aW9uKCBlbGVtLCB2YWx1ZSApIHtcblx0XHR2YXIgbmFtZSwgcHJvcE5hbWUsXG5cdFx0XHRpID0gMCxcblx0XHRcdGF0dHJOYW1lcyA9IHZhbHVlICYmIHZhbHVlLm1hdGNoKCBybm90d2hpdGUgKTtcblxuXHRcdGlmICggYXR0ck5hbWVzICYmIGVsZW0ubm9kZVR5cGUgPT09IDEgKSB7XG5cdFx0XHR3aGlsZSAoIChuYW1lID0gYXR0ck5hbWVzW2krK10pICkge1xuXHRcdFx0XHRwcm9wTmFtZSA9IGpRdWVyeS5wcm9wRml4WyBuYW1lIF0gfHwgbmFtZTtcblxuXHRcdFx0XHQvLyBCb29sZWFuIGF0dHJpYnV0ZXMgZ2V0IHNwZWNpYWwgdHJlYXRtZW50ICgjMTA4NzApXG5cdFx0XHRcdGlmICggalF1ZXJ5LmV4cHIubWF0Y2guYm9vbC50ZXN0KCBuYW1lICkgKSB7XG5cdFx0XHRcdFx0Ly8gU2V0IGNvcnJlc3BvbmRpbmcgcHJvcGVydHkgdG8gZmFsc2Vcblx0XHRcdFx0XHRlbGVtWyBwcm9wTmFtZSBdID0gZmFsc2U7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRlbGVtLnJlbW92ZUF0dHJpYnV0ZSggbmFtZSApO1xuXHRcdFx0fVxuXHRcdH1cblx0fSxcblxuXHRhdHRySG9va3M6IHtcblx0XHR0eXBlOiB7XG5cdFx0XHRzZXQ6IGZ1bmN0aW9uKCBlbGVtLCB2YWx1ZSApIHtcblx0XHRcdFx0aWYgKCAhc3VwcG9ydC5yYWRpb1ZhbHVlICYmIHZhbHVlID09PSBcInJhZGlvXCIgJiZcblx0XHRcdFx0XHRqUXVlcnkubm9kZU5hbWUoIGVsZW0sIFwiaW5wdXRcIiApICkge1xuXHRcdFx0XHRcdHZhciB2YWwgPSBlbGVtLnZhbHVlO1xuXHRcdFx0XHRcdGVsZW0uc2V0QXR0cmlidXRlKCBcInR5cGVcIiwgdmFsdWUgKTtcblx0XHRcdFx0XHRpZiAoIHZhbCApIHtcblx0XHRcdFx0XHRcdGVsZW0udmFsdWUgPSB2YWw7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHJldHVybiB2YWx1ZTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0fVxufSk7XG5cbi8vIEhvb2tzIGZvciBib29sZWFuIGF0dHJpYnV0ZXNcbmJvb2xIb29rID0ge1xuXHRzZXQ6IGZ1bmN0aW9uKCBlbGVtLCB2YWx1ZSwgbmFtZSApIHtcblx0XHRpZiAoIHZhbHVlID09PSBmYWxzZSApIHtcblx0XHRcdC8vIFJlbW92ZSBib29sZWFuIGF0dHJpYnV0ZXMgd2hlbiBzZXQgdG8gZmFsc2Vcblx0XHRcdGpRdWVyeS5yZW1vdmVBdHRyKCBlbGVtLCBuYW1lICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGVsZW0uc2V0QXR0cmlidXRlKCBuYW1lLCBuYW1lICk7XG5cdFx0fVxuXHRcdHJldHVybiBuYW1lO1xuXHR9XG59O1xualF1ZXJ5LmVhY2goIGpRdWVyeS5leHByLm1hdGNoLmJvb2wuc291cmNlLm1hdGNoKCAvXFx3Ky9nICksIGZ1bmN0aW9uKCBpLCBuYW1lICkge1xuXHR2YXIgZ2V0dGVyID0gYXR0ckhhbmRsZVsgbmFtZSBdIHx8IGpRdWVyeS5maW5kLmF0dHI7XG5cblx0YXR0ckhhbmRsZVsgbmFtZSBdID0gZnVuY3Rpb24oIGVsZW0sIG5hbWUsIGlzWE1MICkge1xuXHRcdHZhciByZXQsIGhhbmRsZTtcblx0XHRpZiAoICFpc1hNTCApIHtcblx0XHRcdC8vIEF2b2lkIGFuIGluZmluaXRlIGxvb3AgYnkgdGVtcG9yYXJpbHkgcmVtb3ZpbmcgdGhpcyBmdW5jdGlvbiBmcm9tIHRoZSBnZXR0ZXJcblx0XHRcdGhhbmRsZSA9IGF0dHJIYW5kbGVbIG5hbWUgXTtcblx0XHRcdGF0dHJIYW5kbGVbIG5hbWUgXSA9IHJldDtcblx0XHRcdHJldCA9IGdldHRlciggZWxlbSwgbmFtZSwgaXNYTUwgKSAhPSBudWxsID9cblx0XHRcdFx0bmFtZS50b0xvd2VyQ2FzZSgpIDpcblx0XHRcdFx0bnVsbDtcblx0XHRcdGF0dHJIYW5kbGVbIG5hbWUgXSA9IGhhbmRsZTtcblx0XHR9XG5cdFx0cmV0dXJuIHJldDtcblx0fTtcbn0pO1xuXG5cblxuXG52YXIgcmZvY3VzYWJsZSA9IC9eKD86aW5wdXR8c2VsZWN0fHRleHRhcmVhfGJ1dHRvbikkL2k7XG5cbmpRdWVyeS5mbi5leHRlbmQoe1xuXHRwcm9wOiBmdW5jdGlvbiggbmFtZSwgdmFsdWUgKSB7XG5cdFx0cmV0dXJuIGFjY2VzcyggdGhpcywgalF1ZXJ5LnByb3AsIG5hbWUsIHZhbHVlLCBhcmd1bWVudHMubGVuZ3RoID4gMSApO1xuXHR9LFxuXG5cdHJlbW92ZVByb3A6IGZ1bmN0aW9uKCBuYW1lICkge1xuXHRcdHJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oKSB7XG5cdFx0XHRkZWxldGUgdGhpc1sgalF1ZXJ5LnByb3BGaXhbIG5hbWUgXSB8fCBuYW1lIF07XG5cdFx0fSk7XG5cdH1cbn0pO1xuXG5qUXVlcnkuZXh0ZW5kKHtcblx0cHJvcEZpeDoge1xuXHRcdFwiZm9yXCI6IFwiaHRtbEZvclwiLFxuXHRcdFwiY2xhc3NcIjogXCJjbGFzc05hbWVcIlxuXHR9LFxuXG5cdHByb3A6IGZ1bmN0aW9uKCBlbGVtLCBuYW1lLCB2YWx1ZSApIHtcblx0XHR2YXIgcmV0LCBob29rcywgbm90eG1sLFxuXHRcdFx0blR5cGUgPSBlbGVtLm5vZGVUeXBlO1xuXG5cdFx0Ly8gRG9uJ3QgZ2V0L3NldCBwcm9wZXJ0aWVzIG9uIHRleHQsIGNvbW1lbnQgYW5kIGF0dHJpYnV0ZSBub2Rlc1xuXHRcdGlmICggIWVsZW0gfHwgblR5cGUgPT09IDMgfHwgblR5cGUgPT09IDggfHwgblR5cGUgPT09IDIgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0bm90eG1sID0gblR5cGUgIT09IDEgfHwgIWpRdWVyeS5pc1hNTERvYyggZWxlbSApO1xuXG5cdFx0aWYgKCBub3R4bWwgKSB7XG5cdFx0XHQvLyBGaXggbmFtZSBhbmQgYXR0YWNoIGhvb2tzXG5cdFx0XHRuYW1lID0galF1ZXJ5LnByb3BGaXhbIG5hbWUgXSB8fCBuYW1lO1xuXHRcdFx0aG9va3MgPSBqUXVlcnkucHJvcEhvb2tzWyBuYW1lIF07XG5cdFx0fVxuXG5cdFx0aWYgKCB2YWx1ZSAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0cmV0dXJuIGhvb2tzICYmIFwic2V0XCIgaW4gaG9va3MgJiYgKHJldCA9IGhvb2tzLnNldCggZWxlbSwgdmFsdWUsIG5hbWUgKSkgIT09IHVuZGVmaW5lZCA/XG5cdFx0XHRcdHJldCA6XG5cdFx0XHRcdCggZWxlbVsgbmFtZSBdID0gdmFsdWUgKTtcblxuXHRcdH0gZWxzZSB7XG5cdFx0XHRyZXR1cm4gaG9va3MgJiYgXCJnZXRcIiBpbiBob29rcyAmJiAocmV0ID0gaG9va3MuZ2V0KCBlbGVtLCBuYW1lICkpICE9PSBudWxsID9cblx0XHRcdFx0cmV0IDpcblx0XHRcdFx0ZWxlbVsgbmFtZSBdO1xuXHRcdH1cblx0fSxcblxuXHRwcm9wSG9va3M6IHtcblx0XHR0YWJJbmRleDoge1xuXHRcdFx0Z2V0OiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdFx0cmV0dXJuIGVsZW0uaGFzQXR0cmlidXRlKCBcInRhYmluZGV4XCIgKSB8fCByZm9jdXNhYmxlLnRlc3QoIGVsZW0ubm9kZU5hbWUgKSB8fCBlbGVtLmhyZWYgP1xuXHRcdFx0XHRcdGVsZW0udGFiSW5kZXggOlxuXHRcdFx0XHRcdC0xO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxufSk7XG5cbmlmICggIXN1cHBvcnQub3B0U2VsZWN0ZWQgKSB7XG5cdGpRdWVyeS5wcm9wSG9va3Muc2VsZWN0ZWQgPSB7XG5cdFx0Z2V0OiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdHZhciBwYXJlbnQgPSBlbGVtLnBhcmVudE5vZGU7XG5cdFx0XHRpZiAoIHBhcmVudCAmJiBwYXJlbnQucGFyZW50Tm9kZSApIHtcblx0XHRcdFx0cGFyZW50LnBhcmVudE5vZGUuc2VsZWN0ZWRJbmRleDtcblx0XHRcdH1cblx0XHRcdHJldHVybiBudWxsO1xuXHRcdH1cblx0fTtcbn1cblxualF1ZXJ5LmVhY2goW1xuXHRcInRhYkluZGV4XCIsXG5cdFwicmVhZE9ubHlcIixcblx0XCJtYXhMZW5ndGhcIixcblx0XCJjZWxsU3BhY2luZ1wiLFxuXHRcImNlbGxQYWRkaW5nXCIsXG5cdFwicm93U3BhblwiLFxuXHRcImNvbFNwYW5cIixcblx0XCJ1c2VNYXBcIixcblx0XCJmcmFtZUJvcmRlclwiLFxuXHRcImNvbnRlbnRFZGl0YWJsZVwiXG5dLCBmdW5jdGlvbigpIHtcblx0alF1ZXJ5LnByb3BGaXhbIHRoaXMudG9Mb3dlckNhc2UoKSBdID0gdGhpcztcbn0pO1xuXG5cblxuXG52YXIgcmNsYXNzID0gL1tcXHRcXHJcXG5cXGZdL2c7XG5cbmpRdWVyeS5mbi5leHRlbmQoe1xuXHRhZGRDbGFzczogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdHZhciBjbGFzc2VzLCBlbGVtLCBjdXIsIGNsYXp6LCBqLCBmaW5hbFZhbHVlLFxuXHRcdFx0cHJvY2VlZCA9IHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIiAmJiB2YWx1ZSxcblx0XHRcdGkgPSAwLFxuXHRcdFx0bGVuID0gdGhpcy5sZW5ndGg7XG5cblx0XHRpZiAoIGpRdWVyeS5pc0Z1bmN0aW9uKCB2YWx1ZSApICkge1xuXHRcdFx0cmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbiggaiApIHtcblx0XHRcdFx0alF1ZXJ5KCB0aGlzICkuYWRkQ2xhc3MoIHZhbHVlLmNhbGwoIHRoaXMsIGosIHRoaXMuY2xhc3NOYW1lICkgKTtcblx0XHRcdH0pO1xuXHRcdH1cblxuXHRcdGlmICggcHJvY2VlZCApIHtcblx0XHRcdC8vIFRoZSBkaXNqdW5jdGlvbiBoZXJlIGlzIGZvciBiZXR0ZXIgY29tcHJlc3NpYmlsaXR5IChzZWUgcmVtb3ZlQ2xhc3MpXG5cdFx0XHRjbGFzc2VzID0gKCB2YWx1ZSB8fCBcIlwiICkubWF0Y2goIHJub3R3aGl0ZSApIHx8IFtdO1xuXG5cdFx0XHRmb3IgKCA7IGkgPCBsZW47IGkrKyApIHtcblx0XHRcdFx0ZWxlbSA9IHRoaXNbIGkgXTtcblx0XHRcdFx0Y3VyID0gZWxlbS5ub2RlVHlwZSA9PT0gMSAmJiAoIGVsZW0uY2xhc3NOYW1lID9cblx0XHRcdFx0XHQoIFwiIFwiICsgZWxlbS5jbGFzc05hbWUgKyBcIiBcIiApLnJlcGxhY2UoIHJjbGFzcywgXCIgXCIgKSA6XG5cdFx0XHRcdFx0XCIgXCJcblx0XHRcdFx0KTtcblxuXHRcdFx0XHRpZiAoIGN1ciApIHtcblx0XHRcdFx0XHRqID0gMDtcblx0XHRcdFx0XHR3aGlsZSAoIChjbGF6eiA9IGNsYXNzZXNbaisrXSkgKSB7XG5cdFx0XHRcdFx0XHRpZiAoIGN1ci5pbmRleE9mKCBcIiBcIiArIGNsYXp6ICsgXCIgXCIgKSA8IDAgKSB7XG5cdFx0XHRcdFx0XHRcdGN1ciArPSBjbGF6eiArIFwiIFwiO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIG9ubHkgYXNzaWduIGlmIGRpZmZlcmVudCB0byBhdm9pZCB1bm5lZWRlZCByZW5kZXJpbmcuXG5cdFx0XHRcdFx0ZmluYWxWYWx1ZSA9IGpRdWVyeS50cmltKCBjdXIgKTtcblx0XHRcdFx0XHRpZiAoIGVsZW0uY2xhc3NOYW1lICE9PSBmaW5hbFZhbHVlICkge1xuXHRcdFx0XHRcdFx0ZWxlbS5jbGFzc05hbWUgPSBmaW5hbFZhbHVlO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdHJlbW92ZUNsYXNzOiBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0dmFyIGNsYXNzZXMsIGVsZW0sIGN1ciwgY2xhenosIGosIGZpbmFsVmFsdWUsXG5cdFx0XHRwcm9jZWVkID0gYXJndW1lbnRzLmxlbmd0aCA9PT0gMCB8fCB0eXBlb2YgdmFsdWUgPT09IFwic3RyaW5nXCIgJiYgdmFsdWUsXG5cdFx0XHRpID0gMCxcblx0XHRcdGxlbiA9IHRoaXMubGVuZ3RoO1xuXG5cdFx0aWYgKCBqUXVlcnkuaXNGdW5jdGlvbiggdmFsdWUgKSApIHtcblx0XHRcdHJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oIGogKSB7XG5cdFx0XHRcdGpRdWVyeSggdGhpcyApLnJlbW92ZUNsYXNzKCB2YWx1ZS5jYWxsKCB0aGlzLCBqLCB0aGlzLmNsYXNzTmFtZSApICk7XG5cdFx0XHR9KTtcblx0XHR9XG5cdFx0aWYgKCBwcm9jZWVkICkge1xuXHRcdFx0Y2xhc3NlcyA9ICggdmFsdWUgfHwgXCJcIiApLm1hdGNoKCBybm90d2hpdGUgKSB8fCBbXTtcblxuXHRcdFx0Zm9yICggOyBpIDwgbGVuOyBpKysgKSB7XG5cdFx0XHRcdGVsZW0gPSB0aGlzWyBpIF07XG5cdFx0XHRcdC8vIFRoaXMgZXhwcmVzc2lvbiBpcyBoZXJlIGZvciBiZXR0ZXIgY29tcHJlc3NpYmlsaXR5IChzZWUgYWRkQ2xhc3MpXG5cdFx0XHRcdGN1ciA9IGVsZW0ubm9kZVR5cGUgPT09IDEgJiYgKCBlbGVtLmNsYXNzTmFtZSA/XG5cdFx0XHRcdFx0KCBcIiBcIiArIGVsZW0uY2xhc3NOYW1lICsgXCIgXCIgKS5yZXBsYWNlKCByY2xhc3MsIFwiIFwiICkgOlxuXHRcdFx0XHRcdFwiXCJcblx0XHRcdFx0KTtcblxuXHRcdFx0XHRpZiAoIGN1ciApIHtcblx0XHRcdFx0XHRqID0gMDtcblx0XHRcdFx0XHR3aGlsZSAoIChjbGF6eiA9IGNsYXNzZXNbaisrXSkgKSB7XG5cdFx0XHRcdFx0XHQvLyBSZW1vdmUgKmFsbCogaW5zdGFuY2VzXG5cdFx0XHRcdFx0XHR3aGlsZSAoIGN1ci5pbmRleE9mKCBcIiBcIiArIGNsYXp6ICsgXCIgXCIgKSA+PSAwICkge1xuXHRcdFx0XHRcdFx0XHRjdXIgPSBjdXIucmVwbGFjZSggXCIgXCIgKyBjbGF6eiArIFwiIFwiLCBcIiBcIiApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIE9ubHkgYXNzaWduIGlmIGRpZmZlcmVudCB0byBhdm9pZCB1bm5lZWRlZCByZW5kZXJpbmcuXG5cdFx0XHRcdFx0ZmluYWxWYWx1ZSA9IHZhbHVlID8galF1ZXJ5LnRyaW0oIGN1ciApIDogXCJcIjtcblx0XHRcdFx0XHRpZiAoIGVsZW0uY2xhc3NOYW1lICE9PSBmaW5hbFZhbHVlICkge1xuXHRcdFx0XHRcdFx0ZWxlbS5jbGFzc05hbWUgPSBmaW5hbFZhbHVlO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdHRvZ2dsZUNsYXNzOiBmdW5jdGlvbiggdmFsdWUsIHN0YXRlVmFsICkge1xuXHRcdHZhciB0eXBlID0gdHlwZW9mIHZhbHVlO1xuXG5cdFx0aWYgKCB0eXBlb2Ygc3RhdGVWYWwgPT09IFwiYm9vbGVhblwiICYmIHR5cGUgPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRyZXR1cm4gc3RhdGVWYWwgPyB0aGlzLmFkZENsYXNzKCB2YWx1ZSApIDogdGhpcy5yZW1vdmVDbGFzcyggdmFsdWUgKTtcblx0XHR9XG5cblx0XHRpZiAoIGpRdWVyeS5pc0Z1bmN0aW9uKCB2YWx1ZSApICkge1xuXHRcdFx0cmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbiggaSApIHtcblx0XHRcdFx0alF1ZXJ5KCB0aGlzICkudG9nZ2xlQ2xhc3MoIHZhbHVlLmNhbGwodGhpcywgaSwgdGhpcy5jbGFzc05hbWUsIHN0YXRlVmFsKSwgc3RhdGVWYWwgKTtcblx0XHRcdH0pO1xuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oKSB7XG5cdFx0XHRpZiAoIHR5cGUgPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRcdC8vIFRvZ2dsZSBpbmRpdmlkdWFsIGNsYXNzIG5hbWVzXG5cdFx0XHRcdHZhciBjbGFzc05hbWUsXG5cdFx0XHRcdFx0aSA9IDAsXG5cdFx0XHRcdFx0c2VsZiA9IGpRdWVyeSggdGhpcyApLFxuXHRcdFx0XHRcdGNsYXNzTmFtZXMgPSB2YWx1ZS5tYXRjaCggcm5vdHdoaXRlICkgfHwgW107XG5cblx0XHRcdFx0d2hpbGUgKCAoY2xhc3NOYW1lID0gY2xhc3NOYW1lc1sgaSsrIF0pICkge1xuXHRcdFx0XHRcdC8vIENoZWNrIGVhY2ggY2xhc3NOYW1lIGdpdmVuLCBzcGFjZSBzZXBhcmF0ZWQgbGlzdFxuXHRcdFx0XHRcdGlmICggc2VsZi5oYXNDbGFzcyggY2xhc3NOYW1lICkgKSB7XG5cdFx0XHRcdFx0XHRzZWxmLnJlbW92ZUNsYXNzKCBjbGFzc05hbWUgKTtcblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0c2VsZi5hZGRDbGFzcyggY2xhc3NOYW1lICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cblx0XHRcdC8vIFRvZ2dsZSB3aG9sZSBjbGFzcyBuYW1lXG5cdFx0XHR9IGVsc2UgaWYgKCB0eXBlID09PSBzdHJ1bmRlZmluZWQgfHwgdHlwZSA9PT0gXCJib29sZWFuXCIgKSB7XG5cdFx0XHRcdGlmICggdGhpcy5jbGFzc05hbWUgKSB7XG5cdFx0XHRcdFx0Ly8gc3RvcmUgY2xhc3NOYW1lIGlmIHNldFxuXHRcdFx0XHRcdGRhdGFfcHJpdi5zZXQoIHRoaXMsIFwiX19jbGFzc05hbWVfX1wiLCB0aGlzLmNsYXNzTmFtZSApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gSWYgdGhlIGVsZW1lbnQgaGFzIGEgY2xhc3MgbmFtZSBvciBpZiB3ZSdyZSBwYXNzZWQgYGZhbHNlYCxcblx0XHRcdFx0Ly8gdGhlbiByZW1vdmUgdGhlIHdob2xlIGNsYXNzbmFtZSAoaWYgdGhlcmUgd2FzIG9uZSwgdGhlIGFib3ZlIHNhdmVkIGl0KS5cblx0XHRcdFx0Ly8gT3RoZXJ3aXNlIGJyaW5nIGJhY2sgd2hhdGV2ZXIgd2FzIHByZXZpb3VzbHkgc2F2ZWQgKGlmIGFueXRoaW5nKSxcblx0XHRcdFx0Ly8gZmFsbGluZyBiYWNrIHRvIHRoZSBlbXB0eSBzdHJpbmcgaWYgbm90aGluZyB3YXMgc3RvcmVkLlxuXHRcdFx0XHR0aGlzLmNsYXNzTmFtZSA9IHRoaXMuY2xhc3NOYW1lIHx8IHZhbHVlID09PSBmYWxzZSA/IFwiXCIgOiBkYXRhX3ByaXYuZ2V0KCB0aGlzLCBcIl9fY2xhc3NOYW1lX19cIiApIHx8IFwiXCI7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH0sXG5cblx0aGFzQ2xhc3M6IGZ1bmN0aW9uKCBzZWxlY3RvciApIHtcblx0XHR2YXIgY2xhc3NOYW1lID0gXCIgXCIgKyBzZWxlY3RvciArIFwiIFwiLFxuXHRcdFx0aSA9IDAsXG5cdFx0XHRsID0gdGhpcy5sZW5ndGg7XG5cdFx0Zm9yICggOyBpIDwgbDsgaSsrICkge1xuXHRcdFx0aWYgKCB0aGlzW2ldLm5vZGVUeXBlID09PSAxICYmIChcIiBcIiArIHRoaXNbaV0uY2xhc3NOYW1lICsgXCIgXCIpLnJlcGxhY2UocmNsYXNzLCBcIiBcIikuaW5kZXhPZiggY2xhc3NOYW1lICkgPj0gMCApIHtcblx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9XG59KTtcblxuXG5cblxudmFyIHJyZXR1cm4gPSAvXFxyL2c7XG5cbmpRdWVyeS5mbi5leHRlbmQoe1xuXHR2YWw6IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHR2YXIgaG9va3MsIHJldCwgaXNGdW5jdGlvbixcblx0XHRcdGVsZW0gPSB0aGlzWzBdO1xuXG5cdFx0aWYgKCAhYXJndW1lbnRzLmxlbmd0aCApIHtcblx0XHRcdGlmICggZWxlbSApIHtcblx0XHRcdFx0aG9va3MgPSBqUXVlcnkudmFsSG9va3NbIGVsZW0udHlwZSBdIHx8IGpRdWVyeS52YWxIb29rc1sgZWxlbS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpIF07XG5cblx0XHRcdFx0aWYgKCBob29rcyAmJiBcImdldFwiIGluIGhvb2tzICYmIChyZXQgPSBob29rcy5nZXQoIGVsZW0sIFwidmFsdWVcIiApKSAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRcdHJldHVybiByZXQ7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRyZXQgPSBlbGVtLnZhbHVlO1xuXG5cdFx0XHRcdHJldHVybiB0eXBlb2YgcmV0ID09PSBcInN0cmluZ1wiID9cblx0XHRcdFx0XHQvLyBIYW5kbGUgbW9zdCBjb21tb24gc3RyaW5nIGNhc2VzXG5cdFx0XHRcdFx0cmV0LnJlcGxhY2UocnJldHVybiwgXCJcIikgOlxuXHRcdFx0XHRcdC8vIEhhbmRsZSBjYXNlcyB3aGVyZSB2YWx1ZSBpcyBudWxsL3VuZGVmIG9yIG51bWJlclxuXHRcdFx0XHRcdHJldCA9PSBudWxsID8gXCJcIiA6IHJldDtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlzRnVuY3Rpb24gPSBqUXVlcnkuaXNGdW5jdGlvbiggdmFsdWUgKTtcblxuXHRcdHJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oIGkgKSB7XG5cdFx0XHR2YXIgdmFsO1xuXG5cdFx0XHRpZiAoIHRoaXMubm9kZVR5cGUgIT09IDEgKSB7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCBpc0Z1bmN0aW9uICkge1xuXHRcdFx0XHR2YWwgPSB2YWx1ZS5jYWxsKCB0aGlzLCBpLCBqUXVlcnkoIHRoaXMgKS52YWwoKSApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dmFsID0gdmFsdWU7XG5cdFx0XHR9XG5cblx0XHRcdC8vIFRyZWF0IG51bGwvdW5kZWZpbmVkIGFzIFwiXCI7IGNvbnZlcnQgbnVtYmVycyB0byBzdHJpbmdcblx0XHRcdGlmICggdmFsID09IG51bGwgKSB7XG5cdFx0XHRcdHZhbCA9IFwiXCI7XG5cblx0XHRcdH0gZWxzZSBpZiAoIHR5cGVvZiB2YWwgPT09IFwibnVtYmVyXCIgKSB7XG5cdFx0XHRcdHZhbCArPSBcIlwiO1xuXG5cdFx0XHR9IGVsc2UgaWYgKCBqUXVlcnkuaXNBcnJheSggdmFsICkgKSB7XG5cdFx0XHRcdHZhbCA9IGpRdWVyeS5tYXAoIHZhbCwgZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdFx0XHRcdHJldHVybiB2YWx1ZSA9PSBudWxsID8gXCJcIiA6IHZhbHVlICsgXCJcIjtcblx0XHRcdFx0fSk7XG5cdFx0XHR9XG5cblx0XHRcdGhvb2tzID0galF1ZXJ5LnZhbEhvb2tzWyB0aGlzLnR5cGUgXSB8fCBqUXVlcnkudmFsSG9va3NbIHRoaXMubm9kZU5hbWUudG9Mb3dlckNhc2UoKSBdO1xuXG5cdFx0XHQvLyBJZiBzZXQgcmV0dXJucyB1bmRlZmluZWQsIGZhbGwgYmFjayB0byBub3JtYWwgc2V0dGluZ1xuXHRcdFx0aWYgKCAhaG9va3MgfHwgIShcInNldFwiIGluIGhvb2tzKSB8fCBob29rcy5zZXQoIHRoaXMsIHZhbCwgXCJ2YWx1ZVwiICkgPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0dGhpcy52YWx1ZSA9IHZhbDtcblx0XHRcdH1cblx0XHR9KTtcblx0fVxufSk7XG5cbmpRdWVyeS5leHRlbmQoe1xuXHR2YWxIb29rczoge1xuXHRcdG9wdGlvbjoge1xuXHRcdFx0Z2V0OiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdFx0dmFyIHZhbCA9IGpRdWVyeS5maW5kLmF0dHIoIGVsZW0sIFwidmFsdWVcIiApO1xuXHRcdFx0XHRyZXR1cm4gdmFsICE9IG51bGwgP1xuXHRcdFx0XHRcdHZhbCA6XG5cdFx0XHRcdFx0Ly8gU3VwcG9ydDogSUUxMC0xMStcblx0XHRcdFx0XHQvLyBvcHRpb24udGV4dCB0aHJvd3MgZXhjZXB0aW9ucyAoIzE0Njg2LCAjMTQ4NTgpXG5cdFx0XHRcdFx0alF1ZXJ5LnRyaW0oIGpRdWVyeS50ZXh0KCBlbGVtICkgKTtcblx0XHRcdH1cblx0XHR9LFxuXHRcdHNlbGVjdDoge1xuXHRcdFx0Z2V0OiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdFx0dmFyIHZhbHVlLCBvcHRpb24sXG5cdFx0XHRcdFx0b3B0aW9ucyA9IGVsZW0ub3B0aW9ucyxcblx0XHRcdFx0XHRpbmRleCA9IGVsZW0uc2VsZWN0ZWRJbmRleCxcblx0XHRcdFx0XHRvbmUgPSBlbGVtLnR5cGUgPT09IFwic2VsZWN0LW9uZVwiIHx8IGluZGV4IDwgMCxcblx0XHRcdFx0XHR2YWx1ZXMgPSBvbmUgPyBudWxsIDogW10sXG5cdFx0XHRcdFx0bWF4ID0gb25lID8gaW5kZXggKyAxIDogb3B0aW9ucy5sZW5ndGgsXG5cdFx0XHRcdFx0aSA9IGluZGV4IDwgMCA/XG5cdFx0XHRcdFx0XHRtYXggOlxuXHRcdFx0XHRcdFx0b25lID8gaW5kZXggOiAwO1xuXG5cdFx0XHRcdC8vIExvb3AgdGhyb3VnaCBhbGwgdGhlIHNlbGVjdGVkIG9wdGlvbnNcblx0XHRcdFx0Zm9yICggOyBpIDwgbWF4OyBpKysgKSB7XG5cdFx0XHRcdFx0b3B0aW9uID0gb3B0aW9uc1sgaSBdO1xuXG5cdFx0XHRcdFx0Ly8gSUU2LTkgZG9lc24ndCB1cGRhdGUgc2VsZWN0ZWQgYWZ0ZXIgZm9ybSByZXNldCAoIzI1NTEpXG5cdFx0XHRcdFx0aWYgKCAoIG9wdGlvbi5zZWxlY3RlZCB8fCBpID09PSBpbmRleCApICYmXG5cdFx0XHRcdFx0XHRcdC8vIERvbid0IHJldHVybiBvcHRpb25zIHRoYXQgYXJlIGRpc2FibGVkIG9yIGluIGEgZGlzYWJsZWQgb3B0Z3JvdXBcblx0XHRcdFx0XHRcdFx0KCBzdXBwb3J0Lm9wdERpc2FibGVkID8gIW9wdGlvbi5kaXNhYmxlZCA6IG9wdGlvbi5nZXRBdHRyaWJ1dGUoIFwiZGlzYWJsZWRcIiApID09PSBudWxsICkgJiZcblx0XHRcdFx0XHRcdFx0KCAhb3B0aW9uLnBhcmVudE5vZGUuZGlzYWJsZWQgfHwgIWpRdWVyeS5ub2RlTmFtZSggb3B0aW9uLnBhcmVudE5vZGUsIFwib3B0Z3JvdXBcIiApICkgKSB7XG5cblx0XHRcdFx0XHRcdC8vIEdldCB0aGUgc3BlY2lmaWMgdmFsdWUgZm9yIHRoZSBvcHRpb25cblx0XHRcdFx0XHRcdHZhbHVlID0galF1ZXJ5KCBvcHRpb24gKS52YWwoKTtcblxuXHRcdFx0XHRcdFx0Ly8gV2UgZG9uJ3QgbmVlZCBhbiBhcnJheSBmb3Igb25lIHNlbGVjdHNcblx0XHRcdFx0XHRcdGlmICggb25lICkge1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4gdmFsdWU7XG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdC8vIE11bHRpLVNlbGVjdHMgcmV0dXJuIGFuIGFycmF5XG5cdFx0XHRcdFx0XHR2YWx1ZXMucHVzaCggdmFsdWUgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRyZXR1cm4gdmFsdWVzO1xuXHRcdFx0fSxcblxuXHRcdFx0c2V0OiBmdW5jdGlvbiggZWxlbSwgdmFsdWUgKSB7XG5cdFx0XHRcdHZhciBvcHRpb25TZXQsIG9wdGlvbixcblx0XHRcdFx0XHRvcHRpb25zID0gZWxlbS5vcHRpb25zLFxuXHRcdFx0XHRcdHZhbHVlcyA9IGpRdWVyeS5tYWtlQXJyYXkoIHZhbHVlICksXG5cdFx0XHRcdFx0aSA9IG9wdGlvbnMubGVuZ3RoO1xuXG5cdFx0XHRcdHdoaWxlICggaS0tICkge1xuXHRcdFx0XHRcdG9wdGlvbiA9IG9wdGlvbnNbIGkgXTtcblx0XHRcdFx0XHRpZiAoIChvcHRpb24uc2VsZWN0ZWQgPSBqUXVlcnkuaW5BcnJheSggb3B0aW9uLnZhbHVlLCB2YWx1ZXMgKSA+PSAwKSApIHtcblx0XHRcdFx0XHRcdG9wdGlvblNldCA9IHRydWU7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gRm9yY2UgYnJvd3NlcnMgdG8gYmVoYXZlIGNvbnNpc3RlbnRseSB3aGVuIG5vbi1tYXRjaGluZyB2YWx1ZSBpcyBzZXRcblx0XHRcdFx0aWYgKCAhb3B0aW9uU2V0ICkge1xuXHRcdFx0XHRcdGVsZW0uc2VsZWN0ZWRJbmRleCA9IC0xO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiB2YWx1ZXM7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG59KTtcblxuLy8gUmFkaW9zIGFuZCBjaGVja2JveGVzIGdldHRlci9zZXR0ZXJcbmpRdWVyeS5lYWNoKFsgXCJyYWRpb1wiLCBcImNoZWNrYm94XCIgXSwgZnVuY3Rpb24oKSB7XG5cdGpRdWVyeS52YWxIb29rc1sgdGhpcyBdID0ge1xuXHRcdHNldDogZnVuY3Rpb24oIGVsZW0sIHZhbHVlICkge1xuXHRcdFx0aWYgKCBqUXVlcnkuaXNBcnJheSggdmFsdWUgKSApIHtcblx0XHRcdFx0cmV0dXJuICggZWxlbS5jaGVja2VkID0galF1ZXJ5LmluQXJyYXkoIGpRdWVyeShlbGVtKS52YWwoKSwgdmFsdWUgKSA+PSAwICk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9O1xuXHRpZiAoICFzdXBwb3J0LmNoZWNrT24gKSB7XG5cdFx0alF1ZXJ5LnZhbEhvb2tzWyB0aGlzIF0uZ2V0ID0gZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRyZXR1cm4gZWxlbS5nZXRBdHRyaWJ1dGUoXCJ2YWx1ZVwiKSA9PT0gbnVsbCA/IFwib25cIiA6IGVsZW0udmFsdWU7XG5cdFx0fTtcblx0fVxufSk7XG5cblxuXG5cbi8vIFJldHVybiBqUXVlcnkgZm9yIGF0dHJpYnV0ZXMtb25seSBpbmNsdXNpb25cblxuXG5qUXVlcnkuZWFjaCggKFwiYmx1ciBmb2N1cyBmb2N1c2luIGZvY3Vzb3V0IGxvYWQgcmVzaXplIHNjcm9sbCB1bmxvYWQgY2xpY2sgZGJsY2xpY2sgXCIgK1xuXHRcIm1vdXNlZG93biBtb3VzZXVwIG1vdXNlbW92ZSBtb3VzZW92ZXIgbW91c2VvdXQgbW91c2VlbnRlciBtb3VzZWxlYXZlIFwiICtcblx0XCJjaGFuZ2Ugc2VsZWN0IHN1Ym1pdCBrZXlkb3duIGtleXByZXNzIGtleXVwIGVycm9yIGNvbnRleHRtZW51XCIpLnNwbGl0KFwiIFwiKSwgZnVuY3Rpb24oIGksIG5hbWUgKSB7XG5cblx0Ly8gSGFuZGxlIGV2ZW50IGJpbmRpbmdcblx0alF1ZXJ5LmZuWyBuYW1lIF0gPSBmdW5jdGlvbiggZGF0YSwgZm4gKSB7XG5cdFx0cmV0dXJuIGFyZ3VtZW50cy5sZW5ndGggPiAwID9cblx0XHRcdHRoaXMub24oIG5hbWUsIG51bGwsIGRhdGEsIGZuICkgOlxuXHRcdFx0dGhpcy50cmlnZ2VyKCBuYW1lICk7XG5cdH07XG59KTtcblxualF1ZXJ5LmZuLmV4dGVuZCh7XG5cdGhvdmVyOiBmdW5jdGlvbiggZm5PdmVyLCBmbk91dCApIHtcblx0XHRyZXR1cm4gdGhpcy5tb3VzZWVudGVyKCBmbk92ZXIgKS5tb3VzZWxlYXZlKCBmbk91dCB8fCBmbk92ZXIgKTtcblx0fSxcblxuXHRiaW5kOiBmdW5jdGlvbiggdHlwZXMsIGRhdGEsIGZuICkge1xuXHRcdHJldHVybiB0aGlzLm9uKCB0eXBlcywgbnVsbCwgZGF0YSwgZm4gKTtcblx0fSxcblx0dW5iaW5kOiBmdW5jdGlvbiggdHlwZXMsIGZuICkge1xuXHRcdHJldHVybiB0aGlzLm9mZiggdHlwZXMsIG51bGwsIGZuICk7XG5cdH0sXG5cblx0ZGVsZWdhdGU6IGZ1bmN0aW9uKCBzZWxlY3RvciwgdHlwZXMsIGRhdGEsIGZuICkge1xuXHRcdHJldHVybiB0aGlzLm9uKCB0eXBlcywgc2VsZWN0b3IsIGRhdGEsIGZuICk7XG5cdH0sXG5cdHVuZGVsZWdhdGU6IGZ1bmN0aW9uKCBzZWxlY3RvciwgdHlwZXMsIGZuICkge1xuXHRcdC8vICggbmFtZXNwYWNlICkgb3IgKCBzZWxlY3RvciwgdHlwZXMgWywgZm5dIClcblx0XHRyZXR1cm4gYXJndW1lbnRzLmxlbmd0aCA9PT0gMSA/IHRoaXMub2ZmKCBzZWxlY3RvciwgXCIqKlwiICkgOiB0aGlzLm9mZiggdHlwZXMsIHNlbGVjdG9yIHx8IFwiKipcIiwgZm4gKTtcblx0fVxufSk7XG5cblxudmFyIG5vbmNlID0galF1ZXJ5Lm5vdygpO1xuXG52YXIgcnF1ZXJ5ID0gKC9cXD8vKTtcblxuXG5cbi8vIFN1cHBvcnQ6IEFuZHJvaWQgMi4zXG4vLyBXb3JrYXJvdW5kIGZhaWx1cmUgdG8gc3RyaW5nLWNhc3QgbnVsbCBpbnB1dFxualF1ZXJ5LnBhcnNlSlNPTiA9IGZ1bmN0aW9uKCBkYXRhICkge1xuXHRyZXR1cm4gSlNPTi5wYXJzZSggZGF0YSArIFwiXCIgKTtcbn07XG5cblxuLy8gQ3Jvc3MtYnJvd3NlciB4bWwgcGFyc2luZ1xualF1ZXJ5LnBhcnNlWE1MID0gZnVuY3Rpb24oIGRhdGEgKSB7XG5cdHZhciB4bWwsIHRtcDtcblx0aWYgKCAhZGF0YSB8fCB0eXBlb2YgZGF0YSAhPT0gXCJzdHJpbmdcIiApIHtcblx0XHRyZXR1cm4gbnVsbDtcblx0fVxuXG5cdC8vIFN1cHBvcnQ6IElFOVxuXHR0cnkge1xuXHRcdHRtcCA9IG5ldyBET01QYXJzZXIoKTtcblx0XHR4bWwgPSB0bXAucGFyc2VGcm9tU3RyaW5nKCBkYXRhLCBcInRleHQveG1sXCIgKTtcblx0fSBjYXRjaCAoIGUgKSB7XG5cdFx0eG1sID0gdW5kZWZpbmVkO1xuXHR9XG5cblx0aWYgKCAheG1sIHx8IHhtbC5nZXRFbGVtZW50c0J5VGFnTmFtZSggXCJwYXJzZXJlcnJvclwiICkubGVuZ3RoICkge1xuXHRcdGpRdWVyeS5lcnJvciggXCJJbnZhbGlkIFhNTDogXCIgKyBkYXRhICk7XG5cdH1cblx0cmV0dXJuIHhtbDtcbn07XG5cblxudmFyXG5cdHJoYXNoID0gLyMuKiQvLFxuXHRydHMgPSAvKFs/Jl0pXz1bXiZdKi8sXG5cdHJoZWFkZXJzID0gL14oLio/KTpbIFxcdF0qKFteXFxyXFxuXSopJC9tZyxcblx0Ly8gIzc2NTMsICM4MTI1LCAjODE1MjogbG9jYWwgcHJvdG9jb2wgZGV0ZWN0aW9uXG5cdHJsb2NhbFByb3RvY29sID0gL14oPzphYm91dHxhcHB8YXBwLXN0b3JhZ2V8ListZXh0ZW5zaW9ufGZpbGV8cmVzfHdpZGdldCk6JC8sXG5cdHJub0NvbnRlbnQgPSAvXig/OkdFVHxIRUFEKSQvLFxuXHRycHJvdG9jb2wgPSAvXlxcL1xcLy8sXG5cdHJ1cmwgPSAvXihbXFx3ListXSs6KSg/OlxcL1xcLyg/OlteXFwvPyNdKkB8KShbXlxcLz8jOl0qKSg/OjooXFxkKyl8KXwpLyxcblxuXHQvKiBQcmVmaWx0ZXJzXG5cdCAqIDEpIFRoZXkgYXJlIHVzZWZ1bCB0byBpbnRyb2R1Y2UgY3VzdG9tIGRhdGFUeXBlcyAoc2VlIGFqYXgvanNvbnAuanMgZm9yIGFuIGV4YW1wbGUpXG5cdCAqIDIpIFRoZXNlIGFyZSBjYWxsZWQ6XG5cdCAqICAgIC0gQkVGT1JFIGFza2luZyBmb3IgYSB0cmFuc3BvcnRcblx0ICogICAgLSBBRlRFUiBwYXJhbSBzZXJpYWxpemF0aW9uIChzLmRhdGEgaXMgYSBzdHJpbmcgaWYgcy5wcm9jZXNzRGF0YSBpcyB0cnVlKVxuXHQgKiAzKSBrZXkgaXMgdGhlIGRhdGFUeXBlXG5cdCAqIDQpIHRoZSBjYXRjaGFsbCBzeW1ib2wgXCIqXCIgY2FuIGJlIHVzZWRcblx0ICogNSkgZXhlY3V0aW9uIHdpbGwgc3RhcnQgd2l0aCB0cmFuc3BvcnQgZGF0YVR5cGUgYW5kIFRIRU4gY29udGludWUgZG93biB0byBcIipcIiBpZiBuZWVkZWRcblx0ICovXG5cdHByZWZpbHRlcnMgPSB7fSxcblxuXHQvKiBUcmFuc3BvcnRzIGJpbmRpbmdzXG5cdCAqIDEpIGtleSBpcyB0aGUgZGF0YVR5cGVcblx0ICogMikgdGhlIGNhdGNoYWxsIHN5bWJvbCBcIipcIiBjYW4gYmUgdXNlZFxuXHQgKiAzKSBzZWxlY3Rpb24gd2lsbCBzdGFydCB3aXRoIHRyYW5zcG9ydCBkYXRhVHlwZSBhbmQgVEhFTiBnbyB0byBcIipcIiBpZiBuZWVkZWRcblx0ICovXG5cdHRyYW5zcG9ydHMgPSB7fSxcblxuXHQvLyBBdm9pZCBjb21tZW50LXByb2xvZyBjaGFyIHNlcXVlbmNlICgjMTAwOTgpOyBtdXN0IGFwcGVhc2UgbGludCBhbmQgZXZhZGUgY29tcHJlc3Npb25cblx0YWxsVHlwZXMgPSBcIiovXCIuY29uY2F0KCBcIipcIiApLFxuXG5cdC8vIERvY3VtZW50IGxvY2F0aW9uXG5cdGFqYXhMb2NhdGlvbiA9IHdpbmRvdy5sb2NhdGlvbi5ocmVmLFxuXG5cdC8vIFNlZ21lbnQgbG9jYXRpb24gaW50byBwYXJ0c1xuXHRhamF4TG9jUGFydHMgPSBydXJsLmV4ZWMoIGFqYXhMb2NhdGlvbi50b0xvd2VyQ2FzZSgpICkgfHwgW107XG5cbi8vIEJhc2UgXCJjb25zdHJ1Y3RvclwiIGZvciBqUXVlcnkuYWpheFByZWZpbHRlciBhbmQgalF1ZXJ5LmFqYXhUcmFuc3BvcnRcbmZ1bmN0aW9uIGFkZFRvUHJlZmlsdGVyc09yVHJhbnNwb3J0cyggc3RydWN0dXJlICkge1xuXG5cdC8vIGRhdGFUeXBlRXhwcmVzc2lvbiBpcyBvcHRpb25hbCBhbmQgZGVmYXVsdHMgdG8gXCIqXCJcblx0cmV0dXJuIGZ1bmN0aW9uKCBkYXRhVHlwZUV4cHJlc3Npb24sIGZ1bmMgKSB7XG5cblx0XHRpZiAoIHR5cGVvZiBkYXRhVHlwZUV4cHJlc3Npb24gIT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRmdW5jID0gZGF0YVR5cGVFeHByZXNzaW9uO1xuXHRcdFx0ZGF0YVR5cGVFeHByZXNzaW9uID0gXCIqXCI7XG5cdFx0fVxuXG5cdFx0dmFyIGRhdGFUeXBlLFxuXHRcdFx0aSA9IDAsXG5cdFx0XHRkYXRhVHlwZXMgPSBkYXRhVHlwZUV4cHJlc3Npb24udG9Mb3dlckNhc2UoKS5tYXRjaCggcm5vdHdoaXRlICkgfHwgW107XG5cblx0XHRpZiAoIGpRdWVyeS5pc0Z1bmN0aW9uKCBmdW5jICkgKSB7XG5cdFx0XHQvLyBGb3IgZWFjaCBkYXRhVHlwZSBpbiB0aGUgZGF0YVR5cGVFeHByZXNzaW9uXG5cdFx0XHR3aGlsZSAoIChkYXRhVHlwZSA9IGRhdGFUeXBlc1tpKytdKSApIHtcblx0XHRcdFx0Ly8gUHJlcGVuZCBpZiByZXF1ZXN0ZWRcblx0XHRcdFx0aWYgKCBkYXRhVHlwZVswXSA9PT0gXCIrXCIgKSB7XG5cdFx0XHRcdFx0ZGF0YVR5cGUgPSBkYXRhVHlwZS5zbGljZSggMSApIHx8IFwiKlwiO1xuXHRcdFx0XHRcdChzdHJ1Y3R1cmVbIGRhdGFUeXBlIF0gPSBzdHJ1Y3R1cmVbIGRhdGFUeXBlIF0gfHwgW10pLnVuc2hpZnQoIGZ1bmMgKTtcblxuXHRcdFx0XHQvLyBPdGhlcndpc2UgYXBwZW5kXG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0KHN0cnVjdHVyZVsgZGF0YVR5cGUgXSA9IHN0cnVjdHVyZVsgZGF0YVR5cGUgXSB8fCBbXSkucHVzaCggZnVuYyApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9O1xufVxuXG4vLyBCYXNlIGluc3BlY3Rpb24gZnVuY3Rpb24gZm9yIHByZWZpbHRlcnMgYW5kIHRyYW5zcG9ydHNcbmZ1bmN0aW9uIGluc3BlY3RQcmVmaWx0ZXJzT3JUcmFuc3BvcnRzKCBzdHJ1Y3R1cmUsIG9wdGlvbnMsIG9yaWdpbmFsT3B0aW9ucywganFYSFIgKSB7XG5cblx0dmFyIGluc3BlY3RlZCA9IHt9LFxuXHRcdHNlZWtpbmdUcmFuc3BvcnQgPSAoIHN0cnVjdHVyZSA9PT0gdHJhbnNwb3J0cyApO1xuXG5cdGZ1bmN0aW9uIGluc3BlY3QoIGRhdGFUeXBlICkge1xuXHRcdHZhciBzZWxlY3RlZDtcblx0XHRpbnNwZWN0ZWRbIGRhdGFUeXBlIF0gPSB0cnVlO1xuXHRcdGpRdWVyeS5lYWNoKCBzdHJ1Y3R1cmVbIGRhdGFUeXBlIF0gfHwgW10sIGZ1bmN0aW9uKCBfLCBwcmVmaWx0ZXJPckZhY3RvcnkgKSB7XG5cdFx0XHR2YXIgZGF0YVR5cGVPclRyYW5zcG9ydCA9IHByZWZpbHRlck9yRmFjdG9yeSggb3B0aW9ucywgb3JpZ2luYWxPcHRpb25zLCBqcVhIUiApO1xuXHRcdFx0aWYgKCB0eXBlb2YgZGF0YVR5cGVPclRyYW5zcG9ydCA9PT0gXCJzdHJpbmdcIiAmJiAhc2Vla2luZ1RyYW5zcG9ydCAmJiAhaW5zcGVjdGVkWyBkYXRhVHlwZU9yVHJhbnNwb3J0IF0gKSB7XG5cdFx0XHRcdG9wdGlvbnMuZGF0YVR5cGVzLnVuc2hpZnQoIGRhdGFUeXBlT3JUcmFuc3BvcnQgKTtcblx0XHRcdFx0aW5zcGVjdCggZGF0YVR5cGVPclRyYW5zcG9ydCApO1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9IGVsc2UgaWYgKCBzZWVraW5nVHJhbnNwb3J0ICkge1xuXHRcdFx0XHRyZXR1cm4gISggc2VsZWN0ZWQgPSBkYXRhVHlwZU9yVHJhbnNwb3J0ICk7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdFx0cmV0dXJuIHNlbGVjdGVkO1xuXHR9XG5cblx0cmV0dXJuIGluc3BlY3QoIG9wdGlvbnMuZGF0YVR5cGVzWyAwIF0gKSB8fCAhaW5zcGVjdGVkWyBcIipcIiBdICYmIGluc3BlY3QoIFwiKlwiICk7XG59XG5cbi8vIEEgc3BlY2lhbCBleHRlbmQgZm9yIGFqYXggb3B0aW9uc1xuLy8gdGhhdCB0YWtlcyBcImZsYXRcIiBvcHRpb25zIChub3QgdG8gYmUgZGVlcCBleHRlbmRlZClcbi8vIEZpeGVzICM5ODg3XG5mdW5jdGlvbiBhamF4RXh0ZW5kKCB0YXJnZXQsIHNyYyApIHtcblx0dmFyIGtleSwgZGVlcCxcblx0XHRmbGF0T3B0aW9ucyA9IGpRdWVyeS5hamF4U2V0dGluZ3MuZmxhdE9wdGlvbnMgfHwge307XG5cblx0Zm9yICgga2V5IGluIHNyYyApIHtcblx0XHRpZiAoIHNyY1sga2V5IF0gIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdCggZmxhdE9wdGlvbnNbIGtleSBdID8gdGFyZ2V0IDogKCBkZWVwIHx8IChkZWVwID0ge30pICkgKVsga2V5IF0gPSBzcmNbIGtleSBdO1xuXHRcdH1cblx0fVxuXHRpZiAoIGRlZXAgKSB7XG5cdFx0alF1ZXJ5LmV4dGVuZCggdHJ1ZSwgdGFyZ2V0LCBkZWVwICk7XG5cdH1cblxuXHRyZXR1cm4gdGFyZ2V0O1xufVxuXG4vKiBIYW5kbGVzIHJlc3BvbnNlcyB0byBhbiBhamF4IHJlcXVlc3Q6XG4gKiAtIGZpbmRzIHRoZSByaWdodCBkYXRhVHlwZSAobWVkaWF0ZXMgYmV0d2VlbiBjb250ZW50LXR5cGUgYW5kIGV4cGVjdGVkIGRhdGFUeXBlKVxuICogLSByZXR1cm5zIHRoZSBjb3JyZXNwb25kaW5nIHJlc3BvbnNlXG4gKi9cbmZ1bmN0aW9uIGFqYXhIYW5kbGVSZXNwb25zZXMoIHMsIGpxWEhSLCByZXNwb25zZXMgKSB7XG5cblx0dmFyIGN0LCB0eXBlLCBmaW5hbERhdGFUeXBlLCBmaXJzdERhdGFUeXBlLFxuXHRcdGNvbnRlbnRzID0gcy5jb250ZW50cyxcblx0XHRkYXRhVHlwZXMgPSBzLmRhdGFUeXBlcztcblxuXHQvLyBSZW1vdmUgYXV0byBkYXRhVHlwZSBhbmQgZ2V0IGNvbnRlbnQtdHlwZSBpbiB0aGUgcHJvY2Vzc1xuXHR3aGlsZSAoIGRhdGFUeXBlc1sgMCBdID09PSBcIipcIiApIHtcblx0XHRkYXRhVHlwZXMuc2hpZnQoKTtcblx0XHRpZiAoIGN0ID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRjdCA9IHMubWltZVR5cGUgfHwganFYSFIuZ2V0UmVzcG9uc2VIZWFkZXIoXCJDb250ZW50LVR5cGVcIik7XG5cdFx0fVxuXHR9XG5cblx0Ly8gQ2hlY2sgaWYgd2UncmUgZGVhbGluZyB3aXRoIGEga25vd24gY29udGVudC10eXBlXG5cdGlmICggY3QgKSB7XG5cdFx0Zm9yICggdHlwZSBpbiBjb250ZW50cyApIHtcblx0XHRcdGlmICggY29udGVudHNbIHR5cGUgXSAmJiBjb250ZW50c1sgdHlwZSBdLnRlc3QoIGN0ICkgKSB7XG5cdFx0XHRcdGRhdGFUeXBlcy51bnNoaWZ0KCB0eXBlICk7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdC8vIENoZWNrIHRvIHNlZSBpZiB3ZSBoYXZlIGEgcmVzcG9uc2UgZm9yIHRoZSBleHBlY3RlZCBkYXRhVHlwZVxuXHRpZiAoIGRhdGFUeXBlc1sgMCBdIGluIHJlc3BvbnNlcyApIHtcblx0XHRmaW5hbERhdGFUeXBlID0gZGF0YVR5cGVzWyAwIF07XG5cdH0gZWxzZSB7XG5cdFx0Ly8gVHJ5IGNvbnZlcnRpYmxlIGRhdGFUeXBlc1xuXHRcdGZvciAoIHR5cGUgaW4gcmVzcG9uc2VzICkge1xuXHRcdFx0aWYgKCAhZGF0YVR5cGVzWyAwIF0gfHwgcy5jb252ZXJ0ZXJzWyB0eXBlICsgXCIgXCIgKyBkYXRhVHlwZXNbMF0gXSApIHtcblx0XHRcdFx0ZmluYWxEYXRhVHlwZSA9IHR5cGU7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCAhZmlyc3REYXRhVHlwZSApIHtcblx0XHRcdFx0Zmlyc3REYXRhVHlwZSA9IHR5cGU7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdC8vIE9yIGp1c3QgdXNlIGZpcnN0IG9uZVxuXHRcdGZpbmFsRGF0YVR5cGUgPSBmaW5hbERhdGFUeXBlIHx8IGZpcnN0RGF0YVR5cGU7XG5cdH1cblxuXHQvLyBJZiB3ZSBmb3VuZCBhIGRhdGFUeXBlXG5cdC8vIFdlIGFkZCB0aGUgZGF0YVR5cGUgdG8gdGhlIGxpc3QgaWYgbmVlZGVkXG5cdC8vIGFuZCByZXR1cm4gdGhlIGNvcnJlc3BvbmRpbmcgcmVzcG9uc2Vcblx0aWYgKCBmaW5hbERhdGFUeXBlICkge1xuXHRcdGlmICggZmluYWxEYXRhVHlwZSAhPT0gZGF0YVR5cGVzWyAwIF0gKSB7XG5cdFx0XHRkYXRhVHlwZXMudW5zaGlmdCggZmluYWxEYXRhVHlwZSApO1xuXHRcdH1cblx0XHRyZXR1cm4gcmVzcG9uc2VzWyBmaW5hbERhdGFUeXBlIF07XG5cdH1cbn1cblxuLyogQ2hhaW4gY29udmVyc2lvbnMgZ2l2ZW4gdGhlIHJlcXVlc3QgYW5kIHRoZSBvcmlnaW5hbCByZXNwb25zZVxuICogQWxzbyBzZXRzIHRoZSByZXNwb25zZVhYWCBmaWVsZHMgb24gdGhlIGpxWEhSIGluc3RhbmNlXG4gKi9cbmZ1bmN0aW9uIGFqYXhDb252ZXJ0KCBzLCByZXNwb25zZSwganFYSFIsIGlzU3VjY2VzcyApIHtcblx0dmFyIGNvbnYyLCBjdXJyZW50LCBjb252LCB0bXAsIHByZXYsXG5cdFx0Y29udmVydGVycyA9IHt9LFxuXHRcdC8vIFdvcmsgd2l0aCBhIGNvcHkgb2YgZGF0YVR5cGVzIGluIGNhc2Ugd2UgbmVlZCB0byBtb2RpZnkgaXQgZm9yIGNvbnZlcnNpb25cblx0XHRkYXRhVHlwZXMgPSBzLmRhdGFUeXBlcy5zbGljZSgpO1xuXG5cdC8vIENyZWF0ZSBjb252ZXJ0ZXJzIG1hcCB3aXRoIGxvd2VyY2FzZWQga2V5c1xuXHRpZiAoIGRhdGFUeXBlc1sgMSBdICkge1xuXHRcdGZvciAoIGNvbnYgaW4gcy5jb252ZXJ0ZXJzICkge1xuXHRcdFx0Y29udmVydGVyc1sgY29udi50b0xvd2VyQ2FzZSgpIF0gPSBzLmNvbnZlcnRlcnNbIGNvbnYgXTtcblx0XHR9XG5cdH1cblxuXHRjdXJyZW50ID0gZGF0YVR5cGVzLnNoaWZ0KCk7XG5cblx0Ly8gQ29udmVydCB0byBlYWNoIHNlcXVlbnRpYWwgZGF0YVR5cGVcblx0d2hpbGUgKCBjdXJyZW50ICkge1xuXG5cdFx0aWYgKCBzLnJlc3BvbnNlRmllbGRzWyBjdXJyZW50IF0gKSB7XG5cdFx0XHRqcVhIUlsgcy5yZXNwb25zZUZpZWxkc1sgY3VycmVudCBdIF0gPSByZXNwb25zZTtcblx0XHR9XG5cblx0XHQvLyBBcHBseSB0aGUgZGF0YUZpbHRlciBpZiBwcm92aWRlZFxuXHRcdGlmICggIXByZXYgJiYgaXNTdWNjZXNzICYmIHMuZGF0YUZpbHRlciApIHtcblx0XHRcdHJlc3BvbnNlID0gcy5kYXRhRmlsdGVyKCByZXNwb25zZSwgcy5kYXRhVHlwZSApO1xuXHRcdH1cblxuXHRcdHByZXYgPSBjdXJyZW50O1xuXHRcdGN1cnJlbnQgPSBkYXRhVHlwZXMuc2hpZnQoKTtcblxuXHRcdGlmICggY3VycmVudCApIHtcblxuXHRcdC8vIFRoZXJlJ3Mgb25seSB3b3JrIHRvIGRvIGlmIGN1cnJlbnQgZGF0YVR5cGUgaXMgbm9uLWF1dG9cblx0XHRcdGlmICggY3VycmVudCA9PT0gXCIqXCIgKSB7XG5cblx0XHRcdFx0Y3VycmVudCA9IHByZXY7XG5cblx0XHRcdC8vIENvbnZlcnQgcmVzcG9uc2UgaWYgcHJldiBkYXRhVHlwZSBpcyBub24tYXV0byBhbmQgZGlmZmVycyBmcm9tIGN1cnJlbnRcblx0XHRcdH0gZWxzZSBpZiAoIHByZXYgIT09IFwiKlwiICYmIHByZXYgIT09IGN1cnJlbnQgKSB7XG5cblx0XHRcdFx0Ly8gU2VlayBhIGRpcmVjdCBjb252ZXJ0ZXJcblx0XHRcdFx0Y29udiA9IGNvbnZlcnRlcnNbIHByZXYgKyBcIiBcIiArIGN1cnJlbnQgXSB8fCBjb252ZXJ0ZXJzWyBcIiogXCIgKyBjdXJyZW50IF07XG5cblx0XHRcdFx0Ly8gSWYgbm9uZSBmb3VuZCwgc2VlayBhIHBhaXJcblx0XHRcdFx0aWYgKCAhY29udiApIHtcblx0XHRcdFx0XHRmb3IgKCBjb252MiBpbiBjb252ZXJ0ZXJzICkge1xuXG5cdFx0XHRcdFx0XHQvLyBJZiBjb252MiBvdXRwdXRzIGN1cnJlbnRcblx0XHRcdFx0XHRcdHRtcCA9IGNvbnYyLnNwbGl0KCBcIiBcIiApO1xuXHRcdFx0XHRcdFx0aWYgKCB0bXBbIDEgXSA9PT0gY3VycmVudCApIHtcblxuXHRcdFx0XHRcdFx0XHQvLyBJZiBwcmV2IGNhbiBiZSBjb252ZXJ0ZWQgdG8gYWNjZXB0ZWQgaW5wdXRcblx0XHRcdFx0XHRcdFx0Y29udiA9IGNvbnZlcnRlcnNbIHByZXYgKyBcIiBcIiArIHRtcFsgMCBdIF0gfHxcblx0XHRcdFx0XHRcdFx0XHRjb252ZXJ0ZXJzWyBcIiogXCIgKyB0bXBbIDAgXSBdO1xuXHRcdFx0XHRcdFx0XHRpZiAoIGNvbnYgKSB7XG5cdFx0XHRcdFx0XHRcdFx0Ly8gQ29uZGVuc2UgZXF1aXZhbGVuY2UgY29udmVydGVyc1xuXHRcdFx0XHRcdFx0XHRcdGlmICggY29udiA9PT0gdHJ1ZSApIHtcblx0XHRcdFx0XHRcdFx0XHRcdGNvbnYgPSBjb252ZXJ0ZXJzWyBjb252MiBdO1xuXG5cdFx0XHRcdFx0XHRcdFx0Ly8gT3RoZXJ3aXNlLCBpbnNlcnQgdGhlIGludGVybWVkaWF0ZSBkYXRhVHlwZVxuXHRcdFx0XHRcdFx0XHRcdH0gZWxzZSBpZiAoIGNvbnZlcnRlcnNbIGNvbnYyIF0gIT09IHRydWUgKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRjdXJyZW50ID0gdG1wWyAwIF07XG5cdFx0XHRcdFx0XHRcdFx0XHRkYXRhVHlwZXMudW5zaGlmdCggdG1wWyAxIF0gKTtcblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBBcHBseSBjb252ZXJ0ZXIgKGlmIG5vdCBhbiBlcXVpdmFsZW5jZSlcblx0XHRcdFx0aWYgKCBjb252ICE9PSB0cnVlICkge1xuXG5cdFx0XHRcdFx0Ly8gVW5sZXNzIGVycm9ycyBhcmUgYWxsb3dlZCB0byBidWJibGUsIGNhdGNoIGFuZCByZXR1cm4gdGhlbVxuXHRcdFx0XHRcdGlmICggY29udiAmJiBzWyBcInRocm93c1wiIF0gKSB7XG5cdFx0XHRcdFx0XHRyZXNwb25zZSA9IGNvbnYoIHJlc3BvbnNlICk7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdHRyeSB7XG5cdFx0XHRcdFx0XHRcdHJlc3BvbnNlID0gY29udiggcmVzcG9uc2UgKTtcblx0XHRcdFx0XHRcdH0gY2F0Y2ggKCBlICkge1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4geyBzdGF0ZTogXCJwYXJzZXJlcnJvclwiLCBlcnJvcjogY29udiA/IGUgOiBcIk5vIGNvbnZlcnNpb24gZnJvbSBcIiArIHByZXYgKyBcIiB0byBcIiArIGN1cnJlbnQgfTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHRyZXR1cm4geyBzdGF0ZTogXCJzdWNjZXNzXCIsIGRhdGE6IHJlc3BvbnNlIH07XG59XG5cbmpRdWVyeS5leHRlbmQoe1xuXG5cdC8vIENvdW50ZXIgZm9yIGhvbGRpbmcgdGhlIG51bWJlciBvZiBhY3RpdmUgcXVlcmllc1xuXHRhY3RpdmU6IDAsXG5cblx0Ly8gTGFzdC1Nb2RpZmllZCBoZWFkZXIgY2FjaGUgZm9yIG5leHQgcmVxdWVzdFxuXHRsYXN0TW9kaWZpZWQ6IHt9LFxuXHRldGFnOiB7fSxcblxuXHRhamF4U2V0dGluZ3M6IHtcblx0XHR1cmw6IGFqYXhMb2NhdGlvbixcblx0XHR0eXBlOiBcIkdFVFwiLFxuXHRcdGlzTG9jYWw6IHJsb2NhbFByb3RvY29sLnRlc3QoIGFqYXhMb2NQYXJ0c1sgMSBdICksXG5cdFx0Z2xvYmFsOiB0cnVlLFxuXHRcdHByb2Nlc3NEYXRhOiB0cnVlLFxuXHRcdGFzeW5jOiB0cnVlLFxuXHRcdGNvbnRlbnRUeXBlOiBcImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZDsgY2hhcnNldD1VVEYtOFwiLFxuXHRcdC8qXG5cdFx0dGltZW91dDogMCxcblx0XHRkYXRhOiBudWxsLFxuXHRcdGRhdGFUeXBlOiBudWxsLFxuXHRcdHVzZXJuYW1lOiBudWxsLFxuXHRcdHBhc3N3b3JkOiBudWxsLFxuXHRcdGNhY2hlOiBudWxsLFxuXHRcdHRocm93czogZmFsc2UsXG5cdFx0dHJhZGl0aW9uYWw6IGZhbHNlLFxuXHRcdGhlYWRlcnM6IHt9LFxuXHRcdCovXG5cblx0XHRhY2NlcHRzOiB7XG5cdFx0XHRcIipcIjogYWxsVHlwZXMsXG5cdFx0XHR0ZXh0OiBcInRleHQvcGxhaW5cIixcblx0XHRcdGh0bWw6IFwidGV4dC9odG1sXCIsXG5cdFx0XHR4bWw6IFwiYXBwbGljYXRpb24veG1sLCB0ZXh0L3htbFwiLFxuXHRcdFx0anNvbjogXCJhcHBsaWNhdGlvbi9qc29uLCB0ZXh0L2phdmFzY3JpcHRcIlxuXHRcdH0sXG5cblx0XHRjb250ZW50czoge1xuXHRcdFx0eG1sOiAveG1sLyxcblx0XHRcdGh0bWw6IC9odG1sLyxcblx0XHRcdGpzb246IC9qc29uL1xuXHRcdH0sXG5cblx0XHRyZXNwb25zZUZpZWxkczoge1xuXHRcdFx0eG1sOiBcInJlc3BvbnNlWE1MXCIsXG5cdFx0XHR0ZXh0OiBcInJlc3BvbnNlVGV4dFwiLFxuXHRcdFx0anNvbjogXCJyZXNwb25zZUpTT05cIlxuXHRcdH0sXG5cblx0XHQvLyBEYXRhIGNvbnZlcnRlcnNcblx0XHQvLyBLZXlzIHNlcGFyYXRlIHNvdXJjZSAob3IgY2F0Y2hhbGwgXCIqXCIpIGFuZCBkZXN0aW5hdGlvbiB0eXBlcyB3aXRoIGEgc2luZ2xlIHNwYWNlXG5cdFx0Y29udmVydGVyczoge1xuXG5cdFx0XHQvLyBDb252ZXJ0IGFueXRoaW5nIHRvIHRleHRcblx0XHRcdFwiKiB0ZXh0XCI6IFN0cmluZyxcblxuXHRcdFx0Ly8gVGV4dCB0byBodG1sICh0cnVlID0gbm8gdHJhbnNmb3JtYXRpb24pXG5cdFx0XHRcInRleHQgaHRtbFwiOiB0cnVlLFxuXG5cdFx0XHQvLyBFdmFsdWF0ZSB0ZXh0IGFzIGEganNvbiBleHByZXNzaW9uXG5cdFx0XHRcInRleHQganNvblwiOiBqUXVlcnkucGFyc2VKU09OLFxuXG5cdFx0XHQvLyBQYXJzZSB0ZXh0IGFzIHhtbFxuXHRcdFx0XCJ0ZXh0IHhtbFwiOiBqUXVlcnkucGFyc2VYTUxcblx0XHR9LFxuXG5cdFx0Ly8gRm9yIG9wdGlvbnMgdGhhdCBzaG91bGRuJ3QgYmUgZGVlcCBleHRlbmRlZDpcblx0XHQvLyB5b3UgY2FuIGFkZCB5b3VyIG93biBjdXN0b20gb3B0aW9ucyBoZXJlIGlmXG5cdFx0Ly8gYW5kIHdoZW4geW91IGNyZWF0ZSBvbmUgdGhhdCBzaG91bGRuJ3QgYmVcblx0XHQvLyBkZWVwIGV4dGVuZGVkIChzZWUgYWpheEV4dGVuZClcblx0XHRmbGF0T3B0aW9uczoge1xuXHRcdFx0dXJsOiB0cnVlLFxuXHRcdFx0Y29udGV4dDogdHJ1ZVxuXHRcdH1cblx0fSxcblxuXHQvLyBDcmVhdGVzIGEgZnVsbCBmbGVkZ2VkIHNldHRpbmdzIG9iamVjdCBpbnRvIHRhcmdldFxuXHQvLyB3aXRoIGJvdGggYWpheFNldHRpbmdzIGFuZCBzZXR0aW5ncyBmaWVsZHMuXG5cdC8vIElmIHRhcmdldCBpcyBvbWl0dGVkLCB3cml0ZXMgaW50byBhamF4U2V0dGluZ3MuXG5cdGFqYXhTZXR1cDogZnVuY3Rpb24oIHRhcmdldCwgc2V0dGluZ3MgKSB7XG5cdFx0cmV0dXJuIHNldHRpbmdzID9cblxuXHRcdFx0Ly8gQnVpbGRpbmcgYSBzZXR0aW5ncyBvYmplY3Rcblx0XHRcdGFqYXhFeHRlbmQoIGFqYXhFeHRlbmQoIHRhcmdldCwgalF1ZXJ5LmFqYXhTZXR0aW5ncyApLCBzZXR0aW5ncyApIDpcblxuXHRcdFx0Ly8gRXh0ZW5kaW5nIGFqYXhTZXR0aW5nc1xuXHRcdFx0YWpheEV4dGVuZCggalF1ZXJ5LmFqYXhTZXR0aW5ncywgdGFyZ2V0ICk7XG5cdH0sXG5cblx0YWpheFByZWZpbHRlcjogYWRkVG9QcmVmaWx0ZXJzT3JUcmFuc3BvcnRzKCBwcmVmaWx0ZXJzICksXG5cdGFqYXhUcmFuc3BvcnQ6IGFkZFRvUHJlZmlsdGVyc09yVHJhbnNwb3J0cyggdHJhbnNwb3J0cyApLFxuXG5cdC8vIE1haW4gbWV0aG9kXG5cdGFqYXg6IGZ1bmN0aW9uKCB1cmwsIG9wdGlvbnMgKSB7XG5cblx0XHQvLyBJZiB1cmwgaXMgYW4gb2JqZWN0LCBzaW11bGF0ZSBwcmUtMS41IHNpZ25hdHVyZVxuXHRcdGlmICggdHlwZW9mIHVybCA9PT0gXCJvYmplY3RcIiApIHtcblx0XHRcdG9wdGlvbnMgPSB1cmw7XG5cdFx0XHR1cmwgPSB1bmRlZmluZWQ7XG5cdFx0fVxuXG5cdFx0Ly8gRm9yY2Ugb3B0aW9ucyB0byBiZSBhbiBvYmplY3Rcblx0XHRvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuXHRcdHZhciB0cmFuc3BvcnQsXG5cdFx0XHQvLyBVUkwgd2l0aG91dCBhbnRpLWNhY2hlIHBhcmFtXG5cdFx0XHRjYWNoZVVSTCxcblx0XHRcdC8vIFJlc3BvbnNlIGhlYWRlcnNcblx0XHRcdHJlc3BvbnNlSGVhZGVyc1N0cmluZyxcblx0XHRcdHJlc3BvbnNlSGVhZGVycyxcblx0XHRcdC8vIHRpbWVvdXQgaGFuZGxlXG5cdFx0XHR0aW1lb3V0VGltZXIsXG5cdFx0XHQvLyBDcm9zcy1kb21haW4gZGV0ZWN0aW9uIHZhcnNcblx0XHRcdHBhcnRzLFxuXHRcdFx0Ly8gVG8ga25vdyBpZiBnbG9iYWwgZXZlbnRzIGFyZSB0byBiZSBkaXNwYXRjaGVkXG5cdFx0XHRmaXJlR2xvYmFscyxcblx0XHRcdC8vIExvb3AgdmFyaWFibGVcblx0XHRcdGksXG5cdFx0XHQvLyBDcmVhdGUgdGhlIGZpbmFsIG9wdGlvbnMgb2JqZWN0XG5cdFx0XHRzID0galF1ZXJ5LmFqYXhTZXR1cCgge30sIG9wdGlvbnMgKSxcblx0XHRcdC8vIENhbGxiYWNrcyBjb250ZXh0XG5cdFx0XHRjYWxsYmFja0NvbnRleHQgPSBzLmNvbnRleHQgfHwgcyxcblx0XHRcdC8vIENvbnRleHQgZm9yIGdsb2JhbCBldmVudHMgaXMgY2FsbGJhY2tDb250ZXh0IGlmIGl0IGlzIGEgRE9NIG5vZGUgb3IgalF1ZXJ5IGNvbGxlY3Rpb25cblx0XHRcdGdsb2JhbEV2ZW50Q29udGV4dCA9IHMuY29udGV4dCAmJiAoIGNhbGxiYWNrQ29udGV4dC5ub2RlVHlwZSB8fCBjYWxsYmFja0NvbnRleHQuanF1ZXJ5ICkgP1xuXHRcdFx0XHRqUXVlcnkoIGNhbGxiYWNrQ29udGV4dCApIDpcblx0XHRcdFx0alF1ZXJ5LmV2ZW50LFxuXHRcdFx0Ly8gRGVmZXJyZWRzXG5cdFx0XHRkZWZlcnJlZCA9IGpRdWVyeS5EZWZlcnJlZCgpLFxuXHRcdFx0Y29tcGxldGVEZWZlcnJlZCA9IGpRdWVyeS5DYWxsYmFja3MoXCJvbmNlIG1lbW9yeVwiKSxcblx0XHRcdC8vIFN0YXR1cy1kZXBlbmRlbnQgY2FsbGJhY2tzXG5cdFx0XHRzdGF0dXNDb2RlID0gcy5zdGF0dXNDb2RlIHx8IHt9LFxuXHRcdFx0Ly8gSGVhZGVycyAodGhleSBhcmUgc2VudCBhbGwgYXQgb25jZSlcblx0XHRcdHJlcXVlc3RIZWFkZXJzID0ge30sXG5cdFx0XHRyZXF1ZXN0SGVhZGVyc05hbWVzID0ge30sXG5cdFx0XHQvLyBUaGUganFYSFIgc3RhdGVcblx0XHRcdHN0YXRlID0gMCxcblx0XHRcdC8vIERlZmF1bHQgYWJvcnQgbWVzc2FnZVxuXHRcdFx0c3RyQWJvcnQgPSBcImNhbmNlbGVkXCIsXG5cdFx0XHQvLyBGYWtlIHhoclxuXHRcdFx0anFYSFIgPSB7XG5cdFx0XHRcdHJlYWR5U3RhdGU6IDAsXG5cblx0XHRcdFx0Ly8gQnVpbGRzIGhlYWRlcnMgaGFzaHRhYmxlIGlmIG5lZWRlZFxuXHRcdFx0XHRnZXRSZXNwb25zZUhlYWRlcjogZnVuY3Rpb24oIGtleSApIHtcblx0XHRcdFx0XHR2YXIgbWF0Y2g7XG5cdFx0XHRcdFx0aWYgKCBzdGF0ZSA9PT0gMiApIHtcblx0XHRcdFx0XHRcdGlmICggIXJlc3BvbnNlSGVhZGVycyApIHtcblx0XHRcdFx0XHRcdFx0cmVzcG9uc2VIZWFkZXJzID0ge307XG5cdFx0XHRcdFx0XHRcdHdoaWxlICggKG1hdGNoID0gcmhlYWRlcnMuZXhlYyggcmVzcG9uc2VIZWFkZXJzU3RyaW5nICkpICkge1xuXHRcdFx0XHRcdFx0XHRcdHJlc3BvbnNlSGVhZGVyc1sgbWF0Y2hbMV0udG9Mb3dlckNhc2UoKSBdID0gbWF0Y2hbIDIgXTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0bWF0Y2ggPSByZXNwb25zZUhlYWRlcnNbIGtleS50b0xvd2VyQ2FzZSgpIF07XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHJldHVybiBtYXRjaCA9PSBudWxsID8gbnVsbCA6IG1hdGNoO1xuXHRcdFx0XHR9LFxuXG5cdFx0XHRcdC8vIFJhdyBzdHJpbmdcblx0XHRcdFx0Z2V0QWxsUmVzcG9uc2VIZWFkZXJzOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRyZXR1cm4gc3RhdGUgPT09IDIgPyByZXNwb25zZUhlYWRlcnNTdHJpbmcgOiBudWxsO1xuXHRcdFx0XHR9LFxuXG5cdFx0XHRcdC8vIENhY2hlcyB0aGUgaGVhZGVyXG5cdFx0XHRcdHNldFJlcXVlc3RIZWFkZXI6IGZ1bmN0aW9uKCBuYW1lLCB2YWx1ZSApIHtcblx0XHRcdFx0XHR2YXIgbG5hbWUgPSBuYW1lLnRvTG93ZXJDYXNlKCk7XG5cdFx0XHRcdFx0aWYgKCAhc3RhdGUgKSB7XG5cdFx0XHRcdFx0XHRuYW1lID0gcmVxdWVzdEhlYWRlcnNOYW1lc1sgbG5hbWUgXSA9IHJlcXVlc3RIZWFkZXJzTmFtZXNbIGxuYW1lIF0gfHwgbmFtZTtcblx0XHRcdFx0XHRcdHJlcXVlc3RIZWFkZXJzWyBuYW1lIF0gPSB2YWx1ZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHRcdH0sXG5cblx0XHRcdFx0Ly8gT3ZlcnJpZGVzIHJlc3BvbnNlIGNvbnRlbnQtdHlwZSBoZWFkZXJcblx0XHRcdFx0b3ZlcnJpZGVNaW1lVHlwZTogZnVuY3Rpb24oIHR5cGUgKSB7XG5cdFx0XHRcdFx0aWYgKCAhc3RhdGUgKSB7XG5cdFx0XHRcdFx0XHRzLm1pbWVUeXBlID0gdHlwZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHRcdH0sXG5cblx0XHRcdFx0Ly8gU3RhdHVzLWRlcGVuZGVudCBjYWxsYmFja3Ncblx0XHRcdFx0c3RhdHVzQ29kZTogZnVuY3Rpb24oIG1hcCApIHtcblx0XHRcdFx0XHR2YXIgY29kZTtcblx0XHRcdFx0XHRpZiAoIG1hcCApIHtcblx0XHRcdFx0XHRcdGlmICggc3RhdGUgPCAyICkge1xuXHRcdFx0XHRcdFx0XHRmb3IgKCBjb2RlIGluIG1hcCApIHtcblx0XHRcdFx0XHRcdFx0XHQvLyBMYXp5LWFkZCB0aGUgbmV3IGNhbGxiYWNrIGluIGEgd2F5IHRoYXQgcHJlc2VydmVzIG9sZCBvbmVzXG5cdFx0XHRcdFx0XHRcdFx0c3RhdHVzQ29kZVsgY29kZSBdID0gWyBzdGF0dXNDb2RlWyBjb2RlIF0sIG1hcFsgY29kZSBdIF07XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdC8vIEV4ZWN1dGUgdGhlIGFwcHJvcHJpYXRlIGNhbGxiYWNrc1xuXHRcdFx0XHRcdFx0XHRqcVhIUi5hbHdheXMoIG1hcFsganFYSFIuc3RhdHVzIF0gKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHRcdH0sXG5cblx0XHRcdFx0Ly8gQ2FuY2VsIHRoZSByZXF1ZXN0XG5cdFx0XHRcdGFib3J0OiBmdW5jdGlvbiggc3RhdHVzVGV4dCApIHtcblx0XHRcdFx0XHR2YXIgZmluYWxUZXh0ID0gc3RhdHVzVGV4dCB8fCBzdHJBYm9ydDtcblx0XHRcdFx0XHRpZiAoIHRyYW5zcG9ydCApIHtcblx0XHRcdFx0XHRcdHRyYW5zcG9ydC5hYm9ydCggZmluYWxUZXh0ICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGRvbmUoIDAsIGZpbmFsVGV4dCApO1xuXHRcdFx0XHRcdHJldHVybiB0aGlzO1xuXHRcdFx0XHR9XG5cdFx0XHR9O1xuXG5cdFx0Ly8gQXR0YWNoIGRlZmVycmVkc1xuXHRcdGRlZmVycmVkLnByb21pc2UoIGpxWEhSICkuY29tcGxldGUgPSBjb21wbGV0ZURlZmVycmVkLmFkZDtcblx0XHRqcVhIUi5zdWNjZXNzID0ganFYSFIuZG9uZTtcblx0XHRqcVhIUi5lcnJvciA9IGpxWEhSLmZhaWw7XG5cblx0XHQvLyBSZW1vdmUgaGFzaCBjaGFyYWN0ZXIgKCM3NTMxOiBhbmQgc3RyaW5nIHByb21vdGlvbilcblx0XHQvLyBBZGQgcHJvdG9jb2wgaWYgbm90IHByb3ZpZGVkIChwcmVmaWx0ZXJzIG1pZ2h0IGV4cGVjdCBpdClcblx0XHQvLyBIYW5kbGUgZmFsc3kgdXJsIGluIHRoZSBzZXR0aW5ncyBvYmplY3QgKCMxMDA5MzogY29uc2lzdGVuY3kgd2l0aCBvbGQgc2lnbmF0dXJlKVxuXHRcdC8vIFdlIGFsc28gdXNlIHRoZSB1cmwgcGFyYW1ldGVyIGlmIGF2YWlsYWJsZVxuXHRcdHMudXJsID0gKCAoIHVybCB8fCBzLnVybCB8fCBhamF4TG9jYXRpb24gKSArIFwiXCIgKS5yZXBsYWNlKCByaGFzaCwgXCJcIiApXG5cdFx0XHQucmVwbGFjZSggcnByb3RvY29sLCBhamF4TG9jUGFydHNbIDEgXSArIFwiLy9cIiApO1xuXG5cdFx0Ly8gQWxpYXMgbWV0aG9kIG9wdGlvbiB0byB0eXBlIGFzIHBlciB0aWNrZXQgIzEyMDA0XG5cdFx0cy50eXBlID0gb3B0aW9ucy5tZXRob2QgfHwgb3B0aW9ucy50eXBlIHx8IHMubWV0aG9kIHx8IHMudHlwZTtcblxuXHRcdC8vIEV4dHJhY3QgZGF0YVR5cGVzIGxpc3Rcblx0XHRzLmRhdGFUeXBlcyA9IGpRdWVyeS50cmltKCBzLmRhdGFUeXBlIHx8IFwiKlwiICkudG9Mb3dlckNhc2UoKS5tYXRjaCggcm5vdHdoaXRlICkgfHwgWyBcIlwiIF07XG5cblx0XHQvLyBBIGNyb3NzLWRvbWFpbiByZXF1ZXN0IGlzIGluIG9yZGVyIHdoZW4gd2UgaGF2ZSBhIHByb3RvY29sOmhvc3Q6cG9ydCBtaXNtYXRjaFxuXHRcdGlmICggcy5jcm9zc0RvbWFpbiA9PSBudWxsICkge1xuXHRcdFx0cGFydHMgPSBydXJsLmV4ZWMoIHMudXJsLnRvTG93ZXJDYXNlKCkgKTtcblx0XHRcdHMuY3Jvc3NEb21haW4gPSAhISggcGFydHMgJiZcblx0XHRcdFx0KCBwYXJ0c1sgMSBdICE9PSBhamF4TG9jUGFydHNbIDEgXSB8fCBwYXJ0c1sgMiBdICE9PSBhamF4TG9jUGFydHNbIDIgXSB8fFxuXHRcdFx0XHRcdCggcGFydHNbIDMgXSB8fCAoIHBhcnRzWyAxIF0gPT09IFwiaHR0cDpcIiA/IFwiODBcIiA6IFwiNDQzXCIgKSApICE9PVxuXHRcdFx0XHRcdFx0KCBhamF4TG9jUGFydHNbIDMgXSB8fCAoIGFqYXhMb2NQYXJ0c1sgMSBdID09PSBcImh0dHA6XCIgPyBcIjgwXCIgOiBcIjQ0M1wiICkgKSApXG5cdFx0XHQpO1xuXHRcdH1cblxuXHRcdC8vIENvbnZlcnQgZGF0YSBpZiBub3QgYWxyZWFkeSBhIHN0cmluZ1xuXHRcdGlmICggcy5kYXRhICYmIHMucHJvY2Vzc0RhdGEgJiYgdHlwZW9mIHMuZGF0YSAhPT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdHMuZGF0YSA9IGpRdWVyeS5wYXJhbSggcy5kYXRhLCBzLnRyYWRpdGlvbmFsICk7XG5cdFx0fVxuXG5cdFx0Ly8gQXBwbHkgcHJlZmlsdGVyc1xuXHRcdGluc3BlY3RQcmVmaWx0ZXJzT3JUcmFuc3BvcnRzKCBwcmVmaWx0ZXJzLCBzLCBvcHRpb25zLCBqcVhIUiApO1xuXG5cdFx0Ly8gSWYgcmVxdWVzdCB3YXMgYWJvcnRlZCBpbnNpZGUgYSBwcmVmaWx0ZXIsIHN0b3AgdGhlcmVcblx0XHRpZiAoIHN0YXRlID09PSAyICkge1xuXHRcdFx0cmV0dXJuIGpxWEhSO1xuXHRcdH1cblxuXHRcdC8vIFdlIGNhbiBmaXJlIGdsb2JhbCBldmVudHMgYXMgb2Ygbm93IGlmIGFza2VkIHRvXG5cdFx0Ly8gRG9uJ3QgZmlyZSBldmVudHMgaWYgalF1ZXJ5LmV2ZW50IGlzIHVuZGVmaW5lZCBpbiBhbiBBTUQtdXNhZ2Ugc2NlbmFyaW8gKCMxNTExOClcblx0XHRmaXJlR2xvYmFscyA9IGpRdWVyeS5ldmVudCAmJiBzLmdsb2JhbDtcblxuXHRcdC8vIFdhdGNoIGZvciBhIG5ldyBzZXQgb2YgcmVxdWVzdHNcblx0XHRpZiAoIGZpcmVHbG9iYWxzICYmIGpRdWVyeS5hY3RpdmUrKyA9PT0gMCApIHtcblx0XHRcdGpRdWVyeS5ldmVudC50cmlnZ2VyKFwiYWpheFN0YXJ0XCIpO1xuXHRcdH1cblxuXHRcdC8vIFVwcGVyY2FzZSB0aGUgdHlwZVxuXHRcdHMudHlwZSA9IHMudHlwZS50b1VwcGVyQ2FzZSgpO1xuXG5cdFx0Ly8gRGV0ZXJtaW5lIGlmIHJlcXVlc3QgaGFzIGNvbnRlbnRcblx0XHRzLmhhc0NvbnRlbnQgPSAhcm5vQ29udGVudC50ZXN0KCBzLnR5cGUgKTtcblxuXHRcdC8vIFNhdmUgdGhlIFVSTCBpbiBjYXNlIHdlJ3JlIHRveWluZyB3aXRoIHRoZSBJZi1Nb2RpZmllZC1TaW5jZVxuXHRcdC8vIGFuZC9vciBJZi1Ob25lLU1hdGNoIGhlYWRlciBsYXRlciBvblxuXHRcdGNhY2hlVVJMID0gcy51cmw7XG5cblx0XHQvLyBNb3JlIG9wdGlvbnMgaGFuZGxpbmcgZm9yIHJlcXVlc3RzIHdpdGggbm8gY29udGVudFxuXHRcdGlmICggIXMuaGFzQ29udGVudCApIHtcblxuXHRcdFx0Ly8gSWYgZGF0YSBpcyBhdmFpbGFibGUsIGFwcGVuZCBkYXRhIHRvIHVybFxuXHRcdFx0aWYgKCBzLmRhdGEgKSB7XG5cdFx0XHRcdGNhY2hlVVJMID0gKCBzLnVybCArPSAoIHJxdWVyeS50ZXN0KCBjYWNoZVVSTCApID8gXCImXCIgOiBcIj9cIiApICsgcy5kYXRhICk7XG5cdFx0XHRcdC8vICM5NjgyOiByZW1vdmUgZGF0YSBzbyB0aGF0IGl0J3Mgbm90IHVzZWQgaW4gYW4gZXZlbnR1YWwgcmV0cnlcblx0XHRcdFx0ZGVsZXRlIHMuZGF0YTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQWRkIGFudGktY2FjaGUgaW4gdXJsIGlmIG5lZWRlZFxuXHRcdFx0aWYgKCBzLmNhY2hlID09PSBmYWxzZSApIHtcblx0XHRcdFx0cy51cmwgPSBydHMudGVzdCggY2FjaGVVUkwgKSA/XG5cblx0XHRcdFx0XHQvLyBJZiB0aGVyZSBpcyBhbHJlYWR5IGEgJ18nIHBhcmFtZXRlciwgc2V0IGl0cyB2YWx1ZVxuXHRcdFx0XHRcdGNhY2hlVVJMLnJlcGxhY2UoIHJ0cywgXCIkMV89XCIgKyBub25jZSsrICkgOlxuXG5cdFx0XHRcdFx0Ly8gT3RoZXJ3aXNlIGFkZCBvbmUgdG8gdGhlIGVuZFxuXHRcdFx0XHRcdGNhY2hlVVJMICsgKCBycXVlcnkudGVzdCggY2FjaGVVUkwgKSA/IFwiJlwiIDogXCI/XCIgKSArIFwiXz1cIiArIG5vbmNlKys7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gU2V0IHRoZSBJZi1Nb2RpZmllZC1TaW5jZSBhbmQvb3IgSWYtTm9uZS1NYXRjaCBoZWFkZXIsIGlmIGluIGlmTW9kaWZpZWQgbW9kZS5cblx0XHRpZiAoIHMuaWZNb2RpZmllZCApIHtcblx0XHRcdGlmICggalF1ZXJ5Lmxhc3RNb2RpZmllZFsgY2FjaGVVUkwgXSApIHtcblx0XHRcdFx0anFYSFIuc2V0UmVxdWVzdEhlYWRlciggXCJJZi1Nb2RpZmllZC1TaW5jZVwiLCBqUXVlcnkubGFzdE1vZGlmaWVkWyBjYWNoZVVSTCBdICk7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIGpRdWVyeS5ldGFnWyBjYWNoZVVSTCBdICkge1xuXHRcdFx0XHRqcVhIUi5zZXRSZXF1ZXN0SGVhZGVyKCBcIklmLU5vbmUtTWF0Y2hcIiwgalF1ZXJ5LmV0YWdbIGNhY2hlVVJMIF0gKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBTZXQgdGhlIGNvcnJlY3QgaGVhZGVyLCBpZiBkYXRhIGlzIGJlaW5nIHNlbnRcblx0XHRpZiAoIHMuZGF0YSAmJiBzLmhhc0NvbnRlbnQgJiYgcy5jb250ZW50VHlwZSAhPT0gZmFsc2UgfHwgb3B0aW9ucy5jb250ZW50VHlwZSApIHtcblx0XHRcdGpxWEhSLnNldFJlcXVlc3RIZWFkZXIoIFwiQ29udGVudC1UeXBlXCIsIHMuY29udGVudFR5cGUgKTtcblx0XHR9XG5cblx0XHQvLyBTZXQgdGhlIEFjY2VwdHMgaGVhZGVyIGZvciB0aGUgc2VydmVyLCBkZXBlbmRpbmcgb24gdGhlIGRhdGFUeXBlXG5cdFx0anFYSFIuc2V0UmVxdWVzdEhlYWRlcihcblx0XHRcdFwiQWNjZXB0XCIsXG5cdFx0XHRzLmRhdGFUeXBlc1sgMCBdICYmIHMuYWNjZXB0c1sgcy5kYXRhVHlwZXNbMF0gXSA/XG5cdFx0XHRcdHMuYWNjZXB0c1sgcy5kYXRhVHlwZXNbMF0gXSArICggcy5kYXRhVHlwZXNbIDAgXSAhPT0gXCIqXCIgPyBcIiwgXCIgKyBhbGxUeXBlcyArIFwiOyBxPTAuMDFcIiA6IFwiXCIgKSA6XG5cdFx0XHRcdHMuYWNjZXB0c1sgXCIqXCIgXVxuXHRcdCk7XG5cblx0XHQvLyBDaGVjayBmb3IgaGVhZGVycyBvcHRpb25cblx0XHRmb3IgKCBpIGluIHMuaGVhZGVycyApIHtcblx0XHRcdGpxWEhSLnNldFJlcXVlc3RIZWFkZXIoIGksIHMuaGVhZGVyc1sgaSBdICk7XG5cdFx0fVxuXG5cdFx0Ly8gQWxsb3cgY3VzdG9tIGhlYWRlcnMvbWltZXR5cGVzIGFuZCBlYXJseSBhYm9ydFxuXHRcdGlmICggcy5iZWZvcmVTZW5kICYmICggcy5iZWZvcmVTZW5kLmNhbGwoIGNhbGxiYWNrQ29udGV4dCwganFYSFIsIHMgKSA9PT0gZmFsc2UgfHwgc3RhdGUgPT09IDIgKSApIHtcblx0XHRcdC8vIEFib3J0IGlmIG5vdCBkb25lIGFscmVhZHkgYW5kIHJldHVyblxuXHRcdFx0cmV0dXJuIGpxWEhSLmFib3J0KCk7XG5cdFx0fVxuXG5cdFx0Ly8gQWJvcnRpbmcgaXMgbm8gbG9uZ2VyIGEgY2FuY2VsbGF0aW9uXG5cdFx0c3RyQWJvcnQgPSBcImFib3J0XCI7XG5cblx0XHQvLyBJbnN0YWxsIGNhbGxiYWNrcyBvbiBkZWZlcnJlZHNcblx0XHRmb3IgKCBpIGluIHsgc3VjY2VzczogMSwgZXJyb3I6IDEsIGNvbXBsZXRlOiAxIH0gKSB7XG5cdFx0XHRqcVhIUlsgaSBdKCBzWyBpIF0gKTtcblx0XHR9XG5cblx0XHQvLyBHZXQgdHJhbnNwb3J0XG5cdFx0dHJhbnNwb3J0ID0gaW5zcGVjdFByZWZpbHRlcnNPclRyYW5zcG9ydHMoIHRyYW5zcG9ydHMsIHMsIG9wdGlvbnMsIGpxWEhSICk7XG5cblx0XHQvLyBJZiBubyB0cmFuc3BvcnQsIHdlIGF1dG8tYWJvcnRcblx0XHRpZiAoICF0cmFuc3BvcnQgKSB7XG5cdFx0XHRkb25lKCAtMSwgXCJObyBUcmFuc3BvcnRcIiApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRqcVhIUi5yZWFkeVN0YXRlID0gMTtcblxuXHRcdFx0Ly8gU2VuZCBnbG9iYWwgZXZlbnRcblx0XHRcdGlmICggZmlyZUdsb2JhbHMgKSB7XG5cdFx0XHRcdGdsb2JhbEV2ZW50Q29udGV4dC50cmlnZ2VyKCBcImFqYXhTZW5kXCIsIFsganFYSFIsIHMgXSApO1xuXHRcdFx0fVxuXHRcdFx0Ly8gVGltZW91dFxuXHRcdFx0aWYgKCBzLmFzeW5jICYmIHMudGltZW91dCA+IDAgKSB7XG5cdFx0XHRcdHRpbWVvdXRUaW1lciA9IHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0anFYSFIuYWJvcnQoXCJ0aW1lb3V0XCIpO1xuXHRcdFx0XHR9LCBzLnRpbWVvdXQgKTtcblx0XHRcdH1cblxuXHRcdFx0dHJ5IHtcblx0XHRcdFx0c3RhdGUgPSAxO1xuXHRcdFx0XHR0cmFuc3BvcnQuc2VuZCggcmVxdWVzdEhlYWRlcnMsIGRvbmUgKTtcblx0XHRcdH0gY2F0Y2ggKCBlICkge1xuXHRcdFx0XHQvLyBQcm9wYWdhdGUgZXhjZXB0aW9uIGFzIGVycm9yIGlmIG5vdCBkb25lXG5cdFx0XHRcdGlmICggc3RhdGUgPCAyICkge1xuXHRcdFx0XHRcdGRvbmUoIC0xLCBlICk7XG5cdFx0XHRcdC8vIFNpbXBseSByZXRocm93IG90aGVyd2lzZVxuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHRocm93IGU7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBDYWxsYmFjayBmb3Igd2hlbiBldmVyeXRoaW5nIGlzIGRvbmVcblx0XHRmdW5jdGlvbiBkb25lKCBzdGF0dXMsIG5hdGl2ZVN0YXR1c1RleHQsIHJlc3BvbnNlcywgaGVhZGVycyApIHtcblx0XHRcdHZhciBpc1N1Y2Nlc3MsIHN1Y2Nlc3MsIGVycm9yLCByZXNwb25zZSwgbW9kaWZpZWQsXG5cdFx0XHRcdHN0YXR1c1RleHQgPSBuYXRpdmVTdGF0dXNUZXh0O1xuXG5cdFx0XHQvLyBDYWxsZWQgb25jZVxuXHRcdFx0aWYgKCBzdGF0ZSA9PT0gMiApIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBTdGF0ZSBpcyBcImRvbmVcIiBub3dcblx0XHRcdHN0YXRlID0gMjtcblxuXHRcdFx0Ly8gQ2xlYXIgdGltZW91dCBpZiBpdCBleGlzdHNcblx0XHRcdGlmICggdGltZW91dFRpbWVyICkge1xuXHRcdFx0XHRjbGVhclRpbWVvdXQoIHRpbWVvdXRUaW1lciApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBEZXJlZmVyZW5jZSB0cmFuc3BvcnQgZm9yIGVhcmx5IGdhcmJhZ2UgY29sbGVjdGlvblxuXHRcdFx0Ly8gKG5vIG1hdHRlciBob3cgbG9uZyB0aGUganFYSFIgb2JqZWN0IHdpbGwgYmUgdXNlZClcblx0XHRcdHRyYW5zcG9ydCA9IHVuZGVmaW5lZDtcblxuXHRcdFx0Ly8gQ2FjaGUgcmVzcG9uc2UgaGVhZGVyc1xuXHRcdFx0cmVzcG9uc2VIZWFkZXJzU3RyaW5nID0gaGVhZGVycyB8fCBcIlwiO1xuXG5cdFx0XHQvLyBTZXQgcmVhZHlTdGF0ZVxuXHRcdFx0anFYSFIucmVhZHlTdGF0ZSA9IHN0YXR1cyA+IDAgPyA0IDogMDtcblxuXHRcdFx0Ly8gRGV0ZXJtaW5lIGlmIHN1Y2Nlc3NmdWxcblx0XHRcdGlzU3VjY2VzcyA9IHN0YXR1cyA+PSAyMDAgJiYgc3RhdHVzIDwgMzAwIHx8IHN0YXR1cyA9PT0gMzA0O1xuXG5cdFx0XHQvLyBHZXQgcmVzcG9uc2UgZGF0YVxuXHRcdFx0aWYgKCByZXNwb25zZXMgKSB7XG5cdFx0XHRcdHJlc3BvbnNlID0gYWpheEhhbmRsZVJlc3BvbnNlcyggcywganFYSFIsIHJlc3BvbnNlcyApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBDb252ZXJ0IG5vIG1hdHRlciB3aGF0ICh0aGF0IHdheSByZXNwb25zZVhYWCBmaWVsZHMgYXJlIGFsd2F5cyBzZXQpXG5cdFx0XHRyZXNwb25zZSA9IGFqYXhDb252ZXJ0KCBzLCByZXNwb25zZSwganFYSFIsIGlzU3VjY2VzcyApO1xuXG5cdFx0XHQvLyBJZiBzdWNjZXNzZnVsLCBoYW5kbGUgdHlwZSBjaGFpbmluZ1xuXHRcdFx0aWYgKCBpc1N1Y2Nlc3MgKSB7XG5cblx0XHRcdFx0Ly8gU2V0IHRoZSBJZi1Nb2RpZmllZC1TaW5jZSBhbmQvb3IgSWYtTm9uZS1NYXRjaCBoZWFkZXIsIGlmIGluIGlmTW9kaWZpZWQgbW9kZS5cblx0XHRcdFx0aWYgKCBzLmlmTW9kaWZpZWQgKSB7XG5cdFx0XHRcdFx0bW9kaWZpZWQgPSBqcVhIUi5nZXRSZXNwb25zZUhlYWRlcihcIkxhc3QtTW9kaWZpZWRcIik7XG5cdFx0XHRcdFx0aWYgKCBtb2RpZmllZCApIHtcblx0XHRcdFx0XHRcdGpRdWVyeS5sYXN0TW9kaWZpZWRbIGNhY2hlVVJMIF0gPSBtb2RpZmllZDtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0bW9kaWZpZWQgPSBqcVhIUi5nZXRSZXNwb25zZUhlYWRlcihcImV0YWdcIik7XG5cdFx0XHRcdFx0aWYgKCBtb2RpZmllZCApIHtcblx0XHRcdFx0XHRcdGpRdWVyeS5ldGFnWyBjYWNoZVVSTCBdID0gbW9kaWZpZWQ7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gaWYgbm8gY29udGVudFxuXHRcdFx0XHRpZiAoIHN0YXR1cyA9PT0gMjA0IHx8IHMudHlwZSA9PT0gXCJIRUFEXCIgKSB7XG5cdFx0XHRcdFx0c3RhdHVzVGV4dCA9IFwibm9jb250ZW50XCI7XG5cblx0XHRcdFx0Ly8gaWYgbm90IG1vZGlmaWVkXG5cdFx0XHRcdH0gZWxzZSBpZiAoIHN0YXR1cyA9PT0gMzA0ICkge1xuXHRcdFx0XHRcdHN0YXR1c1RleHQgPSBcIm5vdG1vZGlmaWVkXCI7XG5cblx0XHRcdFx0Ly8gSWYgd2UgaGF2ZSBkYXRhLCBsZXQncyBjb252ZXJ0IGl0XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0c3RhdHVzVGV4dCA9IHJlc3BvbnNlLnN0YXRlO1xuXHRcdFx0XHRcdHN1Y2Nlc3MgPSByZXNwb25zZS5kYXRhO1xuXHRcdFx0XHRcdGVycm9yID0gcmVzcG9uc2UuZXJyb3I7XG5cdFx0XHRcdFx0aXNTdWNjZXNzID0gIWVycm9yO1xuXHRcdFx0XHR9XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHQvLyBFeHRyYWN0IGVycm9yIGZyb20gc3RhdHVzVGV4dCBhbmQgbm9ybWFsaXplIGZvciBub24tYWJvcnRzXG5cdFx0XHRcdGVycm9yID0gc3RhdHVzVGV4dDtcblx0XHRcdFx0aWYgKCBzdGF0dXMgfHwgIXN0YXR1c1RleHQgKSB7XG5cdFx0XHRcdFx0c3RhdHVzVGV4dCA9IFwiZXJyb3JcIjtcblx0XHRcdFx0XHRpZiAoIHN0YXR1cyA8IDAgKSB7XG5cdFx0XHRcdFx0XHRzdGF0dXMgPSAwO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHQvLyBTZXQgZGF0YSBmb3IgdGhlIGZha2UgeGhyIG9iamVjdFxuXHRcdFx0anFYSFIuc3RhdHVzID0gc3RhdHVzO1xuXHRcdFx0anFYSFIuc3RhdHVzVGV4dCA9ICggbmF0aXZlU3RhdHVzVGV4dCB8fCBzdGF0dXNUZXh0ICkgKyBcIlwiO1xuXG5cdFx0XHQvLyBTdWNjZXNzL0Vycm9yXG5cdFx0XHRpZiAoIGlzU3VjY2VzcyApIHtcblx0XHRcdFx0ZGVmZXJyZWQucmVzb2x2ZVdpdGgoIGNhbGxiYWNrQ29udGV4dCwgWyBzdWNjZXNzLCBzdGF0dXNUZXh0LCBqcVhIUiBdICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRkZWZlcnJlZC5yZWplY3RXaXRoKCBjYWxsYmFja0NvbnRleHQsIFsganFYSFIsIHN0YXR1c1RleHQsIGVycm9yIF0gKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gU3RhdHVzLWRlcGVuZGVudCBjYWxsYmFja3Ncblx0XHRcdGpxWEhSLnN0YXR1c0NvZGUoIHN0YXR1c0NvZGUgKTtcblx0XHRcdHN0YXR1c0NvZGUgPSB1bmRlZmluZWQ7XG5cblx0XHRcdGlmICggZmlyZUdsb2JhbHMgKSB7XG5cdFx0XHRcdGdsb2JhbEV2ZW50Q29udGV4dC50cmlnZ2VyKCBpc1N1Y2Nlc3MgPyBcImFqYXhTdWNjZXNzXCIgOiBcImFqYXhFcnJvclwiLFxuXHRcdFx0XHRcdFsganFYSFIsIHMsIGlzU3VjY2VzcyA/IHN1Y2Nlc3MgOiBlcnJvciBdICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIENvbXBsZXRlXG5cdFx0XHRjb21wbGV0ZURlZmVycmVkLmZpcmVXaXRoKCBjYWxsYmFja0NvbnRleHQsIFsganFYSFIsIHN0YXR1c1RleHQgXSApO1xuXG5cdFx0XHRpZiAoIGZpcmVHbG9iYWxzICkge1xuXHRcdFx0XHRnbG9iYWxFdmVudENvbnRleHQudHJpZ2dlciggXCJhamF4Q29tcGxldGVcIiwgWyBqcVhIUiwgcyBdICk7XG5cdFx0XHRcdC8vIEhhbmRsZSB0aGUgZ2xvYmFsIEFKQVggY291bnRlclxuXHRcdFx0XHRpZiAoICEoIC0talF1ZXJ5LmFjdGl2ZSApICkge1xuXHRcdFx0XHRcdGpRdWVyeS5ldmVudC50cmlnZ2VyKFwiYWpheFN0b3BcIik7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4ganFYSFI7XG5cdH0sXG5cblx0Z2V0SlNPTjogZnVuY3Rpb24oIHVybCwgZGF0YSwgY2FsbGJhY2sgKSB7XG5cdFx0cmV0dXJuIGpRdWVyeS5nZXQoIHVybCwgZGF0YSwgY2FsbGJhY2ssIFwianNvblwiICk7XG5cdH0sXG5cblx0Z2V0U2NyaXB0OiBmdW5jdGlvbiggdXJsLCBjYWxsYmFjayApIHtcblx0XHRyZXR1cm4galF1ZXJ5LmdldCggdXJsLCB1bmRlZmluZWQsIGNhbGxiYWNrLCBcInNjcmlwdFwiICk7XG5cdH1cbn0pO1xuXG5qUXVlcnkuZWFjaCggWyBcImdldFwiLCBcInBvc3RcIiBdLCBmdW5jdGlvbiggaSwgbWV0aG9kICkge1xuXHRqUXVlcnlbIG1ldGhvZCBdID0gZnVuY3Rpb24oIHVybCwgZGF0YSwgY2FsbGJhY2ssIHR5cGUgKSB7XG5cdFx0Ly8gU2hpZnQgYXJndW1lbnRzIGlmIGRhdGEgYXJndW1lbnQgd2FzIG9taXR0ZWRcblx0XHRpZiAoIGpRdWVyeS5pc0Z1bmN0aW9uKCBkYXRhICkgKSB7XG5cdFx0XHR0eXBlID0gdHlwZSB8fCBjYWxsYmFjaztcblx0XHRcdGNhbGxiYWNrID0gZGF0YTtcblx0XHRcdGRhdGEgPSB1bmRlZmluZWQ7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGpRdWVyeS5hamF4KHtcblx0XHRcdHVybDogdXJsLFxuXHRcdFx0dHlwZTogbWV0aG9kLFxuXHRcdFx0ZGF0YVR5cGU6IHR5cGUsXG5cdFx0XHRkYXRhOiBkYXRhLFxuXHRcdFx0c3VjY2VzczogY2FsbGJhY2tcblx0XHR9KTtcblx0fTtcbn0pO1xuXG5cbmpRdWVyeS5fZXZhbFVybCA9IGZ1bmN0aW9uKCB1cmwgKSB7XG5cdHJldHVybiBqUXVlcnkuYWpheCh7XG5cdFx0dXJsOiB1cmwsXG5cdFx0dHlwZTogXCJHRVRcIixcblx0XHRkYXRhVHlwZTogXCJzY3JpcHRcIixcblx0XHRhc3luYzogZmFsc2UsXG5cdFx0Z2xvYmFsOiBmYWxzZSxcblx0XHRcInRocm93c1wiOiB0cnVlXG5cdH0pO1xufTtcblxuXG5qUXVlcnkuZm4uZXh0ZW5kKHtcblx0d3JhcEFsbDogZnVuY3Rpb24oIGh0bWwgKSB7XG5cdFx0dmFyIHdyYXA7XG5cblx0XHRpZiAoIGpRdWVyeS5pc0Z1bmN0aW9uKCBodG1sICkgKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKCBpICkge1xuXHRcdFx0XHRqUXVlcnkoIHRoaXMgKS53cmFwQWxsKCBodG1sLmNhbGwodGhpcywgaSkgKTtcblx0XHRcdH0pO1xuXHRcdH1cblxuXHRcdGlmICggdGhpc1sgMCBdICkge1xuXG5cdFx0XHQvLyBUaGUgZWxlbWVudHMgdG8gd3JhcCB0aGUgdGFyZ2V0IGFyb3VuZFxuXHRcdFx0d3JhcCA9IGpRdWVyeSggaHRtbCwgdGhpc1sgMCBdLm93bmVyRG9jdW1lbnQgKS5lcSggMCApLmNsb25lKCB0cnVlICk7XG5cblx0XHRcdGlmICggdGhpc1sgMCBdLnBhcmVudE5vZGUgKSB7XG5cdFx0XHRcdHdyYXAuaW5zZXJ0QmVmb3JlKCB0aGlzWyAwIF0gKTtcblx0XHRcdH1cblxuXHRcdFx0d3JhcC5tYXAoZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHZhciBlbGVtID0gdGhpcztcblxuXHRcdFx0XHR3aGlsZSAoIGVsZW0uZmlyc3RFbGVtZW50Q2hpbGQgKSB7XG5cdFx0XHRcdFx0ZWxlbSA9IGVsZW0uZmlyc3RFbGVtZW50Q2hpbGQ7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRyZXR1cm4gZWxlbTtcblx0XHRcdH0pLmFwcGVuZCggdGhpcyApO1xuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdHdyYXBJbm5lcjogZnVuY3Rpb24oIGh0bWwgKSB7XG5cdFx0aWYgKCBqUXVlcnkuaXNGdW5jdGlvbiggaHRtbCApICkge1xuXHRcdFx0cmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbiggaSApIHtcblx0XHRcdFx0alF1ZXJ5KCB0aGlzICkud3JhcElubmVyKCBodG1sLmNhbGwodGhpcywgaSkgKTtcblx0XHRcdH0pO1xuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgc2VsZiA9IGpRdWVyeSggdGhpcyApLFxuXHRcdFx0XHRjb250ZW50cyA9IHNlbGYuY29udGVudHMoKTtcblxuXHRcdFx0aWYgKCBjb250ZW50cy5sZW5ndGggKSB7XG5cdFx0XHRcdGNvbnRlbnRzLndyYXBBbGwoIGh0bWwgKTtcblxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0c2VsZi5hcHBlbmQoIGh0bWwgKTtcblx0XHRcdH1cblx0XHR9KTtcblx0fSxcblxuXHR3cmFwOiBmdW5jdGlvbiggaHRtbCApIHtcblx0XHR2YXIgaXNGdW5jdGlvbiA9IGpRdWVyeS5pc0Z1bmN0aW9uKCBodG1sICk7XG5cblx0XHRyZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKCBpICkge1xuXHRcdFx0alF1ZXJ5KCB0aGlzICkud3JhcEFsbCggaXNGdW5jdGlvbiA/IGh0bWwuY2FsbCh0aGlzLCBpKSA6IGh0bWwgKTtcblx0XHR9KTtcblx0fSxcblxuXHR1bndyYXA6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLnBhcmVudCgpLmVhY2goZnVuY3Rpb24oKSB7XG5cdFx0XHRpZiAoICFqUXVlcnkubm9kZU5hbWUoIHRoaXMsIFwiYm9keVwiICkgKSB7XG5cdFx0XHRcdGpRdWVyeSggdGhpcyApLnJlcGxhY2VXaXRoKCB0aGlzLmNoaWxkTm9kZXMgKTtcblx0XHRcdH1cblx0XHR9KS5lbmQoKTtcblx0fVxufSk7XG5cblxualF1ZXJ5LmV4cHIuZmlsdGVycy5oaWRkZW4gPSBmdW5jdGlvbiggZWxlbSApIHtcblx0Ly8gU3VwcG9ydDogT3BlcmEgPD0gMTIuMTJcblx0Ly8gT3BlcmEgcmVwb3J0cyBvZmZzZXRXaWR0aHMgYW5kIG9mZnNldEhlaWdodHMgbGVzcyB0aGFuIHplcm8gb24gc29tZSBlbGVtZW50c1xuXHRyZXR1cm4gZWxlbS5vZmZzZXRXaWR0aCA8PSAwICYmIGVsZW0ub2Zmc2V0SGVpZ2h0IDw9IDA7XG59O1xualF1ZXJ5LmV4cHIuZmlsdGVycy52aXNpYmxlID0gZnVuY3Rpb24oIGVsZW0gKSB7XG5cdHJldHVybiAhalF1ZXJ5LmV4cHIuZmlsdGVycy5oaWRkZW4oIGVsZW0gKTtcbn07XG5cblxuXG5cbnZhciByMjAgPSAvJTIwL2csXG5cdHJicmFja2V0ID0gL1xcW1xcXSQvLFxuXHRyQ1JMRiA9IC9cXHI/XFxuL2csXG5cdHJzdWJtaXR0ZXJUeXBlcyA9IC9eKD86c3VibWl0fGJ1dHRvbnxpbWFnZXxyZXNldHxmaWxlKSQvaSxcblx0cnN1Ym1pdHRhYmxlID0gL14oPzppbnB1dHxzZWxlY3R8dGV4dGFyZWF8a2V5Z2VuKS9pO1xuXG5mdW5jdGlvbiBidWlsZFBhcmFtcyggcHJlZml4LCBvYmosIHRyYWRpdGlvbmFsLCBhZGQgKSB7XG5cdHZhciBuYW1lO1xuXG5cdGlmICggalF1ZXJ5LmlzQXJyYXkoIG9iaiApICkge1xuXHRcdC8vIFNlcmlhbGl6ZSBhcnJheSBpdGVtLlxuXHRcdGpRdWVyeS5lYWNoKCBvYmosIGZ1bmN0aW9uKCBpLCB2ICkge1xuXHRcdFx0aWYgKCB0cmFkaXRpb25hbCB8fCByYnJhY2tldC50ZXN0KCBwcmVmaXggKSApIHtcblx0XHRcdFx0Ly8gVHJlYXQgZWFjaCBhcnJheSBpdGVtIGFzIGEgc2NhbGFyLlxuXHRcdFx0XHRhZGQoIHByZWZpeCwgdiApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHQvLyBJdGVtIGlzIG5vbi1zY2FsYXIgKGFycmF5IG9yIG9iamVjdCksIGVuY29kZSBpdHMgbnVtZXJpYyBpbmRleC5cblx0XHRcdFx0YnVpbGRQYXJhbXMoIHByZWZpeCArIFwiW1wiICsgKCB0eXBlb2YgdiA9PT0gXCJvYmplY3RcIiA/IGkgOiBcIlwiICkgKyBcIl1cIiwgdiwgdHJhZGl0aW9uYWwsIGFkZCApO1xuXHRcdFx0fVxuXHRcdH0pO1xuXG5cdH0gZWxzZSBpZiAoICF0cmFkaXRpb25hbCAmJiBqUXVlcnkudHlwZSggb2JqICkgPT09IFwib2JqZWN0XCIgKSB7XG5cdFx0Ly8gU2VyaWFsaXplIG9iamVjdCBpdGVtLlxuXHRcdGZvciAoIG5hbWUgaW4gb2JqICkge1xuXHRcdFx0YnVpbGRQYXJhbXMoIHByZWZpeCArIFwiW1wiICsgbmFtZSArIFwiXVwiLCBvYmpbIG5hbWUgXSwgdHJhZGl0aW9uYWwsIGFkZCApO1xuXHRcdH1cblxuXHR9IGVsc2Uge1xuXHRcdC8vIFNlcmlhbGl6ZSBzY2FsYXIgaXRlbS5cblx0XHRhZGQoIHByZWZpeCwgb2JqICk7XG5cdH1cbn1cblxuLy8gU2VyaWFsaXplIGFuIGFycmF5IG9mIGZvcm0gZWxlbWVudHMgb3IgYSBzZXQgb2Zcbi8vIGtleS92YWx1ZXMgaW50byBhIHF1ZXJ5IHN0cmluZ1xualF1ZXJ5LnBhcmFtID0gZnVuY3Rpb24oIGEsIHRyYWRpdGlvbmFsICkge1xuXHR2YXIgcHJlZml4LFxuXHRcdHMgPSBbXSxcblx0XHRhZGQgPSBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblx0XHRcdC8vIElmIHZhbHVlIGlzIGEgZnVuY3Rpb24sIGludm9rZSBpdCBhbmQgcmV0dXJuIGl0cyB2YWx1ZVxuXHRcdFx0dmFsdWUgPSBqUXVlcnkuaXNGdW5jdGlvbiggdmFsdWUgKSA/IHZhbHVlKCkgOiAoIHZhbHVlID09IG51bGwgPyBcIlwiIDogdmFsdWUgKTtcblx0XHRcdHNbIHMubGVuZ3RoIF0gPSBlbmNvZGVVUklDb21wb25lbnQoIGtleSApICsgXCI9XCIgKyBlbmNvZGVVUklDb21wb25lbnQoIHZhbHVlICk7XG5cdFx0fTtcblxuXHQvLyBTZXQgdHJhZGl0aW9uYWwgdG8gdHJ1ZSBmb3IgalF1ZXJ5IDw9IDEuMy4yIGJlaGF2aW9yLlxuXHRpZiAoIHRyYWRpdGlvbmFsID09PSB1bmRlZmluZWQgKSB7XG5cdFx0dHJhZGl0aW9uYWwgPSBqUXVlcnkuYWpheFNldHRpbmdzICYmIGpRdWVyeS5hamF4U2V0dGluZ3MudHJhZGl0aW9uYWw7XG5cdH1cblxuXHQvLyBJZiBhbiBhcnJheSB3YXMgcGFzc2VkIGluLCBhc3N1bWUgdGhhdCBpdCBpcyBhbiBhcnJheSBvZiBmb3JtIGVsZW1lbnRzLlxuXHRpZiAoIGpRdWVyeS5pc0FycmF5KCBhICkgfHwgKCBhLmpxdWVyeSAmJiAhalF1ZXJ5LmlzUGxhaW5PYmplY3QoIGEgKSApICkge1xuXHRcdC8vIFNlcmlhbGl6ZSB0aGUgZm9ybSBlbGVtZW50c1xuXHRcdGpRdWVyeS5lYWNoKCBhLCBmdW5jdGlvbigpIHtcblx0XHRcdGFkZCggdGhpcy5uYW1lLCB0aGlzLnZhbHVlICk7XG5cdFx0fSk7XG5cblx0fSBlbHNlIHtcblx0XHQvLyBJZiB0cmFkaXRpb25hbCwgZW5jb2RlIHRoZSBcIm9sZFwiIHdheSAodGhlIHdheSAxLjMuMiBvciBvbGRlclxuXHRcdC8vIGRpZCBpdCksIG90aGVyd2lzZSBlbmNvZGUgcGFyYW1zIHJlY3Vyc2l2ZWx5LlxuXHRcdGZvciAoIHByZWZpeCBpbiBhICkge1xuXHRcdFx0YnVpbGRQYXJhbXMoIHByZWZpeCwgYVsgcHJlZml4IF0sIHRyYWRpdGlvbmFsLCBhZGQgKTtcblx0XHR9XG5cdH1cblxuXHQvLyBSZXR1cm4gdGhlIHJlc3VsdGluZyBzZXJpYWxpemF0aW9uXG5cdHJldHVybiBzLmpvaW4oIFwiJlwiICkucmVwbGFjZSggcjIwLCBcIitcIiApO1xufTtcblxualF1ZXJ5LmZuLmV4dGVuZCh7XG5cdHNlcmlhbGl6ZTogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIGpRdWVyeS5wYXJhbSggdGhpcy5zZXJpYWxpemVBcnJheSgpICk7XG5cdH0sXG5cdHNlcmlhbGl6ZUFycmF5OiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5tYXAoZnVuY3Rpb24oKSB7XG5cdFx0XHQvLyBDYW4gYWRkIHByb3BIb29rIGZvciBcImVsZW1lbnRzXCIgdG8gZmlsdGVyIG9yIGFkZCBmb3JtIGVsZW1lbnRzXG5cdFx0XHR2YXIgZWxlbWVudHMgPSBqUXVlcnkucHJvcCggdGhpcywgXCJlbGVtZW50c1wiICk7XG5cdFx0XHRyZXR1cm4gZWxlbWVudHMgPyBqUXVlcnkubWFrZUFycmF5KCBlbGVtZW50cyApIDogdGhpcztcblx0XHR9KVxuXHRcdC5maWx0ZXIoZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgdHlwZSA9IHRoaXMudHlwZTtcblxuXHRcdFx0Ly8gVXNlIC5pcyggXCI6ZGlzYWJsZWRcIiApIHNvIHRoYXQgZmllbGRzZXRbZGlzYWJsZWRdIHdvcmtzXG5cdFx0XHRyZXR1cm4gdGhpcy5uYW1lICYmICFqUXVlcnkoIHRoaXMgKS5pcyggXCI6ZGlzYWJsZWRcIiApICYmXG5cdFx0XHRcdHJzdWJtaXR0YWJsZS50ZXN0KCB0aGlzLm5vZGVOYW1lICkgJiYgIXJzdWJtaXR0ZXJUeXBlcy50ZXN0KCB0eXBlICkgJiZcblx0XHRcdFx0KCB0aGlzLmNoZWNrZWQgfHwgIXJjaGVja2FibGVUeXBlLnRlc3QoIHR5cGUgKSApO1xuXHRcdH0pXG5cdFx0Lm1hcChmdW5jdGlvbiggaSwgZWxlbSApIHtcblx0XHRcdHZhciB2YWwgPSBqUXVlcnkoIHRoaXMgKS52YWwoKTtcblxuXHRcdFx0cmV0dXJuIHZhbCA9PSBudWxsID9cblx0XHRcdFx0bnVsbCA6XG5cdFx0XHRcdGpRdWVyeS5pc0FycmF5KCB2YWwgKSA/XG5cdFx0XHRcdFx0alF1ZXJ5Lm1hcCggdmFsLCBmdW5jdGlvbiggdmFsICkge1xuXHRcdFx0XHRcdFx0cmV0dXJuIHsgbmFtZTogZWxlbS5uYW1lLCB2YWx1ZTogdmFsLnJlcGxhY2UoIHJDUkxGLCBcIlxcclxcblwiICkgfTtcblx0XHRcdFx0XHR9KSA6XG5cdFx0XHRcdFx0eyBuYW1lOiBlbGVtLm5hbWUsIHZhbHVlOiB2YWwucmVwbGFjZSggckNSTEYsIFwiXFxyXFxuXCIgKSB9O1xuXHRcdH0pLmdldCgpO1xuXHR9XG59KTtcblxuXG5qUXVlcnkuYWpheFNldHRpbmdzLnhociA9IGZ1bmN0aW9uKCkge1xuXHR0cnkge1xuXHRcdHJldHVybiBuZXcgWE1MSHR0cFJlcXVlc3QoKTtcblx0fSBjYXRjaCggZSApIHt9XG59O1xuXG52YXIgeGhySWQgPSAwLFxuXHR4aHJDYWxsYmFja3MgPSB7fSxcblx0eGhyU3VjY2Vzc1N0YXR1cyA9IHtcblx0XHQvLyBmaWxlIHByb3RvY29sIGFsd2F5cyB5aWVsZHMgc3RhdHVzIGNvZGUgMCwgYXNzdW1lIDIwMFxuXHRcdDA6IDIwMCxcblx0XHQvLyBTdXBwb3J0OiBJRTlcblx0XHQvLyAjMTQ1MDogc29tZXRpbWVzIElFIHJldHVybnMgMTIyMyB3aGVuIGl0IHNob3VsZCBiZSAyMDRcblx0XHQxMjIzOiAyMDRcblx0fSxcblx0eGhyU3VwcG9ydGVkID0galF1ZXJ5LmFqYXhTZXR0aW5ncy54aHIoKTtcblxuLy8gU3VwcG9ydDogSUU5XG4vLyBPcGVuIHJlcXVlc3RzIG11c3QgYmUgbWFudWFsbHkgYWJvcnRlZCBvbiB1bmxvYWQgKCM1MjgwKVxuLy8gU2VlIGh0dHBzOi8vc3VwcG9ydC5taWNyb3NvZnQuY29tL2tiLzI4NTY3NDYgZm9yIG1vcmUgaW5mb1xuaWYgKCB3aW5kb3cuYXR0YWNoRXZlbnQgKSB7XG5cdHdpbmRvdy5hdHRhY2hFdmVudCggXCJvbnVubG9hZFwiLCBmdW5jdGlvbigpIHtcblx0XHRmb3IgKCB2YXIga2V5IGluIHhockNhbGxiYWNrcyApIHtcblx0XHRcdHhockNhbGxiYWNrc1sga2V5IF0oKTtcblx0XHR9XG5cdH0pO1xufVxuXG5zdXBwb3J0LmNvcnMgPSAhIXhoclN1cHBvcnRlZCAmJiAoIFwid2l0aENyZWRlbnRpYWxzXCIgaW4geGhyU3VwcG9ydGVkICk7XG5zdXBwb3J0LmFqYXggPSB4aHJTdXBwb3J0ZWQgPSAhIXhoclN1cHBvcnRlZDtcblxualF1ZXJ5LmFqYXhUcmFuc3BvcnQoZnVuY3Rpb24oIG9wdGlvbnMgKSB7XG5cdHZhciBjYWxsYmFjaztcblxuXHQvLyBDcm9zcyBkb21haW4gb25seSBhbGxvd2VkIGlmIHN1cHBvcnRlZCB0aHJvdWdoIFhNTEh0dHBSZXF1ZXN0XG5cdGlmICggc3VwcG9ydC5jb3JzIHx8IHhoclN1cHBvcnRlZCAmJiAhb3B0aW9ucy5jcm9zc0RvbWFpbiApIHtcblx0XHRyZXR1cm4ge1xuXHRcdFx0c2VuZDogZnVuY3Rpb24oIGhlYWRlcnMsIGNvbXBsZXRlICkge1xuXHRcdFx0XHR2YXIgaSxcblx0XHRcdFx0XHR4aHIgPSBvcHRpb25zLnhocigpLFxuXHRcdFx0XHRcdGlkID0gKyt4aHJJZDtcblxuXHRcdFx0XHR4aHIub3Blbiggb3B0aW9ucy50eXBlLCBvcHRpb25zLnVybCwgb3B0aW9ucy5hc3luYywgb3B0aW9ucy51c2VybmFtZSwgb3B0aW9ucy5wYXNzd29yZCApO1xuXG5cdFx0XHRcdC8vIEFwcGx5IGN1c3RvbSBmaWVsZHMgaWYgcHJvdmlkZWRcblx0XHRcdFx0aWYgKCBvcHRpb25zLnhockZpZWxkcyApIHtcblx0XHRcdFx0XHRmb3IgKCBpIGluIG9wdGlvbnMueGhyRmllbGRzICkge1xuXHRcdFx0XHRcdFx0eGhyWyBpIF0gPSBvcHRpb25zLnhockZpZWxkc1sgaSBdO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIE92ZXJyaWRlIG1pbWUgdHlwZSBpZiBuZWVkZWRcblx0XHRcdFx0aWYgKCBvcHRpb25zLm1pbWVUeXBlICYmIHhoci5vdmVycmlkZU1pbWVUeXBlICkge1xuXHRcdFx0XHRcdHhoci5vdmVycmlkZU1pbWVUeXBlKCBvcHRpb25zLm1pbWVUeXBlICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBYLVJlcXVlc3RlZC1XaXRoIGhlYWRlclxuXHRcdFx0XHQvLyBGb3IgY3Jvc3MtZG9tYWluIHJlcXVlc3RzLCBzZWVpbmcgYXMgY29uZGl0aW9ucyBmb3IgYSBwcmVmbGlnaHQgYXJlXG5cdFx0XHRcdC8vIGFraW4gdG8gYSBqaWdzYXcgcHV6emxlLCB3ZSBzaW1wbHkgbmV2ZXIgc2V0IGl0IHRvIGJlIHN1cmUuXG5cdFx0XHRcdC8vIChpdCBjYW4gYWx3YXlzIGJlIHNldCBvbiBhIHBlci1yZXF1ZXN0IGJhc2lzIG9yIGV2ZW4gdXNpbmcgYWpheFNldHVwKVxuXHRcdFx0XHQvLyBGb3Igc2FtZS1kb21haW4gcmVxdWVzdHMsIHdvbid0IGNoYW5nZSBoZWFkZXIgaWYgYWxyZWFkeSBwcm92aWRlZC5cblx0XHRcdFx0aWYgKCAhb3B0aW9ucy5jcm9zc0RvbWFpbiAmJiAhaGVhZGVyc1tcIlgtUmVxdWVzdGVkLVdpdGhcIl0gKSB7XG5cdFx0XHRcdFx0aGVhZGVyc1tcIlgtUmVxdWVzdGVkLVdpdGhcIl0gPSBcIlhNTEh0dHBSZXF1ZXN0XCI7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBTZXQgaGVhZGVyc1xuXHRcdFx0XHRmb3IgKCBpIGluIGhlYWRlcnMgKSB7XG5cdFx0XHRcdFx0eGhyLnNldFJlcXVlc3RIZWFkZXIoIGksIGhlYWRlcnNbIGkgXSApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gQ2FsbGJhY2tcblx0XHRcdFx0Y2FsbGJhY2sgPSBmdW5jdGlvbiggdHlwZSApIHtcblx0XHRcdFx0XHRyZXR1cm4gZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0XHRpZiAoIGNhbGxiYWNrICkge1xuXHRcdFx0XHRcdFx0XHRkZWxldGUgeGhyQ2FsbGJhY2tzWyBpZCBdO1xuXHRcdFx0XHRcdFx0XHRjYWxsYmFjayA9IHhoci5vbmxvYWQgPSB4aHIub25lcnJvciA9IG51bGw7XG5cblx0XHRcdFx0XHRcdFx0aWYgKCB0eXBlID09PSBcImFib3J0XCIgKSB7XG5cdFx0XHRcdFx0XHRcdFx0eGhyLmFib3J0KCk7XG5cdFx0XHRcdFx0XHRcdH0gZWxzZSBpZiAoIHR5cGUgPT09IFwiZXJyb3JcIiApIHtcblx0XHRcdFx0XHRcdFx0XHRjb21wbGV0ZShcblx0XHRcdFx0XHRcdFx0XHRcdC8vIGZpbGU6IHByb3RvY29sIGFsd2F5cyB5aWVsZHMgc3RhdHVzIDA7IHNlZSAjODYwNSwgIzE0MjA3XG5cdFx0XHRcdFx0XHRcdFx0XHR4aHIuc3RhdHVzLFxuXHRcdFx0XHRcdFx0XHRcdFx0eGhyLnN0YXR1c1RleHRcblx0XHRcdFx0XHRcdFx0XHQpO1xuXHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRcdGNvbXBsZXRlKFxuXHRcdFx0XHRcdFx0XHRcdFx0eGhyU3VjY2Vzc1N0YXR1c1sgeGhyLnN0YXR1cyBdIHx8IHhoci5zdGF0dXMsXG5cdFx0XHRcdFx0XHRcdFx0XHR4aHIuc3RhdHVzVGV4dCxcblx0XHRcdFx0XHRcdFx0XHRcdC8vIFN1cHBvcnQ6IElFOVxuXHRcdFx0XHRcdFx0XHRcdFx0Ly8gQWNjZXNzaW5nIGJpbmFyeS1kYXRhIHJlc3BvbnNlVGV4dCB0aHJvd3MgYW4gZXhjZXB0aW9uXG5cdFx0XHRcdFx0XHRcdFx0XHQvLyAoIzExNDI2KVxuXHRcdFx0XHRcdFx0XHRcdFx0dHlwZW9mIHhoci5yZXNwb25zZVRleHQgPT09IFwic3RyaW5nXCIgPyB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdHRleHQ6IHhoci5yZXNwb25zZVRleHRcblx0XHRcdFx0XHRcdFx0XHRcdH0gOiB1bmRlZmluZWQsXG5cdFx0XHRcdFx0XHRcdFx0XHR4aHIuZ2V0QWxsUmVzcG9uc2VIZWFkZXJzKClcblx0XHRcdFx0XHRcdFx0XHQpO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fTtcblx0XHRcdFx0fTtcblxuXHRcdFx0XHQvLyBMaXN0ZW4gdG8gZXZlbnRzXG5cdFx0XHRcdHhoci5vbmxvYWQgPSBjYWxsYmFjaygpO1xuXHRcdFx0XHR4aHIub25lcnJvciA9IGNhbGxiYWNrKFwiZXJyb3JcIik7XG5cblx0XHRcdFx0Ly8gQ3JlYXRlIHRoZSBhYm9ydCBjYWxsYmFja1xuXHRcdFx0XHRjYWxsYmFjayA9IHhockNhbGxiYWNrc1sgaWQgXSA9IGNhbGxiYWNrKFwiYWJvcnRcIik7XG5cblx0XHRcdFx0dHJ5IHtcblx0XHRcdFx0XHQvLyBEbyBzZW5kIHRoZSByZXF1ZXN0ICh0aGlzIG1heSByYWlzZSBhbiBleGNlcHRpb24pXG5cdFx0XHRcdFx0eGhyLnNlbmQoIG9wdGlvbnMuaGFzQ29udGVudCAmJiBvcHRpb25zLmRhdGEgfHwgbnVsbCApO1xuXHRcdFx0XHR9IGNhdGNoICggZSApIHtcblx0XHRcdFx0XHQvLyAjMTQ2ODM6IE9ubHkgcmV0aHJvdyBpZiB0aGlzIGhhc24ndCBiZWVuIG5vdGlmaWVkIGFzIGFuIGVycm9yIHlldFxuXHRcdFx0XHRcdGlmICggY2FsbGJhY2sgKSB7XG5cdFx0XHRcdFx0XHR0aHJvdyBlO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fSxcblxuXHRcdFx0YWJvcnQ6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRpZiAoIGNhbGxiYWNrICkge1xuXHRcdFx0XHRcdGNhbGxiYWNrKCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9O1xuXHR9XG59KTtcblxuXG5cblxuLy8gSW5zdGFsbCBzY3JpcHQgZGF0YVR5cGVcbmpRdWVyeS5hamF4U2V0dXAoe1xuXHRhY2NlcHRzOiB7XG5cdFx0c2NyaXB0OiBcInRleHQvamF2YXNjcmlwdCwgYXBwbGljYXRpb24vamF2YXNjcmlwdCwgYXBwbGljYXRpb24vZWNtYXNjcmlwdCwgYXBwbGljYXRpb24veC1lY21hc2NyaXB0XCJcblx0fSxcblx0Y29udGVudHM6IHtcblx0XHRzY3JpcHQ6IC8oPzpqYXZhfGVjbWEpc2NyaXB0L1xuXHR9LFxuXHRjb252ZXJ0ZXJzOiB7XG5cdFx0XCJ0ZXh0IHNjcmlwdFwiOiBmdW5jdGlvbiggdGV4dCApIHtcblx0XHRcdGpRdWVyeS5nbG9iYWxFdmFsKCB0ZXh0ICk7XG5cdFx0XHRyZXR1cm4gdGV4dDtcblx0XHR9XG5cdH1cbn0pO1xuXG4vLyBIYW5kbGUgY2FjaGUncyBzcGVjaWFsIGNhc2UgYW5kIGNyb3NzRG9tYWluXG5qUXVlcnkuYWpheFByZWZpbHRlciggXCJzY3JpcHRcIiwgZnVuY3Rpb24oIHMgKSB7XG5cdGlmICggcy5jYWNoZSA9PT0gdW5kZWZpbmVkICkge1xuXHRcdHMuY2FjaGUgPSBmYWxzZTtcblx0fVxuXHRpZiAoIHMuY3Jvc3NEb21haW4gKSB7XG5cdFx0cy50eXBlID0gXCJHRVRcIjtcblx0fVxufSk7XG5cbi8vIEJpbmQgc2NyaXB0IHRhZyBoYWNrIHRyYW5zcG9ydFxualF1ZXJ5LmFqYXhUcmFuc3BvcnQoIFwic2NyaXB0XCIsIGZ1bmN0aW9uKCBzICkge1xuXHQvLyBUaGlzIHRyYW5zcG9ydCBvbmx5IGRlYWxzIHdpdGggY3Jvc3MgZG9tYWluIHJlcXVlc3RzXG5cdGlmICggcy5jcm9zc0RvbWFpbiApIHtcblx0XHR2YXIgc2NyaXB0LCBjYWxsYmFjaztcblx0XHRyZXR1cm4ge1xuXHRcdFx0c2VuZDogZnVuY3Rpb24oIF8sIGNvbXBsZXRlICkge1xuXHRcdFx0XHRzY3JpcHQgPSBqUXVlcnkoXCI8c2NyaXB0PlwiKS5wcm9wKHtcblx0XHRcdFx0XHRhc3luYzogdHJ1ZSxcblx0XHRcdFx0XHRjaGFyc2V0OiBzLnNjcmlwdENoYXJzZXQsXG5cdFx0XHRcdFx0c3JjOiBzLnVybFxuXHRcdFx0XHR9KS5vbihcblx0XHRcdFx0XHRcImxvYWQgZXJyb3JcIixcblx0XHRcdFx0XHRjYWxsYmFjayA9IGZ1bmN0aW9uKCBldnQgKSB7XG5cdFx0XHRcdFx0XHRzY3JpcHQucmVtb3ZlKCk7XG5cdFx0XHRcdFx0XHRjYWxsYmFjayA9IG51bGw7XG5cdFx0XHRcdFx0XHRpZiAoIGV2dCApIHtcblx0XHRcdFx0XHRcdFx0Y29tcGxldGUoIGV2dC50eXBlID09PSBcImVycm9yXCIgPyA0MDQgOiAyMDAsIGV2dC50eXBlICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHQpO1xuXHRcdFx0XHRkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKCBzY3JpcHRbIDAgXSApO1xuXHRcdFx0fSxcblx0XHRcdGFib3J0OiBmdW5jdGlvbigpIHtcblx0XHRcdFx0aWYgKCBjYWxsYmFjayApIHtcblx0XHRcdFx0XHRjYWxsYmFjaygpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fTtcblx0fVxufSk7XG5cblxuXG5cbnZhciBvbGRDYWxsYmFja3MgPSBbXSxcblx0cmpzb25wID0gLyg9KVxcPyg/PSZ8JCl8XFw/XFw/LztcblxuLy8gRGVmYXVsdCBqc29ucCBzZXR0aW5nc1xualF1ZXJ5LmFqYXhTZXR1cCh7XG5cdGpzb25wOiBcImNhbGxiYWNrXCIsXG5cdGpzb25wQ2FsbGJhY2s6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBjYWxsYmFjayA9IG9sZENhbGxiYWNrcy5wb3AoKSB8fCAoIGpRdWVyeS5leHBhbmRvICsgXCJfXCIgKyAoIG5vbmNlKysgKSApO1xuXHRcdHRoaXNbIGNhbGxiYWNrIF0gPSB0cnVlO1xuXHRcdHJldHVybiBjYWxsYmFjaztcblx0fVxufSk7XG5cbi8vIERldGVjdCwgbm9ybWFsaXplIG9wdGlvbnMgYW5kIGluc3RhbGwgY2FsbGJhY2tzIGZvciBqc29ucCByZXF1ZXN0c1xualF1ZXJ5LmFqYXhQcmVmaWx0ZXIoIFwianNvbiBqc29ucFwiLCBmdW5jdGlvbiggcywgb3JpZ2luYWxTZXR0aW5ncywganFYSFIgKSB7XG5cblx0dmFyIGNhbGxiYWNrTmFtZSwgb3ZlcndyaXR0ZW4sIHJlc3BvbnNlQ29udGFpbmVyLFxuXHRcdGpzb25Qcm9wID0gcy5qc29ucCAhPT0gZmFsc2UgJiYgKCByanNvbnAudGVzdCggcy51cmwgKSA/XG5cdFx0XHRcInVybFwiIDpcblx0XHRcdHR5cGVvZiBzLmRhdGEgPT09IFwic3RyaW5nXCIgJiYgISggcy5jb250ZW50VHlwZSB8fCBcIlwiICkuaW5kZXhPZihcImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZFwiKSAmJiByanNvbnAudGVzdCggcy5kYXRhICkgJiYgXCJkYXRhXCJcblx0XHQpO1xuXG5cdC8vIEhhbmRsZSBpZmYgdGhlIGV4cGVjdGVkIGRhdGEgdHlwZSBpcyBcImpzb25wXCIgb3Igd2UgaGF2ZSBhIHBhcmFtZXRlciB0byBzZXRcblx0aWYgKCBqc29uUHJvcCB8fCBzLmRhdGFUeXBlc1sgMCBdID09PSBcImpzb25wXCIgKSB7XG5cblx0XHQvLyBHZXQgY2FsbGJhY2sgbmFtZSwgcmVtZW1iZXJpbmcgcHJlZXhpc3RpbmcgdmFsdWUgYXNzb2NpYXRlZCB3aXRoIGl0XG5cdFx0Y2FsbGJhY2tOYW1lID0gcy5qc29ucENhbGxiYWNrID0galF1ZXJ5LmlzRnVuY3Rpb24oIHMuanNvbnBDYWxsYmFjayApID9cblx0XHRcdHMuanNvbnBDYWxsYmFjaygpIDpcblx0XHRcdHMuanNvbnBDYWxsYmFjaztcblxuXHRcdC8vIEluc2VydCBjYWxsYmFjayBpbnRvIHVybCBvciBmb3JtIGRhdGFcblx0XHRpZiAoIGpzb25Qcm9wICkge1xuXHRcdFx0c1sganNvblByb3AgXSA9IHNbIGpzb25Qcm9wIF0ucmVwbGFjZSggcmpzb25wLCBcIiQxXCIgKyBjYWxsYmFja05hbWUgKTtcblx0XHR9IGVsc2UgaWYgKCBzLmpzb25wICE9PSBmYWxzZSApIHtcblx0XHRcdHMudXJsICs9ICggcnF1ZXJ5LnRlc3QoIHMudXJsICkgPyBcIiZcIiA6IFwiP1wiICkgKyBzLmpzb25wICsgXCI9XCIgKyBjYWxsYmFja05hbWU7XG5cdFx0fVxuXG5cdFx0Ly8gVXNlIGRhdGEgY29udmVydGVyIHRvIHJldHJpZXZlIGpzb24gYWZ0ZXIgc2NyaXB0IGV4ZWN1dGlvblxuXHRcdHMuY29udmVydGVyc1tcInNjcmlwdCBqc29uXCJdID0gZnVuY3Rpb24oKSB7XG5cdFx0XHRpZiAoICFyZXNwb25zZUNvbnRhaW5lciApIHtcblx0XHRcdFx0alF1ZXJ5LmVycm9yKCBjYWxsYmFja05hbWUgKyBcIiB3YXMgbm90IGNhbGxlZFwiICk7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gcmVzcG9uc2VDb250YWluZXJbIDAgXTtcblx0XHR9O1xuXG5cdFx0Ly8gZm9yY2UganNvbiBkYXRhVHlwZVxuXHRcdHMuZGF0YVR5cGVzWyAwIF0gPSBcImpzb25cIjtcblxuXHRcdC8vIEluc3RhbGwgY2FsbGJhY2tcblx0XHRvdmVyd3JpdHRlbiA9IHdpbmRvd1sgY2FsbGJhY2tOYW1lIF07XG5cdFx0d2luZG93WyBjYWxsYmFja05hbWUgXSA9IGZ1bmN0aW9uKCkge1xuXHRcdFx0cmVzcG9uc2VDb250YWluZXIgPSBhcmd1bWVudHM7XG5cdFx0fTtcblxuXHRcdC8vIENsZWFuLXVwIGZ1bmN0aW9uIChmaXJlcyBhZnRlciBjb252ZXJ0ZXJzKVxuXHRcdGpxWEhSLmFsd2F5cyhmdW5jdGlvbigpIHtcblx0XHRcdC8vIFJlc3RvcmUgcHJlZXhpc3RpbmcgdmFsdWVcblx0XHRcdHdpbmRvd1sgY2FsbGJhY2tOYW1lIF0gPSBvdmVyd3JpdHRlbjtcblxuXHRcdFx0Ly8gU2F2ZSBiYWNrIGFzIGZyZWVcblx0XHRcdGlmICggc1sgY2FsbGJhY2tOYW1lIF0gKSB7XG5cdFx0XHRcdC8vIG1ha2Ugc3VyZSB0aGF0IHJlLXVzaW5nIHRoZSBvcHRpb25zIGRvZXNuJ3Qgc2NyZXcgdGhpbmdzIGFyb3VuZFxuXHRcdFx0XHRzLmpzb25wQ2FsbGJhY2sgPSBvcmlnaW5hbFNldHRpbmdzLmpzb25wQ2FsbGJhY2s7XG5cblx0XHRcdFx0Ly8gc2F2ZSB0aGUgY2FsbGJhY2sgbmFtZSBmb3IgZnV0dXJlIHVzZVxuXHRcdFx0XHRvbGRDYWxsYmFja3MucHVzaCggY2FsbGJhY2tOYW1lICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIENhbGwgaWYgaXQgd2FzIGEgZnVuY3Rpb24gYW5kIHdlIGhhdmUgYSByZXNwb25zZVxuXHRcdFx0aWYgKCByZXNwb25zZUNvbnRhaW5lciAmJiBqUXVlcnkuaXNGdW5jdGlvbiggb3ZlcndyaXR0ZW4gKSApIHtcblx0XHRcdFx0b3ZlcndyaXR0ZW4oIHJlc3BvbnNlQ29udGFpbmVyWyAwIF0gKTtcblx0XHRcdH1cblxuXHRcdFx0cmVzcG9uc2VDb250YWluZXIgPSBvdmVyd3JpdHRlbiA9IHVuZGVmaW5lZDtcblx0XHR9KTtcblxuXHRcdC8vIERlbGVnYXRlIHRvIHNjcmlwdFxuXHRcdHJldHVybiBcInNjcmlwdFwiO1xuXHR9XG59KTtcblxuXG5cblxuLy8gZGF0YTogc3RyaW5nIG9mIGh0bWxcbi8vIGNvbnRleHQgKG9wdGlvbmFsKTogSWYgc3BlY2lmaWVkLCB0aGUgZnJhZ21lbnQgd2lsbCBiZSBjcmVhdGVkIGluIHRoaXMgY29udGV4dCwgZGVmYXVsdHMgdG8gZG9jdW1lbnRcbi8vIGtlZXBTY3JpcHRzIChvcHRpb25hbCk6IElmIHRydWUsIHdpbGwgaW5jbHVkZSBzY3JpcHRzIHBhc3NlZCBpbiB0aGUgaHRtbCBzdHJpbmdcbmpRdWVyeS5wYXJzZUhUTUwgPSBmdW5jdGlvbiggZGF0YSwgY29udGV4dCwga2VlcFNjcmlwdHMgKSB7XG5cdGlmICggIWRhdGEgfHwgdHlwZW9mIGRhdGEgIT09IFwic3RyaW5nXCIgKSB7XG5cdFx0cmV0dXJuIG51bGw7XG5cdH1cblx0aWYgKCB0eXBlb2YgY29udGV4dCA9PT0gXCJib29sZWFuXCIgKSB7XG5cdFx0a2VlcFNjcmlwdHMgPSBjb250ZXh0O1xuXHRcdGNvbnRleHQgPSBmYWxzZTtcblx0fVxuXHRjb250ZXh0ID0gY29udGV4dCB8fCBkb2N1bWVudDtcblxuXHR2YXIgcGFyc2VkID0gcnNpbmdsZVRhZy5leGVjKCBkYXRhICksXG5cdFx0c2NyaXB0cyA9ICFrZWVwU2NyaXB0cyAmJiBbXTtcblxuXHQvLyBTaW5nbGUgdGFnXG5cdGlmICggcGFyc2VkICkge1xuXHRcdHJldHVybiBbIGNvbnRleHQuY3JlYXRlRWxlbWVudCggcGFyc2VkWzFdICkgXTtcblx0fVxuXG5cdHBhcnNlZCA9IGpRdWVyeS5idWlsZEZyYWdtZW50KCBbIGRhdGEgXSwgY29udGV4dCwgc2NyaXB0cyApO1xuXG5cdGlmICggc2NyaXB0cyAmJiBzY3JpcHRzLmxlbmd0aCApIHtcblx0XHRqUXVlcnkoIHNjcmlwdHMgKS5yZW1vdmUoKTtcblx0fVxuXG5cdHJldHVybiBqUXVlcnkubWVyZ2UoIFtdLCBwYXJzZWQuY2hpbGROb2RlcyApO1xufTtcblxuXG4vLyBLZWVwIGEgY29weSBvZiB0aGUgb2xkIGxvYWQgbWV0aG9kXG52YXIgX2xvYWQgPSBqUXVlcnkuZm4ubG9hZDtcblxuLyoqXG4gKiBMb2FkIGEgdXJsIGludG8gYSBwYWdlXG4gKi9cbmpRdWVyeS5mbi5sb2FkID0gZnVuY3Rpb24oIHVybCwgcGFyYW1zLCBjYWxsYmFjayApIHtcblx0aWYgKCB0eXBlb2YgdXJsICE9PSBcInN0cmluZ1wiICYmIF9sb2FkICkge1xuXHRcdHJldHVybiBfbG9hZC5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdH1cblxuXHR2YXIgc2VsZWN0b3IsIHR5cGUsIHJlc3BvbnNlLFxuXHRcdHNlbGYgPSB0aGlzLFxuXHRcdG9mZiA9IHVybC5pbmRleE9mKFwiIFwiKTtcblxuXHRpZiAoIG9mZiA+PSAwICkge1xuXHRcdHNlbGVjdG9yID0galF1ZXJ5LnRyaW0oIHVybC5zbGljZSggb2ZmICkgKTtcblx0XHR1cmwgPSB1cmwuc2xpY2UoIDAsIG9mZiApO1xuXHR9XG5cblx0Ly8gSWYgaXQncyBhIGZ1bmN0aW9uXG5cdGlmICggalF1ZXJ5LmlzRnVuY3Rpb24oIHBhcmFtcyApICkge1xuXG5cdFx0Ly8gV2UgYXNzdW1lIHRoYXQgaXQncyB0aGUgY2FsbGJhY2tcblx0XHRjYWxsYmFjayA9IHBhcmFtcztcblx0XHRwYXJhbXMgPSB1bmRlZmluZWQ7XG5cblx0Ly8gT3RoZXJ3aXNlLCBidWlsZCBhIHBhcmFtIHN0cmluZ1xuXHR9IGVsc2UgaWYgKCBwYXJhbXMgJiYgdHlwZW9mIHBhcmFtcyA9PT0gXCJvYmplY3RcIiApIHtcblx0XHR0eXBlID0gXCJQT1NUXCI7XG5cdH1cblxuXHQvLyBJZiB3ZSBoYXZlIGVsZW1lbnRzIHRvIG1vZGlmeSwgbWFrZSB0aGUgcmVxdWVzdFxuXHRpZiAoIHNlbGYubGVuZ3RoID4gMCApIHtcblx0XHRqUXVlcnkuYWpheCh7XG5cdFx0XHR1cmw6IHVybCxcblxuXHRcdFx0Ly8gaWYgXCJ0eXBlXCIgdmFyaWFibGUgaXMgdW5kZWZpbmVkLCB0aGVuIFwiR0VUXCIgbWV0aG9kIHdpbGwgYmUgdXNlZFxuXHRcdFx0dHlwZTogdHlwZSxcblx0XHRcdGRhdGFUeXBlOiBcImh0bWxcIixcblx0XHRcdGRhdGE6IHBhcmFtc1xuXHRcdH0pLmRvbmUoZnVuY3Rpb24oIHJlc3BvbnNlVGV4dCApIHtcblxuXHRcdFx0Ly8gU2F2ZSByZXNwb25zZSBmb3IgdXNlIGluIGNvbXBsZXRlIGNhbGxiYWNrXG5cdFx0XHRyZXNwb25zZSA9IGFyZ3VtZW50cztcblxuXHRcdFx0c2VsZi5odG1sKCBzZWxlY3RvciA/XG5cblx0XHRcdFx0Ly8gSWYgYSBzZWxlY3RvciB3YXMgc3BlY2lmaWVkLCBsb2NhdGUgdGhlIHJpZ2h0IGVsZW1lbnRzIGluIGEgZHVtbXkgZGl2XG5cdFx0XHRcdC8vIEV4Y2x1ZGUgc2NyaXB0cyB0byBhdm9pZCBJRSAnUGVybWlzc2lvbiBEZW5pZWQnIGVycm9yc1xuXHRcdFx0XHRqUXVlcnkoXCI8ZGl2PlwiKS5hcHBlbmQoIGpRdWVyeS5wYXJzZUhUTUwoIHJlc3BvbnNlVGV4dCApICkuZmluZCggc2VsZWN0b3IgKSA6XG5cblx0XHRcdFx0Ly8gT3RoZXJ3aXNlIHVzZSB0aGUgZnVsbCByZXN1bHRcblx0XHRcdFx0cmVzcG9uc2VUZXh0ICk7XG5cblx0XHR9KS5jb21wbGV0ZSggY2FsbGJhY2sgJiYgZnVuY3Rpb24oIGpxWEhSLCBzdGF0dXMgKSB7XG5cdFx0XHRzZWxmLmVhY2goIGNhbGxiYWNrLCByZXNwb25zZSB8fCBbIGpxWEhSLnJlc3BvbnNlVGV4dCwgc3RhdHVzLCBqcVhIUiBdICk7XG5cdFx0fSk7XG5cdH1cblxuXHRyZXR1cm4gdGhpcztcbn07XG5cblxuXG5cbi8vIEF0dGFjaCBhIGJ1bmNoIG9mIGZ1bmN0aW9ucyBmb3IgaGFuZGxpbmcgY29tbW9uIEFKQVggZXZlbnRzXG5qUXVlcnkuZWFjaCggWyBcImFqYXhTdGFydFwiLCBcImFqYXhTdG9wXCIsIFwiYWpheENvbXBsZXRlXCIsIFwiYWpheEVycm9yXCIsIFwiYWpheFN1Y2Nlc3NcIiwgXCJhamF4U2VuZFwiIF0sIGZ1bmN0aW9uKCBpLCB0eXBlICkge1xuXHRqUXVlcnkuZm5bIHR5cGUgXSA9IGZ1bmN0aW9uKCBmbiApIHtcblx0XHRyZXR1cm4gdGhpcy5vbiggdHlwZSwgZm4gKTtcblx0fTtcbn0pO1xuXG5cblxuXG5qUXVlcnkuZXhwci5maWx0ZXJzLmFuaW1hdGVkID0gZnVuY3Rpb24oIGVsZW0gKSB7XG5cdHJldHVybiBqUXVlcnkuZ3JlcChqUXVlcnkudGltZXJzLCBmdW5jdGlvbiggZm4gKSB7XG5cdFx0cmV0dXJuIGVsZW0gPT09IGZuLmVsZW07XG5cdH0pLmxlbmd0aDtcbn07XG5cblxuXG5cbnZhciBkb2NFbGVtID0gd2luZG93LmRvY3VtZW50LmRvY3VtZW50RWxlbWVudDtcblxuLyoqXG4gKiBHZXRzIGEgd2luZG93IGZyb20gYW4gZWxlbWVudFxuICovXG5mdW5jdGlvbiBnZXRXaW5kb3coIGVsZW0gKSB7XG5cdHJldHVybiBqUXVlcnkuaXNXaW5kb3coIGVsZW0gKSA/IGVsZW0gOiBlbGVtLm5vZGVUeXBlID09PSA5ICYmIGVsZW0uZGVmYXVsdFZpZXc7XG59XG5cbmpRdWVyeS5vZmZzZXQgPSB7XG5cdHNldE9mZnNldDogZnVuY3Rpb24oIGVsZW0sIG9wdGlvbnMsIGkgKSB7XG5cdFx0dmFyIGN1clBvc2l0aW9uLCBjdXJMZWZ0LCBjdXJDU1NUb3AsIGN1clRvcCwgY3VyT2Zmc2V0LCBjdXJDU1NMZWZ0LCBjYWxjdWxhdGVQb3NpdGlvbixcblx0XHRcdHBvc2l0aW9uID0galF1ZXJ5LmNzcyggZWxlbSwgXCJwb3NpdGlvblwiICksXG5cdFx0XHRjdXJFbGVtID0galF1ZXJ5KCBlbGVtICksXG5cdFx0XHRwcm9wcyA9IHt9O1xuXG5cdFx0Ly8gU2V0IHBvc2l0aW9uIGZpcnN0LCBpbi1jYXNlIHRvcC9sZWZ0IGFyZSBzZXQgZXZlbiBvbiBzdGF0aWMgZWxlbVxuXHRcdGlmICggcG9zaXRpb24gPT09IFwic3RhdGljXCIgKSB7XG5cdFx0XHRlbGVtLnN0eWxlLnBvc2l0aW9uID0gXCJyZWxhdGl2ZVwiO1xuXHRcdH1cblxuXHRcdGN1ck9mZnNldCA9IGN1ckVsZW0ub2Zmc2V0KCk7XG5cdFx0Y3VyQ1NTVG9wID0galF1ZXJ5LmNzcyggZWxlbSwgXCJ0b3BcIiApO1xuXHRcdGN1ckNTU0xlZnQgPSBqUXVlcnkuY3NzKCBlbGVtLCBcImxlZnRcIiApO1xuXHRcdGNhbGN1bGF0ZVBvc2l0aW9uID0gKCBwb3NpdGlvbiA9PT0gXCJhYnNvbHV0ZVwiIHx8IHBvc2l0aW9uID09PSBcImZpeGVkXCIgKSAmJlxuXHRcdFx0KCBjdXJDU1NUb3AgKyBjdXJDU1NMZWZ0ICkuaW5kZXhPZihcImF1dG9cIikgPiAtMTtcblxuXHRcdC8vIE5lZWQgdG8gYmUgYWJsZSB0byBjYWxjdWxhdGUgcG9zaXRpb24gaWYgZWl0aGVyXG5cdFx0Ly8gdG9wIG9yIGxlZnQgaXMgYXV0byBhbmQgcG9zaXRpb24gaXMgZWl0aGVyIGFic29sdXRlIG9yIGZpeGVkXG5cdFx0aWYgKCBjYWxjdWxhdGVQb3NpdGlvbiApIHtcblx0XHRcdGN1clBvc2l0aW9uID0gY3VyRWxlbS5wb3NpdGlvbigpO1xuXHRcdFx0Y3VyVG9wID0gY3VyUG9zaXRpb24udG9wO1xuXHRcdFx0Y3VyTGVmdCA9IGN1clBvc2l0aW9uLmxlZnQ7XG5cblx0XHR9IGVsc2Uge1xuXHRcdFx0Y3VyVG9wID0gcGFyc2VGbG9hdCggY3VyQ1NTVG9wICkgfHwgMDtcblx0XHRcdGN1ckxlZnQgPSBwYXJzZUZsb2F0KCBjdXJDU1NMZWZ0ICkgfHwgMDtcblx0XHR9XG5cblx0XHRpZiAoIGpRdWVyeS5pc0Z1bmN0aW9uKCBvcHRpb25zICkgKSB7XG5cdFx0XHRvcHRpb25zID0gb3B0aW9ucy5jYWxsKCBlbGVtLCBpLCBjdXJPZmZzZXQgKTtcblx0XHR9XG5cblx0XHRpZiAoIG9wdGlvbnMudG9wICE9IG51bGwgKSB7XG5cdFx0XHRwcm9wcy50b3AgPSAoIG9wdGlvbnMudG9wIC0gY3VyT2Zmc2V0LnRvcCApICsgY3VyVG9wO1xuXHRcdH1cblx0XHRpZiAoIG9wdGlvbnMubGVmdCAhPSBudWxsICkge1xuXHRcdFx0cHJvcHMubGVmdCA9ICggb3B0aW9ucy5sZWZ0IC0gY3VyT2Zmc2V0LmxlZnQgKSArIGN1ckxlZnQ7XG5cdFx0fVxuXG5cdFx0aWYgKCBcInVzaW5nXCIgaW4gb3B0aW9ucyApIHtcblx0XHRcdG9wdGlvbnMudXNpbmcuY2FsbCggZWxlbSwgcHJvcHMgKTtcblxuXHRcdH0gZWxzZSB7XG5cdFx0XHRjdXJFbGVtLmNzcyggcHJvcHMgKTtcblx0XHR9XG5cdH1cbn07XG5cbmpRdWVyeS5mbi5leHRlbmQoe1xuXHRvZmZzZXQ6IGZ1bmN0aW9uKCBvcHRpb25zICkge1xuXHRcdGlmICggYXJndW1lbnRzLmxlbmd0aCApIHtcblx0XHRcdHJldHVybiBvcHRpb25zID09PSB1bmRlZmluZWQgP1xuXHRcdFx0XHR0aGlzIDpcblx0XHRcdFx0dGhpcy5lYWNoKGZ1bmN0aW9uKCBpICkge1xuXHRcdFx0XHRcdGpRdWVyeS5vZmZzZXQuc2V0T2Zmc2V0KCB0aGlzLCBvcHRpb25zLCBpICk7XG5cdFx0XHRcdH0pO1xuXHRcdH1cblxuXHRcdHZhciBkb2NFbGVtLCB3aW4sXG5cdFx0XHRlbGVtID0gdGhpc1sgMCBdLFxuXHRcdFx0Ym94ID0geyB0b3A6IDAsIGxlZnQ6IDAgfSxcblx0XHRcdGRvYyA9IGVsZW0gJiYgZWxlbS5vd25lckRvY3VtZW50O1xuXG5cdFx0aWYgKCAhZG9jICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGRvY0VsZW0gPSBkb2MuZG9jdW1lbnRFbGVtZW50O1xuXG5cdFx0Ly8gTWFrZSBzdXJlIGl0J3Mgbm90IGEgZGlzY29ubmVjdGVkIERPTSBub2RlXG5cdFx0aWYgKCAhalF1ZXJ5LmNvbnRhaW5zKCBkb2NFbGVtLCBlbGVtICkgKSB7XG5cdFx0XHRyZXR1cm4gYm94O1xuXHRcdH1cblxuXHRcdC8vIFN1cHBvcnQ6IEJsYWNrQmVycnkgNSwgaU9TIDMgKG9yaWdpbmFsIGlQaG9uZSlcblx0XHQvLyBJZiB3ZSBkb24ndCBoYXZlIGdCQ1IsIGp1c3QgdXNlIDAsMCByYXRoZXIgdGhhbiBlcnJvclxuXHRcdGlmICggdHlwZW9mIGVsZW0uZ2V0Qm91bmRpbmdDbGllbnRSZWN0ICE9PSBzdHJ1bmRlZmluZWQgKSB7XG5cdFx0XHRib3ggPSBlbGVtLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuXHRcdH1cblx0XHR3aW4gPSBnZXRXaW5kb3coIGRvYyApO1xuXHRcdHJldHVybiB7XG5cdFx0XHR0b3A6IGJveC50b3AgKyB3aW4ucGFnZVlPZmZzZXQgLSBkb2NFbGVtLmNsaWVudFRvcCxcblx0XHRcdGxlZnQ6IGJveC5sZWZ0ICsgd2luLnBhZ2VYT2Zmc2V0IC0gZG9jRWxlbS5jbGllbnRMZWZ0XG5cdFx0fTtcblx0fSxcblxuXHRwb3NpdGlvbjogZnVuY3Rpb24oKSB7XG5cdFx0aWYgKCAhdGhpc1sgMCBdICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHZhciBvZmZzZXRQYXJlbnQsIG9mZnNldCxcblx0XHRcdGVsZW0gPSB0aGlzWyAwIF0sXG5cdFx0XHRwYXJlbnRPZmZzZXQgPSB7IHRvcDogMCwgbGVmdDogMCB9O1xuXG5cdFx0Ly8gRml4ZWQgZWxlbWVudHMgYXJlIG9mZnNldCBmcm9tIHdpbmRvdyAocGFyZW50T2Zmc2V0ID0ge3RvcDowLCBsZWZ0OiAwfSwgYmVjYXVzZSBpdCBpcyBpdHMgb25seSBvZmZzZXQgcGFyZW50XG5cdFx0aWYgKCBqUXVlcnkuY3NzKCBlbGVtLCBcInBvc2l0aW9uXCIgKSA9PT0gXCJmaXhlZFwiICkge1xuXHRcdFx0Ly8gQXNzdW1lIGdldEJvdW5kaW5nQ2xpZW50UmVjdCBpcyB0aGVyZSB3aGVuIGNvbXB1dGVkIHBvc2l0aW9uIGlzIGZpeGVkXG5cdFx0XHRvZmZzZXQgPSBlbGVtLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuXG5cdFx0fSBlbHNlIHtcblx0XHRcdC8vIEdldCAqcmVhbCogb2Zmc2V0UGFyZW50XG5cdFx0XHRvZmZzZXRQYXJlbnQgPSB0aGlzLm9mZnNldFBhcmVudCgpO1xuXG5cdFx0XHQvLyBHZXQgY29ycmVjdCBvZmZzZXRzXG5cdFx0XHRvZmZzZXQgPSB0aGlzLm9mZnNldCgpO1xuXHRcdFx0aWYgKCAhalF1ZXJ5Lm5vZGVOYW1lKCBvZmZzZXRQYXJlbnRbIDAgXSwgXCJodG1sXCIgKSApIHtcblx0XHRcdFx0cGFyZW50T2Zmc2V0ID0gb2Zmc2V0UGFyZW50Lm9mZnNldCgpO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBBZGQgb2Zmc2V0UGFyZW50IGJvcmRlcnNcblx0XHRcdHBhcmVudE9mZnNldC50b3AgKz0galF1ZXJ5LmNzcyggb2Zmc2V0UGFyZW50WyAwIF0sIFwiYm9yZGVyVG9wV2lkdGhcIiwgdHJ1ZSApO1xuXHRcdFx0cGFyZW50T2Zmc2V0LmxlZnQgKz0galF1ZXJ5LmNzcyggb2Zmc2V0UGFyZW50WyAwIF0sIFwiYm9yZGVyTGVmdFdpZHRoXCIsIHRydWUgKTtcblx0XHR9XG5cblx0XHQvLyBTdWJ0cmFjdCBwYXJlbnQgb2Zmc2V0cyBhbmQgZWxlbWVudCBtYXJnaW5zXG5cdFx0cmV0dXJuIHtcblx0XHRcdHRvcDogb2Zmc2V0LnRvcCAtIHBhcmVudE9mZnNldC50b3AgLSBqUXVlcnkuY3NzKCBlbGVtLCBcIm1hcmdpblRvcFwiLCB0cnVlICksXG5cdFx0XHRsZWZ0OiBvZmZzZXQubGVmdCAtIHBhcmVudE9mZnNldC5sZWZ0IC0galF1ZXJ5LmNzcyggZWxlbSwgXCJtYXJnaW5MZWZ0XCIsIHRydWUgKVxuXHRcdH07XG5cdH0sXG5cblx0b2Zmc2V0UGFyZW50OiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5tYXAoZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgb2Zmc2V0UGFyZW50ID0gdGhpcy5vZmZzZXRQYXJlbnQgfHwgZG9jRWxlbTtcblxuXHRcdFx0d2hpbGUgKCBvZmZzZXRQYXJlbnQgJiYgKCAhalF1ZXJ5Lm5vZGVOYW1lKCBvZmZzZXRQYXJlbnQsIFwiaHRtbFwiICkgJiYgalF1ZXJ5LmNzcyggb2Zmc2V0UGFyZW50LCBcInBvc2l0aW9uXCIgKSA9PT0gXCJzdGF0aWNcIiApICkge1xuXHRcdFx0XHRvZmZzZXRQYXJlbnQgPSBvZmZzZXRQYXJlbnQub2Zmc2V0UGFyZW50O1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gb2Zmc2V0UGFyZW50IHx8IGRvY0VsZW07XG5cdFx0fSk7XG5cdH1cbn0pO1xuXG4vLyBDcmVhdGUgc2Nyb2xsTGVmdCBhbmQgc2Nyb2xsVG9wIG1ldGhvZHNcbmpRdWVyeS5lYWNoKCB7IHNjcm9sbExlZnQ6IFwicGFnZVhPZmZzZXRcIiwgc2Nyb2xsVG9wOiBcInBhZ2VZT2Zmc2V0XCIgfSwgZnVuY3Rpb24oIG1ldGhvZCwgcHJvcCApIHtcblx0dmFyIHRvcCA9IFwicGFnZVlPZmZzZXRcIiA9PT0gcHJvcDtcblxuXHRqUXVlcnkuZm5bIG1ldGhvZCBdID0gZnVuY3Rpb24oIHZhbCApIHtcblx0XHRyZXR1cm4gYWNjZXNzKCB0aGlzLCBmdW5jdGlvbiggZWxlbSwgbWV0aG9kLCB2YWwgKSB7XG5cdFx0XHR2YXIgd2luID0gZ2V0V2luZG93KCBlbGVtICk7XG5cblx0XHRcdGlmICggdmFsID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdHJldHVybiB3aW4gPyB3aW5bIHByb3AgXSA6IGVsZW1bIG1ldGhvZCBdO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHdpbiApIHtcblx0XHRcdFx0d2luLnNjcm9sbFRvKFxuXHRcdFx0XHRcdCF0b3AgPyB2YWwgOiB3aW5kb3cucGFnZVhPZmZzZXQsXG5cdFx0XHRcdFx0dG9wID8gdmFsIDogd2luZG93LnBhZ2VZT2Zmc2V0XG5cdFx0XHRcdCk7XG5cblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGVsZW1bIG1ldGhvZCBdID0gdmFsO1xuXHRcdFx0fVxuXHRcdH0sIG1ldGhvZCwgdmFsLCBhcmd1bWVudHMubGVuZ3RoLCBudWxsICk7XG5cdH07XG59KTtcblxuLy8gU3VwcG9ydDogU2FmYXJpPDcrLCBDaHJvbWU8MzcrXG4vLyBBZGQgdGhlIHRvcC9sZWZ0IGNzc0hvb2tzIHVzaW5nIGpRdWVyeS5mbi5wb3NpdGlvblxuLy8gV2Via2l0IGJ1ZzogaHR0cHM6Ly9idWdzLndlYmtpdC5vcmcvc2hvd19idWcuY2dpP2lkPTI5MDg0XG4vLyBCbGluayBidWc6IGh0dHBzOi8vY29kZS5nb29nbGUuY29tL3AvY2hyb21pdW0vaXNzdWVzL2RldGFpbD9pZD0yMjkyODBcbi8vIGdldENvbXB1dGVkU3R5bGUgcmV0dXJucyBwZXJjZW50IHdoZW4gc3BlY2lmaWVkIGZvciB0b3AvbGVmdC9ib3R0b20vcmlnaHQ7XG4vLyByYXRoZXIgdGhhbiBtYWtlIHRoZSBjc3MgbW9kdWxlIGRlcGVuZCBvbiB0aGUgb2Zmc2V0IG1vZHVsZSwganVzdCBjaGVjayBmb3IgaXQgaGVyZVxualF1ZXJ5LmVhY2goIFsgXCJ0b3BcIiwgXCJsZWZ0XCIgXSwgZnVuY3Rpb24oIGksIHByb3AgKSB7XG5cdGpRdWVyeS5jc3NIb29rc1sgcHJvcCBdID0gYWRkR2V0SG9va0lmKCBzdXBwb3J0LnBpeGVsUG9zaXRpb24sXG5cdFx0ZnVuY3Rpb24oIGVsZW0sIGNvbXB1dGVkICkge1xuXHRcdFx0aWYgKCBjb21wdXRlZCApIHtcblx0XHRcdFx0Y29tcHV0ZWQgPSBjdXJDU1MoIGVsZW0sIHByb3AgKTtcblx0XHRcdFx0Ly8gSWYgY3VyQ1NTIHJldHVybnMgcGVyY2VudGFnZSwgZmFsbGJhY2sgdG8gb2Zmc2V0XG5cdFx0XHRcdHJldHVybiBybnVtbm9ucHgudGVzdCggY29tcHV0ZWQgKSA/XG5cdFx0XHRcdFx0alF1ZXJ5KCBlbGVtICkucG9zaXRpb24oKVsgcHJvcCBdICsgXCJweFwiIDpcblx0XHRcdFx0XHRjb21wdXRlZDtcblx0XHRcdH1cblx0XHR9XG5cdCk7XG59KTtcblxuXG4vLyBDcmVhdGUgaW5uZXJIZWlnaHQsIGlubmVyV2lkdGgsIGhlaWdodCwgd2lkdGgsIG91dGVySGVpZ2h0IGFuZCBvdXRlcldpZHRoIG1ldGhvZHNcbmpRdWVyeS5lYWNoKCB7IEhlaWdodDogXCJoZWlnaHRcIiwgV2lkdGg6IFwid2lkdGhcIiB9LCBmdW5jdGlvbiggbmFtZSwgdHlwZSApIHtcblx0alF1ZXJ5LmVhY2goIHsgcGFkZGluZzogXCJpbm5lclwiICsgbmFtZSwgY29udGVudDogdHlwZSwgXCJcIjogXCJvdXRlclwiICsgbmFtZSB9LCBmdW5jdGlvbiggZGVmYXVsdEV4dHJhLCBmdW5jTmFtZSApIHtcblx0XHQvLyBNYXJnaW4gaXMgb25seSBmb3Igb3V0ZXJIZWlnaHQsIG91dGVyV2lkdGhcblx0XHRqUXVlcnkuZm5bIGZ1bmNOYW1lIF0gPSBmdW5jdGlvbiggbWFyZ2luLCB2YWx1ZSApIHtcblx0XHRcdHZhciBjaGFpbmFibGUgPSBhcmd1bWVudHMubGVuZ3RoICYmICggZGVmYXVsdEV4dHJhIHx8IHR5cGVvZiBtYXJnaW4gIT09IFwiYm9vbGVhblwiICksXG5cdFx0XHRcdGV4dHJhID0gZGVmYXVsdEV4dHJhIHx8ICggbWFyZ2luID09PSB0cnVlIHx8IHZhbHVlID09PSB0cnVlID8gXCJtYXJnaW5cIiA6IFwiYm9yZGVyXCIgKTtcblxuXHRcdFx0cmV0dXJuIGFjY2VzcyggdGhpcywgZnVuY3Rpb24oIGVsZW0sIHR5cGUsIHZhbHVlICkge1xuXHRcdFx0XHR2YXIgZG9jO1xuXG5cdFx0XHRcdGlmICggalF1ZXJ5LmlzV2luZG93KCBlbGVtICkgKSB7XG5cdFx0XHRcdFx0Ly8gQXMgb2YgNS84LzIwMTIgdGhpcyB3aWxsIHlpZWxkIGluY29ycmVjdCByZXN1bHRzIGZvciBNb2JpbGUgU2FmYXJpLCBidXQgdGhlcmVcblx0XHRcdFx0XHQvLyBpc24ndCBhIHdob2xlIGxvdCB3ZSBjYW4gZG8uIFNlZSBwdWxsIHJlcXVlc3QgYXQgdGhpcyBVUkwgZm9yIGRpc2N1c3Npb246XG5cdFx0XHRcdFx0Ly8gaHR0cHM6Ly9naXRodWIuY29tL2pxdWVyeS9qcXVlcnkvcHVsbC83NjRcblx0XHRcdFx0XHRyZXR1cm4gZWxlbS5kb2N1bWVudC5kb2N1bWVudEVsZW1lbnRbIFwiY2xpZW50XCIgKyBuYW1lIF07XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBHZXQgZG9jdW1lbnQgd2lkdGggb3IgaGVpZ2h0XG5cdFx0XHRcdGlmICggZWxlbS5ub2RlVHlwZSA9PT0gOSApIHtcblx0XHRcdFx0XHRkb2MgPSBlbGVtLmRvY3VtZW50RWxlbWVudDtcblxuXHRcdFx0XHRcdC8vIEVpdGhlciBzY3JvbGxbV2lkdGgvSGVpZ2h0XSBvciBvZmZzZXRbV2lkdGgvSGVpZ2h0XSBvciBjbGllbnRbV2lkdGgvSGVpZ2h0XSxcblx0XHRcdFx0XHQvLyB3aGljaGV2ZXIgaXMgZ3JlYXRlc3Rcblx0XHRcdFx0XHRyZXR1cm4gTWF0aC5tYXgoXG5cdFx0XHRcdFx0XHRlbGVtLmJvZHlbIFwic2Nyb2xsXCIgKyBuYW1lIF0sIGRvY1sgXCJzY3JvbGxcIiArIG5hbWUgXSxcblx0XHRcdFx0XHRcdGVsZW0uYm9keVsgXCJvZmZzZXRcIiArIG5hbWUgXSwgZG9jWyBcIm9mZnNldFwiICsgbmFtZSBdLFxuXHRcdFx0XHRcdFx0ZG9jWyBcImNsaWVudFwiICsgbmFtZSBdXG5cdFx0XHRcdFx0KTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHJldHVybiB2YWx1ZSA9PT0gdW5kZWZpbmVkID9cblx0XHRcdFx0XHQvLyBHZXQgd2lkdGggb3IgaGVpZ2h0IG9uIHRoZSBlbGVtZW50LCByZXF1ZXN0aW5nIGJ1dCBub3QgZm9yY2luZyBwYXJzZUZsb2F0XG5cdFx0XHRcdFx0alF1ZXJ5LmNzcyggZWxlbSwgdHlwZSwgZXh0cmEgKSA6XG5cblx0XHRcdFx0XHQvLyBTZXQgd2lkdGggb3IgaGVpZ2h0IG9uIHRoZSBlbGVtZW50XG5cdFx0XHRcdFx0alF1ZXJ5LnN0eWxlKCBlbGVtLCB0eXBlLCB2YWx1ZSwgZXh0cmEgKTtcblx0XHRcdH0sIHR5cGUsIGNoYWluYWJsZSA/IG1hcmdpbiA6IHVuZGVmaW5lZCwgY2hhaW5hYmxlLCBudWxsICk7XG5cdFx0fTtcblx0fSk7XG59KTtcblxuXG4vLyBUaGUgbnVtYmVyIG9mIGVsZW1lbnRzIGNvbnRhaW5lZCBpbiB0aGUgbWF0Y2hlZCBlbGVtZW50IHNldFxualF1ZXJ5LmZuLnNpemUgPSBmdW5jdGlvbigpIHtcblx0cmV0dXJuIHRoaXMubGVuZ3RoO1xufTtcblxualF1ZXJ5LmZuLmFuZFNlbGYgPSBqUXVlcnkuZm4uYWRkQmFjaztcblxuXG5cblxuLy8gUmVnaXN0ZXIgYXMgYSBuYW1lZCBBTUQgbW9kdWxlLCBzaW5jZSBqUXVlcnkgY2FuIGJlIGNvbmNhdGVuYXRlZCB3aXRoIG90aGVyXG4vLyBmaWxlcyB0aGF0IG1heSB1c2UgZGVmaW5lLCBidXQgbm90IHZpYSBhIHByb3BlciBjb25jYXRlbmF0aW9uIHNjcmlwdCB0aGF0XG4vLyB1bmRlcnN0YW5kcyBhbm9ueW1vdXMgQU1EIG1vZHVsZXMuIEEgbmFtZWQgQU1EIGlzIHNhZmVzdCBhbmQgbW9zdCByb2J1c3Rcbi8vIHdheSB0byByZWdpc3Rlci4gTG93ZXJjYXNlIGpxdWVyeSBpcyB1c2VkIGJlY2F1c2UgQU1EIG1vZHVsZSBuYW1lcyBhcmVcbi8vIGRlcml2ZWQgZnJvbSBmaWxlIG5hbWVzLCBhbmQgalF1ZXJ5IGlzIG5vcm1hbGx5IGRlbGl2ZXJlZCBpbiBhIGxvd2VyY2FzZVxuLy8gZmlsZSBuYW1lLiBEbyB0aGlzIGFmdGVyIGNyZWF0aW5nIHRoZSBnbG9iYWwgc28gdGhhdCBpZiBhbiBBTUQgbW9kdWxlIHdhbnRzXG4vLyB0byBjYWxsIG5vQ29uZmxpY3QgdG8gaGlkZSB0aGlzIHZlcnNpb24gb2YgalF1ZXJ5LCBpdCB3aWxsIHdvcmsuXG5cbi8vIE5vdGUgdGhhdCBmb3IgbWF4aW11bSBwb3J0YWJpbGl0eSwgbGlicmFyaWVzIHRoYXQgYXJlIG5vdCBqUXVlcnkgc2hvdWxkXG4vLyBkZWNsYXJlIHRoZW1zZWx2ZXMgYXMgYW5vbnltb3VzIG1vZHVsZXMsIGFuZCBhdm9pZCBzZXR0aW5nIGEgZ2xvYmFsIGlmIGFuXG4vLyBBTUQgbG9hZGVyIGlzIHByZXNlbnQuIGpRdWVyeSBpcyBhIHNwZWNpYWwgY2FzZS4gRm9yIG1vcmUgaW5mb3JtYXRpb24sIHNlZVxuLy8gaHR0cHM6Ly9naXRodWIuY29tL2pyYnVya2UvcmVxdWlyZWpzL3dpa2kvVXBkYXRpbmctZXhpc3RpbmctbGlicmFyaWVzI3dpa2ktYW5vblxuXG5pZiAoIHR5cGVvZiBkZWZpbmUgPT09IFwiZnVuY3Rpb25cIiAmJiBkZWZpbmUuYW1kICkge1xuXHRkZWZpbmUoIFwianF1ZXJ5XCIsIFtdLCBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4galF1ZXJ5O1xuXHR9KTtcbn1cblxuXG5cblxudmFyXG5cdC8vIE1hcCBvdmVyIGpRdWVyeSBpbiBjYXNlIG9mIG92ZXJ3cml0ZVxuXHRfalF1ZXJ5ID0gd2luZG93LmpRdWVyeSxcblxuXHQvLyBNYXAgb3ZlciB0aGUgJCBpbiBjYXNlIG9mIG92ZXJ3cml0ZVxuXHRfJCA9IHdpbmRvdy4kO1xuXG5qUXVlcnkubm9Db25mbGljdCA9IGZ1bmN0aW9uKCBkZWVwICkge1xuXHRpZiAoIHdpbmRvdy4kID09PSBqUXVlcnkgKSB7XG5cdFx0d2luZG93LiQgPSBfJDtcblx0fVxuXG5cdGlmICggZGVlcCAmJiB3aW5kb3cualF1ZXJ5ID09PSBqUXVlcnkgKSB7XG5cdFx0d2luZG93LmpRdWVyeSA9IF9qUXVlcnk7XG5cdH1cblxuXHRyZXR1cm4galF1ZXJ5O1xufTtcblxuLy8gRXhwb3NlIGpRdWVyeSBhbmQgJCBpZGVudGlmaWVycywgZXZlbiBpbiBBTURcbi8vICgjNzEwMiNjb21tZW50OjEwLCBodHRwczovL2dpdGh1Yi5jb20vanF1ZXJ5L2pxdWVyeS9wdWxsLzU1Nylcbi8vIGFuZCBDb21tb25KUyBmb3IgYnJvd3NlciBlbXVsYXRvcnMgKCMxMzU2NilcbmlmICggdHlwZW9mIG5vR2xvYmFsID09PSBzdHJ1bmRlZmluZWQgKSB7XG5cdHdpbmRvdy5qUXVlcnkgPSB3aW5kb3cuJCA9IGpRdWVyeTtcbn1cblxuXG5cblxucmV0dXJuIGpRdWVyeTtcblxufSkpO1xuIiwiKGZ1bmN0aW9uIChnbG9iYWwpe1xuLyoqXG4gKiBAbGljZW5zZVxuICogTG8tRGFzaCAyLjQuMSAoQ3VzdG9tIEJ1aWxkKSA8aHR0cDovL2xvZGFzaC5jb20vPlxuICogQnVpbGQ6IGBsb2Rhc2ggbW9kZXJuIC1vIC4vZGlzdC9sb2Rhc2guanNgXG4gKiBDb3B5cmlnaHQgMjAxMi0yMDEzIFRoZSBEb2pvIEZvdW5kYXRpb24gPGh0dHA6Ly9kb2pvZm91bmRhdGlvbi5vcmcvPlxuICogQmFzZWQgb24gVW5kZXJzY29yZS5qcyAxLjUuMiA8aHR0cDovL3VuZGVyc2NvcmVqcy5vcmcvTElDRU5TRT5cbiAqIENvcHlyaWdodCAyMDA5LTIwMTMgSmVyZW15IEFzaGtlbmFzLCBEb2N1bWVudENsb3VkIGFuZCBJbnZlc3RpZ2F0aXZlIFJlcG9ydGVycyAmIEVkaXRvcnNcbiAqIEF2YWlsYWJsZSB1bmRlciBNSVQgbGljZW5zZSA8aHR0cDovL2xvZGFzaC5jb20vbGljZW5zZT5cbiAqL1xuOyhmdW5jdGlvbigpIHtcblxuICAvKiogVXNlZCBhcyBhIHNhZmUgcmVmZXJlbmNlIGZvciBgdW5kZWZpbmVkYCBpbiBwcmUgRVM1IGVudmlyb25tZW50cyAqL1xuICB2YXIgdW5kZWZpbmVkO1xuXG4gIC8qKiBVc2VkIHRvIHBvb2wgYXJyYXlzIGFuZCBvYmplY3RzIHVzZWQgaW50ZXJuYWxseSAqL1xuICB2YXIgYXJyYXlQb29sID0gW10sXG4gICAgICBvYmplY3RQb29sID0gW107XG5cbiAgLyoqIFVzZWQgdG8gZ2VuZXJhdGUgdW5pcXVlIElEcyAqL1xuICB2YXIgaWRDb3VudGVyID0gMDtcblxuICAvKiogVXNlZCB0byBwcmVmaXgga2V5cyB0byBhdm9pZCBpc3N1ZXMgd2l0aCBgX19wcm90b19fYCBhbmQgcHJvcGVydGllcyBvbiBgT2JqZWN0LnByb3RvdHlwZWAgKi9cbiAgdmFyIGtleVByZWZpeCA9ICtuZXcgRGF0ZSArICcnO1xuXG4gIC8qKiBVc2VkIGFzIHRoZSBzaXplIHdoZW4gb3B0aW1pemF0aW9ucyBhcmUgZW5hYmxlZCBmb3IgbGFyZ2UgYXJyYXlzICovXG4gIHZhciBsYXJnZUFycmF5U2l6ZSA9IDc1O1xuXG4gIC8qKiBVc2VkIGFzIHRoZSBtYXggc2l6ZSBvZiB0aGUgYGFycmF5UG9vbGAgYW5kIGBvYmplY3RQb29sYCAqL1xuICB2YXIgbWF4UG9vbFNpemUgPSA0MDtcblxuICAvKiogVXNlZCB0byBkZXRlY3QgYW5kIHRlc3Qgd2hpdGVzcGFjZSAqL1xuICB2YXIgd2hpdGVzcGFjZSA9IChcbiAgICAvLyB3aGl0ZXNwYWNlXG4gICAgJyBcXHRcXHgwQlxcZlxceEEwXFx1ZmVmZicgK1xuXG4gICAgLy8gbGluZSB0ZXJtaW5hdG9yc1xuICAgICdcXG5cXHJcXHUyMDI4XFx1MjAyOScgK1xuXG4gICAgLy8gdW5pY29kZSBjYXRlZ29yeSBcIlpzXCIgc3BhY2Ugc2VwYXJhdG9yc1xuICAgICdcXHUxNjgwXFx1MTgwZVxcdTIwMDBcXHUyMDAxXFx1MjAwMlxcdTIwMDNcXHUyMDA0XFx1MjAwNVxcdTIwMDZcXHUyMDA3XFx1MjAwOFxcdTIwMDlcXHUyMDBhXFx1MjAyZlxcdTIwNWZcXHUzMDAwJ1xuICApO1xuXG4gIC8qKiBVc2VkIHRvIG1hdGNoIGVtcHR5IHN0cmluZyBsaXRlcmFscyBpbiBjb21waWxlZCB0ZW1wbGF0ZSBzb3VyY2UgKi9cbiAgdmFyIHJlRW1wdHlTdHJpbmdMZWFkaW5nID0gL1xcYl9fcCBcXCs9ICcnOy9nLFxuICAgICAgcmVFbXB0eVN0cmluZ01pZGRsZSA9IC9cXGIoX19wIFxcKz0pICcnIFxcKy9nLFxuICAgICAgcmVFbXB0eVN0cmluZ1RyYWlsaW5nID0gLyhfX2VcXCguKj9cXCl8XFxiX190XFwpKSBcXCtcXG4nJzsvZztcblxuICAvKipcbiAgICogVXNlZCB0byBtYXRjaCBFUzYgdGVtcGxhdGUgZGVsaW1pdGVyc1xuICAgKiBodHRwOi8vcGVvcGxlLm1vemlsbGEub3JnL35qb3JlbmRvcmZmL2VzNi1kcmFmdC5odG1sI3NlYy1saXRlcmFscy1zdHJpbmctbGl0ZXJhbHNcbiAgICovXG4gIHZhciByZUVzVGVtcGxhdGUgPSAvXFwkXFx7KFteXFxcXH1dKig/OlxcXFwuW15cXFxcfV0qKSopXFx9L2c7XG5cbiAgLyoqIFVzZWQgdG8gbWF0Y2ggcmVnZXhwIGZsYWdzIGZyb20gdGhlaXIgY29lcmNlZCBzdHJpbmcgdmFsdWVzICovXG4gIHZhciByZUZsYWdzID0gL1xcdyokLztcblxuICAvKiogVXNlZCB0byBkZXRlY3RlZCBuYW1lZCBmdW5jdGlvbnMgKi9cbiAgdmFyIHJlRnVuY05hbWUgPSAvXlxccypmdW5jdGlvblsgXFxuXFxyXFx0XStcXHcvO1xuXG4gIC8qKiBVc2VkIHRvIG1hdGNoIFwiaW50ZXJwb2xhdGVcIiB0ZW1wbGF0ZSBkZWxpbWl0ZXJzICovXG4gIHZhciByZUludGVycG9sYXRlID0gLzwlPShbXFxzXFxTXSs/KSU+L2c7XG5cbiAgLyoqIFVzZWQgdG8gbWF0Y2ggbGVhZGluZyB3aGl0ZXNwYWNlIGFuZCB6ZXJvcyB0byBiZSByZW1vdmVkICovXG4gIHZhciByZUxlYWRpbmdTcGFjZXNBbmRaZXJvcyA9IFJlZ0V4cCgnXlsnICsgd2hpdGVzcGFjZSArICddKjArKD89LiQpJyk7XG5cbiAgLyoqIFVzZWQgdG8gZW5zdXJlIGNhcHR1cmluZyBvcmRlciBvZiB0ZW1wbGF0ZSBkZWxpbWl0ZXJzICovXG4gIHZhciByZU5vTWF0Y2ggPSAvKCReKS87XG5cbiAgLyoqIFVzZWQgdG8gZGV0ZWN0IGZ1bmN0aW9ucyBjb250YWluaW5nIGEgYHRoaXNgIHJlZmVyZW5jZSAqL1xuICB2YXIgcmVUaGlzID0gL1xcYnRoaXNcXGIvO1xuXG4gIC8qKiBVc2VkIHRvIG1hdGNoIHVuZXNjYXBlZCBjaGFyYWN0ZXJzIGluIGNvbXBpbGVkIHN0cmluZyBsaXRlcmFscyAqL1xuICB2YXIgcmVVbmVzY2FwZWRTdHJpbmcgPSAvWydcXG5cXHJcXHRcXHUyMDI4XFx1MjAyOVxcXFxdL2c7XG5cbiAgLyoqIFVzZWQgdG8gYXNzaWduIGRlZmF1bHQgYGNvbnRleHRgIG9iamVjdCBwcm9wZXJ0aWVzICovXG4gIHZhciBjb250ZXh0UHJvcHMgPSBbXG4gICAgJ0FycmF5JywgJ0Jvb2xlYW4nLCAnRGF0ZScsICdGdW5jdGlvbicsICdNYXRoJywgJ051bWJlcicsICdPYmplY3QnLFxuICAgICdSZWdFeHAnLCAnU3RyaW5nJywgJ18nLCAnYXR0YWNoRXZlbnQnLCAnY2xlYXJUaW1lb3V0JywgJ2lzRmluaXRlJywgJ2lzTmFOJyxcbiAgICAncGFyc2VJbnQnLCAnc2V0VGltZW91dCdcbiAgXTtcblxuICAvKiogVXNlZCB0byBtYWtlIHRlbXBsYXRlIHNvdXJjZVVSTHMgZWFzaWVyIHRvIGlkZW50aWZ5ICovXG4gIHZhciB0ZW1wbGF0ZUNvdW50ZXIgPSAwO1xuXG4gIC8qKiBgT2JqZWN0I3RvU3RyaW5nYCByZXN1bHQgc2hvcnRjdXRzICovXG4gIHZhciBhcmdzQ2xhc3MgPSAnW29iamVjdCBBcmd1bWVudHNdJyxcbiAgICAgIGFycmF5Q2xhc3MgPSAnW29iamVjdCBBcnJheV0nLFxuICAgICAgYm9vbENsYXNzID0gJ1tvYmplY3QgQm9vbGVhbl0nLFxuICAgICAgZGF0ZUNsYXNzID0gJ1tvYmplY3QgRGF0ZV0nLFxuICAgICAgZnVuY0NsYXNzID0gJ1tvYmplY3QgRnVuY3Rpb25dJyxcbiAgICAgIG51bWJlckNsYXNzID0gJ1tvYmplY3QgTnVtYmVyXScsXG4gICAgICBvYmplY3RDbGFzcyA9ICdbb2JqZWN0IE9iamVjdF0nLFxuICAgICAgcmVnZXhwQ2xhc3MgPSAnW29iamVjdCBSZWdFeHBdJyxcbiAgICAgIHN0cmluZ0NsYXNzID0gJ1tvYmplY3QgU3RyaW5nXSc7XG5cbiAgLyoqIFVzZWQgdG8gaWRlbnRpZnkgb2JqZWN0IGNsYXNzaWZpY2F0aW9ucyB0aGF0IGBfLmNsb25lYCBzdXBwb3J0cyAqL1xuICB2YXIgY2xvbmVhYmxlQ2xhc3NlcyA9IHt9O1xuICBjbG9uZWFibGVDbGFzc2VzW2Z1bmNDbGFzc10gPSBmYWxzZTtcbiAgY2xvbmVhYmxlQ2xhc3Nlc1thcmdzQ2xhc3NdID0gY2xvbmVhYmxlQ2xhc3Nlc1thcnJheUNsYXNzXSA9XG4gIGNsb25lYWJsZUNsYXNzZXNbYm9vbENsYXNzXSA9IGNsb25lYWJsZUNsYXNzZXNbZGF0ZUNsYXNzXSA9XG4gIGNsb25lYWJsZUNsYXNzZXNbbnVtYmVyQ2xhc3NdID0gY2xvbmVhYmxlQ2xhc3Nlc1tvYmplY3RDbGFzc10gPVxuICBjbG9uZWFibGVDbGFzc2VzW3JlZ2V4cENsYXNzXSA9IGNsb25lYWJsZUNsYXNzZXNbc3RyaW5nQ2xhc3NdID0gdHJ1ZTtcblxuICAvKiogVXNlZCBhcyBhbiBpbnRlcm5hbCBgXy5kZWJvdW5jZWAgb3B0aW9ucyBvYmplY3QgKi9cbiAgdmFyIGRlYm91bmNlT3B0aW9ucyA9IHtcbiAgICAnbGVhZGluZyc6IGZhbHNlLFxuICAgICdtYXhXYWl0JzogMCxcbiAgICAndHJhaWxpbmcnOiBmYWxzZVxuICB9O1xuXG4gIC8qKiBVc2VkIGFzIHRoZSBwcm9wZXJ0eSBkZXNjcmlwdG9yIGZvciBgX19iaW5kRGF0YV9fYCAqL1xuICB2YXIgZGVzY3JpcHRvciA9IHtcbiAgICAnY29uZmlndXJhYmxlJzogZmFsc2UsXG4gICAgJ2VudW1lcmFibGUnOiBmYWxzZSxcbiAgICAndmFsdWUnOiBudWxsLFxuICAgICd3cml0YWJsZSc6IGZhbHNlXG4gIH07XG5cbiAgLyoqIFVzZWQgdG8gZGV0ZXJtaW5lIGlmIHZhbHVlcyBhcmUgb2YgdGhlIGxhbmd1YWdlIHR5cGUgT2JqZWN0ICovXG4gIHZhciBvYmplY3RUeXBlcyA9IHtcbiAgICAnYm9vbGVhbic6IGZhbHNlLFxuICAgICdmdW5jdGlvbic6IHRydWUsXG4gICAgJ29iamVjdCc6IHRydWUsXG4gICAgJ251bWJlcic6IGZhbHNlLFxuICAgICdzdHJpbmcnOiBmYWxzZSxcbiAgICAndW5kZWZpbmVkJzogZmFsc2VcbiAgfTtcblxuICAvKiogVXNlZCB0byBlc2NhcGUgY2hhcmFjdGVycyBmb3IgaW5jbHVzaW9uIGluIGNvbXBpbGVkIHN0cmluZyBsaXRlcmFscyAqL1xuICB2YXIgc3RyaW5nRXNjYXBlcyA9IHtcbiAgICAnXFxcXCc6ICdcXFxcJyxcbiAgICBcIidcIjogXCInXCIsXG4gICAgJ1xcbic6ICduJyxcbiAgICAnXFxyJzogJ3InLFxuICAgICdcXHQnOiAndCcsXG4gICAgJ1xcdTIwMjgnOiAndTIwMjgnLFxuICAgICdcXHUyMDI5JzogJ3UyMDI5J1xuICB9O1xuXG4gIC8qKiBVc2VkIGFzIGEgcmVmZXJlbmNlIHRvIHRoZSBnbG9iYWwgb2JqZWN0ICovXG4gIHZhciByb290ID0gKG9iamVjdFR5cGVzW3R5cGVvZiB3aW5kb3ddICYmIHdpbmRvdykgfHwgdGhpcztcblxuICAvKiogRGV0ZWN0IGZyZWUgdmFyaWFibGUgYGV4cG9ydHNgICovXG4gIHZhciBmcmVlRXhwb3J0cyA9IG9iamVjdFR5cGVzW3R5cGVvZiBleHBvcnRzXSAmJiBleHBvcnRzICYmICFleHBvcnRzLm5vZGVUeXBlICYmIGV4cG9ydHM7XG5cbiAgLyoqIERldGVjdCBmcmVlIHZhcmlhYmxlIGBtb2R1bGVgICovXG4gIHZhciBmcmVlTW9kdWxlID0gb2JqZWN0VHlwZXNbdHlwZW9mIG1vZHVsZV0gJiYgbW9kdWxlICYmICFtb2R1bGUubm9kZVR5cGUgJiYgbW9kdWxlO1xuXG4gIC8qKiBEZXRlY3QgdGhlIHBvcHVsYXIgQ29tbW9uSlMgZXh0ZW5zaW9uIGBtb2R1bGUuZXhwb3J0c2AgKi9cbiAgdmFyIG1vZHVsZUV4cG9ydHMgPSBmcmVlTW9kdWxlICYmIGZyZWVNb2R1bGUuZXhwb3J0cyA9PT0gZnJlZUV4cG9ydHMgJiYgZnJlZUV4cG9ydHM7XG5cbiAgLyoqIERldGVjdCBmcmVlIHZhcmlhYmxlIGBnbG9iYWxgIGZyb20gTm9kZS5qcyBvciBCcm93c2VyaWZpZWQgY29kZSBhbmQgdXNlIGl0IGFzIGByb290YCAqL1xuICB2YXIgZnJlZUdsb2JhbCA9IG9iamVjdFR5cGVzW3R5cGVvZiBnbG9iYWxdICYmIGdsb2JhbDtcbiAgaWYgKGZyZWVHbG9iYWwgJiYgKGZyZWVHbG9iYWwuZ2xvYmFsID09PSBmcmVlR2xvYmFsIHx8IGZyZWVHbG9iYWwud2luZG93ID09PSBmcmVlR2xvYmFsKSkge1xuICAgIHJvb3QgPSBmcmVlR2xvYmFsO1xuICB9XG5cbiAgLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5cbiAgLyoqXG4gICAqIFRoZSBiYXNlIGltcGxlbWVudGF0aW9uIG9mIGBfLmluZGV4T2ZgIHdpdGhvdXQgc3VwcG9ydCBmb3IgYmluYXJ5IHNlYXJjaGVzXG4gICAqIG9yIGBmcm9tSW5kZXhgIGNvbnN0cmFpbnRzLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge0FycmF5fSBhcnJheSBUaGUgYXJyYXkgdG8gc2VhcmNoLlxuICAgKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBzZWFyY2ggZm9yLlxuICAgKiBAcGFyYW0ge251bWJlcn0gW2Zyb21JbmRleD0wXSBUaGUgaW5kZXggdG8gc2VhcmNoIGZyb20uXG4gICAqIEByZXR1cm5zIHtudW1iZXJ9IFJldHVybnMgdGhlIGluZGV4IG9mIHRoZSBtYXRjaGVkIHZhbHVlIG9yIGAtMWAuXG4gICAqL1xuICBmdW5jdGlvbiBiYXNlSW5kZXhPZihhcnJheSwgdmFsdWUsIGZyb21JbmRleCkge1xuICAgIHZhciBpbmRleCA9IChmcm9tSW5kZXggfHwgMCkgLSAxLFxuICAgICAgICBsZW5ndGggPSBhcnJheSA/IGFycmF5Lmxlbmd0aCA6IDA7XG5cbiAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgaWYgKGFycmF5W2luZGV4XSA9PT0gdmFsdWUpIHtcbiAgICAgICAgcmV0dXJuIGluZGV4O1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gLTE7XG4gIH1cblxuICAvKipcbiAgICogQW4gaW1wbGVtZW50YXRpb24gb2YgYF8uY29udGFpbnNgIGZvciBjYWNoZSBvYmplY3RzIHRoYXQgbWltaWNzIHRoZSByZXR1cm5cbiAgICogc2lnbmF0dXJlIG9mIGBfLmluZGV4T2ZgIGJ5IHJldHVybmluZyBgMGAgaWYgdGhlIHZhbHVlIGlzIGZvdW5kLCBlbHNlIGAtMWAuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBjYWNoZSBUaGUgY2FjaGUgb2JqZWN0IHRvIGluc3BlY3QuXG4gICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIHNlYXJjaCBmb3IuXG4gICAqIEByZXR1cm5zIHtudW1iZXJ9IFJldHVybnMgYDBgIGlmIGB2YWx1ZWAgaXMgZm91bmQsIGVsc2UgYC0xYC5cbiAgICovXG4gIGZ1bmN0aW9uIGNhY2hlSW5kZXhPZihjYWNoZSwgdmFsdWUpIHtcbiAgICB2YXIgdHlwZSA9IHR5cGVvZiB2YWx1ZTtcbiAgICBjYWNoZSA9IGNhY2hlLmNhY2hlO1xuXG4gICAgaWYgKHR5cGUgPT0gJ2Jvb2xlYW4nIHx8IHZhbHVlID09IG51bGwpIHtcbiAgICAgIHJldHVybiBjYWNoZVt2YWx1ZV0gPyAwIDogLTE7XG4gICAgfVxuICAgIGlmICh0eXBlICE9ICdudW1iZXInICYmIHR5cGUgIT0gJ3N0cmluZycpIHtcbiAgICAgIHR5cGUgPSAnb2JqZWN0JztcbiAgICB9XG4gICAgdmFyIGtleSA9IHR5cGUgPT0gJ251bWJlcicgPyB2YWx1ZSA6IGtleVByZWZpeCArIHZhbHVlO1xuICAgIGNhY2hlID0gKGNhY2hlID0gY2FjaGVbdHlwZV0pICYmIGNhY2hlW2tleV07XG5cbiAgICByZXR1cm4gdHlwZSA9PSAnb2JqZWN0J1xuICAgICAgPyAoY2FjaGUgJiYgYmFzZUluZGV4T2YoY2FjaGUsIHZhbHVlKSA+IC0xID8gMCA6IC0xKVxuICAgICAgOiAoY2FjaGUgPyAwIDogLTEpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYSBnaXZlbiB2YWx1ZSB0byB0aGUgY29ycmVzcG9uZGluZyBjYWNoZSBvYmplY3QuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGFkZCB0byB0aGUgY2FjaGUuXG4gICAqL1xuICBmdW5jdGlvbiBjYWNoZVB1c2godmFsdWUpIHtcbiAgICB2YXIgY2FjaGUgPSB0aGlzLmNhY2hlLFxuICAgICAgICB0eXBlID0gdHlwZW9mIHZhbHVlO1xuXG4gICAgaWYgKHR5cGUgPT0gJ2Jvb2xlYW4nIHx8IHZhbHVlID09IG51bGwpIHtcbiAgICAgIGNhY2hlW3ZhbHVlXSA9IHRydWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmICh0eXBlICE9ICdudW1iZXInICYmIHR5cGUgIT0gJ3N0cmluZycpIHtcbiAgICAgICAgdHlwZSA9ICdvYmplY3QnO1xuICAgICAgfVxuICAgICAgdmFyIGtleSA9IHR5cGUgPT0gJ251bWJlcicgPyB2YWx1ZSA6IGtleVByZWZpeCArIHZhbHVlLFxuICAgICAgICAgIHR5cGVDYWNoZSA9IGNhY2hlW3R5cGVdIHx8IChjYWNoZVt0eXBlXSA9IHt9KTtcblxuICAgICAgaWYgKHR5cGUgPT0gJ29iamVjdCcpIHtcbiAgICAgICAgKHR5cGVDYWNoZVtrZXldIHx8ICh0eXBlQ2FjaGVba2V5XSA9IFtdKSkucHVzaCh2YWx1ZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0eXBlQ2FjaGVba2V5XSA9IHRydWU7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFVzZWQgYnkgYF8ubWF4YCBhbmQgYF8ubWluYCBhcyB0aGUgZGVmYXVsdCBjYWxsYmFjayB3aGVuIGEgZ2l2ZW5cbiAgICogY29sbGVjdGlvbiBpcyBhIHN0cmluZyB2YWx1ZS5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQHBhcmFtIHtzdHJpbmd9IHZhbHVlIFRoZSBjaGFyYWN0ZXIgdG8gaW5zcGVjdC5cbiAgICogQHJldHVybnMge251bWJlcn0gUmV0dXJucyB0aGUgY29kZSB1bml0IG9mIGdpdmVuIGNoYXJhY3Rlci5cbiAgICovXG4gIGZ1bmN0aW9uIGNoYXJBdENhbGxiYWNrKHZhbHVlKSB7XG4gICAgcmV0dXJuIHZhbHVlLmNoYXJDb2RlQXQoMCk7XG4gIH1cblxuICAvKipcbiAgICogVXNlZCBieSBgc29ydEJ5YCB0byBjb21wYXJlIHRyYW5zZm9ybWVkIGBjb2xsZWN0aW9uYCBlbGVtZW50cywgc3RhYmxlIHNvcnRpbmdcbiAgICogdGhlbSBpbiBhc2NlbmRpbmcgb3JkZXIuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBhIFRoZSBvYmplY3QgdG8gY29tcGFyZSB0byBgYmAuXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBiIFRoZSBvYmplY3QgdG8gY29tcGFyZSB0byBgYWAuXG4gICAqIEByZXR1cm5zIHtudW1iZXJ9IFJldHVybnMgdGhlIHNvcnQgb3JkZXIgaW5kaWNhdG9yIG9mIGAxYCBvciBgLTFgLlxuICAgKi9cbiAgZnVuY3Rpb24gY29tcGFyZUFzY2VuZGluZyhhLCBiKSB7XG4gICAgdmFyIGFjID0gYS5jcml0ZXJpYSxcbiAgICAgICAgYmMgPSBiLmNyaXRlcmlhLFxuICAgICAgICBpbmRleCA9IC0xLFxuICAgICAgICBsZW5ndGggPSBhYy5sZW5ndGg7XG5cbiAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgdmFyIHZhbHVlID0gYWNbaW5kZXhdLFxuICAgICAgICAgIG90aGVyID0gYmNbaW5kZXhdO1xuXG4gICAgICBpZiAodmFsdWUgIT09IG90aGVyKSB7XG4gICAgICAgIGlmICh2YWx1ZSA+IG90aGVyIHx8IHR5cGVvZiB2YWx1ZSA9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICB9XG4gICAgICAgIGlmICh2YWx1ZSA8IG90aGVyIHx8IHR5cGVvZiBvdGhlciA9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgIHJldHVybiAtMTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICAvLyBGaXhlcyBhbiBgQXJyYXkjc29ydGAgYnVnIGluIHRoZSBKUyBlbmdpbmUgZW1iZWRkZWQgaW4gQWRvYmUgYXBwbGljYXRpb25zXG4gICAgLy8gdGhhdCBjYXVzZXMgaXQsIHVuZGVyIGNlcnRhaW4gY2lyY3Vtc3RhbmNlcywgdG8gcmV0dXJuIHRoZSBzYW1lIHZhbHVlIGZvclxuICAgIC8vIGBhYCBhbmQgYGJgLiBTZWUgaHR0cHM6Ly9naXRodWIuY29tL2phc2hrZW5hcy91bmRlcnNjb3JlL3B1bGwvMTI0N1xuICAgIC8vXG4gICAgLy8gVGhpcyBhbHNvIGVuc3VyZXMgYSBzdGFibGUgc29ydCBpbiBWOCBhbmQgb3RoZXIgZW5naW5lcy5cbiAgICAvLyBTZWUgaHR0cDovL2NvZGUuZ29vZ2xlLmNvbS9wL3Y4L2lzc3Vlcy9kZXRhaWw/aWQ9OTBcbiAgICByZXR1cm4gYS5pbmRleCAtIGIuaW5kZXg7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIGNhY2hlIG9iamVjdCB0byBvcHRpbWl6ZSBsaW5lYXIgc2VhcmNoZXMgb2YgbGFyZ2UgYXJyYXlzLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge0FycmF5fSBbYXJyYXk9W11dIFRoZSBhcnJheSB0byBzZWFyY2guXG4gICAqIEByZXR1cm5zIHtudWxsfE9iamVjdH0gUmV0dXJucyB0aGUgY2FjaGUgb2JqZWN0IG9yIGBudWxsYCBpZiBjYWNoaW5nIHNob3VsZCBub3QgYmUgdXNlZC5cbiAgICovXG4gIGZ1bmN0aW9uIGNyZWF0ZUNhY2hlKGFycmF5KSB7XG4gICAgdmFyIGluZGV4ID0gLTEsXG4gICAgICAgIGxlbmd0aCA9IGFycmF5Lmxlbmd0aCxcbiAgICAgICAgZmlyc3QgPSBhcnJheVswXSxcbiAgICAgICAgbWlkID0gYXJyYXlbKGxlbmd0aCAvIDIpIHwgMF0sXG4gICAgICAgIGxhc3QgPSBhcnJheVtsZW5ndGggLSAxXTtcblxuICAgIGlmIChmaXJzdCAmJiB0eXBlb2YgZmlyc3QgPT0gJ29iamVjdCcgJiZcbiAgICAgICAgbWlkICYmIHR5cGVvZiBtaWQgPT0gJ29iamVjdCcgJiYgbGFzdCAmJiB0eXBlb2YgbGFzdCA9PSAnb2JqZWN0Jykge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICB2YXIgY2FjaGUgPSBnZXRPYmplY3QoKTtcbiAgICBjYWNoZVsnZmFsc2UnXSA9IGNhY2hlWydudWxsJ10gPSBjYWNoZVsndHJ1ZSddID0gY2FjaGVbJ3VuZGVmaW5lZCddID0gZmFsc2U7XG5cbiAgICB2YXIgcmVzdWx0ID0gZ2V0T2JqZWN0KCk7XG4gICAgcmVzdWx0LmFycmF5ID0gYXJyYXk7XG4gICAgcmVzdWx0LmNhY2hlID0gY2FjaGU7XG4gICAgcmVzdWx0LnB1c2ggPSBjYWNoZVB1c2g7XG5cbiAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgcmVzdWx0LnB1c2goYXJyYXlbaW5kZXhdKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBVc2VkIGJ5IGB0ZW1wbGF0ZWAgdG8gZXNjYXBlIGNoYXJhY3RlcnMgZm9yIGluY2x1c2lvbiBpbiBjb21waWxlZFxuICAgKiBzdHJpbmcgbGl0ZXJhbHMuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtYXRjaCBUaGUgbWF0Y2hlZCBjaGFyYWN0ZXIgdG8gZXNjYXBlLlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSBSZXR1cm5zIHRoZSBlc2NhcGVkIGNoYXJhY3Rlci5cbiAgICovXG4gIGZ1bmN0aW9uIGVzY2FwZVN0cmluZ0NoYXIobWF0Y2gpIHtcbiAgICByZXR1cm4gJ1xcXFwnICsgc3RyaW5nRXNjYXBlc1ttYXRjaF07XG4gIH1cblxuICAvKipcbiAgICogR2V0cyBhbiBhcnJheSBmcm9tIHRoZSBhcnJheSBwb29sIG9yIGNyZWF0ZXMgYSBuZXcgb25lIGlmIHRoZSBwb29sIGlzIGVtcHR5LlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcmV0dXJucyB7QXJyYXl9IFRoZSBhcnJheSBmcm9tIHRoZSBwb29sLlxuICAgKi9cbiAgZnVuY3Rpb24gZ2V0QXJyYXkoKSB7XG4gICAgcmV0dXJuIGFycmF5UG9vbC5wb3AoKSB8fCBbXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIGFuIG9iamVjdCBmcm9tIHRoZSBvYmplY3QgcG9vbCBvciBjcmVhdGVzIGEgbmV3IG9uZSBpZiB0aGUgcG9vbCBpcyBlbXB0eS5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQHJldHVybnMge09iamVjdH0gVGhlIG9iamVjdCBmcm9tIHRoZSBwb29sLlxuICAgKi9cbiAgZnVuY3Rpb24gZ2V0T2JqZWN0KCkge1xuICAgIHJldHVybiBvYmplY3RQb29sLnBvcCgpIHx8IHtcbiAgICAgICdhcnJheSc6IG51bGwsXG4gICAgICAnY2FjaGUnOiBudWxsLFxuICAgICAgJ2NyaXRlcmlhJzogbnVsbCxcbiAgICAgICdmYWxzZSc6IGZhbHNlLFxuICAgICAgJ2luZGV4JzogMCxcbiAgICAgICdudWxsJzogZmFsc2UsXG4gICAgICAnbnVtYmVyJzogbnVsbCxcbiAgICAgICdvYmplY3QnOiBudWxsLFxuICAgICAgJ3B1c2gnOiBudWxsLFxuICAgICAgJ3N0cmluZyc6IG51bGwsXG4gICAgICAndHJ1ZSc6IGZhbHNlLFxuICAgICAgJ3VuZGVmaW5lZCc6IGZhbHNlLFxuICAgICAgJ3ZhbHVlJzogbnVsbFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogUmVsZWFzZXMgdGhlIGdpdmVuIGFycmF5IGJhY2sgdG8gdGhlIGFycmF5IHBvb2wuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEBwYXJhbSB7QXJyYXl9IFthcnJheV0gVGhlIGFycmF5IHRvIHJlbGVhc2UuXG4gICAqL1xuICBmdW5jdGlvbiByZWxlYXNlQXJyYXkoYXJyYXkpIHtcbiAgICBhcnJheS5sZW5ndGggPSAwO1xuICAgIGlmIChhcnJheVBvb2wubGVuZ3RoIDwgbWF4UG9vbFNpemUpIHtcbiAgICAgIGFycmF5UG9vbC5wdXNoKGFycmF5KTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmVsZWFzZXMgdGhlIGdpdmVuIG9iamVjdCBiYWNrIHRvIHRoZSBvYmplY3QgcG9vbC5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQHBhcmFtIHtPYmplY3R9IFtvYmplY3RdIFRoZSBvYmplY3QgdG8gcmVsZWFzZS5cbiAgICovXG4gIGZ1bmN0aW9uIHJlbGVhc2VPYmplY3Qob2JqZWN0KSB7XG4gICAgdmFyIGNhY2hlID0gb2JqZWN0LmNhY2hlO1xuICAgIGlmIChjYWNoZSkge1xuICAgICAgcmVsZWFzZU9iamVjdChjYWNoZSk7XG4gICAgfVxuICAgIG9iamVjdC5hcnJheSA9IG9iamVjdC5jYWNoZSA9IG9iamVjdC5jcml0ZXJpYSA9IG9iamVjdC5vYmplY3QgPSBvYmplY3QubnVtYmVyID0gb2JqZWN0LnN0cmluZyA9IG9iamVjdC52YWx1ZSA9IG51bGw7XG4gICAgaWYgKG9iamVjdFBvb2wubGVuZ3RoIDwgbWF4UG9vbFNpemUpIHtcbiAgICAgIG9iamVjdFBvb2wucHVzaChvYmplY3QpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTbGljZXMgdGhlIGBjb2xsZWN0aW9uYCBmcm9tIHRoZSBgc3RhcnRgIGluZGV4IHVwIHRvLCBidXQgbm90IGluY2x1ZGluZyxcbiAgICogdGhlIGBlbmRgIGluZGV4LlxuICAgKlxuICAgKiBOb3RlOiBUaGlzIGZ1bmN0aW9uIGlzIHVzZWQgaW5zdGVhZCBvZiBgQXJyYXkjc2xpY2VgIHRvIHN1cHBvcnQgbm9kZSBsaXN0c1xuICAgKiBpbiBJRSA8IDkgYW5kIHRvIGVuc3VyZSBkZW5zZSBhcnJheXMgYXJlIHJldHVybmVkLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdHxzdHJpbmd9IGNvbGxlY3Rpb24gVGhlIGNvbGxlY3Rpb24gdG8gc2xpY2UuXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBzdGFydCBUaGUgc3RhcnQgaW5kZXguXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBlbmQgVGhlIGVuZCBpbmRleC5cbiAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIHRoZSBuZXcgYXJyYXkuXG4gICAqL1xuICBmdW5jdGlvbiBzbGljZShhcnJheSwgc3RhcnQsIGVuZCkge1xuICAgIHN0YXJ0IHx8IChzdGFydCA9IDApO1xuICAgIGlmICh0eXBlb2YgZW5kID09ICd1bmRlZmluZWQnKSB7XG4gICAgICBlbmQgPSBhcnJheSA/IGFycmF5Lmxlbmd0aCA6IDA7XG4gICAgfVxuICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICBsZW5ndGggPSBlbmQgLSBzdGFydCB8fCAwLFxuICAgICAgICByZXN1bHQgPSBBcnJheShsZW5ndGggPCAwID8gMCA6IGxlbmd0aCk7XG5cbiAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgcmVzdWx0W2luZGV4XSA9IGFycmF5W3N0YXJ0ICsgaW5kZXhdO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhIG5ldyBgbG9kYXNoYCBmdW5jdGlvbiB1c2luZyB0aGUgZ2l2ZW4gY29udGV4dCBvYmplY3QuXG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICogQG1lbWJlck9mIF9cbiAgICogQGNhdGVnb3J5IFV0aWxpdGllc1xuICAgKiBAcGFyYW0ge09iamVjdH0gW2NvbnRleHQ9cm9vdF0gVGhlIGNvbnRleHQgb2JqZWN0LlxuICAgKiBAcmV0dXJucyB7RnVuY3Rpb259IFJldHVybnMgdGhlIGBsb2Rhc2hgIGZ1bmN0aW9uLlxuICAgKi9cbiAgZnVuY3Rpb24gcnVuSW5Db250ZXh0KGNvbnRleHQpIHtcbiAgICAvLyBBdm9pZCBpc3N1ZXMgd2l0aCBzb21lIEVTMyBlbnZpcm9ubWVudHMgdGhhdCBhdHRlbXB0IHRvIHVzZSB2YWx1ZXMsIG5hbWVkXG4gICAgLy8gYWZ0ZXIgYnVpbHQtaW4gY29uc3RydWN0b3JzIGxpa2UgYE9iamVjdGAsIGZvciB0aGUgY3JlYXRpb24gb2YgbGl0ZXJhbHMuXG4gICAgLy8gRVM1IGNsZWFycyB0aGlzIHVwIGJ5IHN0YXRpbmcgdGhhdCBsaXRlcmFscyBtdXN0IHVzZSBidWlsdC1pbiBjb25zdHJ1Y3RvcnMuXG4gICAgLy8gU2VlIGh0dHA6Ly9lczUuZ2l0aHViLmlvLyN4MTEuMS41LlxuICAgIGNvbnRleHQgPSBjb250ZXh0ID8gXy5kZWZhdWx0cyhyb290Lk9iamVjdCgpLCBjb250ZXh0LCBfLnBpY2socm9vdCwgY29udGV4dFByb3BzKSkgOiByb290O1xuXG4gICAgLyoqIE5hdGl2ZSBjb25zdHJ1Y3RvciByZWZlcmVuY2VzICovXG4gICAgdmFyIEFycmF5ID0gY29udGV4dC5BcnJheSxcbiAgICAgICAgQm9vbGVhbiA9IGNvbnRleHQuQm9vbGVhbixcbiAgICAgICAgRGF0ZSA9IGNvbnRleHQuRGF0ZSxcbiAgICAgICAgRnVuY3Rpb24gPSBjb250ZXh0LkZ1bmN0aW9uLFxuICAgICAgICBNYXRoID0gY29udGV4dC5NYXRoLFxuICAgICAgICBOdW1iZXIgPSBjb250ZXh0Lk51bWJlcixcbiAgICAgICAgT2JqZWN0ID0gY29udGV4dC5PYmplY3QsXG4gICAgICAgIFJlZ0V4cCA9IGNvbnRleHQuUmVnRXhwLFxuICAgICAgICBTdHJpbmcgPSBjb250ZXh0LlN0cmluZyxcbiAgICAgICAgVHlwZUVycm9yID0gY29udGV4dC5UeXBlRXJyb3I7XG5cbiAgICAvKipcbiAgICAgKiBVc2VkIGZvciBgQXJyYXlgIG1ldGhvZCByZWZlcmVuY2VzLlxuICAgICAqXG4gICAgICogTm9ybWFsbHkgYEFycmF5LnByb3RvdHlwZWAgd291bGQgc3VmZmljZSwgaG93ZXZlciwgdXNpbmcgYW4gYXJyYXkgbGl0ZXJhbFxuICAgICAqIGF2b2lkcyBpc3N1ZXMgaW4gTmFyd2hhbC5cbiAgICAgKi9cbiAgICB2YXIgYXJyYXlSZWYgPSBbXTtcblxuICAgIC8qKiBVc2VkIGZvciBuYXRpdmUgbWV0aG9kIHJlZmVyZW5jZXMgKi9cbiAgICB2YXIgb2JqZWN0UHJvdG8gPSBPYmplY3QucHJvdG90eXBlO1xuXG4gICAgLyoqIFVzZWQgdG8gcmVzdG9yZSB0aGUgb3JpZ2luYWwgYF9gIHJlZmVyZW5jZSBpbiBgbm9Db25mbGljdGAgKi9cbiAgICB2YXIgb2xkRGFzaCA9IGNvbnRleHQuXztcblxuICAgIC8qKiBVc2VkIHRvIHJlc29sdmUgdGhlIGludGVybmFsIFtbQ2xhc3NdXSBvZiB2YWx1ZXMgKi9cbiAgICB2YXIgdG9TdHJpbmcgPSBvYmplY3RQcm90by50b1N0cmluZztcblxuICAgIC8qKiBVc2VkIHRvIGRldGVjdCBpZiBhIG1ldGhvZCBpcyBuYXRpdmUgKi9cbiAgICB2YXIgcmVOYXRpdmUgPSBSZWdFeHAoJ14nICtcbiAgICAgIFN0cmluZyh0b1N0cmluZylcbiAgICAgICAgLnJlcGxhY2UoL1suKis/XiR7fSgpfFtcXF1cXFxcXS9nLCAnXFxcXCQmJylcbiAgICAgICAgLnJlcGxhY2UoL3RvU3RyaW5nfCBmb3IgW15cXF1dKy9nLCAnLio/JykgKyAnJCdcbiAgICApO1xuXG4gICAgLyoqIE5hdGl2ZSBtZXRob2Qgc2hvcnRjdXRzICovXG4gICAgdmFyIGNlaWwgPSBNYXRoLmNlaWwsXG4gICAgICAgIGNsZWFyVGltZW91dCA9IGNvbnRleHQuY2xlYXJUaW1lb3V0LFxuICAgICAgICBmbG9vciA9IE1hdGguZmxvb3IsXG4gICAgICAgIGZuVG9TdHJpbmcgPSBGdW5jdGlvbi5wcm90b3R5cGUudG9TdHJpbmcsXG4gICAgICAgIGdldFByb3RvdHlwZU9mID0gaXNOYXRpdmUoZ2V0UHJvdG90eXBlT2YgPSBPYmplY3QuZ2V0UHJvdG90eXBlT2YpICYmIGdldFByb3RvdHlwZU9mLFxuICAgICAgICBoYXNPd25Qcm9wZXJ0eSA9IG9iamVjdFByb3RvLmhhc093blByb3BlcnR5LFxuICAgICAgICBwdXNoID0gYXJyYXlSZWYucHVzaCxcbiAgICAgICAgc2V0VGltZW91dCA9IGNvbnRleHQuc2V0VGltZW91dCxcbiAgICAgICAgc3BsaWNlID0gYXJyYXlSZWYuc3BsaWNlLFxuICAgICAgICB1bnNoaWZ0ID0gYXJyYXlSZWYudW5zaGlmdDtcblxuICAgIC8qKiBVc2VkIHRvIHNldCBtZXRhIGRhdGEgb24gZnVuY3Rpb25zICovXG4gICAgdmFyIGRlZmluZVByb3BlcnR5ID0gKGZ1bmN0aW9uKCkge1xuICAgICAgLy8gSUUgOCBvbmx5IGFjY2VwdHMgRE9NIGVsZW1lbnRzXG4gICAgICB0cnkge1xuICAgICAgICB2YXIgbyA9IHt9LFxuICAgICAgICAgICAgZnVuYyA9IGlzTmF0aXZlKGZ1bmMgPSBPYmplY3QuZGVmaW5lUHJvcGVydHkpICYmIGZ1bmMsXG4gICAgICAgICAgICByZXN1bHQgPSBmdW5jKG8sIG8sIG8pICYmIGZ1bmM7XG4gICAgICB9IGNhdGNoKGUpIHsgfVxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9KCkpO1xuXG4gICAgLyogTmF0aXZlIG1ldGhvZCBzaG9ydGN1dHMgZm9yIG1ldGhvZHMgd2l0aCB0aGUgc2FtZSBuYW1lIGFzIG90aGVyIGBsb2Rhc2hgIG1ldGhvZHMgKi9cbiAgICB2YXIgbmF0aXZlQ3JlYXRlID0gaXNOYXRpdmUobmF0aXZlQ3JlYXRlID0gT2JqZWN0LmNyZWF0ZSkgJiYgbmF0aXZlQ3JlYXRlLFxuICAgICAgICBuYXRpdmVJc0FycmF5ID0gaXNOYXRpdmUobmF0aXZlSXNBcnJheSA9IEFycmF5LmlzQXJyYXkpICYmIG5hdGl2ZUlzQXJyYXksXG4gICAgICAgIG5hdGl2ZUlzRmluaXRlID0gY29udGV4dC5pc0Zpbml0ZSxcbiAgICAgICAgbmF0aXZlSXNOYU4gPSBjb250ZXh0LmlzTmFOLFxuICAgICAgICBuYXRpdmVLZXlzID0gaXNOYXRpdmUobmF0aXZlS2V5cyA9IE9iamVjdC5rZXlzKSAmJiBuYXRpdmVLZXlzLFxuICAgICAgICBuYXRpdmVNYXggPSBNYXRoLm1heCxcbiAgICAgICAgbmF0aXZlTWluID0gTWF0aC5taW4sXG4gICAgICAgIG5hdGl2ZVBhcnNlSW50ID0gY29udGV4dC5wYXJzZUludCxcbiAgICAgICAgbmF0aXZlUmFuZG9tID0gTWF0aC5yYW5kb207XG5cbiAgICAvKiogVXNlZCB0byBsb29rdXAgYSBidWlsdC1pbiBjb25zdHJ1Y3RvciBieSBbW0NsYXNzXV0gKi9cbiAgICB2YXIgY3RvckJ5Q2xhc3MgPSB7fTtcbiAgICBjdG9yQnlDbGFzc1thcnJheUNsYXNzXSA9IEFycmF5O1xuICAgIGN0b3JCeUNsYXNzW2Jvb2xDbGFzc10gPSBCb29sZWFuO1xuICAgIGN0b3JCeUNsYXNzW2RhdGVDbGFzc10gPSBEYXRlO1xuICAgIGN0b3JCeUNsYXNzW2Z1bmNDbGFzc10gPSBGdW5jdGlvbjtcbiAgICBjdG9yQnlDbGFzc1tvYmplY3RDbGFzc10gPSBPYmplY3Q7XG4gICAgY3RvckJ5Q2xhc3NbbnVtYmVyQ2xhc3NdID0gTnVtYmVyO1xuICAgIGN0b3JCeUNsYXNzW3JlZ2V4cENsYXNzXSA9IFJlZ0V4cDtcbiAgICBjdG9yQnlDbGFzc1tzdHJpbmdDbGFzc10gPSBTdHJpbmc7XG5cbiAgICAvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSBgbG9kYXNoYCBvYmplY3Qgd2hpY2ggd3JhcHMgdGhlIGdpdmVuIHZhbHVlIHRvIGVuYWJsZSBpbnR1aXRpdmVcbiAgICAgKiBtZXRob2QgY2hhaW5pbmcuXG4gICAgICpcbiAgICAgKiBJbiBhZGRpdGlvbiB0byBMby1EYXNoIG1ldGhvZHMsIHdyYXBwZXJzIGFsc28gaGF2ZSB0aGUgZm9sbG93aW5nIGBBcnJheWAgbWV0aG9kczpcbiAgICAgKiBgY29uY2F0YCwgYGpvaW5gLCBgcG9wYCwgYHB1c2hgLCBgcmV2ZXJzZWAsIGBzaGlmdGAsIGBzbGljZWAsIGBzb3J0YCwgYHNwbGljZWAsXG4gICAgICogYW5kIGB1bnNoaWZ0YFxuICAgICAqXG4gICAgICogQ2hhaW5pbmcgaXMgc3VwcG9ydGVkIGluIGN1c3RvbSBidWlsZHMgYXMgbG9uZyBhcyB0aGUgYHZhbHVlYCBtZXRob2QgaXNcbiAgICAgKiBpbXBsaWNpdGx5IG9yIGV4cGxpY2l0bHkgaW5jbHVkZWQgaW4gdGhlIGJ1aWxkLlxuICAgICAqXG4gICAgICogVGhlIGNoYWluYWJsZSB3cmFwcGVyIGZ1bmN0aW9ucyBhcmU6XG4gICAgICogYGFmdGVyYCwgYGFzc2lnbmAsIGBiaW5kYCwgYGJpbmRBbGxgLCBgYmluZEtleWAsIGBjaGFpbmAsIGBjb21wYWN0YCxcbiAgICAgKiBgY29tcG9zZWAsIGBjb25jYXRgLCBgY291bnRCeWAsIGBjcmVhdGVgLCBgY3JlYXRlQ2FsbGJhY2tgLCBgY3VycnlgLFxuICAgICAqIGBkZWJvdW5jZWAsIGBkZWZhdWx0c2AsIGBkZWZlcmAsIGBkZWxheWAsIGBkaWZmZXJlbmNlYCwgYGZpbHRlcmAsIGBmbGF0dGVuYCxcbiAgICAgKiBgZm9yRWFjaGAsIGBmb3JFYWNoUmlnaHRgLCBgZm9ySW5gLCBgZm9ySW5SaWdodGAsIGBmb3JPd25gLCBgZm9yT3duUmlnaHRgLFxuICAgICAqIGBmdW5jdGlvbnNgLCBgZ3JvdXBCeWAsIGBpbmRleEJ5YCwgYGluaXRpYWxgLCBgaW50ZXJzZWN0aW9uYCwgYGludmVydGAsXG4gICAgICogYGludm9rZWAsIGBrZXlzYCwgYG1hcGAsIGBtYXhgLCBgbWVtb2l6ZWAsIGBtZXJnZWAsIGBtaW5gLCBgb2JqZWN0YCwgYG9taXRgLFxuICAgICAqIGBvbmNlYCwgYHBhaXJzYCwgYHBhcnRpYWxgLCBgcGFydGlhbFJpZ2h0YCwgYHBpY2tgLCBgcGx1Y2tgLCBgcHVsbGAsIGBwdXNoYCxcbiAgICAgKiBgcmFuZ2VgLCBgcmVqZWN0YCwgYHJlbW92ZWAsIGByZXN0YCwgYHJldmVyc2VgLCBgc2h1ZmZsZWAsIGBzbGljZWAsIGBzb3J0YCxcbiAgICAgKiBgc29ydEJ5YCwgYHNwbGljZWAsIGB0YXBgLCBgdGhyb3R0bGVgLCBgdGltZXNgLCBgdG9BcnJheWAsIGB0cmFuc2Zvcm1gLFxuICAgICAqIGB1bmlvbmAsIGB1bmlxYCwgYHVuc2hpZnRgLCBgdW56aXBgLCBgdmFsdWVzYCwgYHdoZXJlYCwgYHdpdGhvdXRgLCBgd3JhcGAsXG4gICAgICogYW5kIGB6aXBgXG4gICAgICpcbiAgICAgKiBUaGUgbm9uLWNoYWluYWJsZSB3cmFwcGVyIGZ1bmN0aW9ucyBhcmU6XG4gICAgICogYGNsb25lYCwgYGNsb25lRGVlcGAsIGBjb250YWluc2AsIGBlc2NhcGVgLCBgZXZlcnlgLCBgZmluZGAsIGBmaW5kSW5kZXhgLFxuICAgICAqIGBmaW5kS2V5YCwgYGZpbmRMYXN0YCwgYGZpbmRMYXN0SW5kZXhgLCBgZmluZExhc3RLZXlgLCBgaGFzYCwgYGlkZW50aXR5YCxcbiAgICAgKiBgaW5kZXhPZmAsIGBpc0FyZ3VtZW50c2AsIGBpc0FycmF5YCwgYGlzQm9vbGVhbmAsIGBpc0RhdGVgLCBgaXNFbGVtZW50YCxcbiAgICAgKiBgaXNFbXB0eWAsIGBpc0VxdWFsYCwgYGlzRmluaXRlYCwgYGlzRnVuY3Rpb25gLCBgaXNOYU5gLCBgaXNOdWxsYCwgYGlzTnVtYmVyYCxcbiAgICAgKiBgaXNPYmplY3RgLCBgaXNQbGFpbk9iamVjdGAsIGBpc1JlZ0V4cGAsIGBpc1N0cmluZ2AsIGBpc1VuZGVmaW5lZGAsIGBqb2luYCxcbiAgICAgKiBgbGFzdEluZGV4T2ZgLCBgbWl4aW5gLCBgbm9Db25mbGljdGAsIGBwYXJzZUludGAsIGBwb3BgLCBgcmFuZG9tYCwgYHJlZHVjZWAsXG4gICAgICogYHJlZHVjZVJpZ2h0YCwgYHJlc3VsdGAsIGBzaGlmdGAsIGBzaXplYCwgYHNvbWVgLCBgc29ydGVkSW5kZXhgLCBgcnVuSW5Db250ZXh0YCxcbiAgICAgKiBgdGVtcGxhdGVgLCBgdW5lc2NhcGVgLCBgdW5pcXVlSWRgLCBhbmQgYHZhbHVlYFxuICAgICAqXG4gICAgICogVGhlIHdyYXBwZXIgZnVuY3Rpb25zIGBmaXJzdGAgYW5kIGBsYXN0YCByZXR1cm4gd3JhcHBlZCB2YWx1ZXMgd2hlbiBgbmAgaXNcbiAgICAgKiBwcm92aWRlZCwgb3RoZXJ3aXNlIHRoZXkgcmV0dXJuIHVud3JhcHBlZCB2YWx1ZXMuXG4gICAgICpcbiAgICAgKiBFeHBsaWNpdCBjaGFpbmluZyBjYW4gYmUgZW5hYmxlZCBieSB1c2luZyB0aGUgYF8uY2hhaW5gIG1ldGhvZC5cbiAgICAgKlxuICAgICAqIEBuYW1lIF9cbiAgICAgKiBAY29uc3RydWN0b3JcbiAgICAgKiBAY2F0ZWdvcnkgQ2hhaW5pbmdcbiAgICAgKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byB3cmFwIGluIGEgYGxvZGFzaGAgaW5zdGFuY2UuXG4gICAgICogQHJldHVybnMge09iamVjdH0gUmV0dXJucyBhIGBsb2Rhc2hgIGluc3RhbmNlLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgd3JhcHBlZCA9IF8oWzEsIDIsIDNdKTtcbiAgICAgKlxuICAgICAqIC8vIHJldHVybnMgYW4gdW53cmFwcGVkIHZhbHVlXG4gICAgICogd3JhcHBlZC5yZWR1Y2UoZnVuY3Rpb24oc3VtLCBudW0pIHtcbiAgICAgKiAgIHJldHVybiBzdW0gKyBudW07XG4gICAgICogfSk7XG4gICAgICogLy8gPT4gNlxuICAgICAqXG4gICAgICogLy8gcmV0dXJucyBhIHdyYXBwZWQgdmFsdWVcbiAgICAgKiB2YXIgc3F1YXJlcyA9IHdyYXBwZWQubWFwKGZ1bmN0aW9uKG51bSkge1xuICAgICAqICAgcmV0dXJuIG51bSAqIG51bTtcbiAgICAgKiB9KTtcbiAgICAgKlxuICAgICAqIF8uaXNBcnJheShzcXVhcmVzKTtcbiAgICAgKiAvLyA9PiBmYWxzZVxuICAgICAqXG4gICAgICogXy5pc0FycmF5KHNxdWFyZXMudmFsdWUoKSk7XG4gICAgICogLy8gPT4gdHJ1ZVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGxvZGFzaCh2YWx1ZSkge1xuICAgICAgLy8gZG9uJ3Qgd3JhcCBpZiBhbHJlYWR5IHdyYXBwZWQsIGV2ZW4gaWYgd3JhcHBlZCBieSBhIGRpZmZlcmVudCBgbG9kYXNoYCBjb25zdHJ1Y3RvclxuICAgICAgcmV0dXJuICh2YWx1ZSAmJiB0eXBlb2YgdmFsdWUgPT0gJ29iamVjdCcgJiYgIWlzQXJyYXkodmFsdWUpICYmIGhhc093blByb3BlcnR5LmNhbGwodmFsdWUsICdfX3dyYXBwZWRfXycpKVxuICAgICAgID8gdmFsdWVcbiAgICAgICA6IG5ldyBsb2Rhc2hXcmFwcGVyKHZhbHVlKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBIGZhc3QgcGF0aCBmb3IgY3JlYXRpbmcgYGxvZGFzaGAgd3JhcHBlciBvYmplY3RzLlxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byB3cmFwIGluIGEgYGxvZGFzaGAgaW5zdGFuY2UuXG4gICAgICogQHBhcmFtIHtib29sZWFufSBjaGFpbkFsbCBBIGZsYWcgdG8gZW5hYmxlIGNoYWluaW5nIGZvciBhbGwgbWV0aG9kc1xuICAgICAqIEByZXR1cm5zIHtPYmplY3R9IFJldHVybnMgYSBgbG9kYXNoYCBpbnN0YW5jZS5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBsb2Rhc2hXcmFwcGVyKHZhbHVlLCBjaGFpbkFsbCkge1xuICAgICAgdGhpcy5fX2NoYWluX18gPSAhIWNoYWluQWxsO1xuICAgICAgdGhpcy5fX3dyYXBwZWRfXyA9IHZhbHVlO1xuICAgIH1cbiAgICAvLyBlbnN1cmUgYG5ldyBsb2Rhc2hXcmFwcGVyYCBpcyBhbiBpbnN0YW5jZSBvZiBgbG9kYXNoYFxuICAgIGxvZGFzaFdyYXBwZXIucHJvdG90eXBlID0gbG9kYXNoLnByb3RvdHlwZTtcblxuICAgIC8qKlxuICAgICAqIEFuIG9iamVjdCB1c2VkIHRvIGZsYWcgZW52aXJvbm1lbnRzIGZlYXR1cmVzLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQHR5cGUgT2JqZWN0XG4gICAgICovXG4gICAgdmFyIHN1cHBvcnQgPSBsb2Rhc2guc3VwcG9ydCA9IHt9O1xuXG4gICAgLyoqXG4gICAgICogRGV0ZWN0IGlmIGZ1bmN0aW9ucyBjYW4gYmUgZGVjb21waWxlZCBieSBgRnVuY3Rpb24jdG9TdHJpbmdgXG4gICAgICogKGFsbCBidXQgUFMzIGFuZCBvbGRlciBPcGVyYSBtb2JpbGUgYnJvd3NlcnMgJiBhdm9pZGVkIGluIFdpbmRvd3MgOCBhcHBzKS5cbiAgICAgKlxuICAgICAqIEBtZW1iZXJPZiBfLnN1cHBvcnRcbiAgICAgKiBAdHlwZSBib29sZWFuXG4gICAgICovXG4gICAgc3VwcG9ydC5mdW5jRGVjb21wID0gIWlzTmF0aXZlKGNvbnRleHQuV2luUlRFcnJvcikgJiYgcmVUaGlzLnRlc3QocnVuSW5Db250ZXh0KTtcblxuICAgIC8qKlxuICAgICAqIERldGVjdCBpZiBgRnVuY3Rpb24jbmFtZWAgaXMgc3VwcG9ydGVkIChhbGwgYnV0IElFKS5cbiAgICAgKlxuICAgICAqIEBtZW1iZXJPZiBfLnN1cHBvcnRcbiAgICAgKiBAdHlwZSBib29sZWFuXG4gICAgICovXG4gICAgc3VwcG9ydC5mdW5jTmFtZXMgPSB0eXBlb2YgRnVuY3Rpb24ubmFtZSA9PSAnc3RyaW5nJztcblxuICAgIC8qKlxuICAgICAqIEJ5IGRlZmF1bHQsIHRoZSB0ZW1wbGF0ZSBkZWxpbWl0ZXJzIHVzZWQgYnkgTG8tRGFzaCBhcmUgc2ltaWxhciB0byB0aG9zZSBpblxuICAgICAqIGVtYmVkZGVkIFJ1YnkgKEVSQikuIENoYW5nZSB0aGUgZm9sbG93aW5nIHRlbXBsYXRlIHNldHRpbmdzIHRvIHVzZSBhbHRlcm5hdGl2ZVxuICAgICAqIGRlbGltaXRlcnMuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAdHlwZSBPYmplY3RcbiAgICAgKi9cbiAgICBsb2Rhc2gudGVtcGxhdGVTZXR0aW5ncyA9IHtcblxuICAgICAgLyoqXG4gICAgICAgKiBVc2VkIHRvIGRldGVjdCBgZGF0YWAgcHJvcGVydHkgdmFsdWVzIHRvIGJlIEhUTUwtZXNjYXBlZC5cbiAgICAgICAqXG4gICAgICAgKiBAbWVtYmVyT2YgXy50ZW1wbGF0ZVNldHRpbmdzXG4gICAgICAgKiBAdHlwZSBSZWdFeHBcbiAgICAgICAqL1xuICAgICAgJ2VzY2FwZSc6IC88JS0oW1xcc1xcU10rPyklPi9nLFxuXG4gICAgICAvKipcbiAgICAgICAqIFVzZWQgdG8gZGV0ZWN0IGNvZGUgdG8gYmUgZXZhbHVhdGVkLlxuICAgICAgICpcbiAgICAgICAqIEBtZW1iZXJPZiBfLnRlbXBsYXRlU2V0dGluZ3NcbiAgICAgICAqIEB0eXBlIFJlZ0V4cFxuICAgICAgICovXG4gICAgICAnZXZhbHVhdGUnOiAvPCUoW1xcc1xcU10rPyklPi9nLFxuXG4gICAgICAvKipcbiAgICAgICAqIFVzZWQgdG8gZGV0ZWN0IGBkYXRhYCBwcm9wZXJ0eSB2YWx1ZXMgdG8gaW5qZWN0LlxuICAgICAgICpcbiAgICAgICAqIEBtZW1iZXJPZiBfLnRlbXBsYXRlU2V0dGluZ3NcbiAgICAgICAqIEB0eXBlIFJlZ0V4cFxuICAgICAgICovXG4gICAgICAnaW50ZXJwb2xhdGUnOiByZUludGVycG9sYXRlLFxuXG4gICAgICAvKipcbiAgICAgICAqIFVzZWQgdG8gcmVmZXJlbmNlIHRoZSBkYXRhIG9iamVjdCBpbiB0aGUgdGVtcGxhdGUgdGV4dC5cbiAgICAgICAqXG4gICAgICAgKiBAbWVtYmVyT2YgXy50ZW1wbGF0ZVNldHRpbmdzXG4gICAgICAgKiBAdHlwZSBzdHJpbmdcbiAgICAgICAqL1xuICAgICAgJ3ZhcmlhYmxlJzogJycsXG5cbiAgICAgIC8qKlxuICAgICAgICogVXNlZCB0byBpbXBvcnQgdmFyaWFibGVzIGludG8gdGhlIGNvbXBpbGVkIHRlbXBsYXRlLlxuICAgICAgICpcbiAgICAgICAqIEBtZW1iZXJPZiBfLnRlbXBsYXRlU2V0dGluZ3NcbiAgICAgICAqIEB0eXBlIE9iamVjdFxuICAgICAgICovXG4gICAgICAnaW1wb3J0cyc6IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogQSByZWZlcmVuY2UgdG8gdGhlIGBsb2Rhc2hgIGZ1bmN0aW9uLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAbWVtYmVyT2YgXy50ZW1wbGF0ZVNldHRpbmdzLmltcG9ydHNcbiAgICAgICAgICogQHR5cGUgRnVuY3Rpb25cbiAgICAgICAgICovXG4gICAgICAgICdfJzogbG9kYXNoXG4gICAgICB9XG4gICAgfTtcblxuICAgIC8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuXG4gICAgLyoqXG4gICAgICogVGhlIGJhc2UgaW1wbGVtZW50YXRpb24gb2YgYF8uYmluZGAgdGhhdCBjcmVhdGVzIHRoZSBib3VuZCBmdW5jdGlvbiBhbmRcbiAgICAgKiBzZXRzIGl0cyBtZXRhIGRhdGEuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7QXJyYXl9IGJpbmREYXRhIFRoZSBiaW5kIGRhdGEgYXJyYXkuXG4gICAgICogQHJldHVybnMge0Z1bmN0aW9ufSBSZXR1cm5zIHRoZSBuZXcgYm91bmQgZnVuY3Rpb24uXG4gICAgICovXG4gICAgZnVuY3Rpb24gYmFzZUJpbmQoYmluZERhdGEpIHtcbiAgICAgIHZhciBmdW5jID0gYmluZERhdGFbMF0sXG4gICAgICAgICAgcGFydGlhbEFyZ3MgPSBiaW5kRGF0YVsyXSxcbiAgICAgICAgICB0aGlzQXJnID0gYmluZERhdGFbNF07XG5cbiAgICAgIGZ1bmN0aW9uIGJvdW5kKCkge1xuICAgICAgICAvLyBgRnVuY3Rpb24jYmluZGAgc3BlY1xuICAgICAgICAvLyBodHRwOi8vZXM1LmdpdGh1Yi5pby8jeDE1LjMuNC41XG4gICAgICAgIGlmIChwYXJ0aWFsQXJncykge1xuICAgICAgICAgIC8vIGF2b2lkIGBhcmd1bWVudHNgIG9iamVjdCBkZW9wdGltaXphdGlvbnMgYnkgdXNpbmcgYHNsaWNlYCBpbnN0ZWFkXG4gICAgICAgICAgLy8gb2YgYEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsYCBhbmQgbm90IGFzc2lnbmluZyBgYXJndW1lbnRzYCB0byBhXG4gICAgICAgICAgLy8gdmFyaWFibGUgYXMgYSB0ZXJuYXJ5IGV4cHJlc3Npb25cbiAgICAgICAgICB2YXIgYXJncyA9IHNsaWNlKHBhcnRpYWxBcmdzKTtcbiAgICAgICAgICBwdXNoLmFwcGx5KGFyZ3MsIGFyZ3VtZW50cyk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gbWltaWMgdGhlIGNvbnN0cnVjdG9yJ3MgYHJldHVybmAgYmVoYXZpb3JcbiAgICAgICAgLy8gaHR0cDovL2VzNS5naXRodWIuaW8vI3gxMy4yLjJcbiAgICAgICAgaWYgKHRoaXMgaW5zdGFuY2VvZiBib3VuZCkge1xuICAgICAgICAgIC8vIGVuc3VyZSBgbmV3IGJvdW5kYCBpcyBhbiBpbnN0YW5jZSBvZiBgZnVuY2BcbiAgICAgICAgICB2YXIgdGhpc0JpbmRpbmcgPSBiYXNlQ3JlYXRlKGZ1bmMucHJvdG90eXBlKSxcbiAgICAgICAgICAgICAgcmVzdWx0ID0gZnVuYy5hcHBseSh0aGlzQmluZGluZywgYXJncyB8fCBhcmd1bWVudHMpO1xuICAgICAgICAgIHJldHVybiBpc09iamVjdChyZXN1bHQpID8gcmVzdWx0IDogdGhpc0JpbmRpbmc7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZ1bmMuYXBwbHkodGhpc0FyZywgYXJncyB8fCBhcmd1bWVudHMpO1xuICAgICAgfVxuICAgICAgc2V0QmluZERhdGEoYm91bmQsIGJpbmREYXRhKTtcbiAgICAgIHJldHVybiBib3VuZDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGUgYmFzZSBpbXBsZW1lbnRhdGlvbiBvZiBgXy5jbG9uZWAgd2l0aG91dCBhcmd1bWVudCBqdWdnbGluZyBvciBzdXBwb3J0XG4gICAgICogZm9yIGB0aGlzQXJnYCBiaW5kaW5nLlxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBjbG9uZS5cbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtpc0RlZXA9ZmFsc2VdIFNwZWNpZnkgYSBkZWVwIGNsb25lLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IFtjYWxsYmFja10gVGhlIGZ1bmN0aW9uIHRvIGN1c3RvbWl6ZSBjbG9uaW5nIHZhbHVlcy5cbiAgICAgKiBAcGFyYW0ge0FycmF5fSBbc3RhY2tBPVtdXSBUcmFja3MgdHJhdmVyc2VkIHNvdXJjZSBvYmplY3RzLlxuICAgICAqIEBwYXJhbSB7QXJyYXl9IFtzdGFja0I9W11dIEFzc29jaWF0ZXMgY2xvbmVzIHdpdGggc291cmNlIGNvdW50ZXJwYXJ0cy5cbiAgICAgKiBAcmV0dXJucyB7Kn0gUmV0dXJucyB0aGUgY2xvbmVkIHZhbHVlLlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGJhc2VDbG9uZSh2YWx1ZSwgaXNEZWVwLCBjYWxsYmFjaywgc3RhY2tBLCBzdGFja0IpIHtcbiAgICAgIGlmIChjYWxsYmFjaykge1xuICAgICAgICB2YXIgcmVzdWx0ID0gY2FsbGJhY2sodmFsdWUpO1xuICAgICAgICBpZiAodHlwZW9mIHJlc3VsdCAhPSAndW5kZWZpbmVkJykge1xuICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIC8vIGluc3BlY3QgW1tDbGFzc11dXG4gICAgICB2YXIgaXNPYmogPSBpc09iamVjdCh2YWx1ZSk7XG4gICAgICBpZiAoaXNPYmopIHtcbiAgICAgICAgdmFyIGNsYXNzTmFtZSA9IHRvU3RyaW5nLmNhbGwodmFsdWUpO1xuICAgICAgICBpZiAoIWNsb25lYWJsZUNsYXNzZXNbY2xhc3NOYW1lXSkge1xuICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgY3RvciA9IGN0b3JCeUNsYXNzW2NsYXNzTmFtZV07XG4gICAgICAgIHN3aXRjaCAoY2xhc3NOYW1lKSB7XG4gICAgICAgICAgY2FzZSBib29sQ2xhc3M6XG4gICAgICAgICAgY2FzZSBkYXRlQ2xhc3M6XG4gICAgICAgICAgICByZXR1cm4gbmV3IGN0b3IoK3ZhbHVlKTtcblxuICAgICAgICAgIGNhc2UgbnVtYmVyQ2xhc3M6XG4gICAgICAgICAgY2FzZSBzdHJpbmdDbGFzczpcbiAgICAgICAgICAgIHJldHVybiBuZXcgY3Rvcih2YWx1ZSk7XG5cbiAgICAgICAgICBjYXNlIHJlZ2V4cENsYXNzOlxuICAgICAgICAgICAgcmVzdWx0ID0gY3Rvcih2YWx1ZS5zb3VyY2UsIHJlRmxhZ3MuZXhlYyh2YWx1ZSkpO1xuICAgICAgICAgICAgcmVzdWx0Lmxhc3RJbmRleCA9IHZhbHVlLmxhc3RJbmRleDtcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgIH1cbiAgICAgIHZhciBpc0FyciA9IGlzQXJyYXkodmFsdWUpO1xuICAgICAgaWYgKGlzRGVlcCkge1xuICAgICAgICAvLyBjaGVjayBmb3IgY2lyY3VsYXIgcmVmZXJlbmNlcyBhbmQgcmV0dXJuIGNvcnJlc3BvbmRpbmcgY2xvbmVcbiAgICAgICAgdmFyIGluaXRlZFN0YWNrID0gIXN0YWNrQTtcbiAgICAgICAgc3RhY2tBIHx8IChzdGFja0EgPSBnZXRBcnJheSgpKTtcbiAgICAgICAgc3RhY2tCIHx8IChzdGFja0IgPSBnZXRBcnJheSgpKTtcblxuICAgICAgICB2YXIgbGVuZ3RoID0gc3RhY2tBLmxlbmd0aDtcbiAgICAgICAgd2hpbGUgKGxlbmd0aC0tKSB7XG4gICAgICAgICAgaWYgKHN0YWNrQVtsZW5ndGhdID09IHZhbHVlKSB7XG4gICAgICAgICAgICByZXR1cm4gc3RhY2tCW2xlbmd0aF07XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJlc3VsdCA9IGlzQXJyID8gY3Rvcih2YWx1ZS5sZW5ndGgpIDoge307XG4gICAgICB9XG4gICAgICBlbHNlIHtcbiAgICAgICAgcmVzdWx0ID0gaXNBcnIgPyBzbGljZSh2YWx1ZSkgOiBhc3NpZ24oe30sIHZhbHVlKTtcbiAgICAgIH1cbiAgICAgIC8vIGFkZCBhcnJheSBwcm9wZXJ0aWVzIGFzc2lnbmVkIGJ5IGBSZWdFeHAjZXhlY2BcbiAgICAgIGlmIChpc0Fycikge1xuICAgICAgICBpZiAoaGFzT3duUHJvcGVydHkuY2FsbCh2YWx1ZSwgJ2luZGV4JykpIHtcbiAgICAgICAgICByZXN1bHQuaW5kZXggPSB2YWx1ZS5pbmRleDtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaGFzT3duUHJvcGVydHkuY2FsbCh2YWx1ZSwgJ2lucHV0JykpIHtcbiAgICAgICAgICByZXN1bHQuaW5wdXQgPSB2YWx1ZS5pbnB1dDtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgLy8gZXhpdCBmb3Igc2hhbGxvdyBjbG9uZVxuICAgICAgaWYgKCFpc0RlZXApIHtcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgIH1cbiAgICAgIC8vIGFkZCB0aGUgc291cmNlIHZhbHVlIHRvIHRoZSBzdGFjayBvZiB0cmF2ZXJzZWQgb2JqZWN0c1xuICAgICAgLy8gYW5kIGFzc29jaWF0ZSBpdCB3aXRoIGl0cyBjbG9uZVxuICAgICAgc3RhY2tBLnB1c2godmFsdWUpO1xuICAgICAgc3RhY2tCLnB1c2gocmVzdWx0KTtcblxuICAgICAgLy8gcmVjdXJzaXZlbHkgcG9wdWxhdGUgY2xvbmUgKHN1c2NlcHRpYmxlIHRvIGNhbGwgc3RhY2sgbGltaXRzKVxuICAgICAgKGlzQXJyID8gZm9yRWFjaCA6IGZvck93bikodmFsdWUsIGZ1bmN0aW9uKG9ialZhbHVlLCBrZXkpIHtcbiAgICAgICAgcmVzdWx0W2tleV0gPSBiYXNlQ2xvbmUob2JqVmFsdWUsIGlzRGVlcCwgY2FsbGJhY2ssIHN0YWNrQSwgc3RhY2tCKTtcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoaW5pdGVkU3RhY2spIHtcbiAgICAgICAgcmVsZWFzZUFycmF5KHN0YWNrQSk7XG4gICAgICAgIHJlbGVhc2VBcnJheShzdGFja0IpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGUgYmFzZSBpbXBsZW1lbnRhdGlvbiBvZiBgXy5jcmVhdGVgIHdpdGhvdXQgc3VwcG9ydCBmb3IgYXNzaWduaW5nXG4gICAgICogcHJvcGVydGllcyB0byB0aGUgY3JlYXRlZCBvYmplY3QuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBwcm90b3R5cGUgVGhlIG9iamVjdCB0byBpbmhlcml0IGZyb20uXG4gICAgICogQHJldHVybnMge09iamVjdH0gUmV0dXJucyB0aGUgbmV3IG9iamVjdC5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBiYXNlQ3JlYXRlKHByb3RvdHlwZSwgcHJvcGVydGllcykge1xuICAgICAgcmV0dXJuIGlzT2JqZWN0KHByb3RvdHlwZSkgPyBuYXRpdmVDcmVhdGUocHJvdG90eXBlKSA6IHt9O1xuICAgIH1cbiAgICAvLyBmYWxsYmFjayBmb3IgYnJvd3NlcnMgd2l0aG91dCBgT2JqZWN0LmNyZWF0ZWBcbiAgICBpZiAoIW5hdGl2ZUNyZWF0ZSkge1xuICAgICAgYmFzZUNyZWF0ZSA9IChmdW5jdGlvbigpIHtcbiAgICAgICAgZnVuY3Rpb24gT2JqZWN0KCkge31cbiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uKHByb3RvdHlwZSkge1xuICAgICAgICAgIGlmIChpc09iamVjdChwcm90b3R5cGUpKSB7XG4gICAgICAgICAgICBPYmplY3QucHJvdG90eXBlID0gcHJvdG90eXBlO1xuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IG5ldyBPYmplY3Q7XG4gICAgICAgICAgICBPYmplY3QucHJvdG90eXBlID0gbnVsbDtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIHJlc3VsdCB8fCBjb250ZXh0Lk9iamVjdCgpO1xuICAgICAgICB9O1xuICAgICAgfSgpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGUgYmFzZSBpbXBsZW1lbnRhdGlvbiBvZiBgXy5jcmVhdGVDYWxsYmFja2Agd2l0aG91dCBzdXBwb3J0IGZvciBjcmVhdGluZ1xuICAgICAqIFwiXy5wbHVja1wiIG9yIFwiXy53aGVyZVwiIHN0eWxlIGNhbGxiYWNrcy5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHsqfSBbZnVuYz1pZGVudGl0eV0gVGhlIHZhbHVlIHRvIGNvbnZlcnQgdG8gYSBjYWxsYmFjay5cbiAgICAgKiBAcGFyYW0geyp9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgdGhlIGNyZWF0ZWQgY2FsbGJhY2suXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IFthcmdDb3VudF0gVGhlIG51bWJlciBvZiBhcmd1bWVudHMgdGhlIGNhbGxiYWNrIGFjY2VwdHMuXG4gICAgICogQHJldHVybnMge0Z1bmN0aW9ufSBSZXR1cm5zIGEgY2FsbGJhY2sgZnVuY3Rpb24uXG4gICAgICovXG4gICAgZnVuY3Rpb24gYmFzZUNyZWF0ZUNhbGxiYWNrKGZ1bmMsIHRoaXNBcmcsIGFyZ0NvdW50KSB7XG4gICAgICBpZiAodHlwZW9mIGZ1bmMgIT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICByZXR1cm4gaWRlbnRpdHk7XG4gICAgICB9XG4gICAgICAvLyBleGl0IGVhcmx5IGZvciBubyBgdGhpc0FyZ2Agb3IgYWxyZWFkeSBib3VuZCBieSBgRnVuY3Rpb24jYmluZGBcbiAgICAgIGlmICh0eXBlb2YgdGhpc0FyZyA9PSAndW5kZWZpbmVkJyB8fCAhKCdwcm90b3R5cGUnIGluIGZ1bmMpKSB7XG4gICAgICAgIHJldHVybiBmdW5jO1xuICAgICAgfVxuICAgICAgdmFyIGJpbmREYXRhID0gZnVuYy5fX2JpbmREYXRhX187XG4gICAgICBpZiAodHlwZW9mIGJpbmREYXRhID09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIGlmIChzdXBwb3J0LmZ1bmNOYW1lcykge1xuICAgICAgICAgIGJpbmREYXRhID0gIWZ1bmMubmFtZTtcbiAgICAgICAgfVxuICAgICAgICBiaW5kRGF0YSA9IGJpbmREYXRhIHx8ICFzdXBwb3J0LmZ1bmNEZWNvbXA7XG4gICAgICAgIGlmICghYmluZERhdGEpIHtcbiAgICAgICAgICB2YXIgc291cmNlID0gZm5Ub1N0cmluZy5jYWxsKGZ1bmMpO1xuICAgICAgICAgIGlmICghc3VwcG9ydC5mdW5jTmFtZXMpIHtcbiAgICAgICAgICAgIGJpbmREYXRhID0gIXJlRnVuY05hbWUudGVzdChzb3VyY2UpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoIWJpbmREYXRhKSB7XG4gICAgICAgICAgICAvLyBjaGVja3MgaWYgYGZ1bmNgIHJlZmVyZW5jZXMgdGhlIGB0aGlzYCBrZXl3b3JkIGFuZCBzdG9yZXMgdGhlIHJlc3VsdFxuICAgICAgICAgICAgYmluZERhdGEgPSByZVRoaXMudGVzdChzb3VyY2UpO1xuICAgICAgICAgICAgc2V0QmluZERhdGEoZnVuYywgYmluZERhdGEpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgLy8gZXhpdCBlYXJseSBpZiB0aGVyZSBhcmUgbm8gYHRoaXNgIHJlZmVyZW5jZXMgb3IgYGZ1bmNgIGlzIGJvdW5kXG4gICAgICBpZiAoYmluZERhdGEgPT09IGZhbHNlIHx8IChiaW5kRGF0YSAhPT0gdHJ1ZSAmJiBiaW5kRGF0YVsxXSAmIDEpKSB7XG4gICAgICAgIHJldHVybiBmdW5jO1xuICAgICAgfVxuICAgICAgc3dpdGNoIChhcmdDb3VudCkge1xuICAgICAgICBjYXNlIDE6IHJldHVybiBmdW5jdGlvbih2YWx1ZSkge1xuICAgICAgICAgIHJldHVybiBmdW5jLmNhbGwodGhpc0FyZywgdmFsdWUpO1xuICAgICAgICB9O1xuICAgICAgICBjYXNlIDI6IHJldHVybiBmdW5jdGlvbihhLCBiKSB7XG4gICAgICAgICAgcmV0dXJuIGZ1bmMuY2FsbCh0aGlzQXJnLCBhLCBiKTtcbiAgICAgICAgfTtcbiAgICAgICAgY2FzZSAzOiByZXR1cm4gZnVuY3Rpb24odmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKSB7XG4gICAgICAgICAgcmV0dXJuIGZ1bmMuY2FsbCh0aGlzQXJnLCB2YWx1ZSwgaW5kZXgsIGNvbGxlY3Rpb24pO1xuICAgICAgICB9O1xuICAgICAgICBjYXNlIDQ6IHJldHVybiBmdW5jdGlvbihhY2N1bXVsYXRvciwgdmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKSB7XG4gICAgICAgICAgcmV0dXJuIGZ1bmMuY2FsbCh0aGlzQXJnLCBhY2N1bXVsYXRvciwgdmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKTtcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBiaW5kKGZ1bmMsIHRoaXNBcmcpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoZSBiYXNlIGltcGxlbWVudGF0aW9uIG9mIGBjcmVhdGVXcmFwcGVyYCB0aGF0IGNyZWF0ZXMgdGhlIHdyYXBwZXIgYW5kXG4gICAgICogc2V0cyBpdHMgbWV0YSBkYXRhLlxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge0FycmF5fSBiaW5kRGF0YSBUaGUgYmluZCBkYXRhIGFycmF5LlxuICAgICAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IGZ1bmN0aW9uLlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGJhc2VDcmVhdGVXcmFwcGVyKGJpbmREYXRhKSB7XG4gICAgICB2YXIgZnVuYyA9IGJpbmREYXRhWzBdLFxuICAgICAgICAgIGJpdG1hc2sgPSBiaW5kRGF0YVsxXSxcbiAgICAgICAgICBwYXJ0aWFsQXJncyA9IGJpbmREYXRhWzJdLFxuICAgICAgICAgIHBhcnRpYWxSaWdodEFyZ3MgPSBiaW5kRGF0YVszXSxcbiAgICAgICAgICB0aGlzQXJnID0gYmluZERhdGFbNF0sXG4gICAgICAgICAgYXJpdHkgPSBiaW5kRGF0YVs1XTtcblxuICAgICAgdmFyIGlzQmluZCA9IGJpdG1hc2sgJiAxLFxuICAgICAgICAgIGlzQmluZEtleSA9IGJpdG1hc2sgJiAyLFxuICAgICAgICAgIGlzQ3VycnkgPSBiaXRtYXNrICYgNCxcbiAgICAgICAgICBpc0N1cnJ5Qm91bmQgPSBiaXRtYXNrICYgOCxcbiAgICAgICAgICBrZXkgPSBmdW5jO1xuXG4gICAgICBmdW5jdGlvbiBib3VuZCgpIHtcbiAgICAgICAgdmFyIHRoaXNCaW5kaW5nID0gaXNCaW5kID8gdGhpc0FyZyA6IHRoaXM7XG4gICAgICAgIGlmIChwYXJ0aWFsQXJncykge1xuICAgICAgICAgIHZhciBhcmdzID0gc2xpY2UocGFydGlhbEFyZ3MpO1xuICAgICAgICAgIHB1c2guYXBwbHkoYXJncywgYXJndW1lbnRzKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAocGFydGlhbFJpZ2h0QXJncyB8fCBpc0N1cnJ5KSB7XG4gICAgICAgICAgYXJncyB8fCAoYXJncyA9IHNsaWNlKGFyZ3VtZW50cykpO1xuICAgICAgICAgIGlmIChwYXJ0aWFsUmlnaHRBcmdzKSB7XG4gICAgICAgICAgICBwdXNoLmFwcGx5KGFyZ3MsIHBhcnRpYWxSaWdodEFyZ3MpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoaXNDdXJyeSAmJiBhcmdzLmxlbmd0aCA8IGFyaXR5KSB7XG4gICAgICAgICAgICBiaXRtYXNrIHw9IDE2ICYgfjMyO1xuICAgICAgICAgICAgcmV0dXJuIGJhc2VDcmVhdGVXcmFwcGVyKFtmdW5jLCAoaXNDdXJyeUJvdW5kID8gYml0bWFzayA6IGJpdG1hc2sgJiB+MyksIGFyZ3MsIG51bGwsIHRoaXNBcmcsIGFyaXR5XSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGFyZ3MgfHwgKGFyZ3MgPSBhcmd1bWVudHMpO1xuICAgICAgICBpZiAoaXNCaW5kS2V5KSB7XG4gICAgICAgICAgZnVuYyA9IHRoaXNCaW5kaW5nW2tleV07XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMgaW5zdGFuY2VvZiBib3VuZCkge1xuICAgICAgICAgIHRoaXNCaW5kaW5nID0gYmFzZUNyZWF0ZShmdW5jLnByb3RvdHlwZSk7XG4gICAgICAgICAgdmFyIHJlc3VsdCA9IGZ1bmMuYXBwbHkodGhpc0JpbmRpbmcsIGFyZ3MpO1xuICAgICAgICAgIHJldHVybiBpc09iamVjdChyZXN1bHQpID8gcmVzdWx0IDogdGhpc0JpbmRpbmc7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZ1bmMuYXBwbHkodGhpc0JpbmRpbmcsIGFyZ3MpO1xuICAgICAgfVxuICAgICAgc2V0QmluZERhdGEoYm91bmQsIGJpbmREYXRhKTtcbiAgICAgIHJldHVybiBib3VuZDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGUgYmFzZSBpbXBsZW1lbnRhdGlvbiBvZiBgXy5kaWZmZXJlbmNlYCB0aGF0IGFjY2VwdHMgYSBzaW5nbGUgYXJyYXlcbiAgICAgKiBvZiB2YWx1ZXMgdG8gZXhjbHVkZS5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtBcnJheX0gYXJyYXkgVGhlIGFycmF5IHRvIHByb2Nlc3MuXG4gICAgICogQHBhcmFtIHtBcnJheX0gW3ZhbHVlc10gVGhlIGFycmF5IG9mIHZhbHVlcyB0byBleGNsdWRlLlxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyBhIG5ldyBhcnJheSBvZiBmaWx0ZXJlZCB2YWx1ZXMuXG4gICAgICovXG4gICAgZnVuY3Rpb24gYmFzZURpZmZlcmVuY2UoYXJyYXksIHZhbHVlcykge1xuICAgICAgdmFyIGluZGV4ID0gLTEsXG4gICAgICAgICAgaW5kZXhPZiA9IGdldEluZGV4T2YoKSxcbiAgICAgICAgICBsZW5ndGggPSBhcnJheSA/IGFycmF5Lmxlbmd0aCA6IDAsXG4gICAgICAgICAgaXNMYXJnZSA9IGxlbmd0aCA+PSBsYXJnZUFycmF5U2l6ZSAmJiBpbmRleE9mID09PSBiYXNlSW5kZXhPZixcbiAgICAgICAgICByZXN1bHQgPSBbXTtcblxuICAgICAgaWYgKGlzTGFyZ2UpIHtcbiAgICAgICAgdmFyIGNhY2hlID0gY3JlYXRlQ2FjaGUodmFsdWVzKTtcbiAgICAgICAgaWYgKGNhY2hlKSB7XG4gICAgICAgICAgaW5kZXhPZiA9IGNhY2hlSW5kZXhPZjtcbiAgICAgICAgICB2YWx1ZXMgPSBjYWNoZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBpc0xhcmdlID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHdoaWxlICgrK2luZGV4IDwgbGVuZ3RoKSB7XG4gICAgICAgIHZhciB2YWx1ZSA9IGFycmF5W2luZGV4XTtcbiAgICAgICAgaWYgKGluZGV4T2YodmFsdWVzLCB2YWx1ZSkgPCAwKSB7XG4gICAgICAgICAgcmVzdWx0LnB1c2godmFsdWUpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAoaXNMYXJnZSkge1xuICAgICAgICByZWxlYXNlT2JqZWN0KHZhbHVlcyk7XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoZSBiYXNlIGltcGxlbWVudGF0aW9uIG9mIGBfLmZsYXR0ZW5gIHdpdGhvdXQgc3VwcG9ydCBmb3IgY2FsbGJhY2tcbiAgICAgKiBzaG9ydGhhbmRzIG9yIGB0aGlzQXJnYCBiaW5kaW5nLlxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge0FycmF5fSBhcnJheSBUaGUgYXJyYXkgdG8gZmxhdHRlbi5cbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtpc1NoYWxsb3c9ZmFsc2VdIEEgZmxhZyB0byByZXN0cmljdCBmbGF0dGVuaW5nIHRvIGEgc2luZ2xlIGxldmVsLlxuICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW2lzU3RyaWN0PWZhbHNlXSBBIGZsYWcgdG8gcmVzdHJpY3QgZmxhdHRlbmluZyB0byBhcnJheXMgYW5kIGBhcmd1bWVudHNgIG9iamVjdHMuXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IFtmcm9tSW5kZXg9MF0gVGhlIGluZGV4IHRvIHN0YXJ0IGZyb20uXG4gICAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIGEgbmV3IGZsYXR0ZW5lZCBhcnJheS5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBiYXNlRmxhdHRlbihhcnJheSwgaXNTaGFsbG93LCBpc1N0cmljdCwgZnJvbUluZGV4KSB7XG4gICAgICB2YXIgaW5kZXggPSAoZnJvbUluZGV4IHx8IDApIC0gMSxcbiAgICAgICAgICBsZW5ndGggPSBhcnJheSA/IGFycmF5Lmxlbmd0aCA6IDAsXG4gICAgICAgICAgcmVzdWx0ID0gW107XG5cbiAgICAgIHdoaWxlICgrK2luZGV4IDwgbGVuZ3RoKSB7XG4gICAgICAgIHZhciB2YWx1ZSA9IGFycmF5W2luZGV4XTtcblxuICAgICAgICBpZiAodmFsdWUgJiYgdHlwZW9mIHZhbHVlID09ICdvYmplY3QnICYmIHR5cGVvZiB2YWx1ZS5sZW5ndGggPT0gJ251bWJlcidcbiAgICAgICAgICAgICYmIChpc0FycmF5KHZhbHVlKSB8fCBpc0FyZ3VtZW50cyh2YWx1ZSkpKSB7XG4gICAgICAgICAgLy8gcmVjdXJzaXZlbHkgZmxhdHRlbiBhcnJheXMgKHN1c2NlcHRpYmxlIHRvIGNhbGwgc3RhY2sgbGltaXRzKVxuICAgICAgICAgIGlmICghaXNTaGFsbG93KSB7XG4gICAgICAgICAgICB2YWx1ZSA9IGJhc2VGbGF0dGVuKHZhbHVlLCBpc1NoYWxsb3csIGlzU3RyaWN0KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgdmFyIHZhbEluZGV4ID0gLTEsXG4gICAgICAgICAgICAgIHZhbExlbmd0aCA9IHZhbHVlLmxlbmd0aCxcbiAgICAgICAgICAgICAgcmVzSW5kZXggPSByZXN1bHQubGVuZ3RoO1xuXG4gICAgICAgICAgcmVzdWx0Lmxlbmd0aCArPSB2YWxMZW5ndGg7XG4gICAgICAgICAgd2hpbGUgKCsrdmFsSW5kZXggPCB2YWxMZW5ndGgpIHtcbiAgICAgICAgICAgIHJlc3VsdFtyZXNJbmRleCsrXSA9IHZhbHVlW3ZhbEluZGV4XTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoIWlzU3RyaWN0KSB7XG4gICAgICAgICAgcmVzdWx0LnB1c2godmFsdWUpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoZSBiYXNlIGltcGxlbWVudGF0aW9uIG9mIGBfLmlzRXF1YWxgLCB3aXRob3V0IHN1cHBvcnQgZm9yIGB0aGlzQXJnYCBiaW5kaW5nLFxuICAgICAqIHRoYXQgYWxsb3dzIHBhcnRpYWwgXCJfLndoZXJlXCIgc3R5bGUgY29tcGFyaXNvbnMuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7Kn0gYSBUaGUgdmFsdWUgdG8gY29tcGFyZS5cbiAgICAgKiBAcGFyYW0geyp9IGIgVGhlIG90aGVyIHZhbHVlIHRvIGNvbXBhcmUuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gW2NhbGxiYWNrXSBUaGUgZnVuY3Rpb24gdG8gY3VzdG9taXplIGNvbXBhcmluZyB2YWx1ZXMuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gW2lzV2hlcmU9ZmFsc2VdIEEgZmxhZyB0byBpbmRpY2F0ZSBwZXJmb3JtaW5nIHBhcnRpYWwgY29tcGFyaXNvbnMuXG4gICAgICogQHBhcmFtIHtBcnJheX0gW3N0YWNrQT1bXV0gVHJhY2tzIHRyYXZlcnNlZCBgYWAgb2JqZWN0cy5cbiAgICAgKiBAcGFyYW0ge0FycmF5fSBbc3RhY2tCPVtdXSBUcmFja3MgdHJhdmVyc2VkIGBiYCBvYmplY3RzLlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgdmFsdWVzIGFyZSBlcXVpdmFsZW50LCBlbHNlIGBmYWxzZWAuXG4gICAgICovXG4gICAgZnVuY3Rpb24gYmFzZUlzRXF1YWwoYSwgYiwgY2FsbGJhY2ssIGlzV2hlcmUsIHN0YWNrQSwgc3RhY2tCKSB7XG4gICAgICAvLyB1c2VkIHRvIGluZGljYXRlIHRoYXQgd2hlbiBjb21wYXJpbmcgb2JqZWN0cywgYGFgIGhhcyBhdCBsZWFzdCB0aGUgcHJvcGVydGllcyBvZiBgYmBcbiAgICAgIGlmIChjYWxsYmFjaykge1xuICAgICAgICB2YXIgcmVzdWx0ID0gY2FsbGJhY2soYSwgYik7XG4gICAgICAgIGlmICh0eXBlb2YgcmVzdWx0ICE9ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgcmV0dXJuICEhcmVzdWx0O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICAvLyBleGl0IGVhcmx5IGZvciBpZGVudGljYWwgdmFsdWVzXG4gICAgICBpZiAoYSA9PT0gYikge1xuICAgICAgICAvLyB0cmVhdCBgKzBgIHZzLiBgLTBgIGFzIG5vdCBlcXVhbFxuICAgICAgICByZXR1cm4gYSAhPT0gMCB8fCAoMSAvIGEgPT0gMSAvIGIpO1xuICAgICAgfVxuICAgICAgdmFyIHR5cGUgPSB0eXBlb2YgYSxcbiAgICAgICAgICBvdGhlclR5cGUgPSB0eXBlb2YgYjtcblxuICAgICAgLy8gZXhpdCBlYXJseSBmb3IgdW5saWtlIHByaW1pdGl2ZSB2YWx1ZXNcbiAgICAgIGlmIChhID09PSBhICYmXG4gICAgICAgICAgIShhICYmIG9iamVjdFR5cGVzW3R5cGVdKSAmJlxuICAgICAgICAgICEoYiAmJiBvYmplY3RUeXBlc1tvdGhlclR5cGVdKSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgICAvLyBleGl0IGVhcmx5IGZvciBgbnVsbGAgYW5kIGB1bmRlZmluZWRgIGF2b2lkaW5nIEVTMydzIEZ1bmN0aW9uI2NhbGwgYmVoYXZpb3JcbiAgICAgIC8vIGh0dHA6Ly9lczUuZ2l0aHViLmlvLyN4MTUuMy40LjRcbiAgICAgIGlmIChhID09IG51bGwgfHwgYiA9PSBudWxsKSB7XG4gICAgICAgIHJldHVybiBhID09PSBiO1xuICAgICAgfVxuICAgICAgLy8gY29tcGFyZSBbW0NsYXNzXV0gbmFtZXNcbiAgICAgIHZhciBjbGFzc05hbWUgPSB0b1N0cmluZy5jYWxsKGEpLFxuICAgICAgICAgIG90aGVyQ2xhc3MgPSB0b1N0cmluZy5jYWxsKGIpO1xuXG4gICAgICBpZiAoY2xhc3NOYW1lID09IGFyZ3NDbGFzcykge1xuICAgICAgICBjbGFzc05hbWUgPSBvYmplY3RDbGFzcztcbiAgICAgIH1cbiAgICAgIGlmIChvdGhlckNsYXNzID09IGFyZ3NDbGFzcykge1xuICAgICAgICBvdGhlckNsYXNzID0gb2JqZWN0Q2xhc3M7XG4gICAgICB9XG4gICAgICBpZiAoY2xhc3NOYW1lICE9IG90aGVyQ2xhc3MpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgICAgc3dpdGNoIChjbGFzc05hbWUpIHtcbiAgICAgICAgY2FzZSBib29sQ2xhc3M6XG4gICAgICAgIGNhc2UgZGF0ZUNsYXNzOlxuICAgICAgICAgIC8vIGNvZXJjZSBkYXRlcyBhbmQgYm9vbGVhbnMgdG8gbnVtYmVycywgZGF0ZXMgdG8gbWlsbGlzZWNvbmRzIGFuZCBib29sZWFuc1xuICAgICAgICAgIC8vIHRvIGAxYCBvciBgMGAgdHJlYXRpbmcgaW52YWxpZCBkYXRlcyBjb2VyY2VkIHRvIGBOYU5gIGFzIG5vdCBlcXVhbFxuICAgICAgICAgIHJldHVybiArYSA9PSArYjtcblxuICAgICAgICBjYXNlIG51bWJlckNsYXNzOlxuICAgICAgICAgIC8vIHRyZWF0IGBOYU5gIHZzLiBgTmFOYCBhcyBlcXVhbFxuICAgICAgICAgIHJldHVybiAoYSAhPSArYSlcbiAgICAgICAgICAgID8gYiAhPSArYlxuICAgICAgICAgICAgLy8gYnV0IHRyZWF0IGArMGAgdnMuIGAtMGAgYXMgbm90IGVxdWFsXG4gICAgICAgICAgICA6IChhID09IDAgPyAoMSAvIGEgPT0gMSAvIGIpIDogYSA9PSArYik7XG5cbiAgICAgICAgY2FzZSByZWdleHBDbGFzczpcbiAgICAgICAgY2FzZSBzdHJpbmdDbGFzczpcbiAgICAgICAgICAvLyBjb2VyY2UgcmVnZXhlcyB0byBzdHJpbmdzIChodHRwOi8vZXM1LmdpdGh1Yi5pby8jeDE1LjEwLjYuNClcbiAgICAgICAgICAvLyB0cmVhdCBzdHJpbmcgcHJpbWl0aXZlcyBhbmQgdGhlaXIgY29ycmVzcG9uZGluZyBvYmplY3QgaW5zdGFuY2VzIGFzIGVxdWFsXG4gICAgICAgICAgcmV0dXJuIGEgPT0gU3RyaW5nKGIpO1xuICAgICAgfVxuICAgICAgdmFyIGlzQXJyID0gY2xhc3NOYW1lID09IGFycmF5Q2xhc3M7XG4gICAgICBpZiAoIWlzQXJyKSB7XG4gICAgICAgIC8vIHVud3JhcCBhbnkgYGxvZGFzaGAgd3JhcHBlZCB2YWx1ZXNcbiAgICAgICAgdmFyIGFXcmFwcGVkID0gaGFzT3duUHJvcGVydHkuY2FsbChhLCAnX193cmFwcGVkX18nKSxcbiAgICAgICAgICAgIGJXcmFwcGVkID0gaGFzT3duUHJvcGVydHkuY2FsbChiLCAnX193cmFwcGVkX18nKTtcblxuICAgICAgICBpZiAoYVdyYXBwZWQgfHwgYldyYXBwZWQpIHtcbiAgICAgICAgICByZXR1cm4gYmFzZUlzRXF1YWwoYVdyYXBwZWQgPyBhLl9fd3JhcHBlZF9fIDogYSwgYldyYXBwZWQgPyBiLl9fd3JhcHBlZF9fIDogYiwgY2FsbGJhY2ssIGlzV2hlcmUsIHN0YWNrQSwgc3RhY2tCKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBleGl0IGZvciBmdW5jdGlvbnMgYW5kIERPTSBub2Rlc1xuICAgICAgICBpZiAoY2xhc3NOYW1lICE9IG9iamVjdENsYXNzKSB7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIC8vIGluIG9sZGVyIHZlcnNpb25zIG9mIE9wZXJhLCBgYXJndW1lbnRzYCBvYmplY3RzIGhhdmUgYEFycmF5YCBjb25zdHJ1Y3RvcnNcbiAgICAgICAgdmFyIGN0b3JBID0gYS5jb25zdHJ1Y3RvcixcbiAgICAgICAgICAgIGN0b3JCID0gYi5jb25zdHJ1Y3RvcjtcblxuICAgICAgICAvLyBub24gYE9iamVjdGAgb2JqZWN0IGluc3RhbmNlcyB3aXRoIGRpZmZlcmVudCBjb25zdHJ1Y3RvcnMgYXJlIG5vdCBlcXVhbFxuICAgICAgICBpZiAoY3RvckEgIT0gY3RvckIgJiZcbiAgICAgICAgICAgICAgIShpc0Z1bmN0aW9uKGN0b3JBKSAmJiBjdG9yQSBpbnN0YW5jZW9mIGN0b3JBICYmIGlzRnVuY3Rpb24oY3RvckIpICYmIGN0b3JCIGluc3RhbmNlb2YgY3RvckIpICYmXG4gICAgICAgICAgICAgICgnY29uc3RydWN0b3InIGluIGEgJiYgJ2NvbnN0cnVjdG9yJyBpbiBiKVxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICAvLyBhc3N1bWUgY3ljbGljIHN0cnVjdHVyZXMgYXJlIGVxdWFsXG4gICAgICAvLyB0aGUgYWxnb3JpdGhtIGZvciBkZXRlY3RpbmcgY3ljbGljIHN0cnVjdHVyZXMgaXMgYWRhcHRlZCBmcm9tIEVTIDUuMVxuICAgICAgLy8gc2VjdGlvbiAxNS4xMi4zLCBhYnN0cmFjdCBvcGVyYXRpb24gYEpPYCAoaHR0cDovL2VzNS5naXRodWIuaW8vI3gxNS4xMi4zKVxuICAgICAgdmFyIGluaXRlZFN0YWNrID0gIXN0YWNrQTtcbiAgICAgIHN0YWNrQSB8fCAoc3RhY2tBID0gZ2V0QXJyYXkoKSk7XG4gICAgICBzdGFja0IgfHwgKHN0YWNrQiA9IGdldEFycmF5KCkpO1xuXG4gICAgICB2YXIgbGVuZ3RoID0gc3RhY2tBLmxlbmd0aDtcbiAgICAgIHdoaWxlIChsZW5ndGgtLSkge1xuICAgICAgICBpZiAoc3RhY2tBW2xlbmd0aF0gPT0gYSkge1xuICAgICAgICAgIHJldHVybiBzdGFja0JbbGVuZ3RoXSA9PSBiO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICB2YXIgc2l6ZSA9IDA7XG4gICAgICByZXN1bHQgPSB0cnVlO1xuXG4gICAgICAvLyBhZGQgYGFgIGFuZCBgYmAgdG8gdGhlIHN0YWNrIG9mIHRyYXZlcnNlZCBvYmplY3RzXG4gICAgICBzdGFja0EucHVzaChhKTtcbiAgICAgIHN0YWNrQi5wdXNoKGIpO1xuXG4gICAgICAvLyByZWN1cnNpdmVseSBjb21wYXJlIG9iamVjdHMgYW5kIGFycmF5cyAoc3VzY2VwdGlibGUgdG8gY2FsbCBzdGFjayBsaW1pdHMpXG4gICAgICBpZiAoaXNBcnIpIHtcbiAgICAgICAgLy8gY29tcGFyZSBsZW5ndGhzIHRvIGRldGVybWluZSBpZiBhIGRlZXAgY29tcGFyaXNvbiBpcyBuZWNlc3NhcnlcbiAgICAgICAgbGVuZ3RoID0gYS5sZW5ndGg7XG4gICAgICAgIHNpemUgPSBiLmxlbmd0aDtcbiAgICAgICAgcmVzdWx0ID0gc2l6ZSA9PSBsZW5ndGg7XG5cbiAgICAgICAgaWYgKHJlc3VsdCB8fCBpc1doZXJlKSB7XG4gICAgICAgICAgLy8gZGVlcCBjb21wYXJlIHRoZSBjb250ZW50cywgaWdub3Jpbmcgbm9uLW51bWVyaWMgcHJvcGVydGllc1xuICAgICAgICAgIHdoaWxlIChzaXplLS0pIHtcbiAgICAgICAgICAgIHZhciBpbmRleCA9IGxlbmd0aCxcbiAgICAgICAgICAgICAgICB2YWx1ZSA9IGJbc2l6ZV07XG5cbiAgICAgICAgICAgIGlmIChpc1doZXJlKSB7XG4gICAgICAgICAgICAgIHdoaWxlIChpbmRleC0tKSB7XG4gICAgICAgICAgICAgICAgaWYgKChyZXN1bHQgPSBiYXNlSXNFcXVhbChhW2luZGV4XSwgdmFsdWUsIGNhbGxiYWNrLCBpc1doZXJlLCBzdGFja0EsIHN0YWNrQikpKSB7XG4gICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSBpZiAoIShyZXN1bHQgPSBiYXNlSXNFcXVhbChhW3NpemVdLCB2YWx1ZSwgY2FsbGJhY2ssIGlzV2hlcmUsIHN0YWNrQSwgc3RhY2tCKSkpIHtcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICBlbHNlIHtcbiAgICAgICAgLy8gZGVlcCBjb21wYXJlIG9iamVjdHMgdXNpbmcgYGZvckluYCwgaW5zdGVhZCBvZiBgZm9yT3duYCwgdG8gYXZvaWQgYE9iamVjdC5rZXlzYFxuICAgICAgICAvLyB3aGljaCwgaW4gdGhpcyBjYXNlLCBpcyBtb3JlIGNvc3RseVxuICAgICAgICBmb3JJbihiLCBmdW5jdGlvbih2YWx1ZSwga2V5LCBiKSB7XG4gICAgICAgICAgaWYgKGhhc093blByb3BlcnR5LmNhbGwoYiwga2V5KSkge1xuICAgICAgICAgICAgLy8gY291bnQgdGhlIG51bWJlciBvZiBwcm9wZXJ0aWVzLlxuICAgICAgICAgICAgc2l6ZSsrO1xuICAgICAgICAgICAgLy8gZGVlcCBjb21wYXJlIGVhY2ggcHJvcGVydHkgdmFsdWUuXG4gICAgICAgICAgICByZXR1cm4gKHJlc3VsdCA9IGhhc093blByb3BlcnR5LmNhbGwoYSwga2V5KSAmJiBiYXNlSXNFcXVhbChhW2tleV0sIHZhbHVlLCBjYWxsYmFjaywgaXNXaGVyZSwgc3RhY2tBLCBzdGFja0IpKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChyZXN1bHQgJiYgIWlzV2hlcmUpIHtcbiAgICAgICAgICAvLyBlbnN1cmUgYm90aCBvYmplY3RzIGhhdmUgdGhlIHNhbWUgbnVtYmVyIG9mIHByb3BlcnRpZXNcbiAgICAgICAgICBmb3JJbihhLCBmdW5jdGlvbih2YWx1ZSwga2V5LCBhKSB7XG4gICAgICAgICAgICBpZiAoaGFzT3duUHJvcGVydHkuY2FsbChhLCBrZXkpKSB7XG4gICAgICAgICAgICAgIC8vIGBzaXplYCB3aWxsIGJlIGAtMWAgaWYgYGFgIGhhcyBtb3JlIHByb3BlcnRpZXMgdGhhbiBgYmBcbiAgICAgICAgICAgICAgcmV0dXJuIChyZXN1bHQgPSAtLXNpemUgPiAtMSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHN0YWNrQS5wb3AoKTtcbiAgICAgIHN0YWNrQi5wb3AoKTtcblxuICAgICAgaWYgKGluaXRlZFN0YWNrKSB7XG4gICAgICAgIHJlbGVhc2VBcnJheShzdGFja0EpO1xuICAgICAgICByZWxlYXNlQXJyYXkoc3RhY2tCKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhlIGJhc2UgaW1wbGVtZW50YXRpb24gb2YgYF8ubWVyZ2VgIHdpdGhvdXQgYXJndW1lbnQganVnZ2xpbmcgb3Igc3VwcG9ydFxuICAgICAqIGZvciBgdGhpc0FyZ2AgYmluZGluZy5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtPYmplY3R9IG9iamVjdCBUaGUgZGVzdGluYXRpb24gb2JqZWN0LlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBzb3VyY2UgVGhlIHNvdXJjZSBvYmplY3QuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gW2NhbGxiYWNrXSBUaGUgZnVuY3Rpb24gdG8gY3VzdG9taXplIG1lcmdpbmcgcHJvcGVydGllcy5cbiAgICAgKiBAcGFyYW0ge0FycmF5fSBbc3RhY2tBPVtdXSBUcmFja3MgdHJhdmVyc2VkIHNvdXJjZSBvYmplY3RzLlxuICAgICAqIEBwYXJhbSB7QXJyYXl9IFtzdGFja0I9W11dIEFzc29jaWF0ZXMgdmFsdWVzIHdpdGggc291cmNlIGNvdW50ZXJwYXJ0cy5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBiYXNlTWVyZ2Uob2JqZWN0LCBzb3VyY2UsIGNhbGxiYWNrLCBzdGFja0EsIHN0YWNrQikge1xuICAgICAgKGlzQXJyYXkoc291cmNlKSA/IGZvckVhY2ggOiBmb3JPd24pKHNvdXJjZSwgZnVuY3Rpb24oc291cmNlLCBrZXkpIHtcbiAgICAgICAgdmFyIGZvdW5kLFxuICAgICAgICAgICAgaXNBcnIsXG4gICAgICAgICAgICByZXN1bHQgPSBzb3VyY2UsXG4gICAgICAgICAgICB2YWx1ZSA9IG9iamVjdFtrZXldO1xuXG4gICAgICAgIGlmIChzb3VyY2UgJiYgKChpc0FyciA9IGlzQXJyYXkoc291cmNlKSkgfHwgaXNQbGFpbk9iamVjdChzb3VyY2UpKSkge1xuICAgICAgICAgIC8vIGF2b2lkIG1lcmdpbmcgcHJldmlvdXNseSBtZXJnZWQgY3ljbGljIHNvdXJjZXNcbiAgICAgICAgICB2YXIgc3RhY2tMZW5ndGggPSBzdGFja0EubGVuZ3RoO1xuICAgICAgICAgIHdoaWxlIChzdGFja0xlbmd0aC0tKSB7XG4gICAgICAgICAgICBpZiAoKGZvdW5kID0gc3RhY2tBW3N0YWNrTGVuZ3RoXSA9PSBzb3VyY2UpKSB7XG4gICAgICAgICAgICAgIHZhbHVlID0gc3RhY2tCW3N0YWNrTGVuZ3RoXTtcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmICghZm91bmQpIHtcbiAgICAgICAgICAgIHZhciBpc1NoYWxsb3c7XG4gICAgICAgICAgICBpZiAoY2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgcmVzdWx0ID0gY2FsbGJhY2sodmFsdWUsIHNvdXJjZSk7XG4gICAgICAgICAgICAgIGlmICgoaXNTaGFsbG93ID0gdHlwZW9mIHJlc3VsdCAhPSAndW5kZWZpbmVkJykpIHtcbiAgICAgICAgICAgICAgICB2YWx1ZSA9IHJlc3VsdDtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFpc1NoYWxsb3cpIHtcbiAgICAgICAgICAgICAgdmFsdWUgPSBpc0FyclxuICAgICAgICAgICAgICAgID8gKGlzQXJyYXkodmFsdWUpID8gdmFsdWUgOiBbXSlcbiAgICAgICAgICAgICAgICA6IChpc1BsYWluT2JqZWN0KHZhbHVlKSA/IHZhbHVlIDoge30pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gYWRkIGBzb3VyY2VgIGFuZCBhc3NvY2lhdGVkIGB2YWx1ZWAgdG8gdGhlIHN0YWNrIG9mIHRyYXZlcnNlZCBvYmplY3RzXG4gICAgICAgICAgICBzdGFja0EucHVzaChzb3VyY2UpO1xuICAgICAgICAgICAgc3RhY2tCLnB1c2godmFsdWUpO1xuXG4gICAgICAgICAgICAvLyByZWN1cnNpdmVseSBtZXJnZSBvYmplY3RzIGFuZCBhcnJheXMgKHN1c2NlcHRpYmxlIHRvIGNhbGwgc3RhY2sgbGltaXRzKVxuICAgICAgICAgICAgaWYgKCFpc1NoYWxsb3cpIHtcbiAgICAgICAgICAgICAgYmFzZU1lcmdlKHZhbHVlLCBzb3VyY2UsIGNhbGxiYWNrLCBzdGFja0EsIHN0YWNrQik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgIGlmIChjYWxsYmFjaykge1xuICAgICAgICAgICAgcmVzdWx0ID0gY2FsbGJhY2sodmFsdWUsIHNvdXJjZSk7XG4gICAgICAgICAgICBpZiAodHlwZW9mIHJlc3VsdCA9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICByZXN1bHQgPSBzb3VyY2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmICh0eXBlb2YgcmVzdWx0ICE9ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICB2YWx1ZSA9IHJlc3VsdDtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgb2JqZWN0W2tleV0gPSB2YWx1ZTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoZSBiYXNlIGltcGxlbWVudGF0aW9uIG9mIGBfLnJhbmRvbWAgd2l0aG91dCBhcmd1bWVudCBqdWdnbGluZyBvciBzdXBwb3J0XG4gICAgICogZm9yIHJldHVybmluZyBmbG9hdGluZy1wb2ludCBudW1iZXJzLlxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gbWluIFRoZSBtaW5pbXVtIHBvc3NpYmxlIHZhbHVlLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBtYXggVGhlIG1heGltdW0gcG9zc2libGUgdmFsdWUuXG4gICAgICogQHJldHVybnMge251bWJlcn0gUmV0dXJucyBhIHJhbmRvbSBudW1iZXIuXG4gICAgICovXG4gICAgZnVuY3Rpb24gYmFzZVJhbmRvbShtaW4sIG1heCkge1xuICAgICAgcmV0dXJuIG1pbiArIGZsb29yKG5hdGl2ZVJhbmRvbSgpICogKG1heCAtIG1pbiArIDEpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGUgYmFzZSBpbXBsZW1lbnRhdGlvbiBvZiBgXy51bmlxYCB3aXRob3V0IHN1cHBvcnQgZm9yIGNhbGxiYWNrIHNob3J0aGFuZHNcbiAgICAgKiBvciBgdGhpc0FyZ2AgYmluZGluZy5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtBcnJheX0gYXJyYXkgVGhlIGFycmF5IHRvIHByb2Nlc3MuXG4gICAgICogQHBhcmFtIHtib29sZWFufSBbaXNTb3J0ZWQ9ZmFsc2VdIEEgZmxhZyB0byBpbmRpY2F0ZSB0aGF0IGBhcnJheWAgaXMgc29ydGVkLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IFtjYWxsYmFja10gVGhlIGZ1bmN0aW9uIGNhbGxlZCBwZXIgaXRlcmF0aW9uLlxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyBhIGR1cGxpY2F0ZS12YWx1ZS1mcmVlIGFycmF5LlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGJhc2VVbmlxKGFycmF5LCBpc1NvcnRlZCwgY2FsbGJhY2spIHtcbiAgICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICAgIGluZGV4T2YgPSBnZXRJbmRleE9mKCksXG4gICAgICAgICAgbGVuZ3RoID0gYXJyYXkgPyBhcnJheS5sZW5ndGggOiAwLFxuICAgICAgICAgIHJlc3VsdCA9IFtdO1xuXG4gICAgICB2YXIgaXNMYXJnZSA9ICFpc1NvcnRlZCAmJiBsZW5ndGggPj0gbGFyZ2VBcnJheVNpemUgJiYgaW5kZXhPZiA9PT0gYmFzZUluZGV4T2YsXG4gICAgICAgICAgc2VlbiA9IChjYWxsYmFjayB8fCBpc0xhcmdlKSA/IGdldEFycmF5KCkgOiByZXN1bHQ7XG5cbiAgICAgIGlmIChpc0xhcmdlKSB7XG4gICAgICAgIHZhciBjYWNoZSA9IGNyZWF0ZUNhY2hlKHNlZW4pO1xuICAgICAgICBpbmRleE9mID0gY2FjaGVJbmRleE9mO1xuICAgICAgICBzZWVuID0gY2FjaGU7XG4gICAgICB9XG4gICAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgICB2YXIgdmFsdWUgPSBhcnJheVtpbmRleF0sXG4gICAgICAgICAgICBjb21wdXRlZCA9IGNhbGxiYWNrID8gY2FsbGJhY2sodmFsdWUsIGluZGV4LCBhcnJheSkgOiB2YWx1ZTtcblxuICAgICAgICBpZiAoaXNTb3J0ZWRcbiAgICAgICAgICAgICAgPyAhaW5kZXggfHwgc2VlbltzZWVuLmxlbmd0aCAtIDFdICE9PSBjb21wdXRlZFxuICAgICAgICAgICAgICA6IGluZGV4T2Yoc2VlbiwgY29tcHV0ZWQpIDwgMFxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgaWYgKGNhbGxiYWNrIHx8IGlzTGFyZ2UpIHtcbiAgICAgICAgICAgIHNlZW4ucHVzaChjb21wdXRlZCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJlc3VsdC5wdXNoKHZhbHVlKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKGlzTGFyZ2UpIHtcbiAgICAgICAgcmVsZWFzZUFycmF5KHNlZW4uYXJyYXkpO1xuICAgICAgICByZWxlYXNlT2JqZWN0KHNlZW4pO1xuICAgICAgfSBlbHNlIGlmIChjYWxsYmFjaykge1xuICAgICAgICByZWxlYXNlQXJyYXkoc2Vlbik7XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSBmdW5jdGlvbiB0aGF0IGFnZ3JlZ2F0ZXMgYSBjb2xsZWN0aW9uLCBjcmVhdGluZyBhbiBvYmplY3QgY29tcG9zZWRcbiAgICAgKiBvZiBrZXlzIGdlbmVyYXRlZCBmcm9tIHRoZSByZXN1bHRzIG9mIHJ1bm5pbmcgZWFjaCBlbGVtZW50IG9mIHRoZSBjb2xsZWN0aW9uXG4gICAgICogdGhyb3VnaCBhIGNhbGxiYWNrLiBUaGUgZ2l2ZW4gYHNldHRlcmAgZnVuY3Rpb24gc2V0cyB0aGUga2V5cyBhbmQgdmFsdWVzXG4gICAgICogb2YgdGhlIGNvbXBvc2VkIG9iamVjdC5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gc2V0dGVyIFRoZSBzZXR0ZXIgZnVuY3Rpb24uXG4gICAgICogQHJldHVybnMge0Z1bmN0aW9ufSBSZXR1cm5zIHRoZSBuZXcgYWdncmVnYXRvciBmdW5jdGlvbi5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBjcmVhdGVBZ2dyZWdhdG9yKHNldHRlcikge1xuICAgICAgcmV0dXJuIGZ1bmN0aW9uKGNvbGxlY3Rpb24sIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICAgIHZhciByZXN1bHQgPSB7fTtcbiAgICAgICAgY2FsbGJhY2sgPSBsb2Rhc2guY3JlYXRlQ2FsbGJhY2soY2FsbGJhY2ssIHRoaXNBcmcsIDMpO1xuXG4gICAgICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICAgICAgbGVuZ3RoID0gY29sbGVjdGlvbiA/IGNvbGxlY3Rpb24ubGVuZ3RoIDogMDtcblxuICAgICAgICBpZiAodHlwZW9mIGxlbmd0aCA9PSAnbnVtYmVyJykge1xuICAgICAgICAgIHdoaWxlICgrK2luZGV4IDwgbGVuZ3RoKSB7XG4gICAgICAgICAgICB2YXIgdmFsdWUgPSBjb2xsZWN0aW9uW2luZGV4XTtcbiAgICAgICAgICAgIHNldHRlcihyZXN1bHQsIHZhbHVlLCBjYWxsYmFjayh2YWx1ZSwgaW5kZXgsIGNvbGxlY3Rpb24pLCBjb2xsZWN0aW9uKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZm9yT3duKGNvbGxlY3Rpb24sIGZ1bmN0aW9uKHZhbHVlLCBrZXksIGNvbGxlY3Rpb24pIHtcbiAgICAgICAgICAgIHNldHRlcihyZXN1bHQsIHZhbHVlLCBjYWxsYmFjayh2YWx1ZSwga2V5LCBjb2xsZWN0aW9uKSwgY29sbGVjdGlvbik7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIGZ1bmN0aW9uIHRoYXQsIHdoZW4gY2FsbGVkLCBlaXRoZXIgY3VycmllcyBvciBpbnZva2VzIGBmdW5jYFxuICAgICAqIHdpdGggYW4gb3B0aW9uYWwgYHRoaXNgIGJpbmRpbmcgYW5kIHBhcnRpYWxseSBhcHBsaWVkIGFyZ3VtZW50cy5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbnxzdHJpbmd9IGZ1bmMgVGhlIGZ1bmN0aW9uIG9yIG1ldGhvZCBuYW1lIHRvIHJlZmVyZW5jZS5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gYml0bWFzayBUaGUgYml0bWFzayBvZiBtZXRob2QgZmxhZ3MgdG8gY29tcG9zZS5cbiAgICAgKiAgVGhlIGJpdG1hc2sgbWF5IGJlIGNvbXBvc2VkIG9mIHRoZSBmb2xsb3dpbmcgZmxhZ3M6XG4gICAgICogIDEgLSBgXy5iaW5kYFxuICAgICAqICAyIC0gYF8uYmluZEtleWBcbiAgICAgKiAgNCAtIGBfLmN1cnJ5YFxuICAgICAqICA4IC0gYF8uY3VycnlgIChib3VuZClcbiAgICAgKiAgMTYgLSBgXy5wYXJ0aWFsYFxuICAgICAqICAzMiAtIGBfLnBhcnRpYWxSaWdodGBcbiAgICAgKiBAcGFyYW0ge0FycmF5fSBbcGFydGlhbEFyZ3NdIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB0byBwcmVwZW5kIHRvIHRob3NlXG4gICAgICogIHByb3ZpZGVkIHRvIHRoZSBuZXcgZnVuY3Rpb24uXG4gICAgICogQHBhcmFtIHtBcnJheX0gW3BhcnRpYWxSaWdodEFyZ3NdIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB0byBhcHBlbmQgdG8gdGhvc2VcbiAgICAgKiAgcHJvdmlkZWQgdG8gdGhlIG5ldyBmdW5jdGlvbi5cbiAgICAgKiBAcGFyYW0geyp9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGZ1bmNgLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbYXJpdHldIFRoZSBhcml0eSBvZiBgZnVuY2AuXG4gICAgICogQHJldHVybnMge0Z1bmN0aW9ufSBSZXR1cm5zIHRoZSBuZXcgZnVuY3Rpb24uXG4gICAgICovXG4gICAgZnVuY3Rpb24gY3JlYXRlV3JhcHBlcihmdW5jLCBiaXRtYXNrLCBwYXJ0aWFsQXJncywgcGFydGlhbFJpZ2h0QXJncywgdGhpc0FyZywgYXJpdHkpIHtcbiAgICAgIHZhciBpc0JpbmQgPSBiaXRtYXNrICYgMSxcbiAgICAgICAgICBpc0JpbmRLZXkgPSBiaXRtYXNrICYgMixcbiAgICAgICAgICBpc0N1cnJ5ID0gYml0bWFzayAmIDQsXG4gICAgICAgICAgaXNDdXJyeUJvdW5kID0gYml0bWFzayAmIDgsXG4gICAgICAgICAgaXNQYXJ0aWFsID0gYml0bWFzayAmIDE2LFxuICAgICAgICAgIGlzUGFydGlhbFJpZ2h0ID0gYml0bWFzayAmIDMyO1xuXG4gICAgICBpZiAoIWlzQmluZEtleSAmJiAhaXNGdW5jdGlvbihmdW5jKSkge1xuICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yO1xuICAgICAgfVxuICAgICAgaWYgKGlzUGFydGlhbCAmJiAhcGFydGlhbEFyZ3MubGVuZ3RoKSB7XG4gICAgICAgIGJpdG1hc2sgJj0gfjE2O1xuICAgICAgICBpc1BhcnRpYWwgPSBwYXJ0aWFsQXJncyA9IGZhbHNlO1xuICAgICAgfVxuICAgICAgaWYgKGlzUGFydGlhbFJpZ2h0ICYmICFwYXJ0aWFsUmlnaHRBcmdzLmxlbmd0aCkge1xuICAgICAgICBiaXRtYXNrICY9IH4zMjtcbiAgICAgICAgaXNQYXJ0aWFsUmlnaHQgPSBwYXJ0aWFsUmlnaHRBcmdzID0gZmFsc2U7XG4gICAgICB9XG4gICAgICB2YXIgYmluZERhdGEgPSBmdW5jICYmIGZ1bmMuX19iaW5kRGF0YV9fO1xuICAgICAgaWYgKGJpbmREYXRhICYmIGJpbmREYXRhICE9PSB0cnVlKSB7XG4gICAgICAgIC8vIGNsb25lIGBiaW5kRGF0YWBcbiAgICAgICAgYmluZERhdGEgPSBzbGljZShiaW5kRGF0YSk7XG4gICAgICAgIGlmIChiaW5kRGF0YVsyXSkge1xuICAgICAgICAgIGJpbmREYXRhWzJdID0gc2xpY2UoYmluZERhdGFbMl0pO1xuICAgICAgICB9XG4gICAgICAgIGlmIChiaW5kRGF0YVszXSkge1xuICAgICAgICAgIGJpbmREYXRhWzNdID0gc2xpY2UoYmluZERhdGFbM10pO1xuICAgICAgICB9XG4gICAgICAgIC8vIHNldCBgdGhpc0JpbmRpbmdgIGlzIG5vdCBwcmV2aW91c2x5IGJvdW5kXG4gICAgICAgIGlmIChpc0JpbmQgJiYgIShiaW5kRGF0YVsxXSAmIDEpKSB7XG4gICAgICAgICAgYmluZERhdGFbNF0gPSB0aGlzQXJnO1xuICAgICAgICB9XG4gICAgICAgIC8vIHNldCBpZiBwcmV2aW91c2x5IGJvdW5kIGJ1dCBub3QgY3VycmVudGx5IChzdWJzZXF1ZW50IGN1cnJpZWQgZnVuY3Rpb25zKVxuICAgICAgICBpZiAoIWlzQmluZCAmJiBiaW5kRGF0YVsxXSAmIDEpIHtcbiAgICAgICAgICBiaXRtYXNrIHw9IDg7XG4gICAgICAgIH1cbiAgICAgICAgLy8gc2V0IGN1cnJpZWQgYXJpdHkgaWYgbm90IHlldCBzZXRcbiAgICAgICAgaWYgKGlzQ3VycnkgJiYgIShiaW5kRGF0YVsxXSAmIDQpKSB7XG4gICAgICAgICAgYmluZERhdGFbNV0gPSBhcml0eTtcbiAgICAgICAgfVxuICAgICAgICAvLyBhcHBlbmQgcGFydGlhbCBsZWZ0IGFyZ3VtZW50c1xuICAgICAgICBpZiAoaXNQYXJ0aWFsKSB7XG4gICAgICAgICAgcHVzaC5hcHBseShiaW5kRGF0YVsyXSB8fCAoYmluZERhdGFbMl0gPSBbXSksIHBhcnRpYWxBcmdzKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBhcHBlbmQgcGFydGlhbCByaWdodCBhcmd1bWVudHNcbiAgICAgICAgaWYgKGlzUGFydGlhbFJpZ2h0KSB7XG4gICAgICAgICAgdW5zaGlmdC5hcHBseShiaW5kRGF0YVszXSB8fCAoYmluZERhdGFbM10gPSBbXSksIHBhcnRpYWxSaWdodEFyZ3MpO1xuICAgICAgICB9XG4gICAgICAgIC8vIG1lcmdlIGZsYWdzXG4gICAgICAgIGJpbmREYXRhWzFdIHw9IGJpdG1hc2s7XG4gICAgICAgIHJldHVybiBjcmVhdGVXcmFwcGVyLmFwcGx5KG51bGwsIGJpbmREYXRhKTtcbiAgICAgIH1cbiAgICAgIC8vIGZhc3QgcGF0aCBmb3IgYF8uYmluZGBcbiAgICAgIHZhciBjcmVhdGVyID0gKGJpdG1hc2sgPT0gMSB8fCBiaXRtYXNrID09PSAxNykgPyBiYXNlQmluZCA6IGJhc2VDcmVhdGVXcmFwcGVyO1xuICAgICAgcmV0dXJuIGNyZWF0ZXIoW2Z1bmMsIGJpdG1hc2ssIHBhcnRpYWxBcmdzLCBwYXJ0aWFsUmlnaHRBcmdzLCB0aGlzQXJnLCBhcml0eV0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFVzZWQgYnkgYGVzY2FwZWAgdG8gY29udmVydCBjaGFyYWN0ZXJzIHRvIEhUTUwgZW50aXRpZXMuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBtYXRjaCBUaGUgbWF0Y2hlZCBjaGFyYWN0ZXIgdG8gZXNjYXBlLlxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IFJldHVybnMgdGhlIGVzY2FwZWQgY2hhcmFjdGVyLlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGVzY2FwZUh0bWxDaGFyKG1hdGNoKSB7XG4gICAgICByZXR1cm4gaHRtbEVzY2FwZXNbbWF0Y2hdO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldHMgdGhlIGFwcHJvcHJpYXRlIFwiaW5kZXhPZlwiIGZ1bmN0aW9uLiBJZiB0aGUgYF8uaW5kZXhPZmAgbWV0aG9kIGlzXG4gICAgICogY3VzdG9taXplZCwgdGhpcyBtZXRob2QgcmV0dXJucyB0aGUgY3VzdG9tIG1ldGhvZCwgb3RoZXJ3aXNlIGl0IHJldHVybnNcbiAgICAgKiB0aGUgYGJhc2VJbmRleE9mYCBmdW5jdGlvbi5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHJldHVybnMge0Z1bmN0aW9ufSBSZXR1cm5zIHRoZSBcImluZGV4T2ZcIiBmdW5jdGlvbi5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBnZXRJbmRleE9mKCkge1xuICAgICAgdmFyIHJlc3VsdCA9IChyZXN1bHQgPSBsb2Rhc2guaW5kZXhPZikgPT09IGluZGV4T2YgPyBiYXNlSW5kZXhPZiA6IHJlc3VsdDtcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIGlmIGB2YWx1ZWAgaXMgYSBuYXRpdmUgZnVuY3Rpb24uXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgYHZhbHVlYCBpcyBhIG5hdGl2ZSBmdW5jdGlvbiwgZWxzZSBgZmFsc2VgLlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGlzTmF0aXZlKHZhbHVlKSB7XG4gICAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09ICdmdW5jdGlvbicgJiYgcmVOYXRpdmUudGVzdCh2YWx1ZSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0cyBgdGhpc2AgYmluZGluZyBkYXRhIG9uIGEgZ2l2ZW4gZnVuY3Rpb24uXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIHNldCBkYXRhIG9uLlxuICAgICAqIEBwYXJhbSB7QXJyYXl9IHZhbHVlIFRoZSBkYXRhIGFycmF5IHRvIHNldC5cbiAgICAgKi9cbiAgICB2YXIgc2V0QmluZERhdGEgPSAhZGVmaW5lUHJvcGVydHkgPyBub29wIDogZnVuY3Rpb24oZnVuYywgdmFsdWUpIHtcbiAgICAgIGRlc2NyaXB0b3IudmFsdWUgPSB2YWx1ZTtcbiAgICAgIGRlZmluZVByb3BlcnR5KGZ1bmMsICdfX2JpbmREYXRhX18nLCBkZXNjcmlwdG9yKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQSBmYWxsYmFjayBpbXBsZW1lbnRhdGlvbiBvZiBgaXNQbGFpbk9iamVjdGAgd2hpY2ggY2hlY2tzIGlmIGEgZ2l2ZW4gdmFsdWVcbiAgICAgKiBpcyBhbiBvYmplY3QgY3JlYXRlZCBieSB0aGUgYE9iamVjdGAgY29uc3RydWN0b3IsIGFzc3VtaW5nIG9iamVjdHMgY3JlYXRlZFxuICAgICAqIGJ5IHRoZSBgT2JqZWN0YCBjb25zdHJ1Y3RvciBoYXZlIG5vIGluaGVyaXRlZCBlbnVtZXJhYmxlIHByb3BlcnRpZXMgYW5kIHRoYXRcbiAgICAgKiB0aGVyZSBhcmUgbm8gYE9iamVjdC5wcm90b3R5cGVgIGV4dGVuc2lvbnMuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiBgdmFsdWVgIGlzIGEgcGxhaW4gb2JqZWN0LCBlbHNlIGBmYWxzZWAuXG4gICAgICovXG4gICAgZnVuY3Rpb24gc2hpbUlzUGxhaW5PYmplY3QodmFsdWUpIHtcbiAgICAgIHZhciBjdG9yLFxuICAgICAgICAgIHJlc3VsdDtcblxuICAgICAgLy8gYXZvaWQgbm9uIE9iamVjdCBvYmplY3RzLCBgYXJndW1lbnRzYCBvYmplY3RzLCBhbmQgRE9NIGVsZW1lbnRzXG4gICAgICBpZiAoISh2YWx1ZSAmJiB0b1N0cmluZy5jYWxsKHZhbHVlKSA9PSBvYmplY3RDbGFzcykgfHxcbiAgICAgICAgICAoY3RvciA9IHZhbHVlLmNvbnN0cnVjdG9yLCBpc0Z1bmN0aW9uKGN0b3IpICYmICEoY3RvciBpbnN0YW5jZW9mIGN0b3IpKSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgICAvLyBJbiBtb3N0IGVudmlyb25tZW50cyBhbiBvYmplY3QncyBvd24gcHJvcGVydGllcyBhcmUgaXRlcmF0ZWQgYmVmb3JlXG4gICAgICAvLyBpdHMgaW5oZXJpdGVkIHByb3BlcnRpZXMuIElmIHRoZSBsYXN0IGl0ZXJhdGVkIHByb3BlcnR5IGlzIGFuIG9iamVjdCdzXG4gICAgICAvLyBvd24gcHJvcGVydHkgdGhlbiB0aGVyZSBhcmUgbm8gaW5oZXJpdGVkIGVudW1lcmFibGUgcHJvcGVydGllcy5cbiAgICAgIGZvckluKHZhbHVlLCBmdW5jdGlvbih2YWx1ZSwga2V5KSB7XG4gICAgICAgIHJlc3VsdCA9IGtleTtcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIHR5cGVvZiByZXN1bHQgPT0gJ3VuZGVmaW5lZCcgfHwgaGFzT3duUHJvcGVydHkuY2FsbCh2YWx1ZSwgcmVzdWx0KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBVc2VkIGJ5IGB1bmVzY2FwZWAgdG8gY29udmVydCBIVE1MIGVudGl0aWVzIHRvIGNoYXJhY3RlcnMuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBtYXRjaCBUaGUgbWF0Y2hlZCBjaGFyYWN0ZXIgdG8gdW5lc2NhcGUuXG4gICAgICogQHJldHVybnMge3N0cmluZ30gUmV0dXJucyB0aGUgdW5lc2NhcGVkIGNoYXJhY3Rlci5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiB1bmVzY2FwZUh0bWxDaGFyKG1hdGNoKSB7XG4gICAgICByZXR1cm4gaHRtbFVuZXNjYXBlc1ttYXRjaF07XG4gICAgfVxuXG4gICAgLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5cbiAgICAvKipcbiAgICAgKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBhbiBgYXJndW1lbnRzYCBvYmplY3QuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgYHZhbHVlYCBpcyBhbiBgYXJndW1lbnRzYCBvYmplY3QsIGVsc2UgYGZhbHNlYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogKGZ1bmN0aW9uKCkgeyByZXR1cm4gXy5pc0FyZ3VtZW50cyhhcmd1bWVudHMpOyB9KSgxLCAyLCAzKTtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICpcbiAgICAgKiBfLmlzQXJndW1lbnRzKFsxLCAyLCAzXSk7XG4gICAgICogLy8gPT4gZmFsc2VcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpc0FyZ3VtZW50cyh2YWx1ZSkge1xuICAgICAgcmV0dXJuIHZhbHVlICYmIHR5cGVvZiB2YWx1ZSA9PSAnb2JqZWN0JyAmJiB0eXBlb2YgdmFsdWUubGVuZ3RoID09ICdudW1iZXInICYmXG4gICAgICAgIHRvU3RyaW5nLmNhbGwodmFsdWUpID09IGFyZ3NDbGFzcyB8fCBmYWxzZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBhbiBhcnJheS5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEB0eXBlIEZ1bmN0aW9uXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBjaGVjay5cbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIGB2YWx1ZWAgaXMgYW4gYXJyYXksIGVsc2UgYGZhbHNlYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogKGZ1bmN0aW9uKCkgeyByZXR1cm4gXy5pc0FycmF5KGFyZ3VtZW50cyk7IH0pKCk7XG4gICAgICogLy8gPT4gZmFsc2VcbiAgICAgKlxuICAgICAqIF8uaXNBcnJheShbMSwgMiwgM10pO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKi9cbiAgICB2YXIgaXNBcnJheSA9IG5hdGl2ZUlzQXJyYXkgfHwgZnVuY3Rpb24odmFsdWUpIHtcbiAgICAgIHJldHVybiB2YWx1ZSAmJiB0eXBlb2YgdmFsdWUgPT0gJ29iamVjdCcgJiYgdHlwZW9mIHZhbHVlLmxlbmd0aCA9PSAnbnVtYmVyJyAmJlxuICAgICAgICB0b1N0cmluZy5jYWxsKHZhbHVlKSA9PSBhcnJheUNsYXNzIHx8IGZhbHNlO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBBIGZhbGxiYWNrIGltcGxlbWVudGF0aW9uIG9mIGBPYmplY3Qua2V5c2Agd2hpY2ggcHJvZHVjZXMgYW4gYXJyYXkgb2YgdGhlXG4gICAgICogZ2l2ZW4gb2JqZWN0J3Mgb3duIGVudW1lcmFibGUgcHJvcGVydHkgbmFtZXMuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEB0eXBlIEZ1bmN0aW9uXG4gICAgICogQHBhcmFtIHtPYmplY3R9IG9iamVjdCBUaGUgb2JqZWN0IHRvIGluc3BlY3QuXG4gICAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIGFuIGFycmF5IG9mIHByb3BlcnR5IG5hbWVzLlxuICAgICAqL1xuICAgIHZhciBzaGltS2V5cyA9IGZ1bmN0aW9uKG9iamVjdCkge1xuICAgICAgdmFyIGluZGV4LCBpdGVyYWJsZSA9IG9iamVjdCwgcmVzdWx0ID0gW107XG4gICAgICBpZiAoIWl0ZXJhYmxlKSByZXR1cm4gcmVzdWx0O1xuICAgICAgaWYgKCEob2JqZWN0VHlwZXNbdHlwZW9mIG9iamVjdF0pKSByZXR1cm4gcmVzdWx0O1xuICAgICAgICBmb3IgKGluZGV4IGluIGl0ZXJhYmxlKSB7XG4gICAgICAgICAgaWYgKGhhc093blByb3BlcnR5LmNhbGwoaXRlcmFibGUsIGluZGV4KSkge1xuICAgICAgICAgICAgcmVzdWx0LnB1c2goaW5kZXgpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3VsdFxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIGFycmF5IGNvbXBvc2VkIG9mIHRoZSBvd24gZW51bWVyYWJsZSBwcm9wZXJ0eSBuYW1lcyBvZiBhbiBvYmplY3QuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3QgVGhlIG9iamVjdCB0byBpbnNwZWN0LlxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyBhbiBhcnJheSBvZiBwcm9wZXJ0eSBuYW1lcy5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5rZXlzKHsgJ29uZSc6IDEsICd0d28nOiAyLCAndGhyZWUnOiAzIH0pO1xuICAgICAqIC8vID0+IFsnb25lJywgJ3R3bycsICd0aHJlZSddIChwcm9wZXJ0eSBvcmRlciBpcyBub3QgZ3VhcmFudGVlZCBhY3Jvc3MgZW52aXJvbm1lbnRzKVxuICAgICAqL1xuICAgIHZhciBrZXlzID0gIW5hdGl2ZUtleXMgPyBzaGltS2V5cyA6IGZ1bmN0aW9uKG9iamVjdCkge1xuICAgICAgaWYgKCFpc09iamVjdChvYmplY3QpKSB7XG4gICAgICAgIHJldHVybiBbXTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBuYXRpdmVLZXlzKG9iamVjdCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFVzZWQgdG8gY29udmVydCBjaGFyYWN0ZXJzIHRvIEhUTUwgZW50aXRpZXM6XG4gICAgICpcbiAgICAgKiBUaG91Z2ggdGhlIGA+YCBjaGFyYWN0ZXIgaXMgZXNjYXBlZCBmb3Igc3ltbWV0cnksIGNoYXJhY3RlcnMgbGlrZSBgPmAgYW5kIGAvYFxuICAgICAqIGRvbid0IHJlcXVpcmUgZXNjYXBpbmcgaW4gSFRNTCBhbmQgaGF2ZSBubyBzcGVjaWFsIG1lYW5pbmcgdW5sZXNzIHRoZXkncmUgcGFydFxuICAgICAqIG9mIGEgdGFnIG9yIGFuIHVucXVvdGVkIGF0dHJpYnV0ZSB2YWx1ZS5cbiAgICAgKiBodHRwOi8vbWF0aGlhc2J5bmVucy5iZS9ub3Rlcy9hbWJpZ3VvdXMtYW1wZXJzYW5kcyAodW5kZXIgXCJzZW1pLXJlbGF0ZWQgZnVuIGZhY3RcIilcbiAgICAgKi9cbiAgICB2YXIgaHRtbEVzY2FwZXMgPSB7XG4gICAgICAnJic6ICcmYW1wOycsXG4gICAgICAnPCc6ICcmbHQ7JyxcbiAgICAgICc+JzogJyZndDsnLFxuICAgICAgJ1wiJzogJyZxdW90OycsXG4gICAgICBcIidcIjogJyYjMzk7J1xuICAgIH07XG5cbiAgICAvKiogVXNlZCB0byBjb252ZXJ0IEhUTUwgZW50aXRpZXMgdG8gY2hhcmFjdGVycyAqL1xuICAgIHZhciBodG1sVW5lc2NhcGVzID0gaW52ZXJ0KGh0bWxFc2NhcGVzKTtcblxuICAgIC8qKiBVc2VkIHRvIG1hdGNoIEhUTUwgZW50aXRpZXMgYW5kIEhUTUwgY2hhcmFjdGVycyAqL1xuICAgIHZhciByZUVzY2FwZWRIdG1sID0gUmVnRXhwKCcoJyArIGtleXMoaHRtbFVuZXNjYXBlcykuam9pbignfCcpICsgJyknLCAnZycpLFxuICAgICAgICByZVVuZXNjYXBlZEh0bWwgPSBSZWdFeHAoJ1snICsga2V5cyhodG1sRXNjYXBlcykuam9pbignJykgKyAnXScsICdnJyk7XG5cbiAgICAvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cblxuICAgIC8qKlxuICAgICAqIEFzc2lnbnMgb3duIGVudW1lcmFibGUgcHJvcGVydGllcyBvZiBzb3VyY2Ugb2JqZWN0KHMpIHRvIHRoZSBkZXN0aW5hdGlvblxuICAgICAqIG9iamVjdC4gU3Vic2VxdWVudCBzb3VyY2VzIHdpbGwgb3ZlcndyaXRlIHByb3BlcnR5IGFzc2lnbm1lbnRzIG9mIHByZXZpb3VzXG4gICAgICogc291cmNlcy4gSWYgYSBjYWxsYmFjayBpcyBwcm92aWRlZCBpdCB3aWxsIGJlIGV4ZWN1dGVkIHRvIHByb2R1Y2UgdGhlXG4gICAgICogYXNzaWduZWQgdmFsdWVzLiBUaGUgY2FsbGJhY2sgaXMgYm91bmQgdG8gYHRoaXNBcmdgIGFuZCBpbnZva2VkIHdpdGggdHdvXG4gICAgICogYXJndW1lbnRzOyAob2JqZWN0VmFsdWUsIHNvdXJjZVZhbHVlKS5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEB0eXBlIEZ1bmN0aW9uXG4gICAgICogQGFsaWFzIGV4dGVuZFxuICAgICAqIEBjYXRlZ29yeSBPYmplY3RzXG4gICAgICogQHBhcmFtIHtPYmplY3R9IG9iamVjdCBUaGUgZGVzdGluYXRpb24gb2JqZWN0LlxuICAgICAqIEBwYXJhbSB7Li4uT2JqZWN0fSBbc291cmNlXSBUaGUgc291cmNlIG9iamVjdHMuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gW2NhbGxiYWNrXSBUaGUgZnVuY3Rpb24gdG8gY3VzdG9taXplIGFzc2lnbmluZyB2YWx1ZXMuXG4gICAgICogQHBhcmFtIHsqfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHJldHVybnMge09iamVjdH0gUmV0dXJucyB0aGUgZGVzdGluYXRpb24gb2JqZWN0LlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLmFzc2lnbih7ICduYW1lJzogJ2ZyZWQnIH0sIHsgJ2VtcGxveWVyJzogJ3NsYXRlJyB9KTtcbiAgICAgKiAvLyA9PiB7ICduYW1lJzogJ2ZyZWQnLCAnZW1wbG95ZXInOiAnc2xhdGUnIH1cbiAgICAgKlxuICAgICAqIHZhciBkZWZhdWx0cyA9IF8ucGFydGlhbFJpZ2h0KF8uYXNzaWduLCBmdW5jdGlvbihhLCBiKSB7XG4gICAgICogICByZXR1cm4gdHlwZW9mIGEgPT0gJ3VuZGVmaW5lZCcgPyBiIDogYTtcbiAgICAgKiB9KTtcbiAgICAgKlxuICAgICAqIHZhciBvYmplY3QgPSB7ICduYW1lJzogJ2Jhcm5leScgfTtcbiAgICAgKiBkZWZhdWx0cyhvYmplY3QsIHsgJ25hbWUnOiAnZnJlZCcsICdlbXBsb3llcic6ICdzbGF0ZScgfSk7XG4gICAgICogLy8gPT4geyAnbmFtZSc6ICdiYXJuZXknLCAnZW1wbG95ZXInOiAnc2xhdGUnIH1cbiAgICAgKi9cbiAgICB2YXIgYXNzaWduID0gZnVuY3Rpb24ob2JqZWN0LCBzb3VyY2UsIGd1YXJkKSB7XG4gICAgICB2YXIgaW5kZXgsIGl0ZXJhYmxlID0gb2JqZWN0LCByZXN1bHQgPSBpdGVyYWJsZTtcbiAgICAgIGlmICghaXRlcmFibGUpIHJldHVybiByZXN1bHQ7XG4gICAgICB2YXIgYXJncyA9IGFyZ3VtZW50cyxcbiAgICAgICAgICBhcmdzSW5kZXggPSAwLFxuICAgICAgICAgIGFyZ3NMZW5ndGggPSB0eXBlb2YgZ3VhcmQgPT0gJ251bWJlcicgPyAyIDogYXJncy5sZW5ndGg7XG4gICAgICBpZiAoYXJnc0xlbmd0aCA+IDMgJiYgdHlwZW9mIGFyZ3NbYXJnc0xlbmd0aCAtIDJdID09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgdmFyIGNhbGxiYWNrID0gYmFzZUNyZWF0ZUNhbGxiYWNrKGFyZ3NbLS1hcmdzTGVuZ3RoIC0gMV0sIGFyZ3NbYXJnc0xlbmd0aC0tXSwgMik7XG4gICAgICB9IGVsc2UgaWYgKGFyZ3NMZW5ndGggPiAyICYmIHR5cGVvZiBhcmdzW2FyZ3NMZW5ndGggLSAxXSA9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIGNhbGxiYWNrID0gYXJnc1stLWFyZ3NMZW5ndGhdO1xuICAgICAgfVxuICAgICAgd2hpbGUgKCsrYXJnc0luZGV4IDwgYXJnc0xlbmd0aCkge1xuICAgICAgICBpdGVyYWJsZSA9IGFyZ3NbYXJnc0luZGV4XTtcbiAgICAgICAgaWYgKGl0ZXJhYmxlICYmIG9iamVjdFR5cGVzW3R5cGVvZiBpdGVyYWJsZV0pIHtcbiAgICAgICAgdmFyIG93bkluZGV4ID0gLTEsXG4gICAgICAgICAgICBvd25Qcm9wcyA9IG9iamVjdFR5cGVzW3R5cGVvZiBpdGVyYWJsZV0gJiYga2V5cyhpdGVyYWJsZSksXG4gICAgICAgICAgICBsZW5ndGggPSBvd25Qcm9wcyA/IG93blByb3BzLmxlbmd0aCA6IDA7XG5cbiAgICAgICAgd2hpbGUgKCsrb3duSW5kZXggPCBsZW5ndGgpIHtcbiAgICAgICAgICBpbmRleCA9IG93blByb3BzW293bkluZGV4XTtcbiAgICAgICAgICByZXN1bHRbaW5kZXhdID0gY2FsbGJhY2sgPyBjYWxsYmFjayhyZXN1bHRbaW5kZXhdLCBpdGVyYWJsZVtpbmRleF0pIDogaXRlcmFibGVbaW5kZXhdO1xuICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHRcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIGNsb25lIG9mIGB2YWx1ZWAuIElmIGBpc0RlZXBgIGlzIGB0cnVlYCBuZXN0ZWQgb2JqZWN0cyB3aWxsIGFsc29cbiAgICAgKiBiZSBjbG9uZWQsIG90aGVyd2lzZSB0aGV5IHdpbGwgYmUgYXNzaWduZWQgYnkgcmVmZXJlbmNlLiBJZiBhIGNhbGxiYWNrXG4gICAgICogaXMgcHJvdmlkZWQgaXQgd2lsbCBiZSBleGVjdXRlZCB0byBwcm9kdWNlIHRoZSBjbG9uZWQgdmFsdWVzLiBJZiB0aGVcbiAgICAgKiBjYWxsYmFjayByZXR1cm5zIGB1bmRlZmluZWRgIGNsb25pbmcgd2lsbCBiZSBoYW5kbGVkIGJ5IHRoZSBtZXRob2QgaW5zdGVhZC5cbiAgICAgKiBUaGUgY2FsbGJhY2sgaXMgYm91bmQgdG8gYHRoaXNBcmdgIGFuZCBpbnZva2VkIHdpdGggb25lIGFyZ3VtZW50OyAodmFsdWUpLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBjbG9uZS5cbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtpc0RlZXA9ZmFsc2VdIFNwZWNpZnkgYSBkZWVwIGNsb25lLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IFtjYWxsYmFja10gVGhlIGZ1bmN0aW9uIHRvIGN1c3RvbWl6ZSBjbG9uaW5nIHZhbHVlcy5cbiAgICAgKiBAcGFyYW0geyp9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7Kn0gUmV0dXJucyB0aGUgY2xvbmVkIHZhbHVlLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgY2hhcmFjdGVycyA9IFtcbiAgICAgKiAgIHsgJ25hbWUnOiAnYmFybmV5JywgJ2FnZSc6IDM2IH0sXG4gICAgICogICB7ICduYW1lJzogJ2ZyZWQnLCAgICdhZ2UnOiA0MCB9XG4gICAgICogXTtcbiAgICAgKlxuICAgICAqIHZhciBzaGFsbG93ID0gXy5jbG9uZShjaGFyYWN0ZXJzKTtcbiAgICAgKiBzaGFsbG93WzBdID09PSBjaGFyYWN0ZXJzWzBdO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKlxuICAgICAqIHZhciBkZWVwID0gXy5jbG9uZShjaGFyYWN0ZXJzLCB0cnVlKTtcbiAgICAgKiBkZWVwWzBdID09PSBjaGFyYWN0ZXJzWzBdO1xuICAgICAqIC8vID0+IGZhbHNlXG4gICAgICpcbiAgICAgKiBfLm1peGluKHtcbiAgICAgKiAgICdjbG9uZSc6IF8ucGFydGlhbFJpZ2h0KF8uY2xvbmUsIGZ1bmN0aW9uKHZhbHVlKSB7XG4gICAgICogICAgIHJldHVybiBfLmlzRWxlbWVudCh2YWx1ZSkgPyB2YWx1ZS5jbG9uZU5vZGUoZmFsc2UpIDogdW5kZWZpbmVkO1xuICAgICAqICAgfSlcbiAgICAgKiB9KTtcbiAgICAgKlxuICAgICAqIHZhciBjbG9uZSA9IF8uY2xvbmUoZG9jdW1lbnQuYm9keSk7XG4gICAgICogY2xvbmUuY2hpbGROb2Rlcy5sZW5ndGg7XG4gICAgICogLy8gPT4gMFxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGNsb25lKHZhbHVlLCBpc0RlZXAsIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICAvLyBhbGxvd3Mgd29ya2luZyB3aXRoIFwiQ29sbGVjdGlvbnNcIiBtZXRob2RzIHdpdGhvdXQgdXNpbmcgdGhlaXIgYGluZGV4YFxuICAgICAgLy8gYW5kIGBjb2xsZWN0aW9uYCBhcmd1bWVudHMgZm9yIGBpc0RlZXBgIGFuZCBgY2FsbGJhY2tgXG4gICAgICBpZiAodHlwZW9mIGlzRGVlcCAhPSAnYm9vbGVhbicgJiYgaXNEZWVwICE9IG51bGwpIHtcbiAgICAgICAgdGhpc0FyZyA9IGNhbGxiYWNrO1xuICAgICAgICBjYWxsYmFjayA9IGlzRGVlcDtcbiAgICAgICAgaXNEZWVwID0gZmFsc2U7XG4gICAgICB9XG4gICAgICByZXR1cm4gYmFzZUNsb25lKHZhbHVlLCBpc0RlZXAsIHR5cGVvZiBjYWxsYmFjayA9PSAnZnVuY3Rpb24nICYmIGJhc2VDcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZywgMSkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSBkZWVwIGNsb25lIG9mIGB2YWx1ZWAuIElmIGEgY2FsbGJhY2sgaXMgcHJvdmlkZWQgaXQgd2lsbCBiZVxuICAgICAqIGV4ZWN1dGVkIHRvIHByb2R1Y2UgdGhlIGNsb25lZCB2YWx1ZXMuIElmIHRoZSBjYWxsYmFjayByZXR1cm5zIGB1bmRlZmluZWRgXG4gICAgICogY2xvbmluZyB3aWxsIGJlIGhhbmRsZWQgYnkgdGhlIG1ldGhvZCBpbnN0ZWFkLiBUaGUgY2FsbGJhY2sgaXMgYm91bmQgdG9cbiAgICAgKiBgdGhpc0FyZ2AgYW5kIGludm9rZWQgd2l0aCBvbmUgYXJndW1lbnQ7ICh2YWx1ZSkuXG4gICAgICpcbiAgICAgKiBOb3RlOiBUaGlzIG1ldGhvZCBpcyBsb29zZWx5IGJhc2VkIG9uIHRoZSBzdHJ1Y3R1cmVkIGNsb25lIGFsZ29yaXRobS4gRnVuY3Rpb25zXG4gICAgICogYW5kIERPTSBub2RlcyBhcmUgKipub3QqKiBjbG9uZWQuIFRoZSBlbnVtZXJhYmxlIHByb3BlcnRpZXMgb2YgYGFyZ3VtZW50c2Agb2JqZWN0cyBhbmRcbiAgICAgKiBvYmplY3RzIGNyZWF0ZWQgYnkgY29uc3RydWN0b3JzIG90aGVyIHRoYW4gYE9iamVjdGAgYXJlIGNsb25lZCB0byBwbGFpbiBgT2JqZWN0YCBvYmplY3RzLlxuICAgICAqIFNlZSBodHRwOi8vd3d3LnczLm9yZy9UUi9odG1sNS9pbmZyYXN0cnVjdHVyZS5odG1sI2ludGVybmFsLXN0cnVjdHVyZWQtY2xvbmluZy1hbGdvcml0aG0uXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGRlZXAgY2xvbmUuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gW2NhbGxiYWNrXSBUaGUgZnVuY3Rpb24gdG8gY3VzdG9taXplIGNsb25pbmcgdmFsdWVzLlxuICAgICAqIEBwYXJhbSB7Kn0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHsqfSBSZXR1cm5zIHRoZSBkZWVwIGNsb25lZCB2YWx1ZS5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIGNoYXJhY3RlcnMgPSBbXG4gICAgICogICB7ICduYW1lJzogJ2Jhcm5leScsICdhZ2UnOiAzNiB9LFxuICAgICAqICAgeyAnbmFtZSc6ICdmcmVkJywgICAnYWdlJzogNDAgfVxuICAgICAqIF07XG4gICAgICpcbiAgICAgKiB2YXIgZGVlcCA9IF8uY2xvbmVEZWVwKGNoYXJhY3RlcnMpO1xuICAgICAqIGRlZXBbMF0gPT09IGNoYXJhY3RlcnNbMF07XG4gICAgICogLy8gPT4gZmFsc2VcbiAgICAgKlxuICAgICAqIHZhciB2aWV3ID0ge1xuICAgICAqICAgJ2xhYmVsJzogJ2RvY3MnLFxuICAgICAqICAgJ25vZGUnOiBlbGVtZW50XG4gICAgICogfTtcbiAgICAgKlxuICAgICAqIHZhciBjbG9uZSA9IF8uY2xvbmVEZWVwKHZpZXcsIGZ1bmN0aW9uKHZhbHVlKSB7XG4gICAgICogICByZXR1cm4gXy5pc0VsZW1lbnQodmFsdWUpID8gdmFsdWUuY2xvbmVOb2RlKHRydWUpIDogdW5kZWZpbmVkO1xuICAgICAqIH0pO1xuICAgICAqXG4gICAgICogY2xvbmUubm9kZSA9PSB2aWV3Lm5vZGU7XG4gICAgICogLy8gPT4gZmFsc2VcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBjbG9uZURlZXAodmFsdWUsIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICByZXR1cm4gYmFzZUNsb25lKHZhbHVlLCB0cnVlLCB0eXBlb2YgY2FsbGJhY2sgPT0gJ2Z1bmN0aW9uJyAmJiBiYXNlQ3JlYXRlQ2FsbGJhY2soY2FsbGJhY2ssIHRoaXNBcmcsIDEpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIG9iamVjdCB0aGF0IGluaGVyaXRzIGZyb20gdGhlIGdpdmVuIGBwcm90b3R5cGVgIG9iamVjdC4gSWYgYVxuICAgICAqIGBwcm9wZXJ0aWVzYCBvYmplY3QgaXMgcHJvdmlkZWQgaXRzIG93biBlbnVtZXJhYmxlIHByb3BlcnRpZXMgYXJlIGFzc2lnbmVkXG4gICAgICogdG8gdGhlIGNyZWF0ZWQgb2JqZWN0LlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gcHJvdG90eXBlIFRoZSBvYmplY3QgdG8gaW5oZXJpdCBmcm9tLlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBbcHJvcGVydGllc10gVGhlIHByb3BlcnRpZXMgdG8gYXNzaWduIHRvIHRoZSBvYmplY3QuXG4gICAgICogQHJldHVybnMge09iamVjdH0gUmV0dXJucyB0aGUgbmV3IG9iamVjdC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogZnVuY3Rpb24gU2hhcGUoKSB7XG4gICAgICogICB0aGlzLnggPSAwO1xuICAgICAqICAgdGhpcy55ID0gMDtcbiAgICAgKiB9XG4gICAgICpcbiAgICAgKiBmdW5jdGlvbiBDaXJjbGUoKSB7XG4gICAgICogICBTaGFwZS5jYWxsKHRoaXMpO1xuICAgICAqIH1cbiAgICAgKlxuICAgICAqIENpcmNsZS5wcm90b3R5cGUgPSBfLmNyZWF0ZShTaGFwZS5wcm90b3R5cGUsIHsgJ2NvbnN0cnVjdG9yJzogQ2lyY2xlIH0pO1xuICAgICAqXG4gICAgICogdmFyIGNpcmNsZSA9IG5ldyBDaXJjbGU7XG4gICAgICogY2lyY2xlIGluc3RhbmNlb2YgQ2lyY2xlO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKlxuICAgICAqIGNpcmNsZSBpbnN0YW5jZW9mIFNoYXBlO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBjcmVhdGUocHJvdG90eXBlLCBwcm9wZXJ0aWVzKSB7XG4gICAgICB2YXIgcmVzdWx0ID0gYmFzZUNyZWF0ZShwcm90b3R5cGUpO1xuICAgICAgcmV0dXJuIHByb3BlcnRpZXMgPyBhc3NpZ24ocmVzdWx0LCBwcm9wZXJ0aWVzKSA6IHJlc3VsdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBc3NpZ25zIG93biBlbnVtZXJhYmxlIHByb3BlcnRpZXMgb2Ygc291cmNlIG9iamVjdChzKSB0byB0aGUgZGVzdGluYXRpb25cbiAgICAgKiBvYmplY3QgZm9yIGFsbCBkZXN0aW5hdGlvbiBwcm9wZXJ0aWVzIHRoYXQgcmVzb2x2ZSB0byBgdW5kZWZpbmVkYC4gT25jZSBhXG4gICAgICogcHJvcGVydHkgaXMgc2V0LCBhZGRpdGlvbmFsIGRlZmF1bHRzIG9mIHRoZSBzYW1lIHByb3BlcnR5IHdpbGwgYmUgaWdub3JlZC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEB0eXBlIEZ1bmN0aW9uXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0IFRoZSBkZXN0aW5hdGlvbiBvYmplY3QuXG4gICAgICogQHBhcmFtIHsuLi5PYmplY3R9IFtzb3VyY2VdIFRoZSBzb3VyY2Ugb2JqZWN0cy5cbiAgICAgKiBAcGFyYW0tIHtPYmplY3R9IFtndWFyZF0gQWxsb3dzIHdvcmtpbmcgd2l0aCBgXy5yZWR1Y2VgIHdpdGhvdXQgdXNpbmcgaXRzXG4gICAgICogIGBrZXlgIGFuZCBgb2JqZWN0YCBhcmd1bWVudHMgYXMgc291cmNlcy5cbiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSBSZXR1cm5zIHRoZSBkZXN0aW5hdGlvbiBvYmplY3QuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIHZhciBvYmplY3QgPSB7ICduYW1lJzogJ2Jhcm5leScgfTtcbiAgICAgKiBfLmRlZmF1bHRzKG9iamVjdCwgeyAnbmFtZSc6ICdmcmVkJywgJ2VtcGxveWVyJzogJ3NsYXRlJyB9KTtcbiAgICAgKiAvLyA9PiB7ICduYW1lJzogJ2Jhcm5leScsICdlbXBsb3llcic6ICdzbGF0ZScgfVxuICAgICAqL1xuICAgIHZhciBkZWZhdWx0cyA9IGZ1bmN0aW9uKG9iamVjdCwgc291cmNlLCBndWFyZCkge1xuICAgICAgdmFyIGluZGV4LCBpdGVyYWJsZSA9IG9iamVjdCwgcmVzdWx0ID0gaXRlcmFibGU7XG4gICAgICBpZiAoIWl0ZXJhYmxlKSByZXR1cm4gcmVzdWx0O1xuICAgICAgdmFyIGFyZ3MgPSBhcmd1bWVudHMsXG4gICAgICAgICAgYXJnc0luZGV4ID0gMCxcbiAgICAgICAgICBhcmdzTGVuZ3RoID0gdHlwZW9mIGd1YXJkID09ICdudW1iZXInID8gMiA6IGFyZ3MubGVuZ3RoO1xuICAgICAgd2hpbGUgKCsrYXJnc0luZGV4IDwgYXJnc0xlbmd0aCkge1xuICAgICAgICBpdGVyYWJsZSA9IGFyZ3NbYXJnc0luZGV4XTtcbiAgICAgICAgaWYgKGl0ZXJhYmxlICYmIG9iamVjdFR5cGVzW3R5cGVvZiBpdGVyYWJsZV0pIHtcbiAgICAgICAgdmFyIG93bkluZGV4ID0gLTEsXG4gICAgICAgICAgICBvd25Qcm9wcyA9IG9iamVjdFR5cGVzW3R5cGVvZiBpdGVyYWJsZV0gJiYga2V5cyhpdGVyYWJsZSksXG4gICAgICAgICAgICBsZW5ndGggPSBvd25Qcm9wcyA/IG93blByb3BzLmxlbmd0aCA6IDA7XG5cbiAgICAgICAgd2hpbGUgKCsrb3duSW5kZXggPCBsZW5ndGgpIHtcbiAgICAgICAgICBpbmRleCA9IG93blByb3BzW293bkluZGV4XTtcbiAgICAgICAgICBpZiAodHlwZW9mIHJlc3VsdFtpbmRleF0gPT0gJ3VuZGVmaW5lZCcpIHJlc3VsdFtpbmRleF0gPSBpdGVyYWJsZVtpbmRleF07XG4gICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3VsdFxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBUaGlzIG1ldGhvZCBpcyBsaWtlIGBfLmZpbmRJbmRleGAgZXhjZXB0IHRoYXQgaXQgcmV0dXJucyB0aGUga2V5IG9mIHRoZVxuICAgICAqIGZpcnN0IGVsZW1lbnQgdGhhdCBwYXNzZXMgdGhlIGNhbGxiYWNrIGNoZWNrLCBpbnN0ZWFkIG9mIHRoZSBlbGVtZW50IGl0c2VsZi5cbiAgICAgKlxuICAgICAqIElmIGEgcHJvcGVydHkgbmFtZSBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ucGx1Y2tcIiBzdHlsZVxuICAgICAqIGNhbGxiYWNrIHdpbGwgcmV0dXJuIHRoZSBwcm9wZXJ0eSB2YWx1ZSBvZiB0aGUgZ2l2ZW4gZWxlbWVudC5cbiAgICAgKlxuICAgICAqIElmIGFuIG9iamVjdCBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFja1xuICAgICAqIHdpbGwgcmV0dXJuIGB0cnVlYCBmb3IgZWxlbWVudHMgdGhhdCBoYXZlIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBnaXZlbiBvYmplY3QsXG4gICAgICogZWxzZSBgZmFsc2VgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0IFRoZSBvYmplY3QgdG8gc2VhcmNoLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb258T2JqZWN0fHN0cmluZ30gW2NhbGxiYWNrPWlkZW50aXR5XSBUaGUgZnVuY3Rpb24gY2FsbGVkIHBlclxuICAgICAqICBpdGVyYXRpb24uIElmIGEgcHJvcGVydHkgbmFtZSBvciBvYmplY3QgaXMgcHJvdmlkZWQgaXQgd2lsbCBiZSB1c2VkIHRvXG4gICAgICogIGNyZWF0ZSBhIFwiXy5wbHVja1wiIG9yIFwiXy53aGVyZVwiIHN0eWxlIGNhbGxiYWNrLCByZXNwZWN0aXZlbHkuXG4gICAgICogQHBhcmFtIHsqfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHJldHVybnMge3N0cmluZ3x1bmRlZmluZWR9IFJldHVybnMgdGhlIGtleSBvZiB0aGUgZm91bmQgZWxlbWVudCwgZWxzZSBgdW5kZWZpbmVkYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIGNoYXJhY3RlcnMgPSB7XG4gICAgICogICAnYmFybmV5JzogeyAgJ2FnZSc6IDM2LCAnYmxvY2tlZCc6IGZhbHNlIH0sXG4gICAgICogICAnZnJlZCc6IHsgICAgJ2FnZSc6IDQwLCAnYmxvY2tlZCc6IHRydWUgfSxcbiAgICAgKiAgICdwZWJibGVzJzogeyAnYWdlJzogMSwgICdibG9ja2VkJzogZmFsc2UgfVxuICAgICAqIH07XG4gICAgICpcbiAgICAgKiBfLmZpbmRLZXkoY2hhcmFjdGVycywgZnVuY3Rpb24oY2hyKSB7XG4gICAgICogICByZXR1cm4gY2hyLmFnZSA8IDQwO1xuICAgICAqIH0pO1xuICAgICAqIC8vID0+ICdiYXJuZXknIChwcm9wZXJ0eSBvcmRlciBpcyBub3QgZ3VhcmFudGVlZCBhY3Jvc3MgZW52aXJvbm1lbnRzKVxuICAgICAqXG4gICAgICogLy8gdXNpbmcgXCJfLndoZXJlXCIgY2FsbGJhY2sgc2hvcnRoYW5kXG4gICAgICogXy5maW5kS2V5KGNoYXJhY3RlcnMsIHsgJ2FnZSc6IDEgfSk7XG4gICAgICogLy8gPT4gJ3BlYmJsZXMnXG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBcIl8ucGx1Y2tcIiBjYWxsYmFjayBzaG9ydGhhbmRcbiAgICAgKiBfLmZpbmRLZXkoY2hhcmFjdGVycywgJ2Jsb2NrZWQnKTtcbiAgICAgKiAvLyA9PiAnZnJlZCdcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBmaW5kS2V5KG9iamVjdCwgY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICAgIHZhciByZXN1bHQ7XG4gICAgICBjYWxsYmFjayA9IGxvZGFzaC5jcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZywgMyk7XG4gICAgICBmb3JPd24ob2JqZWN0LCBmdW5jdGlvbih2YWx1ZSwga2V5LCBvYmplY3QpIHtcbiAgICAgICAgaWYgKGNhbGxiYWNrKHZhbHVlLCBrZXksIG9iamVjdCkpIHtcbiAgICAgICAgICByZXN1bHQgPSBrZXk7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhpcyBtZXRob2QgaXMgbGlrZSBgXy5maW5kS2V5YCBleGNlcHQgdGhhdCBpdCBpdGVyYXRlcyBvdmVyIGVsZW1lbnRzXG4gICAgICogb2YgYSBgY29sbGVjdGlvbmAgaW4gdGhlIG9wcG9zaXRlIG9yZGVyLlxuICAgICAqXG4gICAgICogSWYgYSBwcm9wZXJ0eSBuYW1lIGlzIHByb3ZpZGVkIGZvciBgY2FsbGJhY2tgIHRoZSBjcmVhdGVkIFwiXy5wbHVja1wiIHN0eWxlXG4gICAgICogY2FsbGJhY2sgd2lsbCByZXR1cm4gdGhlIHByb3BlcnR5IHZhbHVlIG9mIHRoZSBnaXZlbiBlbGVtZW50LlxuICAgICAqXG4gICAgICogSWYgYW4gb2JqZWN0IGlzIHByb3ZpZGVkIGZvciBgY2FsbGJhY2tgIHRoZSBjcmVhdGVkIFwiXy53aGVyZVwiIHN0eWxlIGNhbGxiYWNrXG4gICAgICogd2lsbCByZXR1cm4gYHRydWVgIGZvciBlbGVtZW50cyB0aGF0IGhhdmUgdGhlIHByb3BlcnRpZXMgb2YgdGhlIGdpdmVuIG9iamVjdCxcbiAgICAgKiBlbHNlIGBmYWxzZWAuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3QgVGhlIG9iamVjdCB0byBzZWFyY2guXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbnxPYmplY3R8c3RyaW5nfSBbY2FsbGJhY2s9aWRlbnRpdHldIFRoZSBmdW5jdGlvbiBjYWxsZWQgcGVyXG4gICAgICogIGl0ZXJhdGlvbi4gSWYgYSBwcm9wZXJ0eSBuYW1lIG9yIG9iamVjdCBpcyBwcm92aWRlZCBpdCB3aWxsIGJlIHVzZWQgdG9cbiAgICAgKiAgY3JlYXRlIGEgXCJfLnBsdWNrXCIgb3IgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2ssIHJlc3BlY3RpdmVseS5cbiAgICAgKiBAcGFyYW0geyp9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nfHVuZGVmaW5lZH0gUmV0dXJucyB0aGUga2V5IG9mIHRoZSBmb3VuZCBlbGVtZW50LCBlbHNlIGB1bmRlZmluZWRgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgY2hhcmFjdGVycyA9IHtcbiAgICAgKiAgICdiYXJuZXknOiB7ICAnYWdlJzogMzYsICdibG9ja2VkJzogdHJ1ZSB9LFxuICAgICAqICAgJ2ZyZWQnOiB7ICAgICdhZ2UnOiA0MCwgJ2Jsb2NrZWQnOiBmYWxzZSB9LFxuICAgICAqICAgJ3BlYmJsZXMnOiB7ICdhZ2UnOiAxLCAgJ2Jsb2NrZWQnOiB0cnVlIH1cbiAgICAgKiB9O1xuICAgICAqXG4gICAgICogXy5maW5kTGFzdEtleShjaGFyYWN0ZXJzLCBmdW5jdGlvbihjaHIpIHtcbiAgICAgKiAgIHJldHVybiBjaHIuYWdlIDwgNDA7XG4gICAgICogfSk7XG4gICAgICogLy8gPT4gcmV0dXJucyBgcGViYmxlc2AsIGFzc3VtaW5nIGBfLmZpbmRLZXlgIHJldHVybnMgYGJhcm5leWBcbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIFwiXy53aGVyZVwiIGNhbGxiYWNrIHNob3J0aGFuZFxuICAgICAqIF8uZmluZExhc3RLZXkoY2hhcmFjdGVycywgeyAnYWdlJzogNDAgfSk7XG4gICAgICogLy8gPT4gJ2ZyZWQnXG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBcIl8ucGx1Y2tcIiBjYWxsYmFjayBzaG9ydGhhbmRcbiAgICAgKiBfLmZpbmRMYXN0S2V5KGNoYXJhY3RlcnMsICdibG9ja2VkJyk7XG4gICAgICogLy8gPT4gJ3BlYmJsZXMnXG4gICAgICovXG4gICAgZnVuY3Rpb24gZmluZExhc3RLZXkob2JqZWN0LCBjYWxsYmFjaywgdGhpc0FyZykge1xuICAgICAgdmFyIHJlc3VsdDtcbiAgICAgIGNhbGxiYWNrID0gbG9kYXNoLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnLCAzKTtcbiAgICAgIGZvck93blJpZ2h0KG9iamVjdCwgZnVuY3Rpb24odmFsdWUsIGtleSwgb2JqZWN0KSB7XG4gICAgICAgIGlmIChjYWxsYmFjayh2YWx1ZSwga2V5LCBvYmplY3QpKSB7XG4gICAgICAgICAgcmVzdWx0ID0ga2V5O1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEl0ZXJhdGVzIG92ZXIgb3duIGFuZCBpbmhlcml0ZWQgZW51bWVyYWJsZSBwcm9wZXJ0aWVzIG9mIGFuIG9iamVjdCxcbiAgICAgKiBleGVjdXRpbmcgdGhlIGNhbGxiYWNrIGZvciBlYWNoIHByb3BlcnR5LiBUaGUgY2FsbGJhY2sgaXMgYm91bmQgdG8gYHRoaXNBcmdgXG4gICAgICogYW5kIGludm9rZWQgd2l0aCB0aHJlZSBhcmd1bWVudHM7ICh2YWx1ZSwga2V5LCBvYmplY3QpLiBDYWxsYmFja3MgbWF5IGV4aXRcbiAgICAgKiBpdGVyYXRpb24gZWFybHkgYnkgZXhwbGljaXRseSByZXR1cm5pbmcgYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEB0eXBlIEZ1bmN0aW9uXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0IFRoZSBvYmplY3QgdG8gaXRlcmF0ZSBvdmVyLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IFtjYWxsYmFjaz1pZGVudGl0eV0gVGhlIGZ1bmN0aW9uIGNhbGxlZCBwZXIgaXRlcmF0aW9uLlxuICAgICAqIEBwYXJhbSB7Kn0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHtPYmplY3R9IFJldHVybnMgYG9iamVjdGAuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIGZ1bmN0aW9uIFNoYXBlKCkge1xuICAgICAqICAgdGhpcy54ID0gMDtcbiAgICAgKiAgIHRoaXMueSA9IDA7XG4gICAgICogfVxuICAgICAqXG4gICAgICogU2hhcGUucHJvdG90eXBlLm1vdmUgPSBmdW5jdGlvbih4LCB5KSB7XG4gICAgICogICB0aGlzLnggKz0geDtcbiAgICAgKiAgIHRoaXMueSArPSB5O1xuICAgICAqIH07XG4gICAgICpcbiAgICAgKiBfLmZvckluKG5ldyBTaGFwZSwgZnVuY3Rpb24odmFsdWUsIGtleSkge1xuICAgICAqICAgY29uc29sZS5sb2coa2V5KTtcbiAgICAgKiB9KTtcbiAgICAgKiAvLyA9PiBsb2dzICd4JywgJ3knLCBhbmQgJ21vdmUnIChwcm9wZXJ0eSBvcmRlciBpcyBub3QgZ3VhcmFudGVlZCBhY3Jvc3MgZW52aXJvbm1lbnRzKVxuICAgICAqL1xuICAgIHZhciBmb3JJbiA9IGZ1bmN0aW9uKGNvbGxlY3Rpb24sIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICB2YXIgaW5kZXgsIGl0ZXJhYmxlID0gY29sbGVjdGlvbiwgcmVzdWx0ID0gaXRlcmFibGU7XG4gICAgICBpZiAoIWl0ZXJhYmxlKSByZXR1cm4gcmVzdWx0O1xuICAgICAgaWYgKCFvYmplY3RUeXBlc1t0eXBlb2YgaXRlcmFibGVdKSByZXR1cm4gcmVzdWx0O1xuICAgICAgY2FsbGJhY2sgPSBjYWxsYmFjayAmJiB0eXBlb2YgdGhpc0FyZyA9PSAndW5kZWZpbmVkJyA/IGNhbGxiYWNrIDogYmFzZUNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnLCAzKTtcbiAgICAgICAgZm9yIChpbmRleCBpbiBpdGVyYWJsZSkge1xuICAgICAgICAgIGlmIChjYWxsYmFjayhpdGVyYWJsZVtpbmRleF0sIGluZGV4LCBjb2xsZWN0aW9uKSA9PT0gZmFsc2UpIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHRcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogVGhpcyBtZXRob2QgaXMgbGlrZSBgXy5mb3JJbmAgZXhjZXB0IHRoYXQgaXQgaXRlcmF0ZXMgb3ZlciBlbGVtZW50c1xuICAgICAqIG9mIGEgYGNvbGxlY3Rpb25gIGluIHRoZSBvcHBvc2l0ZSBvcmRlci5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBPYmplY3RzXG4gICAgICogQHBhcmFtIHtPYmplY3R9IG9iamVjdCBUaGUgb2JqZWN0IHRvIGl0ZXJhdGUgb3Zlci5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBbY2FsbGJhY2s9aWRlbnRpdHldIFRoZSBmdW5jdGlvbiBjYWxsZWQgcGVyIGl0ZXJhdGlvbi5cbiAgICAgKiBAcGFyYW0geyp9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSBSZXR1cm5zIGBvYmplY3RgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBmdW5jdGlvbiBTaGFwZSgpIHtcbiAgICAgKiAgIHRoaXMueCA9IDA7XG4gICAgICogICB0aGlzLnkgPSAwO1xuICAgICAqIH1cbiAgICAgKlxuICAgICAqIFNoYXBlLnByb3RvdHlwZS5tb3ZlID0gZnVuY3Rpb24oeCwgeSkge1xuICAgICAqICAgdGhpcy54ICs9IHg7XG4gICAgICogICB0aGlzLnkgKz0geTtcbiAgICAgKiB9O1xuICAgICAqXG4gICAgICogXy5mb3JJblJpZ2h0KG5ldyBTaGFwZSwgZnVuY3Rpb24odmFsdWUsIGtleSkge1xuICAgICAqICAgY29uc29sZS5sb2coa2V5KTtcbiAgICAgKiB9KTtcbiAgICAgKiAvLyA9PiBsb2dzICdtb3ZlJywgJ3knLCBhbmQgJ3gnIGFzc3VtaW5nIGBfLmZvckluIGAgbG9ncyAneCcsICd5JywgYW5kICdtb3ZlJ1xuICAgICAqL1xuICAgIGZ1bmN0aW9uIGZvckluUmlnaHQob2JqZWN0LCBjYWxsYmFjaywgdGhpc0FyZykge1xuICAgICAgdmFyIHBhaXJzID0gW107XG5cbiAgICAgIGZvckluKG9iamVjdCwgZnVuY3Rpb24odmFsdWUsIGtleSkge1xuICAgICAgICBwYWlycy5wdXNoKGtleSwgdmFsdWUpO1xuICAgICAgfSk7XG5cbiAgICAgIHZhciBsZW5ndGggPSBwYWlycy5sZW5ndGg7XG4gICAgICBjYWxsYmFjayA9IGJhc2VDcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZywgMyk7XG4gICAgICB3aGlsZSAobGVuZ3RoLS0pIHtcbiAgICAgICAgaWYgKGNhbGxiYWNrKHBhaXJzW2xlbmd0aC0tXSwgcGFpcnNbbGVuZ3RoXSwgb2JqZWN0KSA9PT0gZmFsc2UpIHtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIG9iamVjdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBJdGVyYXRlcyBvdmVyIG93biBlbnVtZXJhYmxlIHByb3BlcnRpZXMgb2YgYW4gb2JqZWN0LCBleGVjdXRpbmcgdGhlIGNhbGxiYWNrXG4gICAgICogZm9yIGVhY2ggcHJvcGVydHkuIFRoZSBjYWxsYmFjayBpcyBib3VuZCB0byBgdGhpc0FyZ2AgYW5kIGludm9rZWQgd2l0aCB0aHJlZVxuICAgICAqIGFyZ3VtZW50czsgKHZhbHVlLCBrZXksIG9iamVjdCkuIENhbGxiYWNrcyBtYXkgZXhpdCBpdGVyYXRpb24gZWFybHkgYnlcbiAgICAgKiBleHBsaWNpdGx5IHJldHVybmluZyBgZmFsc2VgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQHR5cGUgRnVuY3Rpb25cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3QgVGhlIG9iamVjdCB0byBpdGVyYXRlIG92ZXIuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gW2NhbGxiYWNrPWlkZW50aXR5XSBUaGUgZnVuY3Rpb24gY2FsbGVkIHBlciBpdGVyYXRpb24uXG4gICAgICogQHBhcmFtIHsqfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHJldHVybnMge09iamVjdH0gUmV0dXJucyBgb2JqZWN0YC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5mb3JPd24oeyAnMCc6ICd6ZXJvJywgJzEnOiAnb25lJywgJ2xlbmd0aCc6IDIgfSwgZnVuY3Rpb24obnVtLCBrZXkpIHtcbiAgICAgKiAgIGNvbnNvbGUubG9nKGtleSk7XG4gICAgICogfSk7XG4gICAgICogLy8gPT4gbG9ncyAnMCcsICcxJywgYW5kICdsZW5ndGgnIChwcm9wZXJ0eSBvcmRlciBpcyBub3QgZ3VhcmFudGVlZCBhY3Jvc3MgZW52aXJvbm1lbnRzKVxuICAgICAqL1xuICAgIHZhciBmb3JPd24gPSBmdW5jdGlvbihjb2xsZWN0aW9uLCBjYWxsYmFjaywgdGhpc0FyZykge1xuICAgICAgdmFyIGluZGV4LCBpdGVyYWJsZSA9IGNvbGxlY3Rpb24sIHJlc3VsdCA9IGl0ZXJhYmxlO1xuICAgICAgaWYgKCFpdGVyYWJsZSkgcmV0dXJuIHJlc3VsdDtcbiAgICAgIGlmICghb2JqZWN0VHlwZXNbdHlwZW9mIGl0ZXJhYmxlXSkgcmV0dXJuIHJlc3VsdDtcbiAgICAgIGNhbGxiYWNrID0gY2FsbGJhY2sgJiYgdHlwZW9mIHRoaXNBcmcgPT0gJ3VuZGVmaW5lZCcgPyBjYWxsYmFjayA6IGJhc2VDcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZywgMyk7XG4gICAgICAgIHZhciBvd25JbmRleCA9IC0xLFxuICAgICAgICAgICAgb3duUHJvcHMgPSBvYmplY3RUeXBlc1t0eXBlb2YgaXRlcmFibGVdICYmIGtleXMoaXRlcmFibGUpLFxuICAgICAgICAgICAgbGVuZ3RoID0gb3duUHJvcHMgPyBvd25Qcm9wcy5sZW5ndGggOiAwO1xuXG4gICAgICAgIHdoaWxlICgrK293bkluZGV4IDwgbGVuZ3RoKSB7XG4gICAgICAgICAgaW5kZXggPSBvd25Qcm9wc1tvd25JbmRleF07XG4gICAgICAgICAgaWYgKGNhbGxiYWNrKGl0ZXJhYmxlW2luZGV4XSwgaW5kZXgsIGNvbGxlY3Rpb24pID09PSBmYWxzZSkgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3VsdFxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBUaGlzIG1ldGhvZCBpcyBsaWtlIGBfLmZvck93bmAgZXhjZXB0IHRoYXQgaXQgaXRlcmF0ZXMgb3ZlciBlbGVtZW50c1xuICAgICAqIG9mIGEgYGNvbGxlY3Rpb25gIGluIHRoZSBvcHBvc2l0ZSBvcmRlci5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBPYmplY3RzXG4gICAgICogQHBhcmFtIHtPYmplY3R9IG9iamVjdCBUaGUgb2JqZWN0IHRvIGl0ZXJhdGUgb3Zlci5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBbY2FsbGJhY2s9aWRlbnRpdHldIFRoZSBmdW5jdGlvbiBjYWxsZWQgcGVyIGl0ZXJhdGlvbi5cbiAgICAgKiBAcGFyYW0geyp9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSBSZXR1cm5zIGBvYmplY3RgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLmZvck93blJpZ2h0KHsgJzAnOiAnemVybycsICcxJzogJ29uZScsICdsZW5ndGgnOiAyIH0sIGZ1bmN0aW9uKG51bSwga2V5KSB7XG4gICAgICogICBjb25zb2xlLmxvZyhrZXkpO1xuICAgICAqIH0pO1xuICAgICAqIC8vID0+IGxvZ3MgJ2xlbmd0aCcsICcxJywgYW5kICcwJyBhc3N1bWluZyBgXy5mb3JPd25gIGxvZ3MgJzAnLCAnMScsIGFuZCAnbGVuZ3RoJ1xuICAgICAqL1xuICAgIGZ1bmN0aW9uIGZvck93blJpZ2h0KG9iamVjdCwgY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICAgIHZhciBwcm9wcyA9IGtleXMob2JqZWN0KSxcbiAgICAgICAgICBsZW5ndGggPSBwcm9wcy5sZW5ndGg7XG5cbiAgICAgIGNhbGxiYWNrID0gYmFzZUNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnLCAzKTtcbiAgICAgIHdoaWxlIChsZW5ndGgtLSkge1xuICAgICAgICB2YXIga2V5ID0gcHJvcHNbbGVuZ3RoXTtcbiAgICAgICAgaWYgKGNhbGxiYWNrKG9iamVjdFtrZXldLCBrZXksIG9iamVjdCkgPT09IGZhbHNlKSB7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBvYmplY3Q7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIHNvcnRlZCBhcnJheSBvZiBwcm9wZXJ0eSBuYW1lcyBvZiBhbGwgZW51bWVyYWJsZSBwcm9wZXJ0aWVzLFxuICAgICAqIG93biBhbmQgaW5oZXJpdGVkLCBvZiBgb2JqZWN0YCB0aGF0IGhhdmUgZnVuY3Rpb24gdmFsdWVzLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGFsaWFzIG1ldGhvZHNcbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3QgVGhlIG9iamVjdCB0byBpbnNwZWN0LlxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyBhbiBhcnJheSBvZiBwcm9wZXJ0eSBuYW1lcyB0aGF0IGhhdmUgZnVuY3Rpb24gdmFsdWVzLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLmZ1bmN0aW9ucyhfKTtcbiAgICAgKiAvLyA9PiBbJ2FsbCcsICdhbnknLCAnYmluZCcsICdiaW5kQWxsJywgJ2Nsb25lJywgJ2NvbXBhY3QnLCAnY29tcG9zZScsIC4uLl1cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBmdW5jdGlvbnMob2JqZWN0KSB7XG4gICAgICB2YXIgcmVzdWx0ID0gW107XG4gICAgICBmb3JJbihvYmplY3QsIGZ1bmN0aW9uKHZhbHVlLCBrZXkpIHtcbiAgICAgICAgaWYgKGlzRnVuY3Rpb24odmFsdWUpKSB7XG4gICAgICAgICAgcmVzdWx0LnB1c2goa2V5KTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICByZXR1cm4gcmVzdWx0LnNvcnQoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVja3MgaWYgdGhlIHNwZWNpZmllZCBwcm9wZXJ0eSBuYW1lIGV4aXN0cyBhcyBhIGRpcmVjdCBwcm9wZXJ0eSBvZiBgb2JqZWN0YCxcbiAgICAgKiBpbnN0ZWFkIG9mIGFuIGluaGVyaXRlZCBwcm9wZXJ0eS5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBPYmplY3RzXG4gICAgICogQHBhcmFtIHtPYmplY3R9IG9iamVjdCBUaGUgb2JqZWN0IHRvIGluc3BlY3QuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGtleSBUaGUgbmFtZSBvZiB0aGUgcHJvcGVydHkgdG8gY2hlY2suXG4gICAgICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIGtleSBpcyBhIGRpcmVjdCBwcm9wZXJ0eSwgZWxzZSBgZmFsc2VgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLmhhcyh7ICdhJzogMSwgJ2InOiAyLCAnYyc6IDMgfSwgJ2InKTtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICovXG4gICAgZnVuY3Rpb24gaGFzKG9iamVjdCwga2V5KSB7XG4gICAgICByZXR1cm4gb2JqZWN0ID8gaGFzT3duUHJvcGVydHkuY2FsbChvYmplY3QsIGtleSkgOiBmYWxzZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIG9iamVjdCBjb21wb3NlZCBvZiB0aGUgaW52ZXJ0ZWQga2V5cyBhbmQgdmFsdWVzIG9mIHRoZSBnaXZlbiBvYmplY3QuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3QgVGhlIG9iamVjdCB0byBpbnZlcnQuXG4gICAgICogQHJldHVybnMge09iamVjdH0gUmV0dXJucyB0aGUgY3JlYXRlZCBpbnZlcnRlZCBvYmplY3QuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uaW52ZXJ0KHsgJ2ZpcnN0JzogJ2ZyZWQnLCAnc2Vjb25kJzogJ2Jhcm5leScgfSk7XG4gICAgICogLy8gPT4geyAnZnJlZCc6ICdmaXJzdCcsICdiYXJuZXknOiAnc2Vjb25kJyB9XG4gICAgICovXG4gICAgZnVuY3Rpb24gaW52ZXJ0KG9iamVjdCkge1xuICAgICAgdmFyIGluZGV4ID0gLTEsXG4gICAgICAgICAgcHJvcHMgPSBrZXlzKG9iamVjdCksXG4gICAgICAgICAgbGVuZ3RoID0gcHJvcHMubGVuZ3RoLFxuICAgICAgICAgIHJlc3VsdCA9IHt9O1xuXG4gICAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgICB2YXIga2V5ID0gcHJvcHNbaW5kZXhdO1xuICAgICAgICByZXN1bHRbb2JqZWN0W2tleV1dID0ga2V5O1xuICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBhIGJvb2xlYW4gdmFsdWUuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgYHZhbHVlYCBpcyBhIGJvb2xlYW4gdmFsdWUsIGVsc2UgYGZhbHNlYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5pc0Jvb2xlYW4obnVsbCk7XG4gICAgICogLy8gPT4gZmFsc2VcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpc0Jvb2xlYW4odmFsdWUpIHtcbiAgICAgIHJldHVybiB2YWx1ZSA9PT0gdHJ1ZSB8fCB2YWx1ZSA9PT0gZmFsc2UgfHxcbiAgICAgICAgdmFsdWUgJiYgdHlwZW9mIHZhbHVlID09ICdvYmplY3QnICYmIHRvU3RyaW5nLmNhbGwodmFsdWUpID09IGJvb2xDbGFzcyB8fCBmYWxzZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBhIGRhdGUuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgYHZhbHVlYCBpcyBhIGRhdGUsIGVsc2UgYGZhbHNlYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5pc0RhdGUobmV3IERhdGUpO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpc0RhdGUodmFsdWUpIHtcbiAgICAgIHJldHVybiB2YWx1ZSAmJiB0eXBlb2YgdmFsdWUgPT0gJ29iamVjdCcgJiYgdG9TdHJpbmcuY2FsbCh2YWx1ZSkgPT0gZGF0ZUNsYXNzIHx8IGZhbHNlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrcyBpZiBgdmFsdWVgIGlzIGEgRE9NIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgYHZhbHVlYCBpcyBhIERPTSBlbGVtZW50LCBlbHNlIGBmYWxzZWAuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uaXNFbGVtZW50KGRvY3VtZW50LmJvZHkpO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpc0VsZW1lbnQodmFsdWUpIHtcbiAgICAgIHJldHVybiB2YWx1ZSAmJiB2YWx1ZS5ub2RlVHlwZSA9PT0gMSB8fCBmYWxzZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBlbXB0eS4gQXJyYXlzLCBzdHJpbmdzLCBvciBgYXJndW1lbnRzYCBvYmplY3RzIHdpdGggYVxuICAgICAqIGxlbmd0aCBvZiBgMGAgYW5kIG9iamVjdHMgd2l0aCBubyBvd24gZW51bWVyYWJsZSBwcm9wZXJ0aWVzIGFyZSBjb25zaWRlcmVkXG4gICAgICogXCJlbXB0eVwiLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdHxzdHJpbmd9IHZhbHVlIFRoZSB2YWx1ZSB0byBpbnNwZWN0LlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgYHZhbHVlYCBpcyBlbXB0eSwgZWxzZSBgZmFsc2VgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLmlzRW1wdHkoWzEsIDIsIDNdKTtcbiAgICAgKiAvLyA9PiBmYWxzZVxuICAgICAqXG4gICAgICogXy5pc0VtcHR5KHt9KTtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICpcbiAgICAgKiBfLmlzRW1wdHkoJycpO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpc0VtcHR5KHZhbHVlKSB7XG4gICAgICB2YXIgcmVzdWx0ID0gdHJ1ZTtcbiAgICAgIGlmICghdmFsdWUpIHtcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgIH1cbiAgICAgIHZhciBjbGFzc05hbWUgPSB0b1N0cmluZy5jYWxsKHZhbHVlKSxcbiAgICAgICAgICBsZW5ndGggPSB2YWx1ZS5sZW5ndGg7XG5cbiAgICAgIGlmICgoY2xhc3NOYW1lID09IGFycmF5Q2xhc3MgfHwgY2xhc3NOYW1lID09IHN0cmluZ0NsYXNzIHx8IGNsYXNzTmFtZSA9PSBhcmdzQ2xhc3MgKSB8fFxuICAgICAgICAgIChjbGFzc05hbWUgPT0gb2JqZWN0Q2xhc3MgJiYgdHlwZW9mIGxlbmd0aCA9PSAnbnVtYmVyJyAmJiBpc0Z1bmN0aW9uKHZhbHVlLnNwbGljZSkpKSB7XG4gICAgICAgIHJldHVybiAhbGVuZ3RoO1xuICAgICAgfVxuICAgICAgZm9yT3duKHZhbHVlLCBmdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuIChyZXN1bHQgPSBmYWxzZSk7XG4gICAgICB9KTtcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUGVyZm9ybXMgYSBkZWVwIGNvbXBhcmlzb24gYmV0d2VlbiB0d28gdmFsdWVzIHRvIGRldGVybWluZSBpZiB0aGV5IGFyZVxuICAgICAqIGVxdWl2YWxlbnQgdG8gZWFjaCBvdGhlci4gSWYgYSBjYWxsYmFjayBpcyBwcm92aWRlZCBpdCB3aWxsIGJlIGV4ZWN1dGVkXG4gICAgICogdG8gY29tcGFyZSB2YWx1ZXMuIElmIHRoZSBjYWxsYmFjayByZXR1cm5zIGB1bmRlZmluZWRgIGNvbXBhcmlzb25zIHdpbGxcbiAgICAgKiBiZSBoYW5kbGVkIGJ5IHRoZSBtZXRob2QgaW5zdGVhZC4gVGhlIGNhbGxiYWNrIGlzIGJvdW5kIHRvIGB0aGlzQXJnYCBhbmRcbiAgICAgKiBpbnZva2VkIHdpdGggdHdvIGFyZ3VtZW50czsgKGEsIGIpLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0geyp9IGEgVGhlIHZhbHVlIHRvIGNvbXBhcmUuXG4gICAgICogQHBhcmFtIHsqfSBiIFRoZSBvdGhlciB2YWx1ZSB0byBjb21wYXJlLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IFtjYWxsYmFja10gVGhlIGZ1bmN0aW9uIHRvIGN1c3RvbWl6ZSBjb21wYXJpbmcgdmFsdWVzLlxuICAgICAqIEBwYXJhbSB7Kn0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgdmFsdWVzIGFyZSBlcXVpdmFsZW50LCBlbHNlIGBmYWxzZWAuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIHZhciBvYmplY3QgPSB7ICduYW1lJzogJ2ZyZWQnIH07XG4gICAgICogdmFyIGNvcHkgPSB7ICduYW1lJzogJ2ZyZWQnIH07XG4gICAgICpcbiAgICAgKiBvYmplY3QgPT0gY29weTtcbiAgICAgKiAvLyA9PiBmYWxzZVxuICAgICAqXG4gICAgICogXy5pc0VxdWFsKG9iamVjdCwgY29weSk7XG4gICAgICogLy8gPT4gdHJ1ZVxuICAgICAqXG4gICAgICogdmFyIHdvcmRzID0gWydoZWxsbycsICdnb29kYnllJ107XG4gICAgICogdmFyIG90aGVyV29yZHMgPSBbJ2hpJywgJ2dvb2RieWUnXTtcbiAgICAgKlxuICAgICAqIF8uaXNFcXVhbCh3b3Jkcywgb3RoZXJXb3JkcywgZnVuY3Rpb24oYSwgYikge1xuICAgICAqICAgdmFyIHJlR3JlZXQgPSAvXig/OmhlbGxvfGhpKSQvaSxcbiAgICAgKiAgICAgICBhR3JlZXQgPSBfLmlzU3RyaW5nKGEpICYmIHJlR3JlZXQudGVzdChhKSxcbiAgICAgKiAgICAgICBiR3JlZXQgPSBfLmlzU3RyaW5nKGIpICYmIHJlR3JlZXQudGVzdChiKTtcbiAgICAgKlxuICAgICAqICAgcmV0dXJuIChhR3JlZXQgfHwgYkdyZWV0KSA/IChhR3JlZXQgPT0gYkdyZWV0KSA6IHVuZGVmaW5lZDtcbiAgICAgKiB9KTtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICovXG4gICAgZnVuY3Rpb24gaXNFcXVhbChhLCBiLCBjYWxsYmFjaywgdGhpc0FyZykge1xuICAgICAgcmV0dXJuIGJhc2VJc0VxdWFsKGEsIGIsIHR5cGVvZiBjYWxsYmFjayA9PSAnZnVuY3Rpb24nICYmIGJhc2VDcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZywgMikpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrcyBpZiBgdmFsdWVgIGlzLCBvciBjYW4gYmUgY29lcmNlZCB0bywgYSBmaW5pdGUgbnVtYmVyLlxuICAgICAqXG4gICAgICogTm90ZTogVGhpcyBpcyBub3QgdGhlIHNhbWUgYXMgbmF0aXZlIGBpc0Zpbml0ZWAgd2hpY2ggd2lsbCByZXR1cm4gdHJ1ZSBmb3JcbiAgICAgKiBib29sZWFucyBhbmQgZW1wdHkgc3RyaW5ncy4gU2VlIGh0dHA6Ly9lczUuZ2l0aHViLmlvLyN4MTUuMS4yLjUuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgYHZhbHVlYCBpcyBmaW5pdGUsIGVsc2UgYGZhbHNlYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5pc0Zpbml0ZSgtMTAxKTtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICpcbiAgICAgKiBfLmlzRmluaXRlKCcxMCcpO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKlxuICAgICAqIF8uaXNGaW5pdGUodHJ1ZSk7XG4gICAgICogLy8gPT4gZmFsc2VcbiAgICAgKlxuICAgICAqIF8uaXNGaW5pdGUoJycpO1xuICAgICAqIC8vID0+IGZhbHNlXG4gICAgICpcbiAgICAgKiBfLmlzRmluaXRlKEluZmluaXR5KTtcbiAgICAgKiAvLyA9PiBmYWxzZVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGlzRmluaXRlKHZhbHVlKSB7XG4gICAgICByZXR1cm4gbmF0aXZlSXNGaW5pdGUodmFsdWUpICYmICFuYXRpdmVJc05hTihwYXJzZUZsb2F0KHZhbHVlKSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIGlmIGB2YWx1ZWAgaXMgYSBmdW5jdGlvbi5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBPYmplY3RzXG4gICAgICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gY2hlY2suXG4gICAgICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIHRoZSBgdmFsdWVgIGlzIGEgZnVuY3Rpb24sIGVsc2UgYGZhbHNlYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5pc0Z1bmN0aW9uKF8pO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpc0Z1bmN0aW9uKHZhbHVlKSB7XG4gICAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09ICdmdW5jdGlvbic7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIGlmIGB2YWx1ZWAgaXMgdGhlIGxhbmd1YWdlIHR5cGUgb2YgT2JqZWN0LlxuICAgICAqIChlLmcuIGFycmF5cywgZnVuY3Rpb25zLCBvYmplY3RzLCByZWdleGVzLCBgbmV3IE51bWJlcigwKWAsIGFuZCBgbmV3IFN0cmluZygnJylgKVxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBjaGVjay5cbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIGB2YWx1ZWAgaXMgYW4gb2JqZWN0LCBlbHNlIGBmYWxzZWAuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uaXNPYmplY3Qoe30pO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKlxuICAgICAqIF8uaXNPYmplY3QoWzEsIDIsIDNdKTtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICpcbiAgICAgKiBfLmlzT2JqZWN0KDEpO1xuICAgICAqIC8vID0+IGZhbHNlXG4gICAgICovXG4gICAgZnVuY3Rpb24gaXNPYmplY3QodmFsdWUpIHtcbiAgICAgIC8vIGNoZWNrIGlmIHRoZSB2YWx1ZSBpcyB0aGUgRUNNQVNjcmlwdCBsYW5ndWFnZSB0eXBlIG9mIE9iamVjdFxuICAgICAgLy8gaHR0cDovL2VzNS5naXRodWIuaW8vI3g4XG4gICAgICAvLyBhbmQgYXZvaWQgYSBWOCBidWdcbiAgICAgIC8vIGh0dHA6Ly9jb2RlLmdvb2dsZS5jb20vcC92OC9pc3N1ZXMvZGV0YWlsP2lkPTIyOTFcbiAgICAgIHJldHVybiAhISh2YWx1ZSAmJiBvYmplY3RUeXBlc1t0eXBlb2YgdmFsdWVdKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBgTmFOYC5cbiAgICAgKlxuICAgICAqIE5vdGU6IFRoaXMgaXMgbm90IHRoZSBzYW1lIGFzIG5hdGl2ZSBgaXNOYU5gIHdoaWNoIHdpbGwgcmV0dXJuIGB0cnVlYCBmb3JcbiAgICAgKiBgdW5kZWZpbmVkYCBhbmQgb3RoZXIgbm9uLW51bWVyaWMgdmFsdWVzLiBTZWUgaHR0cDovL2VzNS5naXRodWIuaW8vI3gxNS4xLjIuNC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBPYmplY3RzXG4gICAgICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gY2hlY2suXG4gICAgICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIHRoZSBgdmFsdWVgIGlzIGBOYU5gLCBlbHNlIGBmYWxzZWAuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uaXNOYU4oTmFOKTtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICpcbiAgICAgKiBfLmlzTmFOKG5ldyBOdW1iZXIoTmFOKSk7XG4gICAgICogLy8gPT4gdHJ1ZVxuICAgICAqXG4gICAgICogaXNOYU4odW5kZWZpbmVkKTtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICpcbiAgICAgKiBfLmlzTmFOKHVuZGVmaW5lZCk7XG4gICAgICogLy8gPT4gZmFsc2VcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpc05hTih2YWx1ZSkge1xuICAgICAgLy8gYE5hTmAgYXMgYSBwcmltaXRpdmUgaXMgdGhlIG9ubHkgdmFsdWUgdGhhdCBpcyBub3QgZXF1YWwgdG8gaXRzZWxmXG4gICAgICAvLyAocGVyZm9ybSB0aGUgW1tDbGFzc11dIGNoZWNrIGZpcnN0IHRvIGF2b2lkIGVycm9ycyB3aXRoIHNvbWUgaG9zdCBvYmplY3RzIGluIElFKVxuICAgICAgcmV0dXJuIGlzTnVtYmVyKHZhbHVlKSAmJiB2YWx1ZSAhPSArdmFsdWU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIGlmIGB2YWx1ZWAgaXMgYG51bGxgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBjaGVjay5cbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIGB2YWx1ZWAgaXMgYG51bGxgLCBlbHNlIGBmYWxzZWAuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uaXNOdWxsKG51bGwpO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKlxuICAgICAqIF8uaXNOdWxsKHVuZGVmaW5lZCk7XG4gICAgICogLy8gPT4gZmFsc2VcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpc051bGwodmFsdWUpIHtcbiAgICAgIHJldHVybiB2YWx1ZSA9PT0gbnVsbDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBhIG51bWJlci5cbiAgICAgKlxuICAgICAqIE5vdGU6IGBOYU5gIGlzIGNvbnNpZGVyZWQgYSBudW1iZXIuIFNlZSBodHRwOi8vZXM1LmdpdGh1Yi5pby8jeDguNS5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBPYmplY3RzXG4gICAgICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gY2hlY2suXG4gICAgICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIHRoZSBgdmFsdWVgIGlzIGEgbnVtYmVyLCBlbHNlIGBmYWxzZWAuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uaXNOdW1iZXIoOC40ICogNSk7XG4gICAgICogLy8gPT4gdHJ1ZVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGlzTnVtYmVyKHZhbHVlKSB7XG4gICAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09ICdudW1iZXInIHx8XG4gICAgICAgIHZhbHVlICYmIHR5cGVvZiB2YWx1ZSA9PSAnb2JqZWN0JyAmJiB0b1N0cmluZy5jYWxsKHZhbHVlKSA9PSBudW1iZXJDbGFzcyB8fCBmYWxzZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBhbiBvYmplY3QgY3JlYXRlZCBieSB0aGUgYE9iamVjdGAgY29uc3RydWN0b3IuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiBgdmFsdWVgIGlzIGEgcGxhaW4gb2JqZWN0LCBlbHNlIGBmYWxzZWAuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIGZ1bmN0aW9uIFNoYXBlKCkge1xuICAgICAqICAgdGhpcy54ID0gMDtcbiAgICAgKiAgIHRoaXMueSA9IDA7XG4gICAgICogfVxuICAgICAqXG4gICAgICogXy5pc1BsYWluT2JqZWN0KG5ldyBTaGFwZSk7XG4gICAgICogLy8gPT4gZmFsc2VcbiAgICAgKlxuICAgICAqIF8uaXNQbGFpbk9iamVjdChbMSwgMiwgM10pO1xuICAgICAqIC8vID0+IGZhbHNlXG4gICAgICpcbiAgICAgKiBfLmlzUGxhaW5PYmplY3QoeyAneCc6IDAsICd5JzogMCB9KTtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICovXG4gICAgdmFyIGlzUGxhaW5PYmplY3QgPSAhZ2V0UHJvdG90eXBlT2YgPyBzaGltSXNQbGFpbk9iamVjdCA6IGZ1bmN0aW9uKHZhbHVlKSB7XG4gICAgICBpZiAoISh2YWx1ZSAmJiB0b1N0cmluZy5jYWxsKHZhbHVlKSA9PSBvYmplY3RDbGFzcykpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgICAgdmFyIHZhbHVlT2YgPSB2YWx1ZS52YWx1ZU9mLFxuICAgICAgICAgIG9ialByb3RvID0gaXNOYXRpdmUodmFsdWVPZikgJiYgKG9ialByb3RvID0gZ2V0UHJvdG90eXBlT2YodmFsdWVPZikpICYmIGdldFByb3RvdHlwZU9mKG9ialByb3RvKTtcblxuICAgICAgcmV0dXJuIG9ialByb3RvXG4gICAgICAgID8gKHZhbHVlID09IG9ialByb3RvIHx8IGdldFByb3RvdHlwZU9mKHZhbHVlKSA9PSBvYmpQcm90bylcbiAgICAgICAgOiBzaGltSXNQbGFpbk9iamVjdCh2YWx1ZSk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIENoZWNrcyBpZiBgdmFsdWVgIGlzIGEgcmVndWxhciBleHByZXNzaW9uLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBjaGVjay5cbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIGB2YWx1ZWAgaXMgYSByZWd1bGFyIGV4cHJlc3Npb24sIGVsc2UgYGZhbHNlYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5pc1JlZ0V4cCgvZnJlZC8pO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpc1JlZ0V4cCh2YWx1ZSkge1xuICAgICAgcmV0dXJuIHZhbHVlICYmIHR5cGVvZiB2YWx1ZSA9PSAnb2JqZWN0JyAmJiB0b1N0cmluZy5jYWxsKHZhbHVlKSA9PSByZWdleHBDbGFzcyB8fCBmYWxzZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBhIHN0cmluZy5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBPYmplY3RzXG4gICAgICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gY2hlY2suXG4gICAgICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIHRoZSBgdmFsdWVgIGlzIGEgc3RyaW5nLCBlbHNlIGBmYWxzZWAuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uaXNTdHJpbmcoJ2ZyZWQnKTtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICovXG4gICAgZnVuY3Rpb24gaXNTdHJpbmcodmFsdWUpIHtcbiAgICAgIHJldHVybiB0eXBlb2YgdmFsdWUgPT0gJ3N0cmluZycgfHxcbiAgICAgICAgdmFsdWUgJiYgdHlwZW9mIHZhbHVlID09ICdvYmplY3QnICYmIHRvU3RyaW5nLmNhbGwodmFsdWUpID09IHN0cmluZ0NsYXNzIHx8IGZhbHNlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrcyBpZiBgdmFsdWVgIGlzIGB1bmRlZmluZWRgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBjaGVjay5cbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIGB2YWx1ZWAgaXMgYHVuZGVmaW5lZGAsIGVsc2UgYGZhbHNlYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5pc1VuZGVmaW5lZCh2b2lkIDApO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpc1VuZGVmaW5lZCh2YWx1ZSkge1xuICAgICAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PSAndW5kZWZpbmVkJztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIG9iamVjdCB3aXRoIHRoZSBzYW1lIGtleXMgYXMgYG9iamVjdGAgYW5kIHZhbHVlcyBnZW5lcmF0ZWQgYnlcbiAgICAgKiBydW5uaW5nIGVhY2ggb3duIGVudW1lcmFibGUgcHJvcGVydHkgb2YgYG9iamVjdGAgdGhyb3VnaCB0aGUgY2FsbGJhY2suXG4gICAgICogVGhlIGNhbGxiYWNrIGlzIGJvdW5kIHRvIGB0aGlzQXJnYCBhbmQgaW52b2tlZCB3aXRoIHRocmVlIGFyZ3VtZW50cztcbiAgICAgKiAodmFsdWUsIGtleSwgb2JqZWN0KS5cbiAgICAgKlxuICAgICAqIElmIGEgcHJvcGVydHkgbmFtZSBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ucGx1Y2tcIiBzdHlsZVxuICAgICAqIGNhbGxiYWNrIHdpbGwgcmV0dXJuIHRoZSBwcm9wZXJ0eSB2YWx1ZSBvZiB0aGUgZ2l2ZW4gZWxlbWVudC5cbiAgICAgKlxuICAgICAqIElmIGFuIG9iamVjdCBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFja1xuICAgICAqIHdpbGwgcmV0dXJuIGB0cnVlYCBmb3IgZWxlbWVudHMgdGhhdCBoYXZlIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBnaXZlbiBvYmplY3QsXG4gICAgICogZWxzZSBgZmFsc2VgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0IFRoZSBvYmplY3QgdG8gaXRlcmF0ZSBvdmVyLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb258T2JqZWN0fHN0cmluZ30gW2NhbGxiYWNrPWlkZW50aXR5XSBUaGUgZnVuY3Rpb24gY2FsbGVkXG4gICAgICogIHBlciBpdGVyYXRpb24uIElmIGEgcHJvcGVydHkgbmFtZSBvciBvYmplY3QgaXMgcHJvdmlkZWQgaXQgd2lsbCBiZSB1c2VkXG4gICAgICogIHRvIGNyZWF0ZSBhIFwiXy5wbHVja1wiIG9yIFwiXy53aGVyZVwiIHN0eWxlIGNhbGxiYWNrLCByZXNwZWN0aXZlbHkuXG4gICAgICogQHBhcmFtIHsqfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIGEgbmV3IG9iamVjdCB3aXRoIHZhbHVlcyBvZiB0aGUgcmVzdWx0cyBvZiBlYWNoIGBjYWxsYmFja2AgZXhlY3V0aW9uLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLm1hcFZhbHVlcyh7ICdhJzogMSwgJ2InOiAyLCAnYyc6IDN9ICwgZnVuY3Rpb24obnVtKSB7IHJldHVybiBudW0gKiAzOyB9KTtcbiAgICAgKiAvLyA9PiB7ICdhJzogMywgJ2InOiA2LCAnYyc6IDkgfVxuICAgICAqXG4gICAgICogdmFyIGNoYXJhY3RlcnMgPSB7XG4gICAgICogICAnZnJlZCc6IHsgJ25hbWUnOiAnZnJlZCcsICdhZ2UnOiA0MCB9LFxuICAgICAqICAgJ3BlYmJsZXMnOiB7ICduYW1lJzogJ3BlYmJsZXMnLCAnYWdlJzogMSB9XG4gICAgICogfTtcbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIFwiXy5wbHVja1wiIGNhbGxiYWNrIHNob3J0aGFuZFxuICAgICAqIF8ubWFwVmFsdWVzKGNoYXJhY3RlcnMsICdhZ2UnKTtcbiAgICAgKiAvLyA9PiB7ICdmcmVkJzogNDAsICdwZWJibGVzJzogMSB9XG4gICAgICovXG4gICAgZnVuY3Rpb24gbWFwVmFsdWVzKG9iamVjdCwgY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICAgIHZhciByZXN1bHQgPSB7fTtcbiAgICAgIGNhbGxiYWNrID0gbG9kYXNoLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnLCAzKTtcblxuICAgICAgZm9yT3duKG9iamVjdCwgZnVuY3Rpb24odmFsdWUsIGtleSwgb2JqZWN0KSB7XG4gICAgICAgIHJlc3VsdFtrZXldID0gY2FsbGJhY2sodmFsdWUsIGtleSwgb2JqZWN0KTtcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZWN1cnNpdmVseSBtZXJnZXMgb3duIGVudW1lcmFibGUgcHJvcGVydGllcyBvZiB0aGUgc291cmNlIG9iamVjdChzKSwgdGhhdFxuICAgICAqIGRvbid0IHJlc29sdmUgdG8gYHVuZGVmaW5lZGAgaW50byB0aGUgZGVzdGluYXRpb24gb2JqZWN0LiBTdWJzZXF1ZW50IHNvdXJjZXNcbiAgICAgKiB3aWxsIG92ZXJ3cml0ZSBwcm9wZXJ0eSBhc3NpZ25tZW50cyBvZiBwcmV2aW91cyBzb3VyY2VzLiBJZiBhIGNhbGxiYWNrIGlzXG4gICAgICogcHJvdmlkZWQgaXQgd2lsbCBiZSBleGVjdXRlZCB0byBwcm9kdWNlIHRoZSBtZXJnZWQgdmFsdWVzIG9mIHRoZSBkZXN0aW5hdGlvblxuICAgICAqIGFuZCBzb3VyY2UgcHJvcGVydGllcy4gSWYgdGhlIGNhbGxiYWNrIHJldHVybnMgYHVuZGVmaW5lZGAgbWVyZ2luZyB3aWxsXG4gICAgICogYmUgaGFuZGxlZCBieSB0aGUgbWV0aG9kIGluc3RlYWQuIFRoZSBjYWxsYmFjayBpcyBib3VuZCB0byBgdGhpc0FyZ2AgYW5kXG4gICAgICogaW52b2tlZCB3aXRoIHR3byBhcmd1bWVudHM7IChvYmplY3RWYWx1ZSwgc291cmNlVmFsdWUpLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0IFRoZSBkZXN0aW5hdGlvbiBvYmplY3QuXG4gICAgICogQHBhcmFtIHsuLi5PYmplY3R9IFtzb3VyY2VdIFRoZSBzb3VyY2Ugb2JqZWN0cy5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBbY2FsbGJhY2tdIFRoZSBmdW5jdGlvbiB0byBjdXN0b21pemUgbWVyZ2luZyBwcm9wZXJ0aWVzLlxuICAgICAqIEBwYXJhbSB7Kn0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHtPYmplY3R9IFJldHVybnMgdGhlIGRlc3RpbmF0aW9uIG9iamVjdC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIG5hbWVzID0ge1xuICAgICAqICAgJ2NoYXJhY3RlcnMnOiBbXG4gICAgICogICAgIHsgJ25hbWUnOiAnYmFybmV5JyB9LFxuICAgICAqICAgICB7ICduYW1lJzogJ2ZyZWQnIH1cbiAgICAgKiAgIF1cbiAgICAgKiB9O1xuICAgICAqXG4gICAgICogdmFyIGFnZXMgPSB7XG4gICAgICogICAnY2hhcmFjdGVycyc6IFtcbiAgICAgKiAgICAgeyAnYWdlJzogMzYgfSxcbiAgICAgKiAgICAgeyAnYWdlJzogNDAgfVxuICAgICAqICAgXVxuICAgICAqIH07XG4gICAgICpcbiAgICAgKiBfLm1lcmdlKG5hbWVzLCBhZ2VzKTtcbiAgICAgKiAvLyA9PiB7ICdjaGFyYWN0ZXJzJzogW3sgJ25hbWUnOiAnYmFybmV5JywgJ2FnZSc6IDM2IH0sIHsgJ25hbWUnOiAnZnJlZCcsICdhZ2UnOiA0MCB9XSB9XG4gICAgICpcbiAgICAgKiB2YXIgZm9vZCA9IHtcbiAgICAgKiAgICdmcnVpdHMnOiBbJ2FwcGxlJ10sXG4gICAgICogICAndmVnZXRhYmxlcyc6IFsnYmVldCddXG4gICAgICogfTtcbiAgICAgKlxuICAgICAqIHZhciBvdGhlckZvb2QgPSB7XG4gICAgICogICAnZnJ1aXRzJzogWydiYW5hbmEnXSxcbiAgICAgKiAgICd2ZWdldGFibGVzJzogWydjYXJyb3QnXVxuICAgICAqIH07XG4gICAgICpcbiAgICAgKiBfLm1lcmdlKGZvb2QsIG90aGVyRm9vZCwgZnVuY3Rpb24oYSwgYikge1xuICAgICAqICAgcmV0dXJuIF8uaXNBcnJheShhKSA/IGEuY29uY2F0KGIpIDogdW5kZWZpbmVkO1xuICAgICAqIH0pO1xuICAgICAqIC8vID0+IHsgJ2ZydWl0cyc6IFsnYXBwbGUnLCAnYmFuYW5hJ10sICd2ZWdldGFibGVzJzogWydiZWV0JywgJ2NhcnJvdF0gfVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIG1lcmdlKG9iamVjdCkge1xuICAgICAgdmFyIGFyZ3MgPSBhcmd1bWVudHMsXG4gICAgICAgICAgbGVuZ3RoID0gMjtcblxuICAgICAgaWYgKCFpc09iamVjdChvYmplY3QpKSB7XG4gICAgICAgIHJldHVybiBvYmplY3Q7XG4gICAgICB9XG4gICAgICAvLyBhbGxvd3Mgd29ya2luZyB3aXRoIGBfLnJlZHVjZWAgYW5kIGBfLnJlZHVjZVJpZ2h0YCB3aXRob3V0IHVzaW5nXG4gICAgICAvLyB0aGVpciBgaW5kZXhgIGFuZCBgY29sbGVjdGlvbmAgYXJndW1lbnRzXG4gICAgICBpZiAodHlwZW9mIGFyZ3NbMl0gIT0gJ251bWJlcicpIHtcbiAgICAgICAgbGVuZ3RoID0gYXJncy5sZW5ndGg7XG4gICAgICB9XG4gICAgICBpZiAobGVuZ3RoID4gMyAmJiB0eXBlb2YgYXJnc1tsZW5ndGggLSAyXSA9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHZhciBjYWxsYmFjayA9IGJhc2VDcmVhdGVDYWxsYmFjayhhcmdzWy0tbGVuZ3RoIC0gMV0sIGFyZ3NbbGVuZ3RoLS1dLCAyKTtcbiAgICAgIH0gZWxzZSBpZiAobGVuZ3RoID4gMiAmJiB0eXBlb2YgYXJnc1tsZW5ndGggLSAxXSA9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIGNhbGxiYWNrID0gYXJnc1stLWxlbmd0aF07XG4gICAgICB9XG4gICAgICB2YXIgc291cmNlcyA9IHNsaWNlKGFyZ3VtZW50cywgMSwgbGVuZ3RoKSxcbiAgICAgICAgICBpbmRleCA9IC0xLFxuICAgICAgICAgIHN0YWNrQSA9IGdldEFycmF5KCksXG4gICAgICAgICAgc3RhY2tCID0gZ2V0QXJyYXkoKTtcblxuICAgICAgd2hpbGUgKCsraW5kZXggPCBsZW5ndGgpIHtcbiAgICAgICAgYmFzZU1lcmdlKG9iamVjdCwgc291cmNlc1tpbmRleF0sIGNhbGxiYWNrLCBzdGFja0EsIHN0YWNrQik7XG4gICAgICB9XG4gICAgICByZWxlYXNlQXJyYXkoc3RhY2tBKTtcbiAgICAgIHJlbGVhc2VBcnJheShzdGFja0IpO1xuICAgICAgcmV0dXJuIG9iamVjdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgc2hhbGxvdyBjbG9uZSBvZiBgb2JqZWN0YCBleGNsdWRpbmcgdGhlIHNwZWNpZmllZCBwcm9wZXJ0aWVzLlxuICAgICAqIFByb3BlcnR5IG5hbWVzIG1heSBiZSBzcGVjaWZpZWQgYXMgaW5kaXZpZHVhbCBhcmd1bWVudHMgb3IgYXMgYXJyYXlzIG9mXG4gICAgICogcHJvcGVydHkgbmFtZXMuIElmIGEgY2FsbGJhY2sgaXMgcHJvdmlkZWQgaXQgd2lsbCBiZSBleGVjdXRlZCBmb3IgZWFjaFxuICAgICAqIHByb3BlcnR5IG9mIGBvYmplY3RgIG9taXR0aW5nIHRoZSBwcm9wZXJ0aWVzIHRoZSBjYWxsYmFjayByZXR1cm5zIHRydWV5XG4gICAgICogZm9yLiBUaGUgY2FsbGJhY2sgaXMgYm91bmQgdG8gYHRoaXNBcmdgIGFuZCBpbnZva2VkIHdpdGggdGhyZWUgYXJndW1lbnRzO1xuICAgICAqICh2YWx1ZSwga2V5LCBvYmplY3QpLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0IFRoZSBzb3VyY2Ugb2JqZWN0LlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb258Li4uc3RyaW5nfHN0cmluZ1tdfSBbY2FsbGJhY2tdIFRoZSBwcm9wZXJ0aWVzIHRvIG9taXQgb3IgdGhlXG4gICAgICogIGZ1bmN0aW9uIGNhbGxlZCBwZXIgaXRlcmF0aW9uLlxuICAgICAqIEBwYXJhbSB7Kn0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHtPYmplY3R9IFJldHVybnMgYW4gb2JqZWN0IHdpdGhvdXQgdGhlIG9taXR0ZWQgcHJvcGVydGllcy5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5vbWl0KHsgJ25hbWUnOiAnZnJlZCcsICdhZ2UnOiA0MCB9LCAnYWdlJyk7XG4gICAgICogLy8gPT4geyAnbmFtZSc6ICdmcmVkJyB9XG4gICAgICpcbiAgICAgKiBfLm9taXQoeyAnbmFtZSc6ICdmcmVkJywgJ2FnZSc6IDQwIH0sIGZ1bmN0aW9uKHZhbHVlKSB7XG4gICAgICogICByZXR1cm4gdHlwZW9mIHZhbHVlID09ICdudW1iZXInO1xuICAgICAqIH0pO1xuICAgICAqIC8vID0+IHsgJ25hbWUnOiAnZnJlZCcgfVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIG9taXQob2JqZWN0LCBjYWxsYmFjaywgdGhpc0FyZykge1xuICAgICAgdmFyIHJlc3VsdCA9IHt9O1xuICAgICAgaWYgKHR5cGVvZiBjYWxsYmFjayAhPSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHZhciBwcm9wcyA9IFtdO1xuICAgICAgICBmb3JJbihvYmplY3QsIGZ1bmN0aW9uKHZhbHVlLCBrZXkpIHtcbiAgICAgICAgICBwcm9wcy5wdXNoKGtleSk7XG4gICAgICAgIH0pO1xuICAgICAgICBwcm9wcyA9IGJhc2VEaWZmZXJlbmNlKHByb3BzLCBiYXNlRmxhdHRlbihhcmd1bWVudHMsIHRydWUsIGZhbHNlLCAxKSk7XG5cbiAgICAgICAgdmFyIGluZGV4ID0gLTEsXG4gICAgICAgICAgICBsZW5ndGggPSBwcm9wcy5sZW5ndGg7XG5cbiAgICAgICAgd2hpbGUgKCsraW5kZXggPCBsZW5ndGgpIHtcbiAgICAgICAgICB2YXIga2V5ID0gcHJvcHNbaW5kZXhdO1xuICAgICAgICAgIHJlc3VsdFtrZXldID0gb2JqZWN0W2tleV07XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNhbGxiYWNrID0gbG9kYXNoLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnLCAzKTtcbiAgICAgICAgZm9ySW4ob2JqZWN0LCBmdW5jdGlvbih2YWx1ZSwga2V5LCBvYmplY3QpIHtcbiAgICAgICAgICBpZiAoIWNhbGxiYWNrKHZhbHVlLCBrZXksIG9iamVjdCkpIHtcbiAgICAgICAgICAgIHJlc3VsdFtrZXldID0gdmFsdWU7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIHR3byBkaW1lbnNpb25hbCBhcnJheSBvZiBhbiBvYmplY3QncyBrZXktdmFsdWUgcGFpcnMsXG4gICAgICogaS5lLiBgW1trZXkxLCB2YWx1ZTFdLCBba2V5MiwgdmFsdWUyXV1gLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0IFRoZSBvYmplY3QgdG8gaW5zcGVjdC5cbiAgICAgKiBAcmV0dXJucyB7QXJyYXl9IFJldHVybnMgbmV3IGFycmF5IG9mIGtleS12YWx1ZSBwYWlycy5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5wYWlycyh7ICdiYXJuZXknOiAzNiwgJ2ZyZWQnOiA0MCB9KTtcbiAgICAgKiAvLyA9PiBbWydiYXJuZXknLCAzNl0sIFsnZnJlZCcsIDQwXV0gKHByb3BlcnR5IG9yZGVyIGlzIG5vdCBndWFyYW50ZWVkIGFjcm9zcyBlbnZpcm9ubWVudHMpXG4gICAgICovXG4gICAgZnVuY3Rpb24gcGFpcnMob2JqZWN0KSB7XG4gICAgICB2YXIgaW5kZXggPSAtMSxcbiAgICAgICAgICBwcm9wcyA9IGtleXMob2JqZWN0KSxcbiAgICAgICAgICBsZW5ndGggPSBwcm9wcy5sZW5ndGgsXG4gICAgICAgICAgcmVzdWx0ID0gQXJyYXkobGVuZ3RoKTtcblxuICAgICAgd2hpbGUgKCsraW5kZXggPCBsZW5ndGgpIHtcbiAgICAgICAgdmFyIGtleSA9IHByb3BzW2luZGV4XTtcbiAgICAgICAgcmVzdWx0W2luZGV4XSA9IFtrZXksIG9iamVjdFtrZXldXTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIHNoYWxsb3cgY2xvbmUgb2YgYG9iamVjdGAgY29tcG9zZWQgb2YgdGhlIHNwZWNpZmllZCBwcm9wZXJ0aWVzLlxuICAgICAqIFByb3BlcnR5IG5hbWVzIG1heSBiZSBzcGVjaWZpZWQgYXMgaW5kaXZpZHVhbCBhcmd1bWVudHMgb3IgYXMgYXJyYXlzIG9mXG4gICAgICogcHJvcGVydHkgbmFtZXMuIElmIGEgY2FsbGJhY2sgaXMgcHJvdmlkZWQgaXQgd2lsbCBiZSBleGVjdXRlZCBmb3IgZWFjaFxuICAgICAqIHByb3BlcnR5IG9mIGBvYmplY3RgIHBpY2tpbmcgdGhlIHByb3BlcnRpZXMgdGhlIGNhbGxiYWNrIHJldHVybnMgdHJ1ZXlcbiAgICAgKiBmb3IuIFRoZSBjYWxsYmFjayBpcyBib3VuZCB0byBgdGhpc0FyZ2AgYW5kIGludm9rZWQgd2l0aCB0aHJlZSBhcmd1bWVudHM7XG4gICAgICogKHZhbHVlLCBrZXksIG9iamVjdCkuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3QgVGhlIHNvdXJjZSBvYmplY3QuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbnwuLi5zdHJpbmd8c3RyaW5nW119IFtjYWxsYmFja10gVGhlIGZ1bmN0aW9uIGNhbGxlZCBwZXJcbiAgICAgKiAgaXRlcmF0aW9uIG9yIHByb3BlcnR5IG5hbWVzIHRvIHBpY2ssIHNwZWNpZmllZCBhcyBpbmRpdmlkdWFsIHByb3BlcnR5XG4gICAgICogIG5hbWVzIG9yIGFycmF5cyBvZiBwcm9wZXJ0eSBuYW1lcy5cbiAgICAgKiBAcGFyYW0geyp9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSBSZXR1cm5zIGFuIG9iamVjdCBjb21wb3NlZCBvZiB0aGUgcGlja2VkIHByb3BlcnRpZXMuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8ucGljayh7ICduYW1lJzogJ2ZyZWQnLCAnX3VzZXJpZCc6ICdmcmVkMScgfSwgJ25hbWUnKTtcbiAgICAgKiAvLyA9PiB7ICduYW1lJzogJ2ZyZWQnIH1cbiAgICAgKlxuICAgICAqIF8ucGljayh7ICduYW1lJzogJ2ZyZWQnLCAnX3VzZXJpZCc6ICdmcmVkMScgfSwgZnVuY3Rpb24odmFsdWUsIGtleSkge1xuICAgICAqICAgcmV0dXJuIGtleS5jaGFyQXQoMCkgIT0gJ18nO1xuICAgICAqIH0pO1xuICAgICAqIC8vID0+IHsgJ25hbWUnOiAnZnJlZCcgfVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHBpY2sob2JqZWN0LCBjYWxsYmFjaywgdGhpc0FyZykge1xuICAgICAgdmFyIHJlc3VsdCA9IHt9O1xuICAgICAgaWYgKHR5cGVvZiBjYWxsYmFjayAhPSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICAgICAgcHJvcHMgPSBiYXNlRmxhdHRlbihhcmd1bWVudHMsIHRydWUsIGZhbHNlLCAxKSxcbiAgICAgICAgICAgIGxlbmd0aCA9IGlzT2JqZWN0KG9iamVjdCkgPyBwcm9wcy5sZW5ndGggOiAwO1xuXG4gICAgICAgIHdoaWxlICgrK2luZGV4IDwgbGVuZ3RoKSB7XG4gICAgICAgICAgdmFyIGtleSA9IHByb3BzW2luZGV4XTtcbiAgICAgICAgICBpZiAoa2V5IGluIG9iamVjdCkge1xuICAgICAgICAgICAgcmVzdWx0W2tleV0gPSBvYmplY3Rba2V5XTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNhbGxiYWNrID0gbG9kYXNoLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnLCAzKTtcbiAgICAgICAgZm9ySW4ob2JqZWN0LCBmdW5jdGlvbih2YWx1ZSwga2V5LCBvYmplY3QpIHtcbiAgICAgICAgICBpZiAoY2FsbGJhY2sodmFsdWUsIGtleSwgb2JqZWN0KSkge1xuICAgICAgICAgICAgcmVzdWx0W2tleV0gPSB2YWx1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBbiBhbHRlcm5hdGl2ZSB0byBgXy5yZWR1Y2VgIHRoaXMgbWV0aG9kIHRyYW5zZm9ybXMgYG9iamVjdGAgdG8gYSBuZXdcbiAgICAgKiBgYWNjdW11bGF0b3JgIG9iamVjdCB3aGljaCBpcyB0aGUgcmVzdWx0IG9mIHJ1bm5pbmcgZWFjaCBvZiBpdHMgb3duXG4gICAgICogZW51bWVyYWJsZSBwcm9wZXJ0aWVzIHRocm91Z2ggYSBjYWxsYmFjaywgd2l0aCBlYWNoIGNhbGxiYWNrIGV4ZWN1dGlvblxuICAgICAqIHBvdGVudGlhbGx5IG11dGF0aW5nIHRoZSBgYWNjdW11bGF0b3JgIG9iamVjdC4gVGhlIGNhbGxiYWNrIGlzIGJvdW5kIHRvXG4gICAgICogYHRoaXNBcmdgIGFuZCBpbnZva2VkIHdpdGggZm91ciBhcmd1bWVudHM7IChhY2N1bXVsYXRvciwgdmFsdWUsIGtleSwgb2JqZWN0KS5cbiAgICAgKiBDYWxsYmFja3MgbWF5IGV4aXQgaXRlcmF0aW9uIGVhcmx5IGJ5IGV4cGxpY2l0bHkgcmV0dXJuaW5nIGBmYWxzZWAuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fSBvYmplY3QgVGhlIG9iamVjdCB0byBpdGVyYXRlIG92ZXIuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gW2NhbGxiYWNrPWlkZW50aXR5XSBUaGUgZnVuY3Rpb24gY2FsbGVkIHBlciBpdGVyYXRpb24uXG4gICAgICogQHBhcmFtIHsqfSBbYWNjdW11bGF0b3JdIFRoZSBjdXN0b20gYWNjdW11bGF0b3IgdmFsdWUuXG4gICAgICogQHBhcmFtIHsqfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHJldHVybnMgeyp9IFJldHVybnMgdGhlIGFjY3VtdWxhdGVkIHZhbHVlLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgc3F1YXJlcyA9IF8udHJhbnNmb3JtKFsxLCAyLCAzLCA0LCA1LCA2LCA3LCA4LCA5LCAxMF0sIGZ1bmN0aW9uKHJlc3VsdCwgbnVtKSB7XG4gICAgICogICBudW0gKj0gbnVtO1xuICAgICAqICAgaWYgKG51bSAlIDIpIHtcbiAgICAgKiAgICAgcmV0dXJuIHJlc3VsdC5wdXNoKG51bSkgPCAzO1xuICAgICAqICAgfVxuICAgICAqIH0pO1xuICAgICAqIC8vID0+IFsxLCA5LCAyNV1cbiAgICAgKlxuICAgICAqIHZhciBtYXBwZWQgPSBfLnRyYW5zZm9ybSh7ICdhJzogMSwgJ2InOiAyLCAnYyc6IDMgfSwgZnVuY3Rpb24ocmVzdWx0LCBudW0sIGtleSkge1xuICAgICAqICAgcmVzdWx0W2tleV0gPSBudW0gKiAzO1xuICAgICAqIH0pO1xuICAgICAqIC8vID0+IHsgJ2EnOiAzLCAnYic6IDYsICdjJzogOSB9XG4gICAgICovXG4gICAgZnVuY3Rpb24gdHJhbnNmb3JtKG9iamVjdCwgY2FsbGJhY2ssIGFjY3VtdWxhdG9yLCB0aGlzQXJnKSB7XG4gICAgICB2YXIgaXNBcnIgPSBpc0FycmF5KG9iamVjdCk7XG4gICAgICBpZiAoYWNjdW11bGF0b3IgPT0gbnVsbCkge1xuICAgICAgICBpZiAoaXNBcnIpIHtcbiAgICAgICAgICBhY2N1bXVsYXRvciA9IFtdO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHZhciBjdG9yID0gb2JqZWN0ICYmIG9iamVjdC5jb25zdHJ1Y3RvcixcbiAgICAgICAgICAgICAgcHJvdG8gPSBjdG9yICYmIGN0b3IucHJvdG90eXBlO1xuXG4gICAgICAgICAgYWNjdW11bGF0b3IgPSBiYXNlQ3JlYXRlKHByb3RvKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKGNhbGxiYWNrKSB7XG4gICAgICAgIGNhbGxiYWNrID0gbG9kYXNoLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnLCA0KTtcbiAgICAgICAgKGlzQXJyID8gZm9yRWFjaCA6IGZvck93bikob2JqZWN0LCBmdW5jdGlvbih2YWx1ZSwgaW5kZXgsIG9iamVjdCkge1xuICAgICAgICAgIHJldHVybiBjYWxsYmFjayhhY2N1bXVsYXRvciwgdmFsdWUsIGluZGV4LCBvYmplY3QpO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBhY2N1bXVsYXRvcjtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIGFycmF5IGNvbXBvc2VkIG9mIHRoZSBvd24gZW51bWVyYWJsZSBwcm9wZXJ0eSB2YWx1ZXMgb2YgYG9iamVjdGAuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3QgVGhlIG9iamVjdCB0byBpbnNwZWN0LlxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyBhbiBhcnJheSBvZiBwcm9wZXJ0eSB2YWx1ZXMuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8udmFsdWVzKHsgJ29uZSc6IDEsICd0d28nOiAyLCAndGhyZWUnOiAzIH0pO1xuICAgICAqIC8vID0+IFsxLCAyLCAzXSAocHJvcGVydHkgb3JkZXIgaXMgbm90IGd1YXJhbnRlZWQgYWNyb3NzIGVudmlyb25tZW50cylcbiAgICAgKi9cbiAgICBmdW5jdGlvbiB2YWx1ZXMob2JqZWN0KSB7XG4gICAgICB2YXIgaW5kZXggPSAtMSxcbiAgICAgICAgICBwcm9wcyA9IGtleXMob2JqZWN0KSxcbiAgICAgICAgICBsZW5ndGggPSBwcm9wcy5sZW5ndGgsXG4gICAgICAgICAgcmVzdWx0ID0gQXJyYXkobGVuZ3RoKTtcblxuICAgICAgd2hpbGUgKCsraW5kZXggPCBsZW5ndGgpIHtcbiAgICAgICAgcmVzdWx0W2luZGV4XSA9IG9iamVjdFtwcm9wc1tpbmRleF1dO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICAvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW4gYXJyYXkgb2YgZWxlbWVudHMgZnJvbSB0aGUgc3BlY2lmaWVkIGluZGV4ZXMsIG9yIGtleXMsIG9mIHRoZVxuICAgICAqIGBjb2xsZWN0aW9uYC4gSW5kZXhlcyBtYXkgYmUgc3BlY2lmaWVkIGFzIGluZGl2aWR1YWwgYXJndW1lbnRzIG9yIGFzIGFycmF5c1xuICAgICAqIG9mIGluZGV4ZXMuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgQ29sbGVjdGlvbnNcbiAgICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdHxzdHJpbmd9IGNvbGxlY3Rpb24gVGhlIGNvbGxlY3Rpb24gdG8gaXRlcmF0ZSBvdmVyLlxuICAgICAqIEBwYXJhbSB7Li4uKG51bWJlcnxudW1iZXJbXXxzdHJpbmd8c3RyaW5nW10pfSBbaW5kZXhdIFRoZSBpbmRleGVzIG9mIGBjb2xsZWN0aW9uYFxuICAgICAqICAgdG8gcmV0cmlldmUsIHNwZWNpZmllZCBhcyBpbmRpdmlkdWFsIGluZGV4ZXMgb3IgYXJyYXlzIG9mIGluZGV4ZXMuXG4gICAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIGEgbmV3IGFycmF5IG9mIGVsZW1lbnRzIGNvcnJlc3BvbmRpbmcgdG8gdGhlXG4gICAgICogIHByb3ZpZGVkIGluZGV4ZXMuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uYXQoWydhJywgJ2InLCAnYycsICdkJywgJ2UnXSwgWzAsIDIsIDRdKTtcbiAgICAgKiAvLyA9PiBbJ2EnLCAnYycsICdlJ11cbiAgICAgKlxuICAgICAqIF8uYXQoWydmcmVkJywgJ2Jhcm5leScsICdwZWJibGVzJ10sIDAsIDIpO1xuICAgICAqIC8vID0+IFsnZnJlZCcsICdwZWJibGVzJ11cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBhdChjb2xsZWN0aW9uKSB7XG4gICAgICB2YXIgYXJncyA9IGFyZ3VtZW50cyxcbiAgICAgICAgICBpbmRleCA9IC0xLFxuICAgICAgICAgIHByb3BzID0gYmFzZUZsYXR0ZW4oYXJncywgdHJ1ZSwgZmFsc2UsIDEpLFxuICAgICAgICAgIGxlbmd0aCA9IChhcmdzWzJdICYmIGFyZ3NbMl1bYXJnc1sxXV0gPT09IGNvbGxlY3Rpb24pID8gMSA6IHByb3BzLmxlbmd0aCxcbiAgICAgICAgICByZXN1bHQgPSBBcnJheShsZW5ndGgpO1xuXG4gICAgICB3aGlsZSgrK2luZGV4IDwgbGVuZ3RoKSB7XG4gICAgICAgIHJlc3VsdFtpbmRleF0gPSBjb2xsZWN0aW9uW3Byb3BzW2luZGV4XV07XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrcyBpZiBhIGdpdmVuIHZhbHVlIGlzIHByZXNlbnQgaW4gYSBjb2xsZWN0aW9uIHVzaW5nIHN0cmljdCBlcXVhbGl0eVxuICAgICAqIGZvciBjb21wYXJpc29ucywgaS5lLiBgPT09YC4gSWYgYGZyb21JbmRleGAgaXMgbmVnYXRpdmUsIGl0IGlzIHVzZWQgYXMgdGhlXG4gICAgICogb2Zmc2V0IGZyb20gdGhlIGVuZCBvZiB0aGUgY29sbGVjdGlvbi5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBhbGlhcyBpbmNsdWRlXG4gICAgICogQGNhdGVnb3J5IENvbGxlY3Rpb25zXG4gICAgICogQHBhcmFtIHtBcnJheXxPYmplY3R8c3RyaW5nfSBjb2xsZWN0aW9uIFRoZSBjb2xsZWN0aW9uIHRvIGl0ZXJhdGUgb3Zlci5cbiAgICAgKiBAcGFyYW0geyp9IHRhcmdldCBUaGUgdmFsdWUgdG8gY2hlY2sgZm9yLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbZnJvbUluZGV4PTBdIFRoZSBpbmRleCB0byBzZWFyY2ggZnJvbS5cbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIGB0YXJnZXRgIGVsZW1lbnQgaXMgZm91bmQsIGVsc2UgYGZhbHNlYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5jb250YWlucyhbMSwgMiwgM10sIDEpO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKlxuICAgICAqIF8uY29udGFpbnMoWzEsIDIsIDNdLCAxLCAyKTtcbiAgICAgKiAvLyA9PiBmYWxzZVxuICAgICAqXG4gICAgICogXy5jb250YWlucyh7ICduYW1lJzogJ2ZyZWQnLCAnYWdlJzogNDAgfSwgJ2ZyZWQnKTtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICpcbiAgICAgKiBfLmNvbnRhaW5zKCdwZWJibGVzJywgJ2ViJyk7XG4gICAgICogLy8gPT4gdHJ1ZVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGNvbnRhaW5zKGNvbGxlY3Rpb24sIHRhcmdldCwgZnJvbUluZGV4KSB7XG4gICAgICB2YXIgaW5kZXggPSAtMSxcbiAgICAgICAgICBpbmRleE9mID0gZ2V0SW5kZXhPZigpLFxuICAgICAgICAgIGxlbmd0aCA9IGNvbGxlY3Rpb24gPyBjb2xsZWN0aW9uLmxlbmd0aCA6IDAsXG4gICAgICAgICAgcmVzdWx0ID0gZmFsc2U7XG5cbiAgICAgIGZyb21JbmRleCA9IChmcm9tSW5kZXggPCAwID8gbmF0aXZlTWF4KDAsIGxlbmd0aCArIGZyb21JbmRleCkgOiBmcm9tSW5kZXgpIHx8IDA7XG4gICAgICBpZiAoaXNBcnJheShjb2xsZWN0aW9uKSkge1xuICAgICAgICByZXN1bHQgPSBpbmRleE9mKGNvbGxlY3Rpb24sIHRhcmdldCwgZnJvbUluZGV4KSA+IC0xO1xuICAgICAgfSBlbHNlIGlmICh0eXBlb2YgbGVuZ3RoID09ICdudW1iZXInKSB7XG4gICAgICAgIHJlc3VsdCA9IChpc1N0cmluZyhjb2xsZWN0aW9uKSA/IGNvbGxlY3Rpb24uaW5kZXhPZih0YXJnZXQsIGZyb21JbmRleCkgOiBpbmRleE9mKGNvbGxlY3Rpb24sIHRhcmdldCwgZnJvbUluZGV4KSkgPiAtMTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGZvck93bihjb2xsZWN0aW9uLCBmdW5jdGlvbih2YWx1ZSkge1xuICAgICAgICAgIGlmICgrK2luZGV4ID49IGZyb21JbmRleCkge1xuICAgICAgICAgICAgcmV0dXJuICEocmVzdWx0ID0gdmFsdWUgPT09IHRhcmdldCk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbiBvYmplY3QgY29tcG9zZWQgb2Yga2V5cyBnZW5lcmF0ZWQgZnJvbSB0aGUgcmVzdWx0cyBvZiBydW5uaW5nXG4gICAgICogZWFjaCBlbGVtZW50IG9mIGBjb2xsZWN0aW9uYCB0aHJvdWdoIHRoZSBjYWxsYmFjay4gVGhlIGNvcnJlc3BvbmRpbmcgdmFsdWVcbiAgICAgKiBvZiBlYWNoIGtleSBpcyB0aGUgbnVtYmVyIG9mIHRpbWVzIHRoZSBrZXkgd2FzIHJldHVybmVkIGJ5IHRoZSBjYWxsYmFjay5cbiAgICAgKiBUaGUgY2FsbGJhY2sgaXMgYm91bmQgdG8gYHRoaXNBcmdgIGFuZCBpbnZva2VkIHdpdGggdGhyZWUgYXJndW1lbnRzO1xuICAgICAqICh2YWx1ZSwgaW5kZXh8a2V5LCBjb2xsZWN0aW9uKS5cbiAgICAgKlxuICAgICAqIElmIGEgcHJvcGVydHkgbmFtZSBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ucGx1Y2tcIiBzdHlsZVxuICAgICAqIGNhbGxiYWNrIHdpbGwgcmV0dXJuIHRoZSBwcm9wZXJ0eSB2YWx1ZSBvZiB0aGUgZ2l2ZW4gZWxlbWVudC5cbiAgICAgKlxuICAgICAqIElmIGFuIG9iamVjdCBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFja1xuICAgICAqIHdpbGwgcmV0dXJuIGB0cnVlYCBmb3IgZWxlbWVudHMgdGhhdCBoYXZlIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBnaXZlbiBvYmplY3QsXG4gICAgICogZWxzZSBgZmFsc2VgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IENvbGxlY3Rpb25zXG4gICAgICogQHBhcmFtIHtBcnJheXxPYmplY3R8c3RyaW5nfSBjb2xsZWN0aW9uIFRoZSBjb2xsZWN0aW9uIHRvIGl0ZXJhdGUgb3Zlci5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufE9iamVjdHxzdHJpbmd9IFtjYWxsYmFjaz1pZGVudGl0eV0gVGhlIGZ1bmN0aW9uIGNhbGxlZFxuICAgICAqICBwZXIgaXRlcmF0aW9uLiBJZiBhIHByb3BlcnR5IG5hbWUgb3Igb2JqZWN0IGlzIHByb3ZpZGVkIGl0IHdpbGwgYmUgdXNlZFxuICAgICAqICB0byBjcmVhdGUgYSBcIl8ucGx1Y2tcIiBvciBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFjaywgcmVzcGVjdGl2ZWx5LlxuICAgICAqIEBwYXJhbSB7Kn0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHtPYmplY3R9IFJldHVybnMgdGhlIGNvbXBvc2VkIGFnZ3JlZ2F0ZSBvYmplY3QuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uY291bnRCeShbNC4zLCA2LjEsIDYuNF0sIGZ1bmN0aW9uKG51bSkgeyByZXR1cm4gTWF0aC5mbG9vcihudW0pOyB9KTtcbiAgICAgKiAvLyA9PiB7ICc0JzogMSwgJzYnOiAyIH1cbiAgICAgKlxuICAgICAqIF8uY291bnRCeShbNC4zLCA2LjEsIDYuNF0sIGZ1bmN0aW9uKG51bSkgeyByZXR1cm4gdGhpcy5mbG9vcihudW0pOyB9LCBNYXRoKTtcbiAgICAgKiAvLyA9PiB7ICc0JzogMSwgJzYnOiAyIH1cbiAgICAgKlxuICAgICAqIF8uY291bnRCeShbJ29uZScsICd0d28nLCAndGhyZWUnXSwgJ2xlbmd0aCcpO1xuICAgICAqIC8vID0+IHsgJzMnOiAyLCAnNSc6IDEgfVxuICAgICAqL1xuICAgIHZhciBjb3VudEJ5ID0gY3JlYXRlQWdncmVnYXRvcihmdW5jdGlvbihyZXN1bHQsIHZhbHVlLCBrZXkpIHtcbiAgICAgIChoYXNPd25Qcm9wZXJ0eS5jYWxsKHJlc3VsdCwga2V5KSA/IHJlc3VsdFtrZXldKysgOiByZXN1bHRba2V5XSA9IDEpO1xuICAgIH0pO1xuXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBjYWxsYmFjayByZXR1cm5zIHRydWV5IHZhbHVlIGZvciAqKmFsbCoqIGVsZW1lbnRzIG9mXG4gICAgICogYSBjb2xsZWN0aW9uLiBUaGUgY2FsbGJhY2sgaXMgYm91bmQgdG8gYHRoaXNBcmdgIGFuZCBpbnZva2VkIHdpdGggdGhyZWVcbiAgICAgKiBhcmd1bWVudHM7ICh2YWx1ZSwgaW5kZXh8a2V5LCBjb2xsZWN0aW9uKS5cbiAgICAgKlxuICAgICAqIElmIGEgcHJvcGVydHkgbmFtZSBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ucGx1Y2tcIiBzdHlsZVxuICAgICAqIGNhbGxiYWNrIHdpbGwgcmV0dXJuIHRoZSBwcm9wZXJ0eSB2YWx1ZSBvZiB0aGUgZ2l2ZW4gZWxlbWVudC5cbiAgICAgKlxuICAgICAqIElmIGFuIG9iamVjdCBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFja1xuICAgICAqIHdpbGwgcmV0dXJuIGB0cnVlYCBmb3IgZWxlbWVudHMgdGhhdCBoYXZlIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBnaXZlbiBvYmplY3QsXG4gICAgICogZWxzZSBgZmFsc2VgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGFsaWFzIGFsbFxuICAgICAqIEBjYXRlZ29yeSBDb2xsZWN0aW9uc1xuICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fHN0cmluZ30gY29sbGVjdGlvbiBUaGUgY29sbGVjdGlvbiB0byBpdGVyYXRlIG92ZXIuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbnxPYmplY3R8c3RyaW5nfSBbY2FsbGJhY2s9aWRlbnRpdHldIFRoZSBmdW5jdGlvbiBjYWxsZWRcbiAgICAgKiAgcGVyIGl0ZXJhdGlvbi4gSWYgYSBwcm9wZXJ0eSBuYW1lIG9yIG9iamVjdCBpcyBwcm92aWRlZCBpdCB3aWxsIGJlIHVzZWRcbiAgICAgKiAgdG8gY3JlYXRlIGEgXCJfLnBsdWNrXCIgb3IgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2ssIHJlc3BlY3RpdmVseS5cbiAgICAgKiBAcGFyYW0geyp9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgYWxsIGVsZW1lbnRzIHBhc3NlZCB0aGUgY2FsbGJhY2sgY2hlY2ssXG4gICAgICogIGVsc2UgYGZhbHNlYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5ldmVyeShbdHJ1ZSwgMSwgbnVsbCwgJ3llcyddKTtcbiAgICAgKiAvLyA9PiBmYWxzZVxuICAgICAqXG4gICAgICogdmFyIGNoYXJhY3RlcnMgPSBbXG4gICAgICogICB7ICduYW1lJzogJ2Jhcm5leScsICdhZ2UnOiAzNiB9LFxuICAgICAqICAgeyAnbmFtZSc6ICdmcmVkJywgICAnYWdlJzogNDAgfVxuICAgICAqIF07XG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBcIl8ucGx1Y2tcIiBjYWxsYmFjayBzaG9ydGhhbmRcbiAgICAgKiBfLmV2ZXJ5KGNoYXJhY3RlcnMsICdhZ2UnKTtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBcIl8ud2hlcmVcIiBjYWxsYmFjayBzaG9ydGhhbmRcbiAgICAgKiBfLmV2ZXJ5KGNoYXJhY3RlcnMsIHsgJ2FnZSc6IDM2IH0pO1xuICAgICAqIC8vID0+IGZhbHNlXG4gICAgICovXG4gICAgZnVuY3Rpb24gZXZlcnkoY29sbGVjdGlvbiwgY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICAgIHZhciByZXN1bHQgPSB0cnVlO1xuICAgICAgY2FsbGJhY2sgPSBsb2Rhc2guY3JlYXRlQ2FsbGJhY2soY2FsbGJhY2ssIHRoaXNBcmcsIDMpO1xuXG4gICAgICB2YXIgaW5kZXggPSAtMSxcbiAgICAgICAgICBsZW5ndGggPSBjb2xsZWN0aW9uID8gY29sbGVjdGlvbi5sZW5ndGggOiAwO1xuXG4gICAgICBpZiAodHlwZW9mIGxlbmd0aCA9PSAnbnVtYmVyJykge1xuICAgICAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgICAgIGlmICghKHJlc3VsdCA9ICEhY2FsbGJhY2soY29sbGVjdGlvbltpbmRleF0sIGluZGV4LCBjb2xsZWN0aW9uKSkpIHtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZm9yT3duKGNvbGxlY3Rpb24sIGZ1bmN0aW9uKHZhbHVlLCBpbmRleCwgY29sbGVjdGlvbikge1xuICAgICAgICAgIHJldHVybiAocmVzdWx0ID0gISFjYWxsYmFjayh2YWx1ZSwgaW5kZXgsIGNvbGxlY3Rpb24pKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEl0ZXJhdGVzIG92ZXIgZWxlbWVudHMgb2YgYSBjb2xsZWN0aW9uLCByZXR1cm5pbmcgYW4gYXJyYXkgb2YgYWxsIGVsZW1lbnRzXG4gICAgICogdGhlIGNhbGxiYWNrIHJldHVybnMgdHJ1ZXkgZm9yLiBUaGUgY2FsbGJhY2sgaXMgYm91bmQgdG8gYHRoaXNBcmdgIGFuZFxuICAgICAqIGludm9rZWQgd2l0aCB0aHJlZSBhcmd1bWVudHM7ICh2YWx1ZSwgaW5kZXh8a2V5LCBjb2xsZWN0aW9uKS5cbiAgICAgKlxuICAgICAqIElmIGEgcHJvcGVydHkgbmFtZSBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ucGx1Y2tcIiBzdHlsZVxuICAgICAqIGNhbGxiYWNrIHdpbGwgcmV0dXJuIHRoZSBwcm9wZXJ0eSB2YWx1ZSBvZiB0aGUgZ2l2ZW4gZWxlbWVudC5cbiAgICAgKlxuICAgICAqIElmIGFuIG9iamVjdCBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFja1xuICAgICAqIHdpbGwgcmV0dXJuIGB0cnVlYCBmb3IgZWxlbWVudHMgdGhhdCBoYXZlIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBnaXZlbiBvYmplY3QsXG4gICAgICogZWxzZSBgZmFsc2VgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGFsaWFzIHNlbGVjdFxuICAgICAqIEBjYXRlZ29yeSBDb2xsZWN0aW9uc1xuICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fHN0cmluZ30gY29sbGVjdGlvbiBUaGUgY29sbGVjdGlvbiB0byBpdGVyYXRlIG92ZXIuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbnxPYmplY3R8c3RyaW5nfSBbY2FsbGJhY2s9aWRlbnRpdHldIFRoZSBmdW5jdGlvbiBjYWxsZWRcbiAgICAgKiAgcGVyIGl0ZXJhdGlvbi4gSWYgYSBwcm9wZXJ0eSBuYW1lIG9yIG9iamVjdCBpcyBwcm92aWRlZCBpdCB3aWxsIGJlIHVzZWRcbiAgICAgKiAgdG8gY3JlYXRlIGEgXCJfLnBsdWNrXCIgb3IgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2ssIHJlc3BlY3RpdmVseS5cbiAgICAgKiBAcGFyYW0geyp9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7QXJyYXl9IFJldHVybnMgYSBuZXcgYXJyYXkgb2YgZWxlbWVudHMgdGhhdCBwYXNzZWQgdGhlIGNhbGxiYWNrIGNoZWNrLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgZXZlbnMgPSBfLmZpbHRlcihbMSwgMiwgMywgNCwgNSwgNl0sIGZ1bmN0aW9uKG51bSkgeyByZXR1cm4gbnVtICUgMiA9PSAwOyB9KTtcbiAgICAgKiAvLyA9PiBbMiwgNCwgNl1cbiAgICAgKlxuICAgICAqIHZhciBjaGFyYWN0ZXJzID0gW1xuICAgICAqICAgeyAnbmFtZSc6ICdiYXJuZXknLCAnYWdlJzogMzYsICdibG9ja2VkJzogZmFsc2UgfSxcbiAgICAgKiAgIHsgJ25hbWUnOiAnZnJlZCcsICAgJ2FnZSc6IDQwLCAnYmxvY2tlZCc6IHRydWUgfVxuICAgICAqIF07XG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBcIl8ucGx1Y2tcIiBjYWxsYmFjayBzaG9ydGhhbmRcbiAgICAgKiBfLmZpbHRlcihjaGFyYWN0ZXJzLCAnYmxvY2tlZCcpO1xuICAgICAqIC8vID0+IFt7ICduYW1lJzogJ2ZyZWQnLCAnYWdlJzogNDAsICdibG9ja2VkJzogdHJ1ZSB9XVxuICAgICAqXG4gICAgICogLy8gdXNpbmcgXCJfLndoZXJlXCIgY2FsbGJhY2sgc2hvcnRoYW5kXG4gICAgICogXy5maWx0ZXIoY2hhcmFjdGVycywgeyAnYWdlJzogMzYgfSk7XG4gICAgICogLy8gPT4gW3sgJ25hbWUnOiAnYmFybmV5JywgJ2FnZSc6IDM2LCAnYmxvY2tlZCc6IGZhbHNlIH1dXG4gICAgICovXG4gICAgZnVuY3Rpb24gZmlsdGVyKGNvbGxlY3Rpb24sIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICB2YXIgcmVzdWx0ID0gW107XG4gICAgICBjYWxsYmFjayA9IGxvZGFzaC5jcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZywgMyk7XG5cbiAgICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICAgIGxlbmd0aCA9IGNvbGxlY3Rpb24gPyBjb2xsZWN0aW9uLmxlbmd0aCA6IDA7XG5cbiAgICAgIGlmICh0eXBlb2YgbGVuZ3RoID09ICdudW1iZXInKSB7XG4gICAgICAgIHdoaWxlICgrK2luZGV4IDwgbGVuZ3RoKSB7XG4gICAgICAgICAgdmFyIHZhbHVlID0gY29sbGVjdGlvbltpbmRleF07XG4gICAgICAgICAgaWYgKGNhbGxiYWNrKHZhbHVlLCBpbmRleCwgY29sbGVjdGlvbikpIHtcbiAgICAgICAgICAgIHJlc3VsdC5wdXNoKHZhbHVlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGZvck93bihjb2xsZWN0aW9uLCBmdW5jdGlvbih2YWx1ZSwgaW5kZXgsIGNvbGxlY3Rpb24pIHtcbiAgICAgICAgICBpZiAoY2FsbGJhY2sodmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKSkge1xuICAgICAgICAgICAgcmVzdWx0LnB1c2godmFsdWUpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEl0ZXJhdGVzIG92ZXIgZWxlbWVudHMgb2YgYSBjb2xsZWN0aW9uLCByZXR1cm5pbmcgdGhlIGZpcnN0IGVsZW1lbnQgdGhhdFxuICAgICAqIHRoZSBjYWxsYmFjayByZXR1cm5zIHRydWV5IGZvci4gVGhlIGNhbGxiYWNrIGlzIGJvdW5kIHRvIGB0aGlzQXJnYCBhbmRcbiAgICAgKiBpbnZva2VkIHdpdGggdGhyZWUgYXJndW1lbnRzOyAodmFsdWUsIGluZGV4fGtleSwgY29sbGVjdGlvbikuXG4gICAgICpcbiAgICAgKiBJZiBhIHByb3BlcnR5IG5hbWUgaXMgcHJvdmlkZWQgZm9yIGBjYWxsYmFja2AgdGhlIGNyZWF0ZWQgXCJfLnBsdWNrXCIgc3R5bGVcbiAgICAgKiBjYWxsYmFjayB3aWxsIHJldHVybiB0aGUgcHJvcGVydHkgdmFsdWUgb2YgdGhlIGdpdmVuIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBJZiBhbiBvYmplY3QgaXMgcHJvdmlkZWQgZm9yIGBjYWxsYmFja2AgdGhlIGNyZWF0ZWQgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2tcbiAgICAgKiB3aWxsIHJldHVybiBgdHJ1ZWAgZm9yIGVsZW1lbnRzIHRoYXQgaGF2ZSB0aGUgcHJvcGVydGllcyBvZiB0aGUgZ2l2ZW4gb2JqZWN0LFxuICAgICAqIGVsc2UgYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBhbGlhcyBkZXRlY3QsIGZpbmRXaGVyZVxuICAgICAqIEBjYXRlZ29yeSBDb2xsZWN0aW9uc1xuICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fHN0cmluZ30gY29sbGVjdGlvbiBUaGUgY29sbGVjdGlvbiB0byBpdGVyYXRlIG92ZXIuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbnxPYmplY3R8c3RyaW5nfSBbY2FsbGJhY2s9aWRlbnRpdHldIFRoZSBmdW5jdGlvbiBjYWxsZWRcbiAgICAgKiAgcGVyIGl0ZXJhdGlvbi4gSWYgYSBwcm9wZXJ0eSBuYW1lIG9yIG9iamVjdCBpcyBwcm92aWRlZCBpdCB3aWxsIGJlIHVzZWRcbiAgICAgKiAgdG8gY3JlYXRlIGEgXCJfLnBsdWNrXCIgb3IgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2ssIHJlc3BlY3RpdmVseS5cbiAgICAgKiBAcGFyYW0geyp9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7Kn0gUmV0dXJucyB0aGUgZm91bmQgZWxlbWVudCwgZWxzZSBgdW5kZWZpbmVkYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIGNoYXJhY3RlcnMgPSBbXG4gICAgICogICB7ICduYW1lJzogJ2Jhcm5leScsICAnYWdlJzogMzYsICdibG9ja2VkJzogZmFsc2UgfSxcbiAgICAgKiAgIHsgJ25hbWUnOiAnZnJlZCcsICAgICdhZ2UnOiA0MCwgJ2Jsb2NrZWQnOiB0cnVlIH0sXG4gICAgICogICB7ICduYW1lJzogJ3BlYmJsZXMnLCAnYWdlJzogMSwgICdibG9ja2VkJzogZmFsc2UgfVxuICAgICAqIF07XG4gICAgICpcbiAgICAgKiBfLmZpbmQoY2hhcmFjdGVycywgZnVuY3Rpb24oY2hyKSB7XG4gICAgICogICByZXR1cm4gY2hyLmFnZSA8IDQwO1xuICAgICAqIH0pO1xuICAgICAqIC8vID0+IHsgJ25hbWUnOiAnYmFybmV5JywgJ2FnZSc6IDM2LCAnYmxvY2tlZCc6IGZhbHNlIH1cbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIFwiXy53aGVyZVwiIGNhbGxiYWNrIHNob3J0aGFuZFxuICAgICAqIF8uZmluZChjaGFyYWN0ZXJzLCB7ICdhZ2UnOiAxIH0pO1xuICAgICAqIC8vID0+ICB7ICduYW1lJzogJ3BlYmJsZXMnLCAnYWdlJzogMSwgJ2Jsb2NrZWQnOiBmYWxzZSB9XG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBcIl8ucGx1Y2tcIiBjYWxsYmFjayBzaG9ydGhhbmRcbiAgICAgKiBfLmZpbmQoY2hhcmFjdGVycywgJ2Jsb2NrZWQnKTtcbiAgICAgKiAvLyA9PiB7ICduYW1lJzogJ2ZyZWQnLCAnYWdlJzogNDAsICdibG9ja2VkJzogdHJ1ZSB9XG4gICAgICovXG4gICAgZnVuY3Rpb24gZmluZChjb2xsZWN0aW9uLCBjYWxsYmFjaywgdGhpc0FyZykge1xuICAgICAgY2FsbGJhY2sgPSBsb2Rhc2guY3JlYXRlQ2FsbGJhY2soY2FsbGJhY2ssIHRoaXNBcmcsIDMpO1xuXG4gICAgICB2YXIgaW5kZXggPSAtMSxcbiAgICAgICAgICBsZW5ndGggPSBjb2xsZWN0aW9uID8gY29sbGVjdGlvbi5sZW5ndGggOiAwO1xuXG4gICAgICBpZiAodHlwZW9mIGxlbmd0aCA9PSAnbnVtYmVyJykge1xuICAgICAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgICAgIHZhciB2YWx1ZSA9IGNvbGxlY3Rpb25baW5kZXhdO1xuICAgICAgICAgIGlmIChjYWxsYmFjayh2YWx1ZSwgaW5kZXgsIGNvbGxlY3Rpb24pKSB7XG4gICAgICAgICAgICByZXR1cm4gdmFsdWU7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2YXIgcmVzdWx0O1xuICAgICAgICBmb3JPd24oY29sbGVjdGlvbiwgZnVuY3Rpb24odmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKSB7XG4gICAgICAgICAgaWYgKGNhbGxiYWNrKHZhbHVlLCBpbmRleCwgY29sbGVjdGlvbikpIHtcbiAgICAgICAgICAgIHJlc3VsdCA9IHZhbHVlO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhpcyBtZXRob2QgaXMgbGlrZSBgXy5maW5kYCBleGNlcHQgdGhhdCBpdCBpdGVyYXRlcyBvdmVyIGVsZW1lbnRzXG4gICAgICogb2YgYSBgY29sbGVjdGlvbmAgZnJvbSByaWdodCB0byBsZWZ0LlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IENvbGxlY3Rpb25zXG4gICAgICogQHBhcmFtIHtBcnJheXxPYmplY3R8c3RyaW5nfSBjb2xsZWN0aW9uIFRoZSBjb2xsZWN0aW9uIHRvIGl0ZXJhdGUgb3Zlci5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufE9iamVjdHxzdHJpbmd9IFtjYWxsYmFjaz1pZGVudGl0eV0gVGhlIGZ1bmN0aW9uIGNhbGxlZFxuICAgICAqICBwZXIgaXRlcmF0aW9uLiBJZiBhIHByb3BlcnR5IG5hbWUgb3Igb2JqZWN0IGlzIHByb3ZpZGVkIGl0IHdpbGwgYmUgdXNlZFxuICAgICAqICB0byBjcmVhdGUgYSBcIl8ucGx1Y2tcIiBvciBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFjaywgcmVzcGVjdGl2ZWx5LlxuICAgICAqIEBwYXJhbSB7Kn0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHsqfSBSZXR1cm5zIHRoZSBmb3VuZCBlbGVtZW50LCBlbHNlIGB1bmRlZmluZWRgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLmZpbmRMYXN0KFsxLCAyLCAzLCA0XSwgZnVuY3Rpb24obnVtKSB7XG4gICAgICogICByZXR1cm4gbnVtICUgMiA9PSAxO1xuICAgICAqIH0pO1xuICAgICAqIC8vID0+IDNcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBmaW5kTGFzdChjb2xsZWN0aW9uLCBjYWxsYmFjaywgdGhpc0FyZykge1xuICAgICAgdmFyIHJlc3VsdDtcbiAgICAgIGNhbGxiYWNrID0gbG9kYXNoLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnLCAzKTtcbiAgICAgIGZvckVhY2hSaWdodChjb2xsZWN0aW9uLCBmdW5jdGlvbih2YWx1ZSwgaW5kZXgsIGNvbGxlY3Rpb24pIHtcbiAgICAgICAgaWYgKGNhbGxiYWNrKHZhbHVlLCBpbmRleCwgY29sbGVjdGlvbikpIHtcbiAgICAgICAgICByZXN1bHQgPSB2YWx1ZTtcbiAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBJdGVyYXRlcyBvdmVyIGVsZW1lbnRzIG9mIGEgY29sbGVjdGlvbiwgZXhlY3V0aW5nIHRoZSBjYWxsYmFjayBmb3IgZWFjaFxuICAgICAqIGVsZW1lbnQuIFRoZSBjYWxsYmFjayBpcyBib3VuZCB0byBgdGhpc0FyZ2AgYW5kIGludm9rZWQgd2l0aCB0aHJlZSBhcmd1bWVudHM7XG4gICAgICogKHZhbHVlLCBpbmRleHxrZXksIGNvbGxlY3Rpb24pLiBDYWxsYmFja3MgbWF5IGV4aXQgaXRlcmF0aW9uIGVhcmx5IGJ5XG4gICAgICogZXhwbGljaXRseSByZXR1cm5pbmcgYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIE5vdGU6IEFzIHdpdGggb3RoZXIgXCJDb2xsZWN0aW9uc1wiIG1ldGhvZHMsIG9iamVjdHMgd2l0aCBhIGBsZW5ndGhgIHByb3BlcnR5XG4gICAgICogYXJlIGl0ZXJhdGVkIGxpa2UgYXJyYXlzLiBUbyBhdm9pZCB0aGlzIGJlaGF2aW9yIGBfLmZvckluYCBvciBgXy5mb3JPd25gXG4gICAgICogbWF5IGJlIHVzZWQgZm9yIG9iamVjdCBpdGVyYXRpb24uXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAYWxpYXMgZWFjaFxuICAgICAqIEBjYXRlZ29yeSBDb2xsZWN0aW9uc1xuICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fHN0cmluZ30gY29sbGVjdGlvbiBUaGUgY29sbGVjdGlvbiB0byBpdGVyYXRlIG92ZXIuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gW2NhbGxiYWNrPWlkZW50aXR5XSBUaGUgZnVuY3Rpb24gY2FsbGVkIHBlciBpdGVyYXRpb24uXG4gICAgICogQHBhcmFtIHsqfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHJldHVybnMge0FycmF5fE9iamVjdHxzdHJpbmd9IFJldHVybnMgYGNvbGxlY3Rpb25gLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfKFsxLCAyLCAzXSkuZm9yRWFjaChmdW5jdGlvbihudW0pIHsgY29uc29sZS5sb2cobnVtKTsgfSkuam9pbignLCcpO1xuICAgICAqIC8vID0+IGxvZ3MgZWFjaCBudW1iZXIgYW5kIHJldHVybnMgJzEsMiwzJ1xuICAgICAqXG4gICAgICogXy5mb3JFYWNoKHsgJ29uZSc6IDEsICd0d28nOiAyLCAndGhyZWUnOiAzIH0sIGZ1bmN0aW9uKG51bSkgeyBjb25zb2xlLmxvZyhudW0pOyB9KTtcbiAgICAgKiAvLyA9PiBsb2dzIGVhY2ggbnVtYmVyIGFuZCByZXR1cm5zIHRoZSBvYmplY3QgKHByb3BlcnR5IG9yZGVyIGlzIG5vdCBndWFyYW50ZWVkIGFjcm9zcyBlbnZpcm9ubWVudHMpXG4gICAgICovXG4gICAgZnVuY3Rpb24gZm9yRWFjaChjb2xsZWN0aW9uLCBjYWxsYmFjaywgdGhpc0FyZykge1xuICAgICAgdmFyIGluZGV4ID0gLTEsXG4gICAgICAgICAgbGVuZ3RoID0gY29sbGVjdGlvbiA/IGNvbGxlY3Rpb24ubGVuZ3RoIDogMDtcblxuICAgICAgY2FsbGJhY2sgPSBjYWxsYmFjayAmJiB0eXBlb2YgdGhpc0FyZyA9PSAndW5kZWZpbmVkJyA/IGNhbGxiYWNrIDogYmFzZUNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnLCAzKTtcbiAgICAgIGlmICh0eXBlb2YgbGVuZ3RoID09ICdudW1iZXInKSB7XG4gICAgICAgIHdoaWxlICgrK2luZGV4IDwgbGVuZ3RoKSB7XG4gICAgICAgICAgaWYgKGNhbGxiYWNrKGNvbGxlY3Rpb25baW5kZXhdLCBpbmRleCwgY29sbGVjdGlvbikgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGZvck93bihjb2xsZWN0aW9uLCBjYWxsYmFjayk7XG4gICAgICB9XG4gICAgICByZXR1cm4gY29sbGVjdGlvbjtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGlzIG1ldGhvZCBpcyBsaWtlIGBfLmZvckVhY2hgIGV4Y2VwdCB0aGF0IGl0IGl0ZXJhdGVzIG92ZXIgZWxlbWVudHNcbiAgICAgKiBvZiBhIGBjb2xsZWN0aW9uYCBmcm9tIHJpZ2h0IHRvIGxlZnQuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAYWxpYXMgZWFjaFJpZ2h0XG4gICAgICogQGNhdGVnb3J5IENvbGxlY3Rpb25zXG4gICAgICogQHBhcmFtIHtBcnJheXxPYmplY3R8c3RyaW5nfSBjb2xsZWN0aW9uIFRoZSBjb2xsZWN0aW9uIHRvIGl0ZXJhdGUgb3Zlci5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBbY2FsbGJhY2s9aWRlbnRpdHldIFRoZSBmdW5jdGlvbiBjYWxsZWQgcGVyIGl0ZXJhdGlvbi5cbiAgICAgKiBAcGFyYW0geyp9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7QXJyYXl8T2JqZWN0fHN0cmluZ30gUmV0dXJucyBgY29sbGVjdGlvbmAuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8oWzEsIDIsIDNdKS5mb3JFYWNoUmlnaHQoZnVuY3Rpb24obnVtKSB7IGNvbnNvbGUubG9nKG51bSk7IH0pLmpvaW4oJywnKTtcbiAgICAgKiAvLyA9PiBsb2dzIGVhY2ggbnVtYmVyIGZyb20gcmlnaHQgdG8gbGVmdCBhbmQgcmV0dXJucyAnMywyLDEnXG4gICAgICovXG4gICAgZnVuY3Rpb24gZm9yRWFjaFJpZ2h0KGNvbGxlY3Rpb24sIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICB2YXIgbGVuZ3RoID0gY29sbGVjdGlvbiA/IGNvbGxlY3Rpb24ubGVuZ3RoIDogMDtcbiAgICAgIGNhbGxiYWNrID0gY2FsbGJhY2sgJiYgdHlwZW9mIHRoaXNBcmcgPT0gJ3VuZGVmaW5lZCcgPyBjYWxsYmFjayA6IGJhc2VDcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZywgMyk7XG4gICAgICBpZiAodHlwZW9mIGxlbmd0aCA9PSAnbnVtYmVyJykge1xuICAgICAgICB3aGlsZSAobGVuZ3RoLS0pIHtcbiAgICAgICAgICBpZiAoY2FsbGJhY2soY29sbGVjdGlvbltsZW5ndGhdLCBsZW5ndGgsIGNvbGxlY3Rpb24pID09PSBmYWxzZSkge1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2YXIgcHJvcHMgPSBrZXlzKGNvbGxlY3Rpb24pO1xuICAgICAgICBsZW5ndGggPSBwcm9wcy5sZW5ndGg7XG4gICAgICAgIGZvck93bihjb2xsZWN0aW9uLCBmdW5jdGlvbih2YWx1ZSwga2V5LCBjb2xsZWN0aW9uKSB7XG4gICAgICAgICAga2V5ID0gcHJvcHMgPyBwcm9wc1stLWxlbmd0aF0gOiAtLWxlbmd0aDtcbiAgICAgICAgICByZXR1cm4gY2FsbGJhY2soY29sbGVjdGlvbltrZXldLCBrZXksIGNvbGxlY3Rpb24pO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBjb2xsZWN0aW9uO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW4gb2JqZWN0IGNvbXBvc2VkIG9mIGtleXMgZ2VuZXJhdGVkIGZyb20gdGhlIHJlc3VsdHMgb2YgcnVubmluZ1xuICAgICAqIGVhY2ggZWxlbWVudCBvZiBhIGNvbGxlY3Rpb24gdGhyb3VnaCB0aGUgY2FsbGJhY2suIFRoZSBjb3JyZXNwb25kaW5nIHZhbHVlXG4gICAgICogb2YgZWFjaCBrZXkgaXMgYW4gYXJyYXkgb2YgdGhlIGVsZW1lbnRzIHJlc3BvbnNpYmxlIGZvciBnZW5lcmF0aW5nIHRoZSBrZXkuXG4gICAgICogVGhlIGNhbGxiYWNrIGlzIGJvdW5kIHRvIGB0aGlzQXJnYCBhbmQgaW52b2tlZCB3aXRoIHRocmVlIGFyZ3VtZW50cztcbiAgICAgKiAodmFsdWUsIGluZGV4fGtleSwgY29sbGVjdGlvbikuXG4gICAgICpcbiAgICAgKiBJZiBhIHByb3BlcnR5IG5hbWUgaXMgcHJvdmlkZWQgZm9yIGBjYWxsYmFja2AgdGhlIGNyZWF0ZWQgXCJfLnBsdWNrXCIgc3R5bGVcbiAgICAgKiBjYWxsYmFjayB3aWxsIHJldHVybiB0aGUgcHJvcGVydHkgdmFsdWUgb2YgdGhlIGdpdmVuIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBJZiBhbiBvYmplY3QgaXMgcHJvdmlkZWQgZm9yIGBjYWxsYmFja2AgdGhlIGNyZWF0ZWQgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2tcbiAgICAgKiB3aWxsIHJldHVybiBgdHJ1ZWAgZm9yIGVsZW1lbnRzIHRoYXQgaGF2ZSB0aGUgcHJvcGVydGllcyBvZiB0aGUgZ2l2ZW4gb2JqZWN0LFxuICAgICAqIGVsc2UgYGZhbHNlYFxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IENvbGxlY3Rpb25zXG4gICAgICogQHBhcmFtIHtBcnJheXxPYmplY3R8c3RyaW5nfSBjb2xsZWN0aW9uIFRoZSBjb2xsZWN0aW9uIHRvIGl0ZXJhdGUgb3Zlci5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufE9iamVjdHxzdHJpbmd9IFtjYWxsYmFjaz1pZGVudGl0eV0gVGhlIGZ1bmN0aW9uIGNhbGxlZFxuICAgICAqICBwZXIgaXRlcmF0aW9uLiBJZiBhIHByb3BlcnR5IG5hbWUgb3Igb2JqZWN0IGlzIHByb3ZpZGVkIGl0IHdpbGwgYmUgdXNlZFxuICAgICAqICB0byBjcmVhdGUgYSBcIl8ucGx1Y2tcIiBvciBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFjaywgcmVzcGVjdGl2ZWx5LlxuICAgICAqIEBwYXJhbSB7Kn0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHtPYmplY3R9IFJldHVybnMgdGhlIGNvbXBvc2VkIGFnZ3JlZ2F0ZSBvYmplY3QuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uZ3JvdXBCeShbNC4yLCA2LjEsIDYuNF0sIGZ1bmN0aW9uKG51bSkgeyByZXR1cm4gTWF0aC5mbG9vcihudW0pOyB9KTtcbiAgICAgKiAvLyA9PiB7ICc0JzogWzQuMl0sICc2JzogWzYuMSwgNi40XSB9XG4gICAgICpcbiAgICAgKiBfLmdyb3VwQnkoWzQuMiwgNi4xLCA2LjRdLCBmdW5jdGlvbihudW0pIHsgcmV0dXJuIHRoaXMuZmxvb3IobnVtKTsgfSwgTWF0aCk7XG4gICAgICogLy8gPT4geyAnNCc6IFs0LjJdLCAnNic6IFs2LjEsIDYuNF0gfVxuICAgICAqXG4gICAgICogLy8gdXNpbmcgXCJfLnBsdWNrXCIgY2FsbGJhY2sgc2hvcnRoYW5kXG4gICAgICogXy5ncm91cEJ5KFsnb25lJywgJ3R3bycsICd0aHJlZSddLCAnbGVuZ3RoJyk7XG4gICAgICogLy8gPT4geyAnMyc6IFsnb25lJywgJ3R3byddLCAnNSc6IFsndGhyZWUnXSB9XG4gICAgICovXG4gICAgdmFyIGdyb3VwQnkgPSBjcmVhdGVBZ2dyZWdhdG9yKGZ1bmN0aW9uKHJlc3VsdCwgdmFsdWUsIGtleSkge1xuICAgICAgKGhhc093blByb3BlcnR5LmNhbGwocmVzdWx0LCBrZXkpID8gcmVzdWx0W2tleV0gOiByZXN1bHRba2V5XSA9IFtdKS5wdXNoKHZhbHVlKTtcbiAgICB9KTtcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW4gb2JqZWN0IGNvbXBvc2VkIG9mIGtleXMgZ2VuZXJhdGVkIGZyb20gdGhlIHJlc3VsdHMgb2YgcnVubmluZ1xuICAgICAqIGVhY2ggZWxlbWVudCBvZiB0aGUgY29sbGVjdGlvbiB0aHJvdWdoIHRoZSBnaXZlbiBjYWxsYmFjay4gVGhlIGNvcnJlc3BvbmRpbmdcbiAgICAgKiB2YWx1ZSBvZiBlYWNoIGtleSBpcyB0aGUgbGFzdCBlbGVtZW50IHJlc3BvbnNpYmxlIGZvciBnZW5lcmF0aW5nIHRoZSBrZXkuXG4gICAgICogVGhlIGNhbGxiYWNrIGlzIGJvdW5kIHRvIGB0aGlzQXJnYCBhbmQgaW52b2tlZCB3aXRoIHRocmVlIGFyZ3VtZW50cztcbiAgICAgKiAodmFsdWUsIGluZGV4fGtleSwgY29sbGVjdGlvbikuXG4gICAgICpcbiAgICAgKiBJZiBhIHByb3BlcnR5IG5hbWUgaXMgcHJvdmlkZWQgZm9yIGBjYWxsYmFja2AgdGhlIGNyZWF0ZWQgXCJfLnBsdWNrXCIgc3R5bGVcbiAgICAgKiBjYWxsYmFjayB3aWxsIHJldHVybiB0aGUgcHJvcGVydHkgdmFsdWUgb2YgdGhlIGdpdmVuIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBJZiBhbiBvYmplY3QgaXMgcHJvdmlkZWQgZm9yIGBjYWxsYmFja2AgdGhlIGNyZWF0ZWQgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2tcbiAgICAgKiB3aWxsIHJldHVybiBgdHJ1ZWAgZm9yIGVsZW1lbnRzIHRoYXQgaGF2ZSB0aGUgcHJvcGVydGllcyBvZiB0aGUgZ2l2ZW4gb2JqZWN0LFxuICAgICAqIGVsc2UgYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBDb2xsZWN0aW9uc1xuICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fHN0cmluZ30gY29sbGVjdGlvbiBUaGUgY29sbGVjdGlvbiB0byBpdGVyYXRlIG92ZXIuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbnxPYmplY3R8c3RyaW5nfSBbY2FsbGJhY2s9aWRlbnRpdHldIFRoZSBmdW5jdGlvbiBjYWxsZWRcbiAgICAgKiAgcGVyIGl0ZXJhdGlvbi4gSWYgYSBwcm9wZXJ0eSBuYW1lIG9yIG9iamVjdCBpcyBwcm92aWRlZCBpdCB3aWxsIGJlIHVzZWRcbiAgICAgKiAgdG8gY3JlYXRlIGEgXCJfLnBsdWNrXCIgb3IgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2ssIHJlc3BlY3RpdmVseS5cbiAgICAgKiBAcGFyYW0geyp9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSBSZXR1cm5zIHRoZSBjb21wb3NlZCBhZ2dyZWdhdGUgb2JqZWN0LlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIga2V5cyA9IFtcbiAgICAgKiAgIHsgJ2Rpcic6ICdsZWZ0JywgJ2NvZGUnOiA5NyB9LFxuICAgICAqICAgeyAnZGlyJzogJ3JpZ2h0JywgJ2NvZGUnOiAxMDAgfVxuICAgICAqIF07XG4gICAgICpcbiAgICAgKiBfLmluZGV4Qnkoa2V5cywgJ2RpcicpO1xuICAgICAqIC8vID0+IHsgJ2xlZnQnOiB7ICdkaXInOiAnbGVmdCcsICdjb2RlJzogOTcgfSwgJ3JpZ2h0JzogeyAnZGlyJzogJ3JpZ2h0JywgJ2NvZGUnOiAxMDAgfSB9XG4gICAgICpcbiAgICAgKiBfLmluZGV4Qnkoa2V5cywgZnVuY3Rpb24oa2V5KSB7IHJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlKGtleS5jb2RlKTsgfSk7XG4gICAgICogLy8gPT4geyAnYSc6IHsgJ2Rpcic6ICdsZWZ0JywgJ2NvZGUnOiA5NyB9LCAnZCc6IHsgJ2Rpcic6ICdyaWdodCcsICdjb2RlJzogMTAwIH0gfVxuICAgICAqXG4gICAgICogXy5pbmRleEJ5KGNoYXJhY3RlcnMsIGZ1bmN0aW9uKGtleSkgeyB0aGlzLmZyb21DaGFyQ29kZShrZXkuY29kZSk7IH0sIFN0cmluZyk7XG4gICAgICogLy8gPT4geyAnYSc6IHsgJ2Rpcic6ICdsZWZ0JywgJ2NvZGUnOiA5NyB9LCAnZCc6IHsgJ2Rpcic6ICdyaWdodCcsICdjb2RlJzogMTAwIH0gfVxuICAgICAqL1xuICAgIHZhciBpbmRleEJ5ID0gY3JlYXRlQWdncmVnYXRvcihmdW5jdGlvbihyZXN1bHQsIHZhbHVlLCBrZXkpIHtcbiAgICAgIHJlc3VsdFtrZXldID0gdmFsdWU7XG4gICAgfSk7XG5cbiAgICAvKipcbiAgICAgKiBJbnZva2VzIHRoZSBtZXRob2QgbmFtZWQgYnkgYG1ldGhvZE5hbWVgIG9uIGVhY2ggZWxlbWVudCBpbiB0aGUgYGNvbGxlY3Rpb25gXG4gICAgICogcmV0dXJuaW5nIGFuIGFycmF5IG9mIHRoZSByZXN1bHRzIG9mIGVhY2ggaW52b2tlZCBtZXRob2QuIEFkZGl0aW9uYWwgYXJndW1lbnRzXG4gICAgICogd2lsbCBiZSBwcm92aWRlZCB0byBlYWNoIGludm9rZWQgbWV0aG9kLiBJZiBgbWV0aG9kTmFtZWAgaXMgYSBmdW5jdGlvbiBpdFxuICAgICAqIHdpbGwgYmUgaW52b2tlZCBmb3IsIGFuZCBgdGhpc2AgYm91bmQgdG8sIGVhY2ggZWxlbWVudCBpbiB0aGUgYGNvbGxlY3Rpb25gLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IENvbGxlY3Rpb25zXG4gICAgICogQHBhcmFtIHtBcnJheXxPYmplY3R8c3RyaW5nfSBjb2xsZWN0aW9uIFRoZSBjb2xsZWN0aW9uIHRvIGl0ZXJhdGUgb3Zlci5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufHN0cmluZ30gbWV0aG9kTmFtZSBUaGUgbmFtZSBvZiB0aGUgbWV0aG9kIHRvIGludm9rZSBvclxuICAgICAqICB0aGUgZnVuY3Rpb24gaW52b2tlZCBwZXIgaXRlcmF0aW9uLlxuICAgICAqIEBwYXJhbSB7Li4uKn0gW2FyZ10gQXJndW1lbnRzIHRvIGludm9rZSB0aGUgbWV0aG9kIHdpdGguXG4gICAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIGEgbmV3IGFycmF5IG9mIHRoZSByZXN1bHRzIG9mIGVhY2ggaW52b2tlZCBtZXRob2QuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uaW52b2tlKFtbNSwgMSwgN10sIFszLCAyLCAxXV0sICdzb3J0Jyk7XG4gICAgICogLy8gPT4gW1sxLCA1LCA3XSwgWzEsIDIsIDNdXVxuICAgICAqXG4gICAgICogXy5pbnZva2UoWzEyMywgNDU2XSwgU3RyaW5nLnByb3RvdHlwZS5zcGxpdCwgJycpO1xuICAgICAqIC8vID0+IFtbJzEnLCAnMicsICczJ10sIFsnNCcsICc1JywgJzYnXV1cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpbnZva2UoY29sbGVjdGlvbiwgbWV0aG9kTmFtZSkge1xuICAgICAgdmFyIGFyZ3MgPSBzbGljZShhcmd1bWVudHMsIDIpLFxuICAgICAgICAgIGluZGV4ID0gLTEsXG4gICAgICAgICAgaXNGdW5jID0gdHlwZW9mIG1ldGhvZE5hbWUgPT0gJ2Z1bmN0aW9uJyxcbiAgICAgICAgICBsZW5ndGggPSBjb2xsZWN0aW9uID8gY29sbGVjdGlvbi5sZW5ndGggOiAwLFxuICAgICAgICAgIHJlc3VsdCA9IEFycmF5KHR5cGVvZiBsZW5ndGggPT0gJ251bWJlcicgPyBsZW5ndGggOiAwKTtcblxuICAgICAgZm9yRWFjaChjb2xsZWN0aW9uLCBmdW5jdGlvbih2YWx1ZSkge1xuICAgICAgICByZXN1bHRbKytpbmRleF0gPSAoaXNGdW5jID8gbWV0aG9kTmFtZSA6IHZhbHVlW21ldGhvZE5hbWVdKS5hcHBseSh2YWx1ZSwgYXJncyk7XG4gICAgICB9KTtcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbiBhcnJheSBvZiB2YWx1ZXMgYnkgcnVubmluZyBlYWNoIGVsZW1lbnQgaW4gdGhlIGNvbGxlY3Rpb25cbiAgICAgKiB0aHJvdWdoIHRoZSBjYWxsYmFjay4gVGhlIGNhbGxiYWNrIGlzIGJvdW5kIHRvIGB0aGlzQXJnYCBhbmQgaW52b2tlZCB3aXRoXG4gICAgICogdGhyZWUgYXJndW1lbnRzOyAodmFsdWUsIGluZGV4fGtleSwgY29sbGVjdGlvbikuXG4gICAgICpcbiAgICAgKiBJZiBhIHByb3BlcnR5IG5hbWUgaXMgcHJvdmlkZWQgZm9yIGBjYWxsYmFja2AgdGhlIGNyZWF0ZWQgXCJfLnBsdWNrXCIgc3R5bGVcbiAgICAgKiBjYWxsYmFjayB3aWxsIHJldHVybiB0aGUgcHJvcGVydHkgdmFsdWUgb2YgdGhlIGdpdmVuIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBJZiBhbiBvYmplY3QgaXMgcHJvdmlkZWQgZm9yIGBjYWxsYmFja2AgdGhlIGNyZWF0ZWQgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2tcbiAgICAgKiB3aWxsIHJldHVybiBgdHJ1ZWAgZm9yIGVsZW1lbnRzIHRoYXQgaGF2ZSB0aGUgcHJvcGVydGllcyBvZiB0aGUgZ2l2ZW4gb2JqZWN0LFxuICAgICAqIGVsc2UgYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBhbGlhcyBjb2xsZWN0XG4gICAgICogQGNhdGVnb3J5IENvbGxlY3Rpb25zXG4gICAgICogQHBhcmFtIHtBcnJheXxPYmplY3R8c3RyaW5nfSBjb2xsZWN0aW9uIFRoZSBjb2xsZWN0aW9uIHRvIGl0ZXJhdGUgb3Zlci5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufE9iamVjdHxzdHJpbmd9IFtjYWxsYmFjaz1pZGVudGl0eV0gVGhlIGZ1bmN0aW9uIGNhbGxlZFxuICAgICAqICBwZXIgaXRlcmF0aW9uLiBJZiBhIHByb3BlcnR5IG5hbWUgb3Igb2JqZWN0IGlzIHByb3ZpZGVkIGl0IHdpbGwgYmUgdXNlZFxuICAgICAqICB0byBjcmVhdGUgYSBcIl8ucGx1Y2tcIiBvciBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFjaywgcmVzcGVjdGl2ZWx5LlxuICAgICAqIEBwYXJhbSB7Kn0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyBhIG5ldyBhcnJheSBvZiB0aGUgcmVzdWx0cyBvZiBlYWNoIGBjYWxsYmFja2AgZXhlY3V0aW9uLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLm1hcChbMSwgMiwgM10sIGZ1bmN0aW9uKG51bSkgeyByZXR1cm4gbnVtICogMzsgfSk7XG4gICAgICogLy8gPT4gWzMsIDYsIDldXG4gICAgICpcbiAgICAgKiBfLm1hcCh7ICdvbmUnOiAxLCAndHdvJzogMiwgJ3RocmVlJzogMyB9LCBmdW5jdGlvbihudW0pIHsgcmV0dXJuIG51bSAqIDM7IH0pO1xuICAgICAqIC8vID0+IFszLCA2LCA5XSAocHJvcGVydHkgb3JkZXIgaXMgbm90IGd1YXJhbnRlZWQgYWNyb3NzIGVudmlyb25tZW50cylcbiAgICAgKlxuICAgICAqIHZhciBjaGFyYWN0ZXJzID0gW1xuICAgICAqICAgeyAnbmFtZSc6ICdiYXJuZXknLCAnYWdlJzogMzYgfSxcbiAgICAgKiAgIHsgJ25hbWUnOiAnZnJlZCcsICAgJ2FnZSc6IDQwIH1cbiAgICAgKiBdO1xuICAgICAqXG4gICAgICogLy8gdXNpbmcgXCJfLnBsdWNrXCIgY2FsbGJhY2sgc2hvcnRoYW5kXG4gICAgICogXy5tYXAoY2hhcmFjdGVycywgJ25hbWUnKTtcbiAgICAgKiAvLyA9PiBbJ2Jhcm5leScsICdmcmVkJ11cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBtYXAoY29sbGVjdGlvbiwgY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICAgIGxlbmd0aCA9IGNvbGxlY3Rpb24gPyBjb2xsZWN0aW9uLmxlbmd0aCA6IDA7XG5cbiAgICAgIGNhbGxiYWNrID0gbG9kYXNoLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnLCAzKTtcbiAgICAgIGlmICh0eXBlb2YgbGVuZ3RoID09ICdudW1iZXInKSB7XG4gICAgICAgIHZhciByZXN1bHQgPSBBcnJheShsZW5ndGgpO1xuICAgICAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgICAgIHJlc3VsdFtpbmRleF0gPSBjYWxsYmFjayhjb2xsZWN0aW9uW2luZGV4XSwgaW5kZXgsIGNvbGxlY3Rpb24pO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXN1bHQgPSBbXTtcbiAgICAgICAgZm9yT3duKGNvbGxlY3Rpb24sIGZ1bmN0aW9uKHZhbHVlLCBrZXksIGNvbGxlY3Rpb24pIHtcbiAgICAgICAgICByZXN1bHRbKytpbmRleF0gPSBjYWxsYmFjayh2YWx1ZSwga2V5LCBjb2xsZWN0aW9uKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHJpZXZlcyB0aGUgbWF4aW11bSB2YWx1ZSBvZiBhIGNvbGxlY3Rpb24uIElmIHRoZSBjb2xsZWN0aW9uIGlzIGVtcHR5IG9yXG4gICAgICogZmFsc2V5IGAtSW5maW5pdHlgIGlzIHJldHVybmVkLiBJZiBhIGNhbGxiYWNrIGlzIHByb3ZpZGVkIGl0IHdpbGwgYmUgZXhlY3V0ZWRcbiAgICAgKiBmb3IgZWFjaCB2YWx1ZSBpbiB0aGUgY29sbGVjdGlvbiB0byBnZW5lcmF0ZSB0aGUgY3JpdGVyaW9uIGJ5IHdoaWNoIHRoZSB2YWx1ZVxuICAgICAqIGlzIHJhbmtlZC4gVGhlIGNhbGxiYWNrIGlzIGJvdW5kIHRvIGB0aGlzQXJnYCBhbmQgaW52b2tlZCB3aXRoIHRocmVlXG4gICAgICogYXJndW1lbnRzOyAodmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKS5cbiAgICAgKlxuICAgICAqIElmIGEgcHJvcGVydHkgbmFtZSBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ucGx1Y2tcIiBzdHlsZVxuICAgICAqIGNhbGxiYWNrIHdpbGwgcmV0dXJuIHRoZSBwcm9wZXJ0eSB2YWx1ZSBvZiB0aGUgZ2l2ZW4gZWxlbWVudC5cbiAgICAgKlxuICAgICAqIElmIGFuIG9iamVjdCBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFja1xuICAgICAqIHdpbGwgcmV0dXJuIGB0cnVlYCBmb3IgZWxlbWVudHMgdGhhdCBoYXZlIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBnaXZlbiBvYmplY3QsXG4gICAgICogZWxzZSBgZmFsc2VgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IENvbGxlY3Rpb25zXG4gICAgICogQHBhcmFtIHtBcnJheXxPYmplY3R8c3RyaW5nfSBjb2xsZWN0aW9uIFRoZSBjb2xsZWN0aW9uIHRvIGl0ZXJhdGUgb3Zlci5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufE9iamVjdHxzdHJpbmd9IFtjYWxsYmFjaz1pZGVudGl0eV0gVGhlIGZ1bmN0aW9uIGNhbGxlZFxuICAgICAqICBwZXIgaXRlcmF0aW9uLiBJZiBhIHByb3BlcnR5IG5hbWUgb3Igb2JqZWN0IGlzIHByb3ZpZGVkIGl0IHdpbGwgYmUgdXNlZFxuICAgICAqICB0byBjcmVhdGUgYSBcIl8ucGx1Y2tcIiBvciBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFjaywgcmVzcGVjdGl2ZWx5LlxuICAgICAqIEBwYXJhbSB7Kn0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHsqfSBSZXR1cm5zIHRoZSBtYXhpbXVtIHZhbHVlLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLm1heChbNCwgMiwgOCwgNl0pO1xuICAgICAqIC8vID0+IDhcbiAgICAgKlxuICAgICAqIHZhciBjaGFyYWN0ZXJzID0gW1xuICAgICAqICAgeyAnbmFtZSc6ICdiYXJuZXknLCAnYWdlJzogMzYgfSxcbiAgICAgKiAgIHsgJ25hbWUnOiAnZnJlZCcsICAgJ2FnZSc6IDQwIH1cbiAgICAgKiBdO1xuICAgICAqXG4gICAgICogXy5tYXgoY2hhcmFjdGVycywgZnVuY3Rpb24oY2hyKSB7IHJldHVybiBjaHIuYWdlOyB9KTtcbiAgICAgKiAvLyA9PiB7ICduYW1lJzogJ2ZyZWQnLCAnYWdlJzogNDAgfTtcbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIFwiXy5wbHVja1wiIGNhbGxiYWNrIHNob3J0aGFuZFxuICAgICAqIF8ubWF4KGNoYXJhY3RlcnMsICdhZ2UnKTtcbiAgICAgKiAvLyA9PiB7ICduYW1lJzogJ2ZyZWQnLCAnYWdlJzogNDAgfTtcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBtYXgoY29sbGVjdGlvbiwgY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICAgIHZhciBjb21wdXRlZCA9IC1JbmZpbml0eSxcbiAgICAgICAgICByZXN1bHQgPSBjb21wdXRlZDtcblxuICAgICAgLy8gYWxsb3dzIHdvcmtpbmcgd2l0aCBmdW5jdGlvbnMgbGlrZSBgXy5tYXBgIHdpdGhvdXQgdXNpbmdcbiAgICAgIC8vIHRoZWlyIGBpbmRleGAgYXJndW1lbnQgYXMgYSBjYWxsYmFja1xuICAgICAgaWYgKHR5cGVvZiBjYWxsYmFjayAhPSAnZnVuY3Rpb24nICYmIHRoaXNBcmcgJiYgdGhpc0FyZ1tjYWxsYmFja10gPT09IGNvbGxlY3Rpb24pIHtcbiAgICAgICAgY2FsbGJhY2sgPSBudWxsO1xuICAgICAgfVxuICAgICAgaWYgKGNhbGxiYWNrID09IG51bGwgJiYgaXNBcnJheShjb2xsZWN0aW9uKSkge1xuICAgICAgICB2YXIgaW5kZXggPSAtMSxcbiAgICAgICAgICAgIGxlbmd0aCA9IGNvbGxlY3Rpb24ubGVuZ3RoO1xuXG4gICAgICAgIHdoaWxlICgrK2luZGV4IDwgbGVuZ3RoKSB7XG4gICAgICAgICAgdmFyIHZhbHVlID0gY29sbGVjdGlvbltpbmRleF07XG4gICAgICAgICAgaWYgKHZhbHVlID4gcmVzdWx0KSB7XG4gICAgICAgICAgICByZXN1bHQgPSB2YWx1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNhbGxiYWNrID0gKGNhbGxiYWNrID09IG51bGwgJiYgaXNTdHJpbmcoY29sbGVjdGlvbikpXG4gICAgICAgICAgPyBjaGFyQXRDYWxsYmFja1xuICAgICAgICAgIDogbG9kYXNoLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnLCAzKTtcblxuICAgICAgICBmb3JFYWNoKGNvbGxlY3Rpb24sIGZ1bmN0aW9uKHZhbHVlLCBpbmRleCwgY29sbGVjdGlvbikge1xuICAgICAgICAgIHZhciBjdXJyZW50ID0gY2FsbGJhY2sodmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKTtcbiAgICAgICAgICBpZiAoY3VycmVudCA+IGNvbXB1dGVkKSB7XG4gICAgICAgICAgICBjb21wdXRlZCA9IGN1cnJlbnQ7XG4gICAgICAgICAgICByZXN1bHQgPSB2YWx1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXRyaWV2ZXMgdGhlIG1pbmltdW0gdmFsdWUgb2YgYSBjb2xsZWN0aW9uLiBJZiB0aGUgY29sbGVjdGlvbiBpcyBlbXB0eSBvclxuICAgICAqIGZhbHNleSBgSW5maW5pdHlgIGlzIHJldHVybmVkLiBJZiBhIGNhbGxiYWNrIGlzIHByb3ZpZGVkIGl0IHdpbGwgYmUgZXhlY3V0ZWRcbiAgICAgKiBmb3IgZWFjaCB2YWx1ZSBpbiB0aGUgY29sbGVjdGlvbiB0byBnZW5lcmF0ZSB0aGUgY3JpdGVyaW9uIGJ5IHdoaWNoIHRoZSB2YWx1ZVxuICAgICAqIGlzIHJhbmtlZC4gVGhlIGNhbGxiYWNrIGlzIGJvdW5kIHRvIGB0aGlzQXJnYCBhbmQgaW52b2tlZCB3aXRoIHRocmVlXG4gICAgICogYXJndW1lbnRzOyAodmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKS5cbiAgICAgKlxuICAgICAqIElmIGEgcHJvcGVydHkgbmFtZSBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ucGx1Y2tcIiBzdHlsZVxuICAgICAqIGNhbGxiYWNrIHdpbGwgcmV0dXJuIHRoZSBwcm9wZXJ0eSB2YWx1ZSBvZiB0aGUgZ2l2ZW4gZWxlbWVudC5cbiAgICAgKlxuICAgICAqIElmIGFuIG9iamVjdCBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFja1xuICAgICAqIHdpbGwgcmV0dXJuIGB0cnVlYCBmb3IgZWxlbWVudHMgdGhhdCBoYXZlIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBnaXZlbiBvYmplY3QsXG4gICAgICogZWxzZSBgZmFsc2VgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IENvbGxlY3Rpb25zXG4gICAgICogQHBhcmFtIHtBcnJheXxPYmplY3R8c3RyaW5nfSBjb2xsZWN0aW9uIFRoZSBjb2xsZWN0aW9uIHRvIGl0ZXJhdGUgb3Zlci5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufE9iamVjdHxzdHJpbmd9IFtjYWxsYmFjaz1pZGVudGl0eV0gVGhlIGZ1bmN0aW9uIGNhbGxlZFxuICAgICAqICBwZXIgaXRlcmF0aW9uLiBJZiBhIHByb3BlcnR5IG5hbWUgb3Igb2JqZWN0IGlzIHByb3ZpZGVkIGl0IHdpbGwgYmUgdXNlZFxuICAgICAqICB0byBjcmVhdGUgYSBcIl8ucGx1Y2tcIiBvciBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFjaywgcmVzcGVjdGl2ZWx5LlxuICAgICAqIEBwYXJhbSB7Kn0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHsqfSBSZXR1cm5zIHRoZSBtaW5pbXVtIHZhbHVlLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLm1pbihbNCwgMiwgOCwgNl0pO1xuICAgICAqIC8vID0+IDJcbiAgICAgKlxuICAgICAqIHZhciBjaGFyYWN0ZXJzID0gW1xuICAgICAqICAgeyAnbmFtZSc6ICdiYXJuZXknLCAnYWdlJzogMzYgfSxcbiAgICAgKiAgIHsgJ25hbWUnOiAnZnJlZCcsICAgJ2FnZSc6IDQwIH1cbiAgICAgKiBdO1xuICAgICAqXG4gICAgICogXy5taW4oY2hhcmFjdGVycywgZnVuY3Rpb24oY2hyKSB7IHJldHVybiBjaHIuYWdlOyB9KTtcbiAgICAgKiAvLyA9PiB7ICduYW1lJzogJ2Jhcm5leScsICdhZ2UnOiAzNiB9O1xuICAgICAqXG4gICAgICogLy8gdXNpbmcgXCJfLnBsdWNrXCIgY2FsbGJhY2sgc2hvcnRoYW5kXG4gICAgICogXy5taW4oY2hhcmFjdGVycywgJ2FnZScpO1xuICAgICAqIC8vID0+IHsgJ25hbWUnOiAnYmFybmV5JywgJ2FnZSc6IDM2IH07XG4gICAgICovXG4gICAgZnVuY3Rpb24gbWluKGNvbGxlY3Rpb24sIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICB2YXIgY29tcHV0ZWQgPSBJbmZpbml0eSxcbiAgICAgICAgICByZXN1bHQgPSBjb21wdXRlZDtcblxuICAgICAgLy8gYWxsb3dzIHdvcmtpbmcgd2l0aCBmdW5jdGlvbnMgbGlrZSBgXy5tYXBgIHdpdGhvdXQgdXNpbmdcbiAgICAgIC8vIHRoZWlyIGBpbmRleGAgYXJndW1lbnQgYXMgYSBjYWxsYmFja1xuICAgICAgaWYgKHR5cGVvZiBjYWxsYmFjayAhPSAnZnVuY3Rpb24nICYmIHRoaXNBcmcgJiYgdGhpc0FyZ1tjYWxsYmFja10gPT09IGNvbGxlY3Rpb24pIHtcbiAgICAgICAgY2FsbGJhY2sgPSBudWxsO1xuICAgICAgfVxuICAgICAgaWYgKGNhbGxiYWNrID09IG51bGwgJiYgaXNBcnJheShjb2xsZWN0aW9uKSkge1xuICAgICAgICB2YXIgaW5kZXggPSAtMSxcbiAgICAgICAgICAgIGxlbmd0aCA9IGNvbGxlY3Rpb24ubGVuZ3RoO1xuXG4gICAgICAgIHdoaWxlICgrK2luZGV4IDwgbGVuZ3RoKSB7XG4gICAgICAgICAgdmFyIHZhbHVlID0gY29sbGVjdGlvbltpbmRleF07XG4gICAgICAgICAgaWYgKHZhbHVlIDwgcmVzdWx0KSB7XG4gICAgICAgICAgICByZXN1bHQgPSB2YWx1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNhbGxiYWNrID0gKGNhbGxiYWNrID09IG51bGwgJiYgaXNTdHJpbmcoY29sbGVjdGlvbikpXG4gICAgICAgICAgPyBjaGFyQXRDYWxsYmFja1xuICAgICAgICAgIDogbG9kYXNoLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnLCAzKTtcblxuICAgICAgICBmb3JFYWNoKGNvbGxlY3Rpb24sIGZ1bmN0aW9uKHZhbHVlLCBpbmRleCwgY29sbGVjdGlvbikge1xuICAgICAgICAgIHZhciBjdXJyZW50ID0gY2FsbGJhY2sodmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKTtcbiAgICAgICAgICBpZiAoY3VycmVudCA8IGNvbXB1dGVkKSB7XG4gICAgICAgICAgICBjb21wdXRlZCA9IGN1cnJlbnQ7XG4gICAgICAgICAgICByZXN1bHQgPSB2YWx1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXRyaWV2ZXMgdGhlIHZhbHVlIG9mIGEgc3BlY2lmaWVkIHByb3BlcnR5IGZyb20gYWxsIGVsZW1lbnRzIGluIHRoZSBjb2xsZWN0aW9uLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQHR5cGUgRnVuY3Rpb25cbiAgICAgKiBAY2F0ZWdvcnkgQ29sbGVjdGlvbnNcbiAgICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdHxzdHJpbmd9IGNvbGxlY3Rpb24gVGhlIGNvbGxlY3Rpb24gdG8gaXRlcmF0ZSBvdmVyLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wZXJ0eSBUaGUgbmFtZSBvZiB0aGUgcHJvcGVydHkgdG8gcGx1Y2suXG4gICAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIGEgbmV3IGFycmF5IG9mIHByb3BlcnR5IHZhbHVlcy5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIGNoYXJhY3RlcnMgPSBbXG4gICAgICogICB7ICduYW1lJzogJ2Jhcm5leScsICdhZ2UnOiAzNiB9LFxuICAgICAqICAgeyAnbmFtZSc6ICdmcmVkJywgICAnYWdlJzogNDAgfVxuICAgICAqIF07XG4gICAgICpcbiAgICAgKiBfLnBsdWNrKGNoYXJhY3RlcnMsICduYW1lJyk7XG4gICAgICogLy8gPT4gWydiYXJuZXknLCAnZnJlZCddXG4gICAgICovXG4gICAgdmFyIHBsdWNrID0gbWFwO1xuXG4gICAgLyoqXG4gICAgICogUmVkdWNlcyBhIGNvbGxlY3Rpb24gdG8gYSB2YWx1ZSB3aGljaCBpcyB0aGUgYWNjdW11bGF0ZWQgcmVzdWx0IG9mIHJ1bm5pbmdcbiAgICAgKiBlYWNoIGVsZW1lbnQgaW4gdGhlIGNvbGxlY3Rpb24gdGhyb3VnaCB0aGUgY2FsbGJhY2ssIHdoZXJlIGVhY2ggc3VjY2Vzc2l2ZVxuICAgICAqIGNhbGxiYWNrIGV4ZWN1dGlvbiBjb25zdW1lcyB0aGUgcmV0dXJuIHZhbHVlIG9mIHRoZSBwcmV2aW91cyBleGVjdXRpb24uIElmXG4gICAgICogYGFjY3VtdWxhdG9yYCBpcyBub3QgcHJvdmlkZWQgdGhlIGZpcnN0IGVsZW1lbnQgb2YgdGhlIGNvbGxlY3Rpb24gd2lsbCBiZVxuICAgICAqIHVzZWQgYXMgdGhlIGluaXRpYWwgYGFjY3VtdWxhdG9yYCB2YWx1ZS4gVGhlIGNhbGxiYWNrIGlzIGJvdW5kIHRvIGB0aGlzQXJnYFxuICAgICAqIGFuZCBpbnZva2VkIHdpdGggZm91ciBhcmd1bWVudHM7IChhY2N1bXVsYXRvciwgdmFsdWUsIGluZGV4fGtleSwgY29sbGVjdGlvbikuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAYWxpYXMgZm9sZGwsIGluamVjdFxuICAgICAqIEBjYXRlZ29yeSBDb2xsZWN0aW9uc1xuICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fHN0cmluZ30gY29sbGVjdGlvbiBUaGUgY29sbGVjdGlvbiB0byBpdGVyYXRlIG92ZXIuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gW2NhbGxiYWNrPWlkZW50aXR5XSBUaGUgZnVuY3Rpb24gY2FsbGVkIHBlciBpdGVyYXRpb24uXG4gICAgICogQHBhcmFtIHsqfSBbYWNjdW11bGF0b3JdIEluaXRpYWwgdmFsdWUgb2YgdGhlIGFjY3VtdWxhdG9yLlxuICAgICAqIEBwYXJhbSB7Kn0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHsqfSBSZXR1cm5zIHRoZSBhY2N1bXVsYXRlZCB2YWx1ZS5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIHN1bSA9IF8ucmVkdWNlKFsxLCAyLCAzXSwgZnVuY3Rpb24oc3VtLCBudW0pIHtcbiAgICAgKiAgIHJldHVybiBzdW0gKyBudW07XG4gICAgICogfSk7XG4gICAgICogLy8gPT4gNlxuICAgICAqXG4gICAgICogdmFyIG1hcHBlZCA9IF8ucmVkdWNlKHsgJ2EnOiAxLCAnYic6IDIsICdjJzogMyB9LCBmdW5jdGlvbihyZXN1bHQsIG51bSwga2V5KSB7XG4gICAgICogICByZXN1bHRba2V5XSA9IG51bSAqIDM7XG4gICAgICogICByZXR1cm4gcmVzdWx0O1xuICAgICAqIH0sIHt9KTtcbiAgICAgKiAvLyA9PiB7ICdhJzogMywgJ2InOiA2LCAnYyc6IDkgfVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHJlZHVjZShjb2xsZWN0aW9uLCBjYWxsYmFjaywgYWNjdW11bGF0b3IsIHRoaXNBcmcpIHtcbiAgICAgIGlmICghY29sbGVjdGlvbikgcmV0dXJuIGFjY3VtdWxhdG9yO1xuICAgICAgdmFyIG5vYWNjdW0gPSBhcmd1bWVudHMubGVuZ3RoIDwgMztcbiAgICAgIGNhbGxiYWNrID0gbG9kYXNoLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnLCA0KTtcblxuICAgICAgdmFyIGluZGV4ID0gLTEsXG4gICAgICAgICAgbGVuZ3RoID0gY29sbGVjdGlvbi5sZW5ndGg7XG5cbiAgICAgIGlmICh0eXBlb2YgbGVuZ3RoID09ICdudW1iZXInKSB7XG4gICAgICAgIGlmIChub2FjY3VtKSB7XG4gICAgICAgICAgYWNjdW11bGF0b3IgPSBjb2xsZWN0aW9uWysraW5kZXhdO1xuICAgICAgICB9XG4gICAgICAgIHdoaWxlICgrK2luZGV4IDwgbGVuZ3RoKSB7XG4gICAgICAgICAgYWNjdW11bGF0b3IgPSBjYWxsYmFjayhhY2N1bXVsYXRvciwgY29sbGVjdGlvbltpbmRleF0sIGluZGV4LCBjb2xsZWN0aW9uKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZm9yT3duKGNvbGxlY3Rpb24sIGZ1bmN0aW9uKHZhbHVlLCBpbmRleCwgY29sbGVjdGlvbikge1xuICAgICAgICAgIGFjY3VtdWxhdG9yID0gbm9hY2N1bVxuICAgICAgICAgICAgPyAobm9hY2N1bSA9IGZhbHNlLCB2YWx1ZSlcbiAgICAgICAgICAgIDogY2FsbGJhY2soYWNjdW11bGF0b3IsIHZhbHVlLCBpbmRleCwgY29sbGVjdGlvbilcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gYWNjdW11bGF0b3I7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhpcyBtZXRob2QgaXMgbGlrZSBgXy5yZWR1Y2VgIGV4Y2VwdCB0aGF0IGl0IGl0ZXJhdGVzIG92ZXIgZWxlbWVudHNcbiAgICAgKiBvZiBhIGBjb2xsZWN0aW9uYCBmcm9tIHJpZ2h0IHRvIGxlZnQuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAYWxpYXMgZm9sZHJcbiAgICAgKiBAY2F0ZWdvcnkgQ29sbGVjdGlvbnNcbiAgICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdHxzdHJpbmd9IGNvbGxlY3Rpb24gVGhlIGNvbGxlY3Rpb24gdG8gaXRlcmF0ZSBvdmVyLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IFtjYWxsYmFjaz1pZGVudGl0eV0gVGhlIGZ1bmN0aW9uIGNhbGxlZCBwZXIgaXRlcmF0aW9uLlxuICAgICAqIEBwYXJhbSB7Kn0gW2FjY3VtdWxhdG9yXSBJbml0aWFsIHZhbHVlIG9mIHRoZSBhY2N1bXVsYXRvci5cbiAgICAgKiBAcGFyYW0geyp9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7Kn0gUmV0dXJucyB0aGUgYWNjdW11bGF0ZWQgdmFsdWUuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIHZhciBsaXN0ID0gW1swLCAxXSwgWzIsIDNdLCBbNCwgNV1dO1xuICAgICAqIHZhciBmbGF0ID0gXy5yZWR1Y2VSaWdodChsaXN0LCBmdW5jdGlvbihhLCBiKSB7IHJldHVybiBhLmNvbmNhdChiKTsgfSwgW10pO1xuICAgICAqIC8vID0+IFs0LCA1LCAyLCAzLCAwLCAxXVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHJlZHVjZVJpZ2h0KGNvbGxlY3Rpb24sIGNhbGxiYWNrLCBhY2N1bXVsYXRvciwgdGhpc0FyZykge1xuICAgICAgdmFyIG5vYWNjdW0gPSBhcmd1bWVudHMubGVuZ3RoIDwgMztcbiAgICAgIGNhbGxiYWNrID0gbG9kYXNoLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnLCA0KTtcbiAgICAgIGZvckVhY2hSaWdodChjb2xsZWN0aW9uLCBmdW5jdGlvbih2YWx1ZSwgaW5kZXgsIGNvbGxlY3Rpb24pIHtcbiAgICAgICAgYWNjdW11bGF0b3IgPSBub2FjY3VtXG4gICAgICAgICAgPyAobm9hY2N1bSA9IGZhbHNlLCB2YWx1ZSlcbiAgICAgICAgICA6IGNhbGxiYWNrKGFjY3VtdWxhdG9yLCB2YWx1ZSwgaW5kZXgsIGNvbGxlY3Rpb24pO1xuICAgICAgfSk7XG4gICAgICByZXR1cm4gYWNjdW11bGF0b3I7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhlIG9wcG9zaXRlIG9mIGBfLmZpbHRlcmAgdGhpcyBtZXRob2QgcmV0dXJucyB0aGUgZWxlbWVudHMgb2YgYVxuICAgICAqIGNvbGxlY3Rpb24gdGhhdCB0aGUgY2FsbGJhY2sgZG9lcyAqKm5vdCoqIHJldHVybiB0cnVleSBmb3IuXG4gICAgICpcbiAgICAgKiBJZiBhIHByb3BlcnR5IG5hbWUgaXMgcHJvdmlkZWQgZm9yIGBjYWxsYmFja2AgdGhlIGNyZWF0ZWQgXCJfLnBsdWNrXCIgc3R5bGVcbiAgICAgKiBjYWxsYmFjayB3aWxsIHJldHVybiB0aGUgcHJvcGVydHkgdmFsdWUgb2YgdGhlIGdpdmVuIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBJZiBhbiBvYmplY3QgaXMgcHJvdmlkZWQgZm9yIGBjYWxsYmFja2AgdGhlIGNyZWF0ZWQgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2tcbiAgICAgKiB3aWxsIHJldHVybiBgdHJ1ZWAgZm9yIGVsZW1lbnRzIHRoYXQgaGF2ZSB0aGUgcHJvcGVydGllcyBvZiB0aGUgZ2l2ZW4gb2JqZWN0LFxuICAgICAqIGVsc2UgYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBDb2xsZWN0aW9uc1xuICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fHN0cmluZ30gY29sbGVjdGlvbiBUaGUgY29sbGVjdGlvbiB0byBpdGVyYXRlIG92ZXIuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbnxPYmplY3R8c3RyaW5nfSBbY2FsbGJhY2s9aWRlbnRpdHldIFRoZSBmdW5jdGlvbiBjYWxsZWRcbiAgICAgKiAgcGVyIGl0ZXJhdGlvbi4gSWYgYSBwcm9wZXJ0eSBuYW1lIG9yIG9iamVjdCBpcyBwcm92aWRlZCBpdCB3aWxsIGJlIHVzZWRcbiAgICAgKiAgdG8gY3JlYXRlIGEgXCJfLnBsdWNrXCIgb3IgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2ssIHJlc3BlY3RpdmVseS5cbiAgICAgKiBAcGFyYW0geyp9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7QXJyYXl9IFJldHVybnMgYSBuZXcgYXJyYXkgb2YgZWxlbWVudHMgdGhhdCBmYWlsZWQgdGhlIGNhbGxiYWNrIGNoZWNrLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgb2RkcyA9IF8ucmVqZWN0KFsxLCAyLCAzLCA0LCA1LCA2XSwgZnVuY3Rpb24obnVtKSB7IHJldHVybiBudW0gJSAyID09IDA7IH0pO1xuICAgICAqIC8vID0+IFsxLCAzLCA1XVxuICAgICAqXG4gICAgICogdmFyIGNoYXJhY3RlcnMgPSBbXG4gICAgICogICB7ICduYW1lJzogJ2Jhcm5leScsICdhZ2UnOiAzNiwgJ2Jsb2NrZWQnOiBmYWxzZSB9LFxuICAgICAqICAgeyAnbmFtZSc6ICdmcmVkJywgICAnYWdlJzogNDAsICdibG9ja2VkJzogdHJ1ZSB9XG4gICAgICogXTtcbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIFwiXy5wbHVja1wiIGNhbGxiYWNrIHNob3J0aGFuZFxuICAgICAqIF8ucmVqZWN0KGNoYXJhY3RlcnMsICdibG9ja2VkJyk7XG4gICAgICogLy8gPT4gW3sgJ25hbWUnOiAnYmFybmV5JywgJ2FnZSc6IDM2LCAnYmxvY2tlZCc6IGZhbHNlIH1dXG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBcIl8ud2hlcmVcIiBjYWxsYmFjayBzaG9ydGhhbmRcbiAgICAgKiBfLnJlamVjdChjaGFyYWN0ZXJzLCB7ICdhZ2UnOiAzNiB9KTtcbiAgICAgKiAvLyA9PiBbeyAnbmFtZSc6ICdmcmVkJywgJ2FnZSc6IDQwLCAnYmxvY2tlZCc6IHRydWUgfV1cbiAgICAgKi9cbiAgICBmdW5jdGlvbiByZWplY3QoY29sbGVjdGlvbiwgY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICAgIGNhbGxiYWNrID0gbG9kYXNoLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnLCAzKTtcbiAgICAgIHJldHVybiBmaWx0ZXIoY29sbGVjdGlvbiwgZnVuY3Rpb24odmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKSB7XG4gICAgICAgIHJldHVybiAhY2FsbGJhY2sodmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHJpZXZlcyBhIHJhbmRvbSBlbGVtZW50IG9yIGBuYCByYW5kb20gZWxlbWVudHMgZnJvbSBhIGNvbGxlY3Rpb24uXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgQ29sbGVjdGlvbnNcbiAgICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdHxzdHJpbmd9IGNvbGxlY3Rpb24gVGhlIGNvbGxlY3Rpb24gdG8gc2FtcGxlLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbbl0gVGhlIG51bWJlciBvZiBlbGVtZW50cyB0byBzYW1wbGUuXG4gICAgICogQHBhcmFtLSB7T2JqZWN0fSBbZ3VhcmRdIEFsbG93cyB3b3JraW5nIHdpdGggZnVuY3Rpb25zIGxpa2UgYF8ubWFwYFxuICAgICAqICB3aXRob3V0IHVzaW5nIHRoZWlyIGBpbmRleGAgYXJndW1lbnRzIGFzIGBuYC5cbiAgICAgKiBAcmV0dXJucyB7QXJyYXl9IFJldHVybnMgdGhlIHJhbmRvbSBzYW1wbGUocykgb2YgYGNvbGxlY3Rpb25gLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLnNhbXBsZShbMSwgMiwgMywgNF0pO1xuICAgICAqIC8vID0+IDJcbiAgICAgKlxuICAgICAqIF8uc2FtcGxlKFsxLCAyLCAzLCA0XSwgMik7XG4gICAgICogLy8gPT4gWzMsIDFdXG4gICAgICovXG4gICAgZnVuY3Rpb24gc2FtcGxlKGNvbGxlY3Rpb24sIG4sIGd1YXJkKSB7XG4gICAgICBpZiAoY29sbGVjdGlvbiAmJiB0eXBlb2YgY29sbGVjdGlvbi5sZW5ndGggIT0gJ251bWJlcicpIHtcbiAgICAgICAgY29sbGVjdGlvbiA9IHZhbHVlcyhjb2xsZWN0aW9uKTtcbiAgICAgIH1cbiAgICAgIGlmIChuID09IG51bGwgfHwgZ3VhcmQpIHtcbiAgICAgICAgcmV0dXJuIGNvbGxlY3Rpb24gPyBjb2xsZWN0aW9uW2Jhc2VSYW5kb20oMCwgY29sbGVjdGlvbi5sZW5ndGggLSAxKV0gOiB1bmRlZmluZWQ7XG4gICAgICB9XG4gICAgICB2YXIgcmVzdWx0ID0gc2h1ZmZsZShjb2xsZWN0aW9uKTtcbiAgICAgIHJlc3VsdC5sZW5ndGggPSBuYXRpdmVNaW4obmF0aXZlTWF4KDAsIG4pLCByZXN1bHQubGVuZ3RoKTtcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbiBhcnJheSBvZiBzaHVmZmxlZCB2YWx1ZXMsIHVzaW5nIGEgdmVyc2lvbiBvZiB0aGUgRmlzaGVyLVlhdGVzXG4gICAgICogc2h1ZmZsZS4gU2VlIGh0dHA6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvRmlzaGVyLVlhdGVzX3NodWZmbGUuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgQ29sbGVjdGlvbnNcbiAgICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdHxzdHJpbmd9IGNvbGxlY3Rpb24gVGhlIGNvbGxlY3Rpb24gdG8gc2h1ZmZsZS5cbiAgICAgKiBAcmV0dXJucyB7QXJyYXl9IFJldHVybnMgYSBuZXcgc2h1ZmZsZWQgY29sbGVjdGlvbi5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5zaHVmZmxlKFsxLCAyLCAzLCA0LCA1LCA2XSk7XG4gICAgICogLy8gPT4gWzQsIDEsIDYsIDMsIDUsIDJdXG4gICAgICovXG4gICAgZnVuY3Rpb24gc2h1ZmZsZShjb2xsZWN0aW9uKSB7XG4gICAgICB2YXIgaW5kZXggPSAtMSxcbiAgICAgICAgICBsZW5ndGggPSBjb2xsZWN0aW9uID8gY29sbGVjdGlvbi5sZW5ndGggOiAwLFxuICAgICAgICAgIHJlc3VsdCA9IEFycmF5KHR5cGVvZiBsZW5ndGggPT0gJ251bWJlcicgPyBsZW5ndGggOiAwKTtcblxuICAgICAgZm9yRWFjaChjb2xsZWN0aW9uLCBmdW5jdGlvbih2YWx1ZSkge1xuICAgICAgICB2YXIgcmFuZCA9IGJhc2VSYW5kb20oMCwgKytpbmRleCk7XG4gICAgICAgIHJlc3VsdFtpbmRleF0gPSByZXN1bHRbcmFuZF07XG4gICAgICAgIHJlc3VsdFtyYW5kXSA9IHZhbHVlO1xuICAgICAgfSk7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldHMgdGhlIHNpemUgb2YgdGhlIGBjb2xsZWN0aW9uYCBieSByZXR1cm5pbmcgYGNvbGxlY3Rpb24ubGVuZ3RoYCBmb3IgYXJyYXlzXG4gICAgICogYW5kIGFycmF5LWxpa2Ugb2JqZWN0cyBvciB0aGUgbnVtYmVyIG9mIG93biBlbnVtZXJhYmxlIHByb3BlcnRpZXMgZm9yIG9iamVjdHMuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgQ29sbGVjdGlvbnNcbiAgICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdHxzdHJpbmd9IGNvbGxlY3Rpb24gVGhlIGNvbGxlY3Rpb24gdG8gaW5zcGVjdC5cbiAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBSZXR1cm5zIGBjb2xsZWN0aW9uLmxlbmd0aGAgb3IgbnVtYmVyIG9mIG93biBlbnVtZXJhYmxlIHByb3BlcnRpZXMuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uc2l6ZShbMSwgMl0pO1xuICAgICAqIC8vID0+IDJcbiAgICAgKlxuICAgICAqIF8uc2l6ZSh7ICdvbmUnOiAxLCAndHdvJzogMiwgJ3RocmVlJzogMyB9KTtcbiAgICAgKiAvLyA9PiAzXG4gICAgICpcbiAgICAgKiBfLnNpemUoJ3BlYmJsZXMnKTtcbiAgICAgKiAvLyA9PiA3XG4gICAgICovXG4gICAgZnVuY3Rpb24gc2l6ZShjb2xsZWN0aW9uKSB7XG4gICAgICB2YXIgbGVuZ3RoID0gY29sbGVjdGlvbiA/IGNvbGxlY3Rpb24ubGVuZ3RoIDogMDtcbiAgICAgIHJldHVybiB0eXBlb2YgbGVuZ3RoID09ICdudW1iZXInID8gbGVuZ3RoIDoga2V5cyhjb2xsZWN0aW9uKS5sZW5ndGg7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIGlmIHRoZSBjYWxsYmFjayByZXR1cm5zIGEgdHJ1ZXkgdmFsdWUgZm9yICoqYW55KiogZWxlbWVudCBvZiBhXG4gICAgICogY29sbGVjdGlvbi4gVGhlIGZ1bmN0aW9uIHJldHVybnMgYXMgc29vbiBhcyBpdCBmaW5kcyBhIHBhc3NpbmcgdmFsdWUgYW5kXG4gICAgICogZG9lcyBub3QgaXRlcmF0ZSBvdmVyIHRoZSBlbnRpcmUgY29sbGVjdGlvbi4gVGhlIGNhbGxiYWNrIGlzIGJvdW5kIHRvXG4gICAgICogYHRoaXNBcmdgIGFuZCBpbnZva2VkIHdpdGggdGhyZWUgYXJndW1lbnRzOyAodmFsdWUsIGluZGV4fGtleSwgY29sbGVjdGlvbikuXG4gICAgICpcbiAgICAgKiBJZiBhIHByb3BlcnR5IG5hbWUgaXMgcHJvdmlkZWQgZm9yIGBjYWxsYmFja2AgdGhlIGNyZWF0ZWQgXCJfLnBsdWNrXCIgc3R5bGVcbiAgICAgKiBjYWxsYmFjayB3aWxsIHJldHVybiB0aGUgcHJvcGVydHkgdmFsdWUgb2YgdGhlIGdpdmVuIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBJZiBhbiBvYmplY3QgaXMgcHJvdmlkZWQgZm9yIGBjYWxsYmFja2AgdGhlIGNyZWF0ZWQgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2tcbiAgICAgKiB3aWxsIHJldHVybiBgdHJ1ZWAgZm9yIGVsZW1lbnRzIHRoYXQgaGF2ZSB0aGUgcHJvcGVydGllcyBvZiB0aGUgZ2l2ZW4gb2JqZWN0LFxuICAgICAqIGVsc2UgYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBhbGlhcyBhbnlcbiAgICAgKiBAY2F0ZWdvcnkgQ29sbGVjdGlvbnNcbiAgICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdHxzdHJpbmd9IGNvbGxlY3Rpb24gVGhlIGNvbGxlY3Rpb24gdG8gaXRlcmF0ZSBvdmVyLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb258T2JqZWN0fHN0cmluZ30gW2NhbGxiYWNrPWlkZW50aXR5XSBUaGUgZnVuY3Rpb24gY2FsbGVkXG4gICAgICogIHBlciBpdGVyYXRpb24uIElmIGEgcHJvcGVydHkgbmFtZSBvciBvYmplY3QgaXMgcHJvdmlkZWQgaXQgd2lsbCBiZSB1c2VkXG4gICAgICogIHRvIGNyZWF0ZSBhIFwiXy5wbHVja1wiIG9yIFwiXy53aGVyZVwiIHN0eWxlIGNhbGxiYWNrLCByZXNwZWN0aXZlbHkuXG4gICAgICogQHBhcmFtIHsqfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIGFueSBlbGVtZW50IHBhc3NlZCB0aGUgY2FsbGJhY2sgY2hlY2ssXG4gICAgICogIGVsc2UgYGZhbHNlYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5zb21lKFtudWxsLCAwLCAneWVzJywgZmFsc2VdLCBCb29sZWFuKTtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICpcbiAgICAgKiB2YXIgY2hhcmFjdGVycyA9IFtcbiAgICAgKiAgIHsgJ25hbWUnOiAnYmFybmV5JywgJ2FnZSc6IDM2LCAnYmxvY2tlZCc6IGZhbHNlIH0sXG4gICAgICogICB7ICduYW1lJzogJ2ZyZWQnLCAgICdhZ2UnOiA0MCwgJ2Jsb2NrZWQnOiB0cnVlIH1cbiAgICAgKiBdO1xuICAgICAqXG4gICAgICogLy8gdXNpbmcgXCJfLnBsdWNrXCIgY2FsbGJhY2sgc2hvcnRoYW5kXG4gICAgICogXy5zb21lKGNoYXJhY3RlcnMsICdibG9ja2VkJyk7XG4gICAgICogLy8gPT4gdHJ1ZVxuICAgICAqXG4gICAgICogLy8gdXNpbmcgXCJfLndoZXJlXCIgY2FsbGJhY2sgc2hvcnRoYW5kXG4gICAgICogXy5zb21lKGNoYXJhY3RlcnMsIHsgJ2FnZSc6IDEgfSk7XG4gICAgICogLy8gPT4gZmFsc2VcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBzb21lKGNvbGxlY3Rpb24sIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICB2YXIgcmVzdWx0O1xuICAgICAgY2FsbGJhY2sgPSBsb2Rhc2guY3JlYXRlQ2FsbGJhY2soY2FsbGJhY2ssIHRoaXNBcmcsIDMpO1xuXG4gICAgICB2YXIgaW5kZXggPSAtMSxcbiAgICAgICAgICBsZW5ndGggPSBjb2xsZWN0aW9uID8gY29sbGVjdGlvbi5sZW5ndGggOiAwO1xuXG4gICAgICBpZiAodHlwZW9mIGxlbmd0aCA9PSAnbnVtYmVyJykge1xuICAgICAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgICAgIGlmICgocmVzdWx0ID0gY2FsbGJhY2soY29sbGVjdGlvbltpbmRleF0sIGluZGV4LCBjb2xsZWN0aW9uKSkpIHtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZm9yT3duKGNvbGxlY3Rpb24sIGZ1bmN0aW9uKHZhbHVlLCBpbmRleCwgY29sbGVjdGlvbikge1xuICAgICAgICAgIHJldHVybiAhKHJlc3VsdCA9IGNhbGxiYWNrKHZhbHVlLCBpbmRleCwgY29sbGVjdGlvbikpO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiAhIXJlc3VsdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIGFycmF5IG9mIGVsZW1lbnRzLCBzb3J0ZWQgaW4gYXNjZW5kaW5nIG9yZGVyIGJ5IHRoZSByZXN1bHRzIG9mXG4gICAgICogcnVubmluZyBlYWNoIGVsZW1lbnQgaW4gYSBjb2xsZWN0aW9uIHRocm91Z2ggdGhlIGNhbGxiYWNrLiBUaGlzIG1ldGhvZFxuICAgICAqIHBlcmZvcm1zIGEgc3RhYmxlIHNvcnQsIHRoYXQgaXMsIGl0IHdpbGwgcHJlc2VydmUgdGhlIG9yaWdpbmFsIHNvcnQgb3JkZXJcbiAgICAgKiBvZiBlcXVhbCBlbGVtZW50cy4gVGhlIGNhbGxiYWNrIGlzIGJvdW5kIHRvIGB0aGlzQXJnYCBhbmQgaW52b2tlZCB3aXRoXG4gICAgICogdGhyZWUgYXJndW1lbnRzOyAodmFsdWUsIGluZGV4fGtleSwgY29sbGVjdGlvbikuXG4gICAgICpcbiAgICAgKiBJZiBhIHByb3BlcnR5IG5hbWUgaXMgcHJvdmlkZWQgZm9yIGBjYWxsYmFja2AgdGhlIGNyZWF0ZWQgXCJfLnBsdWNrXCIgc3R5bGVcbiAgICAgKiBjYWxsYmFjayB3aWxsIHJldHVybiB0aGUgcHJvcGVydHkgdmFsdWUgb2YgdGhlIGdpdmVuIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBJZiBhbiBhcnJheSBvZiBwcm9wZXJ0eSBuYW1lcyBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY29sbGVjdGlvblxuICAgICAqIHdpbGwgYmUgc29ydGVkIGJ5IGVhY2ggcHJvcGVydHkgdmFsdWUuXG4gICAgICpcbiAgICAgKiBJZiBhbiBvYmplY3QgaXMgcHJvdmlkZWQgZm9yIGBjYWxsYmFja2AgdGhlIGNyZWF0ZWQgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2tcbiAgICAgKiB3aWxsIHJldHVybiBgdHJ1ZWAgZm9yIGVsZW1lbnRzIHRoYXQgaGF2ZSB0aGUgcHJvcGVydGllcyBvZiB0aGUgZ2l2ZW4gb2JqZWN0LFxuICAgICAqIGVsc2UgYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBDb2xsZWN0aW9uc1xuICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fHN0cmluZ30gY29sbGVjdGlvbiBUaGUgY29sbGVjdGlvbiB0byBpdGVyYXRlIG92ZXIuXG4gICAgICogQHBhcmFtIHtBcnJheXxGdW5jdGlvbnxPYmplY3R8c3RyaW5nfSBbY2FsbGJhY2s9aWRlbnRpdHldIFRoZSBmdW5jdGlvbiBjYWxsZWRcbiAgICAgKiAgcGVyIGl0ZXJhdGlvbi4gSWYgYSBwcm9wZXJ0eSBuYW1lIG9yIG9iamVjdCBpcyBwcm92aWRlZCBpdCB3aWxsIGJlIHVzZWRcbiAgICAgKiAgdG8gY3JlYXRlIGEgXCJfLnBsdWNrXCIgb3IgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2ssIHJlc3BlY3RpdmVseS5cbiAgICAgKiBAcGFyYW0geyp9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7QXJyYXl9IFJldHVybnMgYSBuZXcgYXJyYXkgb2Ygc29ydGVkIGVsZW1lbnRzLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLnNvcnRCeShbMSwgMiwgM10sIGZ1bmN0aW9uKG51bSkgeyByZXR1cm4gTWF0aC5zaW4obnVtKTsgfSk7XG4gICAgICogLy8gPT4gWzMsIDEsIDJdXG4gICAgICpcbiAgICAgKiBfLnNvcnRCeShbMSwgMiwgM10sIGZ1bmN0aW9uKG51bSkgeyByZXR1cm4gdGhpcy5zaW4obnVtKTsgfSwgTWF0aCk7XG4gICAgICogLy8gPT4gWzMsIDEsIDJdXG4gICAgICpcbiAgICAgKiB2YXIgY2hhcmFjdGVycyA9IFtcbiAgICAgKiAgIHsgJ25hbWUnOiAnYmFybmV5JywgICdhZ2UnOiAzNiB9LFxuICAgICAqICAgeyAnbmFtZSc6ICdmcmVkJywgICAgJ2FnZSc6IDQwIH0sXG4gICAgICogICB7ICduYW1lJzogJ2Jhcm5leScsICAnYWdlJzogMjYgfSxcbiAgICAgKiAgIHsgJ25hbWUnOiAnZnJlZCcsICAgICdhZ2UnOiAzMCB9XG4gICAgICogXTtcbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIFwiXy5wbHVja1wiIGNhbGxiYWNrIHNob3J0aGFuZFxuICAgICAqIF8ubWFwKF8uc29ydEJ5KGNoYXJhY3RlcnMsICdhZ2UnKSwgXy52YWx1ZXMpO1xuICAgICAqIC8vID0+IFtbJ2Jhcm5leScsIDI2XSwgWydmcmVkJywgMzBdLCBbJ2Jhcm5leScsIDM2XSwgWydmcmVkJywgNDBdXVxuICAgICAqXG4gICAgICogLy8gc29ydGluZyBieSBtdWx0aXBsZSBwcm9wZXJ0aWVzXG4gICAgICogXy5tYXAoXy5zb3J0QnkoY2hhcmFjdGVycywgWyduYW1lJywgJ2FnZSddKSwgXy52YWx1ZXMpO1xuICAgICAqIC8vID0gPiBbWydiYXJuZXknLCAyNl0sIFsnYmFybmV5JywgMzZdLCBbJ2ZyZWQnLCAzMF0sIFsnZnJlZCcsIDQwXV1cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBzb3J0QnkoY29sbGVjdGlvbiwgY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICAgIGlzQXJyID0gaXNBcnJheShjYWxsYmFjayksXG4gICAgICAgICAgbGVuZ3RoID0gY29sbGVjdGlvbiA/IGNvbGxlY3Rpb24ubGVuZ3RoIDogMCxcbiAgICAgICAgICByZXN1bHQgPSBBcnJheSh0eXBlb2YgbGVuZ3RoID09ICdudW1iZXInID8gbGVuZ3RoIDogMCk7XG5cbiAgICAgIGlmICghaXNBcnIpIHtcbiAgICAgICAgY2FsbGJhY2sgPSBsb2Rhc2guY3JlYXRlQ2FsbGJhY2soY2FsbGJhY2ssIHRoaXNBcmcsIDMpO1xuICAgICAgfVxuICAgICAgZm9yRWFjaChjb2xsZWN0aW9uLCBmdW5jdGlvbih2YWx1ZSwga2V5LCBjb2xsZWN0aW9uKSB7XG4gICAgICAgIHZhciBvYmplY3QgPSByZXN1bHRbKytpbmRleF0gPSBnZXRPYmplY3QoKTtcbiAgICAgICAgaWYgKGlzQXJyKSB7XG4gICAgICAgICAgb2JqZWN0LmNyaXRlcmlhID0gbWFwKGNhbGxiYWNrLCBmdW5jdGlvbihrZXkpIHsgcmV0dXJuIHZhbHVlW2tleV07IH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIChvYmplY3QuY3JpdGVyaWEgPSBnZXRBcnJheSgpKVswXSA9IGNhbGxiYWNrKHZhbHVlLCBrZXksIGNvbGxlY3Rpb24pO1xuICAgICAgICB9XG4gICAgICAgIG9iamVjdC5pbmRleCA9IGluZGV4O1xuICAgICAgICBvYmplY3QudmFsdWUgPSB2YWx1ZTtcbiAgICAgIH0pO1xuXG4gICAgICBsZW5ndGggPSByZXN1bHQubGVuZ3RoO1xuICAgICAgcmVzdWx0LnNvcnQoY29tcGFyZUFzY2VuZGluZyk7XG4gICAgICB3aGlsZSAobGVuZ3RoLS0pIHtcbiAgICAgICAgdmFyIG9iamVjdCA9IHJlc3VsdFtsZW5ndGhdO1xuICAgICAgICByZXN1bHRbbGVuZ3RoXSA9IG9iamVjdC52YWx1ZTtcbiAgICAgICAgaWYgKCFpc0Fycikge1xuICAgICAgICAgIHJlbGVhc2VBcnJheShvYmplY3QuY3JpdGVyaWEpO1xuICAgICAgICB9XG4gICAgICAgIHJlbGVhc2VPYmplY3Qob2JqZWN0KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ29udmVydHMgdGhlIGBjb2xsZWN0aW9uYCB0byBhbiBhcnJheS5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBDb2xsZWN0aW9uc1xuICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fHN0cmluZ30gY29sbGVjdGlvbiBUaGUgY29sbGVjdGlvbiB0byBjb252ZXJ0LlxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyB0aGUgbmV3IGNvbnZlcnRlZCBhcnJheS5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogKGZ1bmN0aW9uKCkgeyByZXR1cm4gXy50b0FycmF5KGFyZ3VtZW50cykuc2xpY2UoMSk7IH0pKDEsIDIsIDMsIDQpO1xuICAgICAqIC8vID0+IFsyLCAzLCA0XVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHRvQXJyYXkoY29sbGVjdGlvbikge1xuICAgICAgaWYgKGNvbGxlY3Rpb24gJiYgdHlwZW9mIGNvbGxlY3Rpb24ubGVuZ3RoID09ICdudW1iZXInKSB7XG4gICAgICAgIHJldHVybiBzbGljZShjb2xsZWN0aW9uKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB2YWx1ZXMoY29sbGVjdGlvbik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUGVyZm9ybXMgYSBkZWVwIGNvbXBhcmlzb24gb2YgZWFjaCBlbGVtZW50IGluIGEgYGNvbGxlY3Rpb25gIHRvIHRoZSBnaXZlblxuICAgICAqIGBwcm9wZXJ0aWVzYCBvYmplY3QsIHJldHVybmluZyBhbiBhcnJheSBvZiBhbGwgZWxlbWVudHMgdGhhdCBoYXZlIGVxdWl2YWxlbnRcbiAgICAgKiBwcm9wZXJ0eSB2YWx1ZXMuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAdHlwZSBGdW5jdGlvblxuICAgICAqIEBjYXRlZ29yeSBDb2xsZWN0aW9uc1xuICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fHN0cmluZ30gY29sbGVjdGlvbiBUaGUgY29sbGVjdGlvbiB0byBpdGVyYXRlIG92ZXIuXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHByb3BzIFRoZSBvYmplY3Qgb2YgcHJvcGVydHkgdmFsdWVzIHRvIGZpbHRlciBieS5cbiAgICAgKiBAcmV0dXJucyB7QXJyYXl9IFJldHVybnMgYSBuZXcgYXJyYXkgb2YgZWxlbWVudHMgdGhhdCBoYXZlIHRoZSBnaXZlbiBwcm9wZXJ0aWVzLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgY2hhcmFjdGVycyA9IFtcbiAgICAgKiAgIHsgJ25hbWUnOiAnYmFybmV5JywgJ2FnZSc6IDM2LCAncGV0cyc6IFsnaG9wcHknXSB9LFxuICAgICAqICAgeyAnbmFtZSc6ICdmcmVkJywgICAnYWdlJzogNDAsICdwZXRzJzogWydiYWJ5IHB1c3MnLCAnZGlubyddIH1cbiAgICAgKiBdO1xuICAgICAqXG4gICAgICogXy53aGVyZShjaGFyYWN0ZXJzLCB7ICdhZ2UnOiAzNiB9KTtcbiAgICAgKiAvLyA9PiBbeyAnbmFtZSc6ICdiYXJuZXknLCAnYWdlJzogMzYsICdwZXRzJzogWydob3BweSddIH1dXG4gICAgICpcbiAgICAgKiBfLndoZXJlKGNoYXJhY3RlcnMsIHsgJ3BldHMnOiBbJ2Rpbm8nXSB9KTtcbiAgICAgKiAvLyA9PiBbeyAnbmFtZSc6ICdmcmVkJywgJ2FnZSc6IDQwLCAncGV0cyc6IFsnYmFieSBwdXNzJywgJ2Rpbm8nXSB9XVxuICAgICAqL1xuICAgIHZhciB3aGVyZSA9IGZpbHRlcjtcblxuICAgIC8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbiBhcnJheSB3aXRoIGFsbCBmYWxzZXkgdmFsdWVzIHJlbW92ZWQuIFRoZSB2YWx1ZXMgYGZhbHNlYCwgYG51bGxgLFxuICAgICAqIGAwYCwgYFwiXCJgLCBgdW5kZWZpbmVkYCwgYW5kIGBOYU5gIGFyZSBhbGwgZmFsc2V5LlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEFycmF5c1xuICAgICAqIEBwYXJhbSB7QXJyYXl9IGFycmF5IFRoZSBhcnJheSB0byBjb21wYWN0LlxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyBhIG5ldyBhcnJheSBvZiBmaWx0ZXJlZCB2YWx1ZXMuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uY29tcGFjdChbMCwgMSwgZmFsc2UsIDIsICcnLCAzXSk7XG4gICAgICogLy8gPT4gWzEsIDIsIDNdXG4gICAgICovXG4gICAgZnVuY3Rpb24gY29tcGFjdChhcnJheSkge1xuICAgICAgdmFyIGluZGV4ID0gLTEsXG4gICAgICAgICAgbGVuZ3RoID0gYXJyYXkgPyBhcnJheS5sZW5ndGggOiAwLFxuICAgICAgICAgIHJlc3VsdCA9IFtdO1xuXG4gICAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgICB2YXIgdmFsdWUgPSBhcnJheVtpbmRleF07XG4gICAgICAgIGlmICh2YWx1ZSkge1xuICAgICAgICAgIHJlc3VsdC5wdXNoKHZhbHVlKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIGFycmF5IGV4Y2x1ZGluZyBhbGwgdmFsdWVzIG9mIHRoZSBwcm92aWRlZCBhcnJheXMgdXNpbmcgc3RyaWN0XG4gICAgICogZXF1YWxpdHkgZm9yIGNvbXBhcmlzb25zLCBpLmUuIGA9PT1gLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEFycmF5c1xuICAgICAqIEBwYXJhbSB7QXJyYXl9IGFycmF5IFRoZSBhcnJheSB0byBwcm9jZXNzLlxuICAgICAqIEBwYXJhbSB7Li4uQXJyYXl9IFt2YWx1ZXNdIFRoZSBhcnJheXMgb2YgdmFsdWVzIHRvIGV4Y2x1ZGUuXG4gICAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIGEgbmV3IGFycmF5IG9mIGZpbHRlcmVkIHZhbHVlcy5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5kaWZmZXJlbmNlKFsxLCAyLCAzLCA0LCA1XSwgWzUsIDIsIDEwXSk7XG4gICAgICogLy8gPT4gWzEsIDMsIDRdXG4gICAgICovXG4gICAgZnVuY3Rpb24gZGlmZmVyZW5jZShhcnJheSkge1xuICAgICAgcmV0dXJuIGJhc2VEaWZmZXJlbmNlKGFycmF5LCBiYXNlRmxhdHRlbihhcmd1bWVudHMsIHRydWUsIHRydWUsIDEpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGlzIG1ldGhvZCBpcyBsaWtlIGBfLmZpbmRgIGV4Y2VwdCB0aGF0IGl0IHJldHVybnMgdGhlIGluZGV4IG9mIHRoZSBmaXJzdFxuICAgICAqIGVsZW1lbnQgdGhhdCBwYXNzZXMgdGhlIGNhbGxiYWNrIGNoZWNrLCBpbnN0ZWFkIG9mIHRoZSBlbGVtZW50IGl0c2VsZi5cbiAgICAgKlxuICAgICAqIElmIGEgcHJvcGVydHkgbmFtZSBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ucGx1Y2tcIiBzdHlsZVxuICAgICAqIGNhbGxiYWNrIHdpbGwgcmV0dXJuIHRoZSBwcm9wZXJ0eSB2YWx1ZSBvZiB0aGUgZ2l2ZW4gZWxlbWVudC5cbiAgICAgKlxuICAgICAqIElmIGFuIG9iamVjdCBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFja1xuICAgICAqIHdpbGwgcmV0dXJuIGB0cnVlYCBmb3IgZWxlbWVudHMgdGhhdCBoYXZlIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBnaXZlbiBvYmplY3QsXG4gICAgICogZWxzZSBgZmFsc2VgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEFycmF5c1xuICAgICAqIEBwYXJhbSB7QXJyYXl9IGFycmF5IFRoZSBhcnJheSB0byBzZWFyY2guXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbnxPYmplY3R8c3RyaW5nfSBbY2FsbGJhY2s9aWRlbnRpdHldIFRoZSBmdW5jdGlvbiBjYWxsZWRcbiAgICAgKiAgcGVyIGl0ZXJhdGlvbi4gSWYgYSBwcm9wZXJ0eSBuYW1lIG9yIG9iamVjdCBpcyBwcm92aWRlZCBpdCB3aWxsIGJlIHVzZWRcbiAgICAgKiAgdG8gY3JlYXRlIGEgXCJfLnBsdWNrXCIgb3IgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2ssIHJlc3BlY3RpdmVseS5cbiAgICAgKiBAcGFyYW0geyp9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBSZXR1cm5zIHRoZSBpbmRleCBvZiB0aGUgZm91bmQgZWxlbWVudCwgZWxzZSBgLTFgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgY2hhcmFjdGVycyA9IFtcbiAgICAgKiAgIHsgJ25hbWUnOiAnYmFybmV5JywgICdhZ2UnOiAzNiwgJ2Jsb2NrZWQnOiBmYWxzZSB9LFxuICAgICAqICAgeyAnbmFtZSc6ICdmcmVkJywgICAgJ2FnZSc6IDQwLCAnYmxvY2tlZCc6IHRydWUgfSxcbiAgICAgKiAgIHsgJ25hbWUnOiAncGViYmxlcycsICdhZ2UnOiAxLCAgJ2Jsb2NrZWQnOiBmYWxzZSB9XG4gICAgICogXTtcbiAgICAgKlxuICAgICAqIF8uZmluZEluZGV4KGNoYXJhY3RlcnMsIGZ1bmN0aW9uKGNocikge1xuICAgICAqICAgcmV0dXJuIGNoci5hZ2UgPCAyMDtcbiAgICAgKiB9KTtcbiAgICAgKiAvLyA9PiAyXG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBcIl8ud2hlcmVcIiBjYWxsYmFjayBzaG9ydGhhbmRcbiAgICAgKiBfLmZpbmRJbmRleChjaGFyYWN0ZXJzLCB7ICdhZ2UnOiAzNiB9KTtcbiAgICAgKiAvLyA9PiAwXG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBcIl8ucGx1Y2tcIiBjYWxsYmFjayBzaG9ydGhhbmRcbiAgICAgKiBfLmZpbmRJbmRleChjaGFyYWN0ZXJzLCAnYmxvY2tlZCcpO1xuICAgICAqIC8vID0+IDFcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBmaW5kSW5kZXgoYXJyYXksIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICB2YXIgaW5kZXggPSAtMSxcbiAgICAgICAgICBsZW5ndGggPSBhcnJheSA/IGFycmF5Lmxlbmd0aCA6IDA7XG5cbiAgICAgIGNhbGxiYWNrID0gbG9kYXNoLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnLCAzKTtcbiAgICAgIHdoaWxlICgrK2luZGV4IDwgbGVuZ3RoKSB7XG4gICAgICAgIGlmIChjYWxsYmFjayhhcnJheVtpbmRleF0sIGluZGV4LCBhcnJheSkpIHtcbiAgICAgICAgICByZXR1cm4gaW5kZXg7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiAtMTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGlzIG1ldGhvZCBpcyBsaWtlIGBfLmZpbmRJbmRleGAgZXhjZXB0IHRoYXQgaXQgaXRlcmF0ZXMgb3ZlciBlbGVtZW50c1xuICAgICAqIG9mIGEgYGNvbGxlY3Rpb25gIGZyb20gcmlnaHQgdG8gbGVmdC5cbiAgICAgKlxuICAgICAqIElmIGEgcHJvcGVydHkgbmFtZSBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ucGx1Y2tcIiBzdHlsZVxuICAgICAqIGNhbGxiYWNrIHdpbGwgcmV0dXJuIHRoZSBwcm9wZXJ0eSB2YWx1ZSBvZiB0aGUgZ2l2ZW4gZWxlbWVudC5cbiAgICAgKlxuICAgICAqIElmIGFuIG9iamVjdCBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFja1xuICAgICAqIHdpbGwgcmV0dXJuIGB0cnVlYCBmb3IgZWxlbWVudHMgdGhhdCBoYXZlIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBnaXZlbiBvYmplY3QsXG4gICAgICogZWxzZSBgZmFsc2VgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEFycmF5c1xuICAgICAqIEBwYXJhbSB7QXJyYXl9IGFycmF5IFRoZSBhcnJheSB0byBzZWFyY2guXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbnxPYmplY3R8c3RyaW5nfSBbY2FsbGJhY2s9aWRlbnRpdHldIFRoZSBmdW5jdGlvbiBjYWxsZWRcbiAgICAgKiAgcGVyIGl0ZXJhdGlvbi4gSWYgYSBwcm9wZXJ0eSBuYW1lIG9yIG9iamVjdCBpcyBwcm92aWRlZCBpdCB3aWxsIGJlIHVzZWRcbiAgICAgKiAgdG8gY3JlYXRlIGEgXCJfLnBsdWNrXCIgb3IgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2ssIHJlc3BlY3RpdmVseS5cbiAgICAgKiBAcGFyYW0geyp9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBSZXR1cm5zIHRoZSBpbmRleCBvZiB0aGUgZm91bmQgZWxlbWVudCwgZWxzZSBgLTFgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgY2hhcmFjdGVycyA9IFtcbiAgICAgKiAgIHsgJ25hbWUnOiAnYmFybmV5JywgICdhZ2UnOiAzNiwgJ2Jsb2NrZWQnOiB0cnVlIH0sXG4gICAgICogICB7ICduYW1lJzogJ2ZyZWQnLCAgICAnYWdlJzogNDAsICdibG9ja2VkJzogZmFsc2UgfSxcbiAgICAgKiAgIHsgJ25hbWUnOiAncGViYmxlcycsICdhZ2UnOiAxLCAgJ2Jsb2NrZWQnOiB0cnVlIH1cbiAgICAgKiBdO1xuICAgICAqXG4gICAgICogXy5maW5kTGFzdEluZGV4KGNoYXJhY3RlcnMsIGZ1bmN0aW9uKGNocikge1xuICAgICAqICAgcmV0dXJuIGNoci5hZ2UgPiAzMDtcbiAgICAgKiB9KTtcbiAgICAgKiAvLyA9PiAxXG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBcIl8ud2hlcmVcIiBjYWxsYmFjayBzaG9ydGhhbmRcbiAgICAgKiBfLmZpbmRMYXN0SW5kZXgoY2hhcmFjdGVycywgeyAnYWdlJzogMzYgfSk7XG4gICAgICogLy8gPT4gMFxuICAgICAqXG4gICAgICogLy8gdXNpbmcgXCJfLnBsdWNrXCIgY2FsbGJhY2sgc2hvcnRoYW5kXG4gICAgICogXy5maW5kTGFzdEluZGV4KGNoYXJhY3RlcnMsICdibG9ja2VkJyk7XG4gICAgICogLy8gPT4gMlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGZpbmRMYXN0SW5kZXgoYXJyYXksIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICB2YXIgbGVuZ3RoID0gYXJyYXkgPyBhcnJheS5sZW5ndGggOiAwO1xuICAgICAgY2FsbGJhY2sgPSBsb2Rhc2guY3JlYXRlQ2FsbGJhY2soY2FsbGJhY2ssIHRoaXNBcmcsIDMpO1xuICAgICAgd2hpbGUgKGxlbmd0aC0tKSB7XG4gICAgICAgIGlmIChjYWxsYmFjayhhcnJheVtsZW5ndGhdLCBsZW5ndGgsIGFycmF5KSkge1xuICAgICAgICAgIHJldHVybiBsZW5ndGg7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiAtMTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXRzIHRoZSBmaXJzdCBlbGVtZW50IG9yIGZpcnN0IGBuYCBlbGVtZW50cyBvZiBhbiBhcnJheS4gSWYgYSBjYWxsYmFja1xuICAgICAqIGlzIHByb3ZpZGVkIGVsZW1lbnRzIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIGFycmF5IGFyZSByZXR1cm5lZCBhcyBsb25nXG4gICAgICogYXMgdGhlIGNhbGxiYWNrIHJldHVybnMgdHJ1ZXkuIFRoZSBjYWxsYmFjayBpcyBib3VuZCB0byBgdGhpc0FyZ2AgYW5kXG4gICAgICogaW52b2tlZCB3aXRoIHRocmVlIGFyZ3VtZW50czsgKHZhbHVlLCBpbmRleCwgYXJyYXkpLlxuICAgICAqXG4gICAgICogSWYgYSBwcm9wZXJ0eSBuYW1lIGlzIHByb3ZpZGVkIGZvciBgY2FsbGJhY2tgIHRoZSBjcmVhdGVkIFwiXy5wbHVja1wiIHN0eWxlXG4gICAgICogY2FsbGJhY2sgd2lsbCByZXR1cm4gdGhlIHByb3BlcnR5IHZhbHVlIG9mIHRoZSBnaXZlbiBlbGVtZW50LlxuICAgICAqXG4gICAgICogSWYgYW4gb2JqZWN0IGlzIHByb3ZpZGVkIGZvciBgY2FsbGJhY2tgIHRoZSBjcmVhdGVkIFwiXy53aGVyZVwiIHN0eWxlIGNhbGxiYWNrXG4gICAgICogd2lsbCByZXR1cm4gYHRydWVgIGZvciBlbGVtZW50cyB0aGF0IGhhdmUgdGhlIHByb3BlcnRpZXMgb2YgdGhlIGdpdmVuIG9iamVjdCxcbiAgICAgKiBlbHNlIGBmYWxzZWAuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAYWxpYXMgaGVhZCwgdGFrZVxuICAgICAqIEBjYXRlZ29yeSBBcnJheXNcbiAgICAgKiBAcGFyYW0ge0FycmF5fSBhcnJheSBUaGUgYXJyYXkgdG8gcXVlcnkuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbnxPYmplY3R8bnVtYmVyfHN0cmluZ30gW2NhbGxiYWNrXSBUaGUgZnVuY3Rpb24gY2FsbGVkXG4gICAgICogIHBlciBlbGVtZW50IG9yIHRoZSBudW1iZXIgb2YgZWxlbWVudHMgdG8gcmV0dXJuLiBJZiBhIHByb3BlcnR5IG5hbWUgb3JcbiAgICAgKiAgb2JqZWN0IGlzIHByb3ZpZGVkIGl0IHdpbGwgYmUgdXNlZCB0byBjcmVhdGUgYSBcIl8ucGx1Y2tcIiBvciBcIl8ud2hlcmVcIlxuICAgICAqICBzdHlsZSBjYWxsYmFjaywgcmVzcGVjdGl2ZWx5LlxuICAgICAqIEBwYXJhbSB7Kn0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHsqfSBSZXR1cm5zIHRoZSBmaXJzdCBlbGVtZW50KHMpIG9mIGBhcnJheWAuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uZmlyc3QoWzEsIDIsIDNdKTtcbiAgICAgKiAvLyA9PiAxXG4gICAgICpcbiAgICAgKiBfLmZpcnN0KFsxLCAyLCAzXSwgMik7XG4gICAgICogLy8gPT4gWzEsIDJdXG4gICAgICpcbiAgICAgKiBfLmZpcnN0KFsxLCAyLCAzXSwgZnVuY3Rpb24obnVtKSB7XG4gICAgICogICByZXR1cm4gbnVtIDwgMztcbiAgICAgKiB9KTtcbiAgICAgKiAvLyA9PiBbMSwgMl1cbiAgICAgKlxuICAgICAqIHZhciBjaGFyYWN0ZXJzID0gW1xuICAgICAqICAgeyAnbmFtZSc6ICdiYXJuZXknLCAgJ2Jsb2NrZWQnOiB0cnVlLCAgJ2VtcGxveWVyJzogJ3NsYXRlJyB9LFxuICAgICAqICAgeyAnbmFtZSc6ICdmcmVkJywgICAgJ2Jsb2NrZWQnOiBmYWxzZSwgJ2VtcGxveWVyJzogJ3NsYXRlJyB9LFxuICAgICAqICAgeyAnbmFtZSc6ICdwZWJibGVzJywgJ2Jsb2NrZWQnOiB0cnVlLCAgJ2VtcGxveWVyJzogJ25hJyB9XG4gICAgICogXTtcbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIFwiXy5wbHVja1wiIGNhbGxiYWNrIHNob3J0aGFuZFxuICAgICAqIF8uZmlyc3QoY2hhcmFjdGVycywgJ2Jsb2NrZWQnKTtcbiAgICAgKiAvLyA9PiBbeyAnbmFtZSc6ICdiYXJuZXknLCAnYmxvY2tlZCc6IHRydWUsICdlbXBsb3llcic6ICdzbGF0ZScgfV1cbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIFwiXy53aGVyZVwiIGNhbGxiYWNrIHNob3J0aGFuZFxuICAgICAqIF8ucGx1Y2soXy5maXJzdChjaGFyYWN0ZXJzLCB7ICdlbXBsb3llcic6ICdzbGF0ZScgfSksICduYW1lJyk7XG4gICAgICogLy8gPT4gWydiYXJuZXknLCAnZnJlZCddXG4gICAgICovXG4gICAgZnVuY3Rpb24gZmlyc3QoYXJyYXksIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICB2YXIgbiA9IDAsXG4gICAgICAgICAgbGVuZ3RoID0gYXJyYXkgPyBhcnJheS5sZW5ndGggOiAwO1xuXG4gICAgICBpZiAodHlwZW9mIGNhbGxiYWNrICE9ICdudW1iZXInICYmIGNhbGxiYWNrICE9IG51bGwpIHtcbiAgICAgICAgdmFyIGluZGV4ID0gLTE7XG4gICAgICAgIGNhbGxiYWNrID0gbG9kYXNoLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnLCAzKTtcbiAgICAgICAgd2hpbGUgKCsraW5kZXggPCBsZW5ndGggJiYgY2FsbGJhY2soYXJyYXlbaW5kZXhdLCBpbmRleCwgYXJyYXkpKSB7XG4gICAgICAgICAgbisrO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBuID0gY2FsbGJhY2s7XG4gICAgICAgIGlmIChuID09IG51bGwgfHwgdGhpc0FyZykge1xuICAgICAgICAgIHJldHVybiBhcnJheSA/IGFycmF5WzBdIDogdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gc2xpY2UoYXJyYXksIDAsIG5hdGl2ZU1pbihuYXRpdmVNYXgoMCwgbiksIGxlbmd0aCkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEZsYXR0ZW5zIGEgbmVzdGVkIGFycmF5ICh0aGUgbmVzdGluZyBjYW4gYmUgdG8gYW55IGRlcHRoKS4gSWYgYGlzU2hhbGxvd2BcbiAgICAgKiBpcyB0cnVleSwgdGhlIGFycmF5IHdpbGwgb25seSBiZSBmbGF0dGVuZWQgYSBzaW5nbGUgbGV2ZWwuIElmIGEgY2FsbGJhY2tcbiAgICAgKiBpcyBwcm92aWRlZCBlYWNoIGVsZW1lbnQgb2YgdGhlIGFycmF5IGlzIHBhc3NlZCB0aHJvdWdoIHRoZSBjYWxsYmFjayBiZWZvcmVcbiAgICAgKiBmbGF0dGVuaW5nLiBUaGUgY2FsbGJhY2sgaXMgYm91bmQgdG8gYHRoaXNBcmdgIGFuZCBpbnZva2VkIHdpdGggdGhyZWVcbiAgICAgKiBhcmd1bWVudHM7ICh2YWx1ZSwgaW5kZXgsIGFycmF5KS5cbiAgICAgKlxuICAgICAqIElmIGEgcHJvcGVydHkgbmFtZSBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ucGx1Y2tcIiBzdHlsZVxuICAgICAqIGNhbGxiYWNrIHdpbGwgcmV0dXJuIHRoZSBwcm9wZXJ0eSB2YWx1ZSBvZiB0aGUgZ2l2ZW4gZWxlbWVudC5cbiAgICAgKlxuICAgICAqIElmIGFuIG9iamVjdCBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFja1xuICAgICAqIHdpbGwgcmV0dXJuIGB0cnVlYCBmb3IgZWxlbWVudHMgdGhhdCBoYXZlIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBnaXZlbiBvYmplY3QsXG4gICAgICogZWxzZSBgZmFsc2VgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEFycmF5c1xuICAgICAqIEBwYXJhbSB7QXJyYXl9IGFycmF5IFRoZSBhcnJheSB0byBmbGF0dGVuLlxuICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW2lzU2hhbGxvdz1mYWxzZV0gQSBmbGFnIHRvIHJlc3RyaWN0IGZsYXR0ZW5pbmcgdG8gYSBzaW5nbGUgbGV2ZWwuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbnxPYmplY3R8c3RyaW5nfSBbY2FsbGJhY2s9aWRlbnRpdHldIFRoZSBmdW5jdGlvbiBjYWxsZWRcbiAgICAgKiAgcGVyIGl0ZXJhdGlvbi4gSWYgYSBwcm9wZXJ0eSBuYW1lIG9yIG9iamVjdCBpcyBwcm92aWRlZCBpdCB3aWxsIGJlIHVzZWRcbiAgICAgKiAgdG8gY3JlYXRlIGEgXCJfLnBsdWNrXCIgb3IgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2ssIHJlc3BlY3RpdmVseS5cbiAgICAgKiBAcGFyYW0geyp9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7QXJyYXl9IFJldHVybnMgYSBuZXcgZmxhdHRlbmVkIGFycmF5LlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLmZsYXR0ZW4oWzEsIFsyXSwgWzMsIFtbNF1dXV0pO1xuICAgICAqIC8vID0+IFsxLCAyLCAzLCA0XTtcbiAgICAgKlxuICAgICAqIF8uZmxhdHRlbihbMSwgWzJdLCBbMywgW1s0XV1dXSwgdHJ1ZSk7XG4gICAgICogLy8gPT4gWzEsIDIsIDMsIFtbNF1dXTtcbiAgICAgKlxuICAgICAqIHZhciBjaGFyYWN0ZXJzID0gW1xuICAgICAqICAgeyAnbmFtZSc6ICdiYXJuZXknLCAnYWdlJzogMzAsICdwZXRzJzogWydob3BweSddIH0sXG4gICAgICogICB7ICduYW1lJzogJ2ZyZWQnLCAgICdhZ2UnOiA0MCwgJ3BldHMnOiBbJ2JhYnkgcHVzcycsICdkaW5vJ10gfVxuICAgICAqIF07XG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBcIl8ucGx1Y2tcIiBjYWxsYmFjayBzaG9ydGhhbmRcbiAgICAgKiBfLmZsYXR0ZW4oY2hhcmFjdGVycywgJ3BldHMnKTtcbiAgICAgKiAvLyA9PiBbJ2hvcHB5JywgJ2JhYnkgcHVzcycsICdkaW5vJ11cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBmbGF0dGVuKGFycmF5LCBpc1NoYWxsb3csIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICAvLyBqdWdnbGUgYXJndW1lbnRzXG4gICAgICBpZiAodHlwZW9mIGlzU2hhbGxvdyAhPSAnYm9vbGVhbicgJiYgaXNTaGFsbG93ICE9IG51bGwpIHtcbiAgICAgICAgdGhpc0FyZyA9IGNhbGxiYWNrO1xuICAgICAgICBjYWxsYmFjayA9ICh0eXBlb2YgaXNTaGFsbG93ICE9ICdmdW5jdGlvbicgJiYgdGhpc0FyZyAmJiB0aGlzQXJnW2lzU2hhbGxvd10gPT09IGFycmF5KSA/IG51bGwgOiBpc1NoYWxsb3c7XG4gICAgICAgIGlzU2hhbGxvdyA9IGZhbHNlO1xuICAgICAgfVxuICAgICAgaWYgKGNhbGxiYWNrICE9IG51bGwpIHtcbiAgICAgICAgYXJyYXkgPSBtYXAoYXJyYXksIGNhbGxiYWNrLCB0aGlzQXJnKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBiYXNlRmxhdHRlbihhcnJheSwgaXNTaGFsbG93KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXRzIHRoZSBpbmRleCBhdCB3aGljaCB0aGUgZmlyc3Qgb2NjdXJyZW5jZSBvZiBgdmFsdWVgIGlzIGZvdW5kIHVzaW5nXG4gICAgICogc3RyaWN0IGVxdWFsaXR5IGZvciBjb21wYXJpc29ucywgaS5lLiBgPT09YC4gSWYgdGhlIGFycmF5IGlzIGFscmVhZHkgc29ydGVkXG4gICAgICogcHJvdmlkaW5nIGB0cnVlYCBmb3IgYGZyb21JbmRleGAgd2lsbCBydW4gYSBmYXN0ZXIgYmluYXJ5IHNlYXJjaC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBBcnJheXNcbiAgICAgKiBAcGFyYW0ge0FycmF5fSBhcnJheSBUaGUgYXJyYXkgdG8gc2VhcmNoLlxuICAgICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIHNlYXJjaCBmb3IuXG4gICAgICogQHBhcmFtIHtib29sZWFufG51bWJlcn0gW2Zyb21JbmRleD0wXSBUaGUgaW5kZXggdG8gc2VhcmNoIGZyb20gb3IgYHRydWVgXG4gICAgICogIHRvIHBlcmZvcm0gYSBiaW5hcnkgc2VhcmNoIG9uIGEgc29ydGVkIGFycmF5LlxuICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFJldHVybnMgdGhlIGluZGV4IG9mIHRoZSBtYXRjaGVkIHZhbHVlIG9yIGAtMWAuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uaW5kZXhPZihbMSwgMiwgMywgMSwgMiwgM10sIDIpO1xuICAgICAqIC8vID0+IDFcbiAgICAgKlxuICAgICAqIF8uaW5kZXhPZihbMSwgMiwgMywgMSwgMiwgM10sIDIsIDMpO1xuICAgICAqIC8vID0+IDRcbiAgICAgKlxuICAgICAqIF8uaW5kZXhPZihbMSwgMSwgMiwgMiwgMywgM10sIDIsIHRydWUpO1xuICAgICAqIC8vID0+IDJcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpbmRleE9mKGFycmF5LCB2YWx1ZSwgZnJvbUluZGV4KSB7XG4gICAgICBpZiAodHlwZW9mIGZyb21JbmRleCA9PSAnbnVtYmVyJykge1xuICAgICAgICB2YXIgbGVuZ3RoID0gYXJyYXkgPyBhcnJheS5sZW5ndGggOiAwO1xuICAgICAgICBmcm9tSW5kZXggPSAoZnJvbUluZGV4IDwgMCA/IG5hdGl2ZU1heCgwLCBsZW5ndGggKyBmcm9tSW5kZXgpIDogZnJvbUluZGV4IHx8IDApO1xuICAgICAgfSBlbHNlIGlmIChmcm9tSW5kZXgpIHtcbiAgICAgICAgdmFyIGluZGV4ID0gc29ydGVkSW5kZXgoYXJyYXksIHZhbHVlKTtcbiAgICAgICAgcmV0dXJuIGFycmF5W2luZGV4XSA9PT0gdmFsdWUgPyBpbmRleCA6IC0xO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGJhc2VJbmRleE9mKGFycmF5LCB2YWx1ZSwgZnJvbUluZGV4KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXRzIGFsbCBidXQgdGhlIGxhc3QgZWxlbWVudCBvciBsYXN0IGBuYCBlbGVtZW50cyBvZiBhbiBhcnJheS4gSWYgYVxuICAgICAqIGNhbGxiYWNrIGlzIHByb3ZpZGVkIGVsZW1lbnRzIGF0IHRoZSBlbmQgb2YgdGhlIGFycmF5IGFyZSBleGNsdWRlZCBmcm9tXG4gICAgICogdGhlIHJlc3VsdCBhcyBsb25nIGFzIHRoZSBjYWxsYmFjayByZXR1cm5zIHRydWV5LiBUaGUgY2FsbGJhY2sgaXMgYm91bmRcbiAgICAgKiB0byBgdGhpc0FyZ2AgYW5kIGludm9rZWQgd2l0aCB0aHJlZSBhcmd1bWVudHM7ICh2YWx1ZSwgaW5kZXgsIGFycmF5KS5cbiAgICAgKlxuICAgICAqIElmIGEgcHJvcGVydHkgbmFtZSBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ucGx1Y2tcIiBzdHlsZVxuICAgICAqIGNhbGxiYWNrIHdpbGwgcmV0dXJuIHRoZSBwcm9wZXJ0eSB2YWx1ZSBvZiB0aGUgZ2l2ZW4gZWxlbWVudC5cbiAgICAgKlxuICAgICAqIElmIGFuIG9iamVjdCBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFja1xuICAgICAqIHdpbGwgcmV0dXJuIGB0cnVlYCBmb3IgZWxlbWVudHMgdGhhdCBoYXZlIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBnaXZlbiBvYmplY3QsXG4gICAgICogZWxzZSBgZmFsc2VgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEFycmF5c1xuICAgICAqIEBwYXJhbSB7QXJyYXl9IGFycmF5IFRoZSBhcnJheSB0byBxdWVyeS5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufE9iamVjdHxudW1iZXJ8c3RyaW5nfSBbY2FsbGJhY2s9MV0gVGhlIGZ1bmN0aW9uIGNhbGxlZFxuICAgICAqICBwZXIgZWxlbWVudCBvciB0aGUgbnVtYmVyIG9mIGVsZW1lbnRzIHRvIGV4Y2x1ZGUuIElmIGEgcHJvcGVydHkgbmFtZSBvclxuICAgICAqICBvYmplY3QgaXMgcHJvdmlkZWQgaXQgd2lsbCBiZSB1c2VkIHRvIGNyZWF0ZSBhIFwiXy5wbHVja1wiIG9yIFwiXy53aGVyZVwiXG4gICAgICogIHN0eWxlIGNhbGxiYWNrLCByZXNwZWN0aXZlbHkuXG4gICAgICogQHBhcmFtIHsqfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIGEgc2xpY2Ugb2YgYGFycmF5YC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5pbml0aWFsKFsxLCAyLCAzXSk7XG4gICAgICogLy8gPT4gWzEsIDJdXG4gICAgICpcbiAgICAgKiBfLmluaXRpYWwoWzEsIDIsIDNdLCAyKTtcbiAgICAgKiAvLyA9PiBbMV1cbiAgICAgKlxuICAgICAqIF8uaW5pdGlhbChbMSwgMiwgM10sIGZ1bmN0aW9uKG51bSkge1xuICAgICAqICAgcmV0dXJuIG51bSA+IDE7XG4gICAgICogfSk7XG4gICAgICogLy8gPT4gWzFdXG4gICAgICpcbiAgICAgKiB2YXIgY2hhcmFjdGVycyA9IFtcbiAgICAgKiAgIHsgJ25hbWUnOiAnYmFybmV5JywgICdibG9ja2VkJzogZmFsc2UsICdlbXBsb3llcic6ICdzbGF0ZScgfSxcbiAgICAgKiAgIHsgJ25hbWUnOiAnZnJlZCcsICAgICdibG9ja2VkJzogdHJ1ZSwgICdlbXBsb3llcic6ICdzbGF0ZScgfSxcbiAgICAgKiAgIHsgJ25hbWUnOiAncGViYmxlcycsICdibG9ja2VkJzogdHJ1ZSwgICdlbXBsb3llcic6ICduYScgfVxuICAgICAqIF07XG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBcIl8ucGx1Y2tcIiBjYWxsYmFjayBzaG9ydGhhbmRcbiAgICAgKiBfLmluaXRpYWwoY2hhcmFjdGVycywgJ2Jsb2NrZWQnKTtcbiAgICAgKiAvLyA9PiBbeyAnbmFtZSc6ICdiYXJuZXknLCAgJ2Jsb2NrZWQnOiBmYWxzZSwgJ2VtcGxveWVyJzogJ3NsYXRlJyB9XVxuICAgICAqXG4gICAgICogLy8gdXNpbmcgXCJfLndoZXJlXCIgY2FsbGJhY2sgc2hvcnRoYW5kXG4gICAgICogXy5wbHVjayhfLmluaXRpYWwoY2hhcmFjdGVycywgeyAnZW1wbG95ZXInOiAnbmEnIH0pLCAnbmFtZScpO1xuICAgICAqIC8vID0+IFsnYmFybmV5JywgJ2ZyZWQnXVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGluaXRpYWwoYXJyYXksIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICB2YXIgbiA9IDAsXG4gICAgICAgICAgbGVuZ3RoID0gYXJyYXkgPyBhcnJheS5sZW5ndGggOiAwO1xuXG4gICAgICBpZiAodHlwZW9mIGNhbGxiYWNrICE9ICdudW1iZXInICYmIGNhbGxiYWNrICE9IG51bGwpIHtcbiAgICAgICAgdmFyIGluZGV4ID0gbGVuZ3RoO1xuICAgICAgICBjYWxsYmFjayA9IGxvZGFzaC5jcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZywgMyk7XG4gICAgICAgIHdoaWxlIChpbmRleC0tICYmIGNhbGxiYWNrKGFycmF5W2luZGV4XSwgaW5kZXgsIGFycmF5KSkge1xuICAgICAgICAgIG4rKztcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbiA9IChjYWxsYmFjayA9PSBudWxsIHx8IHRoaXNBcmcpID8gMSA6IGNhbGxiYWNrIHx8IG47XG4gICAgICB9XG4gICAgICByZXR1cm4gc2xpY2UoYXJyYXksIDAsIG5hdGl2ZU1pbihuYXRpdmVNYXgoMCwgbGVuZ3RoIC0gbiksIGxlbmd0aCkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW4gYXJyYXkgb2YgdW5pcXVlIHZhbHVlcyBwcmVzZW50IGluIGFsbCBwcm92aWRlZCBhcnJheXMgdXNpbmdcbiAgICAgKiBzdHJpY3QgZXF1YWxpdHkgZm9yIGNvbXBhcmlzb25zLCBpLmUuIGA9PT1gLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEFycmF5c1xuICAgICAqIEBwYXJhbSB7Li4uQXJyYXl9IFthcnJheV0gVGhlIGFycmF5cyB0byBpbnNwZWN0LlxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyBhbiBhcnJheSBvZiBzaGFyZWQgdmFsdWVzLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLmludGVyc2VjdGlvbihbMSwgMiwgM10sIFs1LCAyLCAxLCA0XSwgWzIsIDFdKTtcbiAgICAgKiAvLyA9PiBbMSwgMl1cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpbnRlcnNlY3Rpb24oKSB7XG4gICAgICB2YXIgYXJncyA9IFtdLFxuICAgICAgICAgIGFyZ3NJbmRleCA9IC0xLFxuICAgICAgICAgIGFyZ3NMZW5ndGggPSBhcmd1bWVudHMubGVuZ3RoLFxuICAgICAgICAgIGNhY2hlcyA9IGdldEFycmF5KCksXG4gICAgICAgICAgaW5kZXhPZiA9IGdldEluZGV4T2YoKSxcbiAgICAgICAgICB0cnVzdEluZGV4T2YgPSBpbmRleE9mID09PSBiYXNlSW5kZXhPZixcbiAgICAgICAgICBzZWVuID0gZ2V0QXJyYXkoKTtcblxuICAgICAgd2hpbGUgKCsrYXJnc0luZGV4IDwgYXJnc0xlbmd0aCkge1xuICAgICAgICB2YXIgdmFsdWUgPSBhcmd1bWVudHNbYXJnc0luZGV4XTtcbiAgICAgICAgaWYgKGlzQXJyYXkodmFsdWUpIHx8IGlzQXJndW1lbnRzKHZhbHVlKSkge1xuICAgICAgICAgIGFyZ3MucHVzaCh2YWx1ZSk7XG4gICAgICAgICAgY2FjaGVzLnB1c2godHJ1c3RJbmRleE9mICYmIHZhbHVlLmxlbmd0aCA+PSBsYXJnZUFycmF5U2l6ZSAmJlxuICAgICAgICAgICAgY3JlYXRlQ2FjaGUoYXJnc0luZGV4ID8gYXJnc1thcmdzSW5kZXhdIDogc2VlbikpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICB2YXIgYXJyYXkgPSBhcmdzWzBdLFxuICAgICAgICAgIGluZGV4ID0gLTEsXG4gICAgICAgICAgbGVuZ3RoID0gYXJyYXkgPyBhcnJheS5sZW5ndGggOiAwLFxuICAgICAgICAgIHJlc3VsdCA9IFtdO1xuXG4gICAgICBvdXRlcjpcbiAgICAgIHdoaWxlICgrK2luZGV4IDwgbGVuZ3RoKSB7XG4gICAgICAgIHZhciBjYWNoZSA9IGNhY2hlc1swXTtcbiAgICAgICAgdmFsdWUgPSBhcnJheVtpbmRleF07XG5cbiAgICAgICAgaWYgKChjYWNoZSA/IGNhY2hlSW5kZXhPZihjYWNoZSwgdmFsdWUpIDogaW5kZXhPZihzZWVuLCB2YWx1ZSkpIDwgMCkge1xuICAgICAgICAgIGFyZ3NJbmRleCA9IGFyZ3NMZW5ndGg7XG4gICAgICAgICAgKGNhY2hlIHx8IHNlZW4pLnB1c2godmFsdWUpO1xuICAgICAgICAgIHdoaWxlICgtLWFyZ3NJbmRleCkge1xuICAgICAgICAgICAgY2FjaGUgPSBjYWNoZXNbYXJnc0luZGV4XTtcbiAgICAgICAgICAgIGlmICgoY2FjaGUgPyBjYWNoZUluZGV4T2YoY2FjaGUsIHZhbHVlKSA6IGluZGV4T2YoYXJnc1thcmdzSW5kZXhdLCB2YWx1ZSkpIDwgMCkge1xuICAgICAgICAgICAgICBjb250aW51ZSBvdXRlcjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgcmVzdWx0LnB1c2godmFsdWUpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICB3aGlsZSAoYXJnc0xlbmd0aC0tKSB7XG4gICAgICAgIGNhY2hlID0gY2FjaGVzW2FyZ3NMZW5ndGhdO1xuICAgICAgICBpZiAoY2FjaGUpIHtcbiAgICAgICAgICByZWxlYXNlT2JqZWN0KGNhY2hlKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmVsZWFzZUFycmF5KGNhY2hlcyk7XG4gICAgICByZWxlYXNlQXJyYXkoc2Vlbik7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldHMgdGhlIGxhc3QgZWxlbWVudCBvciBsYXN0IGBuYCBlbGVtZW50cyBvZiBhbiBhcnJheS4gSWYgYSBjYWxsYmFjayBpc1xuICAgICAqIHByb3ZpZGVkIGVsZW1lbnRzIGF0IHRoZSBlbmQgb2YgdGhlIGFycmF5IGFyZSByZXR1cm5lZCBhcyBsb25nIGFzIHRoZVxuICAgICAqIGNhbGxiYWNrIHJldHVybnMgdHJ1ZXkuIFRoZSBjYWxsYmFjayBpcyBib3VuZCB0byBgdGhpc0FyZ2AgYW5kIGludm9rZWRcbiAgICAgKiB3aXRoIHRocmVlIGFyZ3VtZW50czsgKHZhbHVlLCBpbmRleCwgYXJyYXkpLlxuICAgICAqXG4gICAgICogSWYgYSBwcm9wZXJ0eSBuYW1lIGlzIHByb3ZpZGVkIGZvciBgY2FsbGJhY2tgIHRoZSBjcmVhdGVkIFwiXy5wbHVja1wiIHN0eWxlXG4gICAgICogY2FsbGJhY2sgd2lsbCByZXR1cm4gdGhlIHByb3BlcnR5IHZhbHVlIG9mIHRoZSBnaXZlbiBlbGVtZW50LlxuICAgICAqXG4gICAgICogSWYgYW4gb2JqZWN0IGlzIHByb3ZpZGVkIGZvciBgY2FsbGJhY2tgIHRoZSBjcmVhdGVkIFwiXy53aGVyZVwiIHN0eWxlIGNhbGxiYWNrXG4gICAgICogd2lsbCByZXR1cm4gYHRydWVgIGZvciBlbGVtZW50cyB0aGF0IGhhdmUgdGhlIHByb3BlcnRpZXMgb2YgdGhlIGdpdmVuIG9iamVjdCxcbiAgICAgKiBlbHNlIGBmYWxzZWAuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgQXJyYXlzXG4gICAgICogQHBhcmFtIHtBcnJheX0gYXJyYXkgVGhlIGFycmF5IHRvIHF1ZXJ5LlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb258T2JqZWN0fG51bWJlcnxzdHJpbmd9IFtjYWxsYmFja10gVGhlIGZ1bmN0aW9uIGNhbGxlZFxuICAgICAqICBwZXIgZWxlbWVudCBvciB0aGUgbnVtYmVyIG9mIGVsZW1lbnRzIHRvIHJldHVybi4gSWYgYSBwcm9wZXJ0eSBuYW1lIG9yXG4gICAgICogIG9iamVjdCBpcyBwcm92aWRlZCBpdCB3aWxsIGJlIHVzZWQgdG8gY3JlYXRlIGEgXCJfLnBsdWNrXCIgb3IgXCJfLndoZXJlXCJcbiAgICAgKiAgc3R5bGUgY2FsbGJhY2ssIHJlc3BlY3RpdmVseS5cbiAgICAgKiBAcGFyYW0geyp9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7Kn0gUmV0dXJucyB0aGUgbGFzdCBlbGVtZW50KHMpIG9mIGBhcnJheWAuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8ubGFzdChbMSwgMiwgM10pO1xuICAgICAqIC8vID0+IDNcbiAgICAgKlxuICAgICAqIF8ubGFzdChbMSwgMiwgM10sIDIpO1xuICAgICAqIC8vID0+IFsyLCAzXVxuICAgICAqXG4gICAgICogXy5sYXN0KFsxLCAyLCAzXSwgZnVuY3Rpb24obnVtKSB7XG4gICAgICogICByZXR1cm4gbnVtID4gMTtcbiAgICAgKiB9KTtcbiAgICAgKiAvLyA9PiBbMiwgM11cbiAgICAgKlxuICAgICAqIHZhciBjaGFyYWN0ZXJzID0gW1xuICAgICAqICAgeyAnbmFtZSc6ICdiYXJuZXknLCAgJ2Jsb2NrZWQnOiBmYWxzZSwgJ2VtcGxveWVyJzogJ3NsYXRlJyB9LFxuICAgICAqICAgeyAnbmFtZSc6ICdmcmVkJywgICAgJ2Jsb2NrZWQnOiB0cnVlLCAgJ2VtcGxveWVyJzogJ3NsYXRlJyB9LFxuICAgICAqICAgeyAnbmFtZSc6ICdwZWJibGVzJywgJ2Jsb2NrZWQnOiB0cnVlLCAgJ2VtcGxveWVyJzogJ25hJyB9XG4gICAgICogXTtcbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIFwiXy5wbHVja1wiIGNhbGxiYWNrIHNob3J0aGFuZFxuICAgICAqIF8ucGx1Y2soXy5sYXN0KGNoYXJhY3RlcnMsICdibG9ja2VkJyksICduYW1lJyk7XG4gICAgICogLy8gPT4gWydmcmVkJywgJ3BlYmJsZXMnXVxuICAgICAqXG4gICAgICogLy8gdXNpbmcgXCJfLndoZXJlXCIgY2FsbGJhY2sgc2hvcnRoYW5kXG4gICAgICogXy5sYXN0KGNoYXJhY3RlcnMsIHsgJ2VtcGxveWVyJzogJ25hJyB9KTtcbiAgICAgKiAvLyA9PiBbeyAnbmFtZSc6ICdwZWJibGVzJywgJ2Jsb2NrZWQnOiB0cnVlLCAnZW1wbG95ZXInOiAnbmEnIH1dXG4gICAgICovXG4gICAgZnVuY3Rpb24gbGFzdChhcnJheSwgY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICAgIHZhciBuID0gMCxcbiAgICAgICAgICBsZW5ndGggPSBhcnJheSA/IGFycmF5Lmxlbmd0aCA6IDA7XG5cbiAgICAgIGlmICh0eXBlb2YgY2FsbGJhY2sgIT0gJ251bWJlcicgJiYgY2FsbGJhY2sgIT0gbnVsbCkge1xuICAgICAgICB2YXIgaW5kZXggPSBsZW5ndGg7XG4gICAgICAgIGNhbGxiYWNrID0gbG9kYXNoLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnLCAzKTtcbiAgICAgICAgd2hpbGUgKGluZGV4LS0gJiYgY2FsbGJhY2soYXJyYXlbaW5kZXhdLCBpbmRleCwgYXJyYXkpKSB7XG4gICAgICAgICAgbisrO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBuID0gY2FsbGJhY2s7XG4gICAgICAgIGlmIChuID09IG51bGwgfHwgdGhpc0FyZykge1xuICAgICAgICAgIHJldHVybiBhcnJheSA/IGFycmF5W2xlbmd0aCAtIDFdIDogdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gc2xpY2UoYXJyYXksIG5hdGl2ZU1heCgwLCBsZW5ndGggLSBuKSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0cyB0aGUgaW5kZXggYXQgd2hpY2ggdGhlIGxhc3Qgb2NjdXJyZW5jZSBvZiBgdmFsdWVgIGlzIGZvdW5kIHVzaW5nIHN0cmljdFxuICAgICAqIGVxdWFsaXR5IGZvciBjb21wYXJpc29ucywgaS5lLiBgPT09YC4gSWYgYGZyb21JbmRleGAgaXMgbmVnYXRpdmUsIGl0IGlzIHVzZWRcbiAgICAgKiBhcyB0aGUgb2Zmc2V0IGZyb20gdGhlIGVuZCBvZiB0aGUgY29sbGVjdGlvbi5cbiAgICAgKlxuICAgICAqIElmIGEgcHJvcGVydHkgbmFtZSBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ucGx1Y2tcIiBzdHlsZVxuICAgICAqIGNhbGxiYWNrIHdpbGwgcmV0dXJuIHRoZSBwcm9wZXJ0eSB2YWx1ZSBvZiB0aGUgZ2l2ZW4gZWxlbWVudC5cbiAgICAgKlxuICAgICAqIElmIGFuIG9iamVjdCBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFja1xuICAgICAqIHdpbGwgcmV0dXJuIGB0cnVlYCBmb3IgZWxlbWVudHMgdGhhdCBoYXZlIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBnaXZlbiBvYmplY3QsXG4gICAgICogZWxzZSBgZmFsc2VgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEFycmF5c1xuICAgICAqIEBwYXJhbSB7QXJyYXl9IGFycmF5IFRoZSBhcnJheSB0byBzZWFyY2guXG4gICAgICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gc2VhcmNoIGZvci5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gW2Zyb21JbmRleD1hcnJheS5sZW5ndGgtMV0gVGhlIGluZGV4IHRvIHNlYXJjaCBmcm9tLlxuICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFJldHVybnMgdGhlIGluZGV4IG9mIHRoZSBtYXRjaGVkIHZhbHVlIG9yIGAtMWAuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8ubGFzdEluZGV4T2YoWzEsIDIsIDMsIDEsIDIsIDNdLCAyKTtcbiAgICAgKiAvLyA9PiA0XG4gICAgICpcbiAgICAgKiBfLmxhc3RJbmRleE9mKFsxLCAyLCAzLCAxLCAyLCAzXSwgMiwgMyk7XG4gICAgICogLy8gPT4gMVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGxhc3RJbmRleE9mKGFycmF5LCB2YWx1ZSwgZnJvbUluZGV4KSB7XG4gICAgICB2YXIgaW5kZXggPSBhcnJheSA/IGFycmF5Lmxlbmd0aCA6IDA7XG4gICAgICBpZiAodHlwZW9mIGZyb21JbmRleCA9PSAnbnVtYmVyJykge1xuICAgICAgICBpbmRleCA9IChmcm9tSW5kZXggPCAwID8gbmF0aXZlTWF4KDAsIGluZGV4ICsgZnJvbUluZGV4KSA6IG5hdGl2ZU1pbihmcm9tSW5kZXgsIGluZGV4IC0gMSkpICsgMTtcbiAgICAgIH1cbiAgICAgIHdoaWxlIChpbmRleC0tKSB7XG4gICAgICAgIGlmIChhcnJheVtpbmRleF0gPT09IHZhbHVlKSB7XG4gICAgICAgICAgcmV0dXJuIGluZGV4O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gLTE7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlcyBhbGwgcHJvdmlkZWQgdmFsdWVzIGZyb20gdGhlIGdpdmVuIGFycmF5IHVzaW5nIHN0cmljdCBlcXVhbGl0eSBmb3JcbiAgICAgKiBjb21wYXJpc29ucywgaS5lLiBgPT09YC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBBcnJheXNcbiAgICAgKiBAcGFyYW0ge0FycmF5fSBhcnJheSBUaGUgYXJyYXkgdG8gbW9kaWZ5LlxuICAgICAqIEBwYXJhbSB7Li4uKn0gW3ZhbHVlXSBUaGUgdmFsdWVzIHRvIHJlbW92ZS5cbiAgICAgKiBAcmV0dXJucyB7QXJyYXl9IFJldHVybnMgYGFycmF5YC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIGFycmF5ID0gWzEsIDIsIDMsIDEsIDIsIDNdO1xuICAgICAqIF8ucHVsbChhcnJheSwgMiwgMyk7XG4gICAgICogY29uc29sZS5sb2coYXJyYXkpO1xuICAgICAqIC8vID0+IFsxLCAxXVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHB1bGwoYXJyYXkpIHtcbiAgICAgIHZhciBhcmdzID0gYXJndW1lbnRzLFxuICAgICAgICAgIGFyZ3NJbmRleCA9IDAsXG4gICAgICAgICAgYXJnc0xlbmd0aCA9IGFyZ3MubGVuZ3RoLFxuICAgICAgICAgIGxlbmd0aCA9IGFycmF5ID8gYXJyYXkubGVuZ3RoIDogMDtcblxuICAgICAgd2hpbGUgKCsrYXJnc0luZGV4IDwgYXJnc0xlbmd0aCkge1xuICAgICAgICB2YXIgaW5kZXggPSAtMSxcbiAgICAgICAgICAgIHZhbHVlID0gYXJnc1thcmdzSW5kZXhdO1xuICAgICAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgICAgIGlmIChhcnJheVtpbmRleF0gPT09IHZhbHVlKSB7XG4gICAgICAgICAgICBzcGxpY2UuY2FsbChhcnJheSwgaW5kZXgtLSwgMSk7XG4gICAgICAgICAgICBsZW5ndGgtLTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBhcnJheTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIGFycmF5IG9mIG51bWJlcnMgKHBvc2l0aXZlIGFuZC9vciBuZWdhdGl2ZSkgcHJvZ3Jlc3NpbmcgZnJvbVxuICAgICAqIGBzdGFydGAgdXAgdG8gYnV0IG5vdCBpbmNsdWRpbmcgYGVuZGAuIElmIGBzdGFydGAgaXMgbGVzcyB0aGFuIGBzdG9wYCBhXG4gICAgICogemVyby1sZW5ndGggcmFuZ2UgaXMgY3JlYXRlZCB1bmxlc3MgYSBuZWdhdGl2ZSBgc3RlcGAgaXMgc3BlY2lmaWVkLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEFycmF5c1xuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbc3RhcnQ9MF0gVGhlIHN0YXJ0IG9mIHRoZSByYW5nZS5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gZW5kIFRoZSBlbmQgb2YgdGhlIHJhbmdlLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbc3RlcD0xXSBUaGUgdmFsdWUgdG8gaW5jcmVtZW50IG9yIGRlY3JlbWVudCBieS5cbiAgICAgKiBAcmV0dXJucyB7QXJyYXl9IFJldHVybnMgYSBuZXcgcmFuZ2UgYXJyYXkuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8ucmFuZ2UoNCk7XG4gICAgICogLy8gPT4gWzAsIDEsIDIsIDNdXG4gICAgICpcbiAgICAgKiBfLnJhbmdlKDEsIDUpO1xuICAgICAqIC8vID0+IFsxLCAyLCAzLCA0XVxuICAgICAqXG4gICAgICogXy5yYW5nZSgwLCAyMCwgNSk7XG4gICAgICogLy8gPT4gWzAsIDUsIDEwLCAxNV1cbiAgICAgKlxuICAgICAqIF8ucmFuZ2UoMCwgLTQsIC0xKTtcbiAgICAgKiAvLyA9PiBbMCwgLTEsIC0yLCAtM11cbiAgICAgKlxuICAgICAqIF8ucmFuZ2UoMSwgNCwgMCk7XG4gICAgICogLy8gPT4gWzEsIDEsIDFdXG4gICAgICpcbiAgICAgKiBfLnJhbmdlKDApO1xuICAgICAqIC8vID0+IFtdXG4gICAgICovXG4gICAgZnVuY3Rpb24gcmFuZ2Uoc3RhcnQsIGVuZCwgc3RlcCkge1xuICAgICAgc3RhcnQgPSArc3RhcnQgfHwgMDtcbiAgICAgIHN0ZXAgPSB0eXBlb2Ygc3RlcCA9PSAnbnVtYmVyJyA/IHN0ZXAgOiAoK3N0ZXAgfHwgMSk7XG5cbiAgICAgIGlmIChlbmQgPT0gbnVsbCkge1xuICAgICAgICBlbmQgPSBzdGFydDtcbiAgICAgICAgc3RhcnQgPSAwO1xuICAgICAgfVxuICAgICAgLy8gdXNlIGBBcnJheShsZW5ndGgpYCBzbyBlbmdpbmVzIGxpa2UgQ2hha3JhIGFuZCBWOCBhdm9pZCBzbG93ZXIgbW9kZXNcbiAgICAgIC8vIGh0dHA6Ly95b3V0dS5iZS9YQXFJcEdVOFpaayN0PTE3bTI1c1xuICAgICAgdmFyIGluZGV4ID0gLTEsXG4gICAgICAgICAgbGVuZ3RoID0gbmF0aXZlTWF4KDAsIGNlaWwoKGVuZCAtIHN0YXJ0KSAvIChzdGVwIHx8IDEpKSksXG4gICAgICAgICAgcmVzdWx0ID0gQXJyYXkobGVuZ3RoKTtcblxuICAgICAgd2hpbGUgKCsraW5kZXggPCBsZW5ndGgpIHtcbiAgICAgICAgcmVzdWx0W2luZGV4XSA9IHN0YXJ0O1xuICAgICAgICBzdGFydCArPSBzdGVwO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZW1vdmVzIGFsbCBlbGVtZW50cyBmcm9tIGFuIGFycmF5IHRoYXQgdGhlIGNhbGxiYWNrIHJldHVybnMgdHJ1ZXkgZm9yXG4gICAgICogYW5kIHJldHVybnMgYW4gYXJyYXkgb2YgcmVtb3ZlZCBlbGVtZW50cy4gVGhlIGNhbGxiYWNrIGlzIGJvdW5kIHRvIGB0aGlzQXJnYFxuICAgICAqIGFuZCBpbnZva2VkIHdpdGggdGhyZWUgYXJndW1lbnRzOyAodmFsdWUsIGluZGV4LCBhcnJheSkuXG4gICAgICpcbiAgICAgKiBJZiBhIHByb3BlcnR5IG5hbWUgaXMgcHJvdmlkZWQgZm9yIGBjYWxsYmFja2AgdGhlIGNyZWF0ZWQgXCJfLnBsdWNrXCIgc3R5bGVcbiAgICAgKiBjYWxsYmFjayB3aWxsIHJldHVybiB0aGUgcHJvcGVydHkgdmFsdWUgb2YgdGhlIGdpdmVuIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBJZiBhbiBvYmplY3QgaXMgcHJvdmlkZWQgZm9yIGBjYWxsYmFja2AgdGhlIGNyZWF0ZWQgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2tcbiAgICAgKiB3aWxsIHJldHVybiBgdHJ1ZWAgZm9yIGVsZW1lbnRzIHRoYXQgaGF2ZSB0aGUgcHJvcGVydGllcyBvZiB0aGUgZ2l2ZW4gb2JqZWN0LFxuICAgICAqIGVsc2UgYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBBcnJheXNcbiAgICAgKiBAcGFyYW0ge0FycmF5fSBhcnJheSBUaGUgYXJyYXkgdG8gbW9kaWZ5LlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb258T2JqZWN0fHN0cmluZ30gW2NhbGxiYWNrPWlkZW50aXR5XSBUaGUgZnVuY3Rpb24gY2FsbGVkXG4gICAgICogIHBlciBpdGVyYXRpb24uIElmIGEgcHJvcGVydHkgbmFtZSBvciBvYmplY3QgaXMgcHJvdmlkZWQgaXQgd2lsbCBiZSB1c2VkXG4gICAgICogIHRvIGNyZWF0ZSBhIFwiXy5wbHVja1wiIG9yIFwiXy53aGVyZVwiIHN0eWxlIGNhbGxiYWNrLCByZXNwZWN0aXZlbHkuXG4gICAgICogQHBhcmFtIHsqfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIGEgbmV3IGFycmF5IG9mIHJlbW92ZWQgZWxlbWVudHMuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIHZhciBhcnJheSA9IFsxLCAyLCAzLCA0LCA1LCA2XTtcbiAgICAgKiB2YXIgZXZlbnMgPSBfLnJlbW92ZShhcnJheSwgZnVuY3Rpb24obnVtKSB7IHJldHVybiBudW0gJSAyID09IDA7IH0pO1xuICAgICAqXG4gICAgICogY29uc29sZS5sb2coYXJyYXkpO1xuICAgICAqIC8vID0+IFsxLCAzLCA1XVxuICAgICAqXG4gICAgICogY29uc29sZS5sb2coZXZlbnMpO1xuICAgICAqIC8vID0+IFsyLCA0LCA2XVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHJlbW92ZShhcnJheSwgY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICAgIGxlbmd0aCA9IGFycmF5ID8gYXJyYXkubGVuZ3RoIDogMCxcbiAgICAgICAgICByZXN1bHQgPSBbXTtcblxuICAgICAgY2FsbGJhY2sgPSBsb2Rhc2guY3JlYXRlQ2FsbGJhY2soY2FsbGJhY2ssIHRoaXNBcmcsIDMpO1xuICAgICAgd2hpbGUgKCsraW5kZXggPCBsZW5ndGgpIHtcbiAgICAgICAgdmFyIHZhbHVlID0gYXJyYXlbaW5kZXhdO1xuICAgICAgICBpZiAoY2FsbGJhY2sodmFsdWUsIGluZGV4LCBhcnJheSkpIHtcbiAgICAgICAgICByZXN1bHQucHVzaCh2YWx1ZSk7XG4gICAgICAgICAgc3BsaWNlLmNhbGwoYXJyYXksIGluZGV4LS0sIDEpO1xuICAgICAgICAgIGxlbmd0aC0tO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoZSBvcHBvc2l0ZSBvZiBgXy5pbml0aWFsYCB0aGlzIG1ldGhvZCBnZXRzIGFsbCBidXQgdGhlIGZpcnN0IGVsZW1lbnQgb3JcbiAgICAgKiBmaXJzdCBgbmAgZWxlbWVudHMgb2YgYW4gYXJyYXkuIElmIGEgY2FsbGJhY2sgZnVuY3Rpb24gaXMgcHJvdmlkZWQgZWxlbWVudHNcbiAgICAgKiBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBhcnJheSBhcmUgZXhjbHVkZWQgZnJvbSB0aGUgcmVzdWx0IGFzIGxvbmcgYXMgdGhlXG4gICAgICogY2FsbGJhY2sgcmV0dXJucyB0cnVleS4gVGhlIGNhbGxiYWNrIGlzIGJvdW5kIHRvIGB0aGlzQXJnYCBhbmQgaW52b2tlZFxuICAgICAqIHdpdGggdGhyZWUgYXJndW1lbnRzOyAodmFsdWUsIGluZGV4LCBhcnJheSkuXG4gICAgICpcbiAgICAgKiBJZiBhIHByb3BlcnR5IG5hbWUgaXMgcHJvdmlkZWQgZm9yIGBjYWxsYmFja2AgdGhlIGNyZWF0ZWQgXCJfLnBsdWNrXCIgc3R5bGVcbiAgICAgKiBjYWxsYmFjayB3aWxsIHJldHVybiB0aGUgcHJvcGVydHkgdmFsdWUgb2YgdGhlIGdpdmVuIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBJZiBhbiBvYmplY3QgaXMgcHJvdmlkZWQgZm9yIGBjYWxsYmFja2AgdGhlIGNyZWF0ZWQgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2tcbiAgICAgKiB3aWxsIHJldHVybiBgdHJ1ZWAgZm9yIGVsZW1lbnRzIHRoYXQgaGF2ZSB0aGUgcHJvcGVydGllcyBvZiB0aGUgZ2l2ZW4gb2JqZWN0LFxuICAgICAqIGVsc2UgYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBhbGlhcyBkcm9wLCB0YWlsXG4gICAgICogQGNhdGVnb3J5IEFycmF5c1xuICAgICAqIEBwYXJhbSB7QXJyYXl9IGFycmF5IFRoZSBhcnJheSB0byBxdWVyeS5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufE9iamVjdHxudW1iZXJ8c3RyaW5nfSBbY2FsbGJhY2s9MV0gVGhlIGZ1bmN0aW9uIGNhbGxlZFxuICAgICAqICBwZXIgZWxlbWVudCBvciB0aGUgbnVtYmVyIG9mIGVsZW1lbnRzIHRvIGV4Y2x1ZGUuIElmIGEgcHJvcGVydHkgbmFtZSBvclxuICAgICAqICBvYmplY3QgaXMgcHJvdmlkZWQgaXQgd2lsbCBiZSB1c2VkIHRvIGNyZWF0ZSBhIFwiXy5wbHVja1wiIG9yIFwiXy53aGVyZVwiXG4gICAgICogIHN0eWxlIGNhbGxiYWNrLCByZXNwZWN0aXZlbHkuXG4gICAgICogQHBhcmFtIHsqfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIGEgc2xpY2Ugb2YgYGFycmF5YC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5yZXN0KFsxLCAyLCAzXSk7XG4gICAgICogLy8gPT4gWzIsIDNdXG4gICAgICpcbiAgICAgKiBfLnJlc3QoWzEsIDIsIDNdLCAyKTtcbiAgICAgKiAvLyA9PiBbM11cbiAgICAgKlxuICAgICAqIF8ucmVzdChbMSwgMiwgM10sIGZ1bmN0aW9uKG51bSkge1xuICAgICAqICAgcmV0dXJuIG51bSA8IDM7XG4gICAgICogfSk7XG4gICAgICogLy8gPT4gWzNdXG4gICAgICpcbiAgICAgKiB2YXIgY2hhcmFjdGVycyA9IFtcbiAgICAgKiAgIHsgJ25hbWUnOiAnYmFybmV5JywgICdibG9ja2VkJzogdHJ1ZSwgICdlbXBsb3llcic6ICdzbGF0ZScgfSxcbiAgICAgKiAgIHsgJ25hbWUnOiAnZnJlZCcsICAgICdibG9ja2VkJzogZmFsc2UsICAnZW1wbG95ZXInOiAnc2xhdGUnIH0sXG4gICAgICogICB7ICduYW1lJzogJ3BlYmJsZXMnLCAnYmxvY2tlZCc6IHRydWUsICdlbXBsb3llcic6ICduYScgfVxuICAgICAqIF07XG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBcIl8ucGx1Y2tcIiBjYWxsYmFjayBzaG9ydGhhbmRcbiAgICAgKiBfLnBsdWNrKF8ucmVzdChjaGFyYWN0ZXJzLCAnYmxvY2tlZCcpLCAnbmFtZScpO1xuICAgICAqIC8vID0+IFsnZnJlZCcsICdwZWJibGVzJ11cbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIFwiXy53aGVyZVwiIGNhbGxiYWNrIHNob3J0aGFuZFxuICAgICAqIF8ucmVzdChjaGFyYWN0ZXJzLCB7ICdlbXBsb3llcic6ICdzbGF0ZScgfSk7XG4gICAgICogLy8gPT4gW3sgJ25hbWUnOiAncGViYmxlcycsICdibG9ja2VkJzogdHJ1ZSwgJ2VtcGxveWVyJzogJ25hJyB9XVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHJlc3QoYXJyYXksIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICBpZiAodHlwZW9mIGNhbGxiYWNrICE9ICdudW1iZXInICYmIGNhbGxiYWNrICE9IG51bGwpIHtcbiAgICAgICAgdmFyIG4gPSAwLFxuICAgICAgICAgICAgaW5kZXggPSAtMSxcbiAgICAgICAgICAgIGxlbmd0aCA9IGFycmF5ID8gYXJyYXkubGVuZ3RoIDogMDtcblxuICAgICAgICBjYWxsYmFjayA9IGxvZGFzaC5jcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZywgMyk7XG4gICAgICAgIHdoaWxlICgrK2luZGV4IDwgbGVuZ3RoICYmIGNhbGxiYWNrKGFycmF5W2luZGV4XSwgaW5kZXgsIGFycmF5KSkge1xuICAgICAgICAgIG4rKztcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbiA9IChjYWxsYmFjayA9PSBudWxsIHx8IHRoaXNBcmcpID8gMSA6IG5hdGl2ZU1heCgwLCBjYWxsYmFjayk7XG4gICAgICB9XG4gICAgICByZXR1cm4gc2xpY2UoYXJyYXksIG4pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFVzZXMgYSBiaW5hcnkgc2VhcmNoIHRvIGRldGVybWluZSB0aGUgc21hbGxlc3QgaW5kZXggYXQgd2hpY2ggYSB2YWx1ZVxuICAgICAqIHNob3VsZCBiZSBpbnNlcnRlZCBpbnRvIGEgZ2l2ZW4gc29ydGVkIGFycmF5IGluIG9yZGVyIHRvIG1haW50YWluIHRoZSBzb3J0XG4gICAgICogb3JkZXIgb2YgdGhlIGFycmF5LiBJZiBhIGNhbGxiYWNrIGlzIHByb3ZpZGVkIGl0IHdpbGwgYmUgZXhlY3V0ZWQgZm9yXG4gICAgICogYHZhbHVlYCBhbmQgZWFjaCBlbGVtZW50IG9mIGBhcnJheWAgdG8gY29tcHV0ZSB0aGVpciBzb3J0IHJhbmtpbmcuIFRoZVxuICAgICAqIGNhbGxiYWNrIGlzIGJvdW5kIHRvIGB0aGlzQXJnYCBhbmQgaW52b2tlZCB3aXRoIG9uZSBhcmd1bWVudDsgKHZhbHVlKS5cbiAgICAgKlxuICAgICAqIElmIGEgcHJvcGVydHkgbmFtZSBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ucGx1Y2tcIiBzdHlsZVxuICAgICAqIGNhbGxiYWNrIHdpbGwgcmV0dXJuIHRoZSBwcm9wZXJ0eSB2YWx1ZSBvZiB0aGUgZ2l2ZW4gZWxlbWVudC5cbiAgICAgKlxuICAgICAqIElmIGFuIG9iamVjdCBpcyBwcm92aWRlZCBmb3IgYGNhbGxiYWNrYCB0aGUgY3JlYXRlZCBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFja1xuICAgICAqIHdpbGwgcmV0dXJuIGB0cnVlYCBmb3IgZWxlbWVudHMgdGhhdCBoYXZlIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBnaXZlbiBvYmplY3QsXG4gICAgICogZWxzZSBgZmFsc2VgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEFycmF5c1xuICAgICAqIEBwYXJhbSB7QXJyYXl9IGFycmF5IFRoZSBhcnJheSB0byBpbnNwZWN0LlxuICAgICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGV2YWx1YXRlLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb258T2JqZWN0fHN0cmluZ30gW2NhbGxiYWNrPWlkZW50aXR5XSBUaGUgZnVuY3Rpb24gY2FsbGVkXG4gICAgICogIHBlciBpdGVyYXRpb24uIElmIGEgcHJvcGVydHkgbmFtZSBvciBvYmplY3QgaXMgcHJvdmlkZWQgaXQgd2lsbCBiZSB1c2VkXG4gICAgICogIHRvIGNyZWF0ZSBhIFwiXy5wbHVja1wiIG9yIFwiXy53aGVyZVwiIHN0eWxlIGNhbGxiYWNrLCByZXNwZWN0aXZlbHkuXG4gICAgICogQHBhcmFtIHsqfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHJldHVybnMge251bWJlcn0gUmV0dXJucyB0aGUgaW5kZXggYXQgd2hpY2ggYHZhbHVlYCBzaG91bGQgYmUgaW5zZXJ0ZWRcbiAgICAgKiAgaW50byBgYXJyYXlgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLnNvcnRlZEluZGV4KFsyMCwgMzAsIDUwXSwgNDApO1xuICAgICAqIC8vID0+IDJcbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIFwiXy5wbHVja1wiIGNhbGxiYWNrIHNob3J0aGFuZFxuICAgICAqIF8uc29ydGVkSW5kZXgoW3sgJ3gnOiAyMCB9LCB7ICd4JzogMzAgfSwgeyAneCc6IDUwIH1dLCB7ICd4JzogNDAgfSwgJ3gnKTtcbiAgICAgKiAvLyA9PiAyXG4gICAgICpcbiAgICAgKiB2YXIgZGljdCA9IHtcbiAgICAgKiAgICd3b3JkVG9OdW1iZXInOiB7ICd0d2VudHknOiAyMCwgJ3RoaXJ0eSc6IDMwLCAnZm91cnR5JzogNDAsICdmaWZ0eSc6IDUwIH1cbiAgICAgKiB9O1xuICAgICAqXG4gICAgICogXy5zb3J0ZWRJbmRleChbJ3R3ZW50eScsICd0aGlydHknLCAnZmlmdHknXSwgJ2ZvdXJ0eScsIGZ1bmN0aW9uKHdvcmQpIHtcbiAgICAgKiAgIHJldHVybiBkaWN0LndvcmRUb051bWJlclt3b3JkXTtcbiAgICAgKiB9KTtcbiAgICAgKiAvLyA9PiAyXG4gICAgICpcbiAgICAgKiBfLnNvcnRlZEluZGV4KFsndHdlbnR5JywgJ3RoaXJ0eScsICdmaWZ0eSddLCAnZm91cnR5JywgZnVuY3Rpb24od29yZCkge1xuICAgICAqICAgcmV0dXJuIHRoaXMud29yZFRvTnVtYmVyW3dvcmRdO1xuICAgICAqIH0sIGRpY3QpO1xuICAgICAqIC8vID0+IDJcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBzb3J0ZWRJbmRleChhcnJheSwgdmFsdWUsIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICB2YXIgbG93ID0gMCxcbiAgICAgICAgICBoaWdoID0gYXJyYXkgPyBhcnJheS5sZW5ndGggOiBsb3c7XG5cbiAgICAgIC8vIGV4cGxpY2l0bHkgcmVmZXJlbmNlIGBpZGVudGl0eWAgZm9yIGJldHRlciBpbmxpbmluZyBpbiBGaXJlZm94XG4gICAgICBjYWxsYmFjayA9IGNhbGxiYWNrID8gbG9kYXNoLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnLCAxKSA6IGlkZW50aXR5O1xuICAgICAgdmFsdWUgPSBjYWxsYmFjayh2YWx1ZSk7XG5cbiAgICAgIHdoaWxlIChsb3cgPCBoaWdoKSB7XG4gICAgICAgIHZhciBtaWQgPSAobG93ICsgaGlnaCkgPj4+IDE7XG4gICAgICAgIChjYWxsYmFjayhhcnJheVttaWRdKSA8IHZhbHVlKVxuICAgICAgICAgID8gbG93ID0gbWlkICsgMVxuICAgICAgICAgIDogaGlnaCA9IG1pZDtcbiAgICAgIH1cbiAgICAgIHJldHVybiBsb3c7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbiBhcnJheSBvZiB1bmlxdWUgdmFsdWVzLCBpbiBvcmRlciwgb2YgdGhlIHByb3ZpZGVkIGFycmF5cyB1c2luZ1xuICAgICAqIHN0cmljdCBlcXVhbGl0eSBmb3IgY29tcGFyaXNvbnMsIGkuZS4gYD09PWAuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgQXJyYXlzXG4gICAgICogQHBhcmFtIHsuLi5BcnJheX0gW2FycmF5XSBUaGUgYXJyYXlzIHRvIGluc3BlY3QuXG4gICAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIGFuIGFycmF5IG9mIGNvbWJpbmVkIHZhbHVlcy5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy51bmlvbihbMSwgMiwgM10sIFs1LCAyLCAxLCA0XSwgWzIsIDFdKTtcbiAgICAgKiAvLyA9PiBbMSwgMiwgMywgNSwgNF1cbiAgICAgKi9cbiAgICBmdW5jdGlvbiB1bmlvbigpIHtcbiAgICAgIHJldHVybiBiYXNlVW5pcShiYXNlRmxhdHRlbihhcmd1bWVudHMsIHRydWUsIHRydWUpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgZHVwbGljYXRlLXZhbHVlLWZyZWUgdmVyc2lvbiBvZiBhbiBhcnJheSB1c2luZyBzdHJpY3QgZXF1YWxpdHlcbiAgICAgKiBmb3IgY29tcGFyaXNvbnMsIGkuZS4gYD09PWAuIElmIHRoZSBhcnJheSBpcyBzb3J0ZWQsIHByb3ZpZGluZ1xuICAgICAqIGB0cnVlYCBmb3IgYGlzU29ydGVkYCB3aWxsIHVzZSBhIGZhc3RlciBhbGdvcml0aG0uIElmIGEgY2FsbGJhY2sgaXMgcHJvdmlkZWRcbiAgICAgKiBlYWNoIGVsZW1lbnQgb2YgYGFycmF5YCBpcyBwYXNzZWQgdGhyb3VnaCB0aGUgY2FsbGJhY2sgYmVmb3JlIHVuaXF1ZW5lc3NcbiAgICAgKiBpcyBjb21wdXRlZC4gVGhlIGNhbGxiYWNrIGlzIGJvdW5kIHRvIGB0aGlzQXJnYCBhbmQgaW52b2tlZCB3aXRoIHRocmVlXG4gICAgICogYXJndW1lbnRzOyAodmFsdWUsIGluZGV4LCBhcnJheSkuXG4gICAgICpcbiAgICAgKiBJZiBhIHByb3BlcnR5IG5hbWUgaXMgcHJvdmlkZWQgZm9yIGBjYWxsYmFja2AgdGhlIGNyZWF0ZWQgXCJfLnBsdWNrXCIgc3R5bGVcbiAgICAgKiBjYWxsYmFjayB3aWxsIHJldHVybiB0aGUgcHJvcGVydHkgdmFsdWUgb2YgdGhlIGdpdmVuIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBJZiBhbiBvYmplY3QgaXMgcHJvdmlkZWQgZm9yIGBjYWxsYmFja2AgdGhlIGNyZWF0ZWQgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2tcbiAgICAgKiB3aWxsIHJldHVybiBgdHJ1ZWAgZm9yIGVsZW1lbnRzIHRoYXQgaGF2ZSB0aGUgcHJvcGVydGllcyBvZiB0aGUgZ2l2ZW4gb2JqZWN0LFxuICAgICAqIGVsc2UgYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBhbGlhcyB1bmlxdWVcbiAgICAgKiBAY2F0ZWdvcnkgQXJyYXlzXG4gICAgICogQHBhcmFtIHtBcnJheX0gYXJyYXkgVGhlIGFycmF5IHRvIHByb2Nlc3MuXG4gICAgICogQHBhcmFtIHtib29sZWFufSBbaXNTb3J0ZWQ9ZmFsc2VdIEEgZmxhZyB0byBpbmRpY2F0ZSB0aGF0IGBhcnJheWAgaXMgc29ydGVkLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb258T2JqZWN0fHN0cmluZ30gW2NhbGxiYWNrPWlkZW50aXR5XSBUaGUgZnVuY3Rpb24gY2FsbGVkXG4gICAgICogIHBlciBpdGVyYXRpb24uIElmIGEgcHJvcGVydHkgbmFtZSBvciBvYmplY3QgaXMgcHJvdmlkZWQgaXQgd2lsbCBiZSB1c2VkXG4gICAgICogIHRvIGNyZWF0ZSBhIFwiXy5wbHVja1wiIG9yIFwiXy53aGVyZVwiIHN0eWxlIGNhbGxiYWNrLCByZXNwZWN0aXZlbHkuXG4gICAgICogQHBhcmFtIHsqfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIGEgZHVwbGljYXRlLXZhbHVlLWZyZWUgYXJyYXkuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8udW5pcShbMSwgMiwgMSwgMywgMV0pO1xuICAgICAqIC8vID0+IFsxLCAyLCAzXVxuICAgICAqXG4gICAgICogXy51bmlxKFsxLCAxLCAyLCAyLCAzXSwgdHJ1ZSk7XG4gICAgICogLy8gPT4gWzEsIDIsIDNdXG4gICAgICpcbiAgICAgKiBfLnVuaXEoWydBJywgJ2InLCAnQycsICdhJywgJ0InLCAnYyddLCBmdW5jdGlvbihsZXR0ZXIpIHsgcmV0dXJuIGxldHRlci50b0xvd2VyQ2FzZSgpOyB9KTtcbiAgICAgKiAvLyA9PiBbJ0EnLCAnYicsICdDJ11cbiAgICAgKlxuICAgICAqIF8udW5pcShbMSwgMi41LCAzLCAxLjUsIDIsIDMuNV0sIGZ1bmN0aW9uKG51bSkgeyByZXR1cm4gdGhpcy5mbG9vcihudW0pOyB9LCBNYXRoKTtcbiAgICAgKiAvLyA9PiBbMSwgMi41LCAzXVxuICAgICAqXG4gICAgICogLy8gdXNpbmcgXCJfLnBsdWNrXCIgY2FsbGJhY2sgc2hvcnRoYW5kXG4gICAgICogXy51bmlxKFt7ICd4JzogMSB9LCB7ICd4JzogMiB9LCB7ICd4JzogMSB9XSwgJ3gnKTtcbiAgICAgKiAvLyA9PiBbeyAneCc6IDEgfSwgeyAneCc6IDIgfV1cbiAgICAgKi9cbiAgICBmdW5jdGlvbiB1bmlxKGFycmF5LCBpc1NvcnRlZCwgY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICAgIC8vIGp1Z2dsZSBhcmd1bWVudHNcbiAgICAgIGlmICh0eXBlb2YgaXNTb3J0ZWQgIT0gJ2Jvb2xlYW4nICYmIGlzU29ydGVkICE9IG51bGwpIHtcbiAgICAgICAgdGhpc0FyZyA9IGNhbGxiYWNrO1xuICAgICAgICBjYWxsYmFjayA9ICh0eXBlb2YgaXNTb3J0ZWQgIT0gJ2Z1bmN0aW9uJyAmJiB0aGlzQXJnICYmIHRoaXNBcmdbaXNTb3J0ZWRdID09PSBhcnJheSkgPyBudWxsIDogaXNTb3J0ZWQ7XG4gICAgICAgIGlzU29ydGVkID0gZmFsc2U7XG4gICAgICB9XG4gICAgICBpZiAoY2FsbGJhY2sgIT0gbnVsbCkge1xuICAgICAgICBjYWxsYmFjayA9IGxvZGFzaC5jcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZywgMyk7XG4gICAgICB9XG4gICAgICByZXR1cm4gYmFzZVVuaXEoYXJyYXksIGlzU29ydGVkLCBjYWxsYmFjayk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbiBhcnJheSBleGNsdWRpbmcgYWxsIHByb3ZpZGVkIHZhbHVlcyB1c2luZyBzdHJpY3QgZXF1YWxpdHkgZm9yXG4gICAgICogY29tcGFyaXNvbnMsIGkuZS4gYD09PWAuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgQXJyYXlzXG4gICAgICogQHBhcmFtIHtBcnJheX0gYXJyYXkgVGhlIGFycmF5IHRvIGZpbHRlci5cbiAgICAgKiBAcGFyYW0gey4uLip9IFt2YWx1ZV0gVGhlIHZhbHVlcyB0byBleGNsdWRlLlxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyBhIG5ldyBhcnJheSBvZiBmaWx0ZXJlZCB2YWx1ZXMuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8ud2l0aG91dChbMSwgMiwgMSwgMCwgMywgMSwgNF0sIDAsIDEpO1xuICAgICAqIC8vID0+IFsyLCAzLCA0XVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHdpdGhvdXQoYXJyYXkpIHtcbiAgICAgIHJldHVybiBiYXNlRGlmZmVyZW5jZShhcnJheSwgc2xpY2UoYXJndW1lbnRzLCAxKSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbiBhcnJheSB0aGF0IGlzIHRoZSBzeW1tZXRyaWMgZGlmZmVyZW5jZSBvZiB0aGUgcHJvdmlkZWQgYXJyYXlzLlxuICAgICAqIFNlZSBodHRwOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1N5bW1ldHJpY19kaWZmZXJlbmNlLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEFycmF5c1xuICAgICAqIEBwYXJhbSB7Li4uQXJyYXl9IFthcnJheV0gVGhlIGFycmF5cyB0byBpbnNwZWN0LlxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyBhbiBhcnJheSBvZiB2YWx1ZXMuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8ueG9yKFsxLCAyLCAzXSwgWzUsIDIsIDEsIDRdKTtcbiAgICAgKiAvLyA9PiBbMywgNSwgNF1cbiAgICAgKlxuICAgICAqIF8ueG9yKFsxLCAyLCA1XSwgWzIsIDMsIDVdLCBbMywgNCwgNV0pO1xuICAgICAqIC8vID0+IFsxLCA0LCA1XVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHhvcigpIHtcbiAgICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICAgIGxlbmd0aCA9IGFyZ3VtZW50cy5sZW5ndGg7XG5cbiAgICAgIHdoaWxlICgrK2luZGV4IDwgbGVuZ3RoKSB7XG4gICAgICAgIHZhciBhcnJheSA9IGFyZ3VtZW50c1tpbmRleF07XG4gICAgICAgIGlmIChpc0FycmF5KGFycmF5KSB8fCBpc0FyZ3VtZW50cyhhcnJheSkpIHtcbiAgICAgICAgICB2YXIgcmVzdWx0ID0gcmVzdWx0XG4gICAgICAgICAgICA/IGJhc2VVbmlxKGJhc2VEaWZmZXJlbmNlKHJlc3VsdCwgYXJyYXkpLmNvbmNhdChiYXNlRGlmZmVyZW5jZShhcnJheSwgcmVzdWx0KSkpXG4gICAgICAgICAgICA6IGFycmF5O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0IHx8IFtdO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW4gYXJyYXkgb2YgZ3JvdXBlZCBlbGVtZW50cywgdGhlIGZpcnN0IG9mIHdoaWNoIGNvbnRhaW5zIHRoZSBmaXJzdFxuICAgICAqIGVsZW1lbnRzIG9mIHRoZSBnaXZlbiBhcnJheXMsIHRoZSBzZWNvbmQgb2Ygd2hpY2ggY29udGFpbnMgdGhlIHNlY29uZFxuICAgICAqIGVsZW1lbnRzIG9mIHRoZSBnaXZlbiBhcnJheXMsIGFuZCBzbyBvbi5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBhbGlhcyB1bnppcFxuICAgICAqIEBjYXRlZ29yeSBBcnJheXNcbiAgICAgKiBAcGFyYW0gey4uLkFycmF5fSBbYXJyYXldIEFycmF5cyB0byBwcm9jZXNzLlxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyBhIG5ldyBhcnJheSBvZiBncm91cGVkIGVsZW1lbnRzLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLnppcChbJ2ZyZWQnLCAnYmFybmV5J10sIFszMCwgNDBdLCBbdHJ1ZSwgZmFsc2VdKTtcbiAgICAgKiAvLyA9PiBbWydmcmVkJywgMzAsIHRydWVdLCBbJ2Jhcm5leScsIDQwLCBmYWxzZV1dXG4gICAgICovXG4gICAgZnVuY3Rpb24gemlwKCkge1xuICAgICAgdmFyIGFycmF5ID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgPyBhcmd1bWVudHMgOiBhcmd1bWVudHNbMF0sXG4gICAgICAgICAgaW5kZXggPSAtMSxcbiAgICAgICAgICBsZW5ndGggPSBhcnJheSA/IG1heChwbHVjayhhcnJheSwgJ2xlbmd0aCcpKSA6IDAsXG4gICAgICAgICAgcmVzdWx0ID0gQXJyYXkobGVuZ3RoIDwgMCA/IDAgOiBsZW5ndGgpO1xuXG4gICAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgICByZXN1bHRbaW5kZXhdID0gcGx1Y2soYXJyYXksIGluZGV4KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbiBvYmplY3QgY29tcG9zZWQgZnJvbSBhcnJheXMgb2YgYGtleXNgIGFuZCBgdmFsdWVzYC4gUHJvdmlkZVxuICAgICAqIGVpdGhlciBhIHNpbmdsZSB0d28gZGltZW5zaW9uYWwgYXJyYXksIGkuZS4gYFtba2V5MSwgdmFsdWUxXSwgW2tleTIsIHZhbHVlMl1dYFxuICAgICAqIG9yIHR3byBhcnJheXMsIG9uZSBvZiBga2V5c2AgYW5kIG9uZSBvZiBjb3JyZXNwb25kaW5nIGB2YWx1ZXNgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGFsaWFzIG9iamVjdFxuICAgICAqIEBjYXRlZ29yeSBBcnJheXNcbiAgICAgKiBAcGFyYW0ge0FycmF5fSBrZXlzIFRoZSBhcnJheSBvZiBrZXlzLlxuICAgICAqIEBwYXJhbSB7QXJyYXl9IFt2YWx1ZXM9W11dIFRoZSBhcnJheSBvZiB2YWx1ZXMuXG4gICAgICogQHJldHVybnMge09iamVjdH0gUmV0dXJucyBhbiBvYmplY3QgY29tcG9zZWQgb2YgdGhlIGdpdmVuIGtleXMgYW5kXG4gICAgICogIGNvcnJlc3BvbmRpbmcgdmFsdWVzLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLnppcE9iamVjdChbJ2ZyZWQnLCAnYmFybmV5J10sIFszMCwgNDBdKTtcbiAgICAgKiAvLyA9PiB7ICdmcmVkJzogMzAsICdiYXJuZXknOiA0MCB9XG4gICAgICovXG4gICAgZnVuY3Rpb24gemlwT2JqZWN0KGtleXMsIHZhbHVlcykge1xuICAgICAgdmFyIGluZGV4ID0gLTEsXG4gICAgICAgICAgbGVuZ3RoID0ga2V5cyA/IGtleXMubGVuZ3RoIDogMCxcbiAgICAgICAgICByZXN1bHQgPSB7fTtcblxuICAgICAgaWYgKCF2YWx1ZXMgJiYgbGVuZ3RoICYmICFpc0FycmF5KGtleXNbMF0pKSB7XG4gICAgICAgIHZhbHVlcyA9IFtdO1xuICAgICAgfVxuICAgICAgd2hpbGUgKCsraW5kZXggPCBsZW5ndGgpIHtcbiAgICAgICAgdmFyIGtleSA9IGtleXNbaW5kZXhdO1xuICAgICAgICBpZiAodmFsdWVzKSB7XG4gICAgICAgICAgcmVzdWx0W2tleV0gPSB2YWx1ZXNbaW5kZXhdO1xuICAgICAgICB9IGVsc2UgaWYgKGtleSkge1xuICAgICAgICAgIHJlc3VsdFtrZXlbMF1dID0ga2V5WzFdO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIGZ1bmN0aW9uIHRoYXQgZXhlY3V0ZXMgYGZ1bmNgLCB3aXRoICB0aGUgYHRoaXNgIGJpbmRpbmcgYW5kXG4gICAgICogYXJndW1lbnRzIG9mIHRoZSBjcmVhdGVkIGZ1bmN0aW9uLCBvbmx5IGFmdGVyIGJlaW5nIGNhbGxlZCBgbmAgdGltZXMuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgRnVuY3Rpb25zXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IG4gVGhlIG51bWJlciBvZiB0aW1lcyB0aGUgZnVuY3Rpb24gbXVzdCBiZSBjYWxsZWQgYmVmb3JlXG4gICAgICogIGBmdW5jYCBpcyBleGVjdXRlZC5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBmdW5jIFRoZSBmdW5jdGlvbiB0byByZXN0cmljdC5cbiAgICAgKiBAcmV0dXJucyB7RnVuY3Rpb259IFJldHVybnMgdGhlIG5ldyByZXN0cmljdGVkIGZ1bmN0aW9uLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgc2F2ZXMgPSBbJ3Byb2ZpbGUnLCAnc2V0dGluZ3MnXTtcbiAgICAgKlxuICAgICAqIHZhciBkb25lID0gXy5hZnRlcihzYXZlcy5sZW5ndGgsIGZ1bmN0aW9uKCkge1xuICAgICAqICAgY29uc29sZS5sb2coJ0RvbmUgc2F2aW5nIScpO1xuICAgICAqIH0pO1xuICAgICAqXG4gICAgICogXy5mb3JFYWNoKHNhdmVzLCBmdW5jdGlvbih0eXBlKSB7XG4gICAgICogICBhc3luY1NhdmUoeyAndHlwZSc6IHR5cGUsICdjb21wbGV0ZSc6IGRvbmUgfSk7XG4gICAgICogfSk7XG4gICAgICogLy8gPT4gbG9ncyAnRG9uZSBzYXZpbmchJywgYWZ0ZXIgYWxsIHNhdmVzIGhhdmUgY29tcGxldGVkXG4gICAgICovXG4gICAgZnVuY3Rpb24gYWZ0ZXIobiwgZnVuYykge1xuICAgICAgaWYgKCFpc0Z1bmN0aW9uKGZ1bmMpKSB7XG4gICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3I7XG4gICAgICB9XG4gICAgICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgICAgIGlmICgtLW4gPCAxKSB7XG4gICAgICAgICAgcmV0dXJuIGZ1bmMuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgZnVuY3Rpb24gdGhhdCwgd2hlbiBjYWxsZWQsIGludm9rZXMgYGZ1bmNgIHdpdGggdGhlIGB0aGlzYFxuICAgICAqIGJpbmRpbmcgb2YgYHRoaXNBcmdgIGFuZCBwcmVwZW5kcyBhbnkgYWRkaXRpb25hbCBgYmluZGAgYXJndW1lbnRzIHRvIHRob3NlXG4gICAgICogcHJvdmlkZWQgdG8gdGhlIGJvdW5kIGZ1bmN0aW9uLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEZ1bmN0aW9uc1xuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIGJpbmQuXG4gICAgICogQHBhcmFtIHsqfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBmdW5jYC5cbiAgICAgKiBAcGFyYW0gey4uLip9IFthcmddIEFyZ3VtZW50cyB0byBiZSBwYXJ0aWFsbHkgYXBwbGllZC5cbiAgICAgKiBAcmV0dXJucyB7RnVuY3Rpb259IFJldHVybnMgdGhlIG5ldyBib3VuZCBmdW5jdGlvbi5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIGZ1bmMgPSBmdW5jdGlvbihncmVldGluZykge1xuICAgICAqICAgcmV0dXJuIGdyZWV0aW5nICsgJyAnICsgdGhpcy5uYW1lO1xuICAgICAqIH07XG4gICAgICpcbiAgICAgKiBmdW5jID0gXy5iaW5kKGZ1bmMsIHsgJ25hbWUnOiAnZnJlZCcgfSwgJ2hpJyk7XG4gICAgICogZnVuYygpO1xuICAgICAqIC8vID0+ICdoaSBmcmVkJ1xuICAgICAqL1xuICAgIGZ1bmN0aW9uIGJpbmQoZnVuYywgdGhpc0FyZykge1xuICAgICAgcmV0dXJuIGFyZ3VtZW50cy5sZW5ndGggPiAyXG4gICAgICAgID8gY3JlYXRlV3JhcHBlcihmdW5jLCAxNywgc2xpY2UoYXJndW1lbnRzLCAyKSwgbnVsbCwgdGhpc0FyZylcbiAgICAgICAgOiBjcmVhdGVXcmFwcGVyKGZ1bmMsIDEsIG51bGwsIG51bGwsIHRoaXNBcmcpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEJpbmRzIG1ldGhvZHMgb2YgYW4gb2JqZWN0IHRvIHRoZSBvYmplY3QgaXRzZWxmLCBvdmVyd3JpdGluZyB0aGUgZXhpc3RpbmdcbiAgICAgKiBtZXRob2QuIE1ldGhvZCBuYW1lcyBtYXkgYmUgc3BlY2lmaWVkIGFzIGluZGl2aWR1YWwgYXJndW1lbnRzIG9yIGFzIGFycmF5c1xuICAgICAqIG9mIG1ldGhvZCBuYW1lcy4gSWYgbm8gbWV0aG9kIG5hbWVzIGFyZSBwcm92aWRlZCBhbGwgdGhlIGZ1bmN0aW9uIHByb3BlcnRpZXNcbiAgICAgKiBvZiBgb2JqZWN0YCB3aWxsIGJlIGJvdW5kLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEZ1bmN0aW9uc1xuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3QgVGhlIG9iamVjdCB0byBiaW5kIGFuZCBhc3NpZ24gdGhlIGJvdW5kIG1ldGhvZHMgdG8uXG4gICAgICogQHBhcmFtIHsuLi5zdHJpbmd9IFttZXRob2ROYW1lXSBUaGUgb2JqZWN0IG1ldGhvZCBuYW1lcyB0b1xuICAgICAqICBiaW5kLCBzcGVjaWZpZWQgYXMgaW5kaXZpZHVhbCBtZXRob2QgbmFtZXMgb3IgYXJyYXlzIG9mIG1ldGhvZCBuYW1lcy5cbiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSBSZXR1cm5zIGBvYmplY3RgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgdmlldyA9IHtcbiAgICAgKiAgICdsYWJlbCc6ICdkb2NzJyxcbiAgICAgKiAgICdvbkNsaWNrJzogZnVuY3Rpb24oKSB7IGNvbnNvbGUubG9nKCdjbGlja2VkICcgKyB0aGlzLmxhYmVsKTsgfVxuICAgICAqIH07XG4gICAgICpcbiAgICAgKiBfLmJpbmRBbGwodmlldyk7XG4gICAgICogalF1ZXJ5KCcjZG9jcycpLm9uKCdjbGljaycsIHZpZXcub25DbGljayk7XG4gICAgICogLy8gPT4gbG9ncyAnY2xpY2tlZCBkb2NzJywgd2hlbiB0aGUgYnV0dG9uIGlzIGNsaWNrZWRcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBiaW5kQWxsKG9iamVjdCkge1xuICAgICAgdmFyIGZ1bmNzID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgPyBiYXNlRmxhdHRlbihhcmd1bWVudHMsIHRydWUsIGZhbHNlLCAxKSA6IGZ1bmN0aW9ucyhvYmplY3QpLFxuICAgICAgICAgIGluZGV4ID0gLTEsXG4gICAgICAgICAgbGVuZ3RoID0gZnVuY3MubGVuZ3RoO1xuXG4gICAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgICB2YXIga2V5ID0gZnVuY3NbaW5kZXhdO1xuICAgICAgICBvYmplY3Rba2V5XSA9IGNyZWF0ZVdyYXBwZXIob2JqZWN0W2tleV0sIDEsIG51bGwsIG51bGwsIG9iamVjdCk7XG4gICAgICB9XG4gICAgICByZXR1cm4gb2JqZWN0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSBmdW5jdGlvbiB0aGF0LCB3aGVuIGNhbGxlZCwgaW52b2tlcyB0aGUgbWV0aG9kIGF0IGBvYmplY3Rba2V5XWBcbiAgICAgKiBhbmQgcHJlcGVuZHMgYW55IGFkZGl0aW9uYWwgYGJpbmRLZXlgIGFyZ3VtZW50cyB0byB0aG9zZSBwcm92aWRlZCB0byB0aGUgYm91bmRcbiAgICAgKiBmdW5jdGlvbi4gVGhpcyBtZXRob2QgZGlmZmVycyBmcm9tIGBfLmJpbmRgIGJ5IGFsbG93aW5nIGJvdW5kIGZ1bmN0aW9ucyB0b1xuICAgICAqIHJlZmVyZW5jZSBtZXRob2RzIHRoYXQgd2lsbCBiZSByZWRlZmluZWQgb3IgZG9uJ3QgeWV0IGV4aXN0LlxuICAgICAqIFNlZSBodHRwOi8vbWljaGF1eC5jYS9hcnRpY2xlcy9sYXp5LWZ1bmN0aW9uLWRlZmluaXRpb24tcGF0dGVybi5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBGdW5jdGlvbnNcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0IFRoZSBvYmplY3QgdGhlIG1ldGhvZCBiZWxvbmdzIHRvLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBrZXkgVGhlIGtleSBvZiB0aGUgbWV0aG9kLlxuICAgICAqIEBwYXJhbSB7Li4uKn0gW2FyZ10gQXJndW1lbnRzIHRvIGJlIHBhcnRpYWxseSBhcHBsaWVkLlxuICAgICAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IGJvdW5kIGZ1bmN0aW9uLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgb2JqZWN0ID0ge1xuICAgICAqICAgJ25hbWUnOiAnZnJlZCcsXG4gICAgICogICAnZ3JlZXQnOiBmdW5jdGlvbihncmVldGluZykge1xuICAgICAqICAgICByZXR1cm4gZ3JlZXRpbmcgKyAnICcgKyB0aGlzLm5hbWU7XG4gICAgICogICB9XG4gICAgICogfTtcbiAgICAgKlxuICAgICAqIHZhciBmdW5jID0gXy5iaW5kS2V5KG9iamVjdCwgJ2dyZWV0JywgJ2hpJyk7XG4gICAgICogZnVuYygpO1xuICAgICAqIC8vID0+ICdoaSBmcmVkJ1xuICAgICAqXG4gICAgICogb2JqZWN0LmdyZWV0ID0gZnVuY3Rpb24oZ3JlZXRpbmcpIHtcbiAgICAgKiAgIHJldHVybiBncmVldGluZyArICd5YSAnICsgdGhpcy5uYW1lICsgJyEnO1xuICAgICAqIH07XG4gICAgICpcbiAgICAgKiBmdW5jKCk7XG4gICAgICogLy8gPT4gJ2hpeWEgZnJlZCEnXG4gICAgICovXG4gICAgZnVuY3Rpb24gYmluZEtleShvYmplY3QsIGtleSkge1xuICAgICAgcmV0dXJuIGFyZ3VtZW50cy5sZW5ndGggPiAyXG4gICAgICAgID8gY3JlYXRlV3JhcHBlcihrZXksIDE5LCBzbGljZShhcmd1bWVudHMsIDIpLCBudWxsLCBvYmplY3QpXG4gICAgICAgIDogY3JlYXRlV3JhcHBlcihrZXksIDMsIG51bGwsIG51bGwsIG9iamVjdCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIGZ1bmN0aW9uIHRoYXQgaXMgdGhlIGNvbXBvc2l0aW9uIG9mIHRoZSBwcm92aWRlZCBmdW5jdGlvbnMsXG4gICAgICogd2hlcmUgZWFjaCBmdW5jdGlvbiBjb25zdW1lcyB0aGUgcmV0dXJuIHZhbHVlIG9mIHRoZSBmdW5jdGlvbiB0aGF0IGZvbGxvd3MuXG4gICAgICogRm9yIGV4YW1wbGUsIGNvbXBvc2luZyB0aGUgZnVuY3Rpb25zIGBmKClgLCBgZygpYCwgYW5kIGBoKClgIHByb2R1Y2VzIGBmKGcoaCgpKSlgLlxuICAgICAqIEVhY2ggZnVuY3Rpb24gaXMgZXhlY3V0ZWQgd2l0aCB0aGUgYHRoaXNgIGJpbmRpbmcgb2YgdGhlIGNvbXBvc2VkIGZ1bmN0aW9uLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEZ1bmN0aW9uc1xuICAgICAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IFtmdW5jXSBGdW5jdGlvbnMgdG8gY29tcG9zZS5cbiAgICAgKiBAcmV0dXJucyB7RnVuY3Rpb259IFJldHVybnMgdGhlIG5ldyBjb21wb3NlZCBmdW5jdGlvbi5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIHJlYWxOYW1lTWFwID0ge1xuICAgICAqICAgJ3BlYmJsZXMnOiAncGVuZWxvcGUnXG4gICAgICogfTtcbiAgICAgKlxuICAgICAqIHZhciBmb3JtYXQgPSBmdW5jdGlvbihuYW1lKSB7XG4gICAgICogICBuYW1lID0gcmVhbE5hbWVNYXBbbmFtZS50b0xvd2VyQ2FzZSgpXSB8fCBuYW1lO1xuICAgICAqICAgcmV0dXJuIG5hbWUuY2hhckF0KDApLnRvVXBwZXJDYXNlKCkgKyBuYW1lLnNsaWNlKDEpLnRvTG93ZXJDYXNlKCk7XG4gICAgICogfTtcbiAgICAgKlxuICAgICAqIHZhciBncmVldCA9IGZ1bmN0aW9uKGZvcm1hdHRlZCkge1xuICAgICAqICAgcmV0dXJuICdIaXlhICcgKyBmb3JtYXR0ZWQgKyAnISc7XG4gICAgICogfTtcbiAgICAgKlxuICAgICAqIHZhciB3ZWxjb21lID0gXy5jb21wb3NlKGdyZWV0LCBmb3JtYXQpO1xuICAgICAqIHdlbGNvbWUoJ3BlYmJsZXMnKTtcbiAgICAgKiAvLyA9PiAnSGl5YSBQZW5lbG9wZSEnXG4gICAgICovXG4gICAgZnVuY3Rpb24gY29tcG9zZSgpIHtcbiAgICAgIHZhciBmdW5jcyA9IGFyZ3VtZW50cyxcbiAgICAgICAgICBsZW5ndGggPSBmdW5jcy5sZW5ndGg7XG5cbiAgICAgIHdoaWxlIChsZW5ndGgtLSkge1xuICAgICAgICBpZiAoIWlzRnVuY3Rpb24oZnVuY3NbbGVuZ3RoXSkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBhcmdzID0gYXJndW1lbnRzLFxuICAgICAgICAgICAgbGVuZ3RoID0gZnVuY3MubGVuZ3RoO1xuXG4gICAgICAgIHdoaWxlIChsZW5ndGgtLSkge1xuICAgICAgICAgIGFyZ3MgPSBbZnVuY3NbbGVuZ3RoXS5hcHBseSh0aGlzLCBhcmdzKV07XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGFyZ3NbMF07XG4gICAgICB9O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSBmdW5jdGlvbiB3aGljaCBhY2NlcHRzIG9uZSBvciBtb3JlIGFyZ3VtZW50cyBvZiBgZnVuY2AgdGhhdCB3aGVuXG4gICAgICogaW52b2tlZCBlaXRoZXIgZXhlY3V0ZXMgYGZ1bmNgIHJldHVybmluZyBpdHMgcmVzdWx0LCBpZiBhbGwgYGZ1bmNgIGFyZ3VtZW50c1xuICAgICAqIGhhdmUgYmVlbiBwcm92aWRlZCwgb3IgcmV0dXJucyBhIGZ1bmN0aW9uIHRoYXQgYWNjZXB0cyBvbmUgb3IgbW9yZSBvZiB0aGVcbiAgICAgKiByZW1haW5pbmcgYGZ1bmNgIGFyZ3VtZW50cywgYW5kIHNvIG9uLiBUaGUgYXJpdHkgb2YgYGZ1bmNgIGNhbiBiZSBzcGVjaWZpZWRcbiAgICAgKiBpZiBgZnVuYy5sZW5ndGhgIGlzIG5vdCBzdWZmaWNpZW50LlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEZ1bmN0aW9uc1xuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIGN1cnJ5LlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbYXJpdHk9ZnVuYy5sZW5ndGhdIFRoZSBhcml0eSBvZiBgZnVuY2AuXG4gICAgICogQHJldHVybnMge0Z1bmN0aW9ufSBSZXR1cm5zIHRoZSBuZXcgY3VycmllZCBmdW5jdGlvbi5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIGN1cnJpZWQgPSBfLmN1cnJ5KGZ1bmN0aW9uKGEsIGIsIGMpIHtcbiAgICAgKiAgIGNvbnNvbGUubG9nKGEgKyBiICsgYyk7XG4gICAgICogfSk7XG4gICAgICpcbiAgICAgKiBjdXJyaWVkKDEpKDIpKDMpO1xuICAgICAqIC8vID0+IDZcbiAgICAgKlxuICAgICAqIGN1cnJpZWQoMSwgMikoMyk7XG4gICAgICogLy8gPT4gNlxuICAgICAqXG4gICAgICogY3VycmllZCgxLCAyLCAzKTtcbiAgICAgKiAvLyA9PiA2XG4gICAgICovXG4gICAgZnVuY3Rpb24gY3VycnkoZnVuYywgYXJpdHkpIHtcbiAgICAgIGFyaXR5ID0gdHlwZW9mIGFyaXR5ID09ICdudW1iZXInID8gYXJpdHkgOiAoK2FyaXR5IHx8IGZ1bmMubGVuZ3RoKTtcbiAgICAgIHJldHVybiBjcmVhdGVXcmFwcGVyKGZ1bmMsIDQsIG51bGwsIG51bGwsIG51bGwsIGFyaXR5KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgZnVuY3Rpb24gdGhhdCB3aWxsIGRlbGF5IHRoZSBleGVjdXRpb24gb2YgYGZ1bmNgIHVudGlsIGFmdGVyXG4gICAgICogYHdhaXRgIG1pbGxpc2Vjb25kcyBoYXZlIGVsYXBzZWQgc2luY2UgdGhlIGxhc3QgdGltZSBpdCB3YXMgaW52b2tlZC5cbiAgICAgKiBQcm92aWRlIGFuIG9wdGlvbnMgb2JqZWN0IHRvIGluZGljYXRlIHRoYXQgYGZ1bmNgIHNob3VsZCBiZSBpbnZva2VkIG9uXG4gICAgICogdGhlIGxlYWRpbmcgYW5kL29yIHRyYWlsaW5nIGVkZ2Ugb2YgdGhlIGB3YWl0YCB0aW1lb3V0LiBTdWJzZXF1ZW50IGNhbGxzXG4gICAgICogdG8gdGhlIGRlYm91bmNlZCBmdW5jdGlvbiB3aWxsIHJldHVybiB0aGUgcmVzdWx0IG9mIHRoZSBsYXN0IGBmdW5jYCBjYWxsLlxuICAgICAqXG4gICAgICogTm90ZTogSWYgYGxlYWRpbmdgIGFuZCBgdHJhaWxpbmdgIG9wdGlvbnMgYXJlIGB0cnVlYCBgZnVuY2Agd2lsbCBiZSBjYWxsZWRcbiAgICAgKiBvbiB0aGUgdHJhaWxpbmcgZWRnZSBvZiB0aGUgdGltZW91dCBvbmx5IGlmIHRoZSB0aGUgZGVib3VuY2VkIGZ1bmN0aW9uIGlzXG4gICAgICogaW52b2tlZCBtb3JlIHRoYW4gb25jZSBkdXJpbmcgdGhlIGB3YWl0YCB0aW1lb3V0LlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEZ1bmN0aW9uc1xuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIGRlYm91bmNlLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB3YWl0IFRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIGRlbGF5LlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBbb3B0aW9uc10gVGhlIG9wdGlvbnMgb2JqZWN0LlxuICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdGlvbnMubGVhZGluZz1mYWxzZV0gU3BlY2lmeSBleGVjdXRpb24gb24gdGhlIGxlYWRpbmcgZWRnZSBvZiB0aGUgdGltZW91dC5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gW29wdGlvbnMubWF4V2FpdF0gVGhlIG1heGltdW0gdGltZSBgZnVuY2AgaXMgYWxsb3dlZCB0byBiZSBkZWxheWVkIGJlZm9yZSBpdCdzIGNhbGxlZC5cbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLnRyYWlsaW5nPXRydWVdIFNwZWNpZnkgZXhlY3V0aW9uIG9uIHRoZSB0cmFpbGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0LlxuICAgICAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IGRlYm91bmNlZCBmdW5jdGlvbi5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogLy8gYXZvaWQgY29zdGx5IGNhbGN1bGF0aW9ucyB3aGlsZSB0aGUgd2luZG93IHNpemUgaXMgaW4gZmx1eFxuICAgICAqIHZhciBsYXp5TGF5b3V0ID0gXy5kZWJvdW5jZShjYWxjdWxhdGVMYXlvdXQsIDE1MCk7XG4gICAgICogalF1ZXJ5KHdpbmRvdykub24oJ3Jlc2l6ZScsIGxhenlMYXlvdXQpO1xuICAgICAqXG4gICAgICogLy8gZXhlY3V0ZSBgc2VuZE1haWxgIHdoZW4gdGhlIGNsaWNrIGV2ZW50IGlzIGZpcmVkLCBkZWJvdW5jaW5nIHN1YnNlcXVlbnQgY2FsbHNcbiAgICAgKiBqUXVlcnkoJyNwb3N0Ym94Jykub24oJ2NsaWNrJywgXy5kZWJvdW5jZShzZW5kTWFpbCwgMzAwLCB7XG4gICAgICogICAnbGVhZGluZyc6IHRydWUsXG4gICAgICogICAndHJhaWxpbmcnOiBmYWxzZVxuICAgICAqIH0pO1xuICAgICAqXG4gICAgICogLy8gZW5zdXJlIGBiYXRjaExvZ2AgaXMgZXhlY3V0ZWQgb25jZSBhZnRlciAxIHNlY29uZCBvZiBkZWJvdW5jZWQgY2FsbHNcbiAgICAgKiB2YXIgc291cmNlID0gbmV3IEV2ZW50U291cmNlKCcvc3RyZWFtJyk7XG4gICAgICogc291cmNlLmFkZEV2ZW50TGlzdGVuZXIoJ21lc3NhZ2UnLCBfLmRlYm91bmNlKGJhdGNoTG9nLCAyNTAsIHtcbiAgICAgKiAgICdtYXhXYWl0JzogMTAwMFxuICAgICAqIH0sIGZhbHNlKTtcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBkZWJvdW5jZShmdW5jLCB3YWl0LCBvcHRpb25zKSB7XG4gICAgICB2YXIgYXJncyxcbiAgICAgICAgICBtYXhUaW1lb3V0SWQsXG4gICAgICAgICAgcmVzdWx0LFxuICAgICAgICAgIHN0YW1wLFxuICAgICAgICAgIHRoaXNBcmcsXG4gICAgICAgICAgdGltZW91dElkLFxuICAgICAgICAgIHRyYWlsaW5nQ2FsbCxcbiAgICAgICAgICBsYXN0Q2FsbGVkID0gMCxcbiAgICAgICAgICBtYXhXYWl0ID0gZmFsc2UsXG4gICAgICAgICAgdHJhaWxpbmcgPSB0cnVlO1xuXG4gICAgICBpZiAoIWlzRnVuY3Rpb24oZnVuYykpIHtcbiAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcjtcbiAgICAgIH1cbiAgICAgIHdhaXQgPSBuYXRpdmVNYXgoMCwgd2FpdCkgfHwgMDtcbiAgICAgIGlmIChvcHRpb25zID09PSB0cnVlKSB7XG4gICAgICAgIHZhciBsZWFkaW5nID0gdHJ1ZTtcbiAgICAgICAgdHJhaWxpbmcgPSBmYWxzZTtcbiAgICAgIH0gZWxzZSBpZiAoaXNPYmplY3Qob3B0aW9ucykpIHtcbiAgICAgICAgbGVhZGluZyA9IG9wdGlvbnMubGVhZGluZztcbiAgICAgICAgbWF4V2FpdCA9ICdtYXhXYWl0JyBpbiBvcHRpb25zICYmIChuYXRpdmVNYXgod2FpdCwgb3B0aW9ucy5tYXhXYWl0KSB8fCAwKTtcbiAgICAgICAgdHJhaWxpbmcgPSAndHJhaWxpbmcnIGluIG9wdGlvbnMgPyBvcHRpb25zLnRyYWlsaW5nIDogdHJhaWxpbmc7XG4gICAgICB9XG4gICAgICB2YXIgZGVsYXllZCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgcmVtYWluaW5nID0gd2FpdCAtIChub3coKSAtIHN0YW1wKTtcbiAgICAgICAgaWYgKHJlbWFpbmluZyA8PSAwKSB7XG4gICAgICAgICAgaWYgKG1heFRpbWVvdXRJZCkge1xuICAgICAgICAgICAgY2xlYXJUaW1lb3V0KG1heFRpbWVvdXRJZCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHZhciBpc0NhbGxlZCA9IHRyYWlsaW5nQ2FsbDtcbiAgICAgICAgICBtYXhUaW1lb3V0SWQgPSB0aW1lb3V0SWQgPSB0cmFpbGluZ0NhbGwgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgaWYgKGlzQ2FsbGVkKSB7XG4gICAgICAgICAgICBsYXN0Q2FsbGVkID0gbm93KCk7XG4gICAgICAgICAgICByZXN1bHQgPSBmdW5jLmFwcGx5KHRoaXNBcmcsIGFyZ3MpO1xuICAgICAgICAgICAgaWYgKCF0aW1lb3V0SWQgJiYgIW1heFRpbWVvdXRJZCkge1xuICAgICAgICAgICAgICBhcmdzID0gdGhpc0FyZyA9IG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRpbWVvdXRJZCA9IHNldFRpbWVvdXQoZGVsYXllZCwgcmVtYWluaW5nKTtcbiAgICAgICAgfVxuICAgICAgfTtcblxuICAgICAgdmFyIG1heERlbGF5ZWQgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgaWYgKHRpbWVvdXRJZCkge1xuICAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0SWQpO1xuICAgICAgICB9XG4gICAgICAgIG1heFRpbWVvdXRJZCA9IHRpbWVvdXRJZCA9IHRyYWlsaW5nQ2FsbCA9IHVuZGVmaW5lZDtcbiAgICAgICAgaWYgKHRyYWlsaW5nIHx8IChtYXhXYWl0ICE9PSB3YWl0KSkge1xuICAgICAgICAgIGxhc3RDYWxsZWQgPSBub3coKTtcbiAgICAgICAgICByZXN1bHQgPSBmdW5jLmFwcGx5KHRoaXNBcmcsIGFyZ3MpO1xuICAgICAgICAgIGlmICghdGltZW91dElkICYmICFtYXhUaW1lb3V0SWQpIHtcbiAgICAgICAgICAgIGFyZ3MgPSB0aGlzQXJnID0gbnVsbDtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH07XG5cbiAgICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgICAgYXJncyA9IGFyZ3VtZW50cztcbiAgICAgICAgc3RhbXAgPSBub3coKTtcbiAgICAgICAgdGhpc0FyZyA9IHRoaXM7XG4gICAgICAgIHRyYWlsaW5nQ2FsbCA9IHRyYWlsaW5nICYmICh0aW1lb3V0SWQgfHwgIWxlYWRpbmcpO1xuXG4gICAgICAgIGlmIChtYXhXYWl0ID09PSBmYWxzZSkge1xuICAgICAgICAgIHZhciBsZWFkaW5nQ2FsbCA9IGxlYWRpbmcgJiYgIXRpbWVvdXRJZDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBpZiAoIW1heFRpbWVvdXRJZCAmJiAhbGVhZGluZykge1xuICAgICAgICAgICAgbGFzdENhbGxlZCA9IHN0YW1wO1xuICAgICAgICAgIH1cbiAgICAgICAgICB2YXIgcmVtYWluaW5nID0gbWF4V2FpdCAtIChzdGFtcCAtIGxhc3RDYWxsZWQpLFxuICAgICAgICAgICAgICBpc0NhbGxlZCA9IHJlbWFpbmluZyA8PSAwO1xuXG4gICAgICAgICAgaWYgKGlzQ2FsbGVkKSB7XG4gICAgICAgICAgICBpZiAobWF4VGltZW91dElkKSB7XG4gICAgICAgICAgICAgIG1heFRpbWVvdXRJZCA9IGNsZWFyVGltZW91dChtYXhUaW1lb3V0SWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbGFzdENhbGxlZCA9IHN0YW1wO1xuICAgICAgICAgICAgcmVzdWx0ID0gZnVuYy5hcHBseSh0aGlzQXJnLCBhcmdzKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgZWxzZSBpZiAoIW1heFRpbWVvdXRJZCkge1xuICAgICAgICAgICAgbWF4VGltZW91dElkID0gc2V0VGltZW91dChtYXhEZWxheWVkLCByZW1haW5pbmcpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoaXNDYWxsZWQgJiYgdGltZW91dElkKSB7XG4gICAgICAgICAgdGltZW91dElkID0gY2xlYXJUaW1lb3V0KHRpbWVvdXRJZCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoIXRpbWVvdXRJZCAmJiB3YWl0ICE9PSBtYXhXYWl0KSB7XG4gICAgICAgICAgdGltZW91dElkID0gc2V0VGltZW91dChkZWxheWVkLCB3YWl0KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobGVhZGluZ0NhbGwpIHtcbiAgICAgICAgICBpc0NhbGxlZCA9IHRydWU7XG4gICAgICAgICAgcmVzdWx0ID0gZnVuYy5hcHBseSh0aGlzQXJnLCBhcmdzKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaXNDYWxsZWQgJiYgIXRpbWVvdXRJZCAmJiAhbWF4VGltZW91dElkKSB7XG4gICAgICAgICAgYXJncyA9IHRoaXNBcmcgPSBudWxsO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICB9O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIERlZmVycyBleGVjdXRpbmcgdGhlIGBmdW5jYCBmdW5jdGlvbiB1bnRpbCB0aGUgY3VycmVudCBjYWxsIHN0YWNrIGhhcyBjbGVhcmVkLlxuICAgICAqIEFkZGl0aW9uYWwgYXJndW1lbnRzIHdpbGwgYmUgcHJvdmlkZWQgdG8gYGZ1bmNgIHdoZW4gaXQgaXMgaW52b2tlZC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBGdW5jdGlvbnNcbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBmdW5jIFRoZSBmdW5jdGlvbiB0byBkZWZlci5cbiAgICAgKiBAcGFyYW0gey4uLip9IFthcmddIEFyZ3VtZW50cyB0byBpbnZva2UgdGhlIGZ1bmN0aW9uIHdpdGguXG4gICAgICogQHJldHVybnMge251bWJlcn0gUmV0dXJucyB0aGUgdGltZXIgaWQuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uZGVmZXIoZnVuY3Rpb24odGV4dCkgeyBjb25zb2xlLmxvZyh0ZXh0KTsgfSwgJ2RlZmVycmVkJyk7XG4gICAgICogLy8gbG9ncyAnZGVmZXJyZWQnIGFmdGVyIG9uZSBvciBtb3JlIG1pbGxpc2Vjb25kc1xuICAgICAqL1xuICAgIGZ1bmN0aW9uIGRlZmVyKGZ1bmMpIHtcbiAgICAgIGlmICghaXNGdW5jdGlvbihmdW5jKSkge1xuICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yO1xuICAgICAgfVxuICAgICAgdmFyIGFyZ3MgPSBzbGljZShhcmd1bWVudHMsIDEpO1xuICAgICAgcmV0dXJuIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7IGZ1bmMuYXBwbHkodW5kZWZpbmVkLCBhcmdzKTsgfSwgMSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRXhlY3V0ZXMgdGhlIGBmdW5jYCBmdW5jdGlvbiBhZnRlciBgd2FpdGAgbWlsbGlzZWNvbmRzLiBBZGRpdGlvbmFsIGFyZ3VtZW50c1xuICAgICAqIHdpbGwgYmUgcHJvdmlkZWQgdG8gYGZ1bmNgIHdoZW4gaXQgaXMgaW52b2tlZC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBGdW5jdGlvbnNcbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBmdW5jIFRoZSBmdW5jdGlvbiB0byBkZWxheS5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gd2FpdCBUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byBkZWxheSBleGVjdXRpb24uXG4gICAgICogQHBhcmFtIHsuLi4qfSBbYXJnXSBBcmd1bWVudHMgdG8gaW52b2tlIHRoZSBmdW5jdGlvbiB3aXRoLlxuICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFJldHVybnMgdGhlIHRpbWVyIGlkLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLmRlbGF5KGZ1bmN0aW9uKHRleHQpIHsgY29uc29sZS5sb2codGV4dCk7IH0sIDEwMDAsICdsYXRlcicpO1xuICAgICAqIC8vID0+IGxvZ3MgJ2xhdGVyJyBhZnRlciBvbmUgc2Vjb25kXG4gICAgICovXG4gICAgZnVuY3Rpb24gZGVsYXkoZnVuYywgd2FpdCkge1xuICAgICAgaWYgKCFpc0Z1bmN0aW9uKGZ1bmMpKSB7XG4gICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3I7XG4gICAgICB9XG4gICAgICB2YXIgYXJncyA9IHNsaWNlKGFyZ3VtZW50cywgMik7XG4gICAgICByZXR1cm4gc2V0VGltZW91dChmdW5jdGlvbigpIHsgZnVuYy5hcHBseSh1bmRlZmluZWQsIGFyZ3MpOyB9LCB3YWl0KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgZnVuY3Rpb24gdGhhdCBtZW1vaXplcyB0aGUgcmVzdWx0IG9mIGBmdW5jYC4gSWYgYHJlc29sdmVyYCBpc1xuICAgICAqIHByb3ZpZGVkIGl0IHdpbGwgYmUgdXNlZCB0byBkZXRlcm1pbmUgdGhlIGNhY2hlIGtleSBmb3Igc3RvcmluZyB0aGUgcmVzdWx0XG4gICAgICogYmFzZWQgb24gdGhlIGFyZ3VtZW50cyBwcm92aWRlZCB0byB0aGUgbWVtb2l6ZWQgZnVuY3Rpb24uIEJ5IGRlZmF1bHQsIHRoZVxuICAgICAqIGZpcnN0IGFyZ3VtZW50IHByb3ZpZGVkIHRvIHRoZSBtZW1vaXplZCBmdW5jdGlvbiBpcyB1c2VkIGFzIHRoZSBjYWNoZSBrZXkuXG4gICAgICogVGhlIGBmdW5jYCBpcyBleGVjdXRlZCB3aXRoIHRoZSBgdGhpc2AgYmluZGluZyBvZiB0aGUgbWVtb2l6ZWQgZnVuY3Rpb24uXG4gICAgICogVGhlIHJlc3VsdCBjYWNoZSBpcyBleHBvc2VkIGFzIHRoZSBgY2FjaGVgIHByb3BlcnR5IG9uIHRoZSBtZW1vaXplZCBmdW5jdGlvbi5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBGdW5jdGlvbnNcbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBmdW5jIFRoZSBmdW5jdGlvbiB0byBoYXZlIGl0cyBvdXRwdXQgbWVtb2l6ZWQuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gW3Jlc29sdmVyXSBBIGZ1bmN0aW9uIHVzZWQgdG8gcmVzb2x2ZSB0aGUgY2FjaGUga2V5LlxuICAgICAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IG1lbW9pemluZyBmdW5jdGlvbi5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIGZpYm9uYWNjaSA9IF8ubWVtb2l6ZShmdW5jdGlvbihuKSB7XG4gICAgICogICByZXR1cm4gbiA8IDIgPyBuIDogZmlib25hY2NpKG4gLSAxKSArIGZpYm9uYWNjaShuIC0gMik7XG4gICAgICogfSk7XG4gICAgICpcbiAgICAgKiBmaWJvbmFjY2koOSlcbiAgICAgKiAvLyA9PiAzNFxuICAgICAqXG4gICAgICogdmFyIGRhdGEgPSB7XG4gICAgICogICAnZnJlZCc6IHsgJ25hbWUnOiAnZnJlZCcsICdhZ2UnOiA0MCB9LFxuICAgICAqICAgJ3BlYmJsZXMnOiB7ICduYW1lJzogJ3BlYmJsZXMnLCAnYWdlJzogMSB9XG4gICAgICogfTtcbiAgICAgKlxuICAgICAqIC8vIG1vZGlmeWluZyB0aGUgcmVzdWx0IGNhY2hlXG4gICAgICogdmFyIGdldCA9IF8ubWVtb2l6ZShmdW5jdGlvbihuYW1lKSB7IHJldHVybiBkYXRhW25hbWVdOyB9LCBfLmlkZW50aXR5KTtcbiAgICAgKiBnZXQoJ3BlYmJsZXMnKTtcbiAgICAgKiAvLyA9PiB7ICduYW1lJzogJ3BlYmJsZXMnLCAnYWdlJzogMSB9XG4gICAgICpcbiAgICAgKiBnZXQuY2FjaGUucGViYmxlcy5uYW1lID0gJ3BlbmVsb3BlJztcbiAgICAgKiBnZXQoJ3BlYmJsZXMnKTtcbiAgICAgKiAvLyA9PiB7ICduYW1lJzogJ3BlbmVsb3BlJywgJ2FnZSc6IDEgfVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIG1lbW9pemUoZnVuYywgcmVzb2x2ZXIpIHtcbiAgICAgIGlmICghaXNGdW5jdGlvbihmdW5jKSkge1xuICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yO1xuICAgICAgfVxuICAgICAgdmFyIG1lbW9pemVkID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBjYWNoZSA9IG1lbW9pemVkLmNhY2hlLFxuICAgICAgICAgICAga2V5ID0gcmVzb2x2ZXIgPyByZXNvbHZlci5hcHBseSh0aGlzLCBhcmd1bWVudHMpIDoga2V5UHJlZml4ICsgYXJndW1lbnRzWzBdO1xuXG4gICAgICAgIHJldHVybiBoYXNPd25Qcm9wZXJ0eS5jYWxsKGNhY2hlLCBrZXkpXG4gICAgICAgICAgPyBjYWNoZVtrZXldXG4gICAgICAgICAgOiAoY2FjaGVba2V5XSA9IGZ1bmMuYXBwbHkodGhpcywgYXJndW1lbnRzKSk7XG4gICAgICB9XG4gICAgICBtZW1vaXplZC5jYWNoZSA9IHt9O1xuICAgICAgcmV0dXJuIG1lbW9pemVkO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSBmdW5jdGlvbiB0aGF0IGlzIHJlc3RyaWN0ZWQgdG8gZXhlY3V0ZSBgZnVuY2Agb25jZS4gUmVwZWF0IGNhbGxzIHRvXG4gICAgICogdGhlIGZ1bmN0aW9uIHdpbGwgcmV0dXJuIHRoZSB2YWx1ZSBvZiB0aGUgZmlyc3QgY2FsbC4gVGhlIGBmdW5jYCBpcyBleGVjdXRlZFxuICAgICAqIHdpdGggdGhlIGB0aGlzYCBiaW5kaW5nIG9mIHRoZSBjcmVhdGVkIGZ1bmN0aW9uLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEZ1bmN0aW9uc1xuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIHJlc3RyaWN0LlxuICAgICAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IHJlc3RyaWN0ZWQgZnVuY3Rpb24uXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIHZhciBpbml0aWFsaXplID0gXy5vbmNlKGNyZWF0ZUFwcGxpY2F0aW9uKTtcbiAgICAgKiBpbml0aWFsaXplKCk7XG4gICAgICogaW5pdGlhbGl6ZSgpO1xuICAgICAqIC8vIGBpbml0aWFsaXplYCBleGVjdXRlcyBgY3JlYXRlQXBwbGljYXRpb25gIG9uY2VcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBvbmNlKGZ1bmMpIHtcbiAgICAgIHZhciByYW4sXG4gICAgICAgICAgcmVzdWx0O1xuXG4gICAgICBpZiAoIWlzRnVuY3Rpb24oZnVuYykpIHtcbiAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcjtcbiAgICAgIH1cbiAgICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgICAgaWYgKHJhbikge1xuICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH1cbiAgICAgICAgcmFuID0gdHJ1ZTtcbiAgICAgICAgcmVzdWx0ID0gZnVuYy5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuXG4gICAgICAgIC8vIGNsZWFyIHRoZSBgZnVuY2AgdmFyaWFibGUgc28gdGhlIGZ1bmN0aW9uIG1heSBiZSBnYXJiYWdlIGNvbGxlY3RlZFxuICAgICAgICBmdW5jID0gbnVsbDtcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIGZ1bmN0aW9uIHRoYXQsIHdoZW4gY2FsbGVkLCBpbnZva2VzIGBmdW5jYCB3aXRoIGFueSBhZGRpdGlvbmFsXG4gICAgICogYHBhcnRpYWxgIGFyZ3VtZW50cyBwcmVwZW5kZWQgdG8gdGhvc2UgcHJvdmlkZWQgdG8gdGhlIG5ldyBmdW5jdGlvbi4gVGhpc1xuICAgICAqIG1ldGhvZCBpcyBzaW1pbGFyIHRvIGBfLmJpbmRgIGV4Y2VwdCBpdCBkb2VzICoqbm90KiogYWx0ZXIgdGhlIGB0aGlzYCBiaW5kaW5nLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEZ1bmN0aW9uc1xuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIHBhcnRpYWxseSBhcHBseSBhcmd1bWVudHMgdG8uXG4gICAgICogQHBhcmFtIHsuLi4qfSBbYXJnXSBBcmd1bWVudHMgdG8gYmUgcGFydGlhbGx5IGFwcGxpZWQuXG4gICAgICogQHJldHVybnMge0Z1bmN0aW9ufSBSZXR1cm5zIHRoZSBuZXcgcGFydGlhbGx5IGFwcGxpZWQgZnVuY3Rpb24uXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIHZhciBncmVldCA9IGZ1bmN0aW9uKGdyZWV0aW5nLCBuYW1lKSB7IHJldHVybiBncmVldGluZyArICcgJyArIG5hbWU7IH07XG4gICAgICogdmFyIGhpID0gXy5wYXJ0aWFsKGdyZWV0LCAnaGknKTtcbiAgICAgKiBoaSgnZnJlZCcpO1xuICAgICAqIC8vID0+ICdoaSBmcmVkJ1xuICAgICAqL1xuICAgIGZ1bmN0aW9uIHBhcnRpYWwoZnVuYykge1xuICAgICAgcmV0dXJuIGNyZWF0ZVdyYXBwZXIoZnVuYywgMTYsIHNsaWNlKGFyZ3VtZW50cywgMSkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoaXMgbWV0aG9kIGlzIGxpa2UgYF8ucGFydGlhbGAgZXhjZXB0IHRoYXQgYHBhcnRpYWxgIGFyZ3VtZW50cyBhcmVcbiAgICAgKiBhcHBlbmRlZCB0byB0aG9zZSBwcm92aWRlZCB0byB0aGUgbmV3IGZ1bmN0aW9uLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEZ1bmN0aW9uc1xuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIHBhcnRpYWxseSBhcHBseSBhcmd1bWVudHMgdG8uXG4gICAgICogQHBhcmFtIHsuLi4qfSBbYXJnXSBBcmd1bWVudHMgdG8gYmUgcGFydGlhbGx5IGFwcGxpZWQuXG4gICAgICogQHJldHVybnMge0Z1bmN0aW9ufSBSZXR1cm5zIHRoZSBuZXcgcGFydGlhbGx5IGFwcGxpZWQgZnVuY3Rpb24uXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIHZhciBkZWZhdWx0c0RlZXAgPSBfLnBhcnRpYWxSaWdodChfLm1lcmdlLCBfLmRlZmF1bHRzKTtcbiAgICAgKlxuICAgICAqIHZhciBvcHRpb25zID0ge1xuICAgICAqICAgJ3ZhcmlhYmxlJzogJ2RhdGEnLFxuICAgICAqICAgJ2ltcG9ydHMnOiB7ICdqcSc6ICQgfVxuICAgICAqIH07XG4gICAgICpcbiAgICAgKiBkZWZhdWx0c0RlZXAob3B0aW9ucywgXy50ZW1wbGF0ZVNldHRpbmdzKTtcbiAgICAgKlxuICAgICAqIG9wdGlvbnMudmFyaWFibGVcbiAgICAgKiAvLyA9PiAnZGF0YSdcbiAgICAgKlxuICAgICAqIG9wdGlvbnMuaW1wb3J0c1xuICAgICAqIC8vID0+IHsgJ18nOiBfLCAnanEnOiAkIH1cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBwYXJ0aWFsUmlnaHQoZnVuYykge1xuICAgICAgcmV0dXJuIGNyZWF0ZVdyYXBwZXIoZnVuYywgMzIsIG51bGwsIHNsaWNlKGFyZ3VtZW50cywgMSkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSBmdW5jdGlvbiB0aGF0LCB3aGVuIGV4ZWN1dGVkLCB3aWxsIG9ubHkgY2FsbCB0aGUgYGZ1bmNgIGZ1bmN0aW9uXG4gICAgICogYXQgbW9zdCBvbmNlIHBlciBldmVyeSBgd2FpdGAgbWlsbGlzZWNvbmRzLiBQcm92aWRlIGFuIG9wdGlvbnMgb2JqZWN0IHRvXG4gICAgICogaW5kaWNhdGUgdGhhdCBgZnVuY2Agc2hvdWxkIGJlIGludm9rZWQgb24gdGhlIGxlYWRpbmcgYW5kL29yIHRyYWlsaW5nIGVkZ2VcbiAgICAgKiBvZiB0aGUgYHdhaXRgIHRpbWVvdXQuIFN1YnNlcXVlbnQgY2FsbHMgdG8gdGhlIHRocm90dGxlZCBmdW5jdGlvbiB3aWxsXG4gICAgICogcmV0dXJuIHRoZSByZXN1bHQgb2YgdGhlIGxhc3QgYGZ1bmNgIGNhbGwuXG4gICAgICpcbiAgICAgKiBOb3RlOiBJZiBgbGVhZGluZ2AgYW5kIGB0cmFpbGluZ2Agb3B0aW9ucyBhcmUgYHRydWVgIGBmdW5jYCB3aWxsIGJlIGNhbGxlZFxuICAgICAqIG9uIHRoZSB0cmFpbGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0IG9ubHkgaWYgdGhlIHRoZSB0aHJvdHRsZWQgZnVuY3Rpb24gaXNcbiAgICAgKiBpbnZva2VkIG1vcmUgdGhhbiBvbmNlIGR1cmluZyB0aGUgYHdhaXRgIHRpbWVvdXQuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgRnVuY3Rpb25zXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gZnVuYyBUaGUgZnVuY3Rpb24gdG8gdGhyb3R0bGUuXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHdhaXQgVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gdGhyb3R0bGUgZXhlY3V0aW9ucyB0by5cbiAgICAgKiBAcGFyYW0ge09iamVjdH0gW29wdGlvbnNdIFRoZSBvcHRpb25zIG9iamVjdC5cbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLmxlYWRpbmc9dHJ1ZV0gU3BlY2lmeSBleGVjdXRpb24gb24gdGhlIGxlYWRpbmcgZWRnZSBvZiB0aGUgdGltZW91dC5cbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLnRyYWlsaW5nPXRydWVdIFNwZWNpZnkgZXhlY3V0aW9uIG9uIHRoZSB0cmFpbGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0LlxuICAgICAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IHRocm90dGxlZCBmdW5jdGlvbi5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogLy8gYXZvaWQgZXhjZXNzaXZlbHkgdXBkYXRpbmcgdGhlIHBvc2l0aW9uIHdoaWxlIHNjcm9sbGluZ1xuICAgICAqIHZhciB0aHJvdHRsZWQgPSBfLnRocm90dGxlKHVwZGF0ZVBvc2l0aW9uLCAxMDApO1xuICAgICAqIGpRdWVyeSh3aW5kb3cpLm9uKCdzY3JvbGwnLCB0aHJvdHRsZWQpO1xuICAgICAqXG4gICAgICogLy8gZXhlY3V0ZSBgcmVuZXdUb2tlbmAgd2hlbiB0aGUgY2xpY2sgZXZlbnQgaXMgZmlyZWQsIGJ1dCBub3QgbW9yZSB0aGFuIG9uY2UgZXZlcnkgNSBtaW51dGVzXG4gICAgICogalF1ZXJ5KCcuaW50ZXJhY3RpdmUnKS5vbignY2xpY2snLCBfLnRocm90dGxlKHJlbmV3VG9rZW4sIDMwMDAwMCwge1xuICAgICAqICAgJ3RyYWlsaW5nJzogZmFsc2VcbiAgICAgKiB9KSk7XG4gICAgICovXG4gICAgZnVuY3Rpb24gdGhyb3R0bGUoZnVuYywgd2FpdCwgb3B0aW9ucykge1xuICAgICAgdmFyIGxlYWRpbmcgPSB0cnVlLFxuICAgICAgICAgIHRyYWlsaW5nID0gdHJ1ZTtcblxuICAgICAgaWYgKCFpc0Z1bmN0aW9uKGZ1bmMpKSB7XG4gICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3I7XG4gICAgICB9XG4gICAgICBpZiAob3B0aW9ucyA9PT0gZmFsc2UpIHtcbiAgICAgICAgbGVhZGluZyA9IGZhbHNlO1xuICAgICAgfSBlbHNlIGlmIChpc09iamVjdChvcHRpb25zKSkge1xuICAgICAgICBsZWFkaW5nID0gJ2xlYWRpbmcnIGluIG9wdGlvbnMgPyBvcHRpb25zLmxlYWRpbmcgOiBsZWFkaW5nO1xuICAgICAgICB0cmFpbGluZyA9ICd0cmFpbGluZycgaW4gb3B0aW9ucyA/IG9wdGlvbnMudHJhaWxpbmcgOiB0cmFpbGluZztcbiAgICAgIH1cbiAgICAgIGRlYm91bmNlT3B0aW9ucy5sZWFkaW5nID0gbGVhZGluZztcbiAgICAgIGRlYm91bmNlT3B0aW9ucy5tYXhXYWl0ID0gd2FpdDtcbiAgICAgIGRlYm91bmNlT3B0aW9ucy50cmFpbGluZyA9IHRyYWlsaW5nO1xuXG4gICAgICByZXR1cm4gZGVib3VuY2UoZnVuYywgd2FpdCwgZGVib3VuY2VPcHRpb25zKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgZnVuY3Rpb24gdGhhdCBwcm92aWRlcyBgdmFsdWVgIHRvIHRoZSB3cmFwcGVyIGZ1bmN0aW9uIGFzIGl0c1xuICAgICAqIGZpcnN0IGFyZ3VtZW50LiBBZGRpdGlvbmFsIGFyZ3VtZW50cyBwcm92aWRlZCB0byB0aGUgZnVuY3Rpb24gYXJlIGFwcGVuZGVkXG4gICAgICogdG8gdGhvc2UgcHJvdmlkZWQgdG8gdGhlIHdyYXBwZXIgZnVuY3Rpb24uIFRoZSB3cmFwcGVyIGlzIGV4ZWN1dGVkIHdpdGhcbiAgICAgKiB0aGUgYHRoaXNgIGJpbmRpbmcgb2YgdGhlIGNyZWF0ZWQgZnVuY3Rpb24uXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgRnVuY3Rpb25zXG4gICAgICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gd3JhcC5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSB3cmFwcGVyIFRoZSB3cmFwcGVyIGZ1bmN0aW9uLlxuICAgICAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IGZ1bmN0aW9uLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgcCA9IF8ud3JhcChfLmVzY2FwZSwgZnVuY3Rpb24oZnVuYywgdGV4dCkge1xuICAgICAqICAgcmV0dXJuICc8cD4nICsgZnVuYyh0ZXh0KSArICc8L3A+JztcbiAgICAgKiB9KTtcbiAgICAgKlxuICAgICAqIHAoJ0ZyZWQsIFdpbG1hLCAmIFBlYmJsZXMnKTtcbiAgICAgKiAvLyA9PiAnPHA+RnJlZCwgV2lsbWEsICZhbXA7IFBlYmJsZXM8L3A+J1xuICAgICAqL1xuICAgIGZ1bmN0aW9uIHdyYXAodmFsdWUsIHdyYXBwZXIpIHtcbiAgICAgIHJldHVybiBjcmVhdGVXcmFwcGVyKHdyYXBwZXIsIDE2LCBbdmFsdWVdKTtcbiAgICB9XG5cbiAgICAvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSBmdW5jdGlvbiB0aGF0IHJldHVybnMgYHZhbHVlYC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBVdGlsaXRpZXNcbiAgICAgKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byByZXR1cm4gZnJvbSB0aGUgbmV3IGZ1bmN0aW9uLlxuICAgICAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IGZ1bmN0aW9uLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgb2JqZWN0ID0geyAnbmFtZSc6ICdmcmVkJyB9O1xuICAgICAqIHZhciBnZXR0ZXIgPSBfLmNvbnN0YW50KG9iamVjdCk7XG4gICAgICogZ2V0dGVyKCkgPT09IG9iamVjdDtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICovXG4gICAgZnVuY3Rpb24gY29uc3RhbnQodmFsdWUpIHtcbiAgICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgICAgfTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBQcm9kdWNlcyBhIGNhbGxiYWNrIGJvdW5kIHRvIGFuIG9wdGlvbmFsIGB0aGlzQXJnYC4gSWYgYGZ1bmNgIGlzIGEgcHJvcGVydHlcbiAgICAgKiBuYW1lIHRoZSBjcmVhdGVkIGNhbGxiYWNrIHdpbGwgcmV0dXJuIHRoZSBwcm9wZXJ0eSB2YWx1ZSBmb3IgYSBnaXZlbiBlbGVtZW50LlxuICAgICAqIElmIGBmdW5jYCBpcyBhbiBvYmplY3QgdGhlIGNyZWF0ZWQgY2FsbGJhY2sgd2lsbCByZXR1cm4gYHRydWVgIGZvciBlbGVtZW50c1xuICAgICAqIHRoYXQgY29udGFpbiB0aGUgZXF1aXZhbGVudCBvYmplY3QgcHJvcGVydGllcywgb3RoZXJ3aXNlIGl0IHdpbGwgcmV0dXJuIGBmYWxzZWAuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgVXRpbGl0aWVzXG4gICAgICogQHBhcmFtIHsqfSBbZnVuYz1pZGVudGl0eV0gVGhlIHZhbHVlIHRvIGNvbnZlcnQgdG8gYSBjYWxsYmFjay5cbiAgICAgKiBAcGFyYW0geyp9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgdGhlIGNyZWF0ZWQgY2FsbGJhY2suXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IFthcmdDb3VudF0gVGhlIG51bWJlciBvZiBhcmd1bWVudHMgdGhlIGNhbGxiYWNrIGFjY2VwdHMuXG4gICAgICogQHJldHVybnMge0Z1bmN0aW9ufSBSZXR1cm5zIGEgY2FsbGJhY2sgZnVuY3Rpb24uXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIHZhciBjaGFyYWN0ZXJzID0gW1xuICAgICAqICAgeyAnbmFtZSc6ICdiYXJuZXknLCAnYWdlJzogMzYgfSxcbiAgICAgKiAgIHsgJ25hbWUnOiAnZnJlZCcsICAgJ2FnZSc6IDQwIH1cbiAgICAgKiBdO1xuICAgICAqXG4gICAgICogLy8gd3JhcCB0byBjcmVhdGUgY3VzdG9tIGNhbGxiYWNrIHNob3J0aGFuZHNcbiAgICAgKiBfLmNyZWF0ZUNhbGxiYWNrID0gXy53cmFwKF8uY3JlYXRlQ2FsbGJhY2ssIGZ1bmN0aW9uKGZ1bmMsIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICogICB2YXIgbWF0Y2ggPSAvXiguKz8pX18oW2dsXXQpKC4rKSQvLmV4ZWMoY2FsbGJhY2spO1xuICAgICAqICAgcmV0dXJuICFtYXRjaCA/IGZ1bmMoY2FsbGJhY2ssIHRoaXNBcmcpIDogZnVuY3Rpb24ob2JqZWN0KSB7XG4gICAgICogICAgIHJldHVybiBtYXRjaFsyXSA9PSAnZ3QnID8gb2JqZWN0W21hdGNoWzFdXSA+IG1hdGNoWzNdIDogb2JqZWN0W21hdGNoWzFdXSA8IG1hdGNoWzNdO1xuICAgICAqICAgfTtcbiAgICAgKiB9KTtcbiAgICAgKlxuICAgICAqIF8uZmlsdGVyKGNoYXJhY3RlcnMsICdhZ2VfX2d0MzgnKTtcbiAgICAgKiAvLyA9PiBbeyAnbmFtZSc6ICdmcmVkJywgJ2FnZSc6IDQwIH1dXG4gICAgICovXG4gICAgZnVuY3Rpb24gY3JlYXRlQ2FsbGJhY2soZnVuYywgdGhpc0FyZywgYXJnQ291bnQpIHtcbiAgICAgIHZhciB0eXBlID0gdHlwZW9mIGZ1bmM7XG4gICAgICBpZiAoZnVuYyA9PSBudWxsIHx8IHR5cGUgPT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICByZXR1cm4gYmFzZUNyZWF0ZUNhbGxiYWNrKGZ1bmMsIHRoaXNBcmcsIGFyZ0NvdW50KTtcbiAgICAgIH1cbiAgICAgIC8vIGhhbmRsZSBcIl8ucGx1Y2tcIiBzdHlsZSBjYWxsYmFjayBzaG9ydGhhbmRzXG4gICAgICBpZiAodHlwZSAhPSAnb2JqZWN0Jykge1xuICAgICAgICByZXR1cm4gcHJvcGVydHkoZnVuYyk7XG4gICAgICB9XG4gICAgICB2YXIgcHJvcHMgPSBrZXlzKGZ1bmMpLFxuICAgICAgICAgIGtleSA9IHByb3BzWzBdLFxuICAgICAgICAgIGEgPSBmdW5jW2tleV07XG5cbiAgICAgIC8vIGhhbmRsZSBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFjayBzaG9ydGhhbmRzXG4gICAgICBpZiAocHJvcHMubGVuZ3RoID09IDEgJiYgYSA9PT0gYSAmJiAhaXNPYmplY3QoYSkpIHtcbiAgICAgICAgLy8gZmFzdCBwYXRoIHRoZSBjb21tb24gY2FzZSBvZiBwcm92aWRpbmcgYW4gb2JqZWN0IHdpdGggYSBzaW5nbGVcbiAgICAgICAgLy8gcHJvcGVydHkgY29udGFpbmluZyBhIHByaW1pdGl2ZSB2YWx1ZVxuICAgICAgICByZXR1cm4gZnVuY3Rpb24ob2JqZWN0KSB7XG4gICAgICAgICAgdmFyIGIgPSBvYmplY3Rba2V5XTtcbiAgICAgICAgICByZXR1cm4gYSA9PT0gYiAmJiAoYSAhPT0gMCB8fCAoMSAvIGEgPT0gMSAvIGIpKTtcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBmdW5jdGlvbihvYmplY3QpIHtcbiAgICAgICAgdmFyIGxlbmd0aCA9IHByb3BzLmxlbmd0aCxcbiAgICAgICAgICAgIHJlc3VsdCA9IGZhbHNlO1xuXG4gICAgICAgIHdoaWxlIChsZW5ndGgtLSkge1xuICAgICAgICAgIGlmICghKHJlc3VsdCA9IGJhc2VJc0VxdWFsKG9iamVjdFtwcm9wc1tsZW5ndGhdXSwgZnVuY1twcm9wc1tsZW5ndGhdXSwgbnVsbCwgdHJ1ZSkpKSB7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ29udmVydHMgdGhlIGNoYXJhY3RlcnMgYCZgLCBgPGAsIGA+YCwgYFwiYCwgYW5kIGAnYCBpbiBgc3RyaW5nYCB0byB0aGVpclxuICAgICAqIGNvcnJlc3BvbmRpbmcgSFRNTCBlbnRpdGllcy5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBVdGlsaXRpZXNcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gc3RyaW5nIFRoZSBzdHJpbmcgdG8gZXNjYXBlLlxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IFJldHVybnMgdGhlIGVzY2FwZWQgc3RyaW5nLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLmVzY2FwZSgnRnJlZCwgV2lsbWEsICYgUGViYmxlcycpO1xuICAgICAqIC8vID0+ICdGcmVkLCBXaWxtYSwgJmFtcDsgUGViYmxlcydcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBlc2NhcGUoc3RyaW5nKSB7XG4gICAgICByZXR1cm4gc3RyaW5nID09IG51bGwgPyAnJyA6IFN0cmluZyhzdHJpbmcpLnJlcGxhY2UocmVVbmVzY2FwZWRIdG1sLCBlc2NhcGVIdG1sQ2hhcik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhpcyBtZXRob2QgcmV0dXJucyB0aGUgZmlyc3QgYXJndW1lbnQgcHJvdmlkZWQgdG8gaXQuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgVXRpbGl0aWVzXG4gICAgICogQHBhcmFtIHsqfSB2YWx1ZSBBbnkgdmFsdWUuXG4gICAgICogQHJldHVybnMgeyp9IFJldHVybnMgYHZhbHVlYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIG9iamVjdCA9IHsgJ25hbWUnOiAnZnJlZCcgfTtcbiAgICAgKiBfLmlkZW50aXR5KG9iamVjdCkgPT09IG9iamVjdDtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICovXG4gICAgZnVuY3Rpb24gaWRlbnRpdHkodmFsdWUpIHtcbiAgICAgIHJldHVybiB2YWx1ZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBZGRzIGZ1bmN0aW9uIHByb3BlcnRpZXMgb2YgYSBzb3VyY2Ugb2JqZWN0IHRvIHRoZSBkZXN0aW5hdGlvbiBvYmplY3QuXG4gICAgICogSWYgYG9iamVjdGAgaXMgYSBmdW5jdGlvbiBtZXRob2RzIHdpbGwgYmUgYWRkZWQgdG8gaXRzIHByb3RvdHlwZSBhcyB3ZWxsLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IFV0aWxpdGllc1xuICAgICAqIEBwYXJhbSB7RnVuY3Rpb258T2JqZWN0fSBbb2JqZWN0PWxvZGFzaF0gb2JqZWN0IFRoZSBkZXN0aW5hdGlvbiBvYmplY3QuXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHNvdXJjZSBUaGUgb2JqZWN0IG9mIGZ1bmN0aW9ucyB0byBhZGQuXG4gICAgICogQHBhcmFtIHtPYmplY3R9IFtvcHRpb25zXSBUaGUgb3B0aW9ucyBvYmplY3QuXG4gICAgICogQHBhcmFtIHtib29sZWFufSBbb3B0aW9ucy5jaGFpbj10cnVlXSBTcGVjaWZ5IHdoZXRoZXIgdGhlIGZ1bmN0aW9ucyBhZGRlZCBhcmUgY2hhaW5hYmxlLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBmdW5jdGlvbiBjYXBpdGFsaXplKHN0cmluZykge1xuICAgICAqICAgcmV0dXJuIHN0cmluZy5jaGFyQXQoMCkudG9VcHBlckNhc2UoKSArIHN0cmluZy5zbGljZSgxKS50b0xvd2VyQ2FzZSgpO1xuICAgICAqIH1cbiAgICAgKlxuICAgICAqIF8ubWl4aW4oeyAnY2FwaXRhbGl6ZSc6IGNhcGl0YWxpemUgfSk7XG4gICAgICogXy5jYXBpdGFsaXplKCdmcmVkJyk7XG4gICAgICogLy8gPT4gJ0ZyZWQnXG4gICAgICpcbiAgICAgKiBfKCdmcmVkJykuY2FwaXRhbGl6ZSgpLnZhbHVlKCk7XG4gICAgICogLy8gPT4gJ0ZyZWQnXG4gICAgICpcbiAgICAgKiBfLm1peGluKHsgJ2NhcGl0YWxpemUnOiBjYXBpdGFsaXplIH0sIHsgJ2NoYWluJzogZmFsc2UgfSk7XG4gICAgICogXygnZnJlZCcpLmNhcGl0YWxpemUoKTtcbiAgICAgKiAvLyA9PiAnRnJlZCdcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBtaXhpbihvYmplY3QsIHNvdXJjZSwgb3B0aW9ucykge1xuICAgICAgdmFyIGNoYWluID0gdHJ1ZSxcbiAgICAgICAgICBtZXRob2ROYW1lcyA9IHNvdXJjZSAmJiBmdW5jdGlvbnMoc291cmNlKTtcblxuICAgICAgaWYgKCFzb3VyY2UgfHwgKCFvcHRpb25zICYmICFtZXRob2ROYW1lcy5sZW5ndGgpKSB7XG4gICAgICAgIGlmIChvcHRpb25zID09IG51bGwpIHtcbiAgICAgICAgICBvcHRpb25zID0gc291cmNlO1xuICAgICAgICB9XG4gICAgICAgIGN0b3IgPSBsb2Rhc2hXcmFwcGVyO1xuICAgICAgICBzb3VyY2UgPSBvYmplY3Q7XG4gICAgICAgIG9iamVjdCA9IGxvZGFzaDtcbiAgICAgICAgbWV0aG9kTmFtZXMgPSBmdW5jdGlvbnMoc291cmNlKTtcbiAgICAgIH1cbiAgICAgIGlmIChvcHRpb25zID09PSBmYWxzZSkge1xuICAgICAgICBjaGFpbiA9IGZhbHNlO1xuICAgICAgfSBlbHNlIGlmIChpc09iamVjdChvcHRpb25zKSAmJiAnY2hhaW4nIGluIG9wdGlvbnMpIHtcbiAgICAgICAgY2hhaW4gPSBvcHRpb25zLmNoYWluO1xuICAgICAgfVxuICAgICAgdmFyIGN0b3IgPSBvYmplY3QsXG4gICAgICAgICAgaXNGdW5jID0gaXNGdW5jdGlvbihjdG9yKTtcblxuICAgICAgZm9yRWFjaChtZXRob2ROYW1lcywgZnVuY3Rpb24obWV0aG9kTmFtZSkge1xuICAgICAgICB2YXIgZnVuYyA9IG9iamVjdFttZXRob2ROYW1lXSA9IHNvdXJjZVttZXRob2ROYW1lXTtcbiAgICAgICAgaWYgKGlzRnVuYykge1xuICAgICAgICAgIGN0b3IucHJvdG90eXBlW21ldGhvZE5hbWVdID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgY2hhaW5BbGwgPSB0aGlzLl9fY2hhaW5fXyxcbiAgICAgICAgICAgICAgICB2YWx1ZSA9IHRoaXMuX193cmFwcGVkX18sXG4gICAgICAgICAgICAgICAgYXJncyA9IFt2YWx1ZV07XG5cbiAgICAgICAgICAgIHB1c2guYXBwbHkoYXJncywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIHZhciByZXN1bHQgPSBmdW5jLmFwcGx5KG9iamVjdCwgYXJncyk7XG4gICAgICAgICAgICBpZiAoY2hhaW4gfHwgY2hhaW5BbGwpIHtcbiAgICAgICAgICAgICAgaWYgKHZhbHVlID09PSByZXN1bHQgJiYgaXNPYmplY3QocmVzdWx0KSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBjdG9yKHJlc3VsdCk7XG4gICAgICAgICAgICAgIHJlc3VsdC5fX2NoYWluX18gPSBjaGFpbkFsbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV2ZXJ0cyB0aGUgJ18nIHZhcmlhYmxlIHRvIGl0cyBwcmV2aW91cyB2YWx1ZSBhbmQgcmV0dXJucyBhIHJlZmVyZW5jZSB0b1xuICAgICAqIHRoZSBgbG9kYXNoYCBmdW5jdGlvbi5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBVdGlsaXRpZXNcbiAgICAgKiBAcmV0dXJucyB7RnVuY3Rpb259IFJldHVybnMgdGhlIGBsb2Rhc2hgIGZ1bmN0aW9uLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgbG9kYXNoID0gXy5ub0NvbmZsaWN0KCk7XG4gICAgICovXG4gICAgZnVuY3Rpb24gbm9Db25mbGljdCgpIHtcbiAgICAgIGNvbnRleHQuXyA9IG9sZERhc2g7XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBIG5vLW9wZXJhdGlvbiBmdW5jdGlvbi5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBVdGlsaXRpZXNcbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIG9iamVjdCA9IHsgJ25hbWUnOiAnZnJlZCcgfTtcbiAgICAgKiBfLm5vb3Aob2JqZWN0KSA9PT0gdW5kZWZpbmVkO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBub29wKCkge1xuICAgICAgLy8gbm8gb3BlcmF0aW9uIHBlcmZvcm1lZFxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldHMgdGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdGhhdCBoYXZlIGVsYXBzZWQgc2luY2UgdGhlIFVuaXggZXBvY2hcbiAgICAgKiAoMSBKYW51YXJ5IDE5NzAgMDA6MDA6MDAgVVRDKS5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBVdGlsaXRpZXNcbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIHN0YW1wID0gXy5ub3coKTtcbiAgICAgKiBfLmRlZmVyKGZ1bmN0aW9uKCkgeyBjb25zb2xlLmxvZyhfLm5vdygpIC0gc3RhbXApOyB9KTtcbiAgICAgKiAvLyA9PiBsb2dzIHRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIGl0IHRvb2sgZm9yIHRoZSBkZWZlcnJlZCBmdW5jdGlvbiB0byBiZSBjYWxsZWRcbiAgICAgKi9cbiAgICB2YXIgbm93ID0gaXNOYXRpdmUobm93ID0gRGF0ZS5ub3cpICYmIG5vdyB8fCBmdW5jdGlvbigpIHtcbiAgICAgIHJldHVybiBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQ29udmVydHMgdGhlIGdpdmVuIHZhbHVlIGludG8gYW4gaW50ZWdlciBvZiB0aGUgc3BlY2lmaWVkIHJhZGl4LlxuICAgICAqIElmIGByYWRpeGAgaXMgYHVuZGVmaW5lZGAgb3IgYDBgIGEgYHJhZGl4YCBvZiBgMTBgIGlzIHVzZWQgdW5sZXNzIHRoZVxuICAgICAqIGB2YWx1ZWAgaXMgYSBoZXhhZGVjaW1hbCwgaW4gd2hpY2ggY2FzZSBhIGByYWRpeGAgb2YgYDE2YCBpcyB1c2VkLlxuICAgICAqXG4gICAgICogTm90ZTogVGhpcyBtZXRob2QgYXZvaWRzIGRpZmZlcmVuY2VzIGluIG5hdGl2ZSBFUzMgYW5kIEVTNSBgcGFyc2VJbnRgXG4gICAgICogaW1wbGVtZW50YXRpb25zLiBTZWUgaHR0cDovL2VzNS5naXRodWIuaW8vI0UuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgVXRpbGl0aWVzXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHZhbHVlIFRoZSB2YWx1ZSB0byBwYXJzZS5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gW3JhZGl4XSBUaGUgcmFkaXggdXNlZCB0byBpbnRlcnByZXQgdGhlIHZhbHVlIHRvIHBhcnNlLlxuICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFJldHVybnMgdGhlIG5ldyBpbnRlZ2VyIHZhbHVlLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLnBhcnNlSW50KCcwOCcpO1xuICAgICAqIC8vID0+IDhcbiAgICAgKi9cbiAgICB2YXIgcGFyc2VJbnQgPSBuYXRpdmVQYXJzZUludCh3aGl0ZXNwYWNlICsgJzA4JykgPT0gOCA/IG5hdGl2ZVBhcnNlSW50IDogZnVuY3Rpb24odmFsdWUsIHJhZGl4KSB7XG4gICAgICAvLyBGaXJlZm94IDwgMjEgYW5kIE9wZXJhIDwgMTUgZm9sbG93IHRoZSBFUzMgc3BlY2lmaWVkIGltcGxlbWVudGF0aW9uIG9mIGBwYXJzZUludGBcbiAgICAgIHJldHVybiBuYXRpdmVQYXJzZUludChpc1N0cmluZyh2YWx1ZSkgPyB2YWx1ZS5yZXBsYWNlKHJlTGVhZGluZ1NwYWNlc0FuZFplcm9zLCAnJykgOiB2YWx1ZSwgcmFkaXggfHwgMCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSBcIl8ucGx1Y2tcIiBzdHlsZSBmdW5jdGlvbiwgd2hpY2ggcmV0dXJucyB0aGUgYGtleWAgdmFsdWUgb2YgYVxuICAgICAqIGdpdmVuIG9iamVjdC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBVdGlsaXRpZXNcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5IFRoZSBuYW1lIG9mIHRoZSBwcm9wZXJ0eSB0byByZXRyaWV2ZS5cbiAgICAgKiBAcmV0dXJucyB7RnVuY3Rpb259IFJldHVybnMgdGhlIG5ldyBmdW5jdGlvbi5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIGNoYXJhY3RlcnMgPSBbXG4gICAgICogICB7ICduYW1lJzogJ2ZyZWQnLCAgICdhZ2UnOiA0MCB9LFxuICAgICAqICAgeyAnbmFtZSc6ICdiYXJuZXknLCAnYWdlJzogMzYgfVxuICAgICAqIF07XG4gICAgICpcbiAgICAgKiB2YXIgZ2V0TmFtZSA9IF8ucHJvcGVydHkoJ25hbWUnKTtcbiAgICAgKlxuICAgICAqIF8ubWFwKGNoYXJhY3RlcnMsIGdldE5hbWUpO1xuICAgICAqIC8vID0+IFsnYmFybmV5JywgJ2ZyZWQnXVxuICAgICAqXG4gICAgICogXy5zb3J0QnkoY2hhcmFjdGVycywgZ2V0TmFtZSk7XG4gICAgICogLy8gPT4gW3sgJ25hbWUnOiAnYmFybmV5JywgJ2FnZSc6IDM2IH0sIHsgJ25hbWUnOiAnZnJlZCcsICAgJ2FnZSc6IDQwIH1dXG4gICAgICovXG4gICAgZnVuY3Rpb24gcHJvcGVydHkoa2V5KSB7XG4gICAgICByZXR1cm4gZnVuY3Rpb24ob2JqZWN0KSB7XG4gICAgICAgIHJldHVybiBvYmplY3Rba2V5XTtcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUHJvZHVjZXMgYSByYW5kb20gbnVtYmVyIGJldHdlZW4gYG1pbmAgYW5kIGBtYXhgIChpbmNsdXNpdmUpLiBJZiBvbmx5IG9uZVxuICAgICAqIGFyZ3VtZW50IGlzIHByb3ZpZGVkIGEgbnVtYmVyIGJldHdlZW4gYDBgIGFuZCB0aGUgZ2l2ZW4gbnVtYmVyIHdpbGwgYmVcbiAgICAgKiByZXR1cm5lZC4gSWYgYGZsb2F0aW5nYCBpcyB0cnVleSBvciBlaXRoZXIgYG1pbmAgb3IgYG1heGAgYXJlIGZsb2F0cyBhXG4gICAgICogZmxvYXRpbmctcG9pbnQgbnVtYmVyIHdpbGwgYmUgcmV0dXJuZWQgaW5zdGVhZCBvZiBhbiBpbnRlZ2VyLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IFV0aWxpdGllc1xuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbbWluPTBdIFRoZSBtaW5pbXVtIHBvc3NpYmxlIHZhbHVlLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbbWF4PTFdIFRoZSBtYXhpbXVtIHBvc3NpYmxlIHZhbHVlLlxuICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW2Zsb2F0aW5nPWZhbHNlXSBTcGVjaWZ5IHJldHVybmluZyBhIGZsb2F0aW5nLXBvaW50IG51bWJlci5cbiAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBSZXR1cm5zIGEgcmFuZG9tIG51bWJlci5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5yYW5kb20oMCwgNSk7XG4gICAgICogLy8gPT4gYW4gaW50ZWdlciBiZXR3ZWVuIDAgYW5kIDVcbiAgICAgKlxuICAgICAqIF8ucmFuZG9tKDUpO1xuICAgICAqIC8vID0+IGFsc28gYW4gaW50ZWdlciBiZXR3ZWVuIDAgYW5kIDVcbiAgICAgKlxuICAgICAqIF8ucmFuZG9tKDUsIHRydWUpO1xuICAgICAqIC8vID0+IGEgZmxvYXRpbmctcG9pbnQgbnVtYmVyIGJldHdlZW4gMCBhbmQgNVxuICAgICAqXG4gICAgICogXy5yYW5kb20oMS4yLCA1LjIpO1xuICAgICAqIC8vID0+IGEgZmxvYXRpbmctcG9pbnQgbnVtYmVyIGJldHdlZW4gMS4yIGFuZCA1LjJcbiAgICAgKi9cbiAgICBmdW5jdGlvbiByYW5kb20obWluLCBtYXgsIGZsb2F0aW5nKSB7XG4gICAgICB2YXIgbm9NaW4gPSBtaW4gPT0gbnVsbCxcbiAgICAgICAgICBub01heCA9IG1heCA9PSBudWxsO1xuXG4gICAgICBpZiAoZmxvYXRpbmcgPT0gbnVsbCkge1xuICAgICAgICBpZiAodHlwZW9mIG1pbiA9PSAnYm9vbGVhbicgJiYgbm9NYXgpIHtcbiAgICAgICAgICBmbG9hdGluZyA9IG1pbjtcbiAgICAgICAgICBtaW4gPSAxO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKCFub01heCAmJiB0eXBlb2YgbWF4ID09ICdib29sZWFuJykge1xuICAgICAgICAgIGZsb2F0aW5nID0gbWF4O1xuICAgICAgICAgIG5vTWF4ID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKG5vTWluICYmIG5vTWF4KSB7XG4gICAgICAgIG1heCA9IDE7XG4gICAgICB9XG4gICAgICBtaW4gPSArbWluIHx8IDA7XG4gICAgICBpZiAobm9NYXgpIHtcbiAgICAgICAgbWF4ID0gbWluO1xuICAgICAgICBtaW4gPSAwO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbWF4ID0gK21heCB8fCAwO1xuICAgICAgfVxuICAgICAgaWYgKGZsb2F0aW5nIHx8IG1pbiAlIDEgfHwgbWF4ICUgMSkge1xuICAgICAgICB2YXIgcmFuZCA9IG5hdGl2ZVJhbmRvbSgpO1xuICAgICAgICByZXR1cm4gbmF0aXZlTWluKG1pbiArIChyYW5kICogKG1heCAtIG1pbiArIHBhcnNlRmxvYXQoJzFlLScgKyAoKHJhbmQgKycnKS5sZW5ndGggLSAxKSkpKSwgbWF4KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBiYXNlUmFuZG9tKG1pbiwgbWF4KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXNvbHZlcyB0aGUgdmFsdWUgb2YgcHJvcGVydHkgYGtleWAgb24gYG9iamVjdGAuIElmIGBrZXlgIGlzIGEgZnVuY3Rpb25cbiAgICAgKiBpdCB3aWxsIGJlIGludm9rZWQgd2l0aCB0aGUgYHRoaXNgIGJpbmRpbmcgb2YgYG9iamVjdGAgYW5kIGl0cyByZXN1bHQgcmV0dXJuZWQsXG4gICAgICogZWxzZSB0aGUgcHJvcGVydHkgdmFsdWUgaXMgcmV0dXJuZWQuIElmIGBvYmplY3RgIGlzIGZhbHNleSB0aGVuIGB1bmRlZmluZWRgXG4gICAgICogaXMgcmV0dXJuZWQuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgVXRpbGl0aWVzXG4gICAgICogQHBhcmFtIHtPYmplY3R9IG9iamVjdCBUaGUgb2JqZWN0IHRvIGluc3BlY3QuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGtleSBUaGUgbmFtZSBvZiB0aGUgcHJvcGVydHkgdG8gcmVzb2x2ZS5cbiAgICAgKiBAcmV0dXJucyB7Kn0gUmV0dXJucyB0aGUgcmVzb2x2ZWQgdmFsdWUuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIHZhciBvYmplY3QgPSB7XG4gICAgICogICAnY2hlZXNlJzogJ2NydW1wZXRzJyxcbiAgICAgKiAgICdzdHVmZic6IGZ1bmN0aW9uKCkge1xuICAgICAqICAgICByZXR1cm4gJ25vbnNlbnNlJztcbiAgICAgKiAgIH1cbiAgICAgKiB9O1xuICAgICAqXG4gICAgICogXy5yZXN1bHQob2JqZWN0LCAnY2hlZXNlJyk7XG4gICAgICogLy8gPT4gJ2NydW1wZXRzJ1xuICAgICAqXG4gICAgICogXy5yZXN1bHQob2JqZWN0LCAnc3R1ZmYnKTtcbiAgICAgKiAvLyA9PiAnbm9uc2Vuc2UnXG4gICAgICovXG4gICAgZnVuY3Rpb24gcmVzdWx0KG9iamVjdCwga2V5KSB7XG4gICAgICBpZiAob2JqZWN0KSB7XG4gICAgICAgIHZhciB2YWx1ZSA9IG9iamVjdFtrZXldO1xuICAgICAgICByZXR1cm4gaXNGdW5jdGlvbih2YWx1ZSkgPyBvYmplY3Rba2V5XSgpIDogdmFsdWU7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQSBtaWNyby10ZW1wbGF0aW5nIG1ldGhvZCB0aGF0IGhhbmRsZXMgYXJiaXRyYXJ5IGRlbGltaXRlcnMsIHByZXNlcnZlc1xuICAgICAqIHdoaXRlc3BhY2UsIGFuZCBjb3JyZWN0bHkgZXNjYXBlcyBxdW90ZXMgd2l0aGluIGludGVycG9sYXRlZCBjb2RlLlxuICAgICAqXG4gICAgICogTm90ZTogSW4gdGhlIGRldmVsb3BtZW50IGJ1aWxkLCBgXy50ZW1wbGF0ZWAgdXRpbGl6ZXMgc291cmNlVVJMcyBmb3IgZWFzaWVyXG4gICAgICogZGVidWdnaW5nLiBTZWUgaHR0cDovL3d3dy5odG1sNXJvY2tzLmNvbS9lbi90dXRvcmlhbHMvZGV2ZWxvcGVydG9vbHMvc291cmNlbWFwcy8jdG9jLXNvdXJjZXVybFxuICAgICAqXG4gICAgICogRm9yIG1vcmUgaW5mb3JtYXRpb24gb24gcHJlY29tcGlsaW5nIHRlbXBsYXRlcyBzZWU6XG4gICAgICogaHR0cDovL2xvZGFzaC5jb20vY3VzdG9tLWJ1aWxkc1xuICAgICAqXG4gICAgICogRm9yIG1vcmUgaW5mb3JtYXRpb24gb24gQ2hyb21lIGV4dGVuc2lvbiBzYW5kYm94ZXMgc2VlOlxuICAgICAqIGh0dHA6Ly9kZXZlbG9wZXIuY2hyb21lLmNvbS9zdGFibGUvZXh0ZW5zaW9ucy9zYW5kYm94aW5nRXZhbC5odG1sXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgVXRpbGl0aWVzXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHRleHQgVGhlIHRlbXBsYXRlIHRleHQuXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGRhdGEgVGhlIGRhdGEgb2JqZWN0IHVzZWQgdG8gcG9wdWxhdGUgdGhlIHRleHQuXG4gICAgICogQHBhcmFtIHtPYmplY3R9IFtvcHRpb25zXSBUaGUgb3B0aW9ucyBvYmplY3QuXG4gICAgICogQHBhcmFtIHtSZWdFeHB9IFtvcHRpb25zLmVzY2FwZV0gVGhlIFwiZXNjYXBlXCIgZGVsaW1pdGVyLlxuICAgICAqIEBwYXJhbSB7UmVnRXhwfSBbb3B0aW9ucy5ldmFsdWF0ZV0gVGhlIFwiZXZhbHVhdGVcIiBkZWxpbWl0ZXIuXG4gICAgICogQHBhcmFtIHtPYmplY3R9IFtvcHRpb25zLmltcG9ydHNdIEFuIG9iamVjdCB0byBpbXBvcnQgaW50byB0aGUgdGVtcGxhdGUgYXMgbG9jYWwgdmFyaWFibGVzLlxuICAgICAqIEBwYXJhbSB7UmVnRXhwfSBbb3B0aW9ucy5pbnRlcnBvbGF0ZV0gVGhlIFwiaW50ZXJwb2xhdGVcIiBkZWxpbWl0ZXIuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IFtzb3VyY2VVUkxdIFRoZSBzb3VyY2VVUkwgb2YgdGhlIHRlbXBsYXRlJ3MgY29tcGlsZWQgc291cmNlLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbdmFyaWFibGVdIFRoZSBkYXRhIG9iamVjdCB2YXJpYWJsZSBuYW1lLlxuICAgICAqIEByZXR1cm5zIHtGdW5jdGlvbnxzdHJpbmd9IFJldHVybnMgYSBjb21waWxlZCBmdW5jdGlvbiB3aGVuIG5vIGBkYXRhYCBvYmplY3RcbiAgICAgKiAgaXMgZ2l2ZW4sIGVsc2UgaXQgcmV0dXJucyB0aGUgaW50ZXJwb2xhdGVkIHRleHQuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIHRoZSBcImludGVycG9sYXRlXCIgZGVsaW1pdGVyIHRvIGNyZWF0ZSBhIGNvbXBpbGVkIHRlbXBsYXRlXG4gICAgICogdmFyIGNvbXBpbGVkID0gXy50ZW1wbGF0ZSgnaGVsbG8gPCU9IG5hbWUgJT4nKTtcbiAgICAgKiBjb21waWxlZCh7ICduYW1lJzogJ2ZyZWQnIH0pO1xuICAgICAqIC8vID0+ICdoZWxsbyBmcmVkJ1xuICAgICAqXG4gICAgICogLy8gdXNpbmcgdGhlIFwiZXNjYXBlXCIgZGVsaW1pdGVyIHRvIGVzY2FwZSBIVE1MIGluIGRhdGEgcHJvcGVydHkgdmFsdWVzXG4gICAgICogXy50ZW1wbGF0ZSgnPGI+PCUtIHZhbHVlICU+PC9iPicsIHsgJ3ZhbHVlJzogJzxzY3JpcHQ+JyB9KTtcbiAgICAgKiAvLyA9PiAnPGI+Jmx0O3NjcmlwdCZndDs8L2I+J1xuICAgICAqXG4gICAgICogLy8gdXNpbmcgdGhlIFwiZXZhbHVhdGVcIiBkZWxpbWl0ZXIgdG8gZ2VuZXJhdGUgSFRNTFxuICAgICAqIHZhciBsaXN0ID0gJzwlIF8uZm9yRWFjaChwZW9wbGUsIGZ1bmN0aW9uKG5hbWUpIHsgJT48bGk+PCUtIG5hbWUgJT48L2xpPjwlIH0pOyAlPic7XG4gICAgICogXy50ZW1wbGF0ZShsaXN0LCB7ICdwZW9wbGUnOiBbJ2ZyZWQnLCAnYmFybmV5J10gfSk7XG4gICAgICogLy8gPT4gJzxsaT5mcmVkPC9saT48bGk+YmFybmV5PC9saT4nXG4gICAgICpcbiAgICAgKiAvLyB1c2luZyB0aGUgRVM2IGRlbGltaXRlciBhcyBhbiBhbHRlcm5hdGl2ZSB0byB0aGUgZGVmYXVsdCBcImludGVycG9sYXRlXCIgZGVsaW1pdGVyXG4gICAgICogXy50ZW1wbGF0ZSgnaGVsbG8gJHsgbmFtZSB9JywgeyAnbmFtZSc6ICdwZWJibGVzJyB9KTtcbiAgICAgKiAvLyA9PiAnaGVsbG8gcGViYmxlcydcbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIHRoZSBpbnRlcm5hbCBgcHJpbnRgIGZ1bmN0aW9uIGluIFwiZXZhbHVhdGVcIiBkZWxpbWl0ZXJzXG4gICAgICogXy50ZW1wbGF0ZSgnPCUgcHJpbnQoXCJoZWxsbyBcIiArIG5hbWUpOyAlPiEnLCB7ICduYW1lJzogJ2Jhcm5leScgfSk7XG4gICAgICogLy8gPT4gJ2hlbGxvIGJhcm5leSEnXG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBhIGN1c3RvbSB0ZW1wbGF0ZSBkZWxpbWl0ZXJzXG4gICAgICogXy50ZW1wbGF0ZVNldHRpbmdzID0ge1xuICAgICAqICAgJ2ludGVycG9sYXRlJzogL3t7KFtcXHNcXFNdKz8pfX0vZ1xuICAgICAqIH07XG4gICAgICpcbiAgICAgKiBfLnRlbXBsYXRlKCdoZWxsbyB7eyBuYW1lIH19IScsIHsgJ25hbWUnOiAnbXVzdGFjaGUnIH0pO1xuICAgICAqIC8vID0+ICdoZWxsbyBtdXN0YWNoZSEnXG4gICAgICpcbiAgICAgKiAvLyB1c2luZyB0aGUgYGltcG9ydHNgIG9wdGlvbiB0byBpbXBvcnQgalF1ZXJ5XG4gICAgICogdmFyIGxpc3QgPSAnPCUganEuZWFjaChwZW9wbGUsIGZ1bmN0aW9uKG5hbWUpIHsgJT48bGk+PCUtIG5hbWUgJT48L2xpPjwlIH0pOyAlPic7XG4gICAgICogXy50ZW1wbGF0ZShsaXN0LCB7ICdwZW9wbGUnOiBbJ2ZyZWQnLCAnYmFybmV5J10gfSwgeyAnaW1wb3J0cyc6IHsgJ2pxJzogalF1ZXJ5IH0gfSk7XG4gICAgICogLy8gPT4gJzxsaT5mcmVkPC9saT48bGk+YmFybmV5PC9saT4nXG4gICAgICpcbiAgICAgKiAvLyB1c2luZyB0aGUgYHNvdXJjZVVSTGAgb3B0aW9uIHRvIHNwZWNpZnkgYSBjdXN0b20gc291cmNlVVJMIGZvciB0aGUgdGVtcGxhdGVcbiAgICAgKiB2YXIgY29tcGlsZWQgPSBfLnRlbXBsYXRlKCdoZWxsbyA8JT0gbmFtZSAlPicsIG51bGwsIHsgJ3NvdXJjZVVSTCc6ICcvYmFzaWMvZ3JlZXRpbmcuanN0JyB9KTtcbiAgICAgKiBjb21waWxlZChkYXRhKTtcbiAgICAgKiAvLyA9PiBmaW5kIHRoZSBzb3VyY2Ugb2YgXCJncmVldGluZy5qc3RcIiB1bmRlciB0aGUgU291cmNlcyB0YWIgb3IgUmVzb3VyY2VzIHBhbmVsIG9mIHRoZSB3ZWIgaW5zcGVjdG9yXG4gICAgICpcbiAgICAgKiAvLyB1c2luZyB0aGUgYHZhcmlhYmxlYCBvcHRpb24gdG8gZW5zdXJlIGEgd2l0aC1zdGF0ZW1lbnQgaXNuJ3QgdXNlZCBpbiB0aGUgY29tcGlsZWQgdGVtcGxhdGVcbiAgICAgKiB2YXIgY29tcGlsZWQgPSBfLnRlbXBsYXRlKCdoaSA8JT0gZGF0YS5uYW1lICU+IScsIG51bGwsIHsgJ3ZhcmlhYmxlJzogJ2RhdGEnIH0pO1xuICAgICAqIGNvbXBpbGVkLnNvdXJjZTtcbiAgICAgKiAvLyA9PiBmdW5jdGlvbihkYXRhKSB7XG4gICAgICogICB2YXIgX190LCBfX3AgPSAnJywgX19lID0gXy5lc2NhcGU7XG4gICAgICogICBfX3AgKz0gJ2hpICcgKyAoKF9fdCA9ICggZGF0YS5uYW1lICkpID09IG51bGwgPyAnJyA6IF9fdCkgKyAnISc7XG4gICAgICogICByZXR1cm4gX19wO1xuICAgICAqIH1cbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIHRoZSBgc291cmNlYCBwcm9wZXJ0eSB0byBpbmxpbmUgY29tcGlsZWQgdGVtcGxhdGVzIGZvciBtZWFuaW5nZnVsXG4gICAgICogLy8gbGluZSBudW1iZXJzIGluIGVycm9yIG1lc3NhZ2VzIGFuZCBhIHN0YWNrIHRyYWNlXG4gICAgICogZnMud3JpdGVGaWxlU3luYyhwYXRoLmpvaW4oY3dkLCAnanN0LmpzJyksICdcXFxuICAgICAqICAgdmFyIEpTVCA9IHtcXFxuICAgICAqICAgICBcIm1haW5cIjogJyArIF8udGVtcGxhdGUobWFpblRleHQpLnNvdXJjZSArICdcXFxuICAgICAqICAgfTtcXFxuICAgICAqICcpO1xuICAgICAqL1xuICAgIGZ1bmN0aW9uIHRlbXBsYXRlKHRleHQsIGRhdGEsIG9wdGlvbnMpIHtcbiAgICAgIC8vIGJhc2VkIG9uIEpvaG4gUmVzaWcncyBgdG1wbGAgaW1wbGVtZW50YXRpb25cbiAgICAgIC8vIGh0dHA6Ly9lam9obi5vcmcvYmxvZy9qYXZhc2NyaXB0LW1pY3JvLXRlbXBsYXRpbmcvXG4gICAgICAvLyBhbmQgTGF1cmEgRG9rdG9yb3ZhJ3MgZG9ULmpzXG4gICAgICAvLyBodHRwczovL2dpdGh1Yi5jb20vb2xhZG8vZG9UXG4gICAgICB2YXIgc2V0dGluZ3MgPSBsb2Rhc2gudGVtcGxhdGVTZXR0aW5ncztcbiAgICAgIHRleHQgPSBTdHJpbmcodGV4dCB8fCAnJyk7XG5cbiAgICAgIC8vIGF2b2lkIG1pc3NpbmcgZGVwZW5kZW5jaWVzIHdoZW4gYGl0ZXJhdG9yVGVtcGxhdGVgIGlzIG5vdCBkZWZpbmVkXG4gICAgICBvcHRpb25zID0gZGVmYXVsdHMoe30sIG9wdGlvbnMsIHNldHRpbmdzKTtcblxuICAgICAgdmFyIGltcG9ydHMgPSBkZWZhdWx0cyh7fSwgb3B0aW9ucy5pbXBvcnRzLCBzZXR0aW5ncy5pbXBvcnRzKSxcbiAgICAgICAgICBpbXBvcnRzS2V5cyA9IGtleXMoaW1wb3J0cyksXG4gICAgICAgICAgaW1wb3J0c1ZhbHVlcyA9IHZhbHVlcyhpbXBvcnRzKTtcblxuICAgICAgdmFyIGlzRXZhbHVhdGluZyxcbiAgICAgICAgICBpbmRleCA9IDAsXG4gICAgICAgICAgaW50ZXJwb2xhdGUgPSBvcHRpb25zLmludGVycG9sYXRlIHx8IHJlTm9NYXRjaCxcbiAgICAgICAgICBzb3VyY2UgPSBcIl9fcCArPSAnXCI7XG5cbiAgICAgIC8vIGNvbXBpbGUgdGhlIHJlZ2V4cCB0byBtYXRjaCBlYWNoIGRlbGltaXRlclxuICAgICAgdmFyIHJlRGVsaW1pdGVycyA9IFJlZ0V4cChcbiAgICAgICAgKG9wdGlvbnMuZXNjYXBlIHx8IHJlTm9NYXRjaCkuc291cmNlICsgJ3wnICtcbiAgICAgICAgaW50ZXJwb2xhdGUuc291cmNlICsgJ3wnICtcbiAgICAgICAgKGludGVycG9sYXRlID09PSByZUludGVycG9sYXRlID8gcmVFc1RlbXBsYXRlIDogcmVOb01hdGNoKS5zb3VyY2UgKyAnfCcgK1xuICAgICAgICAob3B0aW9ucy5ldmFsdWF0ZSB8fCByZU5vTWF0Y2gpLnNvdXJjZSArICd8JCdcbiAgICAgICwgJ2cnKTtcblxuICAgICAgdGV4dC5yZXBsYWNlKHJlRGVsaW1pdGVycywgZnVuY3Rpb24obWF0Y2gsIGVzY2FwZVZhbHVlLCBpbnRlcnBvbGF0ZVZhbHVlLCBlc1RlbXBsYXRlVmFsdWUsIGV2YWx1YXRlVmFsdWUsIG9mZnNldCkge1xuICAgICAgICBpbnRlcnBvbGF0ZVZhbHVlIHx8IChpbnRlcnBvbGF0ZVZhbHVlID0gZXNUZW1wbGF0ZVZhbHVlKTtcblxuICAgICAgICAvLyBlc2NhcGUgY2hhcmFjdGVycyB0aGF0IGNhbm5vdCBiZSBpbmNsdWRlZCBpbiBzdHJpbmcgbGl0ZXJhbHNcbiAgICAgICAgc291cmNlICs9IHRleHQuc2xpY2UoaW5kZXgsIG9mZnNldCkucmVwbGFjZShyZVVuZXNjYXBlZFN0cmluZywgZXNjYXBlU3RyaW5nQ2hhcik7XG5cbiAgICAgICAgLy8gcmVwbGFjZSBkZWxpbWl0ZXJzIHdpdGggc25pcHBldHNcbiAgICAgICAgaWYgKGVzY2FwZVZhbHVlKSB7XG4gICAgICAgICAgc291cmNlICs9IFwiJyArXFxuX19lKFwiICsgZXNjYXBlVmFsdWUgKyBcIikgK1xcbidcIjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZXZhbHVhdGVWYWx1ZSkge1xuICAgICAgICAgIGlzRXZhbHVhdGluZyA9IHRydWU7XG4gICAgICAgICAgc291cmNlICs9IFwiJztcXG5cIiArIGV2YWx1YXRlVmFsdWUgKyBcIjtcXG5fX3AgKz0gJ1wiO1xuICAgICAgICB9XG4gICAgICAgIGlmIChpbnRlcnBvbGF0ZVZhbHVlKSB7XG4gICAgICAgICAgc291cmNlICs9IFwiJyArXFxuKChfX3QgPSAoXCIgKyBpbnRlcnBvbGF0ZVZhbHVlICsgXCIpKSA9PSBudWxsID8gJycgOiBfX3QpICtcXG4nXCI7XG4gICAgICAgIH1cbiAgICAgICAgaW5kZXggPSBvZmZzZXQgKyBtYXRjaC5sZW5ndGg7XG5cbiAgICAgICAgLy8gdGhlIEpTIGVuZ2luZSBlbWJlZGRlZCBpbiBBZG9iZSBwcm9kdWN0cyByZXF1aXJlcyByZXR1cm5pbmcgdGhlIGBtYXRjaGBcbiAgICAgICAgLy8gc3RyaW5nIGluIG9yZGVyIHRvIHByb2R1Y2UgdGhlIGNvcnJlY3QgYG9mZnNldGAgdmFsdWVcbiAgICAgICAgcmV0dXJuIG1hdGNoO1xuICAgICAgfSk7XG5cbiAgICAgIHNvdXJjZSArPSBcIic7XFxuXCI7XG5cbiAgICAgIC8vIGlmIGB2YXJpYWJsZWAgaXMgbm90IHNwZWNpZmllZCwgd3JhcCBhIHdpdGgtc3RhdGVtZW50IGFyb3VuZCB0aGUgZ2VuZXJhdGVkXG4gICAgICAvLyBjb2RlIHRvIGFkZCB0aGUgZGF0YSBvYmplY3QgdG8gdGhlIHRvcCBvZiB0aGUgc2NvcGUgY2hhaW5cbiAgICAgIHZhciB2YXJpYWJsZSA9IG9wdGlvbnMudmFyaWFibGUsXG4gICAgICAgICAgaGFzVmFyaWFibGUgPSB2YXJpYWJsZTtcblxuICAgICAgaWYgKCFoYXNWYXJpYWJsZSkge1xuICAgICAgICB2YXJpYWJsZSA9ICdvYmonO1xuICAgICAgICBzb3VyY2UgPSAnd2l0aCAoJyArIHZhcmlhYmxlICsgJykge1xcbicgKyBzb3VyY2UgKyAnXFxufVxcbic7XG4gICAgICB9XG4gICAgICAvLyBjbGVhbnVwIGNvZGUgYnkgc3RyaXBwaW5nIGVtcHR5IHN0cmluZ3NcbiAgICAgIHNvdXJjZSA9IChpc0V2YWx1YXRpbmcgPyBzb3VyY2UucmVwbGFjZShyZUVtcHR5U3RyaW5nTGVhZGluZywgJycpIDogc291cmNlKVxuICAgICAgICAucmVwbGFjZShyZUVtcHR5U3RyaW5nTWlkZGxlLCAnJDEnKVxuICAgICAgICAucmVwbGFjZShyZUVtcHR5U3RyaW5nVHJhaWxpbmcsICckMTsnKTtcblxuICAgICAgLy8gZnJhbWUgY29kZSBhcyB0aGUgZnVuY3Rpb24gYm9keVxuICAgICAgc291cmNlID0gJ2Z1bmN0aW9uKCcgKyB2YXJpYWJsZSArICcpIHtcXG4nICtcbiAgICAgICAgKGhhc1ZhcmlhYmxlID8gJycgOiB2YXJpYWJsZSArICcgfHwgKCcgKyB2YXJpYWJsZSArICcgPSB7fSk7XFxuJykgK1xuICAgICAgICBcInZhciBfX3QsIF9fcCA9ICcnLCBfX2UgPSBfLmVzY2FwZVwiICtcbiAgICAgICAgKGlzRXZhbHVhdGluZ1xuICAgICAgICAgID8gJywgX19qID0gQXJyYXkucHJvdG90eXBlLmpvaW47XFxuJyArXG4gICAgICAgICAgICBcImZ1bmN0aW9uIHByaW50KCkgeyBfX3AgKz0gX19qLmNhbGwoYXJndW1lbnRzLCAnJykgfVxcblwiXG4gICAgICAgICAgOiAnO1xcbidcbiAgICAgICAgKSArXG4gICAgICAgIHNvdXJjZSArXG4gICAgICAgICdyZXR1cm4gX19wXFxufSc7XG5cbiAgICAgIC8vIFVzZSBhIHNvdXJjZVVSTCBmb3IgZWFzaWVyIGRlYnVnZ2luZy5cbiAgICAgIC8vIGh0dHA6Ly93d3cuaHRtbDVyb2Nrcy5jb20vZW4vdHV0b3JpYWxzL2RldmVsb3BlcnRvb2xzL3NvdXJjZW1hcHMvI3RvYy1zb3VyY2V1cmxcbiAgICAgIHZhciBzb3VyY2VVUkwgPSAnXFxuLypcXG4vLyMgc291cmNlVVJMPScgKyAob3B0aW9ucy5zb3VyY2VVUkwgfHwgJy9sb2Rhc2gvdGVtcGxhdGUvc291cmNlWycgKyAodGVtcGxhdGVDb3VudGVyKyspICsgJ10nKSArICdcXG4qLyc7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIHZhciByZXN1bHQgPSBGdW5jdGlvbihpbXBvcnRzS2V5cywgJ3JldHVybiAnICsgc291cmNlICsgc291cmNlVVJMKS5hcHBseSh1bmRlZmluZWQsIGltcG9ydHNWYWx1ZXMpO1xuICAgICAgfSBjYXRjaChlKSB7XG4gICAgICAgIGUuc291cmNlID0gc291cmNlO1xuICAgICAgICB0aHJvdyBlO1xuICAgICAgfVxuICAgICAgaWYgKGRhdGEpIHtcbiAgICAgICAgcmV0dXJuIHJlc3VsdChkYXRhKTtcbiAgICAgIH1cbiAgICAgIC8vIHByb3ZpZGUgdGhlIGNvbXBpbGVkIGZ1bmN0aW9uJ3Mgc291cmNlIGJ5IGl0cyBgdG9TdHJpbmdgIG1ldGhvZCwgaW5cbiAgICAgIC8vIHN1cHBvcnRlZCBlbnZpcm9ubWVudHMsIG9yIHRoZSBgc291cmNlYCBwcm9wZXJ0eSBhcyBhIGNvbnZlbmllbmNlIGZvclxuICAgICAgLy8gaW5saW5pbmcgY29tcGlsZWQgdGVtcGxhdGVzIGR1cmluZyB0aGUgYnVpbGQgcHJvY2Vzc1xuICAgICAgcmVzdWx0LnNvdXJjZSA9IHNvdXJjZTtcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRXhlY3V0ZXMgdGhlIGNhbGxiYWNrIGBuYCB0aW1lcywgcmV0dXJuaW5nIGFuIGFycmF5IG9mIHRoZSByZXN1bHRzXG4gICAgICogb2YgZWFjaCBjYWxsYmFjayBleGVjdXRpb24uIFRoZSBjYWxsYmFjayBpcyBib3VuZCB0byBgdGhpc0FyZ2AgYW5kIGludm9rZWRcbiAgICAgKiB3aXRoIG9uZSBhcmd1bWVudDsgKGluZGV4KS5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBVdGlsaXRpZXNcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gbiBUaGUgbnVtYmVyIG9mIHRpbWVzIHRvIGV4ZWN1dGUgdGhlIGNhbGxiYWNrLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrIFRoZSBmdW5jdGlvbiBjYWxsZWQgcGVyIGl0ZXJhdGlvbi5cbiAgICAgKiBAcGFyYW0geyp9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7QXJyYXl9IFJldHVybnMgYW4gYXJyYXkgb2YgdGhlIHJlc3VsdHMgb2YgZWFjaCBgY2FsbGJhY2tgIGV4ZWN1dGlvbi5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIGRpY2VSb2xscyA9IF8udGltZXMoMywgXy5wYXJ0aWFsKF8ucmFuZG9tLCAxLCA2KSk7XG4gICAgICogLy8gPT4gWzMsIDYsIDRdXG4gICAgICpcbiAgICAgKiBfLnRpbWVzKDMsIGZ1bmN0aW9uKG4pIHsgbWFnZS5jYXN0U3BlbGwobik7IH0pO1xuICAgICAqIC8vID0+IGNhbGxzIGBtYWdlLmNhc3RTcGVsbChuKWAgdGhyZWUgdGltZXMsIHBhc3NpbmcgYG5gIG9mIGAwYCwgYDFgLCBhbmQgYDJgIHJlc3BlY3RpdmVseVxuICAgICAqXG4gICAgICogXy50aW1lcygzLCBmdW5jdGlvbihuKSB7IHRoaXMuY2FzdChuKTsgfSwgbWFnZSk7XG4gICAgICogLy8gPT4gYWxzbyBjYWxscyBgbWFnZS5jYXN0U3BlbGwobilgIHRocmVlIHRpbWVzXG4gICAgICovXG4gICAgZnVuY3Rpb24gdGltZXMobiwgY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICAgIG4gPSAobiA9ICtuKSA+IC0xID8gbiA6IDA7XG4gICAgICB2YXIgaW5kZXggPSAtMSxcbiAgICAgICAgICByZXN1bHQgPSBBcnJheShuKTtcblxuICAgICAgY2FsbGJhY2sgPSBiYXNlQ3JlYXRlQ2FsbGJhY2soY2FsbGJhY2ssIHRoaXNBcmcsIDEpO1xuICAgICAgd2hpbGUgKCsraW5kZXggPCBuKSB7XG4gICAgICAgIHJlc3VsdFtpbmRleF0gPSBjYWxsYmFjayhpbmRleCk7XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoZSBpbnZlcnNlIG9mIGBfLmVzY2FwZWAgdGhpcyBtZXRob2QgY29udmVydHMgdGhlIEhUTUwgZW50aXRpZXNcbiAgICAgKiBgJmFtcDtgLCBgJmx0O2AsIGAmZ3Q7YCwgYCZxdW90O2AsIGFuZCBgJiMzOTtgIGluIGBzdHJpbmdgIHRvIHRoZWlyXG4gICAgICogY29ycmVzcG9uZGluZyBjaGFyYWN0ZXJzLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IFV0aWxpdGllc1xuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBzdHJpbmcgVGhlIHN0cmluZyB0byB1bmVzY2FwZS5cbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nfSBSZXR1cm5zIHRoZSB1bmVzY2FwZWQgc3RyaW5nLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLnVuZXNjYXBlKCdGcmVkLCBCYXJuZXkgJmFtcDsgUGViYmxlcycpO1xuICAgICAqIC8vID0+ICdGcmVkLCBCYXJuZXkgJiBQZWJibGVzJ1xuICAgICAqL1xuICAgIGZ1bmN0aW9uIHVuZXNjYXBlKHN0cmluZykge1xuICAgICAgcmV0dXJuIHN0cmluZyA9PSBudWxsID8gJycgOiBTdHJpbmcoc3RyaW5nKS5yZXBsYWNlKHJlRXNjYXBlZEh0bWwsIHVuZXNjYXBlSHRtbENoYXIpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdlbmVyYXRlcyBhIHVuaXF1ZSBJRC4gSWYgYHByZWZpeGAgaXMgcHJvdmlkZWQgdGhlIElEIHdpbGwgYmUgYXBwZW5kZWQgdG8gaXQuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgVXRpbGl0aWVzXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IFtwcmVmaXhdIFRoZSB2YWx1ZSB0byBwcmVmaXggdGhlIElEIHdpdGguXG4gICAgICogQHJldHVybnMge3N0cmluZ30gUmV0dXJucyB0aGUgdW5pcXVlIElELlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLnVuaXF1ZUlkKCdjb250YWN0XycpO1xuICAgICAqIC8vID0+ICdjb250YWN0XzEwNCdcbiAgICAgKlxuICAgICAqIF8udW5pcXVlSWQoKTtcbiAgICAgKiAvLyA9PiAnMTA1J1xuICAgICAqL1xuICAgIGZ1bmN0aW9uIHVuaXF1ZUlkKHByZWZpeCkge1xuICAgICAgdmFyIGlkID0gKytpZENvdW50ZXI7XG4gICAgICByZXR1cm4gU3RyaW5nKHByZWZpeCA9PSBudWxsID8gJycgOiBwcmVmaXgpICsgaWQ7XG4gICAgfVxuXG4gICAgLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgYGxvZGFzaGAgb2JqZWN0IHRoYXQgd3JhcHMgdGhlIGdpdmVuIHZhbHVlIHdpdGggZXhwbGljaXRcbiAgICAgKiBtZXRob2QgY2hhaW5pbmcgZW5hYmxlZC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBDaGFpbmluZ1xuICAgICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIHdyYXAuXG4gICAgICogQHJldHVybnMge09iamVjdH0gUmV0dXJucyB0aGUgd3JhcHBlciBvYmplY3QuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIHZhciBjaGFyYWN0ZXJzID0gW1xuICAgICAqICAgeyAnbmFtZSc6ICdiYXJuZXknLCAgJ2FnZSc6IDM2IH0sXG4gICAgICogICB7ICduYW1lJzogJ2ZyZWQnLCAgICAnYWdlJzogNDAgfSxcbiAgICAgKiAgIHsgJ25hbWUnOiAncGViYmxlcycsICdhZ2UnOiAxIH1cbiAgICAgKiBdO1xuICAgICAqXG4gICAgICogdmFyIHlvdW5nZXN0ID0gXy5jaGFpbihjaGFyYWN0ZXJzKVxuICAgICAqICAgICAuc29ydEJ5KCdhZ2UnKVxuICAgICAqICAgICAubWFwKGZ1bmN0aW9uKGNocikgeyByZXR1cm4gY2hyLm5hbWUgKyAnIGlzICcgKyBjaHIuYWdlOyB9KVxuICAgICAqICAgICAuZmlyc3QoKVxuICAgICAqICAgICAudmFsdWUoKTtcbiAgICAgKiAvLyA9PiAncGViYmxlcyBpcyAxJ1xuICAgICAqL1xuICAgIGZ1bmN0aW9uIGNoYWluKHZhbHVlKSB7XG4gICAgICB2YWx1ZSA9IG5ldyBsb2Rhc2hXcmFwcGVyKHZhbHVlKTtcbiAgICAgIHZhbHVlLl9fY2hhaW5fXyA9IHRydWU7XG4gICAgICByZXR1cm4gdmFsdWU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSW52b2tlcyBgaW50ZXJjZXB0b3JgIHdpdGggdGhlIGB2YWx1ZWAgYXMgdGhlIGZpcnN0IGFyZ3VtZW50IGFuZCB0aGVuXG4gICAgICogcmV0dXJucyBgdmFsdWVgLiBUaGUgcHVycG9zZSBvZiB0aGlzIG1ldGhvZCBpcyB0byBcInRhcCBpbnRvXCIgYSBtZXRob2RcbiAgICAgKiBjaGFpbiBpbiBvcmRlciB0byBwZXJmb3JtIG9wZXJhdGlvbnMgb24gaW50ZXJtZWRpYXRlIHJlc3VsdHMgd2l0aGluXG4gICAgICogdGhlIGNoYWluLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IENoYWluaW5nXG4gICAgICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gcHJvdmlkZSB0byBgaW50ZXJjZXB0b3JgLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IGludGVyY2VwdG9yIFRoZSBmdW5jdGlvbiB0byBpbnZva2UuXG4gICAgICogQHJldHVybnMgeyp9IFJldHVybnMgYHZhbHVlYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXyhbMSwgMiwgMywgNF0pXG4gICAgICogIC50YXAoZnVuY3Rpb24oYXJyYXkpIHsgYXJyYXkucG9wKCk7IH0pXG4gICAgICogIC5yZXZlcnNlKClcbiAgICAgKiAgLnZhbHVlKCk7XG4gICAgICogLy8gPT4gWzMsIDIsIDFdXG4gICAgICovXG4gICAgZnVuY3Rpb24gdGFwKHZhbHVlLCBpbnRlcmNlcHRvcikge1xuICAgICAgaW50ZXJjZXB0b3IodmFsdWUpO1xuICAgICAgcmV0dXJuIHZhbHVlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEVuYWJsZXMgZXhwbGljaXQgbWV0aG9kIGNoYWluaW5nIG9uIHRoZSB3cmFwcGVyIG9iamVjdC5cbiAgICAgKlxuICAgICAqIEBuYW1lIGNoYWluXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgQ2hhaW5pbmdcbiAgICAgKiBAcmV0dXJucyB7Kn0gUmV0dXJucyB0aGUgd3JhcHBlciBvYmplY3QuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIHZhciBjaGFyYWN0ZXJzID0gW1xuICAgICAqICAgeyAnbmFtZSc6ICdiYXJuZXknLCAnYWdlJzogMzYgfSxcbiAgICAgKiAgIHsgJ25hbWUnOiAnZnJlZCcsICAgJ2FnZSc6IDQwIH1cbiAgICAgKiBdO1xuICAgICAqXG4gICAgICogLy8gd2l0aG91dCBleHBsaWNpdCBjaGFpbmluZ1xuICAgICAqIF8oY2hhcmFjdGVycykuZmlyc3QoKTtcbiAgICAgKiAvLyA9PiB7ICduYW1lJzogJ2Jhcm5leScsICdhZ2UnOiAzNiB9XG4gICAgICpcbiAgICAgKiAvLyB3aXRoIGV4cGxpY2l0IGNoYWluaW5nXG4gICAgICogXyhjaGFyYWN0ZXJzKS5jaGFpbigpXG4gICAgICogICAuZmlyc3QoKVxuICAgICAqICAgLnBpY2soJ2FnZScpXG4gICAgICogICAudmFsdWUoKTtcbiAgICAgKiAvLyA9PiB7ICdhZ2UnOiAzNiB9XG4gICAgICovXG4gICAgZnVuY3Rpb24gd3JhcHBlckNoYWluKCkge1xuICAgICAgdGhpcy5fX2NoYWluX18gPSB0cnVlO1xuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUHJvZHVjZXMgdGhlIGB0b1N0cmluZ2AgcmVzdWx0IG9mIHRoZSB3cmFwcGVkIHZhbHVlLlxuICAgICAqXG4gICAgICogQG5hbWUgdG9TdHJpbmdcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBDaGFpbmluZ1xuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IFJldHVybnMgdGhlIHN0cmluZyByZXN1bHQuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8oWzEsIDIsIDNdKS50b1N0cmluZygpO1xuICAgICAqIC8vID0+ICcxLDIsMydcbiAgICAgKi9cbiAgICBmdW5jdGlvbiB3cmFwcGVyVG9TdHJpbmcoKSB7XG4gICAgICByZXR1cm4gU3RyaW5nKHRoaXMuX193cmFwcGVkX18pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEV4dHJhY3RzIHRoZSB3cmFwcGVkIHZhbHVlLlxuICAgICAqXG4gICAgICogQG5hbWUgdmFsdWVPZlxuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGFsaWFzIHZhbHVlXG4gICAgICogQGNhdGVnb3J5IENoYWluaW5nXG4gICAgICogQHJldHVybnMgeyp9IFJldHVybnMgdGhlIHdyYXBwZWQgdmFsdWUuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8oWzEsIDIsIDNdKS52YWx1ZU9mKCk7XG4gICAgICogLy8gPT4gWzEsIDIsIDNdXG4gICAgICovXG4gICAgZnVuY3Rpb24gd3JhcHBlclZhbHVlT2YoKSB7XG4gICAgICByZXR1cm4gdGhpcy5fX3dyYXBwZWRfXztcbiAgICB9XG5cbiAgICAvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cblxuICAgIC8vIGFkZCBmdW5jdGlvbnMgdGhhdCByZXR1cm4gd3JhcHBlZCB2YWx1ZXMgd2hlbiBjaGFpbmluZ1xuICAgIGxvZGFzaC5hZnRlciA9IGFmdGVyO1xuICAgIGxvZGFzaC5hc3NpZ24gPSBhc3NpZ247XG4gICAgbG9kYXNoLmF0ID0gYXQ7XG4gICAgbG9kYXNoLmJpbmQgPSBiaW5kO1xuICAgIGxvZGFzaC5iaW5kQWxsID0gYmluZEFsbDtcbiAgICBsb2Rhc2guYmluZEtleSA9IGJpbmRLZXk7XG4gICAgbG9kYXNoLmNoYWluID0gY2hhaW47XG4gICAgbG9kYXNoLmNvbXBhY3QgPSBjb21wYWN0O1xuICAgIGxvZGFzaC5jb21wb3NlID0gY29tcG9zZTtcbiAgICBsb2Rhc2guY29uc3RhbnQgPSBjb25zdGFudDtcbiAgICBsb2Rhc2guY291bnRCeSA9IGNvdW50Qnk7XG4gICAgbG9kYXNoLmNyZWF0ZSA9IGNyZWF0ZTtcbiAgICBsb2Rhc2guY3JlYXRlQ2FsbGJhY2sgPSBjcmVhdGVDYWxsYmFjaztcbiAgICBsb2Rhc2guY3VycnkgPSBjdXJyeTtcbiAgICBsb2Rhc2guZGVib3VuY2UgPSBkZWJvdW5jZTtcbiAgICBsb2Rhc2guZGVmYXVsdHMgPSBkZWZhdWx0cztcbiAgICBsb2Rhc2guZGVmZXIgPSBkZWZlcjtcbiAgICBsb2Rhc2guZGVsYXkgPSBkZWxheTtcbiAgICBsb2Rhc2guZGlmZmVyZW5jZSA9IGRpZmZlcmVuY2U7XG4gICAgbG9kYXNoLmZpbHRlciA9IGZpbHRlcjtcbiAgICBsb2Rhc2guZmxhdHRlbiA9IGZsYXR0ZW47XG4gICAgbG9kYXNoLmZvckVhY2ggPSBmb3JFYWNoO1xuICAgIGxvZGFzaC5mb3JFYWNoUmlnaHQgPSBmb3JFYWNoUmlnaHQ7XG4gICAgbG9kYXNoLmZvckluID0gZm9ySW47XG4gICAgbG9kYXNoLmZvckluUmlnaHQgPSBmb3JJblJpZ2h0O1xuICAgIGxvZGFzaC5mb3JPd24gPSBmb3JPd247XG4gICAgbG9kYXNoLmZvck93blJpZ2h0ID0gZm9yT3duUmlnaHQ7XG4gICAgbG9kYXNoLmZ1bmN0aW9ucyA9IGZ1bmN0aW9ucztcbiAgICBsb2Rhc2guZ3JvdXBCeSA9IGdyb3VwQnk7XG4gICAgbG9kYXNoLmluZGV4QnkgPSBpbmRleEJ5O1xuICAgIGxvZGFzaC5pbml0aWFsID0gaW5pdGlhbDtcbiAgICBsb2Rhc2guaW50ZXJzZWN0aW9uID0gaW50ZXJzZWN0aW9uO1xuICAgIGxvZGFzaC5pbnZlcnQgPSBpbnZlcnQ7XG4gICAgbG9kYXNoLmludm9rZSA9IGludm9rZTtcbiAgICBsb2Rhc2gua2V5cyA9IGtleXM7XG4gICAgbG9kYXNoLm1hcCA9IG1hcDtcbiAgICBsb2Rhc2gubWFwVmFsdWVzID0gbWFwVmFsdWVzO1xuICAgIGxvZGFzaC5tYXggPSBtYXg7XG4gICAgbG9kYXNoLm1lbW9pemUgPSBtZW1vaXplO1xuICAgIGxvZGFzaC5tZXJnZSA9IG1lcmdlO1xuICAgIGxvZGFzaC5taW4gPSBtaW47XG4gICAgbG9kYXNoLm9taXQgPSBvbWl0O1xuICAgIGxvZGFzaC5vbmNlID0gb25jZTtcbiAgICBsb2Rhc2gucGFpcnMgPSBwYWlycztcbiAgICBsb2Rhc2gucGFydGlhbCA9IHBhcnRpYWw7XG4gICAgbG9kYXNoLnBhcnRpYWxSaWdodCA9IHBhcnRpYWxSaWdodDtcbiAgICBsb2Rhc2gucGljayA9IHBpY2s7XG4gICAgbG9kYXNoLnBsdWNrID0gcGx1Y2s7XG4gICAgbG9kYXNoLnByb3BlcnR5ID0gcHJvcGVydHk7XG4gICAgbG9kYXNoLnB1bGwgPSBwdWxsO1xuICAgIGxvZGFzaC5yYW5nZSA9IHJhbmdlO1xuICAgIGxvZGFzaC5yZWplY3QgPSByZWplY3Q7XG4gICAgbG9kYXNoLnJlbW92ZSA9IHJlbW92ZTtcbiAgICBsb2Rhc2gucmVzdCA9IHJlc3Q7XG4gICAgbG9kYXNoLnNodWZmbGUgPSBzaHVmZmxlO1xuICAgIGxvZGFzaC5zb3J0QnkgPSBzb3J0Qnk7XG4gICAgbG9kYXNoLnRhcCA9IHRhcDtcbiAgICBsb2Rhc2gudGhyb3R0bGUgPSB0aHJvdHRsZTtcbiAgICBsb2Rhc2gudGltZXMgPSB0aW1lcztcbiAgICBsb2Rhc2gudG9BcnJheSA9IHRvQXJyYXk7XG4gICAgbG9kYXNoLnRyYW5zZm9ybSA9IHRyYW5zZm9ybTtcbiAgICBsb2Rhc2gudW5pb24gPSB1bmlvbjtcbiAgICBsb2Rhc2gudW5pcSA9IHVuaXE7XG4gICAgbG9kYXNoLnZhbHVlcyA9IHZhbHVlcztcbiAgICBsb2Rhc2gud2hlcmUgPSB3aGVyZTtcbiAgICBsb2Rhc2gud2l0aG91dCA9IHdpdGhvdXQ7XG4gICAgbG9kYXNoLndyYXAgPSB3cmFwO1xuICAgIGxvZGFzaC54b3IgPSB4b3I7XG4gICAgbG9kYXNoLnppcCA9IHppcDtcbiAgICBsb2Rhc2guemlwT2JqZWN0ID0gemlwT2JqZWN0O1xuXG4gICAgLy8gYWRkIGFsaWFzZXNcbiAgICBsb2Rhc2guY29sbGVjdCA9IG1hcDtcbiAgICBsb2Rhc2guZHJvcCA9IHJlc3Q7XG4gICAgbG9kYXNoLmVhY2ggPSBmb3JFYWNoO1xuICAgIGxvZGFzaC5lYWNoUmlnaHQgPSBmb3JFYWNoUmlnaHQ7XG4gICAgbG9kYXNoLmV4dGVuZCA9IGFzc2lnbjtcbiAgICBsb2Rhc2gubWV0aG9kcyA9IGZ1bmN0aW9ucztcbiAgICBsb2Rhc2gub2JqZWN0ID0gemlwT2JqZWN0O1xuICAgIGxvZGFzaC5zZWxlY3QgPSBmaWx0ZXI7XG4gICAgbG9kYXNoLnRhaWwgPSByZXN0O1xuICAgIGxvZGFzaC51bmlxdWUgPSB1bmlxO1xuICAgIGxvZGFzaC51bnppcCA9IHppcDtcblxuICAgIC8vIGFkZCBmdW5jdGlvbnMgdG8gYGxvZGFzaC5wcm90b3R5cGVgXG4gICAgbWl4aW4obG9kYXNoKTtcblxuICAgIC8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuXG4gICAgLy8gYWRkIGZ1bmN0aW9ucyB0aGF0IHJldHVybiB1bndyYXBwZWQgdmFsdWVzIHdoZW4gY2hhaW5pbmdcbiAgICBsb2Rhc2guY2xvbmUgPSBjbG9uZTtcbiAgICBsb2Rhc2guY2xvbmVEZWVwID0gY2xvbmVEZWVwO1xuICAgIGxvZGFzaC5jb250YWlucyA9IGNvbnRhaW5zO1xuICAgIGxvZGFzaC5lc2NhcGUgPSBlc2NhcGU7XG4gICAgbG9kYXNoLmV2ZXJ5ID0gZXZlcnk7XG4gICAgbG9kYXNoLmZpbmQgPSBmaW5kO1xuICAgIGxvZGFzaC5maW5kSW5kZXggPSBmaW5kSW5kZXg7XG4gICAgbG9kYXNoLmZpbmRLZXkgPSBmaW5kS2V5O1xuICAgIGxvZGFzaC5maW5kTGFzdCA9IGZpbmRMYXN0O1xuICAgIGxvZGFzaC5maW5kTGFzdEluZGV4ID0gZmluZExhc3RJbmRleDtcbiAgICBsb2Rhc2guZmluZExhc3RLZXkgPSBmaW5kTGFzdEtleTtcbiAgICBsb2Rhc2guaGFzID0gaGFzO1xuICAgIGxvZGFzaC5pZGVudGl0eSA9IGlkZW50aXR5O1xuICAgIGxvZGFzaC5pbmRleE9mID0gaW5kZXhPZjtcbiAgICBsb2Rhc2guaXNBcmd1bWVudHMgPSBpc0FyZ3VtZW50cztcbiAgICBsb2Rhc2guaXNBcnJheSA9IGlzQXJyYXk7XG4gICAgbG9kYXNoLmlzQm9vbGVhbiA9IGlzQm9vbGVhbjtcbiAgICBsb2Rhc2guaXNEYXRlID0gaXNEYXRlO1xuICAgIGxvZGFzaC5pc0VsZW1lbnQgPSBpc0VsZW1lbnQ7XG4gICAgbG9kYXNoLmlzRW1wdHkgPSBpc0VtcHR5O1xuICAgIGxvZGFzaC5pc0VxdWFsID0gaXNFcXVhbDtcbiAgICBsb2Rhc2guaXNGaW5pdGUgPSBpc0Zpbml0ZTtcbiAgICBsb2Rhc2guaXNGdW5jdGlvbiA9IGlzRnVuY3Rpb247XG4gICAgbG9kYXNoLmlzTmFOID0gaXNOYU47XG4gICAgbG9kYXNoLmlzTnVsbCA9IGlzTnVsbDtcbiAgICBsb2Rhc2guaXNOdW1iZXIgPSBpc051bWJlcjtcbiAgICBsb2Rhc2guaXNPYmplY3QgPSBpc09iamVjdDtcbiAgICBsb2Rhc2guaXNQbGFpbk9iamVjdCA9IGlzUGxhaW5PYmplY3Q7XG4gICAgbG9kYXNoLmlzUmVnRXhwID0gaXNSZWdFeHA7XG4gICAgbG9kYXNoLmlzU3RyaW5nID0gaXNTdHJpbmc7XG4gICAgbG9kYXNoLmlzVW5kZWZpbmVkID0gaXNVbmRlZmluZWQ7XG4gICAgbG9kYXNoLmxhc3RJbmRleE9mID0gbGFzdEluZGV4T2Y7XG4gICAgbG9kYXNoLm1peGluID0gbWl4aW47XG4gICAgbG9kYXNoLm5vQ29uZmxpY3QgPSBub0NvbmZsaWN0O1xuICAgIGxvZGFzaC5ub29wID0gbm9vcDtcbiAgICBsb2Rhc2gubm93ID0gbm93O1xuICAgIGxvZGFzaC5wYXJzZUludCA9IHBhcnNlSW50O1xuICAgIGxvZGFzaC5yYW5kb20gPSByYW5kb207XG4gICAgbG9kYXNoLnJlZHVjZSA9IHJlZHVjZTtcbiAgICBsb2Rhc2gucmVkdWNlUmlnaHQgPSByZWR1Y2VSaWdodDtcbiAgICBsb2Rhc2gucmVzdWx0ID0gcmVzdWx0O1xuICAgIGxvZGFzaC5ydW5JbkNvbnRleHQgPSBydW5JbkNvbnRleHQ7XG4gICAgbG9kYXNoLnNpemUgPSBzaXplO1xuICAgIGxvZGFzaC5zb21lID0gc29tZTtcbiAgICBsb2Rhc2guc29ydGVkSW5kZXggPSBzb3J0ZWRJbmRleDtcbiAgICBsb2Rhc2gudGVtcGxhdGUgPSB0ZW1wbGF0ZTtcbiAgICBsb2Rhc2gudW5lc2NhcGUgPSB1bmVzY2FwZTtcbiAgICBsb2Rhc2gudW5pcXVlSWQgPSB1bmlxdWVJZDtcblxuICAgIC8vIGFkZCBhbGlhc2VzXG4gICAgbG9kYXNoLmFsbCA9IGV2ZXJ5O1xuICAgIGxvZGFzaC5hbnkgPSBzb21lO1xuICAgIGxvZGFzaC5kZXRlY3QgPSBmaW5kO1xuICAgIGxvZGFzaC5maW5kV2hlcmUgPSBmaW5kO1xuICAgIGxvZGFzaC5mb2xkbCA9IHJlZHVjZTtcbiAgICBsb2Rhc2guZm9sZHIgPSByZWR1Y2VSaWdodDtcbiAgICBsb2Rhc2guaW5jbHVkZSA9IGNvbnRhaW5zO1xuICAgIGxvZGFzaC5pbmplY3QgPSByZWR1Y2U7XG5cbiAgICBtaXhpbihmdW5jdGlvbigpIHtcbiAgICAgIHZhciBzb3VyY2UgPSB7fVxuICAgICAgZm9yT3duKGxvZGFzaCwgZnVuY3Rpb24oZnVuYywgbWV0aG9kTmFtZSkge1xuICAgICAgICBpZiAoIWxvZGFzaC5wcm90b3R5cGVbbWV0aG9kTmFtZV0pIHtcbiAgICAgICAgICBzb3VyY2VbbWV0aG9kTmFtZV0gPSBmdW5jO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIHJldHVybiBzb3VyY2U7XG4gICAgfSgpLCBmYWxzZSk7XG5cbiAgICAvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cblxuICAgIC8vIGFkZCBmdW5jdGlvbnMgY2FwYWJsZSBvZiByZXR1cm5pbmcgd3JhcHBlZCBhbmQgdW53cmFwcGVkIHZhbHVlcyB3aGVuIGNoYWluaW5nXG4gICAgbG9kYXNoLmZpcnN0ID0gZmlyc3Q7XG4gICAgbG9kYXNoLmxhc3QgPSBsYXN0O1xuICAgIGxvZGFzaC5zYW1wbGUgPSBzYW1wbGU7XG5cbiAgICAvLyBhZGQgYWxpYXNlc1xuICAgIGxvZGFzaC50YWtlID0gZmlyc3Q7XG4gICAgbG9kYXNoLmhlYWQgPSBmaXJzdDtcblxuICAgIGZvck93bihsb2Rhc2gsIGZ1bmN0aW9uKGZ1bmMsIG1ldGhvZE5hbWUpIHtcbiAgICAgIHZhciBjYWxsYmFja2FibGUgPSBtZXRob2ROYW1lICE9PSAnc2FtcGxlJztcbiAgICAgIGlmICghbG9kYXNoLnByb3RvdHlwZVttZXRob2ROYW1lXSkge1xuICAgICAgICBsb2Rhc2gucHJvdG90eXBlW21ldGhvZE5hbWVdPSBmdW5jdGlvbihuLCBndWFyZCkge1xuICAgICAgICAgIHZhciBjaGFpbkFsbCA9IHRoaXMuX19jaGFpbl9fLFxuICAgICAgICAgICAgICByZXN1bHQgPSBmdW5jKHRoaXMuX193cmFwcGVkX18sIG4sIGd1YXJkKTtcblxuICAgICAgICAgIHJldHVybiAhY2hhaW5BbGwgJiYgKG4gPT0gbnVsbCB8fCAoZ3VhcmQgJiYgIShjYWxsYmFja2FibGUgJiYgdHlwZW9mIG4gPT0gJ2Z1bmN0aW9uJykpKVxuICAgICAgICAgICAgPyByZXN1bHRcbiAgICAgICAgICAgIDogbmV3IGxvZGFzaFdyYXBwZXIocmVzdWx0LCBjaGFpbkFsbCk7XG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICAvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cblxuICAgIC8qKlxuICAgICAqIFRoZSBzZW1hbnRpYyB2ZXJzaW9uIG51bWJlci5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEB0eXBlIHN0cmluZ1xuICAgICAqL1xuICAgIGxvZGFzaC5WRVJTSU9OID0gJzIuNC4xJztcblxuICAgIC8vIGFkZCBcIkNoYWluaW5nXCIgZnVuY3Rpb25zIHRvIHRoZSB3cmFwcGVyXG4gICAgbG9kYXNoLnByb3RvdHlwZS5jaGFpbiA9IHdyYXBwZXJDaGFpbjtcbiAgICBsb2Rhc2gucHJvdG90eXBlLnRvU3RyaW5nID0gd3JhcHBlclRvU3RyaW5nO1xuICAgIGxvZGFzaC5wcm90b3R5cGUudmFsdWUgPSB3cmFwcGVyVmFsdWVPZjtcbiAgICBsb2Rhc2gucHJvdG90eXBlLnZhbHVlT2YgPSB3cmFwcGVyVmFsdWVPZjtcblxuICAgIC8vIGFkZCBgQXJyYXlgIGZ1bmN0aW9ucyB0aGF0IHJldHVybiB1bndyYXBwZWQgdmFsdWVzXG4gICAgZm9yRWFjaChbJ2pvaW4nLCAncG9wJywgJ3NoaWZ0J10sIGZ1bmN0aW9uKG1ldGhvZE5hbWUpIHtcbiAgICAgIHZhciBmdW5jID0gYXJyYXlSZWZbbWV0aG9kTmFtZV07XG4gICAgICBsb2Rhc2gucHJvdG90eXBlW21ldGhvZE5hbWVdID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBjaGFpbkFsbCA9IHRoaXMuX19jaGFpbl9fLFxuICAgICAgICAgICAgcmVzdWx0ID0gZnVuYy5hcHBseSh0aGlzLl9fd3JhcHBlZF9fLCBhcmd1bWVudHMpO1xuXG4gICAgICAgIHJldHVybiBjaGFpbkFsbFxuICAgICAgICAgID8gbmV3IGxvZGFzaFdyYXBwZXIocmVzdWx0LCBjaGFpbkFsbClcbiAgICAgICAgICA6IHJlc3VsdDtcbiAgICAgIH07XG4gICAgfSk7XG5cbiAgICAvLyBhZGQgYEFycmF5YCBmdW5jdGlvbnMgdGhhdCByZXR1cm4gdGhlIGV4aXN0aW5nIHdyYXBwZWQgdmFsdWVcbiAgICBmb3JFYWNoKFsncHVzaCcsICdyZXZlcnNlJywgJ3NvcnQnLCAndW5zaGlmdCddLCBmdW5jdGlvbihtZXRob2ROYW1lKSB7XG4gICAgICB2YXIgZnVuYyA9IGFycmF5UmVmW21ldGhvZE5hbWVdO1xuICAgICAgbG9kYXNoLnByb3RvdHlwZVttZXRob2ROYW1lXSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICBmdW5jLmFwcGx5KHRoaXMuX193cmFwcGVkX18sIGFyZ3VtZW50cyk7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgfTtcbiAgICB9KTtcblxuICAgIC8vIGFkZCBgQXJyYXlgIGZ1bmN0aW9ucyB0aGF0IHJldHVybiBuZXcgd3JhcHBlZCB2YWx1ZXNcbiAgICBmb3JFYWNoKFsnY29uY2F0JywgJ3NsaWNlJywgJ3NwbGljZSddLCBmdW5jdGlvbihtZXRob2ROYW1lKSB7XG4gICAgICB2YXIgZnVuYyA9IGFycmF5UmVmW21ldGhvZE5hbWVdO1xuICAgICAgbG9kYXNoLnByb3RvdHlwZVttZXRob2ROYW1lXSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gbmV3IGxvZGFzaFdyYXBwZXIoZnVuYy5hcHBseSh0aGlzLl9fd3JhcHBlZF9fLCBhcmd1bWVudHMpLCB0aGlzLl9fY2hhaW5fXyk7XG4gICAgICB9O1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIGxvZGFzaDtcbiAgfVxuXG4gIC8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuXG4gIC8vIGV4cG9zZSBMby1EYXNoXG4gIHZhciBfID0gcnVuSW5Db250ZXh0KCk7XG5cbiAgLy8gc29tZSBBTUQgYnVpbGQgb3B0aW1pemVycyBsaWtlIHIuanMgY2hlY2sgZm9yIGNvbmRpdGlvbiBwYXR0ZXJucyBsaWtlIHRoZSBmb2xsb3dpbmc6XG4gIGlmICh0eXBlb2YgZGVmaW5lID09ICdmdW5jdGlvbicgJiYgdHlwZW9mIGRlZmluZS5hbWQgPT0gJ29iamVjdCcgJiYgZGVmaW5lLmFtZCkge1xuICAgIC8vIEV4cG9zZSBMby1EYXNoIHRvIHRoZSBnbG9iYWwgb2JqZWN0IGV2ZW4gd2hlbiBhbiBBTUQgbG9hZGVyIGlzIHByZXNlbnQgaW5cbiAgICAvLyBjYXNlIExvLURhc2ggaXMgbG9hZGVkIHdpdGggYSBSZXF1aXJlSlMgc2hpbSBjb25maWcuXG4gICAgLy8gU2VlIGh0dHA6Ly9yZXF1aXJlanMub3JnL2RvY3MvYXBpLmh0bWwjY29uZmlnLXNoaW1cbiAgICByb290Ll8gPSBfO1xuXG4gICAgLy8gZGVmaW5lIGFzIGFuIGFub255bW91cyBtb2R1bGUgc28sIHRocm91Z2ggcGF0aCBtYXBwaW5nLCBpdCBjYW4gYmVcbiAgICAvLyByZWZlcmVuY2VkIGFzIHRoZSBcInVuZGVyc2NvcmVcIiBtb2R1bGVcbiAgICBkZWZpbmUoZnVuY3Rpb24oKSB7XG4gICAgICByZXR1cm4gXztcbiAgICB9KTtcbiAgfVxuICAvLyBjaGVjayBmb3IgYGV4cG9ydHNgIGFmdGVyIGBkZWZpbmVgIGluIGNhc2UgYSBidWlsZCBvcHRpbWl6ZXIgYWRkcyBhbiBgZXhwb3J0c2Agb2JqZWN0XG4gIGVsc2UgaWYgKGZyZWVFeHBvcnRzICYmIGZyZWVNb2R1bGUpIHtcbiAgICAvLyBpbiBOb2RlLmpzIG9yIFJpbmdvSlNcbiAgICBpZiAobW9kdWxlRXhwb3J0cykge1xuICAgICAgKGZyZWVNb2R1bGUuZXhwb3J0cyA9IF8pLl8gPSBfO1xuICAgIH1cbiAgICAvLyBpbiBOYXJ3aGFsIG9yIFJoaW5vIC1yZXF1aXJlXG4gICAgZWxzZSB7XG4gICAgICBmcmVlRXhwb3J0cy5fID0gXztcbiAgICB9XG4gIH1cbiAgZWxzZSB7XG4gICAgLy8gaW4gYSBicm93c2VyIG9yIFJoaW5vXG4gICAgcm9vdC5fID0gXztcbiAgfVxufS5jYWxsKHRoaXMpKTtcblxufSkuY2FsbCh0aGlzLHR5cGVvZiBnbG9iYWwgIT09IFwidW5kZWZpbmVkXCIgPyBnbG9iYWwgOiB0eXBlb2Ygc2VsZiAhPT0gXCJ1bmRlZmluZWRcIiA/IHNlbGYgOiB0eXBlb2Ygd2luZG93ICE9PSBcInVuZGVmaW5lZFwiID8gd2luZG93IDoge30pIiwiZXhwb3J0cy5EZWZhdWx0Um91dGUgPSByZXF1aXJlKCcuL2NvbXBvbmVudHMvRGVmYXVsdFJvdXRlJyk7XG5leHBvcnRzLkxpbmsgPSByZXF1aXJlKCcuL2NvbXBvbmVudHMvTGluaycpO1xuZXhwb3J0cy5Ob3RGb3VuZFJvdXRlID0gcmVxdWlyZSgnLi9jb21wb25lbnRzL05vdEZvdW5kUm91dGUnKTtcbmV4cG9ydHMuUmVkaXJlY3QgPSByZXF1aXJlKCcuL2NvbXBvbmVudHMvUmVkaXJlY3QnKTtcbmV4cG9ydHMuUm91dGUgPSByZXF1aXJlKCcuL2NvbXBvbmVudHMvUm91dGUnKTtcbmV4cG9ydHMuUm91dGVIYW5kbGVyID0gcmVxdWlyZSgnLi9jb21wb25lbnRzL1JvdXRlSGFuZGxlcicpO1xuXG5leHBvcnRzLkhhc2hMb2NhdGlvbiA9IHJlcXVpcmUoJy4vbG9jYXRpb25zL0hhc2hMb2NhdGlvbicpO1xuZXhwb3J0cy5IaXN0b3J5TG9jYXRpb24gPSByZXF1aXJlKCcuL2xvY2F0aW9ucy9IaXN0b3J5TG9jYXRpb24nKTtcbmV4cG9ydHMuUmVmcmVzaExvY2F0aW9uID0gcmVxdWlyZSgnLi9sb2NhdGlvbnMvUmVmcmVzaExvY2F0aW9uJyk7XG5cbmV4cG9ydHMuSW1pdGF0ZUJyb3dzZXJCZWhhdmlvciA9IHJlcXVpcmUoJy4vYmVoYXZpb3JzL0ltaXRhdGVCcm93c2VyQmVoYXZpb3InKTtcbmV4cG9ydHMuU2Nyb2xsVG9Ub3BCZWhhdmlvciA9IHJlcXVpcmUoJy4vYmVoYXZpb3JzL1Njcm9sbFRvVG9wQmVoYXZpb3InKTtcblxuZXhwb3J0cy5OYXZpZ2F0aW9uID0gcmVxdWlyZSgnLi9taXhpbnMvTmF2aWdhdGlvbicpO1xuZXhwb3J0cy5TdGF0ZSA9IHJlcXVpcmUoJy4vbWl4aW5zL1N0YXRlJyk7XG5cbmV4cG9ydHMuY3JlYXRlID0gcmVxdWlyZSgnLi91dGlscy9jcmVhdGVSb3V0ZXInKTtcbmV4cG9ydHMucnVuID0gcmVxdWlyZSgnLi91dGlscy9ydW5Sb3V0ZXInKTtcblxuZXhwb3J0cy5IaXN0b3J5ID0gcmVxdWlyZSgnLi91dGlscy9IaXN0b3J5Jyk7XG4iLCJtb2R1bGUuZXhwb3J0cyA9IHJlcXVpcmUoJy4vbGliL1JlYWN0V2l0aEFkZG9ucycpO1xuIiwibW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKCcuL2xpYi9SZWFjdCcpO1xuIl19
diff --git a/libmproxy/web/templates/index.html b/libmproxy/web/templates/index.html
index 571845b9..5f2c6d5e 100644
--- a/libmproxy/web/templates/index.html
+++ b/libmproxy/web/templates/index.html
@@ -4,10 +4,10 @@
<meta charset="UTF-8">
<title>mitmproxy</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
- <link rel="stylesheet" href="/static/css/vendor.css"/>
- <link rel="stylesheet" href="/static/css/app.css"/>
- <script src="/static/js/vendor.js"></script>
- <script src="/static/js/app.js"></script>
+ <link rel="stylesheet" href="/static/vendor.css"/>
+ <link rel="stylesheet" href="/static/app.css"/>
+ <script src="/static/vendor.js"></script>
+ <script src="/static/app.js"></script>
</head>
<body>
</body>
diff --git a/web/gulpfile.js b/web/gulpfile.js
index 5a0b93af..60f0f1b7 100644
--- a/web/gulpfile.js
+++ b/web/gulpfile.js
@@ -1,179 +1,275 @@
var gulp = require("gulp");
-var merge = require('merge-stream');
+var path = require('path');
+var _ = require('lodash');
+var browserify = require('browserify');
var concat = require('gulp-concat');
+var connect = require('gulp-connect');
+var buffer = require('vinyl-buffer');
var jshint = require("gulp-jshint");
var less = require("gulp-less");
var livereload = require("gulp-livereload");
+var map = require("map-stream");
var minifyCSS = require('gulp-minify-css');
var notify = require("gulp-notify");
-var peg = require("gulp-peg");
var plumber = require("gulp-plumber");
-var qunit = require("gulp-qunit");
+var rev = require("gulp-rev");
var react = require("gulp-react");
+var reactify = require('reactify');
var rename = require("gulp-rename");
+var replace = require('gulp-replace');
+var source = require('vinyl-source-stream');
var sourcemaps = require('gulp-sourcemaps');
+var transform = require('vinyl-transform');
var uglify = require('gulp-uglify');
+var packagejs = require('./package.json');
-var dont_break_on_errors = function () {
- return plumber(function (error) {
- notify.onError("<%= error.message %>").apply(this, arguments);
- this.emit('end');
- });
+
+// FIXME: react-with-addons.min.js for prod use issue
+
+var manifest = {
+ "vendor.css": "vendor.css",
+ "app.css": "app.css",
+ "vendor.js": "vendor.js",
+ "app.js": "app.js",
};
-var path = {
- dist: "../libmproxy/web/",
+var CONF = {
+ dist: "../libmproxy/web",
+ static: "../libmproxy/web/static",
js: {
- vendor: [
- 'vendor/jquery/jquery.js',
- 'vendor/lodash/lodash.js',
- 'vendor/react/react-with-addons.js',
- 'vendor/react-router/react-router.js',
+ // Don't package these in the vendor distribution
+ vendor_excludes: [
+ "bootstrap"
],
- app: [
- 'js/utils.js',
- 'js/dispatcher.js',
- 'js/actions.js',
- 'js/filt/filt.js',
- 'js/flow/utils.js',
- 'js/store/store.js',
- 'js/store/view.js',
- 'js/connection.js',
- 'js/components/utils.jsx.js',
- 'js/components/virtualscroll.jsx.js',
- 'js/components/header.jsx.js',
- 'js/components/flowtable-columns.jsx.js',
- 'js/components/flowtable.jsx.js',
- 'js/components/flowdetail.jsx.js',
- 'js/components/mainview.jsx.js',
- 'js/components/eventlog.jsx.js',
- 'js/components/footer.jsx.js',
- 'js/components/proxyapp.jsx.js',
- 'js/app.js',
+ // Package these as well as the dependencies
+ vendor_includes: [
+ "react/addons"
],
+ app: 'src/js/app.js'
},
- peg: "js/filt/filt.pegjs",
css: {
- vendor: ["css/vendor.less"],
- app: ["css/app.less"],
- all: ["css/**"]
+ vendor: ["src/css/vendor.less"],
+ app: ["src/css/app.less"]
},
- vendor: ["vendor/**"],
- fonts: ["src/vendor/fontawesome/fontawesome-webfont.*"],
- html: ["*.html", "!benchmark.html", "!test.html"],
- images: ["images/**"],
- test: ["test.html"],
- opts: {base: "src", cwd: "src"}
+ copy: [
+ "src/examples/**",
+ "src/fonts/**",
+ ],
+ templates: [
+ "src/templates/*"
+ ],
+ fonts: ["src/fontawesome/fontawesome-webfont.*"],
+ port: 8082
+};
+
+var vendor_packages = _.difference(
+ _.union(
+ _.keys(packagejs.dependencies),
+ CONF.js.vendor_includes
+ ),
+ CONF.js.vendor_excludes
+ );
+
+
+// Custom linting reporter used for error notify
+var jsHintErrorReporter = function(){
+ return map(function (file, cb) {
+ if (file.jshint && !file.jshint.success) {
+ file.jshint.results.forEach(function (err) {
+ if (err) {
+ var msg = [
+ path.basename(file.path),
+ 'Line: ' + err.error.line,
+ 'Reason: ' + err.error.reason
+ ];
+ notify.onError(
+ "Error: <%= error.message %>"
+ )(new Error(msg.join("\n")));
+ }
+ });
+ }
+ cb(null, file);
+ })
+};
+
+var save_rev = function(){
+ return map(function(file, callback){
+ if (file.revOrigBase){
+ manifest[path.basename(file.revOrigPath)] = path.basename(file.path);
+ }
+ callback(null, file);
+ })
+}
+
+var dont_break_on_errors = function(){
+ return plumber(
+ function(error){
+ notify.onError("Error: <%= error.message %>").apply(this, arguments);
+ this.emit('end');
+ }
+ );
};
gulp.task("fonts", function () {
- return gulp.src(path.fonts)
- .pipe(gulp.dest(path.dist + "static/fonts"));
+ return gulp.src(CONF.fonts)
+ .pipe(gulp.dest(CONF.dist + "fonts"));
});
function styles_dev(files) {
- return (gulp.src(files, path.opts)
+ return (gulp.src(files)
.pipe(dont_break_on_errors())
.pipe(sourcemaps.init())
.pipe(less())
.pipe(sourcemaps.write(".", {sourceRoot: "/static"}))
- .pipe(gulp.dest(path.dist + "static"))
- .pipe(livereload({auto: false})));
+ .pipe(gulp.dest(CONF.static))
+ .pipe(livereload({ auto: false })));
}
-gulp.task("styles-app-dev", styles_dev.bind(undefined, path.css.app));
-gulp.task("styles-vendor-dev", styles_dev.bind(undefined, path.css.vendor));
-gulp.task("styles-dev", ["styles-app-dev", "styles-vendor-dev"]);
+gulp.task("styles-app-dev", function(){
+ styles_dev(CONF.css.app);
+});
+gulp.task("styles-vendor-dev", function(){
+ styles_dev(CONF.css.vendor);
+});
function styles_prod(files) {
- return (gulp.src(files, path.opts)
+ return (gulp.src(files)
.pipe(less())
// No sourcemaps support yet :-/
// https://github.com/jonathanepollack/gulp-minify-css/issues/34
.pipe(minifyCSS())
- .pipe(gulp.dest(path.dist + "static"))
- .pipe(livereload({auto: false})));
+ .pipe(rev())
+ .pipe(save_rev())
+ .pipe(gulp.dest(CONF.static))
+ .pipe(livereload({ auto: false })));
}
-gulp.task("styles-app-prod", styles_prod.bind(undefined, path.css.app));
-gulp.task("styles-vendor-prod", styles_prod.bind(undefined, path.css.vendor));
-gulp.task("styles-prod", ["styles-app-prod", "styles-vendor-prod"]);
+gulp.task("styles-app-prod", function(){
+ styles_prod(CONF.css.app);
+});
+gulp.task("styles-vendor-prod", function(){
+ styles_prod(CONF.css.vendor);
+});
-function scripts_dev(files, filename) {
- return gulp.src(files, path.opts)
- .pipe(dont_break_on_errors())
- .pipe(sourcemaps.init())
- .pipe(react())
- .pipe(concat(filename))
- .pipe(sourcemaps.write(".", {sourceRoot: "/static"}))
- .pipe(gulp.dest(path.dist + "static/js"))
- .pipe(livereload({auto: false}));
+function vendor_stream(debug){
+ var vendor = browserify(vendor_packages, {debug: debug});
+ _.each(vendor_packages, function(v){
+ vendor.require(v);
+ });
+ return vendor.bundle()
+ .pipe(source("dummy.js"))
+ .pipe(rename("vendor.js"));
}
-gulp.task("scripts-app-dev", scripts_dev.bind(undefined, path.js.app, "app.js"));
-gulp.task("scripts-vendor-dev", scripts_dev.bind(undefined, path.js.vendor, "vendor.js"));
-gulp.task("scripts-dev", ["scripts-app-dev", "scripts-vendor-dev"]);
+gulp.task("scripts-vendor-dev", function (){
+ return vendor_stream(true)
+ .pipe(gulp.dest(CONF.static));
+});
+gulp.task("scripts-vendor-prod", function(){
+ return vendor_stream(false)
+ .pipe(buffer())
+ .pipe(uglify())
+ .pipe(rev())
+ .pipe(save_rev())
+ .pipe(gulp.dest(CONF.static));
+});
-function scripts_prod(files, filename) {
- return gulp.src(files, path.opts)
- .pipe(react())
- .pipe(concat(filename))
+function app_stream(debug) {
+ var browserified = transform(function(filename) {
+ var b = browserify(filename, {debug: debug})
+ _.each(vendor_packages, function(v){
+ b.external(v);
+ });
+ b.transform(reactify);
+ return b.bundle();
+ });
+ return gulp.src([CONF.js.app])
+ .pipe(dont_break_on_errors())
+ .pipe(browserified)
+ .pipe(rename("app.js"));
+};
+gulp.task('scripts-app-dev', function () {
+ return app_stream(true)
+ .pipe(gulp.dest(CONF.static))
+ .pipe(livereload({ auto: false }));
+});
+gulp.task('scripts-app-prod', function () {
+ return app_stream(true)
+ .pipe(buffer())
.pipe(uglify())
- .pipe(gulp.dest(path.dist + "static/js"))
- .pipe(livereload({auto: false}));
-}
-gulp.task("scripts-app-prod", scripts_prod.bind(undefined, path.js.app, "app.js"));
-gulp.task("scripts-vendor-prod", scripts_prod.bind(undefined, path.js.vendor, "vendor.js"));
-gulp.task("scripts-prod", ["scripts-app-prod", "scripts-vendor-prod"]);
+ .pipe(rev())
+ .pipe(save_rev())
+ .pipe(gulp.dest(CONF.static));
+});
gulp.task("jshint", function () {
- return gulp.src(path.js.app.concat(["!"+path.peg.replace("pegjs","js")]), path.opts)
+ return gulp.src(["src/js/**.js"])
.pipe(dont_break_on_errors())
.pipe(react())
+ .pipe(plumber())
.pipe(jshint())
- .pipe(jshint.reporter("jshint-stylish"));
-});
-
-gulp.task("peg", function () {
- return gulp.src(path.peg, path.opts)
- .pipe(dont_break_on_errors())
- .pipe(peg({exportVar:"Filt"}))
- .pipe(gulp.dest(".", path.opts));
+ .pipe(jshint.reporter("jshint-stylish"))
+ .pipe(jsHintErrorReporter());
});
-gulp.task("images", function () {
- //(spriting code in commit 4ca720b55680e40b3a4361141a2ad39f9de81111)
- return gulp.src(path.images, path.opts)
- .pipe(gulp.dest(path.dist + "static"));
+gulp.task("copy", function(){
+ return gulp.src(CONF.copy, {base:"src/"})
+ .pipe(gulp.dest(CONF.dist));
});
-gulp.task("html", function () {
- return gulp.src(path.html, path.opts)
- .pipe(gulp.dest(path.dist + "templates"))
- .pipe(livereload({auto: false}));
-});
+function templates(){
+ return gulp.src(CONF.templates, {base:"src/"})
+ .pipe(replace(/\{\{\{(\S*)\}\}\}/g, function(match, p1) {
+ return manifest[p1];
+ }))
+ .pipe(gulp.dest(CONF.dist));
+};
+gulp.task('templates', templates);
-gulp.task('test', function () {
- return gulp.src(path.test, path.opts)
- .pipe(qunit({verbose: true}));
+gulp.task('connect', function() {
+ connect.server({
+ port: CONF.port
+ });
});
+common = ["fonts", "copy"];
+gulp.task(
+ "dev",
+ [
+ "fonts",
+ "copy",
+ "styles-vendor-dev",
+ "styles-app-dev",
+ "scripts-vendor-dev",
+ "scripts-app-dev",
+ ],
+ templates
+);
+gulp.task(
+ "prod",
+ [
+ "fonts",
+ "copy",
+ "styles-vendor-prod",
+ "styles-app-prod",
+ "scripts-vendor-prod",
+ "scripts-app-prod",
+ "connect"
+ ],
+ templates
+);
-common = ["fonts", "html", "jshint", "peg", "images"];
-gulp.task("dev", common.concat(["styles-dev", "scripts-dev"]));
-gulp.task("prod", common.concat(["styles-prod", "scripts-prod"]));
-
-gulp.task("default", ["dev"], function () {
+gulp.task("default", ["dev", "connect"], function () {
livereload.listen({auto: true});
- gulp.watch(path.vendor, path.opts, ["scripts-vendor-dev", "styles-vendor-dev"]);
- gulp.watch(path.js.app, path.opts, ["scripts-app-dev", "jshint"]);
- gulp.watch(path.peg, path.opts, ["peg"]);
- gulp.watch(path.css.all, path.opts, ["styles-app-dev"]);
- gulp.watch(path.html, path.opts, ["html"]);
+ gulp.watch(["src/css/vendor*"], ["styles-vendor-dev"]);
+ gulp.watch(["src/js/**"], ["scripts-app-dev", "jshint"]);
+ gulp.watch(["src/css/**"], ["styles-app-dev"]);
+ gulp.watch(CONF.templates, ["templates"]);
+ gulp.watch(CONF.copy, ["copy"]);
});
diff --git a/web/gulpfile.old.js b/web/gulpfile.old.js
new file mode 100644
index 00000000..5a0b93af
--- /dev/null
+++ b/web/gulpfile.old.js
@@ -0,0 +1,179 @@
+var gulp = require("gulp");
+var merge = require('merge-stream');
+
+var concat = require('gulp-concat');
+var jshint = require("gulp-jshint");
+var less = require("gulp-less");
+var livereload = require("gulp-livereload");
+var minifyCSS = require('gulp-minify-css');
+var notify = require("gulp-notify");
+var peg = require("gulp-peg");
+var plumber = require("gulp-plumber");
+var qunit = require("gulp-qunit");
+var react = require("gulp-react");
+var rename = require("gulp-rename");
+var sourcemaps = require('gulp-sourcemaps');
+var uglify = require('gulp-uglify');
+
+
+var dont_break_on_errors = function () {
+ return plumber(function (error) {
+ notify.onError("<%= error.message %>").apply(this, arguments);
+ this.emit('end');
+ });
+};
+
+var path = {
+ dist: "../libmproxy/web/",
+ js: {
+ vendor: [
+ 'vendor/jquery/jquery.js',
+ 'vendor/lodash/lodash.js',
+ 'vendor/react/react-with-addons.js',
+ 'vendor/react-router/react-router.js',
+ ],
+ app: [
+ 'js/utils.js',
+ 'js/dispatcher.js',
+ 'js/actions.js',
+ 'js/filt/filt.js',
+ 'js/flow/utils.js',
+ 'js/store/store.js',
+ 'js/store/view.js',
+ 'js/connection.js',
+ 'js/components/utils.jsx.js',
+ 'js/components/virtualscroll.jsx.js',
+ 'js/components/header.jsx.js',
+ 'js/components/flowtable-columns.jsx.js',
+ 'js/components/flowtable.jsx.js',
+ 'js/components/flowdetail.jsx.js',
+ 'js/components/mainview.jsx.js',
+ 'js/components/eventlog.jsx.js',
+ 'js/components/footer.jsx.js',
+ 'js/components/proxyapp.jsx.js',
+ 'js/app.js',
+ ],
+ },
+ peg: "js/filt/filt.pegjs",
+ css: {
+ vendor: ["css/vendor.less"],
+ app: ["css/app.less"],
+ all: ["css/**"]
+ },
+ vendor: ["vendor/**"],
+ fonts: ["src/vendor/fontawesome/fontawesome-webfont.*"],
+ html: ["*.html", "!benchmark.html", "!test.html"],
+ images: ["images/**"],
+ test: ["test.html"],
+ opts: {base: "src", cwd: "src"}
+};
+
+
+gulp.task("fonts", function () {
+ return gulp.src(path.fonts)
+ .pipe(gulp.dest(path.dist + "static/fonts"));
+});
+
+
+function styles_dev(files) {
+ return (gulp.src(files, path.opts)
+ .pipe(dont_break_on_errors())
+ .pipe(sourcemaps.init())
+ .pipe(less())
+ .pipe(sourcemaps.write(".", {sourceRoot: "/static"}))
+ .pipe(gulp.dest(path.dist + "static"))
+ .pipe(livereload({auto: false})));
+}
+gulp.task("styles-app-dev", styles_dev.bind(undefined, path.css.app));
+gulp.task("styles-vendor-dev", styles_dev.bind(undefined, path.css.vendor));
+gulp.task("styles-dev", ["styles-app-dev", "styles-vendor-dev"]);
+
+
+function styles_prod(files) {
+ return (gulp.src(files, path.opts)
+ .pipe(less())
+ // No sourcemaps support yet :-/
+ // https://github.com/jonathanepollack/gulp-minify-css/issues/34
+ .pipe(minifyCSS())
+ .pipe(gulp.dest(path.dist + "static"))
+ .pipe(livereload({auto: false})));
+}
+gulp.task("styles-app-prod", styles_prod.bind(undefined, path.css.app));
+gulp.task("styles-vendor-prod", styles_prod.bind(undefined, path.css.vendor));
+gulp.task("styles-prod", ["styles-app-prod", "styles-vendor-prod"]);
+
+
+function scripts_dev(files, filename) {
+ return gulp.src(files, path.opts)
+ .pipe(dont_break_on_errors())
+ .pipe(sourcemaps.init())
+ .pipe(react())
+ .pipe(concat(filename))
+ .pipe(sourcemaps.write(".", {sourceRoot: "/static"}))
+ .pipe(gulp.dest(path.dist + "static/js"))
+ .pipe(livereload({auto: false}));
+}
+gulp.task("scripts-app-dev", scripts_dev.bind(undefined, path.js.app, "app.js"));
+gulp.task("scripts-vendor-dev", scripts_dev.bind(undefined, path.js.vendor, "vendor.js"));
+gulp.task("scripts-dev", ["scripts-app-dev", "scripts-vendor-dev"]);
+
+
+function scripts_prod(files, filename) {
+ return gulp.src(files, path.opts)
+ .pipe(react())
+ .pipe(concat(filename))
+ .pipe(uglify())
+ .pipe(gulp.dest(path.dist + "static/js"))
+ .pipe(livereload({auto: false}));
+}
+gulp.task("scripts-app-prod", scripts_prod.bind(undefined, path.js.app, "app.js"));
+gulp.task("scripts-vendor-prod", scripts_prod.bind(undefined, path.js.vendor, "vendor.js"));
+gulp.task("scripts-prod", ["scripts-app-prod", "scripts-vendor-prod"]);
+
+
+gulp.task("jshint", function () {
+ return gulp.src(path.js.app.concat(["!"+path.peg.replace("pegjs","js")]), path.opts)
+ .pipe(dont_break_on_errors())
+ .pipe(react())
+ .pipe(jshint())
+ .pipe(jshint.reporter("jshint-stylish"));
+});
+
+gulp.task("peg", function () {
+ return gulp.src(path.peg, path.opts)
+ .pipe(dont_break_on_errors())
+ .pipe(peg({exportVar:"Filt"}))
+ .pipe(gulp.dest(".", path.opts));
+});
+
+gulp.task("images", function () {
+ //(spriting code in commit 4ca720b55680e40b3a4361141a2ad39f9de81111)
+ return gulp.src(path.images, path.opts)
+ .pipe(gulp.dest(path.dist + "static"));
+});
+
+gulp.task("html", function () {
+ return gulp.src(path.html, path.opts)
+ .pipe(gulp.dest(path.dist + "templates"))
+ .pipe(livereload({auto: false}));
+});
+
+
+gulp.task('test', function () {
+ return gulp.src(path.test, path.opts)
+ .pipe(qunit({verbose: true}));
+});
+
+
+common = ["fonts", "html", "jshint", "peg", "images"];
+gulp.task("dev", common.concat(["styles-dev", "scripts-dev"]));
+gulp.task("prod", common.concat(["styles-prod", "scripts-prod"]));
+
+gulp.task("default", ["dev"], function () {
+ livereload.listen({auto: true});
+ gulp.watch(path.vendor, path.opts, ["scripts-vendor-dev", "styles-vendor-dev"]);
+ gulp.watch(path.js.app, path.opts, ["scripts-app-dev", "jshint"]);
+ gulp.watch(path.peg, path.opts, ["peg"]);
+ gulp.watch(path.css.all, path.opts, ["styles-app-dev"]);
+ gulp.watch(path.html, path.opts, ["html"]);
+});
diff --git a/web/package.json b/web/package.json
index 8e33396a..944dbdb1 100644
--- a/web/package.json
+++ b/web/package.json
@@ -1,28 +1,43 @@
{
"name": "mitmproxy",
"private": true,
+ "dependencies": {
+ "jquery": "",
+ "lodash": "",
+ "react": "",
+ "react-router": "",
+ "bootstrap": ""
+ },
"devDependencies": {
"bower": "",
- "bower-installer": "",
- "clean-css": "",
+ "browserify": "^6.3.4",
"gulp": "",
"gulp-concat": "",
+ "gulp-connect": "",
"gulp-jshint": "",
"gulp-less": "",
"gulp-livereload": "",
"gulp-minify-css": "",
"gulp-notify": "",
- "gulp-peg": "",
"gulp-plumber": "",
- "gulp-qunit": "",
"gulp-react": "",
"gulp-rename": "",
+ "gulp-replace": "",
+ "gulp-rev": "",
"gulp-sourcemaps": "",
"gulp-uglify": "",
"gulp-util": "",
+ "jest-cli": "^0.1.18",
"jshint-stylish": "",
- "merge-stream": "",
+ "lodash": "",
+ "map-stream": "",
"react": "",
- "react-tools": ""
+ "react-tools": "",
+ "reactify": "",
+ "vinyl-buffer": "",
+ "vinyl-source-stream": "",
+ "vinyl-transform": "",
+
+ "gulp-peg": ""
}
}
diff --git a/web/src/fonts/fontawesome-webfont.eot b/web/src/fonts/fontawesome-webfont.eot
new file mode 100644
index 00000000..84677bc0
--- /dev/null
+++ b/web/src/fonts/fontawesome-webfont.eot
Binary files differ
diff --git a/web/src/fonts/fontawesome-webfont.svg b/web/src/fonts/fontawesome-webfont.svg
new file mode 100644
index 00000000..d907b25a
--- /dev/null
+++ b/web/src/fonts/fontawesome-webfont.svg
@@ -0,0 +1,520 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata></metadata>
+<defs>
+<font id="fontawesomeregular" horiz-adv-x="1536" >
+<font-face units-per-em="1792" ascent="1536" descent="-256" />
+<missing-glyph horiz-adv-x="448" />
+<glyph unicode=" " horiz-adv-x="448" />
+<glyph unicode="&#x09;" horiz-adv-x="448" />
+<glyph unicode="&#xa0;" horiz-adv-x="448" />
+<glyph unicode="&#xa8;" horiz-adv-x="1792" />
+<glyph unicode="&#xa9;" horiz-adv-x="1792" />
+<glyph unicode="&#xae;" horiz-adv-x="1792" />
+<glyph unicode="&#xb4;" horiz-adv-x="1792" />
+<glyph unicode="&#xc6;" horiz-adv-x="1792" />
+<glyph unicode="&#xd8;" horiz-adv-x="1792" />
+<glyph unicode="&#x2000;" horiz-adv-x="768" />
+<glyph unicode="&#x2001;" horiz-adv-x="1537" />
+<glyph unicode="&#x2002;" horiz-adv-x="768" />
+<glyph unicode="&#x2003;" horiz-adv-x="1537" />
+<glyph unicode="&#x2004;" horiz-adv-x="512" />
+<glyph unicode="&#x2005;" horiz-adv-x="384" />
+<glyph unicode="&#x2006;" horiz-adv-x="256" />
+<glyph unicode="&#x2007;" horiz-adv-x="256" />
+<glyph unicode="&#x2008;" horiz-adv-x="192" />
+<glyph unicode="&#x2009;" horiz-adv-x="307" />
+<glyph unicode="&#x200a;" horiz-adv-x="85" />
+<glyph unicode="&#x202f;" horiz-adv-x="307" />
+<glyph unicode="&#x205f;" horiz-adv-x="384" />
+<glyph unicode="&#x2122;" horiz-adv-x="1792" />
+<glyph unicode="&#x221e;" horiz-adv-x="1792" />
+<glyph unicode="&#x2260;" horiz-adv-x="1792" />
+<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
+<glyph unicode="&#xf000;" horiz-adv-x="1792" d="M1699 1350q0 -35 -43 -78l-632 -632v-768h320q26 0 45 -19t19 -45t-19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45t45 19h320v768l-632 632q-43 43 -43 78q0 23 18 36.5t38 17.5t43 4h1408q23 0 43 -4t38 -17.5t18 -36.5z" />
+<glyph unicode="&#xf001;" d="M1536 1312v-1120q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v537l-768 -237v-709q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89 t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v967q0 31 19 56.5t49 35.5l832 256q12 4 28 4q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf002;" horiz-adv-x="1664" d="M1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -52 -38 -90t-90 -38q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5 t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" />
+<glyph unicode="&#xf003;" horiz-adv-x="1792" d="M1664 32v768q-32 -36 -69 -66q-268 -206 -426 -338q-51 -43 -83 -67t-86.5 -48.5t-102.5 -24.5h-1h-1q-48 0 -102.5 24.5t-86.5 48.5t-83 67q-158 132 -426 338q-37 30 -69 66v-768q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1664 1083v11v13.5t-0.5 13 t-3 12.5t-5.5 9t-9 7.5t-14 2.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5q0 -168 147 -284q193 -152 401 -317q6 -5 35 -29.5t46 -37.5t44.5 -31.5t50.5 -27.5t43 -9h1h1q20 0 43 9t50.5 27.5t44.5 31.5t46 37.5t35 29.5q208 165 401 317q54 43 100.5 115.5t46.5 131.5z M1792 1120v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf004;" horiz-adv-x="1792" d="M896 -128q-26 0 -44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5q224 0 351 -124t127 -344q0 -221 -229 -450l-623 -600 q-18 -18 -44 -18z" />
+<glyph unicode="&#xf005;" horiz-adv-x="1664" d="M1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -21 -10.5 -35.5t-30.5 -14.5q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455 l502 -73q56 -9 56 -46z" />
+<glyph unicode="&#xf006;" horiz-adv-x="1664" d="M1137 532l306 297l-422 62l-189 382l-189 -382l-422 -62l306 -297l-73 -421l378 199l377 -199zM1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -50 -41 -50q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500 l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455l502 -73q56 -9 56 -46z" />
+<glyph unicode="&#xf007;" horiz-adv-x="1408" d="M1408 131q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5t43 97.5t62 81t85.5 53.5t111.5 20q9 0 42 -21.5t74.5 -48t108 -48t133.5 -21.5t133.5 21.5t108 48t74.5 48t42 21.5q61 0 111.5 -20t85.5 -53.5t62 -81 t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5z" />
+<glyph unicode="&#xf008;" horiz-adv-x="1920" d="M384 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 320v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 704v128q0 26 -19 45t-45 19h-128 q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 -64v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM384 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45 t45 -19h128q26 0 45 19t19 45zM1792 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 704v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1792 320v128 q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 704v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19 t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1920 1248v-1344q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1344q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf009;" horiz-adv-x="1664" d="M768 512v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM768 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 512v-384q0 -52 -38 -90t-90 -38 h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf00a;" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 288v-192q0 -40 -28 -68t-68 -28h-320 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf00b;" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-960 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h960q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf00c;" horiz-adv-x="1792" d="M1671 970q0 -40 -28 -68l-724 -724l-136 -136q-28 -28 -68 -28t-68 28l-136 136l-362 362q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -295l656 657q28 28 68 28t68 -28l136 -136q28 -28 28 -68z" />
+<glyph unicode="&#xf00d;" horiz-adv-x="1408" d="M1298 214q0 -40 -28 -68l-136 -136q-28 -28 -68 -28t-68 28l-294 294l-294 -294q-28 -28 -68 -28t-68 28l-136 136q-28 28 -28 68t28 68l294 294l-294 294q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -294l294 294q28 28 68 28t68 -28l136 -136q28 -28 28 -68 t-28 -68l-294 -294l294 -294q28 -28 28 -68z" />
+<glyph unicode="&#xf00e;" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-224q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v224h-224q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h224v224q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5v-224h224 q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5 t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" />
+<glyph unicode="&#xf010;" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-576q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h576q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5z M1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z " />
+<glyph unicode="&#xf011;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61t-298 61t-245 164t-164 245t-61 298q0 182 80.5 343t226.5 270q43 32 95.5 25t83.5 -50q32 -42 24.5 -94.5t-49.5 -84.5q-98 -74 -151.5 -181t-53.5 -228q0 -104 40.5 -198.5t109.5 -163.5t163.5 -109.5 t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5q0 121 -53.5 228t-151.5 181q-42 32 -49.5 84.5t24.5 94.5q31 43 84 50t95 -25q146 -109 226.5 -270t80.5 -343zM896 1408v-640q0 -52 -38 -90t-90 -38t-90 38t-38 90v640q0 52 38 90t90 38t90 -38t38 -90z" />
+<glyph unicode="&#xf012;" horiz-adv-x="1792" d="M256 96v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 224v-320q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 480v-576q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1408 864v-960q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1376v-1472q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1472q0 14 9 23t23 9h192q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf013;" d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1536 749v-222q0 -12 -8 -23t-20 -13l-185 -28q-19 -54 -39 -91q35 -50 107 -138q10 -12 10 -25t-9 -23q-27 -37 -99 -108t-94 -71q-12 0 -26 9l-138 108q-44 -23 -91 -38 q-16 -136 -29 -186q-7 -28 -36 -28h-222q-14 0 -24.5 8.5t-11.5 21.5l-28 184q-49 16 -90 37l-141 -107q-10 -9 -25 -9q-14 0 -25 11q-126 114 -165 168q-7 10 -7 23q0 12 8 23q15 21 51 66.5t54 70.5q-27 50 -41 99l-183 27q-13 2 -21 12.5t-8 23.5v222q0 12 8 23t19 13 l186 28q14 46 39 92q-40 57 -107 138q-10 12 -10 24q0 10 9 23q26 36 98.5 107.5t94.5 71.5q13 0 26 -10l138 -107q44 23 91 38q16 136 29 186q7 28 36 28h222q14 0 24.5 -8.5t11.5 -21.5l28 -184q49 -16 90 -37l142 107q9 9 24 9q13 0 25 -10q129 -119 165 -170q7 -8 7 -22 q0 -12 -8 -23q-15 -21 -51 -66.5t-54 -70.5q26 -50 41 -98l183 -28q13 -2 21 -12.5t8 -23.5z" />
+<glyph unicode="&#xf014;" horiz-adv-x="1408" d="M512 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM768 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1024 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1152 76v948h-896v-948q0 -22 7 -40.5t14.5 -27t10.5 -8.5h832q3 0 10.5 8.5t14.5 27t7 40.5zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832 q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf015;" horiz-adv-x="1664" d="M1408 544v-480q0 -26 -19 -45t-45 -19h-384v384h-256v-384h-384q-26 0 -45 19t-19 45v480q0 1 0.5 3t0.5 3l575 474l575 -474q1 -2 1 -6zM1631 613l-62 -74q-8 -9 -21 -11h-3q-13 0 -21 7l-692 577l-692 -577q-12 -8 -24 -7q-13 2 -21 11l-62 74q-8 10 -7 23.5t11 21.5 l719 599q32 26 76 26t76 -26l244 -204v195q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-408l219 -182q10 -8 11 -21.5t-7 -23.5z" />
+<glyph unicode="&#xf016;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z " />
+<glyph unicode="&#xf017;" d="M896 992v-448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf018;" horiz-adv-x="1920" d="M1111 540v4l-24 320q-1 13 -11 22.5t-23 9.5h-186q-13 0 -23 -9.5t-11 -22.5l-24 -320v-4q-1 -12 8 -20t21 -8h244q12 0 21 8t8 20zM1870 73q0 -73 -46 -73h-704q13 0 22 9.5t8 22.5l-20 256q-1 13 -11 22.5t-23 9.5h-272q-13 0 -23 -9.5t-11 -22.5l-20 -256 q-1 -13 8 -22.5t22 -9.5h-704q-46 0 -46 73q0 54 26 116l417 1044q8 19 26 33t38 14h339q-13 0 -23 -9.5t-11 -22.5l-15 -192q-1 -14 8 -23t22 -9h166q13 0 22 9t8 23l-15 192q-1 13 -11 22.5t-23 9.5h339q20 0 38 -14t26 -33l417 -1044q26 -62 26 -116z" />
+<glyph unicode="&#xf019;" horiz-adv-x="1664" d="M1280 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 416v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h465l135 -136 q58 -56 136 -56t136 56l136 136h464q40 0 68 -28t28 -68zM1339 985q17 -41 -14 -70l-448 -448q-18 -19 -45 -19t-45 19l-448 448q-31 29 -14 70q17 39 59 39h256v448q0 26 19 45t45 19h256q26 0 45 -19t19 -45v-448h256q42 0 59 -39z" />
+<glyph unicode="&#xf01a;" d="M1120 608q0 -12 -10 -24l-319 -319q-11 -9 -23 -9t-23 9l-320 320q-15 16 -7 35q8 20 30 20h192v352q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-352h192q14 0 23 -9t9 -23zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273 t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf01b;" d="M1118 660q-8 -20 -30 -20h-192v-352q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v352h-192q-14 0 -23 9t-9 23q0 12 10 24l319 319q11 9 23 9t23 -9l320 -320q15 -16 7 -35zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198 t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf01c;" d="M1023 576h316q-1 3 -2.5 8t-2.5 8l-212 496h-708l-212 -496q-1 -2 -2.5 -8t-2.5 -8h316l95 -192h320zM1536 546v-482q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v482q0 62 25 123l238 552q10 25 36.5 42t52.5 17h832q26 0 52.5 -17t36.5 -42l238 -552 q25 -61 25 -123z" />
+<glyph unicode="&#xf01d;" d="M1184 640q0 -37 -32 -55l-544 -320q-15 -9 -32 -9q-16 0 -32 8q-32 19 -32 56v640q0 37 32 56q33 18 64 -1l544 -320q32 -18 32 -55zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf01e;" d="M1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l138 138q-148 137 -349 137q-104 0 -198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5q119 0 225 52t179 147q7 10 23 12q14 0 25 -9 l137 -138q9 -8 9.5 -20.5t-7.5 -22.5q-109 -132 -264 -204.5t-327 -72.5q-156 0 -298 61t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q147 0 284.5 -55.5t244.5 -156.5l130 129q29 31 70 14q39 -17 39 -59z" />
+<glyph unicode="&#xf021;" d="M1511 480q0 -5 -1 -7q-64 -268 -268 -434.5t-478 -166.5q-146 0 -282.5 55t-243.5 157l-129 -129q-19 -19 -45 -19t-45 19t-19 45v448q0 26 19 45t45 19h448q26 0 45 -19t19 -45t-19 -45l-137 -137q71 -66 161 -102t187 -36q134 0 250 65t186 179q11 17 53 117 q8 23 30 23h192q13 0 22.5 -9.5t9.5 -22.5zM1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-26 0 -45 19t-19 45t19 45l138 138q-148 137 -349 137q-134 0 -250 -65t-186 -179q-11 -17 -53 -117q-8 -23 -30 -23h-199q-13 0 -22.5 9.5t-9.5 22.5v7q65 268 270 434.5t480 166.5 q146 0 284 -55.5t245 -156.5l130 129q19 19 45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf022;" horiz-adv-x="1792" d="M384 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M384 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1536 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5z M1536 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5zM1536 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5 t9.5 -22.5zM1664 160v832q0 13 -9.5 22.5t-22.5 9.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1792 1248v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47 t47 -113z" />
+<glyph unicode="&#xf023;" horiz-adv-x="1152" d="M320 768h512v192q0 106 -75 181t-181 75t-181 -75t-75 -181v-192zM1152 672v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v192q0 184 132 316t316 132t316 -132t132 -316v-192h32q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf024;" horiz-adv-x="1792" d="M320 1280q0 -72 -64 -110v-1266q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v1266q-64 38 -64 110q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -25 -12.5 -38.5t-39.5 -27.5q-215 -116 -369 -116q-61 0 -123.5 22t-108.5 48 t-115.5 48t-142.5 22q-192 0 -464 -146q-17 -9 -33 -9q-26 0 -45 19t-19 45v742q0 32 31 55q21 14 79 43q236 120 421 120q107 0 200 -29t219 -88q38 -19 88 -19q54 0 117.5 21t110 47t88 47t54.5 21q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf025;" horiz-adv-x="1664" d="M1664 650q0 -166 -60 -314l-20 -49l-185 -33q-22 -83 -90.5 -136.5t-156.5 -53.5v-32q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-32q71 0 130 -35.5t93 -95.5l68 12q29 95 29 193q0 148 -88 279t-236.5 209t-315.5 78 t-315.5 -78t-236.5 -209t-88 -279q0 -98 29 -193l68 -12q34 60 93 95.5t130 35.5v32q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v32q-88 0 -156.5 53.5t-90.5 136.5l-185 33l-20 49q-60 148 -60 314q0 151 67 291t179 242.5 t266 163.5t320 61t320 -61t266 -163.5t179 -242.5t67 -291z" />
+<glyph unicode="&#xf026;" horiz-adv-x="768" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf027;" horiz-adv-x="1152" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142z" />
+<glyph unicode="&#xf028;" horiz-adv-x="1664" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142zM1408 640q0 -153 -85 -282.5t-225 -188.5q-13 -5 -25 -5q-27 0 -46 19t-19 45q0 39 39 59q56 29 76 44q74 54 115.5 135.5t41.5 173.5t-41.5 173.5 t-115.5 135.5q-20 15 -76 44q-39 20 -39 59q0 26 19 45t45 19q13 0 26 -5q140 -59 225 -188.5t85 -282.5zM1664 640q0 -230 -127 -422.5t-338 -283.5q-13 -5 -26 -5q-26 0 -45 19t-19 45q0 36 39 59q7 4 22.5 10.5t22.5 10.5q46 25 82 51q123 91 192 227t69 289t-69 289 t-192 227q-36 26 -82 51q-7 4 -22.5 10.5t-22.5 10.5q-39 23 -39 59q0 26 19 45t45 19q13 0 26 -5q211 -91 338 -283.5t127 -422.5z" />
+<glyph unicode="&#xf029;" horiz-adv-x="1408" d="M384 384v-128h-128v128h128zM384 1152v-128h-128v128h128zM1152 1152v-128h-128v128h128zM128 129h384v383h-384v-383zM128 896h384v384h-384v-384zM896 896h384v384h-384v-384zM640 640v-640h-640v640h640zM1152 128v-128h-128v128h128zM1408 128v-128h-128v128h128z M1408 640v-384h-384v128h-128v-384h-128v640h384v-128h128v128h128zM640 1408v-640h-640v640h640zM1408 1408v-640h-640v640h640z" />
+<glyph unicode="&#xf02a;" horiz-adv-x="1792" d="M63 0h-63v1408h63v-1408zM126 1h-32v1407h32v-1407zM220 1h-31v1407h31v-1407zM377 1h-31v1407h31v-1407zM534 1h-62v1407h62v-1407zM660 1h-31v1407h31v-1407zM723 1h-31v1407h31v-1407zM786 1h-31v1407h31v-1407zM943 1h-63v1407h63v-1407zM1100 1h-63v1407h63v-1407z M1226 1h-63v1407h63v-1407zM1352 1h-63v1407h63v-1407zM1446 1h-63v1407h63v-1407zM1635 1h-94v1407h94v-1407zM1698 1h-32v1407h32v-1407zM1792 0h-63v1408h63v-1408z" />
+<glyph unicode="&#xf02b;" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91z" />
+<glyph unicode="&#xf02c;" horiz-adv-x="1920" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91zM1899 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-36 0 -59 14t-53 45l470 470q37 37 37 90q0 52 -37 91l-715 714q-38 38 -102 64.5t-117 26.5h224q53 0 117 -26.5t102 -64.5l715 -714q37 -39 37 -91z" />
+<glyph unicode="&#xf02d;" horiz-adv-x="1664" d="M1639 1058q40 -57 18 -129l-275 -906q-19 -64 -76.5 -107.5t-122.5 -43.5h-923q-77 0 -148.5 53.5t-99.5 131.5q-24 67 -2 127q0 4 3 27t4 37q1 8 -3 21.5t-3 19.5q2 11 8 21t16.5 23.5t16.5 23.5q23 38 45 91.5t30 91.5q3 10 0.5 30t-0.5 28q3 11 17 28t17 23 q21 36 42 92t25 90q1 9 -2.5 32t0.5 28q4 13 22 30.5t22 22.5q19 26 42.5 84.5t27.5 96.5q1 8 -3 25.5t-2 26.5q2 8 9 18t18 23t17 21q8 12 16.5 30.5t15 35t16 36t19.5 32t26.5 23.5t36 11.5t47.5 -5.5l-1 -3q38 9 51 9h761q74 0 114 -56t18 -130l-274 -906 q-36 -119 -71.5 -153.5t-128.5 -34.5h-869q-27 0 -38 -15q-11 -16 -1 -43q24 -70 144 -70h923q29 0 56 15.5t35 41.5l300 987q7 22 5 57q38 -15 59 -43zM575 1056q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5 t-16.5 -22.5zM492 800q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5t-16.5 -22.5z" />
+<glyph unicode="&#xf02e;" horiz-adv-x="1280" d="M1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
+<glyph unicode="&#xf02f;" horiz-adv-x="1664" d="M384 0h896v256h-896v-256zM384 640h896v384h-160q-40 0 -68 28t-28 68v160h-640v-640zM1536 576q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 576v-416q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-160q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68 v160h-224q-13 0 -22.5 9.5t-9.5 22.5v416q0 79 56.5 135.5t135.5 56.5h64v544q0 40 28 68t68 28h672q40 0 88 -20t76 -48l152 -152q28 -28 48 -76t20 -88v-256h64q79 0 135.5 -56.5t56.5 -135.5z" />
+<glyph unicode="&#xf030;" horiz-adv-x="1920" d="M960 864q119 0 203.5 -84.5t84.5 -203.5t-84.5 -203.5t-203.5 -84.5t-203.5 84.5t-84.5 203.5t84.5 203.5t203.5 84.5zM1664 1280q106 0 181 -75t75 -181v-896q0 -106 -75 -181t-181 -75h-1408q-106 0 -181 75t-75 181v896q0 106 75 181t181 75h224l51 136 q19 49 69.5 84.5t103.5 35.5h512q53 0 103.5 -35.5t69.5 -84.5l51 -136h224zM960 128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+<glyph unicode="&#xf031;" horiz-adv-x="1664" d="M725 977l-170 -450q33 0 136.5 -2t160.5 -2q19 0 57 2q-87 253 -184 452zM0 -128l2 79q23 7 56 12.5t57 10.5t49.5 14.5t44.5 29t31 50.5l237 616l280 724h75h53q8 -14 11 -21l205 -480q33 -78 106 -257.5t114 -274.5q15 -34 58 -144.5t72 -168.5q20 -45 35 -57 q19 -15 88 -29.5t84 -20.5q6 -38 6 -57q0 -4 -0.5 -13t-0.5 -13q-63 0 -190 8t-191 8q-76 0 -215 -7t-178 -8q0 43 4 78l131 28q1 0 12.5 2.5t15.5 3.5t14.5 4.5t15 6.5t11 8t9 11t2.5 14q0 16 -31 96.5t-72 177.5t-42 100l-450 2q-26 -58 -76.5 -195.5t-50.5 -162.5 q0 -22 14 -37.5t43.5 -24.5t48.5 -13.5t57 -8.5t41 -4q1 -19 1 -58q0 -9 -2 -27q-58 0 -174.5 10t-174.5 10q-8 0 -26.5 -4t-21.5 -4q-80 -14 -188 -14z" />
+<glyph unicode="&#xf032;" horiz-adv-x="1408" d="M555 15q74 -32 140 -32q376 0 376 335q0 114 -41 180q-27 44 -61.5 74t-67.5 46.5t-80.5 25t-84 10.5t-94.5 2q-73 0 -101 -10q0 -53 -0.5 -159t-0.5 -158q0 -8 -1 -67.5t-0.5 -96.5t4.5 -83.5t12 -66.5zM541 761q42 -7 109 -7q82 0 143 13t110 44.5t74.5 89.5t25.5 142 q0 70 -29 122.5t-79 82t-108 43.5t-124 14q-50 0 -130 -13q0 -50 4 -151t4 -152q0 -27 -0.5 -80t-0.5 -79q0 -46 1 -69zM0 -128l2 94q15 4 85 16t106 27q7 12 12.5 27t8.5 33.5t5.5 32.5t3 37.5t0.5 34v35.5v30q0 982 -22 1025q-4 8 -22 14.5t-44.5 11t-49.5 7t-48.5 4.5 t-30.5 3l-4 83q98 2 340 11.5t373 9.5q23 0 68.5 -0.5t67.5 -0.5q70 0 136.5 -13t128.5 -42t108 -71t74 -104.5t28 -137.5q0 -52 -16.5 -95.5t-39 -72t-64.5 -57.5t-73 -45t-84 -40q154 -35 256.5 -134t102.5 -248q0 -100 -35 -179.5t-93.5 -130.5t-138 -85.5t-163.5 -48.5 t-176 -14q-44 0 -132 3t-132 3q-106 0 -307 -11t-231 -12z" />
+<glyph unicode="&#xf033;" horiz-adv-x="1024" d="M0 -126l17 85q6 2 81.5 21.5t111.5 37.5q28 35 41 101q1 7 62 289t114 543.5t52 296.5v25q-24 13 -54.5 18.5t-69.5 8t-58 5.5l19 103q33 -2 120 -6.5t149.5 -7t120.5 -2.5q48 0 98.5 2.5t121 7t98.5 6.5q-5 -39 -19 -89q-30 -10 -101.5 -28.5t-108.5 -33.5 q-8 -19 -14 -42.5t-9 -40t-7.5 -45.5t-6.5 -42q-27 -148 -87.5 -419.5t-77.5 -355.5q-2 -9 -13 -58t-20 -90t-16 -83.5t-6 -57.5l1 -18q17 -4 185 -31q-3 -44 -16 -99q-11 0 -32.5 -1.5t-32.5 -1.5q-29 0 -87 10t-86 10q-138 2 -206 2q-51 0 -143 -9t-121 -11z" />
+<glyph unicode="&#xf034;" horiz-adv-x="1792" d="M1744 128q33 0 42 -18.5t-11 -44.5l-126 -162q-20 -26 -49 -26t-49 26l-126 162q-20 26 -11 44.5t42 18.5h80v1024h-80q-33 0 -42 18.5t11 44.5l126 162q20 26 49 26t49 -26l126 -162q20 -26 11 -44.5t-42 -18.5h-80v-1024h80zM81 1407l54 -27q12 -5 211 -5q44 0 132 2 t132 2q36 0 107.5 -0.5t107.5 -0.5h293q6 0 21 -0.5t20.5 0t16 3t17.5 9t15 17.5l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 48t-14.5 73.5t-7.5 35.5q-6 8 -12 12.5t-15.5 6t-13 2.5t-18 0.5t-16.5 -0.5 q-17 0 -66.5 0.5t-74.5 0.5t-64 -2t-71 -6q-9 -81 -8 -136q0 -94 2 -388t2 -455q0 -16 -2.5 -71.5t0 -91.5t12.5 -69q40 -21 124 -42.5t120 -37.5q5 -40 5 -50q0 -14 -3 -29l-34 -1q-76 -2 -218 8t-207 10q-50 0 -151 -9t-152 -9q-3 51 -3 52v9q17 27 61.5 43t98.5 29t78 27 q19 42 19 383q0 101 -3 303t-3 303v117q0 2 0.5 15.5t0.5 25t-1 25.5t-3 24t-5 14q-11 12 -162 12q-33 0 -93 -12t-80 -26q-19 -13 -34 -72.5t-31.5 -111t-42.5 -53.5q-42 26 -56 44v383z" />
+<glyph unicode="&#xf035;" d="M81 1407l54 -27q12 -5 211 -5q44 0 132 2t132 2q70 0 246.5 1t304.5 0.5t247 -4.5q33 -1 56 31l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 47.5t-15 73.5t-7 36q-10 13 -27 19q-5 2 -66 2q-30 0 -93 1t-103 1 t-94 -2t-96 -7q-9 -81 -8 -136l1 -152v52q0 -55 1 -154t1.5 -180t0.5 -153q0 -16 -2.5 -71.5t0 -91.5t12.5 -69q40 -21 124 -42.5t120 -37.5q5 -40 5 -50q0 -14 -3 -29l-34 -1q-76 -2 -218 8t-207 10q-50 0 -151 -9t-152 -9q-3 51 -3 52v9q17 27 61.5 43t98.5 29t78 27 q7 16 11.5 74t6 145.5t1.5 155t-0.5 153.5t-0.5 89q0 7 -2.5 21.5t-2.5 22.5q0 7 0.5 44t1 73t0 76.5t-3 67.5t-6.5 32q-11 12 -162 12q-41 0 -163 -13.5t-138 -24.5q-19 -12 -34 -71.5t-31.5 -111.5t-42.5 -54q-42 26 -56 44v383zM1310 125q12 0 42 -19.5t57.5 -41.5 t59.5 -49t36 -30q26 -21 26 -49t-26 -49q-4 -3 -36 -30t-59.5 -49t-57.5 -41.5t-42 -19.5q-13 0 -20.5 10.5t-10 28.5t-2.5 33.5t1.5 33t1.5 19.5h-1024q0 -2 1.5 -19.5t1.5 -33t-2.5 -33.5t-10 -28.5t-20.5 -10.5q-12 0 -42 19.5t-57.5 41.5t-59.5 49t-36 30q-26 21 -26 49 t26 49q4 3 36 30t59.5 49t57.5 41.5t42 19.5q13 0 20.5 -10.5t10 -28.5t2.5 -33.5t-1.5 -33t-1.5 -19.5h1024q0 2 -1.5 19.5t-1.5 33t2.5 33.5t10 28.5t20.5 10.5z" />
+<glyph unicode="&#xf036;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf037;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h896q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45t-45 -19 h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h640q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf038;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf039;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf03a;" horiz-adv-x="1792" d="M256 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM256 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5 t9.5 -22.5zM256 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344 q13 0 22.5 -9.5t9.5 -22.5zM256 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192 q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf03b;" horiz-adv-x="1792" d="M384 992v-576q0 -13 -9.5 -22.5t-22.5 -9.5q-14 0 -23 9l-288 288q-9 9 -9 23t9 23l288 288q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf03c;" horiz-adv-x="1792" d="M352 704q0 -14 -9 -23l-288 -288q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v576q0 13 9.5 22.5t22.5 9.5q14 0 23 -9l288 -288q9 -9 9 -23zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf03d;" horiz-adv-x="1792" d="M1792 1184v-1088q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-403 403v-166q0 -119 -84.5 -203.5t-203.5 -84.5h-704q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h704q119 0 203.5 -84.5t84.5 -203.5v-165l403 402q18 19 45 19q12 0 25 -5 q39 -17 39 -59z" />
+<glyph unicode="&#xf03e;" horiz-adv-x="1920" d="M640 960q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 576v-448h-1408v192l320 320l160 -160l512 512zM1760 1280h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5v1216 q0 13 -9.5 22.5t-22.5 9.5zM1920 1248v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf040;" d="M363 0l91 91l-235 235l-91 -91v-107h128v-128h107zM886 928q0 22 -22 22q-10 0 -17 -7l-542 -542q-7 -7 -7 -17q0 -22 22 -22q10 0 17 7l542 542q7 7 7 17zM832 1120l416 -416l-832 -832h-416v416zM1515 1024q0 -53 -37 -90l-166 -166l-416 416l166 165q36 38 90 38 q53 0 91 -38l235 -234q37 -39 37 -91z" />
+<glyph unicode="&#xf041;" horiz-adv-x="1024" d="M768 896q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1024 896q0 -109 -33 -179l-364 -774q-16 -33 -47.5 -52t-67.5 -19t-67.5 19t-46.5 52l-365 774q-33 70 -33 179q0 212 150 362t362 150t362 -150t150 -362z" />
+<glyph unicode="&#xf042;" d="M768 96v1088q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf043;" horiz-adv-x="1024" d="M512 384q0 36 -20 69q-1 1 -15.5 22.5t-25.5 38t-25 44t-21 50.5q-4 16 -21 16t-21 -16q-7 -23 -21 -50.5t-25 -44t-25.5 -38t-15.5 -22.5q-20 -33 -20 -69q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 512q0 -212 -150 -362t-362 -150t-362 150t-150 362 q0 145 81 275q6 9 62.5 90.5t101 151t99.5 178t83 201.5q9 30 34 47t51 17t51.5 -17t33.5 -47q28 -93 83 -201.5t99.5 -178t101 -151t62.5 -90.5q81 -127 81 -275z" />
+<glyph unicode="&#xf044;" horiz-adv-x="1792" d="M888 352l116 116l-152 152l-116 -116v-56h96v-96h56zM1328 1072q-16 16 -33 -1l-350 -350q-17 -17 -1 -33t33 1l350 350q17 17 1 33zM1408 478v-190q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-14 -14 -32 -8q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v126q0 13 9 22l64 64q15 15 35 7t20 -29zM1312 1216l288 -288l-672 -672h-288v288zM1756 1084l-92 -92 l-288 288l92 92q28 28 68 28t68 -28l152 -152q28 -28 28 -68t-28 -68z" />
+<glyph unicode="&#xf045;" horiz-adv-x="1664" d="M1408 547v-259q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h255v0q13 0 22.5 -9.5t9.5 -22.5q0 -27 -26 -32q-77 -26 -133 -60q-10 -4 -16 -4h-112q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832 q66 0 113 47t47 113v214q0 19 18 29q28 13 54 37q16 16 35 8q21 -9 21 -29zM1645 1043l-384 -384q-18 -19 -45 -19q-12 0 -25 5q-39 17 -39 59v192h-160q-323 0 -438 -131q-119 -137 -74 -473q3 -23 -20 -34q-8 -2 -12 -2q-16 0 -26 13q-10 14 -21 31t-39.5 68.5t-49.5 99.5 t-38.5 114t-17.5 122q0 49 3.5 91t14 90t28 88t47 81.5t68.5 74t94.5 61.5t124.5 48.5t159.5 30.5t196.5 11h160v192q0 42 39 59q13 5 25 5q26 0 45 -19l384 -384q19 -19 19 -45t-19 -45z" />
+<glyph unicode="&#xf046;" horiz-adv-x="1664" d="M1408 606v-318q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-10 -10 -23 -10q-3 0 -9 2q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832 q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v254q0 13 9 22l64 64q10 10 23 10q6 0 12 -3q20 -8 20 -29zM1639 1095l-814 -814q-24 -24 -57 -24t-57 24l-430 430q-24 24 -24 57t24 57l110 110q24 24 57 24t57 -24l263 -263l647 647q24 24 57 24t57 -24l110 -110 q24 -24 24 -57t-24 -57z" />
+<glyph unicode="&#xf047;" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-384v-384h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v384h-384v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45 t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h384v384h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45t-19 -45t-45 -19h-128v-384h384v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" />
+<glyph unicode="&#xf048;" horiz-adv-x="1024" d="M979 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19z" />
+<glyph unicode="&#xf049;" horiz-adv-x="1792" d="M1747 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19l710 710 q19 19 32 13t13 -32v-710q4 11 13 19z" />
+<glyph unicode="&#xf04a;" horiz-adv-x="1664" d="M1619 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-8 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-19 19 -19 45t19 45l710 710q19 19 32 13t13 -32v-710q5 11 13 19z" />
+<glyph unicode="&#xf04b;" horiz-adv-x="1408" d="M1384 609l-1328 -738q-23 -13 -39.5 -3t-16.5 36v1472q0 26 16.5 36t39.5 -3l1328 -738q23 -13 23 -31t-23 -31z" />
+<glyph unicode="&#xf04c;" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45zM640 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf04d;" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf04e;" horiz-adv-x="1664" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q19 -19 19 -45t-19 -45l-710 -710q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" />
+<glyph unicode="&#xf050;" horiz-adv-x="1792" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19l-710 -710 q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" />
+<glyph unicode="&#xf051;" horiz-adv-x="1024" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19z" />
+<glyph unicode="&#xf052;" horiz-adv-x="1538" d="M14 557l710 710q19 19 45 19t45 -19l710 -710q19 -19 13 -32t-32 -13h-1472q-26 0 -32 13t13 32zM1473 0h-1408q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1408q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19z" />
+<glyph unicode="&#xf053;" horiz-adv-x="1280" d="M1171 1235l-531 -531l531 -531q19 -19 19 -45t-19 -45l-166 -166q-19 -19 -45 -19t-45 19l-742 742q-19 19 -19 45t19 45l742 742q19 19 45 19t45 -19l166 -166q19 -19 19 -45t-19 -45z" />
+<glyph unicode="&#xf054;" horiz-adv-x="1280" d="M1107 659l-742 -742q-19 -19 -45 -19t-45 19l-166 166q-19 19 -19 45t19 45l531 531l-531 531q-19 19 -19 45t19 45l166 166q19 19 45 19t45 -19l742 -742q19 -19 19 -45t-19 -45z" />
+<glyph unicode="&#xf055;" d="M1216 576v128q0 26 -19 45t-45 19h-256v256q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-256h-256q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h256v-256q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v256h256q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5 t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf056;" d="M1216 576v128q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 t103 -385.5z" />
+<glyph unicode="&#xf057;" d="M1149 414q0 26 -19 45l-181 181l181 181q19 19 19 45q0 27 -19 46l-90 90q-19 19 -46 19q-26 0 -45 -19l-181 -181l-181 181q-19 19 -45 19q-27 0 -46 -19l-90 -90q-19 -19 -19 -46q0 -26 19 -45l181 -181l-181 -181q-19 -19 -19 -45q0 -27 19 -46l90 -90q19 -19 46 -19 q26 0 45 19l181 181l181 -181q19 -19 45 -19q27 0 46 19l90 90q19 19 19 46zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf058;" d="M1284 802q0 28 -18 46l-91 90q-19 19 -45 19t-45 -19l-408 -407l-226 226q-19 19 -45 19t-45 -19l-91 -90q-18 -18 -18 -46q0 -27 18 -45l362 -362q19 -19 45 -19q27 0 46 19l543 543q18 18 18 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf059;" d="M896 160v192q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h192q14 0 23 9t9 23zM1152 832q0 88 -55.5 163t-138.5 116t-170 41q-243 0 -371 -213q-15 -24 8 -42l132 -100q7 -6 19 -6q16 0 25 12q53 68 86 92q34 24 86 24q48 0 85.5 -26t37.5 -59 q0 -38 -20 -61t-68 -45q-63 -28 -115.5 -86.5t-52.5 -125.5v-36q0 -14 9 -23t23 -9h192q14 0 23 9t9 23q0 19 21.5 49.5t54.5 49.5q32 18 49 28.5t46 35t44.5 48t28 60.5t12.5 81zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05a;" d="M1024 160v160q0 14 -9 23t-23 9h-96v512q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h96v-320h-96q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h448q14 0 23 9t9 23zM896 1056v160q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23 t23 -9h192q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05b;" d="M1197 512h-109q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h109q-32 108 -112.5 188.5t-188.5 112.5v-109q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v109q-108 -32 -188.5 -112.5t-112.5 -188.5h109q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-109 q32 -108 112.5 -188.5t188.5 -112.5v109q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-109q108 32 188.5 112.5t112.5 188.5zM1536 704v-128q0 -26 -19 -45t-45 -19h-143q-37 -161 -154.5 -278.5t-278.5 -154.5v-143q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v143 q-161 37 -278.5 154.5t-154.5 278.5h-143q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h143q37 161 154.5 278.5t278.5 154.5v143q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-143q161 -37 278.5 -154.5t154.5 -278.5h143q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf05c;" d="M1097 457l-146 -146q-10 -10 -23 -10t-23 10l-137 137l-137 -137q-10 -10 -23 -10t-23 10l-146 146q-10 10 -10 23t10 23l137 137l-137 137q-10 10 -10 23t10 23l146 146q10 10 23 10t23 -10l137 -137l137 137q10 10 23 10t23 -10l146 -146q10 -10 10 -23t-10 -23 l-137 -137l137 -137q10 -10 10 -23t-10 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5 t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05d;" d="M1171 723l-422 -422q-19 -19 -45 -19t-45 19l-294 294q-19 19 -19 45t19 45l102 102q19 19 45 19t45 -19l147 -147l275 275q19 19 45 19t45 -19l102 -102q19 -19 19 -45t-19 -45zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198 t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05e;" d="M1312 643q0 161 -87 295l-754 -753q137 -89 297 -89q111 0 211.5 43.5t173.5 116.5t116 174.5t43 212.5zM313 344l755 754q-135 91 -300 91q-148 0 -273 -73t-198 -199t-73 -274q0 -162 89 -299zM1536 643q0 -157 -61 -300t-163.5 -246t-245 -164t-298.5 -61t-298.5 61 t-245 164t-163.5 246t-61 300t61 299.5t163.5 245.5t245 164t298.5 61t298.5 -61t245 -164t163.5 -245.5t61 -299.5z" />
+<glyph unicode="&#xf060;" d="M1536 640v-128q0 -53 -32.5 -90.5t-84.5 -37.5h-704l293 -294q38 -36 38 -90t-38 -90l-75 -76q-37 -37 -90 -37q-52 0 -91 37l-651 652q-37 37 -37 90q0 52 37 91l651 650q38 38 91 38q52 0 90 -38l75 -74q38 -38 38 -91t-38 -91l-293 -293h704q52 0 84.5 -37.5 t32.5 -90.5z" />
+<glyph unicode="&#xf061;" d="M1472 576q0 -54 -37 -91l-651 -651q-39 -37 -91 -37q-51 0 -90 37l-75 75q-38 38 -38 91t38 91l293 293h-704q-52 0 -84.5 37.5t-32.5 90.5v128q0 53 32.5 90.5t84.5 37.5h704l-293 294q-38 36 -38 90t38 90l75 75q38 38 90 38q53 0 91 -38l651 -651q37 -35 37 -90z" />
+<glyph unicode="&#xf062;" horiz-adv-x="1664" d="M1611 565q0 -51 -37 -90l-75 -75q-38 -38 -91 -38q-54 0 -90 38l-294 293v-704q0 -52 -37.5 -84.5t-90.5 -32.5h-128q-53 0 -90.5 32.5t-37.5 84.5v704l-294 -293q-36 -38 -90 -38t-90 38l-75 75q-38 38 -38 90q0 53 38 91l651 651q35 37 90 37q54 0 91 -37l651 -651 q37 -39 37 -91z" />
+<glyph unicode="&#xf063;" horiz-adv-x="1664" d="M1611 704q0 -53 -37 -90l-651 -652q-39 -37 -91 -37q-53 0 -90 37l-651 652q-38 36 -38 90q0 53 38 91l74 75q39 37 91 37q53 0 90 -37l294 -294v704q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-704l294 294q37 37 90 37q52 0 91 -37l75 -75q37 -39 37 -91z" />
+<glyph unicode="&#xf064;" horiz-adv-x="1792" d="M1792 896q0 -26 -19 -45l-512 -512q-19 -19 -45 -19t-45 19t-19 45v256h-224q-98 0 -175.5 -6t-154 -21.5t-133 -42.5t-105.5 -69.5t-80 -101t-48.5 -138.5t-17.5 -181q0 -55 5 -123q0 -6 2.5 -23.5t2.5 -26.5q0 -15 -8.5 -25t-23.5 -10q-16 0 -28 17q-7 9 -13 22 t-13.5 30t-10.5 24q-127 285 -127 451q0 199 53 333q162 403 875 403h224v256q0 26 19 45t45 19t45 -19l512 -512q19 -19 19 -45z" />
+<glyph unicode="&#xf065;" d="M755 480q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23zM1536 1344v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332 q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf066;" d="M768 576v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45zM1523 1248q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45 t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23z" />
+<glyph unicode="&#xf067;" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-416v-416q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v416h-416q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h416v416q0 40 28 68t68 28h192q40 0 68 -28t28 -68v-416h416q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf068;" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-1216q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h1216q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf069;" horiz-adv-x="1664" d="M1482 486q46 -26 59.5 -77.5t-12.5 -97.5l-64 -110q-26 -46 -77.5 -59.5t-97.5 12.5l-266 153v-307q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v307l-266 -153q-46 -26 -97.5 -12.5t-77.5 59.5l-64 110q-26 46 -12.5 97.5t59.5 77.5l266 154l-266 154 q-46 26 -59.5 77.5t12.5 97.5l64 110q26 46 77.5 59.5t97.5 -12.5l266 -153v307q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-307l266 153q46 26 97.5 12.5t77.5 -59.5l64 -110q26 -46 12.5 -97.5t-59.5 -77.5l-266 -154z" />
+<glyph unicode="&#xf06a;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM896 161v190q0 14 -9 23.5t-22 9.5h-192q-13 0 -23 -10t-10 -23v-190q0 -13 10 -23t23 -10h192 q13 0 22 9.5t9 23.5zM894 505l18 621q0 12 -10 18q-10 8 -24 8h-220q-14 0 -24 -8q-10 -6 -10 -18l17 -621q0 -10 10 -17.5t24 -7.5h185q14 0 23.5 7.5t10.5 17.5z" />
+<glyph unicode="&#xf06b;" d="M928 180v56v468v192h-320v-192v-468v-56q0 -25 18 -38.5t46 -13.5h192q28 0 46 13.5t18 38.5zM472 1024h195l-126 161q-26 31 -69 31q-40 0 -68 -28t-28 -68t28 -68t68 -28zM1160 1120q0 40 -28 68t-68 28q-43 0 -69 -31l-125 -161h194q40 0 68 28t28 68zM1536 864v-320 q0 -14 -9 -23t-23 -9h-96v-416q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v416h-96q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h440q-93 0 -158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5q107 0 168 -77l128 -165l128 165q61 77 168 77q93 0 158.5 -65.5t65.5 -158.5 t-65.5 -158.5t-158.5 -65.5h440q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf06c;" horiz-adv-x="1792" d="M1280 832q0 26 -19 45t-45 19q-172 0 -318 -49.5t-259.5 -134t-235.5 -219.5q-19 -21 -19 -45q0 -26 19 -45t45 -19q24 0 45 19q27 24 74 71t67 66q137 124 268.5 176t313.5 52q26 0 45 19t19 45zM1792 1030q0 -95 -20 -193q-46 -224 -184.5 -383t-357.5 -268 q-214 -108 -438 -108q-148 0 -286 47q-15 5 -88 42t-96 37q-16 0 -39.5 -32t-45 -70t-52.5 -70t-60 -32q-30 0 -51 11t-31 24t-27 42q-2 4 -6 11t-5.5 10t-3 9.5t-1.5 13.5q0 35 31 73.5t68 65.5t68 56t31 48q0 4 -14 38t-16 44q-9 51 -9 104q0 115 43.5 220t119 184.5 t170.5 139t204 95.5q55 18 145 25.5t179.5 9t178.5 6t163.5 24t113.5 56.5l29.5 29.5t29.5 28t27 20t36.5 16t43.5 4.5q39 0 70.5 -46t47.5 -112t24 -124t8 -96z" />
+<glyph unicode="&#xf06d;" horiz-adv-x="1408" d="M1408 -160v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1152 896q0 -78 -24.5 -144t-64 -112.5t-87.5 -88t-96 -77.5t-87.5 -72t-64 -81.5t-24.5 -96.5q0 -96 67 -224l-4 1l1 -1 q-90 41 -160 83t-138.5 100t-113.5 122.5t-72.5 150.5t-27.5 184q0 78 24.5 144t64 112.5t87.5 88t96 77.5t87.5 72t64 81.5t24.5 96.5q0 94 -66 224l3 -1l-1 1q90 -41 160 -83t138.5 -100t113.5 -122.5t72.5 -150.5t27.5 -184z" />
+<glyph unicode="&#xf06e;" horiz-adv-x="1792" d="M1664 576q-152 236 -381 353q61 -104 61 -225q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 121 61 225q-229 -117 -381 -353q133 -205 333.5 -326.5t434.5 -121.5t434.5 121.5t333.5 326.5zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5 t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1792 576q0 -34 -20 -69q-140 -230 -376.5 -368.5t-499.5 -138.5t-499.5 139t-376.5 368q-20 35 -20 69t20 69q140 229 376.5 368t499.5 139t499.5 -139t376.5 -368q20 -35 20 -69z" />
+<glyph unicode="&#xf070;" horiz-adv-x="1792" d="M555 201l78 141q-87 63 -136 159t-49 203q0 121 61 225q-229 -117 -381 -353q167 -258 427 -375zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1307 1151q0 -7 -1 -9 q-105 -188 -315 -566t-316 -567l-49 -89q-10 -16 -28 -16q-12 0 -134 70q-16 10 -16 28q0 12 44 87q-143 65 -263.5 173t-208.5 245q-20 31 -20 69t20 69q153 235 380 371t496 136q89 0 180 -17l54 97q10 16 28 16q5 0 18 -6t31 -15.5t33 -18.5t31.5 -18.5t19.5 -11.5 q16 -10 16 -27zM1344 704q0 -139 -79 -253.5t-209 -164.5l280 502q8 -45 8 -84zM1792 576q0 -35 -20 -69q-39 -64 -109 -145q-150 -172 -347.5 -267t-419.5 -95l74 132q212 18 392.5 137t301.5 307q-115 179 -282 294l63 112q95 -64 182.5 -153t144.5 -184q20 -34 20 -69z " />
+<glyph unicode="&#xf071;" horiz-adv-x="1792" d="M1024 161v190q0 14 -9.5 23.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -23.5v-190q0 -14 9.5 -23.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 23.5zM1022 535l18 459q0 12 -10 19q-13 11 -24 11h-220q-11 0 -24 -11q-10 -7 -10 -21l17 -457q0 -10 10 -16.5t24 -6.5h185 q14 0 23.5 6.5t10.5 16.5zM1008 1469l768 -1408q35 -63 -2 -126q-17 -29 -46.5 -46t-63.5 -17h-1536q-34 0 -63.5 17t-46.5 46q-37 63 -2 126l768 1408q17 31 47 49t65 18t65 -18t47 -49z" />
+<glyph unicode="&#xf072;" horiz-adv-x="1408" d="M1376 1376q44 -52 12 -148t-108 -172l-161 -161l160 -696q5 -19 -12 -33l-128 -96q-7 -6 -19 -6q-4 0 -7 1q-15 3 -21 16l-279 508l-259 -259l53 -194q5 -17 -8 -31l-96 -96q-9 -9 -23 -9h-2q-15 2 -24 13l-189 252l-252 189q-11 7 -13 23q-1 13 9 25l96 97q9 9 23 9 q6 0 8 -1l194 -53l259 259l-508 279q-14 8 -17 24q-2 16 9 27l128 128q14 13 30 8l665 -159l160 160q76 76 172 108t148 -12z" />
+<glyph unicode="&#xf073;" horiz-adv-x="1664" d="M128 -128h288v288h-288v-288zM480 -128h320v288h-320v-288zM128 224h288v320h-288v-320zM480 224h320v320h-320v-320zM128 608h288v288h-288v-288zM864 -128h320v288h-320v-288zM480 608h320v288h-320v-288zM1248 -128h288v288h-288v-288zM864 224h320v320h-320v-320z M512 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1248 224h288v320h-288v-320zM864 608h320v288h-320v-288zM1248 608h288v288h-288v-288zM1280 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64 q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47 h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf074;" horiz-adv-x="1792" d="M666 1055q-60 -92 -137 -273q-22 45 -37 72.5t-40.5 63.5t-51 56.5t-63 35t-81.5 14.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q250 0 410 -225zM1792 256q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192q-32 0 -85 -0.5t-81 -1t-73 1 t-71 5t-64 10.5t-63 18.5t-58 28.5t-59 40t-55 53.5t-56 69.5q59 93 136 273q22 -45 37 -72.5t40.5 -63.5t51 -56.5t63 -35t81.5 -14.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1792 1152q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5 v192h-256q-48 0 -87 -15t-69 -45t-51 -61.5t-45 -77.5q-32 -62 -78 -171q-29 -66 -49.5 -111t-54 -105t-64 -100t-74 -83t-90 -68.5t-106.5 -42t-128 -16.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q48 0 87 15t69 45t51 61.5t45 77.5q32 62 78 171q29 66 49.5 111 t54 105t64 100t74 83t90 68.5t106.5 42t128 16.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" />
+<glyph unicode="&#xf075;" horiz-adv-x="1792" d="M1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22q-17 -2 -30.5 9t-17.5 29v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281 q0 130 71 248.5t191 204.5t286 136.5t348 50.5q244 0 450 -85.5t326 -233t120 -321.5z" />
+<glyph unicode="&#xf076;" d="M1536 704v-128q0 -201 -98.5 -362t-274 -251.5t-395.5 -90.5t-395.5 90.5t-274 251.5t-98.5 362v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-128q0 -52 23.5 -90t53.5 -57t71 -30t64 -13t44 -2t44 2t64 13t71 30t53.5 57t23.5 90v128q0 26 19 45t45 19h384 q26 0 45 -19t19 -45zM512 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45zM1536 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf077;" horiz-adv-x="1792" d="M1683 205l-166 -165q-19 -19 -45 -19t-45 19l-531 531l-531 -531q-19 -19 -45 -19t-45 19l-166 165q-19 19 -19 45.5t19 45.5l742 741q19 19 45 19t45 -19l742 -741q19 -19 19 -45.5t-19 -45.5z" />
+<glyph unicode="&#xf078;" horiz-adv-x="1792" d="M1683 728l-742 -741q-19 -19 -45 -19t-45 19l-742 741q-19 19 -19 45.5t19 45.5l166 165q19 19 45 19t45 -19l531 -531l531 531q19 19 45 19t45 -19l166 -165q19 -19 19 -45.5t-19 -45.5z" />
+<glyph unicode="&#xf079;" horiz-adv-x="1920" d="M1280 32q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-8 0 -13.5 2t-9 7t-5.5 8t-3 11.5t-1 11.5v13v11v160v416h-192q-26 0 -45 19t-19 45q0 24 15 41l320 384q19 22 49 22t49 -22l320 -384q15 -17 15 -41q0 -26 -19 -45t-45 -19h-192v-384h576q16 0 25 -11l160 -192q7 -11 7 -21 zM1920 448q0 -24 -15 -41l-320 -384q-20 -23 -49 -23t-49 23l-320 384q-15 17 -15 41q0 26 19 45t45 19h192v384h-576q-16 0 -25 12l-160 192q-7 9 -7 20q0 13 9.5 22.5t22.5 9.5h960q8 0 13.5 -2t9 -7t5.5 -8t3 -11.5t1 -11.5v-13v-11v-160v-416h192q26 0 45 -19t19 -45z " />
+<glyph unicode="&#xf07a;" horiz-adv-x="1664" d="M640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5 l-1044 -122q1 -7 4.5 -21.5t6 -26.5t2.5 -22q0 -16 -24 -64h920q26 0 45 -19t19 -45t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 14 11 39.5t29.5 59.5t20.5 38l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t20 -15.5t13 -24.5t7.5 -26.5 t5.5 -29.5t4.5 -25.5h1201q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf07b;" horiz-adv-x="1664" d="M1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf07c;" horiz-adv-x="1920" d="M1879 584q0 -31 -31 -66l-336 -396q-43 -51 -120.5 -86.5t-143.5 -35.5h-1088q-34 0 -60.5 13t-26.5 43q0 31 31 66l336 396q43 51 120.5 86.5t143.5 35.5h1088q34 0 60.5 -13t26.5 -43zM1536 928v-160h-832q-94 0 -197 -47.5t-164 -119.5l-337 -396l-5 -6q0 4 -0.5 12.5 t-0.5 12.5v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf07d;" horiz-adv-x="768" d="M704 1216q0 -26 -19 -45t-45 -19h-128v-1024h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v1024h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45z" />
+<glyph unicode="&#xf07e;" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-1024v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h1024v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" />
+<glyph unicode="&#xf080;" horiz-adv-x="2048" d="M640 640v-512h-256v512h256zM1024 1152v-1024h-256v1024h256zM2048 0v-128h-2048v1536h128v-1408h1920zM1408 896v-768h-256v768h256zM1792 1280v-1152h-256v1152h256z" />
+<glyph unicode="&#xf081;" d="M1280 926q-56 -25 -121 -34q68 40 93 117q-65 -38 -134 -51q-61 66 -153 66q-87 0 -148.5 -61.5t-61.5 -148.5q0 -29 5 -48q-129 7 -242 65t-192 155q-29 -50 -29 -106q0 -114 91 -175q-47 1 -100 26v-2q0 -75 50 -133.5t123 -72.5q-29 -8 -51 -8q-13 0 -39 4 q21 -63 74.5 -104t121.5 -42q-116 -90 -261 -90q-26 0 -50 3q148 -94 322 -94q112 0 210 35.5t168 95t120.5 137t75 162t24.5 168.5q0 18 -1 27q63 45 105 109zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5 t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf082;" d="M1536 160q0 -119 -84.5 -203.5t-203.5 -84.5h-192v608h203l30 224h-233v143q0 54 28 83t96 29l132 1v207q-96 9 -180 9q-136 0 -218 -80.5t-82 -225.5v-166h-224v-224h224v-608h-544q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960 q119 0 203.5 -84.5t84.5 -203.5v-960z" />
+<glyph unicode="&#xf083;" horiz-adv-x="1792" d="M928 704q0 14 -9 23t-23 9q-66 0 -113 -47t-47 -113q0 -14 9 -23t23 -9t23 9t9 23q0 40 28 68t68 28q14 0 23 9t9 23zM1152 574q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM128 0h1536v128h-1536v-128zM1280 574q0 159 -112.5 271.5 t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM256 1216h384v128h-384v-128zM128 1024h1536v118v138h-828l-64 -128h-644v-128zM1792 1280v-1280q0 -53 -37.5 -90.5t-90.5 -37.5h-1536q-53 0 -90.5 37.5t-37.5 90.5v1280 q0 53 37.5 90.5t90.5 37.5h1536q53 0 90.5 -37.5t37.5 -90.5z" />
+<glyph unicode="&#xf084;" horiz-adv-x="1792" d="M832 1024q0 80 -56 136t-136 56t-136 -56t-56 -136q0 -42 19 -83q-41 19 -83 19q-80 0 -136 -56t-56 -136t56 -136t136 -56t136 56t56 136q0 42 -19 83q41 -19 83 -19q80 0 136 56t56 136zM1683 320q0 -17 -49 -66t-66 -49q-9 0 -28.5 16t-36.5 33t-38.5 40t-24.5 26 l-96 -96l220 -220q28 -28 28 -68q0 -42 -39 -81t-81 -39q-40 0 -68 28l-671 671q-176 -131 -365 -131q-163 0 -265.5 102.5t-102.5 265.5q0 160 95 313t248 248t313 95q163 0 265.5 -102.5t102.5 -265.5q0 -189 -131 -365l355 -355l96 96q-3 3 -26 24.5t-40 38.5t-33 36.5 t-16 28.5q0 17 49 66t66 49q13 0 23 -10q6 -6 46 -44.5t82 -79.5t86.5 -86t73 -78t28.5 -41z" />
+<glyph unicode="&#xf085;" horiz-adv-x="1920" d="M896 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1664 128q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1152q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1280 731v-185q0 -10 -7 -19.5t-16 -10.5l-155 -24q-11 -35 -32 -76q34 -48 90 -115q7 -10 7 -20q0 -12 -7 -19q-23 -30 -82.5 -89.5t-78.5 -59.5q-11 0 -21 7l-115 90q-37 -19 -77 -31q-11 -108 -23 -155q-7 -24 -30 -24h-186q-11 0 -20 7.5t-10 17.5 l-23 153q-34 10 -75 31l-118 -89q-7 -7 -20 -7q-11 0 -21 8q-144 133 -144 160q0 9 7 19q10 14 41 53t47 61q-23 44 -35 82l-152 24q-10 1 -17 9.5t-7 19.5v185q0 10 7 19.5t16 10.5l155 24q11 35 32 76q-34 48 -90 115q-7 11 -7 20q0 12 7 20q22 30 82 89t79 59q11 0 21 -7 l115 -90q34 18 77 32q11 108 23 154q7 24 30 24h186q11 0 20 -7.5t10 -17.5l23 -153q34 -10 75 -31l118 89q8 7 20 7q11 0 21 -8q144 -133 144 -160q0 -9 -7 -19q-12 -16 -42 -54t-45 -60q23 -48 34 -82l152 -23q10 -2 17 -10.5t7 -19.5zM1920 198v-140q0 -16 -149 -31 q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20 t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31zM1920 1222v-140q0 -16 -149 -31q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68 q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70 q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31z" />
+<glyph unicode="&#xf086;" horiz-adv-x="1792" d="M1408 768q0 -139 -94 -257t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224 q0 139 94 257t256.5 186.5t353.5 68.5t353.5 -68.5t256.5 -186.5t94 -257zM1792 512q0 -120 -71 -224.5t-195 -176.5q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7 q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230z" />
+<glyph unicode="&#xf087;" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 768q0 51 -39 89.5t-89 38.5h-352q0 58 48 159.5t48 160.5q0 98 -32 145t-128 47q-26 -26 -38 -85t-30.5 -125.5t-59.5 -109.5q-22 -23 -77 -91q-4 -5 -23 -30t-31.5 -41t-34.5 -42.5 t-40 -44t-38.5 -35.5t-40 -27t-35.5 -9h-32v-640h32q13 0 31.5 -3t33 -6.5t38 -11t35 -11.5t35.5 -12.5t29 -10.5q211 -73 342 -73h121q192 0 192 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5q32 1 53.5 47t21.5 81zM1536 769 q0 -89 -49 -163q9 -33 9 -69q0 -77 -38 -144q3 -21 3 -43q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5h-36h-93q-96 0 -189.5 22.5t-216.5 65.5q-116 40 -138 40h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h274q36 24 137 155q58 75 107 128 q24 25 35.5 85.5t30.5 126.5t62 108q39 37 90 37q84 0 151 -32.5t102 -101.5t35 -186q0 -93 -48 -192h176q104 0 180 -76t76 -179z" />
+<glyph unicode="&#xf088;" d="M256 1088q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 512q0 35 -21.5 81t-53.5 47q15 17 25 47.5t10 55.5q0 69 -53 119q18 32 18 69t-17.5 73.5t-47.5 52.5q5 30 5 56q0 85 -49 126t-136 41h-128q-131 0 -342 -73q-5 -2 -29 -10.5 t-35.5 -12.5t-35 -11.5t-38 -11t-33 -6.5t-31.5 -3h-32v-640h32q16 0 35.5 -9t40 -27t38.5 -35.5t40 -44t34.5 -42.5t31.5 -41t23 -30q55 -68 77 -91q41 -43 59.5 -109.5t30.5 -125.5t38 -85q96 0 128 47t32 145q0 59 -48 160.5t-48 159.5h352q50 0 89 38.5t39 89.5z M1536 511q0 -103 -76 -179t-180 -76h-176q48 -99 48 -192q0 -118 -35 -186q-35 -69 -102 -101.5t-151 -32.5q-51 0 -90 37q-34 33 -54 82t-25.5 90.5t-17.5 84.5t-31 64q-48 50 -107 127q-101 131 -137 155h-274q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5 h288q22 0 138 40q128 44 223 66t200 22h112q140 0 226.5 -79t85.5 -216v-5q60 -77 60 -178q0 -22 -3 -43q38 -67 38 -144q0 -36 -9 -69q49 -74 49 -163z" />
+<glyph unicode="&#xf089;" horiz-adv-x="896" d="M832 1504v-1339l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41z" />
+<glyph unicode="&#xf08a;" horiz-adv-x="1792" d="M1664 940q0 81 -21.5 143t-55 98.5t-81.5 59.5t-94 31t-98 8t-112 -25.5t-110.5 -64t-86.5 -72t-60 -61.5q-18 -22 -49 -22t-49 22q-24 28 -60 61.5t-86.5 72t-110.5 64t-112 25.5t-98 -8t-94 -31t-81.5 -59.5t-55 -98.5t-21.5 -143q0 -168 187 -355l581 -560l580 559 q188 188 188 356zM1792 940q0 -221 -229 -450l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5 q224 0 351 -124t127 -344z" />
+<glyph unicode="&#xf08b;" horiz-adv-x="1664" d="M640 96q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h320q13 0 22.5 -9.5t9.5 -22.5q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-66 0 -113 -47t-47 -113v-704 q0 -66 47 -113t113 -47h288h11h13t11.5 -1t11.5 -3t8 -5.5t7 -9t2 -13.5zM1568 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45z" />
+<glyph unicode="&#xf08c;" d="M237 122h231v694h-231v-694zM483 1030q-1 52 -36 86t-93 34t-94.5 -34t-36.5 -86q0 -51 35.5 -85.5t92.5 -34.5h1q59 0 95 34.5t36 85.5zM1068 122h231v398q0 154 -73 233t-193 79q-136 0 -209 -117h2v101h-231q3 -66 0 -694h231v388q0 38 7 56q15 35 45 59.5t74 24.5 q116 0 116 -157v-371zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf08d;" horiz-adv-x="1152" d="M480 672v448q0 14 -9 23t-23 9t-23 -9t-9 -23v-448q0 -14 9 -23t23 -9t23 9t9 23zM1152 320q0 -26 -19 -45t-45 -19h-429l-51 -483q-2 -12 -10.5 -20.5t-20.5 -8.5h-1q-27 0 -32 27l-76 485h-404q-26 0 -45 19t-19 45q0 123 78.5 221.5t177.5 98.5v512q-52 0 -90 38 t-38 90t38 90t90 38h640q52 0 90 -38t38 -90t-38 -90t-90 -38v-512q99 0 177.5 -98.5t78.5 -221.5z" />
+<glyph unicode="&#xf08e;" horiz-adv-x="1792" d="M1408 608v-320q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v320 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1792 1472v-512q0 -26 -19 -45t-45 -19t-45 19l-176 176l-652 -652q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l652 652l-176 176q-19 19 -19 45t19 45t45 19h512q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf090;" d="M1184 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45zM1536 992v-704q0 -119 -84.5 -203.5t-203.5 -84.5h-320q-13 0 -22.5 9.5t-9.5 22.5 q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q66 0 113 47t47 113v704q0 66 -47 113t-113 47h-288h-11h-13t-11.5 1t-11.5 3t-8 5.5t-7 9t-2 13.5q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf091;" horiz-adv-x="1664" d="M458 653q-74 162 -74 371h-256v-96q0 -78 94.5 -162t235.5 -113zM1536 928v96h-256q0 -209 -74 -371q141 29 235.5 113t94.5 162zM1664 1056v-128q0 -71 -41.5 -143t-112 -130t-173 -97.5t-215.5 -44.5q-42 -54 -95 -95q-38 -34 -52.5 -72.5t-14.5 -89.5q0 -54 30.5 -91 t97.5 -37q75 0 133.5 -45.5t58.5 -114.5v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 69 58.5 114.5t133.5 45.5q67 0 97.5 37t30.5 91q0 51 -14.5 89.5t-52.5 72.5q-53 41 -95 95q-113 5 -215.5 44.5t-173 97.5t-112 130t-41.5 143v128q0 40 28 68t68 28h288v96 q0 66 47 113t113 47h576q66 0 113 -47t47 -113v-96h288q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf092;" d="M394 184q-8 -9 -20 3q-13 11 -4 19q8 9 20 -3q12 -11 4 -19zM352 245q9 -12 0 -19q-8 -6 -17 7t0 18q9 7 17 -6zM291 305q-5 -7 -13 -2q-10 5 -7 12q3 5 13 2q10 -5 7 -12zM322 271q-6 -7 -16 3q-9 11 -2 16q6 6 16 -3q9 -11 2 -16zM451 159q-4 -12 -19 -6q-17 4 -13 15 t19 7q16 -5 13 -16zM514 154q0 -11 -16 -11q-17 -2 -17 11q0 11 16 11q17 2 17 -11zM572 164q2 -10 -14 -14t-18 8t14 15q16 2 18 -9zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-224q-16 0 -24.5 1t-19.5 5t-16 14.5t-5 27.5v239q0 97 -52 142q57 6 102.5 18t94 39 t81 66.5t53 105t20.5 150.5q0 121 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-86 13.5q-44 -113 -7 -204q-79 -85 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-40 -36 -49 -103 q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -103t0.5 -68q0 -22 -11 -33.5t-22 -13t-33 -1.5 h-224q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf093;" horiz-adv-x="1664" d="M1280 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 288v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h427q21 -56 70.5 -92 t110.5 -36h256q61 0 110.5 36t70.5 92h427q40 0 68 -28t28 -68zM1339 936q-17 -40 -59 -40h-256v-448q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v448h-256q-42 0 -59 40q-17 39 14 69l448 448q18 19 45 19t45 -19l448 -448q31 -30 14 -69z" />
+<glyph unicode="&#xf094;" d="M1407 710q0 44 -7 113.5t-18 96.5q-12 30 -17 44t-9 36.5t-4 48.5q0 23 5 68.5t5 67.5q0 37 -10 55q-4 1 -13 1q-19 0 -58 -4.5t-59 -4.5q-60 0 -176 24t-175 24q-43 0 -94.5 -11.5t-85 -23.5t-89.5 -34q-137 -54 -202 -103q-96 -73 -159.5 -189.5t-88 -236t-24.5 -248.5 q0 -40 12.5 -120t12.5 -121q0 -23 -11 -66.5t-11 -65.5t12 -36.5t34 -14.5q24 0 72.5 11t73.5 11q57 0 169.5 -15.5t169.5 -15.5q181 0 284 36q129 45 235.5 152.5t166 245.5t59.5 275zM1535 712q0 -165 -70 -327.5t-196 -288t-281 -180.5q-124 -44 -326 -44 q-57 0 -170 14.5t-169 14.5q-24 0 -72.5 -14.5t-73.5 -14.5q-73 0 -123.5 55.5t-50.5 128.5q0 24 11 68t11 67q0 40 -12.5 120.5t-12.5 121.5q0 111 18 217.5t54.5 209.5t100.5 194t150 156q78 59 232 120q194 78 316 78q60 0 175.5 -24t173.5 -24q19 0 57 5t58 5 q81 0 118 -50.5t37 -134.5q0 -23 -5 -68t-5 -68q0 -10 1 -18.5t3 -17t4 -13.5t6.5 -16t6.5 -17q16 -40 25 -118.5t9 -136.5z" />
+<glyph unicode="&#xf095;" horiz-adv-x="1408" d="M1408 296q0 -27 -10 -70.5t-21 -68.5q-21 -50 -122 -106q-94 -51 -186 -51q-27 0 -52.5 3.5t-57.5 12.5t-47.5 14.5t-55.5 20.5t-49 18q-98 35 -175 83q-128 79 -264.5 215.5t-215.5 264.5q-48 77 -83 175q-3 9 -18 49t-20.5 55.5t-14.5 47.5t-12.5 57.5t-3.5 52.5 q0 92 51 186q56 101 106 122q25 11 68.5 21t70.5 10q14 0 21 -3q18 -6 53 -76q11 -19 30 -54t35 -63.5t31 -53.5q3 -4 17.5 -25t21.5 -35.5t7 -28.5q0 -20 -28.5 -50t-62 -55t-62 -53t-28.5 -46q0 -9 5 -22.5t8.5 -20.5t14 -24t11.5 -19q76 -137 174 -235t235 -174 q2 -1 19 -11.5t24 -14t20.5 -8.5t22.5 -5q18 0 46 28.5t53 62t55 62t50 28.5q14 0 28.5 -7t35.5 -21.5t25 -17.5q25 -15 53.5 -31t63.5 -35t54 -30q70 -35 76 -53q3 -7 3 -21z" />
+<glyph unicode="&#xf096;" horiz-adv-x="1408" d="M1120 1280h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v832q0 66 -47 113t-113 47zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf097;" horiz-adv-x="1280" d="M1152 1280h-1024v-1242l423 406l89 85l89 -85l423 -406v1242zM1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289 q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
+<glyph unicode="&#xf098;" d="M1280 343q0 11 -2 16q-3 8 -38.5 29.5t-88.5 49.5l-53 29q-5 3 -19 13t-25 15t-21 5q-18 0 -47 -32.5t-57 -65.5t-44 -33q-7 0 -16.5 3.5t-15.5 6.5t-17 9.5t-14 8.5q-99 55 -170.5 126.5t-126.5 170.5q-2 3 -8.5 14t-9.5 17t-6.5 15.5t-3.5 16.5q0 13 20.5 33.5t45 38.5 t45 39.5t20.5 36.5q0 10 -5 21t-15 25t-13 19q-3 6 -15 28.5t-25 45.5t-26.5 47.5t-25 40.5t-16.5 18t-16 2q-48 0 -101 -22q-46 -21 -80 -94.5t-34 -130.5q0 -16 2.5 -34t5 -30.5t9 -33t10 -29.5t12.5 -33t11 -30q60 -164 216.5 -320.5t320.5 -216.5q6 -2 30 -11t33 -12.5 t29.5 -10t33 -9t30.5 -5t34 -2.5q57 0 130.5 34t94.5 80q22 53 22 101zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf099;" horiz-adv-x="1664" d="M1620 1128q-67 -98 -162 -167q1 -14 1 -42q0 -130 -38 -259.5t-115.5 -248.5t-184.5 -210.5t-258 -146t-323 -54.5q-271 0 -496 145q35 -4 78 -4q225 0 401 138q-105 2 -188 64.5t-114 159.5q33 -5 61 -5q43 0 85 11q-112 23 -185.5 111.5t-73.5 205.5v4q68 -38 146 -41 q-66 44 -105 115t-39 154q0 88 44 163q121 -149 294.5 -238.5t371.5 -99.5q-8 38 -8 74q0 134 94.5 228.5t228.5 94.5q140 0 236 -102q109 21 205 78q-37 -115 -142 -178q93 10 186 50z" />
+<glyph unicode="&#xf09a;" horiz-adv-x="1024" d="M959 1524v-264h-157q-86 0 -116 -36t-30 -108v-189h293l-39 -296h-254v-759h-306v759h-255v296h255v218q0 186 104 288.5t277 102.5q147 0 228 -12z" />
+<glyph unicode="&#xf09b;" d="M1536 640q0 -251 -146.5 -451.5t-378.5 -277.5q-27 -5 -39.5 7t-12.5 30v211q0 97 -52 142q57 6 102.5 18t94 39t81 66.5t53 105t20.5 150.5q0 121 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-86 13.5 q-44 -113 -7 -204q-79 -85 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-40 -36 -49 -103q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23 q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -89t0.5 -54q0 -18 -13 -30t-40 -7q-232 77 -378.5 277.5t-146.5 451.5q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf09c;" horiz-adv-x="1664" d="M1664 960v-256q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-192h96q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h672v192q0 185 131.5 316.5t316.5 131.5 t316.5 -131.5t131.5 -316.5z" />
+<glyph unicode="&#xf09d;" horiz-adv-x="1920" d="M1760 1408q66 0 113 -47t47 -113v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600zM160 1280q-13 0 -22.5 -9.5t-9.5 -22.5v-224h1664v224q0 13 -9.5 22.5t-22.5 9.5h-1600zM1760 0q13 0 22.5 9.5t9.5 22.5v608h-1664v-608 q0 -13 9.5 -22.5t22.5 -9.5h1600zM256 128v128h256v-128h-256zM640 128v128h384v-128h-384z" />
+<glyph unicode="&#xf09e;" horiz-adv-x="1408" d="M384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 69q2 -28 -17 -48q-18 -21 -47 -21h-135q-25 0 -43 16.5t-20 41.5q-22 229 -184.5 391.5t-391.5 184.5q-25 2 -41.5 20t-16.5 43v135q0 29 21 47q17 17 43 17h5q160 -13 306 -80.5 t259 -181.5q114 -113 181.5 -259t80.5 -306zM1408 67q2 -27 -18 -47q-18 -20 -46 -20h-143q-26 0 -44.5 17.5t-19.5 42.5q-12 215 -101 408.5t-231.5 336t-336 231.5t-408.5 102q-25 1 -42.5 19.5t-17.5 43.5v143q0 28 20 46q18 18 44 18h3q262 -13 501.5 -120t425.5 -294 q187 -186 294 -425.5t120 -501.5z" />
+<glyph unicode="&#xf0a0;" d="M1040 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1296 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1408 160v320q0 13 -9.5 22.5t-22.5 9.5 h-1216q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h1216q13 0 22.5 9.5t9.5 22.5zM178 640h1180l-157 482q-4 13 -16 21.5t-26 8.5h-782q-14 0 -26 -8.5t-16 -21.5zM1536 480v-320q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113v320q0 25 16 75 l197 606q17 53 63 86t101 33h782q55 0 101 -33t63 -86l197 -606q16 -50 16 -75z" />
+<glyph unicode="&#xf0a1;" horiz-adv-x="1792" d="M1664 896q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5v-384q0 -52 -38 -90t-90 -38q-417 347 -812 380q-58 -19 -91 -66t-31 -100.5t40 -92.5q-20 -33 -23 -65.5t6 -58t33.5 -55t48 -50t61.5 -50.5q-29 -58 -111.5 -83t-168.5 -11.5t-132 55.5q-7 23 -29.5 87.5 t-32 94.5t-23 89t-15 101t3.5 98.5t22 110.5h-122q-66 0 -113 47t-47 113v192q0 66 47 113t113 47h480q435 0 896 384q52 0 90 -38t38 -90v-384zM1536 292v954q-394 -302 -768 -343v-270q377 -42 768 -341z" />
+<glyph unicode="&#xf0a2;" horiz-adv-x="1792" d="M912 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM246 128h1300q-266 300 -266 832q0 51 -24 105t-69 103t-121.5 80.5t-169.5 31.5t-169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -532 -266 -832z M1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q190 -28 307 -158.5 t117 -282.5q0 -139 19.5 -260t50 -206t74.5 -158.5t85 -119.5t91 -88z" />
+<glyph unicode="&#xf0a3;" d="M1376 640l138 -135q30 -28 20 -70q-12 -41 -52 -51l-188 -48l53 -186q12 -41 -19 -70q-29 -31 -70 -19l-186 53l-48 -188q-10 -40 -51 -52q-12 -2 -19 -2q-31 0 -51 22l-135 138l-135 -138q-28 -30 -70 -20q-41 11 -51 52l-48 188l-186 -53q-41 -12 -70 19q-31 29 -19 70 l53 186l-188 48q-40 10 -52 51q-10 42 20 70l138 135l-138 135q-30 28 -20 70q12 41 52 51l188 48l-53 186q-12 41 19 70q29 31 70 19l186 -53l48 188q10 41 51 51q41 12 70 -19l135 -139l135 139q29 30 70 19q41 -10 51 -51l48 -188l186 53q41 12 70 -19q31 -29 19 -70 l-53 -186l188 -48q40 -10 52 -51q10 -42 -20 -70z" />
+<glyph unicode="&#xf0a4;" horiz-adv-x="1792" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 768q0 51 -39 89.5t-89 38.5h-576q0 20 15 48.5t33 55t33 68t15 84.5q0 67 -44.5 97.5t-115.5 30.5q-24 0 -90 -139q-24 -44 -37 -65q-40 -64 -112 -145q-71 -81 -101 -106 q-69 -57 -140 -57h-32v-640h32q72 0 167 -32t193.5 -64t179.5 -32q189 0 189 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5h331q52 0 90 38t38 90zM1792 769q0 -105 -75.5 -181t-180.5 -76h-169q-4 -62 -37 -119q3 -21 3 -43 q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5q-133 0 -322 69q-164 59 -223 59h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h288q10 0 21.5 4.5t23.5 14t22.5 18t24 22.5t20.5 21.5t19 21.5t14 17q65 74 100 129q13 21 33 62t37 72t40.5 63t55 49.5 t69.5 17.5q125 0 206.5 -67t81.5 -189q0 -68 -22 -128h374q104 0 180 -76t76 -179z" />
+<glyph unicode="&#xf0a5;" horiz-adv-x="1792" d="M1376 128h32v640h-32q-35 0 -67.5 12t-62.5 37t-50 46t-49 54q-2 3 -3.5 4.5t-4 4.5t-4.5 5q-72 81 -112 145q-14 22 -38 68q-1 3 -10.5 22.5t-18.5 36t-20 35.5t-21.5 30.5t-18.5 11.5q-71 0 -115.5 -30.5t-44.5 -97.5q0 -43 15 -84.5t33 -68t33 -55t15 -48.5h-576 q-50 0 -89 -38.5t-39 -89.5q0 -52 38 -90t90 -38h331q-15 -17 -25 -47.5t-10 -55.5q0 -69 53 -119q-18 -32 -18 -69t17.5 -73.5t47.5 -52.5q-4 -24 -4 -56q0 -85 48.5 -126t135.5 -41q84 0 183 32t194 64t167 32zM1664 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45 t45 -19t45 19t19 45zM1792 768v-640q0 -53 -37.5 -90.5t-90.5 -37.5h-288q-59 0 -223 -59q-190 -69 -317 -69q-142 0 -230 77.5t-87 217.5l1 5q-61 76 -61 178q0 22 3 43q-33 57 -37 119h-169q-105 0 -180.5 76t-75.5 181q0 103 76 179t180 76h374q-22 60 -22 128 q0 122 81.5 189t206.5 67q38 0 69.5 -17.5t55 -49.5t40.5 -63t37 -72t33 -62q35 -55 100 -129q2 -3 14 -17t19 -21.5t20.5 -21.5t24 -22.5t22.5 -18t23.5 -14t21.5 -4.5h288q53 0 90.5 -37.5t37.5 -90.5z" />
+<glyph unicode="&#xf0a6;" d="M1280 -64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 700q0 189 -167 189q-26 0 -56 -5q-16 30 -52.5 47.5t-73.5 17.5t-69 -18q-50 53 -119 53q-25 0 -55.5 -10t-47.5 -25v331q0 52 -38 90t-90 38q-51 0 -89.5 -39t-38.5 -89v-576 q-20 0 -48.5 15t-55 33t-68 33t-84.5 15q-67 0 -97.5 -44.5t-30.5 -115.5q0 -24 139 -90q44 -24 65 -37q64 -40 145 -112q81 -71 106 -101q57 -69 57 -140v-32h640v32q0 72 32 167t64 193.5t32 179.5zM1536 705q0 -133 -69 -322q-59 -164 -59 -223v-288q0 -53 -37.5 -90.5 t-90.5 -37.5h-640q-53 0 -90.5 37.5t-37.5 90.5v288q0 10 -4.5 21.5t-14 23.5t-18 22.5t-22.5 24t-21.5 20.5t-21.5 19t-17 14q-74 65 -129 100q-21 13 -62 33t-72 37t-63 40.5t-49.5 55t-17.5 69.5q0 125 67 206.5t189 81.5q68 0 128 -22v374q0 104 76 180t179 76 q105 0 181 -75.5t76 -180.5v-169q62 -4 119 -37q21 3 43 3q101 0 178 -60q139 1 219.5 -85t80.5 -227z" />
+<glyph unicode="&#xf0a7;" d="M1408 576q0 84 -32 183t-64 194t-32 167v32h-640v-32q0 -35 -12 -67.5t-37 -62.5t-46 -50t-54 -49q-9 -8 -14 -12q-81 -72 -145 -112q-22 -14 -68 -38q-3 -1 -22.5 -10.5t-36 -18.5t-35.5 -20t-30.5 -21.5t-11.5 -18.5q0 -71 30.5 -115.5t97.5 -44.5q43 0 84.5 15t68 33 t55 33t48.5 15v-576q0 -50 38.5 -89t89.5 -39q52 0 90 38t38 90v331q46 -35 103 -35q69 0 119 53q32 -18 69 -18t73.5 17.5t52.5 47.5q24 -4 56 -4q85 0 126 48.5t41 135.5zM1280 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 580 q0 -142 -77.5 -230t-217.5 -87l-5 1q-76 -61 -178 -61q-22 0 -43 3q-54 -30 -119 -37v-169q0 -105 -76 -180.5t-181 -75.5q-103 0 -179 76t-76 180v374q-54 -22 -128 -22q-121 0 -188.5 81.5t-67.5 206.5q0 38 17.5 69.5t49.5 55t63 40.5t72 37t62 33q55 35 129 100 q3 2 17 14t21.5 19t21.5 20.5t22.5 24t18 22.5t14 23.5t4.5 21.5v288q0 53 37.5 90.5t90.5 37.5h640q53 0 90.5 -37.5t37.5 -90.5v-288q0 -59 59 -223q69 -190 69 -317z" />
+<glyph unicode="&#xf0a8;" d="M1280 576v128q0 26 -19 45t-45 19h-502l189 189q19 19 19 45t-19 45l-91 91q-18 18 -45 18t-45 -18l-362 -362l-91 -91q-18 -18 -18 -45t18 -45l91 -91l362 -362q18 -18 45 -18t45 18l91 91q18 18 18 45t-18 45l-189 189h502q26 0 45 19t19 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0a9;" d="M1285 640q0 27 -18 45l-91 91l-362 362q-18 18 -45 18t-45 -18l-91 -91q-18 -18 -18 -45t18 -45l189 -189h-502q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h502l-189 -189q-19 -19 -19 -45t19 -45l91 -91q18 -18 45 -18t45 18l362 362l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0aa;" d="M1284 641q0 27 -18 45l-362 362l-91 91q-18 18 -45 18t-45 -18l-91 -91l-362 -362q-18 -18 -18 -45t18 -45l91 -91q18 -18 45 -18t45 18l189 189v-502q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v502l189 -189q19 -19 45 -19t45 19l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0ab;" d="M1284 639q0 27 -18 45l-91 91q-18 18 -45 18t-45 -18l-189 -189v502q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-502l-189 189q-19 19 -45 19t-45 -19l-91 -91q-18 -18 -18 -45t18 -45l362 -362l91 -91q18 -18 45 -18t45 18l91 91l362 362q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0ac;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1042 887q-2 -1 -9.5 -9.5t-13.5 -9.5q2 0 4.5 5t5 11t3.5 7q6 7 22 15q14 6 52 12q34 8 51 -11 q-2 2 9.5 13t14.5 12q3 2 15 4.5t15 7.5l2 22q-12 -1 -17.5 7t-6.5 21q0 -2 -6 -8q0 7 -4.5 8t-11.5 -1t-9 -1q-10 3 -15 7.5t-8 16.5t-4 15q-2 5 -9.5 10.5t-9.5 10.5q-1 2 -2.5 5.5t-3 6.5t-4 5.5t-5.5 2.5t-7 -5t-7.5 -10t-4.5 -5q-3 2 -6 1.5t-4.5 -1t-4.5 -3t-5 -3.5 q-3 -2 -8.5 -3t-8.5 -2q15 5 -1 11q-10 4 -16 3q9 4 7.5 12t-8.5 14h5q-1 4 -8.5 8.5t-17.5 8.5t-13 6q-8 5 -34 9.5t-33 0.5q-5 -6 -4.5 -10.5t4 -14t3.5 -12.5q1 -6 -5.5 -13t-6.5 -12q0 -7 14 -15.5t10 -21.5q-3 -8 -16 -16t-16 -12q-5 -8 -1.5 -18.5t10.5 -16.5 q2 -2 1.5 -4t-3.5 -4.5t-5.5 -4t-6.5 -3.5l-3 -2q-11 -5 -20.5 6t-13.5 26q-7 25 -16 30q-23 8 -29 -1q-5 13 -41 26q-25 9 -58 4q6 1 0 15q-7 15 -19 12q3 6 4 17.5t1 13.5q3 13 12 23q1 1 7 8.5t9.5 13.5t0.5 6q35 -4 50 11q5 5 11.5 17t10.5 17q9 6 14 5.5t14.5 -5.5 t14.5 -5q14 -1 15.5 11t-7.5 20q12 -1 3 17q-5 7 -8 9q-12 4 -27 -5q-8 -4 2 -8q-1 1 -9.5 -10.5t-16.5 -17.5t-16 5q-1 1 -5.5 13.5t-9.5 13.5q-8 0 -16 -15q3 8 -11 15t-24 8q19 12 -8 27q-7 4 -20.5 5t-19.5 -4q-5 -7 -5.5 -11.5t5 -8t10.5 -5.5t11.5 -4t8.5 -3 q14 -10 8 -14q-2 -1 -8.5 -3.5t-11.5 -4.5t-6 -4q-3 -4 0 -14t-2 -14q-5 5 -9 17.5t-7 16.5q7 -9 -25 -6l-10 1q-4 0 -16 -2t-20.5 -1t-13.5 8q-4 8 0 20q1 4 4 2q-4 3 -11 9.5t-10 8.5q-46 -15 -94 -41q6 -1 12 1q5 2 13 6.5t10 5.5q34 14 42 7l5 5q14 -16 20 -25 q-7 4 -30 1q-20 -6 -22 -12q7 -12 5 -18q-4 3 -11.5 10t-14.5 11t-15 5q-16 0 -22 -1q-146 -80 -235 -222q7 -7 12 -8q4 -1 5 -9t2.5 -11t11.5 3q9 -8 3 -19q1 1 44 -27q19 -17 21 -21q3 -11 -10 -18q-1 2 -9 9t-9 4q-3 -5 0.5 -18.5t10.5 -12.5q-7 0 -9.5 -16t-2.5 -35.5 t-1 -23.5l2 -1q-3 -12 5.5 -34.5t21.5 -19.5q-13 -3 20 -43q6 -8 8 -9q3 -2 12 -7.5t15 -10t10 -10.5q4 -5 10 -22.5t14 -23.5q-2 -6 9.5 -20t10.5 -23q-1 0 -2.5 -1t-2.5 -1q3 -7 15.5 -14t15.5 -13q1 -3 2 -10t3 -11t8 -2q2 20 -24 62q-15 25 -17 29q-3 5 -5.5 15.5 t-4.5 14.5q2 0 6 -1.5t8.5 -3.5t7.5 -4t2 -3q-3 -7 2 -17.5t12 -18.5t17 -19t12 -13q6 -6 14 -19.5t0 -13.5q9 0 20 -10t17 -20q5 -8 8 -26t5 -24q2 -7 8.5 -13.5t12.5 -9.5l16 -8t13 -7q5 -2 18.5 -10.5t21.5 -11.5q10 -4 16 -4t14.5 2.5t13.5 3.5q15 2 29 -15t21 -21 q36 -19 55 -11q-2 -1 0.5 -7.5t8 -15.5t9 -14.5t5.5 -8.5q5 -6 18 -15t18 -15q6 4 7 9q-3 -8 7 -20t18 -10q14 3 14 32q-31 -15 -49 18q0 1 -2.5 5.5t-4 8.5t-2.5 8.5t0 7.5t5 3q9 0 10 3.5t-2 12.5t-4 13q-1 8 -11 20t-12 15q-5 -9 -16 -8t-16 9q0 -1 -1.5 -5.5t-1.5 -6.5 q-13 0 -15 1q1 3 2.5 17.5t3.5 22.5q1 4 5.5 12t7.5 14.5t4 12.5t-4.5 9.5t-17.5 2.5q-19 -1 -26 -20q-1 -3 -3 -10.5t-5 -11.5t-9 -7q-7 -3 -24 -2t-24 5q-13 8 -22.5 29t-9.5 37q0 10 2.5 26.5t3 25t-5.5 24.5q3 2 9 9.5t10 10.5q2 1 4.5 1.5t4.5 0t4 1.5t3 6q-1 1 -4 3 q-3 3 -4 3q7 -3 28.5 1.5t27.5 -1.5q15 -11 22 2q0 1 -2.5 9.5t-0.5 13.5q5 -27 29 -9q3 -3 15.5 -5t17.5 -5q3 -2 7 -5.5t5.5 -4.5t5 0.5t8.5 6.5q10 -14 12 -24q11 -40 19 -44q7 -3 11 -2t4.5 9.5t0 14t-1.5 12.5l-1 8v18l-1 8q-15 3 -18.5 12t1.5 18.5t15 18.5q1 1 8 3.5 t15.5 6.5t12.5 8q21 19 15 35q7 0 11 9q-1 0 -5 3t-7.5 5t-4.5 2q9 5 2 16q5 3 7.5 11t7.5 10q9 -12 21 -2q7 8 1 16q5 7 20.5 10.5t18.5 9.5q7 -2 8 2t1 12t3 12q4 5 15 9t13 5l17 11q3 4 0 4q18 -2 31 11q10 11 -6 20q3 6 -3 9.5t-15 5.5q3 1 11.5 0.5t10.5 1.5 q15 10 -7 16q-17 5 -43 -12zM879 10q206 36 351 189q-3 3 -12.5 4.5t-12.5 3.5q-18 7 -24 8q1 7 -2.5 13t-8 9t-12.5 8t-11 7q-2 2 -7 6t-7 5.5t-7.5 4.5t-8.5 2t-10 -1l-3 -1q-3 -1 -5.5 -2.5t-5.5 -3t-4 -3t0 -2.5q-21 17 -36 22q-5 1 -11 5.5t-10.5 7t-10 1.5t-11.5 -7 q-5 -5 -6 -15t-2 -13q-7 5 0 17.5t2 18.5q-3 6 -10.5 4.5t-12 -4.5t-11.5 -8.5t-9 -6.5t-8.5 -5.5t-8.5 -7.5q-3 -4 -6 -12t-5 -11q-2 4 -11.5 6.5t-9.5 5.5q2 -10 4 -35t5 -38q7 -31 -12 -48q-27 -25 -29 -40q-4 -22 12 -26q0 -7 -8 -20.5t-7 -21.5q0 -6 2 -16z" />
+<glyph unicode="&#xf0ad;" horiz-adv-x="1664" d="M384 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1028 484l-682 -682q-37 -37 -90 -37q-52 0 -91 37l-106 108q-38 36 -38 90q0 53 38 91l681 681q39 -98 114.5 -173.5t173.5 -114.5zM1662 919q0 -39 -23 -106q-47 -134 -164.5 -217.5 t-258.5 -83.5q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q58 0 121.5 -16.5t107.5 -46.5q16 -11 16 -28t-16 -28l-293 -169v-224l193 -107q5 3 79 48.5t135.5 81t70.5 35.5q15 0 23.5 -10t8.5 -25z" />
+<glyph unicode="&#xf0ae;" horiz-adv-x="1792" d="M1024 128h640v128h-640v-128zM640 640h1024v128h-1024v-128zM1280 1152h384v128h-384v-128zM1792 320v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 832v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19 t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0b0;" horiz-adv-x="1408" d="M1403 1241q17 -41 -14 -70l-493 -493v-742q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-256 256q-19 19 -19 45v486l-493 493q-31 29 -14 70q17 39 59 39h1280q42 0 59 -39z" />
+<glyph unicode="&#xf0b1;" horiz-adv-x="1792" d="M640 1280h512v128h-512v-128zM1792 640v-480q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v480h672v-160q0 -26 19 -45t45 -19h320q26 0 45 19t19 45v160h672zM1024 640v-128h-256v128h256zM1792 1120v-384h-1792v384q0 66 47 113t113 47h352v160q0 40 28 68 t68 28h576q40 0 68 -28t28 -68v-160h352q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf0b2;" d="M1283 995l-355 -355l355 -355l144 144q29 31 70 14q39 -17 39 -59v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l144 144l-355 355l-355 -355l144 -144q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l144 -144 l355 355l-355 355l-144 -144q-19 -19 -45 -19q-12 0 -24 5q-40 17 -40 59v448q0 26 19 45t45 19h448q42 0 59 -40q17 -39 -14 -69l-144 -144l355 -355l355 355l-144 144q-31 30 -14 69q17 40 59 40h448q26 0 45 -19t19 -45v-448q0 -42 -39 -59q-13 -5 -25 -5q-26 0 -45 19z " />
+<glyph unicode="&#xf0c0;" horiz-adv-x="1920" d="M593 640q-162 -5 -265 -128h-134q-82 0 -138 40.5t-56 118.5q0 353 124 353q6 0 43.5 -21t97.5 -42.5t119 -21.5q67 0 133 23q-5 -37 -5 -66q0 -139 81 -256zM1664 3q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5 t43 97.5t62 81t85.5 53.5t111.5 20q10 0 43 -21.5t73 -48t107 -48t135 -21.5t135 21.5t107 48t73 48t43 21.5q61 0 111.5 -20t85.5 -53.5t62 -81t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM640 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75 t75 -181zM1344 896q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5zM1920 671q0 -78 -56 -118.5t-138 -40.5h-134q-103 123 -265 128q81 117 81 256q0 29 -5 66q66 -23 133 -23q59 0 119 21.5t97.5 42.5 t43.5 21q124 0 124 -353zM1792 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181z" />
+<glyph unicode="&#xf0c1;" horiz-adv-x="1664" d="M1456 320q0 40 -28 68l-208 208q-28 28 -68 28q-42 0 -72 -32q3 -3 19 -18.5t21.5 -21.5t15 -19t13 -25.5t3.5 -27.5q0 -40 -28 -68t-68 -28q-15 0 -27.5 3.5t-25.5 13t-19 15t-21.5 21.5t-18.5 19q-33 -31 -33 -73q0 -40 28 -68l206 -207q27 -27 68 -27q40 0 68 26 l147 146q28 28 28 67zM753 1025q0 40 -28 68l-206 207q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l208 -208q27 -27 68 -27q42 0 72 31q-3 3 -19 18.5t-21.5 21.5t-15 19t-13 25.5t-3.5 27.5q0 40 28 68t68 28q15 0 27.5 -3.5t25.5 -13t19 -15 t21.5 -21.5t18.5 -19q33 31 33 73zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-206 207q-83 83 -83 203q0 123 88 209l-88 88q-86 -88 -208 -88q-120 0 -204 84l-208 208q-84 84 -84 204t85 203l147 146q83 83 203 83q121 0 204 -85l206 -207 q83 -83 83 -203q0 -123 -88 -209l88 -88q86 88 208 88q120 0 204 -84l208 -208q84 -84 84 -204z" />
+<glyph unicode="&#xf0c2;" horiz-adv-x="1920" d="M1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088q-185 0 -316.5 131.5t-131.5 316.5q0 132 71 241.5t187 163.5q-2 28 -2 43q0 212 150 362t362 150q158 0 286.5 -88t187.5 -230q70 62 166 62q106 0 181 -75t75 -181q0 -75 -41 -138q129 -30 213 -134.5t84 -239.5z " />
+<glyph unicode="&#xf0c3;" horiz-adv-x="1664" d="M1527 88q56 -89 21.5 -152.5t-140.5 -63.5h-1152q-106 0 -140.5 63.5t21.5 152.5l503 793v399h-64q-26 0 -45 19t-19 45t19 45t45 19h512q26 0 45 -19t19 -45t-19 -45t-45 -19h-64v-399zM748 813l-272 -429h712l-272 429l-20 31v37v399h-128v-399v-37z" />
+<glyph unicode="&#xf0c4;" horiz-adv-x="1792" d="M960 640q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1260 576l507 -398q28 -20 25 -56q-5 -35 -35 -51l-128 -64q-13 -7 -29 -7q-17 0 -31 8l-690 387l-110 -66q-8 -4 -12 -5q14 -49 10 -97q-7 -77 -56 -147.5t-132 -123.5q-132 -84 -277 -84 q-136 0 -222 78q-90 84 -79 207q7 76 56 147t131 124q132 84 278 84q83 0 151 -31q9 13 22 22l122 73l-122 73q-13 9 -22 22q-68 -31 -151 -31q-146 0 -278 84q-82 53 -131 124t-56 147q-5 59 15.5 113t63.5 93q85 79 222 79q145 0 277 -84q83 -52 132 -123t56 -148 q4 -48 -10 -97q4 -1 12 -5l110 -66l690 387q14 8 31 8q16 0 29 -7l128 -64q30 -16 35 -51q3 -36 -25 -56zM579 836q46 42 21 108t-106 117q-92 59 -192 59q-74 0 -113 -36q-46 -42 -21 -108t106 -117q92 -59 192 -59q74 0 113 36zM494 91q81 51 106 117t-21 108 q-39 36 -113 36q-100 0 -192 -59q-81 -51 -106 -117t21 -108q39 -36 113 -36q100 0 192 59zM672 704l96 -58v11q0 36 33 56l14 8l-79 47l-26 -26q-3 -3 -10 -11t-12 -12q-2 -2 -4 -3.5t-3 -2.5zM896 480l96 -32l736 576l-128 64l-768 -431v-113l-160 -96l9 -8q2 -2 7 -6 q4 -4 11 -12t11 -12l26 -26zM1600 64l128 64l-520 408l-177 -138q-2 -3 -13 -7z" />
+<glyph unicode="&#xf0c5;" horiz-adv-x="1792" d="M1696 1152q40 0 68 -28t28 -68v-1216q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v288h-544q-40 0 -68 28t-28 68v672q0 40 20 88t48 76l408 408q28 28 76 48t88 20h416q40 0 68 -28t28 -68v-328q68 40 128 40h416zM1152 939l-299 -299h299v299zM512 1323l-299 -299 h299v299zM708 676l316 316v416h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h512v256q0 40 20 88t48 76zM1664 -128v1152h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h896z" />
+<glyph unicode="&#xf0c6;" horiz-adv-x="1408" d="M1404 151q0 -117 -79 -196t-196 -79q-135 0 -235 100l-777 776q-113 115 -113 271q0 159 110 270t269 111q158 0 273 -113l605 -606q10 -10 10 -22q0 -16 -30.5 -46.5t-46.5 -30.5q-13 0 -23 10l-606 607q-79 77 -181 77q-106 0 -179 -75t-73 -181q0 -105 76 -181 l776 -777q63 -63 145 -63q64 0 106 42t42 106q0 82 -63 145l-581 581q-26 24 -60 24q-29 0 -48 -19t-19 -48q0 -32 25 -59l410 -410q10 -10 10 -22q0 -16 -31 -47t-47 -31q-12 0 -22 10l-410 410q-63 61 -63 149q0 82 57 139t139 57q88 0 149 -63l581 -581q100 -98 100 -235 z" />
+<glyph unicode="&#xf0c7;" d="M384 0h768v384h-768v-384zM1280 0h128v896q0 14 -10 38.5t-20 34.5l-281 281q-10 10 -34 20t-39 10v-416q0 -40 -28 -68t-68 -28h-576q-40 0 -68 28t-28 68v416h-128v-1280h128v416q0 40 28 68t68 28h832q40 0 68 -28t28 -68v-416zM896 928v320q0 13 -9.5 22.5t-22.5 9.5 h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5zM1536 896v-928q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h928q40 0 88 -20t76 -48l280 -280q28 -28 48 -76t20 -88z" />
+<glyph unicode="&#xf0c8;" d="M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf0c9;" d="M1536 192v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 704v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 1216v-128q0 -26 -19 -45 t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0ca;" horiz-adv-x="1792" d="M384 128q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 640q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1152q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z M1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf0cb;" horiz-adv-x="1792" d="M381 -84q0 -80 -54.5 -126t-135.5 -46q-106 0 -172 66l57 88q49 -45 106 -45q29 0 50.5 14.5t21.5 42.5q0 64 -105 56l-26 56q8 10 32.5 43.5t42.5 54t37 38.5v1q-16 0 -48.5 -1t-48.5 -1v-53h-106v152h333v-88l-95 -115q51 -12 81 -49t30 -88zM383 543v-159h-362 q-6 36 -6 54q0 51 23.5 93t56.5 68t66 47.5t56.5 43.5t23.5 45q0 25 -14.5 38.5t-39.5 13.5q-46 0 -81 -58l-85 59q24 51 71.5 79.5t105.5 28.5q73 0 123 -41.5t50 -112.5q0 -50 -34 -91.5t-75 -64.5t-75.5 -50.5t-35.5 -52.5h127v60h105zM1792 224v-192q0 -13 -9.5 -22.5 t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1123v-99h-335v99h107q0 41 0.5 122t0.5 121v12h-2q-8 -17 -50 -54l-71 76l136 127h106v-404h108zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5 t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf0cc;" horiz-adv-x="1792" d="M1760 640q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1728q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h1728zM483 704q-28 35 -51 80q-48 97 -48 188q0 181 134 309q133 127 393 127q50 0 167 -19q66 -12 177 -48q10 -38 21 -118q14 -123 14 -183q0 -18 -5 -45l-12 -3l-84 6 l-14 2q-50 149 -103 205q-88 91 -210 91q-114 0 -182 -59q-67 -58 -67 -146q0 -73 66 -140t279 -129q69 -20 173 -66q58 -28 95 -52h-743zM990 448h411q7 -39 7 -92q0 -111 -41 -212q-23 -55 -71 -104q-37 -35 -109 -81q-80 -48 -153 -66q-80 -21 -203 -21q-114 0 -195 23 l-140 40q-57 16 -72 28q-8 8 -8 22v13q0 108 -2 156q-1 30 0 68l2 37v44l102 2q15 -34 30 -71t22.5 -56t12.5 -27q35 -57 80 -94q43 -36 105 -57q59 -22 132 -22q64 0 139 27q77 26 122 86q47 61 47 129q0 84 -81 157q-34 29 -137 71z" />
+<glyph unicode="&#xf0cd;" d="M48 1313q-37 2 -45 4l-3 88q13 1 40 1q60 0 112 -4q132 -7 166 -7q86 0 168 3q116 4 146 5q56 0 86 2l-1 -14l2 -64v-9q-60 -9 -124 -9q-60 0 -79 -25q-13 -14 -13 -132q0 -13 0.5 -32.5t0.5 -25.5l1 -229l14 -280q6 -124 51 -202q35 -59 96 -92q88 -47 177 -47 q104 0 191 28q56 18 99 51q48 36 65 64q36 56 53 114q21 73 21 229q0 79 -3.5 128t-11 122.5t-13.5 159.5l-4 59q-5 67 -24 88q-34 35 -77 34l-100 -2l-14 3l2 86h84l205 -10q76 -3 196 10l18 -2q6 -38 6 -51q0 -7 -4 -31q-45 -12 -84 -13q-73 -11 -79 -17q-15 -15 -15 -41 q0 -7 1.5 -27t1.5 -31q8 -19 22 -396q6 -195 -15 -304q-15 -76 -41 -122q-38 -65 -112 -123q-75 -57 -182 -89q-109 -33 -255 -33q-167 0 -284 46q-119 47 -179 122q-61 76 -83 195q-16 80 -16 237v333q0 188 -17 213q-25 36 -147 39zM1536 -96v64q0 14 -9 23t-23 9h-1472 q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h1472q14 0 23 9t9 23z" />
+<glyph unicode="&#xf0ce;" horiz-adv-x="1664" d="M512 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23 v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 160v192 q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192 q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1664 1248v-1088q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1344q66 0 113 -47t47 -113 z" />
+<glyph unicode="&#xf0d0;" horiz-adv-x="1664" d="M1190 955l293 293l-107 107l-293 -293zM1637 1248q0 -27 -18 -45l-1286 -1286q-18 -18 -45 -18t-45 18l-198 198q-18 18 -18 45t18 45l1286 1286q18 18 45 18t45 -18l198 -198q18 -18 18 -45zM286 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM636 1276 l196 -60l-196 -60l-60 -196l-60 196l-196 60l196 60l60 196zM1566 798l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM926 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98z" />
+<glyph unicode="&#xf0d1;" horiz-adv-x="1792" d="M640 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM256 640h384v256h-158q-13 0 -22 -9l-195 -195q-9 -9 -9 -22v-30zM1536 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1792 1216v-1024q0 -15 -4 -26.5t-13.5 -18.5 t-16.5 -11.5t-23.5 -6t-22.5 -2t-25.5 0t-22.5 0.5q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-64q-3 0 -22.5 -0.5t-25.5 0t-22.5 2t-23.5 6t-16.5 11.5t-13.5 18.5t-4 26.5q0 26 19 45t45 19v320q0 8 -0.5 35t0 38 t2.5 34.5t6.5 37t14 30.5t22.5 30l198 198q19 19 50.5 32t58.5 13h160v192q0 26 19 45t45 19h1024q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0d2;" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103q-111 0 -218 32q59 93 78 164q9 34 54 211q20 -39 73 -67.5t114 -28.5q121 0 216 68.5t147 188.5t52 270q0 114 -59.5 214t-172.5 163t-255 63q-105 0 -196 -29t-154.5 -77t-109 -110.5t-67 -129.5t-21.5 -134 q0 -104 40 -183t117 -111q30 -12 38 20q2 7 8 31t8 30q6 23 -11 43q-51 61 -51 151q0 151 104.5 259.5t273.5 108.5q151 0 235.5 -82t84.5 -213q0 -170 -68.5 -289t-175.5 -119q-61 0 -98 43.5t-23 104.5q8 35 26.5 93.5t30 103t11.5 75.5q0 50 -27 83t-77 33 q-62 0 -105 -57t-43 -142q0 -73 25 -122l-99 -418q-17 -70 -13 -177q-206 91 -333 281t-127 423q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0d3;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-725q85 122 108 210q9 34 53 209q21 -39 73.5 -67t112.5 -28q181 0 295.5 147.5t114.5 373.5q0 84 -35 162.5t-96.5 139t-152.5 97t-197 36.5q-104 0 -194.5 -28.5t-153 -76.5 t-107.5 -109.5t-66.5 -128t-21.5 -132.5q0 -102 39.5 -180t116.5 -110q13 -5 23.5 0t14.5 19q10 44 15 61q6 23 -11 42q-50 62 -50 150q0 150 103.5 256.5t270.5 106.5q149 0 232.5 -81t83.5 -210q0 -168 -67.5 -286t-173.5 -118q-60 0 -97 43.5t-23 103.5q8 34 26.5 92.5 t29.5 102t11 74.5q0 49 -26.5 81.5t-75.5 32.5q-61 0 -103.5 -56.5t-42.5 -139.5q0 -72 24 -121l-98 -414q-24 -100 -7 -254h-183q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960z" />
+<glyph unicode="&#xf0d4;" d="M829 318q0 -76 -58.5 -112.5t-139.5 -36.5q-41 0 -80.5 9.5t-75.5 28.5t-58 53t-22 78q0 46 25 80t65.5 51.5t82 25t84.5 7.5q20 0 31 -2q2 -1 23 -16.5t26 -19t23 -18t24.5 -22t19 -22.5t17 -26t9 -26.5t4.5 -31.5zM755 863q0 -60 -33 -99.5t-92 -39.5q-53 0 -93 42.5 t-57.5 96.5t-17.5 106q0 61 32 104t92 43q53 0 93.5 -45t58 -101t17.5 -107zM861 1120l88 64h-265q-85 0 -161 -32t-127.5 -98t-51.5 -153q0 -93 64.5 -154.5t158.5 -61.5q22 0 43 3q-13 -29 -13 -54q0 -44 40 -94q-175 -12 -257 -63q-47 -29 -75.5 -73t-28.5 -95 q0 -43 18.5 -77.5t48.5 -56.5t69 -37t77.5 -21t76.5 -6q60 0 120.5 15.5t113.5 46t86 82.5t33 117q0 49 -20 89.5t-49 66.5t-58 47.5t-49 44t-20 44.5t15.5 42.5t37.5 39.5t44 42t37.5 59.5t15.5 82.5q0 60 -22.5 99.5t-72.5 90.5h83zM1152 672h128v64h-128v128h-64v-128 h-128v-64h128v-160h64v160zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf0d5;" horiz-adv-x="1664" d="M735 740q0 -36 32 -70.5t77.5 -68t90.5 -73.5t77 -104t32 -142q0 -90 -48 -173q-72 -122 -211 -179.5t-298 -57.5q-132 0 -246.5 41.5t-171.5 137.5q-37 60 -37 131q0 81 44.5 150t118.5 115q131 82 404 100q-32 42 -47.5 74t-15.5 73q0 36 21 85q-46 -4 -68 -4 q-148 0 -249.5 96.5t-101.5 244.5q0 82 36 159t99 131q77 66 182.5 98t217.5 32h418l-138 -88h-131q74 -63 112 -133t38 -160q0 -72 -24.5 -129.5t-59 -93t-69.5 -65t-59.5 -61.5t-24.5 -66zM589 836q38 0 78 16.5t66 43.5q53 57 53 159q0 58 -17 125t-48.5 129.5 t-84.5 103.5t-117 41q-42 0 -82.5 -19.5t-65.5 -52.5q-47 -59 -47 -160q0 -46 10 -97.5t31.5 -103t52 -92.5t75 -67t96.5 -26zM591 -37q58 0 111.5 13t99 39t73 73t27.5 109q0 25 -7 49t-14.5 42t-27 41.5t-29.5 35t-38.5 34.5t-36.5 29t-41.5 30t-36.5 26q-16 2 -48 2 q-53 0 -105 -7t-107.5 -25t-97 -46t-68.5 -74.5t-27 -105.5q0 -70 35 -123.5t91.5 -83t119 -44t127.5 -14.5zM1401 839h213v-108h-213v-219h-105v219h-212v108h212v217h105v-217z" />
+<glyph unicode="&#xf0d6;" horiz-adv-x="1920" d="M768 384h384v96h-128v448h-114l-148 -137l77 -80q42 37 55 57h2v-288h-128v-96zM1280 640q0 -70 -21 -142t-59.5 -134t-101.5 -101t-138 -39t-138 39t-101.5 101t-59.5 134t-21 142t21 142t59.5 134t101.5 101t138 39t138 -39t101.5 -101t59.5 -134t21 -142zM1792 384 v512q-106 0 -181 75t-75 181h-1152q0 -106 -75 -181t-181 -75v-512q106 0 181 -75t75 -181h1152q0 106 75 181t181 75zM1920 1216v-1152q0 -26 -19 -45t-45 -19h-1792q-26 0 -45 19t-19 45v1152q0 26 19 45t45 19h1792q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0d7;" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0d8;" horiz-adv-x="1024" d="M1024 320q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0d9;" horiz-adv-x="640" d="M640 1088v-896q0 -26 -19 -45t-45 -19t-45 19l-448 448q-19 19 -19 45t19 45l448 448q19 19 45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf0da;" horiz-adv-x="640" d="M576 640q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19t-19 45v896q0 26 19 45t45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0db;" horiz-adv-x="1664" d="M160 0h608v1152h-640v-1120q0 -13 9.5 -22.5t22.5 -9.5zM1536 32v1120h-640v-1152h608q13 0 22.5 9.5t9.5 22.5zM1664 1248v-1216q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1344q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf0dc;" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45zM1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0dd;" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0de;" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0e0;" horiz-adv-x="1792" d="M1792 826v-794q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v794q44 -49 101 -87q362 -246 497 -345q57 -42 92.5 -65.5t94.5 -48t110 -24.5h1h1q51 0 110 24.5t94.5 48t92.5 65.5q170 123 498 345q57 39 100 87zM1792 1120q0 -79 -49 -151t-122 -123 q-376 -261 -468 -325q-10 -7 -42.5 -30.5t-54 -38t-52 -32.5t-57.5 -27t-50 -9h-1h-1q-23 0 -50 9t-57.5 27t-52 32.5t-54 38t-42.5 30.5q-91 64 -262 182.5t-205 142.5q-62 42 -117 115.5t-55 136.5q0 78 41.5 130t118.5 52h1472q65 0 112.5 -47t47.5 -113z" />
+<glyph unicode="&#xf0e1;" d="M349 911v-991h-330v991h330zM370 1217q1 -73 -50.5 -122t-135.5 -49h-2q-82 0 -132 49t-50 122q0 74 51.5 122.5t134.5 48.5t133 -48.5t51 -122.5zM1536 488v-568h-329v530q0 105 -40.5 164.5t-126.5 59.5q-63 0 -105.5 -34.5t-63.5 -85.5q-11 -30 -11 -81v-553h-329 q2 399 2 647t-1 296l-1 48h329v-144h-2q20 32 41 56t56.5 52t87 43.5t114.5 15.5q171 0 275 -113.5t104 -332.5z" />
+<glyph unicode="&#xf0e2;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298z" />
+<glyph unicode="&#xf0e3;" horiz-adv-x="1792" d="M1771 0q0 -53 -37 -90l-107 -108q-39 -37 -91 -37q-53 0 -90 37l-363 364q-38 36 -38 90q0 53 43 96l-256 256l-126 -126q-14 -14 -34 -14t-34 14q2 -2 12.5 -12t12.5 -13t10 -11.5t10 -13.5t6 -13.5t5.5 -16.5t1.5 -18q0 -38 -28 -68q-3 -3 -16.5 -18t-19 -20.5 t-18.5 -16.5t-22 -15.5t-22 -9t-26 -4.5q-40 0 -68 28l-408 408q-28 28 -28 68q0 13 4.5 26t9 22t15.5 22t16.5 18.5t20.5 19t18 16.5q30 28 68 28q10 0 18 -1.5t16.5 -5.5t13.5 -6t13.5 -10t11.5 -10t13 -12.5t12 -12.5q-14 14 -14 34t14 34l348 348q14 14 34 14t34 -14 q-2 2 -12.5 12t-12.5 13t-10 11.5t-10 13.5t-6 13.5t-5.5 16.5t-1.5 18q0 38 28 68q3 3 16.5 18t19 20.5t18.5 16.5t22 15.5t22 9t26 4.5q40 0 68 -28l408 -408q28 -28 28 -68q0 -13 -4.5 -26t-9 -22t-15.5 -22t-16.5 -18.5t-20.5 -19t-18 -16.5q-30 -28 -68 -28 q-10 0 -18 1.5t-16.5 5.5t-13.5 6t-13.5 10t-11.5 10t-13 12.5t-12 12.5q14 -14 14 -34t-14 -34l-126 -126l256 -256q43 43 96 43q52 0 91 -37l363 -363q37 -39 37 -91z" />
+<glyph unicode="&#xf0e4;" horiz-adv-x="1792" d="M384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM576 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1004 351l101 382q6 26 -7.5 48.5t-38.5 29.5 t-48 -6.5t-30 -39.5l-101 -382q-60 -5 -107 -43.5t-63 -98.5q-20 -77 20 -146t117 -89t146 20t89 117q16 60 -6 117t-72 91zM1664 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 1024q0 53 -37.5 90.5 t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1472 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1792 384q0 -261 -141 -483q-19 -29 -54 -29h-1402q-35 0 -54 29 q-141 221 -141 483q0 182 71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+<glyph unicode="&#xf0e5;" horiz-adv-x="1792" d="M896 1152q-204 0 -381.5 -69.5t-282 -187.5t-104.5 -255q0 -112 71.5 -213.5t201.5 -175.5l87 -50l-27 -96q-24 -91 -70 -172q152 63 275 171l43 38l57 -6q69 -8 130 -8q204 0 381.5 69.5t282 187.5t104.5 255t-104.5 255t-282 187.5t-381.5 69.5zM1792 640 q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22h-5q-15 0 -27 10.5t-16 27.5v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281q0 174 120 321.5 t326 233t450 85.5t450 -85.5t326 -233t120 -321.5z" />
+<glyph unicode="&#xf0e6;" horiz-adv-x="1792" d="M704 1152q-153 0 -286 -52t-211.5 -141t-78.5 -191q0 -82 53 -158t149 -132l97 -56l-35 -84q34 20 62 39l44 31l53 -10q78 -14 153 -14q153 0 286 52t211.5 141t78.5 191t-78.5 191t-211.5 141t-286 52zM704 1280q191 0 353.5 -68.5t256.5 -186.5t94 -257t-94 -257 t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224q0 139 94 257t256.5 186.5 t353.5 68.5zM1526 111q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129 q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230q0 -120 -71 -224.5t-195 -176.5z" />
+<glyph unicode="&#xf0e7;" horiz-adv-x="896" d="M885 970q18 -20 7 -44l-540 -1157q-13 -25 -42 -25q-4 0 -14 2q-17 5 -25.5 19t-4.5 30l197 808l-406 -101q-4 -1 -12 -1q-18 0 -31 11q-18 15 -13 39l201 825q4 14 16 23t28 9h328q19 0 32 -12.5t13 -29.5q0 -8 -5 -18l-171 -463l396 98q8 2 12 2q19 0 34 -15z" />
+<glyph unicode="&#xf0e8;" horiz-adv-x="1792" d="M1792 288v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192q0 52 38 90t90 38h512v192h-96q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h320q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-96v-192h512q52 0 90 -38t38 -90v-192h96q40 0 68 -28t28 -68 z" />
+<glyph unicode="&#xf0e9;" horiz-adv-x="1664" d="M896 708v-580q0 -104 -76 -180t-180 -76t-180 76t-76 180q0 26 19 45t45 19t45 -19t19 -45q0 -50 39 -89t89 -39t89 39t39 89v580q33 11 64 11t64 -11zM1664 681q0 -13 -9.5 -22.5t-22.5 -9.5q-11 0 -23 10q-49 46 -93 69t-102 23q-68 0 -128 -37t-103 -97 q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -28 -17q-18 0 -29 17q-4 6 -14.5 24t-17.5 28q-43 60 -102.5 97t-127.5 37t-127.5 -37t-102.5 -97q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -29 -17q-17 0 -28 17q-4 6 -14.5 24t-17.5 28q-43 60 -103 97t-128 37q-58 0 -102 -23t-93 -69 q-12 -10 -23 -10q-13 0 -22.5 9.5t-9.5 22.5q0 5 1 7q45 183 172.5 319.5t298 204.5t360.5 68q140 0 274.5 -40t246.5 -113.5t194.5 -187t115.5 -251.5q1 -2 1 -7zM896 1408v-98q-42 2 -64 2t-64 -2v98q0 26 19 45t45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf0ea;" horiz-adv-x="1792" d="M768 -128h896v640h-416q-40 0 -68 28t-28 68v416h-384v-1152zM1024 1312v64q0 13 -9.5 22.5t-22.5 9.5h-704q-13 0 -22.5 -9.5t-9.5 -22.5v-64q0 -13 9.5 -22.5t22.5 -9.5h704q13 0 22.5 9.5t9.5 22.5zM1280 640h299l-299 299v-299zM1792 512v-672q0 -40 -28 -68t-68 -28 h-960q-40 0 -68 28t-28 68v160h-544q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1088q40 0 68 -28t28 -68v-328q21 -13 36 -28l408 -408q28 -28 48 -76t20 -88z" />
+<glyph unicode="&#xf0eb;" horiz-adv-x="1024" d="M736 960q0 -13 -9.5 -22.5t-22.5 -9.5t-22.5 9.5t-9.5 22.5q0 46 -54 71t-106 25q-13 0 -22.5 9.5t-9.5 22.5t9.5 22.5t22.5 9.5q50 0 99.5 -16t87 -54t37.5 -90zM896 960q0 72 -34.5 134t-90 101.5t-123 62t-136.5 22.5t-136.5 -22.5t-123 -62t-90 -101.5t-34.5 -134 q0 -101 68 -180q10 -11 30.5 -33t30.5 -33q128 -153 141 -298h228q13 145 141 298q10 11 30.5 33t30.5 33q68 79 68 180zM1024 960q0 -155 -103 -268q-45 -49 -74.5 -87t-59.5 -95.5t-34 -107.5q47 -28 47 -82q0 -37 -25 -64q25 -27 25 -64q0 -52 -45 -81q13 -23 13 -47 q0 -46 -31.5 -71t-77.5 -25q-20 -44 -60 -70t-87 -26t-87 26t-60 70q-46 0 -77.5 25t-31.5 71q0 24 13 47q-45 29 -45 81q0 37 25 64q-25 27 -25 64q0 54 47 82q-4 50 -34 107.5t-59.5 95.5t-74.5 87q-103 113 -103 268q0 99 44.5 184.5t117 142t164 89t186.5 32.5 t186.5 -32.5t164 -89t117 -142t44.5 -184.5z" />
+<glyph unicode="&#xf0ec;" horiz-adv-x="1792" d="M1792 352v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5q-12 0 -24 10l-319 320q-9 9 -9 22q0 14 9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h1376q13 0 22.5 -9.5t9.5 -22.5zM1792 896q0 -14 -9 -23l-320 -320q-9 -9 -23 -9 q-13 0 -22.5 9.5t-9.5 22.5v192h-1376q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1376v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" />
+<glyph unicode="&#xf0ed;" horiz-adv-x="1920" d="M1280 608q0 14 -9 23t-23 9h-224v352q0 13 -9.5 22.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-352h-224q-13 0 -22.5 -9.5t-9.5 -22.5q0 -14 9 -23l352 -352q9 -9 23 -9t23 9l351 351q10 12 10 24zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
+<glyph unicode="&#xf0ee;" horiz-adv-x="1920" d="M1280 672q0 14 -9 23l-352 352q-9 9 -23 9t-23 -9l-351 -351q-10 -12 -10 -24q0 -14 9 -23t23 -9h224v-352q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5v352h224q13 0 22.5 9.5t9.5 22.5zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
+<glyph unicode="&#xf0f0;" horiz-adv-x="1408" d="M384 192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM1408 131q0 -121 -73 -190t-194 -69h-874q-121 0 -194 69t-73 190q0 68 5.5 131t24 138t47.5 132.5t81 103t120 60.5q-22 -52 -22 -120v-203q-58 -20 -93 -70t-35 -111q0 -80 56 -136t136 -56 t136 56t56 136q0 61 -35.5 111t-92.5 70v203q0 62 25 93q132 -104 295 -104t295 104q25 -31 25 -93v-64q-106 0 -181 -75t-75 -181v-89q-32 -29 -32 -71q0 -40 28 -68t68 -28t68 28t28 68q0 42 -32 71v89q0 52 38 90t90 38t90 -38t38 -90v-89q-32 -29 -32 -71q0 -40 28 -68 t68 -28t68 28t28 68q0 42 -32 71v89q0 68 -34.5 127.5t-93.5 93.5q0 10 0.5 42.5t0 48t-2.5 41.5t-7 47t-13 40q68 -15 120 -60.5t81 -103t47.5 -132.5t24 -138t5.5 -131zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5 t271.5 -112.5t112.5 -271.5z" />
+<glyph unicode="&#xf0f1;" horiz-adv-x="1408" d="M1280 832q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 832q0 -62 -35.5 -111t-92.5 -70v-395q0 -159 -131.5 -271.5t-316.5 -112.5t-316.5 112.5t-131.5 271.5v132q-164 20 -274 128t-110 252v512q0 26 19 45t45 19q6 0 16 -2q17 30 47 48 t65 18q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5q-33 0 -64 18v-402q0 -106 94 -181t226 -75t226 75t94 181v402q-31 -18 -64 -18q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5q35 0 65 -18t47 -48q10 2 16 2q26 0 45 -19t19 -45v-512q0 -144 -110 -252 t-274 -128v-132q0 -106 94 -181t226 -75t226 75t94 181v395q-57 21 -92.5 70t-35.5 111q0 80 56 136t136 56t136 -56t56 -136z" />
+<glyph unicode="&#xf0f2;" horiz-adv-x="1792" d="M640 1152h512v128h-512v-128zM288 1152v-1280h-64q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h64zM1408 1152v-1280h-1024v1280h128v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h128zM1792 928v-832q0 -92 -66 -158t-158 -66h-64v1280h64q92 0 158 -66 t66 -158z" />
+<glyph unicode="&#xf0f3;" horiz-adv-x="1792" d="M912 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5 t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q190 -28 307 -158.5t117 -282.5q0 -139 19.5 -260t50 -206t74.5 -158.5t85 -119.5t91 -88z" />
+<glyph unicode="&#xf0f4;" horiz-adv-x="1920" d="M1664 896q0 80 -56 136t-136 56h-64v-384h64q80 0 136 56t56 136zM0 128h1792q0 -106 -75 -181t-181 -75h-1280q-106 0 -181 75t-75 181zM1856 896q0 -159 -112.5 -271.5t-271.5 -112.5h-64v-32q0 -92 -66 -158t-158 -66h-704q-92 0 -158 66t-66 158v736q0 26 19 45 t45 19h1152q159 0 271.5 -112.5t112.5 -271.5z" />
+<glyph unicode="&#xf0f5;" horiz-adv-x="1408" d="M640 1472v-640q0 -61 -35.5 -111t-92.5 -70v-779q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v779q-57 20 -92.5 70t-35.5 111v640q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45 t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45zM1408 1472v-1600q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v512h-224q-13 0 -22.5 9.5t-9.5 22.5v800q0 132 94 226t226 94h256q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0f6;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M384 736q0 14 9 23t23 9h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64zM1120 512q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704zM1120 256q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704 q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704z" />
+<glyph unicode="&#xf0f7;" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1536h-1152v-1536h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM1408 1472v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0f8;" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1152h-256v-32q0 -40 -28 -68t-68 -28h-448q-40 0 -68 28t-28 68v32h-256v-1152h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM896 1056v320q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-96h-128v96q0 13 -9.5 22.5 t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5v96h128v-96q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1408 1088v-1280q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1280q0 26 19 45t45 19h320 v288q0 40 28 68t68 28h448q40 0 68 -28t28 -68v-288h320q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0f9;" horiz-adv-x="1920" d="M640 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM256 640h384v256h-158q-14 -2 -22 -9l-195 -195q-7 -12 -9 -22v-30zM1536 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1664 800v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM1920 1344v-1152 q0 -26 -19 -45t-45 -19h-192q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-128q-26 0 -45 19t-19 45t19 45t45 19v416q0 26 13 58t32 51l198 198q19 19 51 32t58 13h160v320q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0fa;" horiz-adv-x="1792" d="M1280 416v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM640 1152h512v128h-512v-128zM256 1152v-1280h-32 q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h32zM1440 1152v-1280h-1088v1280h160v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h160zM1792 928v-832q0 -92 -66 -158t-158 -66h-32v1280h32q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf0fb;" horiz-adv-x="1920" d="M1920 576q-1 -32 -288 -96l-352 -32l-224 -64h-64l-293 -352h69q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-96h-160h-64v32h64v416h-160l-192 -224h-96l-32 32v192h32v32h128v8l-192 24v128l192 24v8h-128v32h-32v192l32 32h96l192 -224h160v416h-64v32h64h160h96 q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-69l293 -352h64l224 -64l352 -32q261 -58 287 -93z" />
+<glyph unicode="&#xf0fc;" horiz-adv-x="1664" d="M640 640v384h-256v-256q0 -53 37.5 -90.5t90.5 -37.5h128zM1664 192v-192h-1152v192l128 192h-128q-159 0 -271.5 112.5t-112.5 271.5v320l-64 64l32 128h480l32 128h960l32 -192l-64 -32v-800z" />
+<glyph unicode="&#xf0fd;" d="M1280 192v896q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-512v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-896q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h512v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf0fe;" d="M1280 576v128q0 26 -19 45t-45 19h-320v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-320q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h320v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h320q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf100;" horiz-adv-x="1024" d="M627 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23zM1011 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23z" />
+<glyph unicode="&#xf101;" horiz-adv-x="1024" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM979 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23 l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf102;" horiz-adv-x="1152" d="M1075 224q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM1075 608q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393 q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf103;" horiz-adv-x="1152" d="M1075 672q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23zM1075 1056q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+<glyph unicode="&#xf104;" horiz-adv-x="640" d="M627 992q0 -13 -10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+<glyph unicode="&#xf105;" horiz-adv-x="640" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf106;" horiz-adv-x="1152" d="M1075 352q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf107;" horiz-adv-x="1152" d="M1075 800q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+<glyph unicode="&#xf108;" horiz-adv-x="1920" d="M1792 544v832q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5zM1920 1376v-1088q0 -66 -47 -113t-113 -47h-544q0 -37 16 -77.5t32 -71t16 -43.5q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19 t-19 45q0 14 16 44t32 70t16 78h-544q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf109;" horiz-adv-x="1920" d="M416 256q-66 0 -113 47t-47 113v704q0 66 47 113t113 47h1088q66 0 113 -47t47 -113v-704q0 -66 -47 -113t-113 -47h-1088zM384 1120v-704q0 -13 9.5 -22.5t22.5 -9.5h1088q13 0 22.5 9.5t9.5 22.5v704q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5z M1760 192h160v-96q0 -40 -47 -68t-113 -28h-1600q-66 0 -113 28t-47 68v96h160h1600zM1040 96q16 0 16 16t-16 16h-160q-16 0 -16 -16t16 -16h160z" />
+<glyph unicode="&#xf10a;" horiz-adv-x="1152" d="M640 128q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1024 288v960q0 13 -9.5 22.5t-22.5 9.5h-832q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h832q13 0 22.5 9.5t9.5 22.5zM1152 1248v-1088q0 -66 -47 -113t-113 -47h-832 q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h832q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf10b;" horiz-adv-x="768" d="M464 128q0 33 -23.5 56.5t-56.5 23.5t-56.5 -23.5t-23.5 -56.5t23.5 -56.5t56.5 -23.5t56.5 23.5t23.5 56.5zM672 288v704q0 13 -9.5 22.5t-22.5 9.5h-512q-13 0 -22.5 -9.5t-9.5 -22.5v-704q0 -13 9.5 -22.5t22.5 -9.5h512q13 0 22.5 9.5t9.5 22.5zM480 1136 q0 16 -16 16h-160q-16 0 -16 -16t16 -16h160q16 0 16 16zM768 1152v-1024q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v1024q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf10c;" d="M768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103 t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf10d;" horiz-adv-x="1664" d="M768 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z M1664 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z" />
+<glyph unicode="&#xf10e;" horiz-adv-x="1664" d="M768 1216v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136zM1664 1216 v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136z" />
+<glyph unicode="&#xf110;" horiz-adv-x="1568" d="M496 192q0 -60 -42.5 -102t-101.5 -42q-60 0 -102 42t-42 102t42 102t102 42q59 0 101.5 -42t42.5 -102zM928 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM320 640q0 -66 -47 -113t-113 -47t-113 47t-47 113 t47 113t113 47t113 -47t47 -113zM1360 192q0 -46 -33 -79t-79 -33t-79 33t-33 79t33 79t79 33t79 -33t33 -79zM528 1088q0 -73 -51.5 -124.5t-124.5 -51.5t-124.5 51.5t-51.5 124.5t51.5 124.5t124.5 51.5t124.5 -51.5t51.5 -124.5zM992 1280q0 -80 -56 -136t-136 -56 t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1536 640q0 -40 -28 -68t-68 -28t-68 28t-28 68t28 68t68 28t68 -28t28 -68zM1328 1088q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5z" />
+<glyph unicode="&#xf111;" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf112;" horiz-adv-x="1792" d="M1792 416q0 -166 -127 -451q-3 -7 -10.5 -24t-13.5 -30t-13 -22q-12 -17 -28 -17q-15 0 -23.5 10t-8.5 25q0 9 2.5 26.5t2.5 23.5q5 68 5 123q0 101 -17.5 181t-48.5 138.5t-80 101t-105.5 69.5t-133 42.5t-154 21.5t-175.5 6h-224v-256q0 -26 -19 -45t-45 -19t-45 19 l-512 512q-19 19 -19 45t19 45l512 512q19 19 45 19t45 -19t19 -45v-256h224q713 0 875 -403q53 -134 53 -333z" />
+<glyph unicode="&#xf113;" horiz-adv-x="1664" d="M640 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1280 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1440 320 q0 120 -69 204t-187 84q-41 0 -195 -21q-71 -11 -157 -11t-157 11q-152 21 -195 21q-118 0 -187 -84t-69 -204q0 -88 32 -153.5t81 -103t122 -60t140 -29.5t149 -7h168q82 0 149 7t140 29.5t122 60t81 103t32 153.5zM1664 496q0 -207 -61 -331q-38 -77 -105.5 -133t-141 -86 t-170 -47.5t-171.5 -22t-167 -4.5q-78 0 -142 3t-147.5 12.5t-152.5 30t-137 51.5t-121 81t-86 115q-62 123 -62 331q0 237 136 396q-27 82 -27 170q0 116 51 218q108 0 190 -39.5t189 -123.5q147 35 309 35q148 0 280 -32q105 82 187 121t189 39q51 -102 51 -218 q0 -87 -27 -168q136 -160 136 -398z" />
+<glyph unicode="&#xf114;" horiz-adv-x="1664" d="M1536 224v704q0 40 -28 68t-68 28h-704q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68v-960q0 -40 28 -68t68 -28h1216q40 0 68 28t28 68zM1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320 q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf115;" horiz-adv-x="1920" d="M1781 605q0 35 -53 35h-1088q-40 0 -85.5 -21.5t-71.5 -52.5l-294 -363q-18 -24 -18 -40q0 -35 53 -35h1088q40 0 86 22t71 53l294 363q18 22 18 39zM640 768h768v160q0 40 -28 68t-68 28h-576q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68 v-853l256 315q44 53 116 87.5t140 34.5zM1909 605q0 -62 -46 -120l-295 -363q-43 -53 -116 -87.5t-140 -34.5h-1088q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158v-160h192q54 0 99 -24.5t67 -70.5q15 -32 15 -68z " />
+<glyph unicode="&#xf116;" horiz-adv-x="1792" />
+<glyph unicode="&#xf117;" horiz-adv-x="1792" />
+<glyph unicode="&#xf118;" d="M1134 461q-37 -121 -138 -195t-228 -74t-228 74t-138 195q-8 25 4 48.5t38 31.5q25 8 48.5 -4t31.5 -38q25 -80 92.5 -129.5t151.5 -49.5t151.5 49.5t92.5 129.5q8 26 32 38t49 4t37 -31.5t4 -48.5zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5 t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf119;" d="M1134 307q8 -25 -4 -48.5t-37 -31.5t-49 4t-32 38q-25 80 -92.5 129.5t-151.5 49.5t-151.5 -49.5t-92.5 -129.5q-8 -26 -31.5 -38t-48.5 -4q-26 8 -38 31.5t-4 48.5q37 121 138 195t228 74t228 -74t138 -195zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204 t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf11a;" d="M1152 448q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h640q26 0 45 -19t19 -45zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf11b;" horiz-adv-x="1920" d="M832 448v128q0 14 -9 23t-23 9h-192v192q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-192h-192q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h192v-192q0 -14 9 -23t23 -9h128q14 0 23 9t9 23v192h192q14 0 23 9t9 23zM1408 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1920 512q0 -212 -150 -362t-362 -150q-192 0 -338 128h-220q-146 -128 -338 -128q-212 0 -362 150 t-150 362t150 362t362 150h896q212 0 362 -150t150 -362z" />
+<glyph unicode="&#xf11c;" horiz-adv-x="1920" d="M384 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM512 624v-96q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h224q16 0 16 -16zM384 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 368v-96q0 -16 -16 -16 h-864q-16 0 -16 16v96q0 16 16 16h864q16 0 16 -16zM768 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM640 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1024 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16 h96q16 0 16 -16zM896 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1280 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1152 880v-96 q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 880v-352q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h112v240q0 16 16 16h96q16 0 16 -16zM1792 128v896h-1664v-896 h1664zM1920 1024v-896q0 -53 -37.5 -90.5t-90.5 -37.5h-1664q-53 0 -90.5 37.5t-37.5 90.5v896q0 53 37.5 90.5t90.5 37.5h1664q53 0 90.5 -37.5t37.5 -90.5z" />
+<glyph unicode="&#xf11d;" horiz-adv-x="1792" d="M1664 491v616q-169 -91 -306 -91q-82 0 -145 32q-100 49 -184 76.5t-178 27.5q-173 0 -403 -127v-599q245 113 433 113q55 0 103.5 -7.5t98 -26t77 -31t82.5 -39.5l28 -14q44 -22 101 -22q120 0 293 92zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9 h-64q-14 0 -23 9t-9 23v1266q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102 q-15 -9 -33 -9q-16 0 -32 8q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" />
+<glyph unicode="&#xf11e;" horiz-adv-x="1792" d="M832 536v192q-181 -16 -384 -117v-185q205 96 384 110zM832 954v197q-172 -8 -384 -126v-189q215 111 384 118zM1664 491v184q-235 -116 -384 -71v224q-20 6 -39 15q-5 3 -33 17t-34.5 17t-31.5 15t-34.5 15.5t-32.5 13t-36 12.5t-35 8.5t-39.5 7.5t-39.5 4t-44 2 q-23 0 -49 -3v-222h19q102 0 192.5 -29t197.5 -82q19 -9 39 -15v-188q42 -17 91 -17q120 0 293 92zM1664 918v189q-169 -91 -306 -91q-45 0 -78 8v-196q148 -42 384 90zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v1266 q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102q-15 -9 -33 -9q-16 0 -32 8 q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" />
+<glyph unicode="&#xf120;" horiz-adv-x="1664" d="M585 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23zM1664 96v-64q0 -14 -9 -23t-23 -9h-960q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h960q14 0 23 -9 t9 -23z" />
+<glyph unicode="&#xf121;" horiz-adv-x="1920" d="M617 137l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23zM1208 1204l-373 -1291q-4 -13 -15.5 -19.5t-23.5 -2.5l-62 17q-13 4 -19.5 15.5t-2.5 24.5 l373 1291q4 13 15.5 19.5t23.5 2.5l62 -17q13 -4 19.5 -15.5t2.5 -24.5zM1865 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23z" />
+<glyph unicode="&#xf122;" horiz-adv-x="1792" d="M640 454v-70q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-69l-397 -398q-19 -19 -19 -45t19 -45zM1792 416q0 -58 -17 -133.5t-38.5 -138t-48 -125t-40.5 -90.5l-20 -40q-8 -17 -28 -17q-6 0 -9 1 q-25 8 -23 34q43 400 -106 565q-64 71 -170.5 110.5t-267.5 52.5v-251q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-262q411 -28 599 -221q169 -173 169 -509z" />
+<glyph unicode="&#xf123;" horiz-adv-x="1664" d="M1186 579l257 250l-356 52l-66 10l-30 60l-159 322v-963l59 -31l318 -168l-60 355l-12 66zM1638 841l-363 -354l86 -500q5 -33 -6 -51.5t-34 -18.5q-17 0 -40 12l-449 236l-449 -236q-23 -12 -40 -12q-23 0 -34 18.5t-6 51.5l86 500l-364 354q-32 32 -23 59.5t54 34.5 l502 73l225 455q20 41 49 41q28 0 49 -41l225 -455l502 -73q45 -7 54 -34.5t-24 -59.5z" />
+<glyph unicode="&#xf124;" horiz-adv-x="1408" d="M1401 1187l-640 -1280q-17 -35 -57 -35q-5 0 -15 2q-22 5 -35.5 22.5t-13.5 39.5v576h-576q-22 0 -39.5 13.5t-22.5 35.5t4 42t29 30l1280 640q13 7 29 7q27 0 45 -19q15 -14 18.5 -34.5t-6.5 -39.5z" />
+<glyph unicode="&#xf125;" horiz-adv-x="1664" d="M557 256h595v595zM512 301l595 595h-595v-595zM1664 224v-192q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v224h-864q-14 0 -23 9t-9 23v864h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224v224q0 14 9 23t23 9h192q14 0 23 -9t9 -23 v-224h851l246 247q10 9 23 9t23 -9q9 -10 9 -23t-9 -23l-247 -246v-851h224q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf126;" horiz-adv-x="1024" d="M288 64q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM288 1216q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM928 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1024 1088q0 -52 -26 -96.5t-70 -69.5 q-2 -287 -226 -414q-68 -38 -203 -81q-128 -40 -169.5 -71t-41.5 -100v-26q44 -25 70 -69.5t26 -96.5q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 52 26 96.5t70 69.5v820q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136q0 -52 -26 -96.5t-70 -69.5v-497 q54 26 154 57q55 17 87.5 29.5t70.5 31t59 39.5t40.5 51t28 69.5t8.5 91.5q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136z" />
+<glyph unicode="&#xf127;" horiz-adv-x="1664" d="M439 265l-256 -256q-10 -9 -23 -9q-12 0 -23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23zM608 224v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM384 448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23t9 23t23 9h320 q14 0 23 -9t9 -23zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-334 335q-21 21 -42 56l239 18l273 -274q27 -27 68 -27.5t68 26.5l147 146q28 28 28 67q0 40 -28 68l-274 275l18 239q35 -21 56 -42l336 -336q84 -86 84 -204zM1031 1044l-239 -18 l-273 274q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l274 -274l-18 -240q-35 21 -56 42l-336 336q-84 86 -84 204q0 120 85 203l147 146q83 83 203 83q121 0 204 -85l334 -335q21 -21 42 -56zM1664 960q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9 t-9 23t9 23t23 9h320q14 0 23 -9t9 -23zM1120 1504v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM1527 1353l-256 -256q-11 -9 -23 -9t-23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" />
+<glyph unicode="&#xf128;" horiz-adv-x="1024" d="M704 280v-240q0 -16 -12 -28t-28 -12h-240q-16 0 -28 12t-12 28v240q0 16 12 28t28 12h240q16 0 28 -12t12 -28zM1020 880q0 -54 -15.5 -101t-35 -76.5t-55 -59.5t-57.5 -43.5t-61 -35.5q-41 -23 -68.5 -65t-27.5 -67q0 -17 -12 -32.5t-28 -15.5h-240q-15 0 -25.5 18.5 t-10.5 37.5v45q0 83 65 156.5t143 108.5q59 27 84 56t25 76q0 42 -46.5 74t-107.5 32q-65 0 -108 -29q-35 -25 -107 -115q-13 -16 -31 -16q-12 0 -25 8l-164 125q-13 10 -15.5 25t5.5 28q160 266 464 266q80 0 161 -31t146 -83t106 -127.5t41 -158.5z" />
+<glyph unicode="&#xf129;" horiz-adv-x="640" d="M640 192v-128q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64v384h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-576h64q26 0 45 -19t19 -45zM512 1344v-192q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v192 q0 26 19 45t45 19h256q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf12a;" horiz-adv-x="640" d="M512 288v-224q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v224q0 26 19 45t45 19h256q26 0 45 -19t19 -45zM542 1344l-28 -768q-1 -26 -20.5 -45t-45.5 -19h-256q-26 0 -45.5 19t-20.5 45l-28 768q-1 26 17.5 45t44.5 19h320q26 0 44.5 -19t17.5 -45z" />
+<glyph unicode="&#xf12b;" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1534 846v-206h-514l-3 27 q-4 28 -4 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q83 65 188 65q110 0 178 -59.5t68 -158.5q0 -56 -24.5 -103t-62 -76.5t-81.5 -58.5t-82 -50.5t-65.5 -51.5t-30.5 -63h232v80 h126z" />
+<glyph unicode="&#xf12c;" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1536 -50v-206h-514l-4 27 q-3 45 -3 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q80 65 188 65q110 0 178 -59.5t68 -158.5q0 -66 -34.5 -118.5t-84 -86t-99.5 -62.5t-87 -63t-41 -73h232v80h126z" />
+<glyph unicode="&#xf12d;" horiz-adv-x="1920" d="M896 128l336 384h-768l-336 -384h768zM1909 1205q15 -34 9.5 -71.5t-30.5 -65.5l-896 -1024q-38 -44 -96 -44h-768q-38 0 -69.5 20.5t-47.5 54.5q-15 34 -9.5 71.5t30.5 65.5l896 1024q38 44 96 44h768q38 0 69.5 -20.5t47.5 -54.5z" />
+<glyph unicode="&#xf12e;" horiz-adv-x="1664" d="M1664 438q0 -81 -44.5 -135t-123.5 -54q-41 0 -77.5 17.5t-59 38t-56.5 38t-71 17.5q-110 0 -110 -124q0 -39 16 -115t15 -115v-5q-22 0 -33 -1q-34 -3 -97.5 -11.5t-115.5 -13.5t-98 -5q-61 0 -103 26.5t-42 83.5q0 37 17.5 71t38 56.5t38 59t17.5 77.5q0 79 -54 123.5 t-135 44.5q-84 0 -143 -45.5t-59 -127.5q0 -43 15 -83t33.5 -64.5t33.5 -53t15 -50.5q0 -45 -46 -89q-37 -35 -117 -35q-95 0 -245 24q-9 2 -27.5 4t-27.5 4l-13 2q-1 0 -3 1q-2 0 -2 1v1024q2 -1 17.5 -3.5t34 -5t21.5 -3.5q150 -24 245 -24q80 0 117 35q46 44 46 89 q0 22 -15 50.5t-33.5 53t-33.5 64.5t-15 83q0 82 59 127.5t144 45.5q80 0 134 -44.5t54 -123.5q0 -41 -17.5 -77.5t-38 -59t-38 -56.5t-17.5 -71q0 -57 42 -83.5t103 -26.5q64 0 180 15t163 17v-2q-1 -2 -3.5 -17.5t-5 -34t-3.5 -21.5q-24 -150 -24 -245q0 -80 35 -117 q44 -46 89 -46q22 0 50.5 15t53 33.5t64.5 33.5t83 15q82 0 127.5 -59t45.5 -143z" />
+<glyph unicode="&#xf130;" horiz-adv-x="1152" d="M1152 832v-128q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-217 24 -364.5 187.5t-147.5 384.5v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -185 131.5 -316.5t316.5 -131.5 t316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45zM896 1216v-512q0 -132 -94 -226t-226 -94t-226 94t-94 226v512q0 132 94 226t226 94t226 -94t94 -226z" />
+<glyph unicode="&#xf131;" horiz-adv-x="1408" d="M271 591l-101 -101q-42 103 -42 214v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -53 15 -113zM1385 1193l-361 -361v-128q0 -132 -94 -226t-226 -94q-55 0 -109 19l-96 -96q97 -51 205 -51q185 0 316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45v-128 q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-125 13 -235 81l-254 -254q-10 -10 -23 -10t-23 10l-82 82q-10 10 -10 23t10 23l1234 1234q10 10 23 10t23 -10l82 -82q10 -10 10 -23 t-10 -23zM1005 1325l-621 -621v512q0 132 94 226t226 94q102 0 184.5 -59t116.5 -152z" />
+<glyph unicode="&#xf132;" horiz-adv-x="1280" d="M1088 576v640h-448v-1137q119 63 213 137q235 184 235 360zM1280 1344v-768q0 -86 -33.5 -170.5t-83 -150t-118 -127.5t-126.5 -103t-121 -77.5t-89.5 -49.5t-42.5 -20q-12 -6 -26 -6t-26 6q-16 7 -42.5 20t-89.5 49.5t-121 77.5t-126.5 103t-118 127.5t-83 150 t-33.5 170.5v768q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf133;" horiz-adv-x="1664" d="M128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280 q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf134;" horiz-adv-x="1408" d="M512 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 1376v-320q0 -16 -12 -25q-8 -7 -20 -7q-4 0 -7 1l-448 96q-11 2 -18 11t-7 20h-256v-102q111 -23 183.5 -111t72.5 -203v-800q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v800 q0 106 62.5 190.5t161.5 114.5v111h-32q-59 0 -115 -23.5t-91.5 -53t-66 -66.5t-40.5 -53.5t-14 -24.5q-17 -35 -57 -35q-16 0 -29 7q-23 12 -31.5 37t3.5 49q5 10 14.5 26t37.5 53.5t60.5 70t85 67t108.5 52.5q-25 42 -25 86q0 66 47 113t113 47t113 -47t47 -113 q0 -33 -14 -64h302q0 11 7 20t18 11l448 96q3 1 7 1q12 0 20 -7q12 -9 12 -25z" />
+<glyph unicode="&#xf135;" horiz-adv-x="1664" d="M1440 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1664 1376q0 -249 -75.5 -430.5t-253.5 -360.5q-81 -80 -195 -176l-20 -379q-2 -16 -16 -26l-384 -224q-7 -4 -16 -4q-12 0 -23 9l-64 64q-13 14 -8 32l85 276l-281 281l-276 -85q-3 -1 -9 -1 q-14 0 -23 9l-64 64q-17 19 -5 39l224 384q10 14 26 16l379 20q96 114 176 195q188 187 358 258t431 71q14 0 24 -9.5t10 -22.5z" />
+<glyph unicode="&#xf136;" horiz-adv-x="1792" d="M1745 763l-164 -763h-334l178 832q13 56 -15 88q-27 33 -83 33h-169l-204 -953h-334l204 953h-286l-204 -953h-334l204 953l-153 327h1276q101 0 189.5 -40.5t147.5 -113.5q60 -73 81 -168.5t0 -194.5z" />
+<glyph unicode="&#xf137;" d="M909 141l102 102q19 19 19 45t-19 45l-307 307l307 307q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf138;" d="M717 141l454 454q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l307 -307l-307 -307q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf139;" d="M1165 397l102 102q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l307 307l307 -307q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf13a;" d="M813 237l454 454q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-307 -307l-307 307q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf13b;" horiz-adv-x="1408" d="M1130 939l16 175h-884l47 -534h612l-22 -228l-197 -53l-196 53l-13 140h-175l22 -278l362 -100h4v1l359 99l50 544h-644l-15 181h674zM0 1408h1408l-128 -1438l-578 -162l-574 162z" />
+<glyph unicode="&#xf13c;" horiz-adv-x="1792" d="M275 1408h1505l-266 -1333l-804 -267l-698 267l71 356h297l-29 -147l422 -161l486 161l68 339h-1208l58 297h1209l38 191h-1208z" />
+<glyph unicode="&#xf13d;" horiz-adv-x="1792" d="M960 1280q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1792 352v-352q0 -22 -20 -30q-8 -2 -12 -2q-13 0 -23 9l-93 93q-119 -143 -318.5 -226.5t-429.5 -83.5t-429.5 83.5t-318.5 226.5l-93 -93q-9 -9 -23 -9q-4 0 -12 2q-20 8 -20 30v352 q0 14 9 23t23 9h352q22 0 30 -20q8 -19 -7 -35l-100 -100q67 -91 189.5 -153.5t271.5 -82.5v647h-192q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h192v163q-58 34 -93 92.5t-35 128.5q0 106 75 181t181 75t181 -75t75 -181q0 -70 -35 -128.5t-93 -92.5v-163h192q26 0 45 -19 t19 -45v-128q0 -26 -19 -45t-45 -19h-192v-647q149 20 271.5 82.5t189.5 153.5l-100 100q-15 16 -7 35q8 20 30 20h352q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf13e;" horiz-adv-x="1152" d="M1056 768q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v320q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45q0 106 -75 181t-181 75t-181 -75t-75 -181 v-320h736z" />
+<glyph unicode="&#xf140;" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM1152 640q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM1280 640q0 -212 -150 -362t-362 -150t-362 150 t-150 362t150 362t362 150t362 -150t150 -362zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf141;" horiz-adv-x="1408" d="M384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM896 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM1408 800v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf142;" horiz-adv-x="384" d="M384 288v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 1312v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf143;" d="M512 256q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM863 162q-13 232 -177 396t-396 177q-14 1 -24 -9t-10 -23v-128q0 -13 8.5 -22t21.5 -10q154 -11 264 -121t121 -264q1 -13 10 -21.5t22 -8.5h128q13 0 23 10 t9 24zM1247 161q-5 154 -56 297.5t-139.5 260t-205 205t-260 139.5t-297.5 56q-14 1 -23 -9q-10 -10 -10 -23v-128q0 -13 9 -22t22 -10q204 -7 378 -111.5t278.5 -278.5t111.5 -378q1 -13 10 -22t22 -9h128q13 0 23 10q11 9 9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf144;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1152 585q32 18 32 55t-32 55l-544 320q-31 19 -64 1q-32 -19 -32 -56v-640q0 -37 32 -56 q16 -8 32 -8q17 0 32 9z" />
+<glyph unicode="&#xf145;" horiz-adv-x="1792" d="M1024 1084l316 -316l-572 -572l-316 316zM813 105l618 618q19 19 19 45t-19 45l-362 362q-18 18 -45 18t-45 -18l-618 -618q-19 -19 -19 -45t19 -45l362 -362q18 -18 45 -18t45 18zM1702 742l-907 -908q-37 -37 -90.5 -37t-90.5 37l-126 126q56 56 56 136t-56 136 t-136 56t-136 -56l-125 126q-37 37 -37 90.5t37 90.5l907 906q37 37 90.5 37t90.5 -37l125 -125q-56 -56 -56 -136t56 -136t136 -56t136 56l126 -125q37 -37 37 -90.5t-37 -90.5z" />
+<glyph unicode="&#xf146;" d="M1280 576v128q0 26 -19 45t-45 19h-896q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h896q26 0 45 19t19 45zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" />
+<glyph unicode="&#xf147;" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h832q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5 t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf148;" horiz-adv-x="1024" d="M1018 933q-18 -37 -58 -37h-192v-864q0 -14 -9 -23t-23 -9h-704q-21 0 -29 18q-8 20 4 35l160 192q9 11 25 11h320v640h-192q-40 0 -58 37q-17 37 9 68l320 384q18 22 49 22t49 -22l320 -384q27 -32 9 -68z" />
+<glyph unicode="&#xf149;" horiz-adv-x="1024" d="M32 1280h704q13 0 22.5 -9.5t9.5 -23.5v-863h192q40 0 58 -37t-9 -69l-320 -384q-18 -22 -49 -22t-49 22l-320 384q-26 31 -9 69q18 37 58 37h192v640h-320q-14 0 -25 11l-160 192q-13 14 -4 34q9 19 29 19z" />
+<glyph unicode="&#xf14a;" d="M685 237l614 614q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-467 -467l-211 211q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l358 -358q19 -19 45 -19t45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5 t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14b;" d="M404 428l152 -152l-52 -52h-56v96h-96v56zM818 818q14 -13 -3 -30l-291 -291q-17 -17 -30 -3q-14 13 3 30l291 291q17 17 30 3zM544 128l544 544l-288 288l-544 -544v-288h288zM1152 736l92 92q28 28 28 68t-28 68l-152 152q-28 28 -68 28t-68 -28l-92 -92zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14c;" d="M1280 608v480q0 26 -19 45t-45 19h-480q-42 0 -59 -39q-17 -41 14 -70l144 -144l-534 -534q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l534 534l144 -144q18 -19 45 -19q12 0 25 5q39 17 39 59zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14d;" d="M1005 435l352 352q19 19 19 45t-19 45l-352 352q-30 31 -69 14q-40 -17 -40 -59v-160q-119 0 -216 -19.5t-162.5 -51t-114 -79t-76.5 -95.5t-44.5 -109t-21.5 -111.5t-5 -110.5q0 -181 167 -404q10 -12 25 -12q7 0 13 3q22 9 19 33q-44 354 62 473q46 52 130 75.5 t224 23.5v-160q0 -42 40 -59q12 -5 24 -5q26 0 45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14e;" d="M640 448l256 128l-256 128v-256zM1024 1039v-542l-512 -256v542zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf150;" d="M1145 861q18 -35 -5 -66l-320 -448q-19 -27 -52 -27t-52 27l-320 448q-23 31 -5 66q17 35 57 35h640q40 0 57 -35zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf151;" d="M1145 419q-17 -35 -57 -35h-640q-40 0 -57 35q-18 35 5 66l320 448q19 27 52 27t52 -27l320 -448q23 -31 5 -66zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf152;" d="M1088 640q0 -33 -27 -52l-448 -320q-31 -23 -66 -5q-35 17 -35 57v640q0 40 35 57q35 18 66 -5l448 -320q27 -19 27 -52zM1280 160v960q0 14 -9 23t-23 9h-960q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h960q14 0 23 9t9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf153;" horiz-adv-x="1024" d="M976 229l35 -159q3 -12 -3 -22.5t-17 -14.5l-5 -1q-4 -2 -10.5 -3.5t-16 -4.5t-21.5 -5.5t-25.5 -5t-30 -5t-33.5 -4.5t-36.5 -3t-38.5 -1q-234 0 -409 130.5t-238 351.5h-95q-13 0 -22.5 9.5t-9.5 22.5v113q0 13 9.5 22.5t22.5 9.5h66q-2 57 1 105h-67q-14 0 -23 9 t-9 23v114q0 14 9 23t23 9h98q67 210 243.5 338t400.5 128q102 0 194 -23q11 -3 20 -15q6 -11 3 -24l-43 -159q-3 -13 -14 -19.5t-24 -2.5l-4 1q-4 1 -11.5 2.5l-17.5 3.5t-22.5 3.5t-26 3t-29 2.5t-29.5 1q-126 0 -226 -64t-150 -176h468q16 0 25 -12q10 -12 7 -26 l-24 -114q-5 -26 -32 -26h-488q-3 -37 0 -105h459q15 0 25 -12q9 -12 6 -27l-24 -112q-2 -11 -11 -18.5t-20 -7.5h-387q48 -117 149.5 -185.5t228.5 -68.5q18 0 36 1.5t33.5 3.5t29.5 4.5t24.5 5t18.5 4.5l12 3l5 2q13 5 26 -2q12 -7 15 -21z" />
+<glyph unicode="&#xf154;" horiz-adv-x="1024" d="M1020 399v-367q0 -14 -9 -23t-23 -9h-956q-14 0 -23 9t-9 23v150q0 13 9.5 22.5t22.5 9.5h97v383h-95q-14 0 -23 9.5t-9 22.5v131q0 14 9 23t23 9h95v223q0 171 123.5 282t314.5 111q185 0 335 -125q9 -8 10 -20.5t-7 -22.5l-103 -127q-9 -11 -22 -12q-13 -2 -23 7 q-5 5 -26 19t-69 32t-93 18q-85 0 -137 -47t-52 -123v-215h305q13 0 22.5 -9t9.5 -23v-131q0 -13 -9.5 -22.5t-22.5 -9.5h-305v-379h414v181q0 13 9 22.5t23 9.5h162q14 0 23 -9.5t9 -22.5z" />
+<glyph unicode="&#xf155;" horiz-adv-x="1024" d="M978 351q0 -153 -99.5 -263.5t-258.5 -136.5v-175q0 -14 -9 -23t-23 -9h-135q-13 0 -22.5 9.5t-9.5 22.5v175q-66 9 -127.5 31t-101.5 44.5t-74 48t-46.5 37.5t-17.5 18q-17 21 -2 41l103 135q7 10 23 12q15 2 24 -9l2 -2q113 -99 243 -125q37 -8 74 -8q81 0 142.5 43 t61.5 122q0 28 -15 53t-33.5 42t-58.5 37.5t-66 32t-80 32.5q-39 16 -61.5 25t-61.5 26.5t-62.5 31t-56.5 35.5t-53.5 42.5t-43.5 49t-35.5 58t-21 66.5t-8.5 78q0 138 98 242t255 134v180q0 13 9.5 22.5t22.5 9.5h135q14 0 23 -9t9 -23v-176q57 -6 110.5 -23t87 -33.5 t63.5 -37.5t39 -29t15 -14q17 -18 5 -38l-81 -146q-8 -15 -23 -16q-14 -3 -27 7q-3 3 -14.5 12t-39 26.5t-58.5 32t-74.5 26t-85.5 11.5q-95 0 -155 -43t-60 -111q0 -26 8.5 -48t29.5 -41.5t39.5 -33t56 -31t60.5 -27t70 -27.5q53 -20 81 -31.5t76 -35t75.5 -42.5t62 -50 t53 -63.5t31.5 -76.5t13 -94z" />
+<glyph unicode="&#xf156;" horiz-adv-x="898" d="M898 1066v-102q0 -14 -9 -23t-23 -9h-168q-23 -144 -129 -234t-276 -110q167 -178 459 -536q14 -16 4 -34q-8 -18 -29 -18h-195q-16 0 -25 12q-306 367 -498 571q-9 9 -9 22v127q0 13 9.5 22.5t22.5 9.5h112q132 0 212.5 43t102.5 125h-427q-14 0 -23 9t-9 23v102 q0 14 9 23t23 9h413q-57 113 -268 113h-145q-13 0 -22.5 9.5t-9.5 22.5v133q0 14 9 23t23 9h832q14 0 23 -9t9 -23v-102q0 -14 -9 -23t-23 -9h-233q47 -61 64 -144h171q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf157;" horiz-adv-x="1027" d="M603 0h-172q-13 0 -22.5 9t-9.5 23v330h-288q-13 0 -22.5 9t-9.5 23v103q0 13 9.5 22.5t22.5 9.5h288v85h-288q-13 0 -22.5 9t-9.5 23v104q0 13 9.5 22.5t22.5 9.5h214l-321 578q-8 16 0 32q10 16 28 16h194q19 0 29 -18l215 -425q19 -38 56 -125q10 24 30.5 68t27.5 61 l191 420q8 19 29 19h191q17 0 27 -16q9 -14 1 -31l-313 -579h215q13 0 22.5 -9.5t9.5 -22.5v-104q0 -14 -9.5 -23t-22.5 -9h-290v-85h290q13 0 22.5 -9.5t9.5 -22.5v-103q0 -14 -9.5 -23t-22.5 -9h-290v-330q0 -13 -9.5 -22.5t-22.5 -9.5z" />
+<glyph unicode="&#xf158;" horiz-adv-x="1280" d="M1043 971q0 100 -65 162t-171 62h-320v-448h320q106 0 171 62t65 162zM1280 971q0 -193 -126.5 -315t-326.5 -122h-340v-118h505q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9h-505v-192q0 -14 -9.5 -23t-22.5 -9h-167q-14 0 -23 9t-9 23v192h-224q-14 0 -23 9t-9 23v128 q0 14 9 23t23 9h224v118h-224q-14 0 -23 9t-9 23v149q0 13 9 22.5t23 9.5h224v629q0 14 9 23t23 9h539q200 0 326.5 -122t126.5 -315z" />
+<glyph unicode="&#xf159;" horiz-adv-x="1792" d="M514 341l81 299h-159l75 -300q1 -1 1 -3t1 -3q0 1 0.5 3.5t0.5 3.5zM630 768l35 128h-292l32 -128h225zM822 768h139l-35 128h-70zM1271 340l78 300h-162l81 -299q0 -1 0.5 -3.5t1.5 -3.5q0 1 0.5 3t0.5 3zM1382 768l33 128h-297l34 -128h230zM1792 736v-64q0 -14 -9 -23 t-23 -9h-213l-164 -616q-7 -24 -31 -24h-159q-24 0 -31 24l-166 616h-209l-167 -616q-7 -24 -31 -24h-159q-11 0 -19.5 7t-10.5 17l-160 616h-208q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h175l-33 128h-142q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h109l-89 344q-5 15 5 28 q10 12 26 12h137q26 0 31 -24l90 -360h359l97 360q7 24 31 24h126q24 0 31 -24l98 -360h365l93 360q5 24 31 24h137q16 0 26 -12q10 -13 5 -28l-91 -344h111q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-145l-34 -128h179q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf15a;" horiz-adv-x="1280" d="M1167 896q18 -182 -131 -258q117 -28 175 -103t45 -214q-7 -71 -32.5 -125t-64.5 -89t-97 -58.5t-121.5 -34.5t-145.5 -15v-255h-154v251q-80 0 -122 1v-252h-154v255q-18 0 -54 0.5t-55 0.5h-200l31 183h111q50 0 58 51v402h16q-6 1 -16 1v287q-13 68 -89 68h-111v164 l212 -1q64 0 97 1v252h154v-247q82 2 122 2v245h154v-252q79 -7 140 -22.5t113 -45t82.5 -78t36.5 -114.5zM952 351q0 36 -15 64t-37 46t-57.5 30.5t-65.5 18.5t-74 9t-69 3t-64.5 -1t-47.5 -1v-338q8 0 37 -0.5t48 -0.5t53 1.5t58.5 4t57 8.5t55.5 14t47.5 21t39.5 30 t24.5 40t9.5 51zM881 827q0 33 -12.5 58.5t-30.5 42t-48 28t-55 16.5t-61.5 8t-58 2.5t-54 -1t-39.5 -0.5v-307q5 0 34.5 -0.5t46.5 0t50 2t55 5.5t51.5 11t48.5 18.5t37 27t27 38.5t9 51z" />
+<glyph unicode="&#xf15b;" d="M1024 1024v472q22 -14 36 -28l408 -408q14 -14 28 -36h-472zM896 992q0 -40 28 -68t68 -28h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544z" />
+<glyph unicode="&#xf15c;" d="M1468 1060q14 -14 28 -36h-472v472q22 -14 36 -28zM992 896h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544q0 -40 28 -68t68 -28zM1152 160v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704 q14 0 23 9t9 23zM1152 416v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1152 672v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23z" />
+<glyph unicode="&#xf15d;" horiz-adv-x="1664" d="M1191 1128h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1572 -23 v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -11v-2l14 2q9 2 30 2h248v119h121zM1661 874v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162 l230 -662h70z" />
+<glyph unicode="&#xf15e;" horiz-adv-x="1664" d="M1191 104h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1661 -150 v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162l230 -662h70zM1572 1001v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -10v-3l14 3q9 1 30 1h248 v119h121z" />
+<glyph unicode="&#xf160;" horiz-adv-x="1792" d="M736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1792 -32v-192q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832 q14 0 23 -9t9 -23zM1600 480v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1408 992v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1216 1504v-192q0 -14 -9 -23t-23 -9h-256 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf161;" horiz-adv-x="1792" d="M1216 -32v-192q0 -14 -9 -23t-23 -9h-256q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192 q14 0 23 -9t9 -23zM1408 480v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1600 992v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1792 1504v-192q0 -14 -9 -23t-23 -9h-832 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf162;" d="M1346 223q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23 zM1486 165q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5 t82 -252.5zM1456 882v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165z" />
+<glyph unicode="&#xf163;" d="M1346 1247q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9 t9 -23zM1456 -142v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165zM1486 1189q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13 q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5t82 -252.5z" />
+<glyph unicode="&#xf164;" horiz-adv-x="1664" d="M256 192q0 26 -19 45t-45 19q-27 0 -45.5 -19t-18.5 -45q0 -27 18.5 -45.5t45.5 -18.5q26 0 45 18.5t19 45.5zM416 704v-640q0 -26 -19 -45t-45 -19h-288q-26 0 -45 19t-19 45v640q0 26 19 45t45 19h288q26 0 45 -19t19 -45zM1600 704q0 -86 -55 -149q15 -44 15 -76 q3 -76 -43 -137q17 -56 0 -117q-15 -57 -54 -94q9 -112 -49 -181q-64 -76 -197 -78h-36h-76h-17q-66 0 -144 15.5t-121.5 29t-120.5 39.5q-123 43 -158 44q-26 1 -45 19.5t-19 44.5v641q0 25 18 43.5t43 20.5q24 2 76 59t101 121q68 87 101 120q18 18 31 48t17.5 48.5 t13.5 60.5q7 39 12.5 61t19.5 52t34 50q19 19 45 19q46 0 82.5 -10.5t60 -26t40 -40.5t24 -45t12 -50t5 -45t0.5 -39q0 -38 -9.5 -76t-19 -60t-27.5 -56q-3 -6 -10 -18t-11 -22t-8 -24h277q78 0 135 -57t57 -135z" />
+<glyph unicode="&#xf165;" horiz-adv-x="1664" d="M256 960q0 -26 -19 -45t-45 -19q-27 0 -45.5 19t-18.5 45q0 27 18.5 45.5t45.5 18.5q26 0 45 -18.5t19 -45.5zM416 448v640q0 26 -19 45t-45 19h-288q-26 0 -45 -19t-19 -45v-640q0 -26 19 -45t45 -19h288q26 0 45 19t19 45zM1545 597q55 -61 55 -149q-1 -78 -57.5 -135 t-134.5 -57h-277q4 -14 8 -24t11 -22t10 -18q18 -37 27 -57t19 -58.5t10 -76.5q0 -24 -0.5 -39t-5 -45t-12 -50t-24 -45t-40 -40.5t-60 -26t-82.5 -10.5q-26 0 -45 19q-20 20 -34 50t-19.5 52t-12.5 61q-9 42 -13.5 60.5t-17.5 48.5t-31 48q-33 33 -101 120q-49 64 -101 121 t-76 59q-25 2 -43 20.5t-18 43.5v641q0 26 19 44.5t45 19.5q35 1 158 44q77 26 120.5 39.5t121.5 29t144 15.5h17h76h36q133 -2 197 -78q58 -69 49 -181q39 -37 54 -94q17 -61 0 -117q46 -61 43 -137q0 -32 -15 -76z" />
+<glyph unicode="&#xf166;" d="M919 233v157q0 50 -29 50q-17 0 -33 -16v-224q16 -16 33 -16q29 0 29 49zM1103 355h66v34q0 51 -33 51t-33 -51v-34zM532 621v-70h-80v-423h-74v423h-78v70h232zM733 495v-367h-67v40q-39 -45 -76 -45q-33 0 -42 28q-6 16 -6 54v290h66v-270q0 -24 1 -26q1 -15 15 -15 q20 0 42 31v280h67zM985 384v-146q0 -52 -7 -73q-12 -42 -53 -42q-35 0 -68 41v-36h-67v493h67v-161q32 40 68 40q41 0 53 -42q7 -21 7 -74zM1236 255v-9q0 -29 -2 -43q-3 -22 -15 -40q-27 -40 -80 -40q-52 0 -81 38q-21 27 -21 86v129q0 59 20 86q29 38 80 38t78 -38 q21 -28 21 -86v-76h-133v-65q0 -51 34 -51q24 0 30 26q0 1 0.5 7t0.5 16.5v21.5h68zM785 1079v-156q0 -51 -32 -51t-32 51v156q0 52 32 52t32 -52zM1318 366q0 177 -19 260q-10 44 -43 73.5t-76 34.5q-136 15 -412 15q-275 0 -411 -15q-44 -5 -76.5 -34.5t-42.5 -73.5 q-20 -87 -20 -260q0 -176 20 -260q10 -43 42.5 -73t75.5 -35q137 -15 412 -15t412 15q43 5 75.5 35t42.5 73q20 84 20 260zM563 1017l90 296h-75l-51 -195l-53 195h-78l24 -69t23 -69q35 -103 46 -158v-201h74v201zM852 936v130q0 58 -21 87q-29 38 -78 38q-51 0 -78 -38 q-21 -29 -21 -87v-130q0 -58 21 -87q27 -38 78 -38q49 0 78 38q21 27 21 87zM1033 816h67v370h-67v-283q-22 -31 -42 -31q-15 0 -16 16q-1 2 -1 26v272h-67v-293q0 -37 6 -55q11 -27 43 -27q36 0 77 45v-40zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf167;" d="M971 292v-211q0 -67 -39 -67q-23 0 -45 22v301q22 22 45 22q39 0 39 -67zM1309 291v-46h-90v46q0 68 45 68t45 -68zM343 509h107v94h-312v-94h105v-569h100v569zM631 -60h89v494h-89v-378q-30 -42 -57 -42q-18 0 -21 21q-1 3 -1 35v364h-89v-391q0 -49 8 -73 q12 -37 58 -37q48 0 102 61v-54zM1060 88v197q0 73 -9 99q-17 56 -71 56q-50 0 -93 -54v217h-89v-663h89v48q45 -55 93 -55q54 0 71 55q9 27 9 100zM1398 98v13h-91q0 -51 -2 -61q-7 -36 -40 -36q-46 0 -46 69v87h179v103q0 79 -27 116q-39 51 -106 51q-68 0 -107 -51 q-28 -37 -28 -116v-173q0 -79 29 -116q39 -51 108 -51q72 0 108 53q18 27 21 54q2 9 2 58zM790 1011v210q0 69 -43 69t-43 -69v-210q0 -70 43 -70t43 70zM1509 260q0 -234 -26 -350q-14 -59 -58 -99t-102 -46q-184 -21 -555 -21t-555 21q-58 6 -102.5 46t-57.5 99 q-26 112 -26 350q0 234 26 350q14 59 58 99t103 47q183 20 554 20t555 -20q58 -7 102.5 -47t57.5 -99q26 -112 26 -350zM511 1536h102l-121 -399v-271h-100v271q-14 74 -61 212q-37 103 -65 187h106l71 -263zM881 1203v-175q0 -81 -28 -118q-37 -51 -106 -51q-67 0 -105 51 q-28 38 -28 118v175q0 80 28 117q38 51 105 51q69 0 106 -51q28 -37 28 -117zM1216 1365v-499h-91v55q-53 -62 -103 -62q-46 0 -59 37q-8 24 -8 75v394h91v-367q0 -33 1 -35q3 -22 21 -22q27 0 57 43v381h91z" />
+<glyph unicode="&#xf168;" horiz-adv-x="1408" d="M597 869q-10 -18 -257 -456q-27 -46 -65 -46h-239q-21 0 -31 17t0 36l253 448q1 0 0 1l-161 279q-12 22 -1 37q9 15 32 15h239q40 0 66 -45zM1403 1511q11 -16 0 -37l-528 -934v-1l336 -615q11 -20 1 -37q-10 -15 -32 -15h-239q-42 0 -66 45l-339 622q18 32 531 942 q25 45 64 45h241q22 0 31 -15z" />
+<glyph unicode="&#xf169;" d="M685 771q0 1 -126 222q-21 34 -52 34h-184q-18 0 -26 -11q-7 -12 1 -29l125 -216v-1l-196 -346q-9 -14 0 -28q8 -13 24 -13h185q31 0 50 36zM1309 1268q-7 12 -24 12h-187q-30 0 -49 -35l-411 -729q1 -2 262 -481q20 -35 52 -35h184q18 0 25 12q8 13 -1 28l-260 476v1 l409 723q8 16 0 28zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf16a;" horiz-adv-x="1792" d="M1280 640q0 37 -30 54l-512 320q-31 20 -65 2q-33 -18 -33 -56v-640q0 -38 33 -56q16 -8 31 -8q20 0 34 10l512 320q30 17 30 54zM1792 640q0 -96 -1 -150t-8.5 -136.5t-22.5 -147.5q-16 -73 -69 -123t-124 -58q-222 -25 -671 -25t-671 25q-71 8 -124.5 58t-69.5 123 q-14 65 -21.5 147.5t-8.5 136.5t-1 150t1 150t8.5 136.5t22.5 147.5q16 73 69 123t124 58q222 25 671 25t671 -25q71 -8 124.5 -58t69.5 -123q14 -65 21.5 -147.5t8.5 -136.5t1 -150z" />
+<glyph unicode="&#xf16b;" horiz-adv-x="1792" d="M402 829l494 -305l-342 -285l-490 319zM1388 274v-108l-490 -293v-1l-1 1l-1 -1v1l-489 293v108l147 -96l342 284v2l1 -1l1 1v-2l343 -284zM554 1418l342 -285l-494 -304l-338 270zM1390 829l338 -271l-489 -319l-343 285zM1239 1418l489 -319l-338 -270l-494 304z" />
+<glyph unicode="&#xf16c;" horiz-adv-x="1408" d="M928 135v-151l-707 -1v151zM1169 481v-701l-1 -35v-1h-1132l-35 1h-1v736h121v-618h928v618h120zM241 393l704 -65l-13 -150l-705 65zM309 709l683 -183l-39 -146l-683 183zM472 1058l609 -360l-77 -130l-609 360zM832 1389l398 -585l-124 -85l-399 584zM1285 1536 l121 -697l-149 -26l-121 697z" />
+<glyph unicode="&#xf16d;" d="M1362 110v648h-135q20 -63 20 -131q0 -126 -64 -232.5t-174 -168.5t-240 -62q-197 0 -337 135.5t-140 327.5q0 68 20 131h-141v-648q0 -26 17.5 -43.5t43.5 -17.5h1069q25 0 43 17.5t18 43.5zM1078 643q0 124 -90.5 211.5t-218.5 87.5q-127 0 -217.5 -87.5t-90.5 -211.5 t90.5 -211.5t217.5 -87.5q128 0 218.5 87.5t90.5 211.5zM1362 1003v165q0 28 -20 48.5t-49 20.5h-174q-29 0 -49 -20.5t-20 -48.5v-165q0 -29 20 -49t49 -20h174q29 0 49 20t20 49zM1536 1211v-1142q0 -81 -58 -139t-139 -58h-1142q-81 0 -139 58t-58 139v1142q0 81 58 139 t139 58h1142q81 0 139 -58t58 -139z" />
+<glyph unicode="&#xf16e;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM698 640q0 88 -62 150t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150zM1262 640q0 88 -62 150 t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150z" />
+<glyph unicode="&#xf170;" d="M768 914l201 -306h-402zM1133 384h94l-459 691l-459 -691h94l104 160h522zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf171;" horiz-adv-x="1408" d="M815 677q8 -63 -50.5 -101t-111.5 -6q-39 17 -53.5 58t-0.5 82t52 58q36 18 72.5 12t64 -35.5t27.5 -67.5zM926 698q-14 107 -113 164t-197 13q-63 -28 -100.5 -88.5t-34.5 -129.5q4 -91 77.5 -155t165.5 -56q91 8 152 84t50 168zM1165 1240q-20 27 -56 44.5t-58 22 t-71 12.5q-291 47 -566 -2q-43 -7 -66 -12t-55 -22t-50 -43q30 -28 76 -45.5t73.5 -22t87.5 -11.5q228 -29 448 -1q63 8 89.5 12t72.5 21.5t75 46.5zM1222 205q-8 -26 -15.5 -76.5t-14 -84t-28.5 -70t-58 -56.5q-86 -48 -189.5 -71.5t-202 -22t-201.5 18.5q-46 8 -81.5 18 t-76.5 27t-73 43.5t-52 61.5q-25 96 -57 292l6 16l18 9q223 -148 506.5 -148t507.5 148q21 -6 24 -23t-5 -45t-8 -37zM1403 1166q-26 -167 -111 -655q-5 -30 -27 -56t-43.5 -40t-54.5 -31q-252 -126 -610 -88q-248 27 -394 139q-15 12 -25.5 26.5t-17 35t-9 34t-6 39.5 t-5.5 35q-9 50 -26.5 150t-28 161.5t-23.5 147.5t-22 158q3 26 17.5 48.5t31.5 37.5t45 30t46 22.5t48 18.5q125 46 313 64q379 37 676 -50q155 -46 215 -122q16 -20 16.5 -51t-5.5 -54z" />
+<glyph unicode="&#xf172;" d="M848 666q0 43 -41 66t-77 1q-43 -20 -42.5 -72.5t43.5 -70.5q39 -23 81 4t36 72zM928 682q8 -66 -36 -121t-110 -61t-119 40t-56 113q-2 49 25.5 93t72.5 64q70 31 141.5 -10t81.5 -118zM1100 1073q-20 -21 -53.5 -34t-53 -16t-63.5 -8q-155 -20 -324 0q-44 6 -63 9.5 t-52.5 16t-54.5 32.5q13 19 36 31t40 15.5t47 8.5q198 35 408 1q33 -5 51 -8.5t43 -16t39 -31.5zM1142 327q0 7 5.5 26.5t3 32t-17.5 16.5q-161 -106 -365 -106t-366 106l-12 -6l-5 -12q26 -154 41 -210q47 -81 204 -108q249 -46 428 53q34 19 49 51.5t22.5 85.5t12.5 71z M1272 1020q9 53 -8 75q-43 55 -155 88q-216 63 -487 36q-132 -12 -226 -46q-38 -15 -59.5 -25t-47 -34t-29.5 -54q8 -68 19 -138t29 -171t24 -137q1 -5 5 -31t7 -36t12 -27t22 -28q105 -80 284 -100q259 -28 440 63q24 13 39.5 23t31 29t19.5 40q48 267 80 473zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf173;" horiz-adv-x="1024" d="M944 207l80 -237q-23 -35 -111 -66t-177 -32q-104 -2 -190.5 26t-142.5 74t-95 106t-55.5 120t-16.5 118v544h-168v215q72 26 129 69.5t91 90t58 102t34 99t15 88.5q1 5 4.5 8.5t7.5 3.5h244v-424h333v-252h-334v-518q0 -30 6.5 -56t22.5 -52.5t49.5 -41.5t81.5 -14 q78 2 134 29z" />
+<glyph unicode="&#xf174;" d="M1136 75l-62 183q-44 -22 -103 -22q-36 -1 -62 10.5t-38.5 31.5t-17.5 40.5t-5 43.5v398h257v194h-256v326h-188q-8 0 -9 -10q-5 -44 -17.5 -87t-39 -95t-77 -95t-118.5 -68v-165h130v-418q0 -57 21.5 -115t65 -111t121 -85.5t176.5 -30.5q69 1 136.5 25t85.5 50z M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf175;" horiz-adv-x="768" d="M765 237q8 -19 -5 -35l-350 -384q-10 -10 -23 -10q-14 0 -24 10l-355 384q-13 16 -5 35q9 19 29 19h224v1248q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1248h224q21 0 29 -19z" />
+<glyph unicode="&#xf176;" horiz-adv-x="768" d="M765 1043q-9 -19 -29 -19h-224v-1248q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1248h-224q-21 0 -29 19t5 35l350 384q10 10 23 10q14 0 24 -10l355 -384q13 -16 5 -35z" />
+<glyph unicode="&#xf177;" horiz-adv-x="1792" d="M1792 736v-192q0 -14 -9 -23t-23 -9h-1248v-224q0 -21 -19 -29t-35 5l-384 350q-10 10 -10 23q0 14 10 24l384 354q16 14 35 6q19 -9 19 -29v-224h1248q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf178;" horiz-adv-x="1792" d="M1728 643q0 -14 -10 -24l-384 -354q-16 -14 -35 -6q-19 9 -19 29v224h-1248q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h1248v224q0 21 19 29t35 -5l384 -350q10 -10 10 -23z" />
+<glyph unicode="&#xf179;" horiz-adv-x="1408" d="M1393 321q-39 -125 -123 -250q-129 -196 -257 -196q-49 0 -140 32q-86 32 -151 32q-61 0 -142 -33q-81 -34 -132 -34q-152 0 -301 259q-147 261 -147 503q0 228 113 374q112 144 284 144q72 0 177 -30q104 -30 138 -30q45 0 143 34q102 34 173 34q119 0 213 -65 q52 -36 104 -100q-79 -67 -114 -118q-65 -94 -65 -207q0 -124 69 -223t158 -126zM1017 1494q0 -61 -29 -136q-30 -75 -93 -138q-54 -54 -108 -72q-37 -11 -104 -17q3 149 78 257q74 107 250 148q1 -3 2.5 -11t2.5 -11q0 -4 0.5 -10t0.5 -10z" />
+<glyph unicode="&#xf17a;" horiz-adv-x="1664" d="M682 530v-651l-682 94v557h682zM682 1273v-659h-682v565zM1664 530v-786l-907 125v661h907zM1664 1408v-794h-907v669z" />
+<glyph unicode="&#xf17b;" horiz-adv-x="1408" d="M493 1053q16 0 27.5 11.5t11.5 27.5t-11.5 27.5t-27.5 11.5t-27 -11.5t-11 -27.5t11 -27.5t27 -11.5zM915 1053q16 0 27 11.5t11 27.5t-11 27.5t-27 11.5t-27.5 -11.5t-11.5 -27.5t11.5 -27.5t27.5 -11.5zM103 869q42 0 72 -30t30 -72v-430q0 -43 -29.5 -73t-72.5 -30 t-73 30t-30 73v430q0 42 30 72t73 30zM1163 850v-666q0 -46 -32 -78t-77 -32h-75v-227q0 -43 -30 -73t-73 -30t-73 30t-30 73v227h-138v-227q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73l-1 227h-74q-46 0 -78 32t-32 78v666h918zM931 1255q107 -55 171 -153.5t64 -215.5 h-925q0 117 64 215.5t172 153.5l-71 131q-7 13 5 20q13 6 20 -6l72 -132q95 42 201 42t201 -42l72 132q7 12 20 6q12 -7 5 -20zM1408 767v-430q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73v430q0 43 30 72.5t72 29.5q43 0 73 -29.5t30 -72.5z" />
+<glyph unicode="&#xf17c;" d="M663 1125q-11 -1 -15.5 -10.5t-8.5 -9.5q-5 -1 -5 5q0 12 19 15h10zM750 1111q-4 -1 -11.5 6.5t-17.5 4.5q24 11 32 -2q3 -6 -3 -9zM399 684q-4 1 -6 -3t-4.5 -12.5t-5.5 -13.5t-10 -13q-7 -10 -1 -12q4 -1 12.5 7t12.5 18q1 3 2 7t2 6t1.5 4.5t0.5 4v3t-1 2.5t-3 2z M1254 325q0 18 -55 42q4 15 7.5 27.5t5 26t3 21.5t0.5 22.5t-1 19.5t-3.5 22t-4 20.5t-5 25t-5.5 26.5q-10 48 -47 103t-72 75q24 -20 57 -83q87 -162 54 -278q-11 -40 -50 -42q-31 -4 -38.5 18.5t-8 83.5t-11.5 107q-9 39 -19.5 69t-19.5 45.5t-15.5 24.5t-13 15t-7.5 7 q-14 62 -31 103t-29.5 56t-23.5 33t-15 40q-4 21 6 53.5t4.5 49.5t-44.5 25q-15 3 -44.5 18t-35.5 16q-8 1 -11 26t8 51t36 27q37 3 51 -30t4 -58q-11 -19 -2 -26.5t30 -0.5q13 4 13 36v37q-5 30 -13.5 50t-21 30.5t-23.5 15t-27 7.5q-107 -8 -89 -134q0 -15 -1 -15 q-9 9 -29.5 10.5t-33 -0.5t-15.5 5q1 57 -16 90t-45 34q-27 1 -41.5 -27.5t-16.5 -59.5q-1 -15 3.5 -37t13 -37.5t15.5 -13.5q10 3 16 14q4 9 -7 8q-7 0 -15.5 14.5t-9.5 33.5q-1 22 9 37t34 14q17 0 27 -21t9.5 -39t-1.5 -22q-22 -15 -31 -29q-8 -12 -27.5 -23.5 t-20.5 -12.5q-13 -14 -15.5 -27t7.5 -18q14 -8 25 -19.5t16 -19t18.5 -13t35.5 -6.5q47 -2 102 15q2 1 23 7t34.5 10.5t29.5 13t21 17.5q9 14 20 8q5 -3 6.5 -8.5t-3 -12t-16.5 -9.5q-20 -6 -56.5 -21.5t-45.5 -19.5q-44 -19 -70 -23q-25 -5 -79 2q-10 2 -9 -2t17 -19 q25 -23 67 -22q17 1 36 7t36 14t33.5 17.5t30 17t24.5 12t17.5 2.5t8.5 -11q0 -2 -1 -4.5t-4 -5t-6 -4.5t-8.5 -5t-9 -4.5t-10 -5t-9.5 -4.5q-28 -14 -67.5 -44t-66.5 -43t-49 -1q-21 11 -63 73q-22 31 -25 22q-1 -3 -1 -10q0 -25 -15 -56.5t-29.5 -55.5t-21 -58t11.5 -63 q-23 -6 -62.5 -90t-47.5 -141q-2 -18 -1.5 -69t-5.5 -59q-8 -24 -29 -3q-32 31 -36 94q-2 28 4 56q4 19 -1 18l-4 -5q-36 -65 10 -166q5 -12 25 -28t24 -20q20 -23 104 -90.5t93 -76.5q16 -15 17.5 -38t-14 -43t-45.5 -23q8 -15 29 -44.5t28 -54t7 -70.5q46 24 7 92 q-4 8 -10.5 16t-9.5 12t-2 6q3 5 13 9.5t20 -2.5q46 -52 166 -36q133 15 177 87q23 38 34 30q12 -6 10 -52q-1 -25 -23 -92q-9 -23 -6 -37.5t24 -15.5q3 19 14.5 77t13.5 90q2 21 -6.5 73.5t-7.5 97t23 70.5q15 18 51 18q1 37 34.5 53t72.5 10.5t60 -22.5zM626 1152 q3 17 -2.5 30t-11.5 15q-9 2 -9 -7q2 -5 5 -6q10 0 7 -15q-3 -20 8 -20q3 0 3 3zM1045 955q-2 8 -6.5 11.5t-13 5t-14.5 5.5q-5 3 -9.5 8t-7 8t-5.5 6.5t-4 4t-4 -1.5q-14 -16 7 -43.5t39 -31.5q9 -1 14.5 8t3.5 20zM867 1168q0 11 -5 19.5t-11 12.5t-9 3q-14 -1 -7 -7l4 -2 q14 -4 18 -31q0 -3 8 2zM921 1401q0 2 -2.5 5t-9 7t-9.5 6q-15 15 -24 15q-9 -1 -11.5 -7.5t-1 -13t-0.5 -12.5q-1 -4 -6 -10.5t-6 -9t3 -8.5q4 -3 8 0t11 9t15 9q1 1 9 1t15 2t9 7zM1486 60q20 -12 31 -24.5t12 -24t-2.5 -22.5t-15.5 -22t-23.5 -19.5t-30 -18.5 t-31.5 -16.5t-32 -15.5t-27 -13q-38 -19 -85.5 -56t-75.5 -64q-17 -16 -68 -19.5t-89 14.5q-18 9 -29.5 23.5t-16.5 25.5t-22 19.5t-47 9.5q-44 1 -130 1q-19 0 -57 -1.5t-58 -2.5q-44 -1 -79.5 -15t-53.5 -30t-43.5 -28.5t-53.5 -11.5q-29 1 -111 31t-146 43q-19 4 -51 9.5 t-50 9t-39.5 9.5t-33.5 14.5t-17 19.5q-10 23 7 66.5t18 54.5q1 16 -4 40t-10 42.5t-4.5 36.5t10.5 27q14 12 57 14t60 12q30 18 42 35t12 51q21 -73 -32 -106q-32 -20 -83 -15q-34 3 -43 -10q-13 -15 5 -57q2 -6 8 -18t8.5 -18t4.5 -17t1 -22q0 -15 -17 -49t-14 -48 q3 -17 37 -26q20 -6 84.5 -18.5t99.5 -20.5q24 -6 74 -22t82.5 -23t55.5 -4q43 6 64.5 28t23 48t-7.5 58.5t-19 52t-20 36.5q-121 190 -169 242q-68 74 -113 40q-11 -9 -15 15q-3 16 -2 38q1 29 10 52t24 47t22 42q8 21 26.5 72t29.5 78t30 61t39 54q110 143 124 195 q-12 112 -16 310q-2 90 24 151.5t106 104.5q39 21 104 21q53 1 106 -13.5t89 -41.5q57 -42 91.5 -121.5t29.5 -147.5q-5 -95 30 -214q34 -113 133 -218q55 -59 99.5 -163t59.5 -191q8 -49 5 -84.5t-12 -55.5t-20 -22q-10 -2 -23.5 -19t-27 -35.5t-40.5 -33.5t-61 -14 q-18 1 -31.5 5t-22.5 13.5t-13.5 15.5t-11.5 20.5t-9 19.5q-22 37 -41 30t-28 -49t7 -97q20 -70 1 -195q-10 -65 18 -100.5t73 -33t85 35.5q59 49 89.5 66.5t103.5 42.5q53 18 77 36.5t18.5 34.5t-25 28.5t-51.5 23.5q-33 11 -49.5 48t-15 72.5t15.5 47.5q1 -31 8 -56.5 t14.5 -40.5t20.5 -28.5t21 -19t21.5 -13t16.5 -9.5z" />
+<glyph unicode="&#xf17d;" d="M1024 36q-42 241 -140 498h-2l-2 -1q-16 -6 -43 -16.5t-101 -49t-137 -82t-131 -114.5t-103 -148l-15 11q184 -150 418 -150q132 0 256 52zM839 643q-21 49 -53 111q-311 -93 -673 -93q-1 -7 -1 -21q0 -124 44 -236.5t124 -201.5q50 89 123.5 166.5t142.5 124.5t130.5 81 t99.5 48l37 13q4 1 13 3.5t13 4.5zM732 855q-120 213 -244 378q-138 -65 -234 -186t-128 -272q302 0 606 80zM1416 536q-210 60 -409 29q87 -239 128 -469q111 75 185 189.5t96 250.5zM611 1277q-1 0 -2 -1q1 1 2 1zM1201 1132q-185 164 -433 164q-76 0 -155 -19 q131 -170 246 -382q69 26 130 60.5t96.5 61.5t65.5 57t37.5 40.5zM1424 647q-3 232 -149 410l-1 -1q-9 -12 -19 -24.5t-43.5 -44.5t-71 -60.5t-100 -65t-131.5 -64.5q25 -53 44 -95q2 -6 6.5 -17.5t7.5 -16.5q36 5 74.5 7t73.5 2t69 -1.5t64 -4t56.5 -5.5t48 -6.5t36.5 -6 t25 -4.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf17e;" d="M1173 473q0 50 -19.5 91.5t-48.5 68.5t-73 49t-82.5 34t-87.5 23l-104 24q-30 7 -44 10.5t-35 11.5t-30 16t-16.5 21t-7.5 30q0 77 144 77q43 0 77 -12t54 -28.5t38 -33.5t40 -29t48 -12q47 0 75.5 32t28.5 77q0 55 -56 99.5t-142 67.5t-182 23q-68 0 -132 -15.5 t-119.5 -47t-89 -87t-33.5 -128.5q0 -61 19 -106.5t56 -75.5t80 -48.5t103 -32.5l146 -36q90 -22 112 -36q32 -20 32 -60q0 -39 -40 -64.5t-105 -25.5q-51 0 -91.5 16t-65 38.5t-45.5 45t-46 38.5t-54 16q-50 0 -75.5 -30t-25.5 -75q0 -92 122 -157.5t291 -65.5 q73 0 140 18.5t122.5 53.5t88.5 93.5t33 131.5zM1536 256q0 -159 -112.5 -271.5t-271.5 -112.5q-130 0 -234 80q-77 -16 -150 -16q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5q0 73 16 150q-80 104 -80 234q0 159 112.5 271.5t271.5 112.5q130 0 234 -80 q77 16 150 16q143 0 273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -73 -16 -150q80 -104 80 -234z" />
+<glyph unicode="&#xf180;" horiz-adv-x="1280" d="M1000 1102l37 194q5 23 -9 40t-35 17h-712q-23 0 -38.5 -17t-15.5 -37v-1101q0 -7 6 -1l291 352q23 26 38 33.5t48 7.5h239q22 0 37 14.5t18 29.5q24 130 37 191q4 21 -11.5 40t-36.5 19h-294q-29 0 -48 19t-19 48v42q0 29 19 47.5t48 18.5h346q18 0 35 13.5t20 29.5z M1227 1324q-15 -73 -53.5 -266.5t-69.5 -350t-35 -173.5q-6 -22 -9 -32.5t-14 -32.5t-24.5 -33t-38.5 -21t-58 -10h-271q-13 0 -22 -10q-8 -9 -426 -494q-22 -25 -58.5 -28.5t-48.5 5.5q-55 22 -55 98v1410q0 55 38 102.5t120 47.5h888q95 0 127 -53t10 -159zM1227 1324 l-158 -790q4 17 35 173.5t69.5 350t53.5 266.5z" />
+<glyph unicode="&#xf181;" d="M704 192v1024q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-1024q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1376 576v640q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-640q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408 q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf182;" horiz-adv-x="1280" d="M1280 480q0 -40 -28 -68t-68 -28q-51 0 -80 43l-227 341h-45v-132l247 -411q9 -15 9 -33q0 -26 -19 -45t-45 -19h-192v-272q0 -46 -33 -79t-79 -33h-160q-46 0 -79 33t-33 79v272h-192q-26 0 -45 19t-19 45q0 18 9 33l247 411v132h-45l-227 -341q-29 -43 -80 -43 q-40 0 -68 28t-28 68q0 29 16 53l256 384q73 107 176 107h384q103 0 176 -107l256 -384q16 -24 16 -53zM864 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf183;" horiz-adv-x="1024" d="M1024 832v-416q0 -40 -28 -68t-68 -28t-68 28t-28 68v352h-64v-912q0 -46 -33 -79t-79 -33t-79 33t-33 79v464h-64v-464q0 -46 -33 -79t-79 -33t-79 33t-33 79v912h-64v-352q0 -40 -28 -68t-68 -28t-68 28t-28 68v416q0 80 56 136t136 56h640q80 0 136 -56t56 -136z M736 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf184;" d="M773 234l350 473q16 22 24.5 59t-6 85t-61.5 79q-40 26 -83 25.5t-73.5 -17.5t-54.5 -45q-36 -40 -96 -40q-59 0 -95 40q-24 28 -54.5 45t-73.5 17.5t-84 -25.5q-46 -31 -60.5 -79t-6 -85t24.5 -59zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf185;" horiz-adv-x="1792" d="M1472 640q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5t-223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5t45.5 -223.5t123 -184t184 -123t223.5 -45.5t223.5 45.5t184 123t123 184t45.5 223.5zM1748 363q-4 -15 -20 -20l-292 -96v-306q0 -16 -13 -26q-15 -10 -29 -4 l-292 94l-180 -248q-10 -13 -26 -13t-26 13l-180 248l-292 -94q-14 -6 -29 4q-13 10 -13 26v306l-292 96q-16 5 -20 20q-5 17 4 29l180 248l-180 248q-9 13 -4 29q4 15 20 20l292 96v306q0 16 13 26q15 10 29 4l292 -94l180 248q9 12 26 12t26 -12l180 -248l292 94 q14 6 29 -4q13 -10 13 -26v-306l292 -96q16 -5 20 -20q5 -16 -4 -29l-180 -248l180 -248q9 -12 4 -29z" />
+<glyph unicode="&#xf186;" d="M1262 233q-54 -9 -110 -9q-182 0 -337 90t-245 245t-90 337q0 192 104 357q-201 -60 -328.5 -229t-127.5 -384q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51q144 0 273.5 61.5t220.5 171.5zM1465 318q-94 -203 -283.5 -324.5t-413.5 -121.5q-156 0 -298 61 t-245 164t-164 245t-61 298q0 153 57.5 292.5t156 241.5t235.5 164.5t290 68.5q44 2 61 -39q18 -41 -15 -72q-86 -78 -131.5 -181.5t-45.5 -218.5q0 -148 73 -273t198 -198t273 -73q118 0 228 51q41 18 72 -13q14 -14 17.5 -34t-4.5 -38z" />
+<glyph unicode="&#xf187;" horiz-adv-x="1792" d="M1088 704q0 26 -19 45t-45 19h-256q-26 0 -45 -19t-19 -45t19 -45t45 -19h256q26 0 45 19t19 45zM1664 896v-960q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v960q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1728 1344v-256q0 -26 -19 -45t-45 -19h-1536 q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1536q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf188;" horiz-adv-x="1664" d="M1632 576q0 -26 -19 -45t-45 -19h-224q0 -171 -67 -290l208 -209q19 -19 19 -45t-19 -45q-18 -19 -45 -19t-45 19l-198 197q-5 -5 -15 -13t-42 -28.5t-65 -36.5t-82 -29t-97 -13v896h-128v-896q-51 0 -101.5 13.5t-87 33t-66 39t-43.5 32.5l-15 14l-183 -207 q-20 -21 -48 -21q-24 0 -43 16q-19 18 -20.5 44.5t15.5 46.5l202 227q-58 114 -58 274h-224q-26 0 -45 19t-19 45t19 45t45 19h224v294l-173 173q-19 19 -19 45t19 45t45 19t45 -19l173 -173h844l173 173q19 19 45 19t45 -19t19 -45t-19 -45l-173 -173v-294h224q26 0 45 -19 t19 -45zM1152 1152h-640q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5z" />
+<glyph unicode="&#xf189;" horiz-adv-x="1920" d="M1917 1016q23 -64 -150 -294q-24 -32 -65 -85q-78 -100 -90 -131q-17 -41 14 -81q17 -21 81 -82h1l1 -1l1 -1l2 -2q141 -131 191 -221q3 -5 6.5 -12.5t7 -26.5t-0.5 -34t-25 -27.5t-59 -12.5l-256 -4q-24 -5 -56 5t-52 22l-20 12q-30 21 -70 64t-68.5 77.5t-61 58 t-56.5 15.5q-3 -1 -8 -3.5t-17 -14.5t-21.5 -29.5t-17 -52t-6.5 -77.5q0 -15 -3.5 -27.5t-7.5 -18.5l-4 -5q-18 -19 -53 -22h-115q-71 -4 -146 16.5t-131.5 53t-103 66t-70.5 57.5l-25 24q-10 10 -27.5 30t-71.5 91t-106 151t-122.5 211t-130.5 272q-6 16 -6 27t3 16l4 6 q15 19 57 19l274 2q12 -2 23 -6.5t16 -8.5l5 -3q16 -11 24 -32q20 -50 46 -103.5t41 -81.5l16 -29q29 -60 56 -104t48.5 -68.5t41.5 -38.5t34 -14t27 5q2 1 5 5t12 22t13.5 47t9.5 81t0 125q-2 40 -9 73t-14 46l-6 12q-25 34 -85 43q-13 2 5 24q17 19 38 30q53 26 239 24 q82 -1 135 -13q20 -5 33.5 -13.5t20.5 -24t10.5 -32t3.5 -45.5t-1 -55t-2.5 -70.5t-1.5 -82.5q0 -11 -1 -42t-0.5 -48t3.5 -40.5t11.5 -39t22.5 -24.5q8 -2 17 -4t26 11t38 34.5t52 67t68 107.5q60 104 107 225q4 10 10 17.5t11 10.5l4 3l5 2.5t13 3t20 0.5l288 2 q39 5 64 -2.5t31 -16.5z" />
+<glyph unicode="&#xf18a;" horiz-adv-x="1792" d="M675 252q21 34 11 69t-45 50q-34 14 -73 1t-60 -46q-22 -34 -13 -68.5t43 -50.5t74.5 -2.5t62.5 47.5zM769 373q8 13 3.5 26.5t-17.5 18.5q-14 5 -28.5 -0.5t-21.5 -18.5q-17 -31 13 -45q14 -5 29 0.5t22 18.5zM943 266q-45 -102 -158 -150t-224 -12 q-107 34 -147.5 126.5t6.5 187.5q47 93 151.5 139t210.5 19q111 -29 158.5 -119.5t2.5 -190.5zM1255 426q-9 96 -89 170t-208.5 109t-274.5 21q-223 -23 -369.5 -141.5t-132.5 -264.5q9 -96 89 -170t208.5 -109t274.5 -21q223 23 369.5 141.5t132.5 264.5zM1563 422 q0 -68 -37 -139.5t-109 -137t-168.5 -117.5t-226 -83t-270.5 -31t-275 33.5t-240.5 93t-171.5 151t-65 199.5q0 115 69.5 245t197.5 258q169 169 341.5 236t246.5 -7q65 -64 20 -209q-4 -14 -1 -20t10 -7t14.5 0.5t13.5 3.5l6 2q139 59 246 59t153 -61q45 -63 0 -178 q-2 -13 -4.5 -20t4.5 -12.5t12 -7.5t17 -6q57 -18 103 -47t80 -81.5t34 -116.5zM1489 1046q42 -47 54.5 -108.5t-6.5 -117.5q-8 -23 -29.5 -34t-44.5 -4q-23 8 -34 29.5t-4 44.5q20 63 -24 111t-107 35q-24 -5 -45 8t-25 37q-5 24 8 44.5t37 25.5q60 13 119 -5.5t101 -65.5z M1670 1209q87 -96 112.5 -222.5t-13.5 -241.5q-9 -27 -34 -40t-52 -4t-40 34t-5 52q28 82 10 172t-80 158q-62 69 -148 95.5t-173 8.5q-28 -6 -52 9.5t-30 43.5t9.5 51.5t43.5 29.5q123 26 244 -11.5t208 -134.5z" />
+<glyph unicode="&#xf18b;" d="M1133 -34q-171 -94 -368 -94q-196 0 -367 94q138 87 235.5 211t131.5 268q35 -144 132.5 -268t235.5 -211zM638 1394v-485q0 -252 -126.5 -459.5t-330.5 -306.5q-181 215 -181 495q0 187 83.5 349.5t229.5 269.5t325 137zM1536 638q0 -280 -181 -495 q-204 99 -330.5 306.5t-126.5 459.5v485q179 -30 325 -137t229.5 -269.5t83.5 -349.5z" />
+<glyph unicode="&#xf18c;" horiz-adv-x="1408" d="M1402 433q-32 -80 -76 -138t-91 -88.5t-99 -46.5t-101.5 -14.5t-96.5 8.5t-86.5 22t-69.5 27.5t-46 22.5l-17 10q-113 -228 -289.5 -359.5t-384.5 -132.5q-19 0 -32 13t-13 32t13 31.5t32 12.5q173 1 322.5 107.5t251.5 294.5q-36 -14 -72 -23t-83 -13t-91 2.5t-93 28.5 t-92 59t-84.5 100t-74.5 146q114 47 214 57t167.5 -7.5t124.5 -56.5t88.5 -77t56.5 -82q53 131 79 291q-7 -1 -18 -2.5t-46.5 -2.5t-69.5 0.5t-81.5 10t-88.5 23t-84 42.5t-75 65t-54.5 94.5t-28.5 127.5q70 28 133.5 36.5t112.5 -1t92 -30t73.5 -50t56 -61t42 -63t27.5 -56 t16 -39.5l4 -16q12 122 12 195q-8 6 -21.5 16t-49 44.5t-63.5 71.5t-54 93t-33 112.5t12 127t70 138.5q73 -25 127.5 -61.5t84.5 -76.5t48 -85t20.5 -89t-0.5 -85.5t-13 -76.5t-19 -62t-17 -42l-7 -15q1 -5 1 -50.5t-1 -71.5q3 7 10 18.5t30.5 43t50.5 58t71 55.5t91.5 44.5 t112 14.5t132.5 -24q-2 -78 -21.5 -141.5t-50 -104.5t-69.5 -71.5t-81.5 -45.5t-84.5 -24t-80 -9.5t-67.5 1t-46.5 4.5l-17 3q-23 -147 -73 -283q6 7 18 18.5t49.5 41t77.5 52.5t99.5 42t117.5 20t129 -23.5t137 -77.5z" />
+<glyph unicode="&#xf18d;" horiz-adv-x="1280" d="M1259 283v-66q0 -85 -57.5 -144.5t-138.5 -59.5h-57l-260 -269v269h-529q-81 0 -138.5 59.5t-57.5 144.5v66h1238zM1259 609v-255h-1238v255h1238zM1259 937v-255h-1238v255h1238zM1259 1077v-67h-1238v67q0 84 57.5 143.5t138.5 59.5h846q81 0 138.5 -59.5t57.5 -143.5z " />
+<glyph unicode="&#xf18e;" d="M1152 640q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192h-352q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h352v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf190;" d="M1152 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-352v-192q0 -14 -9 -23t-23 -9q-12 0 -24 10l-319 319q-9 9 -9 23t9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h352q13 0 22.5 -9.5t9.5 -22.5zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf191;" d="M1024 960v-640q0 -26 -19 -45t-45 -19q-20 0 -37 12l-448 320q-27 19 -27 52t27 52l448 320q17 12 37 12q26 0 45 -19t19 -45zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5z M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf192;" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5 t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf193;" horiz-adv-x="1664" d="M1023 349l102 -204q-58 -179 -210 -290t-339 -111q-156 0 -288.5 77.5t-210 210t-77.5 288.5q0 181 104.5 330t274.5 211l17 -131q-122 -54 -195 -165.5t-73 -244.5q0 -185 131.5 -316.5t316.5 -131.5q126 0 232.5 65t165 175.5t49.5 236.5zM1571 249l58 -114l-256 -128 q-13 -7 -29 -7q-40 0 -57 35l-239 477h-472q-24 0 -42.5 16.5t-21.5 40.5l-96 779q-2 16 6 42q14 51 57 82.5t97 31.5q66 0 113 -47t47 -113q0 -69 -52 -117.5t-120 -41.5l37 -289h423v-128h-407l16 -128h455q40 0 57 -35l228 -455z" />
+<glyph unicode="&#xf194;" d="M1254 899q16 85 -21 132q-52 65 -187 45q-17 -3 -41 -12.5t-57.5 -30.5t-64.5 -48.5t-59.5 -70t-44.5 -91.5q80 7 113.5 -16t26.5 -99q-5 -52 -52 -143q-43 -78 -71 -99q-44 -32 -87 14q-23 24 -37.5 64.5t-19 73t-10 84t-8.5 71.5q-23 129 -34 164q-12 37 -35.5 69 t-50.5 40q-57 16 -127 -25q-54 -32 -136.5 -106t-122.5 -102v-7q16 -8 25.5 -26t21.5 -20q21 -3 54.5 8.5t58 10.5t41.5 -30q11 -18 18.5 -38.5t15 -48t12.5 -40.5q17 -46 53 -187q36 -146 57 -197q42 -99 103 -125q43 -12 85 -1.5t76 31.5q131 77 250 237 q104 139 172.5 292.5t82.5 226.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf195;" horiz-adv-x="1152" d="M1152 704q0 -191 -94.5 -353t-256.5 -256.5t-353 -94.5h-160q-14 0 -23 9t-9 23v611l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v93l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v250q0 14 9 23t23 9h160 q14 0 23 -9t9 -23v-181l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-93l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-487q188 13 318 151t130 328q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf196;" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-352v-352q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v352h-352q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h352v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-352h352q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832 q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf197;" horiz-adv-x="2176" d="M620 416q-110 -64 -268 -64h-128v64h-64q-13 0 -22.5 23.5t-9.5 56.5q0 24 7 49q-58 2 -96.5 10.5t-38.5 20.5t38.5 20.5t96.5 10.5q-7 25 -7 49q0 33 9.5 56.5t22.5 23.5h64v64h128q158 0 268 -64h1113q42 -7 106.5 -18t80.5 -14q89 -15 150 -40.5t83.5 -47.5t22.5 -40 t-22.5 -40t-83.5 -47.5t-150 -40.5q-16 -3 -80.5 -14t-106.5 -18h-1113zM1739 668q53 -36 53 -92t-53 -92l81 -30q68 48 68 122t-68 122zM625 400h1015q-217 -38 -456 -80q-57 0 -113 -24t-83 -48l-28 -24l-288 -288q-26 -26 -70.5 -45t-89.5 -19h-96l-93 464h29 q157 0 273 64zM352 816h-29l93 464h96q46 0 90 -19t70 -45l288 -288q4 -4 11 -10.5t30.5 -23t48.5 -29t61.5 -23t72.5 -10.5l456 -80h-1015q-116 64 -273 64z" />
+<glyph unicode="&#xf198;" horiz-adv-x="1664" d="M1519 760q62 0 103.5 -40.5t41.5 -101.5q0 -97 -93 -130l-172 -59l56 -167q7 -21 7 -47q0 -59 -42 -102t-101 -43q-47 0 -85.5 27t-53.5 72l-55 165l-310 -106l55 -164q8 -24 8 -47q0 -59 -42 -102t-102 -43q-47 0 -85 27t-53 72l-55 163l-153 -53q-29 -9 -50 -9 q-61 0 -101.5 40t-40.5 101q0 47 27.5 85t71.5 53l156 53l-105 313l-156 -54q-26 -8 -48 -8q-60 0 -101 40.5t-41 100.5q0 47 27.5 85t71.5 53l157 53l-53 159q-8 24 -8 47q0 60 42 102.5t102 42.5q47 0 85 -27t53 -72l54 -160l310 105l-54 160q-8 24 -8 47q0 59 42.5 102 t101.5 43q47 0 85.5 -27.5t53.5 -71.5l53 -161l162 55q21 6 43 6q60 0 102.5 -39.5t42.5 -98.5q0 -45 -30 -81.5t-74 -51.5l-157 -54l105 -316l164 56q24 8 46 8zM725 498l310 105l-105 315l-310 -107z" />
+<glyph unicode="&#xf199;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM1280 352v436q-31 -35 -64 -55q-34 -22 -132.5 -85t-151.5 -99q-98 -69 -164 -69v0v0q-66 0 -164 69 q-46 32 -141.5 92.5t-142.5 92.5q-12 8 -33 27t-31 27v-436q0 -40 28 -68t68 -28h832q40 0 68 28t28 68zM1280 925q0 41 -27.5 70t-68.5 29h-832q-40 0 -68 -28t-28 -68q0 -37 30.5 -76.5t67.5 -64.5q47 -32 137.5 -89t129.5 -83q3 -2 17 -11.5t21 -14t21 -13t23.5 -13 t21.5 -9.5t22.5 -7.5t20.5 -2.5t20.5 2.5t22.5 7.5t21.5 9.5t23.5 13t21 13t21 14t17 11.5l267 174q35 23 66.5 62.5t31.5 73.5z" />
+<glyph unicode="&#xf19a;" horiz-adv-x="1792" d="M127 640q0 163 67 313l367 -1005q-196 95 -315 281t-119 411zM1415 679q0 -19 -2.5 -38.5t-10 -49.5t-11.5 -44t-17.5 -59t-17.5 -58l-76 -256l-278 826q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-75 1 -202 10q-12 1 -20.5 -5t-11.5 -15t-1.5 -18.5t9 -16.5 t19.5 -8l80 -8l120 -328l-168 -504l-280 832q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-7 0 -23 0.5t-26 0.5q105 160 274.5 253.5t367.5 93.5q147 0 280.5 -53t238.5 -149h-10q-55 0 -92 -40.5t-37 -95.5q0 -12 2 -24t4 -21.5t8 -23t9 -21t12 -22.5t12.5 -21 t14.5 -24t14 -23q63 -107 63 -212zM909 573l237 -647q1 -6 5 -11q-126 -44 -255 -44q-112 0 -217 32zM1570 1009q95 -174 95 -369q0 -209 -104 -385.5t-279 -278.5l235 678q59 169 59 276q0 42 -6 79zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286 t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM896 -215q173 0 331.5 68t273 182.5t182.5 273t68 331.5t-68 331.5t-182.5 273t-273 182.5t-331.5 68t-331.5 -68t-273 -182.5t-182.5 -273t-68 -331.5t68 -331.5t182.5 -273 t273 -182.5t331.5 -68z" />
+<glyph unicode="&#xf19b;" horiz-adv-x="1792" d="M1086 1536v-1536l-272 -128q-228 20 -414 102t-293 208.5t-107 272.5q0 140 100.5 263.5t275 205.5t391.5 108v-172q-217 -38 -356.5 -150t-139.5 -255q0 -152 154.5 -267t388.5 -145v1360zM1755 954l37 -390l-525 114l147 83q-119 70 -280 99v172q277 -33 481 -157z" />
+<glyph unicode="&#xf19c;" horiz-adv-x="2048" d="M960 1536l960 -384v-128h-128q0 -26 -20.5 -45t-48.5 -19h-1526q-28 0 -48.5 19t-20.5 45h-128v128zM256 896h256v-768h128v768h256v-768h128v768h256v-768h128v768h256v-768h59q28 0 48.5 -19t20.5 -45v-64h-1664v64q0 26 20.5 45t48.5 19h59v768zM1851 -64 q28 0 48.5 -19t20.5 -45v-128h-1920v128q0 26 20.5 45t48.5 19h1782z" />
+<glyph unicode="&#xf19d;" horiz-adv-x="2304" d="M1774 700l18 -316q4 -69 -82 -128t-235 -93.5t-323 -34.5t-323 34.5t-235 93.5t-82 128l18 316l574 -181q22 -7 48 -7t48 7zM2304 1024q0 -23 -22 -31l-1120 -352q-4 -1 -10 -1t-10 1l-652 206q-43 -34 -71 -111.5t-34 -178.5q63 -36 63 -109q0 -69 -58 -107l58 -433 q2 -14 -8 -25q-9 -11 -24 -11h-192q-15 0 -24 11q-10 11 -8 25l58 433q-58 38 -58 107q0 73 65 111q11 207 98 330l-333 104q-22 8 -22 31t22 31l1120 352q4 1 10 1t10 -1l1120 -352q22 -8 22 -31z" />
+<glyph unicode="&#xf19e;" d="M859 579l13 -707q-62 11 -105 11q-41 0 -105 -11l13 707q-40 69 -168.5 295.5t-216.5 374.5t-181 287q58 -15 108 -15q43 0 111 15q63 -111 133.5 -229.5t167 -276.5t138.5 -227q37 61 109.5 177.5t117.5 190t105 176t107 189.5q54 -14 107 -14q56 0 114 14v0 q-28 -39 -60 -88.5t-49.5 -78.5t-56.5 -96t-49 -84q-146 -248 -353 -610z" />
+<glyph unicode="&#xf1a0;" horiz-adv-x="1280" d="M981 197q0 25 -7 49t-14.5 42t-27 41.5t-29.5 35t-38.5 34.5t-36.5 29t-41.5 30t-36.5 26q-16 2 -49 2q-53 0 -104.5 -7t-107 -25t-97 -46t-68.5 -74.5t-27 -105.5q0 -56 23.5 -102t61 -75.5t87 -50t100 -29t101.5 -8.5q58 0 111.5 13t99 39t73 73t27.5 109zM864 1055 q0 59 -17 125.5t-48 129t-84 103.5t-117 41q-42 0 -82.5 -19.5t-66.5 -52.5q-46 -59 -46 -160q0 -46 10 -97.5t31.5 -103t52 -92.5t75 -67t96.5 -26q37 0 77.5 16.5t65.5 43.5q53 56 53 159zM752 1536h417l-137 -88h-132q75 -63 113 -133t38 -160q0 -72 -24.5 -129.5 t-59.5 -93t-69.5 -65t-59 -61.5t-24.5 -66q0 -36 32 -70.5t77 -68t90.5 -73.5t77.5 -104t32 -142q0 -91 -49 -173q-71 -122 -209.5 -179.5t-298.5 -57.5q-132 0 -246.5 41.5t-172.5 137.5q-36 59 -36 131q0 81 44.5 150t118.5 115q131 82 404 100q-32 41 -47.5 73.5 t-15.5 73.5q0 40 21 85q-46 -4 -68 -4q-148 0 -249.5 96.5t-101.5 244.5q0 82 36 159t99 131q76 66 182 98t218 32z" />
+<glyph unicode="&#xf1a1;" horiz-adv-x="1984" d="M831 572q0 -56 -40.5 -96t-96.5 -40q-57 0 -98 40t-41 96q0 57 41.5 98t97.5 41t96.5 -41t40.5 -98zM1292 711q56 0 96.5 -41t40.5 -98q0 -56 -40.5 -96t-96.5 -40q-57 0 -98 40t-41 96q0 57 41.5 98t97.5 41zM1984 722q0 -62 -31 -114t-83 -82q5 -33 5 -61 q0 -121 -68.5 -230.5t-197.5 -193.5q-125 -82 -285.5 -125.5t-335.5 -43.5q-176 0 -336.5 43.5t-284.5 125.5q-129 84 -197.5 193t-68.5 231q0 29 5 66q-48 31 -77 81.5t-29 109.5q0 94 66 160t160 66q83 0 148 -55q248 158 592 164l134 423q4 14 17.5 21.5t28.5 4.5 l347 -82q22 50 68.5 81t102.5 31q77 0 131.5 -54.5t54.5 -131.5t-54.5 -132t-131.5 -55q-76 0 -130.5 54t-55.5 131l-315 74l-116 -366q327 -14 560 -166q64 58 151 58q94 0 160 -66t66 -160zM1664 1459q-45 0 -77 -32t-32 -77t32 -77t77 -32t77 32t32 77t-32 77t-77 32z M77 722q0 -67 51 -111q49 131 180 235q-36 25 -82 25q-62 0 -105.5 -43.5t-43.5 -105.5zM1567 105q112 73 171.5 166t59.5 194t-59.5 193.5t-171.5 165.5q-116 75 -265.5 115.5t-313.5 40.5t-313.5 -40.5t-265.5 -115.5q-112 -73 -171.5 -165.5t-59.5 -193.5t59.5 -194 t171.5 -166q116 -75 265.5 -115.5t313.5 -40.5t313.5 40.5t265.5 115.5zM1850 605q57 46 57 117q0 62 -43.5 105.5t-105.5 43.5q-49 0 -86 -28q131 -105 178 -238zM1258 237q11 11 27 11t27 -11t11 -27.5t-11 -27.5q-99 -99 -319 -99h-2q-220 0 -319 99q-11 11 -11 27.5 t11 27.5t27 11t27 -11q77 -77 265 -77h2q188 0 265 77z" />
+<glyph unicode="&#xf1a2;" d="M950 393q7 7 17.5 7t17.5 -7t7 -18t-7 -18q-65 -64 -208 -64h-1h-1q-143 0 -207 64q-8 7 -8 18t8 18q7 7 17.5 7t17.5 -7q49 -51 172 -51h1h1q122 0 173 51zM671 613q0 -37 -26 -64t-63 -27t-63 27t-26 64t26 63t63 26t63 -26t26 -63zM1214 1049q-29 0 -50 21t-21 50 q0 30 21 51t50 21q30 0 51 -21t21 -51q0 -29 -21 -50t-51 -21zM1216 1408q132 0 226 -94t94 -227v-894q0 -133 -94 -227t-226 -94h-896q-132 0 -226 94t-94 227v894q0 133 94 227t226 94h896zM1321 596q35 14 57 45.5t22 70.5q0 51 -36 87.5t-87 36.5q-60 0 -98 -48 q-151 107 -375 115l83 265l206 -49q1 -50 36.5 -85t84.5 -35q50 0 86 35.5t36 85.5t-36 86t-86 36q-36 0 -66 -20.5t-45 -53.5l-227 54q-9 2 -17.5 -2.5t-11.5 -14.5l-95 -302q-224 -4 -381 -113q-36 43 -93 43q-51 0 -87 -36.5t-36 -87.5q0 -37 19.5 -67.5t52.5 -45.5 q-7 -25 -7 -54q0 -98 74 -181.5t201.5 -132t278.5 -48.5q150 0 277.5 48.5t201.5 132t74 181.5q0 27 -6 54zM971 702q37 0 63 -26t26 -63t-26 -64t-63 -27t-63 27t-26 64t26 63t63 26z" />
+<glyph unicode="&#xf1a3;" d="M866 697l90 27v62q0 79 -58 135t-138 56t-138 -55.5t-58 -134.5v-283q0 -20 -14 -33.5t-33 -13.5t-32.5 13.5t-13.5 33.5v120h-151v-122q0 -82 57.5 -139t139.5 -57q81 0 138.5 56.5t57.5 136.5v280q0 19 13.5 33t33.5 14q19 0 32.5 -14t13.5 -33v-54zM1199 502v122h-150 v-126q0 -20 -13.5 -33.5t-33.5 -13.5q-19 0 -32.5 14t-13.5 33v123l-90 -26l-60 28v-123q0 -80 58 -137t139 -57t138.5 57t57.5 139zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103 t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf1a4;" horiz-adv-x="1920" d="M1062 824v118q0 42 -30 72t-72 30t-72 -30t-30 -72v-612q0 -175 -126 -299t-303 -124q-178 0 -303.5 125.5t-125.5 303.5v266h328v-262q0 -43 30 -72.5t72 -29.5t72 29.5t30 72.5v620q0 171 126.5 292t301.5 121q176 0 302 -122t126 -294v-136l-195 -58zM1592 602h328 v-266q0 -178 -125.5 -303.5t-303.5 -125.5q-177 0 -303 124.5t-126 300.5v268l131 -61l195 58v-270q0 -42 30 -71.5t72 -29.5t72 29.5t30 71.5v275z" />
+<glyph unicode="&#xf1a5;" d="M1472 160v480h-704v704h-480q-93 0 -158.5 -65.5t-65.5 -158.5v-480h704v-704h480q93 0 158.5 65.5t65.5 158.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" />
+<glyph unicode="&#xf1a6;" horiz-adv-x="2048" d="M328 1254h204v-983h-532v697h328v286zM328 435v369h-123v-369h123zM614 968v-697h205v697h-205zM614 1254v-204h205v204h-205zM901 968h533v-942h-533v163h328v82h-328v697zM1229 435v369h-123v-369h123zM1516 968h532v-942h-532v163h327v82h-327v697zM1843 435v369h-123 v-369h123z" />
+<glyph unicode="&#xf1a7;" d="M1046 516q0 -64 -38 -109t-91 -45q-43 0 -70 15v277q28 17 70 17q53 0 91 -45.5t38 -109.5zM703 944q0 -64 -38 -109.5t-91 -45.5q-43 0 -70 15v277q28 17 70 17q53 0 91 -45t38 -109zM1265 513q0 134 -88 229t-213 95q-20 0 -39 -3q-23 -78 -78 -136q-87 -95 -211 -101 v-636l211 41v206q51 -19 117 -19q125 0 213 95t88 229zM922 940q0 134 -88.5 229t-213.5 95q-74 0 -141 -36h-186v-840l211 41v206q55 -19 116 -19q125 0 213.5 95t88.5 229zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960 q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf1a8;" horiz-adv-x="2038" d="M1222 607q75 3 143.5 -20.5t118 -58.5t101 -94.5t84 -108t75.5 -120.5q33 -56 78.5 -109t75.5 -80.5t99 -88.5q-48 -30 -108.5 -57.5t-138.5 -59t-114 -47.5q-44 37 -74 115t-43.5 164.5t-33 180.5t-42.5 168.5t-72.5 123t-122.5 48.5l-10 -2l-6 -4q4 -5 13 -14 q6 -5 28 -23.5t25.5 -22t19 -18t18 -20.5t11.5 -21t10.5 -27.5t4.5 -31t4 -40.5l1 -33q1 -26 -2.5 -57.5t-7.5 -52t-12.5 -58.5t-11.5 -53q-35 1 -101 -9.5t-98 -10.5q-39 0 -72 10q-2 16 -2 47q0 74 3 96q2 13 31.5 41.5t57 59t26.5 51.5q-24 2 -43 -24 q-36 -53 -111.5 -99.5t-136.5 -46.5q-25 0 -75.5 63t-106.5 139.5t-84 96.5q-6 4 -27 30q-482 -112 -513 -112q-16 0 -28 11t-12 27q0 15 8.5 26.5t22.5 14.5l486 106q-8 14 -8 25t5.5 17.5t16 11.5t20 7t23 4.5t18.5 4.5q4 1 15.5 7.5t17.5 6.5q15 0 28 -16t20 -33 q163 37 172 37q17 0 29.5 -11t12.5 -28q0 -15 -8.5 -26t-23.5 -14l-182 -40l-1 -16q-1 -26 81.5 -117.5t104.5 -91.5q47 0 119 80t72 129q0 36 -23.5 53t-51 18.5t-51 11.5t-23.5 34q0 16 10 34l-68 19q43 44 43 117q0 26 -5 58q82 16 144 16q44 0 71.5 -1.5t48.5 -8.5 t31 -13.5t20.5 -24.5t15.5 -33.5t17 -47.5t24 -60l50 25q-3 -40 -23 -60t-42.5 -21t-40 -6.5t-16.5 -20.5zM1282 842q-5 5 -13.5 15.5t-12 14.5t-10.5 11.5t-10 10.5l-8 8t-8.5 7.5t-8 5t-8.5 4.5q-7 3 -14.5 5t-20.5 2.5t-22 0.5h-32.5h-37.5q-126 0 -217 -43 q16 30 36 46.5t54 29.5t65.5 36t46 36.5t50 55t43.5 50.5q12 -9 28 -31.5t32 -36.5t38 -13l12 1v-76l22 -1q247 95 371 190q28 21 50 39t42.5 37.5t33 31t29.5 34t24 31t24.5 37t23 38t27 47.5t29.5 53l7 9q-2 -53 -43 -139q-79 -165 -205 -264t-306 -142q-14 -3 -42 -7.5 t-50 -9.5t-39 -14q3 -19 24.5 -46t21.5 -34q0 -11 -26 -30zM1061 -79q39 26 131.5 47.5t146.5 21.5q9 0 22.5 -15.5t28 -42.5t26 -50t24 -51t14.5 -33q-121 -45 -244 -45q-61 0 -125 11zM822 568l48 12l109 -177l-73 -48zM1323 51q3 -15 3 -16q0 -7 -17.5 -14.5t-46 -13 t-54 -9.5t-53.5 -7.5t-32 -4.5l-7 43q21 2 60.5 8.5t72 10t60.5 3.5h14zM866 679l-96 -20l-6 17q10 1 32.5 7t34.5 6q19 0 35 -10zM1061 45h31l10 -83l-41 -12v95zM1950 1535v1v-1zM1950 1535l-1 -5l-2 -2l1 3zM1950 1535l1 1z" />
+<glyph unicode="&#xf1a9;" d="M1167 -50q-5 19 -24 5q-30 -22 -87 -39t-131 -17q-129 0 -193 49q-5 4 -13 4q-11 0 -26 -12q-7 -6 -7.5 -16t7.5 -20q34 -32 87.5 -46t102.5 -12.5t99 4.5q41 4 84.5 20.5t65 30t28.5 20.5q12 12 7 29zM1128 65q-19 47 -39 61q-23 15 -76 15q-47 0 -71 -10 q-29 -12 -78 -56q-26 -24 -12 -44q9 -8 17.5 -4.5t31.5 23.5q3 2 10.5 8.5t10.5 8.5t10 7t11.5 7t12.5 5t15 4.5t16.5 2.5t20.5 1q27 0 44.5 -7.5t23 -14.5t13.5 -22q10 -17 12.5 -20t12.5 1q23 12 14 34zM1483 346q0 22 -5 44.5t-16.5 45t-34 36.5t-52.5 14 q-33 0 -97 -41.5t-129 -83.5t-101 -42q-27 -1 -63.5 19t-76 49t-83.5 58t-100 49t-111 19q-115 -1 -197 -78.5t-84 -178.5q-2 -112 74 -164q29 -20 62.5 -28.5t103.5 -8.5q57 0 132 32.5t134 71t120 70.5t93 31q26 -1 65 -31.5t71.5 -67t68 -67.5t55.5 -32q35 -3 58.5 14 t55.5 63q28 41 42.5 101t14.5 106zM1536 506q0 -164 -62 -304.5t-166 -236t-242.5 -149.5t-290.5 -54t-293 57.5t-247.5 157t-170.5 241.5t-64 302q0 89 19.5 172.5t49 145.5t70.5 118.5t78.5 94t78.5 69.5t64.5 46.5t42.5 24.5q14 8 51 26.5t54.5 28.5t48 30t60.5 44 q36 28 58 72.5t30 125.5q129 -155 186 -193q44 -29 130 -68t129 -66q21 -13 39 -25t60.5 -46.5t76 -70.5t75 -95t69 -122t47 -148.5t19.5 -177.5z" />
+<glyph unicode="&#xf1aa;" d="M1070 463l-160 -160l-151 -152l-30 -30q-65 -64 -151.5 -87t-171.5 -2q-16 -70 -72 -115t-129 -45q-85 0 -145 60.5t-60 145.5q0 72 44.5 128t113.5 72q-22 86 1 173t88 152l12 12l151 -152l-11 -11q-37 -37 -37 -89t37 -90q37 -37 89 -37t89 37l30 30l151 152l161 160z M729 1145l12 -12l-152 -152l-12 12q-37 37 -89 37t-89 -37t-37 -89.5t37 -89.5l29 -29l152 -152l160 -160l-151 -152l-161 160l-151 152l-30 30q-68 67 -90 159.5t5 179.5q-70 15 -115 71t-45 129q0 85 60 145.5t145 60.5q76 0 133.5 -49t69.5 -123q84 20 169.5 -3.5 t149.5 -87.5zM1536 78q0 -85 -60 -145.5t-145 -60.5q-74 0 -131 47t-71 118q-86 -28 -179.5 -6t-161.5 90l-11 12l151 152l12 -12q37 -37 89 -37t89 37t37 89t-37 89l-30 30l-152 152l-160 160l152 152l160 -160l152 -152l29 -30q64 -64 87.5 -150.5t2.5 -171.5 q76 -11 126.5 -68.5t50.5 -134.5zM1534 1202q0 -77 -51 -135t-127 -69q26 -85 3 -176.5t-90 -158.5l-12 -12l-151 152l12 12q37 37 37 89t-37 89t-89 37t-89 -37l-30 -30l-152 -152l-160 -160l-152 152l161 160l152 152l29 30q67 67 159 89.5t178 -3.5q11 75 68.5 126 t135.5 51q85 0 145 -60.5t60 -145.5z" />
+<glyph unicode="&#xf1ab;" d="M654 458q-1 -3 -12.5 0.5t-31.5 11.5l-20 9q-44 20 -87 49q-7 5 -41 31.5t-38 28.5q-67 -103 -134 -181q-81 -95 -105 -110q-4 -2 -19.5 -4t-18.5 0q6 4 82 92q21 24 85.5 115t78.5 118q17 30 51 98.5t36 77.5q-8 1 -110 -33q-8 -2 -27.5 -7.5t-34.5 -9.5t-17 -5 q-2 -2 -2 -10.5t-1 -9.5q-5 -10 -31 -15q-23 -7 -47 0q-18 4 -28 21q-4 6 -5 23q6 2 24.5 5t29.5 6q58 16 105 32q100 35 102 35q10 2 43 19.5t44 21.5q9 3 21.5 8t14.5 5.5t6 -0.5q2 -12 -1 -33q0 -2 -12.5 -27t-26.5 -53.5t-17 -33.5q-25 -50 -77 -131l64 -28 q12 -6 74.5 -32t67.5 -28q4 -1 10.5 -25.5t4.5 -30.5zM449 944q3 -15 -4 -28q-12 -23 -50 -38q-30 -12 -60 -12q-26 3 -49 26q-14 15 -18 41l1 3q3 -3 19.5 -5t26.5 0t58 16q36 12 55 14q17 0 21 -17zM1147 815l63 -227l-139 42zM39 15l694 232v1032l-694 -233v-1031z M1280 332l102 -31l-181 657l-100 31l-216 -536l102 -31l45 110l211 -65zM777 1294l573 -184v380zM1088 -29l158 -13l-54 -160l-40 66q-130 -83 -276 -108q-58 -12 -91 -12h-84q-79 0 -199.5 39t-183.5 85q-8 7 -8 16q0 8 5 13.5t13 5.5q4 0 18 -7.5t30.5 -16.5t20.5 -11 q73 -37 159.5 -61.5t157.5 -24.5q95 0 167 14.5t157 50.5q15 7 30.5 15.5t34 19t28.5 16.5zM1536 1050v-1079l-774 246q-14 -6 -375 -127.5t-368 -121.5q-13 0 -18 13q0 1 -1 3v1078q3 9 4 10q5 6 20 11q106 35 149 50v384l558 -198q2 0 160.5 55t316 108.5t161.5 53.5 q20 0 20 -21v-418z" />
+<glyph unicode="&#xf1ac;" horiz-adv-x="1792" d="M288 1152q66 0 113 -47t47 -113v-1088q0 -66 -47 -113t-113 -47h-128q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h128zM1664 989q58 -34 93 -93t35 -128v-768q0 -106 -75 -181t-181 -75h-864q-66 0 -113 47t-47 113v1536q0 40 28 68t68 28h672q40 0 88 -20t76 -48 l152 -152q28 -28 48 -76t20 -88v-163zM928 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM928 256v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM928 512v128q0 14 -9 23 t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1184 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1184 256v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128 q14 0 23 9t9 23zM1184 512v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 256v128q0 14 -9 23t-23 9h-128 q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 512v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1536 896v256h-160q-40 0 -68 28t-28 68v160h-640v-512h896z" />
+<glyph unicode="&#xf1ad;" d="M1344 1536q26 0 45 -19t19 -45v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280zM512 1248v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 992v-64q0 -14 9 -23t23 -9h64q14 0 23 9 t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 736v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 480v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM384 160v64 q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64 q14 0 23 9t9 23zM384 928v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 -96v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9 t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM896 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 928v64 q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 160v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64 q14 0 23 9t9 23zM1152 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 928v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9 t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23z" />
+<glyph unicode="&#xf1ae;" horiz-adv-x="1280" d="M1188 988l-292 -292v-824q0 -46 -33 -79t-79 -33t-79 33t-33 79v384h-64v-384q0 -46 -33 -79t-79 -33t-79 33t-33 79v824l-292 292q-28 28 -28 68t28 68t68 28t68 -28l228 -228h368l228 228q28 28 68 28t68 -28t28 -68t-28 -68zM864 1152q0 -93 -65.5 -158.5 t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf1b0;" horiz-adv-x="1664" d="M780 1064q0 -60 -19 -113.5t-63 -92.5t-105 -39q-76 0 -138 57.5t-92 135.5t-30 151q0 60 19 113.5t63 92.5t105 39q77 0 138.5 -57.5t91.5 -135t30 -151.5zM438 581q0 -80 -42 -139t-119 -59q-76 0 -141.5 55.5t-100.5 133.5t-35 152q0 80 42 139.5t119 59.5 q76 0 141.5 -55.5t100.5 -134t35 -152.5zM832 608q118 0 255 -97.5t229 -237t92 -254.5q0 -46 -17 -76.5t-48.5 -45t-64.5 -20t-76 -5.5q-68 0 -187.5 45t-182.5 45q-66 0 -192.5 -44.5t-200.5 -44.5q-183 0 -183 146q0 86 56 191.5t139.5 192.5t187.5 146t193 59zM1071 819 q-61 0 -105 39t-63 92.5t-19 113.5q0 74 30 151.5t91.5 135t138.5 57.5q61 0 105 -39t63 -92.5t19 -113.5q0 -73 -30 -151t-92 -135.5t-138 -57.5zM1503 923q77 0 119 -59.5t42 -139.5q0 -74 -35 -152t-100.5 -133.5t-141.5 -55.5q-77 0 -119 59t-42 139q0 74 35 152.5 t100.5 134t141.5 55.5z" />
+<glyph unicode="&#xf1b1;" horiz-adv-x="768" d="M704 1008q0 -145 -57 -243.5t-152 -135.5l45 -821q2 -26 -16 -45t-44 -19h-192q-26 0 -44 19t-16 45l45 821q-95 37 -152 135.5t-57 243.5q0 128 42.5 249.5t117.5 200t160 78.5t160 -78.5t117.5 -200t42.5 -249.5z" />
+<glyph unicode="&#xf1b2;" horiz-adv-x="1792" d="M896 -93l640 349v636l-640 -233v-752zM832 772l698 254l-698 254l-698 -254zM1664 1024v-768q0 -35 -18 -65t-49 -47l-704 -384q-28 -16 -61 -16t-61 16l-704 384q-31 17 -49 47t-18 65v768q0 40 23 73t61 47l704 256q22 8 44 8t44 -8l704 -256q38 -14 61 -47t23 -73z " />
+<glyph unicode="&#xf1b3;" horiz-adv-x="2304" d="M640 -96l384 192v314l-384 -164v-342zM576 358l404 173l-404 173l-404 -173zM1664 -96l384 192v314l-384 -164v-342zM1600 358l404 173l-404 173l-404 -173zM1152 651l384 165v266l-384 -164v-267zM1088 1030l441 189l-441 189l-441 -189zM2176 512v-416q0 -36 -19 -67 t-52 -47l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-5 2 -7 4q-2 -2 -7 -4l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-33 16 -52 47t-19 67v416q0 38 21.5 70t56.5 48l434 186v400q0 38 21.5 70t56.5 48l448 192q23 10 50 10t50 -10l448 -192q35 -16 56.5 -48t21.5 -70 v-400l434 -186q36 -16 57 -48t21 -70z" />
+<glyph unicode="&#xf1b4;" horiz-adv-x="2048" d="M1848 1197h-511v-124h511v124zM1596 771q-90 0 -146 -52.5t-62 -142.5h408q-18 195 -200 195zM1612 186q63 0 122 32t76 87h221q-100 -307 -427 -307q-214 0 -340.5 132t-126.5 347q0 208 130.5 345.5t336.5 137.5q138 0 240.5 -68t153 -179t50.5 -248q0 -17 -2 -47h-658 q0 -111 57.5 -171.5t166.5 -60.5zM277 236h296q205 0 205 167q0 180 -199 180h-302v-347zM277 773h281q78 0 123.5 36.5t45.5 113.5q0 144 -190 144h-260v-294zM0 1282h594q87 0 155 -14t126.5 -47.5t90 -96.5t31.5 -154q0 -181 -172 -263q114 -32 172 -115t58 -204 q0 -75 -24.5 -136.5t-66 -103.5t-98.5 -71t-121 -42t-134 -13h-611v1260z" />
+<glyph unicode="&#xf1b5;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM499 1041h-371v-787h382q117 0 197 57.5t80 170.5q0 158 -143 200q107 52 107 164q0 57 -19.5 96.5 t-56.5 60.5t-79 29.5t-97 8.5zM477 723h-176v184h163q119 0 119 -90q0 -94 -106 -94zM486 388h-185v217h189q124 0 124 -113q0 -104 -128 -104zM1136 356q-68 0 -104 38t-36 107h411q1 10 1 30q0 132 -74.5 220.5t-203.5 88.5q-128 0 -210 -86t-82 -216q0 -135 79 -217 t213 -82q205 0 267 191h-138q-11 -34 -47.5 -54t-75.5 -20zM1126 722q113 0 124 -122h-254q4 56 39 89t91 33zM964 988h319v-77h-319v77z" />
+<glyph unicode="&#xf1b6;" horiz-adv-x="1792" d="M1582 954q0 -101 -71.5 -172.5t-172.5 -71.5t-172.5 71.5t-71.5 172.5t71.5 172.5t172.5 71.5t172.5 -71.5t71.5 -172.5zM812 212q0 104 -73 177t-177 73q-27 0 -54 -6l104 -42q77 -31 109.5 -106.5t1.5 -151.5q-31 -77 -107 -109t-152 -1q-21 8 -62 24.5t-61 24.5 q32 -60 91 -96.5t130 -36.5q104 0 177 73t73 177zM1642 953q0 126 -89.5 215.5t-215.5 89.5q-127 0 -216.5 -89.5t-89.5 -215.5q0 -127 89.5 -216t216.5 -89q126 0 215.5 89t89.5 216zM1792 953q0 -189 -133.5 -322t-321.5 -133l-437 -319q-12 -129 -109 -218t-229 -89 q-121 0 -214 76t-118 192l-230 92v429l389 -157q79 48 173 48q13 0 35 -2l284 407q2 187 135.5 319t320.5 132q188 0 321.5 -133.5t133.5 -321.5z" />
+<glyph unicode="&#xf1b7;" d="M1242 889q0 80 -57 136.5t-137 56.5t-136.5 -57t-56.5 -136q0 -80 56.5 -136.5t136.5 -56.5t137 56.5t57 136.5zM632 301q0 -83 -58 -140.5t-140 -57.5q-56 0 -103 29t-72 77q52 -20 98 -40q60 -24 120 1.5t85 86.5q24 60 -1.5 120t-86.5 84l-82 33q22 5 42 5 q82 0 140 -57.5t58 -140.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v153l172 -69q20 -92 93.5 -152t168.5 -60q104 0 181 70t87 173l345 252q150 0 255.5 105.5t105.5 254.5q0 150 -105.5 255.5t-255.5 105.5 q-148 0 -253 -104.5t-107 -252.5l-225 -322q-9 1 -28 1q-75 0 -137 -37l-297 119v468q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5zM1289 887q0 -100 -71 -170.5t-171 -70.5t-170.5 70.5t-70.5 170.5t70.5 171t170.5 71q101 0 171.5 -70.5t70.5 -171.5z " />
+<glyph unicode="&#xf1b8;" horiz-adv-x="1792" d="M836 367l-15 -368l-2 -22l-420 29q-36 3 -67 31.5t-47 65.5q-11 27 -14.5 55t4 65t12 55t21.5 64t19 53q78 -12 509 -28zM449 953l180 -379l-147 92q-63 -72 -111.5 -144.5t-72.5 -125t-39.5 -94.5t-18.5 -63l-4 -21l-190 357q-17 26 -18 56t6 47l8 18q35 63 114 188 l-140 86zM1680 436l-188 -359q-12 -29 -36.5 -46.5t-43.5 -20.5l-18 -4q-71 -7 -219 -12l8 -164l-230 367l211 362l7 -173q170 -16 283 -5t170 33zM895 1360q-47 -63 -265 -435l-317 187l-19 12l225 356q20 31 60 45t80 10q24 -2 48.5 -12t42 -21t41.5 -33t36 -34.5 t36 -39.5t32 -35zM1550 1053l212 -363q18 -37 12.5 -76t-27.5 -74q-13 -20 -33 -37t-38 -28t-48.5 -22t-47 -16t-51.5 -14t-46 -12q-34 72 -265 436l313 195zM1407 1279l142 83l-220 -373l-419 20l151 86q-34 89 -75 166t-75.5 123.5t-64.5 80t-47 46.5l-17 13l405 -1 q31 3 58 -10.5t39 -28.5l11 -15q39 -61 112 -190z" />
+<glyph unicode="&#xf1b9;" horiz-adv-x="2048" d="M480 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM516 768h1016l-89 357q-2 8 -14 17.5t-21 9.5h-768q-9 0 -21 -9.5t-14 -17.5zM1888 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM2048 544v-384 q0 -14 -9 -23t-23 -9h-96v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-1024v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94 104 157.5t179 63.5h768q98 0 179 -63.5t104 -157.5 l105 -419h28q93 0 158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf1ba;" horiz-adv-x="2048" d="M1824 640q93 0 158.5 -65.5t65.5 -158.5v-384q0 -14 -9 -23t-23 -9h-96v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-1024v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94 104 157.5 t179 63.5h128v224q0 14 9 23t23 9h448q14 0 23 -9t9 -23v-224h128q98 0 179 -63.5t104 -157.5l105 -419h28zM320 160q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47zM516 640h1016l-89 357q-2 8 -14 17.5t-21 9.5h-768q-9 0 -21 -9.5t-14 -17.5z M1728 160q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47z" />
+<glyph unicode="&#xf1bb;" d="M1504 64q0 -26 -19 -45t-45 -19h-462q1 -17 6 -87.5t5 -108.5q0 -25 -18 -42.5t-43 -17.5h-320q-25 0 -43 17.5t-18 42.5q0 38 5 108.5t6 87.5h-462q-26 0 -45 19t-19 45t19 45l402 403h-229q-26 0 -45 19t-19 45t19 45l402 403h-197q-26 0 -45 19t-19 45t19 45l384 384 q19 19 45 19t45 -19l384 -384q19 -19 19 -45t-19 -45t-45 -19h-197l402 -403q19 -19 19 -45t-19 -45t-45 -19h-229l402 -403q19 -19 19 -45z" />
+<glyph unicode="&#xf1bc;" d="M1127 326q0 32 -30 51q-193 115 -447 115q-133 0 -287 -34q-42 -9 -42 -52q0 -20 13.5 -34.5t35.5 -14.5q5 0 37 8q132 27 243 27q226 0 397 -103q19 -11 33 -11q19 0 33 13.5t14 34.5zM1223 541q0 40 -35 61q-237 141 -548 141q-153 0 -303 -42q-48 -13 -48 -64 q0 -25 17.5 -42.5t42.5 -17.5q7 0 37 8q122 33 251 33q279 0 488 -124q24 -13 38 -13q25 0 42.5 17.5t17.5 42.5zM1331 789q0 47 -40 70q-126 73 -293 110.5t-343 37.5q-204 0 -364 -47q-23 -7 -38.5 -25.5t-15.5 -48.5q0 -31 20.5 -52t51.5 -21q11 0 40 8q133 37 307 37 q159 0 309.5 -34t253.5 -95q21 -12 40 -12q29 0 50.5 20.5t21.5 51.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf1bd;" d="M1397 1408q58 0 98.5 -40.5t40.5 -98.5v-1258q0 -58 -40.5 -98.5t-98.5 -40.5h-1258q-58 0 -98.5 40.5t-40.5 98.5v1258q0 58 40.5 98.5t98.5 40.5h1258zM1465 11v1258q0 28 -20 48t-48 20h-1258q-28 0 -48 -20t-20 -48v-1258q0 -28 20 -48t48 -20h1258q28 0 48 20t20 48 zM694 749l188 -387l533 145v-496q0 -7 -5.5 -12.5t-12.5 -5.5h-1258q-7 0 -12.5 5.5t-5.5 12.5v141l711 195l-212 439q4 1 12 2.5t12 1.5q170 32 303.5 21.5t221 -46t143.5 -94.5q27 -28 -25 -42q-64 -16 -256 -62l-97 198q-111 7 -240 -16zM1397 1287q7 0 12.5 -5.5 t5.5 -12.5v-428q-85 30 -188 52q-294 64 -645 12l-18 -3l-65 134h-233l85 -190q-132 -51 -230 -137v560q0 7 5.5 12.5t12.5 5.5h1258zM286 387q-14 -3 -26 4.5t-14 21.5q-24 203 166 305l129 -270z" />
+<glyph unicode="&#xf1be;" horiz-adv-x="2304" d="M784 164l16 241l-16 523q-1 10 -7.5 17t-16.5 7q-9 0 -16 -7t-7 -17l-14 -523l14 -241q1 -10 7.5 -16.5t15.5 -6.5q22 0 24 23zM1080 193l11 211l-12 586q0 16 -13 24q-8 5 -16 5t-16 -5q-13 -8 -13 -24l-1 -6l-10 -579q0 -1 11 -236v-1q0 -10 6 -17q9 -11 23 -11 q11 0 20 9q9 7 9 20zM35 533l20 -128l-20 -126q-2 -9 -9 -9t-9 9l-17 126l17 128q2 9 9 9t9 -9zM121 612l26 -207l-26 -203q-2 -9 -10 -9q-9 0 -9 10l-23 202l23 207q0 9 9 9q8 0 10 -9zM401 159zM213 650l25 -245l-25 -237q0 -11 -11 -11q-10 0 -12 11l-21 237l21 245 q2 12 12 12q11 0 11 -12zM307 657l23 -252l-23 -244q-2 -13 -14 -13q-13 0 -13 13l-21 244l21 252q0 13 13 13q12 0 14 -13zM401 639l21 -234l-21 -246q-2 -16 -16 -16q-6 0 -10.5 4.5t-4.5 11.5l-20 246l20 234q0 6 4.5 10.5t10.5 4.5q14 0 16 -15zM784 164zM495 785 l21 -380l-21 -246q0 -7 -5 -12.5t-12 -5.5q-16 0 -18 18l-18 246l18 380q2 18 18 18q7 0 12 -5.5t5 -12.5zM589 871l19 -468l-19 -244q0 -8 -5.5 -13.5t-13.5 -5.5q-18 0 -20 19l-16 244l16 468q2 19 20 19q8 0 13.5 -5.5t5.5 -13.5zM687 911l18 -506l-18 -242 q-2 -21 -22 -21q-19 0 -21 21l-16 242l16 506q0 9 6.5 15.5t14.5 6.5q9 0 15 -6.5t7 -15.5zM1079 169v0v0zM881 915l15 -510l-15 -239q0 -10 -7.5 -17.5t-17.5 -7.5t-17 7t-8 18l-14 239l14 510q0 11 7.5 18t17.5 7t17.5 -7t7.5 -18zM980 896l14 -492l-14 -236q0 -11 -8 -19 t-19 -8t-19 8t-9 19l-12 236l12 492q1 12 9 20t19 8t18.5 -8t8.5 -20zM1192 404l-14 -231v0q0 -13 -9 -22t-22 -9t-22 9t-10 22l-6 114l-6 117l12 636v3q2 15 12 24q9 7 20 7q8 0 15 -5q14 -8 16 -26zM2304 423q0 -117 -83 -199.5t-200 -82.5h-786q-13 2 -22 11t-9 22v899 q0 23 28 33q85 34 181 34q195 0 338 -131.5t160 -323.5q53 22 110 22q117 0 200 -83t83 -201z" />
+<glyph unicode="&#xf1c0;" d="M768 768q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 0q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127 t443 -43zM768 384q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 1536q208 0 385 -34.5t280 -93.5t103 -128v-128q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5 t-103 128v128q0 69 103 128t280 93.5t385 34.5z" />
+<glyph unicode="&#xf1c1;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M894 465q33 -26 84 -56q59 7 117 7q147 0 177 -49q16 -22 2 -52q0 -1 -1 -2l-2 -2v-1q-6 -38 -71 -38q-48 0 -115 20t-130 53q-221 -24 -392 -83q-153 -262 -242 -262q-15 0 -28 7l-24 12q-1 1 -6 5q-10 10 -6 36q9 40 56 91.5t132 96.5q14 9 23 -6q2 -2 2 -4q52 85 107 197 q68 136 104 262q-24 82 -30.5 159.5t6.5 127.5q11 40 42 40h21h1q23 0 35 -15q18 -21 9 -68q-2 -6 -4 -8q1 -3 1 -8v-30q-2 -123 -14 -192q55 -164 146 -238zM318 54q52 24 137 158q-51 -40 -87.5 -84t-49.5 -74zM716 974q-15 -42 -2 -132q1 7 7 44q0 3 7 43q1 4 4 8 q-1 1 -1 2t-0.5 1.5t-0.5 1.5q-1 22 -13 36q0 -1 -1 -2v-2zM592 313q135 54 284 81q-2 1 -13 9.5t-16 13.5q-76 67 -127 176q-27 -86 -83 -197q-30 -56 -45 -83zM1238 329q-24 24 -140 24q76 -28 124 -28q14 0 18 1q0 1 -2 3z" />
+<glyph unicode="&#xf1c2;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M233 768v-107h70l164 -661h159l128 485q7 20 10 46q2 16 2 24h4l3 -24q1 -3 3.5 -20t5.5 -26l128 -485h159l164 661h70v107h-300v-107h90l-99 -438q-5 -20 -7 -46l-2 -21h-4l-3 21q-1 5 -4 21t-5 25l-144 545h-114l-144 -545q-2 -9 -4.5 -24.5t-3.5 -21.5l-4 -21h-4l-2 21 q-2 26 -7 46l-99 438h90v107h-300z" />
+<glyph unicode="&#xf1c3;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M429 106v-106h281v106h-75l103 161q5 7 10 16.5t7.5 13.5t3.5 4h2q1 -4 5 -10q2 -4 4.5 -7.5t6 -8t6.5 -8.5l107 -161h-76v-106h291v106h-68l-192 273l195 282h67v107h-279v-107h74l-103 -159q-4 -7 -10 -16.5t-9 -13.5l-2 -3h-2q-1 4 -5 10q-6 11 -17 23l-106 159h76v107 h-290v-107h68l189 -272l-194 -283h-68z" />
+<glyph unicode="&#xf1c4;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M416 106v-106h327v106h-93v167h137q76 0 118 15q67 23 106.5 87t39.5 146q0 81 -37 141t-100 87q-48 19 -130 19h-368v-107h92v-555h-92zM769 386h-119v268h120q52 0 83 -18q56 -33 56 -115q0 -89 -62 -120q-31 -15 -78 -15z" />
+<glyph unicode="&#xf1c5;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M1280 320v-320h-1024v192l192 192l128 -128l384 384zM448 512q-80 0 -136 56t-56 136t56 136t136 56t136 -56t56 -136t-56 -136t-136 -56z" />
+<glyph unicode="&#xf1c6;" d="M640 1152v128h-128v-128h128zM768 1024v128h-128v-128h128zM640 896v128h-128v-128h128zM768 768v128h-128v-128h128zM1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400 v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-128v-128h-128v128h-512v-1536h1280zM781 593l107 -349q8 -27 8 -52q0 -83 -72.5 -137.5t-183.5 -54.5t-183.5 54.5t-72.5 137.5q0 25 8 52q21 63 120 396v128h128v-128h79 q22 0 39 -13t23 -34zM640 128q53 0 90.5 19t37.5 45t-37.5 45t-90.5 19t-90.5 -19t-37.5 -45t37.5 -45t90.5 -19z" />
+<glyph unicode="&#xf1c7;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M620 686q20 -8 20 -30v-544q0 -22 -20 -30q-8 -2 -12 -2q-12 0 -23 9l-166 167h-131q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h131l166 167q16 15 35 7zM1037 -3q31 0 50 24q129 159 129 363t-129 363q-16 21 -43 24t-47 -14q-21 -17 -23.5 -43.5t14.5 -47.5 q100 -123 100 -282t-100 -282q-17 -21 -14.5 -47.5t23.5 -42.5q18 -15 40 -15zM826 145q27 0 47 20q87 93 87 219t-87 219q-18 19 -45 20t-46 -17t-20 -44.5t18 -46.5q52 -57 52 -131t-52 -131q-19 -20 -18 -46.5t20 -44.5q20 -17 44 -17z" />
+<glyph unicode="&#xf1c8;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M768 768q52 0 90 -38t38 -90v-384q0 -52 -38 -90t-90 -38h-384q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h384zM1260 766q20 -8 20 -30v-576q0 -22 -20 -30q-8 -2 -12 -2q-14 0 -23 9l-265 266v90l265 266q9 9 23 9q4 0 12 -2z" />
+<glyph unicode="&#xf1c9;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M480 768q8 11 21 12.5t24 -6.5l51 -38q11 -8 12.5 -21t-6.5 -24l-182 -243l182 -243q8 -11 6.5 -24t-12.5 -21l-51 -38q-11 -8 -24 -6.5t-21 12.5l-226 301q-14 19 0 38zM1282 467q14 -19 0 -38l-226 -301q-8 -11 -21 -12.5t-24 6.5l-51 38q-11 8 -12.5 21t6.5 24l182 243 l-182 243q-8 11 -6.5 24t12.5 21l51 38q11 8 24 6.5t21 -12.5zM662 6q-13 2 -20.5 13t-5.5 24l138 831q2 13 13 20.5t24 5.5l63 -10q13 -2 20.5 -13t5.5 -24l-138 -831q-2 -13 -13 -20.5t-24 -5.5z" />
+<glyph unicode="&#xf1ca;" d="M1497 709v-198q-101 -23 -198 -23q-65 -136 -165.5 -271t-181.5 -215.5t-128 -106.5q-80 -45 -162 3q-28 17 -60.5 43.5t-85 83.5t-102.5 128.5t-107.5 184t-105.5 244t-91.5 314.5t-70.5 390h283q26 -218 70 -398.5t104.5 -317t121.5 -235.5t140 -195q169 169 287 406 q-142 72 -223 220t-81 333q0 192 104 314.5t284 122.5q178 0 273 -105.5t95 -297.5q0 -159 -58 -286q-7 -1 -19.5 -3t-46 -2t-63 6t-62 25.5t-50.5 51.5q31 103 31 184q0 87 -29 132t-79 45q-53 0 -85 -49.5t-32 -140.5q0 -186 105 -293.5t267 -107.5q62 0 121 14z" />
+<glyph unicode="&#xf1cb;" horiz-adv-x="1792" d="M216 367l603 -402v359l-334 223zM154 511l193 129l-193 129v-258zM973 -35l603 402l-269 180l-334 -223v-359zM896 458l272 182l-272 182l-272 -182zM485 733l334 223v359l-603 -402zM1445 640l193 -129v258zM1307 733l269 180l-603 402v-359zM1792 913v-546 q0 -41 -34 -64l-819 -546q-21 -13 -43 -13t-43 13l-819 546q-34 23 -34 64v546q0 41 34 64l819 546q21 13 43 13t43 -13l819 -546q34 -23 34 -64z" />
+<glyph unicode="&#xf1cc;" horiz-adv-x="2048" d="M1800 764q111 -46 179.5 -145.5t68.5 -221.5q0 -164 -118 -280.5t-285 -116.5q-4 0 -11.5 0.5t-10.5 0.5h-1209h-1h-2h-5q-170 10 -288 125.5t-118 280.5q0 110 55 203t147 147q-12 39 -12 82q0 115 82 196t199 81q95 0 172 -58q75 154 222.5 248t326.5 94 q166 0 306 -80.5t221.5 -218.5t81.5 -301q0 -6 -0.5 -18t-0.5 -18zM468 498q0 -122 84 -193t208 -71q137 0 240 99q-16 20 -47.5 56.5t-43.5 50.5q-67 -65 -144 -65q-55 0 -93.5 33.5t-38.5 87.5q0 53 38.5 87t91.5 34q44 0 84.5 -21t73 -55t65 -75t69 -82t77 -75t97 -55 t121.5 -21q121 0 204.5 71.5t83.5 190.5q0 121 -84 192t-207 71q-143 0 -241 -97q14 -16 29.5 -34t34.5 -40t29 -34q66 64 142 64q52 0 92 -33t40 -84q0 -57 -37 -91.5t-94 -34.5q-43 0 -82.5 21t-72 55t-65.5 75t-69.5 82t-77.5 75t-96.5 55t-118.5 21q-122 0 -207 -70.5 t-85 -189.5z" />
+<glyph unicode="&#xf1cd;" horiz-adv-x="1792" d="M896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM896 1408q-190 0 -361 -90l194 -194q82 28 167 28t167 -28l194 194q-171 90 -361 90zM218 279l194 194 q-28 82 -28 167t28 167l-194 194q-90 -171 -90 -361t90 -361zM896 -128q190 0 361 90l-194 194q-82 -28 -167 -28t-167 28l-194 -194q171 -90 361 -90zM896 256q159 0 271.5 112.5t112.5 271.5t-112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5 t271.5 -112.5zM1380 473l194 -194q90 171 90 361t-90 361l-194 -194q28 -82 28 -167t-28 -167z" />
+<glyph unicode="&#xf1ce;" horiz-adv-x="1792" d="M1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348q0 222 101 414.5t276.5 317t390.5 155.5v-260q-221 -45 -366.5 -221t-145.5 -406q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5 q0 230 -145.5 406t-366.5 221v260q215 -31 390.5 -155.5t276.5 -317t101 -414.5z" />
+<glyph unicode="&#xf1d0;" horiz-adv-x="1792" d="M19 662q8 217 116 406t305 318h5q0 -1 -1 -3q-8 -8 -28 -33.5t-52 -76.5t-60 -110.5t-44.5 -135.5t-14 -150.5t39 -157.5t108.5 -154q50 -50 102 -69.5t90.5 -11.5t69.5 23.5t47 32.5l16 16q39 51 53 116.5t6.5 122.5t-21 107t-26.5 80l-14 29q-10 25 -30.5 49.5t-43 41 t-43.5 29.5t-35 19l-13 6l104 115q39 -17 78 -52t59 -61l19 -27q1 48 -18.5 103.5t-40.5 87.5l-20 31l161 183l160 -181q-33 -46 -52.5 -102.5t-22.5 -90.5l-4 -33q22 37 61.5 72.5t67.5 52.5l28 17l103 -115q-44 -14 -85 -50t-60 -65l-19 -29q-31 -56 -48 -133.5t-7 -170 t57 -156.5q33 -45 77.5 -60.5t85 -5.5t76 26.5t57.5 33.5l21 16q60 53 96.5 115t48.5 121.5t10 121.5t-18 118t-37 107.5t-45.5 93t-45 72t-34.5 47.5l-13 17q-14 13 -7 13l10 -3q40 -29 62.5 -46t62 -50t64 -58t58.5 -65t55.5 -77t45.5 -88t38 -103t23.5 -117t10.5 -136 q3 -259 -108 -465t-312 -321t-456 -115q-185 0 -351 74t-283.5 198t-184 293t-60.5 353z" />
+<glyph unicode="&#xf1d1;" horiz-adv-x="1792" d="M874 -102v-66q-208 6 -385 109.5t-283 275.5l58 34q29 -49 73 -99l65 57q148 -168 368 -212l-17 -86q65 -12 121 -13zM276 428l-83 -28q22 -60 49 -112l-57 -33q-98 180 -98 385t98 385l57 -33q-30 -56 -49 -112l82 -28q-35 -100 -35 -212q0 -109 36 -212zM1528 251 l58 -34q-106 -172 -283 -275.5t-385 -109.5v66q56 1 121 13l-17 86q220 44 368 212l65 -57q44 50 73 99zM1377 805l-233 -80q14 -42 14 -85t-14 -85l232 -80q-31 -92 -98 -169l-185 162q-57 -67 -147 -85l48 -241q-52 -10 -98 -10t-98 10l48 241q-90 18 -147 85l-185 -162 q-67 77 -98 169l232 80q-14 42 -14 85t14 85l-233 80q33 93 99 169l185 -162q59 68 147 86l-48 240q44 10 98 10t98 -10l-48 -240q88 -18 147 -86l185 162q66 -76 99 -169zM874 1448v-66q-65 -2 -121 -13l17 -86q-220 -42 -368 -211l-65 56q-38 -42 -73 -98l-57 33 q106 172 282 275.5t385 109.5zM1705 640q0 -205 -98 -385l-57 33q27 52 49 112l-83 28q36 103 36 212q0 112 -35 212l82 28q-19 56 -49 112l57 33q98 -180 98 -385zM1585 1063l-57 -33q-35 56 -73 98l-65 -56q-148 169 -368 211l17 86q-56 11 -121 13v66q209 -6 385 -109.5 t282 -275.5zM1748 640q0 173 -67.5 331t-181.5 272t-272 181.5t-331 67.5t-331 -67.5t-272 -181.5t-181.5 -272t-67.5 -331t67.5 -331t181.5 -272t272 -181.5t331 -67.5t331 67.5t272 181.5t181.5 272t67.5 331zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71 t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+<glyph unicode="&#xf1d2;" d="M582 228q0 -66 -93 -66q-107 0 -107 63q0 64 98 64q102 0 102 -61zM546 694q0 -85 -74 -85q-77 0 -77 84q0 90 77 90q36 0 55 -25.5t19 -63.5zM712 769v125q-78 -29 -135 -29q-50 29 -110 29q-86 0 -145 -57t-59 -143q0 -50 29.5 -102t73.5 -67v-3q-38 -17 -38 -85 q0 -53 41 -77v-3q-113 -37 -113 -139q0 -45 20 -78.5t54 -51t72 -25.5t81 -8q224 0 224 188q0 67 -48 99t-126 46q-27 5 -51.5 20.5t-24.5 39.5q0 44 49 52q77 15 122 70t45 134q0 24 -10 52q37 9 49 13zM771 350h137q-2 27 -2 82v387q0 46 2 69h-137q3 -23 3 -71v-392 q0 -50 -3 -75zM1280 366v121q-30 -21 -68 -21q-53 0 -53 82v225h52q9 0 26.5 -1t26.5 -1v117h-105q0 82 3 102h-140q4 -24 4 -55v-47h-60v-117q36 3 37 3q3 0 11 -0.5t12 -0.5v-2h-2v-217q0 -37 2.5 -64t11.5 -56.5t24.5 -48.5t43.5 -31t66 -12q64 0 108 24zM924 1072 q0 36 -24 63.5t-60 27.5t-60.5 -27t-24.5 -64q0 -36 25 -62.5t60 -26.5t59.5 27t24.5 62zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf1d3;" horiz-adv-x="1792" d="M595 22q0 100 -165 100q-158 0 -158 -104q0 -101 172 -101q151 0 151 105zM536 777q0 61 -30 102t-89 41q-124 0 -124 -145q0 -135 124 -135q119 0 119 137zM805 1101v-202q-36 -12 -79 -22q16 -43 16 -84q0 -127 -73 -216.5t-197 -112.5q-40 -8 -59.5 -27t-19.5 -58 q0 -31 22.5 -51.5t58 -32t78.5 -22t86 -25.5t78.5 -37.5t58 -64t22.5 -98.5q0 -304 -363 -304q-69 0 -130 12.5t-116 41t-87.5 82t-32.5 127.5q0 165 182 225v4q-67 41 -67 126q0 109 63 137v4q-72 24 -119.5 108.5t-47.5 165.5q0 139 95 231.5t235 92.5q96 0 178 -47 q98 0 218 47zM1123 220h-222q4 45 4 134v609q0 94 -4 128h222q-4 -33 -4 -124v-613q0 -89 4 -134zM1724 442v-196q-71 -39 -174 -39q-62 0 -107 20t-70 50t-39.5 78t-18.5 92t-4 103v351h2v4q-7 0 -19 1t-18 1q-21 0 -59 -6v190h96v76q0 54 -6 89h227q-6 -41 -6 -165h171 v-190q-15 0 -43.5 2t-42.5 2h-85v-365q0 -131 87 -131q61 0 109 33zM1148 1389q0 -58 -39 -101.5t-96 -43.5q-58 0 -98 43.5t-40 101.5q0 59 39.5 103t98.5 44q58 0 96.5 -44.5t38.5 -102.5z" />
+<glyph unicode="&#xf1d4;" d="M825 547l343 588h-150q-21 -39 -63.5 -118.5t-68 -128.5t-59.5 -118.5t-60 -128.5h-3q-21 48 -44.5 97t-52 105.5t-46.5 92t-54 104.5t-49 95h-150l323 -589v-435h134v436zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960 q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf1d5;" horiz-adv-x="1280" d="M842 964q0 -80 -57 -136.5t-136 -56.5q-60 0 -111 35q-62 -67 -115 -146q-247 -371 -202 -859q1 -22 -12.5 -38.5t-34.5 -18.5h-5q-20 0 -35 13.5t-17 33.5q-14 126 -3.5 247.5t29.5 217t54 186t69 155.5t74 125q61 90 132 165q-16 35 -16 77q0 80 56.5 136.5t136.5 56.5 t136.5 -56.5t56.5 -136.5zM1223 953q0 -158 -78 -292t-212.5 -212t-292.5 -78q-64 0 -131 14q-21 5 -32.5 23.5t-6.5 39.5q5 20 23 31.5t39 7.5q51 -13 108 -13q97 0 186 38t153 102t102 153t38 186t-38 186t-102 153t-153 102t-186 38t-186 -38t-153 -102t-102 -153 t-38 -186q0 -114 52 -218q10 -20 3.5 -40t-25.5 -30t-39.5 -3t-30.5 26q-64 123 -64 265q0 119 46.5 227t124.5 186t186 124t226 46q158 0 292.5 -78t212.5 -212.5t78 -292.5z" />
+<glyph unicode="&#xf1d6;" horiz-adv-x="1792" d="M270 730q-8 19 -8 52q0 20 11 49t24 45q-1 22 7.5 53t22.5 43q0 139 92.5 288.5t217.5 209.5q139 66 324 66q133 0 266 -55q49 -21 90 -48t71 -56t55 -68t42 -74t32.5 -84.5t25.5 -89.5t22 -98l1 -5q55 -83 55 -150q0 -14 -9 -40t-9 -38q0 -1 1.5 -3.5t3.5 -5t2 -3.5 q77 -114 120.5 -214.5t43.5 -208.5q0 -43 -19.5 -100t-55.5 -57q-9 0 -19.5 7.5t-19 17.5t-19 26t-16 26.5t-13.5 26t-9 17.5q-1 1 -3 1l-5 -4q-59 -154 -132 -223q20 -20 61.5 -38.5t69 -41.5t35.5 -65q-2 -4 -4 -16t-7 -18q-64 -97 -302 -97q-53 0 -110.5 9t-98 20 t-104.5 30q-15 5 -23 7q-14 4 -46 4.5t-40 1.5q-41 -45 -127.5 -65t-168.5 -20q-35 0 -69 1.5t-93 9t-101 20.5t-74.5 40t-32.5 64q0 40 10 59.5t41 48.5q11 2 40.5 13t49.5 12q4 0 14 2q2 2 2 4l-2 3q-48 11 -108 105.5t-73 156.5l-5 3q-4 0 -12 -20q-18 -41 -54.5 -74.5 t-77.5 -37.5h-1q-4 0 -6 4.5t-5 5.5q-23 54 -23 100q0 275 252 466z" />
+<glyph unicode="&#xf1d7;" horiz-adv-x="2048" d="M580 1075q0 41 -25 66t-66 25q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 66 24.5t25 65.5zM1323 568q0 28 -25.5 50t-65.5 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q40 0 65.5 22t25.5 51zM1087 1075q0 41 -24.5 66t-65.5 25 q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 65.5 24.5t24.5 65.5zM1722 568q0 28 -26 50t-65 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q39 0 65 22t26 51zM1456 965q-31 4 -70 4q-169 0 -311 -77t-223.5 -208.5t-81.5 -287.5 q0 -78 23 -152q-35 -3 -68 -3q-26 0 -50 1.5t-55 6.5t-44.5 7t-54.5 10.5t-50 10.5l-253 -127l72 218q-290 203 -290 490q0 169 97.5 311t264 223.5t363.5 81.5q176 0 332.5 -66t262 -182.5t136.5 -260.5zM2048 404q0 -117 -68.5 -223.5t-185.5 -193.5l55 -181l-199 109 q-150 -37 -218 -37q-169 0 -311 70.5t-223.5 191.5t-81.5 264t81.5 264t223.5 191.5t311 70.5q161 0 303 -70.5t227.5 -192t85.5 -263.5z" />
+<glyph unicode="&#xf1d8;" horiz-adv-x="1792" d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-453 185l-242 -295q-18 -23 -49 -23q-13 0 -22 4q-19 7 -30.5 23.5t-11.5 36.5v349l864 1059l-1069 -925l-395 162q-37 14 -40 55q-2 40 32 59l1664 960q15 9 32 9q20 0 36 -11z" />
+<glyph unicode="&#xf1d9;" horiz-adv-x="1792" d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-527 215l-298 -327q-18 -21 -47 -21q-14 0 -23 4q-19 7 -30 23.5t-11 36.5v452l-472 193q-37 14 -40 55q-3 39 32 59l1664 960q35 21 68 -2zM1422 26l221 1323l-1434 -827l336 -137 l863 639l-478 -797z" />
+<glyph unicode="&#xf1da;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298zM896 928v-448q0 -14 -9 -23 t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf1db;" d="M768 1280q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf1dc;" horiz-adv-x="1792" d="M1682 -128q-44 0 -132.5 3.5t-133.5 3.5q-44 0 -132 -3.5t-132 -3.5q-24 0 -37 20.5t-13 45.5q0 31 17 46t39 17t51 7t45 15q33 21 33 140l-1 391q0 21 -1 31q-13 4 -50 4h-675q-38 0 -51 -4q-1 -10 -1 -31l-1 -371q0 -142 37 -164q16 -10 48 -13t57 -3.5t45 -15 t20 -45.5q0 -26 -12.5 -48t-36.5 -22q-47 0 -139.5 3.5t-138.5 3.5q-43 0 -128 -3.5t-127 -3.5q-23 0 -35.5 21t-12.5 45q0 30 15.5 45t36 17.5t47.5 7.5t42 15q33 23 33 143l-1 57v813q0 3 0.5 26t0 36.5t-1.5 38.5t-3.5 42t-6.5 36.5t-11 31.5t-16 18q-15 10 -45 12t-53 2 t-41 14t-18 45q0 26 12 48t36 22q46 0 138.5 -3.5t138.5 -3.5q42 0 126.5 3.5t126.5 3.5q25 0 37.5 -22t12.5 -48q0 -30 -17 -43.5t-38.5 -14.5t-49.5 -4t-43 -13q-35 -21 -35 -160l1 -320q0 -21 1 -32q13 -3 39 -3h699q25 0 38 3q1 11 1 32l1 320q0 139 -35 160 q-18 11 -58.5 12.5t-66 13t-25.5 49.5q0 26 12.5 48t37.5 22q44 0 132 -3.5t132 -3.5q43 0 129 3.5t129 3.5q25 0 37.5 -22t12.5 -48q0 -30 -17.5 -44t-40 -14.5t-51.5 -3t-44 -12.5q-35 -23 -35 -161l1 -943q0 -119 34 -140q16 -10 46 -13.5t53.5 -4.5t41.5 -15.5t18 -44.5 q0 -26 -12 -48t-36 -22z" />
+<glyph unicode="&#xf1dd;" horiz-adv-x="1280" d="M1278 1347v-73q0 -29 -18.5 -61t-42.5 -32q-50 0 -54 -1q-26 -6 -32 -31q-3 -11 -3 -64v-1152q0 -25 -18 -43t-43 -18h-108q-25 0 -43 18t-18 43v1218h-143v-1218q0 -25 -17.5 -43t-43.5 -18h-108q-26 0 -43.5 18t-17.5 43v496q-147 12 -245 59q-126 58 -192 179 q-64 117 -64 259q0 166 88 286q88 118 209 159q111 37 417 37h479q25 0 43 -18t18 -43z" />
+<glyph unicode="&#xf1de;" d="M352 128v-128h-352v128h352zM704 256q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM864 640v-128h-864v128h864zM224 1152v-128h-224v128h224zM1536 128v-128h-736v128h736zM576 1280q26 0 45 -19t19 -45v-256 q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1216 768q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1536 640v-128h-224v128h224zM1536 1152v-128h-864v128h864z" />
+<glyph unicode="&#xf1e0;" d="M1216 512q133 0 226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5t-226.5 93.5t-93.5 226.5q0 12 2 34l-360 180q-92 -86 -218 -86q-133 0 -226.5 93.5t-93.5 226.5t93.5 226.5t226.5 93.5q126 0 218 -86l360 180q-2 22 -2 34q0 133 93.5 226.5t226.5 93.5 t226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5q-126 0 -218 86l-360 -180q2 -22 2 -34t-2 -34l360 -180q92 86 218 86z" />
+<glyph unicode="&#xf1e1;" d="M1280 341q0 88 -62.5 151t-150.5 63q-84 0 -145 -58l-241 120q2 16 2 23t-2 23l241 120q61 -58 145 -58q88 0 150.5 63t62.5 151t-62.5 150.5t-150.5 62.5t-151 -62.5t-63 -150.5q0 -7 2 -23l-241 -120q-62 57 -145 57q-88 0 -150.5 -62.5t-62.5 -150.5t62.5 -150.5 t150.5 -62.5q83 0 145 57l241 -120q-2 -16 -2 -23q0 -88 63 -150.5t151 -62.5t150.5 62.5t62.5 150.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf1e2;" horiz-adv-x="1792" d="M571 947q-10 25 -34 35t-49 0q-108 -44 -191 -127t-127 -191q-10 -25 0 -49t35 -34q13 -5 24 -5q42 0 60 40q34 84 98.5 148.5t148.5 98.5q25 11 35 35t0 49zM1513 1303l46 -46l-244 -243l68 -68q19 -19 19 -45.5t-19 -45.5l-64 -64q89 -161 89 -343q0 -143 -55.5 -273.5 t-150 -225t-225 -150t-273.5 -55.5t-273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5q182 0 343 -89l64 64q19 19 45.5 19t45.5 -19l68 -68zM1521 1359q-10 -10 -22 -10q-13 0 -23 10l-91 90q-9 10 -9 23t9 23q10 9 23 9t23 -9l90 -91 q10 -9 10 -22.5t-10 -22.5zM1751 1129q-11 -9 -23 -9t-23 9l-90 91q-10 9 -10 22.5t10 22.5q9 10 22.5 10t22.5 -10l91 -90q9 -10 9 -23t-9 -23zM1792 1312q0 -14 -9 -23t-23 -9h-96q-14 0 -23 9t-9 23t9 23t23 9h96q14 0 23 -9t9 -23zM1600 1504v-96q0 -14 -9 -23t-23 -9 t-23 9t-9 23v96q0 14 9 23t23 9t23 -9t9 -23zM1751 1449l-91 -90q-10 -10 -22 -10q-13 0 -23 10q-10 9 -10 22.5t10 22.5l90 91q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" />
+<glyph unicode="&#xf1e3;" horiz-adv-x="1792" d="M609 720l287 208l287 -208l-109 -336h-355zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM1515 186q149 203 149 454v3l-102 -89l-240 224l63 323 l134 -12q-150 206 -389 282l53 -124l-287 -159l-287 159l53 124q-239 -76 -389 -282l135 12l62 -323l-240 -224l-102 89v-3q0 -251 149 -454l30 132l326 -40l139 -298l-116 -69q117 -39 240 -39t240 39l-116 69l139 298l326 40z" />
+<glyph unicode="&#xf1e4;" horiz-adv-x="1792" d="M448 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM256 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM832 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM66 768q-28 0 -47 19t-19 46v129h514v-129q0 -27 -19 -46t-46 -19h-383zM1216 224v-192q0 -14 -9 -23t-23 -9h-192 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1600 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23 zM1408 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1016v-13h-514v10q0 104 -382 102q-382 -1 -382 -102v-10h-514v13q0 17 8.5 43t34 64t65.5 75.5t110.5 76t160 67.5t224 47.5t293.5 18.5t293 -18.5t224 -47.5 t160.5 -67.5t110.5 -76t65.5 -75.5t34 -64t8.5 -43zM1792 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 962v-129q0 -27 -19 -46t-46 -19h-384q-27 0 -46 19t-19 46v129h514z" />
+<glyph unicode="&#xf1e5;" horiz-adv-x="1792" d="M704 1216v-768q0 -26 -19 -45t-45 -19v-576q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v512l249 873q7 23 31 23h424zM1024 1216v-704h-256v704h256zM1792 320v-512q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v576q-26 0 -45 19t-19 45v768h424q24 0 31 -23z M736 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23zM1408 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf1e6;" horiz-adv-x="1792" d="M1755 1083q37 -37 37 -90t-37 -91l-401 -400l150 -150l-160 -160q-163 -163 -389.5 -186.5t-411.5 100.5l-362 -362h-181v181l362 362q-124 185 -100.5 411.5t186.5 389.5l160 160l150 -150l400 401q38 37 91 37t90 -37t37 -90.5t-37 -90.5l-400 -401l234 -234l401 400 q38 37 91 37t90 -37z" />
+<glyph unicode="&#xf1e7;" horiz-adv-x="1792" d="M873 796q0 -83 -63.5 -142.5t-152.5 -59.5t-152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59t152.5 -59t63.5 -143zM1375 796q0 -83 -63 -142.5t-153 -59.5q-89 0 -152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59q90 0 153 -59t63 -143zM1600 616v667q0 87 -32 123.5 t-111 36.5h-1112q-83 0 -112.5 -34t-29.5 -126v-673q43 -23 88.5 -40t81 -28t81 -18.5t71 -11t70 -4t58.5 -0.5t56.5 2t44.5 2q68 1 95 -27q6 -6 10 -9q26 -25 61 -51q7 91 118 87q5 0 36.5 -1.5t43 -2t45.5 -1t53 1t54.5 4.5t61 8.5t62 13.5t67 19.5t67.5 27t72 34.5z M1763 621q-121 -149 -372 -252q84 -285 -23 -465q-66 -113 -183 -148q-104 -32 -182 15q-86 51 -82 164l-1 326v1q-8 2 -24.5 6t-23.5 5l-1 -338q4 -114 -83 -164q-79 -47 -183 -15q-117 36 -182 150q-105 180 -22 463q-251 103 -372 252q-25 37 -4 63t60 -1q3 -2 11 -7 t11 -8v694q0 72 47 123t114 51h1257q67 0 114 -51t47 -123v-694l21 15q39 27 60 1t-4 -63z" />
+<glyph unicode="&#xf1e8;" horiz-adv-x="1792" d="M896 1102v-434h-145v434h145zM1294 1102v-434h-145v434h145zM1294 342l253 254v795h-1194v-1049h326v-217l217 217h398zM1692 1536v-1013l-434 -434h-326l-217 -217h-217v217h-398v1158l109 289h1483z" />
+<glyph unicode="&#xf1e9;" d="M773 217v-127q-1 -292 -6 -305q-12 -32 -51 -40q-54 -9 -181.5 38t-162.5 89q-13 15 -17 36q-1 12 4 26q4 10 34 47t181 216q1 0 60 70q15 19 39.5 24.5t49.5 -3.5q24 -10 37.5 -29t12.5 -42zM624 468q-3 -55 -52 -70l-120 -39q-275 -88 -292 -88q-35 2 -54 36 q-12 25 -17 75q-8 76 1 166.5t30 124.5t56 32q13 0 202 -77q70 -29 115 -47l84 -34q23 -9 35.5 -30.5t11.5 -48.5zM1450 171q-7 -54 -91.5 -161t-135.5 -127q-37 -14 -63 7q-14 10 -184 287l-47 77q-14 21 -11.5 46t19.5 46q35 43 83 26q1 -1 119 -40q203 -66 242 -79.5 t47 -20.5q28 -22 22 -61zM778 803q5 -102 -54 -122q-58 -17 -114 71l-378 598q-8 35 19 62q41 43 207.5 89.5t224.5 31.5q40 -10 49 -45q3 -18 22 -305.5t24 -379.5zM1440 695q3 -39 -26 -59q-15 -10 -329 -86q-67 -15 -91 -23l1 2q-23 -6 -46 4t-37 32q-30 47 0 87 q1 1 75 102q125 171 150 204t34 39q28 19 65 2q48 -23 123 -133.5t81 -167.5v-3z" />
+<glyph unicode="&#xf1ea;" horiz-adv-x="2048" d="M1024 1024h-384v-384h384v384zM1152 384v-128h-640v128h640zM1152 1152v-640h-640v640h640zM1792 384v-128h-512v128h512zM1792 640v-128h-512v128h512zM1792 896v-128h-512v128h512zM1792 1152v-128h-512v128h512zM256 192v960h-128v-960q0 -26 19 -45t45 -19t45 19 t19 45zM1920 192v1088h-1536v-1088q0 -33 -11 -64h1483q26 0 45 19t19 45zM2048 1408v-1216q0 -80 -56 -136t-136 -56h-1664q-80 0 -136 56t-56 136v1088h256v128h1792z" />
+<glyph unicode="&#xf1eb;" horiz-adv-x="2048" d="M1024 13q-20 0 -93 73.5t-73 93.5q0 32 62.5 54t103.5 22t103.5 -22t62.5 -54q0 -20 -73 -93.5t-93 -73.5zM1294 284q-2 0 -40 25t-101.5 50t-128.5 25t-128.5 -25t-101 -50t-40.5 -25q-18 0 -93.5 75t-75.5 93q0 13 10 23q78 77 196 121t233 44t233 -44t196 -121 q10 -10 10 -23q0 -18 -75.5 -93t-93.5 -75zM1567 556q-11 0 -23 8q-136 105 -252 154.5t-268 49.5q-85 0 -170.5 -22t-149 -53t-113.5 -62t-79 -53t-31 -22q-17 0 -92 75t-75 93q0 12 10 22q132 132 320 205t380 73t380 -73t320 -205q10 -10 10 -22q0 -18 -75 -93t-92 -75z M1838 827q-11 0 -22 9q-179 157 -371.5 236.5t-420.5 79.5t-420.5 -79.5t-371.5 -236.5q-11 -9 -22 -9q-17 0 -92.5 75t-75.5 93q0 13 10 23q187 186 445 288t527 102t527 -102t445 -288q10 -10 10 -23q0 -18 -75.5 -93t-92.5 -75z" />
+<glyph unicode="&#xf1ec;" horiz-adv-x="1792" d="M384 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5 t37.5 90.5zM384 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 768q0 53 -37.5 90.5t-90.5 37.5 t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1536 0v384q0 52 -38 90t-90 38t-90 -38t-38 -90v-384q0 -52 38 -90t90 -38t90 38t38 90zM1152 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5z M1536 1088v256q0 26 -19 45t-45 19h-1280q-26 0 -45 -19t-19 -45v-256q0 -26 19 -45t45 -19h1280q26 0 45 19t19 45zM1536 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1408v-1536q0 -52 -38 -90t-90 -38 h-1408q-52 0 -90 38t-38 90v1536q0 52 38 90t90 38h1408q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1ed;" horiz-adv-x="1792" d="M1112 1090q0 159 -237 159h-70q-32 0 -59.5 -21.5t-34.5 -52.5l-63 -276q-2 -5 -2 -16q0 -24 17 -39.5t41 -15.5h53q69 0 128.5 13t112.5 41t83.5 81.5t30.5 126.5zM1716 938q0 -265 -220 -428q-219 -161 -612 -161h-61q-32 0 -59 -21.5t-34 -52.5l-73 -316 q-8 -36 -40.5 -61.5t-69.5 -25.5h-213q-31 0 -53 20t-22 51q0 10 13 65h151q34 0 64 23.5t38 56.5l73 316q8 33 37.5 57t63.5 24h61q390 0 607 160t217 421q0 129 -51 207q183 -92 183 -335zM1533 1123q0 -264 -221 -428q-218 -161 -612 -161h-60q-32 0 -59.5 -22t-34.5 -53 l-73 -315q-8 -36 -40 -61.5t-69 -25.5h-214q-31 0 -52.5 19.5t-21.5 51.5q0 8 2 20l300 1301q8 36 40.5 61.5t69.5 25.5h444q68 0 125 -4t120.5 -15t113.5 -30t96.5 -50.5t77.5 -74t49.5 -103.5t18.5 -136z" />
+<glyph unicode="&#xf1ee;" horiz-adv-x="1792" d="M602 949q19 -61 31 -123.5t17 -141.5t-14 -159t-62 -145q-21 81 -67 157t-95.5 127t-99 90.5t-78.5 57.5t-33 19q-62 34 -81.5 100t14.5 128t101 81.5t129 -14.5q138 -83 238 -177zM927 1236q11 -25 20.5 -46t36.5 -100.5t42.5 -150.5t25.5 -179.5t0 -205.5t-47.5 -209.5 t-105.5 -208.5q-51 -72 -138 -72q-54 0 -98 31q-57 40 -69 109t28 127q60 85 81 195t13 199.5t-32 180.5t-39 128t-22 52q-31 63 -8.5 129.5t85.5 97.5q34 17 75 17q47 0 88.5 -25t63.5 -69zM1248 567q-17 -160 -72 -311q-17 131 -63 246q25 174 -5 361q-27 178 -94 342 q114 -90 212 -211q9 -37 15 -80q26 -179 7 -347zM1520 1440q9 -17 23.5 -49.5t43.5 -117.5t50.5 -178t34 -227.5t5 -269t-47 -300t-112.5 -323.5q-22 -48 -66 -75.5t-95 -27.5q-39 0 -74 16q-67 31 -92.5 100t4.5 136q58 126 90 257.5t37.5 239.5t-3.5 213.5t-26.5 180.5 t-38.5 138.5t-32.5 90t-15.5 32.5q-34 65 -11.5 135.5t87.5 104.5q37 20 81 20q49 0 91.5 -25.5t66.5 -70.5z" />
+<glyph unicode="&#xf1f0;" horiz-adv-x="2304" d="M1975 546h-138q14 37 66 179l3 9q4 10 10 26t9 26l12 -55zM531 611l-58 295q-11 54 -75 54h-268l-2 -13q311 -79 403 -336zM710 960l-162 -438l-17 89q-26 70 -85 129.5t-131 88.5l135 -510h175l261 641h-176zM849 318h166l104 642h-166zM1617 944q-69 27 -149 27 q-123 0 -201 -59t-79 -153q-1 -102 145 -174q48 -23 67 -41t19 -39q0 -30 -30 -46t-69 -16q-86 0 -156 33l-22 11l-23 -144q74 -34 185 -34q130 -1 208.5 59t80.5 160q0 106 -140 174q-49 25 -71 42t-22 38q0 22 24.5 38.5t70.5 16.5q70 1 124 -24l15 -8zM2042 960h-128 q-65 0 -87 -54l-246 -588h174l35 96h212q5 -22 20 -96h154zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1f1;" horiz-adv-x="2304" d="M671 603h-13q-47 0 -47 -32q0 -22 20 -22q17 0 28 15t12 39zM1066 639h62v3q1 4 0.5 6.5t-1 7t-2 8t-4.5 6.5t-7.5 5t-11.5 2q-28 0 -36 -38zM1606 603h-12q-48 0 -48 -32q0 -22 20 -22q17 0 28 15t12 39zM1925 629q0 41 -30 41q-19 0 -31 -20t-12 -51q0 -42 28 -42 q20 0 32.5 20t12.5 52zM480 770h87l-44 -262h-56l32 201l-71 -201h-39l-4 200l-34 -200h-53l44 262h81l2 -163zM733 663q0 -6 -4 -42q-16 -101 -17 -113h-47l1 22q-20 -26 -58 -26q-23 0 -37.5 16t-14.5 42q0 39 26 60.5t73 21.5q14 0 23 -1q0 3 0.5 5.5t1 4.5t0.5 3 q0 20 -36 20q-29 0 -59 -10q0 4 7 48q38 11 67 11q74 0 74 -62zM889 721l-8 -49q-22 3 -41 3q-27 0 -27 -17q0 -8 4.5 -12t21.5 -11q40 -19 40 -60q0 -72 -87 -71q-34 0 -58 6q0 2 7 49q29 -8 51 -8q32 0 32 19q0 7 -4.5 11.5t-21.5 12.5q-43 20 -43 59q0 72 84 72 q30 0 50 -4zM977 721h28l-7 -52h-29q-2 -17 -6.5 -40.5t-7 -38.5t-2.5 -18q0 -16 19 -16q8 0 16 2l-8 -47q-21 -7 -40 -7q-43 0 -45 47q0 12 8 56q3 20 25 146h55zM1180 648q0 -23 -7 -52h-111q-3 -22 10 -33t38 -11q30 0 58 14l-9 -54q-30 -8 -57 -8q-95 0 -95 95 q0 55 27.5 90.5t69.5 35.5q35 0 55.5 -21t20.5 -56zM1319 722q-13 -23 -22 -62q-22 2 -31 -24t-25 -128h-56l3 14q22 130 29 199h51l-3 -33q14 21 25.5 29.5t28.5 4.5zM1506 763l-9 -57q-28 14 -50 14q-31 0 -51 -27.5t-20 -70.5q0 -30 13.5 -47t38.5 -17q21 0 48 13 l-10 -59q-28 -8 -50 -8q-45 0 -71.5 30.5t-26.5 82.5q0 70 35.5 114.5t91.5 44.5q26 0 61 -13zM1668 663q0 -18 -4 -42q-13 -79 -17 -113h-46l1 22q-20 -26 -59 -26q-23 0 -37 16t-14 42q0 39 25.5 60.5t72.5 21.5q15 0 23 -1q2 7 2 13q0 20 -36 20q-29 0 -59 -10q0 4 8 48 q38 11 67 11q73 0 73 -62zM1809 722q-14 -24 -21 -62q-23 2 -31.5 -23t-25.5 -129h-56l3 14q19 104 29 199h52q0 -11 -4 -33q15 21 26.5 29.5t27.5 4.5zM1950 770h56l-43 -262h-53l3 19q-23 -23 -52 -23q-31 0 -49.5 24t-18.5 64q0 53 27.5 92t64.5 39q31 0 53 -29z M2061 640q0 148 -72.5 273t-198 198t-273.5 73q-181 0 -328 -110q127 -116 171 -284h-50q-44 150 -158 253q-114 -103 -158 -253h-50q44 168 171 284q-147 110 -328 110q-148 0 -273.5 -73t-198 -198t-72.5 -273t72.5 -273t198 -198t273.5 -73q181 0 328 110 q-120 111 -165 264h50q46 -138 152 -233q106 95 152 233h50q-45 -153 -165 -264q147 -110 328 -110q148 0 273.5 73t198 198t72.5 273zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1f2;" horiz-adv-x="2304" d="M313 759q0 -51 -36 -84q-29 -26 -89 -26h-17v220h17q61 0 89 -27q36 -31 36 -83zM2089 824q0 -52 -64 -52h-19v101h20q63 0 63 -49zM380 759q0 74 -50 120.5t-129 46.5h-95v-333h95q74 0 119 38q60 51 60 128zM410 593h65v333h-65v-333zM730 694q0 40 -20.5 62t-75.5 42 q-29 10 -39.5 19t-10.5 23q0 16 13.5 26.5t34.5 10.5q29 0 53 -27l34 44q-41 37 -98 37q-44 0 -74 -27.5t-30 -67.5q0 -35 18 -55.5t64 -36.5q37 -13 45 -19q19 -12 19 -34q0 -20 -14 -33.5t-36 -13.5q-48 0 -71 44l-42 -40q44 -64 115 -64q51 0 83 30.5t32 79.5zM1008 604 v77q-37 -37 -78 -37q-49 0 -80.5 32.5t-31.5 82.5q0 48 31.5 81.5t77.5 33.5q43 0 81 -38v77q-40 20 -80 20q-74 0 -125.5 -50.5t-51.5 -123.5t51 -123.5t125 -50.5q42 0 81 19zM2240 0v527q-65 -40 -144.5 -84t-237.5 -117t-329.5 -137.5t-417.5 -134.5t-504 -118h1569 q26 0 45 19t19 45zM1389 757q0 75 -53 128t-128 53t-128 -53t-53 -128t53 -128t128 -53t128 53t53 128zM1541 584l144 342h-71l-90 -224l-89 224h-71l142 -342h35zM1714 593h184v56h-119v90h115v56h-115v74h119v57h-184v-333zM2105 593h80l-105 140q76 16 76 94q0 47 -31 73 t-87 26h-97v-333h65v133h9zM2304 1274v-1268q0 -56 -38.5 -95t-93.5 -39h-2040q-55 0 -93.5 39t-38.5 95v1268q0 56 38.5 95t93.5 39h2040q55 0 93.5 -39t38.5 -95z" />
+<glyph unicode="&#xf1f3;" horiz-adv-x="2304" d="M119 854h89l-45 108zM740 328l74 79l-70 79h-163v-49h142v-55h-142v-54h159zM898 406l99 -110v217zM1186 453q0 33 -40 33h-84v-69h83q41 0 41 36zM1475 457q0 29 -42 29h-82v-61h81q43 0 43 32zM1197 923q0 29 -42 29h-82v-60h81q43 0 43 31zM1656 854h89l-44 108z M699 1009v-271h-66v212l-94 -212h-57l-94 212v-212h-132l-25 60h-135l-25 -60h-70l116 271h96l110 -257v257h106l85 -184l77 184h108zM1255 453q0 -20 -5.5 -35t-14 -25t-22.5 -16.5t-26 -10t-31.5 -4.5t-31.5 -1t-32.5 0.5t-29.5 0.5v-91h-126l-80 90l-83 -90h-256v271h260 l80 -89l82 89h207q109 0 109 -89zM964 794v-56h-217v271h217v-57h-152v-49h148v-55h-148v-54h152zM2304 235v-229q0 -55 -38.5 -94.5t-93.5 -39.5h-2040q-55 0 -93.5 39.5t-38.5 94.5v678h111l25 61h55l25 -61h218v46l19 -46h113l20 47v-47h541v99l10 1q10 0 10 -14v-86h279 v23q23 -12 55 -18t52.5 -6.5t63 0.5t51.5 1l25 61h56l25 -61h227v58l34 -58h182v378h-180v-44l-25 44h-185v-44l-23 44h-249q-69 0 -109 -22v22h-172v-22q-24 22 -73 22h-628l-43 -97l-43 97h-198v-44l-22 44h-169l-78 -179v391q0 55 38.5 94.5t93.5 39.5h2040 q55 0 93.5 -39.5t38.5 -94.5v-678h-120q-51 0 -81 -22v22h-177q-55 0 -78 -22v22h-316v-22q-31 22 -87 22h-209v-22q-23 22 -91 22h-234l-54 -58l-50 58h-349v-378h343l55 59l52 -59h211v89h21q59 0 90 13v-102h174v99h8q8 0 10 -2t2 -10v-87h529q57 0 88 24v-24h168 q60 0 95 17zM1546 469q0 -23 -12 -43t-34 -29q25 -9 34 -26t9 -46v-54h-65v45q0 33 -12 43.5t-46 10.5h-69v-99h-65v271h154q48 0 77 -15t29 -58zM1269 936q0 -24 -12.5 -44t-33.5 -29q26 -9 34.5 -25.5t8.5 -46.5v-53h-65q0 9 0.5 26.5t0 25t-3 18.5t-8.5 16t-17.5 8.5 t-29.5 3.5h-70v-98h-64v271l153 -1q49 0 78 -14.5t29 -57.5zM1798 327v-56h-216v271h216v-56h-151v-49h148v-55h-148v-54zM1372 1009v-271h-66v271h66zM2065 357q0 -86 -102 -86h-126v58h126q34 0 34 25q0 16 -17 21t-41.5 5t-49.5 3.5t-42 22.5t-17 55q0 39 26 60t66 21 h130v-57h-119q-36 0 -36 -25q0 -16 17.5 -20.5t42 -4t49 -2.5t42 -21.5t17.5 -54.5zM2304 407v-101q-24 -35 -88 -35h-125v58h125q33 0 33 25q0 13 -12.5 19t-31 5.5t-40 2t-40 8t-31 24t-12.5 48.5q0 39 26.5 60t66.5 21h129v-57h-118q-36 0 -36 -25q0 -20 29 -22t68.5 -5 t56.5 -26zM2139 1008v-270h-92l-122 203v-203h-132l-26 60h-134l-25 -60h-75q-129 0 -129 133q0 138 133 138h63v-59q-7 0 -28 1t-28.5 0.5t-23 -2t-21.5 -6.5t-14.5 -13.5t-11.5 -23t-3 -33.5q0 -38 13.5 -58t49.5 -20h29l92 213h97l109 -256v256h99l114 -188v188h66z" />
+<glyph unicode="&#xf1f4;" horiz-adv-x="2304" d="M322 689h-15q-19 0 -19 18q0 28 19 85q5 15 15 19.5t28 4.5q77 0 77 -49q0 -41 -30.5 -59.5t-74.5 -18.5zM664 528q-47 0 -47 29q0 62 123 62l3 -3q-5 -88 -79 -88zM1438 687h-15q-19 0 -19 19q0 28 19 85q5 15 14.5 19t28.5 4q77 0 77 -49q0 -41 -30.5 -59.5 t-74.5 -18.5zM1780 527q-47 0 -47 30q0 62 123 62l3 -3q-5 -89 -79 -89zM373 894h-128q-8 0 -14.5 -4t-8.5 -7.5t-7 -12.5q-3 -7 -45 -190t-42 -192q0 -7 5.5 -12.5t13.5 -5.5h62q25 0 32.5 34.5l15 69t32.5 34.5q47 0 87.5 7.5t80.5 24.5t63.5 52.5t23.5 84.5 q0 36 -14.5 61t-41 36.5t-53.5 15.5t-62 4zM719 798q-38 0 -74 -6q-2 0 -8.5 -1t-9 -1.5l-7.5 -1.5t-7.5 -2t-6.5 -3t-6.5 -4t-5 -5t-4.5 -7t-4 -9q-9 -29 -9 -39t9 -10q5 0 21.5 5t19.5 6q30 8 58 8q74 0 74 -36q0 -11 -10 -14q-8 -2 -18 -3t-21.5 -1.5t-17.5 -1.5 q-38 -4 -64.5 -10t-56.5 -19.5t-45.5 -39t-15.5 -62.5q0 -38 26 -59.5t64 -21.5q24 0 45.5 6.5t33 13t38.5 23.5q-3 -7 -3 -15t5.5 -13.5t12.5 -5.5h56q1 1 7 3.5t7.5 3.5t5 3.5t5 5.5t2.5 8l45 194q4 13 4 30q0 81 -145 81zM1247 793h-74q-22 0 -39 -23q-5 -7 -29.5 -51 t-46.5 -81.5t-26 -38.5l-5 4q0 77 -27 166q-1 5 -3.5 8.5t-6 6.5t-6.5 5t-8.5 3t-8.5 1.5t-9.5 1t-9 0.5h-10h-8.5q-38 0 -38 -21l1 -5q5 -53 25 -151t25 -143q2 -16 2 -24q0 -19 -30.5 -61.5t-30.5 -58.5q0 -13 40 -13q61 0 76 25l245 415q10 20 10 26q0 9 -8 9zM1489 892 h-129q-18 0 -29 -23q-6 -13 -46.5 -191.5t-40.5 -190.5q0 -20 43 -20h7.5h9h9t9.5 1t8.5 2t8.5 3t6.5 4.5t5.5 6t3 8.5l21 91q2 10 10.5 17t19.5 7q47 0 87.5 7t80.5 24.5t63.5 52.5t23.5 84q0 36 -14.5 61t-41 36.5t-53.5 15.5t-62 4zM1835 798q-26 0 -74 -6 q-38 -6 -48 -16q-7 -8 -11 -19q-8 -24 -8 -39q0 -10 8 -10q1 0 41 12q30 8 58 8q74 0 74 -36q0 -12 -10 -14q-4 -1 -57 -7q-38 -4 -64.5 -10t-56.5 -19.5t-45.5 -39t-15.5 -62.5t26 -58.5t64 -21.5q24 0 45 6t34 13t38 24q-3 -15 -3 -16q0 -5 2 -8.5t6.5 -5.5t8 -3.5 t10.5 -2t9.5 -0.5h9.5h8q42 0 48 25l45 194q3 15 3 31q0 81 -145 81zM2157 889h-55q-25 0 -33 -40q-10 -44 -36.5 -167t-42.5 -190v-5q0 -16 16 -18h1h57q10 0 18.5 6.5t10.5 16.5l83 374h-1l1 5q0 7 -5.5 12.5t-13.5 5.5zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048 q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1f5;" horiz-adv-x="2304" d="M1597 633q0 -69 -21 -106q-19 -35 -52 -35q-23 0 -41 9v224q29 30 57 30q57 0 57 -122zM2035 669h-110q6 98 56 98q51 0 54 -98zM476 534q0 59 -33 91.5t-101 57.5q-36 13 -52 24t-16 25q0 26 38 26q58 0 124 -33l18 112q-67 32 -149 32q-77 0 -123 -38q-48 -39 -48 -109 q0 -58 32.5 -90.5t99.5 -56.5q39 -14 54.5 -25.5t15.5 -27.5q0 -31 -48 -31q-29 0 -70 12.5t-72 30.5l-18 -113q72 -41 168 -41q81 0 129 37q51 41 51 117zM771 749l19 111h-96v135l-129 -21l-18 -114l-46 -8l-17 -103h62v-219q0 -84 44 -120q38 -30 111 -30q32 0 79 11v118 q-32 -7 -44 -7q-42 0 -42 50v197h77zM1087 724v139q-15 3 -28 3q-32 0 -55.5 -16t-33.5 -46l-10 56h-131v-471h150v306q26 31 82 31q16 0 26 -2zM1124 389h150v471h-150v-471zM1746 638q0 122 -45 179q-40 52 -111 52q-64 0 -117 -56l-8 47h-132v-645l150 25v151 q36 -11 68 -11q83 0 134 56q61 65 61 202zM1278 986q0 33 -23 56t-56 23t-56 -23t-23 -56t23 -56.5t56 -23.5t56 23.5t23 56.5zM2176 629q0 113 -48 176q-50 64 -144 64q-96 0 -151.5 -66t-55.5 -180q0 -128 63 -188q55 -55 161 -55q101 0 160 40l-16 103q-57 -31 -128 -31 q-43 0 -63 19q-23 19 -28 66h248q2 14 2 52zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1f6;" horiz-adv-x="2048" d="M1558 684q61 -356 298 -556q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5zM1024 -176q16 0 16 16t-16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5zM2026 1424q8 -10 7.5 -23.5t-10.5 -22.5 l-1872 -1622q-10 -8 -23.5 -7t-21.5 11l-84 96q-8 10 -7.5 23.5t10.5 21.5l186 161q-19 32 -19 66q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q124 -18 219 -82.5t148 -157.5 l418 363q10 8 23.5 7t21.5 -11z" />
+<glyph unicode="&#xf1f7;" horiz-adv-x="2048" d="M1040 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM503 315l877 760q-42 88 -132.5 146.5t-223.5 58.5q-93 0 -169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -384 -137 -645zM1856 128 q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5l149 129h757q-166 187 -227 459l111 97q61 -356 298 -556zM1942 1520l84 -96q8 -10 7.5 -23.5t-10.5 -22.5l-1872 -1622q-10 -8 -23.5 -7t-21.5 11l-84 96q-8 10 -7.5 23.5t10.5 21.5l186 161 q-19 32 -19 66q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q124 -18 219 -82.5t148 -157.5l418 363q10 8 23.5 7t21.5 -11z" />
+<glyph unicode="&#xf1f8;" horiz-adv-x="1408" d="M512 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM768 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1024 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704 q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167 q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf1f9;" d="M1150 462v-109q0 -50 -36.5 -89t-94 -60.5t-118 -32.5t-117.5 -11q-205 0 -342.5 139t-137.5 346q0 203 136 339t339 136q34 0 75.5 -4.5t93 -18t92.5 -34t69 -56.5t28 -81v-109q0 -16 -16 -16h-118q-16 0 -16 16v70q0 43 -65.5 67.5t-137.5 24.5q-140 0 -228.5 -91.5 t-88.5 -237.5q0 -151 91.5 -249.5t233.5 -98.5q68 0 138 24t70 66v70q0 7 4.5 11.5t10.5 4.5h119q6 0 11 -4.5t5 -11.5zM768 1280q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5 t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf1fa;" d="M972 761q0 108 -53.5 169t-147.5 61q-63 0 -124 -30.5t-110 -84.5t-79.5 -137t-30.5 -180q0 -112 53.5 -173t150.5 -61q96 0 176 66.5t122.5 166t42.5 203.5zM1536 640q0 -111 -37 -197t-98.5 -135t-131.5 -74.5t-145 -27.5q-6 0 -15.5 -0.5t-16.5 -0.5q-95 0 -142 53 q-28 33 -33 83q-52 -66 -131.5 -110t-173.5 -44q-161 0 -249.5 95.5t-88.5 269.5q0 157 66 290t179 210.5t246 77.5q87 0 155 -35.5t106 -99.5l2 19l11 56q1 6 5.5 12t9.5 6h118q5 0 13 -11q5 -5 3 -16l-120 -614q-5 -24 -5 -48q0 -39 12.5 -52t44.5 -13q28 1 57 5.5t73 24 t77 50t57 89.5t24 137q0 292 -174 466t-466 174q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51q228 0 405 144q11 9 24 8t21 -12l41 -49q8 -12 7 -24q-2 -13 -12 -22q-102 -83 -227.5 -128t-258.5 -45q-156 0 -298 61 t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q344 0 556 -212t212 -556z" />
+<glyph unicode="&#xf1fb;" horiz-adv-x="1792" d="M1698 1442q94 -94 94 -226.5t-94 -225.5l-225 -223l104 -104q10 -10 10 -23t-10 -23l-210 -210q-10 -10 -23 -10t-23 10l-105 105l-603 -603q-37 -37 -90 -37h-203l-256 -128l-64 64l128 256v203q0 53 37 90l603 603l-105 105q-10 10 -10 23t10 23l210 210q10 10 23 10 t23 -10l104 -104l223 225q93 94 225.5 94t226.5 -94zM512 64l576 576l-192 192l-576 -576v-192h192z" />
+<glyph unicode="&#xf1fc;" horiz-adv-x="1792" d="M1615 1536q70 0 122.5 -46.5t52.5 -116.5q0 -63 -45 -151q-332 -629 -465 -752q-97 -91 -218 -91q-126 0 -216.5 92.5t-90.5 219.5q0 128 92 212l638 579q59 54 130 54zM706 502q39 -76 106.5 -130t150.5 -76l1 -71q4 -213 -129.5 -347t-348.5 -134q-123 0 -218 46.5 t-152.5 127.5t-86.5 183t-29 220q7 -5 41 -30t62 -44.5t59 -36.5t46 -17q41 0 55 37q25 66 57.5 112.5t69.5 76t88 47.5t103 25.5t125 10.5z" />
+<glyph unicode="&#xf1fd;" horiz-adv-x="1792" d="M1792 128v-384h-1792v384q45 0 85 14t59 27.5t47 37.5q30 27 51.5 38t56.5 11t55.5 -11t52.5 -38q29 -25 47 -38t58 -27t86 -14q45 0 85 14.5t58 27t48 37.5q21 19 32.5 27t31 15t43.5 7q35 0 56.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14t85 14t59 27.5t47 37.5 q30 27 51.5 38t56.5 11q34 0 55.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14zM1792 448v-192q-35 0 -55.5 11t-52.5 38q-29 25 -47 38t-58 27t-85 14q-46 0 -86 -14t-58 -27t-47 -38q-22 -19 -33 -27t-31 -15t-44 -7q-35 0 -56.5 11t-51.5 38q-29 25 -47 38t-58 27 t-86 14q-45 0 -85 -14.5t-58 -27t-48 -37.5q-21 -19 -32.5 -27t-31 -15t-43.5 -7q-35 0 -56.5 11t-51.5 38q-28 24 -47 37.5t-59 27.5t-85 14q-46 0 -86 -14t-58 -27t-47 -38q-30 -27 -51.5 -38t-56.5 -11v192q0 80 56 136t136 56h64v448h256v-448h256v448h256v-448h256v448 h256v-448h64q80 0 136 -56t56 -136zM512 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150zM1024 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51 t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150zM1536 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150z" />
+<glyph unicode="&#xf1fe;" horiz-adv-x="2048" d="M2048 0v-128h-2048v1536h128v-1408h1920zM1664 1024l256 -896h-1664v576l448 576l576 -576z" />
+<glyph unicode="&#xf200;" horiz-adv-x="1792" d="M768 646l546 -546q-106 -108 -247.5 -168t-298.5 -60q-209 0 -385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103v-762zM955 640h773q0 -157 -60 -298.5t-168 -247.5zM1664 768h-768v768q209 0 385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf201;" horiz-adv-x="2048" d="M2048 0v-128h-2048v1536h128v-1408h1920zM1920 1248v-435q0 -21 -19.5 -29.5t-35.5 7.5l-121 121l-633 -633q-10 -10 -23 -10t-23 10l-233 233l-416 -416l-192 192l585 585q10 10 23 10t23 -10l233 -233l464 464l-121 121q-16 16 -7.5 35.5t29.5 19.5h435q14 0 23 -9 t9 -23z" />
+<glyph unicode="&#xf202;" horiz-adv-x="1792" d="M1292 832q0 -6 10 -41q10 -29 25 -49.5t41 -34t44 -20t55 -16.5q325 -91 325 -332q0 -146 -105.5 -242.5t-254.5 -96.5q-59 0 -111.5 18.5t-91.5 45.5t-77 74.5t-63 87.5t-53.5 103.5t-43.5 103t-39.5 106.5t-35.5 95q-32 81 -61.5 133.5t-73.5 96.5t-104 64t-142 20 q-96 0 -183 -55.5t-138 -144.5t-51 -185q0 -160 106.5 -279.5t263.5 -119.5q177 0 258 95q56 63 83 116l84 -152q-15 -34 -44 -70l1 -1q-131 -152 -388 -152q-147 0 -269.5 79t-190.5 207.5t-68 274.5q0 105 43.5 206t116 176.5t172 121.5t204.5 46q87 0 159 -19t123.5 -50 t95 -80t72.5 -99t58.5 -117t50.5 -124.5t50 -130.5t55 -127q96 -200 233 -200q81 0 138.5 48.5t57.5 128.5q0 42 -19 72t-50.5 46t-72.5 31.5t-84.5 27t-87.5 34t-81 52t-65 82t-39 122.5q-3 16 -3 33q0 110 87.5 192t198.5 78q78 -3 120.5 -14.5t90.5 -53.5h-1 q12 -11 23 -24.5t26 -36t19 -27.5l-129 -99q-26 49 -54 70v1q-23 21 -97 21q-49 0 -84 -33t-35 -83z" />
+<glyph unicode="&#xf203;" d="M1432 484q0 173 -234 239q-35 10 -53 16.5t-38 25t-29 46.5q0 2 -2 8.5t-3 12t-1 7.5q0 36 24.5 59.5t60.5 23.5q54 0 71 -15h-1q20 -15 39 -51l93 71q-39 54 -49 64q-33 29 -67.5 39t-85.5 10q-80 0 -142 -57.5t-62 -137.5q0 -7 2 -23q16 -96 64.5 -140t148.5 -73 q29 -8 49 -15.5t45 -21.5t38.5 -34.5t13.5 -46.5v-5q1 -58 -40.5 -93t-100.5 -35q-97 0 -167 144q-23 47 -51.5 121.5t-48 125.5t-54 110.5t-74 95.5t-103.5 60.5t-147 24.5q-101 0 -192 -56t-144 -148t-50 -192v-1q4 -108 50.5 -199t133.5 -147.5t196 -56.5q186 0 279 110 q20 27 31 51l-60 109q-42 -80 -99 -116t-146 -36q-115 0 -191 87t-76 204q0 105 82 189t186 84q112 0 170 -53.5t104 -172.5q8 -21 25.5 -68.5t28.5 -76.5t31.5 -74.5t38.5 -74t45.5 -62.5t55.5 -53.5t66 -33t80 -13.5q107 0 183 69.5t76 174.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf204;" horiz-adv-x="2048" d="M1152 640q0 104 -40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM1920 640q0 104 -40.5 198.5 t-109.5 163.5t-163.5 109.5t-198.5 40.5h-386q119 -90 188.5 -224t69.5 -288t-69.5 -288t-188.5 -224h386q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM2048 640q0 -130 -51 -248.5t-136.5 -204t-204 -136.5t-248.5 -51h-768q-130 0 -248.5 51t-204 136.5 t-136.5 204t-51 248.5t51 248.5t136.5 204t204 136.5t248.5 51h768q130 0 248.5 -51t204 -136.5t136.5 -204t51 -248.5z" />
+<glyph unicode="&#xf205;" horiz-adv-x="2048" d="M0 640q0 130 51 248.5t136.5 204t204 136.5t248.5 51h768q130 0 248.5 -51t204 -136.5t136.5 -204t51 -248.5t-51 -248.5t-136.5 -204t-204 -136.5t-248.5 -51h-768q-130 0 -248.5 51t-204 136.5t-136.5 204t-51 248.5zM1408 128q104 0 198.5 40.5t163.5 109.5 t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5z" />
+<glyph unicode="&#xf206;" horiz-adv-x="2304" d="M762 384h-314q-40 0 -57.5 35t6.5 67l188 251q-65 31 -137 31q-132 0 -226 -94t-94 -226t94 -226t226 -94q115 0 203 72.5t111 183.5zM576 512h186q-18 85 -75 148zM1056 512l288 384h-480l-99 -132q105 -103 126 -252h165zM2176 448q0 132 -94 226t-226 94 q-60 0 -121 -24l174 -260q15 -23 10 -49t-27 -40q-15 -11 -36 -11q-35 0 -53 29l-174 260q-93 -95 -93 -225q0 -132 94 -226t226 -94t226 94t94 226zM2304 448q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 97 39.5 183.5t109.5 149.5l-65 98l-353 -469 q-18 -26 -51 -26h-197q-23 -164 -149 -274t-294 -110q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q114 0 215 -55l137 183h-224q-26 0 -45 19t-19 45t19 45t45 19h384v-128h435l-85 128h-222q-26 0 -45 19t-19 45t19 45t45 19h256q33 0 53 -28l267 -400 q91 44 192 44q185 0 316.5 -131.5t131.5 -316.5z" />
+<glyph unicode="&#xf207;" d="M384 320q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1408 320q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1362 716l-72 384q-5 23 -22.5 37.5t-40.5 14.5 h-918q-23 0 -40.5 -14.5t-22.5 -37.5l-72 -384q-5 -30 14 -53t49 -23h1062q30 0 49 23t14 53zM1136 1328q0 20 -14 34t-34 14h-640q-20 0 -34 -14t-14 -34t14 -34t34 -14h640q20 0 34 14t14 34zM1536 603v-603h-128v-128q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5v128h-768v-128q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5v128h-128v603q0 112 25 223l103 454q9 78 97.5 137t230 89t312.5 30t312.5 -30t230 -89t97.5 -137l105 -454q23 -102 23 -223z" />
+<glyph unicode="&#xf208;" horiz-adv-x="2048" d="M1463 704q0 -35 -25 -60.5t-61 -25.5h-702q-36 0 -61 25.5t-25 60.5t25 60.5t61 25.5h702q36 0 61 -25.5t25 -60.5zM1677 704q0 86 -23 170h-982q-36 0 -61 25t-25 60q0 36 25 61t61 25h908q-88 143 -235 227t-320 84q-177 0 -327.5 -87.5t-238 -237.5t-87.5 -327 q0 -86 23 -170h982q36 0 61 -25t25 -60q0 -36 -25 -61t-61 -25h-908q88 -143 235.5 -227t320.5 -84q132 0 253 51.5t208 139t139 208t52 253.5zM2048 959q0 -35 -25 -60t-61 -25h-131q17 -85 17 -170q0 -167 -65.5 -319.5t-175.5 -263t-262.5 -176t-319.5 -65.5 q-246 0 -448.5 133t-301.5 350h-189q-36 0 -61 25t-25 61q0 35 25 60t61 25h132q-17 85 -17 170q0 167 65.5 319.5t175.5 263t262.5 176t320.5 65.5q245 0 447.5 -133t301.5 -350h188q36 0 61 -25t25 -61z" />
+<glyph unicode="&#xf209;" horiz-adv-x="1280" d="M953 1158l-114 -328l117 -21q165 451 165 518q0 56 -38 56q-57 0 -130 -225zM654 471l33 -88q37 42 71 67l-33 5.5t-38.5 7t-32.5 8.5zM362 1367q0 -98 159 -521q18 10 49 10q15 0 75 -5l-121 351q-75 220 -123 220q-19 0 -29 -17.5t-10 -37.5zM283 608q0 -36 51.5 -119 t117.5 -153t100 -70q14 0 25.5 13t11.5 27q0 24 -32 102q-13 32 -32 72t-47.5 89t-61.5 81t-62 32q-20 0 -45.5 -27t-25.5 -47zM125 273q0 -41 25 -104q59 -145 183.5 -227t281.5 -82q227 0 382 170q152 169 152 427q0 43 -1 67t-11.5 62t-30.5 56q-56 49 -211.5 75.5 t-270.5 26.5q-37 0 -49 -11q-12 -5 -12 -35q0 -34 21.5 -60t55.5 -40t77.5 -23.5t87.5 -11.5t85 -4t70 0h23q24 0 40 -19q15 -19 19 -55q-28 -28 -96 -54q-61 -22 -93 -46q-64 -46 -108.5 -114t-44.5 -137q0 -31 18.5 -88.5t18.5 -87.5l-3 -12q-4 -12 -4 -14 q-137 10 -146 216q-8 -2 -41 -2q2 -7 2 -21q0 -53 -40.5 -89.5t-94.5 -36.5q-82 0 -166.5 78t-84.5 159q0 34 33 67q52 -64 60 -76q77 -104 133 -104q12 0 26.5 8.5t14.5 20.5q0 34 -87.5 145t-116.5 111q-43 0 -70 -44.5t-27 -90.5zM11 264q0 101 42.5 163t136.5 88 q-28 74 -28 104q0 62 61 123t122 61q29 0 70 -15q-163 462 -163 567q0 80 41 130.5t119 50.5q131 0 325 -581q6 -17 8 -23q6 16 29 79.5t43.5 118.5t54 127.5t64.5 123t70.5 86.5t76.5 36q71 0 112 -49t41 -122q0 -108 -159 -550q61 -15 100.5 -46t58.5 -78t26 -93.5 t7 -110.5q0 -150 -47 -280t-132 -225t-211 -150t-278 -55q-111 0 -223 42q-149 57 -258 191.5t-109 286.5z" />
+<glyph unicode="&#xf20a;" horiz-adv-x="2048" d="M785 528h207q-14 -158 -98.5 -248.5t-214.5 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-203q-5 64 -35.5 99t-81.5 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t40 -51.5t66 -18q95 0 109 139zM1497 528h206 q-14 -158 -98 -248.5t-214 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-204q-4 64 -35 99t-81 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t39.5 -51.5t65.5 -18q49 0 76.5 38t33.5 101zM1856 647q0 207 -15.5 307 t-60.5 161q-6 8 -13.5 14t-21.5 15t-16 11q-86 63 -697 63q-625 0 -710 -63q-5 -4 -17.5 -11.5t-21 -14t-14.5 -14.5q-45 -60 -60 -159.5t-15 -308.5q0 -208 15 -307.5t60 -160.5q6 -8 15 -15t20.5 -14t17.5 -12q44 -33 239.5 -49t470.5 -16q610 0 697 65q5 4 17 11t20.5 14 t13.5 16q46 60 61 159t15 309zM2048 1408v-1536h-2048v1536h2048z" />
+<glyph unicode="&#xf20b;" d="M992 912v-496q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v496q0 112 -80 192t-192 80h-272v-1152q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v1344q0 14 9 23t23 9h464q135 0 249 -66.5t180.5 -180.5t66.5 -249zM1376 1376v-880q0 -135 -66.5 -249t-180.5 -180.5 t-249 -66.5h-464q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h160q14 0 23 -9t9 -23v-768h272q112 0 192 80t80 192v880q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf20c;" d="M1311 694v-114q0 -24 -13.5 -38t-37.5 -14h-202q-24 0 -38 14t-14 38v114q0 24 14 38t38 14h202q24 0 37.5 -14t13.5 -38zM821 464v250q0 53 -32.5 85.5t-85.5 32.5h-133q-68 0 -96 -52q-28 52 -96 52h-130q-53 0 -85.5 -32.5t-32.5 -85.5v-250q0 -22 21 -22h55 q22 0 22 22v230q0 24 13.5 38t38.5 14h94q24 0 38 -14t14 -38v-230q0 -22 21 -22h54q22 0 22 22v230q0 24 14 38t38 14h97q24 0 37.5 -14t13.5 -38v-230q0 -22 22 -22h55q21 0 21 22zM1410 560v154q0 53 -33 85.5t-86 32.5h-264q-53 0 -86 -32.5t-33 -85.5v-410 q0 -21 22 -21h55q21 0 21 21v180q31 -42 94 -42h191q53 0 86 32.5t33 85.5zM1536 1176v-1072q0 -96 -68 -164t-164 -68h-1072q-96 0 -164 68t-68 164v1072q0 96 68 164t164 68h1072q96 0 164 -68t68 -164z" />
+<glyph unicode="&#xf20d;" horiz-adv-x="1792" />
+<glyph unicode="&#xf20e;" horiz-adv-x="1792" />
+<glyph unicode="&#xf500;" horiz-adv-x="1792" />
+</font>
+</defs></svg> \ No newline at end of file
diff --git a/web/src/fonts/fontawesome-webfont.ttf b/web/src/fonts/fontawesome-webfont.ttf
new file mode 100644
index 00000000..96a3639c
--- /dev/null
+++ b/web/src/fonts/fontawesome-webfont.ttf
Binary files differ
diff --git a/web/src/fonts/fontawesome-webfont.woff b/web/src/fonts/fontawesome-webfont.woff
new file mode 100644
index 00000000..628b6a52
--- /dev/null
+++ b/web/src/fonts/fontawesome-webfont.woff
Binary files differ
diff --git a/web/src/index.html b/web/src/index.html
index 571845b9..c40936e0 100644
--- a/web/src/index.html
+++ b/web/src/index.html
@@ -4,11 +4,10 @@
<meta charset="UTF-8">
<title>mitmproxy</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
- <link rel="stylesheet" href="/static/css/vendor.css"/>
- <link rel="stylesheet" href="/static/css/app.css"/>
- <script src="/static/js/vendor.js"></script>
- <script src="/static/js/app.js"></script>
+ <link rel="stylesheet" href="/static/vendor.css"/>
+ <link rel="stylesheet" href="/static/app.css"/>
+ <script src="/static/vendor.js"></script>
+ <script src="/static/app.js"></script>
</head>
-<body>
-</body>
+<body> </body>
</html> \ No newline at end of file
diff --git a/web/src/js/actions.js b/web/src/js/actions.js
index 7f4fd0b0..6dc11825 100644
--- a/web/src/js/actions.js
+++ b/web/src/js/actions.js
@@ -108,4 +108,10 @@ Query = {
FILTER: "f",
HIGHLIGHT: "h",
SHOW_EVENTLOG: "e"
+};
+
+module.exports = {
+ ActionTypes: ActionTypes,
+ ConnectionActions: ConnectionActions
+
}; \ No newline at end of file
diff --git a/web/src/js/app.js b/web/src/js/app.js
index 5146cb46..f2ddc2ae 100644
--- a/web/src/js/app.js
+++ b/web/src/js/app.js
@@ -1,7 +1,15 @@
+
+var React = require("react");
+var ReactRouter = require("react-router");
+var $ = require("jquery");
+
+var Connection = require("./connection");
+var proxyapp = require("./components/proxyapp.jsx.js");
+
$(function () {
window.ws = new Connection("/updates");
- ReactRouter.run(routes, function (Handler) {
+ ReactRouter.run(proxyapp.routes, function (Handler) {
React.render(<Handler/>, document.body);
});
}); \ No newline at end of file
diff --git a/web/src/js/components/flowdetail.jsx.js b/web/src/js/components/flowdetail.jsx.js
index 594d1a0e..0f91bde1 100644
--- a/web/src/js/components/flowdetail.jsx.js
+++ b/web/src/js/components/flowdetail.jsx.js
@@ -34,11 +34,11 @@ var FlowDetailNav = React.createClass({
var acceptButton = null;
if(flow.intercepted){
- acceptButton = <NavAction title="[a]ccept intercepted flow" icon="fa-play" onClick={FlowActions.accept.bind(null, flow)} />
+ acceptButton = <NavAction title="[a]ccept intercepted flow" icon="fa-play" onClick={FlowActions.accept.bind(null, flow)} />;
}
var revertButton = null;
if(flow.modified){
- revertButton = <NavAction title="revert changes to flow [V]" icon="fa-history" onClick={FlowActions.revert.bind(null, flow)} />
+ revertButton = <NavAction title="revert changes to flow [V]" icon="fa-history" onClick={FlowActions.revert.bind(null, flow)} />;
}
return (
diff --git a/web/src/js/components/flowtable-columns.jsx.js b/web/src/js/components/flowtable-columns.jsx.js
index 9162e077..39c4bd8d 100644
--- a/web/src/js/components/flowtable-columns.jsx.js
+++ b/web/src/js/components/flowtable-columns.jsx.js
@@ -1,3 +1,7 @@
+var React = require("react");
+var flowutils = require("../flow/utils.js");
+var utils = require("../utils.js");
+
var TLSColumn = React.createClass({
statics: {
renderTitle: function () {
@@ -29,7 +33,7 @@ var IconColumn = React.createClass({
var icon;
if (flow.response) {
- var contentType = ResponseUtils.getContentType(flow.response);
+ var contentType = flowutils.ResponseUtils.getContentType(flow.response);
//TODO: We should assign a type to the flow somewhere else.
if (flow.response.code == 304) {
@@ -120,7 +124,7 @@ var SizeColumn = React.createClass({
if (flow.response) {
total += flow.response.contentLength || 0;
}
- var size = formatSize(total);
+ var size = utils.formatSize(total);
return <td className="col-size">{size}</td>;
}
});
@@ -136,7 +140,7 @@ var TimeColumn = React.createClass({
var flow = this.props.flow;
var time;
if (flow.response) {
- time = formatTimeDelta(1000 * (flow.response.timestamp_end - flow.request.timestamp_start));
+ time = utils.formatTimeDelta(1000 * (flow.response.timestamp_end - flow.request.timestamp_start));
} else {
time = "...";
}
@@ -154,3 +158,7 @@ var all_columns = [
SizeColumn,
TimeColumn];
+
+module.exports = all_columns;
+
+
diff --git a/web/src/js/components/flowtable.jsx.js b/web/src/js/components/flowtable.jsx.js
index a3a37c40..90eebbc1 100644
--- a/web/src/js/components/flowtable.jsx.js
+++ b/web/src/js/components/flowtable.jsx.js
@@ -1,3 +1,8 @@
+var React = require("react");
+var utils = require("./utils.jsx.js");
+var VirtualScrollMixin = require("./virtualscroll.jsx.js");
+var flowtable_columns = require("./flowtable-columns.jsx.js");
+
var FlowRow = React.createClass({
render: function () {
var flow = this.props.flow;
@@ -52,10 +57,10 @@ var FlowTableHead = React.createClass({
var ROW_HEIGHT = 32;
var FlowTable = React.createClass({
- mixins: [StickyHeadMixin, AutoScrollMixin, VirtualScrollMixin],
+ mixins: [utils.StickyHeadMixin, utils.AutoScrollMixin, VirtualScrollMixin],
getInitialState: function () {
return {
- columns: all_columns
+ columns: flowtable_columns
};
},
componentWillMount: function () {
@@ -127,3 +132,5 @@ var FlowTable = React.createClass({
);
}
});
+
+module.exports = FlowTable;
diff --git a/web/src/js/components/footer.jsx.js b/web/src/js/components/footer.jsx.js
index 52d52e0f..d04fb615 100644
--- a/web/src/js/components/footer.jsx.js
+++ b/web/src/js/components/footer.jsx.js
@@ -1,3 +1,5 @@
+var React = require("react");
+
var Footer = React.createClass({
render: function () {
var mode = this.props.settings.mode;
@@ -11,3 +13,5 @@ var Footer = React.createClass({
);
}
});
+
+module.exports = Footer; \ No newline at end of file
diff --git a/web/src/js/components/header.jsx.js b/web/src/js/components/header.jsx.js
index 6470aec5..d9fd9ab0 100644
--- a/web/src/js/components/header.jsx.js
+++ b/web/src/js/components/header.jsx.js
@@ -1,3 +1,8 @@
+var React = require("react");
+var $ = require("jquery");
+
+var utils = require("./utils.jsx.js");
+
var FilterDocs = React.createClass({
statics: {
xhr: false,
@@ -148,7 +153,7 @@ var FilterInput = React.createClass({
});
var MainMenu = React.createClass({
- mixins: [Navigation, State],
+ mixins: [utils.Navigation, utils.State],
statics: {
title: "Start",
route: "flows"
@@ -205,7 +210,7 @@ var ViewMenu = React.createClass({
title: "View",
route: "flows"
},
- mixins: [Navigation, State],
+ mixins: [utils.Navigation, utils.State],
toggleEventLog: function () {
var d = {};
@@ -334,7 +339,7 @@ var header_entries = [MainMenu, ViewMenu /*, ReportsMenu */];
var Header = React.createClass({
- mixins: [Navigation],
+ mixins: [utils.Navigation],
getInitialState: function () {
return {
active: header_entries[0]
@@ -377,3 +382,8 @@ var Header = React.createClass({
);
}
});
+
+
+module.exports = {
+ Header: Header
+} \ No newline at end of file
diff --git a/web/src/js/components/mainview.jsx.js b/web/src/js/components/mainview.jsx.js
index af65ca1e..85ca36bb 100644
--- a/web/src/js/components/mainview.jsx.js
+++ b/web/src/js/components/mainview.jsx.js
@@ -1,5 +1,13 @@
+var React = require("react");
+
+var utils = require("./utils.jsx.js");
+var views = require("../store/view.js");
+var Filt = require("../filt/filt.js");
+FlowTable = require("./flowtable.jsx.js");
+
+
var MainView = React.createClass({
- mixins: [Navigation, State],
+ mixins: [utils.Navigation, utils.State],
getInitialState: function () {
this.onQueryChange(Query.FILTER, function () {
this.state.view.recalculate(this.getViewFilt(), this.getViewSort());
@@ -37,7 +45,7 @@ var MainView = React.createClass({
}
},
openView: function (store) {
- var view = new StoreView(store, this.getViewFilt(), this.getViewSort());
+ var view = new views.StoreView(store, this.getViewFilt(), this.getViewSort());
this.setState({
view: view
});
@@ -217,4 +225,6 @@ var MainView = React.createClass({
</div>
);
}
-}); \ No newline at end of file
+});
+
+module.exports = MainView;
diff --git a/web/src/js/components/proxyapp.jsx.js b/web/src/js/components/proxyapp.jsx.js
index 92fc0e49..2431ad46 100644
--- a/web/src/js/components/proxyapp.jsx.js
+++ b/web/src/js/components/proxyapp.jsx.js
@@ -1,3 +1,14 @@
+var React = require("react");
+var ReactRouter = require("react-router");
+var _ = require("lodash");
+
+var utils = require("./utils.jsx.js");
+var MainView = require("./mainview.jsx.js");
+var Footer = require("./footer.jsx.js");
+var header = require("./header.jsx.js");
+var store = require("../store/store.js");
+
+
//TODO: Move out of here, just a stub.
var Reports = React.createClass({
render: function () {
@@ -7,11 +18,11 @@ var Reports = React.createClass({
var ProxyAppMain = React.createClass({
- mixins: [State],
+ mixins: [utils.State],
getInitialState: function () {
- var eventStore = new EventLogStore();
- var flowStore = new FlowStore();
- var settings = new SettingsStore();
+ var eventStore = new store.EventLogStore();
+ var flowStore = new store.FlowStore();
+ var settings = new store.SettingsStore();
// Default Settings before fetch
_.extend(settings.dict,{
@@ -48,7 +59,7 @@ var ProxyAppMain = React.createClass({
return (
<div id="container">
- <Header settings={this.state.settings.dict}/>
+ <header.Header settings={this.state.settings.dict}/>
<RouteHandler settings={this.state.settings.dict} flowStore={this.state.flowStore}/>
{eventlog}
<Footer settings={this.state.settings.dict}/>
@@ -72,4 +83,9 @@ var routes = (
<Route name="reports" handler={Reports}/>
<Redirect path="/" to="flows" />
</Route>
-); \ No newline at end of file
+);
+
+module.exports = {
+ routes: routes
+};
+
diff --git a/web/src/js/components/utils.jsx.js b/web/src/js/components/utils.jsx.js
index 1714bfa9..9afcfbc7 100644
--- a/web/src/js/components/utils.jsx.js
+++ b/web/src/js/components/utils.jsx.js
@@ -1,3 +1,7 @@
+var React = require("react");
+var ReactRouter = require("react-router");
+var _ = require("lodash");
+
//React utils. For other utilities, see ../utils.js
// http://blog.vjeux.com/2013/javascript/scroll-position-with-react.html (also contains inverse example)
@@ -181,4 +185,12 @@ var Splitter = React.createClass({
</div>
);
}
-}); \ No newline at end of file
+});
+
+module.exports = {
+ State: State,
+ Navigation: Navigation,
+ StickyHeadMixin: StickyHeadMixin,
+ AutoScrollMixin: AutoScrollMixin,
+ Splitter: Splitter
+} \ No newline at end of file
diff --git a/web/src/js/components/virtualscroll.jsx.js b/web/src/js/components/virtualscroll.jsx.js
index 4f946cb4..956e1a0b 100644
--- a/web/src/js/components/virtualscroll.jsx.js
+++ b/web/src/js/components/virtualscroll.jsx.js
@@ -1,3 +1,5 @@
+var React = require("react");
+
var VirtualScrollMixin = {
getInitialState: function () {
return {
@@ -78,4 +80,6 @@ var VirtualScrollMixin = {
viewport.scrollTop = row_bottom - viewport.offsetHeight;
}
},
-}; \ No newline at end of file
+};
+
+module.exports = VirtualScrollMixin; \ No newline at end of file
diff --git a/web/src/js/connection.js b/web/src/js/connection.js
index 6ca353b3..85514c3c 100644
--- a/web/src/js/connection.js
+++ b/web/src/js/connection.js
@@ -1,24 +1,28 @@
-function Connection(url) {
+var actions = require("./actions.js");
+
+function Connection(url) {
if (url[0] === "/") {
url = location.origin.replace("http", "ws") + url;
}
var ws = new WebSocket(url);
ws.onopen = function () {
- ConnectionActions.open();
+ actions.ConnectionActions.open();
};
ws.onmessage = function (message) {
var m = JSON.parse(message.data);
AppDispatcher.dispatchServerAction(m);
};
ws.onerror = function () {
- ConnectionActions.error();
+ actions.ConnectionActions.error();
EventLogActions.add_event("WebSocket connection error.");
};
ws.onclose = function () {
- ConnectionActions.close();
+ actions.ConnectionActions.close();
EventLogActions.add_event("WebSocket connection closed.");
};
return ws;
-} \ No newline at end of file
+}
+
+module.exports = Connection; \ No newline at end of file
diff --git a/web/src/js/dispatcher.js b/web/src/js/dispatcher.js
index 860ade9f..9a5dd3dd 100644
--- a/web/src/js/dispatcher.js
+++ b/web/src/js/dispatcher.js
@@ -33,3 +33,7 @@ AppDispatcher.dispatchServerAction = function (action) {
action.source = PayloadSources.SERVER;
this.dispatch(action);
};
+
+module.exports = {
+ AppDispatcher: AppDispatcher
+}; \ No newline at end of file
diff --git a/web/src/js/filt/filt.js b/web/src/js/filt/filt.js
index 0d93b767..095081ac 100644
--- a/web/src/js/filt/filt.js
+++ b/web/src/js/filt/filt.js
@@ -1,3 +1,4 @@
+/* jshint ignore:start */
Filt = (function() {
/*
* Generated by PEG.js 0.8.0.
@@ -278,11 +279,11 @@ Filt = (function() {
expectedDescs[i] = expected[i].description;
}
- expectedDesc = (expected.length > 1
+ expectedDesc = expected.length > 1
? expectedDescs.slice(0, -1).join(", ")
+ " or "
+ expectedDescs[expected.length - 1]
- : expectedDescs[0]);
+ : expectedDescs[0];
foundDesc = found ? "\"" + stringEscape(found) + "\"" : "end of input";
@@ -1769,4 +1770,7 @@ Filt = (function() {
SyntaxError: SyntaxError,
parse: parse
};
-})(); \ No newline at end of file
+})();
+/* jshint ignore:end */
+
+module.exports = Filt;
diff --git a/web/src/js/flow/utils.js b/web/src/js/flow/utils.js
index 113f0b1a..50305482 100644
--- a/web/src/js/flow/utils.js
+++ b/web/src/js/flow/utils.js
@@ -1,3 +1,5 @@
+var _ = require("lodash");
+
var _MessageUtils = {
getContentType: function (message) {
return this.get_first_header(message, /^Content-Type$/i);
@@ -54,4 +56,9 @@ var RequestUtils = _.extend(_MessageUtils, {
}
});
-var ResponseUtils = _.extend(_MessageUtils, {}); \ No newline at end of file
+var ResponseUtils = _.extend(_MessageUtils, {});
+
+
+module.exports = {
+ ResponseUtils: ResponseUtils
+} \ No newline at end of file
diff --git a/web/src/js/store/store.js b/web/src/js/store/store.js
index ce5c0338..60913ca6 100644
--- a/web/src/js/store/store.js
+++ b/web/src/js/store/store.js
@@ -1,8 +1,17 @@
+
+var _ = require("lodash");
+var $ = require("jquery");
+
+var utils = require("../utils.js");
+var actions = require("../actions.js");
+var dispatcher = require("../dispatcher.js");
+
+
function ListStore() {
- EventEmitter.call(this);
+ utils.EventEmitter.call(this);
this.reset();
}
-_.extend(ListStore.prototype, EventEmitter.prototype, {
+_.extend(ListStore.prototype, utils.EventEmitter.prototype, {
add: function (elem) {
if (elem.id in this._pos_map) {
return;
@@ -48,10 +57,10 @@ _.extend(ListStore.prototype, EventEmitter.prototype, {
function DictStore() {
- EventEmitter.call(this);
+ utils.EventEmitter.call(this);
this.reset();
}
-_.extend(DictStore.prototype, EventEmitter.prototype, {
+_.extend(DictStore.prototype, utils.EventEmitter.prototype, {
update: function (dict) {
_.merge(this.dict, dict);
this.emit("recalculate");
@@ -69,7 +78,7 @@ function LiveStoreMixin(type) {
this._fetchxhr = false;
this.handle = this.handle.bind(this);
- AppDispatcher.register(this.handle);
+ dispatcher.AppDispatcher.register(this.handle);
// Avoid double-fetch on startup.
if (!(window.ws && window.ws.readyState === WebSocket.CONNECTING)) {
@@ -78,7 +87,7 @@ function LiveStoreMixin(type) {
}
_.extend(LiveStoreMixin.prototype, {
handle: function (event) {
- if (event.type === ActionTypes.CONNECTION_OPEN) {
+ if (event.type === actions.ActionTypes.CONNECTION_OPEN) {
return this.fetch();
}
if (event.type === this.type) {
@@ -93,7 +102,7 @@ _.extend(LiveStoreMixin.prototype, {
}
},
close: function () {
- AppDispatcher.unregister(this.handle);
+ dispatcher.AppDispatcher.unregister(this.handle);
},
fetch: function (data) {
console.log("fetch " + this.type);
@@ -139,15 +148,15 @@ _.extend(LiveDictStore.prototype, DictStore.prototype, LiveStoreMixin.prototype)
function FlowStore() {
- return new LiveListStore(ActionTypes.FLOW_STORE);
+ return new LiveListStore(actions.ActionTypes.FLOW_STORE);
}
function SettingsStore() {
- return new LiveDictStore(ActionTypes.SETTINGS_STORE);
+ return new LiveDictStore(actions.ActionTypes.SETTINGS_STORE);
}
function EventLogStore() {
- LiveListStore.call(this, ActionTypes.EVENT_STORE);
+ LiveListStore.call(this, actions.ActionTypes.EVENT_STORE);
}
_.extend(EventLogStore.prototype, LiveListStore.prototype, {
fetch: function(){
@@ -161,4 +170,11 @@ _.extend(EventLogStore.prototype, LiveListStore.prototype, {
}.bind(this));
}
}
-}); \ No newline at end of file
+});
+
+
+module.exports = {
+ EventLogStore: EventLogStore,
+ SettingsStore: SettingsStore,
+ FlowStore: FlowStore
+}; \ No newline at end of file
diff --git a/web/src/js/store/view.js b/web/src/js/store/view.js
index 9619f994..e96d1bcc 100644
--- a/web/src/js/store/view.js
+++ b/web/src/js/store/view.js
@@ -1,3 +1,7 @@
+var _ = require("lodash");
+
+var utils = require("../utils.js");
+
function SortByStoreOrder(elem) {
return this.store.index(elem.id);
}
@@ -8,7 +12,7 @@ var default_filt = function(elem){
};
function StoreView(store, filt, sortfun) {
- EventEmitter.call(this);
+ utils.EventEmitter.call(this);
filt = filt || default_filt;
sortfun = sortfun || default_sort;
@@ -26,7 +30,7 @@ function StoreView(store, filt, sortfun) {
this.recalculate(filt, sortfun);
}
-_.extend(StoreView.prototype, EventEmitter.prototype, {
+_.extend(StoreView.prototype, utils.EventEmitter.prototype, {
close: function () {
this.store.removeListener("add", this.add);
this.store.removeListener("update", this.update);
@@ -96,4 +100,8 @@ _.extend(StoreView.prototype, EventEmitter.prototype, {
}
}
}
-}); \ No newline at end of file
+});
+
+module.exports = {
+ StoreView: StoreView
+}; \ No newline at end of file
diff --git a/web/src/js/utils.js b/web/src/js/utils.js
index a8565243..0371810c 100644
--- a/web/src/js/utils.js
+++ b/web/src/js/utils.js
@@ -1,3 +1,6 @@
+var $ = require("jquery");
+
+
var Key = {
UP: 38,
DOWN: 40,
@@ -88,7 +91,7 @@ function getCookie(name) {
var xsrf = $.param({_xsrf: getCookie("_xsrf")});
//Tornado XSRF Protection.
-jQuery.ajaxPrefilter(function (options) {
+$.ajaxPrefilter(function (options) {
if (["post", "put", "delete"].indexOf(options.type.toLowerCase()) >= 0 && options.url[0] === "/") {
if (options.data) {
options.data += ("&" + xsrf);
@@ -103,4 +106,11 @@ $(document).ajaxError(function (event, jqXHR, ajaxSettings, thrownError) {
console.error(message, arguments);
EventLogActions.add_event(thrownError + ": " + message);
window.alert(message);
-}); \ No newline at end of file
+});
+
+module.exports = {
+ EventEmitter: EventEmitter,
+ formatSize: formatSize,
+ formatTimeDelta: formatTimeDelta,
+ formatTimeStamp: formatTimeStamp
+}; \ No newline at end of file