made with requirebin
Last active
April 25, 2017 03:14
-
-
Save tholman/8471aa2108bff253894fbcfb9deb80b5 to your computer and use it in GitHub Desktop.
requirebin sketch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Welcome! require() some modules from npm (like you were using browserify) | |
// and then hit Run Code to run your code on the right side. | |
// Modules get downloaded from browserify-cdn and bundled in your browser. | |
require('@emmetio/abbreviation'); | |
require('@emmetio/html-transform'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
setTimeout(function(){ | |
;require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | |
'use strict'; | |
/** | |
* Attribute descriptor of parsed abbreviation node | |
* @param {String} name Attribute name | |
* @param {String} value Attribute value | |
* @param {Object} options Additional custom attribute options | |
* @param {Boolean} options.boolean Attribute is boolean (e.g. name equals value) | |
* @param {Boolean} options.implied Attribute is implied (e.g. must be outputted | |
* only if contains non-null value) | |
*/ | |
class Attribute { | |
constructor(name, value, options) { | |
this.name = name; | |
this.value = value != null ? value : null; | |
this.options = options || {}; | |
} | |
/** | |
* Create a copy of current attribute | |
* @return {Attribute} | |
*/ | |
clone() { | |
return new Attribute(this.name, this.value, Object.assign({}, this.options)); | |
} | |
/** | |
* A string representation of current node | |
*/ | |
valueOf() { | |
return `${this.name}="${this.value}"`; | |
} | |
} | |
/** | |
* A parsed abbreviation AST node. Nodes build up an abbreviation AST tree | |
*/ | |
class Node { | |
/** | |
* Creates a new node | |
* @param {String} [name] Node name | |
* @param {Array} [attributes] Array of attributes to add | |
*/ | |
constructor(name, attributes) { | |
// own properties | |
this.name = name || null; | |
this.value = null; | |
this.repeat = null; | |
this.selfClosing = false; | |
this.children = []; | |
/** @type {Node} Pointer to parent node */ | |
this.parent = null; | |
/** @type {Node} Pointer to next sibling */ | |
this.next = null; | |
/** @type {Node} Pointer to previous sibling */ | |
this.previous = null; | |
this._attributes = []; | |
if (Array.isArray(attributes)) { | |
attributes.forEach(attr => this.setAttribute(attr)); | |
} | |
} | |
/** | |
* Array of current node attributes | |
* @return {Attribute[]} Array of attributes | |
*/ | |
get attributes() { | |
return this._attributes; | |
} | |
/** | |
* A shorthand to retreive node attributes as map | |
* @return {Object} | |
*/ | |
get attributesMap() { | |
return this.attributes.reduce((out, attr) => { | |
out[attr.name] = attr.options.boolean ? attr.name : attr.value; | |
return out; | |
}, {}); | |
} | |
/** | |
* Check if current node is a grouping one, e.g. has no actual representation | |
* and is used for grouping subsequent nodes only | |
* @return {Boolean} | |
*/ | |
get isGroup() { | |
return !this.name && !this.value && !this._attributes.length; | |
} | |
/** | |
* Check if given node is a text-only node, e.g. contains only value | |
* @return {Boolean} | |
*/ | |
get isTextOnly() { | |
return !this.name && !!this.value && !this._attributes.length; | |
} | |
/** | |
* Returns first child node | |
* @return {Node} | |
*/ | |
get firstChild() { | |
return this.children[0]; | |
} | |
/** | |
* Returns last child of current node | |
* @return {Node} | |
*/ | |
get lastChild() { | |
return this.children[this.children.length - 1]; | |
} | |
/** | |
* Return index of current node in its parent child list | |
* @return {Number} Returns -1 if current node is a root one | |
*/ | |
get childIndex() { | |
return this.parent ? this.parent.children.indexOf(this) : -1; | |
} | |
/** | |
* Returns next sibling of current node | |
* @return {Node} | |
*/ | |
get nextSibling() { | |
return this.next; | |
} | |
/** | |
* Returns previous sibling of current node | |
* @return {Node} | |
*/ | |
get previousSibling() { | |
return this.previous; | |
} | |
/** | |
* Returns array of unique class names in current node | |
* @return {String[]} | |
*/ | |
get classList() { | |
const attr = this.getAttribute('class'); | |
return attr && attr.value | |
? attr.value.split(/\s+/g).filter(uniqueClass) | |
: []; | |
} | |
/** | |
* Convenient alias to create a new node instance | |
* @param {String} [name] Node name | |
* @param {Object} [attributes] Attributes hash | |
* @return {Node} | |
*/ | |
create(name, attributes) { | |
return new Node(name, attributes); | |
} | |
/** | |
* Sets given attribute for current node | |
* @param {String|Object|Attribute} name Attribute name or attribute object | |
* @param {String} [value] Attribute value | |
*/ | |
setAttribute(name, value) { | |
const attr = createAttribute(name, value); | |
const curAttr = this.getAttribute(name); | |
if (curAttr) { | |
this.replaceAttribute(curAttr, attr); | |
} else { | |
this._attributes.push(attr); | |
} | |
} | |
/** | |
* Check if attribute with given name exists in node | |
* @param {String} name | |
* @return {Boolean} | |
*/ | |
hasAttribute(name) { | |
return !!this.getAttribute(name); | |
} | |
/** | |
* Returns attribute object by given name | |
* @param {String} name | |
* @return {Attribute} | |
*/ | |
getAttribute(name) { | |
if (typeof name === 'object') { | |
name = name.name; | |
} | |
for (var i = 0; i < this._attributes.length; i++) { | |
const attr = this._attributes[i]; | |
if (attr.name === name) { | |
return attr; | |
} | |
} | |
} | |
/** | |
* Replaces attribute with new instance | |
* @param {String|Attribute} curAttribute Current attribute name or instance | |
* to replace | |
* @param {String|Object|Attribute} newName New attribute name or attribute object | |
* @param {String} [newValue] New attribute value | |
*/ | |
replaceAttribute(curAttribute, newName, newValue) { | |
if (typeof curAttribute === 'string') { | |
curAttribute = this.getAttribute(curAttribute); | |
} | |
const ix = this._attributes.indexOf(curAttribute); | |
if (ix !== -1) { | |
this._attributes.splice(ix, 1, createAttribute(newName, newValue)); | |
} | |
} | |
/** | |
* Removes attribute with given name | |
* @param {String|Attribute} attr Atrtibute name or instance | |
*/ | |
removeAttribute(attr) { | |
if (typeof attr === 'string') { | |
attr = this.getAttribute(attr); | |
} | |
const ix = this._attributes.indexOf(attr); | |
if (ix !== -1) { | |
this._attributes.splice(ix, 1); | |
} | |
} | |
/** | |
* Removes all attributes from current node | |
*/ | |
clearAttributes() { | |
this._attributes.length = 0; | |
} | |
/** | |
* Adds given class name to class attribute | |
* @param {String} token Class name token | |
*/ | |
addClass(token) { | |
token = normalize(token); | |
if (!this.hasAttribute('class')) { | |
this.setAttribute('class', token); | |
} else if (token && !this.hasClass(token)) { | |
this.setAttribute('class', this.classList.concat(token).join(' ')); | |
} | |
} | |
/** | |
* Check if current node contains given class name | |
* @param {String} token Class name token | |
* @return {Boolean} | |
*/ | |
hasClass(token) { | |
return this.classList.indexOf(normalize(token)) !== -1; | |
} | |
/** | |
* Removes given class name from class attribute | |
* @param {String} token Class name token | |
*/ | |
removeClass(token) { | |
token = normalize(token); | |
if (this.hasClass(token)) { | |
this.setAttribute('class', this.classList.filter(name => name !== token).join(' ')); | |
} | |
} | |
/** | |
* Appends child to current node | |
* @param {Node} node | |
*/ | |
appendChild(node) { | |
this.insertAt(node, this.children.length); | |
} | |
/** | |
* Inserts given `newNode` before `refNode` child node | |
* @param {Node} newNode | |
* @param {Node} refNode | |
*/ | |
insertBefore(newNode, refNode) { | |
this.insertAt(newNode, this.children.indexOf(refNode)); | |
} | |
/** | |
* Insert given `node` at `pos` position of child list | |
* @param {Node} node | |
* @param {Number} pos | |
*/ | |
insertAt(node, pos) { | |
if (pos < 0 || pos > this.children.length) { | |
throw new Error('Unable to insert node: position is out of child list range'); | |
} | |
const prev = this.children[pos - 1]; | |
const next = this.children[pos]; | |
node.remove(); | |
node.parent = this; | |
this.children.splice(pos, 0, node); | |
if (prev) { | |
node.previous = prev; | |
prev.next = node; | |
} | |
if (next) { | |
node.next = next; | |
next.previous = node; | |
} | |
} | |
/** | |
* Removes given child from current node | |
* @param {Node} node | |
*/ | |
removeChild(node) { | |
const ix = this.children.indexOf(node); | |
if (ix !== -1) { | |
this.children.splice(ix, 1); | |
if (node.previous) { | |
node.previous.next = node.next; | |
} | |
if (node.next) { | |
node.next.previous = node.previous; | |
} | |
node.parent = node.next = node.previous = null; | |
} | |
} | |
/** | |
* Removes current node from its parent | |
*/ | |
remove() { | |
if (this.parent) { | |
this.parent.removeChild(this); | |
} | |
} | |
/** | |
* Creates a detached copy of current node | |
* @param {Boolean} deep Clone node contents as well | |
* @return {Node} | |
*/ | |
clone(deep) { | |
const clone = new Node(this.name); | |
clone.value = this.value; | |
clone.selfClosing = this.selfClosing; | |
if (this.repeat) { | |
clone.repeat = Object.assign({}, this.repeat); | |
} | |
this._attributes.forEach(attr => clone.setAttribute(attr.clone())); | |
if (deep) { | |
this.children.forEach(child => clone.appendChild(child.clone(true))); | |
} | |
return clone; | |
} | |
/** | |
* Walks on each descendant node and invokes given `fn` function on it. | |
* The function receives two arguments: the node itself and its depth level | |
* from current node. If function returns `false`, it stops walking | |
* @param {Function} fn | |
*/ | |
walk(fn, _level) { | |
_level = _level || 0; | |
let ctx = this.firstChild; | |
while (ctx) { | |
// in case if context node will be detached during `fn` call | |
const next = ctx.next; | |
if (fn(ctx, _level) === false || ctx.walk(fn, _level + 1) === false) { | |
return false; | |
} | |
ctx = next; | |
} | |
} | |
/** | |
* A helper method for transformation chaining: runs given `fn` function on | |
* current node and returns the same node | |
*/ | |
use(fn) { | |
const args = [this]; | |
for (var i = 1; i < arguments.length; i++) { | |
args.push(arguments[i]); | |
} | |
fn.apply(null, args); | |
return this; | |
} | |
toString() { | |
const attrs = this.attributes.map(attr => { | |
attr = this.getAttribute(attr.name); | |
const opt = attr.options; | |
let out = `${opt && opt.implied ? '!' : ''}${attr.name || ''}`; | |
if (opt && opt.boolean) { | |
out += '.'; | |
} else if (attr.value != null) { | |
out += `="${attr.value}"`; | |
} | |
return out; | |
}); | |
let out = `${this.name || ''}`; | |
if (attrs.length) { | |
out += `[${attrs.join(' ')}]`; | |
} | |
if (this.value != null) { | |
out += `{${this.value}}`; | |
} | |
if (this.selfClosing) { | |
out += '/'; | |
} | |
if (this.repeat) { | |
out += `*${this.repeat.count ? this.repeat.count : ''}`; | |
if (this.repeat.value != null) { | |
out += `@${this.repeat.value}`; | |
} | |
} | |
return out; | |
} | |
} | |
/** | |
* Attribute factory | |
* @param {String|Attribute|Object} name Attribute name or attribute descriptor | |
* @param {*} value Attribute value | |
* @return {Attribute} | |
*/ | |
function createAttribute(name, value) { | |
if (name instanceof Attribute) { | |
return name; | |
} | |
if (typeof name === 'string') { | |
return new Attribute(name, value); | |
} | |
if (name && typeof name === 'object') { | |
return new Attribute(name.name, name.value, name.options); | |
} | |
} | |
/** | |
* @param {String} str | |
* @return {String} | |
*/ | |
function normalize(str) { | |
return String(str).trim(); | |
} | |
function uniqueClass(item, i, arr) { | |
return item && arr.indexOf(item) === i; | |
} | |
module.exports = Node; | |
},{}],2:[function(require,module,exports){ | |
'use strict'; | |
Object.defineProperty(exports, '__esModule', { value: true }); | |
/** | |
* Methods for consuming quoted values | |
*/ | |
const SINGLE_QUOTE = 39; // ' | |
const DOUBLE_QUOTE = 34; // " | |
const defaultOptions = { | |
escape: 92, // \ character | |
throws: false | |
}; | |
/** | |
* Consumes 'single' or "double"-quoted string from given string, if possible | |
* @param {StreamReader} stream | |
* @param {Number} options.escape A character code of quote-escape symbol | |
* @param {Boolean} options.throws Throw error if quotes string can’t be properly consumed | |
* @return {Boolean} `true` if quoted string was consumed. The contents | |
* of quoted string will be availabe as `stream.current()` | |
*/ | |
var eatQuoted = function(stream, options) { | |
options = options ? Object.assign({}, defaultOptions, options) : defaultOptions; | |
const start = stream.pos; | |
const quote = stream.peek(); | |
if (stream.eat(isQuote)) { | |
while (!stream.eof()) { | |
switch (stream.next()) { | |
case quote: | |
stream.start = start; | |
return true; | |
case options.escape: | |
stream.next(); | |
break; | |
} | |
} | |
// If we’re here then stream wasn’t properly consumed. | |
// Revert stream and decide what to do | |
stream.pos = start; | |
if (options.throws) { | |
throw stream.error('Unable to consume quoted string'); | |
} | |
} | |
return false; | |
}; | |
function isQuote(code) { | |
return code === SINGLE_QUOTE || code === DOUBLE_QUOTE; | |
} | |
/** | |
* Check if given code is a number | |
* @param {Number} code | |
* @return {Boolean} | |
*/ | |
function isNumber(code) { | |
return code > 47 && code < 58; | |
} | |
/** | |
* Check if given character code is alpha code (letter through A to Z) | |
* @param {Number} code | |
* @param {Number} [from] | |
* @param {Number} [to] | |
* @return {Boolean} | |
*/ | |
function isAlpha(code, from, to) { | |
from = from || 65; // A | |
to = to || 90; // Z | |
code &= ~32; // quick hack to convert any char code to uppercase char code | |
return code >= from && code <= to; | |
} | |
/** | |
* Check if given character code is alpha-numeric (letter through A to Z or number) | |
* @param {Number} code | |
* @return {Boolean} | |
*/ | |
function isAlphaNumeric(code) { | |
return isNumber(code) || isAlpha(code); | |
} | |
function isWhiteSpace(code) { | |
return code === 32 /* space */ | |
|| code === 9 /* tab */ | |
|| code === 160; /* non-breaking space */ | |
} | |
/** | |
* Check if given character code is a space | |
* @param {Number} code | |
* @return {Boolean} | |
*/ | |
function isSpace(code) { | |
return isWhiteSpace(code) | |
|| code === 10 /* LF */ | |
|| code === 13; /* CR */ | |
} | |
const defaultOptions$1 = { | |
escape: 92, // \ character | |
throws: false | |
}; | |
/** | |
* Eats paired characters substring, for example `(foo)` or `[bar]` | |
* @param {StreamReader} stream | |
* @param {Number} open Character code of pair openinig | |
* @param {Number} close Character code of pair closing | |
* @param {Object} [options] | |
* @return {Boolean} Returns `true` if chacarter pair was successfully | |
* consumed, it’s content will be available as `stream.current()` | |
*/ | |
function eatPair(stream, open, close, options) { | |
options = options ? Object.assign({}, defaultOptions$1, options) : defaultOptions$1; | |
const start = stream.pos; | |
if (stream.eat(open)) { | |
let stack = 1, ch; | |
while (!stream.eof()) { | |
if (eatQuoted(stream, options)) { | |
continue; | |
} | |
ch = stream.next(); | |
if (ch === open) { | |
stack++; | |
} else if (ch === close) { | |
stack--; | |
if (!stack) { | |
stream.start = start; | |
return true; | |
} | |
} else if (ch === options.escape) { | |
stream.next(); | |
} | |
} | |
// If we’re here then paired character can’t be consumed | |
stream.pos = start; | |
if (options.throws) { | |
throw stream.error(`Unable to find matching pair for ${String.fromCharCode(open)}`); | |
} | |
} | |
return false; | |
} | |
exports.eatQuoted = eatQuoted; | |
exports.isQuote = isQuote; | |
exports.isAlpha = isAlpha; | |
exports.isNumber = isNumber; | |
exports.isAlphaNumeric = isAlphaNumeric; | |
exports.isSpace = isSpace; | |
exports.isWhiteSpace = isWhiteSpace; | |
exports.eatPair = eatPair; | |
},{}],3:[function(require,module,exports){ | |
'use strict'; | |
/** | |
* A streaming, character code-based string reader | |
*/ | |
class StreamReader { | |
constructor(string, start, end) { | |
if (end == null && typeof string === 'string') { | |
end = string.length; | |
} | |
this.string = string; | |
this.pos = this.start = start || 0; | |
this.end = end; | |
} | |
/** | |
* Returns true only if the stream is at the end of the file. | |
* @returns {Boolean} | |
*/ | |
eof() { | |
return this.pos >= this.end; | |
} | |
/** | |
* Creates a new stream instance which is limited to given `start` and `end` | |
* range. E.g. its `eof()` method will look at `end` property, not actual | |
* stream end | |
* @param {Point} start | |
* @param {Point} end | |
* @return {StreamReader} | |
*/ | |
limit(start, end) { | |
return new this.constructor(this.string, start, end); | |
} | |
/** | |
* Returns the next character code in the stream without advancing it. | |
* Will return NaN at the end of the file. | |
* @returns {Number} | |
*/ | |
peek() { | |
return this.string.charCodeAt(this.pos); | |
} | |
/** | |
* Returns the next character in the stream and advances it. | |
* Also returns <code>undefined</code> when no more characters are available. | |
* @returns {Number} | |
*/ | |
next() { | |
if (this.pos < this.string.length) { | |
return this.string.charCodeAt(this.pos++); | |
} | |
} | |
/** | |
* `match` can be a character code or a function that takes a character code | |
* and returns a boolean. If the next character in the stream 'matches' | |
* the given argument, it is consumed and returned. | |
* Otherwise, `false` is returned. | |
* @param {Number|Function} match | |
* @returns {Boolean} | |
*/ | |
eat(match) { | |
const ch = this.peek(); | |
const ok = typeof match === 'function' ? match(ch) : ch === match; | |
if (ok) { | |
this.next(); | |
} | |
return ok; | |
} | |
/** | |
* Repeatedly calls <code>eat</code> with the given argument, until it | |
* fails. Returns <code>true</code> if any characters were eaten. | |
* @param {Object} match | |
* @returns {Boolean} | |
*/ | |
eatWhile(match) { | |
const start = this.pos; | |
while (!this.eof() && this.eat(match)) {} | |
return this.pos !== start; | |
} | |
/** | |
* Backs up the stream n characters. Backing it up further than the | |
* start of the current token will cause things to break, so be careful. | |
* @param {Number} n | |
*/ | |
backUp(n) { | |
this.pos -= (n || 1); | |
} | |
/** | |
* Get the string between the start of the current token and the | |
* current stream position. | |
* @returns {String} | |
*/ | |
current() { | |
return this.string.slice(this.start, this.pos); | |
} | |
/** | |
* Creates error object with current stream state | |
* @param {String} message | |
* @return {Error} | |
*/ | |
error(message) { | |
const err = new Error(`${message} at char ${this.pos + 1}`); | |
err.originalMessage = message; | |
err.pos = this.pos; | |
err.string = this.string; | |
return err; | |
} | |
} | |
module.exports = StreamReader; | |
},{}],"@emmetio/abbreviation":[function(require,module,exports){ | |
'use strict'; | |
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } | |
var Node = _interopDefault(require('@emmetio/node')); | |
var StreamReader = _interopDefault(require('@emmetio/stream-reader')); | |
var _emmetio_streamReaderUtils = require('@emmetio/stream-reader-utils'); | |
const ASTERISK = 42; // * | |
/** | |
* Consumes node repeat token from current stream position and returns its | |
* parsed value | |
* @param {StringReader} stream | |
* @return {Object} | |
*/ | |
var consumeRepeat = function(stream) { | |
if (stream.eat(ASTERISK)) { | |
stream.start = stream.pos; | |
// XXX think about extending repeat syntax with through numbering | |
return { count: stream.eatWhile(_emmetio_streamReaderUtils.isNumber) ? +stream.current() : null }; | |
} | |
}; | |
const opt = { throws: true }; | |
/** | |
* Consumes quoted literal from current stream position and returns it’s inner, | |
* unquoted, value | |
* @param {StringReader} stream | |
* @return {String} Returns `null` if unable to consume quoted value from current | |
* position | |
*/ | |
var consumeQuoted = function(stream) { | |
if (_emmetio_streamReaderUtils.eatQuoted(stream, opt)) { | |
return stream.current().slice(1, -1); | |
} | |
}; | |
const LCURLY = 123; // { | |
const RCURLY = 125; // } | |
const opt$1 = { throws: true }; | |
/** | |
* Consumes text node, e.g. contents of `{...}` and returns its inner value | |
* @param {StringReader} stream | |
* @return {String} Consumed text content or `null` otherwise | |
*/ | |
var consumeTextNode = function(stream) { | |
return _emmetio_streamReaderUtils.eatPair(stream, LCURLY, RCURLY, opt$1) | |
? stream.current().slice(1, -1) | |
: null; | |
}; | |
const EXCL = 33; // . | |
const DOT$1 = 46; // . | |
const EQUALS = 61; // = | |
const ATTR_OPEN = 91; // [ | |
const ATTR_CLOSE = 93; // ] | |
const reAttributeName = /^\!?[\w\-:\$@]+\.?$/; | |
/** | |
* Consumes attributes defined in square braces from given stream. | |
* Example: | |
* [attr col=3 title="Quoted string" selected. support={react}] | |
* @param {StringReader} stream | |
* @returns {Array} Array of consumed attributes | |
*/ | |
var consumeAttributes = function(stream) { | |
if (!stream.eat(ATTR_OPEN)) { | |
return null; | |
} | |
const result = []; | |
let token, attr; | |
while (!stream.eof()) { | |
stream.eatWhile(_emmetio_streamReaderUtils.isWhiteSpace); | |
if (stream.eat(ATTR_CLOSE)) { | |
return result; // End of attribute set | |
} else if ((token = consumeQuoted(stream)) != null) { | |
// Consumed quoted value: anonymous attribute | |
result.push({ | |
name: null, | |
value: token | |
}); | |
} else if (eatUnquoted(stream)) { | |
// Consumed next word: could be either attribute name or unquoted default value | |
token = stream.current(); | |
if (!reAttributeName.test(token)) { | |
// anonymous attribute | |
result.push({ name: null, value: token }); | |
} else { | |
// Looks like a regular attribute | |
attr = parseAttributeName(token); | |
result.push(attr); | |
if (stream.eat(EQUALS)) { | |
// Explicitly defined value. Could be a word, a quoted string | |
// or React-like expression | |
if ((token = consumeQuoted(stream)) != null) { | |
attr.value = token; | |
} else if ((token = consumeTextNode(stream)) != null) { | |
attr.value = token; | |
attr.options = { | |
before: '{', | |
after: '}' | |
}; | |
} else if (eatUnquoted(stream)) { | |
attr.value = stream.current(); | |
} | |
} | |
} | |
} else { | |
throw stream.error('Expected attribute name'); | |
} | |
} | |
throw stream.error('Expected closing "]" brace'); | |
}; | |
function parseAttributeName(name) { | |
const options = {}; | |
// If a first character in attribute name is `!` — it’s an implied | |
// default attribute | |
if (name.charCodeAt(0) === EXCL) { | |
name = name.slice(1); | |
options.implied = true; | |
} | |
// Check for last character: if it’s a `.`, user wants boolean attribute | |
if (name.charCodeAt(name.length - 1) === DOT$1) { | |
name = name.slice(0, name.length - 1); | |
options.boolean = true; | |
} | |
const attr = { name }; | |
if (Object.keys(options).length) { | |
attr.options = options; | |
} | |
return attr; | |
} | |
/** | |
* Eats token that can be an unquoted value from given stream | |
* @param {StreamReader} stream | |
* @return {Boolean} | |
*/ | |
function eatUnquoted(stream) { | |
const start = stream.pos; | |
if (stream.eatWhile(isUnquoted)) { | |
stream.start = start; | |
return true; | |
} | |
} | |
function isUnquoted(code) { | |
return !_emmetio_streamReaderUtils.isSpace(code) && !_emmetio_streamReaderUtils.isQuote(code) | |
&& code !== ATTR_OPEN && code !== ATTR_CLOSE && code !== EQUALS; | |
} | |
const HASH = 35; // # | |
const DOT = 46; // . | |
const SLASH = 47; // / | |
/** | |
* Consumes a single element node from current abbreviation stream | |
* @param {StringReader} stream | |
* @return {Node} | |
*/ | |
var consumeElement = function(stream) { | |
// consume element name, if provided | |
const start = stream.pos; | |
const node = new Node(eatName(stream)); | |
let next; | |
while (!stream.eof()) { | |
if (stream.eat(DOT)) { | |
node.addClass(eatName(stream)); | |
} else if (stream.eat(HASH)) { | |
node.setAttribute('id', eatName(stream)); | |
} else if (stream.eat(SLASH)) { | |
// A self-closing indicator must be at the end of non-grouping node | |
if (node.isGroup) { | |
stream.backUp(1); | |
throw stream.error('Unexpected self-closing indicator'); | |
} | |
node.selfClosing = true; | |
if (next = consumeRepeat(stream)) { | |
node.repeat = next; | |
} | |
break; | |
} else if (next = consumeAttributes(stream)) { | |
for (let i = 0, il = next.length; i < il; i++) { | |
node.setAttribute(next[i]); | |
} | |
} else if ((next = consumeTextNode(stream)) !== null) { | |
node.value = next; | |
} else if (next = consumeRepeat(stream)) { | |
node.repeat = next; | |
} else { | |
break; | |
} | |
} | |
if (start === stream.pos) { | |
throw stream.error(`Unable to consume abbreviation node, unexpected ${stream.peek()}`); | |
} | |
return node; | |
}; | |
function eatName(stream) { | |
stream.start = stream.pos; | |
stream.eatWhile(isName); | |
return stream.current(); | |
} | |
function isName(code) { | |
return _emmetio_streamReaderUtils.isAlphaNumeric(code) | |
|| code === 45 /* - */ | |
|| code === 58 /* : */ | |
|| code === 36 /* $ */ | |
|| code === 64 /* @ */ | |
|| code === 33 /* ! */ | |
|| code === 37 /* % */; | |
} | |
const GROUP_START = 40; // ( | |
const GROUP_END = 41; // ) | |
const OP_SIBLING = 43; // + | |
const OP_CHILD = 62; // > | |
const OP_CLIMB = 94; // ^ | |
/** | |
* Parses given string into a node tree | |
* @param {String} str Abbreviation to parse | |
* @return {Node} | |
*/ | |
function parse(str) { | |
const stream = new StreamReader(str.trim()); | |
const root = new Node(); | |
let ctx = root, groupStack = [], ch; | |
while (!stream.eof()) { | |
ch = stream.peek(); | |
if (ch === GROUP_START) { // start of group | |
// The grouping node should be detached to properly handle | |
// out-of-bounds `^` operator. Node will be attached right on group end | |
const node = new Node(); | |
const groupCtx = groupStack.length ? last(groupStack)[0] : ctx; | |
groupStack.push([node, groupCtx, stream.pos]); | |
ctx = node; | |
stream.next(); | |
continue; | |
} else if (ch === GROUP_END) { // end of group | |
const lastGroup = groupStack.pop(); | |
if (!lastGroup) { | |
throw stream.error('Unexpected ")" group end'); | |
} | |
const node = lastGroup[0]; | |
ctx = lastGroup[1]; | |
stream.next(); | |
// a group can have a repeater | |
if (node.repeat = consumeRepeat(stream)) { | |
ctx.appendChild(node); | |
} else { | |
// move all children of group into parent node | |
while (node.firstChild) { | |
ctx.appendChild(node.firstChild); | |
} | |
// for convenience, groups can be joined with optional `+` operator | |
stream.eat(OP_SIBLING); | |
} | |
continue; | |
} | |
const node = consumeElement(stream); | |
ctx.appendChild(node); | |
if (stream.eof()) { | |
break; | |
} | |
switch (stream.peek()) { | |
case OP_SIBLING: | |
stream.next(); | |
continue; | |
case OP_CHILD: | |
stream.next(); | |
ctx = node; | |
continue; | |
case OP_CLIMB: | |
// it’s perfectly valid to have multiple `^` operators | |
while (stream.eat(OP_CLIMB)) { | |
ctx = ctx.parent || ctx; | |
} | |
continue; | |
} | |
} | |
if (groupStack.length) { | |
stream.pos = groupStack.pop()[2]; | |
throw stream.error('Expected group close'); | |
} | |
return root; | |
} | |
function last(arr) { | |
return arr[arr.length - 1]; | |
} | |
/** | |
* Parses given abbreviation and un-rolls it into a full tree: recursively | |
* replaces repeated elements with actual nodes | |
* @param {String} abbr | |
* @return {Node} | |
*/ | |
var index = function(abbr) { | |
const tree = parse(abbr); | |
tree.walk(unroll); | |
return tree; | |
}; | |
function unroll(node) { | |
if (!node.repeat || !node.repeat.count) { | |
return; | |
} | |
for (let i = 1; i < node.repeat.count; i++) { | |
const clone = node.clone(true); | |
clone.repeat.value = i; | |
clone.walk(unroll); | |
node.parent.insertBefore(clone, node); | |
} | |
node.repeat.value = node.repeat.count; | |
} | |
module.exports = index; | |
},{"@emmetio/node":1,"@emmetio/stream-reader":3,"@emmetio/stream-reader-utils":2}]},{},[]) | |
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsIm5vZGVfbW9kdWxlcy9AZW1tZXRpby9ub2RlL2Rpc3Qvbm9kZS5janMuanMiLCJub2RlX21vZHVsZXMvQGVtbWV0aW8vc3RyZWFtLXJlYWRlci11dGlscy9kaXN0L3N0cmVhbS1yZWFkZXItdXRpbHMuY2pzLmpzIiwibm9kZV9tb2R1bGVzL0BlbW1ldGlvL3N0cmVhbS1yZWFkZXIvZGlzdC9zdHJlYW0tcmVhZGVyLmNqcy5qcyIsIkBlbW1ldGlvJTJGYWJicmV2aWF0aW9uIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbmVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2S0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuICogQXR0cmlidXRlIGRlc2NyaXB0b3Igb2YgcGFyc2VkIGFiYnJldmlhdGlvbiBub2RlXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZSBBdHRyaWJ1dGUgbmFtZVxuICogQHBhcmFtIHtTdHJpbmd9IHZhbHVlIEF0dHJpYnV0ZSB2YWx1ZVxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgQWRkaXRpb25hbCBjdXN0b20gYXR0cmlidXRlIG9wdGlvbnNcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gb3B0aW9ucy5ib29sZWFuIEF0dHJpYnV0ZSBpcyBib29sZWFuIChlLmcuIG5hbWUgZXF1YWxzIHZhbHVlKVxuICogQHBhcmFtIHtCb29sZWFufSBvcHRpb25zLmltcGxpZWQgQXR0cmlidXRlIGlzIGltcGxpZWQgKGUuZy4gbXVzdCBiZSBvdXRwdXR0ZWRcbiAqIG9ubHkgaWYgY29udGFpbnMgbm9uLW51bGwgdmFsdWUpXG4gKi9cbmNsYXNzIEF0dHJpYnV0ZSB7XG5cdGNvbnN0cnVjdG9yKG5hbWUsIHZhbHVlLCBvcHRpb25zKSB7XG5cdFx0dGhpcy5uYW1lID0gbmFtZTtcblx0XHR0aGlzLnZhbHVlID0gdmFsdWUgIT0gbnVsbCA/IHZhbHVlIDogbnVsbDtcblx0XHR0aGlzLm9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXHR9XG5cblx0LyoqXG5cdCAqIENyZWF0ZSBhIGNvcHkgb2YgY3VycmVudCBhdHRyaWJ1dGVcblx0ICogQHJldHVybiB7QXR0cmlidXRlfVxuXHQgKi9cblx0Y2xvbmUoKSB7XG5cdFx0cmV0dXJuIG5ldyBBdHRyaWJ1dGUodGhpcy5uYW1lLCB0aGlzLnZhbHVlLCBPYmplY3QuYXNzaWduKHt9LCB0aGlzLm9wdGlvbnMpKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBBIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiBjdXJyZW50IG5vZGVcblx0ICovXG5cdHZhbHVlT2YoKSB7XG5cdFx0cmV0dXJuIGAke3RoaXMubmFtZX09XCIke3RoaXMudmFsdWV9XCJgO1xuXHR9XG59XG5cbi8qKlxuICogQSBwYXJzZWQgYWJicmV2aWF0aW9uIEFTVCBub2RlLiBOb2RlcyBidWlsZCB1cCBhbiBhYmJyZXZpYXRpb24gQVNUIHRyZWVcbiAqL1xuY2xhc3MgTm9kZSB7XG5cdC8qKlxuXHQgKiBDcmVhdGVzIGEgbmV3IG5vZGVcblx0ICogQHBhcmFtIHtTdHJpbmd9IFtuYW1lXSBOb2RlIG5hbWVcblx0ICogQHBhcmFtIHtBcnJheX0gW2F0dHJpYnV0ZXNdIEFycmF5IG9mIGF0dHJpYnV0ZXMgdG8gYWRkXG5cdCAqL1xuXHRjb25zdHJ1Y3RvcihuYW1lLCBhdHRyaWJ1dGVzKSB7XG5cdFx0Ly8gb3duIHByb3BlcnRpZXNcblx0XHR0aGlzLm5hbWUgPSBuYW1lIHx8IG51bGw7XG5cdFx0dGhpcy52YWx1ZSA9IG51bGw7XG5cdFx0dGhpcy5yZXBlYXQgPSBudWxsO1xuXHRcdHRoaXMuc2VsZkNsb3NpbmcgPSBmYWxzZTtcblxuXHRcdHRoaXMuY2hpbGRyZW4gPSBbXTtcblxuXHRcdC8qKiBAdHlwZSB7Tm9kZX0gUG9pbnRlciB0byBwYXJlbnQgbm9kZSAqL1xuXHRcdHRoaXMucGFyZW50ID0gbnVsbDtcblxuXHRcdC8qKiBAdHlwZSB7Tm9kZX0gUG9pbnRlciB0byBuZXh0IHNpYmxpbmcgKi9cblx0XHR0aGlzLm5leHQgPSBudWxsO1xuXG5cdFx0LyoqIEB0eXBlIHtOb2RlfSBQb2ludGVyIHRvIHByZXZpb3VzIHNpYmxpbmcgKi9cblx0XHR0aGlzLnByZXZpb3VzID0gbnVsbDtcblxuXHRcdHRoaXMuX2F0dHJpYnV0ZXMgPSBbXTtcblxuXHRcdGlmIChBcnJheS5pc0FycmF5KGF0dHJpYnV0ZXMpKSB7XG5cdFx0XHRhdHRyaWJ1dGVzLmZvckVhY2goYXR0ciA9PiB0aGlzLnNldEF0dHJpYnV0ZShhdHRyKSk7XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIEFycmF5IG9mIGN1cnJlbnQgbm9kZSBhdHRyaWJ1dGVzXG5cdCAqIEByZXR1cm4ge0F0dHJpYnV0ZVtdfSBBcnJheSBvZiBhdHRyaWJ1dGVzXG5cdCAqL1xuXHRnZXQgYXR0cmlidXRlcygpIHtcblx0XHRyZXR1cm4gdGhpcy5fYXR0cmlidXRlcztcblx0fVxuXG5cdC8qKlxuXHQgKiBBIHNob3J0aGFuZCB0byByZXRyZWl2ZSBub2RlIGF0dHJpYnV0ZXMgYXMgbWFwXG5cdCAqIEByZXR1cm4ge09iamVjdH1cblx0ICovXG5cdGdldCBhdHRyaWJ1dGVzTWFwKCkge1xuXHRcdHJldHVybiB0aGlzLmF0dHJpYnV0ZXMucmVkdWNlKChvdXQsIGF0dHIpID0+IHtcblx0XHRcdG91dFthdHRyLm5hbWVdID0gYXR0ci5vcHRpb25zLmJvb2xlYW4gPyBhdHRyLm5hbWUgOiBhdHRyLnZhbHVlO1xuXHRcdFx0cmV0dXJuIG91dDtcblx0XHR9LCB7fSk7XG5cdH1cblxuXHQvKipcblx0ICogQ2hlY2sgaWYgY3VycmVudCBub2RlIGlzIGEgZ3JvdXBpbmcgb25lLCBlLmcuIGhhcyBubyBhY3R1YWwgcmVwcmVzZW50YXRpb25cblx0ICogYW5kIGlzIHVzZWQgZm9yIGdyb3VwaW5nIHN1YnNlcXVlbnQgbm9kZXMgb25seVxuXHQgKiBAcmV0dXJuIHtCb29sZWFufVxuXHQgKi9cblx0Z2V0IGlzR3JvdXAoKSB7XG5cdFx0cmV0dXJuICF0aGlzLm5hbWUgJiYgIXRoaXMudmFsdWUgJiYgIXRoaXMuX2F0dHJpYnV0ZXMubGVuZ3RoO1xuXHR9XG5cblx0LyoqXG5cdCAqIENoZWNrIGlmIGdpdmVuIG5vZGUgaXMgYSB0ZXh0LW9ubHkgbm9kZSwgZS5nLiBjb250YWlucyBvbmx5IHZhbHVlXG5cdCAqIEByZXR1cm4ge0Jvb2xlYW59XG5cdCAqL1xuXHRnZXQgaXNUZXh0T25seSgpIHtcblx0XHRyZXR1cm4gIXRoaXMubmFtZSAmJiAhIXRoaXMudmFsdWUgJiYgIXRoaXMuX2F0dHJpYnV0ZXMubGVuZ3RoO1xuXHR9XG5cblx0LyoqXG5cdCAqIFJldHVybnMgZmlyc3QgY2hpbGQgbm9kZVxuXHQgKiBAcmV0dXJuIHtOb2RlfVxuXHQgKi9cblx0Z2V0IGZpcnN0Q2hpbGQoKSB7XG5cdFx0cmV0dXJuIHRoaXMuY2hpbGRyZW5bMF07XG5cdH1cblxuXHQvKipcblx0ICogUmV0dXJucyBsYXN0IGNoaWxkIG9mIGN1cnJlbnQgbm9kZVxuXHQgKiBAcmV0dXJuIHtOb2RlfVxuXHQgKi9cblx0Z2V0IGxhc3RDaGlsZCgpIHtcblx0XHRyZXR1cm4gdGhpcy5jaGlsZHJlblt0aGlzLmNoaWxkcmVuLmxlbmd0aCAtIDFdO1xuXHR9XG5cblx0LyoqXG5cdCAqIFJldHVybiBpbmRleCBvZiBjdXJyZW50IG5vZGUgaW4gaXRzIHBhcmVudCBjaGlsZCBsaXN0XG5cdCAqIEByZXR1cm4ge051bWJlcn0gUmV0dXJucyAtMSBpZiBjdXJyZW50IG5vZGUgaXMgYSByb290IG9uZVxuXHQgKi9cblx0Z2V0IGNoaWxkSW5kZXgoKSB7XG5cdFx0cmV0dXJuIHRoaXMucGFyZW50ID8gdGhpcy5wYXJlbnQuY2hpbGRyZW4uaW5kZXhPZih0aGlzKSA6IC0xO1xuXHR9XG5cblx0LyoqXG5cdCAqIFJldHVybnMgbmV4dCBzaWJsaW5nIG9mIGN1cnJlbnQgbm9kZVxuXHQgKiBAcmV0dXJuIHtOb2RlfVxuXHQgKi9cblx0Z2V0IG5leHRTaWJsaW5nKCkge1xuXHRcdHJldHVybiB0aGlzLm5leHQ7XG5cdH1cblxuXHQvKipcblx0ICogUmV0dXJucyBwcmV2aW91cyBzaWJsaW5nIG9mIGN1cnJlbnQgbm9kZVxuXHQgKiBAcmV0dXJuIHtOb2RlfVxuXHQgKi9cblx0Z2V0IHByZXZpb3VzU2libGluZygpIHtcblx0XHRyZXR1cm4gdGhpcy5wcmV2aW91cztcblx0fVxuXG5cdC8qKlxuXHQgKiBSZXR1cm5zIGFycmF5IG9mIHVuaXF1ZSBjbGFzcyBuYW1lcyBpbiBjdXJyZW50IG5vZGVcblx0ICogQHJldHVybiB7U3RyaW5nW119XG5cdCAqL1xuXHRnZXQgY2xhc3NMaXN0KCkge1xuXHRcdGNvbnN0IGF0dHIgPSB0aGlzLmdldEF0dHJpYnV0ZSgnY2xhc3MnKTtcblx0XHRyZXR1cm4gYXR0ciAmJiBhdHRyLnZhbHVlXG5cdFx0XHQ/IGF0dHIudmFsdWUuc3BsaXQoL1xccysvZykuZmlsdGVyKHVuaXF1ZUNsYXNzKVxuXHRcdFx0OiBbXTtcblx0fVxuXG5cdC8qKlxuXHQgKiBDb252ZW5pZW50IGFsaWFzIHRvIGNyZWF0ZSBhIG5ldyBub2RlIGluc3RhbmNlXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBbbmFtZV0gTm9kZSBuYW1lXG5cdCAqIEBwYXJhbSB7T2JqZWN0fSBbYXR0cmlidXRlc10gQXR0cmlidXRlcyBoYXNoXG5cdCAqIEByZXR1cm4ge05vZGV9XG5cdCAqL1xuXHRjcmVhdGUobmFtZSwgYXR0cmlidXRlcykge1xuXHRcdHJldHVybiBuZXcgTm9kZShuYW1lLCBhdHRyaWJ1dGVzKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBTZXRzIGdpdmVuIGF0dHJpYnV0ZSBmb3IgY3VycmVudCBub2RlXG5cdCAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdHxBdHRyaWJ1dGV9IG5hbWUgQXR0cmlidXRlIG5hbWUgb3IgYXR0cmlidXRlIG9iamVjdFxuXHQgKiBAcGFyYW0ge1N0cmluZ30gW3ZhbHVlXSBBdHRyaWJ1dGUgdmFsdWVcblx0ICovXG5cdHNldEF0dHJpYnV0ZShuYW1lLCB2YWx1ZSkge1xuXHRcdGNvbnN0IGF0dHIgPSBjcmVhdGVBdHRyaWJ1dGUobmFtZSwgdmFsdWUpO1xuXHRcdGNvbnN0IGN1ckF0dHIgPSB0aGlzLmdldEF0dHJpYnV0ZShuYW1lKTtcblx0XHRpZiAoY3VyQXR0cikge1xuXHRcdFx0dGhpcy5yZXBsYWNlQXR0cmlidXRlKGN1ckF0dHIsIGF0dHIpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLl9hdHRyaWJ1dGVzLnB1c2goYXR0cik7XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIENoZWNrIGlmIGF0dHJpYnV0ZSB3aXRoIGdpdmVuIG5hbWUgZXhpc3RzIGluIG5vZGVcblx0ICogQHBhcmFtICB7U3RyaW5nfSBuYW1lXG5cdCAqIEByZXR1cm4ge0Jvb2xlYW59XG5cdCAqL1xuXHRoYXNBdHRyaWJ1dGUobmFtZSkge1xuXHRcdHJldHVybiAhIXRoaXMuZ2V0QXR0cmlidXRlKG5hbWUpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFJldHVybnMgYXR0cmlidXRlIG9iamVjdCBieSBnaXZlbiBuYW1lXG5cdCAqIEBwYXJhbSAge1N0cmluZ30gbmFtZVxuXHQgKiBAcmV0dXJuIHtBdHRyaWJ1dGV9XG5cdCAqL1xuXHRnZXRBdHRyaWJ1dGUobmFtZSkge1xuXHRcdGlmICh0eXBlb2YgbmFtZSA9PT0gJ29iamVjdCcpIHtcblx0XHRcdG5hbWUgPSBuYW1lLm5hbWU7XG5cdFx0fVxuXG5cdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLl9hdHRyaWJ1dGVzLmxlbmd0aDsgaSsrKSB7XG5cdFx0XHRjb25zdCBhdHRyID0gdGhpcy5fYXR0cmlidXRlc1tpXTtcblx0XHRcdGlmIChhdHRyLm5hbWUgPT09IG5hbWUpIHtcblx0XHRcdFx0cmV0dXJuIGF0dHI7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIFJlcGxhY2VzIGF0dHJpYnV0ZSB3aXRoIG5ldyBpbnN0YW5jZVxuXHQgKiBAcGFyYW0ge1N0cmluZ3xBdHRyaWJ1dGV9IGN1ckF0dHJpYnV0ZSBDdXJyZW50IGF0dHJpYnV0ZSBuYW1lIG9yIGluc3RhbmNlXG5cdCAqIHRvIHJlcGxhY2Vcblx0ICogQHBhcmFtIHtTdHJpbmd8T2JqZWN0fEF0dHJpYnV0ZX0gbmV3TmFtZSBOZXcgYXR0cmlidXRlIG5hbWUgb3IgYXR0cmlidXRlIG9iamVjdFxuXHQgKiBAcGFyYW0ge1N0cmluZ30gW25ld1ZhbHVlXSBOZXcgYXR0cmlidXRlIHZhbHVlXG5cdCAqL1xuXHRyZXBsYWNlQXR0cmlidXRlKGN1ckF0dHJpYnV0ZSwgbmV3TmFtZSwgbmV3VmFsdWUpIHtcblx0XHRpZiAodHlwZW9mIGN1ckF0dHJpYnV0ZSA9PT0gJ3N0cmluZycpIHtcblx0XHRcdGN1ckF0dHJpYnV0ZSA9IHRoaXMuZ2V0QXR0cmlidXRlKGN1ckF0dHJpYnV0ZSk7XG5cdFx0fVxuXG5cdFx0Y29uc3QgaXggPSB0aGlzLl9hdHRyaWJ1dGVzLmluZGV4T2YoY3VyQXR0cmlidXRlKTtcblx0XHRpZiAoaXggIT09IC0xKSB7XG5cdFx0XHR0aGlzLl9hdHRyaWJ1dGVzLnNwbGljZShpeCwgMSwgY3JlYXRlQXR0cmlidXRlKG5ld05hbWUsIG5ld1ZhbHVlKSk7XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIFJlbW92ZXMgYXR0cmlidXRlIHdpdGggZ2l2ZW4gbmFtZVxuXHQgKiBAcGFyYW0gIHtTdHJpbmd8QXR0cmlidXRlfSBhdHRyIEF0cnRpYnV0ZSBuYW1lIG9yIGluc3RhbmNlXG5cdCAqL1xuXHRyZW1vdmVBdHRyaWJ1dGUoYXR0cikge1xuXHRcdGlmICh0eXBlb2YgYXR0ciA9PT0gJ3N0cmluZycpIHtcblx0XHRcdGF0dHIgPSB0aGlzLmdldEF0dHJpYnV0ZShhdHRyKTtcblx0XHR9XG5cblx0XHRjb25zdCBpeCA9IHRoaXMuX2F0dHJpYnV0ZXMuaW5kZXhPZihhdHRyKTtcblx0XHRpZiAoaXggIT09IC0xKSB7XG5cdFx0XHR0aGlzLl9hdHRyaWJ1dGVzLnNwbGljZShpeCwgMSk7XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIFJlbW92ZXMgYWxsIGF0dHJpYnV0ZXMgZnJvbSBjdXJyZW50IG5vZGVcblx0ICovXG5cdGNsZWFyQXR0cmlidXRlcygpIHtcblx0XHR0aGlzLl9hdHRyaWJ1dGVzLmxlbmd0aCA9IDA7XG5cdH1cblxuXHQvKipcblx0ICogQWRkcyBnaXZlbiBjbGFzcyBuYW1lIHRvIGNsYXNzIGF0dHJpYnV0ZVxuXHQgKiBAcGFyYW0ge1N0cmluZ30gdG9rZW4gQ2xhc3MgbmFtZSB0b2tlblxuXHQgKi9cblx0YWRkQ2xhc3ModG9rZW4pIHtcblx0XHR0b2tlbiA9IG5vcm1hbGl6ZSh0b2tlbik7XG5cblx0XHRpZiAoIXRoaXMuaGFzQXR0cmlidXRlKCdjbGFzcycpKSB7XG5cdFx0XHR0aGlzLnNldEF0dHJpYnV0ZSgnY2xhc3MnLCB0b2tlbik7XG5cdFx0fSBlbHNlIGlmICh0b2tlbiAmJiAhdGhpcy5oYXNDbGFzcyh0b2tlbikpIHtcblx0XHRcdHRoaXMuc2V0QXR0cmlidXRlKCdjbGFzcycsIHRoaXMuY2xhc3NMaXN0LmNvbmNhdCh0b2tlbikuam9pbignICcpKTtcblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogQ2hlY2sgaWYgY3VycmVudCBub2RlIGNvbnRhaW5zIGdpdmVuIGNsYXNzIG5hbWVcblx0ICogQHBhcmFtIHtTdHJpbmd9IHRva2VuIENsYXNzIG5hbWUgdG9rZW5cblx0ICogQHJldHVybiB7Qm9vbGVhbn1cblx0ICovXG5cdGhhc0NsYXNzKHRva2VuKSB7XG5cdFx0cmV0dXJuIHRoaXMuY2xhc3NMaXN0LmluZGV4T2Yobm9ybWFsaXplKHRva2VuKSkgIT09IC0xO1xuXHR9XG5cblx0LyoqXG5cdCAqIFJlbW92ZXMgZ2l2ZW4gY2xhc3MgbmFtZSBmcm9tIGNsYXNzIGF0dHJpYnV0ZVxuXHQgKiBAcGFyYW0ge1N0cmluZ30gdG9rZW4gQ2xhc3MgbmFtZSB0b2tlblxuXHQgKi9cblx0cmVtb3ZlQ2xhc3ModG9rZW4pIHtcblx0XHR0b2tlbiA9IG5vcm1hbGl6ZSh0b2tlbik7XG5cdFx0aWYgKHRoaXMuaGFzQ2xhc3ModG9rZW4pKSB7XG5cdFx0XHR0aGlzLnNldEF0dHJpYnV0ZSgnY2xhc3MnLCB0aGlzLmNsYXNzTGlzdC5maWx0ZXIobmFtZSA9PiBuYW1lICE9PSB0b2tlbikuam9pbignICcpKTtcblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogQXBwZW5kcyBjaGlsZCB0byBjdXJyZW50IG5vZGVcblx0ICogQHBhcmFtIHtOb2RlfSBub2RlXG5cdCAqL1xuXHRhcHBlbmRDaGlsZChub2RlKSB7XG5cdFx0dGhpcy5pbnNlcnRBdChub2RlLCB0aGlzLmNoaWxkcmVuLmxlbmd0aCk7XG5cdH1cblxuXHQvKipcblx0ICogSW5zZXJ0cyBnaXZlbiBgbmV3Tm9kZWAgYmVmb3JlIGByZWZOb2RlYCBjaGlsZCBub2RlXG5cdCAqIEBwYXJhbSB7Tm9kZX0gbmV3Tm9kZVxuXHQgKiBAcGFyYW0ge05vZGV9IHJlZk5vZGVcblx0ICovXG5cdGluc2VydEJlZm9yZShuZXdOb2RlLCByZWZOb2RlKSB7XG5cdFx0dGhpcy5pbnNlcnRBdChuZXdOb2RlLCB0aGlzLmNoaWxkcmVuLmluZGV4T2YocmVmTm9kZSkpO1xuXHR9XG5cblx0LyoqXG5cdCAqIEluc2VydCBnaXZlbiBgbm9kZWAgYXQgYHBvc2AgcG9zaXRpb24gb2YgY2hpbGQgbGlzdFxuXHQgKiBAcGFyYW0ge05vZGV9IG5vZGVcblx0ICogQHBhcmFtIHtOdW1iZXJ9IHBvc1xuXHQgKi9cblx0aW5zZXJ0QXQobm9kZSwgcG9zKSB7XG5cdFx0aWYgKHBvcyA8IDAgfHwgcG9zID4gdGhpcy5jaGlsZHJlbi5sZW5ndGgpIHtcblx0XHRcdHRocm93IG5ldyBFcnJvcignVW5hYmxlIHRvIGluc2VydCBub2RlOiBwb3NpdGlvbiBpcyBvdXQgb2YgY2hpbGQgbGlzdCByYW5nZScpO1xuXHRcdH1cblxuXHRcdGNvbnN0IHByZXYgPSB0aGlzLmNoaWxkcmVuW3BvcyAtIDFdO1xuXHRcdGNvbnN0IG5leHQgPSB0aGlzLmNoaWxkcmVuW3Bvc107XG5cblx0XHRub2RlLnJlbW92ZSgpO1xuXHRcdG5vZGUucGFyZW50ID0gdGhpcztcblx0XHR0aGlzLmNoaWxkcmVuLnNwbGljZShwb3MsIDAsIG5vZGUpO1xuXG5cdFx0aWYgKHByZXYpIHtcblx0XHRcdG5vZGUucHJldmlvdXMgPSBwcmV2O1xuXHRcdFx0cHJldi5uZXh0ID0gbm9kZTtcblx0XHR9XG5cblx0XHRpZiAobmV4dCkge1xuXHRcdFx0bm9kZS5uZXh0ID0gbmV4dDtcblx0XHRcdG5leHQucHJldmlvdXMgPSBub2RlO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBSZW1vdmVzIGdpdmVuIGNoaWxkIGZyb20gY3VycmVudCBub2RlXG5cdCAqIEBwYXJhbSB7Tm9kZX0gbm9kZVxuXHQgKi9cblx0cmVtb3ZlQ2hpbGQobm9kZSkge1xuXHRcdGNvbnN0IGl4ID0gdGhpcy5jaGlsZHJlbi5pbmRleE9mKG5vZGUpO1xuXHRcdGlmIChpeCAhPT0gLTEpIHtcblx0XHRcdHRoaXMuY2hpbGRyZW4uc3BsaWNlKGl4LCAxKTtcblx0XHRcdGlmIChub2RlLnByZXZpb3VzKSB7XG5cdFx0XHRcdG5vZGUucHJldmlvdXMubmV4dCA9IG5vZGUubmV4dDtcblx0XHRcdH1cblxuXHRcdFx0aWYgKG5vZGUubmV4dCkge1xuXHRcdFx0XHRub2RlLm5leHQucHJldmlvdXMgPSBub2RlLnByZXZpb3VzO1xuXHRcdFx0fVxuXG5cdFx0XHRub2RlLnBhcmVudCA9IG5vZGUubmV4dCA9IG5vZGUucHJldmlvdXMgPSBudWxsO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBSZW1vdmVzIGN1cnJlbnQgbm9kZSBmcm9tIGl0cyBwYXJlbnRcblx0ICovXG5cdHJlbW92ZSgpIHtcblx0XHRpZiAodGhpcy5wYXJlbnQpIHtcblx0XHRcdHRoaXMucGFyZW50LnJlbW92ZUNoaWxkKHRoaXMpO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBDcmVhdGVzIGEgZGV0YWNoZWQgY29weSBvZiBjdXJyZW50IG5vZGVcblx0ICogQHBhcmFtIHtCb29sZWFufSBkZWVwIENsb25lIG5vZGUgY29udGVudHMgYXMgd2VsbFxuXHQgKiBAcmV0dXJuIHtOb2RlfVxuXHQgKi9cblx0Y2xvbmUoZGVlcCkge1xuXHRcdGNvbnN0IGNsb25lID0gbmV3IE5vZGUodGhpcy5uYW1lKTtcblx0XHRjbG9uZS52YWx1ZSA9IHRoaXMudmFsdWU7XG5cdFx0Y2xvbmUuc2VsZkNsb3NpbmcgPSB0aGlzLnNlbGZDbG9zaW5nO1xuXHRcdGlmICh0aGlzLnJlcGVhdCkge1xuXHRcdFx0Y2xvbmUucmVwZWF0ID0gT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5yZXBlYXQpO1xuXHRcdH1cblxuXHRcdHRoaXMuX2F0dHJpYnV0ZXMuZm9yRWFjaChhdHRyID0+IGNsb25lLnNldEF0dHJpYnV0ZShhdHRyLmNsb25lKCkpKTtcblxuXHRcdGlmIChkZWVwKSB7XG5cdFx0XHR0aGlzLmNoaWxkcmVuLmZvckVhY2goY2hpbGQgPT4gY2xvbmUuYXBwZW5kQ2hpbGQoY2hpbGQuY2xvbmUodHJ1ZSkpKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gY2xvbmU7XG5cdH1cblxuXHQvKipcblx0ICogV2Fsa3Mgb24gZWFjaCBkZXNjZW5kYW50IG5vZGUgYW5kIGludm9rZXMgZ2l2ZW4gYGZuYCBmdW5jdGlvbiBvbiBpdC5cblx0ICogVGhlIGZ1bmN0aW9uIHJlY2VpdmVzIHR3byBhcmd1bWVudHM6IHRoZSBub2RlIGl0c2VsZiBhbmQgaXRzIGRlcHRoIGxldmVsXG5cdCAqIGZyb20gY3VycmVudCBub2RlLiBJZiBmdW5jdGlvbiByZXR1cm5zIGBmYWxzZWAsIGl0IHN0b3BzIHdhbGtpbmdcblx0ICogQHBhcmFtIHtGdW5jdGlvbn0gZm5cblx0ICovXG5cdHdhbGsoZm4sIF9sZXZlbCkge1xuXHRcdF9sZXZlbCA9IF9sZXZlbCB8fCAwO1xuXHRcdGxldCBjdHggPSB0aGlzLmZpcnN0Q2hpbGQ7XG5cblx0XHR3aGlsZSAoY3R4KSB7XG5cdFx0XHQvLyBpbiBjYXNlIGlmIGNvbnRleHQgbm9kZSB3aWxsIGJlIGRldGFjaGVkIGR1cmluZyBgZm5gIGNhbGxcblx0XHRcdGNvbnN0IG5leHQgPSBjdHgubmV4dDtcblxuXHRcdFx0aWYgKGZuKGN0eCwgX2xldmVsKSA9PT0gZmFsc2UgfHwgY3R4LndhbGsoZm4sIF9sZXZlbCArIDEpID09PSBmYWxzZSkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cblx0XHRcdGN0eCA9IG5leHQ7XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIEEgaGVscGVyIG1ldGhvZCBmb3IgdHJhbnNmb3JtYXRpb24gY2hhaW5pbmc6IHJ1bnMgZ2l2ZW4gYGZuYCBmdW5jdGlvbiBvblxuXHQgKiBjdXJyZW50IG5vZGUgYW5kIHJldHVybnMgdGhlIHNhbWUgbm9kZVxuXHQgKi9cblx0dXNlKGZuKSB7XG5cdFx0Y29uc3QgYXJncyA9IFt0aGlzXTtcblx0XHRmb3IgKHZhciBpID0gMTsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykge1xuXHRcdFx0YXJncy5wdXNoKGFyZ3VtZW50c1tpXSk7XG5cdFx0fVxuXG5cdFx0Zm4uYXBwbHkobnVsbCwgYXJncyk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHR0b1N0cmluZygpIHtcblx0XHRjb25zdCBhdHRycyA9IHRoaXMuYXR0cmlidXRlcy5tYXAoYXR0ciA9PiB7XG5cdFx0XHRhdHRyID0gdGhpcy5nZXRBdHRyaWJ1dGUoYXR0ci5uYW1lKTtcblx0XHRcdGNvbnN0IG9wdCA9IGF0dHIub3B0aW9ucztcblx0XHRcdGxldCBvdXQgPSBgJHtvcHQgJiYgb3B0LmltcGxpZWQgPyAnIScgOiAnJ30ke2F0dHIubmFtZSB8fCAnJ31gO1xuXHRcdFx0aWYgKG9wdCAmJiBvcHQuYm9vbGVhbikge1xuXHRcdFx0XHRvdXQgKz0gJy4nO1xuXHRcdFx0fSBlbHNlIGlmIChhdHRyLnZhbHVlICE9IG51bGwpIHtcblx0XHRcdFx0b3V0ICs9IGA9XCIke2F0dHIudmFsdWV9XCJgO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIG91dDtcblx0XHR9KTtcblxuXHRcdGxldCBvdXQgPSBgJHt0aGlzLm5hbWUgfHwgJyd9YDtcblx0XHRpZiAoYXR0cnMubGVuZ3RoKSB7XG5cdFx0XHRvdXQgKz0gYFske2F0dHJzLmpvaW4oJyAnKX1dYDtcblx0XHR9XG5cblx0XHRpZiAodGhpcy52YWx1ZSAhPSBudWxsKSB7XG5cdFx0XHRvdXQgKz0gYHske3RoaXMudmFsdWV9fWA7XG5cdFx0fVxuXG5cdFx0aWYgKHRoaXMuc2VsZkNsb3NpbmcpIHtcblx0XHRcdG91dCArPSAnLyc7XG5cdFx0fVxuXG5cdFx0aWYgKHRoaXMucmVwZWF0KSB7XG5cdFx0XHRvdXQgKz0gYCoke3RoaXMucmVwZWF0LmNvdW50ID8gdGhpcy5yZXBlYXQuY291bnQgOiAnJ31gO1xuXHRcdFx0aWYgKHRoaXMucmVwZWF0LnZhbHVlICE9IG51bGwpIHtcblx0XHRcdFx0b3V0ICs9IGBAJHt0aGlzLnJlcGVhdC52YWx1ZX1gO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiBvdXQ7XG5cdH1cbn1cblxuLyoqXG4gKiBBdHRyaWJ1dGUgZmFjdG9yeVxuICogQHBhcmFtICB7U3RyaW5nfEF0dHJpYnV0ZXxPYmplY3R9IG5hbWUgIEF0dHJpYnV0ZSBuYW1lIG9yIGF0dHJpYnV0ZSBkZXNjcmlwdG9yXG4gKiBAcGFyYW0gIHsqfSB2YWx1ZSBBdHRyaWJ1dGUgdmFsdWVcbiAqIEByZXR1cm4ge0F0dHJpYnV0ZX1cbiAqL1xuZnVuY3Rpb24gY3JlYXRlQXR0cmlidXRlKG5hbWUsIHZhbHVlKSB7XG5cdGlmIChuYW1lIGluc3RhbmNlb2YgQXR0cmlidXRlKSB7XG5cdFx0cmV0dXJuIG5hbWU7XG5cdH1cblxuXHRpZiAodHlwZW9mIG5hbWUgPT09ICdzdHJpbmcnKSB7XG5cdFx0cmV0dXJuIG5ldyBBdHRyaWJ1dGUobmFtZSwgdmFsdWUpO1xuXHR9XG5cblx0aWYgKG5hbWUgJiYgdHlwZW9mIG5hbWUgPT09ICdvYmplY3QnKSB7XG5cdFx0cmV0dXJuIG5ldyBBdHRyaWJ1dGUobmFtZS5uYW1lLCBuYW1lLnZhbHVlLCBuYW1lLm9wdGlvbnMpO1xuXHR9XG59XG5cbi8qKlxuICogQHBhcmFtICB7U3RyaW5nfSBzdHJcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xuZnVuY3Rpb24gbm9ybWFsaXplKHN0cikge1xuXHRyZXR1cm4gU3RyaW5nKHN0cikudHJpbSgpO1xufVxuXG5mdW5jdGlvbiB1bmlxdWVDbGFzcyhpdGVtLCBpLCBhcnIpIHtcblx0cmV0dXJuIGl0ZW0gJiYgYXJyLmluZGV4T2YoaXRlbSkgPT09IGk7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gTm9kZTtcbiIsIid1c2Ugc3RyaWN0JztcblxuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsICdfX2VzTW9kdWxlJywgeyB2YWx1ZTogdHJ1ZSB9KTtcblxuLyoqXG4gKiBNZXRob2RzIGZvciBjb25zdW1pbmcgcXVvdGVkIHZhbHVlc1xuICovXG5cbmNvbnN0IFNJTkdMRV9RVU9URSA9IDM5OyAvLyAnXG5jb25zdCBET1VCTEVfUVVPVEUgPSAzNDsgLy8gXCJcblxuY29uc3QgZGVmYXVsdE9wdGlvbnMgPSB7XG5cdGVzY2FwZTogOTIsICAgLy8gXFwgY2hhcmFjdGVyXG5cdHRocm93czogZmFsc2Vcbn07XG5cbi8qKlxuICogQ29uc3VtZXMgJ3NpbmdsZScgb3IgXCJkb3VibGVcIi1xdW90ZWQgc3RyaW5nIGZyb20gZ2l2ZW4gc3RyaW5nLCBpZiBwb3NzaWJsZVxuICogQHBhcmFtICB7U3RyZWFtUmVhZGVyfSBzdHJlYW1cbiAqIEBwYXJhbSAge051bWJlcn0gIG9wdGlvbnMuZXNjYXBlIEEgY2hhcmFjdGVyIGNvZGUgb2YgcXVvdGUtZXNjYXBlIHN5bWJvbFxuICogQHBhcmFtICB7Qm9vbGVhbn0gb3B0aW9ucy50aHJvd3MgVGhyb3cgZXJyb3IgaWYgcXVvdGVzIHN0cmluZyBjYW7igJl0IGJlIHByb3Blcmx5IGNvbnN1bWVkXG4gKiBAcmV0dXJuIHtCb29sZWFufSBgdHJ1ZWAgaWYgcXVvdGVkIHN0cmluZyB3YXMgY29uc3VtZWQuIFRoZSBjb250ZW50c1xuICogICAgICAgICAgICAgICAgICAgb2YgcXVvdGVkIHN0cmluZyB3aWxsIGJlIGF2YWlsYWJlIGFzIGBzdHJlYW0uY3VycmVudCgpYFxuICovXG52YXIgZWF0UXVvdGVkID0gZnVuY3Rpb24oc3RyZWFtLCBvcHRpb25zKSB7XG5cdG9wdGlvbnMgPSBvcHRpb25zID8gT2JqZWN0LmFzc2lnbih7fSwgZGVmYXVsdE9wdGlvbnMsIG9wdGlvbnMpIDogZGVmYXVsdE9wdGlvbnM7XG5cdGNvbnN0IHN0YXJ0ID0gc3RyZWFtLnBvcztcblx0Y29uc3QgcXVvdGUgPSBzdHJlYW0ucGVlaygpO1xuXG5cdGlmIChzdHJlYW0uZWF0KGlzUXVvdGUpKSB7XG5cdFx0d2hpbGUgKCFzdHJlYW0uZW9mKCkpIHtcblx0XHRcdHN3aXRjaCAoc3RyZWFtLm5leHQoKSkge1xuXHRcdFx0XHRjYXNlIHF1b3RlOlxuXHRcdFx0XHRcdHN0cmVhbS5zdGFydCA9IHN0YXJ0O1xuXHRcdFx0XHRcdHJldHVybiB0cnVlO1xuXG5cdFx0XHRcdGNhc2Ugb3B0aW9ucy5lc2NhcGU6XG5cdFx0XHRcdFx0c3RyZWFtLm5leHQoKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBJZiB3ZeKAmXJlIGhlcmUgdGhlbiBzdHJlYW0gd2FzbuKAmXQgcHJvcGVybHkgY29uc3VtZWQuXG5cdFx0Ly8gUmV2ZXJ0IHN0cmVhbSBhbmQgZGVjaWRlIHdoYXQgdG8gZG9cblx0XHRzdHJlYW0ucG9zID0gc3RhcnQ7XG5cblx0XHRpZiAob3B0aW9ucy50aHJvd3MpIHtcblx0XHRcdHRocm93IHN0cmVhbS5lcnJvcignVW5hYmxlIHRvIGNvbnN1bWUgcXVvdGVkIHN0cmluZycpO1xuXHRcdH1cblx0fVxuXG5cdHJldHVybiBmYWxzZTtcbn07XG5cbmZ1bmN0aW9uIGlzUXVvdGUoY29kZSkge1xuXHRyZXR1cm4gY29kZSA9PT0gU0lOR0xFX1FVT1RFIHx8IGNvZGUgPT09IERPVUJMRV9RVU9URTtcbn1cblxuLyoqXG4gKiBDaGVjayBpZiBnaXZlbiBjb2RlIGlzIGEgbnVtYmVyXG4gKiBAcGFyYW0gIHtOdW1iZXJ9ICBjb2RlXG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG5mdW5jdGlvbiBpc051bWJlcihjb2RlKSB7XG5cdHJldHVybiBjb2RlID4gNDcgJiYgY29kZSA8IDU4O1xufVxuXG4vKipcbiAqIENoZWNrIGlmIGdpdmVuIGNoYXJhY3RlciBjb2RlIGlzIGFscGhhIGNvZGUgKGxldHRlciB0aHJvdWdoIEEgdG8gWilcbiAqIEBwYXJhbSAge051bWJlcn0gIGNvZGVcbiAqIEBwYXJhbSAge051bWJlcn0gIFtmcm9tXVxuICogQHBhcmFtICB7TnVtYmVyfSAgW3RvXVxuICogQHJldHVybiB7Qm9vbGVhbn1cbiAqL1xuZnVuY3Rpb24gaXNBbHBoYShjb2RlLCBmcm9tLCB0bykge1xuXHRmcm9tID0gZnJvbSB8fCA2NTsgLy8gQVxuXHR0byAgID0gdG8gICB8fCA5MDsgLy8gWlxuXHRjb2RlICY9IH4zMjsgLy8gcXVpY2sgaGFjayB0byBjb252ZXJ0IGFueSBjaGFyIGNvZGUgdG8gdXBwZXJjYXNlIGNoYXIgY29kZVxuXG5cdHJldHVybiBjb2RlID49IGZyb20gJiYgY29kZSA8PSB0bztcbn1cblxuLyoqXG4gKiBDaGVjayBpZiBnaXZlbiBjaGFyYWN0ZXIgY29kZSBpcyBhbHBoYS1udW1lcmljIChsZXR0ZXIgdGhyb3VnaCBBIHRvIFogb3IgbnVtYmVyKVxuICogQHBhcmFtICB7TnVtYmVyfSAgY29kZVxuICogQHJldHVybiB7Qm9vbGVhbn1cbiAqL1xuZnVuY3Rpb24gaXNBbHBoYU51bWVyaWMoY29kZSkge1xuXHRyZXR1cm4gaXNOdW1iZXIoY29kZSkgfHwgaXNBbHBoYShjb2RlKTtcbn1cblxuZnVuY3Rpb24gaXNXaGl0ZVNwYWNlKGNvZGUpIHtcblx0cmV0dXJuIGNvZGUgPT09IDMyICAgLyogc3BhY2UgKi9cblx0XHR8fCBjb2RlID09PSA5ICAgIC8qIHRhYiAqL1xuXHRcdHx8IGNvZGUgPT09IDE2MDsgLyogbm9uLWJyZWFraW5nIHNwYWNlICovXG59XG5cbi8qKlxuICogQ2hlY2sgaWYgZ2l2ZW4gY2hhcmFjdGVyIGNvZGUgaXMgYSBzcGFjZVxuICogQHBhcmFtICB7TnVtYmVyfSAgY29kZVxuICogQHJldHVybiB7Qm9vbGVhbn1cbiAqL1xuZnVuY3Rpb24gaXNTcGFjZShjb2RlKSB7XG5cdHJldHVybiBpc1doaXRlU3BhY2UoY29kZSlcblx0XHR8fCBjb2RlID09PSAxMCAgLyogTEYgKi9cblx0XHR8fCBjb2RlID09PSAxMzsgLyogQ1IgKi9cbn1cblxuY29uc3QgZGVmYXVsdE9wdGlvbnMkMSA9IHtcblx0ZXNjYXBlOiA5MiwgICAvLyBcXCBjaGFyYWN0ZXJcblx0dGhyb3dzOiBmYWxzZVxufTtcblxuLyoqXG4gKiBFYXRzIHBhaXJlZCBjaGFyYWN0ZXJzIHN1YnN0cmluZywgZm9yIGV4YW1wbGUgYChmb28pYCBvciBgW2Jhcl1gXG4gKiBAcGFyYW0gIHtTdHJlYW1SZWFkZXJ9IHN0cmVhbVxuICogQHBhcmFtICB7TnVtYmVyfSBvcGVuICAgICAgQ2hhcmFjdGVyIGNvZGUgb2YgcGFpciBvcGVuaW5pZ1xuICogQHBhcmFtICB7TnVtYmVyfSBjbG9zZSAgICAgQ2hhcmFjdGVyIGNvZGUgb2YgcGFpciBjbG9zaW5nXG4gKiBAcGFyYW0gIHtPYmplY3R9IFtvcHRpb25zXVxuICogQHJldHVybiB7Qm9vbGVhbn0gICAgICAgUmV0dXJucyBgdHJ1ZWAgaWYgY2hhY2FydGVyIHBhaXIgd2FzIHN1Y2Nlc3NmdWxseVxuICogICAgICAgICAgICAgICAgICAgICAgICAgY29uc3VtZWQsIGl04oCZcyBjb250ZW50IHdpbGwgYmUgYXZhaWxhYmxlIGFzIGBzdHJlYW0uY3VycmVudCgpYFxuICovXG5mdW5jdGlvbiBlYXRQYWlyKHN0cmVhbSwgb3BlbiwgY2xvc2UsIG9wdGlvbnMpIHtcblx0b3B0aW9ucyA9IG9wdGlvbnMgPyBPYmplY3QuYXNzaWduKHt9LCBkZWZhdWx0T3B0aW9ucyQxLCBvcHRpb25zKSA6IGRlZmF1bHRPcHRpb25zJDE7XG5cdGNvbnN0IHN0YXJ0ID0gc3RyZWFtLnBvcztcblxuXHRpZiAoc3RyZWFtLmVhdChvcGVuKSkge1xuXHRcdGxldCBzdGFjayA9IDEsIGNoO1xuXG5cdFx0d2hpbGUgKCFzdHJlYW0uZW9mKCkpIHtcblx0XHRcdGlmIChlYXRRdW90ZWQoc3RyZWFtLCBvcHRpb25zKSkge1xuXHRcdFx0XHRjb250aW51ZTtcblx0XHRcdH1cblxuXHRcdFx0Y2ggPSBzdHJlYW0ubmV4dCgpO1xuXHRcdFx0aWYgKGNoID09PSBvcGVuKSB7XG5cdFx0XHRcdHN0YWNrKys7XG5cdFx0XHR9IGVsc2UgaWYgKGNoID09PSBjbG9zZSkge1xuXHRcdFx0XHRzdGFjay0tO1xuXHRcdFx0XHRpZiAoIXN0YWNrKSB7XG5cdFx0XHRcdFx0c3RyZWFtLnN0YXJ0ID0gc3RhcnQ7XG5cdFx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSBpZiAoY2ggPT09IG9wdGlvbnMuZXNjYXBlKSB7XG5cdFx0XHRcdHN0cmVhbS5uZXh0KCk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gSWYgd2XigJlyZSBoZXJlIHRoZW4gcGFpcmVkIGNoYXJhY3RlciBjYW7igJl0IGJlIGNvbnN1bWVkXG5cdFx0c3RyZWFtLnBvcyA9IHN0YXJ0O1xuXG5cdFx0aWYgKG9wdGlvbnMudGhyb3dzKSB7XG5cdFx0XHR0aHJvdyBzdHJlYW0uZXJyb3IoYFVuYWJsZSB0byBmaW5kIG1hdGNoaW5nIHBhaXIgZm9yICR7U3RyaW5nLmZyb21DaGFyQ29kZShvcGVuKX1gKTtcblx0XHR9XG5cdH1cblxuXHRyZXR1cm4gZmFsc2U7XG59XG5cbmV4cG9ydHMuZWF0UXVvdGVkID0gZWF0UXVvdGVkO1xuZXhwb3J0cy5pc1F1b3RlID0gaXNRdW90ZTtcbmV4cG9ydHMuaXNBbHBoYSA9IGlzQWxwaGE7XG5leHBvcnRzLmlzTnVtYmVyID0gaXNOdW1iZXI7XG5leHBvcnRzLmlzQWxwaGFOdW1lcmljID0gaXNBbHBoYU51bWVyaWM7XG5leHBvcnRzLmlzU3BhY2UgPSBpc1NwYWNlO1xuZXhwb3J0cy5pc1doaXRlU3BhY2UgPSBpc1doaXRlU3BhY2U7XG5leHBvcnRzLmVhdFBhaXIgPSBlYXRQYWlyO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqIEEgc3RyZWFtaW5nLCBjaGFyYWN0ZXIgY29kZS1iYXNlZCBzdHJpbmcgcmVhZGVyXG4gKi9cbmNsYXNzIFN0cmVhbVJlYWRlciB7XG5cdGNvbnN0cnVjdG9yKHN0cmluZywgc3RhcnQsIGVuZCkge1xuXHRcdGlmIChlbmQgPT0gbnVsbCAmJiB0eXBlb2Ygc3RyaW5nID09PSAnc3RyaW5nJykge1xuXHRcdFx0ZW5kID0gc3RyaW5nLmxlbmd0aDtcblx0XHR9XG5cblx0XHR0aGlzLnN0cmluZyA9IHN0cmluZztcblx0XHR0aGlzLnBvcyA9IHRoaXMuc3RhcnQgPSBzdGFydCB8fCAwO1xuXHRcdHRoaXMuZW5kID0gZW5kO1xuXHR9XG5cblx0LyoqXG5cdCAqIFJldHVybnMgdHJ1ZSBvbmx5IGlmIHRoZSBzdHJlYW0gaXMgYXQgdGhlIGVuZCBvZiB0aGUgZmlsZS5cblx0ICogQHJldHVybnMge0Jvb2xlYW59XG5cdCAqL1xuXHRlb2YoKSB7XG5cdFx0cmV0dXJuIHRoaXMucG9zID49IHRoaXMuZW5kO1xuXHR9XG5cblx0LyoqXG5cdCAqIENyZWF0ZXMgYSBuZXcgc3RyZWFtIGluc3RhbmNlIHdoaWNoIGlzIGxpbWl0ZWQgdG8gZ2l2ZW4gYHN0YXJ0YCBhbmQgYGVuZGBcblx0ICogcmFuZ2UuIEUuZy4gaXRzIGBlb2YoKWAgbWV0aG9kIHdpbGwgbG9vayBhdCBgZW5kYCBwcm9wZXJ0eSwgbm90IGFjdHVhbFxuXHQgKiBzdHJlYW0gZW5kXG5cdCAqIEBwYXJhbSAge1BvaW50fSBzdGFydFxuXHQgKiBAcGFyYW0gIHtQb2ludH0gZW5kXG5cdCAqIEByZXR1cm4ge1N0cmVhbVJlYWRlcn1cblx0ICovXG5cdGxpbWl0KHN0YXJ0LCBlbmQpIHtcblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IodGhpcy5zdHJpbmcsIHN0YXJ0LCBlbmQpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFJldHVybnMgdGhlIG5leHQgY2hhcmFjdGVyIGNvZGUgaW4gdGhlIHN0cmVhbSB3aXRob3V0IGFkdmFuY2luZyBpdC5cblx0ICogV2lsbCByZXR1cm4gTmFOIGF0IHRoZSBlbmQgb2YgdGhlIGZpbGUuXG5cdCAqIEByZXR1cm5zIHtOdW1iZXJ9XG5cdCAqL1xuXHRwZWVrKCkge1xuXHRcdHJldHVybiB0aGlzLnN0cmluZy5jaGFyQ29kZUF0KHRoaXMucG9zKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBSZXR1cm5zIHRoZSBuZXh0IGNoYXJhY3RlciBpbiB0aGUgc3RyZWFtIGFuZCBhZHZhbmNlcyBpdC5cblx0ICogQWxzbyByZXR1cm5zIDxjb2RlPnVuZGVmaW5lZDwvY29kZT4gd2hlbiBubyBtb3JlIGNoYXJhY3RlcnMgYXJlIGF2YWlsYWJsZS5cblx0ICogQHJldHVybnMge051bWJlcn1cblx0ICovXG5cdG5leHQoKSB7XG5cdFx0aWYgKHRoaXMucG9zIDwgdGhpcy5zdHJpbmcubGVuZ3RoKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5zdHJpbmcuY2hhckNvZGVBdCh0aGlzLnBvcysrKTtcblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogYG1hdGNoYCBjYW4gYmUgYSBjaGFyYWN0ZXIgY29kZSBvciBhIGZ1bmN0aW9uIHRoYXQgdGFrZXMgYSBjaGFyYWN0ZXIgY29kZVxuXHQgKiBhbmQgcmV0dXJucyBhIGJvb2xlYW4uIElmIHRoZSBuZXh0IGNoYXJhY3RlciBpbiB0aGUgc3RyZWFtICdtYXRjaGVzJ1xuXHQgKiB0aGUgZ2l2ZW4gYXJndW1lbnQsIGl0IGlzIGNvbnN1bWVkIGFuZCByZXR1cm5lZC5cblx0ICogT3RoZXJ3aXNlLCBgZmFsc2VgIGlzIHJldHVybmVkLlxuXHQgKiBAcGFyYW0ge051bWJlcnxGdW5jdGlvbn0gbWF0Y2hcblx0ICogQHJldHVybnMge0Jvb2xlYW59XG5cdCAqL1xuXHRlYXQobWF0Y2gpIHtcblx0XHRjb25zdCBjaCA9IHRoaXMucGVlaygpO1xuXHRcdGNvbnN0IG9rID0gdHlwZW9mIG1hdGNoID09PSAnZnVuY3Rpb24nID8gbWF0Y2goY2gpIDogY2ggPT09IG1hdGNoO1xuXG5cdFx0aWYgKG9rKSB7XG5cdFx0XHR0aGlzLm5leHQoKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gb2s7XG5cdH1cblxuXHQvKipcblx0ICogUmVwZWF0ZWRseSBjYWxscyA8Y29kZT5lYXQ8L2NvZGU+IHdpdGggdGhlIGdpdmVuIGFyZ3VtZW50LCB1bnRpbCBpdFxuXHQgKiBmYWlscy4gUmV0dXJucyA8Y29kZT50cnVlPC9jb2RlPiBpZiBhbnkgY2hhcmFjdGVycyB3ZXJlIGVhdGVuLlxuXHQgKiBAcGFyYW0ge09iamVjdH0gbWF0Y2hcblx0ICogQHJldHVybnMge0Jvb2xlYW59XG5cdCAqL1xuXHRlYXRXaGlsZShtYXRjaCkge1xuXHRcdGNvbnN0IHN0YXJ0ID0gdGhpcy5wb3M7XG5cdFx0d2hpbGUgKCF0aGlzLmVvZigpICYmIHRoaXMuZWF0KG1hdGNoKSkge31cblx0XHRyZXR1cm4gdGhpcy5wb3MgIT09IHN0YXJ0O1xuXHR9XG5cblx0LyoqXG5cdCAqIEJhY2tzIHVwIHRoZSBzdHJlYW0gbiBjaGFyYWN0ZXJzLiBCYWNraW5nIGl0IHVwIGZ1cnRoZXIgdGhhbiB0aGVcblx0ICogc3RhcnQgb2YgdGhlIGN1cnJlbnQgdG9rZW4gd2lsbCBjYXVzZSB0aGluZ3MgdG8gYnJlYWssIHNvIGJlIGNhcmVmdWwuXG5cdCAqIEBwYXJhbSB7TnVtYmVyfSBuXG5cdCAqL1xuXHRiYWNrVXAobikge1xuXHRcdHRoaXMucG9zIC09IChuIHx8IDEpO1xuXHR9XG5cblx0LyoqXG5cdCAqIEdldCB0aGUgc3RyaW5nIGJldHdlZW4gdGhlIHN0YXJ0IG9mIHRoZSBjdXJyZW50IHRva2VuIGFuZCB0aGVcblx0ICogY3VycmVudCBzdHJlYW0gcG9zaXRpb24uXG5cdCAqIEByZXR1cm5zIHtTdHJpbmd9XG5cdCAqL1xuXHRjdXJyZW50KCkge1xuXHRcdHJldHVybiB0aGlzLnN0cmluZy5zbGljZSh0aGlzLnN0YXJ0LCB0aGlzLnBvcyk7XG5cdH1cblxuXHQvKipcblx0ICogQ3JlYXRlcyBlcnJvciBvYmplY3Qgd2l0aCBjdXJyZW50IHN0cmVhbSBzdGF0ZVxuXHQgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuXHQgKiBAcmV0dXJuIHtFcnJvcn1cblx0ICovXG5cdGVycm9yKG1lc3NhZ2UpIHtcblx0XHRjb25zdCBlcnIgPSBuZXcgRXJyb3IoYCR7bWVzc2FnZX0gYXQgY2hhciAke3RoaXMucG9zICsgMX1gKTtcblx0XHRlcnIub3JpZ2luYWxNZXNzYWdlID0gbWVzc2FnZTtcblx0XHRlcnIucG9zID0gdGhpcy5wb3M7XG5cdFx0ZXJyLnN0cmluZyA9IHRoaXMuc3RyaW5nO1xuXHRcdHJldHVybiBlcnI7XG5cdH1cbn1cblxubW9kdWxlLmV4cG9ydHMgPSBTdHJlYW1SZWFkZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbmZ1bmN0aW9uIF9pbnRlcm9wRGVmYXVsdCAoZXgpIHsgcmV0dXJuIChleCAmJiAodHlwZW9mIGV4ID09PSAnb2JqZWN0JykgJiYgJ2RlZmF1bHQnIGluIGV4KSA/IGV4WydkZWZhdWx0J10gOiBleDsgfVxuXG52YXIgTm9kZSA9IF9pbnRlcm9wRGVmYXVsdChyZXF1aXJlKCdAZW1tZXRpby9ub2RlJykpO1xudmFyIFN0cmVhbVJlYWRlciA9IF9pbnRlcm9wRGVmYXVsdChyZXF1aXJlKCdAZW1tZXRpby9zdHJlYW0tcmVhZGVyJykpO1xudmFyIF9lbW1ldGlvX3N0cmVhbVJlYWRlclV0aWxzID0gcmVxdWlyZSgnQGVtbWV0aW8vc3RyZWFtLXJlYWRlci11dGlscycpO1xuXG5jb25zdCBBU1RFUklTSyA9IDQyOyAvLyAqXG5cbi8qKlxuICogQ29uc3VtZXMgbm9kZSByZXBlYXQgdG9rZW4gZnJvbSBjdXJyZW50IHN0cmVhbSBwb3NpdGlvbiBhbmQgcmV0dXJucyBpdHNcbiAqIHBhcnNlZCB2YWx1ZVxuICogQHBhcmFtICB7U3RyaW5nUmVhZGVyfSBzdHJlYW1cbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xudmFyIGNvbnN1bWVSZXBlYXQgPSBmdW5jdGlvbihzdHJlYW0pIHtcblx0aWYgKHN0cmVhbS5lYXQoQVNURVJJU0spKSB7XG5cdFx0c3RyZWFtLnN0YXJ0ID0gc3RyZWFtLnBvcztcblxuXHRcdC8vIFhYWCB0aGluayBhYm91dCBleHRlbmRpbmcgcmVwZWF0IHN5bnRheCB3aXRoIHRocm91Z2ggbnVtYmVyaW5nXG5cdFx0cmV0dXJuIHsgY291bnQ6IHN0cmVhbS5lYXRXaGlsZShfZW1tZXRpb19zdHJlYW1SZWFkZXJVdGlscy5pc051bWJlcikgPyArc3RyZWFtLmN1cnJlbnQoKSA6IG51bGwgfTtcblx0fVxufTtcblxuY29uc3Qgb3B0ID0geyB0aHJvd3M6IHRydWUgfTtcblxuLyoqXG4gKiBDb25zdW1lcyBxdW90ZWQgbGl0ZXJhbCBmcm9tIGN1cnJlbnQgc3RyZWFtIHBvc2l0aW9uIGFuZCByZXR1cm5zIGl04oCZcyBpbm5lcixcbiAqIHVucXVvdGVkLCB2YWx1ZVxuICogQHBhcmFtICB7U3RyaW5nUmVhZGVyfSBzdHJlYW1cbiAqIEByZXR1cm4ge1N0cmluZ30gUmV0dXJucyBgbnVsbGAgaWYgdW5hYmxlIHRvIGNvbnN1bWUgcXVvdGVkIHZhbHVlIGZyb20gY3VycmVudFxuICogcG9zaXRpb25cbiAqL1xudmFyIGNvbnN1bWVRdW90ZWQgPSBmdW5jdGlvbihzdHJlYW0pIHtcblx0aWYgKF9lbW1ldGlvX3N0cmVhbVJlYWRlclV0aWxzLmVhdFF1b3RlZChzdHJlYW0sIG9wdCkpIHtcblx0XHRyZXR1cm4gc3RyZWFtLmN1cnJlbnQoKS5zbGljZSgxLCAtMSk7XG5cdH1cbn07XG5cbmNvbnN0IExDVVJMWSA9IDEyMzsgLy8ge1xuY29uc3QgUkNVUkxZID0gMTI1OyAvLyB9XG5cbmNvbnN0IG9wdCQxID0geyB0aHJvd3M6IHRydWUgfTtcblxuLyoqXG4gKiBDb25zdW1lcyB0ZXh0IG5vZGUsIGUuZy4gY29udGVudHMgb2YgYHsuLi59YCBhbmQgcmV0dXJucyBpdHMgaW5uZXIgdmFsdWVcbiAqIEBwYXJhbSAge1N0cmluZ1JlYWRlcn0gc3RyZWFtXG4gKiBAcmV0dXJuIHtTdHJpbmd9IENvbnN1bWVkIHRleHQgY29udGVudCBvciBgbnVsbGAgb3RoZXJ3aXNlXG4gKi9cbnZhciBjb25zdW1lVGV4dE5vZGUgPSBmdW5jdGlvbihzdHJlYW0pIHtcblx0cmV0dXJuIF9lbW1ldGlvX3N0cmVhbVJlYWRlclV0aWxzLmVhdFBhaXIoc3RyZWFtLCBMQ1VSTFksIFJDVVJMWSwgb3B0JDEpXG5cdFx0PyBzdHJlYW0uY3VycmVudCgpLnNsaWNlKDEsIC0xKVxuXHRcdDogbnVsbDtcbn07XG5cbmNvbnN0IEVYQ0wgICAgICAgPSAzMzsgLy8gLlxuY29uc3QgRE9UJDEgICAgICAgID0gNDY7IC8vIC5cbmNvbnN0IEVRVUFMUyAgICAgPSA2MTsgLy8gPVxuY29uc3QgQVRUUl9PUEVOICA9IDkxOyAvLyBbXG5jb25zdCBBVFRSX0NMT1NFID0gOTM7IC8vIF1cblxuY29uc3QgcmVBdHRyaWJ1dGVOYW1lID0gL15cXCE/W1xcd1xcLTpcXCRAXStcXC4/JC87XG5cbi8qKlxuICogQ29uc3VtZXMgYXR0cmlidXRlcyBkZWZpbmVkIGluIHNxdWFyZSBicmFjZXMgZnJvbSBnaXZlbiBzdHJlYW0uXG4gKiBFeGFtcGxlOlxuICogW2F0dHIgY29sPTMgdGl0bGU9XCJRdW90ZWQgc3RyaW5nXCIgc2VsZWN0ZWQuIHN1cHBvcnQ9e3JlYWN0fV1cbiAqIEBwYXJhbSB7U3RyaW5nUmVhZGVyfSBzdHJlYW1cbiAqIEByZXR1cm5zIHtBcnJheX0gQXJyYXkgb2YgY29uc3VtZWQgYXR0cmlidXRlc1xuICovXG52YXIgY29uc3VtZUF0dHJpYnV0ZXMgPSBmdW5jdGlvbihzdHJlYW0pIHtcblx0aWYgKCFzdHJlYW0uZWF0KEFUVFJfT1BFTikpIHtcblx0XHRyZXR1cm4gbnVsbDtcblx0fVxuXG5cdGNvbnN0IHJlc3VsdCA9IFtdO1xuXHRsZXQgdG9rZW4sIGF0dHI7XG5cblx0d2hpbGUgKCFzdHJlYW0uZW9mKCkpIHtcblx0XHRzdHJlYW0uZWF0V2hpbGUoX2VtbWV0aW9fc3RyZWFtUmVhZGVyVXRpbHMuaXNXaGl0ZVNwYWNlKTtcblxuXHRcdGlmIChzdHJlYW0uZWF0KEFUVFJfQ0xPU0UpKSB7XG5cdFx0XHRyZXR1cm4gcmVzdWx0OyAvLyBFbmQgb2YgYXR0cmlidXRlIHNldFxuXHRcdH0gZWxzZSBpZiAoKHRva2VuID0gY29uc3VtZVF1b3RlZChzdHJlYW0pKSAhPSBudWxsKSB7XG5cdFx0XHQvLyBDb25zdW1lZCBxdW90ZWQgdmFsdWU6IGFub255bW91cyBhdHRyaWJ1dGVcblx0XHRcdHJlc3VsdC5wdXNoKHtcblx0XHRcdFx0bmFtZTogbnVsbCxcblx0XHRcdFx0dmFsdWU6IHRva2VuXG5cdFx0XHR9KTtcblx0XHR9IGVsc2UgaWYgKGVhdFVucXVvdGVkKHN0cmVhbSkpIHtcblx0XHRcdC8vIENvbnN1bWVkIG5leHQgd29yZDogY291bGQgYmUgZWl0aGVyIGF0dHJpYnV0ZSBuYW1lIG9yIHVucXVvdGVkIGRlZmF1bHQgdmFsdWVcblx0XHRcdHRva2VuID0gc3RyZWFtLmN1cnJlbnQoKTtcblx0XHRcdGlmICghcmVBdHRyaWJ1dGVOYW1lLnRlc3QodG9rZW4pKSB7XG5cdFx0XHRcdC8vIGFub255bW91cyBhdHRyaWJ1dGVcblx0XHRcdFx0cmVzdWx0LnB1c2goeyBuYW1lOiBudWxsLCB2YWx1ZTogdG9rZW4gfSk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHQvLyBMb29rcyBsaWtlIGEgcmVndWxhciBhdHRyaWJ1dGVcblx0XHRcdFx0YXR0ciA9IHBhcnNlQXR0cmlidXRlTmFtZSh0b2tlbik7XG5cdFx0XHRcdHJlc3VsdC5wdXNoKGF0dHIpO1xuXG5cdFx0XHRcdGlmIChzdHJlYW0uZWF0KEVRVUFMUykpIHtcblx0XHRcdFx0XHQvLyBFeHBsaWNpdGx5IGRlZmluZWQgdmFsdWUuIENvdWxkIGJlIGEgd29yZCwgYSBxdW90ZWQgc3RyaW5nXG5cdFx0XHRcdFx0Ly8gb3IgUmVhY3QtbGlrZSBleHByZXNzaW9uXG5cdFx0XHRcdFx0aWYgKCh0b2tlbiA9IGNvbnN1bWVRdW90ZWQoc3RyZWFtKSkgIT0gbnVsbCkge1xuXHRcdFx0XHRcdFx0YXR0ci52YWx1ZSA9IHRva2VuO1xuXHRcdFx0XHRcdH0gZWxzZSBpZiAoKHRva2VuID0gY29uc3VtZVRleHROb2RlKHN0cmVhbSkpICE9IG51bGwpIHtcblx0XHRcdFx0XHRcdGF0dHIudmFsdWUgPSB0b2tlbjtcblx0XHRcdFx0XHRcdGF0dHIub3B0aW9ucyA9IHtcblx0XHRcdFx0XHRcdFx0YmVmb3JlOiAneycsXG5cdFx0XHRcdFx0XHRcdGFmdGVyOiAnfSdcblx0XHRcdFx0XHRcdH07XG5cdFx0XHRcdFx0fSBlbHNlIGlmIChlYXRVbnF1b3RlZChzdHJlYW0pKSB7XG5cdFx0XHRcdFx0XHRhdHRyLnZhbHVlID0gc3RyZWFtLmN1cnJlbnQoKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhyb3cgc3RyZWFtLmVycm9yKCdFeHBlY3RlZCBhdHRyaWJ1dGUgbmFtZScpO1xuXHRcdH1cblx0fVxuXG5cdHRocm93IHN0cmVhbS5lcnJvcignRXhwZWN0ZWQgY2xvc2luZyBcIl1cIiBicmFjZScpO1xufTtcblxuZnVuY3Rpb24gcGFyc2VBdHRyaWJ1dGVOYW1lKG5hbWUpIHtcblx0Y29uc3Qgb3B0aW9ucyA9IHt9O1xuXG5cdC8vIElmIGEgZmlyc3QgY2hhcmFjdGVyIGluIGF0dHJpYnV0ZSBuYW1lIGlzIGAhYCDigJQgaXTigJlzIGFuIGltcGxpZWRcblx0Ly8gZGVmYXVsdCBhdHRyaWJ1dGVcblx0aWYgKG5hbWUuY2hhckNvZGVBdCgwKSA9PT0gRVhDTCkge1xuXHRcdG5hbWUgPSBuYW1lLnNsaWNlKDEpO1xuXHRcdG9wdGlvbnMuaW1wbGllZCA9IHRydWU7XG5cdH1cblxuXHQvLyBDaGVjayBmb3IgbGFzdCBjaGFyYWN0ZXI6IGlmIGl04oCZcyBhIGAuYCwgdXNlciB3YW50cyBib29sZWFuIGF0dHJpYnV0ZVxuXHRpZiAobmFtZS5jaGFyQ29kZUF0KG5hbWUubGVuZ3RoIC0gMSkgPT09IERPVCQxKSB7XG5cdFx0bmFtZSA9IG5hbWUuc2xpY2UoMCwgbmFtZS5sZW5ndGggLSAxKTtcblx0XHRvcHRpb25zLmJvb2xlYW4gPSB0cnVlO1xuXHR9XG5cblx0Y29uc3QgYXR0ciA9IHsgbmFtZSB9O1xuXHRpZiAoT2JqZWN0LmtleXMob3B0aW9ucykubGVuZ3RoKSB7XG5cdFx0YXR0ci5vcHRpb25zID0gb3B0aW9ucztcblx0fVxuXG5cdHJldHVybiBhdHRyO1xufVxuXG4vKipcbiAqIEVhdHMgdG9rZW4gdGhhdCBjYW4gYmUgYW4gdW5xdW90ZWQgdmFsdWUgZnJvbSBnaXZlbiBzdHJlYW1cbiAqIEBwYXJhbSAge1N0cmVhbVJlYWRlcn0gc3RyZWFtXG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG5mdW5jdGlvbiBlYXRVbnF1b3RlZChzdHJlYW0pIHtcblx0Y29uc3Qgc3RhcnQgPSBzdHJlYW0ucG9zO1xuXHRpZiAoc3RyZWFtLmVhdFdoaWxlKGlzVW5xdW90ZWQpKSB7XG5cdFx0c3RyZWFtLnN0YXJ0ID0gc3RhcnQ7XG5cdFx0cmV0dXJuIHRydWU7XG5cdH1cbn1cblxuZnVuY3Rpb24gaXNVbnF1b3RlZChjb2RlKSB7XG5cdHJldHVybiAhX2VtbWV0aW9fc3RyZWFtUmVhZGVyVXRpbHMuaXNTcGFjZShjb2RlKSAmJiAhX2VtbWV0aW9fc3RyZWFtUmVhZGVyVXRpbHMuaXNRdW90ZShjb2RlKVxuXHRcdCYmIGNvZGUgIT09IEFUVFJfT1BFTiAmJiBjb2RlICE9PSBBVFRSX0NMT1NFICYmIGNvZGUgIT09IEVRVUFMUztcbn1cblxuY29uc3QgSEFTSCAgICA9IDM1OyAvLyAjXG5jb25zdCBET1QgICAgID0gNDY7IC8vIC5cbmNvbnN0IFNMQVNIICAgPSA0NzsgLy8gL1xuXG4vKipcbiAqIENvbnN1bWVzIGEgc2luZ2xlIGVsZW1lbnQgbm9kZSBmcm9tIGN1cnJlbnQgYWJicmV2aWF0aW9uIHN0cmVhbVxuICogQHBhcmFtICB7U3RyaW5nUmVhZGVyfSBzdHJlYW1cbiAqIEByZXR1cm4ge05vZGV9XG4gKi9cbnZhciBjb25zdW1lRWxlbWVudCA9IGZ1bmN0aW9uKHN0cmVhbSkge1xuXHQvLyBjb25zdW1lIGVsZW1lbnQgbmFtZSwgaWYgcHJvdmlkZWRcblx0Y29uc3Qgc3RhcnQgPSBzdHJlYW0ucG9zO1xuXHRjb25zdCBub2RlID0gbmV3IE5vZGUoZWF0TmFtZShzdHJlYW0pKTtcblx0bGV0IG5leHQ7XG5cblx0d2hpbGUgKCFzdHJlYW0uZW9mKCkpIHtcblx0XHRpZiAoc3RyZWFtLmVhdChET1QpKSB7XG5cdFx0XHRub2RlLmFkZENsYXNzKGVhdE5hbWUoc3RyZWFtKSk7XG5cdFx0fSBlbHNlIGlmIChzdHJlYW0uZWF0KEhBU0gpKSB7XG5cdFx0XHRub2RlLnNldEF0dHJpYnV0ZSgnaWQnLCBlYXROYW1lKHN0cmVhbSkpO1xuXHRcdH0gZWxzZSBpZiAoc3RyZWFtLmVhdChTTEFTSCkpIHtcblx0XHRcdC8vIEEgc2VsZi1jbG9zaW5nIGluZGljYXRvciBtdXN0IGJlIGF0IHRoZSBlbmQgb2Ygbm9uLWdyb3VwaW5nIG5vZGVcblx0XHRcdGlmIChub2RlLmlzR3JvdXApIHtcblx0XHRcdFx0c3RyZWFtLmJhY2tVcCgxKTtcblx0XHRcdFx0dGhyb3cgc3RyZWFtLmVycm9yKCdVbmV4cGVjdGVkIHNlbGYtY2xvc2luZyBpbmRpY2F0b3InKTtcblx0XHRcdH1cblx0XHRcdG5vZGUuc2VsZkNsb3NpbmcgPSB0cnVlO1xuXHRcdFx0aWYgKG5leHQgPSBjb25zdW1lUmVwZWF0KHN0cmVhbSkpIHtcblx0XHRcdFx0bm9kZS5yZXBlYXQgPSBuZXh0O1xuXHRcdFx0fVxuXHRcdFx0YnJlYWs7XG5cdFx0fSBlbHNlIGlmIChuZXh0ID0gY29uc3VtZUF0dHJpYnV0ZXMoc3RyZWFtKSkge1xuXHRcdFx0Zm9yIChsZXQgaSA9IDAsIGlsID0gbmV4dC5sZW5ndGg7IGkgPCBpbDsgaSsrKSB7XG5cdFx0XHRcdG5vZGUuc2V0QXR0cmlidXRlKG5leHRbaV0pO1xuXHRcdFx0fVxuXHRcdH0gZWxzZSBpZiAoKG5leHQgPSBjb25zdW1lVGV4dE5vZGUoc3RyZWFtKSkgIT09IG51bGwpIHtcblx0XHRcdG5vZGUudmFsdWUgPSBuZXh0O1xuXHRcdH0gZWxzZSBpZiAobmV4dCA9IGNvbnN1bWVSZXBlYXQoc3RyZWFtKSkge1xuXHRcdFx0bm9kZS5yZXBlYXQgPSBuZXh0O1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRicmVhaztcblx0XHR9XG5cdH1cblxuXHRpZiAoc3RhcnQgPT09IHN0cmVhbS5wb3MpIHtcblx0XHR0aHJvdyBzdHJlYW0uZXJyb3IoYFVuYWJsZSB0byBjb25zdW1lIGFiYnJldmlhdGlvbiBub2RlLCB1bmV4cGVjdGVkICR7c3RyZWFtLnBlZWsoKX1gKTtcblx0fVxuXG5cdHJldHVybiBub2RlO1xufTtcblxuZnVuY3Rpb24gZWF0TmFtZShzdHJlYW0pIHtcblx0c3RyZWFtLnN0YXJ0ID0gc3RyZWFtLnBvcztcblx0c3RyZWFtLmVhdFdoaWxlKGlzTmFtZSk7XG5cdHJldHVybiBzdHJlYW0uY3VycmVudCgpO1xufVxuXG5mdW5jdGlvbiBpc05hbWUoY29kZSkge1xuXHRyZXR1cm4gX2VtbWV0aW9fc3RyZWFtUmVhZGVyVXRpbHMuaXNBbHBoYU51bWVyaWMoY29kZSlcblx0XHR8fCBjb2RlID09PSA0NSAvKiAtICovXG5cdFx0fHwgY29kZSA9PT0gNTggLyogOiAqL1xuXHRcdHx8IGNvZGUgPT09IDM2IC8qICQgKi9cblx0XHR8fCBjb2RlID09PSA2NCAvKiBAICovXG5cdFx0fHwgY29kZSA9PT0gMzMgLyogISAqL1xuXHRcdHx8IGNvZGUgPT09IDM3IC8qICUgKi87XG59XG5cbmNvbnN0IEdST1VQX1NUQVJUID0gNDA7IC8vIChcbmNvbnN0IEdST1VQX0VORCAgID0gNDE7IC8vIClcbmNvbnN0IE9QX1NJQkxJTkcgID0gNDM7IC8vICtcbmNvbnN0IE9QX0NISUxEICAgID0gNjI7IC8vID5cbmNvbnN0IE9QX0NMSU1CICAgID0gOTQ7IC8vIF5cblxuLyoqXG4gKiBQYXJzZXMgZ2l2ZW4gc3RyaW5nIGludG8gYSBub2RlIHRyZWVcbiAqIEBwYXJhbSAge1N0cmluZ30gc3RyIEFiYnJldmlhdGlvbiB0byBwYXJzZVxuICogQHJldHVybiB7Tm9kZX1cbiAqL1xuZnVuY3Rpb24gcGFyc2Uoc3RyKSB7XG5cdGNvbnN0IHN0cmVhbSA9IG5ldyBTdHJlYW1SZWFkZXIoc3RyLnRyaW0oKSk7XG5cdGNvbnN0IHJvb3QgPSBuZXcgTm9kZSgpO1xuXHRsZXQgY3R4ID0gcm9vdCwgZ3JvdXBTdGFjayA9IFtdLCBjaDtcblxuXHR3aGlsZSAoIXN0cmVhbS5lb2YoKSkge1xuXHRcdGNoID0gc3RyZWFtLnBlZWsoKTtcblxuXHRcdGlmIChjaCA9PT0gR1JPVVBfU1RBUlQpIHsgLy8gc3RhcnQgb2YgZ3JvdXBcblx0XHRcdC8vIFRoZSBncm91cGluZyBub2RlIHNob3VsZCBiZSBkZXRhY2hlZCB0byBwcm9wZXJseSBoYW5kbGVcblx0XHRcdC8vIG91dC1vZi1ib3VuZHMgYF5gIG9wZXJhdG9yLiBOb2RlIHdpbGwgYmUgYXR0YWNoZWQgcmlnaHQgb24gZ3JvdXAgZW5kXG5cdFx0XHRjb25zdCBub2RlID0gbmV3IE5vZGUoKTtcblx0XHRcdGNvbnN0IGdyb3VwQ3R4ID0gZ3JvdXBTdGFjay5sZW5ndGggPyBsYXN0KGdyb3VwU3RhY2spWzBdIDogY3R4O1xuXHRcdFx0Z3JvdXBTdGFjay5wdXNoKFtub2RlLCBncm91cEN0eCwgc3RyZWFtLnBvc10pO1xuXHRcdFx0Y3R4ID0gbm9kZTtcblx0XHRcdHN0cmVhbS5uZXh0KCk7XG5cdFx0XHRjb250aW51ZTtcblx0XHR9IGVsc2UgaWYgKGNoID09PSBHUk9VUF9FTkQpIHsgLy8gZW5kIG9mIGdyb3VwXG5cdFx0XHRjb25zdCBsYXN0R3JvdXAgPSBncm91cFN0YWNrLnBvcCgpO1xuXHRcdFx0aWYgKCFsYXN0R3JvdXApIHtcblx0XHRcdFx0dGhyb3cgc3RyZWFtLmVycm9yKCdVbmV4cGVjdGVkIFwiKVwiIGdyb3VwIGVuZCcpO1xuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCBub2RlID0gbGFzdEdyb3VwWzBdO1xuXHRcdFx0Y3R4ID0gbGFzdEdyb3VwWzFdO1xuXHRcdFx0c3RyZWFtLm5leHQoKTtcblxuXHRcdFx0Ly8gYSBncm91cCBjYW4gaGF2ZSBhIHJlcGVhdGVyXG5cdFx0XHRpZiAobm9kZS5yZXBlYXQgPSBjb25zdW1lUmVwZWF0KHN0cmVhbSkpIHtcblx0XHRcdFx0Y3R4LmFwcGVuZENoaWxkKG5vZGUpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Ly8gbW92ZSBhbGwgY2hpbGRyZW4gb2YgZ3JvdXAgaW50byBwYXJlbnQgbm9kZVxuXHRcdFx0XHR3aGlsZSAobm9kZS5maXJzdENoaWxkKSB7XG5cdFx0XHRcdFx0Y3R4LmFwcGVuZENoaWxkKG5vZGUuZmlyc3RDaGlsZCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0Ly8gZm9yIGNvbnZlbmllbmNlLCBncm91cHMgY2FuIGJlIGpvaW5lZCB3aXRoIG9wdGlvbmFsIGArYCBvcGVyYXRvclxuXHRcdFx0XHRzdHJlYW0uZWF0KE9QX1NJQkxJTkcpO1xuXHRcdFx0fVxuXG5cdFx0XHRjb250aW51ZTtcblx0XHR9XG5cblx0XHRjb25zdCBub2RlID0gY29uc3VtZUVsZW1lbnQoc3RyZWFtKTtcblx0XHRjdHguYXBwZW5kQ2hpbGQobm9kZSk7XG5cblx0XHRpZiAoc3RyZWFtLmVvZigpKSB7XG5cdFx0XHRicmVhaztcblx0XHR9XG5cblx0XHRzd2l0Y2ggKHN0cmVhbS5wZWVrKCkpIHtcblx0XHRcdGNhc2UgT1BfU0lCTElORzpcblx0XHRcdFx0c3RyZWFtLm5leHQoKTtcblx0XHRcdFx0Y29udGludWU7XG5cblx0XHRcdGNhc2UgT1BfQ0hJTEQ6XG5cdFx0XHRcdHN0cmVhbS5uZXh0KCk7XG5cdFx0XHRcdGN0eCA9IG5vZGU7XG5cdFx0XHRcdGNvbnRpbnVlO1xuXG5cdFx0XHRjYXNlIE9QX0NMSU1COlxuXHRcdFx0XHQvLyBpdOKAmXMgcGVyZmVjdGx5IHZhbGlkIHRvIGhhdmUgbXVsdGlwbGUgYF5gIG9wZXJhdG9yc1xuXHRcdFx0XHR3aGlsZSAoc3RyZWFtLmVhdChPUF9DTElNQikpIHtcblx0XHRcdFx0XHRjdHggPSBjdHgucGFyZW50IHx8IGN0eDtcblx0XHRcdFx0fVxuXHRcdFx0XHRjb250aW51ZTtcblx0XHR9XG5cdH1cblxuXHRpZiAoZ3JvdXBTdGFjay5sZW5ndGgpIHtcblx0XHRzdHJlYW0ucG9zID0gZ3JvdXBTdGFjay5wb3AoKVsyXTtcblx0XHR0aHJvdyBzdHJlYW0uZXJyb3IoJ0V4cGVjdGVkIGdyb3VwIGNsb3NlJyk7XG5cdH1cblxuXHRyZXR1cm4gcm9vdDtcbn1cblxuZnVuY3Rpb24gbGFzdChhcnIpIHtcblx0cmV0dXJuIGFyclthcnIubGVuZ3RoIC0gMV07XG59XG5cbi8qKlxuICogUGFyc2VzIGdpdmVuIGFiYnJldmlhdGlvbiBhbmQgdW4tcm9sbHMgaXQgaW50byBhIGZ1bGwgdHJlZTogcmVjdXJzaXZlbHlcbiAqIHJlcGxhY2VzIHJlcGVhdGVkIGVsZW1lbnRzIHdpdGggYWN0dWFsIG5vZGVzXG4gKiBAcGFyYW0gIHtTdHJpbmd9IGFiYnJcbiAqIEByZXR1cm4ge05vZGV9XG4gKi9cbnZhciBpbmRleCA9IGZ1bmN0aW9uKGFiYnIpIHtcblx0Y29uc3QgdHJlZSA9IHBhcnNlKGFiYnIpO1xuXHR0cmVlLndhbGsodW5yb2xsKTtcblx0cmV0dXJuIHRyZWU7XG59O1xuXG5mdW5jdGlvbiB1bnJvbGwobm9kZSkge1xuXHRpZiAoIW5vZGUucmVwZWF0IHx8ICFub2RlLnJlcGVhdC5jb3VudCkge1xuXHRcdHJldHVybjtcblx0fVxuXG5cdGZvciAobGV0IGkgPSAxOyBpIDwgbm9kZS5yZXBlYXQuY291bnQ7IGkrKykge1xuXHRcdGNvbnN0IGNsb25lID0gbm9kZS5jbG9uZSh0cnVlKTtcblx0XHRjbG9uZS5yZXBlYXQudmFsdWUgPSBpO1xuXHRcdGNsb25lLndhbGsodW5yb2xsKTtcblx0XHRub2RlLnBhcmVudC5pbnNlcnRCZWZvcmUoY2xvbmUsIG5vZGUpO1xuXHR9XG5cblx0bm9kZS5yZXBlYXQudmFsdWUgPSBub2RlLnJlcGVhdC5jb3VudDtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBpbmRleDtcbiJdfQ== | |
require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | |
'use strict'; | |
const inlineElements = new Set('a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var'.split(',')); | |
const elementMap = { | |
p: 'span', | |
ul: 'li', | |
ol: 'li', | |
table: 'tr', | |
tr: 'td', | |
tbody: 'tr', | |
thead: 'tr', | |
tfoot: 'tr', | |
colgroup: 'col', | |
select: 'option', | |
optgroup: 'option', | |
audio: 'source', | |
video: 'source', | |
object: 'param', | |
map: 'area' | |
}; | |
/** | |
* Returns best child node name for given parent node name | |
* @param {String} parentName Name of parent node | |
* @return {String} | |
*/ | |
function resolveImplicitName(parentName) { | |
parentName = (parentName || '').toLowerCase(); | |
return elementMap[parentName] | |
|| (inlineElements.has(parentName) ? 'span' : 'div'); | |
} | |
module.exports = resolveImplicitName; | |
},{}],"@emmetio/html-transform":[function(require,module,exports){ | |
'use strict'; | |
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } | |
var resolveImplicitTag = _interopDefault(require('@emmetio/implicit-tag')); | |
/** | |
* Adds missing tag names for given tree depending on node’s parent name | |
*/ | |
var implicitTags = function(tree) { | |
tree.walk(node => { | |
// resolve only nameless nodes without content | |
if (node.name == null && node.attributes.length) { | |
node.name = resolveImplicitTag(node.parent.name); | |
} | |
}); | |
return tree; | |
}; | |
/** | |
* Locates all occurances of given `token` which are not escaped (e.g. are not | |
* preceded with `\`) given in `str` | |
* @param {String} str | |
* @return {Array} Array of token ranges | |
*/ | |
function findUnescapedTokens(str, token) { | |
const result = new Set(); | |
const tlen = token.length; | |
// 1. Find all occurances of tokens | |
let pos = 0; | |
while ((pos = str.indexOf(token, pos)) !== -1) { | |
result.add(pos); | |
pos += tlen; | |
} | |
if (result.size) { | |
// 2. Remove ones that escaped | |
let pos = 0; | |
const len = str.length; | |
while (pos < len) { | |
if (str[pos++] === '\\') { | |
result.delete(pos++); | |
} | |
} | |
} | |
return Array.from(result).map(ix => range(ix, tlen)); | |
} | |
/** | |
* Replaces `ranges`, generated by `range()` function, with given `value` in `str` | |
* @param {String} str Where to replace ranges | |
* @param {Array} ranges Ranes, created by `range()` function | |
* @param {String|Function} value Replacement value. If it’s a function, it | |
* will take a range value as argument and should return a new string | |
* @return {String} | |
*/ | |
function replaceRanges(str, ranges, value) { | |
// should walk from the end of array to keep ranges valid after replacement | |
for (let i = ranges.length - 1; i >= 0; i--) { | |
const r = ranges[i]; | |
str = str.substring(0, r[0]) | |
+ (typeof value === 'function' ? value(str.substr(r[0], r[1])) : value) | |
+ str.substring(r[0] + r[1]); | |
} | |
return str; | |
} | |
function range(start, length) { | |
return [start, length]; | |
} | |
const numberingToken = '$'; | |
/** | |
* Numbering of expanded abbreviation: finds all nodes with `$` in value | |
* or attributes and replaces its occurances with repeater value | |
*/ | |
var applyNumbering = function(tree) { | |
tree.walk(applyNumbering$1); | |
return tree; | |
}; | |
/** | |
* Applies numbering for given node: replaces occurances of numbering token | |
* in node’s name, content and attributes | |
* @param {Node} node | |
* @return {Node} | |
*/ | |
function applyNumbering$1(node) { | |
const repeater = findRepeater(node); | |
if (repeater && repeater.value != null) { | |
// NB replace numbering in nodes with explicit repeater only: | |
// it solves issues with abbreviations like `xsl:if[test=$foo]` where | |
// `$foo` is preferred output | |
const value = repeater.value; | |
node.name = replaceNumbering(node.name, value); | |
node.value = replaceNumbering(node.value, value); | |
node.attributes.forEach(attr => { | |
const copy = node.getAttribute(attr.name).clone(); | |
copy.name = replaceNumbering(attr.name, value); | |
copy.value = replaceNumbering(attr.value, value); | |
node.replaceAttribute(attr.name, copy); | |
}); | |
} | |
return node; | |
} | |
/** | |
* Returns repeater object for given node | |
* @param {Node} node | |
* @return {Object} | |
*/ | |
function findRepeater(node) { | |
while (node) { | |
if (node.repeat) { | |
return node.repeat; | |
} | |
node = node.parent; | |
} | |
} | |
/** | |
* Replaces numbering in given string | |
* @param {String} str | |
* @param {Number} value | |
* @return {String} | |
*/ | |
function replaceNumbering(str, value) { | |
// replace numbering in strings only: skip explicit wrappers that could | |
// contain unescaped numbering tokens | |
if (typeof str === 'string') { | |
const ranges = getNumberingRanges(str); | |
return replaceNumberingRanges(str, ranges, value); | |
} | |
return str; | |
} | |
/** | |
* Returns numbering ranges, e.g. ranges of `$` occurances, in given string. | |
* Multiple adjacent ranges are combined | |
* @param {String} str | |
* @return {Array} | |
*/ | |
function getNumberingRanges(str) { | |
return findUnescapedTokens(str || '', numberingToken) | |
.reduce((out, range$$1) => { | |
// skip ranges that actually belongs to output placeholder or tabstops | |
if (!/[#{]/.test(str[range$$1[0] + 1] || '')) { | |
const lastRange = out[out.length - 1]; | |
if (lastRange && lastRange[0] + lastRange[1] === range$$1[0]) { | |
lastRange[1] += range$$1[1]; | |
} else { | |
out.push(range$$1); | |
} | |
} | |
return out; | |
}, []); | |
} | |
/** | |
* @param {String} str | |
* @param {Array} ranges | |
* @param {Number} value | |
* @return {String} | |
*/ | |
function replaceNumberingRanges(str, ranges, value) { | |
const replaced = replaceRanges(str, ranges, token => { | |
let _value = String(value); | |
// pad values for multiple numbering tokens, e.g. 3 for $$$ becomes 003 | |
while (_value.length < token.length) { | |
_value = '0' + _value; | |
} | |
return _value; | |
}); | |
// unescape screened numbering tokens | |
return unescapeString(replaced); | |
} | |
/** | |
* Unescapes characters, screened with `\`, in given string | |
* @param {String} str | |
* @return {String} | |
*/ | |
function unescapeString(str) { | |
let i = 0, result = ''; | |
const len = str.length; | |
while (i < len) { | |
const ch = str[i++]; | |
result += (ch === '\\') ? (str[i++] || '') : ch; | |
} | |
return result; | |
} | |
/** Placeholder for inserted content */ | |
const placeholder = '$#'; | |
/** Placeholder for caret */ | |
const caret = '|'; | |
const reUrl = /^((?:https?|ftp|file):\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/; | |
const reEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/; | |
const reProto = /^([a-z]+:)?\/\//i; | |
/** | |
* Inserts content into node with implicit repeat count: this node is then | |
* duplicated for each content item and content itself is inserted either into | |
* deepest child or instead of a special token. | |
* | |
* This method uses two distinct steps: `prepare()` and `insert()` since most | |
* likely these steps will be used separately to properly insert content | |
* with unescaped `$` numbering markers. | |
* | |
* @param {Node} tree Parsed abbreviation | |
* @param {String[]} content Array of content items to insert | |
* @return {Node} | |
*/ | |
/** | |
* Finds nodes with implicit repeat and creates `amount` copies of it in tree | |
* @param {Node} tree | |
* @param {Number} amount | |
* @return {Node} | |
*/ | |
function prepare(tree, amount) { | |
amount = amount || 1; | |
tree.walk(node => { | |
if (node.repeat && node.repeat.count === null) { | |
for (let i = 0; i < amount; i++) { | |
const clone = node.clone(true); | |
clone.repeat.implicit = true; | |
clone.repeat.count = amount; | |
clone.repeat.value = i + 1; | |
clone.repeat.index = i; | |
node.parent.insertBefore(clone, node); | |
} | |
node.remove(); | |
} | |
}); | |
return tree; | |
} | |
/** | |
* Inserts content into implicitly repeated nodes, created by `prepare()` method | |
* @param {Node} tree | |
* @param {String[]} content | |
* @return {Node} | |
*/ | |
function insert(tree, content) { | |
if (Array.isArray(content) && content.length) { | |
let updated = false; | |
tree.walk(node => { | |
if (node.repeat && node.repeat.implicit) { | |
updated = true; | |
insertContent(node, content[node.repeat.index]); | |
} | |
}); | |
if (!updated) { | |
// no node with implicit repeat was found, insert content as | |
// deepest child | |
setNodeContent(findDeepestNode(tree), content.join('\n')); | |
} | |
} | |
return tree; | |
} | |
/** | |
* Inserts `content` into given `node`: either replaces output placeholders | |
* or inserts it into deepest child node | |
* @param {Node} node | |
* @param {String} content | |
* @return {Node} | |
*/ | |
function insertContent(node, content) { | |
let inserted = insertContentIntoPlaceholder(node, content); | |
node.walk(child => inserted |= insertContentIntoPlaceholder(child, content)); | |
if (!inserted) { | |
// no placeholders were found in node, insert content into deepest child | |
setNodeContent(findDeepestNode(node), content); | |
} | |
return node; | |
} | |
/** | |
* Inserts given `content` into placeholders for given `node`. Placeholders | |
* might be available in attribute values and node content | |
* @param {Node} node | |
* @param {String} content | |
* @return {Boolean} Returns `true` if placeholders were found and replaced in node | |
*/ | |
function insertContentIntoPlaceholder(node, content) { | |
const state = {replaced: false}; | |
node.value = replacePlaceholder(node.value, content, state); | |
node.attributes.forEach(attr => { | |
if (attr.value) { | |
node.setAttribute(attr.name, replacePlaceholder(attr.value, content, state)); | |
} | |
}); | |
return state.replaced; | |
} | |
/** | |
* Replaces all placeholder occurances in given `str` with `value` | |
* @param {String} str | |
* @param {String} value | |
* @param {Object} [_state] If provided, set `replaced` property of given | |
* object to `true` if placeholder was found and replaced | |
* @return {String} | |
*/ | |
function replacePlaceholder(str, value, _state) { | |
if (typeof str === 'string') { | |
const ranges = findUnescapedTokens(str, placeholder); | |
if (ranges.length) { | |
if (_state) { | |
_state.replaced = true; | |
} | |
str = replaceRanges(str, ranges, value); | |
} | |
} | |
return str; | |
} | |
/** | |
* Finds node which is the deepest for in current node or node iteself. | |
* @param {Node} node | |
* @return {Node} | |
*/ | |
function findDeepestNode(node) { | |
while (node.children.length) { | |
node = node.children[node.children.length - 1]; | |
} | |
return node; | |
} | |
/** | |
* Updates content of given node | |
* @param {Node} node | |
* @param {String} content | |
*/ | |
function setNodeContent(node, content) { | |
// find caret position and replace it with content, if possible | |
if (node.value) { | |
const ranges = findUnescapedTokens(node.value, caret); | |
if (ranges.length) { | |
node.value = replaceRanges(node.value, ranges, content); | |
return; | |
} | |
} | |
if (node.name.toLowerCase('a') || node.hasAttribute('href')) { | |
// special case: inserting content into `<a>` tag | |
if (reUrl.test(content)) { | |
node.setAttribute('href', (reProto.test(content) ? '' : 'http://') + content); | |
} else if (reEmail.test(content)) { | |
node.setAttribute('href', 'mailto:' + content); | |
} | |
} | |
node.value = content; | |
} | |
const defaultOptions = { | |
element: '__', | |
modifier: '_' | |
}; | |
const reElement = /^(-+)([a-z0-9]+)/i; | |
const reModifier = /^(_+)([a-z0-9]+)/i; | |
const blockCandidates1 = className => /^[a-z]\-/i.test(className); | |
const blockCandidates2 = className => /^[a-z]/i.test(className); | |
/** | |
* BEM transformer: updates class names written as `-element` and | |
* `_modifier` into full class names as described in BEM specs. Also adds missing | |
* class names: fir example, if node contains `.block_modifier` class, ensures | |
* that element contains `.block` class as well | |
*/ | |
var bem = function(tree, options) { | |
options = Object.assign({}, defaultOptions, options); | |
tree.walk(node => expandClassNames(node, options)); | |
const lookup = createBlockLookup(tree); | |
tree.walk(node => expandShortNotation(node, lookup, options)); | |
return tree; | |
}; | |
/** | |
* Expands existing class names in BEM notation in given `node`. | |
* For example, if node contains `b__el_mod` class name, this method ensures | |
* that element contains `b__el` class as well | |
* @param {Node} node | |
* @param {Object} options | |
* @return {Set} | |
*/ | |
function expandClassNames(node, options) { | |
const classNames = node.classList.reduce((out, cl) => { | |
// remove all modifiers from class name to get a base element name | |
const ix = cl.indexOf(options.modifier); | |
if (ix !== -1) { | |
out.add(cl.slice(0, ix)); | |
} | |
return out.add(cl); | |
}, new Set()); | |
if (classNames.size) { | |
node.setAttribute('class', Array.from(classNames).join(' ')); | |
} | |
} | |
/** | |
* Expands short BEM notation, e.g. `-element` and `_modifier` | |
* @param {Node} node Parsed Emmet abbreviation node | |
* @param {Map} lookup BEM block name lookup | |
* @param {Object} options | |
*/ | |
function expandShortNotation(node, lookup, options) { | |
const classNames = node.classList.reduce((out, cl) => { | |
let prefix, m; | |
const originalClass = cl; | |
// parse element definition (could be only one) | |
if (m = cl.match(reElement)) { | |
prefix = getBlockName(node, lookup, m[1]) + options.element + m[2]; | |
out.add(prefix); | |
cl = cl.slice(m[0].length); | |
} | |
// parse modifiers definitions (may contain multiple) | |
while (m = cl.match(reModifier)) { | |
if (!prefix) { | |
prefix = getBlockName(node, lookup, m[1]); | |
out.add(prefix); | |
} | |
out.add(`${prefix}${options.modifier}${m[2]}`); | |
cl = cl.slice(m[0].length); | |
} | |
if (cl === originalClass) { | |
// class name wasn’t modified: it’s not a BEM-specific class, | |
// add it as-is into output | |
out.add(originalClass); | |
} | |
return out; | |
}, new Set()); | |
node.setAttribute('class', Array.from(classNames).join(' ')); | |
} | |
/** | |
* Creates block name lookup for each node in given tree, e.g. finds block | |
* name explicitly for each node | |
* @param {Node} tree | |
* @return {Map} | |
*/ | |
function createBlockLookup(tree) { | |
const lookup = new Map(); | |
tree.walk(node => { | |
const classNames = node.classList; | |
if (classNames.length) { | |
// guess best block name from class or use parent’s block name | |
lookup.set(node, | |
find(classNames, blockCandidates1) | |
|| find(classNames, blockCandidates2) | |
|| lookup.get(node.parent) | |
); | |
} | |
}); | |
return lookup; | |
} | |
/** | |
* Returns block name for given `node` by `prefix`, which tells the depth of | |
* of parent node lookup | |
* @param {Node} node | |
* @param {Map} lookup | |
* @param {String} prefix | |
* @return {String} | |
*/ | |
function getBlockName(node, lookup, prefix) { | |
let depth = prefix.length > 1 ? prefix.length : 0; | |
while (node.parent && depth--) { | |
node = node.parent; | |
} | |
return lookup.get(node); | |
} | |
function find(arr, filter) { | |
return arr.filter(filter)[0]; | |
} | |
/** | |
* JSX transformer: replaces `class` and `for` attributes with `className` and | |
* `htmlFor` attributes respectively | |
*/ | |
var jsx = function(tree) { | |
tree.walk(node => { | |
replace(node, 'class', 'className'); | |
replace(node, 'for', 'htmlFor'); | |
}); | |
return tree; | |
}; | |
function replace(node, oldName, newName) { | |
let attr = node.getAttribute(oldName); | |
if (attr) { | |
attr.name = newName; | |
} | |
} | |
const reSupporterNames = /^xsl:(variable|with\-param)$/i; | |
/** | |
* XSL transformer: removes `select` attributes from certain nodes that contain | |
* children | |
*/ | |
var xsl = function(tree) { | |
tree.walk(node => { | |
if (reSupporterNames.test(node.name || '') && (node.children.length || node.value)) { | |
node.removeAttribute('select'); | |
} | |
}); | |
return tree; | |
}; | |
const supportedAddons = { bem, jsx, xsl }; | |
/** | |
* Runs additional transforms on given tree. | |
* These transforms may introduce side-effects and unexpected result | |
* so they are not applied by default, authors must specify which addons | |
* in `addons` argument as `{addonName: addonOptions}` | |
* @param {Node} tree Parsed Emmet abbreviation | |
* @param {Object} addons Add-ons to apply and their options | |
*/ | |
var addons = function(tree, addons) { | |
Object.keys(addons || {}).forEach(key => { | |
if (key in supportedAddons) { | |
const addonOpt = typeof addons[key] === 'object' ? addons[key] : null; | |
tree = tree.use(supportedAddons[key], addonOpt); | |
} | |
}); | |
return tree; | |
}; | |
/** | |
* Applies basic HTML-specific transformations for given parsed abbreviation: | |
* – resolve implied tag names | |
* – insert repeated content | |
* – resolve node numbering | |
*/ | |
var index = function(tree, content, appliedAddons) { | |
if (typeof content === 'string') { | |
content = [content]; | |
} else if (content && typeof content === 'object' && !Array.isArray(content)) { | |
appliedAddons = content; | |
content = null; | |
} | |
return tree | |
.use(implicitTags) | |
.use(prepare, Array.isArray(content) ? content.length : null) | |
.use(applyNumbering) | |
.use(insert, content) | |
.use(addons, appliedAddons); | |
}; | |
module.exports = index; | |
},{"@emmetio/implicit-tag":1}]},{},[]) | |
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsIm5vZGVfbW9kdWxlcy9AZW1tZXRpby9pbXBsaWNpdC10YWcvZGlzdC9pbXBsaWNpdC10YWcuY2pzLmpzIiwiQGVtbWV0aW8lMkZodG1sLXRyYW5zZm9ybSJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiJ3VzZSBzdHJpY3QnO1xuXG5jb25zdCBpbmxpbmVFbGVtZW50cyA9IG5ldyBTZXQoJ2EsYWJicixhY3JvbnltLGFwcGxldCxiLGJhc2Vmb250LGJkbyxiaWcsYnIsYnV0dG9uLGNpdGUsY29kZSxkZWwsZGZuLGVtLGZvbnQsaSxpZnJhbWUsaW1nLGlucHV0LGlucyxrYmQsbGFiZWwsbWFwLG9iamVjdCxxLHMsc2FtcCxzZWxlY3Qsc21hbGwsc3BhbixzdHJpa2Usc3Ryb25nLHN1YixzdXAsdGV4dGFyZWEsdHQsdSx2YXInLnNwbGl0KCcsJykpO1xuY29uc3QgZWxlbWVudE1hcCA9IHtcbiAgICBwOiAnc3BhbicsXG4gICAgdWw6ICdsaScsXG4gICAgb2w6ICdsaScsXG4gICAgdGFibGU6ICd0cicsXG4gICAgdHI6ICd0ZCcsXG4gICAgdGJvZHk6ICd0cicsXG4gICAgdGhlYWQ6ICd0cicsXG4gICAgdGZvb3Q6ICd0cicsXG4gICAgY29sZ3JvdXA6ICdjb2wnLFxuICAgIHNlbGVjdDogJ29wdGlvbicsXG4gICAgb3B0Z3JvdXA6ICdvcHRpb24nLFxuICAgIGF1ZGlvOiAnc291cmNlJyxcbiAgICB2aWRlbzogJ3NvdXJjZScsXG4gICAgb2JqZWN0OiAncGFyYW0nLFxuICAgIG1hcDogJ2FyZWEnXG59O1xuXG4vKipcbiAqIFJldHVybnMgYmVzdCBjaGlsZCBub2RlIG5hbWUgZm9yIGdpdmVuIHBhcmVudCBub2RlIG5hbWVcbiAqIEBwYXJhbSAge1N0cmluZ30gcGFyZW50TmFtZSBOYW1lIG9mIHBhcmVudCBub2RlXG4gKiBAcmV0dXJuIHtTdHJpbmd9XG4gKi9cbmZ1bmN0aW9uIHJlc29sdmVJbXBsaWNpdE5hbWUocGFyZW50TmFtZSkge1xuICAgIHBhcmVudE5hbWUgPSAocGFyZW50TmFtZSB8fCAnJykudG9Mb3dlckNhc2UoKTtcbiAgICByZXR1cm4gZWxlbWVudE1hcFtwYXJlbnROYW1lXVxuICAgICAgICB8fCAoaW5saW5lRWxlbWVudHMuaGFzKHBhcmVudE5hbWUpID8gJ3NwYW4nIDogJ2RpdicpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHJlc29sdmVJbXBsaWNpdE5hbWU7XG4iLCIndXNlIHN0cmljdCc7XG5cbmZ1bmN0aW9uIF9pbnRlcm9wRGVmYXVsdCAoZXgpIHsgcmV0dXJuIChleCAmJiAodHlwZW9mIGV4ID09PSAnb2JqZWN0JykgJiYgJ2RlZmF1bHQnIGluIGV4KSA/IGV4WydkZWZhdWx0J10gOiBleDsgfVxuXG52YXIgcmVzb2x2ZUltcGxpY2l0VGFnID0gX2ludGVyb3BEZWZhdWx0KHJlcXVpcmUoJ0BlbW1ldGlvL2ltcGxpY2l0LXRhZycpKTtcblxuLyoqXG4gKiBBZGRzIG1pc3NpbmcgdGFnIG5hbWVzIGZvciBnaXZlbiB0cmVlIGRlcGVuZGluZyBvbiBub2Rl4oCZcyBwYXJlbnQgbmFtZVxuICovXG52YXIgaW1wbGljaXRUYWdzID0gZnVuY3Rpb24odHJlZSkge1xuICAgIHRyZWUud2Fsayhub2RlID0+IHtcbiAgICAgICAgLy8gcmVzb2x2ZSBvbmx5IG5hbWVsZXNzIG5vZGVzIHdpdGhvdXQgY29udGVudFxuICAgICAgICBpZiAobm9kZS5uYW1lID09IG51bGwgJiYgbm9kZS5hdHRyaWJ1dGVzLmxlbmd0aCkge1xuICAgICAgICAgICAgbm9kZS5uYW1lID0gcmVzb2x2ZUltcGxpY2l0VGFnKG5vZGUucGFyZW50Lm5hbWUpO1xuICAgICAgICB9XG4gICAgfSk7XG4gICAgcmV0dXJuIHRyZWU7XG59O1xuXG4vKipcbiAqIExvY2F0ZXMgYWxsIG9jY3VyYW5jZXMgb2YgZ2l2ZW4gYHRva2VuYCB3aGljaCBhcmUgbm90IGVzY2FwZWQgKGUuZy4gYXJlIG5vdFxuICogcHJlY2VkZWQgd2l0aCBgXFxgKSBnaXZlbiBpbiBgc3RyYFxuICogQHBhcmFtICB7U3RyaW5nfSBzdHJcbiAqIEByZXR1cm4ge0FycmF5fSAgQXJyYXkgb2YgdG9rZW4gcmFuZ2VzXG4gKi9cbmZ1bmN0aW9uIGZpbmRVbmVzY2FwZWRUb2tlbnMoc3RyLCB0b2tlbikge1xuICAgIGNvbnN0IHJlc3VsdCA9IG5ldyBTZXQoKTtcbiAgICBjb25zdCB0bGVuID0gdG9rZW4ubGVuZ3RoO1xuXG4gICAgLy8gMS4gRmluZCBhbGwgb2NjdXJhbmNlcyBvZiB0b2tlbnNcbiAgICBsZXQgcG9zID0gMDtcbiAgICB3aGlsZSAoKHBvcyA9IHN0ci5pbmRleE9mKHRva2VuLCBwb3MpKSAhPT0gLTEpIHtcbiAgICAgICAgcmVzdWx0LmFkZChwb3MpO1xuICAgICAgICBwb3MgKz0gdGxlbjtcbiAgICB9XG5cbiAgICBpZiAocmVzdWx0LnNpemUpIHtcbiAgICAgICAgLy8gMi4gUmVtb3ZlIG9uZXMgdGhhdCBlc2NhcGVkXG4gICAgICAgIGxldCBwb3MgPSAwO1xuICAgICAgICBjb25zdCBsZW4gPSBzdHIubGVuZ3RoO1xuXG4gICAgICAgIHdoaWxlIChwb3MgPCBsZW4pIHtcbiAgICAgICAgICAgIGlmIChzdHJbcG9zKytdID09PSAnXFxcXCcpIHtcbiAgICAgICAgICAgICAgICByZXN1bHQuZGVsZXRlKHBvcysrKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBBcnJheS5mcm9tKHJlc3VsdCkubWFwKGl4ID0+IHJhbmdlKGl4LCB0bGVuKSk7XG59XG5cbi8qKlxuICogUmVwbGFjZXMgYHJhbmdlc2AsIGdlbmVyYXRlZCBieSBgcmFuZ2UoKWAgZnVuY3Rpb24sIHdpdGggZ2l2ZW4gYHZhbHVlYCBpbiBgc3RyYFxuICogQHBhcmFtICB7U3RyaW5nfSBzdHIgICAgV2hlcmUgdG8gcmVwbGFjZSByYW5nZXNcbiAqIEBwYXJhbSAge0FycmF5fSByYW5nZXMgUmFuZXMsIGNyZWF0ZWQgYnkgYHJhbmdlKClgIGZ1bmN0aW9uXG4gKiBAcGFyYW0gIHtTdHJpbmd8RnVuY3Rpb259IHZhbHVlICBSZXBsYWNlbWVudCB2YWx1ZS4gSWYgaXTigJlzIGEgZnVuY3Rpb24sIGl0XG4gKiB3aWxsIHRha2UgYSByYW5nZSB2YWx1ZSBhcyBhcmd1bWVudCBhbmQgc2hvdWxkIHJldHVybiBhIG5ldyBzdHJpbmdcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xuZnVuY3Rpb24gcmVwbGFjZVJhbmdlcyhzdHIsIHJhbmdlcywgdmFsdWUpIHtcblx0Ly8gc2hvdWxkIHdhbGsgZnJvbSB0aGUgZW5kIG9mIGFycmF5IHRvIGtlZXAgcmFuZ2VzIHZhbGlkIGFmdGVyIHJlcGxhY2VtZW50XG5cdGZvciAobGV0IGkgPSByYW5nZXMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHtcblx0XHRjb25zdCByID0gcmFuZ2VzW2ldO1xuXG5cdFx0c3RyID0gc3RyLnN1YnN0cmluZygwLCByWzBdKVxuXHRcdFx0KyAodHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nID8gdmFsdWUoc3RyLnN1YnN0cihyWzBdLCByWzFdKSkgOiB2YWx1ZSlcblx0XHRcdCsgc3RyLnN1YnN0cmluZyhyWzBdICsgclsxXSk7XG5cdH1cblxuXHRyZXR1cm4gc3RyO1xufVxuXG5mdW5jdGlvbiByYW5nZShzdGFydCwgbGVuZ3RoKSB7XG4gICAgcmV0dXJuIFtzdGFydCwgbGVuZ3RoXTtcbn1cblxuY29uc3QgbnVtYmVyaW5nVG9rZW4gPSAnJCc7XG5cbi8qKlxuICogTnVtYmVyaW5nIG9mIGV4cGFuZGVkIGFiYnJldmlhdGlvbjogZmluZHMgYWxsIG5vZGVzIHdpdGggYCRgIGluIHZhbHVlXG4gKiBvciBhdHRyaWJ1dGVzIGFuZCByZXBsYWNlcyBpdHMgb2NjdXJhbmNlcyB3aXRoIHJlcGVhdGVyIHZhbHVlXG4gKi9cbnZhciBhcHBseU51bWJlcmluZyA9IGZ1bmN0aW9uKHRyZWUpIHtcbiAgICB0cmVlLndhbGsoYXBwbHlOdW1iZXJpbmckMSk7XG4gICAgcmV0dXJuIHRyZWU7XG59O1xuXG4vKipcbiAqIEFwcGxpZXMgbnVtYmVyaW5nIGZvciBnaXZlbiBub2RlOiByZXBsYWNlcyBvY2N1cmFuY2VzIG9mIG51bWJlcmluZyB0b2tlblxuICogaW4gbm9kZeKAmXMgbmFtZSwgY29udGVudCBhbmQgYXR0cmlidXRlc1xuICogQHBhcmFtICB7Tm9kZX0gbm9kZVxuICogQHJldHVybiB7Tm9kZX1cbiAqL1xuZnVuY3Rpb24gYXBwbHlOdW1iZXJpbmckMShub2RlKSB7XG4gICAgY29uc3QgcmVwZWF0ZXIgPSBmaW5kUmVwZWF0ZXIobm9kZSk7XG5cbiAgICBpZiAocmVwZWF0ZXIgJiYgcmVwZWF0ZXIudmFsdWUgIT0gbnVsbCkge1xuICAgICAgICAvLyBOQiByZXBsYWNlIG51bWJlcmluZyBpbiBub2RlcyB3aXRoIGV4cGxpY2l0IHJlcGVhdGVyIG9ubHk6XG4gICAgICAgIC8vIGl0IHNvbHZlcyBpc3N1ZXMgd2l0aCBhYmJyZXZpYXRpb25zIGxpa2UgYHhzbDppZlt0ZXN0PSRmb29dYCB3aGVyZVxuICAgICAgICAvLyBgJGZvb2AgaXMgcHJlZmVycmVkIG91dHB1dFxuICAgICAgICBjb25zdCB2YWx1ZSA9IHJlcGVhdGVyLnZhbHVlO1xuXG4gICAgICAgIG5vZGUubmFtZSA9IHJlcGxhY2VOdW1iZXJpbmcobm9kZS5uYW1lLCB2YWx1ZSk7XG4gICAgICAgIG5vZGUudmFsdWUgPSByZXBsYWNlTnVtYmVyaW5nKG5vZGUudmFsdWUsIHZhbHVlKTtcbiAgICAgICAgbm9kZS5hdHRyaWJ1dGVzLmZvckVhY2goYXR0ciA9PiB7XG4gICAgICAgICAgICBjb25zdCBjb3B5ID0gbm9kZS5nZXRBdHRyaWJ1dGUoYXR0ci5uYW1lKS5jbG9uZSgpO1xuICAgICAgICAgICAgY29weS5uYW1lID0gcmVwbGFjZU51bWJlcmluZyhhdHRyLm5hbWUsIHZhbHVlKTtcbiAgICAgICAgICAgIGNvcHkudmFsdWUgPSByZXBsYWNlTnVtYmVyaW5nKGF0dHIudmFsdWUsIHZhbHVlKTtcbiAgICAgICAgICAgIG5vZGUucmVwbGFjZUF0dHJpYnV0ZShhdHRyLm5hbWUsIGNvcHkpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4gbm9kZTtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIHJlcGVhdGVyIG9iamVjdCBmb3IgZ2l2ZW4gbm9kZVxuICogQHBhcmFtICB7Tm9kZX0gbm9kZVxuICogQHJldHVybiB7T2JqZWN0fVxuICovXG5mdW5jdGlvbiBmaW5kUmVwZWF0ZXIobm9kZSkge1xuICAgIHdoaWxlIChub2RlKSB7XG4gICAgICAgIGlmIChub2RlLnJlcGVhdCkge1xuICAgICAgICAgICAgcmV0dXJuIG5vZGUucmVwZWF0O1xuICAgICAgICB9XG5cbiAgICAgICAgbm9kZSA9IG5vZGUucGFyZW50O1xuICAgIH1cbn1cblxuLyoqXG4gKiBSZXBsYWNlcyBudW1iZXJpbmcgaW4gZ2l2ZW4gc3RyaW5nXG4gKiBAcGFyYW0gIHtTdHJpbmd9IHN0clxuICogQHBhcmFtICB7TnVtYmVyfSB2YWx1ZVxuICogQHJldHVybiB7U3RyaW5nfVxuICovXG5mdW5jdGlvbiByZXBsYWNlTnVtYmVyaW5nKHN0ciwgdmFsdWUpIHtcbiAgICAvLyByZXBsYWNlIG51bWJlcmluZyBpbiBzdHJpbmdzIG9ubHk6IHNraXAgZXhwbGljaXQgd3JhcHBlcnMgdGhhdCBjb3VsZFxuICAgIC8vIGNvbnRhaW4gdW5lc2NhcGVkIG51bWJlcmluZyB0b2tlbnNcbiAgICBpZiAodHlwZW9mIHN0ciA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgY29uc3QgcmFuZ2VzID0gZ2V0TnVtYmVyaW5nUmFuZ2VzKHN0cik7XG4gICAgICAgIHJldHVybiByZXBsYWNlTnVtYmVyaW5nUmFuZ2VzKHN0ciwgcmFuZ2VzLCB2YWx1ZSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHN0cjtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIG51bWJlcmluZyByYW5nZXMsIGUuZy4gcmFuZ2VzIG9mIGAkYCBvY2N1cmFuY2VzLCBpbiBnaXZlbiBzdHJpbmcuXG4gKiBNdWx0aXBsZSBhZGphY2VudCByYW5nZXMgYXJlIGNvbWJpbmVkXG4gKiBAcGFyYW0gIHtTdHJpbmd9IHN0clxuICogQHJldHVybiB7QXJyYXl9XG4gKi9cbmZ1bmN0aW9uIGdldE51bWJlcmluZ1JhbmdlcyhzdHIpIHtcbiAgICByZXR1cm4gZmluZFVuZXNjYXBlZFRva2VucyhzdHIgfHwgJycsIG51bWJlcmluZ1Rva2VuKVxuICAgIC5yZWR1Y2UoKG91dCwgcmFuZ2UkJDEpID0+IHtcbiAgICAgICAgLy8gc2tpcCByYW5nZXMgdGhhdCBhY3R1YWxseSBiZWxvbmdzIHRvIG91dHB1dCBwbGFjZWhvbGRlciBvciB0YWJzdG9wc1xuICAgICAgICBpZiAoIS9bI3tdLy50ZXN0KHN0cltyYW5nZSQkMVswXSArIDFdIHx8ICcnKSkge1xuICAgICAgICAgICAgY29uc3QgbGFzdFJhbmdlID0gb3V0W291dC5sZW5ndGggLSAxXTtcbiAgICAgICAgICAgIGlmIChsYXN0UmFuZ2UgJiYgbGFzdFJhbmdlWzBdICsgbGFzdFJhbmdlWzFdID09PSByYW5nZSQkMVswXSkge1xuICAgICAgICAgICAgICAgIGxhc3RSYW5nZVsxXSArPSByYW5nZSQkMVsxXTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgb3V0LnB1c2gocmFuZ2UkJDEpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG91dDtcbiAgICB9LCBbXSk7XG59XG5cbi8qKlxuICogQHBhcmFtICB7U3RyaW5nfSBzdHJcbiAqIEBwYXJhbSAge0FycmF5fSByYW5nZXNcbiAqIEBwYXJhbSAge051bWJlcn0gdmFsdWVcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xuZnVuY3Rpb24gcmVwbGFjZU51bWJlcmluZ1JhbmdlcyhzdHIsIHJhbmdlcywgdmFsdWUpIHtcbiAgICBjb25zdCByZXBsYWNlZCA9IHJlcGxhY2VSYW5nZXMoc3RyLCByYW5nZXMsIHRva2VuID0+IHtcbiAgICAgICAgbGV0IF92YWx1ZSA9IFN0cmluZyh2YWx1ZSk7XG4gICAgICAgIC8vIHBhZCB2YWx1ZXMgZm9yIG11bHRpcGxlIG51bWJlcmluZyB0b2tlbnMsIGUuZy4gMyBmb3IgJCQkIGJlY29tZXMgMDAzXG4gICAgICAgIHdoaWxlIChfdmFsdWUubGVuZ3RoIDwgdG9rZW4ubGVuZ3RoKSB7XG4gICAgICAgICAgICBfdmFsdWUgPSAnMCcgKyBfdmFsdWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIF92YWx1ZTtcbiAgICB9KTtcblxuICAgIC8vIHVuZXNjYXBlIHNjcmVlbmVkIG51bWJlcmluZyB0b2tlbnNcbiAgICByZXR1cm4gdW5lc2NhcGVTdHJpbmcocmVwbGFjZWQpO1xufVxuXG4vKipcbiAqIFVuZXNjYXBlcyBjaGFyYWN0ZXJzLCBzY3JlZW5lZCB3aXRoIGBcXGAsIGluIGdpdmVuIHN0cmluZ1xuICogQHBhcmFtICB7U3RyaW5nfSBzdHJcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xuZnVuY3Rpb24gdW5lc2NhcGVTdHJpbmcoc3RyKSB7XG4gICAgbGV0IGkgPSAwLCByZXN1bHQgPSAnJztcbiAgICBjb25zdCBsZW4gPSBzdHIubGVuZ3RoO1xuXG4gICAgd2hpbGUgKGkgPCBsZW4pIHtcbiAgICAgICAgY29uc3QgY2ggPSBzdHJbaSsrXTtcbiAgICAgICAgcmVzdWx0ICs9IChjaCA9PT0gJ1xcXFwnKSA/IChzdHJbaSsrXSB8fCAnJykgOiBjaDtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0O1xufVxuXG4vKiogUGxhY2Vob2xkZXIgZm9yIGluc2VydGVkIGNvbnRlbnQgKi9cbmNvbnN0IHBsYWNlaG9sZGVyID0gJyQjJztcblxuLyoqIFBsYWNlaG9sZGVyIGZvciBjYXJldCAqL1xuY29uc3QgY2FyZXQgPSAnfCc7XG5cbmNvbnN0IHJlVXJsID0gL14oKD86aHR0cHM/fGZ0cHxmaWxlKTpcXC9cXC8pPyhbXFxkYS16XFwuLV0rKVxcLihbYS16XFwuXXsyLDZ9KShbXFwvXFx3IFxcLi1dKikqXFwvPyQvO1xuY29uc3QgcmVFbWFpbCA9IC9eKFthLXowLTlfXFwuLV0rKUAoW1xcZGEtelxcLi1dKylcXC4oW2EtelxcLl17Miw2fSkkLztcbmNvbnN0IHJlUHJvdG8gPSAvXihbYS16XSs6KT9cXC9cXC8vaTtcblxuLyoqXG4gKiBJbnNlcnRzIGNvbnRlbnQgaW50byBub2RlIHdpdGggaW1wbGljaXQgcmVwZWF0IGNvdW50OiB0aGlzIG5vZGUgaXMgdGhlblxuICogZHVwbGljYXRlZCBmb3IgZWFjaCBjb250ZW50IGl0ZW0gYW5kIGNvbnRlbnQgaXRzZWxmIGlzIGluc2VydGVkIGVpdGhlciBpbnRvXG4gKiBkZWVwZXN0IGNoaWxkIG9yIGluc3RlYWQgb2YgYSBzcGVjaWFsIHRva2VuLlxuICpcbiAqIFRoaXMgbWV0aG9kIHVzZXMgdHdvIGRpc3RpbmN0IHN0ZXBzOiBgcHJlcGFyZSgpYCBhbmQgYGluc2VydCgpYCBzaW5jZSBtb3N0XG4gKiBsaWtlbHkgdGhlc2Ugc3RlcHMgd2lsbCBiZSB1c2VkIHNlcGFyYXRlbHkgdG8gcHJvcGVybHkgaW5zZXJ0IGNvbnRlbnRcbiAqIHdpdGggdW5lc2NhcGVkIGAkYCBudW1iZXJpbmcgbWFya2Vycy5cbiAqXG4gKiBAcGFyYW0ge05vZGV9IHRyZWUgUGFyc2VkIGFiYnJldmlhdGlvblxuICogQHBhcmFtIHtTdHJpbmdbXX0gY29udGVudCBBcnJheSBvZiBjb250ZW50IGl0ZW1zIHRvIGluc2VydFxuICogQHJldHVybiB7Tm9kZX1cbiAqL1xuLyoqXG4gKiBGaW5kcyBub2RlcyB3aXRoIGltcGxpY2l0IHJlcGVhdCBhbmQgY3JlYXRlcyBgYW1vdW50YCBjb3BpZXMgb2YgaXQgaW4gdHJlZVxuICogQHBhcmFtICB7Tm9kZX0gdHJlZVxuICogQHBhcmFtICB7TnVtYmVyfSBhbW91bnRcbiAqIEByZXR1cm4ge05vZGV9XG4gKi9cbmZ1bmN0aW9uIHByZXBhcmUodHJlZSwgYW1vdW50KSB7XG4gICAgYW1vdW50ID0gYW1vdW50IHx8IDE7XG4gICAgdHJlZS53YWxrKG5vZGUgPT4ge1xuICAgICAgICBpZiAobm9kZS5yZXBlYXQgJiYgbm9kZS5yZXBlYXQuY291bnQgPT09IG51bGwpIHtcbiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYW1vdW50OyBpKyspIHtcbiAgICAgICAgICAgICAgICBjb25zdCBjbG9uZSA9IG5vZGUuY2xvbmUodHJ1ZSk7XG4gICAgICAgICAgICAgICAgY2xvbmUucmVwZWF0LmltcGxpY2l0ID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBjbG9uZS5yZXBlYXQuY291bnQgPSBhbW91bnQ7XG4gICAgICAgICAgICAgICAgY2xvbmUucmVwZWF0LnZhbHVlID0gaSArIDE7XG4gICAgICAgICAgICAgICAgY2xvbmUucmVwZWF0LmluZGV4ID0gaTtcbiAgICAgICAgICAgICAgICBub2RlLnBhcmVudC5pbnNlcnRCZWZvcmUoY2xvbmUsIG5vZGUpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBub2RlLnJlbW92ZSgpO1xuICAgICAgICB9XG4gICAgfSk7XG5cbiAgICByZXR1cm4gdHJlZTtcbn1cblxuLyoqXG4gKiBJbnNlcnRzIGNvbnRlbnQgaW50byBpbXBsaWNpdGx5IHJlcGVhdGVkIG5vZGVzLCBjcmVhdGVkIGJ5IGBwcmVwYXJlKClgIG1ldGhvZFxuICogQHBhcmFtICB7Tm9kZX0gdHJlZVxuICogQHBhcmFtICB7U3RyaW5nW119IGNvbnRlbnRcbiAqIEByZXR1cm4ge05vZGV9XG4gKi9cbmZ1bmN0aW9uIGluc2VydCh0cmVlLCBjb250ZW50KSB7XG4gICAgaWYgKEFycmF5LmlzQXJyYXkoY29udGVudCkgJiYgY29udGVudC5sZW5ndGgpIHtcbiAgICAgICAgbGV0IHVwZGF0ZWQgPSBmYWxzZTtcbiAgICAgICAgdHJlZS53YWxrKG5vZGUgPT4ge1xuICAgICAgICAgICAgaWYgKG5vZGUucmVwZWF0ICYmIG5vZGUucmVwZWF0LmltcGxpY2l0KSB7XG4gICAgICAgICAgICAgICAgdXBkYXRlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgaW5zZXJ0Q29udGVudChub2RlLCBjb250ZW50W25vZGUucmVwZWF0LmluZGV4XSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmICghdXBkYXRlZCkge1xuICAgICAgICAgICAgLy8gbm8gbm9kZSB3aXRoIGltcGxpY2l0IHJlcGVhdCB3YXMgZm91bmQsIGluc2VydCBjb250ZW50IGFzXG4gICAgICAgICAgICAvLyBkZWVwZXN0IGNoaWxkXG4gICAgICAgICAgICBzZXROb2RlQ29udGVudChmaW5kRGVlcGVzdE5vZGUodHJlZSksIGNvbnRlbnQuam9pbignXFxuJykpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRyZWU7XG59XG5cbi8qKlxuICogSW5zZXJ0cyBgY29udGVudGAgaW50byBnaXZlbiBgbm9kZWA6IGVpdGhlciByZXBsYWNlcyBvdXRwdXQgcGxhY2Vob2xkZXJzXG4gKiBvciBpbnNlcnRzIGl0IGludG8gZGVlcGVzdCBjaGlsZCBub2RlXG4gKiBAcGFyYW0gIHtOb2RlfSBub2RlXG4gKiBAcGFyYW0gIHtTdHJpbmd9IGNvbnRlbnRcbiAqIEByZXR1cm4ge05vZGV9XG4gKi9cbmZ1bmN0aW9uIGluc2VydENvbnRlbnQobm9kZSwgY29udGVudCkge1xuXHRsZXQgaW5zZXJ0ZWQgPSBpbnNlcnRDb250ZW50SW50b1BsYWNlaG9sZGVyKG5vZGUsIGNvbnRlbnQpO1xuXHRub2RlLndhbGsoY2hpbGQgPT4gaW5zZXJ0ZWQgfD0gaW5zZXJ0Q29udGVudEludG9QbGFjZWhvbGRlcihjaGlsZCwgY29udGVudCkpO1xuXG5cdGlmICghaW5zZXJ0ZWQpIHtcblx0XHQvLyBubyBwbGFjZWhvbGRlcnMgd2VyZSBmb3VuZCBpbiBub2RlLCBpbnNlcnQgY29udGVudCBpbnRvIGRlZXBlc3QgY2hpbGRcblx0XHRzZXROb2RlQ29udGVudChmaW5kRGVlcGVzdE5vZGUobm9kZSksIGNvbnRlbnQpO1xuXHR9XG5cblx0cmV0dXJuIG5vZGU7XG59XG5cbi8qKlxuICogSW5zZXJ0cyBnaXZlbiBgY29udGVudGAgaW50byBwbGFjZWhvbGRlcnMgZm9yIGdpdmVuIGBub2RlYC4gUGxhY2Vob2xkZXJzXG4gKiBtaWdodCBiZSBhdmFpbGFibGUgaW4gYXR0cmlidXRlIHZhbHVlcyBhbmQgbm9kZSBjb250ZW50XG4gKiBAcGFyYW0gIHtOb2RlfSBub2RlXG4gKiBAcGFyYW0gIHtTdHJpbmd9IGNvbnRlbnRcbiAqIEByZXR1cm4ge0Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIHBsYWNlaG9sZGVycyB3ZXJlIGZvdW5kIGFuZCByZXBsYWNlZCBpbiBub2RlXG4gKi9cbmZ1bmN0aW9uIGluc2VydENvbnRlbnRJbnRvUGxhY2Vob2xkZXIobm9kZSwgY29udGVudCkge1xuXHRjb25zdCBzdGF0ZSA9IHtyZXBsYWNlZDogZmFsc2V9O1xuXG5cdG5vZGUudmFsdWUgPSByZXBsYWNlUGxhY2Vob2xkZXIobm9kZS52YWx1ZSwgY29udGVudCwgc3RhdGUpO1xuXHRub2RlLmF0dHJpYnV0ZXMuZm9yRWFjaChhdHRyID0+IHtcblx0XHRpZiAoYXR0ci52YWx1ZSkge1xuXHRcdFx0bm9kZS5zZXRBdHRyaWJ1dGUoYXR0ci5uYW1lLCByZXBsYWNlUGxhY2Vob2xkZXIoYXR0ci52YWx1ZSwgY29udGVudCwgc3RhdGUpKTtcblx0XHR9XG5cdH0pO1xuXG5cdHJldHVybiBzdGF0ZS5yZXBsYWNlZDtcbn1cblxuLyoqXG4gKiBSZXBsYWNlcyBhbGwgcGxhY2Vob2xkZXIgb2NjdXJhbmNlcyBpbiBnaXZlbiBgc3RyYCB3aXRoIGB2YWx1ZWBcbiAqIEBwYXJhbSAge1N0cmluZ30gc3RyXG4gKiBAcGFyYW0gIHtTdHJpbmd9IHZhbHVlXG4gKiBAcGFyYW0gIHtPYmplY3R9IFtfc3RhdGVdIElmIHByb3ZpZGVkLCBzZXQgYHJlcGxhY2VkYCBwcm9wZXJ0eSBvZiBnaXZlblxuICogb2JqZWN0IHRvIGB0cnVlYCBpZiBwbGFjZWhvbGRlciB3YXMgZm91bmQgYW5kIHJlcGxhY2VkXG4gKiBAcmV0dXJuIHtTdHJpbmd9XG4gKi9cbmZ1bmN0aW9uIHJlcGxhY2VQbGFjZWhvbGRlcihzdHIsIHZhbHVlLCBfc3RhdGUpIHtcblx0aWYgKHR5cGVvZiBzdHIgPT09ICdzdHJpbmcnKSB7XG5cdFx0Y29uc3QgcmFuZ2VzID0gZmluZFVuZXNjYXBlZFRva2VucyhzdHIsIHBsYWNlaG9sZGVyKTtcblx0XHRpZiAocmFuZ2VzLmxlbmd0aCkge1xuXHRcdFx0aWYgKF9zdGF0ZSkge1xuXHRcdFx0XHRfc3RhdGUucmVwbGFjZWQgPSB0cnVlO1xuXHRcdFx0fVxuXG5cdFx0XHRzdHIgPSByZXBsYWNlUmFuZ2VzKHN0ciwgcmFuZ2VzLCB2YWx1ZSk7XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIHN0cjtcbn1cblxuLyoqXG4gKiBGaW5kcyBub2RlIHdoaWNoIGlzIHRoZSBkZWVwZXN0IGZvciBpbiBjdXJyZW50IG5vZGUgb3Igbm9kZSBpdGVzZWxmLlxuICogQHBhcmFtICB7Tm9kZX0gbm9kZVxuICogQHJldHVybiB7Tm9kZX1cbiAqL1xuZnVuY3Rpb24gZmluZERlZXBlc3ROb2RlKG5vZGUpIHtcblx0d2hpbGUgKG5vZGUuY2hpbGRyZW4ubGVuZ3RoKSB7XG5cdFx0bm9kZSA9IG5vZGUuY2hpbGRyZW5bbm9kZS5jaGlsZHJlbi5sZW5ndGggLSAxXTtcblx0fVxuXG5cdHJldHVybiBub2RlO1xufVxuXG4vKipcbiAqIFVwZGF0ZXMgY29udGVudCBvZiBnaXZlbiBub2RlXG4gKiBAcGFyYW0ge05vZGV9IG5vZGVcbiAqIEBwYXJhbSB7U3RyaW5nfSBjb250ZW50XG4gKi9cbmZ1bmN0aW9uIHNldE5vZGVDb250ZW50KG5vZGUsIGNvbnRlbnQpIHtcblx0Ly8gZmluZCBjYXJldCBwb3NpdGlvbiBhbmQgcmVwbGFjZSBpdCB3aXRoIGNvbnRlbnQsIGlmIHBvc3NpYmxlXG5cdGlmIChub2RlLnZhbHVlKSB7XG5cdFx0Y29uc3QgcmFuZ2VzID0gZmluZFVuZXNjYXBlZFRva2Vucyhub2RlLnZhbHVlLCBjYXJldCk7XG5cdFx0aWYgKHJhbmdlcy5sZW5ndGgpIHtcblx0XHRcdG5vZGUudmFsdWUgPSByZXBsYWNlUmFuZ2VzKG5vZGUudmFsdWUsIHJhbmdlcywgY29udGVudCk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHR9XG5cblx0aWYgKG5vZGUubmFtZS50b0xvd2VyQ2FzZSgnYScpIHx8IG5vZGUuaGFzQXR0cmlidXRlKCdocmVmJykpIHtcblx0XHQvLyBzcGVjaWFsIGNhc2U6IGluc2VydGluZyBjb250ZW50IGludG8gYDxhPmAgdGFnXG5cdFx0aWYgKHJlVXJsLnRlc3QoY29udGVudCkpIHtcblx0XHRcdG5vZGUuc2V0QXR0cmlidXRlKCdocmVmJywgKHJlUHJvdG8udGVzdChjb250ZW50KSA/ICcnIDogJ2h0dHA6Ly8nKSArIGNvbnRlbnQpO1xuXHRcdH0gZWxzZSBpZiAocmVFbWFpbC50ZXN0KGNvbnRlbnQpKSB7XG5cdFx0XHRub2RlLnNldEF0dHJpYnV0ZSgnaHJlZicsICdtYWlsdG86JyArIGNvbnRlbnQpO1xuXHRcdH1cblx0fVxuXG5cdG5vZGUudmFsdWUgPSBjb250ZW50O1xufVxuXG5jb25zdCBkZWZhdWx0T3B0aW9ucyA9IHtcblx0ZWxlbWVudDogJ19fJyxcblx0bW9kaWZpZXI6ICdfJ1xufTtcblxuY29uc3QgcmVFbGVtZW50ICA9IC9eKC0rKShbYS16MC05XSspL2k7XG5jb25zdCByZU1vZGlmaWVyID0gL14oXyspKFthLXowLTldKykvaTtcbmNvbnN0IGJsb2NrQ2FuZGlkYXRlczEgPSBjbGFzc05hbWUgPT4gL15bYS16XVxcLS9pLnRlc3QoY2xhc3NOYW1lKTtcbmNvbnN0IGJsb2NrQ2FuZGlkYXRlczIgPSBjbGFzc05hbWUgPT4gL15bYS16XS9pLnRlc3QoY2xhc3NOYW1lKTtcblxuLyoqXG4gKiBCRU0gdHJhbnNmb3JtZXI6IHVwZGF0ZXMgY2xhc3MgbmFtZXMgd3JpdHRlbiBhcyBgLWVsZW1lbnRgIGFuZFxuICogYF9tb2RpZmllcmAgaW50byBmdWxsIGNsYXNzIG5hbWVzIGFzIGRlc2NyaWJlZCBpbiBCRU0gc3BlY3MuIEFsc28gYWRkcyBtaXNzaW5nXG4gKiBjbGFzcyBuYW1lczogZmlyIGV4YW1wbGUsIGlmIG5vZGUgY29udGFpbnMgYC5ibG9ja19tb2RpZmllcmAgY2xhc3MsIGVuc3VyZXNcbiAqIHRoYXQgZWxlbWVudCBjb250YWlucyBgLmJsb2NrYCBjbGFzcyBhcyB3ZWxsXG4gKi9cbnZhciBiZW0gPSBmdW5jdGlvbih0cmVlLCBvcHRpb25zKSB7XG5cdG9wdGlvbnMgPSBPYmplY3QuYXNzaWduKHt9LCBkZWZhdWx0T3B0aW9ucywgb3B0aW9ucyk7XG5cblx0dHJlZS53YWxrKG5vZGUgPT4gZXhwYW5kQ2xhc3NOYW1lcyhub2RlLCBvcHRpb25zKSk7XG5cblx0Y29uc3QgbG9va3VwID0gY3JlYXRlQmxvY2tMb29rdXAodHJlZSk7XG4gICAgdHJlZS53YWxrKG5vZGUgPT4gZXhwYW5kU2hvcnROb3RhdGlvbihub2RlLCBsb29rdXAsIG9wdGlvbnMpKTtcblxuXHRyZXR1cm4gdHJlZTtcbn07XG5cbi8qKlxuICogRXhwYW5kcyBleGlzdGluZyBjbGFzcyBuYW1lcyBpbiBCRU0gbm90YXRpb24gaW4gZ2l2ZW4gYG5vZGVgLlxuICogRm9yIGV4YW1wbGUsIGlmIG5vZGUgY29udGFpbnMgYGJfX2VsX21vZGAgY2xhc3MgbmFtZSwgdGhpcyBtZXRob2QgZW5zdXJlc1xuICogdGhhdCBlbGVtZW50IGNvbnRhaW5zIGBiX19lbGAgY2xhc3MgYXMgd2VsbFxuICogQHBhcmFtICB7Tm9kZX0gbm9kZVxuICogQHBhcmFtICB7T2JqZWN0fSBvcHRpb25zXG4gKiBAcmV0dXJuIHtTZXR9XG4gKi9cbmZ1bmN0aW9uIGV4cGFuZENsYXNzTmFtZXMobm9kZSwgb3B0aW9ucykge1xuXHRjb25zdCBjbGFzc05hbWVzID0gbm9kZS5jbGFzc0xpc3QucmVkdWNlKChvdXQsIGNsKSA9PiB7XG5cdFx0Ly8gcmVtb3ZlIGFsbCBtb2RpZmllcnMgZnJvbSBjbGFzcyBuYW1lIHRvIGdldCBhIGJhc2UgZWxlbWVudCBuYW1lXG5cdFx0Y29uc3QgaXggPSBjbC5pbmRleE9mKG9wdGlvbnMubW9kaWZpZXIpO1xuXHRcdGlmIChpeCAhPT0gLTEpIHtcblx0XHRcdG91dC5hZGQoY2wuc2xpY2UoMCwgaXgpKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gb3V0LmFkZChjbCk7XG5cdH0sIG5ldyBTZXQoKSk7XG5cblx0aWYgKGNsYXNzTmFtZXMuc2l6ZSkge1xuXHRcdG5vZGUuc2V0QXR0cmlidXRlKCdjbGFzcycsIEFycmF5LmZyb20oY2xhc3NOYW1lcykuam9pbignICcpKTtcblx0fVxufVxuXG4vKipcbiAqIEV4cGFuZHMgc2hvcnQgQkVNIG5vdGF0aW9uLCBlLmcuIGAtZWxlbWVudGAgYW5kIGBfbW9kaWZpZXJgXG4gKiBAcGFyYW0gIHtOb2RlfSBub2RlICAgICAgUGFyc2VkIEVtbWV0IGFiYnJldmlhdGlvbiBub2RlXG4gKiBAcGFyYW0gIHtNYXB9IGxvb2t1cCAgICAgQkVNIGJsb2NrIG5hbWUgbG9va3VwXG4gKiBAcGFyYW0gIHtPYmplY3R9IG9wdGlvbnNcbiAqL1xuZnVuY3Rpb24gZXhwYW5kU2hvcnROb3RhdGlvbihub2RlLCBsb29rdXAsIG9wdGlvbnMpIHtcblx0Y29uc3QgY2xhc3NOYW1lcyA9IG5vZGUuY2xhc3NMaXN0LnJlZHVjZSgob3V0LCBjbCkgPT4ge1xuXHRcdGxldCBwcmVmaXgsIG07XG5cdFx0Y29uc3Qgb3JpZ2luYWxDbGFzcyA9IGNsO1xuXG5cdFx0Ly8gcGFyc2UgZWxlbWVudCBkZWZpbml0aW9uIChjb3VsZCBiZSBvbmx5IG9uZSlcblx0XHRpZiAobSA9IGNsLm1hdGNoKHJlRWxlbWVudCkpIHtcblx0XHRcdHByZWZpeCA9IGdldEJsb2NrTmFtZShub2RlLCBsb29rdXAsIG1bMV0pICsgb3B0aW9ucy5lbGVtZW50ICsgbVsyXTtcblx0XHRcdG91dC5hZGQocHJlZml4KTtcblx0XHRcdGNsID0gY2wuc2xpY2UobVswXS5sZW5ndGgpO1xuXHRcdH1cblxuXHRcdC8vIHBhcnNlIG1vZGlmaWVycyBkZWZpbml0aW9ucyAobWF5IGNvbnRhaW4gbXVsdGlwbGUpXG5cdFx0d2hpbGUgKG0gPSBjbC5tYXRjaChyZU1vZGlmaWVyKSkge1xuXHRcdFx0aWYgKCFwcmVmaXgpIHtcblx0XHRcdFx0cHJlZml4ID0gZ2V0QmxvY2tOYW1lKG5vZGUsIGxvb2t1cCwgbVsxXSk7XG5cdFx0XHRcdG91dC5hZGQocHJlZml4KTtcblx0XHRcdH1cblxuXHRcdFx0b3V0LmFkZChgJHtwcmVmaXh9JHtvcHRpb25zLm1vZGlmaWVyfSR7bVsyXX1gKTtcblx0XHRcdGNsID0gY2wuc2xpY2UobVswXS5sZW5ndGgpO1xuXHRcdH1cblxuXHRcdGlmIChjbCA9PT0gb3JpZ2luYWxDbGFzcykge1xuXHRcdFx0Ly8gY2xhc3MgbmFtZSB3YXNu4oCZdCBtb2RpZmllZDogaXTigJlzIG5vdCBhIEJFTS1zcGVjaWZpYyBjbGFzcyxcblx0XHRcdC8vIGFkZCBpdCBhcy1pcyBpbnRvIG91dHB1dFxuXHRcdFx0b3V0LmFkZChvcmlnaW5hbENsYXNzKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gb3V0O1xuXHR9LCBuZXcgU2V0KCkpO1xuXG5cdG5vZGUuc2V0QXR0cmlidXRlKCdjbGFzcycsIEFycmF5LmZyb20oY2xhc3NOYW1lcykuam9pbignICcpKTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGJsb2NrIG5hbWUgbG9va3VwIGZvciBlYWNoIG5vZGUgaW4gZ2l2ZW4gdHJlZSwgZS5nLiBmaW5kcyBibG9ja1xuICogbmFtZSBleHBsaWNpdGx5IGZvciBlYWNoIG5vZGVcbiAqIEBwYXJhbSAge05vZGV9IHRyZWVcbiAqIEByZXR1cm4ge01hcH1cbiAqL1xuZnVuY3Rpb24gY3JlYXRlQmxvY2tMb29rdXAodHJlZSkge1xuXHRjb25zdCBsb29rdXAgPSBuZXcgTWFwKCk7XG5cblx0dHJlZS53YWxrKG5vZGUgPT4ge1xuXHRcdGNvbnN0IGNsYXNzTmFtZXMgPSBub2RlLmNsYXNzTGlzdDtcblx0XHRpZiAoY2xhc3NOYW1lcy5sZW5ndGgpIHtcblx0XHRcdC8vIGd1ZXNzIGJlc3QgYmxvY2sgbmFtZSBmcm9tIGNsYXNzIG9yIHVzZSBwYXJlbnTigJlzIGJsb2NrIG5hbWVcblx0XHRcdGxvb2t1cC5zZXQobm9kZSxcblx0XHRcdFx0ZmluZChjbGFzc05hbWVzLCBibG9ja0NhbmRpZGF0ZXMxKVxuXHRcdFx0XHR8fCBmaW5kKGNsYXNzTmFtZXMsIGJsb2NrQ2FuZGlkYXRlczIpXG5cdFx0XHRcdHx8IGxvb2t1cC5nZXQobm9kZS5wYXJlbnQpXG5cdFx0XHQpO1xuXHRcdH1cblx0fSk7XG5cblx0cmV0dXJuIGxvb2t1cDtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIGJsb2NrIG5hbWUgZm9yIGdpdmVuIGBub2RlYCBieSBgcHJlZml4YCwgd2hpY2ggdGVsbHMgdGhlIGRlcHRoIG9mXG4gKiBvZiBwYXJlbnQgbm9kZSBsb29rdXBcbiAqIEBwYXJhbSAge05vZGV9IG5vZGVcbiAqIEBwYXJhbSAge01hcH0gbG9va3VwXG4gKiBAcGFyYW0gIHtTdHJpbmd9IHByZWZpeFxuICogQHJldHVybiB7U3RyaW5nfVxuICovXG5mdW5jdGlvbiBnZXRCbG9ja05hbWUobm9kZSwgbG9va3VwLCBwcmVmaXgpIHtcblx0bGV0IGRlcHRoID0gcHJlZml4Lmxlbmd0aCA+IDEgPyBwcmVmaXgubGVuZ3RoIDogMDtcblx0d2hpbGUgKG5vZGUucGFyZW50ICYmIGRlcHRoLS0pIHtcblx0XHRub2RlID0gbm9kZS5wYXJlbnQ7XG5cdH1cblxuXHRyZXR1cm4gbG9va3VwLmdldChub2RlKTtcbn1cblxuZnVuY3Rpb24gZmluZChhcnIsIGZpbHRlcikge1xuXHRyZXR1cm4gYXJyLmZpbHRlcihmaWx0ZXIpWzBdO1xufVxuXG4vKipcbiAqIEpTWCB0cmFuc2Zvcm1lcjogcmVwbGFjZXMgYGNsYXNzYCBhbmQgYGZvcmAgYXR0cmlidXRlcyB3aXRoIGBjbGFzc05hbWVgIGFuZFxuICogYGh0bWxGb3JgIGF0dHJpYnV0ZXMgcmVzcGVjdGl2ZWx5XG4gKi9cbnZhciBqc3ggPSBmdW5jdGlvbih0cmVlKSB7XG5cdHRyZWUud2Fsayhub2RlID0+IHtcblx0XHRyZXBsYWNlKG5vZGUsICdjbGFzcycsICdjbGFzc05hbWUnKTtcblx0XHRyZXBsYWNlKG5vZGUsICdmb3InLCAnaHRtbEZvcicpO1xuXHR9KTtcblx0cmV0dXJuIHRyZWU7XG59O1xuXG5mdW5jdGlvbiByZXBsYWNlKG5vZGUsIG9sZE5hbWUsIG5ld05hbWUpIHtcblx0bGV0IGF0dHIgPSBub2RlLmdldEF0dHJpYnV0ZShvbGROYW1lKTtcblx0aWYgKGF0dHIpIHtcblx0XHRhdHRyLm5hbWUgPSBuZXdOYW1lO1xuXHR9XG59XG5cbmNvbnN0IHJlU3VwcG9ydGVyTmFtZXMgPSAvXnhzbDoodmFyaWFibGV8d2l0aFxcLXBhcmFtKSQvaTtcblxuLyoqXG4gKiBYU0wgdHJhbnNmb3JtZXI6IHJlbW92ZXMgYHNlbGVjdGAgYXR0cmlidXRlcyBmcm9tIGNlcnRhaW4gbm9kZXMgdGhhdCBjb250YWluXG4gKiBjaGlsZHJlblxuICovXG52YXIgeHNsID0gZnVuY3Rpb24odHJlZSkge1xuXHR0cmVlLndhbGsobm9kZSA9PiB7XG5cdFx0aWYgKHJlU3VwcG9ydGVyTmFtZXMudGVzdChub2RlLm5hbWUgfHwgJycpICYmIChub2RlLmNoaWxkcmVuLmxlbmd0aCB8fCBub2RlLnZhbHVlKSkge1xuXHRcdFx0bm9kZS5yZW1vdmVBdHRyaWJ1dGUoJ3NlbGVjdCcpO1xuXHRcdH1cblx0fSk7XG5cdHJldHVybiB0cmVlO1xufTtcblxuY29uc3Qgc3VwcG9ydGVkQWRkb25zID0geyBiZW0sIGpzeCwgeHNsIH07XG5cbi8qKlxuICogUnVucyBhZGRpdGlvbmFsIHRyYW5zZm9ybXMgb24gZ2l2ZW4gdHJlZS5cbiAqIFRoZXNlIHRyYW5zZm9ybXMgbWF5IGludHJvZHVjZSBzaWRlLWVmZmVjdHMgYW5kIHVuZXhwZWN0ZWQgcmVzdWx0XG4gKiBzbyB0aGV5IGFyZSBub3QgYXBwbGllZCBieSBkZWZhdWx0LCBhdXRob3JzIG11c3Qgc3BlY2lmeSB3aGljaCBhZGRvbnNcbiAqIGluIGBhZGRvbnNgIGFyZ3VtZW50IGFzIGB7YWRkb25OYW1lOiBhZGRvbk9wdGlvbnN9YFxuICogQHBhcmFtIHtOb2RlfSB0cmVlIFBhcnNlZCBFbW1ldCBhYmJyZXZpYXRpb25cbiAqIEBwYXJhbSB7T2JqZWN0fSBhZGRvbnMgQWRkLW9ucyB0byBhcHBseSBhbmQgdGhlaXIgb3B0aW9uc1xuICovXG52YXIgYWRkb25zID0gZnVuY3Rpb24odHJlZSwgYWRkb25zKSB7XG4gICAgT2JqZWN0LmtleXMoYWRkb25zIHx8IHt9KS5mb3JFYWNoKGtleSA9PiB7XG4gICAgICAgIGlmIChrZXkgaW4gc3VwcG9ydGVkQWRkb25zKSB7XG4gICAgICAgICAgICBjb25zdCBhZGRvbk9wdCA9IHR5cGVvZiBhZGRvbnNba2V5XSA9PT0gJ29iamVjdCcgPyBhZGRvbnNba2V5XSA6IG51bGw7XG4gICAgICAgICAgICB0cmVlID0gdHJlZS51c2Uoc3VwcG9ydGVkQWRkb25zW2tleV0sIGFkZG9uT3B0KTtcbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgcmV0dXJuIHRyZWU7XG59O1xuXG4vKipcbiAqIEFwcGxpZXMgYmFzaWMgSFRNTC1zcGVjaWZpYyB0cmFuc2Zvcm1hdGlvbnMgZm9yIGdpdmVuIHBhcnNlZCBhYmJyZXZpYXRpb246XG4gKiDigJMgcmVzb2x2ZSBpbXBsaWVkIHRhZyBuYW1lc1xuICog4oCTIGluc2VydCByZXBlYXRlZCBjb250ZW50XG4gKiDigJMgcmVzb2x2ZSBub2RlIG51bWJlcmluZ1xuICovXG52YXIgaW5kZXggPSBmdW5jdGlvbih0cmVlLCBjb250ZW50LCBhcHBsaWVkQWRkb25zKSB7XG4gICAgaWYgKHR5cGVvZiBjb250ZW50ID09PSAnc3RyaW5nJykge1xuICAgICAgICBjb250ZW50ID0gW2NvbnRlbnRdO1xuICAgIH0gZWxzZSBpZiAoY29udGVudCAmJiB0eXBlb2YgY29udGVudCA9PT0gJ29iamVjdCcgJiYgIUFycmF5LmlzQXJyYXkoY29udGVudCkpIHtcbiAgICAgICAgYXBwbGllZEFkZG9ucyA9IGNvbnRlbnQ7XG4gICAgICAgIGNvbnRlbnQgPSBudWxsO1xuICAgIH1cblxuICAgIHJldHVybiB0cmVlXG4gICAgLnVzZShpbXBsaWNpdFRhZ3MpXG4gICAgLnVzZShwcmVwYXJlLCBBcnJheS5pc0FycmF5KGNvbnRlbnQpID8gY29udGVudC5sZW5ndGggOiBudWxsKVxuICAgIC51c2UoYXBwbHlOdW1iZXJpbmcpXG4gICAgLnVzZShpbnNlcnQsIGNvbnRlbnQpXG4gICAgLnVzZShhZGRvbnMsIGFwcGxpZWRBZGRvbnMpO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBpbmRleDtcbiJdfQ== | |
// Welcome! require() some modules from npm (like you were using browserify) | |
// and then hit Run Code to run your code on the right side. | |
// Modules get downloaded from browserify-cdn and bundled in your browser. | |
require('@emmetio/abbreviation'); | |
require('@emmetio/html-transform'); | |
;}, 0) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "requirebin-sketch", | |
"version": "1.0.0", | |
"dependencies": { | |
"@emmetio/abbreviation": "0.6.0", | |
"@emmetio/html-transform": "0.3.1" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- contents of this file will be placed inside the <body> --> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- contents of this file will be placed inside the <head> --> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment