Skip to content

Instantly share code, notes, and snippets.

@achun
Last active May 13, 2018 15:11
Show Gist options
  • Save achun/7f29bedba40cb8029e30880fc857fc9b to your computer and use it in GitHub Desktop.
Save achun/7f29bedba40cb8029e30880fc857fc9b to your computer and use it in GitHub Desktop.
requirebin sketch
// powcss demonstration
const powcss=require('powcss');
let pre = document.createElement('pre');
pre.textContent = powcss([]).run(
`
let /**/
rem=(px) => px/16 +'rem', /*Line-Continuation*/
spacing=(tracking)=>tracking/12 +'rem',
cols = [1,2,3,4].join(',.col-')
.col-\${cols}
display: block
letter-spacing: \${spacing(-1.5)}
`
).toCSS();
document.body.append(pre);
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){
// shim for using process in browser
var process = module.exports = {};
// cached from whatever global is present so that test runners that stub it
// don't break things. But we need to wrap it in a try catch in case it is
// wrapped in strict mode code which doesn't define any globals. It's inside a
// function because try/catches deoptimize in certain engines.
var cachedSetTimeout;
var cachedClearTimeout;
function defaultSetTimout() {
throw new Error('setTimeout has not been defined');
}
function defaultClearTimeout () {
throw new Error('clearTimeout has not been defined');
}
(function () {
try {
if (typeof setTimeout === 'function') {
cachedSetTimeout = setTimeout;
} else {
cachedSetTimeout = defaultSetTimout;
}
} catch (e) {
cachedSetTimeout = defaultSetTimout;
}
try {
if (typeof clearTimeout === 'function') {
cachedClearTimeout = clearTimeout;
} else {
cachedClearTimeout = defaultClearTimeout;
}
} catch (e) {
cachedClearTimeout = defaultClearTimeout;
}
} ())
function runTimeout(fun) {
if (cachedSetTimeout === setTimeout) {
//normal enviroments in sane situations
return setTimeout(fun, 0);
}
// if setTimeout wasn't available but was latter defined
if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
cachedSetTimeout = setTimeout;
return setTimeout(fun, 0);
}
try {
// when when somebody has screwed with setTimeout but no I.E. maddness
return cachedSetTimeout(fun, 0);
} catch(e){
try {
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
return cachedSetTimeout.call(null, fun, 0);
} catch(e){
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
return cachedSetTimeout.call(this, fun, 0);
}
}
}
function runClearTimeout(marker) {
if (cachedClearTimeout === clearTimeout) {
//normal enviroments in sane situations
return clearTimeout(marker);
}
// if clearTimeout wasn't available but was latter defined
if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
cachedClearTimeout = clearTimeout;
return clearTimeout(marker);
}
try {
// when when somebody has screwed with setTimeout but no I.E. maddness
return cachedClearTimeout(marker);
} catch (e){
try {
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
return cachedClearTimeout.call(null, marker);
} catch (e){
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
// Some versions of I.E. have different rules for clearTimeout vs setTimeout
return cachedClearTimeout.call(this, marker);
}
}
}
var queue = [];
var draining = false;
var currentQueue;
var queueIndex = -1;
function cleanUpNextTick() {
if (!draining || !currentQueue) {
return;
}
draining = false;
if (currentQueue.length) {
queue = currentQueue.concat(queue);
} else {
queueIndex = -1;
}
if (queue.length) {
drainQueue();
}
}
function drainQueue() {
if (draining) {
return;
}
var timeout = runTimeout(cleanUpNextTick);
draining = true;
var len = queue.length;
while(len) {
currentQueue = queue;
queue = [];
while (++queueIndex < len) {
if (currentQueue) {
currentQueue[queueIndex].run();
}
}
queueIndex = -1;
len = queue.length;
}
currentQueue = null;
draining = false;
runClearTimeout(timeout);
}
process.nextTick = function (fun) {
var args = new Array(arguments.length - 1);
if (arguments.length > 1) {
for (var i = 1; i < arguments.length; i++) {
args[i - 1] = arguments[i];
}
}
queue.push(new Item(fun, args));
if (queue.length === 1 && !draining) {
runTimeout(drainQueue);
}
};
// v8 likes predictible objects
function Item(fun, array) {
this.fun = fun;
this.array = array;
}
Item.prototype.run = function () {
this.fun.apply(null, this.array);
};
process.title = 'browser';
process.browser = true;
process.env = {};
process.argv = [];
process.version = ''; // empty string to avoid regexp issues
process.versions = {};
function noop() {}
process.on = noop;
process.addListener = noop;
process.once = noop;
process.off = noop;
process.removeListener = noop;
process.removeAllListeners = noop;
process.emit = noop;
process.binding = function (name) {
throw new Error('process.binding is not supported');
};
process.cwd = function () { return '/' };
process.chdir = function (dir) {
throw new Error('process.chdir is not supported');
};
process.umask = function() { return 0; };
},{}],2:[function(require,module,exports){
const IFX = /if[ ]+([_$a-zA-Z]+)[ ]*=/,
util = require('./util');
/**
* PowCSS 缺省的 Compiler 实现.
* 所有方法采用原生 js 语法, 要求源码自带嵌套占位符 '...'.
*/
class Compiler{
/**
* 构造, 参数用来对 this 进行扩展.
* 缺省 this.ctx = 'ctx' 表示 context 的形参名
*/
constructor(...extend) {
extend.forEach((ext) => {
if (typeof ext === 'function')
this[ext.name] = ext;
else if (Object.prototype.toString.call(ext) === '[object Object]') {
for (let key in ext) {
this[key] = ext[key];
}
}
});
this.ctx = this.ctx || 'ctx';
}
/**
* compile 接口
*/
compile(n, i, ns) {
return this.decl(n) ||
this.if(n) ||
this.each(n) ||
this.let(n) ||
this.comment(n) ||
this.rule(n);
}
/**
* 编译 n.mode === 'comment' 的节点, '/*!' 开头的顶层注释被保留, 其它被抛弃.
*/
comment(n) {
if (n.mode !== 'comment') return;
if (n.column === 1 && n.source[1] === '*' && n.source[2] === '!'){
let c = JSON.stringify(n.source);
return `${this.ctx}.open(${c}).close();`;
}
return ' ';
}
/**
* 编译 !n.mode 的节点为规则节点
*/
rule(n) {
if (n.mode) return;
let c = n.source.indexOf('${') === -1 && '\'' || '`';
return n.nodes && n.nodes.length &&
`${this.ctx}.open(${c}${n.source}${c});
...${this.ctx}.close();` ||
`${this.ctx}.open(${c}${n.source}${c}).close();`;
}
/**
* 编译 n.mode === 'decl' 的节点
*/
decl(n) {
if (n.mode !== 'decl') return;
let c = n.key.indexOf('${') === -1 && '\'' || '`',
v = n.val.endsWith(';') ?
n.val.substring(0, n.val.length - 1) :
n.val,
d = v.indexOf('${') === -1 && '\'' || '`';
return `${this.ctx}.decl(${c}${n.key}${c},${d}${v}${d});`;
}
/**
* if 语句, 原生语法:
* if(expr) code;
* if (expr) code;
*/
if(n) {
if (n.source.startsWith('if(') || n.source.startsWith('if ('))
return n.source;
}
/**
* each 语句, 原生语法:
*
* each(expr, (val, key)=>{code});
* ctx.each(expr, (val, key)=>{code});
*
*/
each(n) {
if (n.source.startsWith(`${this.ctx}.each(`))
return n.source;
if (n.source.startsWith('each(')) return this.ctx + '.' + n.source;
}
/**
* let 语句, 原生语法:
*
* let v1 = expr;
* let [v1,v2] = [expr, expr]; // ES6 解构赋值
* let v1 = expr; code;
*/
let(n) {
if (n.source.startsWith('let ')) return n.source;
}
}
module.exports = function(...extend) {
return new Compiler(...extend);
};
},{"./util":5}],3:[function(require,module,exports){
/**
* @typedef {object} Rule 抽象规则
* @property {string} name 规则名, 也可能是个定义值, 比如 @charset
* @property {?object<string, string|Rule>} decls 键值声明
*/
/**
* PowCSS 缺省的 Context 实现.
* 该实现不分析 CSS 规则的合法性, 只提供结构上的操作和一些辅助方法.
* 如果要对结果进行再次处理, 推荐使用 walk 方法.
*
* @property {Rule} rule 当前维护的规则, 初始 null
* @property {Rule[]} rules 最终的规则数组
* @property {Rule[]} stack 当前规则的 parent 栈
*/
class Context {
/**
* 构造, 参数用来对 this 进行扩展.
*/
constructor(...extend) {
extend.forEach((ext) => {
if (typeof ext === 'function')
this[ext.name] = ext;
else if (Object.prototype.toString.call(ext) === '[object Object]') {
for (let key in ext) {
this[key] = ext[key];
}
}
});
this.reset();
}
/**
* 重置 .rule, .rules, .stack 为初始状态
* @return {this}
*/
reset() {
this.rule = null;
this.rules = [];
this.stack = [];
return this;
}
/**
* 遍历 x 回调 callback(val, key)
* @param {object|array} x
* @param {Function( *, string)} callback 参数顺序 (val, key)
* @return {this}
*/
each(x, callback) {
if (Array.isArray(x)) {
x.forEach(callback);
}else
Object.keys(x).forEach(function(key) {
callback(x[key], key);
});
return this;
}
/**
* 开启一个具名规则并替换 name 中的占位符 '&', 该方法必须与 close 成对使用.
* 嵌套使用时 this.stack 会增长.
* @param {string} name
* @return {this}
*/
open(name) {
if (this.rule) {
this.stack.push(this.rule);
if (name.indexOf('&') !== -1)
name = name.replace(/&/g, this.rule.name);
if (!this.rule.decls) {
if (this.rule.name[0] === '@') {
this.rule.decls = [];
this.stack.push(this.rules);
this.rules = this.rule.decls;
}else if (
this.rule.name[0] !== '/' &&
this.rule === this.rules[this.rules.length - 1]
) {
this.rules.pop();
}
}
}
this.rule = {name};
this.rules.push(this.rule);
return this;
}
/**
* 关闭当前的规则, this.stack 会减少, 该方法必须与 .open 成对使用.
* @return {this}
*/
close() {
this.rule = this.stack.pop();
if (Array.isArray(this.rule)) {
this.rules = this.rule;
return this.close();
}
return this;
}
/**
* 返回 this.rule.name
* @return {string}
*/
name() {
return this.rule && this.rule.name || '';
}
/**
* 返回或设置当前规则的 key 声明
* @param {string} key
* @param {?string} val
* @return {string}
*/
decl(key, val) {
if (val) {
if (!this.rule.decls)
this.rule.decls = {};
this.rule.decls[key] = val;
return val;
}
return this.rule.decls[key] || '';
}
/**
* 输出 this.rules 为 CSS 源码
* @return {string} css
*/
toCSS() {
let toCSS = (css, rule)=> {
if (rule.decls) {
css += rule.name + ' {\n';
if (Array.isArray(rule.decls)) {
css += rule.decls.reduce(toCSS, '');
}else for (let key in rule.decls) {
if (typeof rule.decls[key] === 'string')
css += key + ': ' + rule.decls[key] + ';\n';
else
throw new Error('decls must be a string or array: ' + rule.name + '{' + key + '}');
}
css += '}\n';
}else if (rule.name[0] === '/') // comment
css += rule.name + '\n';
else if (rule.name[0] === '@') // 有些规则只是为了嵌套 '&', 没有 decls
css += rule.name + ';\n';
else
throw new Error('Unexpected bare rule: ' + rule.name);
return css;
};
return this.rules.reduce(toCSS, '');
}
/**
* 遍历 this.rules 调用 context 的 open, close, decl 方法.
* context 的 open, close 返回的对象会用于后续的迭代.
* 任何一个方法返回非真值会终止遍历.
* @param {object} context 实现 open, close, decl 方法的对象
* @return {boolean} finished 是否完全遍历
*/
walk(context) {
let walk = function(rule) {
let self = this;
if (rule.decls) {
self = self.open(rule.name);
if (Array.isArray(rule.decls)) {
if (!rule.decls.every(walk, self))
return false;
}else for (let key in rule.decls) {
if (typeof rule.decls[key] === 'string') {
if (!self.decl(key, rule.decls[key])) return false;
}else {
throw new Error('decls must be a string or array: ' + rule.name + '{' + key + '}');
}
}
}else if (rule.name[0] === '/' || rule.name[0] === '@') {
self = self.open(rule.name);
}else {
throw new Error('Unexpected bare rule: ' + rule.name);
}
if (self) self = self.close();
return !!self;
};
return this.rules.every(walk, context);
}
}
module.exports = function(...extend) {
return new Context(...extend);
};
},{}],4:[function(require,module,exports){
/**
* lineify 是个非空白行扫描器, 扫描并返回非空白行信息.
* @param {string} source 待扫描的字符串
*/
class lineify{
constructor(source) {
this.crlf = source.indexOf('\r\n') != -1 && '\r\n' ||
source.indexOf('\r') != -1 && '\r' || '\n';
this.crlfLength = this.crlf.length;
this.bol = 0;
this.eol = 0;
this.column = 1;
this.line = 1;
this.source = source;
this.scan(null);
}
/**
* 返回扫描到的非空白行字符串和位置信息, 并前进. 结构:
* {source, offset, line, column}
* @return {Object|null} token 返回 null 表示 EOF
*/
scan() {
let tok = {
source: this.source.substring(this.bol, this.eol).trimRight(),
offset: this.bol,
line: this.line,
column: this.column
};
if (this.eol === this.source.length) {
this.bol = this.eol;
return tok.source && tok || null;
}
if (this.eol) {
this.bol = this.eol + this.crlfLength;
this.line++;
this.column = 1;
}
this.eol = this.source.indexOf(this.crlf, this.bol);
if (this.eol === -1)
this.eol = this.source.length;
while (1) {
let c = this.source.charCodeAt(this.bol);
if (c === 32 || c === 9) {
this.bol++;
this.column++;
continue;
}
if (this.eol !== this.bol) break;
if (this.eol === this.source.length) break;
this.line++;
this.column = 1;
this.bol = this.eol + this.crlfLength;
this.eol = this.source.indexOf(this.crlf, this.bol);
if (this.eol === -1)
this.eol = this.source.length;
}
return tok;
}
}
module.exports = function(source) {
return new lineify(source);
};
},{}],5:[function(require,module,exports){
const toString = Object.prototype.toString;
/**
* 辅助方法集合
*/
let util = {
/**
* 返回包含位置信息的字符串, 常用于出错信息
* @param {string} message 自定义信息
* @param {object} loc 含有 line, column 的位置信息
* @param {?string} at 缺省为 <anonymous>
* @return {string}
*/
info: function(message, loc, at) {
return `${message} at: ${at || '<anonymous>'}:${loc.line}:${loc.column}`;
},
/**
* isObject
* @param {*} x
* @return {Boolean}
*/
isObject: function(x) {
return toString.call(x) === '[object Object]';
},
/**
* isNumber
* @param {*} x
* @return {Boolean}
*/
isNumber: function(x) {
return toString.call(x) === '[object Number]';
},
/**
* isArray
* @param {*} x
* @return {Boolean}
*/
isArray: function(x) {
return Array.isArray(x);
},
/**
* isString
* @param {*} x
* @return {Boolean}
*/
isString: function(x) {
return typeof x === 'string';
},
/**
* isFunction
* @param {*} x
* @return {Boolean}
*/
isFunction: function(x) {
return typeof x === 'function';
}
};
module.exports = util;
},{}],"powcss":[function(require,module,exports){
(function (process){
const lineify = require('./lineify'),
compiler = require('./compiler'),
context = require('./context'),
util = require('./util'),
CONTINUATION = '&\\,+-/*|=([';
/**
* PowCSS 负责解析 source 为节点树, 并拼接编译器的编译结果.
* 在 PowCSS 中的插件就是 compiler, compiler 负责与 context 配合.
*/
class PowCSS {
/**
* @param {?Compiler[]} plugins 编译器数组, 缺省为 [compiler()]
*/
constructor(plugins) {
this.plugins = plugins && plugins.length && plugins || [compiler()];
}
/**
* 使用一个编译器插件
* @param {Compiler} plugin
* @return {this}
*/
use(plugin) {
if (plugin)
this.plugins.push(plugin);
return this;
}
/**
* 包装 this.result = this.parse(source) 并返回 this.
* @param {string} source 源码
* @return {this}
*/
process(source) {
this.result = source;
if (!source) return this;
this.result = this.parse(source);
return this;
}
/**
* 解析 source 为节点树.
* 节点类型:
* 1. root {mode:'root', nodes}
* 1. comment {mode:'comment', source} 只保留非行尾注释
* 1. decl {mode:'decl', source, key, val}
* 1. pending {mode:'', source, nodes}
*
* 即所有 !mode 的节点需要通过编译插件进行确认
* @param {string} source 源码
* @return {object} root 节点树
*/
parse(source) {
if (typeof source !== 'string') return source;
let root = {
offset: 0,
line: 0,
column: 0,
mode: 'root',
nodes: []
},
parent = root,
stack = [],
i = 0,
tokens = [],
lines = lineify(source),
tok = lines.scan(),
algin = tok && tok.column || 1;
while (tok) {
tokens.push(tok);
tok = lines.scan();
}
while (i < tokens.length) {
tok = tokens[i];
while (tok.column <= parent.column) {
parent = stack.pop();
algin = parent.nodes[parent.nodes.length - 1].column;
}
// 传统花括号块格式
if (tok.source[0] === '}') {
let last = parent.nodes[parent.nodes.length - 1];
if (!last.source.endsWith('{'))
throw new Error(util.info(`Unpaired brackets from ${last.line}:${last.column}` , tok));
last.source = last.source.slice(0, -1).trimRight();
i++;
continue;
}
if (tok.column > algin) {
algin = tok.column;
tok.nodes = tok.nodes || [];
stack.push(parent);
if (!parent.nodes.length)
throw new Error(util.info('PowCSS broken', tok));
parent = parent.nodes[parent.nodes.length - 1];
continue;
}
i++;
parent.nodes.push(tok);
if (tok.source.startsWith('//')) {
tok.mode = 'comment';
continue;
}
if (tok.source.startsWith('/*')) {
if (tok.source.endsWith('*/'))
tok.mode = 'comment';
else while (i < tokens.length) {
tok.source += '\n' + tokens[i++].source;
if (tok.source.endsWith('*/')) {
tok.mode = 'comment';
break;
}
}
if (tok.mode !== 'comment')
throw new Error(util.info('Unclosed comments', tok));
continue;
}
let tail = tok.source.indexOf(' //');
/**
* 行尾注释必须以 ' //' 开头
*/
if (tail !== -1)
tok.source = tok.source.substring(0, tail).trim();
/**
* 属性名和值不能以 '@' 开头
* 属性分隔符 ':' 之后必须是空格或者换行 `:[ \n]`
*/
let pos = tok.source[0] === '@' && -1 || tok.source.indexOf(':') + 1;
tok.mode = pos > 0 &&
(pos === tok.source.length || tok.source[pos] === ' ') &&
'decl' || '';
tok.nodes = [];
/**
* 续行符包括 `\\,+-/*|=([`
*/
tail = CONTINUATION.indexOf(tok.source.charAt(tok.source.length - 1));
if (tail === 1)
tok.source = tok.source.slice(0, -1).trim();
if (tail > 0 && tok.mode === '' ||
tail !== -1 && tok.mode === 'decl')
while (i < tokens.length) {
let t = tokens[i++];
// 不检查缩进, 忽略注释
if (t.source.startsWith('//')) continue;
if (t.source.startsWith('/*')) {
while (!t.source.endsWith('*/') &&
i < tokens.length) {
t = tokens[i++];
}
continue;
}
tail = t.source.indexOf(' //');
tok.source += tail === -1 && t.source ||
t.source.substring(0, tail).trimRight();
tail = CONTINUATION.indexOf(tok.source.charAt(tok.source.length - 1));
if (tail === 1)
tok.source = tok.source.slice(0, -1).trim();
if (tail === -1 || tail === 0 && tok.mode === '')
break;
}
if (tok.mode === 'decl') {
tok.key = tok.source.substring(0, pos - 1).trimRight();
tok.val = tok.source.substring(pos).trimLeft();
}
}
return root;
}
/**
* 格式化输出 root.nodes
* @param {object} root 解析后的节点树
* @return {string} CSS 无花括号两空格缩进格式
*/
format(root) {
let fmt = '',
sp = '\n';
this.walk(root.nodes, null, (n, c, i, ns) => {
if (fmt) fmt += sp;
switch (n.mode) {
case 'comment':
fmt += n.source.replace('\n', sp + ' ');
break;
case 'decl':
fmt += n.key + ': ' + n.val;
break;
default: // block, rule
fmt += n.source;
break;
}
if (!i && n.nodes && n.nodes.length) {
sp += ' ';
}else if (i && i + 1 === ns.length) {
sp = sp.slice(0, -2);
}
return true;
});
return fmt;
}
/**
* 遍历 this.result 所有节点拼接编译插件的编译结果.
* 未被编译的节点和其子节点被抛弃.
* @return {string} body 编译后的函数主体代码;
*/
compile() {
let root = this.result, plugins = this.plugins;
if (!root || root.mode != 'root')
return '';
let ctx = {body: ''};
let compile = (item, ctx, index, nodes) => {
let body;
plugins.some((plugin) => {
if (typeof plugin.compile === 'function') {
body = plugin.compile(item, index, nodes);
return body != null;
}});
if (!body || body === ' ') return false;
let pos = body.indexOf('...');
if (pos !== -1) {
if (body.indexOf('...', pos + 1) !== -1)
throw new Error(util.info('Nested placeholders too much', item));
if (!item.nodes || !item.nodes.length)
throw new Error(util.info('Nested placeholders can not be used for empty nodes', item));
}
if (item.nodes && item.nodes.length) {
let child = {body: ''};
this.walk(item.nodes, child, compile);
if (pos !== -1)
body = body.substring(0, pos) + child.body + body.substring(pos + 3);
else
body += '\n' + child.body;
}
ctx.body += body + '\n';
return false;
};
this.walk(root.nodes, ctx, compile);
return ctx.body;
}
/**
* 返回 Function(params, this.compile(this.result + ';return '+ params.split(',')[0]))
*
* @param {?string} params 形参, 缺省为 'ctx'
* @return {object} ctx
*/
build(params) {
params = params || 'ctx';
return Function( // jshint ignore:line
params,
this.compile() + ';return ' + params.split(',')[0]
);
}
/**
* 包装 process, build 并返回执行结果
* @param {string} source CSS 源码
* @param {?string} params 形参, 缺省为 'ctx'
* @param {?array} args 实参, 缺省为 [context()]
* @return {object}
*/
run(source, params, args) {
return this.process(source).build(params)(...(args || [context()]));
}
/**
* 使用 nodes.forEach 深度遍历节点树并调用 callback(item, context, index, nodes).
* 如果 callback 返回非真值, item.nodes 将不参与遍历.
* @param {array} nodes
* @param {Object} context 上下文
* @param {function(object,object,number,array):Boolean} callback 回调函数
* @return {this}
*/
walk(nodes, context, callback) {
if (nodes && typeof nodes.forEach === 'function')
nodes.forEach((item, index) => {
if (callback(item, context, index, nodes) && item.nodes)
this.walk(item.nodes, context, callback);
}, this);
return this;
}
}
module.exports = function(plugins) {
return new PowCSS(plugins);
};
}).call(this,require('_process'))
},{"./compiler":2,"./context":3,"./lineify":4,"./util":5,"_process":1}]},{},[])
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL3Byb2Nlc3MvYnJvd3Nlci5qcyIsImxpYi9jb21waWxlci5qcyIsImxpYi9jb250ZXh0LmpzIiwibGliL2xpbmVpZnkuanMiLCJsaWIvdXRpbC5qcyIsImxpYi9wb3djc3MuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0xBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQzNEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIi8vIHNoaW0gZm9yIHVzaW5nIHByb2Nlc3MgaW4gYnJvd3NlclxudmFyIHByb2Nlc3MgPSBtb2R1bGUuZXhwb3J0cyA9IHt9O1xuXG4vLyBjYWNoZWQgZnJvbSB3aGF0ZXZlciBnbG9iYWwgaXMgcHJlc2VudCBzbyB0aGF0IHRlc3QgcnVubmVycyB0aGF0IHN0dWIgaXRcbi8vIGRvbid0IGJyZWFrIHRoaW5ncy4gIEJ1dCB3ZSBuZWVkIHRvIHdyYXAgaXQgaW4gYSB0cnkgY2F0Y2ggaW4gY2FzZSBpdCBpc1xuLy8gd3JhcHBlZCBpbiBzdHJpY3QgbW9kZSBjb2RlIHdoaWNoIGRvZXNuJ3QgZGVmaW5lIGFueSBnbG9iYWxzLiAgSXQncyBpbnNpZGUgYVxuLy8gZnVuY3Rpb24gYmVjYXVzZSB0cnkvY2F0Y2hlcyBkZW9wdGltaXplIGluIGNlcnRhaW4gZW5naW5lcy5cblxudmFyIGNhY2hlZFNldFRpbWVvdXQ7XG52YXIgY2FjaGVkQ2xlYXJUaW1lb3V0O1xuXG5mdW5jdGlvbiBkZWZhdWx0U2V0VGltb3V0KCkge1xuICAgIHRocm93IG5ldyBFcnJvcignc2V0VGltZW91dCBoYXMgbm90IGJlZW4gZGVmaW5lZCcpO1xufVxuZnVuY3Rpb24gZGVmYXVsdENsZWFyVGltZW91dCAoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdjbGVhclRpbWVvdXQgaGFzIG5vdCBiZWVuIGRlZmluZWQnKTtcbn1cbihmdW5jdGlvbiAoKSB7XG4gICAgdHJ5IHtcbiAgICAgICAgaWYgKHR5cGVvZiBzZXRUaW1lb3V0ID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICBjYWNoZWRTZXRUaW1lb3V0ID0gc2V0VGltZW91dDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNhY2hlZFNldFRpbWVvdXQgPSBkZWZhdWx0U2V0VGltb3V0O1xuICAgICAgICB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBjYWNoZWRTZXRUaW1lb3V0ID0gZGVmYXVsdFNldFRpbW91dDtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgICAgaWYgKHR5cGVvZiBjbGVhclRpbWVvdXQgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgIGNhY2hlZENsZWFyVGltZW91dCA9IGNsZWFyVGltZW91dDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNhY2hlZENsZWFyVGltZW91dCA9IGRlZmF1bHRDbGVhclRpbWVvdXQ7XG4gICAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGNhY2hlZENsZWFyVGltZW91dCA9IGRlZmF1bHRDbGVhclRpbWVvdXQ7XG4gICAgfVxufSAoKSlcbmZ1bmN0aW9uIHJ1blRpbWVvdXQoZnVuKSB7XG4gICAgaWYgKGNhY2hlZFNldFRpbWVvdXQgPT09IHNldFRpbWVvdXQpIHtcbiAgICAgICAgLy9ub3JtYWwgZW52aXJvbWVudHMgaW4gc2FuZSBzaXR1YXRpb25zXG4gICAgICAgIHJldHVybiBzZXRUaW1lb3V0KGZ1biwgMCk7XG4gICAgfVxuICAgIC8vIGlmIHNldFRpbWVvdXQgd2Fzbid0IGF2YWlsYWJsZSBidXQgd2FzIGxhdHRlciBkZWZpbmVkXG4gICAgaWYgKChjYWNoZWRTZXRUaW1lb3V0ID09PSBkZWZhdWx0U2V0VGltb3V0IHx8ICFjYWNoZWRTZXRUaW1lb3V0KSAmJiBzZXRUaW1lb3V0KSB7XG4gICAgICAgIGNhY2hlZFNldFRpbWVvdXQgPSBzZXRUaW1lb3V0O1xuICAgICAgICByZXR1cm4gc2V0VGltZW91dChmdW4sIDApO1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgICAvLyB3aGVuIHdoZW4gc29tZWJvZHkgaGFzIHNjcmV3ZWQgd2l0aCBzZXRUaW1lb3V0IGJ1dCBubyBJLkUuIG1hZGRuZXNzXG4gICAgICAgIHJldHVybiBjYWNoZWRTZXRUaW1lb3V0KGZ1biwgMCk7XG4gICAgfSBjYXRjaChlKXtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIC8vIFdoZW4gd2UgYXJlIGluIEkuRS4gYnV0IHRoZSBzY3JpcHQgaGFzIGJlZW4gZXZhbGVkIHNvIEkuRS4gZG9lc24ndCB0cnVzdCB0aGUgZ2xvYmFsIG9iamVjdCB3aGVuIGNhbGxlZCBub3JtYWxseVxuICAgICAgICAgICAgcmV0dXJuIGNhY2hlZFNldFRpbWVvdXQuY2FsbChudWxsLCBmdW4sIDApO1xuICAgICAgICB9IGNhdGNoKGUpe1xuICAgICAgICAgICAgLy8gc2FtZSBhcyBhYm92ZSBidXQgd2hlbiBpdCdzIGEgdmVyc2lvbiBvZiBJLkUuIHRoYXQgbXVzdCBoYXZlIHRoZSBnbG9iYWwgb2JqZWN0IGZvciAndGhpcycsIGhvcGZ1bGx5IG91ciBjb250ZXh0IGNvcnJlY3Qgb3RoZXJ3aXNlIGl0IHdpbGwgdGhyb3cgYSBnbG9iYWwgZXJyb3JcbiAgICAgICAgICAgIHJldHVybiBjYWNoZWRTZXRUaW1lb3V0LmNhbGwodGhpcywgZnVuLCAwKTtcbiAgICAgICAgfVxuICAgIH1cblxuXG59XG5mdW5jdGlvbiBydW5DbGVhclRpbWVvdXQobWFya2VyKSB7XG4gICAgaWYgKGNhY2hlZENsZWFyVGltZW91dCA9PT0gY2xlYXJUaW1lb3V0KSB7XG4gICAgICAgIC8vbm9ybWFsIGVudmlyb21lbnRzIGluIHNhbmUgc2l0dWF0aW9uc1xuICAgICAgICByZXR1cm4gY2xlYXJUaW1lb3V0KG1hcmtlcik7XG4gICAgfVxuICAgIC8vIGlmIGNsZWFyVGltZW91dCB3YXNuJ3QgYXZhaWxhYmxlIGJ1dCB3YXMgbGF0dGVyIGRlZmluZWRcbiAgICBpZiAoKGNhY2hlZENsZWFyVGltZW91dCA9PT0gZGVmYXVsdENsZWFyVGltZW91dCB8fCAhY2FjaGVkQ2xlYXJUaW1lb3V0KSAmJiBjbGVhclRpbWVvdXQpIHtcbiAgICAgICAgY2FjaGVkQ2xlYXJUaW1lb3V0ID0gY2xlYXJUaW1lb3V0O1xuICAgICAgICByZXR1cm4gY2xlYXJUaW1lb3V0KG1hcmtlcik7XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICAgIC8vIHdoZW4gd2hlbiBzb21lYm9keSBoYXMgc2NyZXdlZCB3aXRoIHNldFRpbWVvdXQgYnV0IG5vIEkuRS4gbWFkZG5lc3NcbiAgICAgICAgcmV0dXJuIGNhY2hlZENsZWFyVGltZW91dChtYXJrZXIpO1xuICAgIH0gY2F0Y2ggKGUpe1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgLy8gV2hlbiB3ZSBhcmUgaW4gSS5FLiBidXQgdGhlIHNjcmlwdCBoYXMgYmVlbiBldmFsZWQgc28gSS5FLiBkb2Vzbid0ICB0cnVzdCB0aGUgZ2xvYmFsIG9iamVjdCB3aGVuIGNhbGxlZCBub3JtYWxseVxuICAgICAgICAgICAgcmV0dXJuIGNhY2hlZENsZWFyVGltZW91dC5jYWxsKG51bGwsIG1hcmtlcik7XG4gICAgICAgIH0gY2F0Y2ggKGUpe1xuICAgICAgICAgICAgLy8gc2FtZSBhcyBhYm92ZSBidXQgd2hlbiBpdCdzIGEgdmVyc2lvbiBvZiBJLkUuIHRoYXQgbXVzdCBoYXZlIHRoZSBnbG9iYWwgb2JqZWN0IGZvciAndGhpcycsIGhvcGZ1bGx5IG91ciBjb250ZXh0IGNvcnJlY3Qgb3RoZXJ3aXNlIGl0IHdpbGwgdGhyb3cgYSBnbG9iYWwgZXJyb3IuXG4gICAgICAgICAgICAvLyBTb21lIHZlcnNpb25zIG9mIEkuRS4gaGF2ZSBkaWZmZXJlbnQgcnVsZXMgZm9yIGNsZWFyVGltZW91dCB2cyBzZXRUaW1lb3V0XG4gICAgICAgICAgICByZXR1cm4gY2FjaGVkQ2xlYXJUaW1lb3V0LmNhbGwodGhpcywgbWFya2VyKTtcbiAgICAgICAgfVxuICAgIH1cblxuXG5cbn1cbnZhciBxdWV1ZSA9IFtdO1xudmFyIGRyYWluaW5nID0gZmFsc2U7XG52YXIgY3VycmVudFF1ZXVlO1xudmFyIHF1ZXVlSW5kZXggPSAtMTtcblxuZnVuY3Rpb24gY2xlYW5VcE5leHRUaWNrKCkge1xuICAgIGlmICghZHJhaW5pbmcgfHwgIWN1cnJlbnRRdWV1ZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGRyYWluaW5nID0gZmFsc2U7XG4gICAgaWYgKGN1cnJlbnRRdWV1ZS5sZW5ndGgpIHtcbiAgICAgICAgcXVldWUgPSBjdXJyZW50UXVldWUuY29uY2F0KHF1ZXVlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBxdWV1ZUluZGV4ID0gLTE7XG4gICAgfVxuICAgIGlmIChxdWV1ZS5sZW5ndGgpIHtcbiAgICAgICAgZHJhaW5RdWV1ZSgpO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gZHJhaW5RdWV1ZSgpIHtcbiAgICBpZiAoZHJhaW5pbmcpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB2YXIgdGltZW91dCA9IHJ1blRpbWVvdXQoY2xlYW5VcE5leHRUaWNrKTtcbiAgICBkcmFpbmluZyA9IHRydWU7XG5cbiAgICB2YXIgbGVuID0gcXVldWUubGVuZ3RoO1xuICAgIHdoaWxlKGxlbikge1xuICAgICAgICBjdXJyZW50UXVldWUgPSBxdWV1ZTtcbiAgICAgICAgcXVldWUgPSBbXTtcbiAgICAgICAgd2hpbGUgKCsrcXVldWVJbmRleCA8IGxlbikge1xuICAgICAgICAgICAgaWYgKGN1cnJlbnRRdWV1ZSkge1xuICAgICAgICAgICAgICAgIGN1cnJlbnRRdWV1ZVtxdWV1ZUluZGV4XS5ydW4oKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBxdWV1ZUluZGV4ID0gLTE7XG4gICAgICAgIGxlbiA9IHF1ZXVlLmxlbmd0aDtcbiAgICB9XG4gICAgY3VycmVudFF1ZXVlID0gbnVsbDtcbiAgICBkcmFpbmluZyA9IGZhbHNlO1xuICAgIHJ1bkNsZWFyVGltZW91dCh0aW1lb3V0KTtcbn1cblxucHJvY2Vzcy5uZXh0VGljayA9IGZ1bmN0aW9uIChmdW4pIHtcbiAgICB2YXIgYXJncyA9IG5ldyBBcnJheShhcmd1bWVudHMubGVuZ3RoIC0gMSk7XG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAxKSB7XG4gICAgICAgIGZvciAodmFyIGkgPSAxOyBpIDwgYXJndW1lbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBhcmdzW2kgLSAxXSA9IGFyZ3VtZW50c1tpXTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBxdWV1ZS5wdXNoKG5ldyBJdGVtKGZ1biwgYXJncykpO1xuICAgIGlmIChxdWV1ZS5sZW5ndGggPT09IDEgJiYgIWRyYWluaW5nKSB7XG4gICAgICAgIHJ1blRpbWVvdXQoZHJhaW5RdWV1ZSk7XG4gICAgfVxufTtcblxuLy8gdjggbGlrZXMgcHJlZGljdGlibGUgb2JqZWN0c1xuZnVuY3Rpb24gSXRlbShmdW4sIGFycmF5KSB7XG4gICAgdGhpcy5mdW4gPSBmdW47XG4gICAgdGhpcy5hcnJheSA9IGFycmF5O1xufVxuSXRlbS5wcm90b3R5cGUucnVuID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuZnVuLmFwcGx5KG51bGwsIHRoaXMuYXJyYXkpO1xufTtcbnByb2Nlc3MudGl0bGUgPSAnYnJvd3Nlcic7XG5wcm9jZXNzLmJyb3dzZXIgPSB0cnVlO1xucHJvY2Vzcy5lbnYgPSB7fTtcbnByb2Nlc3MuYXJndiA9IFtdO1xucHJvY2Vzcy52ZXJzaW9uID0gJyc7IC8vIGVtcHR5IHN0cmluZyB0byBhdm9pZCByZWdleHAgaXNzdWVzXG5wcm9jZXNzLnZlcnNpb25zID0ge307XG5cbmZ1bmN0aW9uIG5vb3AoKSB7fVxuXG5wcm9jZXNzLm9uID0gbm9vcDtcbnByb2Nlc3MuYWRkTGlzdGVuZXIgPSBub29wO1xucHJvY2Vzcy5vbmNlID0gbm9vcDtcbnByb2Nlc3Mub2ZmID0gbm9vcDtcbnByb2Nlc3MucmVtb3ZlTGlzdGVuZXIgPSBub29wO1xucHJvY2Vzcy5yZW1vdmVBbGxMaXN0ZW5lcnMgPSBub29wO1xucHJvY2Vzcy5lbWl0ID0gbm9vcDtcblxucHJvY2Vzcy5iaW5kaW5nID0gZnVuY3Rpb24gKG5hbWUpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3Byb2Nlc3MuYmluZGluZyBpcyBub3Qgc3VwcG9ydGVkJyk7XG59O1xuXG5wcm9jZXNzLmN3ZCA9IGZ1bmN0aW9uICgpIHsgcmV0dXJuICcvJyB9O1xucHJvY2Vzcy5jaGRpciA9IGZ1bmN0aW9uIChkaXIpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3Byb2Nlc3MuY2hkaXIgaXMgbm90IHN1cHBvcnRlZCcpO1xufTtcbnByb2Nlc3MudW1hc2sgPSBmdW5jdGlvbigpIHsgcmV0dXJuIDA7IH07XG4iLCJjb25zdCBJRlggPSAvaWZbIF0rKFtfJGEtekEtWl0rKVsgXSo9LyxcbiAgdXRpbCA9ICByZXF1aXJlKCcuL3V0aWwnKTtcblxuLyoqXG4gKiBQb3dDU1Mg57y655yB55qEIENvbXBpbGVyIOWunueOsC5cbiAqIOaJgOacieaWueazlemHh+eUqOWOn+eUnyBqcyDor63ms5UsIOimgeaxgua6kOeggeiHquW4puW1jOWll+WNoOS9jeespiAnLi4uJy5cbiAqL1xuY2xhc3MgQ29tcGlsZXJ7XG5cbiAgLyoqXG4gICAqIOaehOmAoCwg5Y+C5pWw55So5p2l5a+5IHRoaXMg6L+b6KGM5omp5bGVLlxuICAgKiDnvLrnnIEgdGhpcy5jdHggPSAnY3R4JyDooajnpLogY29udGV4dCDnmoTlvaLlj4LlkI1cbiAgICovXG4gIGNvbnN0cnVjdG9yKC4uLmV4dGVuZCkge1xuICAgIGV4dGVuZC5mb3JFYWNoKChleHQpID0+IHtcbiAgICAgIGlmICh0eXBlb2YgZXh0ID09PSAnZnVuY3Rpb24nKVxuICAgICAgICB0aGlzW2V4dC5uYW1lXSA9IGV4dDtcbiAgICAgIGVsc2UgaWYgKE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChleHQpID09PSAnW29iamVjdCBPYmplY3RdJykge1xuICAgICAgICBmb3IgKGxldCBrZXkgaW4gZXh0KSB7XG4gICAgICAgICAgdGhpc1trZXldID0gZXh0W2tleV07XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgICB0aGlzLmN0eCA9IHRoaXMuY3R4IHx8ICdjdHgnO1xuICB9XG5cbiAgLyoqXG4gICAqIGNvbXBpbGUg5o6l5Y+jXG4gICAqL1xuICBjb21waWxlKG4sIGksIG5zKSB7XG4gICAgcmV0dXJuIHRoaXMuZGVjbChuKSB8fFxuICAgICAgdGhpcy5pZihuKSB8fFxuICAgICAgdGhpcy5lYWNoKG4pIHx8XG4gICAgICB0aGlzLmxldChuKSB8fFxuICAgICAgdGhpcy5jb21tZW50KG4pIHx8XG4gICAgICB0aGlzLnJ1bGUobik7XG4gIH1cblxuICAvKipcbiAgICog57yW6K+RIG4ubW9kZSA9PT0gJ2NvbW1lbnQnIOeahOiKgueCuSwgJy8qIScg5byA5aS055qE6aG25bGC5rOo6YeK6KKr5L+d55WZLCDlhbblroPooqvmipvlvIMuXG4gICAqL1xuICBjb21tZW50KG4pIHtcbiAgICBpZiAobi5tb2RlICE9PSAnY29tbWVudCcpIHJldHVybjtcbiAgICBpZiAobi5jb2x1bW4gPT09IDEgJiYgbi5zb3VyY2VbMV0gPT09ICcqJyAmJiBuLnNvdXJjZVsyXSA9PT0gJyEnKXtcbiAgICAgIGxldCBjID0gSlNPTi5zdHJpbmdpZnkobi5zb3VyY2UpO1xuICAgICAgcmV0dXJuIGAke3RoaXMuY3R4fS5vcGVuKCR7Y30pLmNsb3NlKCk7YDtcbiAgICB9XG4gICAgcmV0dXJuICcgJztcbiAgfVxuXG4gIC8qKlxuICAgKiDnvJbor5EgIW4ubW9kZSDnmoToioLngrnkuLrop4TliJnoioLngrlcbiAgICovXG4gIHJ1bGUobikge1xuICAgIGlmIChuLm1vZGUpIHJldHVybjtcbiAgICBsZXQgYyA9IG4uc291cmNlLmluZGV4T2YoJyR7JykgPT09IC0xICYmICdcXCcnIHx8ICdgJztcbiAgICByZXR1cm4gbi5ub2RlcyAmJiBuLm5vZGVzLmxlbmd0aCAmJlxuICAgIGAke3RoaXMuY3R4fS5vcGVuKCR7Y30ke24uc291cmNlfSR7Y30pO1xuLi4uJHt0aGlzLmN0eH0uY2xvc2UoKTtgIHx8XG4gICAgYCR7dGhpcy5jdHh9Lm9wZW4oJHtjfSR7bi5zb3VyY2V9JHtjfSkuY2xvc2UoKTtgO1xuICB9XG5cbiAgLyoqXG4gICAqIOe8luivkSBuLm1vZGUgPT09ICdkZWNsJyDnmoToioLngrlcbiAgICovXG4gIGRlY2wobikge1xuICAgIGlmIChuLm1vZGUgIT09ICdkZWNsJykgcmV0dXJuO1xuXG4gICAgbGV0IGMgPSBuLmtleS5pbmRleE9mKCckeycpID09PSAtMSAmJiAnXFwnJyB8fCAnYCcsXG4gICAgICB2ID0gbi52YWwuZW5kc1dpdGgoJzsnKSA/XG4gICAgICAgIG4udmFsLnN1YnN0cmluZygwLCBuLnZhbC5sZW5ndGggLSAxKSA6XG4gICAgICAgIG4udmFsLFxuICAgICAgZCA9IHYuaW5kZXhPZignJHsnKSA9PT0gLTEgJiYgJ1xcJycgfHwgJ2AnO1xuXG4gICAgcmV0dXJuIGAke3RoaXMuY3R4fS5kZWNsKCR7Y30ke24ua2V5fSR7Y30sJHtkfSR7dn0ke2R9KTtgO1xuICB9XG5cbiAgLyoqXG4gICAqIGlmIOivreWPpSwg5Y6f55Sf6K+t5rOVOlxuICAgKiAgICBpZihleHByKSBjb2RlO1xuICAgKiAgICBpZiAoZXhwcikgY29kZTtcbiAgICovXG4gIGlmKG4pIHtcbiAgICBpZiAobi5zb3VyY2Uuc3RhcnRzV2l0aCgnaWYoJykgfHwgbi5zb3VyY2Uuc3RhcnRzV2l0aCgnaWYgKCcpKVxuICAgICAgcmV0dXJuIG4uc291cmNlO1xuICB9XG5cbiAgLyoqXG4gICAqIGVhY2gg6K+t5Y+lLCDljp/nlJ/or63ms5U6XG4gICAqXG4gICAqICAgZWFjaChleHByLCAodmFsLCBrZXkpPT57Y29kZX0pO1xuICAgKiAgIGN0eC5lYWNoKGV4cHIsICh2YWwsIGtleSk9Pntjb2RlfSk7XG4gICAqXG4gICAqL1xuICBlYWNoKG4pIHtcbiAgICBpZiAobi5zb3VyY2Uuc3RhcnRzV2l0aChgJHt0aGlzLmN0eH0uZWFjaChgKSlcbiAgICAgIHJldHVybiBuLnNvdXJjZTtcbiAgICBpZiAobi5zb3VyY2Uuc3RhcnRzV2l0aCgnZWFjaCgnKSkgcmV0dXJuIHRoaXMuY3R4ICsgJy4nICsgbi5zb3VyY2U7XG4gIH1cblxuICAvKipcbiAgICogbGV0IOivreWPpSwg5Y6f55Sf6K+t5rOVOlxuICAgKlxuICAgKiAgIGxldCB2MSA9IGV4cHI7XG4gICAqICAgbGV0IFt2MSx2Ml0gPSBbZXhwciwgZXhwcl07IC8vIEVTNiDop6PmnoTotYvlgLxcbiAgICogICBsZXQgdjEgPSBleHByOyBjb2RlO1xuICAgKi9cbiAgbGV0KG4pIHtcbiAgICBpZiAobi5zb3VyY2Uuc3RhcnRzV2l0aCgnbGV0ICcpKSByZXR1cm4gbi5zb3VyY2U7XG4gIH1cblxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uKC4uLmV4dGVuZCkge1xuICByZXR1cm4gbmV3IENvbXBpbGVyKC4uLmV4dGVuZCk7XG59O1xuIiwiLyoqXG4gKiBAdHlwZWRlZiB7b2JqZWN0fSBSdWxlICAg5oq96LGh6KeE5YiZXG4gKiBAcHJvcGVydHkge3N0cmluZ30gbmFtZSAg6KeE5YiZ5ZCNLCDkuZ/lj6/og73mmK/kuKrlrprkuYnlgLwsIOavlOWmgiBAY2hhcnNldFxuICogQHByb3BlcnR5IHs/b2JqZWN0PHN0cmluZywgc3RyaW5nfFJ1bGU+fSBkZWNscyDplK7lgLzlo7DmmI5cbiAqL1xuXG4vKipcbiAqIFBvd0NTUyDnvLrnnIHnmoQgQ29udGV4dCDlrp7njrAuXG4gKiDor6Xlrp7njrDkuI3liIbmnpAgQ1NTIOinhOWImeeahOWQiOazleaApywg5Y+q5o+Q5L6b57uT5p6E5LiK55qE5pON5L2c5ZKM5LiA5Lqb6L6F5Yqp5pa55rOVLlxuICog5aaC5p6c6KaB5a+557uT5p6c6L+b6KGM5YaN5qyh5aSE55CGLCDmjqjojZDkvb/nlKggd2FsayDmlrnms5UuXG4gKlxuICogQHByb3BlcnR5IHtSdWxlfSAgIHJ1bGUgIOW9k+WJjee7tOaKpOeahOinhOWImSwg5Yid5aeLIG51bGxcbiAqIEBwcm9wZXJ0eSB7UnVsZVtdfSBydWxlcyDmnIDnu4jnmoTop4TliJnmlbDnu4RcbiAqIEBwcm9wZXJ0eSB7UnVsZVtdfSBzdGFjayDlvZPliY3op4TliJnnmoQgcGFyZW50IOagiFxuICovXG5jbGFzcyBDb250ZXh0IHtcbiAgLyoqXG4gICAqIOaehOmAoCwg5Y+C5pWw55So5p2l5a+5IHRoaXMg6L+b6KGM5omp5bGVLlxuICAgKi9cbiAgY29uc3RydWN0b3IoLi4uZXh0ZW5kKSB7XG4gICAgZXh0ZW5kLmZvckVhY2goKGV4dCkgPT4ge1xuICAgICAgaWYgKHR5cGVvZiBleHQgPT09ICdmdW5jdGlvbicpXG4gICAgICAgIHRoaXNbZXh0Lm5hbWVdID0gZXh0O1xuICAgICAgZWxzZSBpZiAoT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGV4dCkgPT09ICdbb2JqZWN0IE9iamVjdF0nKSB7XG4gICAgICAgIGZvciAobGV0IGtleSBpbiBleHQpIHtcbiAgICAgICAgICB0aGlzW2tleV0gPSBleHRba2V5XTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICAgIHRoaXMucmVzZXQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiDph43nva4gLnJ1bGUsIC5ydWxlcywgLnN0YWNrIOS4uuWIneWni+eKtuaAgVxuICAgKiBAcmV0dXJuIHt0aGlzfVxuICAgKi9cbiAgcmVzZXQoKSB7XG4gICAgdGhpcy5ydWxlID0gbnVsbDtcbiAgICB0aGlzLnJ1bGVzID0gW107XG4gICAgdGhpcy5zdGFjayA9IFtdO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIC8qKlxuICAgKiDpgY3ljoYgeCDlm57osIMgY2FsbGJhY2sodmFsLCBrZXkpXG4gICAqIEBwYXJhbSAge29iamVjdHxhcnJheX0gICB4XG4gICAqIEBwYXJhbSAge0Z1bmN0aW9uKCAqLCBzdHJpbmcpfSBjYWxsYmFjayDlj4LmlbDpobrluo8gKHZhbCwga2V5KVxuICAgKiBAcmV0dXJuIHt0aGlzfVxuICAgKi9cbiAgZWFjaCh4LCBjYWxsYmFjaykge1xuICAgIGlmIChBcnJheS5pc0FycmF5KHgpKSB7XG4gICAgICB4LmZvckVhY2goY2FsbGJhY2spO1xuICAgIH1lbHNlXG4gICAgICBPYmplY3Qua2V5cyh4KS5mb3JFYWNoKGZ1bmN0aW9uKGtleSkge1xuICAgICAgICBjYWxsYmFjayh4W2tleV0sIGtleSk7XG4gICAgICB9KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiDlvIDlkK/kuIDkuKrlhbflkI3op4TliJnlubbmm7/mjaIgbmFtZSDkuK3nmoTljaDkvY3nrKYgJyYnLCDor6Xmlrnms5Xlv4XpobvkuI4gY2xvc2Ug5oiQ5a+55L2/55SoLlxuICAgKiDltYzlpZfkvb/nlKjml7YgdGhpcy5zdGFjayDkvJrlop7plb8uXG4gICAqIEBwYXJhbSAge3N0cmluZ30gbmFtZVxuICAgKiBAcmV0dXJuIHt0aGlzfVxuICAgKi9cbiAgb3BlbihuYW1lKSB7XG4gICAgaWYgKHRoaXMucnVsZSkge1xuICAgICAgdGhpcy5zdGFjay5wdXNoKHRoaXMucnVsZSk7XG4gICAgICBpZiAobmFtZS5pbmRleE9mKCcmJykgIT09IC0xKVxuICAgICAgICBuYW1lID0gbmFtZS5yZXBsYWNlKC8mL2csIHRoaXMucnVsZS5uYW1lKTtcblxuICAgICAgaWYgKCF0aGlzLnJ1bGUuZGVjbHMpIHtcbiAgICAgICAgaWYgKHRoaXMucnVsZS5uYW1lWzBdID09PSAnQCcpIHtcbiAgICAgICAgICB0aGlzLnJ1bGUuZGVjbHMgPSBbXTtcbiAgICAgICAgICB0aGlzLnN0YWNrLnB1c2godGhpcy5ydWxlcyk7XG4gICAgICAgICAgdGhpcy5ydWxlcyA9IHRoaXMucnVsZS5kZWNscztcbiAgICAgICAgfWVsc2UgaWYgKFxuICAgICAgICAgIHRoaXMucnVsZS5uYW1lWzBdICE9PSAnLycgJiZcbiAgICAgICAgICB0aGlzLnJ1bGUgPT09IHRoaXMucnVsZXNbdGhpcy5ydWxlcy5sZW5ndGggLSAxXVxuICAgICAgICAgKSB7XG4gICAgICAgICAgdGhpcy5ydWxlcy5wb3AoKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICB0aGlzLnJ1bGUgPSB7bmFtZX07XG4gICAgdGhpcy5ydWxlcy5wdXNoKHRoaXMucnVsZSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICog5YWz6Zet5b2T5YmN55qE6KeE5YiZLCB0aGlzLnN0YWNrIOS8muWHj+WwkSwg6K+l5pa55rOV5b+F6aG75LiOIC5vcGVuIOaIkOWvueS9v+eUqC5cbiAgICogQHJldHVybiB7dGhpc31cbiAgICovXG4gIGNsb3NlKCkge1xuICAgIHRoaXMucnVsZSA9IHRoaXMuc3RhY2sucG9wKCk7XG4gICAgaWYgKEFycmF5LmlzQXJyYXkodGhpcy5ydWxlKSkge1xuICAgICAgdGhpcy5ydWxlcyA9IHRoaXMucnVsZTtcbiAgICAgIHJldHVybiB0aGlzLmNsb3NlKCk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIOi/lOWbniB0aGlzLnJ1bGUubmFtZVxuICAgKiBAcmV0dXJuIHtzdHJpbmd9XG4gICAqL1xuICBuYW1lKCkge1xuICAgIHJldHVybiB0aGlzLnJ1bGUgJiYgdGhpcy5ydWxlLm5hbWUgfHwgJyc7XG4gIH1cblxuICAvKipcbiAgICog6L+U5Zue5oiW6K6+572u5b2T5YmN6KeE5YiZ55qEIGtleSDlo7DmmI5cbiAgICogQHBhcmFtICB7c3RyaW5nfSAga2V5XG4gICAqIEBwYXJhbSAgez9zdHJpbmd9IHZhbFxuICAgKiBAcmV0dXJuIHtzdHJpbmd9XG4gICAqL1xuICBkZWNsKGtleSwgdmFsKSB7XG4gICAgaWYgKHZhbCkge1xuICAgICAgaWYgKCF0aGlzLnJ1bGUuZGVjbHMpXG4gICAgICAgIHRoaXMucnVsZS5kZWNscyA9IHt9O1xuICAgICAgdGhpcy5ydWxlLmRlY2xzW2tleV0gPSB2YWw7XG4gICAgICByZXR1cm4gdmFsO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5ydWxlLmRlY2xzW2tleV0gfHwgJyc7XG4gIH1cblxuICAvKipcbiAgICog6L6T5Ye6IHRoaXMucnVsZXMg5Li6IENTUyDmupDnoIFcbiAgICogQHJldHVybiB7c3RyaW5nfSBjc3NcbiAgICovXG4gIHRvQ1NTKCkge1xuICAgIGxldCB0b0NTUyA9IChjc3MsIHJ1bGUpPT4ge1xuICAgICAgaWYgKHJ1bGUuZGVjbHMpIHtcbiAgICAgICAgY3NzICs9IHJ1bGUubmFtZSArICcge1xcbic7XG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KHJ1bGUuZGVjbHMpKSB7XG4gICAgICAgICAgY3NzICs9IHJ1bGUuZGVjbHMucmVkdWNlKHRvQ1NTLCAnJyk7XG4gICAgICAgIH1lbHNlIGZvciAobGV0IGtleSBpbiBydWxlLmRlY2xzKSB7XG4gICAgICAgICAgaWYgKHR5cGVvZiBydWxlLmRlY2xzW2tleV0gPT09ICdzdHJpbmcnKVxuICAgICAgICAgICAgY3NzICs9IGtleSArICc6ICcgKyBydWxlLmRlY2xzW2tleV0gKyAnO1xcbic7XG4gICAgICAgICAgZWxzZVxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdkZWNscyBtdXN0IGJlIGEgc3RyaW5nIG9yIGFycmF5OiAnICsgcnVsZS5uYW1lICsgJ3snICsga2V5ICsgJ30nKTtcbiAgICAgICAgfVxuICAgICAgICBjc3MgKz0gJ31cXG4nO1xuICAgICAgfWVsc2UgaWYgKHJ1bGUubmFtZVswXSA9PT0gJy8nKSAvLyBjb21tZW50XG4gICAgICAgIGNzcyArPSBydWxlLm5hbWUgKyAnXFxuJztcbiAgICAgIGVsc2UgaWYgKHJ1bGUubmFtZVswXSA9PT0gJ0AnKSAvLyDmnInkupvop4TliJnlj6rmmK/kuLrkuobltYzlpZcgJyYnLCDmsqHmnIkgZGVjbHNcbiAgICAgICAgY3NzICs9IHJ1bGUubmFtZSArICc7XFxuJztcbiAgICAgIGVsc2VcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdVbmV4cGVjdGVkIGJhcmUgcnVsZTogJyArIHJ1bGUubmFtZSk7XG4gICAgICByZXR1cm4gY3NzO1xuICAgIH07XG5cbiAgICByZXR1cm4gdGhpcy5ydWxlcy5yZWR1Y2UodG9DU1MsICcnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiDpgY3ljoYgdGhpcy5ydWxlcyDosIPnlKggY29udGV4dCDnmoQgb3BlbiwgY2xvc2UsIGRlY2wg5pa55rOVLlxuICAgKiBjb250ZXh0IOeahCBvcGVuLCBjbG9zZSDov5Tlm57nmoTlr7nosaHkvJrnlKjkuo7lkI7nu63nmoTov63ku6MuXG4gICAqIOS7u+S9leS4gOS4quaWueazlei/lOWbnumdnuecn+WAvOS8mue7iOatoumBjeWOhi5cbiAgICogQHBhcmFtICB7b2JqZWN0fSAgY29udGV4dCAg5a6e546wIG9wZW4sIGNsb3NlLCBkZWNsIOaWueazleeahOWvueixoVxuICAgKiBAcmV0dXJuIHtib29sZWFufSBmaW5pc2hlZCDmmK/lkKblrozlhajpgY3ljoZcbiAgICovXG4gIHdhbGsoY29udGV4dCkge1xuICAgIGxldCB3YWxrID0gZnVuY3Rpb24ocnVsZSkge1xuICAgICAgbGV0IHNlbGYgPSB0aGlzO1xuICAgICAgaWYgKHJ1bGUuZGVjbHMpIHtcbiAgICAgICAgc2VsZiA9IHNlbGYub3BlbihydWxlLm5hbWUpO1xuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShydWxlLmRlY2xzKSkge1xuICAgICAgICAgIGlmICghcnVsZS5kZWNscy5ldmVyeSh3YWxrLCBzZWxmKSlcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfWVsc2UgZm9yIChsZXQga2V5IGluIHJ1bGUuZGVjbHMpIHtcbiAgICAgICAgICBpZiAodHlwZW9mIHJ1bGUuZGVjbHNba2V5XSA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIGlmICghc2VsZi5kZWNsKGtleSwgcnVsZS5kZWNsc1trZXldKSkgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgIH1lbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignZGVjbHMgbXVzdCBiZSBhIHN0cmluZyBvciBhcnJheTogJyArIHJ1bGUubmFtZSArICd7JyArIGtleSArICd9Jyk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9ZWxzZSBpZiAocnVsZS5uYW1lWzBdID09PSAnLycgfHwgcnVsZS5uYW1lWzBdID09PSAnQCcpIHtcbiAgICAgICAgc2VsZiA9IHNlbGYub3BlbihydWxlLm5hbWUpO1xuICAgICAgfWVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1VuZXhwZWN0ZWQgYmFyZSBydWxlOiAnICsgcnVsZS5uYW1lKTtcbiAgICAgIH1cbiAgICAgIGlmIChzZWxmKSBzZWxmID0gc2VsZi5jbG9zZSgpO1xuICAgICAgcmV0dXJuICEhc2VsZjtcbiAgICB9O1xuICAgIHJldHVybiB0aGlzLnJ1bGVzLmV2ZXJ5KHdhbGssIGNvbnRleHQpO1xuICB9XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24oLi4uZXh0ZW5kKSB7XG4gIHJldHVybiBuZXcgQ29udGV4dCguLi5leHRlbmQpO1xufTtcbiIsIi8qKlxuICogbGluZWlmeSDmmK/kuKrpnZ7nqbrnmb3ooYzmiavmj4/lmagsIOaJq+aPj+W5tui/lOWbnumdnuepuueZveihjOS/oeaBry5cbiAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2Ug5b6F5omr5o+P55qE5a2X56ym5LiyXG4gKi9cbmNsYXNzIGxpbmVpZnl7XG4gIGNvbnN0cnVjdG9yKHNvdXJjZSkge1xuICAgIHRoaXMuY3JsZiA9IHNvdXJjZS5pbmRleE9mKCdcXHJcXG4nKSAhPSAtMSAmJiAnXFxyXFxuJyB8fFxuICAgICAgc291cmNlLmluZGV4T2YoJ1xccicpICE9IC0xICYmICdcXHInIHx8ICdcXG4nO1xuICAgIHRoaXMuY3JsZkxlbmd0aCA9IHRoaXMuY3JsZi5sZW5ndGg7XG5cbiAgICB0aGlzLmJvbCA9IDA7XG4gICAgdGhpcy5lb2wgPSAwO1xuICAgIHRoaXMuY29sdW1uID0gMTtcbiAgICB0aGlzLmxpbmUgPSAxO1xuICAgIHRoaXMuc291cmNlID0gc291cmNlO1xuICAgIHRoaXMuc2NhbihudWxsKTtcbiAgfVxuXG4gIC8qKlxuICAgKiDov5Tlm57miavmj4/liLDnmoTpnZ7nqbrnmb3ooYzlrZfnrKbkuLLlkozkvY3nva7kv6Hmga8sIOW5tuWJjei/my4g57uT5p6EOlxuICAgKiAgIHtzb3VyY2UsIG9mZnNldCwgbGluZSwgY29sdW1ufVxuICAgKiBAcmV0dXJuIHtPYmplY3R8bnVsbH0gdG9rZW4g6L+U5ZueIG51bGwg6KGo56S6IEVPRlxuICAgKi9cbiAgc2NhbigpIHtcbiAgICBsZXQgdG9rID0ge1xuICAgICAgc291cmNlOiB0aGlzLnNvdXJjZS5zdWJzdHJpbmcodGhpcy5ib2wsIHRoaXMuZW9sKS50cmltUmlnaHQoKSxcbiAgICAgIG9mZnNldDogdGhpcy5ib2wsXG4gICAgICBsaW5lOiB0aGlzLmxpbmUsXG4gICAgICBjb2x1bW46IHRoaXMuY29sdW1uXG4gICAgfTtcblxuICAgIGlmICh0aGlzLmVvbCA9PT0gdGhpcy5zb3VyY2UubGVuZ3RoKSB7XG4gICAgICB0aGlzLmJvbCA9IHRoaXMuZW9sO1xuICAgICAgcmV0dXJuIHRvay5zb3VyY2UgJiYgdG9rIHx8IG51bGw7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuZW9sKSB7XG4gICAgICB0aGlzLmJvbCA9IHRoaXMuZW9sICsgdGhpcy5jcmxmTGVuZ3RoO1xuICAgICAgdGhpcy5saW5lKys7XG4gICAgICB0aGlzLmNvbHVtbiA9IDE7XG4gICAgfVxuXG4gICAgdGhpcy5lb2wgPSB0aGlzLnNvdXJjZS5pbmRleE9mKHRoaXMuY3JsZiwgdGhpcy5ib2wpO1xuXG4gICAgaWYgKHRoaXMuZW9sID09PSAtMSlcbiAgICAgIHRoaXMuZW9sID0gdGhpcy5zb3VyY2UubGVuZ3RoO1xuXG4gICAgd2hpbGUgKDEpIHtcbiAgICAgIGxldCBjID0gdGhpcy5zb3VyY2UuY2hhckNvZGVBdCh0aGlzLmJvbCk7XG4gICAgICBpZiAoYyA9PT0gMzIgfHwgYyA9PT0gOSkge1xuICAgICAgICB0aGlzLmJvbCsrO1xuICAgICAgICB0aGlzLmNvbHVtbisrO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuZW9sICE9PSB0aGlzLmJvbCkgYnJlYWs7XG4gICAgICBpZiAodGhpcy5lb2wgPT09IHRoaXMuc291cmNlLmxlbmd0aCkgYnJlYWs7XG5cbiAgICAgIHRoaXMubGluZSsrO1xuICAgICAgdGhpcy5jb2x1bW4gPSAxO1xuXG4gICAgICB0aGlzLmJvbCA9IHRoaXMuZW9sICsgdGhpcy5jcmxmTGVuZ3RoO1xuICAgICAgdGhpcy5lb2wgPSB0aGlzLnNvdXJjZS5pbmRleE9mKHRoaXMuY3JsZiwgdGhpcy5ib2wpO1xuXG4gICAgICBpZiAodGhpcy5lb2wgPT09IC0xKVxuICAgICAgICB0aGlzLmVvbCA9IHRoaXMuc291cmNlLmxlbmd0aDtcbiAgICB9XG5cbiAgICByZXR1cm4gdG9rO1xuICB9XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24oc291cmNlKSB7XG4gIHJldHVybiBuZXcgbGluZWlmeShzb3VyY2UpO1xufTtcbiIsImNvbnN0IHRvU3RyaW5nID0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZztcblxuLyoqXG4gKiDovoXliqnmlrnms5Xpm4blkIhcbiAqL1xubGV0IHV0aWwgPSB7XG4gIC8qKlxuICAgKiDov5Tlm57ljIXlkKvkvY3nva7kv6Hmga/nmoTlrZfnrKbkuLIsIOW4uOeUqOS6juWHuumUmeS/oeaBr1xuICAgKiBAcGFyYW0gIHtzdHJpbmd9ICBtZXNzYWdlIOiHquWumuS5ieS/oeaBr1xuICAgKiBAcGFyYW0gIHtvYmplY3R9ICBsb2MgICAgIOWQq+aciSBsaW5lLCBjb2x1bW4g55qE5L2N572u5L+h5oGvXG4gICAqIEBwYXJhbSAgez9zdHJpbmd9IGF0ICAgICAg57y655yB5Li6IDxhbm9ueW1vdXM+XG4gICAqIEByZXR1cm4ge3N0cmluZ31cbiAgICovXG4gIGluZm86IGZ1bmN0aW9uKG1lc3NhZ2UsIGxvYywgYXQpIHtcbiAgICByZXR1cm4gYCR7bWVzc2FnZX0gYXQ6ICR7YXQgfHwgJzxhbm9ueW1vdXM+J306JHtsb2MubGluZX06JHtsb2MuY29sdW1ufWA7XG4gIH0sXG4gIC8qKlxuICAgKiBpc09iamVjdFxuICAgKiBAcGFyYW0gIHsqfSB4XG4gICAqIEByZXR1cm4ge0Jvb2xlYW59XG4gICAqL1xuICBpc09iamVjdDogZnVuY3Rpb24oeCkge1xuICAgIHJldHVybiB0b1N0cmluZy5jYWxsKHgpID09PSAnW29iamVjdCBPYmplY3RdJztcbiAgfSxcbiAgLyoqXG4gICAqIGlzTnVtYmVyXG4gICAqIEBwYXJhbSAgeyp9IHhcbiAgICogQHJldHVybiB7Qm9vbGVhbn1cbiAgICovXG4gIGlzTnVtYmVyOiBmdW5jdGlvbih4KSB7XG4gICAgcmV0dXJuIHRvU3RyaW5nLmNhbGwoeCkgPT09ICdbb2JqZWN0IE51bWJlcl0nO1xuICB9LFxuICAvKipcbiAgICogaXNBcnJheVxuICAgKiBAcGFyYW0gIHsqfSB4XG4gICAqIEByZXR1cm4ge0Jvb2xlYW59XG4gICAqL1xuICBpc0FycmF5OiBmdW5jdGlvbih4KSB7XG4gICAgcmV0dXJuIEFycmF5LmlzQXJyYXkoeCk7XG4gIH0sXG4gIC8qKlxuICAgKiBpc1N0cmluZ1xuICAgKiBAcGFyYW0gIHsqfSB4XG4gICAqIEByZXR1cm4ge0Jvb2xlYW59XG4gICAqL1xuICBpc1N0cmluZzogZnVuY3Rpb24oeCkge1xuICAgIHJldHVybiB0eXBlb2YgeCA9PT0gJ3N0cmluZyc7XG4gIH0sXG4gIC8qKlxuICAgKiBpc0Z1bmN0aW9uXG4gICAqIEBwYXJhbSAgeyp9IHhcbiAgICogQHJldHVybiB7Qm9vbGVhbn1cbiAgICovXG4gIGlzRnVuY3Rpb246IGZ1bmN0aW9uKHgpIHtcbiAgICByZXR1cm4gdHlwZW9mIHggPT09ICdmdW5jdGlvbic7XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gdXRpbDtcbiIsImNvbnN0IGxpbmVpZnkgPSByZXF1aXJlKCcuL2xpbmVpZnknKSxcbiAgY29tcGlsZXIgPSByZXF1aXJlKCcuL2NvbXBpbGVyJyksXG4gIGNvbnRleHQgPSByZXF1aXJlKCcuL2NvbnRleHQnKSxcbiAgdXRpbCA9ICByZXF1aXJlKCcuL3V0aWwnKSxcbiAgQ09OVElOVUFUSU9OID0gJyZcXFxcLCstLyp8PShbJztcblxuLyoqXG4gKiBQb3dDU1Mg6LSf6LSj6Kej5p6QIHNvdXJjZSDkuLroioLngrnmoJEsIOW5tuaLvOaOpee8luivkeWZqOeahOe8luivkee7k+aenC5cbiAqIOWcqCBQb3dDU1Mg5Lit55qE5o+S5Lu25bCx5pivIGNvbXBpbGVyLCBjb21waWxlciDotJ/otKPkuI4gY29udGV4dCDphY3lkIguXG4gKi9cbmNsYXNzIFBvd0NTUyB7XG4gIC8qKlxuICAgKiBAcGFyYW0gIHs/Q29tcGlsZXJbXX0gcGx1Z2lucyDnvJbor5HlmajmlbDnu4QsIOe8uuecgeS4uiBbY29tcGlsZXIoKV1cbiAgICovXG4gIGNvbnN0cnVjdG9yKHBsdWdpbnMpIHtcbiAgICB0aGlzLnBsdWdpbnMgPSBwbHVnaW5zICYmIHBsdWdpbnMubGVuZ3RoICYmIHBsdWdpbnMgfHwgW2NvbXBpbGVyKCldO1xuICB9XG5cbiAgLyoqXG4gICAqIOS9v+eUqOS4gOS4que8luivkeWZqOaPkuS7tlxuICAgKiBAcGFyYW0gIHtDb21waWxlcn0gcGx1Z2luXG4gICAqIEByZXR1cm4ge3RoaXN9XG4gICAqL1xuICB1c2UocGx1Z2luKSB7XG4gICAgaWYgKHBsdWdpbilcbiAgICAgIHRoaXMucGx1Z2lucy5wdXNoKHBsdWdpbik7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICog5YyF6KOFIHRoaXMucmVzdWx0ID0gdGhpcy5wYXJzZShzb3VyY2UpIOW5tui/lOWbniB0aGlzLlxuICAgKiBAcGFyYW0gIHtzdHJpbmd9ICBzb3VyY2UgIOa6kOeggVxuICAgKiBAcmV0dXJuIHt0aGlzfVxuICAgKi9cbiAgcHJvY2Vzcyhzb3VyY2UpIHtcbiAgICB0aGlzLnJlc3VsdCA9IHNvdXJjZTtcbiAgICBpZiAoIXNvdXJjZSkgcmV0dXJuIHRoaXM7XG4gICAgdGhpcy5yZXN1bHQgPSB0aGlzLnBhcnNlKHNvdXJjZSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICog6Kej5p6QIHNvdXJjZSDkuLroioLngrnmoJEuXG4gICAqIOiKgueCueexu+WeizpcbiAgICogICAxLiByb290ICAgIHttb2RlOidyb290Jywgbm9kZXN9XG4gICAqICAgMS4gY29tbWVudCB7bW9kZTonY29tbWVudCcsIHNvdXJjZX0g5Y+q5L+d55WZ6Z2e6KGM5bC+5rOo6YeKXG4gICAqICAgMS4gZGVjbCAgICB7bW9kZTonZGVjbCcsIHNvdXJjZSwga2V5LCB2YWx9XG4gICAqICAgMS4gcGVuZGluZyB7bW9kZTonJywgc291cmNlLCBub2Rlc31cbiAgICpcbiAgICog5Y2z5omA5pyJICFtb2RlIOeahOiKgueCuemcgOimgemAmui/h+e8luivkeaPkuS7tui/m+ihjOehruiupFxuICAgKiBAcGFyYW0gIHtzdHJpbmd9IHNvdXJjZSDmupDnoIFcbiAgICogQHJldHVybiB7b2JqZWN0fSByb290IOiKgueCueagkVxuICAgKi9cbiAgcGFyc2Uoc291cmNlKSB7XG4gICAgaWYgKHR5cGVvZiBzb3VyY2UgIT09ICdzdHJpbmcnKSByZXR1cm4gc291cmNlO1xuXG4gICAgbGV0IHJvb3QgPSB7XG4gICAgICAgICAgb2Zmc2V0OiAwLFxuICAgICAgICAgIGxpbmU6IDAsXG4gICAgICAgICAgY29sdW1uOiAwLFxuICAgICAgICAgIG1vZGU6ICdyb290JyxcbiAgICAgICAgICBub2RlczogW11cbiAgICAgICAgfSxcbiAgICAgICAgcGFyZW50ID0gcm9vdCxcbiAgICAgICAgc3RhY2sgPSBbXSxcbiAgICAgICAgaSA9IDAsXG4gICAgICAgIHRva2VucyA9IFtdLFxuICAgICAgICBsaW5lcyA9IGxpbmVpZnkoc291cmNlKSxcbiAgICAgICAgdG9rID0gbGluZXMuc2NhbigpLFxuICAgICAgICBhbGdpbiA9IHRvayAmJiB0b2suY29sdW1uIHx8IDE7XG5cbiAgICB3aGlsZSAodG9rKSB7XG4gICAgICB0b2tlbnMucHVzaCh0b2spO1xuICAgICAgdG9rID0gbGluZXMuc2NhbigpO1xuICAgIH1cblxuICAgIHdoaWxlIChpIDwgdG9rZW5zLmxlbmd0aCkge1xuICAgICAgdG9rID0gdG9rZW5zW2ldO1xuXG4gICAgICB3aGlsZSAodG9rLmNvbHVtbiA8PSBwYXJlbnQuY29sdW1uKSB7XG4gICAgICAgIHBhcmVudCA9IHN0YWNrLnBvcCgpO1xuICAgICAgICBhbGdpbiA9IHBhcmVudC5ub2Rlc1twYXJlbnQubm9kZXMubGVuZ3RoIC0gMV0uY29sdW1uO1xuICAgICAgfVxuXG4gICAgICAvLyDkvKDnu5/oirHmi6zlj7flnZfmoLzlvI9cbiAgICAgIGlmICh0b2suc291cmNlWzBdID09PSAnfScpIHtcbiAgICAgICAgbGV0IGxhc3QgPSBwYXJlbnQubm9kZXNbcGFyZW50Lm5vZGVzLmxlbmd0aCAtIDFdO1xuICAgICAgICBpZiAoIWxhc3Quc291cmNlLmVuZHNXaXRoKCd7JykpXG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKHV0aWwuaW5mbyhgVW5wYWlyZWQgYnJhY2tldHMgZnJvbSAke2xhc3QubGluZX06JHtsYXN0LmNvbHVtbn1gICwgdG9rKSk7XG4gICAgICAgIGxhc3Quc291cmNlID0gbGFzdC5zb3VyY2Uuc2xpY2UoMCwgLTEpLnRyaW1SaWdodCgpO1xuICAgICAgICBpKys7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBpZiAodG9rLmNvbHVtbiA+IGFsZ2luKSB7XG4gICAgICAgIGFsZ2luID0gdG9rLmNvbHVtbjtcbiAgICAgICAgdG9rLm5vZGVzID0gdG9rLm5vZGVzIHx8IFtdO1xuICAgICAgICBzdGFjay5wdXNoKHBhcmVudCk7XG4gICAgICAgIGlmICghcGFyZW50Lm5vZGVzLmxlbmd0aClcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IodXRpbC5pbmZvKCdQb3dDU1MgYnJva2VuJywgdG9rKSk7XG4gICAgICAgIHBhcmVudCA9IHBhcmVudC5ub2Rlc1twYXJlbnQubm9kZXMubGVuZ3RoIC0gMV07XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgaSsrO1xuICAgICAgcGFyZW50Lm5vZGVzLnB1c2godG9rKTtcblxuICAgICAgaWYgKHRvay5zb3VyY2Uuc3RhcnRzV2l0aCgnLy8nKSkge1xuICAgICAgICB0b2subW9kZSA9ICdjb21tZW50JztcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIGlmICh0b2suc291cmNlLnN0YXJ0c1dpdGgoJy8qJykpIHtcbiAgICAgICAgaWYgKHRvay5zb3VyY2UuZW5kc1dpdGgoJyovJykpXG4gICAgICAgICAgdG9rLm1vZGUgPSAnY29tbWVudCc7XG4gICAgICAgIGVsc2Ugd2hpbGUgKGkgPCB0b2tlbnMubGVuZ3RoKSB7XG4gICAgICAgICAgdG9rLnNvdXJjZSArPSAnXFxuJyArIHRva2Vuc1tpKytdLnNvdXJjZTtcbiAgICAgICAgICBpZiAodG9rLnNvdXJjZS5lbmRzV2l0aCgnKi8nKSkge1xuICAgICAgICAgICAgdG9rLm1vZGUgPSAnY29tbWVudCc7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRvay5tb2RlICE9PSAnY29tbWVudCcpXG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKHV0aWwuaW5mbygnVW5jbG9zZWQgY29tbWVudHMnLCB0b2spKTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIGxldCB0YWlsID0gdG9rLnNvdXJjZS5pbmRleE9mKCcgLy8nKTtcblxuICAgICAgLyoqXG4gICAgICAgKiDooYzlsL7ms6jph4rlv4Xpobvku6UgJyAvLycg5byA5aS0XG4gICAgICAgKi9cbiAgICAgIGlmICh0YWlsICE9PSAtMSlcbiAgICAgICAgdG9rLnNvdXJjZSA9IHRvay5zb3VyY2Uuc3Vic3RyaW5nKDAsIHRhaWwpLnRyaW0oKTtcblxuICAgICAgLyoqXG4gICAgICAgKiDlsZ7mgKflkI3lkozlgLzkuI3og73ku6UgJ0AnIOW8gOWktFxuICAgICAgICog5bGe5oCn5YiG6ZqU56ymICc6JyDkuYvlkI7lv4XpobvmmK/nqbrmoLzmiJbogIXmjaLooYwgYDpbIFxcbl1gXG4gICAgICAgKi9cbiAgICAgIGxldCBwb3MgPSB0b2suc291cmNlWzBdID09PSAnQCcgJiYgLTEgfHwgdG9rLnNvdXJjZS5pbmRleE9mKCc6JykgKyAxO1xuICAgICAgdG9rLm1vZGUgPSBwb3MgPiAwICYmXG4gICAgICAgIChwb3MgPT09IHRvay5zb3VyY2UubGVuZ3RoIHx8IHRvay5zb3VyY2VbcG9zXSA9PT0gJyAnKSAmJlxuICAgICAgICAnZGVjbCcgfHwgJyc7XG5cbiAgICAgIHRvay5ub2RlcyA9IFtdO1xuXG4gICAgICAvKipcbiAgICAgICAqIOe7reihjOespuWMheaLrCBgXFxcXCwrLS8qfD0oW2BcbiAgICAgICAqL1xuICAgICAgdGFpbCA9IENPTlRJTlVBVElPTi5pbmRleE9mKHRvay5zb3VyY2UuY2hhckF0KHRvay5zb3VyY2UubGVuZ3RoIC0gMSkpO1xuICAgICAgaWYgKHRhaWwgPT09IDEpXG4gICAgICAgIHRvay5zb3VyY2UgPSB0b2suc291cmNlLnNsaWNlKDAsIC0xKS50cmltKCk7XG4gICAgICBpZiAodGFpbCA+IDAgJiYgdG9rLm1vZGUgPT09ICcnIHx8XG4gICAgICAgIHRhaWwgIT09IC0xICYmIHRvay5tb2RlID09PSAnZGVjbCcpXG5cbiAgICAgIHdoaWxlIChpIDwgdG9rZW5zLmxlbmd0aCkge1xuICAgICAgICBsZXQgdCA9IHRva2Vuc1tpKytdO1xuICAgICAgICAvLyDkuI3mo4Dmn6XnvKnov5ssIOW/veeVpeazqOmHilxuICAgICAgICBpZiAodC5zb3VyY2Uuc3RhcnRzV2l0aCgnLy8nKSkgY29udGludWU7XG5cbiAgICAgICAgaWYgKHQuc291cmNlLnN0YXJ0c1dpdGgoJy8qJykpIHtcbiAgICAgICAgICB3aGlsZSAoIXQuc291cmNlLmVuZHNXaXRoKCcqLycpICYmXG4gICAgICAgICAgICBpIDwgdG9rZW5zLmxlbmd0aCkge1xuICAgICAgICAgICAgdCA9IHRva2Vuc1tpKytdO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRhaWwgPSB0LnNvdXJjZS5pbmRleE9mKCcgLy8nKTtcbiAgICAgICAgdG9rLnNvdXJjZSArPSB0YWlsID09PSAtMSAmJiB0LnNvdXJjZSB8fFxuICAgICAgICAgIHQuc291cmNlLnN1YnN0cmluZygwLCB0YWlsKS50cmltUmlnaHQoKTtcblxuICAgICAgICB0YWlsID0gQ09OVElOVUFUSU9OLmluZGV4T2YodG9rLnNvdXJjZS5jaGFyQXQodG9rLnNvdXJjZS5sZW5ndGggLSAxKSk7XG5cbiAgICAgICAgaWYgKHRhaWwgPT09IDEpXG4gICAgICAgICAgdG9rLnNvdXJjZSA9IHRvay5zb3VyY2Uuc2xpY2UoMCwgLTEpLnRyaW0oKTtcblxuICAgICAgICBpZiAodGFpbCA9PT0gLTEgfHwgdGFpbCA9PT0gMCAmJiB0b2subW9kZSA9PT0gJycpXG4gICAgICAgICAgYnJlYWs7XG4gICAgICB9XG5cbiAgICAgIGlmICh0b2subW9kZSA9PT0gJ2RlY2wnKSB7XG4gICAgICAgIHRvay5rZXkgPSB0b2suc291cmNlLnN1YnN0cmluZygwLCBwb3MgLSAxKS50cmltUmlnaHQoKTtcbiAgICAgICAgdG9rLnZhbCA9IHRvay5zb3VyY2Uuc3Vic3RyaW5nKHBvcykudHJpbUxlZnQoKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gcm9vdDtcbiAgfVxuXG4gIC8qKlxuICAgKiDmoLzlvI/ljJbovpPlh7ogcm9vdC5ub2Rlc1xuICAgKiBAcGFyYW0gIHtvYmplY3R9IHJvb3Qg6Kej5p6Q5ZCO55qE6IqC54K55qCRXG4gICAqIEByZXR1cm4ge3N0cmluZ30gQ1NTICDml6DoirHmi6zlj7fkuKTnqbrmoLznvKnov5vmoLzlvI9cbiAgICovXG4gIGZvcm1hdChyb290KSB7XG4gICAgbGV0IGZtdCA9ICcnLFxuICAgICAgICBzcCA9ICdcXG4nO1xuICAgIHRoaXMud2Fsayhyb290Lm5vZGVzLCBudWxsLCAobiwgYywgaSwgbnMpID0+IHtcbiAgICAgIGlmIChmbXQpIGZtdCArPSBzcDtcbiAgICAgIHN3aXRjaCAobi5tb2RlKSB7XG4gICAgICAgIGNhc2UgJ2NvbW1lbnQnOlxuICAgICAgICAgIGZtdCArPSBuLnNvdXJjZS5yZXBsYWNlKCdcXG4nLCBzcCArICcgJyk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgJ2RlY2wnOlxuICAgICAgICAgIGZtdCArPSBuLmtleSArICc6ICcgKyBuLnZhbDtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgZGVmYXVsdDogLy8gYmxvY2ssIHJ1bGVcbiAgICAgICAgICBmbXQgKz0gbi5zb3VyY2U7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBpZiAoIWkgJiYgbi5ub2RlcyAmJiBuLm5vZGVzLmxlbmd0aCkge1xuICAgICAgICBzcCArPSAnICAnO1xuICAgICAgfWVsc2UgaWYgKGkgJiYgaSArIDEgPT09IG5zLmxlbmd0aCkge1xuICAgICAgICBzcCA9IHNwLnNsaWNlKDAsIC0yKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIGZtdDtcbiAgfVxuXG4gIC8qKlxuICAgKiDpgY3ljoYgdGhpcy5yZXN1bHQg5omA5pyJ6IqC54K55ou85o6l57yW6K+R5o+S5Lu255qE57yW6K+R57uT5p6cLlxuICAgKiDmnKrooqvnvJbor5HnmoToioLngrnlkozlhbblrZDoioLngrnooqvmipvlvIMuXG4gICAqIEByZXR1cm4ge3N0cmluZ30gIGJvZHkg57yW6K+R5ZCO55qE5Ye95pWw5Li75L2T5Luj56CBO1xuICAgKi9cbiAgY29tcGlsZSgpIHtcbiAgICBsZXQgcm9vdCA9IHRoaXMucmVzdWx0LCBwbHVnaW5zID0gdGhpcy5wbHVnaW5zO1xuICAgIGlmICghcm9vdCB8fCByb290Lm1vZGUgIT0gJ3Jvb3QnKVxuICAgICAgcmV0dXJuICcnO1xuICAgIGxldCBjdHggPSB7Ym9keTogJyd9O1xuICAgIGxldCBjb21waWxlID0gKGl0ZW0sIGN0eCwgaW5kZXgsIG5vZGVzKSA9PiB7XG4gICAgICBsZXQgYm9keTtcbiAgICAgIHBsdWdpbnMuc29tZSgocGx1Z2luKSA9PiB7XG4gICAgICAgIGlmICh0eXBlb2YgcGx1Z2luLmNvbXBpbGUgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICBib2R5ID0gcGx1Z2luLmNvbXBpbGUoaXRlbSwgaW5kZXgsIG5vZGVzKTtcbiAgICAgICAgICByZXR1cm4gYm9keSAhPSBudWxsO1xuICAgICAgICB9fSk7XG5cbiAgICAgIGlmICghYm9keSB8fCBib2R5ID09PSAnICcpIHJldHVybiBmYWxzZTtcblxuICAgICAgbGV0IHBvcyA9IGJvZHkuaW5kZXhPZignLi4uJyk7XG5cbiAgICAgIGlmIChwb3MgIT09IC0xKSB7XG4gICAgICAgIGlmIChib2R5LmluZGV4T2YoJy4uLicsIHBvcyArIDEpICE9PSAtMSlcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IodXRpbC5pbmZvKCdOZXN0ZWQgcGxhY2Vob2xkZXJzIHRvbyBtdWNoJywgaXRlbSkpO1xuXG4gICAgICAgIGlmICghaXRlbS5ub2RlcyB8fCAhaXRlbS5ub2Rlcy5sZW5ndGgpXG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKHV0aWwuaW5mbygnTmVzdGVkIHBsYWNlaG9sZGVycyBjYW4gbm90IGJlIHVzZWQgZm9yIGVtcHR5IG5vZGVzJywgaXRlbSkpO1xuICAgICAgfVxuXG4gICAgICBpZiAoaXRlbS5ub2RlcyAmJiBpdGVtLm5vZGVzLmxlbmd0aCkge1xuICAgICAgICBsZXQgY2hpbGQgPSB7Ym9keTogJyd9O1xuICAgICAgICB0aGlzLndhbGsoaXRlbS5ub2RlcywgY2hpbGQsIGNvbXBpbGUpO1xuICAgICAgICBpZiAocG9zICE9PSAtMSlcbiAgICAgICAgICBib2R5ID0gYm9keS5zdWJzdHJpbmcoMCwgcG9zKSArIGNoaWxkLmJvZHkgKyBib2R5LnN1YnN0cmluZyhwb3MgKyAzKTtcbiAgICAgICAgZWxzZVxuICAgICAgICAgIGJvZHkgKz0gJ1xcbicgKyBjaGlsZC5ib2R5O1xuICAgICAgfVxuXG4gICAgICBjdHguYm9keSArPSBib2R5ICsgJ1xcbic7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfTtcblxuICAgIHRoaXMud2Fsayhyb290Lm5vZGVzLCBjdHgsIGNvbXBpbGUpO1xuICAgIHJldHVybiBjdHguYm9keTtcbiAgfVxuXG4gIC8qKlxuICAgKiDov5Tlm54gRnVuY3Rpb24ocGFyYW1zLCB0aGlzLmNvbXBpbGUodGhpcy5yZXN1bHQgKyAnO3JldHVybiAnKyBwYXJhbXMuc3BsaXQoJywnKVswXSkpXG4gICAqXG4gICAqIEBwYXJhbSAgez9zdHJpbmd9IHBhcmFtcyDlvaLlj4IsIOe8uuecgeS4uiAnY3R4J1xuICAgKiBAcmV0dXJuIHtvYmplY3R9ICBjdHhcbiAgICovXG4gIGJ1aWxkKHBhcmFtcykge1xuICAgIHBhcmFtcyA9IHBhcmFtcyB8fCAnY3R4JztcblxuICAgIHJldHVybiBGdW5jdGlvbiggLy8ganNoaW50IGlnbm9yZTpsaW5lXG4gICAgICAgIHBhcmFtcyxcbiAgICAgICAgdGhpcy5jb21waWxlKCkgKyAnO3JldHVybiAnICsgcGFyYW1zLnNwbGl0KCcsJylbMF1cbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIOWMheijhSBwcm9jZXNzLCBidWlsZCDlubbov5Tlm57miafooYznu5PmnpxcbiAgICogQHBhcmFtICB7c3RyaW5nfSAgc291cmNlIENTUyDmupDnoIFcbiAgICogQHBhcmFtICB7P3N0cmluZ30gcGFyYW1zIOW9ouWPgiwg57y655yB5Li6ICdjdHgnXG4gICAqIEBwYXJhbSAgez9hcnJheX0gIGFyZ3MgICDlrp7lj4IsIOe8uuecgeS4uiBbY29udGV4dCgpXVxuICAgKiBAcmV0dXJuIHtvYmplY3R9XG4gICAqL1xuICBydW4oc291cmNlLCBwYXJhbXMsIGFyZ3MpIHtcbiAgICByZXR1cm4gdGhpcy5wcm9jZXNzKHNvdXJjZSkuYnVpbGQocGFyYW1zKSguLi4oYXJncyB8fCBbY29udGV4dCgpXSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIOS9v+eUqCBub2Rlcy5mb3JFYWNoIOa3seW6pumBjeWOhuiKgueCueagkeW5tuiwg+eUqCBjYWxsYmFjayhpdGVtLCBjb250ZXh0LCBpbmRleCwgbm9kZXMpLlxuICAgKiDlpoLmnpwgY2FsbGJhY2sg6L+U5Zue6Z2e55yf5YC8LCBpdGVtLm5vZGVzIOWwhuS4jeWPguS4jumBjeWOhi5cbiAgICogQHBhcmFtICB7YXJyYXl9IG5vZGVzXG4gICAqIEBwYXJhbSAge09iamVjdH0gY29udGV4dCDkuIrkuIvmlodcbiAgICogQHBhcmFtICB7ZnVuY3Rpb24ob2JqZWN0LG9iamVjdCxudW1iZXIsYXJyYXkpOkJvb2xlYW59IGNhbGxiYWNrIOWbnuiwg+WHveaVsFxuICAgKiBAcmV0dXJuIHt0aGlzfVxuICAgKi9cbiAgd2Fsayhub2RlcywgY29udGV4dCwgY2FsbGJhY2spIHtcbiAgICBpZiAobm9kZXMgJiYgdHlwZW9mIG5vZGVzLmZvckVhY2ggPT09ICdmdW5jdGlvbicpXG4gICAgbm9kZXMuZm9yRWFjaCgoaXRlbSwgaW5kZXgpID0+IHtcbiAgICAgIGlmIChjYWxsYmFjayhpdGVtLCBjb250ZXh0LCBpbmRleCwgbm9kZXMpICYmIGl0ZW0ubm9kZXMpXG4gICAgICAgIHRoaXMud2FsayhpdGVtLm5vZGVzLCBjb250ZXh0LCBjYWxsYmFjayk7XG4gICAgfSwgdGhpcyk7XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uKHBsdWdpbnMpIHtcbiAgcmV0dXJuIG5ldyBQb3dDU1MocGx1Z2lucyk7XG59O1xuIl19
// powcss demonstration
const powcss=require('powcss');
let pre = document.createElement('pre');
pre.textContent = powcss([]).run(
`
let /**/
rem=(px) => px/16 +'rem', /*Line-Continuation*/
spacing=(tracking)=>tracking/12 +'rem',
cols = [1,2,3,4].join(',.col-')
.col-\${cols}
display: block
letter-spacing: \${spacing(-1.5)}
`
).toCSS();
document.body.append(pre);
;}, 0)
{
"name": "requirebin-sketch",
"version": "1.0.0",
"dependencies": {
"powcss": "1.0.5"
}
}
<!-- contents of this file will be placed inside the <body> -->
<!-- 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