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.stack; 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+fVxuICAgKi9cbiAgdGhpcy5odG1sID0ge307XG5cbiAgLyoqXG4gICAqIEEgbWFwLCBrZXllZCBieSBwYXRoLCBvZiBIVE1MIGRvY3VtZW50IEFTVHMuXG4gICAqIEB0eXBlIHtPYmplY3R9XG4gICAqL1xuICB0aGlzLnBhcnNlZERvY3VtZW50cyA9IHt9O1xuXG4gIC8qKlxuICAgKiBBIG1hcCwga2V5ZWQgYnkgcGF0aCwgb2YgSlMgc2NyaXB0IEFTVHMuXG4gICAqXG4gICAqIElmIHRoZSBwYXRoIGlzIGFuIEhUTUwgZmlsZSB3aXRoIG11bHRpcGxlIHNjcmlwdHMsIHRoZSBlbnRyeSB3aWxsIGJlIGFuIGFycmF5IG9mIHNjcmlwdHMuXG4gICAqXG4gICAqIEB0eXBlIHtPYmplY3Q8c3RyaW5nLEFycmF5PFBhcnNlZEpTPj59XG4gICAqL1xuICB0aGlzLnBhcnNlZFNjcmlwdHMgPSB7fTtcblxuXG5cbiAgLyoqXG4gICAqIEEgbWFwLCBrZXllZCBieSBwYXRoLCBvZiBkb2N1bWVudCBjb250ZW50LlxuICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgKi9cbiAgdGhpcy5fY29udGVudCA9IHt9O1xufTtcblxuLyoqXG4gKiBPcHRpb25zIGZvciBgQW5hbHl6ZXIuYW5hbHp5ZWBcbiAqIEB0eXBlZGVmIHtPYmplY3R9IExvYWRPcHRpb25zXG4gKiBAbWVtYmVyb2YgaHlkcm9seXNpc1xuICogQHByb3BlcnR5IHtib29sZWFufSBub0Fubm90YXRpb25zIFdoZXRoZXIgYGFubm90YXRlKClgIHNob3VsZCBiZSBza2lwcGVkLlxuICogQHByb3BlcnR5IHtib29sZWFufSBjbGVhbiBXaGV0aGVyIHRoZSBnZW5lcmF0ZWQgZGVzY3JpcHRvcnMgc2hvdWxkIGJlIGNsZWFuZWRcbiAqICAgICBvZiByZWR1bmRhbnQgZGF0YS5cbiAqIEBwcm9wZXJ0eSB7ZnVuY3Rpb24oc3RyaW5nKTogYm9vbGVhbn0gZmlsdGVyIEEgcHJlZGljYXRlIGZ1bmN0aW9uIHRoYXRcbiAqICAgICBpbmRpY2F0ZXMgd2hpY2ggZmlsZXMgc2hvdWxkIGJlIGlnbm9yZWQgYnkgdGhlIGxvYWRlci4gQnkgZGVmYXVsdCBhbGxcbiAqICAgICBmaWxlcyBub3QgbG9jYXRlZCB1bmRlciB0aGUgZGlybmFtZSBvZiBgaHJlZmAgd2lsbCBiZSBpZ25vcmVkLlxuICovXG5cbi8qKlxuICogU2hvcnRoYW5kIGZvciB0cmFuc2l0aXZlbHkgbG9hZGluZyBhbmQgcHJvY2Vzc2luZyBhbGwgaW1wb3J0cyBiZWdpbm5pbmcgYXRcbiAqIGBocmVmYC5cbiAqXG4gKiBJbiBvcmRlciB0byBwcm9wZXJseSBmaWx0ZXIgcGF0aHMsIGBocmVmYCBfbXVzdF8gYmUgYW4gYWJzb2x1dGUgVVJJLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBocmVmIFRoZSByb290IGltcG9ydCB0byBiZWdpbiBsb2FkaW5nIGZyb20uXG4gKiBAcGFyYW0ge0xvYWRPcHRpb25zPX0gb3B0aW9ucyBBbnkgYWRkaXRpb25hbCBvcHRpb25zIGZvciB0aGUgbG9hZC5cbiAqIEByZXR1cm4ge1Byb21pc2U8QW5hbHl6ZXI+fSBBIHByb21pc2UgdGhhdCB3aWxsIHJlc29sdmUgb25jZSBgaHJlZmAgYW5kIGl0c1xuICogICAgIGRlcGVuZGVuY2llcyBoYXZlIGJlZW4gbG9hZGVkIGFuZCBhbmFseXplZC5cbiAqL1xuQW5hbHl6ZXIuYW5hbHl6ZSA9IGZ1bmN0aW9uIGFuYWx5emUoaHJlZiwgb3B0aW9ucykge1xuICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgb3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmZpbHRlciB8fCBfZGVmYXVsdEZpbHRlcihocmVmKTtcblxuICB2YXIgbG9hZGVyID0gbmV3IEZpbGVMb2FkZXIoKTtcbiAgdmFyIFByaW1hcnlSZXNvbHZlciA9IHR5cGVvZiB3aW5kb3cgPT09ICd1bmRlZmluZWQnID9cbiAgICAgICAgICAgICAgICAgICAgICAgIHJlcXVpcmUoJy4vbG9hZGVyL2ZzLXJlc29sdmVyJykgOlxuICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZSgnLi9sb2FkZXIveGhyLXJlc29sdmVyJyk7XG4gIGxvYWRlci5hZGRSZXNvbHZlcihuZXcgUHJpbWFyeVJlc29sdmVyKG9wdGlvbnMpKTtcbiAgbG9hZGVyLmFkZFJlc29sdmVyKG5ldyBOb29wUmVzb2x2ZXIoe3Rlc3Q6IG9wdGlvbnMuZmlsdGVyfSkpO1xuXG4gIHZhciBhbmFseXplciA9IG5ldyB0aGlzKG51bGwsIGxvYWRlcik7XG4gIHJldHVybiBhbmFseXplci5tZXRhZGF0YVRyZWUoaHJlZikudGhlbihmdW5jdGlvbihyb290KSB7XG4gICAgaWYgKCFvcHRpb25zLm5vQW5ub3RhdGlvbnMpIHtcbiAgICAgIGFuYWx5emVyLmFubm90YXRlKCk7XG4gICAgfVxuICAgIGlmIChvcHRpb25zLmNsZWFuKSB7XG4gICAgICBhbmFseXplci5jbGVhbigpO1xuICAgIH1cbiAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKGFuYWx5emVyKTtcbiAgfSk7XG59O1xuXG4vKipcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0ge3N0cmluZ30gaHJlZlxuICogQHJldHVybiB7ZnVuY3Rpb24oc3RyaW5nKTogYm9vbGVhbn1cbiAqL1xuZnVuY3Rpb24gX2RlZmF1bHRGaWx0ZXIoaHJlZikge1xuICAvLyBFdmVyeXRoaW5nIHVwIHRvIHRoZSBsYXN0IGAvYCBvciBgXFxgLlxuICB2YXIgYmFzZSA9IGhyZWYubWF0Y2goL14oLio/KVteXFwvXFxcXF0qJC8pWzFdO1xuICByZXR1cm4gZnVuY3Rpb24odXJpKSB7XG4gICAgcmV0dXJuIHVyaS5pbmRleE9mKGJhc2UpICE9PSAwO1xuICB9O1xufVxuXG5BbmFseXplci5wcm90b3R5cGUubG9hZCA9IGZ1bmN0aW9uIGxvYWQoaHJlZikge1xuICByZXR1cm4gdGhpcy5sb2FkZXIucmVxdWVzdChocmVmKS50aGVuKGZ1bmN0aW9uKGNvbnRlbnQpIHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24ocmVzb2x2ZSwgcmVqZWN0KSB7XG4gICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgICAgICB0aGlzLl9jb250ZW50W2hyZWZdID0gY29udGVudDtcbiAgICAgICAgcmVzb2x2ZSh0aGlzLl9wYXJzZUhUTUwoY29udGVudCwgaHJlZikpO1xuICAgICAgfS5iaW5kKHRoaXMpLCAwKTtcbiAgICB9LmJpbmQodGhpcykpLmNhdGNoKGZ1bmN0aW9uKGVycil7XG4gICAgICBjb25zb2xlLmVycm9yKFwiRXJyb3IgcHJvY2Vzc2luZyBkb2N1bWVudCBhdCBcIiArIGhyZWYpO1xuICAgICAgdGhyb3cgZXJyO1xuICAgIH0pO1xuICB9LmJpbmQodGhpcykpO1xufTtcblxuLyoqXG4gKiBSZXR1cm5zIGFuIGBBbmFseXplZERvY3VtZW50YCByZXByZXNlbnRpbmcgdGhlIHByb3ZpZGVkIGRvY3VtZW50XG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtICB7c3RyaW5nfSBodG1sSW1wb3J0IFJhdyB0ZXh0IG9mIGFuIEhUTUwgZG9jdW1lbnRcbiAqIEBwYXJhbSAge3N0cmluZ30gaHJlZiAgICAgICBUaGUgZG9jdW1lbnQncyBVUkwuXG4gKiBAcmV0dXJuIHtBbmFseXplZERvY3VtZW50fSAgICAgICBBbiAgYEFuYWx5emVkRG9jdW1lbnRgXG4gKi9cbkFuYWx5emVyLnByb3RvdHlwZS5fcGFyc2VIVE1MID0gZnVuY3Rpb24gX3BhcnNlSFRNTChodG1sSW1wb3J0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBocmVmKSB7XG4gIGlmIChocmVmIGluIHRoaXMuaHRtbCkge1xuICAgIHJldHVybiB0aGlzLmh0bWxbaHJlZl07XG4gIH1cbiAgdmFyIGRlcHNMb2FkZWQgPSBbXTtcbiAgdmFyIGRlcEhyZWZzID0gW107XG4gIHZhciBtZXRhZGF0YUxvYWRlZCA9IFByb21pc2UucmVzb2x2ZShFTVBUWV9NRVRBREFUQSk7XG4gIHZhciBwYXJzZWQ7XG4gIHRyeSB7XG4gICAgcGFyc2VkID0gaW1wb3J0UGFyc2UoaHRtbEltcG9ydCwgaHJlZik7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGNvbnNvbGUuZXJyb3IoJ0Vycm9yIHBhcnNpbmchJyk7XG4gICAgdGhyb3cgZXJyO1xuICB9XG4gIHZhciBodG1sTG9hZGVkID0gUHJvbWlzZS5yZXNvbHZlKHBhcnNlZCk7XG4gIGlmIChwYXJzZWQuc2NyaXB0KSB7XG4gICAgbWV0YWRhdGFMb2FkZWQgPSB0aGlzLl9wcm9jZXNzU2NyaXB0cyhwYXJzZWQuc2NyaXB0LCBocmVmKTtcbiAgfVxuICB2YXIgY29tbWVudFRleHQgPSBwYXJzZWQuY29tbWVudC5tYXAoZnVuY3Rpb24oY29tbWVudCl7XG4gICAgcmV0dXJuIGRvbTUuZ2V0VGV4dENvbnRlbnQoY29tbWVudCk7XG4gIH0pO1xuICB2YXIgcHNldWRvRWxlbWVudHMgPSBkb2NzLnBhcnNlUHNldWRvRWxlbWVudHMoY29tbWVudFRleHQpO1xuICBwc2V1ZG9FbGVtZW50cy5mb3JFYWNoKGZ1bmN0aW9uKGVsZW1lbnQpe1xuICAgIGVsZW1lbnQuY29udGVudEhyZWYgPSBocmVmO1xuICAgIHRoaXMuZWxlbWVudHMucHVzaChlbGVtZW50KTtcbiAgICB0aGlzLmVsZW1lbnRzQnlUYWdOYW1lW2VsZW1lbnQuaXNdID0gZWxlbWVudDtcbiAgfS5iaW5kKHRoaXMpKTtcbiAgbWV0YWRhdGFMb2FkZWQgPSBtZXRhZGF0YUxvYWRlZC50aGVuKGZ1bmN0aW9uKG1ldGFkYXRhKXtcbiAgICB2YXIgbWV0YWRhdGFFbnRyeSA9IHtcbiAgICAgIGVsZW1lbnRzOiBwc2V1ZG9FbGVtZW50cyxcbiAgICAgIGZlYXR1cmVzOiBbXSxcbiAgICAgIGJlaGF2aW9yczogW11cbiAgICB9O1xuICAgIHJldHVybiBbbWV0YWRhdGEsIG1ldGFkYXRhRW50cnldLnJlZHVjZShyZWR1Y2VNZXRhZGF0YSk7XG4gIH0pO1xuICBkZXBzTG9hZGVkLnB1c2gobWV0YWRhdGFMb2FkZWQpO1xuXG5cbiAgaWYgKHRoaXMubG9hZGVyKSB7XG4gICAgdmFyIGJhc2VVcmkgPSBocmVmO1xuICAgIGlmIChwYXJzZWQuYmFzZS5sZW5ndGggPiAxKSB7XG4gICAgICBjb25zb2xlLmVycm9yKFwiT25seSBvbmUgYmFzZSB0YWcgcGVyIGRvY3VtZW50IVwiKTtcbiAgICAgIHRocm93IFwiTXVsdGlwbGUgYmFzZSB0YWdzIGluIFwiICsgaHJlZjtcbiAgICB9IGVsc2UgaWYgKHBhcnNlZC5iYXNlLmxlbmd0aCA9PSAxKSB7XG4gICAgICB2YXIgYmFzZUhyZWYgPSBkb201LmdldEF0dHJpYnV0ZShwYXJzZWQuYmFzZVswXSwgXCJocmVmXCIpO1xuICAgICAgaWYgKGJhc2VIcmVmKSB7XG4gICAgICAgIGJhc2VIcmVmID0gYmFzZUhyZWYgKyBcIi9cIjtcbiAgICAgICAgYmFzZVVyaSA9IHVybC5yZXNvbHZlKGJhc2VVcmksIGJhc2VIcmVmKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcGFyc2VkLmltcG9ydC5mb3JFYWNoKGZ1bmN0aW9uKGxpbmspIHtcbiAgICAgIHZhciBsaW5rdXJsID0gZG9tNS5nZXRBdHRyaWJ1dGUobGluaywgJ2hyZWYnKTtcbiAgICAgIGlmIChsaW5rdXJsKSB7XG4gICAgICAgIHZhciByZXNvbHZlZFVybCA9IHVybC5yZXNvbHZlKGJhc2VVcmksIGxpbmt1cmwpO1xuICAgICAgICBkZXBIcmVmcy5wdXNoKHJlc29sdmVkVXJsKTtcbiAgICAgICAgZGVwc0xvYWRlZC5wdXNoKHRoaXMuX2RlcGVuZGVuY2llc0xvYWRlZEZvcihyZXNvbHZlZFVybCwgaHJlZikpO1xuICAgICAgfVxuICAgIH0uYmluZCh0aGlzKSk7XG4gICAgcGFyc2VkLnN0eWxlLmZvckVhY2goZnVuY3Rpb24oc3R5bGVFbGVtZW50KSB7XG4gICAgICBpZiAocG9seW1lckV4dGVybmFsU3R5bGUoc3R5bGVFbGVtZW50KSkge1xuICAgICAgICB2YXIgc3R5bGVIcmVmID0gZG9tNS5nZXRBdHRyaWJ1dGUoc3R5bGVFbGVtZW50LCAnaHJlZicpO1xuICAgICAgICBpZiAoaHJlZikge1xuICAgICAgICAgIHN0eWxlSHJlZiA9IHVybC5yZXNvbHZlKGJhc2VVcmksIHN0eWxlSHJlZik7XG4gICAgICAgICAgZGVwc0xvYWRlZC5wdXNoKHRoaXMubG9hZGVyLnJlcXVlc3Qoc3R5bGVIcmVmKS50aGVuKGZ1bmN0aW9uKGNvbnRlbnQpe1xuICAgICAgICAgICAgdGhpcy5fY29udGVudFtzdHlsZUhyZWZdID0gY29udGVudDtcbiAgICAgICAgICB9LmJpbmQodGhpcykpKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0uYmluZCh0aGlzKSk7XG4gIH1cbiAgZGVwc0xvYWRlZCA9IFByb21pc2UuYWxsKGRlcHNMb2FkZWQpXG4gICAgICAgIC50aGVuKGZ1bmN0aW9uKCkge3JldHVybiBkZXBIcmVmczt9KVxuICAgICAgICAuY2F0Y2goZnVuY3Rpb24oZXJyKSB7dGhyb3cgZXJyO30pO1xuICB0aGlzLnBhcnNlZERvY3VtZW50c1tocmVmXSA9IHBhcnNlZC5hc3Q7XG4gIHRoaXMuaHRtbFtocmVmXSA9IHtcbiAgICAgIGhyZWY6IGhyZWYsXG4gICAgICBodG1sTG9hZGVkOiBodG1sTG9hZGVkLFxuICAgICAgbWV0YWRhdGFMb2FkZWQ6IG1ldGFkYXRhTG9hZGVkLFxuICAgICAgZGVwSHJlZnM6IGRlcEhyZWZzLFxuICAgICAgZGVwc0xvYWRlZDogZGVwc0xvYWRlZFxuICB9O1xuICByZXR1cm4gdGhpcy5odG1sW2hyZWZdO1xufTtcblxuQW5hbHl6ZXIucHJvdG90eXBlLl9wcm9jZXNzU2NyaXB0cyA9IGZ1bmN0aW9uIF9wcm9jZXNzU2NyaXB0cyhzY3JpcHRzLCBocmVmKSB7XG4gIHZhciBzY3JpcHRQcm9taXNlcyA9IFtdO1xuICBzY3JpcHRzLmZvckVhY2goZnVuY3Rpb24oc2NyaXB0KSB7XG4gICAgc2NyaXB0UHJvbWlzZXMucHVzaCh0aGlzLl9wcm9jZXNzU2NyaXB0KHNjcmlwdCwgaHJlZikpO1xuICB9LmJpbmQodGhpcykpO1xuICByZXR1cm4gUHJvbWlzZS5hbGwoc2NyaXB0UHJvbWlzZXMpLnRoZW4oZnVuY3Rpb24obWV0YWRhdGFMaXN0KSB7XG4gICAgcmV0dXJuIG1ldGFkYXRhTGlzdC5yZWR1Y2UocmVkdWNlTWV0YWRhdGEsIEVNUFRZX01FVEFEQVRBKTtcbiAgfSk7XG59O1xuXG5BbmFseXplci5wcm90b3R5cGUuX3Byb2Nlc3NTY3JpcHQgPSBmdW5jdGlvbiBfcHJvY2Vzc1NjcmlwdChzY3JpcHQsIGhyZWYpIHtcbiAgdmFyIHNyYyA9IGRvbTUuZ2V0QXR0cmlidXRlKHNjcmlwdCwgJ3NyYycpO1xuICB2YXIgcGFyc2VkSnM7XG4gIGlmICghc3JjKSB7XG4gICAgdHJ5IHtcbiAgICAgIHBhcnNlZEpzID0ganNQYXJzZSgoc2NyaXB0LmNoaWxkTm9kZXMubGVuZ3RoKSA/IHNjcmlwdC5jaGlsZE5vZGVzWzBdLnZhbHVlIDogJycpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgLy8gRmlndXJlIG91dCB0aGUgY29ycmVjdCBsaW5lIG51bWJlciBmb3IgdGhlIGVycm9yLlxuICAgICAgdmFyIGxpbmUgPSAwO1xuICAgICAgdmFyIGNvbCA9IDA7XG4gICAgICBpZiAoc2NyaXB0Ll9fb3duZXJEb2N1bWVudCAmJiBzY3JpcHQuX19vd25lckRvY3VtZW50ID09IGhyZWYpIHtcbiAgICAgICAgbGluZSA9IHNjcmlwdC5fX2xvY2F0aW9uRGV0YWlsLmxpbmUgLSAxO1xuICAgICAgICBjb2wgPSBzY3JpcHQuX19sb2NhdGlvbkRldGFpbC5saW5lIC0gMTtcbiAgICAgIH1cbiAgICAgIGxpbmUgKz0gZXJyLmxpbmVOdW1iZXI7XG4gICAgICBjb2wgKz0gZXJyLmNvbHVtbjtcbiAgICAgIHZhciBtZXNzYWdlID0gXCJFcnJvciBwYXJzaW5nIHNjcmlwdCBpbiBcIiArIGhyZWYgKyBcIiBhdCBcIiArIGxpbmUgKyBcIjpcIiArIGNvbDtcbiAgICAgIG1lc3NhZ2UgKz0gXCJcXG5cIiArIGVyci5zdGFjaztcbiAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChuZXcgRXJyb3IobWVzc2FnZSkpO1xuICAgIH1cbiAgICBpZiAocGFyc2VkSnMuZWxlbWVudHMpIHtcbiAgICAgIHBhcnNlZEpzLmVsZW1lbnRzLmZvckVhY2goZnVuY3Rpb24oZWxlbWVudCkge1xuICAgICAgICBlbGVtZW50LnNjcmlwdEVsZW1lbnQgPSBzY3JpcHQ7XG4gICAgICAgIGVsZW1lbnQuY29udGVudEhyZWYgPSBocmVmO1xuICAgICAgICB0aGlzLmVsZW1lbnRzLnB1c2goZWxlbWVudCk7XG4gICAgICAgIGlmIChlbGVtZW50LmlzIGluIHRoaXMuZWxlbWVudHNCeVRhZ05hbWUpIHtcbiAgICAgICAgICBjb25zb2xlLndhcm4oJ0lnbm9yaW5nIGR1cGxpY2F0ZSBlbGVtZW50IGRlZmluaXRpb246ICcgKyBlbGVtZW50LmlzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLmVsZW1lbnRzQnlUYWdOYW1lW2VsZW1lbnQuaXNdID0gZWxlbWVudDtcbiAgICAgICAgfVxuICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICB9XG4gICAgaWYgKHBhcnNlZEpzLmZlYXR1cmVzKSB7XG4gICAgICBwYXJzZWRKcy5mZWF0dXJlcy5mb3JFYWNoKGZ1bmN0aW9uKGZlYXR1cmUpe1xuICAgICAgICBmZWF0dXJlLmNvbnRlbnRIcmVmID0gaHJlZjtcbiAgICAgICAgZmVhdHVyZS5zY3JpcHRFbGVtZW50ID0gc2NyaXB0O1xuICAgICAgfSk7XG4gICAgICB0aGlzLmZlYXR1cmVzID0gdGhpcy5mZWF0dXJlcy5jb25jYXQocGFyc2VkSnMuZmVhdHVyZXMpO1xuICAgIH1cbiAgICBpZiAocGFyc2VkSnMuYmVoYXZpb3JzKSB7XG4gICAgICBwYXJzZWRKcy5iZWhhdmlvcnMuZm9yRWFjaChmdW5jdGlvbihiZWhhdmlvcil7XG4gICAgICAgIGJlaGF2aW9yLmNvbnRlbnRIcmVmID0gaHJlZjtcbiAgICAgICAgdGhpcy5iZWhhdmlvcnNCeU5hbWVbYmVoYXZpb3IuaXNdID0gYmVoYXZpb3I7XG4gICAgICAgIHRoaXMuYmVoYXZpb3JzQnlOYW1lW2JlaGF2aW9yLnN5bWJvbF0gPSBiZWhhdmlvcjtcbiAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgICB0aGlzLmJlaGF2aW9ycyA9IHRoaXMuYmVoYXZpb3JzLmNvbmNhdChwYXJzZWRKcy5iZWhhdmlvcnMpO1xuICAgIH1cbiAgICBpZiAoIU9iamVjdC5oYXNPd25Qcm9wZXJ0eS5jYWxsKHRoaXMucGFyc2VkU2NyaXB0cywgaHJlZikpIHtcbiAgICAgIHRoaXMucGFyc2VkU2NyaXB0c1tocmVmXSA9IFtdO1xuICAgIH1cbiAgICB2YXIgc2NyaXB0RWxlbWVudDtcbiAgICBpZiAoc2NyaXB0Ll9fb3duZXJEb2N1bWVudCAmJiBzY3JpcHQuX19vd25lckRvY3VtZW50ID09IGhyZWYpIHtcbiAgICAgIHNjcmlwdEVsZW1lbnQgPSBzY3JpcHQ7XG4gICAgfVxuICAgIHRoaXMucGFyc2VkU2NyaXB0c1tocmVmXS5wdXNoKHtcbiAgICAgIGFzdDogcGFyc2VkSnMucGFyc2VkU2NyaXB0LFxuICAgICAgc2NyaXB0RWxlbWVudDogc2NyaXB0RWxlbWVudFxuICAgIH0pO1xuICAgIHJldHVybiBwYXJzZWRKcztcbiAgfVxuICBpZiAodGhpcy5sb2FkZXIpIHtcbiAgICB2YXIgcmVzb2x2ZWRTcmMgPSB1cmwucmVzb2x2ZShocmVmLCBzcmMpO1xuICAgIHJldHVybiB0aGlzLmxvYWRlci5yZXF1ZXN0KHJlc29sdmVkU3JjKS50aGVuKGZ1bmN0aW9uKGNvbnRlbnQpIHtcbiAgICAgIHRoaXMuX2NvbnRlbnRbcmVzb2x2ZWRTcmNdID0gY29udGVudDtcbiAgICAgIHZhciByZXNvbHZlZFNjcmlwdCA9IE9iamVjdC5jcmVhdGUoc2NyaXB0KTtcbiAgICAgIHJlc29sdmVkU2NyaXB0LmNoaWxkTm9kZXMgPSBbe3ZhbHVlOiBjb250ZW50fV07XG4gICAgICByZXNvbHZlZFNjcmlwdC5hdHRycyA9IHJlc29sdmVkU2NyaXB0LmF0dHJzLnNsaWNlKCk7XG4gICAgICBkb201LnJlbW92ZUF0dHJpYnV0ZShyZXNvbHZlZFNjcmlwdCwgJ3NyYycpO1xuICAgICAgcmV0dXJuIHRoaXMuX3Byb2Nlc3NTY3JpcHQocmVzb2x2ZWRTY3JpcHQsIHJlc29sdmVkU3JjKTtcbiAgICB9LmJpbmQodGhpcykpLmNhdGNoKGZ1bmN0aW9uKGVycikge3Rocm93IGVycjt9KTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKEVNUFRZX01FVEFEQVRBKTtcbiAgfVxufTtcblxuQW5hbHl6ZXIucHJvdG90eXBlLl9kZXBlbmRlbmNpZXNMb2FkZWRGb3IgPSBmdW5jdGlvbiBfZGVwZW5kZW5jaWVzTG9hZGVkRm9yKGhyZWYsIHJvb3QpIHtcbiAgdmFyIGZvdW5kID0ge307XG4gIGlmIChyb290ICE9PSB1bmRlZmluZWQpIHtcbiAgICBmb3VuZFtyb290XSA9IHRydWU7XG4gIH1cbiAgcmV0dXJuIHRoaXMuX2dldERlcGVuZGVuY2llcyhocmVmLCBmb3VuZCkudGhlbihmdW5jdGlvbihkZXBzKSB7XG4gICAgdmFyIGRlcE1ldGFkYXRhTG9hZGVkID0gW107XG4gICAgdmFyIGRlcFByb21pc2VzID0gZGVwcy5tYXAoZnVuY3Rpb24oZGVwSHJlZil7XG4gICAgICByZXR1cm4gdGhpcy5sb2FkKGRlcEhyZWYpLnRoZW4oZnVuY3Rpb24oaHRtbE1vbm9tZXIpIHtcbiAgICAgICAgcmV0dXJuIGh0bWxNb25vbWVyLm1ldGFkYXRhTG9hZGVkO1xuICAgICAgfSk7XG4gICAgfS5iaW5kKHRoaXMpKTtcbiAgICByZXR1cm4gUHJvbWlzZS5hbGwoZGVwUHJvbWlzZXMpO1xuICB9LmJpbmQodGhpcykpO1xufTtcblxuLyoqXG4gKiBMaXN0IGFsbCB0aGUgaHRtbCBkZXBlbmRlbmNpZXMgZm9yIHRoZSBkb2N1bWVudCBhdCBgaHJlZmAuXG4gKiBAcGFyYW0gIHtzdHJpbmd9ICAgICAgICAgICAgICAgICAgIGhyZWYgICAgICBUaGUgaHJlZiB0byBnZXQgZGVwZW5kZW5jaWVzIGZvci5cbiAqIEBwYXJhbSAge09iamVjdC48c3RyaW5nLGJvb2xlYW4+PX0gZm91bmQgICAgIEFuIG9iamVjdCBrZXllZCBieSBVUkwgb2YgdGhlXG4gKiAgICAgYWxyZWFkeSByZXNvbHZlZCBkZXBlbmRlbmNpZXMuXG4gKiBAcGFyYW0gIHtib29sZWFuPX0gICAgICAgICAgICAgICAgdHJhbnNpdGl2ZSBXaGV0aGVyIHRvIGxvYWQgdHJhbnNpdGl2ZVxuICogICAgIGRlcGVuZGVuY2llcy4gRGVmYXVsdHMgdG8gdHJ1ZS5cbiAqIEByZXR1cm4ge0FycmF5LjxzdHJpbmc+fSAgQSBsaXN0IG9mIGFsbCB0aGUgaHRtbCBkZXBlbmRlbmNpZXMuXG4gKi9cbkFuYWx5emVyLnByb3RvdHlwZS5fZ2V0RGVwZW5kZW5jaWVzID0gZnVuY3Rpb24gX2dldERlcGVuZGVuY2llcyhocmVmLCBmb3VuZCwgdHJhbnNpdGl2ZSkge1xuICBpZiAoZm91bmQgPT09IHVuZGVmaW5lZCkge1xuICAgIGZvdW5kID0ge307XG4gICAgZm91bmRbaHJlZl0gPSB0cnVlO1xuICB9XG4gIGlmICh0cmFuc2l0aXZlID09PSB1bmRlZmluZWQpIHtcbiAgICB0cmFuc2l0aXZlID0gdHJ1ZTtcbiAgfVxuICB2YXIgZGVwcyA9IFtdO1xuICByZXR1cm4gdGhpcy5sb2FkKGhyZWYpLnRoZW4oZnVuY3Rpb24oaHRtbE1vbm9tZXIpIHtcbiAgICB2YXIgdHJhbnNpdGl2ZURlcHMgPSBbXTtcbiAgICBodG1sTW9ub21lci5kZXBIcmVmcy5mb3JFYWNoKGZ1bmN0aW9uKGRlcEhyZWYpe1xuICAgICAgaWYgKGZvdW5kW2RlcEhyZWZdKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGRlcHMucHVzaChkZXBIcmVmKTtcbiAgICAgIGZvdW5kW2RlcEhyZWZdID0gdHJ1ZTtcbiAgICAgIGlmICh0cmFuc2l0aXZlKSB7XG4gICAgICAgIHRyYW5zaXRpdmVEZXBzLnB1c2godGhpcy5fZ2V0RGVwZW5kZW5jaWVzKGRlcEhyZWYsIGZvdW5kKSk7XG4gICAgICB9XG4gICAgfS5iaW5kKHRoaXMpKTtcbiAgICByZXR1cm4gUHJvbWlzZS5hbGwodHJhbnNpdGl2ZURlcHMpO1xuICB9LmJpbmQodGhpcykpLnRoZW4oZnVuY3Rpb24odHJhbnNpdGl2ZURlcHMpIHtcbiAgICB2YXIgYWxsZGVwcyA9IHRyYW5zaXRpdmVEZXBzLnJlZHVjZShmdW5jdGlvbihhLCBiKSB7XG4gICAgICByZXR1cm4gYS5jb25jYXQoYik7XG4gICAgfSwgW10pLmNvbmNhdChkZXBzKTtcbiAgICByZXR1cm4gYWxsZGVwcztcbiAgfSk7XG59O1xuXG5mdW5jdGlvbiBtYXRjaGVzRG9jdW1lbnRGb2xkZXIoZGVzY3JpcHRvciwgaHJlZikge1xuICBpZiAoIWRlc2NyaXB0b3IuY29udGVudEhyZWYpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgdmFyIGRlc2NyaXB0b3JEb2MgPSB1cmwucGFyc2UoZGVzY3JpcHRvci5jb250ZW50SHJlZik7XG4gIGlmICghZGVzY3JpcHRvckRvYyB8fCAhZGVzY3JpcHRvckRvYy5wYXRobmFtZSkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICB2YXIgc2VhcmNoRG9jID0gdXJsLnBhcnNlKGhyZWYpO1xuICBpZiAoIXNlYXJjaERvYyB8fCAhc2VhcmNoRG9jLnBhdGhuYW1lKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIHZhciBzZWFyY2hQYXRoID0gc2VhcmNoRG9jLnBhdGhuYW1lO1xuICB2YXIgbGFzdFNsYXNoID0gc2VhcmNoUGF0aC5sYXN0SW5kZXhPZihcIi9cIik7XG4gIGlmIChsYXN0U2xhc2ggPiAwKSB7XG4gICAgc2VhcmNoUGF0aCA9IHNlYXJjaFBhdGguc2xpY2UoMCwgbGFzdFNsYXNoKTtcbiAgfVxuICByZXR1cm4gZGVzY3JpcHRvckRvYy5wYXRobmFtZS5pbmRleE9mKHNlYXJjaFBhdGgpID09PSAwO1xufVxuXG5BbmFseXplci5wcm90b3R5cGUuZWxlbWVudHNGb3JGb2xkZXIgPSBmdW5jdGlvbiBlbGVtZW50c0ZvckZvbGRlcihocmVmKSB7XG4gIHJldHVybiB0aGlzLmVsZW1lbnRzLmZpbHRlcihmdW5jdGlvbihlbGVtZW50KXtcbiAgICByZXR1cm4gbWF0Y2hlc0RvY3VtZW50Rm9sZGVyKGVsZW1lbnQsIGhyZWYpO1xuICB9KTtcbn07XG5cbkFuYWx5emVyLnByb3RvdHlwZS5iZWhhdmlvcnNGb3JGb2xkZXIgPSBmdW5jdGlvbiBiZWhhdmlvcnNGb3JGb2xkZXIoaHJlZikge1xuICByZXR1cm4gdGhpcy5iZWhhdmlvcnMuZmlsdGVyKGZ1bmN0aW9uKGJlaGF2aW9yKXtcbiAgICByZXR1cm4gbWF0Y2hlc0RvY3VtZW50Rm9sZGVyKGJlaGF2aW9yLCBocmVmKTtcbiAgfSk7XG59O1xuXG4vKipcbiAqIFJldHVybnMgYSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYSBQT0pPIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBpbXBvcnRcbiAqIHRyZWUsIGluIGEgZm9ybWF0IHRoYXQgbWFpbnRhaW5zIHRoZSBvcmRlcmluZyBvZiB0aGUgSFRNTCBpbXBvcnRzIHNwZWMuXG4gKiBAcGFyYW0ge3N0cmluZ30gaHJlZiB0aGUgaW1wb3J0IHRvIGdldCBtZXRhZGF0YSBmb3IuXG4gKiBAcmV0dXJuIHtQcm9taXNlfVxuICovXG5BbmFseXplci5wcm90b3R5cGUubWV0YWRhdGFUcmVlID0gZnVuY3Rpb24gbWV0YWRhdGFUcmVlKGhyZWYpIHtcbiAgcmV0dXJuIHRoaXMubG9hZChocmVmKS50aGVuKGZ1bmN0aW9uKG1vbm9tZXIpe1xuICAgIHZhciBsb2FkZWRIcmVmcyA9IHt9O1xuICAgIGxvYWRlZEhyZWZzW2hyZWZdID0gdHJ1ZTtcbiAgICByZXR1cm4gdGhpcy5fbWV0YWRhdGFUcmVlKG1vbm9tZXIsIGxvYWRlZEhyZWZzKTtcbiAgfS5iaW5kKHRoaXMpKTtcbn07XG5cbkFuYWx5emVyLnByb3RvdHlwZS5fbWV0YWRhdGFUcmVlID0gZnVuY3Rpb24gX21ldGFkYXRhVHJlZShodG1sTW9ub21lcixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2FkZWRIcmVmcykge1xuICBpZiAobG9hZGVkSHJlZnMgPT09IHVuZGVmaW5lZCkge1xuICAgIGxvYWRlZEhyZWZzID0ge307XG4gIH1cbiAgcmV0dXJuIGh0bWxNb25vbWVyLm1ldGFkYXRhTG9hZGVkLnRoZW4oZnVuY3Rpb24obWV0YWRhdGEpIHtcbiAgICBtZXRhZGF0YSA9IHtcbiAgICAgIGVsZW1lbnRzOiBtZXRhZGF0YS5lbGVtZW50cyxcbiAgICAgIGZlYXR1cmVzOiBtZXRhZGF0YS5mZWF0dXJlcyxcbiAgICAgIGhyZWY6IGh0bWxNb25vbWVyLmhyZWZcbiAgICB9O1xuICAgIHJldHVybiBodG1sTW9ub21lci5kZXBzTG9hZGVkLnRoZW4oZnVuY3Rpb24oaHJlZnMpIHtcbiAgICAgIHZhciBkZXBNZXRhZGF0YSA9IFtdO1xuICAgICAgaHJlZnMuZm9yRWFjaChmdW5jdGlvbihocmVmKSB7XG4gICAgICAgIHZhciBtZXRhZGF0YVByb21pc2UgPSBQcm9taXNlLnJlc29sdmUodHJ1ZSk7XG4gICAgICAgIGlmIChkZXBNZXRhZGF0YS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgbWV0YWRhdGFQcm9taXNlID0gZGVwTWV0YWRhdGFbZGVwTWV0YWRhdGEubGVuZ3RoIC0gMV07XG4gICAgICAgIH1cbiAgICAgICAgbWV0YWRhdGFQcm9taXNlID0gbWV0YWRhdGFQcm9taXNlLnRoZW4oZnVuY3Rpb24oKSB7XG4gICAgICAgICAgaWYgKCFsb2FkZWRIcmVmc1tocmVmXSkge1xuICAgICAgICAgICAgbG9hZGVkSHJlZnNbaHJlZl0gPSB0cnVlO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX21ldGFkYXRhVHJlZSh0aGlzLmh0bWxbaHJlZl0sIGxvYWRlZEhyZWZzKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh7fSk7XG4gICAgICAgICAgfVxuICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgICAgICBkZXBNZXRhZGF0YS5wdXNoKG1ldGFkYXRhUHJvbWlzZSk7XG4gICAgICB9LmJpbmQodGhpcykpO1xuICAgICAgcmV0dXJuIFByb21pc2UuYWxsKGRlcE1ldGFkYXRhKS50aGVuKGZ1bmN0aW9uKGltcG9ydE1ldGFkYXRhKSB7XG4gICAgICAgIG1ldGFkYXRhLmltcG9ydHMgPSBpbXBvcnRNZXRhZGF0YTtcbiAgICAgICAgcmV0dXJuIGh0bWxNb25vbWVyLmh0bWxMb2FkZWQudGhlbihmdW5jdGlvbihwYXJzZWRIdG1sKSB7XG4gICAgICAgICAgbWV0YWRhdGEuaHRtbCA9IHBhcnNlZEh0bWw7XG4gICAgICAgICAgaWYgKG1ldGFkYXRhLmVsZW1lbnRzKSB7XG4gICAgICAgICAgICBtZXRhZGF0YS5lbGVtZW50cy5mb3JFYWNoKGZ1bmN0aW9uKGVsZW1lbnQpIHtcbiAgICAgICAgICAgICAgYXR0YWNoRG9tTW9kdWxlKHBhcnNlZEh0bWwsIGVsZW1lbnQpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiBtZXRhZGF0YTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9LmJpbmQodGhpcykpO1xuICB9LmJpbmQodGhpcykpO1xufTtcblxuZnVuY3Rpb24gbWF0Y2hpbmdJbXBvcnQoaW1wb3J0RWxlbWVudCkge1xuICB2YXIgbWF0Y2hlc1RhZyA9IGRvbTUucHJlZGljYXRlcy5oYXNUYWdOYW1lKGltcG9ydEVsZW1lbnQudGFnTmFtZSk7XG4gIHZhciBtYXRjaGVzSHJlZiA9IGRvbTUucHJlZGljYXRlcy5oYXNBdHRyVmFsdWUoJ2hyZWYnLCBkb201LmdldEF0dHJpYnV0ZShpbXBvcnRFbGVtZW50LCAnaHJlZicpKTtcbiAgdmFyIG1hdGNoZXNSZWwgPSBkb201LnByZWRpY2F0ZXMuaGFzQXR0clZhbHVlKCdyZWwnLCBkb201LmdldEF0dHJpYnV0ZShpbXBvcnRFbGVtZW50LCAncmVsJykpO1xuICByZXR1cm4gZG9tNS5wcmVkaWNhdGVzLkFORChtYXRjaGVzVGFnLCBtYXRjaGVzSHJlZiwgbWF0Y2hlc1JlbCk7XG59XG5cbi8vIFRPRE8oYWpvKTogUmVmYWN0b3Igb3V0IG9mIHZ1bGNhbml6ZSBpbnRvIGRvbTUuXG52YXIgcG9seW1lckV4dGVybmFsU3R5bGUgPSBkb201LnByZWRpY2F0ZXMuQU5EKFxuICBkb201LnByZWRpY2F0ZXMuaGFzVGFnTmFtZSgnbGluaycpLFxuICBkb201LnByZWRpY2F0ZXMuaGFzQXR0clZhbHVlKCdyZWwnLCAnaW1wb3J0JyksXG4gIGRvbTUucHJlZGljYXRlcy5oYXNBdHRyVmFsdWUoJ3R5cGUnLCAnY3NzJylcbik7XG5cbnZhciBleHRlcm5hbFNjcmlwdCA9IGRvbTUucHJlZGljYXRlcy5BTkQoXG4gIGRvbTUucHJlZGljYXRlcy5oYXNUYWdOYW1lKCdzY3JpcHQnKSxcbiAgZG9tNS5wcmVkaWNhdGVzLmhhc0F0dHIoJ3NyYycpXG4pO1xuXG52YXIgaXNIdG1sSW1wb3J0Tm9kZSA9IGRvbTUucHJlZGljYXRlcy5BTkQoXG4gIGRvbTUucHJlZGljYXRlcy5oYXNUYWdOYW1lKCdsaW5rJyksXG4gIGRvbTUucHJlZGljYXRlcy5oYXNBdHRyVmFsdWUoJ3JlbCcsICdpbXBvcnQnKSxcbiAgZG9tNS5wcmVkaWNhdGVzLk5PVChcbiAgICBkb201LnByZWRpY2F0ZXMuaGFzQXR0clZhbHVlKCd0eXBlJywgJ2NzcycpXG4gIClcbik7XG5cbkFuYWx5emVyLnByb3RvdHlwZS5faW5saW5lU3R5bGVzID0gZnVuY3Rpb24gX2lubGluZVN0eWxlcyhhc3QsIGhyZWYpIHtcbiAgdmFyIGNzc0xpbmtzID0gZG9tNS5xdWVyeUFsbChhc3QsIHBvbHltZXJFeHRlcm5hbFN0eWxlKTtcbiAgY3NzTGlua3MuZm9yRWFjaChmdW5jdGlvbihsaW5rKSB7XG4gICAgdmFyIGxpbmtIcmVmID0gZG9tNS5nZXRBdHRyaWJ1dGUobGluaywgJ2hyZWYnKTtcbiAgICB2YXIgdXJpID0gdXJsLnJlc29sdmUoaHJlZiwgbGlua0hyZWYpO1xuICAgIHZhciBjb250ZW50ID0gdGhpcy5fY29udGVudFt1cmldO1xuICAgIHZhciBzdHlsZSA9IGRvbTUuY29uc3RydWN0b3JzLmVsZW1lbnQoJ3N0eWxlJyk7XG4gICAgZG9tNS5zZXRUZXh0Q29udGVudChzdHlsZSwgJ1xcbicgKyBjb250ZW50ICsgJ1xcbicpO1xuICAgIGRvbTUucmVwbGFjZShsaW5rLCBzdHlsZSk7XG4gIH0uYmluZCh0aGlzKSk7XG4gIHJldHVybiBjc3NMaW5rcy5sZW5ndGggPiAwO1xufTtcblxuQW5hbHl6ZXIucHJvdG90eXBlLl9pbmxpbmVTY3JpcHRzID0gZnVuY3Rpb24gX2lubGluZVNjcmlwdHMoYXN0LCBocmVmKSB7XG4gIHZhciBzY3JpcHRzID0gZG9tNS5xdWVyeUFsbChhc3QsIGV4dGVybmFsU2NyaXB0KTtcbiAgc2NyaXB0cy5mb3JFYWNoKGZ1bmN0aW9uKHNjcmlwdCkge1xuICAgIHZhciBzY3JpcHRIcmVmID0gZG9tNS5nZXRBdHRyaWJ1dGUoc2NyaXB0LCAnc3JjJyk7XG4gICAgdmFyIHVyaSA9IHVybC5yZXNvbHZlKGhyZWYsIHNjcmlwdEhyZWYpO1xuICAgIHZhciBjb250ZW50ID0gdGhpcy5fY29udGVudFt1cmldO1xuICAgIHZhciBpbmxpbmVkID0gZG9tNS5jb25zdHJ1Y3RvcnMuZWxlbWVudCgnc2NyaXB0Jyk7XG4gICAgZG9tNS5zZXRUZXh0Q29udGVudChpbmxpbmVkLCAnXFxuJyArIGNvbnRlbnQgKyAnXFxuJyk7XG4gICAgZG9tNS5yZXBsYWNlKHNjcmlwdCwgaW5saW5lZCk7XG4gIH0uYmluZCh0aGlzKSk7XG4gIHJldHVybiBzY3JpcHRzLmxlbmd0aCA+IDA7XG59O1xuXG5BbmFseXplci5wcm90b3R5cGUuX2lubGluZUltcG9ydHMgPSBmdW5jdGlvbiBfaW5saW5lSW1wb3J0cyhhc3QsIGhyZWYsIGxvYWRlZCkge1xuICB2YXIgaW1wb3J0cyA9IGRvbTUucXVlcnlBbGwoYXN0LCBpc0h0bWxJbXBvcnROb2RlKTtcbiAgaW1wb3J0cy5mb3JFYWNoKGZ1bmN0aW9uKGh0bWxJbXBvcnQpIHtcbiAgICB2YXIgaW1wb3J0SHJlZiA9IGRvbTUuZ2V0QXR0cmlidXRlKGh0bWxJbXBvcnQsICdocmVmJyk7XG4gICAgdmFyIHVyaSA9IHVybC5yZXNvbHZlKGhyZWYsIGltcG9ydEhyZWYpO1xuICAgIGlmIChsb2FkZWRbdXJpXSkge1xuICAgICAgZG9tNS5yZW1vdmUoaHRtbEltcG9ydCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHZhciBjb250ZW50ID0gdGhpcy5nZXRMb2FkZWRBc3QodXJpLCBsb2FkZWQpO1xuICAgIGRvbTUucmVwbGFjZShodG1sSW1wb3J0LCBjb250ZW50KTtcbiAgfS5iaW5kKHRoaXMpKTtcbiAgcmV0dXJuIGltcG9ydHMubGVuZ3RoID4gMDtcbn07XG5cbi8qKlxuICogUmV0dXJucyBhIHByb21pc2UgcmVzb2x2aW5nIHRvIGEgZm9ybSBvZiB0aGUgQVNUIHdpdGggYWxsIGxpbmtzIHJlcGxhY2VkXG4gKiB3aXRoIHRoZSBkb2N1bWVudCB0aGV5IGxpbmsgdG8uIC5jc3MgYW5kIC5zY3JpcHQgZmlsZXMgYmVjb21lICZsdDtzdHlsZSZndDsgYW5kXG4gKiAmbHQ7c2NyaXB0Jmd0OywgcmVzcGVjdGl2ZWx5LlxuICpcbiAqIFRoZSBlbGVtZW50cyBpbiB0aGUgbG9hZGVkIGRvY3VtZW50IGFyZSB1bm1vZGlmaWVkIGZyb20gdGhlaXIgb3JpZ2luYWxcbiAqIGRvY3VtZW50cy5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gaHJlZiBUaGUgZG9jdW1lbnQgdG8gbG9hZC5cbiAqIEBwYXJhbSB7T2JqZWN0LjxzdHJpbmcsYm9vbGVhbj49fSBsb2FkZWQgQW4gb2JqZWN0IGtleWVkIGJ5IGFscmVhZHkgbG9hZGVkIGRvY3VtZW50cy5cbiAqIEByZXR1cm4ge1Byb21pc2UuPERvY3VtZW50QVNUPn1cbiAqL1xuQW5hbHl6ZXIucHJvdG90eXBlLmdldExvYWRlZEFzdCA9IGZ1bmN0aW9uIGdldExvYWRlZEFzdChocmVmLCBsb2FkZWQpIHtcbiAgaWYgKCFsb2FkZWQpIHtcbiAgICBsb2FkZWQgPSB7fTtcbiAgfVxuICBsb2FkZWRbaHJlZl0gPSB0cnVlO1xuICB2YXIgcGFyc2VkRG9jdW1lbnQgPSB0aGlzLnBhcnNlZERvY3VtZW50c1tocmVmXTtcbiAgdmFyIGFuYWx5emVkRG9jdW1lbnQgPSB0aGlzLmh0bWxbaHJlZl07XG4gIHZhciBhc3RDb3B5ID0gZG9tNS5wYXJzZShkb201LnNlcmlhbGl6ZShwYXJzZWREb2N1bWVudCkpO1xuICAvLyBXaGVuZXZlciB3ZSBpbmxpbmUgc29tZXRoaW5nLCByZXNldCBpbmxpbmVkIHRvIHRydWUgdG8ga25vdyB0aGF0IGFub2F0aGVyXG4gIC8vIGlubGluaW5nIHBhc3MgaXMgbmVlZGVkO1xuICB0aGlzLl9pbmxpbmVTdHlsZXMoYXN0Q29weSwgaHJlZik7XG4gIHRoaXMuX2lubGluZVNjcmlwdHMoYXN0Q29weSwgaHJlZik7XG4gIHRoaXMuX2lubGluZUltcG9ydHMoYXN0Q29weSwgaHJlZiwgbG9hZGVkKTtcbiAgcmV0dXJuIGFzdENvcHk7XG59O1xuXG4vKipcbiAqIENhbGxzIGBkb201Lm5vZGVXYWxrQWxsYCBvbiBlYWNoIGRvY3VtZW50IHRoYXQgYEFuYXl6bGVyYCBoYXMgbGFvZGVkLlxuICogQHBhcmFtICB7T2JqZWN0fSBwcmVkaWNhdGUgQSBkb201IHByZWRpY2F0ZS5cbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuQW5hbHl6ZXIucHJvdG90eXBlLm5vZGVXYWxrRG9jdW1lbnRzID0gZnVuY3Rpb24gbm9kZVdhbGtEb2N1bWVudHMocHJlZGljYXRlKSB7XG4gIGZvciAodmFyIGhyZWYgaW4gdGhpcy5wYXJzZWREb2N1bWVudHMpIHtcbiAgICB2YXIgbWF0Y2ggPSBkb201Lm5vZGVXYWxrKHRoaXMucGFyc2VkRG9jdW1lbnRzW2hyZWZdLCBwcmVkaWNhdGUpO1xuICAgIGlmIChtYXRjaCkge1xuICAgICAgcmV0dXJuIG1hdGNoO1xuICAgIH1cbiAgfVxuICByZXR1cm4gbnVsbDtcbn07XG5cbi8qKlxuICogQ2FsbHMgYGRvbTUubm9kZVdhbGtBbGxgIG9uIGVhY2ggZG9jdW1lbnQgdGhhdCBgQW5heXpsZXJgIGhhcyBsYW9kZWQuXG4gKiBAcGFyYW0gIHtPYmplY3R9IHByZWRpY2F0ZSBBIGRvbTUgcHJlZGljYXRlLlxuICogQHJldHVybiB7T2JqZWN0fVxuICovXG5BbmFseXplci5wcm90b3R5cGUubm9kZVdhbGtBbGxEb2N1bWVudHMgPSBmdW5jdGlvbiBub2RlV2Fsa0RvY3VtZW50cyhwcmVkaWNhdGUpIHtcbiAgdmFyIHJlc3VsdHMgPSBbXTtcbiAgZm9yICh2YXIgaHJlZiBpbiB0aGlzLnBhcnNlZERvY3VtZW50cykge1xuICAgIHZhciBuZXdOb2RlcyA9IGRvbTUubm9kZVdhbGtBbGwodGhpcy5wYXJzZWREb2N1bWVudHNbaHJlZl0sIHByZWRpY2F0ZSk7XG4gICAgcmVzdWx0cyA9IHJlc3VsdHMuY29uY2F0KG5ld05vZGVzKTtcbiAgfVxuICByZXR1cm4gcmVzdWx0cztcbn07XG5cbi8qKiBBbm5vdGF0ZXMgYWxsIGxvYWRlZCBtZXRhZGF0YSB3aXRoIGl0cyBkb2N1bWVudGF0aW9uLiAqL1xuQW5hbHl6ZXIucHJvdG90eXBlLmFubm90YXRlID0gZnVuY3Rpb24gYW5ub3RhdGUoKSB7XG4gIGlmICh0aGlzLmZlYXR1cmVzLmxlbmd0aCA+IDApIHtcbiAgICB2YXIgZmVhdHVyZUVsID0gZG9jcy5mZWF0dXJlRWxlbWVudCh0aGlzLmZlYXR1cmVzKTtcbiAgICB0aGlzLmVsZW1lbnRzLnVuc2hpZnQoZmVhdHVyZUVsKTtcbiAgICB0aGlzLmVsZW1lbnRzQnlUYWdOYW1lW2ZlYXR1cmVFbC5pc10gPSBmZWF0dXJlRWw7XG4gIH1cbiAgdmFyIGJlaGF2aW9yc0J5TmFtZSA9IHRoaXMuYmVoYXZpb3JzQnlOYW1lO1xuICB2YXIgZWxlbWVudEhlbHBlciA9IGZ1bmN0aW9uKGRlc2NyaXB0b3Ipe1xuICAgIGRvY3MuYW5ub3RhdGVFbGVtZW50KGRlc2NyaXB0b3IsIGJlaGF2aW9yc0J5TmFtZSk7XG4gIH07XG4gIHRoaXMuZWxlbWVudHMuZm9yRWFjaChlbGVtZW50SGVscGVyKTtcbiAgdGhpcy5iZWhhdmlvcnMuZm9yRWFjaChlbGVtZW50SGVscGVyKTsgLy8gU2FtZSBzaGFwZS5cbiAgdGhpcy5iZWhhdmlvcnMuZm9yRWFjaChmdW5jdGlvbihiZWhhdmlvcil7XG4gICAgaWYgKGJlaGF2aW9yLmlzICE9PSBiZWhhdmlvci5zeW1ib2wgJiYgYmVoYXZpb3Iuc3ltYm9sKSB7XG4gICAgICB0aGlzLmJlaGF2aW9yc0J5TmFtZVtiZWhhdmlvci5zeW1ib2xdID0gdW5kZWZpbmVkO1xuICAgIH1cbiAgfS5iaW5kKHRoaXMpKTtcbn07XG5cbmZ1bmN0aW9uIGF0dGFjaERvbU1vZHVsZShwYXJzZWRJbXBvcnQsIGVsZW1lbnQpIHtcbiAgdmFyIGRvbU1vZHVsZXMgPSBwYXJzZWRJbXBvcnRbJ2RvbS1tb2R1bGUnXTtcbiAgZm9yICh2YXIgaSA9IDAsIGRvbU1vZHVsZTsgaSA8IGRvbU1vZHVsZXMubGVuZ3RoOyBpKyspIHtcbiAgICBkb21Nb2R1bGUgPSBkb21Nb2R1bGVzW2ldO1xuICAgIGlmIChkb201LmdldEF0dHJpYnV0ZShkb21Nb2R1bGUsICdpZCcpID09PSBlbGVtZW50LmlzKSB7XG4gICAgICBlbGVtZW50LmRvbU1vZHVsZSA9IGRvbU1vZHVsZTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gIH1cbn1cblxuLyoqIFJlbW92ZXMgcmVkdW5kYW50IHByb3BlcnRpZXMgZnJvbSB0aGUgY29sbGVjdGVkIGRlc2NyaXB0b3JzLiAqL1xuQW5hbHl6ZXIucHJvdG90eXBlLmNsZWFuID0gZnVuY3Rpb24gY2xlYW4oKSB7XG4gIHRoaXMuZWxlbWVudHMuZm9yRWFjaChkb2NzLmNsZWFuRWxlbWVudCk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEFuYWx5emVyO1xuIl19 },{"./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', '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); }); from.events.forEach(function(fromEvent){ for (var toEvent, i = 0; i < to.events.length; i++) { toEvent = to.events[i]; if (fromEvent.name === toEvent.name) { return; } } if (fromEvent.__fromBehavior) { return; } var newEvent = Object.create(fromEvent); newEvent.__fromBehavior = from.is; to.events.push(newEvent); }); } 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 `