"use babel";
var app = angular.module('plunker', [
'scheming',
'ui.dropdown'
]);
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<link rel="stylesheet" href="button.css" />
<link rel="stylesheet" href="dropdown.css" />
<script src="https://code.angularjs.org/1.4.3/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>
<script src="scheming.js"></script>
<script src="scheming-angular.js"></script>
<script src="app.js"></script>
<script src="dropdown.js"></script>
</head>
<body>
<h4>Static Options</h4>
<ui-dropdown
ui-dropdown-options="['Option A','Option B','Option C']"
ng-model="selected"
></ui-dropdown>
<div>
Selected value: {{ selected }}
</div>
<h4>Dynamic Options</h4>
<ui-dropdown
ui-dropdown-dynamic-options
ui-dropdown-dynamic-options-prefix="foo"
ng-model="dynamic1"
></ui-dropdown>
<div>
Selected value: {{ dynamic1 }}
</div>
</body>
</html>
/* Put your css in here */
"use babel";
var DropdownModel = Scheming.create({
display: {
type: String,
default: null
},
placeholder: {
type: String,
default: 'Please Select'
},
intent: {
type: '*',
default: null
},
options: {
type: ['*'],
default: []
},
isOpened: {
type: Boolean,
default: false
},
isFocused: {
type: Boolean,
default: false
}
});
class DropdownController {
constructor (uiDropdownModel) {
if (!this.model) {
this.model = new uiDropdownModel();
}
}
setOptions (options = []) {
this.model.options = options;
}
selectItem (item) {
this.model.display = item;
this.close();
}
isIntent (item) {
return item === this.model.intent;
}
setIntent (item) {
this.model.intent = item;
}
focus () {
this.model.isFocused = true;
this.open();
}
blur () {
this.model.isFocused = false;
this.close();
}
open () {
this.model.isOpened = true;
}
close () {
this.model.isOpened = false;
}
}
function DropdownComponent () {
return {
restrict: 'E',
scope: {
model: '=uiDropdownModel'
},
controller: 'uiDropdownController',
controllerAs: 'dropdown',
bindToController: true,
require: ['uiDropdown', '?ngModel'],
template: `
<button
ui-dropdown-button
type="button"
class="ui button selected"
ng-disabled="dropdown.model.isDisabled"
ng-class="{focus: dropdown.model.isFocused}"
>
{{ dropdown.model.display || dropdown.model.placeholder }}
</button>
<div class="options-container" ng-if="dropdown.model.isOpened">
<ul class="options">
<li
class="option"
ng-repeat="item in dropdown.model.options"
ng-mouseover="dropdown.setIntent(item)"
ng-class="{intent: dropdown.isIntent(item)}"
ng-click="dropdown.selectItem(item)"
>
{{item}}
</li>
</ul>
</div>
`,
link: {
pre: function ($scope, $element, $attrs, [dropdown, ngModel]) {
// ngModel - only two-way data-binding allowed
if (ngModel) {
ngModel.$render = function () {
dropdown.selectItem(ngModel.$viewValue);
};
$scope.schemingWatch(dropdown.model, 'display', function (value, oldValue) {
if (value !== oldValue) {
// tell ngModel about a change only if there is one
ngModel.$setViewValue(value);
}
});
// observed view properties
$scope.schemingWatch(dropdown.model, ['isOpened', 'isFocused', 'options'], function () {
$scope.$digest();
});
}
},
post: function ($scope, $element, $attrs, [dropdown, ngModel]) {
$element.on('mousedown', (event) => {
// prevent unintended focus changes
event.preventDefault();
});
}
}
};
}
// helper directive for button events - not a component because 'button' has semantic meaning in HTML...
function DropdownButton () {
return {
restrict: 'A',
require: '^^uiDropdown',
link: function ($scope, $element, $attrs, dropdown) {
// events
$element.on('focus', (event) => {
dropdown.focus();
});
$element.on('blur', (event) => {
dropdown.blur();
});
$element.on('click', (event) => {
if (!dropdown.model.isOpened) {
dropdown.focus();
}
});
$element.on('mousedown', (event) => {
event.preventDefault(); // force button focus
if (!dropdown.model.isOpened) {
$element[0].focus();
}
});
}
}
}
function DropdownOptionsDecorator () {
return {
restrict: 'A',
require: 'uiDropdown',
link: {
pre: function ($scope, $element, $attrs, dropdown) {
$scope.$watchCollection($attrs.uiDropdownOptions, function (options) {
if (options) {
dropdown.setOptions(options);
}
});
}
}
}
}
// Note: This type of decorator would exist in the application
function DropdownDynamicOptionsDecorator ($timeout) {
return {
restrict: 'A',
require: 'uiDropdown',
link: {
pre: function ($scope, $element, $attrs, dropdown) {
$scope.schemingWatch(dropdown.model, 'isOpened', function (isOpened) {
if (isOpened) {
$timeout(function () {
dropdown.setOptions(['a','b','c'].map((o) => $attrs.uiDropdownDynamicOptionsPrefix + ' ' + o));
}, 50, false);
} else {
dropdown.setOptions([]);
}
});
}
}
}
}
angular.module('ui.dropdown', [])
.constant('uiDropdownModel', DropdownModel)
.controller('uiDropdownController', DropdownController)
.directive('uiDropdown', DropdownComponent)
.directive('uiDropdownButton', DropdownButton)
.directive('uiDropdownOptions', DropdownOptionsDecorator)
.directive('uiDropdownDynamicOptions', DropdownDynamicOptionsDecorator)
;
ui-dropdown {
display: inline-block;
position: relative;
vertical-align: middle;
.selected {
display: block;
width: 100%;
text-align: left;
&:after {
content: '\25bc';
font-size: 0.7em;
}
}
.options-container {
position: absolute;
min-width: 100%;
z-index: 1;
}
.options {
position: relative;
list-style: none;
margin: 0;
padding: 0;
}
.option {
cursor: pointer;
padding: 3px 20px 3px 10px;
background: #ddd;
line-height: 1.5;
border-top: 1px solid #ccc;
&.intent {
background: #ccc;
}
}
}
.ui.button {
cursor: pointer;
display: inline-block;
box-sizing: border-box;
padding: 5px 20px;
border-radius: 3px;
background: hsl(0, 0%, 85%);
border: 1px solid hsl(0, 0%, 75%);
&:hover {
border-color: hsl(0, 0%, 95%);
}
}
;(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);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.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){
var ChangeManager, _,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
_ = (window._);
ChangeManager = (function() {
ChangeManager.prototype.THROTTLE = {
TIMEOUT: 'timeout',
IMMEDIATE: 'immediate',
ANIMATION_FRAME: 'animationFrame'
};
ChangeManager.prototype.ITERATION_LIMIT = 100;
function ChangeManager() {
this.resolve = bind(this.resolve, this);
this.flush = bind(this.flush, this);
this.getQueuedChanges = bind(this.getQueuedChanges, this);
this.queueChanges = bind(this.queueChanges, this);
this.reset = bind(this.reset, this);
this.cleanupCycle = bind(this.cleanupCycle, this);
this.unregisterResolveCallback = bind(this.unregisterResolveCallback, this);
this.registerResolveCallback = bind(this.registerResolveCallback, this);
this.unregisterQueueCallback = bind(this.unregisterQueueCallback, this);
this.registerQueueCallback = bind(this.registerQueueCallback, this);
this.setThrottle = bind(this.setThrottle, this);
this.changes = {};
this.internalChangeQueue = [];
this.timeout = null;
this.recursionCount = 0;
this.setThrottle(this.THROTTLE.TIMEOUT);
this._activeClearTimeout = null;
this._queueCallback = null;
this._resolveCallback = null;
}
ChangeManager.prototype.setThrottle = function(throttle) {
if (!_.contains(this.THROTTLE, throttle)) {
throw new Error("Throttle option must be set to one of the strategies specified on Scheming.THROTTLE");
}
switch (throttle) {
case this.THROTTLE.TIMEOUT:
this.setTimeout = (function(_this) {
return function() {
return _this.timeout != null ? _this.timeout : _this.timeout = setTimeout(_this.resolve, 0);
};
})(this);
return this.clearTimeout = (function(_this) {
return function() {
clearTimeout(_this.timeout);
return _this.timeout = null;
};
})(this);
case this.THROTTLE.IMMEDIATE:
if ((typeof setImmediate !== "undefined" && setImmediate !== null) && (typeof clearImmediate !== "undefined" && clearImmediate !== null)) {
this.setTimeout = (function(_this) {
return function() {
return _this.timeout != null ? _this.timeout : _this.timeout = setImmediate(_this.resolve);
};
})(this);
return this.clearTimeout = (function(_this) {
return function() {
clearImmediate(_this.timeout);
return _this.timeout = null;
};
})(this);
} else {
console.warn("Cannot use strategy IMMEDIATE: `setImmediate` or `clearImmediate` are not available in the current environment.");
return this.setThrottle(this.THROTTLE.TIMEOUT);
}
break;
case this.THROTTLE.ANIMATION_FRAME:
if ((typeof requestAnimationFrame !== "undefined" && requestAnimationFrame !== null) && (typeof cancelAnimationFrame !== "undefined" && cancelAnimationFrame !== null)) {
this.setTimeout = (function(_this) {
return function() {
return _this.timeout != null ? _this.timeout : _this.timeout = requestAnimationFrame(_this.resolve);
};
})(this);
return this.clearTimeout = (function(_this) {
return function() {
cancelAnimationFrame(_this.timeout);
return _this.timeout = null;
};
})(this);
} else {
console.warn("Cannot use strategy ANIMATION_FRAME: `requestAnimationFrame` or `cancelAnimationFrame` are not available in the current environment.");
return this.setThrottle(this.THROTTLE.TIMEOUT);
}
}
};
ChangeManager.prototype.setTimeout = function() {
throw new Error("A throttle strategy must be set.");
};
clearTimeout(function() {
throw new Error("A throttle strategy must be set.");
});
ChangeManager.prototype.registerQueueCallback = function(callback) {
if (!_.isFunction(callback)) {
throw new Error("Callback must be a function");
}
return this._queueCallback = callback;
};
ChangeManager.prototype.unregisterQueueCallback = function() {
return this._queueCallback = null;
};
ChangeManager.prototype.registerResolveCallback = function(callback) {
if (!_.isFunction(callback)) {
throw new Error("Callback must be a function");
}
return this._resolveCallback = callback;
};
ChangeManager.prototype.unregisterResolveCallback = function() {
return this._resolveCallback = null;
};
ChangeManager.prototype.cleanupCycle = function() {
this.changes = {};
this.internalChangeQueue = [];
if (typeof this._activeClearTimeout === "function") {
this._activeClearTimeout();
}
return this.recursionCount = 0;
};
ChangeManager.prototype.reset = function() {
this.changes = {};
this.internalChangeQueue = [];
if (typeof this._activeClearTimeout === "function") {
this._activeClearTimeout();
}
this.timeout = null;
this.recursionCount = 0;
this.setThrottle(this.THROTTLE.TIMEOUT);
this._queueCallback = null;
return this._resolveCallback = null;
};
ChangeManager.prototype.queueChanges = function(arg, fireWatchers) {
var base, changedProps, equals, force, id, newVal, oldVal, propName;
id = arg.id, propName = arg.propName, oldVal = arg.oldVal, newVal = arg.newVal, equals = arg.equals, force = arg.force;
if (!_.has(this.changes, id)) {
if ((base = this.changes)[id] == null) {
base[id] = {
changedProps: {},
fireWatchers: fireWatchers
};
}
this.internalChangeQueue.push(id);
}
changedProps = this.changes[id].changedProps;
if (propName) {
if (_.has(changedProps, propName) && equals(changedProps[propName], newVal)) {
delete changedProps[propName];
} else if (force || (!_.has(changedProps, propName) && !equals(oldVal, newVal))) {
changedProps[propName] = oldVal;
}
}
if (this.timeout == null) {
if (typeof this._queueCallback === "function") {
this._queueCallback();
}
this.setTimeout();
return this._activeClearTimeout = this.clearTimeout;
}
};
ChangeManager.prototype.getQueuedChanges = function(arg) {
var id, propName, ref;
id = arg.id, propName = arg.propName;
return (ref = this.changes[id]) != null ? ref.changedProps[propName] : void 0;
};
ChangeManager.prototype.flush = function() {
return this.resolve();
};
ChangeManager.prototype.resolve = function() {
var changedProps, changes, fireWatchers, i, id, internalChanges, len, ref, ref1;
this.recursionCount++;
if (this.ITERATION_LIMIT > 0 && this.recursionCount > this.ITERATION_LIMIT) {
changes = this.changes;
this.cleanupCycle();
throw new Error("Aborting change propagation after " + this.ITERATION_LIMIT + " cycles.\nThis is probably indicative of a circular watch. Check the following watches for clues:\n" + (JSON.stringify(changes)));
}
internalChanges = _.unique(this.internalChangeQueue);
this.internalChangeQueue = [];
for (i = 0, len = internalChanges.length; i < len; i++) {
id = internalChanges[i];
ref = this.changes[id], changedProps = ref.changedProps, fireWatchers = ref.fireWatchers;
fireWatchers(changedProps, 'internal');
}
if (this.internalChangeQueue.length) {
return this.resolve();
}
changes = this.changes;
this.changes = {};
for (id in changes) {
ref1 = changes[id], changedProps = ref1.changedProps, fireWatchers = ref1.fireWatchers;
fireWatchers(changedProps, 'external');
}
if (_.size(this.changes) > 0) {
return this.resolve();
}
if (typeof this._resolveCallback === "function") {
this._resolveCallback();
}
return this.cleanupCycle();
};
return ChangeManager;
})();
module.exports = new ChangeManager();
},{}],2:[function(require,module,exports){
var _;
_ = window._;
window.Scheming = require('./Scheming');
},{"./Scheming":6}],3:[function(require,module,exports){
var ChangeManager, InstanceFactory, Types, _,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
slice = [].slice;
_ = (window._);
Types = require('./Types');
ChangeManager = require('./ChangeManager');
InstanceFactory = (function() {
function InstanceFactory() {
this.create = bind(this.create, this);
this.uuid = bind(this.uuid, this);
}
InstanceFactory.prototype.ARRAY_MUTATORS = ['copyWithin', 'fill', 'push', 'pop', 'reverse', 'shift', 'sort', 'splice', 'unshift'];
InstanceFactory.prototype.uuid = function() {
var now;
now = Date.now();
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r;
r = (now + Math.random() * 16) % 16 | 0;
now = Math.floor(now / 16);
return (c === "x" ? r : r & 0x3 | 0x8).toString(16);
});
};
InstanceFactory.prototype.create = function(instance, normalizedSchema, initialState, opts) {
var _initializing, addWatcher, data, fireWatchers, fn, get, id, propConfig, propName, removeWatcher, seal, set, strict, unwatchers, val, watchForPropagation, watchers;
_initializing = true;
data = {};
watchers = {
internal: [],
external: []
};
unwatchers = {};
id = this.uuid();
strict = opts.strict, seal = opts.seal;
set = (function(_this) {
return function(propName, val) {
var prevVal, ref, setter, type;
prevVal = data[propName];
if (!normalizedSchema[propName]) {
return instance[propName] = val;
}
ref = normalizedSchema[propName], type = ref.type, setter = ref.setter;
if (val != null) {
if (setter) {
val = setter.call(instance, val);
}
if (!type.identifier(val)) {
if (strict) {
throw new Error("Error assigning " + val + " to " + propName + ". Value is not of type " + type.string);
}
val = type.parser(val);
}
if (type.string === Types.NESTED_TYPES.Array.string) {
val = type.childParser(val);
Object.defineProperty(val, '_arrayId', {
configurable: true,
value: _this.uuid()
});
_.each(_this.ARRAY_MUTATORS, function(method) {
if ((prevVal != null) && prevVal[method]) {
delete prevVal[method];
}
if (Array.prototype[method] != null) {
return Object.defineProperty(val, method, {
configurable: true,
writable: true,
value: function() {
var clone, ref1, toReturn;
clone = _.clone(this);
toReturn = (ref1 = Array.prototype[method]).call.apply(ref1, [this].concat(slice.call(arguments)));
ChangeManager.queueChanges({
id: id,
propName: propName,
oldVal: clone,
newVal: val,
equals: type.equals
}, fireWatchers);
instance[propName] = this;
return toReturn;
}
});
}
});
}
}
data[propName] = val;
watchForPropagation(propName, val);
if (!_initializing) {
return ChangeManager.queueChanges({
id: id,
propName: propName,
oldVal: prevVal,
newVal: val,
equals: type.equals
}, fireWatchers);
}
};
})(this);
get = function(propName) {
var getter, val;
getter = normalizedSchema[propName].getter;
val = data[propName];
if (getter) {
val = getter.call(instance, val);
}
return val;
};
addWatcher = function(properties, cb, opts) {
var j, len, propName, target, watcher;
if (_.isFunction(properties)) {
opts = cb;
cb = properties;
properties = _.keys(normalizedSchema);
}
if (opts == null) {
opts = {};
}
if (opts.internal == null) {
opts.internal = false;
}
target = opts.internal ? 'internal' : 'external';
if (!_.isFunction(cb)) {
throw new Error('A watch must be provided with a callback function.');
}
if (properties && !_.isArray(properties)) {
properties = [properties];
}
for (j = 0, len = properties.length; j < len; j++) {
propName = properties[j];
if (!_.has(normalizedSchema, propName)) {
throw new Error("Cannot set watch on " + propName + ", property is not defined in schema.");
}
}
watcher = {
properties: properties,
cb: cb,
first: !opts.internal
};
watchers[target].push(watcher);
ChangeManager.queueChanges({
id: id
}, fireWatchers);
return function() {
return removeWatcher(watcher, target);
};
};
removeWatcher = function(watcher, target) {
return _.remove(watchers[target], watcher);
};
watchForPropagation = function(propName, val) {
var j, len, ref, type, unwatcher;
type = normalizedSchema[propName].type;
if (type.string === Types.NESTED_TYPES.Schema.string) {
if (typeof unwatchers[propName] === "function") {
unwatchers[propName]();
}
unwatchers[propName] = val != null ? val.watch(function(newVal, oldVal) {
return ChangeManager.queueChanges({
id: id,
propName: propName,
oldVal: oldVal,
newVal: newVal,
equals: type.equals
}, fireWatchers);
}, {
internal: true
}) : void 0;
}
if (type.string === Types.NESTED_TYPES.Array.string && type.childType.string === Types.NESTED_TYPES.Schema.string) {
ref = unwatchers[propName] || [];
for (j = 0, len = ref.length; j < len; j++) {
unwatcher = ref[j];
if (typeof unwatcher === "function") {
unwatcher();
}
}
unwatchers[propName] = [];
return _.each(val, function(schema, i) {
return unwatchers[propName].push(schema != null ? schema.watch(function(newVal, oldVal) {
var newArray, oldArray;
newArray = instance[propName];
oldArray = ChangeManager.getQueuedChanges({
id: id,
propName: propName
});
if (oldArray == null) {
if (oldArray == null) {
oldArray = _.clone(newArray);
}
Object.defineProperty(oldArray, '_arrayId', {
configurable: true,
value: newArray._arrayId
});
}
if (oldArray._arrayId === newArray._arrayId) {
oldArray[i] = oldVal;
return ChangeManager.queueChanges({
id: id,
propName: propName,
oldVal: oldArray,
newVal: newArray,
equals: type.equals,
force: true
}, fireWatchers);
}
}, {
internal: true
}) : void 0);
});
}
};
fireWatchers = function(queuedChanges, target) {
var e, getPrevVal, i, j, len, newVals, oldVals, propName, ref, results, shouldFire, triggeringProperties, watcher;
if (target == null) {
target = 'external';
}
triggeringProperties = _.keys(queuedChanges);
getPrevVal = function(propName) {
if (_.has(queuedChanges, propName)) {
return queuedChanges[propName];
} else {
return instance[propName];
}
};
i = 0;
results = [];
while ((watcher = watchers[target][i])) {
i++;
shouldFire = watcher.first || (_.intersection(triggeringProperties, watcher.properties).length > 0);
watcher.first = false;
if (shouldFire) {
newVals = {};
oldVals = {};
ref = watcher.properties;
for (j = 0, len = ref.length; j < len; j++) {
propName = ref[j];
newVals[propName] = instance[propName];
oldVals[propName] = getPrevVal(propName);
}
if (watcher.properties.length === 1) {
propName = watcher.properties[0];
newVals = newVals[propName];
oldVals = oldVals[propName];
}
try {
results.push(watcher.cb(newVals, oldVals));
} catch (_error) {
e = _error;
results.push(console.error(e.stack || e));
}
} else {
results.push(void 0);
}
}
return results;
};
Object.defineProperty(instance, 'watch', {
configurable: false,
enumerable: false,
writable: false,
value: function(properties, cb, opts) {
return addWatcher(properties, cb, opts);
}
});
Object.defineProperty(instance, '_validating', {
configurable: false,
enumerable: false,
writable: true,
value: false
});
fn = (function(_this) {
return function(propName, propConfig) {
var val;
Object.defineProperty(instance, propName, {
configurable: false,
enumerable: true,
set: function(val) {
return set(propName, val);
},
get: function() {
return get(propName);
}
});
if (propConfig["default"] !== void 0) {
val = _.isFunction(propConfig["default"]) ? propConfig["default"]() : propConfig["default"];
return instance[propName] = val;
}
};
})(this);
for (propName in normalizedSchema) {
propConfig = normalizedSchema[propName];
fn(propName, propConfig);
}
if (seal) {
Object.seal(instance);
}
for (propName in initialState) {
val = initialState[propName];
instance[propName] = val;
}
return _initializing = false;
};
return InstanceFactory;
})();
module.exports = new InstanceFactory();
},{"./ChangeManager":1,"./Types":7}],4:[function(require,module,exports){
var InstanceFactory, ModelFactory, Registry, Types, _,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
slice = [].slice;
_ = (window._);
Types = require('./Types');
InstanceFactory = require('./InstanceFactory');
Registry = require('./Registry');
ModelFactory = (function() {
ModelFactory.prototype.DEFAULT_OPTIONS = {
seal: false,
strict: false
};
function ModelFactory() {
this.create = bind(this.create, this);
this.nameFunction = bind(this.nameFunction, this);
this.normalizePropertyConfig = bind(this.normalizePropertyConfig, this);
this.generateName = bind(this.generateName, this);
this.nameCounter = 0;
}
ModelFactory.prototype.generateName = function() {
return "SchemingModel" + (this.nameCounter++);
};
/*
Normalizes a field declaration on a schema to capture type, default value, setter, getter, and validation.
Used internally when a schema is created to build a normalized schema definition.
*/
ModelFactory.prototype.normalizePropertyConfig = function(propConfig, propName) {
var definition, fn, getter, j, len, required, setter, type, validate;
if (propName == null) {
propName = 'field';
}
definition = {
type: null,
"default": null,
getter: null,
setter: null,
validate: null,
required: false
};
if (!(_.isPlainObject(propConfig) && (propConfig.type != null))) {
propConfig = {
type: propConfig
};
}
type = propConfig.type, getter = propConfig.getter, setter = propConfig.setter, validate = propConfig.validate, required = propConfig.required;
if (type == null) {
throw new Error("Error resolving " + propName + ". Schema type must be defined.");
}
if ((getter != null) && !_.isFunction(getter)) {
throw new Error("Error resolving " + propName + ". Schema getter must be a function.");
}
if ((setter != null) && !_.isFunction(setter)) {
throw new Error("Error resolving " + propName + ". Schema setter must be a function.");
}
if (validate == null) {
validate = [];
}
if (!_.isArray(validate)) {
validate = [validate];
}
for (j = 0, len = validate.length; j < len; j++) {
fn = validate[j];
if (!_.isFunction(fn)) {
throw new Error("Error resolving " + propName + ". Schema validate must be a function or array of functions.");
}
}
definition.type = Types.resolveType(type);
if (definition.type == null) {
throw new Error("Error resolving " + propName + ". Unrecognized type " + type);
}
definition["default"] = propConfig["default"];
definition.getter = getter;
definition.setter = setter;
definition.validate = validate;
definition.required = required;
definition = _.extend({}, propConfig, definition);
return definition;
};
ModelFactory.prototype.nameFunction = function(name, fn) {
var err, fnStr, renamed;
fnStr = "return function " + name + "(){return fn.apply(this, arguments)}";
try {
renamed = new Function('fn', fnStr)(fn);
} catch (_error) {
err = _error;
throw new Error(name + " is not a valid function name.");
}
_.extend(renamed, fn);
_.extend(renamed.prototype, fn.prototype);
return renamed;
};
ModelFactory.prototype.create = function() {
var Model, args, factory, name, normalizedSchema, opts, schemaConfig;
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
factory = this;
if (!_.isString(args[0])) {
args.unshift(this.generateName());
}
name = args[0], schemaConfig = args[1], opts = args[2];
opts = _.defaults(opts || {}, this.DEFAULT_OPTIONS);
normalizedSchema = {};
Model = (function() {
Model.__schemaId = name;
Model.defineProperty = function(propName, propConfig) {
if (!_.isString(propName)) {
throw new Error("First argument: property name must be a string.");
}
if (propConfig == null) {
throw new Error("Second argument: property configuration is required.");
}
return normalizedSchema[propName] = factory.normalizePropertyConfig(propConfig, propName);
};
Model.defineProperties = function(config) {
var k, results, v;
if (!_.isPlainObject(config)) {
throw new Error("First argument: properties must be an object.");
}
results = [];
for (k in config) {
v = config[k];
results.push(this.defineProperty(k, v));
}
return results;
};
Model.getProperties = function() {
return _.cloneDeep(normalizedSchema);
};
Model.getProperty = function(propName) {
return _.cloneDeep(normalizedSchema[propName]);
};
Model.eachProperty = function(cb) {
var propConfig, propName, results;
if (!_.isFunction(cb)) {
throw new Error("First argument: callback must be a function.");
}
results = [];
for (propName in normalizedSchema) {
propConfig = normalizedSchema[propName];
results.push(cb(propName, _.cloneDeep(propConfig)));
}
return results;
};
Model.validate = function(instance) {
var childErrors, e, err, errors, i, j, k, key, l, len, len1, member, pushError, required, requiredMessage, type, v, val, validate, validator, value;
errors = {};
if (instance._validating) {
return null;
}
instance._validating = true;
pushError = function(key, error) {
var err, j, len;
if (_.isArray(error)) {
for (j = 0, len = error.length; j < len; j++) {
err = error[j];
return pushError(key, err);
}
}
if (!_.isString(error)) {
error = 'Validation error occurred.';
}
if (errors[key] == null) {
errors[key] = [];
}
return errors[key].push(error);
};
for (key in normalizedSchema) {
value = normalizedSchema[key];
validate = value.validate, required = value.required;
val = instance[key];
if (required && (val == null)) {
requiredMessage = _.isString(required) ? required : "Field is required.";
pushError(key, requiredMessage);
}
if (val != null) {
type = normalizedSchema[key].type;
for (j = 0, len = validate.length; j < len; j++) {
validator = validate[j];
err = true;
try {
err = validator.call(instance, val);
} catch (_error) {
e = _error;
if (e) {
err = e.message;
}
}
if (err !== true) {
pushError(key, err);
}
}
if (type.string === 'schema') {
childErrors = type.childType.validate.call(instance, val);
for (k in childErrors) {
v = childErrors[k];
pushError(key + "." + k, v);
}
}
if (type.string === 'array' && type.childType.string === 'schema') {
for (i = l = 0, len1 = val.length; l < len1; i = ++l) {
member = val[i];
childErrors = type.childType.childType.validate.call(instance, member);
for (k in childErrors) {
v = childErrors[k];
pushError(key + "[" + i + "]." + k, v);
}
}
}
}
}
instance._validating = false;
if (_.size(errors) === 0) {
return null;
} else {
return errors;
}
};
function Model(initialState) {
InstanceFactory.create(this, normalizedSchema, initialState, opts);
}
return Model;
})();
Model = this.nameFunction(name, Model);
if (schemaConfig != null) {
Model.defineProperties(schemaConfig);
}
Registry.register(name, Model);
return Model;
};
return ModelFactory;
})();
module.exports = new ModelFactory();
},{"./InstanceFactory":3,"./Registry":5,"./Types":7}],5:[function(require,module,exports){
var Registry,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
Registry = (function() {
function Registry() {
this.reset = bind(this.reset, this);
this.get = bind(this.get, this);
this.register = bind(this.register, this);
this.schemas = {};
}
Registry.prototype.register = function(name, model) {
if (this.schemas[name]) {
throw new Error("Naming conflict encountered. Model " + name + " already exists");
}
return this.schemas[name] = model;
};
Registry.prototype.get = function(name) {
return this.schemas[name];
};
Registry.prototype.reset = function() {
return this.schemas = {};
};
return Registry;
})();
module.exports = new Registry();
},{}],6:[function(require,module,exports){
var ChangeManager, DEFAULT_OPTIONS, InstanceFactory, ModelFactory, NESTED_TYPES, Registry, Scheming, THROTTLE, TYPES, Types, create, flush, get, normalizePropertyConfig, registerQueueCallback, registerResolveCallback, reset, resolveType, setThrottle, unregisterQueueCallback, unregisterResolveCallback, uuid;
Types = require('./Types');
Registry = require('./Registry');
ChangeManager = require('./ChangeManager');
ModelFactory = require('./ModelFactory');
InstanceFactory = require('./InstanceFactory');
TYPES = Types.TYPES, NESTED_TYPES = Types.NESTED_TYPES, resolveType = Types.resolveType;
THROTTLE = ChangeManager.THROTTLE, setThrottle = ChangeManager.setThrottle, registerQueueCallback = ChangeManager.registerQueueCallback, unregisterQueueCallback = ChangeManager.unregisterQueueCallback, registerResolveCallback = ChangeManager.registerResolveCallback, unregisterResolveCallback = ChangeManager.unregisterResolveCallback, flush = ChangeManager.flush;
DEFAULT_OPTIONS = ModelFactory.DEFAULT_OPTIONS, normalizePropertyConfig = ModelFactory.normalizePropertyConfig, create = ModelFactory.create;
uuid = InstanceFactory.uuid;
get = Registry.get, reset = Registry.reset;
reset = function() {
Registry.reset();
return ChangeManager.reset();
};
Scheming = {
TYPES: TYPES,
NESTED_TYPES: NESTED_TYPES,
DEFAULT_OPTIONS: DEFAULT_OPTIONS,
THROTTLE: THROTTLE,
uuid: uuid,
get: get,
reset: reset,
resolveType: resolveType,
normalizePropertyConfig: normalizePropertyConfig,
setThrottle: setThrottle,
registerQueueCallback: registerQueueCallback,
unregisterQueueCallback: unregisterQueueCallback,
registerResolveCallback: registerResolveCallback,
unregisterResolveCallback: unregisterResolveCallback,
flush: flush,
create: create
};
module.exports = Scheming;
},{"./ChangeManager":1,"./InstanceFactory":3,"./ModelFactory":4,"./Registry":5,"./Types":7}],7:[function(require,module,exports){
var Types, _,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
_ = (window._);
Types = (function() {
function Types() {
this.resolveType = bind(this.resolveType, this);
this.resolveSchemaType = bind(this.resolveSchemaType, this);
this.getPrimitiveTypeOf = bind(this.getPrimitiveTypeOf, this);
}
/*
Scheming exports the default types that it uses for parsing schemas. You can extend with custom types, or
override the identifier / parser functions of the default types. A custom type should provide:
- ctor (optional) - Used in schema definitions to declare a type. `Scheming.create name : String`
- string - Used in schema definitions to declare a type. `Scheming.create name : 'string'`
- identifier - Function, returns true or false. Determines whether a value needs to be parsed.
- parser - Function, parses a value into the type.
*/
Types.prototype.TYPES = {
String: {
ctor: String,
string: 'string',
identifier: _.isString,
parser: function(val) {
return '' + val;
},
equals: function(a, b) {
return a === b;
}
},
Number: {
ctor: Number,
string: 'number',
identifier: _.isNumber,
parser: parseFloat,
comparator: function(a, b) {
return a === b;
},
equals: function(a, b) {
return a === b;
}
},
Integer: {
string: 'integer',
identifier: function(val) {
return _.isNumber(val) && val % 1 === 0;
},
parser: parseInt,
equals: function(a, b) {
return a === b;
}
},
Date: {
ctor: Date,
string: 'date',
identifier: _.isDate,
parser: function(val) {
return new Date(val);
},
equals: function(a, b) {
return (a != null ? a.valueOf() : void 0) === (b != null ? b.valueOf() : void 0);
}
},
Boolean: {
ctor: Boolean,
string: 'boolean',
identifier: _.isBoolean,
parser: function(val) {
return !!val;
},
equals: function(a, b) {
return a === b;
}
},
Mixed: {
ctor: function(val) {
return val;
},
string: '*',
identifier: function() {
return true;
},
parser: _.identity,
equals: function(a, b) {
return a === b;
}
}
};
/*
Special type definitions for nested types. Used to identify and parse nested Arrays and Schemas.
Should not be extended or overridden.
*/
Types.prototype.NESTED_TYPES = {
Array: {
ctor: Array,
string: 'array',
identifier: _.isArray,
parser: _.toArray,
childType: null,
childParser: null,
equals: function(a, b) {
return _.isEqual(a, b);
}
},
Schema: {
ctor: Object,
string: 'schema',
identifier: null,
parser: null,
childType: null,
equals: function(a, b) {
return a === b;
}
}
};
Types.prototype.getPrimitiveTypeOf = function(type) {
var TYPE, k, ref;
ref = this.TYPES;
for (k in ref) {
TYPE = ref[k];
if (type === TYPE || (TYPE.ctor && type === TYPE.ctor) || (type != null ? typeof type.toLowerCase === "function" ? type.toLowerCase() : void 0 : void 0) === TYPE.string) {
return TYPE;
}
}
return null;
};
Types.prototype.resolveSchemaType = function(type, childType) {
type.childType = childType;
type.identifier = function(val) {
return val instanceof childType;
};
return type.parser = function(val) {
return new childType(val);
};
};
Types.prototype.resolveType = function(typeDef) {
var childType, fn, fn1, i, len, ref, type;
type = this.getPrimitiveTypeOf(typeDef);
if (type == null) {
if (_.isArray(typeDef)) {
type = _.cloneDeep(this.NESTED_TYPES.Array);
if (typeDef.length) {
childType = this.resolveType(typeDef[0]);
}
if (!childType) {
throw new Error("Error resolving type of array value " + typeDef);
}
type.childType = childType;
type.childParser = function(val) {
var index, member;
for (index in val) {
member = val[index];
if (!childType.identifier(member)) {
val[index] = childType.parser(member);
}
}
return val;
};
/*
- If the type definition is an object `{}`
- Create a new Schema from the object
- Treat the field as a nested Schema
- Set identifier and parser functions immediately
*/
} else if (_.isPlainObject(typeDef)) {
type = _.cloneDeep(this.NESTED_TYPES.Schema);
childType = require('./ModelFactory').create(typeDef);
this.resolveSchemaType(type, childType);
/*
- If the type definition is a reference to a Schema constructor
- Treat the field as a nested Schema
- Set identifier and parser functions immediately
*/
} else if (_.isFunction(typeDef) && typeDef.__schemaId) {
type = _.cloneDeep(this.NESTED_TYPES.Schema);
childType = typeDef;
this.resolveSchemaType(type, childType);
/*
- If the type definition is a string that begins with Schema:, such as `'Schema:Car'`
- It is assumed that the field is a reference to a nested Schema that will be registered with the name Car,
but may not be registered yet
- The Schema is not resolved immediately
- The parser and identifier functions are written as wrappers, so that the first time they are invoked the Schema
will be looked up at that time via `Scheming.get`, and real identifier and parser are set at that time.
- If the registered Schema cannot be resolved, throw an error.
*/
} else if (_.isString(typeDef) && typeDef.slice(0, 7) === 'Schema:') {
type = _.cloneDeep(this.NESTED_TYPES.Schema);
childType = typeDef.slice(7);
ref = ['identifier', 'parser'];
fn1 = (function(_this) {
return function(fn) {
return type[fn] = function(val) {
childType = require('./Registry').get(childType);
if (!childType) {
throw new Error("Error resolving " + typeDef + " on lazy initialization");
}
_this.resolveSchemaType(type, childType);
return type[fn](val);
};
};
})(this);
for (i = 0, len = ref.length; i < len; i++) {
fn = ref[i];
fn1(fn);
}
}
}
return type || null;
};
return Types;
})();
module.exports = new Types();
},{"./ModelFactory":4,"./Registry":5}]},{},[2])
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9lcmluLm5vZS1wYXluZS9sb2NhbC9zY2hlbWluZy9ub2RlX21vZHVsZXMvZ3VscC1icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCIvVXNlcnMvZXJpbi5ub2UtcGF5bmUvbG9jYWwvc2NoZW1pbmcvc3JjL0NoYW5nZU1hbmFnZXIuY29mZmVlIiwiL1VzZXJzL2VyaW4ubm9lLXBheW5lL2xvY2FsL3NjaGVtaW5nL3NyYy9FeHBvcnRCcm93c2VyLmNvZmZlZSIsIi9Vc2Vycy9lcmluLm5vZS1wYXluZS9sb2NhbC9zY2hlbWluZy9zcmMvSW5zdGFuY2VGYWN0b3J5LmNvZmZlZSIsIi9Vc2Vycy9lcmluLm5vZS1wYXluZS9sb2NhbC9zY2hlbWluZy9zcmMvTW9kZWxGYWN0b3J5LmNvZmZlZSIsIi9Vc2Vycy9lcmluLm5vZS1wYXluZS9sb2NhbC9zY2hlbWluZy9zcmMvUmVnaXN0cnkuY29mZmVlIiwiL1VzZXJzL2VyaW4ubm9lLXBheW5lL2xvY2FsL3NjaGVtaW5nL3NyYy9TY2hlbWluZy5jb2ZmZWUiLCIvVXNlcnMvZXJpbi5ub2UtcGF5bmUvbG9jYWwvc2NoZW1pbmcvc3JjL1R5cGVzLmNvZmZlZSJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBLElBQUEsZ0JBQUE7RUFBQTs7QUFBQSxDQUFBLEdBQUksT0FBQSxDQUFRLFFBQVI7O0FBSUU7MEJBQ0osUUFBQSxHQUNFO0lBQUEsT0FBQSxFQUFVLFNBQVY7SUFDQSxTQUFBLEVBQVksV0FEWjtJQUVBLGVBQUEsRUFBa0IsZ0JBRmxCOzs7MEJBS0YsZUFBQSxHQUFrQjs7RUFFSix1QkFBQTs7Ozs7Ozs7Ozs7O0lBQ1osSUFBQyxDQUFBLE9BQUQsR0FBVztJQUNYLElBQUMsQ0FBQSxtQkFBRCxHQUF1QjtJQUN2QixJQUFDLENBQUEsT0FBRCxHQUFXO0lBRVgsSUFBQyxDQUFBLGNBQUQsR0FBa0I7SUFF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TTtBQUROLFNBSEc7T0FwRFA7O0FBa0VBLFdBQU8sSUFBQSxJQUFRO0VBdEVIOzs7Ozs7QUF3RWhCLE1BQU0sQ0FBQyxPQUFQLEdBQXFCLElBQUEsS0FBQSxDQUFBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3Rocm93IG5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIil9dmFyIGY9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGYuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sZixmLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIl8gPSByZXF1aXJlICdsb2Rhc2gnXG5cbiMgIyMjIENoYW5nZSBNYW5hZ2VyXG4jIEludGVybmFsIENoYW5nZSBNYW5hZ2VyIGNsYXNzLCByZXNwb25zaWJsZSBmb3IgcXVldWVpbmcgYW5kIHJlc29sdmluZyBjaGFuZ2UgZXZlbnQgcHJvcGFnYXRpb24gZm9yIHdhdGNoZXNcbmNsYXNzIENoYW5nZU1hbmFnZXJcbiAgVEhST1RUTEUgOlxuICAgIFRJTUVPVVQgOiAndGltZW91dCdcbiAgICBJTU1FRElBVEUgOiAnaW1tZWRpYXRlJ1xuICAgIEFOSU1BVElPTl9GUkFNRSA6ICdhbmltYXRpb25GcmFtZSdcblxuICAjIENvbmZpZ3VyYXRpb24gZm9yIGxpbWl0aW5nIG51bWJlciBvZiBpdGVyYXRpb25zXG4gIElURVJBVElPTl9MSU1JVCA6IDEwMFxuXG4gIGNvbnN0cnVjdG9yIDogLT5cbiAgICBAY2hhbmdlcyA9IHt9XG4gICAgQGludGVybmFsQ2hhbmdlUXVldWUgPSBbXVxuICAgIEB0aW1lb3V0ID0gbnVsbFxuXG4gICAgQHJlY3Vyc2lvbkNvdW50ID0gMFxuXG4gICAgQHNldFRocm90dGxlIEBUSFJPVFRMRS5USU1FT1VUXG4gICAgQF9hY3RpdmVDbGVhclRpbWVvdXQgPSBudWxsXG4gICAgQF9xdWV1ZUNhbGxiYWNrID0gbnVsbFxuICAgIEBfcmVzb2x2ZUNhbGxiYWNrID0gbnVsbFxuXG4gICMgIyMjIHNldFRocm90dGxlXG4gICMgU2V0cyB0aGUgdGhyb3R0bGluZyBzdHJhdGVneSB0aGF0IFNjaGVtaW5nIHVzZXMgZm9yIHJlc29sdmluZyBxdWV1ZWQgY2hhbmdlcy5cbiAgc2V0VGhyb3R0bGUgOiAodGhyb3R0bGUpID0+XG4gICAgaWYgIV8uY29udGFpbnMgQFRIUk9UVExFLCB0aHJvdHRsZVxuICAgICAgdGhyb3cgbmV3IEVycm9yIFwiVGhyb3R0bGUgb3B0aW9uIG11c3QgYmUgc2V0IHRvIG9uZSBvZiB0aGUgc3RyYXRlZ2llcyBzcGVjaWZpZWQgb24gU2NoZW1pbmcuVEhST1RUTEVcIlxuXG4gICAgc3dpdGNoIHRocm90dGxlXG4gICAgICB3aGVuIEBUSFJPVFRMRS5USU1FT1VUXG4gICAgICAgIEBzZXRUaW1lb3V0ID0gPT5cbiAgICAgICAgICBAdGltZW91dCA/PSBzZXRUaW1lb3V0IEByZXNvbHZlLCAwXG4gICAgICAgIEBjbGVhclRpbWVvdXQgPSA9PlxuICAgICAgICAgIGNsZWFyVGltZW91dCBAdGltZW91dFxuICAgICAgICAgIEB0aW1lb3V0ID0gbnVsbFxuXG4gICAgICB3aGVuIEBUSFJPVFRMRS5JTU1FRElBVEVcbiAgICAgICAgaWYgc2V0SW1tZWRpYXRlPyAmJiBjbGVhckltbWVkaWF0ZT9cbiAgICAgICAgICBAc2V0VGltZW91dCA9ID0+XG4gICAgICAgICAgICBAdGltZW91dCA/PSBzZXRJbW1lZGlhdGUgQHJlc29sdmVcbiAgICAgICAgICBAY2xlYXJUaW1lb3V0ID0gPT5cbiAgICAgICAgICAgIGNsZWFySW1tZWRpYXRlIEB0aW1lb3V0XG4gICAgICAgICAgICBAdGltZW91dCA9IG51bGxcbiAgICAgICAgZWxzZVxuICAgICAgICAgIGNvbnNvbGUud2FybiBcIkNhbm5vdCB1c2Ugc3RyYXRlZ3kgSU1NRURJQVRFOiBgc2V0SW1tZWRpYXRlYCBvciBgY2xlYXJJbW1lZGlhdGVgIGFyZSBub3QgYXZhaWxhYmxlIGluIHRoZSBjdXJyZW50IGVudmlyb25tZW50LlwiXG4gICAgICAgICAgQHNldFRocm90dGxlIEBUSFJPVFRMRS5USU1FT1VUXG5cbiAgICAgIHdoZW4gQFRIUk9UVExFLkFOSU1BVElPTl9GUkFNRVxuICAgICAgICBpZiByZXF1ZXN0QW5pbWF0aW9uRnJhbWU/ICYmIGNhbmNlbEFuaW1hdGlvbkZyYW1lP1xuICAgICAgICAgIEBzZXRUaW1lb3V0ID0gPT5cbiAgICAgICAgICAgIEB0aW1lb3V0ID89IHJlcXVlc3RBbmltYXRpb25GcmFtZSBAcmVzb2x2ZVxuICAgICAgICAgIEBjbGVhclRpbWVvdXQgPSA9PlxuICAgICAgICAgICAgY2FuY2VsQW5pbWF0aW9uRnJhbWUgQHRpbWVvdXRcbiAgICAgICAgICAgIEB0aW1lb3V0ID0gbnVsbFxuICAgICAgICBlbHNlXG4gICAgICAgICAgY29uc29sZS53YXJuIFwiQ2Fubm90IHVzZSBzdHJhdGVneSBBTklNQVRJT05fRlJBTUU6IGByZXF1ZXN0QW5pbWF0aW9uRnJhbWVgIG9yIGBjYW5jZWxBbmltYXRpb25GcmFtZWAgYXJlIG5vdCBhdmFpbGFibGUgaW4gdGhlIGN1cnJlbnQgZW52aXJvbm1lbnQuXCJcbiAgICAgICAgICBAc2V0VGhyb3R0bGUgQFRIUk9UVExFLlRJTUVPVVRcblxuICAjIFB1c2ggdGhlIHJlc29sdXRpb24gc3RlcCBvbnRvIHRoZSBldmVudCBxdWV1ZSwgb25jZSB0aGUgdGhyZWFkIGhhcyBiZWVuIHJlbGVhc2VkIGZyb21cbiAgIyBhIHN5bmNocm9ub3VzIGJsb2NrIG9mIGNoYW5nZXNcbiAgc2V0VGltZW91dCA6IC0+XG4gICAgdGhyb3cgbmV3IEVycm9yIFwiQSB0aHJvdHRsZSBzdHJhdGVneSBtdXN0IGJlIHNldC5cIlxuXG4gICMgY2xlYXIgdGltZW91dCB0byBndWFyYW50ZWUgcmVzb2x2ZSBpcyBub3QgY2FsbGVkIG1vcmUgdGhhbiBvbmNlLlxuICBjbGVhclRpbWVvdXQgLT5cbiAgICB0aHJvdyBuZXcgRXJyb3IgXCJBIHRocm90dGxlIHN0cmF0ZWd5IG11c3QgYmUgc2V0LlwiXG5cbiAgIyAjIyMgcmVnaXN0ZXJRdWV1ZUNhbGxiYWNrXG4gICMgcmVnaXN0ZXJzIGEgY2FsbGJhY2sgd2hlbiB0aGUgZmlyc3QgU2NoZW1pbmcgY2hhbmdlIGlzIHF1ZXVlZCB3aXRoIHRoZSBjaGFuZ2UgbWFuYWdlci4gVGhpcyBpcyB1c2VmdWwgZm9yIHRlc3RzXG4gIHJlZ2lzdGVyUXVldWVDYWxsYmFjayA6IChjYWxsYmFjaykgPT5cbiAgICBpZiAhXy5pc0Z1bmN0aW9uIGNhbGxiYWNrXG4gICAgICB0aHJvdyBuZXcgRXJyb3IgXCJDYWxsYmFjayBtdXN0IGJlIGEgZnVuY3Rpb25cIlxuICAgIEBfcXVldWVDYWxsYmFjayA9IGNhbGxiYWNrXG5cbiAgIyAjIyMgdW5yZWdpc3RlclF1ZXVlQ2FsbGJhY2tcbiAgIyB1bnJlZ2lzdGVycyBhIGNhbGxiYWNrIHdoZW4gdGhlIGZpcnN0IFNjaGVtaW5nIGNoYW5nZSBpcyBxdWV1ZWQgd2l0aCB0aGUgY2hhbmdlIG1hbmFnZXIuXG4gIHVucmVnaXN0ZXJRdWV1ZUNhbGxiYWNrIDogPT5cbiAgICBAX3F1ZXVlQ2FsbGJhY2sgPSBudWxsXG5cbiAgIyAjIyMgcmVnaXN0ZXJSZXNvbHZlQ2FsbGJhY2tcbiAgIyByZWdpc3RlcnMgYSBjYWxsYmFjayB3aGVuIHRoZSBjaGFuZ2UgbWFuYWdlciBpcyBmaW5pc2hlZCByZXNvbHZpbmcgY2hhbmdlc1xuICByZWdpc3RlclJlc29sdmVDYWxsYmFjayA6IChjYWxsYmFjaykgPT5cbiAgICBpZiAhXy5pc0Z1bmN0aW9uIGNhbGxiYWNrXG4gICAgICB0aHJvdyBuZXcgRXJyb3IgXCJDYWxsYmFjayBtdXN0IGJlIGEgZnVuY3Rpb25cIlxuICAgIEBfcmVzb2x2ZUNhbGxiYWNrID0gY2FsbGJhY2tcblxuICAjICMjIyB1bnJlZ2lzdGVyUmVzb2x2ZUNhbGxiYWNrXG4gICMgdW5yZWdpc3RlcnMgYSBjYWxsYmFjayB3aGVuIHRoZSBjaGFuZ2UgbWFuYWdlciBpcyBmaW5pc2hlZCByZXNvbHZpbmcgY2hhbmdlc1xuICB1bnJlZ2lzdGVyUmVzb2x2ZUNhbGxiYWNrIDogPT5cbiAgICBAX3Jlc29sdmVDYWxsYmFjayA9IG51bGxcbiAgICAjIHJlc2V0IHRoZSB0aGUgY2hhbmdlIG1hbmFnZXIgdG8gYSBwcmlzdGluZSBzdGF0ZVxuXG4gIGNsZWFudXBDeWNsZSA6ID0+XG4gICAgQGNoYW5nZXMgPSB7fVxuICAgIEBpbnRlcm5hbENoYW5nZVF1ZXVlID0gW11cbiAgICBAX2FjdGl2ZUNsZWFyVGltZW91dD8oKVxuICAgIEByZWN1cnNpb25Db3VudCA9IDBcblxuICByZXNldCA6ID0+XG4gICAgQGNoYW5nZXMgPSB7fVxuICAgIEBpbnRlcm5hbENoYW5nZVF1ZXVlID0gW11cbiAgICBAX2FjdGl2ZUNsZWFyVGltZW91dD8oKVxuICAgIEB0aW1lb3V0ID0gbnVsbFxuXG4gICAgQHJlY3Vyc2lvbkNvdW50ID0gMFxuXG4gICAgQHNldFRocm90dGxlIEBUSFJPVFRMRS5USU1FT1VUXG4gICAgQF9xdWV1ZUNhbGxiYWNrID0gbnVsbFxuICAgIEBfcmVzb2x2ZUNhbGxiYWNrID0gbnVsbFxuXG4gICMgUmVnaXN0ZXJzIGNoYW5nZXMgdGhhdCBoYXZlIG9jY3VycmVkIG9uIGFuIGluc3RhbmNlIGJ5IGluc3RhbmNlIGlkLCBob2xkaW5nIGEgcmVmZXJlbmNlIHRvIHRoZSBvcmlnaW5hbCB2YWx1ZVxuICBxdWV1ZUNoYW5nZXMgOiAoe2lkLCBwcm9wTmFtZSwgb2xkVmFsLCBuZXdWYWwsIGVxdWFscywgZm9yY2V9LCBmaXJlV2F0Y2hlcnMpID0+XG4gICAgIyBpZiB0aGVyZSBhcmUgbm8gY2hhbmdlcyB5ZXQgcXVldWVkIGZvciB0aGUgaW5zdGFuY2UsIGFkZCB0byB0aGUgY2hhbmdlcyBoYXNoIGJ5IGlkXG4gICAgaWYgIV8uaGFzIEBjaGFuZ2VzLCBpZFxuICAgICAgQGNoYW5nZXNbaWRdID89IHtjaGFuZ2VkUHJvcHMgOiB7fSwgZmlyZVdhdGNoZXJzfVxuICAgICAgQGludGVybmFsQ2hhbmdlUXVldWUucHVzaCBpZFxuICAgIHtjaGFuZ2VkUHJvcHN9ID0gQGNoYW5nZXNbaWRdXG5cbiAgICBpZiBwcm9wTmFtZVxuICAgICAgIyBpZiB3ZSBhcmUgYWxyZWFkeSB0cmFja2luZyB0aGlzIHByb3BlcnR5LCBhbmQgaXQgaGFzIGJlZW4gcmVzZXQgdG8gaXRzIG9yaWdpbmFsIHZhbHVlLCBjbGVhciBpdCBmcm9tIGNoYW5nZXNcbiAgICAgIGlmIF8uaGFzKGNoYW5nZWRQcm9wcywgcHJvcE5hbWUpICYmIGVxdWFscyhjaGFuZ2VkUHJvcHNbcHJvcE5hbWVdLCBuZXdWYWwpXG4gICAgICAgIGRlbGV0ZSBjaGFuZ2VkUHJvcHNbcHJvcE5hbWVdXG4gICAgICAgICMgaWYgd2UgYXJlIG5vdCB0cmFja2luZyB0aGlzIHByb3BlcnR5IGFuZCBpdCBpcyBiZWluZyBjaGFuZ2VkLCBvciBpZiBmb3JjZSBpcyBmbGFnZ2VkIHRydWUsIGFkZCBpdCB0byBjaGFuZ2VzXG4gICAgICBlbHNlIGlmIGZvcmNlIHx8ICghXy5oYXMoY2hhbmdlZFByb3BzLCBwcm9wTmFtZSkgJiYgIWVxdWFscyhvbGRWYWwsIG5ld1ZhbCkpXG4gICAgICAgIGNoYW5nZWRQcm9wc1twcm9wTmFtZV0gPSBvbGRWYWxcblxuICAgICMgQ2FsbCB0aGUgcXVldWUgY2FsbGJhY2sgaWYgYSB0aW1lb3V0IGhhc24ndCBiZWVuIGRlZmluZWQgeWV0XG4gICAgaWYgIUB0aW1lb3V0P1xuICAgICAgQF9xdWV1ZUNhbGxiYWNrPygpXG4gICAgICBAc2V0VGltZW91dCgpXG4gICAgICBAX2FjdGl2ZUNsZWFyVGltZW91dCA9IEBjbGVhclRpbWVvdXRcblxuICAjIGdldHMgdGhlIHByZXZpb3VzIHN0YXRlIG9mIGEgcXVldWVkIGNoYW5nZVxuICBnZXRRdWV1ZWRDaGFuZ2VzIDogKHtpZCwgcHJvcE5hbWV9KSA9PlxuICAgIHJldHVybiBAY2hhbmdlc1tpZF0/LmNoYW5nZWRQcm9wc1twcm9wTmFtZV1cblxuICAjIFN5bmNocm9ub3VzbHkgY2F1c2UgdGhlIGNoYW5nZSBtYW5hZ2VyIHJlc29sdmUuIE1heSBiZSB1c2VkIGZvciB0ZXN0aW5nIHRvIGF2b2lkIGFzeW5jaHJvbm91cyB0ZXN0cyxcbiAgIyBvciBtYXkgYmUgdXNlZCB0byBmb3JjZSBjaGFuZ2UgcmVzb2x1dGlvbiB3aXRoaW4gY2xpZW50IGNvZGUuXG4gIGZsdXNoIDogPT5cbiAgICBAcmVzb2x2ZSgpXG5cbiAgIyByZXNvbHZlcyBxdWV1ZWQgY2hhbmdlcywgZmlyaW5nIHdhdGNoZXJzIG9uIGluc3RhbmNlcyB0aGF0IGhhdmUgY2hhbmdlZFxuICByZXNvbHZlIDogPT5cbiAgICBAcmVjdXJzaW9uQ291bnQrK1xuICAgICMgdHJhY2sgaXRlcmF0aW9uIGNvdW50IGFuZCB0aHJvdyBhbiBlcnJvciBhZnRlciBzb21lIGxpbWl0IHRvIHByZXZlbnQgaW5maW5pdGUgbG9vcHNcbiAgICBpZiBASVRFUkFUSU9OX0xJTUlUID4gMCAmJiBAcmVjdXJzaW9uQ291bnQgPiBASVRFUkFUSU9OX0xJTUlUXG4gICAgICBjaGFuZ2VzID0gQGNoYW5nZXNcbiAgICAgIEBjbGVhbnVwQ3ljbGUoKVxuICAgICAgIyBUT0RPOiB0cnkgdG8gbWFrZSBhIG1vcmUgbWVhbmluZ2Z1bCBlcnJvciBtZXNzYWdlIGZyb20gdGhlIGluc3RhbmNlcyAoc2NoZW1hIHR5cGUsIHByb3BlcnRpZXMsIGV0YylcbiAgICAgIHRocm93IG5ldyBFcnJvciBcIlwiXCJBYm9ydGluZyBjaGFuZ2UgcHJvcGFnYXRpb24gYWZ0ZXIgI3tASVRFUkFUSU9OX0xJTUlUfSBjeWNsZXMuXG4gICAgICAgIFRoaXMgaXMgcHJvYmFibHkgaW5kaWNhdGl2ZSBvZiBhIGNpcmN1bGFyIHdhdGNoLiBDaGVjayB0aGUgZm9sbG93aW5nIHdhdGNoZXMgZm9yIGNsdWVzOlxuICAgICAgICAje0pTT04uc3RyaW5naWZ5KGNoYW5nZXMpfVwiXCJcIlxuXG4gICAgIyBBIHNpbmdsZSBpZCBtYXkgaGF2ZSBiZWVuIHB1c2hlZCB0byB0aGUgY2hhbmdlIHF1ZXVlIG1hbnkgdGltZXMsIHRvIHRha2UgYSB1bmlxdWUgbGlzdCBvZiBpZHMuXG4gICAgaW50ZXJuYWxDaGFuZ2VzID0gXy51bmlxdWUgQGludGVybmFsQ2hhbmdlUXVldWVcbiAgICAjIEltbWVkaWF0ZWx5IHJlc2V0IHRoZSBzdGF0ZSBvZiB0aGUgY2hhbmdlIHF1ZXVlXG4gICAgQGludGVybmFsQ2hhbmdlUXVldWUgPSBbXVxuXG4gICAgIyBGaXJlIGludGVybmFsIHdhdGNoZXJzIG9uIGFsbCBpbnN0YW5jZXMgdGhhdCBoYXZlIGNoYW5nZWQuIFRoaXMgd2lsbCBjYXVzZSB0aGUgY2hhbmdlIGV2ZW50IHRvIHByb3BhZ2F0ZSB0b1xuICAgICMgYW55IHBhcmVudCBzY2hlbWFzLCB3aG9zZSBjaGFuZ2VzIHdpbGwgcG9wdWxhdGUgYEBpbnRlcm5hbENoYW5nZVF1ZXVlYFxuICAgIGZvciBpZCBpbiBpbnRlcm5hbENoYW5nZXNcbiAgICAgIHtjaGFuZ2VkUHJvcHMsIGZpcmVXYXRjaGVyc30gPSBAY2hhbmdlc1tpZF1cbiAgICAgIGZpcmVXYXRjaGVycyBjaGFuZ2VkUHJvcHMsICdpbnRlcm5hbCdcbiAgICAgICMgaWYgYW55IG5ldyBpbnRlcm5hbCBjaGFuZ2VzIHdlcmUgcmVnaXN0ZXJlZCwgcmVjdXJzaXZlbHkgY2FsbCByZXNvbHZlIHRvIGNvbnRpbnVlIHByb3BhZ2F0aW9uXG4gICAgaWYgQGludGVybmFsQ2hhbmdlUXVldWUubGVuZ3RoXG4gICAgICByZXR1cm4gQHJlc29sdmUoKVxuXG4gICAgIyBPbmNlIGludGVybmFsIHdhdGNoZXMgaGF2ZSBmaXJlZCB3aXRob3V0IGNhdXNpbmcgYSBjaGFuZ2Ugb24gYSBwYXJlbnQgc2NoZW1hIGluc3RhbmNlLCB0aGVyZSBhcmUgbm8gbW9yZSBjaGFuZ2VzXG4gICAgIyB0byBwcm9wYWdhdGUuIEF0IHRoaXMgcG9pbnQgYWxsIGNoYW5nZXMgb24gZWFjaCBpbnN0YW5jZSBoYXZlIGJlZW4gYWdncmVnYXRlZCBpbnRvIGEgc2luZ2xlIGNoYW5nZSBzZXQuIE5vd1xuICAgICMgZmlyZSBhbGwgZXh0ZXJuYWwgd2F0Y2hlcnMgb24gZWFjaCBpbnN0YW5jZS5cbiAgICBjaGFuZ2VzID0gQGNoYW5nZXNcbiAgICAjIEltbWVkaWF0ZWx5IHJlc2V0IHRoZSBjaGFuZ2Ugc2V0XG4gICAgQGNoYW5nZXMgPSB7fVxuXG4gICAgIyBGaXJlIGFsbCBleHRlcm5hbCB3YXRjaGVyc1xuICAgIGZvciBpZCBvZiBjaGFuZ2VzXG4gICAgICB7Y2hhbmdlZFByb3BzLCBmaXJlV2F0Y2hlcnN9ID0gY2hhbmdlc1tpZF1cbiAgICAgIGZpcmVXYXRjaGVycyBjaGFuZ2VkUHJvcHMsICdleHRlcm5hbCdcblxuICAgICAgIyBJZiBhbnkgZXh0ZXJuYWwgd2F0Y2hlcyBjYXVzZWQgbmV3IGNoYW5nZXMgdG8gYmUgcXVldWVkLCByZS1ydW4gcmVzb2x2ZSB0byBlbnN1cmUgcHJvcGFnYXRpb25cbiAgICBpZiBfLnNpemUoQGNoYW5nZXMpID4gMFxuICAgICAgcmV0dXJuIEByZXNvbHZlKClcblxuICAgICMgSWYgd2UgZ2V0IGhlcmUsIGFsbCBjaGFuZ2VzIGhhdmUgYmVlbiBmdWxseSBwcm9wYWdhdGVkLiBSZXNldCBjaGFuZ2UgbWFuYWdlciBzdGF0ZSB0byBwcmlzdGluZSBqdXN0IGZvciBleHBsaWNpdG5lc3NcbiAgICBAX3Jlc29sdmVDYWxsYmFjaz8oKVxuICAgIEBjbGVhbnVwQ3ljbGUoKVxuXG5tb2R1bGUuZXhwb3J0cyA9IG5ldyBDaGFuZ2VNYW5hZ2VyKCkiLCJfID0gd2luZG93Ll9cblxud2luZG93LlNjaGVtaW5nID0gcmVxdWlyZSAnLi9TY2hlbWluZydcbiIsIl8gPSByZXF1aXJlICdsb2Rhc2gnXG5UeXBlcyA9IHJlcXVpcmUgJy4vVHlwZXMnXG5DaGFuZ2VNYW5hZ2VyID0gcmVxdWlyZSAnLi9DaGFuZ2VNYW5hZ2VyJ1xuXG5cblxuXG5jbGFzcyBJbnN0YW5jZUZhY3RvcnlcbiAgIyBBcyBsaXN0ZWQgYnkgaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvQXJyYXkjTXV0YXRvcl9tZXRob2RzXG4gIEFSUkFZX01VVEFUT1JTIDogWydjb3B5V2l0aGluJywgJ2ZpbGwnLCAncHVzaCcsICdwb3AnLCAncmV2ZXJzZScsICdzaGlmdCcsICdzb3J0JywgJ3NwbGljZScsICd1bnNoaWZ0J11cblxuICAjIFV1aWQgZ2VuZXJhdG9yIGZvciBhbm9ueW1vdXMgU2NoZW1hIGlkc1xuICB1dWlkIDogPT5cbiAgICBub3cgPSBEYXRlLm5vdygpXG4gICAgJ3h4eHh4eHh4LXh4eHgtNHh4eC15eHh4LXh4eHh4eHh4eHh4eCcucmVwbGFjZSAvW3h5XS9nLCAoYykgLT5cbiAgICAgIHIgPSAobm93ICsgTWF0aC5yYW5kb20oKSAqIDE2KSAlIDE2IHwgMFxuICAgICAgbm93ID0gTWF0aC5mbG9vciBub3cgLyAxNlxuICAgICAgKChpZiBjIGlzIFwieFwiIHRoZW4gciBlbHNlIChyICYgMHgzIHwgMHg4KSkpLnRvU3RyaW5nIDE2XG5cbiAgIyAjIyBJbnN0YW5jZVxuICAjIEZhY3RvcnkgbWV0aG9kIHRoYXQgYnVpbGRzIGEgTW9kZWwgaW5zdGFuY2VcbiAgY3JlYXRlIDogKGluc3RhbmNlLCBub3JtYWxpemVkU2NoZW1hLCBpbml0aWFsU3RhdGUsIG9wdHMpID0+XG4gICAgIyBmbGFnIHRvIGluZGljYXRlIGluaXRpYWxpemluZyBzdGF0ZSBvZiBpbnN0YW5jZVxuICAgIF9pbml0aWFsaXppbmcgPSB0cnVlXG4gICAgIyBkYXRhIGhhc2ggd3JhcHBlZCBpbiBjbG9zdXJlLCBrZWVwcyBhY3R1YWwgZGF0YSBtZW1iZXJzIHByaXZhdGVcbiAgICBkYXRhID0ge31cbiAgICAjIHByaXZhdGUgd2F0Y2hlcnMgYXJyYXkuIEV4dGVybmFsIHdhdGNoZXMgLSB0aG9zZSBzZXQgYnkgY29uc3VtaW5nIGNsaWVudCBjb2RlIC0gYXJlIHRyYWNrZWQgc2VwYXJhdGVseSBmcm9tXG4gICAgIyBpbnRlcm5hbCB3YXRjaGVzIC0gdGhvc2UgdG8gd2F0Y2ggY2hhbmdlIHByb3BhZ2F0aW9uIG9uIG5lc3RlZCBzY2hlbWFzXG4gICAgd2F0Y2hlcnMgPVxuICAgICAgaW50ZXJuYWwgOiBbXVxuICAgICAgZXh0ZXJuYWwgOiBbXVxuICAgICMgVGhlIHVud2F0Y2ggZnVuY3Rpb25zIGZyb20gaW50ZXJuYWwgd2F0Y2hlc1xuICAgIHVud2F0Y2hlcnMgPSB7fVxuXG4gICAgIyBTZXQgYW4gaWQgb24gZWFjaCBpbnN0YW5jZSB0aGF0IGlzIG5vdCBleHBvc2VkLCBpcyB1c2VkIGludGVybmFsbHkgb25seSBmb3IgY2hhbmdlIG1hbmFnZW1lbnRcbiAgICBpZCA9IEB1dWlkKClcblxuICAgIHtzdHJpY3QsIHNlYWx9ID0gb3B0c1xuXG4gICAgIyAjIyMgUHJvcGVydHkgU2V0dGVyXG4gICAgc2V0ID0gKHByb3BOYW1lLCB2YWwpID0+XG4gICAgICBwcmV2VmFsID0gZGF0YVtwcm9wTmFtZV1cblxuICAgICAgIyBpZiB0aGUgcHJvcGVydHkgaXMgbm90IGEgcGFydCBvZiB0aGUgc2NoZW1hLCBzaW1wbHkgc2V0IGl0IG9uIHRoZSBpbnN0YW5jZS5cbiAgICAgICMgaWYgdGhlIHNlYWwgb3B0aW9uIGlzIGVuYWJsZWQgdGhpcyB3aWxsIGZhaWwgc2lsZW50bHksIG90aGVyd2lzZSBpdCB3aWxsIGFsbG93IGZvciBhcmJpdHJhcnkgcHJvcGVydGllc1xuICAgICAgaWYgIW5vcm1hbGl6ZWRTY2hlbWFbcHJvcE5hbWVdXG4gICAgICAgIHJldHVybiBpbnN0YW5jZVtwcm9wTmFtZV0gPSB2YWxcblxuICAgICAgIyByZXRyaWV2ZSB0aGUgdHlwZSwgZ2V0dGVyLCBhbmQgc2V0dGVyIGZyb20gdGhlIG5vcm1hbGl6ZWQgZmllbGQgY29uZmlnXG4gICAgICB7dHlwZSwgc2V0dGVyfSA9IG5vcm1hbGl6ZWRTY2hlbWFbcHJvcE5hbWVdXG5cbiAgICAgICMgLSBJZiBhIHByb3BlcnR5IGlzIHNldCB0byB1bmRlZmluZWQsIGRvIG5vdCB0eXBlIGNhc3Qgb3IgcnVuIHRocm91Z2ggc2V0dGVyLlxuICAgICAgIyBZb3Ugc2hvdWxkIGFsd2F5cyBiZSBhYmxlIHRvIGNsZWFyIGEgcHJvcGVydHkuXG4gICAgICBpZiB2YWw/XG4gICAgICAgICMgLSBJZiBhIHNldHRlciBpcyBkZWZpbmVkLCBydW4gdGhlIHZhbHVlIHRocm91Z2ggc2V0dGVyXG4gICAgICAgIGlmIHNldHRlclxuICAgICAgICAgIHZhbCA9IHNldHRlci5jYWxsIGluc3RhbmNlLCB2YWxcbiAgICAgICAgIyAtIElmIHZhbHVlIGlzIG5vdCB1bmRlZmluZWQsIHJ1biB0aHJvdWdoIHR5cGUgaWRlbnRpZmllciB0byBkZXRlcm1pbmUgaWYgaXQgaXMgdGhlIGNvcnJlY3QgdHlwZVxuICAgICAgICBpZiAhdHlwZS5pZGVudGlmaWVyKHZhbClcbiAgICAgICAgICAjICAgLSBJZiBub3QgYW5kIHN0cmljdCBtb2RlIGlzIGVuYWJsZWQsIHRocm93IGFuIGVycm9yXG4gICAgICAgICAgaWYgc3RyaWN0IHRoZW4gdGhyb3cgbmV3IEVycm9yIFwiRXJyb3IgYXNzaWduaW5nICN7dmFsfSB0byAje3Byb3BOYW1lfS4gVmFsdWUgaXMgbm90IG9mIHR5cGUgI3t0eXBlLnN0cmluZ31cIlxuICAgICAgICAgICMgICAtIE90aGVyd2lzZSwgdXNlIHBhcnNlciB0byBjYXN0IHRvIHRoZSBjb3JyZWN0IHR5cGVcbiAgICAgICAgICB2YWwgPSB0eXBlLnBhcnNlciB2YWxcbiAgICAgICAgIyAtIElmIHRoZSBwcm9wZXJ0eSB0eXBlIGlzIG9mIGFycmF5LCBwZXJmb3JtIHBhcnNpbmcgb24gY2hpbGQgbWVtYmVycy5cbiAgICAgICAgaWYgdHlwZS5zdHJpbmcgPT0gVHlwZXMuTkVTVEVEX1RZUEVTLkFycmF5LnN0cmluZ1xuICAgICAgICAgIHZhbCA9IHR5cGUuY2hpbGRQYXJzZXIgdmFsXG4gICAgICAgICAgIyBBZGQgYSB1bmlxdWUgYXJyYXlJZCB0byBzY2hlbWluZyBhcnJheXMgdG8gaWRlbnRpZnkgdGhlIHNvdXJjZSBvZiBjaGFuZ2VzXG4gICAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5IHZhbCwgJ19hcnJheUlkJyxcbiAgICAgICAgICAgIGNvbmZpZ3VyYWJsZSA6IHRydWVcbiAgICAgICAgICAgIHZhbHVlIDogQHV1aWQoKVxuICAgICAgICAgICMgT3ZlcndyaXRlIG11dGF0b3IgZnVuY3Rpb25zIG9uIHRoaXMgYXJyYXkgY2FwdHVyZSBhbmQgcXVldWUgdGhlIG11dGF0aW9uLiBUaGlzIGd1YXJhbnRlZXNcbiAgICAgICAgICAjIHRoYXQgb3RoZXJ3aXNlIG11dGF0aW5nIGNoYW5nZXMgYXJlIHJ1biB0aHJvdWdoIHRoZSBzZXR0ZXJzIGFuZCBjaGFuZ2VzIGFyZSBjYXB0dXJlZC5cbiAgICAgICAgICBfLmVhY2ggQEFSUkFZX01VVEFUT1JTLCAobWV0aG9kKSAtPlxuICAgICAgICAgICAgaWYgcHJldlZhbD8gJiYgcHJldlZhbFttZXRob2RdXG4gICAgICAgICAgICAgIGRlbGV0ZSBwcmV2VmFsW21ldGhvZF1cblxuICAgICAgICAgICAgaWYgQXJyYXkucHJvdG90eXBlW21ldGhvZF0/XG4gICAgICAgICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSB2YWwsIG1ldGhvZCxcbiAgICAgICAgICAgICAgICBjb25maWd1cmFibGUgOiB0cnVlXG4gICAgICAgICAgICAgICAgd3JpdGFibGUgOiB0cnVlXG4gICAgICAgICAgICAgICAgdmFsdWUgOiAtPlxuICAgICAgICAgICAgICAgICAgY2xvbmUgPSBfLmNsb25lIEBcbiAgICAgICAgICAgICAgICAgIHRvUmV0dXJuID0gQXJyYXkucHJvdG90eXBlW21ldGhvZF0uY2FsbCBALCBhcmd1bWVudHMuLi5cbiAgICAgICAgICAgICAgICAgIENoYW5nZU1hbmFnZXIucXVldWVDaGFuZ2VzIHtpZCwgcHJvcE5hbWUsIG9sZFZhbCA6IGNsb25lLCBuZXdWYWwgOiB2YWwsIGVxdWFscyA6IHR5cGUuZXF1YWxzfSwgZmlyZVdhdGNoZXJzXG4gICAgICAgICAgICAgICAgICBpbnN0YW5jZVtwcm9wTmFtZV0gPSBAXG4gICAgICAgICAgICAgICAgICByZXR1cm4gdG9SZXR1cm5cblxuXG4gICAgICAjIC0gQXNzaWduIHRvIHRoZSBkYXRhIGhhc2hcbiAgICAgIGRhdGFbcHJvcE5hbWVdID0gdmFsXG4gICAgICAjIC0gSWYgdGhlIHZhbHVlIGJlaW5nIGFzc2lnbmVkIGlzIG9mIHR5cGUgc2NoZW1hLCB3ZSBuZWVkIHRvIGxpc3RlbiBmb3IgY2hhbmdlcyB0byBwcm9wYWdhdGVcbiAgICAgIHdhdGNoRm9yUHJvcGFnYXRpb24gcHJvcE5hbWUsIHZhbFxuICAgICAgIyAtIFF1ZXVlIHVwIGEgY2hhbmdlIHRvIGZpcmUsIHVubGVzcyB5b3UgYXJlIHNldHRpbmcgdGhlIGluaXRpYWwgc3RhdGUgb2YgdGhlIGluc3RhbmNlXG4gICAgICBpZiAhX2luaXRpYWxpemluZ1xuICAgICAgICBDaGFuZ2VNYW5hZ2VyLnF1ZXVlQ2hhbmdlcyB7aWQsIHByb3BOYW1lLCBvbGRWYWwgOiBwcmV2VmFsLCBuZXdWYWwgOiB2YWwsIGVxdWFscyA6IHR5cGUuZXF1YWxzfSwgZmlyZVdhdGNoZXJzXG5cbiAgICAjICMjIyBQcm9wZXJ0eSBHZXR0ZXJcbiAgICBnZXQgPSAocHJvcE5hbWUpIC0+XG4gICAgICAjIHJldHJpZXZlIHRoZSB0eXBlLCBnZXR0ZXIsIGFuZCBzZXR0ZXIgZnJvbSB0aGUgbm9ybWFsaXplZCBmaWVsZCBjb25maWdcbiAgICAgIHtnZXR0ZXJ9ID0gbm9ybWFsaXplZFNjaGVtYVtwcm9wTmFtZV1cblxuICAgICAgIyAtIFJldHJpZXZlIGRhdGEgdmFsdWUgZnJvbSB0aGUgaGFzaFxuICAgICAgdmFsID0gZGF0YVtwcm9wTmFtZV1cbiAgICAgICMgLSBJZiBnZXR0ZXIgaXMgZGVmaW5lZCwgcnVuIHZhbHVlIHRocm91Z2ggZ2V0dGVyXG4gICAgICBpZiBnZXR0ZXJcbiAgICAgICAgdmFsID0gZ2V0dGVyLmNhbGwgaW5zdGFuY2UsIHZhbFxuICAgICAgIyAtIEZpbmFsbHksIHJldHVybiB0aGUgdmFsdWVcbiAgICAgIHJldHVybiB2YWxcblxuICAgICMgQWRkcyBhIHdhdGNoZXIgdG8gdGhlIGluc3RhbmNlXG4gICAgYWRkV2F0Y2hlciA9IChwcm9wZXJ0aWVzLCBjYiwgb3B0cykgLT5cbiAgICAgICMgcHJvcGVydGllcyBhbmQgb3B0cyBhcmd1bWVudHMgYXJlIG9wdGlvbmFsXG4gICAgICBpZiBfLmlzRnVuY3Rpb24gcHJvcGVydGllc1xuICAgICAgICBvcHRzID0gY2JcbiAgICAgICAgY2IgPSBwcm9wZXJ0aWVzXG4gICAgICAgICMgaWYgbm8gcHJvcGVydGllcyBhcmUgc3BlY2lmaWVkLCB0aGUgd2F0Y2hlciBpcyByZWdpc3RlcmVkIHRvIHdhdGNoIGFsbCBwcm9wZXJ0aWVzIG9mIHRoZSBvYmplY3RcbiAgICAgICAgcHJvcGVydGllcyA9IF8ua2V5cyBub3JtYWxpemVkU2NoZW1hXG5cbiAgICAgICMgdW5sZXNzIHNwZWNpZmllZCwgYSB3YXRjaCBpcyBhc3N1bWVkIHRvIGJlIGV4dGVybmFsLiBDbGluZXQgY29kZSBzaG91bGQgbm90IHNldCB3YXRjaGVzIGFzIGludGVybmFsIVxuICAgICAgIyBCZWhhdmlvciBpcyB1bmRlZmluZWQuXG4gICAgICBvcHRzID89IHt9XG4gICAgICBvcHRzLmludGVybmFsID89IGZhbHNlXG5cbiAgICAgIHRhcmdldCA9IGlmIG9wdHMuaW50ZXJuYWwgdGhlbiAnaW50ZXJuYWwnIGVsc2UgJ2V4dGVybmFsJ1xuXG4gICAgICBpZiAhXy5pc0Z1bmN0aW9uIGNiXG4gICAgICAgIHRocm93IG5ldyBFcnJvciAnQSB3YXRjaCBtdXN0IGJlIHByb3ZpZGVkIHdpdGggYSBjYWxsYmFjayBmdW5jdGlvbi4nXG5cbiAgICAgICMgQ2FzdCB0aGUgcHJvcGVydGllcyB0byBhbiBhcnJheS4gQSB3YXRjaCBjYW4gc3VwcG9ydCBvbmUgb3IgbW9yZSBwcm9wZXJ0eSBuYW1lcy5cbiAgICAgIGlmIHByb3BlcnRpZXMgJiYgIV8uaXNBcnJheSBwcm9wZXJ0aWVzXG4gICAgICAgIHByb3BlcnRpZXMgPSBbcHJvcGVydGllc11cblxuICAgICAgIyBUaHJvdyBhbiBlcnJvciBpZiBjbGllbnQgY29kZSBhdHRlbXB0cyB0byBzZXQgYSB3YXRjaCBvbiBhIHByb3BlcnR5IHRoYXQgaXMgbm90IGRlZmluZWQgYXMgcGFydCBvZiB0aGUgc2NoZW1hLlxuICAgICAgZm9yIHByb3BOYW1lIGluIHByb3BlcnRpZXNcbiAgICAgICAgaWYgIV8uaGFzIG5vcm1hbGl6ZWRTY2hlbWEsIHByb3BOYW1lXG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yIFwiQ2Fubm90IHNldCB3YXRjaCBvbiAje3Byb3BOYW1lfSwgcHJvcGVydHkgaXMgbm90IGRlZmluZWQgaW4gc2NoZW1hLlwiXG5cbiAgICAgICMgUmVnaXN0ZXIgdGhlIHdhdGNoZXIgb24gdGhlIGNvcnJlY3QgaW50ZXJuYWwgb3IgZXh0ZXJuYWwgd2F0Y2hlcnMgYXJyYXkuIEZsYWcgbmV3IGV4dGVybmFsIHdhdGNoZXJzIHdpdGggYGZpcnN0YFxuICAgICAgIyBzbyB0aGF0IHRoZXkgd2lsbCBnZXQgY2FsbGVkIG9uIHRoZSBmaXJzdCBjaGFuZ2UgbG9vcCwgcmVnYXJkbGVzcyBvZiB3aGV0aGVyIHRoZSB3YXRjaCBwcm9wZXJ0aWVzIGhhdmUgY2hhbmdlZC5cbiAgICAgICMgSW50ZXJuYWwgd2F0Y2hlcnMgZG8gbm90IG5lZWQgdG8gYmUgaW52b2tlZCBvbiBmaXJzdCB3YXRjaC5cbiAgICAgIHdhdGNoZXIgPSB7cHJvcGVydGllcywgY2IsIGZpcnN0IDogIW9wdHMuaW50ZXJuYWx9XG4gICAgICB3YXRjaGVyc1t0YXJnZXRdLnB1c2ggd2F0Y2hlclxuXG4gICAgICAjIFF1ZXVlIGEgY2hhbmdlIGV2ZW50IG9uIHRoZSBjaGFuZ2UgbWFuYWdlci5cbiAgICAgIENoYW5nZU1hbmFnZXIucXVldWVDaGFuZ2VzIHtpZH0sIGZpcmVXYXRjaGVyc1xuXG4gICAgICAjIHJldHVybiBhbiB1bndhdGNoIGZ1bmN0aW9uXG4gICAgICByZXR1cm4gLT5cbiAgICAgICAgcmVtb3ZlV2F0Y2hlciB3YXRjaGVyLCB0YXJnZXRcblxuICAgICMgUmVtb3ZlIGEgd2F0Y2ggbGlzdGVuZXIgZnJvbSB0aGUgYXBwcm9wcmFpdGUgd2F0Y2hlcnMgYXJyYXlcbiAgICByZW1vdmVXYXRjaGVyID0gKHdhdGNoZXIsIHRhcmdldCkgLT5cbiAgICAgIF8ucmVtb3ZlIHdhdGNoZXJzW3RhcmdldF0sIHdhdGNoZXJcblxuICAgICMgVGhpcyBmdW5jdGlvbiBpcyBjYWxsZWQgb24gdmFsdWUgYXNzaWdubWVudFxuICAgIHdhdGNoRm9yUHJvcGFnYXRpb24gPSAocHJvcE5hbWUsIHZhbCkgLT5cbiAgICAgIHt0eXBlfSA9IG5vcm1hbGl6ZWRTY2hlbWFbcHJvcE5hbWVdXG5cbiAgICAgICMgSWYgdGhlIGFzc2lnbmVkIHByb3BlcnR5IGlzIG9mIHR5cGUgc2NoZW1hLCB3ZSBuZWVkIHRvIGxpc3RlbiBmb3IgY2hhbmdlcyBvbiB0aGUgY2hpbGQgaW5zdGFuY2UgdG8gcHJvcGFnYXRlXG4gICAgICAjIGNoYW5nZXMgdG8gdGhpcyBpbnN0YW5jZVxuICAgICAgaWYgdHlwZS5zdHJpbmcgPT0gVHlwZXMuTkVTVEVEX1RZUEVTLlNjaGVtYS5zdHJpbmdcbiAgICAgICAgIyBJZiB0aGVyZSB3YXMgYSB3YXRjaGVyIGZyb20gdGhlIHByZXZpb3VzbHkgYXNzaWduZWQgdmFsdWUsIHN0b3AgbGlzdGVuaW5nLlxuICAgICAgICB1bndhdGNoZXJzW3Byb3BOYW1lXT8oKVxuICAgICAgICAjIFdhdGNoIHRoZSBuZXcgdmFsdWUgZm9yIGNoYW5nZXMgYW5kIHByb3BhZ2F0ZSB0aGlzIGNoYW5nZXMgdG8gdGhpcyBpbnN0YW5jZS4gRmxhZyB0aGUgd2F0Y2ggYXMgaW50ZXJuYWwuXG4gICAgICAgIHVud2F0Y2hlcnNbcHJvcE5hbWVdID0gdmFsPy53YXRjaCAobmV3VmFsLCBvbGRWYWwpLT5cbiAgICAgICAgICBDaGFuZ2VNYW5hZ2VyLnF1ZXVlQ2hhbmdlcyB7aWQsIHByb3BOYW1lLCBvbGRWYWwsIG5ld1ZhbCwgZXF1YWxzOiB0eXBlLmVxdWFsc30sIGZpcmVXYXRjaGVyc1xuICAgICAgICAsIGludGVybmFsIDogdHJ1ZVxuXG4gICAgICAjIElmIHRoZSBhc3NpZ25lZCBwcm9wZXJ0eSBpcyBhbiBhcnJheSBvZiB0eXBlIHNjaGVtYSwgc2V0IGEgd2F0Y2ggb24gZWFjaCBhcnJheSBtZW1lYmVyLlxuICAgICAgaWYgdHlwZS5zdHJpbmcgPT0gVHlwZXMuTkVTVEVEX1RZUEVTLkFycmF5LnN0cmluZyBhbmQgdHlwZS5jaGlsZFR5cGUuc3RyaW5nID09IFR5cGVzLk5FU1RFRF9UWVBFUy5TY2hlbWEuc3RyaW5nXG4gICAgICAgICMgSWYgdGhlcmUgd2VyZSB3YXRjaGVycyBvbiB0aGUgcHJldmlvdXMgYXJyYXkgbWVtYmVycywgY2xlYXIgdGhvc2UgbGlzdGVuZXJzLlxuICAgICAgICBmb3IgdW53YXRjaGVyIGluICh1bndhdGNoZXJzW3Byb3BOYW1lXSB8fCBbXSlcbiAgICAgICAgICB1bndhdGNoZXI/KClcbiAgICAgICAgIyByZXNldCB0aGUgdW53YXRjaGVycyBhcnJheVxuICAgICAgICB1bndhdGNoZXJzW3Byb3BOYW1lXSA9IFtdXG4gICAgICAgIF8uZWFjaCB2YWwsIChzY2hlbWEsIGkpIC0+XG4gICAgICAgICAgIyBzZXQgYSBuZXcgd2F0Y2ggb24gZWFjaCBhcnJheSBtZW1iZXIgdG8gcHJvcGFnYXRlIGNoYW5nZXMgdG8gdGhpcyBpbnN0YW5jZS4gRmxhZyB0aGUgd2F0Y2ggYXMgaW50ZXJuYWwuXG4gICAgICAgICAgdW53YXRjaGVyc1twcm9wTmFtZV0ucHVzaCBzY2hlbWE/LndhdGNoIChuZXdWYWwsIG9sZFZhbCktPlxuICAgICAgICAgICAgbmV3QXJyYXkgPSBpbnN0YW5jZVtwcm9wTmFtZV1cbiAgICAgICAgICAgICMgY2hlY2sgaWYgdGhlcmUgaXMgYWxyZWFkeSBhIHF1ZXVlZCBjaGFuZ2UgZm9yIHRoaXMgYXJyYXlcbiAgICAgICAgICAgIG9sZEFycmF5ID0gQ2hhbmdlTWFuYWdlci5nZXRRdWV1ZWRDaGFuZ2VzIHtpZCwgcHJvcE5hbWV9XG4gICAgICAgICAgICAjIGlmIHRoZXJlIGlzIG5vdCwgY2xvbmUgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIGFycmF5LCBpbmNsdWRpbmcgdGhlIGFycmF5SWRcbiAgICAgICAgICAgIGlmICFvbGRBcnJheT9cbiAgICAgICAgICAgICAgb2xkQXJyYXkgPz0gXy5jbG9uZSBuZXdBcnJheVxuICAgICAgICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkgb2xkQXJyYXksICdfYXJyYXlJZCcsXG4gICAgICAgICAgICAgICAgY29uZmlndXJhYmxlIDogdHJ1ZVxuICAgICAgICAgICAgICAgIHZhbHVlIDogbmV3QXJyYXkuX2FycmF5SWRcbiAgICAgICAgICAgICMgaWYgdGhlIHNvdXJjZSBvZiB0aGlzIGNobmFnZSBpcyB0aGUgc2FtZSBhcyB0aGUgYWxyZWFkeSBxdWV1ZWQgYXJyYXksIHByb3BhZ2F0ZSB0aGUgY2hhbmdlXG4gICAgICAgICAgICBpZiBvbGRBcnJheS5fYXJyYXlJZCA9PSBuZXdBcnJheS5fYXJyYXlJZFxuICAgICAgICAgICAgICBvbGRBcnJheVtpXSA9IG9sZFZhbFxuICAgICAgICAgICAgICBDaGFuZ2VNYW5hZ2VyLnF1ZXVlQ2hhbmdlcyB7aWQsIHByb3BOYW1lLCBvbGRWYWwgOiBvbGRBcnJheSwgbmV3VmFsIDogbmV3QXJyYXksIGVxdWFscyA6IHR5cGUuZXF1YWxzLCBmb3JjZTogdHJ1ZX0sIGZpcmVXYXRjaGVyc1xuICAgICAgICAgICwgaW50ZXJuYWwgOiB0cnVlXG5cbiAgICAjIEdpdmVuIGEgY2hhbmdlIHNldCwgZmlyZXMgYWxsIHdhdGNoZXJzIHRoYXQgYXJlIHdhdGNoaW5nIG9uZSBvciBtb3JlIG9mIHRoZSBjaGFuZ2VkIHByb3BlcnRpZXNcbiAgICBmaXJlV2F0Y2hlcnMgPSAocXVldWVkQ2hhbmdlcywgdGFyZ2V0PSdleHRlcm5hbCcpIC0+XG4gICAgICB0cmlnZ2VyaW5nUHJvcGVydGllcyA9IF8ua2V5cyBxdWV1ZWRDaGFuZ2VzXG5cbiAgICAgICMgUmV0cmlldmVzIHRoZSBwcmV2aW91cyB2YWx1ZSBmb3IgYSBwcm9wZXJ0eSwgcHVsbGluZyBmcm9tIHF1ZXVlZCBjaGFuZ2VzIGlmIHByZXNlbnQsIG90aGVyd2lzZSByZXRyZWl2aW5nXG4gICAgICAjIGN1cnJlbnQgdmFsdWUgLSBpLmUuIG5vIGNoYW5nZS5cbiAgICAgIGdldFByZXZWYWwgPSAocHJvcE5hbWUpIC0+XG4gICAgICAgIGlmIF8uaGFzIHF1ZXVlZENoYW5nZXMsIHByb3BOYW1lXG4gICAgICAgICAgcmV0dXJuIHF1ZXVlZENoYW5nZXNbcHJvcE5hbWVdXG4gICAgICAgIGVsc2VcbiAgICAgICAgICByZXR1cm4gaW5zdGFuY2VbcHJvcE5hbWVdXG5cbiAgICAgICMgZm9yIGVhY2ggcmVnaXN0ZXJlZCB3YXRjaGVyIC0gdXNlIGEgd2hpbGUgbG9vcCBzaW5jZSBmaXJpbmcgb25lIHdhdGNoZXIgY2FuIGNhdXNlIG90aGVyIHdhdGNoZXJzIHRvIGJlIGFkZGVkIG9yXG4gICAgICAjIHJlbW92ZWRcbiAgICAgIGkgPSAwXG4gICAgICAjIFRPRE86IHRoZXJlIGlzIGEgcG9zc2libGUgZXJyb3IgaGVyZSB3aGVyZSBmaXJpbmcgb25lIHdhdGNoZXIgcmVtb3ZlcyBhbm90aGVyIHdhdGNoZXIgZnJvbVxuICAgICAgIyB0aGUgYXJyYXkgLSB0aGUgaW5kZXggd291bGQgYmUgb2ZmIGJ5IG9uZSBhbmQgYSB3YXRjaGVyIGNvdWxkIGJlIHNraXBwZWRcbiAgICAgIHdoaWxlICh3YXRjaGVyID0gd2F0Y2hlcnNbdGFyZ2V0XVtpXSlcbiAgICAgICAgaSsrXG4gICAgICAgICMgVGhhdCB3YXRjaGVyIHNob3VsZCBmaXJlIGlmIGl0IGlzIG5ldywgb3IgaWYgaXQgaXMgd2F0Y2hpbmcgb25lIG9yIG1vcmUgb2YgdGhlIGNoYW5nZWQgcHJvcGVydGllc1xuICAgICAgICBzaG91bGRGaXJlID0gd2F0Y2hlci5maXJzdCB8fCAoXy5pbnRlcnNlY3Rpb24odHJpZ2dlcmluZ1Byb3BlcnRpZXMsIHdhdGNoZXIucHJvcGVydGllcykubGVuZ3RoID4gMClcbiAgICAgICAgd2F0Y2hlci5maXJzdCA9IGZhbHNlXG4gICAgICAgIGlmIHNob3VsZEZpcmVcbiAgICAgICAgICBuZXdWYWxzID0ge31cbiAgICAgICAgICBvbGRWYWxzID0ge31cblxuICAgICAgICAgICMgYnVpbGQgdGhlIGhhc2ggb2YgbmV3IC8gb2xkIHZhbHVlc1xuICAgICAgICAgIGZvciBwcm9wTmFtZSBpbiB3YXRjaGVyLnByb3BlcnRpZXNcbiAgICAgICAgICAgIG5ld1ZhbHNbcHJvcE5hbWVdID0gaW5zdGFuY2VbcHJvcE5hbWVdXG4gICAgICAgICAgICBvbGRWYWxzW3Byb3BOYW1lXSA9IGdldFByZXZWYWwocHJvcE5hbWUpXG5cbiAgICAgICAgICAjIGlmIHRoZSB3YXRjaGVyIGlzIHNldCBhZ2FpbnN0IGEgc2luZ2xlIHByb3BlcnR5LCBpbnZva2UgdGhlIGNhbGxiYWNrIHdpdGggdGhlIHJhdyBuZXcgLyBvbGQgdmFsdWVzXG4gICAgICAgICAgaWYgd2F0Y2hlci5wcm9wZXJ0aWVzLmxlbmd0aCA9PSAxXG4gICAgICAgICAgICBwcm9wTmFtZSA9IHdhdGNoZXIucHJvcGVydGllc1swXVxuICAgICAgICAgICAgbmV3VmFscyA9IG5ld1ZhbHNbcHJvcE5hbWVdXG4gICAgICAgICAgICBvbGRWYWxzID0gb2xkVmFsc1twcm9wTmFtZV1cblxuICAgICAgICAgIHRyeVxuICAgICAgICAgICAgd2F0Y2hlci5jYiBuZXdWYWxzLCBvbGRWYWxzXG4gICAgICAgICAgY2F0Y2ggZVxuICAgICAgICAgICAgIyBUT0RPOiBicm93c2VyIHN1cHBvcnQ/XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yIGUuc3RhY2sgfHwgZVxuXG4gICAgIyAjIyMgd2F0Y2hcbiAgICAjIFdhdGNoZXMgYW4gaW5zdGFuY2UgZm9yIGNoYW5nZXMgdG8gb25lIG9yIG1vcmUgcHJvcGVydGllc1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSBpbnN0YW5jZSwgJ3dhdGNoJyxcbiAgICAgIGNvbmZpZ3VyYWJsZSA6IGZhbHNlXG4gICAgICBlbnVtZXJhYmxlIDogZmFsc2VcbiAgICAgIHdyaXRhYmxlIDogZmFsc2VcbiAgICAgIHZhbHVlIDogKHByb3BlcnRpZXMsIGNiLCBvcHRzKSAtPiBhZGRXYXRjaGVyIHByb3BlcnRpZXMsIGNiLCBvcHRzXG5cbiAgICAjIERlZmluZSBhIHZhbGlkYXRpbmcgZmxhZywgd2hpY2ggaXMgdXNlZCB0byBwcmV2ZW50IGluZmluaXRlIGxvb3BzIG9uIHZhbGlkYXRpb24gb2YgY2lyY3VsYXIgcmVmZXJlbmNlc1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSBpbnN0YW5jZSwgJ192YWxpZGF0aW5nJyxcbiAgICAgIGNvbmZpZ3VyYWJsZSA6IGZhbHNlXG4gICAgICBlbnVtZXJhYmxlIDogZmFsc2VcbiAgICAgIHdyaXRhYmxlIDogdHJ1ZVxuICAgICAgdmFsdWUgOiBmYWxzZVxuXG4gICAgIyAjIyMgY29uc3RydWN0b3JcbiAgICAjIGZvciBlYWNoIHByb3BlcnR5IG9mIHRoZSBub3JtYWxpemVkIHNjaGVtYVxuICAgIGZvciBwcm9wTmFtZSwgcHJvcENvbmZpZyBvZiBub3JtYWxpemVkU2NoZW1hXG4gICAgICBkbyAocHJvcE5hbWUsIHByb3BDb25maWcpID0+XG4gICAgICAgICMgZGVmaW5lIGFuIGVudW1lcmFibGUgcHJvcGVydHkgb24gdGhlIGluc3RhbmNlIHRoYXQgaXMgbm90IGNvbmZpZ3VyYWJsZVxuICAgICAgICAjIHVzZXIgZ2V0IGFuZCBzZXQgdG8gbWFuYWdlIGdldHRlcnMsIHNldHRlcnMsIGFuZCB0eXBlIHBhcnNpbmdcbiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5IGluc3RhbmNlLCBwcm9wTmFtZSxcbiAgICAgICAgICBjb25maWd1cmFibGUgOiBmYWxzZVxuICAgICAgICAgIGVudW1lcmFibGUgICA6IHRydWVcbiAgICAgICAgIyAqKnNldCoqXG4gICAgICAgICAgc2V0ICAgICAgICAgIDogKHZhbCkgLT4gc2V0IHByb3BOYW1lLCB2YWxcbiAgICAgICAgIyAqKmdldCoqXG4gICAgICAgICAgZ2V0ICAgICAgICAgIDogLT4gZ2V0IHByb3BOYW1lXG5cbiAgICAgICAgIyBPbmNlIHRoZSBwcm9wZXJ0eSBpcyBjb25maWd1cmVkLCBhc3NpZ24gYSBkZWZhdWx0IHZhbHVlLiBUaGlzIGVuc3VyZXMgdGhhdCBkZWZhdWx0IHZhbHVlcyBhcmUgc3RpbGxcbiAgICAgICAgIyBhZmZlY3RlZCBieSB0eXBlIHBhcnNpbmcgYW5kIHNldHRlcnNcbiAgICAgICAgaWYgcHJvcENvbmZpZy5kZWZhdWx0ICE9IHVuZGVmaW5lZFxuICAgICAgICAgIHZhbCA9IGlmIF8uaXNGdW5jdGlvbihwcm9wQ29uZmlnLmRlZmF1bHQpIHRoZW4gcHJvcENvbmZpZy5kZWZhdWx0KCkgZWxzZSBwcm9wQ29uZmlnLmRlZmF1bHRcbiAgICAgICAgICBpbnN0YW5jZVtwcm9wTmFtZV0gPSB2YWxcblxuICAgICMgSWYgc2VhbCBvcHRpb24gaXMgZW5hYmxlZCwgc2VhbCB0aGUgaW5zdGFuY2UsIHByZXZlbnRpbmcgYWRkaXRpb24gb2Ygb3RoZXIgcHJvcGVydGllcyBiZXNpZGVzIHRob3NlIGV4cGxpY2l0bHlcbiAgICAjIGRlZmluZWQgYnkgdGhlIFNjaGVtYVxuICAgIGlmIHNlYWxcbiAgICAgIE9iamVjdC5zZWFsIGluc3RhbmNlXG5cbiAgICAjIHNldCB0aGUgaW5pdGlhbCBzdGF0ZSBvZiB0aGUgaW5zdGFuY2UsIHRoZW4gY2xlYXIgdGhlIGluaXRpYWxpemluZyBmbGFnXG4gICAgZm9yIHByb3BOYW1lLCB2YWwgb2YgaW5pdGlhbFN0YXRlXG4gICAgICBpbnN0YW5jZVtwcm9wTmFtZV0gPSB2YWxcblxuICAgIF9pbml0aWFsaXppbmcgPSBmYWxzZVxuXG5tb2R1bGUuZXhwb3J0cyA9IG5ldyBJbnN0YW5jZUZhY3RvcnkoKVxuIiwiXyA9IHJlcXVpcmUgJ2xvZGFzaCdcblR5cGVzID0gcmVxdWlyZSAnLi9UeXBlcydcbkluc3RhbmNlRmFjdG9yeSA9IHJlcXVpcmUgJy4vSW5zdGFuY2VGYWN0b3J5J1xuUmVnaXN0cnkgPSByZXF1aXJlICcuL1JlZ2lzdHJ5J1xuXG5cbmNsYXNzIE1vZGVsRmFjdG9yeVxuXG4gICMgIyMjIERFRkFVTFRfT1BUSU9OU1xuICAjIERlZmF1bHQgb3B0aW9ucyBmb3IgYFNjaGVtYS5jcmVhdGVgXG4gIERFRkFVTFRfT1BUSU9OUyA6XG4gICAgc2VhbCAgIDogZmFsc2VcbiAgICBzdHJpY3QgOiBmYWxzZVxuXG4gIGNvbnN0cnVjdG9yIDogLT5cbiAgICBAbmFtZUNvdW50ZXI9MFxuXG4gIGdlbmVyYXRlTmFtZSA6ID0+XG4gICAgcmV0dXJuIFwiU2NoZW1pbmdNb2RlbCN7QG5hbWVDb3VudGVyKyt9XCJcblxuICAjICMjIyBub3JtYWxpemVQcm9wZXJ0eUNvbmZpZ1xuICAjIyNcbiAgICBOb3JtYWxpemVzIGEgZmllbGQgZGVjbGFyYXRpb24gb24gYSBzY2hlbWEgdG8gY2FwdHVyZSB0eXBlLCBkZWZhdWx0IHZhbHVlLCBzZXR0ZXIsIGdldHRlciwgYW5kIHZhbGlkYXRpb24uXG4gICAgVXNlZCBpbnRlcm5hbGx5IHdoZW4gYSBzY2hlbWEgaXMgY3JlYXRlZCB0byBidWlsZCBhIG5vcm1hbGl6ZWQgc2NoZW1hIGRlZmluaXRpb24uXG4gICMjI1xuICBub3JtYWxpemVQcm9wZXJ0eUNvbmZpZyA6IChwcm9wQ29uZmlnLCBwcm9wTmFtZSA9ICdmaWVsZCcpID0+XG4gICAgIyBpbml0aWFsaXplIG5vcm1hbGl6ZWQgcHJvcGVydHkgZGVmaW5pdGlvbiB0aGF0IHdlIHdpbGwgcmV0dXJuXG4gICAgZGVmaW5pdGlvbiA9XG4gICAgICB0eXBlICAgICAgIDogbnVsbFxuICAgICAgZGVmYXVsdCAgICA6IG51bGxcbiAgICAgIGdldHRlciAgICAgOiBudWxsXG4gICAgICBzZXR0ZXIgICAgIDogbnVsbFxuICAgICAgdmFsaWRhdGUgICA6IG51bGxcbiAgICAgIHJlcXVpcmVkICAgOiBmYWxzZVxuXG4gICAgIyBpZiBwcm9wZXJ0eSBjb25maWd1cmF0aW9uIGlzIG5vdCBhbiBvYmplY3Qgd2l0aCBhIHR5cGUga2V5LCBhc3N1bWUgdGhhdFxuICAgICMgdGhlIGNvbmZpZ3VyYXRpb24gdmFsdWUgaXMganVzdCB0aGUgcHJvcGVydHkgdHlwZVxuICAgIGlmICEoXy5pc1BsYWluT2JqZWN0KHByb3BDb25maWcpICYmIHByb3BDb25maWcudHlwZT8pXG4gICAgICBwcm9wQ29uZmlnID0ge3R5cGUgOiBwcm9wQ29uZmlnfVxuXG4gICAge3R5cGUsIGdldHRlciwgc2V0dGVyLCB2YWxpZGF0ZSwgcmVxdWlyZWR9ID0gcHJvcENvbmZpZ1xuICAgICMgVGhpcyBmdW5jdGlvbiB0aHJvd3MgZXJyb3JzIG9uIGFueSBiYWQgY29uZmlndXJhdGlvbiwgYXR0ZW1wdGluZyB0byBmYWlsIGZhc3QuXG5cbiAgICAjIC0gVGhyb3cgYW4gZXJyb3IgaWYgdHlwZSBpcyBub3QgZGVmaW5lZC4gVHlwZSBtdXN0IGFsd2F5cyBiZSBleHBsaWNpdGx5IGRlY2xhcmVkLiBVbnR5cGVkIGZpZWxkc1xuICAgICMgbXVzdCBleHBsaWNpdGx5IGRlY2xhcmVkIGFzIFNjaGVtYS5UWVBFUy5NaXhlZFxuICAgIGlmICF0eXBlP1xuICAgICAgdGhyb3cgbmV3IEVycm9yIFwiRXJyb3IgcmVzb2x2aW5nICN7cHJvcE5hbWV9LiBTY2hlbWEgdHlwZSBtdXN0IGJlIGRlZmluZWQuXCJcbiAgICAjIC0gVGhyb3cgYW4gZXJyb3IgaWYgZ2V0dGVyIGlzIG5vdCBhIGZ1bmN0aW9uXG4gICAgaWYgZ2V0dGVyPyAmJiAhXy5pc0Z1bmN0aW9uIGdldHRlclxuICAgICAgdGhyb3cgbmV3IEVycm9yIFwiRXJyb3IgcmVzb2x2aW5nICN7cHJvcE5hbWV9LiBTY2hlbWEgZ2V0dGVyIG11c3QgYmUgYSBmdW5jdGlvbi5cIlxuICAgICMgLSBUaHJvdyBhbiBlcnJvciBpZiBzZXR0ZXIgaXMgbm90IGEgZnVuY3Rpb25cbiAgICBpZiBzZXR0ZXI/ICYmICFfLmlzRnVuY3Rpb24gc2V0dGVyXG4gICAgICB0aHJvdyBuZXcgRXJyb3IgXCJFcnJvciByZXNvbHZpbmcgI3twcm9wTmFtZX0uIFNjaGVtYSBzZXR0ZXIgbXVzdCBiZSBhIGZ1bmN0aW9uLlwiXG5cbiAgICB2YWxpZGF0ZSA/PSBbXVxuICAgICMgLSBJZiB2YWxpZGF0ZSBpcyBhIHNpbmdsZSBmdW5jdGlvbiwgdHJhbnNmb3JtIHRvIGFuIGFycmF5IHdpdGggb25lIG1lbWJlclxuICAgIGlmICFfLmlzQXJyYXkodmFsaWRhdGUpXG4gICAgICB2YWxpZGF0ZSA9IFt2YWxpZGF0ZV1cbiAgICAjIC0gQ2hlY2sgdGhhdCBhbGwgdmFsaWRhdGUgYXJlIGEgZnVuY3Rpb24sIHRocm93IGFuIGVycm9yIGlmIGl0IGlzIG5vdC5cbiAgICBmb3IgZm4gaW4gdmFsaWRhdGVcbiAgICAgIGlmICFfLmlzRnVuY3Rpb24gZm5cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yIFwiRXJyb3IgcmVzb2x2aW5nICN7cHJvcE5hbWV9LiBTY2hlbWEgdmFsaWRhdGUgbXVzdCBiZSBhIGZ1bmN0aW9uIG9yIGFycmF5IG9mIGZ1bmN0aW9ucy5cIlxuXG4gICAgIyAtIFJlc29sdmUgdGhlIGRlY2xhcmVkIHR5cGVcbiAgICBkZWZpbml0aW9uLnR5cGUgPSBUeXBlcy5yZXNvbHZlVHlwZSB0eXBlXG5cbiAgICAjIC0gSWYgdHlwZSBjb3VsZCBub3QgYmUgcmVzb2x2ZWQsIHRocm93IGFuIGVycm9yXG4gICAgaWYgIWRlZmluaXRpb24udHlwZT9cbiAgICAgIHRocm93IG5ldyBFcnJvciBcIkVycm9yIHJlc29sdmluZyAje3Byb3BOYW1lfS4gVW5yZWNvZ25pemVkIHR5cGUgI3t0eXBlfVwiXG5cbiAgICAjIGBkZWZhdWx0YCBpcyBhIHJlc2VydmVkIHdvcmQsIHNvIHdlIGNhbid0IGRvIHRoZSBuaWNlIGNsZWFuIGRlbmF0dXJlZCBhc3NpZ25tZW50XG4gICAgZGVmaW5pdGlvbi5kZWZhdWx0ID0gcHJvcENvbmZpZy5kZWZhdWx0XG4gICAgZGVmaW5pdGlvbi5nZXR0ZXIgPSBnZXR0ZXJcbiAgICBkZWZpbml0aW9uLnNldHRlciA9IHNldHRlclxuICAgIGRlZmluaXRpb24udmFsaWRhdGUgPSB2YWxpZGF0ZVxuICAgIGRlZmluaXRpb24ucmVxdWlyZWQgPSByZXF1aXJlZFxuXG4gICAgIyBhbGxvdyBhbnkgY3VzdG9tIHByb3BlcnRpZXMgdG8gYmUgZXhwb3NlZCBvbiB0aGUgZGVmaW5pdGlvbiBvYmplY3RcbiAgICBkZWZpbml0aW9uID0gXy5leHRlbmQge30sIHByb3BDb25maWcsIGRlZmluaXRpb25cblxuICAgICMgUmV0dXJuIGEgdmFsaWQgcHJvcGVydHkgY29uZmlndXJhdGlvblxuICAgIHJldHVybiBkZWZpbml0aW9uXG5cbiAgbmFtZUZ1bmN0aW9uIDogKG5hbWUsIGZuKSA9PlxuICAgIGZuU3RyID0gXCJyZXR1cm4gZnVuY3Rpb24gI3tuYW1lfSgpe3JldHVybiBmbi5hcHBseSh0aGlzLCBhcmd1bWVudHMpfVwiXG4gICAgdHJ5XG4gICAgICByZW5hbWVkID0gbmV3IEZ1bmN0aW9uKCdmbicsIGZuU3RyKShmbilcbiAgICBjYXRjaCBlcnJcbiAgICAgIHRocm93IG5ldyBFcnJvciBcIiN7bmFtZX0gaXMgbm90IGEgdmFsaWQgZnVuY3Rpb24gbmFtZS5cIlxuXG4gICAgXy5leHRlbmQgcmVuYW1lZCwgZm5cbiAgICBfLmV4dGVuZCByZW5hbWVkLnByb3RvdHlwZSwgZm4ucHJvdG90eXBlXG5cbiAgICByZXR1cm4gcmVuYW1lZFxuXG4gICMgIyMjIGNyZWF0ZVxuICAjIENyZWF0ZXMgYSBuZXcgU2NoZW1hIGNvbnN0cnVjdG9yXG4gIGNyZWF0ZSA6IChhcmdzLi4uKSA9PlxuICAgIGZhY3RvcnkgPSBAXG4gICAgIyBJZiB0aGUgZmlyc3QgYXJndW1lbnQgaXMgYSBzdHJpbmcsIHRoZW4gdGhlIFNjaGVtYSBpcyBiZWluZyBuYW1lZCAmIHJlZ2lzdGVyZWQuIE90aGVyd2lzZSwgaXQgaXMgYmVpbmdcbiAgICAjIGNyZWF0ZWQgYW5vbnltb3VzbHksIGFuZCB3ZSBuZWVkIHRvIGdpdmUgaXQgYSB1dWlkIGZvciByZWdpc3RyYXRpb24uXG4gICAgaWYgIV8uaXNTdHJpbmcoYXJnc1swXSlcbiAgICAgIGFyZ3MudW5zaGlmdCBAZ2VuZXJhdGVOYW1lKClcblxuICAgICMgR2V0IG5hbWUsIGNvbmZpZywgYW5kIG9wdGlvbnMgZnJvbSB0aGUgY3JlYXRlIGFyZ3VtZW50c1xuICAgIFtuYW1lLCBzY2hlbWFDb25maWcsIG9wdHNdID0gYXJnc1xuXG4gICAgIyBTZXQgb3B0aW9ucywgZGVmYXVsdGluZyB0byB0aGUgU2NoZW1pbmcuREVGQVVMVF9PUFRJT05TXG4gICAgb3B0cyA9IF8uZGVmYXVsdHMgKG9wdHMgfHwge30pLCBAREVGQVVMVF9PUFRJT05TXG5cbiAgICAjIE5vcm1hbGl6ZWQgU2NoZW1hIGlzIGNhcHR1cmVkIGluIGNsb3N1cmVcbiAgICBub3JtYWxpemVkU2NoZW1hID0ge31cblxuICAgICMgQ3JlYXRlIHRoZSBuZXcgTW9kZWxcbiAgICBjbGFzcyBNb2RlbFxuICAgICAgIyBfX3NjaGVtYUlkIHByb3BlcnR5IHJlZmVyZW5jZXMgdGhlIHNjaGVtYSBuYW1lIGFuZCBpZGVudGlmaWVzIFNjaGVtYSBjb25zdHJ1Y3RvcnMgZnJvbSBhbnkgb3RoZXIgZnVuY3Rpb25cbiAgICAgIEBfX3NjaGVtYUlkICAgICAgIDogbmFtZVxuXG4gICAgICAjICMjIyBkZWZpbmVQcm9wZXJ0eVxuICAgICAgIyBEZWZpbmVzIGEgcHJvcGVydHkgb24gdGhlIG5vcm1hbGl6ZWQgc2NoZW1hLCB3aGljaCBpcyB1c2VkIGF0IHRpbWUgb2YgaW5zdGFuY2UgY29uc3RydWN0aW9uXG4gICAgICBAZGVmaW5lUHJvcGVydHkgICA6IChwcm9wTmFtZSwgcHJvcENvbmZpZykgLT5cbiAgICAgICAgaWYgIV8uaXNTdHJpbmcocHJvcE5hbWUpXG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yIFwiRmlyc3QgYXJndW1lbnQ6IHByb3BlcnR5IG5hbWUgbXVzdCBiZSBhIHN0cmluZy5cIlxuICAgICAgICBpZiAhcHJvcENvbmZpZz9cbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IgXCJTZWNvbmQgYXJndW1lbnQ6IHByb3BlcnR5IGNvbmZpZ3VyYXRpb24gaXMgcmVxdWlyZWQuXCJcbiAgICAgICAgbm9ybWFsaXplZFNjaGVtYVtwcm9wTmFtZV0gPSBmYWN0b3J5Lm5vcm1hbGl6ZVByb3BlcnR5Q29uZmlnKHByb3BDb25maWcsIHByb3BOYW1lKVxuXG4gICAgICAjICMjIyBkZWZpbmVQcm9wZXJ0aWVzXG4gICAgICAjIENvbnZlbmllbmNlIG1ldGhvZCBmb3IgZGVmaW5pbmcgcHJvcGVydGllcyBpbiBidWxrXG4gICAgICBAZGVmaW5lUHJvcGVydGllcyA6IChjb25maWcpIC0+XG4gICAgICAgIGlmICFfLmlzUGxhaW5PYmplY3QoY29uZmlnKVxuICAgICAgICAgIHRocm93IG5ldyBFcnJvciBcIkZpcnN0IGFyZ3VtZW50OiBwcm9wZXJ0aWVzIG11c3QgYmUgYW4gb2JqZWN0LlwiXG4gICAgICAgIGZvciBrLCB2IG9mIGNvbmZpZ1xuICAgICAgICAgIEBkZWZpbmVQcm9wZXJ0eSBrLCB2XG5cbiAgICAgICMgIyMjIGdldFByb3BlcnRpZXNcbiAgICAgICMgcmV0dXJucyBhIGNsb25lIG9mIHRoZSBub3JtYWxpemVkIFNjaGVtYVxuICAgICAgQGdldFByb3BlcnRpZXMgOiAtPlxuICAgICAgICByZXR1cm4gXy5jbG9uZURlZXAgbm9ybWFsaXplZFNjaGVtYVxuXG4gICAgICAjICMjIyBnZXRQcm9wZXJ0eVxuICAgICAgIyByZXR1cm5zIGEgY2xvbmUgb2YgdGhlIG5vcm1hbGl6ZWQgU2NoZW1hIHByb3BlcnR5XG4gICAgICBAZ2V0UHJvcGVydHkgOiAocHJvcE5hbWUpIC0+XG4gICAgICAgIHJldHVybiBfLmNsb25lRGVlcCBub3JtYWxpemVkU2NoZW1hW3Byb3BOYW1lXVxuXG4gICAgICAjICMjIyBlYWNoUHJvcGVydHlcbiAgICAgICMgSXRlcmF0ZXMgb3ZlciBlYWNoIHByb3BlcnR5IG5hbWUgYW5kIGNvbmZpZ3VyYXRpb24gb2YgdGhlIHNjaGVtYSwgaW52b2tpbmcgdGhlIHByb3ZpZGVkIGNhbGxiYWNrXG4gICAgICBAZWFjaFByb3BlcnR5IDogKGNiKSAtPlxuICAgICAgICBpZiAhXy5pc0Z1bmN0aW9uKGNiKVxuICAgICAgICAgIHRocm93IG5ldyBFcnJvciBcIkZpcnN0IGFyZ3VtZW50OiBjYWxsYmFjayBtdXN0IGJlIGEgZnVuY3Rpb24uXCJcbiAgICAgICAgZm9yIHByb3BOYW1lLCBwcm9wQ29uZmlnIG9mIG5vcm1hbGl6ZWRTY2hlbWFcbiAgICAgICAgICBjYiBwcm9wTmFtZSwgXy5jbG9uZURlZXAgcHJvcENvbmZpZ1xuXG4gICAgICAjICMjIyB2YWxpZGF0ZVxuICAgICAgIyBSdW4gdmFsaWRhdGlvbiBvbiBhbiBpbnN0YW5jZSBvZiB0aGUgc2NoZW1hXG4gICAgICBAdmFsaWRhdGUgOiAoaW5zdGFuY2UpIC0+XG4gICAgICAgICMgQ3JlYXRlIGVycm9ycyBoYXNoIHRoYXQgd2lsbCBiZSByZXR1cm5lZCBvbiBhbnkgdmFsaWRhdGlvbiBmYWlsdXJlLlxuICAgICAgICBlcnJvcnMgPSB7fVxuXG4gICAgICAgICMgRmxhZyB2YWxpZGF0aW5nIHN0YXRlIHRvIHByZXZlbnQgaW5maW5pdGUgbG9vcCBpbiB0aGUgY2FzZSBvZiBjaXJjdWxhciByZWZlcmVuY2VzXG4gICAgICAgIGlmIGluc3RhbmNlLl92YWxpZGF0aW5nIHRoZW4gcmV0dXJuIG51bGxcbiAgICAgICAgaW5zdGFuY2UuX3ZhbGlkYXRpbmcgPSB0cnVlXG5cbiAgICAgICAgIyBGYWN0b3JlZCBjb2RlIHRvIHB1c2ggZXJyb3IgbWVzc2FnZXMgb250byB0aGUgZXJyb3JzIGhhc2hcbiAgICAgICAgcHVzaEVycm9yID0gKGtleSwgZXJyb3IpIC0+XG4gICAgICAgICAgaWYgXy5pc0FycmF5IGVycm9yXG4gICAgICAgICAgICByZXR1cm4gcHVzaEVycm9yKGtleSwgZXJyKSBmb3IgZXJyIGluIGVycm9yXG4gICAgICAgICAgaWYgIV8uaXNTdHJpbmcgZXJyb3JcbiAgICAgICAgICAgIGVycm9yID0gJ1ZhbGlkYXRpb24gZXJyb3Igb2NjdXJyZWQuJ1xuICAgICAgICAgIGVycm9yc1trZXldID89IFtdXG4gICAgICAgICAgZXJyb3JzW2tleV0ucHVzaCBlcnJvclxuXG4gICAgICAgICMgQXBwbHkgdmFsaWRhdGlvbiBydWxlc1xuICAgICAgICBmb3Iga2V5LCB2YWx1ZSBvZiBub3JtYWxpemVkU2NoZW1hXG4gICAgICAgICAge3ZhbGlkYXRlLCByZXF1aXJlZH0gPSB2YWx1ZVxuXG4gICAgICAgICAgIyAtIFJldHJpZXZlIHZhbHVlLiBUaGlzIHdpbGwgYmUgYWZmZWN0ZWQgYnkgZ2V0dGVycy5cbiAgICAgICAgICB2YWwgPSBpbnN0YW5jZVtrZXldXG5cbiAgICAgICAgICAjIC0gSWYgdGhlIGZpZWxkIGlzIHJlcXVpcmVkIGFuZCBub3QgZGVmaW5lZCwgcHVzaCB0aGUgZXJyb3IgYW5kIGJlIGRvbmVcbiAgICAgICAgICBpZiByZXF1aXJlZCAmJiAhdmFsP1xuICAgICAgICAgICAgcmVxdWlyZWRNZXNzYWdlID0gaWYgXy5pc1N0cmluZyhyZXF1aXJlZCkgdGhlbiByZXF1aXJlZCBlbHNlIFwiRmllbGQgaXMgcmVxdWlyZWQuXCJcbiAgICAgICAgICAgIHB1c2hFcnJvciBrZXksIHJlcXVpcmVkTWVzc2FnZVxuICAgICAgICAgICMgLSBPbmx5IHJ1biB2YWxpZGF0aW9uIG9uIGZpZWxkcyB0aGF0IGFyZSBkZWZpbmVkXG4gICAgICAgICAgaWYgdmFsP1xuICAgICAgICAgICAge3R5cGV9ID0gbm9ybWFsaXplZFNjaGVtYVtrZXldXG5cbiAgICAgICAgICAgICMgLSBSdW4gZWFjaCB2YWxpZGF0b3Igb24gdGhlIGZpZWxkIHZhbHVlXG4gICAgICAgICAgICBmb3IgdmFsaWRhdG9yIGluIHZhbGlkYXRlXG4gICAgICAgICAgICAgIGVyciA9IHRydWVcbiAgICAgICAgICAgICAgIyAtIEFjY2VwdCBlcnJvciBzdHJpbmdzIHRoYXQgYXJlIHJldHVybmVkLCBvciBlcnJvcnMgdGhhdCBhcmUgdGhyb3duIGR1cmluZyBwcm9jZXNzaW5nXG4gICAgICAgICAgICAgIHRyeVxuICAgICAgICAgICAgICAgIGVyciA9IHZhbGlkYXRvci5jYWxsKGluc3RhbmNlLCB2YWwpXG4gICAgICAgICAgICAgIGNhdGNoIGVcbiAgICAgICAgICAgICAgICBpZiBlIHRoZW4gZXJyID0gZS5tZXNzYWdlXG4gICAgICAgICAgICAgICMgLSBJZiBhbnkgdmFsaWRhdGlvbiBlcnJvcnMgYXJlIGRldGVjdGVkLCBwdXNoIHRoZW1cbiAgICAgICAgICAgICAgaWYgZXJyICE9IHRydWUgdGhlbiBwdXNoRXJyb3Iga2V5LCBlcnJcblxuICAgICAgICAgICAgIyAtIEFkZGl0aW9uYWxseSwgaWYgdGhlIHByb3BlcnR5IGlzIGEgbmVzdGVkIHNjaGVtYSwgcnVuIGl0cyB2YWxpZGF0aW9uXG4gICAgICAgICAgICBpZiB0eXBlLnN0cmluZyA9PSAnc2NoZW1hJ1xuICAgICAgICAgICAgICBjaGlsZEVycm9ycyA9IHR5cGUuY2hpbGRUeXBlLnZhbGlkYXRlLmNhbGwoaW5zdGFuY2UsIHZhbClcbiAgICAgICAgICAgICAgZm9yIGssIHYgb2YgY2hpbGRFcnJvcnNcbiAgICAgICAgICAgICAgICAjICAgLSBUaGUga2V5IG9uIHRoZSBlcnJvcnMgaGFzaCBzaG91bGQgYmUgdGhlIHBhdGggdG8gdGhlIGZpZWxkIHRoYXQgaGFkIGEgdmFsaWRhdGlvbiBlcnJvclxuICAgICAgICAgICAgICAgIHB1c2hFcnJvciBcIiN7a2V5fS4je2t9XCIsIHZcbiAgICAgICAgICAgICMgLSBJZiB0aGUgcHJvcGVydHkgaXMgYW4gYXJyYXkgb2Ygc2NoZW1hcywgcnVuIHZhbGlkYXRpb24gb24gZWFjaCBtZW1iZXIgb2YgdGhlIGFycmF5XG4gICAgICAgICAgICBpZiB0eXBlLnN0cmluZyA9PSAnYXJyYXknICYmIHR5cGUuY2hpbGRUeXBlLnN0cmluZyA9PSAnc2NoZW1hJ1xuICAgICAgICAgICAgICBmb3IgbWVtYmVyLCBpIGluIHZhbFxuICAgICAgICAgICAgICAgIGNoaWxkRXJyb3JzID0gdHlwZS5jaGlsZFR5cGUuY2hpbGRUeXBlLnZhbGlkYXRlLmNhbGwoaW5zdGFuY2UsIG1lbWJlcilcbiAgICAgICAgICAgICAgICBmb3IgaywgdiBvZiBjaGlsZEVycm9yc1xuICAgICAgICAgICAgICAgICAgIyAgIC0gQWdhaW4sIHRoZSBrZXkgb24gdGhlIGVycm9ycyBoYXNoIHNob3VsZCBiZSB0aGUgcGF0aCB0byB0aGUgZmllbGQgdGhhdCBoYWQgYSB2YWxpZGF0aW9uIGVycm9yXG4gICAgICAgICAgICAgICAgICBwdXNoRXJyb3IgXCIje2tleX1bI3tpfV0uI3trfVwiLCB2XG5cbiAgICAgICAgICAjIFVuc2V0IGZsYWcsIGluZGljYXRpbmcgdmFsaWRhdGlvbiBpcyBjb21wbGV0ZVxuICAgICAgICBpbnN0YW5jZS5fdmFsaWRhdGluZyA9IGZhbHNlXG5cbiAgICAgICAgIyBSZXR1cm4gbnVsbCBpZiBubyB2YWxpZGF0aW9uIGVycnJvcnMgb2N1cnJlZFxuICAgICAgICBpZiBfLnNpemUoZXJyb3JzKSA9PSAwXG4gICAgICAgICAgcmV0dXJuIG51bGxcbiAgICAgICAgZWxzZVxuICAgICAgICAgIHJldHVybiBlcnJvcnNcblxuICAgICAgIyAjIyMgY29uc3RydWN0b3JcbiAgICAgICMgQ29uc3RydWN0b3IgdGhhdCBidWlsZHMgaW5zdGFuY2VzIG9mIHRoZSBTY2hlbWFcbiAgICAgIGNvbnN0cnVjdG9yICAgICAgIDogKGluaXRpYWxTdGF0ZSkgLT5cblxuICAgICAgICAjIHR1cm4gYHRoaXNgIGludG8gYSBNb2RlbCBpbnN0YW5jZVxuICAgICAgICBJbnN0YW5jZUZhY3RvcnkuY3JlYXRlKEAsIG5vcm1hbGl6ZWRTY2hlbWEsIGluaXRpYWxTdGF0ZSwgb3B0cylcblxuICAgIE1vZGVsID0gQG5hbWVGdW5jdGlvbiBuYW1lLCBNb2RlbFxuXG4gICAgIyBEZWZpbmUgcHJvcGVydGllcyBvbiB0aGUgU2NoZW1hIGJhc2VkIG9uIHRoZSBzY2hlbWEgY29uZmlndXJhdGlvblxuICAgIGlmIHNjaGVtYUNvbmZpZz8gdGhlbiBNb2RlbC5kZWZpbmVQcm9wZXJ0aWVzIHNjaGVtYUNvbmZpZ1xuXG4gICAgIyBSZWdpc3RlciB0aGUgbmV3IFNjaGVtYSBieSB0aGUgbmFtZSBwcm92aWRlZCBvciBnZW5lcmF0ZWRcbiAgICBSZWdpc3RyeS5yZWdpc3RlciBuYW1lLCBNb2RlbFxuXG4gICAgcmV0dXJuIE1vZGVsXG5cbm1vZHVsZS5leHBvcnRzID0gbmV3IE1vZGVsRmFjdG9yeSgpXG4iLCIjIEludGVybmFsIHJlZ2lzdHJ5IGZvciBzY2hlbWFzIGNyZWF0ZWQgYnkgYFNjaGVtaW5nLmNyZWF0ZWAuIFNjaGVtYXMgYXJlIHJlZ2lzdGVyZWQgYnkgdGhlaXIgbmFtZSwgd2hpY2ggaXMgZWl0aGVyXG4jIHByb3ZpZGVkIGF0IHRpbWUgb2YgY3JlYXRpb24sIG9yIGdlbmVyYXRlZCBhcyBhIHV1aWQuXG5jbGFzcyBSZWdpc3RyeVxuICBjb25zdHJ1Y3RvciA6IC0+XG4gICAgQHNjaGVtYXMgPSB7fVxuXG4gICMgVXNlZCBpbnRlcm5hbGx5IGFzIHBhcnQgb2YgYFNjaGVtaW5nLmNyZWF0ZWAsIGRvIG5vdCBuZWVkIHRvIGV4cG9zZSByZWdpc3RyYXRpb24gb3V0c2lkZSBvZiBTY2hlbWEgY3JlYXRpb24uXG4gIHJlZ2lzdGVyIDogKG5hbWUsIG1vZGVsKSA9PlxuICAgICMgVGhyb3cgYW4gZXJyb3Igb24gbmFtaW5nIGNvbGxpc2lvbnNcbiAgICBpZiBAc2NoZW1hc1tuYW1lXVxuICAgICAgdGhyb3cgbmV3IEVycm9yIFwiTmFtaW5nIGNvbmZsaWN0IGVuY291bnRlcmVkLiBNb2RlbCAje25hbWV9IGFscmVhZHkgZXhpc3RzXCJcbiAgICBAc2NoZW1hc1tuYW1lXSA9IG1vZGVsXG5cbiAgIyAjIyMgZ2V0XG4gICMgUmV0cmlldmVzIGEgc2NoZW1hIGJ5IHJlZ2lzdGVyZWQgbmFtZVxuICBnZXQgOiAobmFtZSkgPT5cbiAgICByZXR1cm4gQHNjaGVtYXNbbmFtZV1cblxuICAjICMjIyByZXNldFxuICAjIFJlc2V0cyB0aGUgc3RhdGUgb2YgdGhlIFNjaGVtYSByZWdpc3RyeS4gTWFpbmx5IGV4cG9zZWQgZm9yIHRlc3RpbmcsIGJ1dCBjb3VsZCBoYXZlIHVzZSBpbiBwcm9kdWN0aW9uLlxuICByZXNldCA6ID0+XG4gICAgQHNjaGVtYXMgPSB7fVxuXG5tb2R1bGUuZXhwb3J0cyA9IG5ldyBSZWdpc3RyeSgpIiwiVHlwZXMgPSByZXF1aXJlICcuL1R5cGVzJ1xuUmVnaXN0cnkgPSByZXF1aXJlICcuL1JlZ2lzdHJ5J1xuQ2hhbmdlTWFuYWdlciA9IHJlcXVpcmUgJy4vQ2hhbmdlTWFuYWdlcidcbk1vZGVsRmFjdG9yeSA9IHJlcXVpcmUgJy4vTW9kZWxGYWN0b3J5J1xuSW5zdGFuY2VGYWN0b3J5ID0gcmVxdWlyZSAnLi9JbnN0YW5jZUZhY3RvcnknXG5cbntUWVBFUywgTkVTVEVEX1RZUEVTLCByZXNvbHZlVHlwZX0gPSBUeXBlc1xue1RIUk9UVExFLCBzZXRUaHJvdHRsZSwgcmVnaXN0ZXJRdWV1ZUNhbGxiYWNrLCB1bnJlZ2lzdGVyUXVldWVDYWxsYmFjayxcbnJlZ2lzdGVyUmVzb2x2ZUNhbGxiYWNrLCB1bnJlZ2lzdGVyUmVzb2x2ZUNhbGxiYWNrLCBmbHVzaH0gPSBDaGFuZ2VNYW5hZ2VyXG57REVGQVVMVF9PUFRJT05TLCBub3JtYWxpemVQcm9wZXJ0eUNvbmZpZywgY3JlYXRlfSA9IE1vZGVsRmFjdG9yeVxue3V1aWR9ID0gSW5zdGFuY2VGYWN0b3J5XG57Z2V0LCByZXNldH0gPSBSZWdpc3RyeVxuXG5cbnJlc2V0ID0gLT5cbiAgUmVnaXN0cnkucmVzZXQoKVxuICBDaGFuZ2VNYW5hZ2VyLnJlc2V0KClcblxuU2NoZW1pbmcgPSB7XG4gIFRZUEVTLCBORVNURURfVFlQRVMsIERFRkFVTFRfT1BUSU9OUywgVEhST1RUTEUsXG5cbiAgdXVpZCwgZ2V0LCByZXNldCxcblxuICByZXNvbHZlVHlwZSwgbm9ybWFsaXplUHJvcGVydHlDb25maWdcblxuICBzZXRUaHJvdHRsZSwgcmVnaXN0ZXJRdWV1ZUNhbGxiYWNrLCB1bnJlZ2lzdGVyUXVldWVDYWxsYmFjayxcbiAgcmVnaXN0ZXJSZXNvbHZlQ2FsbGJhY2ssIHVucmVnaXN0ZXJSZXNvbHZlQ2FsbGJhY2ssXG5cbiAgZmx1c2gsIGNyZWF0ZVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IFNjaGVtaW5nIiwiXyA9IHJlcXVpcmUgJ2xvZGFzaCdcblxuY2xhc3MgVHlwZXNcbiAgIyAjIyMgVFlQRVNcbiAgIyMjXG4gICAgU2NoZW1pbmcgZXhwb3J0cyB0aGUgZGVmYXVsdCB0eXBlcyB0aGF0IGl0IHVzZXMgZm9yIHBhcnNpbmcgc2NoZW1hcy4gWW91IGNhbiBleHRlbmQgd2l0aCBjdXN0b20gdHlwZXMsIG9yXG4gICAgb3ZlcnJpZGUgdGhlIGlkZW50aWZpZXIgLyBwYXJzZXIgZnVuY3Rpb25zIG9mIHRoZSBkZWZhdWx0IHR5cGVzLiBBIGN1c3RvbSB0eXBlIHNob3VsZCBwcm92aWRlOlxuICAgICAtIGN0b3IgKG9wdGlvbmFsKSAtIFVzZWQgaW4gc2NoZW1hIGRlZmluaXRpb25zIHRvIGRlY2xhcmUgYSB0eXBlLiBgU2NoZW1pbmcuY3JlYXRlIG5hbWUgOiBTdHJpbmdgXG4gICAgIC0gc3RyaW5nIC0gVXNlZCBpbiBzY2hlbWEgZGVmaW5pdGlvbnMgdG8gZGVjbGFyZSBhIHR5cGUuIGBTY2hlbWluZy5jcmVhdGUgbmFtZSA6ICdzdHJpbmcnYFxuICAgICAtIGlkZW50aWZpZXIgLSBGdW5jdGlvbiwgcmV0dXJucyB0cnVlIG9yIGZhbHNlLiBEZXRlcm1pbmVzIHdoZXRoZXIgYSB2YWx1ZSBuZWVkcyB0byBiZSBwYXJzZWQuXG4gICAgIC0gcGFyc2VyIC0gRnVuY3Rpb24sIHBhcnNlcyBhIHZhbHVlIGludG8gdGhlIHR5cGUuXG4gICMjI1xuICBUWVBFUyA6XG4gICAgU3RyaW5nICA6XG4gICAgICBjdG9yICAgICAgIDogU3RyaW5nXG4gICAgICBzdHJpbmcgICAgIDogJ3N0cmluZydcbiAgICAgIGlkZW50aWZpZXIgOiBfLmlzU3RyaW5nXG4gICAgICBwYXJzZXIgICAgIDogKHZhbCkgLT5cbiAgICAgICAgJycgKyB2YWxcbiAgICAgIGVxdWFscyAgICAgOiAoYSwgYikgLT4gYT09YlxuICAgIE51bWJlciAgOlxuICAgICAgY3RvciAgICAgICA6IE51bWJlclxuICAgICAgc3RyaW5nICAgICA6ICdudW1iZXInXG4gICAgICBpZGVudGlmaWVyIDogXy5pc051bWJlclxuICAgICAgcGFyc2VyICAgICA6IHBhcnNlRmxvYXRcbiAgICAgIGNvbXBhcmF0b3IgOiAoYSwgYikgLT4gYT09YlxuICAgICAgZXF1YWxzICAgICA6IChhLCBiKSAtPiBhPT1iXG4gICAgSW50ZWdlciA6XG4gICAgICBzdHJpbmcgICAgIDogJ2ludGVnZXInXG4gICAgICBpZGVudGlmaWVyIDogKHZhbCkgLT5cbiAgICAgICAgXy5pc051bWJlcih2YWwpICYmIHZhbCAlIDEgPT0gMFxuICAgICAgcGFyc2VyICAgICA6IHBhcnNlSW50XG4gICAgICBlcXVhbHMgICAgIDogKGEsIGIpIC0+IGE9PWJcbiAgICBEYXRlICAgIDpcbiAgICAgIGN0b3IgICAgICAgOiBEYXRlXG4gICAgICBzdHJpbmcgICAgIDogJ2RhdGUnXG4gICAgICBpZGVudGlmaWVyIDogXy5pc0RhdGVcbiAgICAgIHBhcnNlciAgICAgOiAodmFsKSAtPlxuICAgICAgICBuZXcgRGF0ZSB2YWxcbiAgICAgIGVxdWFscyAgICAgOiAoYSwgYikgLT4gYT8udmFsdWVPZigpID09IGI/LnZhbHVlT2YoKVxuICAgIEJvb2xlYW4gOlxuICAgICAgY3RvciAgICAgICA6IEJvb2xlYW5cbiAgICAgIHN0cmluZyAgICAgOiAnYm9vbGVhbidcbiAgICAgIGlkZW50aWZpZXIgOiBfLmlzQm9vbGVhblxuICAgICAgcGFyc2VyICAgICA6ICh2YWwpIC0+XG4gICAgICAgICEhdmFsXG4gICAgICBlcXVhbHMgICAgIDogKGEsIGIpIC0+IGE9PWJcbiAgICBNaXhlZCAgIDpcbiAgICAgIGN0b3IgICAgICAgOiAodmFsKSAtPlxuICAgICAgICB2YWxcbiAgICAgIHN0cmluZyAgICAgOiAnKidcbiAgICAgIGlkZW50aWZpZXIgOiAtPlxuICAgICAgICB0cnVlXG4gICAgICBwYXJzZXIgICAgIDogXy5pZGVudGl0eVxuICAgICAgZXF1YWxzICAgICA6IChhLCBiKSAtPiBhPT1iXG5cbiAgIyAjIyMgTkVTVEVEX1RZUEVTXG4gICMjI1xuICAgIFNwZWNpYWwgdHlwZSBkZWZpbml0aW9ucyBmb3IgbmVzdGVkIHR5cGVzLiBVc2VkIHRvIGlkZW50aWZ5IGFuZCBwYXJzZSBuZXN0ZWQgQXJyYXlzIGFuZCBTY2hlbWFzLlxuICAgIFNob3VsZCBub3QgYmUgZXh0ZW5kZWQgb3Igb3ZlcnJpZGRlbi5cbiAgIyMjXG4gIE5FU1RFRF9UWVBFUyA6XG4gICAgQXJyYXkgIDpcbiAgICAgIGN0b3IgICAgICAgIDogQXJyYXlcbiAgICAgIHN0cmluZyAgICAgIDogJ2FycmF5J1xuICAgICAgaWRlbnRpZmllciAgOiBfLmlzQXJyYXlcbiAgICAgIHBhcnNlciAgICAgIDogXy50b0FycmF5XG4gICAgICBjaGlsZFR5cGUgICA6IG51bGxcbiAgICAgIGNoaWxkUGFyc2VyIDogbnVsbFxuICAgICAgZXF1YWxzICAgICA6IChhLCBiKSAtPiBfLmlzRXF1YWwgYSwgYlxuICAgIFNjaGVtYSA6XG4gICAgICBjdG9yICAgICAgIDogT2JqZWN0XG4gICAgICBzdHJpbmcgICAgIDogJ3NjaGVtYSdcbiAgICAgIGlkZW50aWZpZXIgOiBudWxsXG4gICAgICBwYXJzZXIgICAgIDogbnVsbFxuICAgICAgY2hpbGRUeXBlICA6IG51bGxcbiAgICAgIGVxdWFscyAgICAgOiAoYSwgYikgLT4gYSA9PSBiXG5cblxuICAjIFVzZWQgaW50ZXJuYWxseSB0byByZXNvbHZlIGEgdHlwZSBkZWNsYXJhdGlvbiB0byBpdHMgcHJpbWl0aXZlIHR5cGUuXG4gICMgTWF0Y2hlcyBhIHByaW1pdGl2ZSB0eXBlIGlmIGl0IGlzLi4uXG4gICMgLSBhIHJlZmVyZW5jZSB0byB0aGUgb2JqZWN0IHN0cmFpZ2h0IGZyb20gdGhlIGBTY2hlbWEuVFlQRVNgIG9iamVjdFxuICAjIC0gYSByZWZlcmVuY2UgdG8gdGhlIGBjdG9yYFxuICAjIC0gYSBtYXRjaCB3aXRoIHRoZSB0eXBlIGBzdHJpbmdgIChjYXNlIGluc2Vuc2l0aXZlKVxuICBnZXRQcmltaXRpdmVUeXBlT2YgOiAodHlwZSkgPT5cbiAgICBmb3IgaywgVFlQRSBvZiBAVFlQRVNcbiAgICAgIGlmIHR5cGUgPT0gVFlQRSBvclxuICAgICAgICAgIChUWVBFLmN0b3IgJiYgdHlwZSA9PSBUWVBFLmN0b3IpIG9yXG4gICAgICAgICAgdHlwZT8udG9Mb3dlckNhc2U/KCkgPT0gVFlQRS5zdHJpbmdcblxuICAgICAgICByZXR1cm4gVFlQRVxuXG4gICAgcmV0dXJuIG51bGxcblxuICAjIEZ1bmN0aW9uIHRoYXQgYnVpbGRzIGlkZW50aWZpZXIgYW5kIHBhcnNlciBmb3IgbmVzdGVkIHNjaGVtYSB0eXBlcy4gTmVlZHMgdG8gYmUgZmFjdG9yZWQgb3V0XG4gICMgYmVjYXVzZSBuZXN0ZWQgc2NoZW1hcyBtYXkgYmUgcmVzb2x2ZWQgbGF6aWx5IGF0IGEgbGF0ZXIgdGltZVxuICByZXNvbHZlU2NoZW1hVHlwZSA6ICh0eXBlLCBjaGlsZFR5cGUpID0+XG4gICAgdHlwZS5jaGlsZFR5cGUgPSBjaGlsZFR5cGVcbiAgICB0eXBlLmlkZW50aWZpZXIgPSAodmFsKSAtPlxuICAgICAgcmV0dXJuIHZhbCBpbnN0YW5jZW9mIGNoaWxkVHlwZVxuICAgIHR5cGUucGFyc2VyID0gKHZhbCkgLT5cbiAgICAgIHJldHVybiBuZXcgY2hpbGRUeXBlKHZhbClcblxuICAjICMjIyByZXNvbHZlVHlwZVxuICAjIFJlc29sdmVzIGEgdHlwZSBkZWNsYXJhdGlvbiB0byBhIHByaW1pdGl2ZSBvciBuZXN0ZWQgdHlwZS4gVXNlZCBpbnRlcm5hbGx5IHdoZW4gbm9ybWFsaXppbmcgYSBzY2hlbWEuXG4gIHJlc29sdmVUeXBlIDogKHR5cGVEZWYpID0+XG4gICAgIyAtIEF0dGVtcHQgdG8gcmVzb2x2ZSB0aGUgdHlwZSBkZWNsYXJhdGlvbiB0byBhIHByaW1pdGl2ZSB0eXBlXG4gICAgdHlwZSA9IEBnZXRQcmltaXRpdmVUeXBlT2YgdHlwZURlZlxuXG4gICAgaWYgIXR5cGU/XG4gICAgICAjIC0gSWYgdGhlIHR5cGUgZGVmaW5pdGlvbiBpcyBhbiBhcnJheSBgW11gXG4gICAgICBpZiBfLmlzQXJyYXkgdHlwZURlZlxuICAgICAgICAjICAgLSBTZXQgdGhlIHR5cGUgdG8gYSBjbG9uZSBvZiB0aGUgYXJyYXkgTkVTVEVEX1RZUEVcbiAgICAgICAgdHlwZSA9IF8uY2xvbmVEZWVwIEBORVNURURfVFlQRVMuQXJyYXlcblxuICAgICAgICAjICAgLSBSZWN1cnNlIHRvIHJlc29sdmUgY2hpbGRUeXBlIG9mIGFycmF5IG1lbWJlcnNcbiAgICAgICAgaWYgdHlwZURlZi5sZW5ndGhcbiAgICAgICAgICBjaGlsZFR5cGUgPSBAcmVzb2x2ZVR5cGUodHlwZURlZlswXSlcblxuICAgICAgICAjICAgLSBUaHJvdyBhbiBlcnJvciBpZiB0eXBlIGlzIG5vdCBleHBsaWNpdGx5IGRlY2xhcmVkXG4gICAgICAgIGlmICFjaGlsZFR5cGUgdGhlbiB0aHJvdyBuZXcgRXJyb3IgXCJFcnJvciByZXNvbHZpbmcgdHlwZSBvZiBhcnJheSB2YWx1ZSAje3R5cGVEZWZ9XCJcblxuICAgICAgICB0eXBlLmNoaWxkVHlwZSA9IGNoaWxkVHlwZVxuICAgICAgICAjICAgLSBXcml0ZSBwYXJzZXIgZm9yIGNoaWxkIG1lbWJlcnMgb2YgdGhlIGFycmF5XG4gICAgICAgIHR5cGUuY2hpbGRQYXJzZXIgPSAodmFsKSAtPlxuICAgICAgICAgIGZvciBpbmRleCwgbWVtYmVyIG9mIHZhbFxuICAgICAgICAgICAgaWYgIWNoaWxkVHlwZS5pZGVudGlmaWVyKG1lbWJlcilcbiAgICAgICAgICAgICAgdmFsW2luZGV4XSA9IGNoaWxkVHlwZS5wYXJzZXIobWVtYmVyKVxuXG4gICAgICAgICAgcmV0dXJuIHZhbFxuXG4gICAgICAgICMjI1xuICAgICAgICAtIElmIHRoZSB0eXBlIGRlZmluaXRpb24gaXMgYW4gb2JqZWN0IGB7fWBcbiAgICAgICAgICAtIENyZWF0ZSBhIG5ldyBTY2hlbWEgZnJvbSB0aGUgb2JqZWN0XG4gICAgICAgICAgLSBUcmVhdCB0aGUgZmllbGQgYXMgYSBuZXN0ZWQgU2NoZW1hXG4gICAgICAgICAgLSBTZXQgaWRlbnRpZmllciBhbmQgcGFyc2VyIGZ1bmN0aW9ucyBpbW1lZGlhdGVseVxuICAgICAgICAjIyNcbiAgICAgIGVsc2UgaWYgXy5pc1BsYWluT2JqZWN0IHR5cGVEZWZcbiAgICAgICAgdHlwZSA9IF8uY2xvbmVEZWVwIEBORVNURURfVFlQRVMuU2NoZW1hXG4gICAgICAgIGNoaWxkVHlwZSA9IHJlcXVpcmUoJy4vTW9kZWxGYWN0b3J5JykuY3JlYXRlIHR5cGVEZWZcbiAgICAgICAgQHJlc29sdmVTY2hlbWFUeXBlIHR5cGUsIGNoaWxkVHlwZVxuXG4gICAgICAgICMjI1xuICAgICAgICAtIElmIHRoZSB0eXBlIGRlZmluaXRpb24gaXMgYSByZWZlcmVuY2UgdG8gYSBTY2hlbWEgY29uc3RydWN0b3JcbiAgICAgICAgICAtIFRyZWF0IHRoZSBmaWVsZCBhcyBhIG5lc3RlZCBTY2hlbWFcbiAgICAgICAgICAtIFNldCBpZGVudGlmaWVyIGFuZCBwYXJzZXIgZnVuY3Rpb25zIGltbWVkaWF0ZWx5XG4gICAgICAgICMjI1xuICAgICAgZWxzZSBpZiBfLmlzRnVuY3Rpb24odHlwZURlZikgJiYgdHlwZURlZi5fX3NjaGVtYUlkXG4gICAgICAgIHR5cGUgPSBfLmNsb25lRGVlcCBATkVTVEVEX1RZUEVTLlNjaGVtYVxuICAgICAgICBjaGlsZFR5cGUgPSB0eXBlRGVmXG4gICAgICAgIEByZXNvbHZlU2NoZW1hVHlwZSB0eXBlLCBjaGlsZFR5cGVcblxuICAgICAgICAjIyNcbiAgICAgICAgLSBJZiB0aGUgdHlwZSBkZWZpbml0aW9uIGlzIGEgc3RyaW5nIHRoYXQgYmVnaW5zIHdpdGggU2NoZW1hOiwgc3VjaCBhcyBgJ1NjaGVtYTpDYXInYFxuICAgICAgICAgIC0gSXQgaXMgYXNzdW1lZCB0aGF0IHRoZSBmaWVsZCBpcyBhIHJlZmVyZW5jZSB0byBhIG5lc3RlZCBTY2hlbWEgdGhhdCB3aWxsIGJlIHJlZ2lzdGVyZWQgd2l0aCB0aGUgbmFtZSBDYXIsXG4gICAgICAgIGJ1dCBtYXkgbm90IGJlIHJlZ2lzdGVyZWQgeWV0XG4gICAgICAgICAgLSBUaGUgU2NoZW1hIGlzIG5vdCByZXNvbHZlZCBpbW1lZGlhdGVseVxuICAgICAgICAgIC0gVGhlIHBhcnNlciBhbmQgaWRlbnRpZmllciBmdW5jdGlvbnMgYXJlIHdyaXR0ZW4gYXMgd3JhcHBlcnMsIHNvIHRoYXQgdGhlIGZpcnN0IHRpbWUgdGhleSBhcmUgaW52b2tlZCB0aGUgU2NoZW1hXG4gICAgICAgIHdpbGwgYmUgbG9va2VkIHVwIGF0IHRoYXQgdGltZSB2aWEgYFNjaGVtaW5nLmdldGAsIGFuZCByZWFsIGlkZW50aWZpZXIgYW5kIHBhcnNlciBhcmUgc2V0IGF0IHRoYXQgdGltZS5cbiAgICAgICAgICAtIElmIHRoZSByZWdpc3RlcmVkIFNjaGVtYSBjYW5ub3QgYmUgcmVzb2x2ZWQsIHRocm93IGFuIGVycm9yLlxuICAgICAgICAjIyNcbiAgICAgIGVsc2UgaWYgXy5pc1N0cmluZyh0eXBlRGVmKSAmJiB0eXBlRGVmWy4uLjddID09ICdTY2hlbWE6J1xuICAgICAgICB0eXBlID0gXy5jbG9uZURlZXAgQE5FU1RFRF9UWVBFUy5TY2hlbWFcbiAgICAgICAgY2hpbGRUeXBlID0gdHlwZURlZls3Li5dXG4gICAgICAgIGZvciBmbiBpbiBbJ2lkZW50aWZpZXInLCAncGFyc2VyJ11cbiAgICAgICAgICBkbyAoZm4pID0+XG4gICAgICAgICAgICB0eXBlW2ZuXSA9ICh2YWwpID0+XG4gICAgICAgICAgICAgIGNoaWxkVHlwZSA9IHJlcXVpcmUoJy4vUmVnaXN0cnknKS5nZXQgY2hpbGRUeXBlXG4gICAgICAgICAgICAgIGlmICFjaGlsZFR5cGVcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IgXCJFcnJvciByZXNvbHZpbmcgI3t0eXBlRGVmfSBvbiBsYXp5IGluaXRpYWxpemF0aW9uXCJcbiAgICAgICAgICAgICAgQHJlc29sdmVTY2hlbWFUeXBlIHR5cGUsIGNoaWxkVHlwZVxuXG4gICAgICAgICAgICAgIHJldHVybiB0eXBlW2ZuXSB2YWxcblxuXG4gICAgcmV0dXJuIHR5cGUgfHwgbnVsbFxuXG5tb2R1bGUuZXhwb3J0cyA9IG5ldyBUeXBlcygpXG4iXX0=
;
angular.module('scheming', []).run(function ($rootScope) {
// attach schemingWatch to the Scope prototype
$rootScope.__proto__.schemingWatch = function (model, attrs, callback) {
var unwatch = model.watch(attrs, callback);
this.$on('$destroy', function () {
console.log('$destroy');
unwatch();
});
}
})
.constant('Scheming', window.Scheming)
;