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 {String=} content Content to resolve `href` to instead of loading * from the file system. * @property {boolean} clean Whether the generated descriptors should be cleaned * of redundant data. * @property {string=} resolver. * `xhr` to use XMLHttpRequest * `fs` to use the local filesystem. * `permissive` to use the local filesystem and return empty files when a * path can't be found. * Default is `fs` in node and `xhr` in the browser. * @property {function(string): boolean} filter A predicate function that * indicates which files should be ignored by the loader. By default all * files not located under the dirname of `href` will be ignored. */ /** * Shorthand for transitively loading and processing all imports beginning at * `href`. * * In order to properly filter paths, `href` _must_ be an absolute URI. * * @param {string} href The root import to begin loading from. * @param {LoadOptions=} options Any additional options for the load. * @return {Promise} A promise that will resolve once `href` and its * dependencies have been loaded and analyzed. */ Analyzer.analyze = function analyze(href, options) { options = options || {}; options.filter = options.filter || _defaultFilter(href); var loader = new FileLoader(); var resolver = options.resolver; if (resolver === undefined) { if (typeof window === 'undefined') { resolver = 'fs'; } else { resolver = 'xhr'; } } var PrimaryResolver; if (resolver === 'fs') { PrimaryResolver = require('./loader/fs-resolver'); } else if (resolver === 'xhr') { PrimaryResolver = require('./loader/xhr-resolver'); } else if (resolver === 'permissive') { PrimaryResolver = require('./loader/error-swallowing-fs-resolver'); } else { throw new Error("Resolver must be one of 'fs' or 'xhr'"); } loader.addResolver(new PrimaryResolver(options)); if (options.content) { loader.addResolver(new StringResolver({url: href, content: options.content})); } loader.addResolver(new NoopResolver({test: options.filter})); var analyzer = new this(null, loader); return analyzer.metadataTree(href).then(function(root) { if (!options.noAnnotations) { analyzer.annotate(); } if (options.clean) { analyzer.clean(); } return Promise.resolve(analyzer); }); }; /** * @private * @param {string} href * @return {function(string): boolean} */ function _defaultFilter(href) { // Everything up to the last `/` or `\`. var base = href.match(/^(.*?)[^\/\\]*$/)[1]; return function(uri) { return uri.indexOf(base) !== 0; }; } Analyzer.prototype.load = function load(href) { return this.loader.request(href).then(function(content) { return new Promise(function(resolve, reject) { setTimeout(function() { this._content[href] = content; resolve(this._parseHTML(content, href)); }.bind(this), 0); }.bind(this)).catch(function(err){ console.error("Error processing document at " + href); throw err; }); }.bind(this)); }; /** * Returns an `AnalyzedDocument` representing the provided document * @private * @param {string} htmlImport Raw text of an HTML document * @param {string} href The document's URL. * @return {AnalyzedDocument} An `AnalyzedDocument` */ Analyzer.prototype._parseHTML = function _parseHTML(htmlImport, href) { if (href in this.html) { return this.html[href]; } var depsLoaded = []; var depHrefs = []; var metadataLoaded = Promise.resolve(EMPTY_METADATA); var parsed; try { parsed = importParse(htmlImport, href); } catch (err) { console.error('Error parsing!'); throw err; } var htmlLoaded = Promise.resolve(parsed); if (parsed.script) { metadataLoaded = this._processScripts(parsed.script, href); } var commentText = parsed.comment.map(function(comment){ return dom5.getTextContent(comment); }); var pseudoElements = docs.parsePseudoElements(commentText); pseudoElements.forEach(function(element){ element.contentHref = href; this.elements.push(element); this.elementsByTagName[element.is] = element; }.bind(this)); metadataLoaded = metadataLoaded.then(function(metadata){ var metadataEntry = { elements: pseudoElements, features: [], behaviors: [] }; return [metadata, metadataEntry].reduce(reduceMetadata); }); depsLoaded.push(metadataLoaded); if (this.loader) { var baseUri = href; if (parsed.base.length > 1) { console.error("Only one base tag per document!"); throw "Multiple base tags in " + href; } else if (parsed.base.length == 1) { var baseHref = dom5.getAttribute(parsed.base[0], "href"); if (baseHref) { baseHref = baseHref + "/"; baseUri = url.resolve(baseUri, baseHref); } } parsed.import.forEach(function(link) { var linkurl = dom5.getAttribute(link, 'href'); if (linkurl) { var resolvedUrl = url.resolve(baseUri, linkurl); depHrefs.push(resolvedUrl); depsLoaded.push(this._dependenciesLoadedFor(resolvedUrl, href)); } }.bind(this)); parsed.style.forEach(function(styleElement) { if (polymerExternalStyle(styleElement)) { var styleHref = dom5.getAttribute(styleElement, 'href'); if (href) { styleHref = url.resolve(baseUri, styleHref); depsLoaded.push(this.loader.request(styleHref).then(function(content){ this._content[styleHref] = content; }.bind(this))); } } }.bind(this)); } depsLoaded = Promise.all(depsLoaded) .then(function() {return depHrefs;}) .catch(function(err) {throw err;}); this.parsedDocuments[href] = parsed.ast; this.html[href] = { href: href, htmlLoaded: htmlLoaded, metadataLoaded: metadataLoaded, depHrefs: depHrefs, depsLoaded: depsLoaded }; return this.html[href]; }; Analyzer.prototype._processScripts = function _processScripts(scripts, href) { var scriptPromises = []; scripts.forEach(function(script) { scriptPromises.push(this._processScript(script, href)); }.bind(this)); return Promise.all(scriptPromises).then(function(metadataList) { return metadataList.reduce(reduceMetadata, EMPTY_METADATA); }); }; Analyzer.prototype._processScript = function _processScript(script, href) { var src = dom5.getAttribute(script, 'src'); var parsedJs; if (!src) { try { parsedJs = jsParse((script.childNodes.length) ? script.childNodes[0].value : ''); } catch (err) { // Figure out the correct line number for the error. var line = 0; var col = 0; if (script.__ownerDocument && script.__ownerDocument == href) { line = script.__locationDetail.line - 1; col = script.__locationDetail.column - 1; } line += err.lineNumber; col += err.column; var message = "Error parsing script in " + href + " at " + line + ":" + col; message += "\n" + err.stack; var fixedErr = new Error(message); fixedErr.location = {line: line, column: col}; fixedErr.ownerDocument = script.__ownerDocument; return Promise.reject(fixedErr); } if (parsedJs.elements) { parsedJs.elements.forEach(function(element) { element.scriptElement = script; element.contentHref = href; this.elements.push(element); if (element.is in this.elementsByTagName) { console.warn('Ignoring duplicate element definition: ' + element.is); } else { this.elementsByTagName[element.is] = element; } }.bind(this)); } if (parsedJs.features) { parsedJs.features.forEach(function(feature){ feature.contentHref = href; feature.scriptElement = script; }); this.features = this.features.concat(parsedJs.features); } if (parsedJs.behaviors) { parsedJs.behaviors.forEach(function(behavior){ behavior.contentHref = href; this.behaviorsByName[behavior.is] = behavior; this.behaviorsByName[behavior.symbol] = behavior; }.bind(this)); this.behaviors = this.behaviors.concat(parsedJs.behaviors); } if (!Object.hasOwnProperty.call(this.parsedScripts, href)) { this.parsedScripts[href] = []; } var scriptElement; if (script.__ownerDocument && script.__ownerDocument == href) { scriptElement = script; } this.parsedScripts[href].push({ ast: parsedJs.parsedScript, scriptElement: scriptElement }); return parsedJs; } if (this.loader) { var resolvedSrc = url.resolve(href, src); return this.loader.request(resolvedSrc).then(function(content) { this._content[resolvedSrc] = content; var resolvedScript = Object.create(script); resolvedScript.childNodes = [{value: content}]; resolvedScript.attrs = resolvedScript.attrs.slice(); dom5.removeAttribute(resolvedScript, 'src'); return this._processScript(resolvedScript, resolvedSrc); }.bind(this)).catch(function(err) {throw err;}); } else { return Promise.resolve(EMPTY_METADATA); } }; Analyzer.prototype._dependenciesLoadedFor = function _dependenciesLoadedFor(href, root) { var found = {}; if (root !== undefined) { found[root] = true; } return this._getDependencies(href, found).then(function(deps) { var depMetadataLoaded = []; var depPromises = deps.map(function(depHref){ return this.load(depHref).then(function(htmlMonomer) { return htmlMonomer.metadataLoaded; }); }.bind(this)); return Promise.all(depPromises); }.bind(this)); }; /** * List all the html dependencies for the document at `href`. * @param {string} href The href to get dependencies for. * @param {Object.=} 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; } /** * Returns the elements defined in the folder containing `href`. * @param {string} href path to search. * @return {Array.} */ Analyzer.prototype.elementsForFolder = function elementsForFolder(href) { return this.elements.filter(function(element){ return matchesDocumentFolder(element, href); }); }; /** * Returns the behaviors defined in the folder containing `href`. * @param {string} href path to search. * @return {Array.} */ 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,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImxpYi9hbmFseXplci5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTUgVGhlIFBvbHltZXIgUHJvamVjdCBBdXRob3JzLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogVGhpcyBjb2RlIG1heSBvbmx5IGJlIHVzZWQgdW5kZXIgdGhlIEJTRCBzdHlsZSBsaWNlbnNlIGZvdW5kIGF0IGh0dHA6Ly9wb2x5bWVyLmdpdGh1Yi5pby9MSUNFTlNFLnR4dFxuICogVGhlIGNvbXBsZXRlIHNldCBvZiBhdXRob3JzIG1heSBiZSBmb3VuZCBhdCBodHRwOi8vcG9seW1lci5naXRodWIuaW8vQVVUSE9SUy50eHRcbiAqIFRoZSBjb21wbGV0ZSBzZXQgb2YgY29udHJpYnV0b3JzIG1heSBiZSBmb3VuZCBhdCBodHRwOi8vcG9seW1lci5naXRodWIuaW8vQ09OVFJJQlVUT1JTLnR4dFxuICogQ29kZSBkaXN0cmlidXRlZCBieSBHb29nbGUgYXMgcGFydCBvZiB0aGUgcG9seW1lciBwcm9qZWN0IGlzIGFsc29cbiAqIHN1YmplY3QgdG8gYW4gYWRkaXRpb25hbCBJUCByaWdodHMgZ3JhbnQgZm91bmQgYXQgaHR0cDovL3BvbHltZXIuZ2l0aHViLmlvL1BBVEVOVFMudHh0XG4gKi9cbi8vIGpzaGludCBub2RlOiB0cnVlXG4ndXNlIHN0cmljdCc7XG4vLyBqc2hpbnQgLVcwNzlcbnZhciBQcm9taXNlID0gZ2xvYmFsLlByb21pc2UgfHwgcmVxdWlyZSgnZXM2LXByb21pc2UnKS5Qcm9taXNlO1xuLy8ganNoaW50ICtXMDc5XG5cbnZhciBkb201ID0gcmVxdWlyZSgnZG9tNScpO1xudmFyIHVybCA9IHJlcXVpcmUoJ3VybCcpO1xuXG52YXIgZG9jcyA9IHJlcXVpcmUoJy4vYXN0LXV0aWxzL2RvY3MnKTtcbnZhciBGaWxlTG9hZGVyID0gcmVxdWlyZSgnLi9sb2FkZXIvZmlsZS1sb2FkZXInKTtcbnZhciBpbXBvcnRQYXJzZSA9IHJlcXVpcmUoJy4vYXN0LXV0aWxzL2ltcG9ydC1wYXJzZScpO1xudmFyIGpzUGFyc2UgPSByZXF1aXJlKCcuL2FzdC11dGlscy9qcy1wYXJzZScpO1xudmFyIE5vb3BSZXNvbHZlciA9IHJlcXVpcmUoJy4vbG9hZGVyL25vb3AtcmVzb2x2ZXInKTtcbnZhciBTdHJpbmdSZXNvbHZlciA9IHJlcXVpcmUoJy4vbG9hZGVyL3N0cmluZy1yZXNvbHZlcicpO1xuXG5mdW5jdGlvbiByZWR1Y2VNZXRhZGF0YShtMSwgbTIpIHtcbiAgcmV0dXJuIHtcbiAgICBlbGVtZW50czogIG0xLmVsZW1lbnRzLmNvbmNhdChtMi5lbGVtZW50cyksXG4gICAgZmVhdHVyZXM6ICBtMS5mZWF0dXJlcy5jb25jYXQobTIuZmVhdHVyZXMpLFxuICAgIGJlaGF2aW9yczogbTEuYmVoYXZpb3JzLmNvbmNhdChtMi5iZWhhdmlvcnMpLFxuICB9O1xufVxuXG52YXIgRU1QVFlfTUVUQURBVEEgPSB7ZWxlbWVudHM6IFtdLCBmZWF0dXJlczogW10sIGJlaGF2aW9yczogW119O1xuXG4vKipcbiAqIFBhcnNlNSdzIHJlcHJlc2VudGF0aW9uIG9mIGEgcGFyc2VkIGh0bWwgZG9jdW1lbnRcbiAqIEB0eXBlZGVmIHtPYmplY3R9IERvY3VtZW50QVNUXG4gKiBAbWVtYmVyb2YgaHlkcm9seXNpc1xuICovXG5cbi8qKlxuICogZXNwcmVlJ3MgcmVwcmVzZW50YXRpb24gb2YgYSBwYXJzZWQgaHRtbCBkb2N1bWVudFxuICogQHR5cGVkZWYge09iamVjdH0gSlNBU1RcbiAqIEBtZW1iZXJvZiBoeWRyb2x5c2lzXG4gKi9cblxuLyoqXG4gKiBQYWNrYWdlIG9mIGEgcGFyc2VkIEpTIHNjcmlwdFxuICogQHR5cGVkZWYge09iamVjdH0gUGFyc2VkSlNcbiAqIEBwcm9wZXJ0eSB7SlNBU1R9IGFzdCBUaGUgc2NyaXB0J3MgQVNUXG4gKiBAcHJvcGVydHkge0RvY3VtZW50QVNUfSBzY3JpcHRFbGVtZW50IElmIGlubGluZSwgdGhlIHNjcmlwdCdzIGNvbnRhaW5pbmcgdGFnLlxuICogQG1lbWJlcm9mIGh5ZHJvbHlzaXNcbiAqL1xuXG4vKipcbiAqIFRoZSBtZXRhZGF0YSBmb3IgYSBzaW5nbGUgcG9seW1lciBlbGVtZW50XG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBFbGVtZW50RGVzY3JpcHRvclxuICogQG1lbWJlcm9mIGh5ZHJvbHlzaXNcbiAqL1xuXG4vKipcbiAqIFRoZSBtZXRhZGF0YSBmb3IgYSBQb2x5bWVyIGZlYXR1cmUuXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBGZWF0dXJlRGVzY3JpcHRvclxuICogQG1lbWJlcm9mIGh5ZHJvbHlzaXNcbiAqL1xuXG4vKipcbiAqIFRoZSBtZXRhZGF0YSBmb3IgYSBQb2x5bWVyIGJlaGF2aW9yIG1peGluLlxuICogQHR5cGVkZWYge09iamVjdH0gQmVoYXZpb3JEZXNjcmlwdG9yXG4gKiBAbWVtYmVyb2YgaHlkcm9seXNpc1xuICovXG5cbi8qKlxuICogVGhlIG1ldGFkYXRhIGZvciBhbGwgZmVhdHVyZXMgYW5kIGVsZW1lbnRzIGRlZmluZWQgaW4gb25lIGRvY3VtZW50XG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBEb2N1bWVudERlc2NyaXB0b3JcbiAqIEBtZW1iZXJvZiBoeWRyb2x5c2lzXG4gKiBAcHJvcGVydHkge0FycmF5PEVsZW1lbnREZXNjcmlwdG9yPn0gZWxlbWVudHMgVGhlIGVsZW1lbnRzIGZyb20gdGhlIGRvY3VtZW50XG4gKiBAcHJvcGVydHkge0FycmF5PEZlYXR1cmVEZXNjcmlwdG9yPn0gIGZlYXR1cmVzIFRoZSBmZWF0dXJlcyBmcm9tIHRoZSBkb2N1bWVudFxuICogQHByb3BlcnR5IHtBcnJheTxGZWF0dXJlRGVzY3JpcHRvcj59ICBiZWhhdmlvcnMgVGhlIGJlaGF2aW9ycyBmcm9tIHRoZSBkb2N1bWVudFxuICovXG5cbi8qKlxuICogVGhlIG1ldGFkYXRhIG9mIGFuIGVudGlyZSBIVE1MIGRvY3VtZW50LCBpbiBwcm9taXNlcy5cbiAqIEB0eXBlZGVmIHtPYmplY3R9IEFuYWx5emVkRG9jdW1lbnRcbiAqIEBtZW1iZXJvZiBoeWRyb2x5c2lzXG4gKiBAcHJvcGVydHkge3N0cmluZ30gaHJlZiBUaGUgdXJsIG9mIHRoZSBkb2N1bWVudC5cbiAqIEBwcm9wZXJ0eSB7UHJvbWlzZTxQYXJzZWRJbXBvcnQ+fSAgaHRtbExvYWRlZCBUaGUgcGFyc2VkIHJlcHJlc2VudGF0aW9uIG9mXG4gKiAgICAgdGhlIGRvYy4gVXNlIHRoZSBgYXN0YCBwcm9wZXJ0eSB0byBnZXQgdGhlIGZ1bGwgYHBhcnNlNWAgYXN0XG4gKlxuICogQHByb3BlcnR5IHtQcm9taXNlPEFycmF5PHN0cmluZz4+fSBkZXBzTG9hZGVkIFJlc29sdmVzIHRvIHRoZSBsaXN0IG9mIHRoaXNcbiAqICAgICBEb2N1bWVudCdzIHRyYW5zaXRpdmUgaW1wb3J0IGRlcGVuZGVuY2llc1xuICpcbiAqIEBwcm9wZXJ0eSB7QXJyYXk8c3RyaW5nPn0gZGVwSHJlZnMgVGhlIGRpcmVjdCBkZXBlbmRlbmNpZXMgb2YgdGhlIGRvY3VtZW50LlxuICpcbiAqIEBwcm9wZXJ0eSB7UHJvbWlzZTxEb2N1bWVudERlc2NyaXB0b3I+fSBtZXRhZGF0YUxvYWRlZCBSZXNvbHZlcyB0byB0aGUgbGlzdCBvZlxuICogICAgIHRoaXMgRG9jdW1lbnQncyBpbXBvcnQgZGVwZW5kZW5jaWVzXG4gKi9cblxuLyoqXG4gKiBBIGRhdGFiYXNlIG9mIFBvbHltZXIgbWV0YWRhdGEgZGVmaW5lZCBpbiBIVE1MXG4gKlxuICogQGNvbnN0cnVjdG9yXG4gKiBAbWVtYmVyT2YgaHlkcm9seXNpc1xuICogQHBhcmFtICB7Ym9vbGVhbn0gYXR0YWNoQVNUICBJZiB0cnVlLCBhdHRhY2ggYSBwYXJzZTUgY29tcGxpYW50IEFTVFxuICogQHBhcmFtICB7RmlsZUxvYWRlcj19IGxvYWRlciBBbiBvcHRpb25hbCBgRmlsZUxvYWRlcmAgdXNlZCB0byBsb2FkIGV4dGVybmFsXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc291cmNlc1xuICovXG52YXIgQW5hbHl6ZXIgPSBmdW5jdGlvbiBBbmFseXplcihhdHRhY2hBU1QsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2FkZXIpIHtcbiAgdGhpcy5sb2FkZXIgPSBsb2FkZXI7XG5cbiAgLyoqXG4gICAqIEEgbGlzdCBvZiBhbGwgZWxlbWVudHMgdGhlIGBBbmFseXplcmAgaGFzIG1ldGFkYXRhIGZvci5cbiAgICogQG1lbWJlciB7QXJyYXkuPEVsZW1lbnREZXNjcmlwdG9yPn1cbiAgICovXG4gIHRoaXMuZWxlbWVudHMgPSBbXTtcblxuICAvKipcbiAgICogQSB2aWV3IGludG8gYGVsZW1lbnRzYCwga2V5ZWQgYnkgdGFnIG5hbWUuXG4gICAqIEBtZW1iZXIge09iamVjdC48c3RyaW5nLEVsZW1lbnREZXNjcmlwdG9yPn1cbiAgICovXG4gIHRoaXMuZWxlbWVudHNCeVRhZ05hbWUgPSB7fTtcblxuICAvKipcbiAgICogQSBsaXN0IG9mIEFQSSBmZWF0dXJlcyBhZGRlZCB0byBgUG9seW1lci5CYXNlYCBlbmNvdW50ZXJlZCBieSB0aGVcbiAgICogYW5hbHl6ZXIuXG4gICAqIEBtZW1iZXIge0FycmF5PEZlYXR1cmVEZXNjcmlwdG9yPn1cbiAgICovXG4gIHRoaXMuZmVhdHVyZXMgPSBbXTtcblxuICAvKipcbiAgICogVGhlIGJlaGF2aW9ycyBjb2xsZWN0ZWQgYnkgdGhlIGFuYWx5c2lzIHBhc3MuXG4gICAqXG4gICAqIEBtZW1iZXIge0FycmF5PEJlaGF2aW9yRGVzY3JpcHRvcj59XG4gICAqL1xuICB0aGlzLmJlaGF2aW9ycyA9IFtdO1xuXG4gIC8qKlxuICAgKiBUaGUgYmVoYXZpb3JzIGNvbGxlY3RlZCBieSB0aGUgYW5hbHlzaXMgcGFzcyBieSBuYW1lLlxuICAgKlxuICAgKiBAbWVtYmVyIHtPYmplY3Q8c3RyaW5nLEJlaGF2aW9yRGVzY3JpcHRvcj59XG4gICAqL1xuICB0aGlzLmJlaGF2aW9yc0J5TmFtZSA9IHt9O1xuXG4gIC8qKlxuICAgKiBBIG1hcCwga2V5ZWQgYnkgYWJzb2x1dGUgcGF0aCwgb2YgRG9jdW1lbnQgbWV0YWRhdGEuXG4gICAqIEBtZW1iZXIge09iamVjdDxzdHJpbmcsQW5hbHl6ZWREb2N1bWVudD59XG4gICAqL1xuICB0aGlzLmh0bWwgPSB7fTtcblxuICAvKipcbiAgICogQSBtYXAsIGtleWVkIGJ5IHBhdGgsIG9mIEhUTUwgZG9jdW1lbnQgQVNUcy5cbiAgICogQHR5cGUge09iamVjdH1cbiAgICovXG4gIHRoaXMucGFyc2VkRG9jdW1lbnRzID0ge307XG5cbiAgLyoqXG4gICAqIEEgbWFwLCBrZXllZCBieSBwYXRoLCBvZiBKUyBzY3JpcHQgQVNUcy5cbiAgICpcbiAgICogSWYgdGhlIHBhdGggaXMgYW4gSFRNTCBmaWxlIHdpdGggbXVsdGlwbGUgc2NyaXB0cywgdGhlIGVudHJ5IHdpbGwgYmUgYW4gYXJyYXkgb2Ygc2NyaXB0cy5cbiAgICpcbiAgICogQHR5cGUge09iamVjdDxzdHJpbmcsQXJyYXk8UGFyc2VkSlM+Pn1cbiAgICovXG4gIHRoaXMucGFyc2VkU2NyaXB0cyA9IHt9O1xuXG5cblxuICAvKipcbiAgICogQSBtYXAsIGtleWVkIGJ5IHBhdGgsIG9mIGRvY3VtZW50IGNvbnRlbnQuXG4gICAqIEB0eXBlIHtPYmplY3R9XG4gICAqL1xuICB0aGlzLl9jb250ZW50ID0ge307XG59O1xuXG4vKipcbiAqIE9wdGlvbnMgZm9yIGBBbmFseXplci5hbmFsenllYFxuICogQHR5cGVkZWYge09iamVjdH0gTG9hZE9wdGlvbnNcbiAqIEBtZW1iZXJvZiBoeWRyb2x5c2lzXG4gKiBAcHJvcGVydHkge2Jvb2xlYW59IG5vQW5ub3RhdGlvbnMgV2hldGhlciBgYW5ub3RhdGUoKWAgc2hvdWxkIGJlIHNraXBwZWQuXG4gKiBAcHJvcGVydHkge1N0cmluZz19IGNvbnRlbnQgQ29udGVudCB0byByZXNvbHZlIGBocmVmYCB0byBpbnN0ZWFkIG9mIGxvYWRpbmdcbiAqICAgICBmcm9tIHRoZSBmaWxlIHN5c3RlbS5cbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gY2xlYW4gV2hldGhlciB0aGUgZ2VuZXJhdGVkIGRlc2NyaXB0b3JzIHNob3VsZCBiZSBjbGVhbmVkXG4gKiAgICAgb2YgcmVkdW5kYW50IGRhdGEuXG4gKiBAcHJvcGVydHkge3N0cmluZz19IHJlc29sdmVyLlxuICogICAgIGB4aHJgIHRvIHVzZSBYTUxIdHRwUmVxdWVzdFxuICogICAgIGBmc2AgdG8gdXNlIHRoZSBsb2NhbCBmaWxlc3lzdGVtLlxuICogICAgIGBwZXJtaXNzaXZlYCB0byB1c2UgdGhlIGxvY2FsIGZpbGVzeXN0ZW0gYW5kIHJldHVybiBlbXB0eSBmaWxlcyB3aGVuIGFcbiAqICAgICBwYXRoIGNhbid0IGJlIGZvdW5kLlxuICogICAgIERlZmF1bHQgaXMgYGZzYCBpbiBub2RlIGFuZCBgeGhyYCBpbiB0aGUgYnJvd3Nlci5cbiAqIEBwcm9wZXJ0eSB7ZnVuY3Rpb24oc3RyaW5nKTogYm9vbGVhbn0gZmlsdGVyIEEgcHJlZGljYXRlIGZ1bmN0aW9uIHRoYXRcbiAqICAgICBpbmRpY2F0ZXMgd2hpY2ggZmlsZXMgc2hvdWxkIGJlIGlnbm9yZWQgYnkgdGhlIGxvYWRlci4gQnkgZGVmYXVsdCBhbGxcbiAqICAgICBmaWxlcyBub3QgbG9jYXRlZCB1bmRlciB0aGUgZGlybmFtZSBvZiBgaHJlZmAgd2lsbCBiZSBpZ25vcmVkLlxuICovXG5cbi8qKlxuICogU2hvcnRoYW5kIGZvciB0cmFuc2l0aXZlbHkgbG9hZGluZyBhbmQgcHJvY2Vzc2luZyBhbGwgaW1wb3J0cyBiZWdpbm5pbmcgYXRcbiAqIGBocmVmYC5cbiAqXG4gKiBJbiBvcmRlciB0byBwcm9wZXJseSBmaWx0ZXIgcGF0aHMsIGBocmVmYCBfbXVzdF8gYmUgYW4gYWJzb2x1dGUgVVJJLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBocmVmIFRoZSByb290IGltcG9ydCB0byBiZWdpbiBsb2FkaW5nIGZyb20uXG4gKiBAcGFyYW0ge0xvYWRPcHRpb25zPX0gb3B0aW9ucyBBbnkgYWRkaXRpb25hbCBvcHRpb25zIGZvciB0aGUgbG9hZC5cbiAqIEByZXR1cm4ge1Byb21pc2U8QW5hbHl6ZXI+fSBBIHByb21pc2UgdGhhdCB3aWxsIHJlc29sdmUgb25jZSBgaHJlZmAgYW5kIGl0c1xuICogICAgIGRlcGVuZGVuY2llcyBoYXZlIGJlZW4gbG9hZGVkIGFuZCBhbmFseXplZC5cbiAqL1xuQW5hbHl6ZXIuYW5hbHl6ZSA9IGZ1bmN0aW9uIGFuYWx5emUoaHJlZiwgb3B0aW9ucykge1xuICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgb3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmZpbHRlciB8fCBfZGVmYXVsdEZpbHRlcihocmVmKTtcblxuICB2YXIgbG9hZGVyID0gbmV3IEZpbGVMb2FkZXIoKTtcblxuICB2YXIgcmVzb2x2ZXIgPSBvcHRpb25zLnJlc29sdmVyO1xuICBpZiAocmVzb2x2ZXIgPT09IHVuZGVmaW5lZCkge1xuICAgIGlmICh0eXBlb2Ygd2luZG93ID09PSAndW5kZWZpbmVkJykge1xuICAgICAgcmVzb2x2ZXIgPSAnZnMnO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXNvbHZlciA9ICd4aHInO1xuICAgIH1cbiAgfVxuICB2YXIgUHJpbWFyeVJlc29sdmVyO1xuICBpZiAocmVzb2x2ZXIgPT09ICdmcycpIHtcbiAgICBQcmltYXJ5UmVzb2x2ZXIgPSByZXF1aXJlKCcuL2xvYWRlci9mcy1yZXNvbHZlcicpO1xuICB9IGVsc2UgaWYgKHJlc29sdmVyID09PSAneGhyJykge1xuICAgIFByaW1hcnlSZXNvbHZlciA9IHJlcXVpcmUoJy4vbG9hZGVyL3hoci1yZXNvbHZlcicpO1xuICB9IGVsc2UgaWYgKHJlc29sdmVyID09PSAncGVybWlzc2l2ZScpIHtcbiAgICBQcmltYXJ5UmVzb2x2ZXIgPSByZXF1aXJlKCcuL2xvYWRlci9lcnJvci1zd2FsbG93aW5nLWZzLXJlc29sdmVyJyk7XG4gIH0gZWxzZSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFwiUmVzb2x2ZXIgbXVzdCBiZSBvbmUgb2YgJ2ZzJyBvciAneGhyJ1wiKTtcbiAgfVxuXG4gIGxvYWRlci5hZGRSZXNvbHZlcihuZXcgUHJpbWFyeVJlc29sdmVyKG9wdGlvbnMpKTtcbiAgaWYgKG9wdGlvbnMuY29udGVudCkge1xuICAgIGxvYWRlci5hZGRSZXNvbHZlcihuZXcgU3RyaW5nUmVzb2x2ZXIoe3VybDogaHJlZiwgY29udGVudDogb3B0aW9ucy5jb250ZW50fSkpO1xuICB9XG4gIGxvYWRlci5hZGRSZXNvbHZlcihuZXcgTm9vcFJlc29sdmVyKHt0ZXN0OiBvcHRpb25zLmZpbHRlcn0pKTtcblxuICB2YXIgYW5hbHl6ZXIgPSBuZXcgdGhpcyhudWxsLCBsb2FkZXIpO1xuICByZXR1cm4gYW5hbHl6ZXIubWV0YWRhdGFUcmVlKGhyZWYpLnRoZW4oZnVuY3Rpb24ocm9vdCkge1xuICAgIGlmICghb3B0aW9ucy5ub0Fubm90YXRpb25zKSB7XG4gICAgICBhbmFseXplci5hbm5vdGF0ZSgpO1xuICAgIH1cbiAgICBpZiAob3B0aW9ucy5jbGVhbikge1xuICAgICAgYW5hbHl6ZXIuY2xlYW4oKTtcbiAgICB9XG4gICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShhbmFseXplcik7XG4gIH0pO1xufTtcblxuLyoqXG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtIHtzdHJpbmd9IGhyZWZcbiAqIEByZXR1cm4ge2Z1bmN0aW9uKHN0cmluZyk6IGJvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIF9kZWZhdWx0RmlsdGVyKGhyZWYpIHtcbiAgLy8gRXZlcnl0aGluZyB1cCB0byB0aGUgbGFzdCBgL2Agb3IgYFxcYC5cbiAgdmFyIGJhc2UgPSBocmVmLm1hdGNoKC9eKC4qPylbXlxcL1xcXFxdKiQvKVsxXTtcbiAgcmV0dXJuIGZ1bmN0aW9uKHVyaSkge1xuICAgIHJldHVybiB1cmkuaW5kZXhPZihiYXNlKSAhPT0gMDtcbiAgfTtcbn1cblxuQW5hbHl6ZXIucHJvdG90eXBlLmxvYWQgPSBmdW5jdGlvbiBsb2FkKGhyZWYpIHtcbiAgcmV0dXJuIHRoaXMubG9hZGVyLnJlcXVlc3QoaHJlZikudGhlbihmdW5jdGlvbihjb250ZW50KSB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgdGhpcy5fY29udGVudFtocmVmXSA9IGNvbnRlbnQ7XG4gICAgICAgIHJlc29sdmUodGhpcy5fcGFyc2VIVE1MKGNvbnRlbnQsIGhyZWYpKTtcbiAgICAgIH0uYmluZCh0aGlzKSwgMCk7XG4gICAgfS5iaW5kKHRoaXMpKS5jYXRjaChmdW5jdGlvbihlcnIpe1xuICAgICAgY29uc29sZS5lcnJvcihcIkVycm9yIHByb2Nlc3NpbmcgZG9jdW1lbnQgYXQgXCIgKyBocmVmKTtcbiAgICAgIHRocm93IGVycjtcbiAgICB9KTtcbiAgfS5iaW5kKHRoaXMpKTtcbn07XG5cbi8qKlxuICogUmV0dXJucyBhbiBgQW5hbHl6ZWREb2N1bWVudGAgcmVwcmVzZW50aW5nIHRoZSBwcm92aWRlZCBkb2N1bWVudFxuICogQHByaXZhdGVcbiAqIEBwYXJhbSAge3N0cmluZ30gaHRtbEltcG9ydCBSYXcgdGV4dCBvZiBhbiBIVE1MIGRvY3VtZW50XG4gKiBAcGFyYW0gIHtzdHJpbmd9IGhyZWYgICAgICAgVGhlIGRvY3VtZW50J3MgVVJMLlxuICogQHJldHVybiB7QW5hbHl6ZWREb2N1bWVudH0gICAgICAgQW4gIGBBbmFseXplZERvY3VtZW50YFxuICovXG5BbmFseXplci5wcm90b3R5cGUuX3BhcnNlSFRNTCA9IGZ1bmN0aW9uIF9wYXJzZUhUTUwoaHRtbEltcG9ydCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaHJlZikge1xuICBpZiAoaHJlZiBpbiB0aGlzLmh0bWwpIHtcbiAgICByZXR1cm4gdGhpcy5odG1sW2hyZWZdO1xuICB9XG4gIHZhciBkZXBzTG9hZGVkID0gW107XG4gIHZhciBkZXBIcmVmcyA9IFtdO1xuICB2YXIgbWV0YWRhdGFMb2FkZWQgPSBQcm9taXNlLnJlc29sdmUoRU1QVFlfTUVUQURBVEEpO1xuICB2YXIgcGFyc2VkO1xuICB0cnkge1xuICAgIHBhcnNlZCA9IGltcG9ydFBhcnNlKGh0bWxJbXBvcnQsIGhyZWYpO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBjb25zb2xlLmVycm9yKCdFcnJvciBwYXJzaW5nIScpO1xuICAgIHRocm93IGVycjtcbiAgfVxuICB2YXIgaHRtbExvYWRlZCA9IFByb21pc2UucmVzb2x2ZShwYXJzZWQpO1xuICBpZiAocGFyc2VkLnNjcmlwdCkge1xuICAgIG1ldGFkYXRhTG9hZGVkID0gdGhpcy5fcHJvY2Vzc1NjcmlwdHMocGFyc2VkLnNjcmlwdCwgaHJlZik7XG4gIH1cbiAgdmFyIGNvbW1lbnRUZXh0ID0gcGFyc2VkLmNvbW1lbnQubWFwKGZ1bmN0aW9uKGNvbW1lbnQpe1xuICAgIHJldHVybiBkb201LmdldFRleHRDb250ZW50KGNvbW1lbnQpO1xuICB9KTtcbiAgdmFyIHBzZXVkb0VsZW1lbnRzID0gZG9jcy5wYXJzZVBzZXVkb0VsZW1lbnRzKGNvbW1lbnRUZXh0KTtcbiAgcHNldWRvRWxlbWVudHMuZm9yRWFjaChmdW5jdGlvbihlbGVtZW50KXtcbiAgICBlbGVtZW50LmNvbnRlbnRIcmVmID0gaHJlZjtcbiAgICB0aGlzLmVsZW1lbnRzLnB1c2goZWxlbWVudCk7XG4gICAgdGhpcy5lbGVtZW50c0J5VGFnTmFtZVtlbGVtZW50LmlzXSA9IGVsZW1lbnQ7XG4gIH0uYmluZCh0aGlzKSk7XG4gIG1ldGFkYXRhTG9hZGVkID0gbWV0YWRhdGFMb2FkZWQudGhlbihmdW5jdGlvbihtZXRhZGF0YSl7XG4gICAgdmFyIG1ldGFkYXRhRW50cnkgPSB7XG4gICAgICBlbGVtZW50czogcHNldWRvRWxlbWVudHMsXG4gICAgICBmZWF0dXJlczogW10sXG4gICAgICBiZWhhdmlvcnM6IFtdXG4gICAgfTtcbiAgICByZXR1cm4gW21ldGFkYXRhLCBtZXRhZGF0YUVudHJ5XS5yZWR1Y2UocmVkdWNlTWV0YWRhdGEpO1xuICB9KTtcbiAgZGVwc0xvYWRlZC5wdXNoKG1ldGFkYXRhTG9hZGVkKTtcblxuXG4gIGlmICh0aGlzLmxvYWRlcikge1xuICAgIHZhciBiYXNlVXJpID0gaHJlZjtcbiAgICBpZiAocGFyc2VkLmJhc2UubGVuZ3RoID4gMSkge1xuICAgICAgY29uc29sZS5lcnJvcihcIk9ubHkgb25lIGJhc2UgdGFnIHBlciBkb2N1bWVudCFcIik7XG4gICAgICB0aHJvdyBcIk11bHRpcGxlIGJhc2UgdGFncyBpbiBcIiArIGhyZWY7XG4gICAgfSBlbHNlIGlmIChwYXJzZWQuYmFzZS5sZW5ndGggPT0gMSkge1xuICAgICAgdmFyIGJhc2VIcmVmID0gZG9tNS5nZXRBdHRyaWJ1dGUocGFyc2VkLmJhc2VbMF0sIFwiaHJlZlwiKTtcbiAgICAgIGlmIChiYXNlSHJlZikge1xuICAgICAgICBiYXNlSHJlZiA9IGJhc2VIcmVmICsgXCIvXCI7XG4gICAgICAgIGJhc2VVcmkgPSB1cmwucmVzb2x2ZShiYXNlVXJpLCBiYXNlSHJlZik7XG4gICAgICB9XG4gICAgfVxuICAgIHBhcnNlZC5pbXBvcnQuZm9yRWFjaChmdW5jdGlvbihsaW5rKSB7XG4gICAgICB2YXIgbGlua3VybCA9IGRvbTUuZ2V0QXR0cmlidXRlKGxpbmssICdocmVmJyk7XG4gICAgICBpZiAobGlua3VybCkge1xuICAgICAgICB2YXIgcmVzb2x2ZWRVcmwgPSB1cmwucmVzb2x2ZShiYXNlVXJpLCBsaW5rdXJsKTtcbiAgICAgICAgZGVwSHJlZnMucHVzaChyZXNvbHZlZFVybCk7XG4gICAgICAgIGRlcHNMb2FkZWQucHVzaCh0aGlzLl9kZXBlbmRlbmNpZXNMb2FkZWRGb3IocmVzb2x2ZWRVcmwsIGhyZWYpKTtcbiAgICAgIH1cbiAgICB9LmJpbmQodGhpcykpO1xuICAgIHBhcnNlZC5zdHlsZS5mb3JFYWNoKGZ1bmN0aW9uKHN0eWxlRWxlbWVudCkge1xuICAgICAgaWYgKHBvbHltZXJFeHRlcm5hbFN0eWxlKHN0eWxlRWxlbWVudCkpIHtcbiAgICAgICAgdmFyIHN0eWxlSHJlZiA9IGRvbTUuZ2V0QXR0cmlidXRlKHN0eWxlRWxlbWVudCwgJ2hyZWYnKTtcbiAgICAgICAgaWYgKGhyZWYpIHtcbiAgICAgICAgICBzdHlsZUhyZWYgPSB1cmwucmVzb2x2ZShiYXNlVXJpLCBzdHlsZUhyZWYpO1xuICAgICAgICAgIGRlcHNMb2FkZWQucHVzaCh0aGlzLmxvYWRlci5yZXF1ZXN0KHN0eWxlSHJlZikudGhlbihmdW5jdGlvbihjb250ZW50KXtcbiAgICAgICAgICAgIHRoaXMuX2NvbnRlbnRbc3R5bGVIcmVmXSA9IGNvbnRlbnQ7XG4gICAgICAgICAgfS5iaW5kKHRoaXMpKSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LmJpbmQodGhpcykpO1xuICB9XG4gIGRlcHNMb2FkZWQgPSBQcm9taXNlLmFsbChkZXBzTG9hZGVkKVxuICAgICAgICAudGhlbihmdW5jdGlvbigpIHtyZXR1cm4gZGVwSHJlZnM7fSlcbiAgICAgICAgLmNhdGNoKGZ1bmN0aW9uKGVycikge3Rocm93IGVycjt9KTtcbiAgdGhpcy5wYXJzZWREb2N1bWVudHNbaHJlZl0gPSBwYXJzZWQuYXN0O1xuICB0aGlzLmh0bWxbaHJlZl0gPSB7XG4gICAgICBocmVmOiBocmVmLFxuICAgICAgaHRtbExvYWRlZDogaHRtbExvYWRlZCxcbiAgICAgIG1ldGFkYXRhTG9hZGVkOiBtZXRhZGF0YUxvYWRlZCxcbiAgICAgIGRlcEhyZWZzOiBkZXBIcmVmcyxcbiAgICAgIGRlcHNMb2FkZWQ6IGRlcHNMb2FkZWRcbiAgfTtcbiAgcmV0dXJuIHRoaXMuaHRtbFtocmVmXTtcbn07XG5cbkFuYWx5emVyLnByb3RvdHlwZS5fcHJvY2Vzc1NjcmlwdHMgPSBmdW5jdGlvbiBfcHJvY2Vzc1NjcmlwdHMoc2NyaXB0cywgaHJlZikge1xuICB2YXIgc2NyaXB0UHJvbWlzZXMgPSBbXTtcbiAgc2NyaXB0cy5mb3JFYWNoKGZ1bmN0aW9uKHNjcmlwdCkge1xuICAgIHNjcmlwdFByb21pc2VzLnB1c2godGhpcy5fcHJvY2Vzc1NjcmlwdChzY3JpcHQsIGhyZWYpKTtcbiAgfS5iaW5kKHRoaXMpKTtcbiAgcmV0dXJuIFByb21pc2UuYWxsKHNjcmlwdFByb21pc2VzKS50aGVuKGZ1bmN0aW9uKG1ldGFkYXRhTGlzdCkge1xuICAgIHJldHVybiBtZXRhZGF0YUxpc3QucmVkdWNlKHJlZHVjZU1ldGFkYXRhLCBFTVBUWV9NRVRBREFUQSk7XG4gIH0pO1xufTtcblxuQW5hbHl6ZXIucHJvdG90eXBlLl9wcm9jZXNzU2NyaXB0ID0gZnVuY3Rpb24gX3Byb2Nlc3NTY3JpcHQoc2NyaXB0LCBocmVmKSB7XG4gIHZhciBzcmMgPSBkb201LmdldEF0dHJpYnV0ZShzY3JpcHQsICdzcmMnKTtcbiAgdmFyIHBhcnNlZEpzO1xuICBpZiAoIXNyYykge1xuICAgIHRyeSB7XG4gICAgICBwYXJzZWRKcyA9IGpzUGFyc2UoKHNjcmlwdC5jaGlsZE5vZGVzLmxlbmd0aCkgPyBzY3JpcHQuY2hpbGROb2Rlc1swXS52YWx1ZSA6ICcnKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIC8vIEZpZ3VyZSBvdXQgdGhlIGNvcnJlY3QgbGluZSBudW1iZXIgZm9yIHRoZSBlcnJvci5cbiAgICAgIHZhciBsaW5lID0gMDtcbiAgICAgIHZhciBjb2wgPSAwO1xuICAgICAgaWYgKHNjcmlwdC5fX293bmVyRG9jdW1lbnQgJiYgc2NyaXB0Ll9fb3duZXJEb2N1bWVudCA9PSBocmVmKSB7XG4gICAgICAgIGxpbmUgPSBzY3JpcHQuX19sb2NhdGlvbkRldGFpbC5saW5lIC0gMTtcbiAgICAgICAgY29sID0gc2NyaXB0Ll9fbG9jYXRpb25EZXRhaWwuY29sdW1uIC0gMTtcbiAgICAgIH1cbiAgICAgIGxpbmUgKz0gZXJyLmxpbmVOdW1iZXI7XG4gICAgICBjb2wgKz0gZXJyLmNvbHVtbjtcbiAgICAgIHZhciBtZXNzYWdlID0gXCJFcnJvciBwYXJzaW5nIHNjcmlwdCBpbiBcIiArIGhyZWYgKyBcIiBhdCBcIiArIGxpbmUgKyBcIjpcIiArIGNvbDtcbiAgICAgIG1lc3NhZ2UgKz0gXCJcXG5cIiArIGVyci5zdGFjaztcbiAgICAgIHZhciBmaXhlZEVyciA9IG5ldyBFcnJvcihtZXNzYWdlKTtcbiAgICAgIGZpeGVkRXJyLmxvY2F0aW9uID0ge2xpbmU6IGxpbmUsIGNvbHVtbjogY29sfTtcbiAgICAgIGZpeGVkRXJyLm93bmVyRG9jdW1lbnQgPSBzY3JpcHQuX19vd25lckRvY3VtZW50O1xuICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KGZpeGVkRXJyKTtcbiAgICB9XG4gICAgaWYgKHBhcnNlZEpzLmVsZW1lbnRzKSB7XG4gICAgICBwYXJzZWRKcy5lbGVtZW50cy5mb3JFYWNoKGZ1bmN0aW9uKGVsZW1lbnQpIHtcbiAgICAgICAgZWxlbWVudC5zY3JpcHRFbGVtZW50ID0gc2NyaXB0O1xuICAgICAgICBlbGVtZW50LmNvbnRlbnRIcmVmID0gaHJlZjtcbiAgICAgICAgdGhpcy5lbGVtZW50cy5wdXNoKGVsZW1lbnQpO1xuICAgICAgICBpZiAoZWxlbWVudC5pcyBpbiB0aGlzLmVsZW1lbnRzQnlUYWdOYW1lKSB7XG4gICAgICAgICAgY29uc29sZS53YXJuKCdJZ25vcmluZyBkdXBsaWNhdGUgZWxlbWVudCBkZWZpbml0aW9uOiAnICsgZWxlbWVudC5pcyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5lbGVtZW50c0J5VGFnTmFtZVtlbGVtZW50LmlzXSA9IGVsZW1lbnQ7XG4gICAgICAgIH1cbiAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfVxuICAgIGlmIChwYXJzZWRKcy5mZWF0dXJlcykge1xuICAgICAgcGFyc2VkSnMuZmVhdHVyZXMuZm9yRWFjaChmdW5jdGlvbihmZWF0dXJlKXtcbiAgICAgICAgZmVhdHVyZS5jb250ZW50SHJlZiA9IGhyZWY7XG4gICAgICAgIGZlYXR1cmUuc2NyaXB0RWxlbWVudCA9IHNjcmlwdDtcbiAgICAgIH0pO1xuICAgICAgdGhpcy5mZWF0dXJlcyA9IHRoaXMuZmVhdHVyZXMuY29uY2F0KHBhcnNlZEpzLmZlYXR1cmVzKTtcbiAgICB9XG4gICAgaWYgKHBhcnNlZEpzLmJlaGF2aW9ycykge1xuICAgICAgcGFyc2VkSnMuYmVoYXZpb3JzLmZvckVhY2goZnVuY3Rpb24oYmVoYXZpb3Ipe1xuICAgICAgICBiZWhhdmlvci5jb250ZW50SHJlZiA9IGhyZWY7XG4gICAgICAgIHRoaXMuYmVoYXZpb3JzQnlOYW1lW2JlaGF2aW9yLmlzXSA9IGJlaGF2aW9yO1xuICAgICAgICB0aGlzLmJlaGF2aW9yc0J5TmFtZVtiZWhhdmlvci5zeW1ib2xdID0gYmVoYXZpb3I7XG4gICAgICB9LmJpbmQodGhpcykpO1xuICAgICAgdGhpcy5iZWhhdmlvcnMgPSB0aGlzLmJlaGF2aW9ycy5jb25jYXQocGFyc2VkSnMuYmVoYXZpb3JzKTtcbiAgICB9XG4gICAgaWYgKCFPYmplY3QuaGFzT3duUHJvcGVydHkuY2FsbCh0aGlzLnBhcnNlZFNjcmlwdHMsIGhyZWYpKSB7XG4gICAgICB0aGlzLnBhcnNlZFNjcmlwdHNbaHJlZl0gPSBbXTtcbiAgICB9XG4gICAgdmFyIHNjcmlwdEVsZW1lbnQ7XG4gICAgaWYgKHNjcmlwdC5fX293bmVyRG9jdW1lbnQgJiYgc2NyaXB0Ll9fb3duZXJEb2N1bWVudCA9PSBocmVmKSB7XG4gICAgICBzY3JpcHRFbGVtZW50ID0gc2NyaXB0O1xuICAgIH1cbiAgICB0aGlzLnBhcnNlZFNjcmlwdHNbaHJlZl0ucHVzaCh7XG4gICAgICBhc3Q6IHBhcnNlZEpzLnBhcnNlZFNjcmlwdCxcbiAgICAgIHNjcmlwdEVsZW1lbnQ6IHNjcmlwdEVsZW1lbnRcbiAgICB9KTtcbiAgICByZXR1cm4gcGFyc2VkSnM7XG4gIH1cbiAgaWYgKHRoaXMubG9hZGVyKSB7XG4gICAgdmFyIHJlc29sdmVkU3JjID0gdXJsLnJlc29sdmUoaHJlZiwgc3JjKTtcbiAgICByZXR1cm4gdGhpcy5sb2FkZXIucmVxdWVzdChyZXNvbHZlZFNyYykudGhlbihmdW5jdGlvbihjb250ZW50KSB7XG4gICAgICB0aGlzLl9jb250ZW50W3Jlc29sdmVkU3JjXSA9IGNvbnRlbnQ7XG4gICAgICB2YXIgcmVzb2x2ZWRTY3JpcHQgPSBPYmplY3QuY3JlYXRlKHNjcmlwdCk7XG4gICAgICByZXNvbHZlZFNjcmlwdC5jaGlsZE5vZGVzID0gW3t2YWx1ZTogY29udGVudH1dO1xuICAgICAgcmVzb2x2ZWRTY3JpcHQuYXR0cnMgPSByZXNvbHZlZFNjcmlwdC5hdHRycy5zbGljZSgpO1xuICAgICAgZG9tNS5yZW1vdmVBdHRyaWJ1dGUocmVzb2x2ZWRTY3JpcHQsICdzcmMnKTtcbiAgICAgIHJldHVybiB0aGlzLl9wcm9jZXNzU2NyaXB0KHJlc29sdmVkU2NyaXB0LCByZXNvbHZlZFNyYyk7XG4gICAgfS5iaW5kKHRoaXMpKS5jYXRjaChmdW5jdGlvbihlcnIpIHt0aHJvdyBlcnI7fSk7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShFTVBUWV9NRVRBREFUQSk7XG4gIH1cbn07XG5cbkFuYWx5emVyLnByb3RvdHlwZS5fZGVwZW5kZW5jaWVzTG9hZGVkRm9yID0gZnVuY3Rpb24gX2RlcGVuZGVuY2llc0xvYWRlZEZvcihocmVmLCByb290KSB7XG4gIHZhciBmb3VuZCA9IHt9O1xuICBpZiAocm9vdCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgZm91bmRbcm9vdF0gPSB0cnVlO1xuICB9XG4gIHJldHVybiB0aGlzLl9nZXREZXBlbmRlbmNpZXMoaHJlZiwgZm91bmQpLnRoZW4oZnVuY3Rpb24oZGVwcykge1xuICAgIHZhciBkZXBNZXRhZGF0YUxvYWRlZCA9IFtdO1xuICAgIHZhciBkZXBQcm9taXNlcyA9IGRlcHMubWFwKGZ1bmN0aW9uKGRlcEhyZWYpe1xuICAgICAgcmV0dXJuIHRoaXMubG9hZChkZXBIcmVmKS50aGVuKGZ1bmN0aW9uKGh0bWxNb25vbWVyKSB7XG4gICAgICAgIHJldHVybiBodG1sTW9ub21lci5tZXRhZGF0YUxvYWRlZDtcbiAgICAgIH0pO1xuICAgIH0uYmluZCh0aGlzKSk7XG4gICAgcmV0dXJuIFByb21pc2UuYWxsKGRlcFByb21pc2VzKTtcbiAgfS5iaW5kKHRoaXMpKTtcbn07XG5cbi8qKlxuICogTGlzdCBhbGwgdGhlIGh0bWwgZGVwZW5kZW5jaWVzIGZvciB0aGUgZG9jdW1lbnQgYXQgYGhyZWZgLlxuICogQHBhcmFtICB7c3RyaW5nfSAgICAgICAgICAgICAgICAgICBocmVmICAgICAgVGhlIGhyZWYgdG8gZ2V0IGRlcGVuZGVuY2llcyBmb3IuXG4gKiBAcGFyYW0gIHtPYmplY3QuPHN0cmluZyxib29sZWFuPj19IGZvdW5kICAgICBBbiBvYmplY3Qga2V5ZWQgYnkgVVJMIG9mIHRoZVxuICogICAgIGFscmVhZHkgcmVzb2x2ZWQgZGVwZW5kZW5jaWVzLlxuICogQHBhcmFtICB7Ym9vbGVhbj19ICAgICAgICAgICAgICAgIHRyYW5zaXRpdmUgV2hldGhlciB0byBsb2FkIHRyYW5zaXRpdmVcbiAqICAgICBkZXBlbmRlbmNpZXMuIERlZmF1bHRzIHRvIHRydWUuXG4gKiBAcmV0dXJuIHtBcnJheS48c3RyaW5nPn0gIEEgbGlzdCBvZiBhbGwgdGhlIGh0bWwgZGVwZW5kZW5jaWVzLlxuICovXG5BbmFseXplci5wcm90b3R5cGUuX2dldERlcGVuZGVuY2llcyA9IGZ1bmN0aW9uIF9nZXREZXBlbmRlbmNpZXMoaHJlZiwgZm91bmQsIHRyYW5zaXRpdmUpIHtcbiAgaWYgKGZvdW5kID09PSB1bmRlZmluZWQpIHtcbiAgICBmb3VuZCA9IHt9O1xuICAgIGZvdW5kW2hyZWZdID0gdHJ1ZTtcbiAgfVxuICBpZiAodHJhbnNpdGl2ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgdHJhbnNpdGl2ZSA9IHRydWU7XG4gIH1cbiAgdmFyIGRlcHMgPSBbXTtcbiAgcmV0dXJuIHRoaXMubG9hZChocmVmKS50aGVuKGZ1bmN0aW9uKGh0bWxNb25vbWVyKSB7XG4gICAgdmFyIHRyYW5zaXRpdmVEZXBzID0gW107XG4gICAgaHRtbE1vbm9tZXIuZGVwSHJlZnMuZm9yRWFjaChmdW5jdGlvbihkZXBIcmVmKXtcbiAgICAgIGlmIChmb3VuZFtkZXBIcmVmXSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBkZXBzLnB1c2goZGVwSHJlZik7XG4gICAgICBmb3VuZFtkZXBIcmVmXSA9IHRydWU7XG4gICAgICBpZiAodHJhbnNpdGl2ZSkge1xuICAgICAgICB0cmFuc2l0aXZlRGVwcy5wdXNoKHRoaXMuX2dldERlcGVuZGVuY2llcyhkZXBIcmVmLCBmb3VuZCkpO1xuICAgICAgfVxuICAgIH0uYmluZCh0aGlzKSk7XG4gICAgcmV0dXJuIFByb21pc2UuYWxsKHRyYW5zaXRpdmVEZXBzKTtcbiAgfS5iaW5kKHRoaXMpKS50aGVuKGZ1bmN0aW9uKHRyYW5zaXRpdmVEZXBzKSB7XG4gICAgdmFyIGFsbGRlcHMgPSB0cmFuc2l0aXZlRGVwcy5yZWR1Y2UoZnVuY3Rpb24oYSwgYikge1xuICAgICAgcmV0dXJuIGEuY29uY2F0KGIpO1xuICAgIH0sIFtdKS5jb25jYXQoZGVwcyk7XG4gICAgcmV0dXJuIGFsbGRlcHM7XG4gIH0pO1xufTtcblxuZnVuY3Rpb24gbWF0Y2hlc0RvY3VtZW50Rm9sZGVyKGRlc2NyaXB0b3IsIGhyZWYpIHtcbiAgaWYgKCFkZXNjcmlwdG9yLmNvbnRlbnRIcmVmKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIHZhciBkZXNjcmlwdG9yRG9jID0gdXJsLnBhcnNlKGRlc2NyaXB0b3IuY29udGVudEhyZWYpO1xuICBpZiAoIWRlc2NyaXB0b3JEb2MgfHwgIWRlc2NyaXB0b3JEb2MucGF0aG5hbWUpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgdmFyIHNlYXJjaERvYyA9IHVybC5wYXJzZShocmVmKTtcbiAgaWYgKCFzZWFyY2hEb2MgfHwgIXNlYXJjaERvYy5wYXRobmFtZSkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICB2YXIgc2VhcmNoUGF0aCA9IHNlYXJjaERvYy5wYXRobmFtZTtcbiAgdmFyIGxhc3RTbGFzaCA9IHNlYXJjaFBhdGgubGFzdEluZGV4T2YoXCIvXCIpO1xuICBpZiAobGFzdFNsYXNoID4gMCkge1xuICAgIHNlYXJjaFBhdGggPSBzZWFyY2hQYXRoLnNsaWNlKDAsIGxhc3RTbGFzaCk7XG4gIH1cbiAgcmV0dXJuIGRlc2NyaXB0b3JEb2MucGF0aG5hbWUuaW5kZXhPZihzZWFyY2hQYXRoKSA9PT0gMDtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBlbGVtZW50cyBkZWZpbmVkIGluIHRoZSBmb2xkZXIgY29udGFpbmluZyBgaHJlZmAuXG4gKiBAcGFyYW0ge3N0cmluZ30gaHJlZiBwYXRoIHRvIHNlYXJjaC5cbiAqIEByZXR1cm4ge0FycmF5LjxFbGVtZW50RGVzY3JpcHRvcj59XG4gKi9cbkFuYWx5emVyLnByb3RvdHlwZS5lbGVtZW50c0ZvckZvbGRlciA9IGZ1bmN0aW9uIGVsZW1lbnRzRm9yRm9sZGVyKGhyZWYpIHtcbiAgcmV0dXJuIHRoaXMuZWxlbWVudHMuZmlsdGVyKGZ1bmN0aW9uKGVsZW1lbnQpe1xuICAgIHJldHVybiBtYXRjaGVzRG9jdW1lbnRGb2xkZXIoZWxlbWVudCwgaHJlZik7XG4gIH0pO1xufTtcblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBiZWhhdmlvcnMgZGVmaW5lZCBpbiB0aGUgZm9sZGVyIGNvbnRhaW5pbmcgYGhyZWZgLlxuICogQHBhcmFtIHtzdHJpbmd9IGhyZWYgcGF0aCB0byBzZWFyY2guXG4gKiBAcmV0dXJuIHtBcnJheS48QmVoYXZpb3JEZXNjcmlwdG9yPn1cbiAqL1xuQW5hbHl6ZXIucHJvdG90eXBlLmJlaGF2aW9yc0ZvckZvbGRlciA9IGZ1bmN0aW9uIGJlaGF2aW9yc0ZvckZvbGRlcihocmVmKSB7XG4gIHJldHVybiB0aGlzLmJlaGF2aW9ycy5maWx0ZXIoZnVuY3Rpb24oYmVoYXZpb3Ipe1xuICAgIHJldHVybiBtYXRjaGVzRG9jdW1lbnRGb2xkZXIoYmVoYXZpb3IsIGhyZWYpO1xuICB9KTtcbn07XG5cbi8qKlxuICogUmV0dXJucyBhIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhIFBPSk8gcmVwcmVzZW50YXRpb24gb2YgdGhlIGltcG9ydFxuICogdHJlZSwgaW4gYSBmb3JtYXQgdGhhdCBtYWludGFpbnMgdGhlIG9yZGVyaW5nIG9mIHRoZSBIVE1MIGltcG9ydHMgc3BlYy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBocmVmIHRoZSBpbXBvcnQgdG8gZ2V0IG1ldGFkYXRhIGZvci5cbiAqIEByZXR1cm4ge1Byb21pc2V9XG4gKi9cbkFuYWx5emVyLnByb3RvdHlwZS5tZXRhZGF0YVRyZWUgPSBmdW5jdGlvbiBtZXRhZGF0YVRyZWUoaHJlZikge1xuICByZXR1cm4gdGhpcy5sb2FkKGhyZWYpLnRoZW4oZnVuY3Rpb24obW9ub21lcil7XG4gICAgdmFyIGxvYWRlZEhyZWZzID0ge307XG4gICAgbG9hZGVkSHJlZnNbaHJlZl0gPSB0cnVlO1xuICAgIHJldHVybiB0aGlzLl9tZXRhZGF0YVRyZWUobW9ub21lciwgbG9hZGVkSHJlZnMpO1xuICB9LmJpbmQodGhpcykpO1xufTtcblxuQW5hbHl6ZXIucHJvdG90eXBlLl9tZXRhZGF0YVRyZWUgPSBmdW5jdGlvbiBfbWV0YWRhdGFUcmVlKGh0bWxNb25vbWVyLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvYWRlZEhyZWZzKSB7XG4gIGlmIChsb2FkZWRIcmVmcyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgbG9hZGVkSHJlZnMgPSB7fTtcbiAgfVxuICByZXR1cm4gaHRtbE1vbm9tZXIubWV0YWRhdGFMb2FkZWQudGhlbihmdW5jdGlvbihtZXRhZGF0YSkge1xuICAgIG1ldGFkYXRhID0ge1xuICAgICAgZWxlbWVudHM6IG1ldGFkYXRhLmVsZW1lbnRzLFxuICAgICAgZmVhdHVyZXM6IG1ldGFkYXRhLmZlYXR1cmVzLFxuICAgICAgaHJlZjogaHRtbE1vbm9tZXIuaHJlZlxuICAgIH07XG4gICAgcmV0dXJuIGh0bWxNb25vbWVyLmRlcHNMb2FkZWQudGhlbihmdW5jdGlvbihocmVmcykge1xuICAgICAgdmFyIGRlcE1ldGFkYXRhID0gW107XG4gICAgICBocmVmcy5mb3JFYWNoKGZ1bmN0aW9uKGhyZWYpIHtcbiAgICAgICAgdmFyIG1ldGFkYXRhUHJvbWlzZSA9IFByb21pc2UucmVzb2x2ZSh0cnVlKTtcbiAgICAgICAgaWYgKGRlcE1ldGFkYXRhLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICBtZXRhZGF0YVByb21pc2UgPSBkZXBNZXRhZGF0YVtkZXBNZXRhZGF0YS5sZW5ndGggLSAxXTtcbiAgICAgICAgfVxuICAgICAgICBtZXRhZGF0YVByb21pc2UgPSBtZXRhZGF0YVByb21pc2UudGhlbihmdW5jdGlvbigpIHtcbiAgICAgICAgICBpZiAoIWxvYWRlZEhyZWZzW2hyZWZdKSB7XG4gICAgICAgICAgICBsb2FkZWRIcmVmc1tocmVmXSA9IHRydWU7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fbWV0YWRhdGFUcmVlKHRoaXMuaHRtbFtocmVmXSwgbG9hZGVkSHJlZnMpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHt9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgICAgIGRlcE1ldGFkYXRhLnB1c2gobWV0YWRhdGFQcm9taXNlKTtcbiAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgICByZXR1cm4gUHJvbWlzZS5hbGwoZGVwTWV0YWRhdGEpLnRoZW4oZnVuY3Rpb24oaW1wb3J0TWV0YWRhdGEpIHtcbiAgICAgICAgbWV0YWRhdGEuaW1wb3J0cyA9IGltcG9ydE1ldGFkYXRhO1xuICAgICAgICByZXR1cm4gaHRtbE1vbm9tZXIuaHRtbExvYWRlZC50aGVuKGZ1bmN0aW9uKHBhcnNlZEh0bWwpIHtcbiAgICAgICAgICBtZXRhZGF0YS5odG1sID0gcGFyc2VkSHRtbDtcbiAgICAgICAgICBpZiAobWV0YWRhdGEuZWxlbWVudHMpIHtcbiAgICAgICAgICAgIG1ldGFkYXRhLmVsZW1lbnRzLmZvckVhY2goZnVuY3Rpb24oZWxlbWVudCkge1xuICAgICAgICAgICAgICBhdHRhY2hEb21Nb2R1bGUocGFyc2VkSHRtbCwgZWxlbWVudCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIG1ldGFkYXRhO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0uYmluZCh0aGlzKSk7XG4gIH0uYmluZCh0aGlzKSk7XG59O1xuXG5mdW5jdGlvbiBtYXRjaGluZ0ltcG9ydChpbXBvcnRFbGVtZW50KSB7XG4gIHZhciBtYXRjaGVzVGFnID0gZG9tNS5wcmVkaWNhdGVzLmhhc1RhZ05hbWUoaW1wb3J0RWxlbWVudC50YWdOYW1lKTtcbiAgdmFyIG1hdGNoZXNIcmVmID0gZG9tNS5wcmVkaWNhdGVzLmhhc0F0dHJWYWx1ZSgnaHJlZicsIGRvbTUuZ2V0QXR0cmlidXRlKGltcG9ydEVsZW1lbnQsICdocmVmJykpO1xuICB2YXIgbWF0Y2hlc1JlbCA9IGRvbTUucHJlZGljYXRlcy5oYXNBdHRyVmFsdWUoJ3JlbCcsIGRvbTUuZ2V0QXR0cmlidXRlKGltcG9ydEVsZW1lbnQsICdyZWwnKSk7XG4gIHJldHVybiBkb201LnByZWRpY2F0ZXMuQU5EKG1hdGNoZXNUYWcsIG1hdGNoZXNIcmVmLCBtYXRjaGVzUmVsKTtcbn1cblxuLy8gVE9ETyhham8pOiBSZWZhY3RvciBvdXQgb2YgdnVsY2FuaXplIGludG8gZG9tNS5cbnZhciBwb2x5bWVyRXh0ZXJuYWxTdHlsZSA9IGRvbTUucHJlZGljYXRlcy5BTkQoXG4gIGRvbTUucHJlZGljYXRlcy5oYXNUYWdOYW1lKCdsaW5rJyksXG4gIGRvbTUucHJlZGljYXRlcy5oYXNBdHRyVmFsdWUoJ3JlbCcsICdpbXBvcnQnKSxcbiAgZG9tNS5wcmVkaWNhdGVzLmhhc0F0dHJWYWx1ZSgndHlwZScsICdjc3MnKVxuKTtcblxudmFyIGV4dGVybmFsU2NyaXB0ID0gZG9tNS5wcmVkaWNhdGVzLkFORChcbiAgZG9tNS5wcmVkaWNhdGVzLmhhc1RhZ05hbWUoJ3NjcmlwdCcpLFxuICBkb201LnByZWRpY2F0ZXMuaGFzQXR0cignc3JjJylcbik7XG5cbnZhciBpc0h0bWxJbXBvcnROb2RlID0gZG9tNS5wcmVkaWNhdGVzLkFORChcbiAgZG9tNS5wcmVkaWNhdGVzLmhhc1RhZ05hbWUoJ2xpbmsnKSxcbiAgZG9tNS5wcmVkaWNhdGVzLmhhc0F0dHJWYWx1ZSgncmVsJywgJ2ltcG9ydCcpLFxuICBkb201LnByZWRpY2F0ZXMuTk9UKFxuICAgIGRvbTUucHJlZGljYXRlcy5oYXNBdHRyVmFsdWUoJ3R5cGUnLCAnY3NzJylcbiAgKVxuKTtcblxuQW5hbHl6ZXIucHJvdG90eXBlLl9pbmxpbmVTdHlsZXMgPSBmdW5jdGlvbiBfaW5saW5lU3R5bGVzKGFzdCwgaHJlZikge1xuICB2YXIgY3NzTGlua3MgPSBkb201LnF1ZXJ5QWxsKGFzdCwgcG9seW1lckV4dGVybmFsU3R5bGUpO1xuICBjc3NMaW5rcy5mb3JFYWNoKGZ1bmN0aW9uKGxpbmspIHtcbiAgICB2YXIgbGlua0hyZWYgPSBkb201LmdldEF0dHJpYnV0ZShsaW5rLCAnaHJlZicpO1xuICAgIHZhciB1cmkgPSB1cmwucmVzb2x2ZShocmVmLCBsaW5rSHJlZik7XG4gICAgdmFyIGNvbnRlbnQgPSB0aGlzLl9jb250ZW50W3VyaV07XG4gICAgdmFyIHN0eWxlID0gZG9tNS5jb25zdHJ1Y3RvcnMuZWxlbWVudCgnc3R5bGUnKTtcbiAgICBkb201LnNldFRleHRDb250ZW50KHN0eWxlLCAnXFxuJyArIGNvbnRlbnQgKyAnXFxuJyk7XG4gICAgZG9tNS5yZXBsYWNlKGxpbmssIHN0eWxlKTtcbiAgfS5iaW5kKHRoaXMpKTtcbiAgcmV0dXJuIGNzc0xpbmtzLmxlbmd0aCA+IDA7XG59O1xuXG5BbmFseXplci5wcm90b3R5cGUuX2lubGluZVNjcmlwdHMgPSBmdW5jdGlvbiBfaW5saW5lU2NyaXB0cyhhc3QsIGhyZWYpIHtcbiAgdmFyIHNjcmlwdHMgPSBkb201LnF1ZXJ5QWxsKGFzdCwgZXh0ZXJuYWxTY3JpcHQpO1xuICBzY3JpcHRzLmZvckVhY2goZnVuY3Rpb24oc2NyaXB0KSB7XG4gICAgdmFyIHNjcmlwdEhyZWYgPSBkb201LmdldEF0dHJpYnV0ZShzY3JpcHQsICdzcmMnKTtcbiAgICB2YXIgdXJpID0gdXJsLnJlc29sdmUoaHJlZiwgc2NyaXB0SHJlZik7XG4gICAgdmFyIGNvbnRlbnQgPSB0aGlzLl9jb250ZW50W3VyaV07XG4gICAgdmFyIGlubGluZWQgPSBkb201LmNvbnN0cnVjdG9ycy5lbGVtZW50KCdzY3JpcHQnKTtcbiAgICBkb201LnNldFRleHRDb250ZW50KGlubGluZWQsICdcXG4nICsgY29udGVudCArICdcXG4nKTtcbiAgICBkb201LnJlcGxhY2Uoc2NyaXB0LCBpbmxpbmVkKTtcbiAgfS5iaW5kKHRoaXMpKTtcbiAgcmV0dXJuIHNjcmlwdHMubGVuZ3RoID4gMDtcbn07XG5cbkFuYWx5emVyLnByb3RvdHlwZS5faW5saW5lSW1wb3J0cyA9IGZ1bmN0aW9uIF9pbmxpbmVJbXBvcnRzKGFzdCwgaHJlZiwgbG9hZGVkKSB7XG4gIHZhciBpbXBvcnRzID0gZG9tNS5xdWVyeUFsbChhc3QsIGlzSHRtbEltcG9ydE5vZGUpO1xuICBpbXBvcnRzLmZvckVhY2goZnVuY3Rpb24oaHRtbEltcG9ydCkge1xuICAgIHZhciBpbXBvcnRIcmVmID0gZG9tNS5nZXRBdHRyaWJ1dGUoaHRtbEltcG9ydCwgJ2hyZWYnKTtcbiAgICB2YXIgdXJpID0gdXJsLnJlc29sdmUoaHJlZiwgaW1wb3J0SHJlZik7XG4gICAgaWYgKGxvYWRlZFt1cmldKSB7XG4gICAgICBkb201LnJlbW92ZShodG1sSW1wb3J0KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdmFyIGNvbnRlbnQgPSB0aGlzLmdldExvYWRlZEFzdCh1cmksIGxvYWRlZCk7XG4gICAgZG9tNS5yZXBsYWNlKGh0bWxJbXBvcnQsIGNvbnRlbnQpO1xuICB9LmJpbmQodGhpcykpO1xuICByZXR1cm4gaW1wb3J0cy5sZW5ndGggPiAwO1xufTtcblxuLyoqXG4gKiBSZXR1cm5zIGEgcHJvbWlzZSByZXNvbHZpbmcgdG8gYSBmb3JtIG9mIHRoZSBBU1Qgd2l0aCBhbGwgbGlua3MgcmVwbGFjZWRcbiAqIHdpdGggdGhlIGRvY3VtZW50IHRoZXkgbGluayB0by4gLmNzcyBhbmQgLnNjcmlwdCBmaWxlcyBiZWNvbWUgJmx0O3N0eWxlJmd0OyBhbmRcbiAqICZsdDtzY3JpcHQmZ3Q7LCByZXNwZWN0aXZlbHkuXG4gKlxuICogVGhlIGVsZW1lbnRzIGluIHRoZSBsb2FkZWQgZG9jdW1lbnQgYXJlIHVubW9kaWZpZWQgZnJvbSB0aGVpciBvcmlnaW5hbFxuICogZG9jdW1lbnRzLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBocmVmIFRoZSBkb2N1bWVudCB0byBsb2FkLlxuICogQHBhcmFtIHtPYmplY3QuPHN0cmluZyxib29sZWFuPj19IGxvYWRlZCBBbiBvYmplY3Qga2V5ZWQgYnkgYWxyZWFkeSBsb2FkZWQgZG9jdW1lbnRzLlxuICogQHJldHVybiB7UHJvbWlzZS48RG9jdW1lbnRBU1Q+fVxuICovXG5BbmFseXplci5wcm90b3R5cGUuZ2V0TG9hZGVkQXN0ID0gZnVuY3Rpb24gZ2V0TG9hZGVkQXN0KGhyZWYsIGxvYWRlZCkge1xuICBpZiAoIWxvYWRlZCkge1xuICAgIGxvYWRlZCA9IHt9O1xuICB9XG4gIGxvYWRlZFtocmVmXSA9IHRydWU7XG4gIHZhciBwYXJzZWREb2N1bWVudCA9IHRoaXMucGFyc2VkRG9jdW1lbnRzW2hyZWZdO1xuICB2YXIgYW5hbHl6ZWREb2N1bWVudCA9IHRoaXMuaHRtbFtocmVmXTtcbiAgdmFyIGFzdENvcHkgPSBkb201LnBhcnNlKGRvbTUuc2VyaWFsaXplKHBhcnNlZERvY3VtZW50KSk7XG4gIC8vIFdoZW5ldmVyIHdlIGlubGluZSBzb21ldGhpbmcsIHJlc2V0IGlubGluZWQgdG8gdHJ1ZSB0byBrbm93IHRoYXQgYW5vYXRoZXJcbiAgLy8gaW5saW5pbmcgcGFzcyBpcyBuZWVkZWQ7XG4gIHRoaXMuX2lubGluZVN0eWxlcyhhc3RDb3B5LCBocmVmKTtcbiAgdGhpcy5faW5saW5lU2NyaXB0cyhhc3RDb3B5LCBocmVmKTtcbiAgdGhpcy5faW5saW5lSW1wb3J0cyhhc3RDb3B5LCBocmVmLCBsb2FkZWQpO1xuICByZXR1cm4gYXN0Q29weTtcbn07XG5cbi8qKlxuICogQ2FsbHMgYGRvbTUubm9kZVdhbGtBbGxgIG9uIGVhY2ggZG9jdW1lbnQgdGhhdCBgQW5heXpsZXJgIGhhcyBsYW9kZWQuXG4gKiBAcGFyYW0gIHtPYmplY3R9IHByZWRpY2F0ZSBBIGRvbTUgcHJlZGljYXRlLlxuICogQHJldHVybiB7T2JqZWN0fVxuICovXG5BbmFseXplci5wcm90b3R5cGUubm9kZVdhbGtEb2N1bWVudHMgPSBmdW5jdGlvbiBub2RlV2Fsa0RvY3VtZW50cyhwcmVkaWNhdGUpIHtcbiAgZm9yICh2YXIgaHJlZiBpbiB0aGlzLnBhcnNlZERvY3VtZW50cykge1xuICAgIHZhciBtYXRjaCA9IGRvbTUubm9kZVdhbGsodGhpcy5wYXJzZWREb2N1bWVudHNbaHJlZl0sIHByZWRpY2F0ZSk7XG4gICAgaWYgKG1hdGNoKSB7XG4gICAgICByZXR1cm4gbWF0Y2g7XG4gICAgfVxuICB9XG4gIHJldHVybiBudWxsO1xufTtcblxuLyoqXG4gKiBDYWxscyBgZG9tNS5ub2RlV2Fsa0FsbGAgb24gZWFjaCBkb2N1bWVudCB0aGF0IGBBbmF5emxlcmAgaGFzIGxhb2RlZC5cbiAqIEBwYXJhbSAge09iamVjdH0gcHJlZGljYXRlIEEgZG9tNSBwcmVkaWNhdGUuXG4gKiBAcmV0dXJuIHtPYmplY3R9XG4gKi9cbkFuYWx5emVyLnByb3RvdHlwZS5ub2RlV2Fsa0FsbERvY3VtZW50cyA9IGZ1bmN0aW9uIG5vZGVXYWxrRG9jdW1lbnRzKHByZWRpY2F0ZSkge1xuICB2YXIgcmVzdWx0cyA9IFtdO1xuICBmb3IgKHZhciBocmVmIGluIHRoaXMucGFyc2VkRG9jdW1lbnRzKSB7XG4gICAgdmFyIG5ld05vZGVzID0gZG9tNS5ub2RlV2Fsa0FsbCh0aGlzLnBhcnNlZERvY3VtZW50c1tocmVmXSwgcHJlZGljYXRlKTtcbiAgICByZXN1bHRzID0gcmVzdWx0cy5jb25jYXQobmV3Tm9kZXMpO1xuICB9XG4gIHJldHVybiByZXN1bHRzO1xufTtcblxuLyoqIEFubm90YXRlcyBhbGwgbG9hZGVkIG1ldGFkYXRhIHdpdGggaXRzIGRvY3VtZW50YXRpb24uICovXG5BbmFseXplci5wcm90b3R5cGUuYW5ub3RhdGUgPSBmdW5jdGlvbiBhbm5vdGF0ZSgpIHtcbiAgaWYgKHRoaXMuZmVhdHVyZXMubGVuZ3RoID4gMCkge1xuICAgIHZhciBmZWF0dXJlRWwgPSBkb2NzLmZlYXR1cmVFbGVtZW50KHRoaXMuZmVhdHVyZXMpO1xuICAgIHRoaXMuZWxlbWVudHMudW5zaGlmdChmZWF0dXJlRWwpO1xuICAgIHRoaXMuZWxlbWVudHNCeVRhZ05hbWVbZmVhdHVyZUVsLmlzXSA9IGZlYXR1cmVFbDtcbiAgfVxuICB2YXIgYmVoYXZpb3JzQnlOYW1lID0gdGhpcy5iZWhhdmlvcnNCeU5hbWU7XG4gIHZhciBlbGVtZW50SGVscGVyID0gZnVuY3Rpb24oZGVzY3JpcHRvcil7XG4gICAgZG9jcy5hbm5vdGF0ZUVsZW1lbnQoZGVzY3JpcHRvciwgYmVoYXZpb3JzQnlOYW1lKTtcbiAgfTtcbiAgdGhpcy5lbGVtZW50cy5mb3JFYWNoKGVsZW1lbnRIZWxwZXIpO1xuICB0aGlzLmJlaGF2aW9ycy5mb3JFYWNoKGVsZW1lbnRIZWxwZXIpOyAvLyBTYW1lIHNoYXBlLlxuICB0aGlzLmJlaGF2aW9ycy5mb3JFYWNoKGZ1bmN0aW9uKGJlaGF2aW9yKXtcbiAgICBpZiAoYmVoYXZpb3IuaXMgIT09IGJlaGF2aW9yLnN5bWJvbCAmJiBiZWhhdmlvci5zeW1ib2wpIHtcbiAgICAgIHRoaXMuYmVoYXZpb3JzQnlOYW1lW2JlaGF2aW9yLnN5bWJvbF0gPSB1bmRlZmluZWQ7XG4gICAgfVxuICB9LmJpbmQodGhpcykpO1xufTtcblxuZnVuY3Rpb24gYXR0YWNoRG9tTW9kdWxlKHBhcnNlZEltcG9ydCwgZWxlbWVudCkge1xuICB2YXIgZG9tTW9kdWxlcyA9IHBhcnNlZEltcG9ydFsnZG9tLW1vZHVsZSddO1xuICBmb3IgKHZhciBpID0gMCwgZG9tTW9kdWxlOyBpIDwgZG9tTW9kdWxlcy5sZW5ndGg7IGkrKykge1xuICAgIGRvbU1vZHVsZSA9IGRvbU1vZHVsZXNbaV07XG4gICAgaWYgKGRvbTUuZ2V0QXR0cmlidXRlKGRvbU1vZHVsZSwgJ2lkJykgPT09IGVsZW1lbnQuaXMpIHtcbiAgICAgIGVsZW1lbnQuZG9tTW9kdWxlID0gZG9tTW9kdWxlO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgfVxufVxuXG4vKiogUmVtb3ZlcyByZWR1bmRhbnQgcHJvcGVydGllcyBmcm9tIHRoZSBjb2xsZWN0ZWQgZGVzY3JpcHRvcnMuICovXG5BbmFseXplci5wcm90b3R5cGUuY2xlYW4gPSBmdW5jdGlvbiBjbGVhbigpIHtcbiAgdGhpcy5lbGVtZW50cy5mb3JFYWNoKGRvY3MuY2xlYW5FbGVtZW50KTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gQW5hbHl6ZXI7XG4iXX0= },{"./ast-utils/docs":6,"./ast-utils/import-parse":11,"./ast-utils/js-parse":12,"./loader/error-swallowing-fs-resolver":14,"./loader/file-loader":15,"./loader/fs-resolver":16,"./loader/noop-resolver":17,"./loader/string-resolver":19,"./loader/xhr-resolver":20,"dom5":36,"es6-promise":58,"url":29}],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":8}],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; var propertyHandlers = null; /** * 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 observers behaviors[i].observers = (behaviors[i].observers || []).concat(newBehavior.observers || []); // 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}; }) }; propertyHandlers = declarationPropertyHandlers(currentBehavior); docs.annotateBehavior(currentBehavior); // Make sure that we actually parsed a behavior tag! if (!jsdoc.hasTag(currentBehavior.jsdoc, 'polymerBehavior') && symbol !== templatizer) { currentBehavior = null; propertyHandlers = 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); propertyHandlers = declarationPropertyHandlers(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.observers) currentBehavior.observers = []; if (!currentBehavior.properties) currentBehavior.properties = []; if (behaviors.indexOf(currentBehavior) === -1) behaviors.push(currentBehavior); currentBehavior = null; propertyHandlers = 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 || []; currentBehavior.observers = currentBehavior.observers || []; 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,"./declaration-property-handlers":5,"./docs":6,"./esutil":8,"./jsdoc":13,"estraverse":70}],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 */ // jshint node: true 'use strict'; var astValue = require('./ast-value'); var analyzeProperties = require('./analyze-properties'); /** * Returns an object containing functions that will annotate `declaration` with * the polymer-specificmeaning of the value nodes for the named properties. * * @param {ElementDescriptor} declaration The descriptor to annotate. * @return {object.} An object containing property * handlers. */ function declarationPropertyHandlers(declaration) { return { is: function(node) { if (node.type == 'Literal') { declaration.is = node.value; } }, properties: function(node) { var props = analyzeProperties(node); for (var i=0; i. * * @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 `