npm-polymer-elements
Version:
Polymer Elements package for npm
778 lines (719 loc) • 2.87 MB
JavaScript
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){
(function (global){
/**
* @license
* Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
* Code distributed by Google as part of the polymer project is also
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/
// jshint node: true
'use strict';
// jshint -W079
var Promise = global.Promise || require('es6-promise').Promise;
// jshint +W079
var dom5 = require('dom5');
var url = require('url');
var docs = require('./ast-utils/docs');
var FileLoader = require('./loader/file-loader');
var importParse = require('./ast-utils/import-parse');
var jsParse = require('./ast-utils/js-parse');
var NoopResolver = require('./loader/noop-resolver');
var StringResolver = require('./loader/string-resolver');
function reduceMetadata(m1, m2) {
return {
elements: m1.elements.concat(m2.elements),
features: m1.features.concat(m2.features),
behaviors: m1.behaviors.concat(m2.behaviors),
};
}
var EMPTY_METADATA = {elements: [], features: [], behaviors: []};
/**
* Parse5's representation of a parsed html document
* @typedef {Object} DocumentAST
* @memberof hydrolysis
*/
/**
* espree's representation of a parsed html document
* @typedef {Object} JSAST
* @memberof hydrolysis
*/
/**
* Package of a parsed JS script
* @typedef {Object} ParsedJS
* @property {JSAST} ast The script's AST
* @property {DocumentAST} scriptElement If inline, the script's containing tag.
* @memberof hydrolysis
*/
/**
* The metadata for a single polymer element
* @typedef {Object} ElementDescriptor
* @memberof hydrolysis
*/
/**
* The metadata for a Polymer feature.
* @typedef {Object} FeatureDescriptor
* @memberof hydrolysis
*/
/**
* The metadata for a Polymer behavior mixin.
* @typedef {Object} BehaviorDescriptor
* @memberof hydrolysis
*/
/**
* The metadata for all features and elements defined in one document
* @typedef {Object} DocumentDescriptor
* @memberof hydrolysis
* @property {Array<ElementDescriptor>} elements The elements from the document
* @property {Array<FeatureDescriptor>} features The features from the document
* @property {Array<FeatureDescriptor>} behaviors The behaviors from the document
*/
/**
* The metadata of an entire HTML document, in promises.
* @typedef {Object} AnalyzedDocument
* @memberof hydrolysis
* @property {string} href The url of the document.
* @property {Promise<ParsedImport>} htmlLoaded The parsed representation of
* the doc. Use the `ast` property to get the full `parse5` ast
*
* @property {Promise<Array<string>>} depsLoaded Resolves to the list of this
* Document's transitive import dependencies
*
* @property {Array<string>} depHrefs The direct dependencies of the document.
*
* @property {Promise<DocumentDescriptor>} metadataLoaded Resolves to the list of
* this Document's import dependencies
*/
/**
* A database of Polymer metadata defined in HTML
*
* @constructor
* @memberOf hydrolysis
* @param {boolean} attachAST If true, attach a parse5 compliant AST
* @param {FileLoader=} loader An optional `FileLoader` used to load external
* resources
*/
var Analyzer = function Analyzer(attachAST,
loader) {
this.loader = loader;
/**
* A list of all elements the `Analyzer` has metadata for.
* @member {Array.<ElementDescriptor>}
*/
this.elements = [];
/**
* A view into `elements`, keyed by tag name.
* @member {Object.<string,ElementDescriptor>}
*/
this.elementsByTagName = {};
/**
* A list of API features added to `Polymer.Base` encountered by the
* analyzer.
* @member {Array<FeatureDescriptor>}
*/
this.features = [];
/**
* The behaviors collected by the analysis pass.
*
* @member {Array<BehaviorDescriptor>}
*/
this.behaviors = [];
/**
* The behaviors collected by the analysis pass by name.
*
* @member {Object<string,BehaviorDescriptor>}
*/
this.behaviorsByName = {};
/**
* A map, keyed by absolute path, of Document metadata.
* @member {Object<string,AnalyzedDocument>}
*/
this.html = {};
/**
* A map, keyed by path, of HTML document ASTs.
* @type {Object}
*/
this.parsedDocuments = {};
/**
* A map, keyed by path, of JS script ASTs.
*
* If the path is an HTML file with multiple scripts, the entry will be an array of scripts.
*
* @type {Object<string,Array<ParsedJS>>}
*/
this.parsedScripts = {};
/**
* A map, keyed by path, of document content.
* @type {Object}
*/
this._content = {};
};
/**
* Options for `Analyzer.analzye`
* @typedef {Object} LoadOptions
* @memberof hydrolysis
* @property {boolean} noAnnotations Whether `annotate()` should be skipped.
* @property {String=} content Content to resolve `href` to instead of loading
* from the file system.
* @property {boolean} clean Whether the generated descriptors should be cleaned
* of redundant data.
* @property {string=} resolver.
* `xhr` to use XMLHttpRequest
* `fs` to use the local filesystem.
* `permissive` to use the local filesystem and return empty files when a
* path can't be found.
* Default is `fs` in node and `xhr` in the browser.
* @property {function(string): boolean} filter A predicate function that
* indicates which files should be ignored by the loader. By default all
* files not located under the dirname of `href` will be ignored.
*/
/**
* Shorthand for transitively loading and processing all imports beginning at
* `href`.
*
* In order to properly filter paths, `href` _must_ be an absolute URI.
*
* @param {string} href The root import to begin loading from.
* @param {LoadOptions=} options Any additional options for the load.
* @return {Promise<Analyzer>} A promise that will resolve once `href` and its
* dependencies have been loaded and analyzed.
*/
Analyzer.analyze = function analyze(href, options) {
options = options || {};
options.filter = options.filter || _defaultFilter(href);
var loader = new FileLoader();
var resolver = options.resolver;
if (resolver === undefined) {
if (typeof window === 'undefined') {
resolver = 'fs';
} else {
resolver = 'xhr';
}
}
var PrimaryResolver;
if (resolver === 'fs') {
PrimaryResolver = require('./loader/fs-resolver');
} else if (resolver === 'xhr') {
PrimaryResolver = require('./loader/xhr-resolver');
} else if (resolver === 'permissive') {
PrimaryResolver = require('./loader/error-swallowing-fs-resolver');
} else {
throw new Error("Resolver must be one of 'fs' or 'xhr'");
}
loader.addResolver(new PrimaryResolver(options));
if (options.content) {
loader.addResolver(new StringResolver({url: href, content: options.content}));
}
loader.addResolver(new NoopResolver({test: options.filter}));
var analyzer = new this(null, loader);
return analyzer.metadataTree(href).then(function(root) {
if (!options.noAnnotations) {
analyzer.annotate();
}
if (options.clean) {
analyzer.clean();
}
return Promise.resolve(analyzer);
});
};
/**
* @private
* @param {string} href
* @return {function(string): boolean}
*/
function _defaultFilter(href) {
// Everything up to the last `/` or `\`.
var base = href.match(/^(.*?)[^\/\\]*$/)[1];
return function(uri) {
return uri.indexOf(base) !== 0;
};
}
Analyzer.prototype.load = function load(href) {
return this.loader.request(href).then(function(content) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
this._content[href] = content;
resolve(this._parseHTML(content, href));
}.bind(this), 0);
}.bind(this)).catch(function(err){
console.error("Error processing document at " + href);
throw err;
});
}.bind(this));
};
/**
* Returns an `AnalyzedDocument` representing the provided document
* @private
* @param {string} htmlImport Raw text of an HTML document
* @param {string} href The document's URL.
* @return {AnalyzedDocument} An `AnalyzedDocument`
*/
Analyzer.prototype._parseHTML = function _parseHTML(htmlImport,
href) {
if (href in this.html) {
return this.html[href];
}
var depsLoaded = [];
var depHrefs = [];
var metadataLoaded = Promise.resolve(EMPTY_METADATA);
var parsed;
try {
parsed = importParse(htmlImport, href);
} catch (err) {
console.error('Error parsing!');
throw err;
}
var htmlLoaded = Promise.resolve(parsed);
if (parsed.script) {
metadataLoaded = this._processScripts(parsed.script, href);
}
var commentText = parsed.comment.map(function(comment){
return dom5.getTextContent(comment);
});
var pseudoElements = docs.parsePseudoElements(commentText);
pseudoElements.forEach(function(element){
element.contentHref = href;
this.elements.push(element);
this.elementsByTagName[element.is] = element;
}.bind(this));
metadataLoaded = metadataLoaded.then(function(metadata){
var metadataEntry = {
elements: pseudoElements,
features: [],
behaviors: []
};
return [metadata, metadataEntry].reduce(reduceMetadata);
});
depsLoaded.push(metadataLoaded);
if (this.loader) {
var baseUri = href;
if (parsed.base.length > 1) {
console.error("Only one base tag per document!");
throw "Multiple base tags in " + href;
} else if (parsed.base.length == 1) {
var baseHref = dom5.getAttribute(parsed.base[0], "href");
if (baseHref) {
baseHref = baseHref + "/";
baseUri = url.resolve(baseUri, baseHref);
}
}
parsed.import.forEach(function(link) {
var linkurl = dom5.getAttribute(link, 'href');
if (linkurl) {
var resolvedUrl = url.resolve(baseUri, linkurl);
depHrefs.push(resolvedUrl);
depsLoaded.push(this._dependenciesLoadedFor(resolvedUrl, href));
}
}.bind(this));
parsed.style.forEach(function(styleElement) {
if (polymerExternalStyle(styleElement)) {
var styleHref = dom5.getAttribute(styleElement, 'href');
if (href) {
styleHref = url.resolve(baseUri, styleHref);
depsLoaded.push(this.loader.request(styleHref).then(function(content){
this._content[styleHref] = content;
}.bind(this)));
}
}
}.bind(this));
}
depsLoaded = Promise.all(depsLoaded)
.then(function() {return depHrefs;})
.catch(function(err) {throw err;});
this.parsedDocuments[href] = parsed.ast;
this.html[href] = {
href: href,
htmlLoaded: htmlLoaded,
metadataLoaded: metadataLoaded,
depHrefs: depHrefs,
depsLoaded: depsLoaded
};
return this.html[href];
};
Analyzer.prototype._processScripts = function _processScripts(scripts, href) {
var scriptPromises = [];
scripts.forEach(function(script) {
scriptPromises.push(this._processScript(script, href));
}.bind(this));
return Promise.all(scriptPromises).then(function(metadataList) {
return metadataList.reduce(reduceMetadata, EMPTY_METADATA);
});
};
Analyzer.prototype._processScript = function _processScript(script, href) {
var src = dom5.getAttribute(script, 'src');
var parsedJs;
if (!src) {
try {
parsedJs = jsParse((script.childNodes.length) ? script.childNodes[0].value : '');
} catch (err) {
// Figure out the correct line number for the error.
var line = 0;
var col = 0;
if (script.__ownerDocument && script.__ownerDocument == href) {
line = script.__locationDetail.line - 1;
col = script.__locationDetail.column - 1;
}
line += err.lineNumber;
col += err.column;
var message = "Error parsing script in " + href + " at " + line + ":" + col;
message += "\n" + err.stack;
var fixedErr = new Error(message);
fixedErr.location = {line: line, column: col};
fixedErr.ownerDocument = script.__ownerDocument;
return Promise.reject(fixedErr);
}
if (parsedJs.elements) {
parsedJs.elements.forEach(function(element) {
element.scriptElement = script;
element.contentHref = href;
this.elements.push(element);
if (element.is in this.elementsByTagName) {
console.warn('Ignoring duplicate element definition: ' + element.is);
} else {
this.elementsByTagName[element.is] = element;
}
}.bind(this));
}
if (parsedJs.features) {
parsedJs.features.forEach(function(feature){
feature.contentHref = href;
feature.scriptElement = script;
});
this.features = this.features.concat(parsedJs.features);
}
if (parsedJs.behaviors) {
parsedJs.behaviors.forEach(function(behavior){
behavior.contentHref = href;
this.behaviorsByName[behavior.is] = behavior;
this.behaviorsByName[behavior.symbol] = behavior;
}.bind(this));
this.behaviors = this.behaviors.concat(parsedJs.behaviors);
}
if (!Object.hasOwnProperty.call(this.parsedScripts, href)) {
this.parsedScripts[href] = [];
}
var scriptElement;
if (script.__ownerDocument && script.__ownerDocument == href) {
scriptElement = script;
}
this.parsedScripts[href].push({
ast: parsedJs.parsedScript,
scriptElement: scriptElement
});
return parsedJs;
}
if (this.loader) {
var resolvedSrc = url.resolve(href, src);
return this.loader.request(resolvedSrc).then(function(content) {
this._content[resolvedSrc] = content;
var resolvedScript = Object.create(script);
resolvedScript.childNodes = [{value: content}];
resolvedScript.attrs = resolvedScript.attrs.slice();
dom5.removeAttribute(resolvedScript, 'src');
return this._processScript(resolvedScript, resolvedSrc);
}.bind(this)).catch(function(err) {throw err;});
} else {
return Promise.resolve(EMPTY_METADATA);
}
};
Analyzer.prototype._dependenciesLoadedFor = function _dependenciesLoadedFor(href, root) {
var found = {};
if (root !== undefined) {
found[root] = true;
}
return this._getDependencies(href, found).then(function(deps) {
var depMetadataLoaded = [];
var depPromises = deps.map(function(depHref){
return this.load(depHref).then(function(htmlMonomer) {
return htmlMonomer.metadataLoaded;
});
}.bind(this));
return Promise.all(depPromises);
}.bind(this));
};
/**
* List all the html dependencies for the document at `href`.
* @param {string} href The href to get dependencies for.
* @param {Object.<string,boolean>=} found An object keyed by URL of the
* already resolved dependencies.
* @param {boolean=} transitive Whether to load transitive
* dependencies. Defaults to true.
* @return {Array.<string>} A list of all the html dependencies.
*/
Analyzer.prototype._getDependencies = function _getDependencies(href, found, transitive) {
if (found === undefined) {
found = {};
found[href] = true;
}
if (transitive === undefined) {
transitive = true;
}
var deps = [];
return this.load(href).then(function(htmlMonomer) {
var transitiveDeps = [];
htmlMonomer.depHrefs.forEach(function(depHref){
if (found[depHref]) {
return;
}
deps.push(depHref);
found[depHref] = true;
if (transitive) {
transitiveDeps.push(this._getDependencies(depHref, found));
}
}.bind(this));
return Promise.all(transitiveDeps);
}.bind(this)).then(function(transitiveDeps) {
var alldeps = transitiveDeps.reduce(function(a, b) {
return a.concat(b);
}, []).concat(deps);
return alldeps;
});
};
function matchesDocumentFolder(descriptor, href) {
if (!descriptor.contentHref) {
return false;
}
var descriptorDoc = url.parse(descriptor.contentHref);
if (!descriptorDoc || !descriptorDoc.pathname) {
return false;
}
var searchDoc = url.parse(href);
if (!searchDoc || !searchDoc.pathname) {
return false;
}
var searchPath = searchDoc.pathname;
var lastSlash = searchPath.lastIndexOf("/");
if (lastSlash > 0) {
searchPath = searchPath.slice(0, lastSlash);
}
return descriptorDoc.pathname.indexOf(searchPath) === 0;
}
/**
* Returns the elements defined in the folder containing `href`.
* @param {string} href path to search.
* @return {Array.<ElementDescriptor>}
*/
Analyzer.prototype.elementsForFolder = function elementsForFolder(href) {
return this.elements.filter(function(element){
return matchesDocumentFolder(element, href);
});
};
/**
* Returns the behaviors defined in the folder containing `href`.
* @param {string} href path to search.
* @return {Array.<BehaviorDescriptor>}
*/
Analyzer.prototype.behaviorsForFolder = function behaviorsForFolder(href) {
return this.behaviors.filter(function(behavior){
return matchesDocumentFolder(behavior, href);
});
};
/**
* Returns a promise that resolves to a POJO representation of the import
* tree, in a format that maintains the ordering of the HTML imports spec.
* @param {string} href the import to get metadata for.
* @return {Promise}
*/
Analyzer.prototype.metadataTree = function metadataTree(href) {
return this.load(href).then(function(monomer){
var loadedHrefs = {};
loadedHrefs[href] = true;
return this._metadataTree(monomer, loadedHrefs);
}.bind(this));
};
Analyzer.prototype._metadataTree = function _metadataTree(htmlMonomer,
loadedHrefs) {
if (loadedHrefs === undefined) {
loadedHrefs = {};
}
return htmlMonomer.metadataLoaded.then(function(metadata) {
metadata = {
elements: metadata.elements,
features: metadata.features,
href: htmlMonomer.href
};
return htmlMonomer.depsLoaded.then(function(hrefs) {
var depMetadata = [];
hrefs.forEach(function(href) {
var metadataPromise = Promise.resolve(true);
if (depMetadata.length > 0) {
metadataPromise = depMetadata[depMetadata.length - 1];
}
metadataPromise = metadataPromise.then(function() {
if (!loadedHrefs[href]) {
loadedHrefs[href] = true;
return this._metadataTree(this.html[href], loadedHrefs);
} else {
return Promise.resolve({});
}
}.bind(this));
depMetadata.push(metadataPromise);
}.bind(this));
return Promise.all(depMetadata).then(function(importMetadata) {
metadata.imports = importMetadata;
return htmlMonomer.htmlLoaded.then(function(parsedHtml) {
metadata.html = parsedHtml;
if (metadata.elements) {
metadata.elements.forEach(function(element) {
attachDomModule(parsedHtml, element);
});
}
return metadata;
});
});
}.bind(this));
}.bind(this));
};
function matchingImport(importElement) {
var matchesTag = dom5.predicates.hasTagName(importElement.tagName);
var matchesHref = dom5.predicates.hasAttrValue('href', dom5.getAttribute(importElement, 'href'));
var matchesRel = dom5.predicates.hasAttrValue('rel', dom5.getAttribute(importElement, 'rel'));
return dom5.predicates.AND(matchesTag, matchesHref, matchesRel);
}
// TODO(ajo): Refactor out of vulcanize into dom5.
var polymerExternalStyle = dom5.predicates.AND(
dom5.predicates.hasTagName('link'),
dom5.predicates.hasAttrValue('rel', 'import'),
dom5.predicates.hasAttrValue('type', 'css')
);
var externalScript = dom5.predicates.AND(
dom5.predicates.hasTagName('script'),
dom5.predicates.hasAttr('src')
);
var isHtmlImportNode = dom5.predicates.AND(
dom5.predicates.hasTagName('link'),
dom5.predicates.hasAttrValue('rel', 'import'),
dom5.predicates.NOT(
dom5.predicates.hasAttrValue('type', 'css')
)
);
Analyzer.prototype._inlineStyles = function _inlineStyles(ast, href) {
var cssLinks = dom5.queryAll(ast, polymerExternalStyle);
cssLinks.forEach(function(link) {
var linkHref = dom5.getAttribute(link, 'href');
var uri = url.resolve(href, linkHref);
var content = this._content[uri];
var style = dom5.constructors.element('style');
dom5.setTextContent(style, '\n' + content + '\n');
dom5.replace(link, style);
}.bind(this));
return cssLinks.length > 0;
};
Analyzer.prototype._inlineScripts = function _inlineScripts(ast, href) {
var scripts = dom5.queryAll(ast, externalScript);
scripts.forEach(function(script) {
var scriptHref = dom5.getAttribute(script, 'src');
var uri = url.resolve(href, scriptHref);
var content = this._content[uri];
var inlined = dom5.constructors.element('script');
dom5.setTextContent(inlined, '\n' + content + '\n');
dom5.replace(script, inlined);
}.bind(this));
return scripts.length > 0;
};
Analyzer.prototype._inlineImports = function _inlineImports(ast, href, loaded) {
var imports = dom5.queryAll(ast, isHtmlImportNode);
imports.forEach(function(htmlImport) {
var importHref = dom5.getAttribute(htmlImport, 'href');
var uri = url.resolve(href, importHref);
if (loaded[uri]) {
dom5.remove(htmlImport);
return;
}
var content = this.getLoadedAst(uri, loaded);
dom5.replace(htmlImport, content);
}.bind(this));
return imports.length > 0;
};
/**
* Returns a promise resolving to a form of the AST with all links replaced
* with the document they link to. .css and .script files become <style> and
* <script>, respectively.
*
* The elements in the loaded document are unmodified from their original
* documents.
*
* @param {string} href The document to load.
* @param {Object.<string,boolean>=} loaded An object keyed by already loaded documents.
* @return {Promise.<DocumentAST>}
*/
Analyzer.prototype.getLoadedAst = function getLoadedAst(href, loaded) {
if (!loaded) {
loaded = {};
}
loaded[href] = true;
var parsedDocument = this.parsedDocuments[href];
var analyzedDocument = this.html[href];
var astCopy = dom5.parse(dom5.serialize(parsedDocument));
// Whenever we inline something, reset inlined to true to know that anoather
// inlining pass is needed;
this._inlineStyles(astCopy, href);
this._inlineScripts(astCopy, href);
this._inlineImports(astCopy, href, loaded);
return astCopy;
};
/**
* Calls `dom5.nodeWalkAll` on each document that `Anayzler` has laoded.
* @param {Object} predicate A dom5 predicate.
* @return {Object}
*/
Analyzer.prototype.nodeWalkDocuments = function nodeWalkDocuments(predicate) {
for (var href in this.parsedDocuments) {
var match = dom5.nodeWalk(this.parsedDocuments[href], predicate);
if (match) {
return match;
}
}
return null;
};
/**
* Calls `dom5.nodeWalkAll` on each document that `Anayzler` has laoded.
* @param {Object} predicate A dom5 predicate.
* @return {Object}
*/
Analyzer.prototype.nodeWalkAllDocuments = function nodeWalkDocuments(predicate) {
var results = [];
for (var href in this.parsedDocuments) {
var newNodes = dom5.nodeWalkAll(this.parsedDocuments[href], predicate);
results = results.concat(newNodes);
}
return results;
};
/** Annotates all loaded metadata with its documentation. */
Analyzer.prototype.annotate = function annotate() {
if (this.features.length > 0) {
var featureEl = docs.featureElement(this.features);
this.elements.unshift(featureEl);
this.elementsByTagName[featureEl.is] = featureEl;
}
var behaviorsByName = this.behaviorsByName;
var elementHelper = function(descriptor){
docs.annotateElement(descriptor, behaviorsByName);
};
this.elements.forEach(elementHelper);
this.behaviors.forEach(elementHelper); // Same shape.
this.behaviors.forEach(function(behavior){
if (behavior.is !== behavior.symbol && behavior.symbol) {
this.behaviorsByName[behavior.symbol] = undefined;
}
}.bind(this));
};
function attachDomModule(parsedImport, element) {
var domModules = parsedImport['dom-module'];
for (var i = 0, domModule; i < domModules.length; i++) {
domModule = domModules[i];
if (dom5.getAttribute(domModule, 'id') === element.is) {
element.domModule = domModule;
return;
}
}
}
/** Removes redundant properties from the collected descriptors. */
Analyzer.prototype.clean = function clean() {
this.elements.forEach(docs.cleanElement);
};
module.exports = Analyzer;
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImxpYi9hbmFseXplci5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTUgVGhlIFBvbHltZXIgUHJvamVjdCBBdXRob3JzLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogVGhpcyBjb2RlIG1heSBvbmx5IGJlIHVzZWQgdW5kZXIgdGhlIEJTRCBzdHlsZSBsaWNlbnNlIGZvdW5kIGF0IGh0dHA6Ly9wb2x5bWVyLmdpdGh1Yi5pby9MSUNFTlNFLnR4dFxuICogVGhlIGNvbXBsZXRlIHNldCBvZiBhdXRob3JzIG1heSBiZSBmb3VuZCBhdCBodHRwOi8vcG9seW1lci5naXRodWIuaW8vQVVUSE9SUy50eHRcbiAqIFRoZSBjb21wbGV0ZSBzZXQgb2YgY29udHJpYnV0b3JzIG1heSBiZSBmb3VuZCBhdCBodHRwOi8vcG9seW1lci5naXRodWIuaW8vQ09OVFJJQlVUT1JTLnR4dFxuICogQ29kZSBkaXN0cmlidXRlZCBieSBHb29nbGUgYXMgcGFydCBvZiB0aGUgcG9seW1lciBwcm9qZWN0IGlzIGFsc29cbiAqIHN1YmplY3QgdG8gYW4gYWRkaXRpb25hbCBJUCByaWdodHMgZ3JhbnQgZm91bmQgYXQgaHR0cDovL3BvbHltZXIuZ2l0aHViLmlvL1BBVEVOVFMudHh0XG4gKi9cbi8vIGpzaGludCBub2RlOiB0cnVlXG4ndXNlIHN0cmljdCc7XG4vLyBqc2hpbnQgLVcwNzlcbnZhciBQcm9taXNlID0gZ2xvYmFsLlByb21pc2UgfHwgcmVxdWlyZSgnZXM2LXByb21pc2UnKS5Qcm9taXNlO1xuLy8ganNoaW50ICtXMDc5XG5cbnZhciBkb201ID0gcmVxdWlyZSgnZG9tNScpO1xudmFyIHVybCA9IHJlcXVpcmUoJ3VybCcpO1xuXG52YXIgZG9jcyA9IHJlcXVpcmUoJy4vYXN0LXV0aWxzL2RvY3MnKTtcbnZhciBGaWxlTG9hZGVyID0gcmVxdWlyZSgnLi9sb2FkZXIvZmlsZS1sb2FkZXInKTtcbnZhciBpbXBvcnRQYXJzZSA9IHJlcXVpcmUoJy4vYXN0LXV0aWxzL2ltcG9ydC1wYXJzZScpO1xudmFyIGpzUGFyc2UgPSByZXF1aXJlKCcuL2FzdC11dGlscy9qcy1wYXJzZScpO1xudmFyIE5vb3BSZXNvbHZlciA9IHJlcXVpcmUoJy4vbG9hZGVyL25vb3AtcmVzb2x2ZXInKTtcbnZhciBTdHJpbmdSZXNvbHZlciA9IHJlcXVpcmUoJy4vbG9hZGVyL3N0cmluZy1yZXNvbHZlcicpO1xuXG5mdW5jdGlvbiByZWR1Y2VNZXRhZGF0YShtMSwgbTIpIHtcbiAgcmV0dXJuIHtcbiAgICBlbGVtZW50czogIG0xLmVsZW1lbnRzLmNvbmNhdChtMi5lbGVtZW50cyksXG4gICAgZmVhdHVyZXM6ICBtMS5mZWF0dXJlcy5jb25jYXQobTIuZmVhdHVyZXMpLFxuICAgIGJlaGF2aW9yczogbTEuYmVoYXZpb3JzLmNvbmNhdChtMi5iZWhhdmlvcnMpLFxuICB9O1xufVxuXG52YXIgRU1QVFlfTUVUQURBVEEgPSB7ZWxlbWVudHM6IFtdLCBmZWF0dXJlczogW10sIGJlaGF2aW9yczogW119O1xuXG4vKipcbiAqIFBhcnNlNSdzIHJlcHJlc2VudGF0aW9uIG9mIGEgcGFyc2VkIGh0bWwgZG9jdW1lbnRcbiAqIEB0eXBlZGVmIHtPYmplY3R9IERvY3VtZW50QVNUXG4gKiBAbWVtYmVyb2YgaHlkcm9seXNpc1xuICovXG5cbi8qKlxuICogZXNwcmVlJ3MgcmVwcmVzZW50YXRpb24gb2YgYSBwYXJzZWQgaHRtbCBkb2N1bWVudFxuICogQHR5cGVkZWYge09iamVjdH0gSlNBU1RcbiAqIEBtZW1iZXJvZiBoeWRyb2x5c2lzXG4gKi9cblxuLyoqXG4gKiBQYWNrYWdlIG9mIGEgcGFyc2VkIEpTIHNjcmlwdFxuICogQHR5cGVkZWYge09iamVjdH0gUGFyc2VkSlNcbiAqIEBwcm9wZXJ0eSB7SlNBU1R9IGFzdCBUaGUgc2NyaXB0J3MgQVNUXG4gKiBAcHJvcGVydHkge0RvY3VtZW50QVNUfSBzY3JpcHRFbGVtZW50IElmIGlubGluZSwgdGhlIHNjcmlwdCdzIGNvbnRhaW5pbmcgdGFnLlxuICogQG1lbWJlcm9mIGh5ZHJvbHlzaXNcbiAqL1xuXG4vKipcbiAqIFRoZSBtZXRhZGF0YSBmb3IgYSBzaW5nbGUgcG9seW1lciBlbGVtZW50XG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBFbGVtZW50RGVzY3JpcHRvclxuICogQG1lbWJlcm9mIGh5ZHJvbHlzaXNcbiAqL1xuXG4vKipcbiAqIFRoZSBtZXRhZGF0YSBmb3IgYSBQb2x5bWVyIGZlYXR1cmUuXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBGZWF0dXJlRGVzY3JpcHRvclxuICogQG1lbWJlcm9mIGh5ZHJvbHlzaXNcbiAqL1xuXG4vKipcbiAqIFRoZSBtZXRhZGF0YSBmb3IgYSBQb2x5bWVyIGJlaGF2aW9yIG1peGluLlxuICogQHR5cGVkZWYge09iamVjdH0gQmVoYXZpb3JEZXNjcmlwdG9yXG4gKiBAbWVtYmVyb2YgaHlkcm9seXNpc1xuICovXG5cbi8qKlxuICogVGhlIG1ldGFkYXRhIGZvciBhbGwgZmVhdHVyZXMgYW5kIGVsZW1lbnRzIGRlZmluZWQgaW4gb25lIGRvY3VtZW50XG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBEb2N1bWVudERlc2NyaXB0b3JcbiAqIEBtZW1iZXJvZiBoeWRyb2x5c2lzXG4gKiBAcHJvcGVydHkge0FycmF5PEVsZW1lbnREZXNjcmlwdG9yPn0gZWxlbWVudHMgVGhlIGVsZW1lbnRzIGZyb20gdGhlIGRvY3VtZW50XG4gKiBAcHJvcGVydHkge0FycmF5PEZlYXR1cmVEZXNjcmlwdG9yPn0gIGZlYXR1cmVzIFRoZSBmZWF0dXJlcyBmcm9tIHRoZSBkb2N1bWVudFxuICogQHByb3BlcnR5IHtBcnJheTxGZWF0dXJlRGVzY3JpcHRvcj59ICBiZWhhdmlvcnMgVGhlIGJlaGF2aW9ycyBmcm9tIHRoZSBkb2N1bWVudFxuICovXG5cbi8qKlxuICogVGhlIG1ldGFkYXRhIG9mIGFuIGVudGlyZSBIVE1MIGRvY3VtZW50LCBpbiBwcm9taXNlcy5cbiAqIEB0eXBlZGVmIHtPYmplY3R9IEFuYWx5emVkRG9jdW1lbnRcbiAqIEBtZW1iZXJvZiBoeWRyb2x5c2lzXG4gKiBAcHJvcGVydHkge3N0cmluZ30gaHJlZiBUaGUgdXJsIG9mIHRoZSBkb2N1bWVudC5cbiAqIEBwcm9wZXJ0eSB7UHJvbWlzZTxQYXJzZWRJbXBvcnQ+fSAgaHRtbExvYWRlZCBUaGUgcGFyc2VkIHJlcHJlc2VudGF0aW9uIG9mXG4gKiAgICAgdGhlIGRvYy4gVXNlIHRoZSBgYXN0YCBwcm9wZXJ0eSB0byBnZXQgdGhlIGZ1bGwgYHBhcnNlNWAgYXN0XG4gKlxuICogQHByb3BlcnR5IHtQcm9taXNlPEFycmF5PHN0cmluZz4+fSBkZXBzTG9hZGVkIFJlc29sdmVzIHRvIHRoZSBsaXN0IG9mIHRoaXNcbiAqICAgICBEb2N1bWVudCdzIHRyYW5zaXRpdmUgaW1wb3J0IGRlcGVuZGVuY2llc1xuICpcbiAqIEBwcm9wZXJ0eSB7QXJyYXk8c3RyaW5nPn0gZGVwSHJlZnMgVGhlIGRpcmVjdCBkZXBlbmRlbmNpZXMgb2YgdGhlIGRvY3VtZW50LlxuICpcbiAqIEBwcm9wZXJ0eSB7UHJvbWlzZTxEb2N1bWVudERlc2NyaXB0b3I+fSBtZXRhZGF0YUxvYWRlZCBSZXNvbHZlcyB0byB0aGUgbGlzdCBvZlxuICogICAgIHRoaXMgRG9jdW1lbnQncyBpbXBvcnQgZGVwZW5kZW5jaWVzXG4gKi9cblxuLyoqXG4gKiBBIGRhdGFiYXNlIG9mIFBvbHltZXIgbWV0YWRhdGEgZGVmaW5lZCBpbiBIVE1MXG4gKlxuICogQGNvbnN0cnVjdG9yXG4gKiBAbWVtYmVyT2YgaHlkcm9seXNpc1xuICogQHBhcmFtICB7Ym9vbGVhbn0gYXR0YWNoQVNUICBJZiB0cnVlLCBhdHRhY2ggYSBwYXJzZTUgY29tcGxpYW50IEFTVFxuICogQHBhcmFtICB7RmlsZUxvYWRlcj19IGxvYWRlciBBbiBvcHRpb25hbCBgRmlsZUxvYWRlcmAgdXNlZCB0byBsb2FkIGV4dGVybmFsXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc291cmNlc1xuICovXG52YXIgQW5hbHl6ZXIgPSBmdW5jdGlvbiBBbmFseXplcihhdHRhY2hBU1QsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2FkZXIpIHtcbiAgdGhpcy5sb2FkZXIgPSBsb2FkZXI7XG5cbiAgLyoqXG4gICAqIEEgbGlzdCBvZiBhbGwgZWxlbWVudHMgdGhlIGBBbmFseXplcmAgaGFzIG1ldGFkYXRhIGZvci5cbiAgICogQG1lbWJlciB7QXJyYXkuPEVsZW1lbnREZXNjcmlwdG9yPn1cbiAgICovXG4gIHRoaXMuZWxlbWVudHMgPSBbXTtcblxuICAvKipcbiAgICogQSB2aWV3IGludG8gYGVsZW1lbnRzYCwga2V5ZWQgYnkgdGFnIG5hbWUuXG4gICAqIEBtZW1iZXIge09iamVjdC48c3RyaW5nLEVsZW1lbnREZXNjcmlwdG9yPn1cbiAgICovXG4gIHRoaXMuZWxlbWVudHNCeVRhZ05hbWUgPSB7fTtcblxuICAvKipcbiAgICogQSBsaXN0IG9mIEFQSSBmZWF0dXJlcyBhZGRlZCB0byBgUG9seW1lci5CYXNlYCBlbmNvdW50ZXJlZCBieSB0aGVcbiAgICogYW5hbHl6ZXIuXG4gICAqIEBtZW1iZXIge0FycmF5PEZlYXR1cmVEZXNjcmlwdG9yPn1cbiAgICovXG4gIHRoaXMuZmVhdHVyZXMgPSBbXTtcblxuICAvKipcbiAgICogVGhlIGJlaGF2aW9ycyBjb2xsZWN0ZWQgYnkgdGhlIGFuYWx5c2lzIHBhc3MuXG4gICAqXG4gICAqIEBtZW1iZXIge0FycmF5PEJlaGF2aW9yRGVzY3JpcHRvcj59XG4gICAqL1xuICB0aGlzLmJlaGF2aW9ycyA9IFtdO1xuXG4gIC8qKlxuICAgKiBUaGUgYmVoYXZpb3JzIGNvbGxlY3RlZCBieSB0aGUgYW5hbHlzaXMgcGFzcyBieSBuYW1lLlxuICAgKlxuICAgKiBAbWVtYmVyIHtPYmplY3Q8c3RyaW5nLEJlaGF2aW9yRGVzY3JpcHRvcj59XG4gICAqL1xuICB0aGlzLmJlaGF2aW9yc0J5TmFtZSA9IHt9O1xuXG4gIC8qKlxuICAgKiBBIG1hcCwga2V5ZWQgYnkgYWJzb2x1dGUgcGF0aCwgb2YgRG9jdW1lbnQgbWV0YWRhdGEuXG4gICAqIEBtZW1iZXIge09iamVjdDxzdHJpbmcsQW5hbHl6ZWREb2N1bWVudD59XG4gICAqL1xuICB0aGlzLmh0bWwgPSB7fTtcblxuICAvKipcbiAgICogQSBtYXAsIGtleWVkIGJ5IHBhdGgsIG9mIEhUTUwgZG9jdW1lbnQgQVNUcy5cbiAgICogQHR5cGUge09iamVjdH1cbiAgICovXG4gIHRoaXMucGFyc2VkRG9jdW1lbnRzID0ge307XG5cbiAgLyoqXG4gICAqIEEgbWFwLCBrZXllZCBieSBwYXRoLCBvZiBKUyBzY3JpcHQgQVNUcy5cbiAgICpcbiAgICogSWYgdGhlIHBhdGggaXMgYW4gSFRNTCBmaWxlIHdpdGggbXVsdGlwbGUgc2NyaXB0cywgdGhlIGVudHJ5IHdpbGwgYmUgYW4gYXJyYXkgb2Ygc2NyaXB0cy5cbiAgICpcbiAgICogQHR5cGUge09iamVjdDxzdHJpbmcsQXJyYXk8UGFyc2VkSlM+Pn1cbiAgICovXG4gIHRoaXMucGFyc2VkU2NyaXB0cyA9IHt9O1xuXG5cblxuICAvKipcbiAgICogQSBtYXAsIGtleWVkIGJ5IHBhdGgsIG9mIGRvY3VtZW50IGNvbnRlbnQuXG4gICAqIEB0eXBlIHtPYmplY3R9XG4gICAqL1xuICB0aGlzLl9jb250ZW50ID0ge307XG59O1xuXG4vKipcbiAqIE9wdGlvbnMgZm9yIGBBbmFseXplci5hbmFsenllYFxuICogQHR5cGVkZWYge09iamVjdH0gTG9hZE9wdGlvbnNcbiAqIEBtZW1iZXJvZiBoeWRyb2x5c2lzXG4gKiBAcHJvcGVydHkge2Jvb2xlYW59IG5vQW5ub3RhdGlvbnMgV2hldGhlciBgYW5ub3RhdGUoKWAgc2hvdWxkIGJlIHNraXBwZWQuXG4gKiBAcHJvcGVydHkge1N0cmluZz19IGNvbnRlbnQgQ29udGVudCB0byByZXNvbHZlIGBocmVmYCB0byBpbnN0ZWFkIG9mIGxvYWRpbmdcbiAqICAgICBmcm9tIHRoZSBmaWxlIHN5c3RlbS5cbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gY2xlYW4gV2hldGhlciB0aGUgZ2VuZXJhdGVkIGRlc2NyaXB0b3JzIHNob3VsZCBiZSBjbGVhbmVkXG4gKiAgICAgb2YgcmVkdW5kYW50IGRhdGEuXG4gKiBAcHJvcGVydHkge3N0cmluZz19IHJlc29sdmVyLlxuICogICAgIGB4aHJgIHRvIHVzZSBYTUxIdHRwUmVxdWVzdFxuICogICAgIGBmc2AgdG8gdXNlIHRoZSBsb2NhbCBmaWxlc3lzdGVtLlxuICogICAgIGBwZXJtaXNzaXZlYCB0byB1c2UgdGhlIGxvY2FsIGZpbGVzeXN0ZW0gYW5kIHJldHVybiBlbXB0eSBmaWxlcyB3aGVuIGFcbiAqICAgICBwYXRoIGNhbid0IGJlIGZvdW5kLlxuICogICAgIERlZmF1bHQgaXMgYGZzYCBpbiBub2RlIGFuZCBgeGhyYCBpbiB0aGUgYnJvd3Nlci5cbiAqIEBwcm9wZXJ0eSB7ZnVuY3Rpb24oc3RyaW5nKTogYm9vbGVhbn0gZmlsdGVyIEEgcHJlZGljYXRlIGZ1bmN0aW9uIHRoYXRcbiAqICAgICBpbmRpY2F0ZXMgd2hpY2ggZmlsZXMgc2hvdWxkIGJlIGlnbm9yZWQgYnkgdGhlIGxvYWRlci4gQnkgZGVmYXVsdCBhbGxcbiAqICAgICBmaWxlcyBub3QgbG9jYXRlZCB1bmRlciB0aGUgZGlybmFtZSBvZiBgaHJlZmAgd2lsbCBiZSBpZ25vcmVkLlxuICovXG5cbi8qKlxuICogU2hvcnRoYW5kIGZvciB0cmFuc2l0aXZlbHkgbG9hZGluZyBhbmQgcHJvY2Vzc2luZyBhbGwgaW1wb3J0cyBiZWdpbm5pbmcgYXRcbiAqIGBocmVmYC5cbiAqXG4gKiBJbiBvcmRlciB0byBwcm9wZXJseSBmaWx0ZXIgcGF0aHMsIGBocmVmYCBfbXVzdF8gYmUgYW4gYWJzb2x1dGUgVVJJLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBocmVmIFRoZSByb290IGltcG9ydCB0byBiZWdpbiBsb2FkaW5nIGZyb20uXG4gKiBAcGFyYW0ge0xvYWRPcHRpb25zPX0gb3B0aW9ucyBBbnkgYWRkaXRpb25hbCBvcHRpb25zIGZvciB0aGUgbG9hZC5cbiAqIEByZXR1cm4ge1Byb21pc2U8QW5hbHl6ZXI+fSBBIHByb21pc2UgdGhhdCB3aWxsIHJlc29sdmUgb25jZSBgaHJlZmAgYW5kIGl0c1xuICogICAgIGRlcGVuZGVuY2llcyBoYXZlIGJlZW4gbG9hZGVkIGFuZCBhbmFseXplZC5cbiAqL1xuQW5hbHl6ZXIuYW5hbHl6ZSA9IGZ1bmN0aW9uIGFuYWx5emUoaHJlZiwgb3B0aW9ucykge1xuICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgb3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmZpbHRlciB8fCBfZGVmYXVsdEZpbHRlcihocmVmKTtcblxuICB2YXIgbG9hZGVyID0gbmV3IEZpbGVMb2FkZXIoKTtcblxuICB2YXIgcmVzb2x2ZXIgPSBvcHRpb25zLnJlc29sdmVyO1xuICBpZiAocmVzb2x2ZXIgPT09IHVuZGVmaW5lZCkge1xuICAgIGlmICh0eXBlb2Ygd2luZG93ID09PSAndW5kZWZpbmVkJykge1xuICAgICAgcmVzb2x2ZXIgPSAnZnMnO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXNvbHZlciA9ICd4aHInO1xuICAgIH1cbiAgfVxuICB2YXIgUHJpbWFyeVJlc29sdmVyO1xuICBpZiAocmVzb2x2ZXIgPT09ICdmcycpIHtcbiAgICBQcmltYXJ5UmVzb2x2ZXIgPSByZXF1aXJlKCcuL2xvYWRlci9mcy1yZXNvbHZlcicpO1xuICB9IGVsc2UgaWYgKHJlc29sdmVyID09PSAneGhyJykge1xuICAgIFByaW1hcnlSZXNvbHZlciA9IHJlcXVpcmUoJy4vbG9hZGVyL3hoci1yZXNvbHZlcicpO1xuICB9IGVsc2UgaWYgKHJlc29sdmVyID09PSAncGVybWlzc2l2ZScpIHtcbiAgICBQcmltYXJ5UmVzb2x2ZXIgPSByZXF1aXJlKCcuL2xvYWRlci9lcnJvci1zd2FsbG93aW5nLWZzLXJlc29sdmVyJyk7XG4gIH0gZWxzZSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFwiUmVzb2x2ZXIgbXVzdCBiZSBvbmUgb2YgJ2ZzJyBvciAneGhyJ1wiKTtcbiAgfVxuXG4gIGxvYWRlci5hZGRSZXNvbHZlcihuZXcgUHJpbWFyeVJlc29sdmVyKG9wdGlvbnMpKTtcbiAgaWYgKG9wdGlvbnMuY29udGVudCkge1xuICAgIGxvYWRlci5hZGRSZXNvbHZlcihuZXcgU3RyaW5nUmVzb2x2ZXIoe3VybDogaHJlZiwgY29udGVudDogb3B0aW9ucy5jb250ZW50fSkpO1xuICB9XG4gIGxvYWRlci5hZGRSZXNvbHZlcihuZXcgTm9vcFJlc29sdmVyKHt0ZXN0OiBvcHRpb25zLmZpbHRlcn0pKTtcblxuICB2YXIgYW5hbHl6ZXIgPSBuZXcgdGhpcyhudWxsLCBsb2FkZXIpO1xuICByZXR1cm4gYW5hbHl6ZXIubWV0YWRhdGFUcmVlKGhyZWYpLnRoZW4oZnVuY3Rpb24ocm9vdCkge1xuICAgIGlmICghb3B0aW9ucy5ub0Fubm90YXRpb25zKSB7XG4gICAgICBhbmFseXplci5hbm5vdGF0ZSgpO1xuICAgIH1cbiAgICBpZiAob3B0aW9ucy5jbGVhbikge1xuICAgICAgYW5hbHl6ZXIuY2xlYW4oKTtcbiAgICB9XG4gICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShhbmFseXplcik7XG4gIH0pO1xufTtcblxuLyoqXG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtIHtzdHJpbmd9IGhyZWZcbiAqIEByZXR1cm4ge2Z1bmN0aW9uKHN0cmluZyk6IGJvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIF9kZWZhdWx0RmlsdGVyKGhyZWYpIHtcbiAgLy8gRXZlcnl0aGluZyB1cCB0byB0aGUgbGFzdCBgL2Agb3IgYFxcYC5cbiAgdmFyIGJhc2UgPSBocmVmLm1hdGNoKC9eKC4qPylbXlxcL1xcXFxdKiQvKVsxXTtcbiAgcmV0dXJuIGZ1bmN0aW9uKHVyaSkge1xuICAgIHJldHVybiB1cmkuaW5kZXhPZihiYXNlKSAhPT0gMDtcbiAgfTtcbn1cblxuQW5hbHl6ZXIucHJvdG90eXBlLmxvYWQgPSBmdW5jdGlvbiBsb2FkKGhyZWYpIHtcbiAgcmV0dXJuIHRoaXMubG9hZGVyLnJlcXVlc3QoaHJlZikudGhlbihmdW5jdGlvbihjb250ZW50KSB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgdGhpcy5fY29udGVudFtocmVmXSA9IGNvbnRlbnQ7XG4gICAgICAgIHJlc29sdmUodGhpcy5fcGFyc2VIVE1MKGNvbnRlbnQsIGhyZWYpKTtcbiAgICAgIH0uYmluZCh0aGlzKSwgMCk7XG4gICAgfS5iaW5kKHRoaXMpKS5jYXRjaChmdW5jdGlvbihlcnIpe1xuICAgICAgY29uc29sZS5lcnJvcihcIkVycm9yIHByb2Nlc3NpbmcgZG9jdW1lbnQgYXQgXCIgKyBocmVmKTtcbiAgICAgIHRocm93IGVycjtcbiAgICB9KTtcbiAgfS5iaW5kKHRoaXMpKTtcbn07XG5cbi8qKlxuICogUmV0dXJucyBhbiBgQW5hbHl6ZWREb2N1bWVudGAgcmVwcmVzZW50aW5nIHRoZSBwcm92aWRlZCBkb2N1bWVudFxuICogQHByaXZhdGVcbiAqIEBwYXJhbSAge3N0cmluZ30gaHRtbEltcG9ydCBSYXcgdGV4dCBvZiBhbiBIVE1MIGRvY3VtZW50XG4gKiBAcGFyYW0gIHtzdHJpbmd9IGhyZWYgICAgICAgVGhlIGRvY3VtZW50J3MgVVJMLlxuICogQHJldHVybiB7QW5hbHl6ZWREb2N1bWVudH0gICAgICAgQW4gIGBBbmFseXplZERvY3VtZW50YFxuICovXG5BbmFseXplci5wcm90b3R5cGUuX3BhcnNlSFRNTCA9IGZ1bmN0aW9uIF9wYXJzZUhUTUwoaHRtbEltcG9ydCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaHJlZikge1xuICBpZiAoaHJlZiBpbiB0aGlzLmh0bWwpIHtcbiAgICByZXR1cm4gdGhpcy5odG1sW2hyZWZdO1xuICB9XG4gIHZhciBkZXBzTG9hZGVkID0gW107XG4gIHZhciBkZXBIcmVmcyA9IFtdO1xuICB2YXIgbWV0YWRhdGFMb2FkZWQgPSBQcm9taXNlLnJlc29sdmUoRU1QVFlfTUVUQURBVEEpO1xuICB2YXIgcGFyc2VkO1xuICB0cnkge1xuICAgIHBhcnNlZCA9IGltcG9ydFBhcnNlKGh0bWxJbXBvcnQsIGhyZWYpO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBjb25zb2xlLmVycm9yKCdFcnJvciBwYXJzaW5nIScpO1xuICAgIHRocm93IGVycjtcbiAgfVxuICB2YXIgaHRtbExvYWRlZCA9IFByb21pc2UucmVzb2x2ZShwYXJzZWQpO1xuICBpZiAocGFyc2VkLnNjcmlwdCkge1xuICAgIG1ldGFkYXRhTG9hZGVkID0gdGhpcy5fcHJvY2Vzc1NjcmlwdHMocGFyc2VkLnNjcmlwdCwgaHJlZik7XG4gIH1cbiAgdmFyIGNvbW1lbnRUZXh0ID0gcGFyc2VkLmNvbW1lbnQubWFwKGZ1bmN0aW9uKGNvbW1lbnQpe1xuICAgIHJldHVybiBkb201LmdldFRleHRDb250ZW50KGNvbW1lbnQpO1xuICB9KTtcbiAgdmFyIHBzZXVkb0VsZW1lbnRzID0gZG9jcy5wYXJzZVBzZXVkb0VsZW1lbnRzKGNvbW1lbnRUZXh0KTtcbiAgcHNldWRvRWxlbWVudHMuZm9yRWFjaChmdW5jdGlvbihlbGVtZW50KXtcbiAgICBlbGVtZW50LmNvbnRlbnRIcmVmID0gaHJlZjtcbiAgICB0aGlzLmVsZW1lbnRzLnB1c2goZWxlbWVudCk7XG4gICAgdGhpcy5lbGVtZW50c0J5VGFnTmFtZVtlbGVtZW50LmlzXSA9IGVsZW1lbnQ7XG4gIH0uYmluZCh0aGlzKSk7XG4gIG1ldGFkYXRhTG9hZGVkID0gbWV0YWRhdGFMb2FkZWQudGhlbihmdW5jdGlvbihtZXRhZGF0YSl7XG4gICAgdmFyIG1ldGFkYXRhRW50cnkgPSB7XG4gICAgICBlbGVtZW50czogcHNldWRvRWxlbWVudHMsXG4gICAgICBmZWF0dXJlczogW10sXG4gICAgICBiZWhhdmlvcnM6IFtdXG4gICAgfTtcbiAgICByZXR1cm4gW21ldGFkYXRhLCBtZXRhZGF0YUVudHJ5XS5yZWR1Y2UocmVkdWNlTWV0YWRhdGEpO1xuICB9KTtcbiAgZGVwc0xvYWRlZC5wdXNoKG1ldGFkYXRhTG9hZGVkKTtcblxuXG4gIGlmICh0aGlzLmxvYWRlcikge1xuICAgIHZhciBiYXNlVXJpID0gaHJlZjtcbiAgICBpZiAocGFyc2VkLmJhc2UubGVuZ3RoID4gMSkge1xuICAgICAgY29uc29sZS5lcnJvcihcIk9ubHkgb25lIGJhc2UgdGFnIHBlciBkb2N1bWVudCFcIik7XG4gICAgICB0aHJvdyBcIk11bHRpcGxlIGJhc2UgdGFncyBpbiBcIiArIGhyZWY7XG4gICAgfSBlbHNlIGlmIChwYXJzZWQuYmFzZS5sZW5ndGggPT0gMSkge1xuICAgICAgdmFyIGJhc2VIcmVmID0gZG9tNS5nZXRBdHRyaWJ1dGUocGFyc2VkLmJhc2VbMF0sIFwiaHJlZlwiKTtcbiAgICAgIGlmIChiYXNlSHJlZikge1xuICAgICAgICBiYXNlSHJlZiA9IGJhc2VIcmVmICsgXCIvXCI7XG4gICAgICAgIGJhc2VVcmkgPSB1cmwucmVzb2x2ZShiYXNlVXJpLCBiYXNlSHJlZik7XG4gICAgICB9XG4gICAgfVxuICAgIHBhcnNlZC5pbXBvcnQuZm9yRWFjaChmdW5jdGlvbihsaW5rKSB7XG4gICAgICB2YXIgbGlua3VybCA9IGRvbTUuZ2V0QXR0cmlidXRlKGxpbmssICdocmVmJyk7XG4gICAgICBpZiAobGlua3VybCkge1xuICAgICAgICB2YXIgcmVzb2x2ZWRVcmwgPSB1cmwucmVzb2x2ZShiYXNlVXJpLCBsaW5rdXJsKTtcbiAgICAgICAgZGVwSHJlZnMucHVzaChyZXNvbHZlZFVybCk7XG4gICAgICAgIGRlcHNMb2FkZWQucHVzaCh0aGlzLl9kZXBlbmRlbmNpZXNMb2FkZWRGb3IocmVzb2x2ZWRVcmwsIGhyZWYpKTtcbiAgICAgIH1cbiAgICB9LmJpbmQodGhpcykpO1xuICAgIHBhcnNlZC5zdHlsZS5mb3JFYWNoKGZ1bmN0aW9uKHN0eWxlRWxlbWVudCkge1xuICAgICAgaWYgKHBvbHltZXJFeHRlcm5hbFN0eWxlKHN0eWxlRWxlbWVudCkpIHtcbiAgICAgICAgdmFyIHN0eWxlSHJlZiA9IGRvbTUuZ2V0QXR0cmlidXRlKHN0eWxlRWxlbWVudCwgJ2hyZWYnKTtcbiAgICAgICAgaWYgKGhyZWYpIHtcbiAgICAgICAgICBzdHlsZUhyZWYgPSB1cmwucmVzb2x2ZShiYXNlVXJpLCBzdHlsZUhyZWYpO1xuICAgICAgICAgIGRlcHNMb2FkZWQucHVzaCh0aGlzLmxvYWRlci5yZXF1ZXN0KHN0eWxlSHJlZikudGhlbihmdW5jdGlvbihjb250ZW50KXtcbiAgICAgICAgICAgIHRoaXMuX2NvbnRlbnRbc3R5bGVIcmVmXSA9IGNvbnRlbnQ7XG4gICAgICAgICAgfS5iaW5kKHRoaXMpKSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LmJpbmQodGhpcykpO1xuICB9XG4gIGRlcHNMb2FkZWQgPSBQcm9taXNlLmFsbChkZXBzTG9hZGVkKVxuICAgICAgICAudGhlbihmdW5jdGlvbigpIHtyZXR1cm4gZGVwSHJlZnM7fSlcbiAgICAgICAgLmNhdGNoKGZ1bmN0aW9uKGVycikge3Rocm93IGVycjt9KTtcbiAgdGhpcy5wYXJzZWREb2N1bWVudHNbaHJlZl0gPSBwYXJzZWQuYXN0O1xuICB0aGlzLmh0bWxbaHJlZl0gPSB7XG4gICAgICBocmVmOiBocmVmLFxuICAgICAgaHRtbExvYWRlZDogaHRtbExvYWRlZCxcbiAgICAgIG1ldGFkYXRhTG9hZGVkOiBtZXRhZGF0YUxvYWRlZCxcbiAgICAgIGRlcEhyZWZzOiBkZXBIcmVmcyxcbiAgICAgIGRlcHNMb2FkZWQ6IGRlcHNMb2FkZWRcbiAgfTtcbiAgcmV0dXJuIHRoaXMuaHRtbFtocmVmXTtcbn07XG5cbkFuYWx5emVyLnByb3RvdHlwZS5fcHJvY2Vzc1NjcmlwdHMgPSBmdW5jdGlvbiBfcHJvY2Vzc1NjcmlwdHMoc2NyaXB0cywgaHJlZikge1xuICB2YXIgc2NyaXB0UHJvbWlzZXMgPSBbXTtcbiAgc2NyaXB0cy5mb3JFYWNoKGZ1bmN0aW9uKHNjcmlwdCkge1xuICAgIHNjcmlwdFByb21pc2VzLnB1c2godGhpcy5fcHJvY2Vzc1NjcmlwdChzY3JpcHQsIGhyZWYpKTtcbiAgfS5iaW5kKHRoaXMpKTtcbiAgcmV0dXJuIFByb21pc2UuYWxsKHNjcmlwdFByb21pc2VzKS50aGVuKGZ1bmN0aW9uKG1ldGFkYXRhTGlzdCkge1xuICAgIHJldHVybiBtZXRhZGF0YUxpc3QucmVkdWNlKHJlZHVjZU1ldGFkYXRhLCBFTVBUWV9NRVRBREFUQSk7XG4gIH0pO1xufTtcblxuQW5hbHl6ZXIucHJvdG90eXBlLl9wcm9jZXNzU2NyaXB0ID0gZnVuY3Rpb24gX3Byb2Nlc3NTY3JpcHQoc2NyaXB0LCBocmVmKSB7XG4gIHZhciBzcmMgPSBkb201LmdldEF0dHJpYnV0ZShzY3JpcHQsICdzcmMnKTtcbiAgdmFyIHBhcnNlZEpzO1xuICBpZiAoIXNyYykge1xuICAgIHRyeSB7XG4gICAgICBwYXJzZWRKcyA9IGpzUGFyc2UoKHNjcmlwdC5jaGlsZE5vZGVzLmxlbmd0aCkgPyBzY3JpcHQuY2hpbGROb2Rlc1swXS52YWx1ZSA6ICcnKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIC8vIEZpZ3VyZSBvdXQgdGhlIGNvcnJlY3QgbGluZSBudW1iZXIgZm9yIHRoZSBlcnJvci5cbiAgICAgIHZhciBsaW5lID0gMDtcbiAgICAgIHZhciBjb2wgPSAwO1xuICAgICAgaWYgKHNjcmlwdC5fX293bmVyRG9jdW1lbnQgJiYgc2NyaXB0Ll9fb3duZXJEb2N1bWVudCA9PSBocmVmKSB7XG4gICAgICAgIGxpbmUgPSBzY3JpcHQuX19sb2NhdGlvbkRldGFpbC5saW5lIC0gMTtcbiAgICAgICAgY29sID0gc2NyaXB0Ll9fbG9jYXRpb25EZXRhaWwuY29sdW1uIC0gMTtcbiAgICAgIH1cbiAgICAgIGxpbmUgKz0gZXJyLmxpbmVOdW1iZXI7XG4gICAgICBjb2wgKz0gZXJyLmNvbHVtbjtcbiAgICAgIHZhciBtZXNzYWdlID0gXCJFcnJvciBwYXJzaW5nIHNjcmlwdCBpbiBcIiArIGhyZWYgKyBcIiBhdCBcIiArIGxpbmUgKyBcIjpcIiArIGNvbDtcbiAgICAgIG1lc3NhZ2UgKz0gXCJcXG5cIiArIGVyci5zdGFjaztcbiAgICAgIHZhciBmaXhlZEVyciA9IG5ldyBFcnJvcihtZXNzYWdlKTtcbiAgICAgIGZpeGVkRXJyLmxvY2F0aW9uID0ge2xpbmU6IGxpbmUsIGNvbHVtbjogY29sfTtcbiAgICAgIGZpeGVkRXJyLm93bmVyRG9jdW1lbnQgPSBzY3JpcHQuX19vd25lckRvY3VtZW50O1xuICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KGZpeGVkRXJyKTtcbiAgICB9XG4gICAgaWYgKHBhcnNlZEpzLmVsZW1lbnRzKSB7XG4gICAgICBwYXJzZWRKcy5lbGVtZW50cy5mb3JFYWNoKGZ1bmN0aW9uKGVsZW1lbnQpIHtcbiAgICAgICAgZWxlbWVudC5zY3JpcHRFbGVtZW50ID0gc2NyaXB0O1xuICAgICAgICBlbGVtZW50LmNvbnRlbnRIcmVmID0gaHJlZjtcbiAgICAgICAgdGhpcy5lbGVtZW50cy5wdXNoKGVsZW1lbnQpO1xuICAgICAgICBpZiAoZWxlbWVudC5pcyBpbiB0aGlzLmVsZW1lbnRzQnlUYWdOYW1lKSB7XG4gICAgICAgICAgY29uc29sZS53YXJuKCdJZ25vcmluZyBkdXBsaWNhdGUgZWxlbWVudCBkZWZpbml0aW9uOiAnICsgZWxlbWVudC5pcyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5lbGVtZW50c0J5VGFnTmFtZVtlbGVtZW50LmlzXSA9IGVsZW1lbnQ7XG4gICAgICAgIH1cbiAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfVxuICAgIGlmIChwYXJzZWRKcy5mZWF0dXJlcykge1xuICAgICAgcGFyc2VkSnMuZmVhdHVyZXMuZm9yRWFjaChmdW5jdGlvbihmZWF0dXJlKXtcbiAgICAgICAgZmVhdHVyZS5jb250ZW50SHJlZiA9IGhyZWY7XG4gICAgICAgIGZlYXR1cmUuc2NyaXB0RWxlbWVudCA9IHNjcmlwdDtcbiAgICAgIH0pO1xuICAgICAgdGhpcy5mZWF0dXJlcyA9IHRoaXMuZmVhdHVyZXMuY29uY2F0KHBhcnNlZEpzLmZlYXR1cmVzKTtcbiAgICB9XG4gICAgaWYgKHBhcnNlZEpzLmJlaGF2aW9ycykge1xuICAgICAgcGFyc2VkSnMuYmVoYXZpb3JzLmZvckVhY2goZnVuY3Rpb24oYmVoYXZpb3Ipe1xuICAgICAgICBiZWhhdmlvci5jb250ZW50SHJlZiA9IGhyZWY7XG4gICAgICAgIHRoaXMuYmVoYXZpb3JzQnlOYW1lW2JlaGF2aW9yLmlzXSA9IGJlaGF2aW9yO1xuICAgICAgICB0aGlzLmJlaGF2aW9yc0J5TmFtZVtiZWhhdmlvci5zeW1ib2xdID0gYmVoYXZpb3I7XG4gICAgICB9LmJpbmQodGhpcykpO1xuICAgICAgdGhpcy5iZWhhdmlvcnMgPSB0aGlzLmJlaGF2aW9ycy5jb25jYXQocGFyc2VkSnMuYmVoYXZpb3JzKTtcbiAgICB9XG4gICAgaWYgKCFPYmplY3QuaGFzT3duUHJvcGVydHkuY2FsbCh0aGlzLnBhcnNlZFNjcmlwdHMsIGhyZWYpKSB7XG4gICAgICB0aGlzLnBhcnNlZFNjcmlwdHNbaHJlZl0gPSBbXTtcbiAgICB9XG4gICAgdmFyIHNjcmlwdEVsZW1lbnQ7XG4gICAgaWYgKHNjcmlwdC5fX293bmVyRG9jdW1lbnQgJiYgc2NyaXB0Ll9fb3duZXJEb2N1bWVudCA9PSBocmVmKSB7XG4gICAgICBzY3JpcHRFbGVtZW50ID0gc2NyaXB0O1xuICAgIH1cbiAgICB0aGlzLnBhcnNlZFNjcmlwdHNbaHJlZl0ucHVzaCh7XG4gICAgICBhc3Q6IHBhcnNlZEpzLnBhcnNlZFNjcmlwdCxcbiAgICAgIHNjcmlwdEVsZW1lbnQ6IHNjcmlwdEVsZW1lbnRcbiAgICB9KTtcbiAgICByZXR1cm4gcGFyc2VkSnM7XG4gIH1cbiAgaWYgKHRoaXMubG9hZGVyKSB7XG4gICAgdmFyIHJlc29sdmVkU3JjID0gdXJsLnJlc29sdmUoaHJlZiwgc3JjKTtcbiAgICByZXR1cm4gdGhpcy5sb2FkZXIucmVxdWVzdChyZXNvbHZlZFNyYykudGhlbihmdW5jdGlvbihjb250ZW50KSB7XG4gICAgICB0aGlzLl9jb250