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} elements The elements from the document * @property {Array} features The features from the document * @property {Array} 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} htmlLoaded The parsed representation of * the doc. Use the `ast` property to get the full `parse5` ast * * @property {Promise>} depsLoaded Resolves to the list of this * Document's transitive import dependencies * * @property {Array} depHrefs The direct dependencies of the document. * * @property {Promise} 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.} */ this.elements = []; /** * A view into `elements`, keyed by tag name. * @member {Object.} */ this.elementsByTagName = {}; /** * A list of API features added to `Polymer.Base` encountered by the * analyzer. * @member {Array} */ this.features = []; /** * The behaviors collected by the analysis pass. * * @member {Array} */ this.behaviors = []; /** * The behaviors collected by the analysis pass by name. * * @member {Object} */ this.behaviorsByName = {}; /** * A map, keyed by absolute path, of Document metadata. * @member {Object} */ 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>} */ 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 {boolean} clean Whether the generated descriptors should be cleaned * of redundant data. * @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} 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 PrimaryResolver = typeof window === 'undefined' ? require('./loader/fs-resolver') : require('./loader/xhr-resolver'); loader.addResolver(new PrimaryResolver(options)); 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.line - 1; } line += err.lineNumber; col += err.column; var message = "Error parsing script in " + href + " at " + line + ":" + col; message += "\n" + err.description; return Promise.reject(new Error(message)); } 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.=} found An object keyed by URL of the * already resolved dependencies. * @param {boolean=} transitive Whether to load transitive * dependencies. Defaults to true. * @return {Array.} 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; } Analyzer.prototype.elementsForFolder = function elementsForFolder(href) { return this.elements.filter(function(element){ return matchesDocumentFolder(element, href); }); }; 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.=} loaded An object keyed by already loaded documents. * @return {Promise.} */ 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,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImxpYi9hbmFseXplci5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTUgVGhlIFBvbHltZXIgUHJvamVjdCBBdXRob3JzLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogVGhpcyBjb2RlIG1heSBvbmx5IGJlIHVzZWQgdW5kZXIgdGhlIEJTRCBzdHlsZSBsaWNlbnNlIGZvdW5kIGF0IGh0dHA6Ly9wb2x5bWVyLmdpdGh1Yi5pby9MSUNFTlNFLnR4dFxuICogVGhlIGNvbXBsZXRlIHNldCBvZiBhdXRob3JzIG1heSBiZSBmb3VuZCBhdCBodHRwOi8vcG9seW1lci5naXRodWIuaW8vQVVUSE9SUy50eHRcbiAqIFRoZSBjb21wbGV0ZSBzZXQgb2YgY29udHJpYnV0b3JzIG1heSBiZSBmb3VuZCBhdCBodHRwOi8vcG9seW1lci5naXRodWIuaW8vQ09OVFJJQlVUT1JTLnR4dFxuICogQ29kZSBkaXN0cmlidXRlZCBieSBHb29nbGUgYXMgcGFydCBvZiB0aGUgcG9seW1lciBwcm9qZWN0IGlzIGFsc29cbiAqIHN1YmplY3QgdG8gYW4gYWRkaXRpb25hbCBJUCByaWdodHMgZ3JhbnQgZm91bmQgYXQgaHR0cDovL3BvbHltZXIuZ2l0aHViLmlvL1BBVEVOVFMudHh0XG4gKi9cbi8vIGpzaGludCBub2RlOiB0cnVlXG4ndXNlIHN0cmljdCc7XG4vLyBqc2hpbnQgLVcwNzlcbnZhciBQcm9taXNlID0gZ2xvYmFsLlByb21pc2UgfHwgcmVxdWlyZSgnZXM2LXByb21pc2UnKS5Qcm9taXNlO1xuLy8ganNoaW50ICtXMDc5XG5cbnZhciBkb201ID0gcmVxdWlyZSgnZG9tNScpO1xudmFyIHVybCA9IHJlcXVpcmUoJ3VybCcpO1xuXG52YXIgZG9jcyA9IHJlcXVpcmUoJy4vYXN0LXV0aWxzL2RvY3MnKTtcbnZhciBGaWxlTG9hZGVyID0gcmVxdWlyZSgnLi9sb2FkZXIvZmlsZS1sb2FkZXInKTtcbnZhciBpbXBvcnRQYXJzZSA9IHJlcXVpcmUoJy4vYXN0LXV0aWxzL2ltcG9ydC1wYXJzZScpO1xudmFyIGpzUGFyc2UgPSByZXF1aXJlKCcuL2FzdC11dGlscy9qcy1wYXJzZScpO1xudmFyIE5vb3BSZXNvbHZlciA9IHJlcXVpcmUoJy4vbG9hZGVyL25vb3AtcmVzb2x2ZXInKTtcblxuZnVuY3Rpb24gcmVkdWNlTWV0YWRhdGEobTEsIG0yKSB7XG4gIHJldHVybiB7XG4gICAgZWxlbWVudHM6ICBtMS5lbGVtZW50cy5jb25jYXQobTIuZWxlbWVudHMpLFxuICAgIGZlYXR1cmVzOiAgbTEuZmVhdHVyZXMuY29uY2F0KG0yLmZlYXR1cmVzKSxcbiAgICBiZWhhdmlvcnM6IG0xLmJlaGF2aW9ycy5jb25jYXQobTIuYmVoYXZpb3JzKSxcbiAgfTtcbn1cblxudmFyIEVNUFRZX01FVEFEQVRBID0ge2VsZW1lbnRzOiBbXSwgZmVhdHVyZXM6IFtdLCBiZWhhdmlvcnM6IFtdfTtcblxuLyoqXG4gKiBQYXJzZTUncyByZXByZXNlbnRhdGlvbiBvZiBhIHBhcnNlZCBodG1sIGRvY3VtZW50XG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBEb2N1bWVudEFTVFxuICogQG1lbWJlcm9mIGh5ZHJvbHlzaXNcbiAqL1xuXG4vKipcbiAqIGVzcHJlZSdzIHJlcHJlc2VudGF0aW9uIG9mIGEgcGFyc2VkIGh0bWwgZG9jdW1lbnRcbiAqIEB0eXBlZGVmIHtPYmplY3R9IEpTQVNUXG4gKiBAbWVtYmVyb2YgaHlkcm9seXNpc1xuICovXG5cbi8qKlxuICogUGFja2FnZSBvZiBhIHBhcnNlZCBKUyBzY3JpcHRcbiAqIEB0eXBlZGVmIHtPYmplY3R9IFBhcnNlZEpTXG4gKiBAcHJvcGVydHkge0pTQVNUfSBhc3QgVGhlIHNjcmlwdCdzIEFTVFxuICogQHByb3BlcnR5IHtEb2N1bWVudEFTVH0gc2NyaXB0RWxlbWVudCBJZiBpbmxpbmUsIHRoZSBzY3JpcHQncyBjb250YWluaW5nIHRhZy5cbiAqIEBtZW1iZXJvZiBoeWRyb2x5c2lzXG4gKi9cblxuLyoqXG4gKiBUaGUgbWV0YWRhdGEgZm9yIGEgc2luZ2xlIHBvbHltZXIgZWxlbWVudFxuICogQHR5cGVkZWYge09iamVjdH0gRWxlbWVudERlc2NyaXB0b3JcbiAqIEBtZW1iZXJvZiBoeWRyb2x5c2lzXG4gKi9cblxuLyoqXG4gKiBUaGUgbWV0YWRhdGEgZm9yIGEgUG9seW1lciBmZWF0dXJlLlxuICogQHR5cGVkZWYge09iamVjdH0gRmVhdHVyZURlc2NyaXB0b3JcbiAqIEBtZW1iZXJvZiBoeWRyb2x5c2lzXG4gKi9cblxuLyoqXG4gKiBUaGUgbWV0YWRhdGEgZm9yIGEgUG9seW1lciBiZWhhdmlvciBtaXhpbi5cbiAqIEB0eXBlZGVmIHtPYmplY3R9IEJlaGF2aW9yRGVzY3JpcHRvclxuICogQG1lbWJlcm9mIGh5ZHJvbHlzaXNcbiAqL1xuXG4vKipcbiAqIFRoZSBtZXRhZGF0YSBmb3IgYWxsIGZlYXR1cmVzIGFuZCBlbGVtZW50cyBkZWZpbmVkIGluIG9uZSBkb2N1bWVudFxuICogQHR5cGVkZWYge09iamVjdH0gRG9jdW1lbnREZXNjcmlwdG9yXG4gKiBAbWVtYmVyb2YgaHlkcm9seXNpc1xuICogQHByb3BlcnR5IHtBcnJheTxFbGVtZW50RGVzY3JpcHRvcj59IGVsZW1lbnRzIFRoZSBlbGVtZW50cyBmcm9tIHRoZSBkb2N1bWVudFxuICogQHByb3BlcnR5IHtBcnJheTxGZWF0dXJlRGVzY3JpcHRvcj59ICBmZWF0dXJlcyBUaGUgZmVhdHVyZXMgZnJvbSB0aGUgZG9jdW1lbnRcbiAqIEBwcm9wZXJ0eSB7QXJyYXk8RmVhdHVyZURlc2NyaXB0b3I+fSAgYmVoYXZpb3JzIFRoZSBiZWhhdmlvcnMgZnJvbSB0aGUgZG9jdW1lbnRcbiAqL1xuXG4vKipcbiAqIFRoZSBtZXRhZGF0YSBvZiBhbiBlbnRpcmUgSFRNTCBkb2N1bWVudCwgaW4gcHJvbWlzZXMuXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBBbmFseXplZERvY3VtZW50XG4gKiBAbWVtYmVyb2YgaHlkcm9seXNpc1xuICogQHByb3BlcnR5IHtzdHJpbmd9IGhyZWYgVGhlIHVybCBvZiB0aGUgZG9jdW1lbnQuXG4gKiBAcHJvcGVydHkge1Byb21pc2U8UGFyc2VkSW1wb3J0Pn0gIGh0bWxMb2FkZWQgVGhlIHBhcnNlZCByZXByZXNlbnRhdGlvbiBvZlxuICogICAgIHRoZSBkb2MuIFVzZSB0aGUgYGFzdGAgcHJvcGVydHkgdG8gZ2V0IHRoZSBmdWxsIGBwYXJzZTVgIGFzdFxuICpcbiAqIEBwcm9wZXJ0eSB7UHJvbWlzZTxBcnJheTxzdHJpbmc+Pn0gZGVwc0xvYWRlZCBSZXNvbHZlcyB0byB0aGUgbGlzdCBvZiB0aGlzXG4gKiAgICAgRG9jdW1lbnQncyB0cmFuc2l0aXZlIGltcG9ydCBkZXBlbmRlbmNpZXNcbiAqXG4gKiBAcHJvcGVydHkge0FycmF5PHN0cmluZz59IGRlcEhyZWZzIFRoZSBkaXJlY3QgZGVwZW5kZW5jaWVzIG9mIHRoZSBkb2N1bWVudC5cbiAqXG4gKiBAcHJvcGVydHkge1Byb21pc2U8RG9jdW1lbnREZXNjcmlwdG9yPn0gbWV0YWRhdGFMb2FkZWQgUmVzb2x2ZXMgdG8gdGhlIGxpc3Qgb2ZcbiAqICAgICB0aGlzIERvY3VtZW50J3MgaW1wb3J0IGRlcGVuZGVuY2llc1xuICovXG5cbi8qKlxuICogQSBkYXRhYmFzZSBvZiBQb2x5bWVyIG1ldGFkYXRhIGRlZmluZWQgaW4gSFRNTFxuICpcbiAqIEBjb25zdHJ1Y3RvclxuICogQG1lbWJlck9mIGh5ZHJvbHlzaXNcbiAqIEBwYXJhbSAge2Jvb2xlYW59IGF0dGFjaEFTVCAgSWYgdHJ1ZSwgYXR0YWNoIGEgcGFyc2U1IGNvbXBsaWFudCBBU1RcbiAqIEBwYXJhbSAge0ZpbGVMb2FkZXI9fSBsb2FkZXIgQW4gb3B0aW9uYWwgYEZpbGVMb2FkZXJgIHVzZWQgdG8gbG9hZCBleHRlcm5hbFxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNvdXJjZXNcbiAqL1xudmFyIEFuYWx5emVyID0gZnVuY3Rpb24gQW5hbHl6ZXIoYXR0YWNoQVNULFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9hZGVyKSB7XG4gIHRoaXMubG9hZGVyID0gbG9hZGVyO1xuXG4gIC8qKlxuICAgKiBBIGxpc3Qgb2YgYWxsIGVsZW1lbnRzIHRoZSBgQW5hbHl6ZXJgIGhhcyBtZXRhZGF0YSBmb3IuXG4gICAqIEBtZW1iZXIge0FycmF5LjxFbGVtZW50RGVzY3JpcHRvcj59XG4gICAqL1xuICB0aGlzLmVsZW1lbnRzID0gW107XG5cbiAgLyoqXG4gICAqIEEgdmlldyBpbnRvIGBlbGVtZW50c2AsIGtleWVkIGJ5IHRhZyBuYW1lLlxuICAgKiBAbWVtYmVyIHtPYmplY3QuPHN0cmluZyxFbGVtZW50RGVzY3JpcHRvcj59XG4gICAqL1xuICB0aGlzLmVsZW1lbnRzQnlUYWdOYW1lID0ge307XG5cbiAgLyoqXG4gICAqIEEgbGlzdCBvZiBBUEkgZmVhdHVyZXMgYWRkZWQgdG8gYFBvbHltZXIuQmFzZWAgZW5jb3VudGVyZWQgYnkgdGhlXG4gICAqIGFuYWx5emVyLlxuICAgKiBAbWVtYmVyIHtBcnJheTxGZWF0dXJlRGVzY3JpcHRvcj59XG4gICAqL1xuICB0aGlzLmZlYXR1cmVzID0gW107XG5cbiAgLyoqXG4gICAqIFRoZSBiZWhhdmlvcnMgY29sbGVjdGVkIGJ5IHRoZSBhbmFseXNpcyBwYXNzLlxuICAgKlxuICAgKiBAbWVtYmVyIHtBcnJheTxCZWhhdmlvckRlc2NyaXB0b3I+fVxuICAgKi9cbiAgdGhpcy5iZWhhdmlvcnMgPSBbXTtcblxuICAvKipcbiAgICogVGhlIGJlaGF2aW9ycyBjb2xsZWN0ZWQgYnkgdGhlIGFuYWx5c2lzIHBhc3MgYnkgbmFtZS5cbiAgICpcbiAgICogQG1lbWJlciB7T2JqZWN0PHN0cmluZyxCZWhhdmlvckRlc2NyaXB0b3I+fVxuICAgKi9cbiAgdGhpcy5iZWhhdmlvcnNCeU5hbWUgPSB7fTtcblxuICAvKipcbiAgICogQSBtYXAsIGtleWVkIGJ5IGFic29sdXRlIHBhdGgsIG9mIERvY3VtZW50IG1ldGFkYXRhLlxuICAgKiBAbWVtYmVyIHtPYmplY3Q8c3RyaW5nLEFuYWx5emVkRG9jdW1lbnQ+fVxuICAgKi9cbiAgdGhpcy5odG1sID0ge307XG5cbiAgLyoqXG4gICAqIEEgbWFwLCBrZXllZCBieSBwYXRoLCBvZiBIVE1MIGRvY3VtZW50IEFTVHMuXG4gICAqIEB0eXBlIHtPYmplY3R9XG4gICAqL1xuICB0aGlzLnBhcnNlZERvY3VtZW50cyA9IHt9O1xuXG4gIC8qKlxuICAgKiBBIG1hcCwga2V5ZWQgYnkgcGF0aCwgb2YgSlMgc2NyaXB0IEFTVHMuXG4gICAqXG4gICAqIElmIHRoZSBwYXRoIGlzIGFuIEhUTUwgZmlsZSB3aXRoIG11bHRpcGxlIHNjcmlwdHMsIHRoZSBlbnRyeSB3aWxsIGJlIGFuIGFycmF5IG9mIHNjcmlwdHMuXG4gICAqXG4gICAqIEB0eXBlIHtPYmplY3Q8c3RyaW5nLEFycmF5PFBhcnNlZEpTPj59XG4gICAqL1xuICB0aGlzLnBhcnNlZFNjcmlwdHMgPSB7fTtcblxuICBcblxuICAvKipcbiAgICogQSBtYXAsIGtleWVkIGJ5IHBhdGgsIG9mIGRvY3VtZW50IGNvbnRlbnQuXG4gICAqIEB0eXBlIHtPYmplY3R9XG4gICAqL1xuICB0aGlzLl9jb250ZW50ID0ge307XG59O1xuXG4vKipcbiAqIE9wdGlvbnMgZm9yIGBBbmFseXplci5hbmFsenllYFxuICogQHR5cGVkZWYge09iamVjdH0gTG9hZE9wdGlvbnNcbiAqIEBtZW1iZXJvZiBoeWRyb2x5c2lzXG4gKiBAcHJvcGVydHkge2Jvb2xlYW59IG5vQW5ub3RhdGlvbnMgV2hldGhlciBgYW5ub3RhdGUoKWAgc2hvdWxkIGJlIHNraXBwZWQuXG4gKiBAcHJvcGVydHkge2Jvb2xlYW59IGNsZWFuIFdoZXRoZXIgdGhlIGdlbmVyYXRlZCBkZXNjcmlwdG9ycyBzaG91bGQgYmUgY2xlYW5lZFxuICogICAgIG9mIHJlZHVuZGFudCBkYXRhLlxuICogQHByb3BlcnR5IHtmdW5jdGlvbihzdHJpbmcpOiBib29sZWFufSBmaWx0ZXIgQSBwcmVkaWNhdGUgZnVuY3Rpb24gdGhhdFxuICogICAgIGluZGljYXRlcyB3aGljaCBmaWxlcyBzaG91bGQgYmUgaWdub3JlZCBieSB0aGUgbG9hZGVyLiBCeSBkZWZhdWx0IGFsbFxuICogICAgIGZpbGVzIG5vdCBsb2NhdGVkIHVuZGVyIHRoZSBkaXJuYW1lIG9mIGBocmVmYCB3aWxsIGJlIGlnbm9yZWQuXG4gKi9cblxuLyoqXG4gKiBTaG9ydGhhbmQgZm9yIHRyYW5zaXRpdmVseSBsb2FkaW5nIGFuZCBwcm9jZXNzaW5nIGFsbCBpbXBvcnRzIGJlZ2lubmluZyBhdFxuICogYGhyZWZgLlxuICpcbiAqIEluIG9yZGVyIHRvIHByb3Blcmx5IGZpbHRlciBwYXRocywgYGhyZWZgIF9tdXN0XyBiZSBhbiBhYnNvbHV0ZSBVUkkuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGhyZWYgVGhlIHJvb3QgaW1wb3J0IHRvIGJlZ2luIGxvYWRpbmcgZnJvbS5cbiAqIEBwYXJhbSB7TG9hZE9wdGlvbnM9fSBvcHRpb25zIEFueSBhZGRpdGlvbmFsIG9wdGlvbnMgZm9yIHRoZSBsb2FkLlxuICogQHJldHVybiB7UHJvbWlzZTxBbmFseXplcj59IEEgcHJvbWlzZSB0aGF0IHdpbGwgcmVzb2x2ZSBvbmNlIGBocmVmYCBhbmQgaXRzXG4gKiAgICAgZGVwZW5kZW5jaWVzIGhhdmUgYmVlbiBsb2FkZWQgYW5kIGFuYWx5emVkLlxuICovXG5BbmFseXplci5hbmFseXplID0gZnVuY3Rpb24gYW5hbHl6ZShocmVmLCBvcHRpb25zKSB7XG4gIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICBvcHRpb25zLmZpbHRlciA9IG9wdGlvbnMuZmlsdGVyIHx8IF9kZWZhdWx0RmlsdGVyKGhyZWYpO1xuXG4gIHZhciBsb2FkZXIgPSBuZXcgRmlsZUxvYWRlcigpO1xuICB2YXIgUHJpbWFyeVJlc29sdmVyID0gdHlwZW9mIHdpbmRvdyA9PT0gJ3VuZGVmaW5lZCcgP1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZSgnLi9sb2FkZXIvZnMtcmVzb2x2ZXInKSA6XG4gICAgICAgICAgICAgICAgICAgICAgICByZXF1aXJlKCcuL2xvYWRlci94aHItcmVzb2x2ZXInKTtcbiAgbG9hZGVyLmFkZFJlc29sdmVyKG5ldyBQcmltYXJ5UmVzb2x2ZXIob3B0aW9ucykpO1xuICBsb2FkZXIuYWRkUmVzb2x2ZXIobmV3IE5vb3BSZXNvbHZlcih7dGVzdDogb3B0aW9ucy5maWx0ZXJ9KSk7XG5cbiAgdmFyIGFuYWx5emVyID0gbmV3IHRoaXMobnVsbCwgbG9hZGVyKTtcbiAgcmV0dXJuIGFuYWx5emVyLm1ldGFkYXRhVHJlZShocmVmKS50aGVuKGZ1bmN0aW9uKHJvb3QpIHtcbiAgICBpZiAoIW9wdGlvbnMubm9Bbm5vdGF0aW9ucykge1xuICAgICAgYW5hbHl6ZXIuYW5ub3RhdGUoKTtcbiAgICB9XG4gICAgaWYgKG9wdGlvbnMuY2xlYW4pIHtcbiAgICAgIGFuYWx5emVyLmNsZWFuKCk7XG4gICAgfVxuICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoYW5hbHl6ZXIpO1xuICB9KTtcbn07XG5cbi8qKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSB7c3RyaW5nfSBocmVmXG4gKiBAcmV0dXJuIHtmdW5jdGlvbihzdHJpbmcpOiBib29sZWFufVxuICovXG5mdW5jdGlvbiBfZGVmYXVsdEZpbHRlcihocmVmKSB7XG4gIC8vIEV2ZXJ5dGhpbmcgdXAgdG8gdGhlIGxhc3QgYC9gIG9yIGBcXGAuXG4gIHZhciBiYXNlID0gaHJlZi5tYXRjaCgvXiguKj8pW15cXC9cXFxcXSokLylbMV07XG4gIHJldHVybiBmdW5jdGlvbih1cmkpIHtcbiAgICByZXR1cm4gdXJpLmluZGV4T2YoYmFzZSkgIT09IDA7XG4gIH07XG59XG5cbkFuYWx5emVyLnByb3RvdHlwZS5sb2FkID0gZnVuY3Rpb24gbG9hZChocmVmKSB7XG4gIHJldHVybiB0aGlzLmxvYWRlci5yZXF1ZXN0KGhyZWYpLnRoZW4oZnVuY3Rpb24oY29udGVudCkge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihyZXNvbHZlLCByZWplY3QpIHtcbiAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICAgIHRoaXMuX2NvbnRlbnRbaHJlZl0gPSBjb250ZW50O1xuICAgICAgICByZXNvbHZlKHRoaXMuX3BhcnNlSFRNTChjb250ZW50LCBocmVmKSk7XG4gICAgICB9LmJpbmQodGhpcyksIDApO1xuICAgIH0uYmluZCh0aGlzKSkuY2F0Y2goZnVuY3Rpb24oZXJyKXtcbiAgICAgIGNvbnNvbGUuZXJyb3IoXCJFcnJvciBwcm9jZXNzaW5nIGRvY3VtZW50IGF0IFwiICsgaHJlZik7XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfSk7XG4gIH0uYmluZCh0aGlzKSk7XG59O1xuXG4vKipcbiAqIFJldHVybnMgYW4gYEFuYWx5emVkRG9jdW1lbnRgIHJlcHJlc2VudGluZyB0aGUgcHJvdmlkZWQgZG9jdW1lbnRcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0gIHtzdHJpbmd9IGh0bWxJbXBvcnQgUmF3IHRleHQgb2YgYW4gSFRNTCBkb2N1bWVudFxuICogQHBhcmFtICB7c3RyaW5nfSBocmVmICAgICAgIFRoZSBkb2N1bWVudCdzIFVSTC5cbiAqIEByZXR1cm4ge0FuYWx5emVkRG9jdW1lbnR9ICAgICAgIEFuICBgQW5hbHl6ZWREb2N1bWVudGBcbiAqL1xuQW5hbHl6ZXIucHJvdG90eXBlLl9wYXJzZUhUTUwgPSBmdW5jdGlvbiBfcGFyc2VIVE1MKGh0bWxJbXBvcnQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhyZWYpIHtcbiAgaWYgKGhyZWYgaW4gdGhpcy5odG1sKSB7XG4gICAgcmV0dXJuIHRoaXMuaHRtbFtocmVmXTtcbiAgfVxuICB2YXIgZGVwc0xvYWRlZCA9IFtdO1xuICB2YXIgZGVwSHJlZnMgPSBbXTtcbiAgdmFyIG1ldGFkYXRhTG9hZGVkID0gUHJvbWlzZS5yZXNvbHZlKEVNUFRZX01FVEFEQVRBKTtcbiAgdmFyIHBhcnNlZDtcbiAgdHJ5IHtcbiAgICBwYXJzZWQgPSBpbXBvcnRQYXJzZShodG1sSW1wb3J0LCBocmVmKTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgY29uc29sZS5lcnJvcignRXJyb3IgcGFyc2luZyEnKTtcbiAgICB0aHJvdyBlcnI7XG4gIH1cbiAgdmFyIGh0bWxMb2FkZWQgPSBQcm9taXNlLnJlc29sdmUocGFyc2VkKTtcbiAgaWYgKHBhcnNlZC5zY3JpcHQpIHtcbiAgICBtZXRhZGF0YUxvYWRlZCA9IHRoaXMuX3Byb2Nlc3NTY3JpcHRzKHBhcnNlZC5zY3JpcHQsIGhyZWYpO1xuICB9XG4gIHZhciBjb21tZW50VGV4dCA9IHBhcnNlZC5jb21tZW50Lm1hcChmdW5jdGlvbihjb21tZW50KXtcbiAgICByZXR1cm4gZG9tNS5nZXRUZXh0Q29udGVudChjb21tZW50KTtcbiAgfSk7XG4gIHZhciBwc2V1ZG9FbGVtZW50cyA9IGRvY3MucGFyc2VQc2V1ZG9FbGVtZW50cyhjb21tZW50VGV4dCk7XG4gIHBzZXVkb0VsZW1lbnRzLmZvckVhY2goZnVuY3Rpb24oZWxlbWVudCl7XG4gICAgZWxlbWVudC5jb250ZW50SHJlZiA9IGhyZWY7XG4gICAgdGhpcy5lbGVtZW50cy5wdXNoKGVsZW1lbnQpO1xuICAgIHRoaXMuZWxlbWVudHNCeVRhZ05hbWVbZWxlbWVudC5pc10gPSBlbGVtZW50O1xuICB9LmJpbmQodGhpcykpO1xuICBtZXRhZGF0YUxvYWRlZCA9IG1ldGFkYXRhTG9hZGVkLnRoZW4oZnVuY3Rpb24obWV0YWRhdGEpe1xuICAgIHZhciBtZXRhZGF0YUVudHJ5ID0ge1xuICAgICAgZWxlbWVudHM6IHBzZXVkb0VsZW1lbnRzLFxuICAgICAgZmVhdHVyZXM6IFtdLFxuICAgICAgYmVoYXZpb3JzOiBbXVxuICAgIH07XG4gICAgcmV0dXJuIFttZXRhZGF0YSwgbWV0YWRhdGFFbnRyeV0ucmVkdWNlKHJlZHVjZU1ldGFkYXRhKTtcbiAgfSk7XG4gIGRlcHNMb2FkZWQucHVzaChtZXRhZGF0YUxvYWRlZCk7XG5cblxuICBpZiAodGhpcy5sb2FkZXIpIHtcbiAgICB2YXIgYmFzZVVyaSA9IGhyZWY7XG4gICAgaWYgKHBhcnNlZC5iYXNlLmxlbmd0aCA+IDEpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoXCJPbmx5IG9uZSBiYXNlIHRhZyBwZXIgZG9jdW1lbnQhXCIpO1xuICAgICAgdGhyb3cgXCJNdWx0aXBsZSBiYXNlIHRhZ3MgaW4gXCIgKyBocmVmO1xuICAgIH0gZWxzZSBpZiAocGFyc2VkLmJhc2UubGVuZ3RoID09IDEpIHtcbiAgICAgIHZhciBiYXNlSHJlZiA9IGRvbTUuZ2V0QXR0cmlidXRlKHBhcnNlZC5iYXNlWzBdLCBcImhyZWZcIik7XG4gICAgICBpZiAoYmFzZUhyZWYpIHtcbiAgICAgICAgYmFzZUhyZWYgPSBiYXNlSHJlZiArIFwiL1wiO1xuICAgICAgICBiYXNlVXJpID0gdXJsLnJlc29sdmUoYmFzZVVyaSwgYmFzZUhyZWYpO1xuICAgICAgfVxuICAgIH1cbiAgICBwYXJzZWQuaW1wb3J0LmZvckVhY2goZnVuY3Rpb24obGluaykge1xuICAgICAgdmFyIGxpbmt1cmwgPSBkb201LmdldEF0dHJpYnV0ZShsaW5rLCAnaHJlZicpO1xuICAgICAgaWYgKGxpbmt1cmwpIHtcbiAgICAgICAgdmFyIHJlc29sdmVkVXJsID0gdXJsLnJlc29sdmUoYmFzZVVyaSwgbGlua3VybCk7XG4gICAgICAgIGRlcEhyZWZzLnB1c2gocmVzb2x2ZWRVcmwpO1xuICAgICAgICBkZXBzTG9hZGVkLnB1c2godGhpcy5fZGVwZW5kZW5jaWVzTG9hZGVkRm9yKHJlc29sdmVkVXJsLCBocmVmKSk7XG4gICAgICB9XG4gICAgfS5iaW5kKHRoaXMpKTtcbiAgICBwYXJzZWQuc3R5bGUuZm9yRWFjaChmdW5jdGlvbihzdHlsZUVsZW1lbnQpIHtcbiAgICAgIGlmIChwb2x5bWVyRXh0ZXJuYWxTdHlsZShzdHlsZUVsZW1lbnQpKSB7XG4gICAgICAgIHZhciBzdHlsZUhyZWYgPSBkb201LmdldEF0dHJpYnV0ZShzdHlsZUVsZW1lbnQsICdocmVmJyk7XG4gICAgICAgIGlmIChocmVmKSB7XG4gICAgICAgICAgc3R5bGVIcmVmID0gdXJsLnJlc29sdmUoYmFzZVVyaSwgc3R5bGVIcmVmKTtcbiAgICAgICAgICBkZXBzTG9hZGVkLnB1c2godGhpcy5sb2FkZXIucmVxdWVzdChzdHlsZUhyZWYpLnRoZW4oZnVuY3Rpb24oY29udGVudCl7XG4gICAgICAgICAgICB0aGlzLl9jb250ZW50W3N0eWxlSHJlZl0gPSBjb250ZW50O1xuICAgICAgICAgIH0uYmluZCh0aGlzKSkpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfS5iaW5kKHRoaXMpKTtcbiAgfVxuICBkZXBzTG9hZGVkID0gUHJvbWlzZS5hbGwoZGVwc0xvYWRlZClcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24oKSB7cmV0dXJuIGRlcEhyZWZzO30pXG4gICAgICAgIC5jYXRjaChmdW5jdGlvbihlcnIpIHt0aHJvdyBlcnI7fSk7XG4gIHRoaXMucGFyc2VkRG9jdW1lbnRzW2hyZWZdID0gcGFyc2VkLmFzdDtcbiAgdGhpcy5odG1sW2hyZWZdID0ge1xuICAgICAgaHJlZjogaHJlZixcbiAgICAgIGh0bWxMb2FkZWQ6IGh0bWxMb2FkZWQsXG4gICAgICBtZXRhZGF0YUxvYWRlZDogbWV0YWRhdGFMb2FkZWQsXG4gICAgICBkZXBIcmVmczogZGVwSHJlZnMsXG4gICAgICBkZXBzTG9hZGVkOiBkZXBzTG9hZGVkXG4gIH07XG4gIHJldHVybiB0aGlzLmh0bWxbaHJlZl07XG59O1xuXG5BbmFseXplci5wcm90b3R5cGUuX3Byb2Nlc3NTY3JpcHRzID0gZnVuY3Rpb24gX3Byb2Nlc3NTY3JpcHRzKHNjcmlwdHMsIGhyZWYpIHtcbiAgdmFyIHNjcmlwdFByb21pc2VzID0gW107XG4gIHNjcmlwdHMuZm9yRWFjaChmdW5jdGlvbihzY3JpcHQpIHtcbiAgICBzY3JpcHRQcm9taXNlcy5wdXNoKHRoaXMuX3Byb2Nlc3NTY3JpcHQoc2NyaXB0LCBocmVmKSk7XG4gIH0uYmluZCh0aGlzKSk7XG4gIHJldHVybiBQcm9taXNlLmFsbChzY3JpcHRQcm9taXNlcykudGhlbihmdW5jdGlvbihtZXRhZGF0YUxpc3QpIHtcbiAgICByZXR1cm4gbWV0YWRhdGFMaXN0LnJlZHVjZShyZWR1Y2VNZXRhZGF0YSwgRU1QVFlfTUVUQURBVEEpO1xuICB9KTtcbn07XG5cbkFuYWx5emVyLnByb3RvdHlwZS5fcHJvY2Vzc1NjcmlwdCA9IGZ1bmN0aW9uIF9wcm9jZXNzU2NyaXB0KHNjcmlwdCwgaHJlZikge1xuICB2YXIgc3JjID0gZG9tNS5nZXRBdHRyaWJ1dGUoc2NyaXB0LCAnc3JjJyk7XG4gIHZhciBwYXJzZWRKcztcbiAgaWYgKCFzcmMpIHtcbiAgICB0cnkge1xuICAgICAgcGFyc2VkSnMgPSBqc1BhcnNlKChzY3JpcHQuY2hpbGROb2Rlcy5sZW5ndGgpID8gc2NyaXB0LmNoaWxkTm9kZXNbMF0udmFsdWUgOiAnJyk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAvLyBGaWd1cmUgb3V0IHRoZSBjb3JyZWN0IGxpbmUgbnVtYmVyIGZvciB0aGUgZXJyb3IuXG4gICAgICB2YXIgbGluZSA9IDA7XG4gICAgICB2YXIgY29sID0gMDtcbiAgICAgIGlmIChzY3JpcHQuX19vd25lckRvY3VtZW50ICYmIHNjcmlwdC5fX293bmVyRG9jdW1lbnQgPT0gaHJlZikge1xuICAgICAgICBsaW5lID0gc2NyaXB0Ll9fbG9jYXRpb25EZXRhaWwubGluZSAtIDE7XG4gICAgICAgIGNvbCA9IHNjcmlwdC5fX2xvY2F0aW9uRGV0YWlsLmxpbmUgLSAxO1xuICAgICAgfVxuICAgICAgbGluZSArPSBlcnIubGluZU51bWJlcjtcbiAgICAgIGNvbCArPSBlcnIuY29sdW1uO1xuICAgICAgdmFyIG1lc3NhZ2UgPSBcIkVycm9yIHBhcnNpbmcgc2NyaXB0IGluIFwiICsgaHJlZiArIFwiIGF0IFwiICsgbGluZSArIFwiOlwiICsgY29sO1xuICAgICAgbWVzc2FnZSArPSBcIlxcblwiICsgZXJyLmRlc2NyaXB0aW9uO1xuICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KG5ldyBFcnJvcihtZXNzYWdlKSk7XG4gICAgfVxuICAgIGlmIChwYXJzZWRKcy5lbGVtZW50cykge1xuICAgICAgcGFyc2VkSnMuZWxlbWVudHMuZm9yRWFjaChmdW5jdGlvbihlbGVtZW50KSB7XG4gICAgICAgIGVsZW1lbnQuc2NyaXB0RWxlbWVudCA9IHNjcmlwdDtcbiAgICAgICAgZWxlbWVudC5jb250ZW50SHJlZiA9IGhyZWY7XG4gICAgICAgIHRoaXMuZWxlbWVudHMucHVzaChlbGVtZW50KTtcbiAgICAgICAgaWYgKGVsZW1lbnQuaXMgaW4gdGhpcy5lbGVtZW50c0J5VGFnTmFtZSkge1xuICAgICAgICAgIGNvbnNvbGUud2FybignSWdub3JpbmcgZHVwbGljYXRlIGVsZW1lbnQgZGVmaW5pdGlvbjogJyArIGVsZW1lbnQuaXMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMuZWxlbWVudHNCeVRhZ05hbWVbZWxlbWVudC5pc10gPSBlbGVtZW50O1xuICAgICAgICB9XG4gICAgICB9LmJpbmQodGhpcykpO1xuICAgIH1cbiAgICBpZiAocGFyc2VkSnMuZmVhdHVyZXMpIHtcbiAgICAgIHBhcnNlZEpzLmZlYXR1cmVzLmZvckVhY2goZnVuY3Rpb24oZmVhdHVyZSl7XG4gICAgICAgIGZlYXR1cmUuY29udGVudEhyZWYgPSBocmVmO1xuICAgICAgICBmZWF0dXJlLnNjcmlwdEVsZW1lbnQgPSBzY3JpcHQ7XG4gICAgICB9KTtcbiAgICAgIHRoaXMuZmVhdHVyZXMgPSB0aGlzLmZlYXR1cmVzLmNvbmNhdChwYXJzZWRKcy5mZWF0dXJlcyk7XG4gICAgfVxuICAgIGlmIChwYXJzZWRKcy5iZWhhdmlvcnMpIHtcbiAgICAgIHBhcnNlZEpzLmJlaGF2aW9ycy5mb3JFYWNoKGZ1bmN0aW9uKGJlaGF2aW9yKXtcbiAgICAgICAgYmVoYXZpb3IuY29udGVudEhyZWYgPSBocmVmO1xuICAgICAgICB0aGlzLmJlaGF2aW9yc0J5TmFtZVtiZWhhdmlvci5pc10gPSBiZWhhdmlvcjtcbiAgICAgICAgdGhpcy5iZWhhdmlvcnNCeU5hbWVbYmVoYXZpb3Iuc3ltYm9sXSA9IGJlaGF2aW9yO1xuICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICAgIHRoaXMuYmVoYXZpb3JzID0gdGhpcy5iZWhhdmlvcnMuY29uY2F0KHBhcnNlZEpzLmJlaGF2aW9ycyk7XG4gICAgfVxuICAgIGlmICghT2JqZWN0Lmhhc093blByb3BlcnR5LmNhbGwodGhpcy5wYXJzZWRTY3JpcHRzLCBocmVmKSkge1xuICAgICAgdGhpcy5wYXJzZWRTY3JpcHRzW2hyZWZdID0gW107XG4gICAgfVxuICAgIHZhciBzY3JpcHRFbGVtZW50O1xuICAgIGlmIChzY3JpcHQuX19vd25lckRvY3VtZW50ICYmIHNjcmlwdC5fX293bmVyRG9jdW1lbnQgPT0gaHJlZikge1xuICAgICAgc2NyaXB0RWxlbWVudCA9IHNjcmlwdDtcbiAgICB9XG4gICAgdGhpcy5wYXJzZWRTY3JpcHRzW2hyZWZdLnB1c2goe1xuICAgICAgYXN0OiBwYXJzZWRKcy5wYXJzZWRTY3JpcHQsXG4gICAgICBzY3JpcHRFbGVtZW50OiBzY3JpcHRFbGVtZW50XG4gICAgfSk7XG4gICAgcmV0dXJuIHBhcnNlZEpzO1xuICB9XG4gIGlmICh0aGlzLmxvYWRlcikge1xuICAgIHZhciByZXNvbHZlZFNyYyA9IHVybC5yZXNvbHZlKGhyZWYsIHNyYyk7XG4gICAgcmV0dXJuIHRoaXMubG9hZGVyLnJlcXVlc3QocmVzb2x2ZWRTcmMpLnRoZW4oZnVuY3Rpb24oY29udGVudCkge1xuICAgICAgdGhpcy5fY29udGVudFtyZXNvbHZlZFNyY10gPSBjb250ZW50O1xuICAgICAgdmFyIHJlc29sdmVkU2NyaXB0ID0gT2JqZWN0LmNyZWF0ZShzY3JpcHQpO1xuICAgICAgcmVzb2x2ZWRTY3JpcHQuY2hpbGROb2RlcyA9IFt7dmFsdWU6IGNvbnRlbnR9XTtcbiAgICAgIHJlc29sdmVkU2NyaXB0LmF0dHJzID0gcmVzb2x2ZWRTY3JpcHQuYXR0cnMuc2xpY2UoKTtcbiAgICAgIGRvbTUucmVtb3ZlQXR0cmlidXRlKHJlc29sdmVkU2NyaXB0LCAnc3JjJyk7XG4gICAgICByZXR1cm4gdGhpcy5fcHJvY2Vzc1NjcmlwdChyZXNvbHZlZFNjcmlwdCwgcmVzb2x2ZWRTcmMpO1xuICAgIH0uYmluZCh0aGlzKSkuY2F0Y2goZnVuY3Rpb24oZXJyKSB7dGhyb3cgZXJyO30pO1xuICB9IGVsc2Uge1xuICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoRU1QVFlfTUVUQURBVEEpO1xuICB9XG59O1xuXG5BbmFseXplci5wcm90b3R5cGUuX2RlcGVuZGVuY2llc0xvYWRlZEZvciA9IGZ1bmN0aW9uIF9kZXBlbmRlbmNpZXNMb2FkZWRGb3IoaHJlZiwgcm9vdCkge1xuICB2YXIgZm91bmQgPSB7fTtcbiAgaWYgKHJvb3QgIT09IHVuZGVmaW5lZCkge1xuICAgIGZvdW5kW3Jvb3RdID0gdHJ1ZTtcbiAgfVxuICByZXR1cm4gdGhpcy5fZ2V0RGVwZW5kZW5jaWVzKGhyZWYsIGZvdW5kKS50aGVuKGZ1bmN0aW9uKGRlcHMpIHtcbiAgICB2YXIgZGVwTWV0YWRhdGFMb2FkZWQgPSBbXTtcbiAgICB2YXIgZGVwUHJvbWlzZXMgPSBkZXBzLm1hcChmdW5jdGlvbihkZXBIcmVmKXtcbiAgICAgIHJldHVybiB0aGlzLmxvYWQoZGVwSHJlZikudGhlbihmdW5jdGlvbihodG1sTW9ub21lcikge1xuICAgICAgICByZXR1cm4gaHRtbE1vbm9tZXIubWV0YWRhdGFMb2FkZWQ7XG4gICAgICB9KTtcbiAgICB9LmJpbmQodGhpcykpO1xuICAgIHJldHVybiBQcm9taXNlLmFsbChkZXBQcm9taXNlcyk7XG4gIH0uYmluZCh0aGlzKSk7XG59O1xuXG4vKipcbiAqIExpc3QgYWxsIHRoZSBodG1sIGRlcGVuZGVuY2llcyBmb3IgdGhlIGRvY3VtZW50IGF0IGBocmVmYC5cbiAqIEBwYXJhbSAge3N0cmluZ30gICAgICAgICAgICAgICAgICAgaHJlZiAgICAgIFRoZSBocmVmIHRvIGdldCBkZXBlbmRlbmNpZXMgZm9yLlxuICogQHBhcmFtICB7T2JqZWN0LjxzdHJpbmcsYm9vbGVhbj49fSBmb3VuZCAgICAgQW4gb2JqZWN0IGtleWVkIGJ5IFVSTCBvZiB0aGVcbiAqICAgICBhbHJlYWR5IHJlc29sdmVkIGRlcGVuZGVuY2llcy5cbiAqIEBwYXJhbSAge2Jvb2xlYW49fSAgICAgICAgICAgICAgICB0cmFuc2l0aXZlIFdoZXRoZXIgdG8gbG9hZCB0cmFuc2l0aXZlXG4gKiAgICAgZGVwZW5kZW5jaWVzLiBEZWZhdWx0cyB0byB0cnVlLlxuICogQHJldHVybiB7QXJyYXkuPHN0cmluZz59ICBBIGxpc3Qgb2YgYWxsIHRoZSBodG1sIGRlcGVuZGVuY2llcy5cbiAqL1xuQW5hbHl6ZXIucHJvdG90eXBlLl9nZXREZXBlbmRlbmNpZXMgPSBmdW5jdGlvbiBfZ2V0RGVwZW5kZW5jaWVzKGhyZWYsIGZvdW5kLCB0cmFuc2l0aXZlKSB7XG4gIGlmIChmb3VuZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgZm91bmQgPSB7fTtcbiAgICBmb3VuZFtocmVmXSA9IHRydWU7XG4gIH1cbiAgaWYgKHRyYW5zaXRpdmUgPT09IHVuZGVmaW5lZCkge1xuICAgIHRyYW5zaXRpdmUgPSB0cnVlO1xuICB9XG4gIHZhciBkZXBzID0gW107XG4gIHJldHVybiB0aGlzLmxvYWQoaHJlZikudGhlbihmdW5jdGlvbihodG1sTW9ub21lcikge1xuICAgIHZhciB0cmFuc2l0aXZlRGVwcyA9IFtdO1xuICAgIGh0bWxNb25vbWVyLmRlcEhyZWZzLmZvckVhY2goZnVuY3Rpb24oZGVwSHJlZil7XG4gICAgICBpZiAoZm91bmRbZGVwSHJlZl0pIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgZGVwcy5wdXNoKGRlcEhyZWYpO1xuICAgICAgZm91bmRbZGVwSHJlZl0gPSB0cnVlO1xuICAgICAgaWYgKHRyYW5zaXRpdmUpIHtcbiAgICAgICAgdHJhbnNpdGl2ZURlcHMucHVzaCh0aGlzLl9nZXREZXBlbmRlbmNpZXMoZGVwSHJlZiwgZm91bmQpKTtcbiAgICAgIH1cbiAgICB9LmJpbmQodGhpcykpO1xuICAgIHJldHVybiBQcm9taXNlLmFsbCh0cmFuc2l0aXZlRGVwcyk7XG4gIH0uYmluZCh0aGlzKSkudGhlbihmdW5jdGlvbih0cmFuc2l0aXZlRGVwcykge1xuICAgIHZhciBhbGxkZXBzID0gdHJhbnNpdGl2ZURlcHMucmVkdWNlKGZ1bmN0aW9uKGEsIGIpIHtcbiAgICAgIHJldHVybiBhLmNvbmNhdChiKTtcbiAgICB9LCBbXSkuY29uY2F0KGRlcHMpO1xuICAgIHJldHVybiBhbGxkZXBzO1xuICB9KTtcbn07XG5cbmZ1bmN0aW9uIG1hdGNoZXNEb2N1bWVudEZvbGRlcihkZXNjcmlwdG9yLCBocmVmKSB7XG4gIGlmICghZGVzY3JpcHRvci5jb250ZW50SHJlZikge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICB2YXIgZGVzY3JpcHRvckRvYyA9IHVybC5wYXJzZShkZXNjcmlwdG9yLmNvbnRlbnRIcmVmKTtcbiAgaWYgKCFkZXNjcmlwdG9yRG9jIHx8ICFkZXNjcmlwdG9yRG9jLnBhdGhuYW1lKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIHZhciBzZWFyY2hEb2MgPSB1cmwucGFyc2UoaHJlZik7XG4gIGlmICghc2VhcmNoRG9jIHx8ICFzZWFyY2hEb2MucGF0aG5hbWUpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgdmFyIHNlYXJjaFBhdGggPSBzZWFyY2hEb2MucGF0aG5hbWU7XG4gIHZhciBsYXN0U2xhc2ggPSBzZWFyY2hQYXRoLmxhc3RJbmRleE9mKFwiL1wiKTtcbiAgaWYgKGxhc3RTbGFzaCA+IDApIHtcbiAgICBzZWFyY2hQYXRoID0gc2VhcmNoUGF0aC5zbGljZSgwLCBsYXN0U2xhc2gpO1xuICB9XG4gIHJldHVybiBkZXNjcmlwdG9yRG9jLnBhdGhuYW1lLmluZGV4T2Yoc2VhcmNoUGF0aCkgPT09IDA7XG59XG5cbkFuYWx5emVyLnByb3RvdHlwZS5lbGVtZW50c0ZvckZvbGRlciA9IGZ1bmN0aW9uIGVsZW1lbnRzRm9yRm9sZGVyKGhyZWYpIHtcbiAgcmV0dXJuIHRoaXMuZWxlbWVudHMuZmlsdGVyKGZ1bmN0aW9uKGVsZW1lbnQpe1xuICAgIHJldHVybiBtYXRjaGVzRG9jdW1lbnRGb2xkZXIoZWxlbWVudCwgaHJlZik7XG4gIH0pO1xufTtcblxuQW5hbHl6ZXIucHJvdG90eXBlLmJlaGF2aW9yc0ZvckZvbGRlciA9IGZ1bmN0aW9uIGJlaGF2aW9yc0ZvckZvbGRlcihocmVmKSB7XG4gIHJldHVybiB0aGlzLmJlaGF2aW9ycy5maWx0ZXIoZnVuY3Rpb24oYmVoYXZpb3Ipe1xuICAgIHJldHVybiBtYXRjaGVzRG9jdW1lbnRGb2xkZXIoYmVoYXZpb3IsIGhyZWYpO1xuICB9KTtcbn07XG5cbi8qKlxuICogUmV0dXJucyBhIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhIFBPSk8gcmVwcmVzZW50YXRpb24gb2YgdGhlIGltcG9ydFxuICogdHJlZSwgaW4gYSBmb3JtYXQgdGhhdCBtYWludGFpbnMgdGhlIG9yZGVyaW5nIG9mIHRoZSBIVE1MIGltcG9ydHMgc3BlYy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBocmVmIHRoZSBpbXBvcnQgdG8gZ2V0IG1ldGFkYXRhIGZvci5cbiAqIEByZXR1cm4ge1Byb21pc2V9XG4gKi9cbkFuYWx5emVyLnByb3RvdHlwZS5tZXRhZGF0YVRyZWUgPSBmdW5jdGlvbiBtZXRhZGF0YVRyZWUoaHJlZikge1xuICByZXR1cm4gdGhpcy5sb2FkKGhyZWYpLnRoZW4oZnVuY3Rpb24obW9ub21lcil7XG4gICAgdmFyIGxvYWRlZEhyZWZzID0ge307XG4gICAgbG9hZGVkSHJlZnNbaHJlZl0gPSB0cnVlO1xuICAgIHJldHVybiB0aGlzLl9tZXRhZGF0YVRyZWUobW9ub21lciwgbG9hZGVkSHJlZnMpO1xuICB9LmJpbmQodGhpcykpO1xufTtcblxuQW5hbHl6ZXIucHJvdG90eXBlLl9tZXRhZGF0YVRyZWUgPSBmdW5jdGlvbiBfbWV0YWRhdGFUcmVlKGh0bWxNb25vbWVyLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvYWRlZEhyZWZzKSB7XG4gIGlmIChsb2FkZWRIcmVmcyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgbG9hZGVkSHJlZnMgPSB7fTtcbiAgfVxuICByZXR1cm4gaHRtbE1vbm9tZXIubWV0YWRhdGFMb2FkZWQudGhlbihmdW5jdGlvbihtZXRhZGF0YSkge1xuICAgIG1ldGFkYXRhID0ge1xuICAgICAgZWxlbWVudHM6IG1ldGFkYXRhLmVsZW1lbnRzLFxuICAgICAgZmVhdHVyZXM6IG1ldGFkYXRhLmZlYXR1cmVzLFxuICAgICAgaHJlZjogaHRtbE1vbm9tZXIuaHJlZlxuICAgIH07XG4gICAgcmV0dXJuIGh0bWxNb25vbWVyLmRlcHNMb2FkZWQudGhlbihmdW5jdGlvbihocmVmcykge1xuICAgICAgdmFyIGRlcE1ldGFkYXRhID0gW107XG4gICAgICBocmVmcy5mb3JFYWNoKGZ1bmN0aW9uKGhyZWYpIHtcbiAgICAgICAgdmFyIG1ldGFkYXRhUHJvbWlzZSA9IFByb21pc2UucmVzb2x2ZSh0cnVlKTtcbiAgICAgICAgaWYgKGRlcE1ldGFkYXRhLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICBtZXRhZGF0YVByb21pc2UgPSBkZXBNZXRhZGF0YVtkZXBNZXRhZGF0YS5sZW5ndGggLSAxXTtcbiAgICAgICAgfVxuICAgICAgICBtZXRhZGF0YVByb21pc2UgPSBtZXRhZGF0YVByb21pc2UudGhlbihmdW5jdGlvbigpIHtcbiAgICAgICAgICBpZiAoIWxvYWRlZEhyZWZzW2hyZWZdKSB7XG4gICAgICAgICAgICBsb2FkZWRIcmVmc1tocmVmXSA9IHRydWU7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fbWV0YWRhdGFUcmVlKHRoaXMuaHRtbFtocmVmXSwgbG9hZGVkSHJlZnMpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHt9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgICAgIGRlcE1ldGFkYXRhLnB1c2gobWV0YWRhdGFQcm9taXNlKTtcbiAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgICByZXR1cm4gUHJvbWlzZS5hbGwoZGVwTWV0YWRhdGEpLnRoZW4oZnVuY3Rpb24oaW1wb3J0TWV0YWRhdGEpIHtcbiAgICAgICAgbWV0YWRhdGEuaW1wb3J0cyA9IGltcG9ydE1ldGFkYXRhO1xuICAgICAgICByZXR1cm4gaHRtbE1vbm9tZXIuaHRtbExvYWRlZC50aGVuKGZ1bmN0aW9uKHBhcnNlZEh0bWwpIHtcbiAgICAgICAgICBtZXRhZGF0YS5odG1sID0gcGFyc2VkSHRtbDtcbiAgICAgICAgICBpZiAobWV0YWRhdGEuZWxlbWVudHMpIHtcbiAgICAgICAgICAgIG1ldGFkYXRhLmVsZW1lbnRzLmZvckVhY2goZnVuY3Rpb24oZWxlbWVudCkge1xuICAgICAgICAgICAgICBhdHRhY2hEb21Nb2R1bGUocGFyc2VkSHRtbCwgZWxlbWVudCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIG1ldGFkYXRhO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0uYmluZCh0aGlzKSk7XG4gIH0uYmluZCh0aGlzKSk7XG59O1xuXG5mdW5jdGlvbiBtYXRjaGluZ0ltcG9ydChpbXBvcnRFbGVtZW50KSB7XG4gIHZhciBtYXRjaGVzVGFnID0gZG9tNS5wcmVkaWNhdGVzLmhhc1RhZ05hbWUoaW1wb3J0RWxlbWVudC50YWdOYW1lKTtcbiAgdmFyIG1hdGNoZXNIcmVmID0gZG9tNS5wcmVkaWNhdGVzLmhhc0F0dHJWYWx1ZSgnaHJlZicsIGRvbTUuZ2V0QXR0cmlidXRlKGltcG9ydEVsZW1lbnQsICdocmVmJykpO1xuICB2YXIgbWF0Y2hlc1JlbCA9IGRvbTUucHJlZGljYXRlcy5oYXNBdHRyVmFsdWUoJ3JlbCcsIGRvbTUuZ2V0QXR0cmlidXRlKGltcG9ydEVsZW1lbnQsICdyZWwnKSk7XG4gIHJldHVybiBkb201LnByZWRpY2F0ZXMuQU5EKG1hdGNoZXNUYWcsIG1hdGNoZXNIcmVmLCBtYXRjaGVzUmVsKTtcbn1cblxuLy8gVE9ETyhham8pOiBSZWZhY3RvciBvdXQgb2YgdnVsY2FuaXplIGludG8gZG9tNS5cbnZhciBwb2x5bWVyRXh0ZXJuYWxTdHlsZSA9IGRvbTUucHJlZGljYXRlcy5BTkQoXG4gIGRvbTUucHJlZGljYXRlcy5oYXNUYWdOYW1lKCdsaW5rJyksXG4gIGRvbTUucHJlZGljYXRlcy5oYXNBdHRyVmFsdWUoJ3JlbCcsICdpbXBvcnQnKSxcbiAgZG9tNS5wcmVkaWNhdGVzLmhhc0F0dHJWYWx1ZSgndHlwZScsICdjc3MnKVxuKTtcblxudmFyIGV4dGVybmFsU2NyaXB0ID0gZG9tNS5wcmVkaWNhdGVzLkFORChcbiAgZG9tNS5wcmVkaWNhdGVzLmhhc1RhZ05hbWUoJ3NjcmlwdCcpLFxuICBkb201LnByZWRpY2F0ZXMuaGFzQXR0cignc3JjJylcbik7XG5cbnZhciBpc0h0bWxJbXBvcnROb2RlID0gZG9tNS5wcmVkaWNhdGVzLkFORChcbiAgZG9tNS5wcmVkaWNhdGVzLmhhc1RhZ05hbWUoJ2xpbmsnKSxcbiAgZG9tNS5wcmVkaWNhdGVzLmhhc0F0dHJWYWx1ZSgncmVsJywgJ2ltcG9ydCcpLFxuICBkb201LnByZWRpY2F0ZXMuTk9UKFxuICAgIGRvbTUucHJlZGljYXRlcy5oYXNBdHRyVmFsdWUoJ3R5cGUnLCAnY3NzJylcbiAgKVxuKTtcblxuQW5hbHl6ZXIucHJvdG90eXBlLl9pbmxpbmVTdHlsZXMgPSBmdW5jdGlvbiBfaW5saW5lU3R5bGVzKGFzdCwgaHJlZikge1xuICB2YXIgY3NzTGlua3MgPSBkb201LnF1ZXJ5QWxsKGFzdCwgcG9seW1lckV4dGVybmFsU3R5bGUpO1xuICBjc3NMaW5rcy5mb3JFYWNoKGZ1bmN0aW9uKGxpbmspIHtcbiAgICB2YXIgbGlua0hyZWYgPSBkb201LmdldEF0dHJpYnV0ZShsaW5rLCAnaHJlZicpO1xuICAgIHZhciB1cmkgPSB1cmwucmVzb2x2ZShocmVmLCBsaW5rSHJlZik7XG4gICAgdmFyIGNvbnRlbnQgPSB0aGlzLl9jb250ZW50W3VyaV07XG4gICAgdmFyIHN0eWxlID0gZG9tNS5jb25zdHJ1Y3RvcnMuZWxlbWVudCgnc3R5bGUnKTtcbiAgICBkb201LnNldFRleHRDb250ZW50KHN0eWxlLCAnXFxuJyArIGNvbnRlbnQgKyAnXFxuJyk7XG4gICAgZG9tNS5yZXBsYWNlKGxpbmssIHN0eWxlKTtcbiAgfS5iaW5kKHRoaXMpKTtcbiAgcmV0dXJuIGNzc0xpbmtzLmxlbmd0aCA+IDA7XG59O1xuXG5BbmFseXplci5wcm90b3R5cGUuX2lubGluZVNjcmlwdHMgPSBmdW5jdGlvbiBfaW5saW5lU2NyaXB0cyhhc3QsIGhyZWYpIHtcbiAgdmFyIHNjcmlwdHMgPSBkb201LnF1ZXJ5QWxsKGFzdCwgZXh0ZXJuYWxTY3JpcHQpO1xuICBzY3JpcHRzLmZvckVhY2goZnVuY3Rpb24oc2NyaXB0KSB7XG4gICAgdmFyIHNjcmlwdEhyZWYgPSBkb201LmdldEF0dHJpYnV0ZShzY3JpcHQsICdzcmMnKTtcbiAgICB2YXIgdXJpID0gdXJsLnJlc29sdmUoaHJlZiwgc2NyaXB0SHJlZik7XG4gICAgdmFyIGNvbnRlbnQgPSB0aGlzLl9jb250ZW50W3VyaV07XG4gICAgdmFyIGlubGluZWQgPSBkb201LmNvbnN0cnVjdG9ycy5lbGVtZW50KCdzY3JpcHQnKTtcbiAgICBkb201LnNldFRleHRDb250ZW50KGlubGluZWQsICdcXG4nICsgY29udGVudCArICdcXG4nKTtcbiAgICBkb201LnJlcGxhY2Uoc2NyaXB0LCBpbmxpbmVkKTtcbiAgfS5iaW5kKHRoaXMpKTtcbiAgcmV0dXJuIHNjcmlwdHMubGVuZ3RoID4gMDtcbn07XG5cbkFuYWx5emVyLnByb3RvdHlwZS5faW5saW5lSW1wb3J0cyA9IGZ1bmN0aW9uIF9pbmxpbmVJbXBvcnRzKGFzdCwgaHJlZiwgbG9hZGVkKSB7XG4gIHZhciBpbXBvcnRzID0gZG9tNS5xdWVyeUFsbChhc3QsIGlzSHRtbEltcG9ydE5vZGUpO1xuICBpbXBvcnRzLmZvckVhY2goZnVuY3Rpb24oaHRtbEltcG9ydCkge1xuICAgIHZhciBpbXBvcnRIcmVmID0gZG9tNS5nZXRBdHRyaWJ1dGUoaHRtbEltcG9ydCwgJ2hyZWYnKTtcbiAgICB2YXIgdXJpID0gdXJsLnJlc29sdmUoaHJlZiwgaW1wb3J0SHJlZik7XG4gICAgaWYgKGxvYWRlZFt1cmldKSB7XG4gICAgICBkb201LnJlbW92ZShodG1sSW1wb3J0KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdmFyIGNvbnRlbnQgPSB0aGlzLmdldExvYWRlZEFzdCh1cmksIGxvYWRlZCk7XG4gICAgZG9tNS5yZXBsYWNlKGh0bWxJbXBvcnQsIGNvbnRlbnQpO1xuICB9LmJpbmQodGhpcykpO1xuICByZXR1cm4gaW1wb3J0cy5sZW5ndGggPiAwO1xufTtcblxuLyoqXG4gKiBSZXR1cm5zIGEgcHJvbWlzZSByZXNvbHZpbmcgdG8gYSBmb3JtIG9mIHRoZSBBU1Qgd2l0aCBhbGwgbGlua3MgcmVwbGFjZWRcbiAqIHdpdGggdGhlIGRvY3VtZW50IHRoZXkgbGluayB0by4gLmNzcyBhbmQgLnNjcmlwdCBmaWxlcyBiZWNvbWUgJmx0O3N0eWxlJmd0OyBhbmRcbiAqICZsdDtzY3JpcHQmZ3Q7LCByZXNwZWN0aXZlbHkuXG4gKlxuICogVGhlIGVsZW1lbnRzIGluIHRoZSBsb2FkZWQgZG9jdW1lbnQgYXJlIHVubW9kaWZpZWQgZnJvbSB0aGVpciBvcmlnaW5hbFxuICogZG9jdW1lbnRzLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBocmVmIFRoZSBkb2N1bWVudCB0byBsb2FkLlxuICogQHBhcmFtIHtPYmplY3QuPHN0cmluZyxib29sZWFuPj19IGxvYWRlZCBBbiBvYmplY3Qga2V5ZWQgYnkgYWxyZWFkeSBsb2FkZWQgZG9jdW1lbnRzLlxuICogQHJldHVybiB7UHJvbWlzZS48RG9jdW1lbnRBU1Q+fVxuICovXG5BbmFseXplci5wcm90b3R5cGUuZ2V0TG9hZGVkQXN0ID0gZnVuY3Rpb24gZ2V0TG9hZGVkQXN0KGhyZWYsIGxvYWRlZCkge1xuICBpZiAoIWxvYWRlZCkge1xuICAgIGxvYWRlZCA9IHt9O1xuICB9XG4gIGxvYWRlZFtocmVmXSA9IHRydWU7XG4gIHZhciBwYXJzZWREb2N1bWVudCA9IHRoaXMucGFyc2VkRG9jdW1lbnRzW2hyZWZdO1xuICB2YXIgYW5hbHl6ZWREb2N1bWVudCA9IHRoaXMuaHRtbFtocmVmXTtcbiAgdmFyIGFzdENvcHkgPSBkb201LnBhcnNlKGRvbTUuc2VyaWFsaXplKHBhcnNlZERvY3VtZW50KSk7XG4gIC8vIFdoZW5ldmVyIHdlIGlubGluZSBzb21ldGhpbmcsIHJlc2V0IGlubGluZWQgdG8gdHJ1ZSB0byBrbm93IHRoYXQgYW5vYXRoZXJcbiAgLy8gaW5saW5pbmcgcGFzcyBpcyBuZWVkZWQ7XG4gIHRoaXMuX2lubGluZVN0eWxlcyhhc3RDb3B5LCBocmVmKTtcbiAgdGhpcy5faW5saW5lU2NyaXB0cyhhc3RDb3B5LCBocmVmKTtcbiAgdGhpcy5faW5saW5lSW1wb3J0cyhhc3RDb3B5LCBocmVmLCBsb2FkZWQpO1xuICByZXR1cm4gYXN0Q29weTtcbn07XG5cbi8qKlxuICogQ2FsbHMgYGRvbTUubm9kZVdhbGtBbGxgIG9uIGVhY2ggZG9jdW1lbnQgdGhhdCBgQW5heXpsZXJgIGhhcyBsYW9kZWQuXG4gKiBAcGFyYW0gIHtPYmplY3R9IHByZWRpY2F0ZSBBIGRvbTUgcHJlZGljYXRlLlxuICogQHJldHVybiB7T2JqZWN0fVxuICovXG5BbmFseXplci5wcm90b3R5cGUubm9kZVdhbGtEb2N1bWVudHMgPSBmdW5jdGlvbiBub2RlV2Fsa0RvY3VtZW50cyhwcmVkaWNhdGUpIHtcbiAgZm9yICh2YXIgaHJlZiBpbiB0aGlzLnBhcnNlZERvY3VtZW50cykge1xuICAgIHZhciBtYXRjaCA9IGRvbTUubm9kZVdhbGsodGhpcy5wYXJzZWREb2N1bWVudHNbaHJlZl0sIHByZWRpY2F0ZSk7XG4gICAgaWYgKG1hdGNoKSB7XG4gICAgICByZXR1cm4gbWF0Y2g7XG4gICAgfVxuICB9XG4gIHJldHVybiBudWxsO1xufTtcblxuLyoqXG4gKiBDYWxscyBgZG9tNS5ub2RlV2Fsa0FsbGAgb24gZWFjaCBkb2N1bWVudCB0aGF0IGBBbmF5emxlcmAgaGFzIGxhb2RlZC5cbiAqIEBwYXJhbSAge09iamVjdH0gcHJlZGljYXRlIEEgZG9tNSBwcmVkaWNhdGUuXG4gKiBAcmV0dXJuIHtPYmplY3R9XG4gKi9cbkFuYWx5emVyLnByb3RvdHlwZS5ub2RlV2Fsa0FsbERvY3VtZW50cyA9IGZ1bmN0aW9uIG5vZGVXYWxrRG9jdW1lbnRzKHByZWRpY2F0ZSkge1xuICB2YXIgcmVzdWx0cyA9IFtdO1xuICBmb3IgKHZhciBocmVmIGluIHRoaXMucGFyc2VkRG9jdW1lbnRzKSB7XG4gICAgdmFyIG5ld05vZGVzID0gZG9tNS5ub2RlV2Fsa0FsbCh0aGlzLnBhcnNlZERvY3VtZW50c1tocmVmXSwgcHJlZGljYXRlKTtcbiAgICByZXN1bHRzID0gcmVzdWx0cy5jb25jYXQobmV3Tm9kZXMpO1xuICB9XG4gIHJldHVybiByZXN1bHRzO1xufTtcblxuLyoqIEFubm90YXRlcyBhbGwgbG9hZGVkIG1ldGFkYXRhIHdpdGggaXRzIGRvY3VtZW50YXRpb24uICovXG5BbmFseXplci5wcm90b3R5cGUuYW5ub3RhdGUgPSBmdW5jdGlvbiBhbm5vdGF0ZSgpIHtcbiAgaWYgKHRoaXMuZmVhdHVyZXMubGVuZ3RoID4gMCkge1xuICAgIHZhciBmZWF0dXJlRWwgPSBkb2NzLmZlYXR1cmVFbGVtZW50KHRoaXMuZmVhdHVyZXMpO1xuICAgIHRoaXMuZWxlbWVudHMudW5zaGlmdChmZWF0dXJlRWwpO1xuICAgIHRoaXMuZWxlbWVudHNCeVRhZ05hbWVbZmVhdHVyZUVsLmlzXSA9IGZlYXR1cmVFbDtcbiAgfVxuICB2YXIgYmVoYXZpb3JzQnlOYW1lID0gdGhpcy5iZWhhdmlvcnNCeU5hbWU7XG4gIHZhciBlbGVtZW50SGVscGVyID0gZnVuY3Rpb24oZGVzY3JpcHRvcil7XG4gICAgZG9jcy5hbm5vdGF0ZUVsZW1lbnQoZGVzY3JpcHRvciwgYmVoYXZpb3JzQnlOYW1lKTtcbiAgfTtcbiAgdGhpcy5lbGVtZW50cy5mb3JFYWNoKGVsZW1lbnRIZWxwZXIpO1xuICB0aGlzLmJlaGF2aW9ycy5mb3JFYWNoKGVsZW1lbnRIZWxwZXIpOyAvLyBTYW1lIHNoYXBlLlxuICB0aGlzLmJlaGF2aW9ycy5mb3JFYWNoKGZ1bmN0aW9uKGJlaGF2aW9yKXtcbiAgICBpZiAoYmVoYXZpb3IuaXMgIT09IGJlaGF2aW9yLnN5bWJvbCAmJiBiZWhhdmlvci5zeW1ib2wpIHtcbiAgICAgIHRoaXMuYmVoYXZpb3JzQnlOYW1lW2JlaGF2aW9yLnN5bWJvbF0gPSB1bmRlZmluZWQ7XG4gICAgfVxuICB9LmJpbmQodGhpcykpO1xufTtcblxuZnVuY3Rpb24gYXR0YWNoRG9tTW9kdWxlKHBhcnNlZEltcG9ydCwgZWxlbWVudCkge1xuICB2YXIgZG9tTW9kdWxlcyA9IHBhcnNlZEltcG9ydFsnZG9tLW1vZHVsZSddO1xuICBmb3IgKHZhciBpID0gMCwgZG9tTW9kdWxlOyBpIDwgZG9tTW9kdWxlcy5sZW5ndGg7IGkrKykge1xuICAgIGRvbU1vZHVsZSA9IGRvbU1vZHVsZXNbaV07XG4gICAgaWYgKGRvbTUuZ2V0QXR0cmlidXRlKGRvbU1vZHVsZSwgJ2lkJykgPT09IGVsZW1lbnQuaXMpIHtcbiAgICAgIGVsZW1lbnQuZG9tTW9kdWxlID0gZG9tTW9kdWxlO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgfVxufVxuXG4vKiogUmVtb3ZlcyByZWR1bmRhbnQgcHJvcGVydGllcyBmcm9tIHRoZSBjb2xsZWN0ZWQgZGVzY3JpcHRvcnMuICovXG5BbmFseXplci5wcm90b3R5cGUuY2xlYW4gPSBmdW5jdGlvbiBjbGVhbigpIHtcbiAgdGhpcy5lbGVtZW50cy5mb3JFYWNoKGRvY3MuY2xlYW5FbGVtZW50KTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gQW5hbHl6ZXI7XG4iXX0= },{"./ast-utils/docs":5,"./ast-utils/import-parse":10,"./ast-utils/js-parse":11,"./loader/file-loader":13,"./loader/fs-resolver":14,"./loader/noop-resolver":15,"./loader/xhr-resolver":17,"dom5":39,"es6-promise":61,"url":27}],2:[function(require,module,exports){ /** * @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'; var esutil = require('./esutil'); var astValue = require('./ast-value'); var analyzeProperties = function(node) { var analyzedProps = []; if (node.type != 'ObjectExpression') { return analyzedProps; } for (var i = 0; i < node.properties.length; i++) { var property = node.properties[i]; var prop = esutil.toPropertyDescriptor(property); prop.published = true; if (property.value.type == 'ObjectExpression') { /** * Parse the expression inside a property object block. * property: { * key: { * type: String, * notify: true, * value: -1, * readOnly: true, * reflectToAttribute: true * } * } */ for (var j = 0; j < property.value.properties.length; j++) { var propertyArg = property.value.properties[j]; var propertyKey = esutil.objectKeyToString(propertyArg.key); switch(propertyKey) { case 'type': { prop.type = esutil.objectKeyToString(propertyArg.value); if (prop.type === undefined) { throw { message: 'Invalid type in property object.', location: propertyArg.loc.start }; } } break; case 'notify': { prop.notify = astValue.expressionToValue(propertyArg.value); if (prop.notify === undefined) prop.notify = astValue.CANT_CONVERT; } break; case 'observer': { prop.observer = astValue.expressionToValue(propertyArg.value); prop.observerNode = propertyArg.value; if (prop.observer === undefined) prop.observer = astValue.CANT_CONVERT; } break; case 'readOnly': { prop.readOnly = astValue.expressionToValue(propertyArg.value); if (prop.readOnly === undefined) prop.readOnly = astValue.CANT_CONVERT; } break; case 'reflectToAttribute': { prop.reflectToAttribute = astValue.expressionToValue(propertyArg); if (prop.reflectToAttribute === undefined) prop.reflectToAttribute = astValue.CANT_CONVERT; } break; case 'value': { prop.default = astValue.expressionToValue(propertyArg.value); if (prop.default === undefined) prop.default = astValue.CANT_CONVERT; } break; default: break; } } } if (!prop.type) { throw { message: 'Unable to determine name for property key.', location: node.loc.start }; } analyzedProps.push(prop); } return analyzedProps; }; module.exports = analyzeProperties; },{"./ast-value":3,"./esutil":7}],3:[function(require,module,exports){ /** * @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'; // useful tool to visualize AST: http://esprima.org/demo/parse.html /** * converts literal: {"type": "Literal", "value": 5, "raw": "5" } * to string */ function literalToValue(literal) { return literal.value; } /** * converts unary to string * unary: { type: 'UnaryExpression', operator: '-', argument: { ... } } */ function unaryToValue(unary) { var argValue = expressionToValue(unary.argument); if (argValue === undefined) return; return unary.operator + argValue; } /** * converts identifier to its value * identifier { "type": "Identifier", "name": "Number } */ function identifierToValue(identifier) { return identifier.name; } /** * Function is a block statement. */ function functionDeclarationToValue(fn) { if (fn.body.type == "BlockStatement") return blockStatementToValue(fn.body); } function functionExpressionToValue(fn) { if (fn.body.type == "BlockStatement") return blockStatementToValue(fn.body); } /** * Block statement: find last return statement, and return its value */ function blockStatementToValue(block) { for (var i=block.body.length - 1; i>= 0; i--) { if (block.body[i].type === "ReturnStatement") return returnStatementToValue(block.body[i]); } } /** * Evaluates return's argument */ function returnStatementToValue(ret) { return expressionToValue(ret.argument); } /** * Enclose containing values in [] */ function arrayExpressionToValue(arry) { var value = '['; for (var i=0; i} The behaviors we've found. */ var behaviors = []; var currentBehavior = null; /** * special-case properties */ var propertyHandlers = { properties: function(node) { var props = analyzeProperties(node); for (var i=0; i < props.length; i++) { currentBehavior.properties.push(props[i]); } } }; /** * merges behavior with preexisting behavior with the same name. * here to support multiple @polymerBehavior tags referring * to same behavior. See iron-multi-selectable for example. */ function mergeBehavior(newBehavior) { var isBehaviorImpl = function(b) { // filter out BehaviorImpl return b.indexOf(newBehavior.is) === -1; }; for (var i=0; i behaviors[i].desc.length) behaviors[i].desc = newBehavior.desc; } else { behaviors[i].desc = newBehavior.desc; } } // merge demos behaviors[i].demos = (behaviors[i].demos || []).concat(newBehavior.demos || []); // merge events, behaviors[i].events = (behaviors[i].events || []).concat(newBehavior.events || []); // merge properties behaviors[i].properties = (behaviors[i].properties || []).concat(newBehavior.properties || []); // merge behaviors behaviors[i].behaviors = (behaviors[i].behaviors || []).concat(newBehavior.behaviors || []) .filter(isBehaviorImpl); return behaviors[i]; } return newBehavior; } /** * gets the expression representing a behavior from a node. */ function behaviorExpression(node) { switch(node.type) { case 'ExpressionStatement': return node.expression.right; case 'VariableDeclaration': return node.declarations.length > 0 ? node.declarations[0].init : null; } } /** * checks whether an expression is a simple array containing only member * expressions or identifiers. */ function isSimpleBehaviorArray(expression) { if (!expression || expression.type !== 'ArrayExpression') return false; for (var i=0; i < expression.elements.length; i++) { if (expression.elements[i].type !== 'MemberExpression' && expression.elements[i].type !== 'Identifier') { return false; } } return true; } var templatizer = "Polymer.Templatizer"; var visitors = { /** * Look for object declarations with @behavior in the docs. */ enterVariableDeclaration: function(node, parent) { if (node.declarations.length !== 1) return; // Ambiguous. this._initBehavior(node, function () { return esutil.objectKeyToString(node.declarations[0].id); }); }, /** * Look for object assignments with @polymerBehavior in the docs. */ enterAssignmentExpression: function(node, parent) { this._initBehavior(parent, function () { return esutil.objectKeyToString(node.left); }); }, _parseChainedBehaviors: function(node) { // if current behavior is part of an array, it gets extended by other behaviors // inside the array. Ex: // Polymer.IronMultiSelectableBehavior = [ {....}, Polymer.IronSelectableBehavior] // We add these to behaviors array var expression = behaviorExpression(node); var chained = []; if (expression && expression.type === 'ArrayExpression') { for (var i=0; i < expression.elements.length; i++) { if (expression.elements[i].type === 'MemberExpression' || expression.elements[i].type === 'Identifier') { chained.push(astValue.expressionToValue(expression.elements[i])); } } if (chained.length > 0) currentBehavior.behaviors = chained; } }, _initBehavior: function(node, getName) { var comment = esutil.getAttachedComment(node); var symbol = getName(); // Quickly filter down to potential candidates. if (!comment || comment.indexOf('@polymerBehavior') === -1) { if (symbol !== templatizer) { return; } } currentBehavior = { type: 'behavior', desc: comment, events: esutil.getEventComments(node).map( function(event) { return { desc: event}; }) }; docs.annotateBehavior(currentBehavior); // Make sure that we actually parsed a behavior tag! if (!jsdoc.hasTag(currentBehavior.jsdoc, 'polymerBehavior') && symbol !== templatizer) { currentBehavior = null; return; } var name = jsdoc.getTag(currentBehavior.jsdoc, 'polymerBehavior', 'name'); currentBehavior.symbol = symbol; if (!name) { name = currentBehavior.symbol; } if (!name) { console.warn('Unable to determine name for @polymerBehavior:', comment); } currentBehavior.is = name; this._parseChainedBehaviors(node); currentBehavior = mergeBehavior(currentBehavior); // Some behaviors are just lists of other behaviors. If this is one then // add it to behaviors right away. if (isSimpleBehaviorArray(behaviorExpression(node))) { // TODO(ajo): Add a test to confirm the presence of `properties`. if (!currentBehavior.properties) currentBehavior.properties = []; if (behaviors.indexOf(currentBehavior) === -1) behaviors.push(currentBehavior); currentBehavior = null; } }, /** * We assume that the object expression after such an assignment is the * behavior's declaration. Seems to be a decent assumption for now. */ enterObjectExpression: function(node, parent) { if (!currentBehavior || currentBehavior.properties) return; currentBehavior.properties = currentBehavior.properties || []; for (var i = 0; i < node.properties.length; i++) { var prop = node.properties[i]; var name = esutil.objectKeyToString(prop.key); if (!name) { throw { message: 'Cant determine name for property key.', location: node.loc.start }; } if (name in propertyHandlers) { propertyHandlers[name](prop.value); } else { currentBehavior.properties.push(esutil.toPropertyDescriptor(prop)); } } behaviors.push(currentBehavior); currentBehavior = null; }, }; return {visitors: visitors, behaviors: behaviors}; }; },{"./analyze-properties":2,"./ast-value.js":3,"./docs":5,"./esutil":7,"./jsdoc":12,"estraverse":73}],5:[function(require,module,exports){ /** * @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 */ 'use strict'; // jshint node:true var jsdoc = require('./jsdoc'); var dom5 = require('dom5'); /** Properties on element prototypes that are purely configuration. */ var ELEMENT_CONFIGURATION = [ 'attached', 'attributeChanged', 'configure', 'constructor', 'created', 'detached', 'enableCustomStyleProperties', 'extends', 'hostAttributes', 'is', 'listeners', 'mixins', 'observers', 'properties', 'ready', 'registered' ]; /** Tags understood by the annotation process, to be removed during `clean`. */ var HANDLED_TAGS = [ 'param', 'return', 'type', ]; /** * Annotates Hydrolysis descriptors, processing any `desc` properties as JSDoc. * * You probably want to use a more specialized version of this, such as * `annotateElement`. * * Processed JSDoc values will be made available via the `jsdoc` property on a * descriptor node. * * @param {Object} descriptor The descriptor node to process. * @return {Object} The descriptor that was given. */ function annotate(descriptor) { if (!descriptor || descriptor.jsdoc) return descriptor; if (typeof descriptor.desc === 'string') { descriptor.jsdoc = jsdoc.parseJsdoc(descriptor.desc); // We want to present the normalized form of a descriptor. descriptor.jsdoc.orig = descriptor.desc; descriptor.desc = descriptor.jsdoc.description; } return descriptor; } /** * Annotates @event, @hero, & @demo tags */ function annotateElementHeader(descriptor) { if (descriptor.events) { descriptor.events.forEach(function(event) { _annotateEvent(event); }); descriptor.events.sort( function(a,b) { return a.name.localeCompare(b.name); }); } descriptor.demos = []; if (descriptor.jsdoc && descriptor.jsdoc.tags) { descriptor.jsdoc.tags.forEach( function(tag) { switch(tag.tag) { case 'hero': descriptor.hero = tag.name || 'hero.png'; break; case 'demo': descriptor.demos.push({ desc: tag.description || 'demo', path: tag.name || 'demo/index.html' }); } }); } } function matchByName(propa, propb) { return propa.name == propb.name; } function copyProperties(from, to, behaviorsByName) { if (from.properties) { from.properties.forEach(function(fromProp){ for (var toProp, i = 0; i < to.properties.length; i++) { toProp = to.properties[i]; if (fromProp.name === toProp.name) { return; } } var newProp = {__fromBehavior: from.is}; if (fromProp.__fromBehavior) { return; } Object.keys(fromProp).forEach(function(propertyField){ newProp[propertyField] = fromProp[propertyField]; }); to.properties.push(newProp); }); } if (!from.behaviors) { return; } from.behaviors.forEach(function(behavior){ var definedBehavior = behaviorsByName[behavior] || behaviorsByName[behavior.symbol]; if (!definedBehavior) { return; } copyProperties(definedBehavior, to, behaviorsByName); }); } function mixinBehaviors(descriptor, behaviorsByName) { if (descriptor.behaviors) { descriptor.behaviors.forEach(function(behavior){ if (!behaviorsByName[behavior]) { console.warn("Behavior " + behavior + " not found!"); return; } var definedBehavior = behaviorsByName[behavior]; copyProperties(definedBehavior, descriptor, behaviorsByName); }); } } /** * Annotates documentation found within a Hydrolysis element descriptor. Also * supports behaviors. * * If the element was processed via `hydrolize`, the element's documentation * will also be extracted via its . * * @param {Object} descriptor The element descriptor. * @return {Object} The descriptor that was given. */ function annotateElement(descriptor, behaviorsByName) { if (!descriptor.desc && descriptor.type === 'element') { descriptor.desc = _findElementDocs(descriptor.is, descriptor.domModule, descriptor.scriptElement); } annotate(descriptor); // The `` is too low level for most needs, and it is _not_ // serializable. So we drop it now that we've extracted all the useful bits // from it. // TODO: Don't worry about serializability here, provide an API to get JSON. delete descriptor.domModule; mixinBehaviors(descriptor, behaviorsByName); // Descriptors that should have their `desc` properties parsed as JSDoc. descriptor.properties.forEach(function(property) { // Feature properties are special, configuration is really just a matter of // inheritance... annotateProperty(property, descriptor.abstract); }); // It may seem like overkill to always sort, but we have an assumption that // these properties are typically being consumed by user-visible tooling. // As such, it's good to have consistent output/ordering to aid the user. descriptor.properties.sort(function(a, b) { // Private properties are always last. if (a.private && !b.private) { return 1; } else if (!a.private && b.private) { return -1; // Otherwise, we're just sorting alphabetically. } else { return a.name.localeCompare(b.name); } }); annotateElementHeader(descriptor); return descriptor; } /** * Annotates behavior descriptor. * @param {Object} descriptor behavior descriptor * @return {Object} descriptor passed in as param */ function annotateBehavior(descriptor, behaviorsByName) { annotate(descriptor); annotateElementHeader(descriptor); return descriptor; } /** * Annotates event documentation */ function _annotateEvent(descriptor) { annotate(descriptor); // process @event var eventTag = jsdoc.getTag(descriptor.jsdoc, 'event'); descriptor.name = eventTag ? eventTag.description : "N/A"; // process @params descriptor.params = (descriptor.jsdoc.tags || []) .filter( function(tag) { return tag.tag === 'param'; }) .map( function(tag) { return { type: tag.type || "N/A", desc: tag.description, name: tag.name || "N/A" }; }); // process @params return descriptor; } /** * Annotates documentation found about a Hydrolysis property descriptor. * * @param {Object} descriptor The property descriptor. * @param {boolean} ignoreConfiguration If true, `configuration` is not set. * @return {Object} The descriptior that was given. */ function annotateProperty(descriptor, ignoreConfiguration) { annotate(descriptor); if (descriptor.name[0] === '_' || jsdoc.hasTag(descriptor.jsdoc, 'private')) { descriptor.private = true; } if (!ignoreConfiguration && ELEMENT_CONFIGURATION.indexOf(descriptor.name) !== -1) { descriptor.private = true; descriptor.configuration = true; } // @type JSDoc wins descriptor.type = jsdoc.getTag(descriptor.jsdoc, 'type', 'type') || descriptor.type; if (descriptor.type.match(/^function/i)) { _annotateFunctionProperty(descriptor); } // @default JSDoc wins var defaultTag = jsdoc.getTag(descriptor.jsdoc, 'default'); if (defaultTag !== null) { var newDefault = (defaultTag.name || '') + (defaultTag.description || ''); if (newDefault !== '') { descriptor.default = newDefault; } } return descriptor; } /** @param {Object} descriptor */ function _annotateFunctionProperty(descriptor) { descriptor.function = true; var returnTag = jsdoc.getTag(descriptor.jsdoc, 'return'); if (returnTag) { descriptor.return = { type: returnTag.type, desc: returnTag.description, }; } var paramsByName = {}; (descriptor.params || []).forEach(function(param) { paramsByName[param.name] = param; }); (descriptor.jsdoc && descriptor.jsdoc.tags || []).forEach(function(tag) { if (tag.tag !== 'param') return; var param = paramsByName[tag.name]; if (!param) { return; } param.type = tag.type || param.type; param.desc = tag.description; }); } /** * Converts raw features into an abstract `Polymer.Base` element. * * Note that docs on this element _are not processed_. You must call * `annotateElement` on it yourself if you wish that. * * @param {Array} features * @return {ElementDescriptor} */ function featureElement(features) { var properties = features.reduce(function(result, feature) { return result.concat(feature.properties); }, []); return { type: 'element', is: 'Polymer.Base', abstract: true, properties: properties, desc: '`Polymer.Base` acts as a base prototype for all Polymer ' + 'elements. It is composed via various calls to ' + '`Polymer.Base._addFeature()`.\n' + '\n' + 'The properties reflected here are the combined view of all ' + 'features found in this library. There may be more properties ' + 'added via other libraries, as well.', }; } /** * Cleans redundant properties from a descriptor, assuming that you have already * called `annotate`. * * @param {Object} descriptor */ function clean(descriptor) { if (!descriptor.jsdoc) return; // The doctext was written to `descriptor.desc` delete descriptor.jsdoc.description; delete descriptor.jsdoc.orig; var cleanTags = []; (descriptor.jsdoc.tags || []).forEach(function(tag) { // Drop any tags we've consumed. if (HANDLED_TAGS.indexOf(tag.tag) !== -1) return; cleanTags.push(tag); }); if (cleanTags.length === 0) { // No tags? no docs left! delete descriptor.jsdoc; } else { descriptor.jsdoc.tags = cleanTags; } } /** * Cleans redundant properties from an element, assuming that you have already * called `annotateElement`. * * @param {ElementDescriptor|BehaviorDescriptor} element */ function cleanElement(element) { clean(element); element.properties.forEach(cleanProperty); } /** * Cleans redundant properties from a property, assuming that you have already * called `annotateProperty`. * * @param {PropertyDescriptor} property */ function cleanProperty(property) { clean(property); } /** * Parse elements defined only in comments. * @param {comments} Array A list of comments to parse. * @return {ElementDescriptor} A list of pseudo-elements. */ function parsePseudoElements(comments) { var elements = []; comments.forEach(function(comment) { var parsed = jsdoc.parseJsdoc(comment); var pseudoTag = jsdoc.getTag(parsed, 'pseudoElement', 'name'); if (pseudoTag) { parsed.is = pseudoTag; parsed.jsdoc = {description: parsed.description, tags: parsed.tags}; parsed.properties = []; parsed.desc = parsed.description; parsed.description = undefined; parsed.tags = undefined; annotateElementHeader(parsed); elements.push(parsed); } }); return elements; } /** * @param {string} elementId * @param {DocumentAST} domModule * @param {DocumentAST} scriptElement The script that the element was defined in. */ function _findElementDocs(elementId, domModule, scriptElement) { // Note that we concatenate docs from all sources if we find them. // element can be defined in: // html comment right before dom-module // html commnet right before script defining the module, if dom-module is empty var found = []; // Do we have a HTML comment on the `` or `