diff --git a/CHANGES.md b/CHANGES.md
index 07679c2..2c0498e 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,14 @@
+**0.4.1**
+ - Fixed bug where form element is required, but no validations
+
+**0.4.0**:
+ - Possibility to handle form data manually using "onSubmit"
+ - Added two more default rules. *isWords* and *isSpecialWords*
+
+**0.3.0**:
+ - Deprecated everything related to buttons automatically added
+ - Added onValid and onInvalid handlers, use those to manipulate submit buttons etc.
+
**0.2.3**:
- Fixed bug where child does not have props property
diff --git a/README.md b/README.md
index 7ef3cdd..bafa788 100644
--- a/README.md
+++ b/README.md
@@ -22,6 +22,7 @@ A form input builder and validator for React JS
- [onError()](#onerror)
- [onValid()](#onvalid)
- [onInvalid()](#oninvalid)
+ - [onChange()](#onchange)
- [Formsy.Mixin](#formsymixin)
- [name](#name)
- [value](#value)
@@ -49,7 +50,7 @@ The main concept is that forms, inputs and validation is done very differently a
## What you can do
- 1. Build any kind of form input components. Not just traditional inputs, but anything you want and get that validation for free
+ 1. Build any kind of form element components. Not just traditional inputs, but anything you want and get that validation for free
2. Add validation rules and use them with simple syntax
@@ -57,6 +58,8 @@ The main concept is that forms, inputs and validation is done very differently a
4. Server validation errors automatically binds to the correct form input component
+ 5. You can dynamically add form elements to your form and they will register/unregister to the form
+
## Install
1. Download from this REPO and use globally (Formsy) or with requirejs
@@ -65,6 +68,12 @@ The main concept is that forms, inputs and validation is done very differently a
## Changes
+**0.7.0**
+ - Dynamic form elements. Add them at any point and they will be registered with the form
+ - **onChange()** handler is called whenever an form element has changed its value or a new form element is added to the form
+ - isNumeric validator now also handles actual numbers, not only strings
+ - Some more tests
+
**0.6.0**
- **onSubmit()** now has the same signature regardless of passing url attribute or not
- **isPristine()** is a new method to handle "touched" form elements (thanks @FoxxMD)
@@ -83,17 +92,6 @@ The main concept is that forms, inputs and validation is done very differently a
- Fixed bug where validation rule refers to a string
- Added "invalidateForm" function when manually submitting the form
-**0.4.1**
- - Fixed bug where form element is required, but no validations
-
-**0.4.0**:
- - Possibility to handle form data manually using "onSubmit"
- - Added two more default rules. *isWords* and *isSpecialWords*
-
-**0.3.0**:
- - Deprecated everything related to buttons automatically added
- - Added onValid and onInvalid handlers, use those to manipulate submit buttons etc.
-
[Older changes](CHANGES.md)
## How to use
@@ -130,7 +128,7 @@ The main concept is that forms, inputs and validation is done very differently a
This code results in a form with a submit button that will POST to /users when clicked. The submit button is disabled as long as the input is empty (required) or the value is not an email (isEmail). On validation error it will show the message: "This is not a valid email".
-#### Building a form element
+#### Building a form element (required)
```javascript
/** @jsx React.DOM */
var Formsy = require('formsy-react');
@@ -166,7 +164,7 @@ This code results in a form with a submit button that will POST to /users when c
}
});
```
-So this is basically how you build your form elements. As you can see it is very flexible, you just have a small API to help you identify the state of the component and set its value.
+The form element component is what gives the form validation functionality to whatever you want to put inside this wrapper. You do not have to use traditional inputs, it can be anything you want and the value of the form element can also be anything you want. As you can see it is very flexible, you just have a small API to help you identify the state of the component and set its value.
## API
@@ -274,6 +272,12 @@ Whenever the form becomes valid the "onValid" handler is called. Use it to chang
```
Whenever the form becomes invalid the "onInvalid" handler is called. Use it to for example revert "onValid" state.
+#### onChange(currentValues)
+```html
+
+```
+"onChange" triggers when setValue is called on your form elements. It is also triggered when dynamic form elements have been added to the form. The "currentValues" is an object where the key is the name of the input and the value is the current value.
+
### Formsy.Mixin
#### name
diff --git a/bower.json b/bower.json
index 0822397..5a45961 100644
--- a/bower.json
+++ b/bower.json
@@ -1,6 +1,6 @@
{
"name": "formsy-react",
- "version": "0.6.0",
+ "version": "0.7.0",
"main": "src/main.js",
"dependencies": {
"react": "^0.11.2"
diff --git a/build/formsy-react.js b/build/formsy-react.js
index 3481860..78f641f 100755
--- a/build/formsy-react.js
+++ b/build/formsy-react.js
@@ -13,7 +13,11 @@ var validationRules = {
return value === true;
},
'isNumeric': function (value) {
- return value.match(/^-?[0-9]+$/)
+ if (typeof value === 'number') {
+ return true;
+ } else {
+ return value.match(/^-?[0-9]+$/);
+ }
},
'isAlpha': function (value) {
return value.match(/^[a-zA-Z]+$/);
@@ -32,6 +36,9 @@ var validationRules = {
},
equals: function (value, eql) {
return value == eql;
+ },
+ equalsField: function (value, field) {
+ return value === this[field];
}
};
@@ -86,6 +93,21 @@ var request = function (method, url, data, contentType, headers) {
});
};
+
+var arraysDiffer = function (arrayA, arrayB) {
+ var isDifferent = false;
+ if (arrayA.length !== arrayB.length) {
+ isDifferent = true;
+ } else {
+ arrayA.forEach(function (item, index) {
+ if (item !== arrayB[index]) {
+ isDifferent = true;
+ }
+ });
+ }
+ return isDifferent;
+};
+
var ajax = {
post: request.bind(null, 'POST'),
put: request.bind(null, 'PUT')
@@ -106,22 +128,31 @@ Formsy.Mixin = {
},
componentWillMount: function () {
+ var configure = function () {
+ // Add validations to the store itself as the props object can not be modified
+ this._validations = this.props.validations || '';
+
+ if (this.props.required) {
+ this._validations = this.props.validations ? this.props.validations + ',' : '';
+ this._validations += 'isValue';
+ }
+ this.props._attachToForm(this);
+ }.bind(this);
+
if (!this.props.name) {
throw new Error('Form Input requires a name property when used');
}
if (!this.props._attachToForm) {
- throw new Error('Form Mixin requires component to be nested in a Form');
+ return setTimeout(function () {
+ if (!this.props._attachToForm) {
+ throw new Error('Form Mixin requires component to be nested in a Form');
+ }
+ configure();
+ }.bind(this), 0);
}
+ configure();
- // Add validations to the store itself as the props object can not be modified
- this._validations = this.props.validations || '';
-
- if (this.props.required) {
- this._validations = this.props.validations ? this.props.validations + ',' : '';
- this._validations += 'isValue';
- }
- this.props._attachToForm(this);
},
// We have to make the validate method is kept when new props are added
@@ -187,7 +218,8 @@ Formsy.Form = React.createClass({displayName: "Form",
getInitialState: function () {
return {
isValid: true,
- isSubmitting: false
+ isSubmitting: false,
+ canChange: false
};
},
getDefaultProps: function () {
@@ -198,7 +230,8 @@ Formsy.Form = React.createClass({displayName: "Form",
onSubmit: function () {},
onSubmitted: function () {},
onValid: function () {},
- onInvalid: function () {}
+ onInvalid: function () {},
+ onChange: function () {}
};
},
@@ -214,6 +247,21 @@ Formsy.Form = React.createClass({displayName: "Form",
this.validateForm();
},
+ componentWillUpdate: function () {
+ var inputKeys = Object.keys(this.inputs);
+
+ // The updated children array is not available here for some reason,
+ // we need to wait for next event loop
+ setTimeout(function () {
+ this.registerInputs(this.props.children);
+
+ var newInputKeys = Object.keys(this.inputs);
+ if (arraysDiffer(inputKeys, newInputKeys)) {
+ this.validateForm();
+ }
+ }.bind(this), 0);
+ },
+
// Update model, submit to url prop and send the model
submit: function (event) {
event.preventDefault();
@@ -326,7 +374,7 @@ Formsy.Form = React.createClass({displayName: "Form",
}.bind(this), {});
},
- setFormPristine: function(isPristine) {
+ setFormPristine: function (isPristine) {
var inputs = this.inputs;
var inputKeys = Object.keys(inputs);
@@ -345,6 +393,9 @@ Formsy.Form = React.createClass({displayName: "Form",
// state of the form itself
validate: function (component) {
+ // Trigger onChange
+ this.state.canChange && this.props.onChange && this.props.onChange(this.getCurrentValues());
+
if (!component.props.required && !component._validations) {
return;
}
@@ -408,6 +459,9 @@ Formsy.Form = React.createClass({displayName: "Form",
allIsValid && this.props.onValid();
!allIsValid && this.props.onInvalid();
+ // Tell the form that it can start to trigger change events
+ this.setState({canChange: true});
+
}.bind(this);
// Run validation again in case affected by other inputs. The
@@ -421,6 +475,11 @@ Formsy.Form = React.createClass({displayName: "Form",
}, index === inputKeys.length - 1 ? onValidationComplete : null);
}.bind(this));
+ // If there are no inputs, it is ready to trigger change events
+ if (!inputKeys.length) {
+ this.setState({canChange: true});
+ }
+
},
// Method put on each input component to register
@@ -458,4 +517,4 @@ module.exports = Formsy;
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"react":"react"}]},{},["./src/main.js"])
-//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcmMvbWFpbi5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsInZhciBSZWFjdCA9IGdsb2JhbC5SZWFjdCB8fCByZXF1aXJlKCdyZWFjdCcpO1xudmFyIEZvcm1zeSA9IHt9O1xudmFyIHZhbGlkYXRpb25SdWxlcyA9IHtcbiAgJ2lzVmFsdWUnOiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICByZXR1cm4gdmFsdWUgIT09ICcnO1xuICB9LFxuICAnaXNFbWFpbCc6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgIHJldHVybiB2YWx1ZS5tYXRjaCgvXigoKFthLXpdfFxcZHxbISNcXCQlJidcXCpcXCtcXC1cXC89XFw/XFxeX2B7XFx8fX5dfFtcXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZdKSsoXFwuKFthLXpdfFxcZHxbISNcXCQlJidcXCpcXCtcXC1cXC89XFw/XFxeX2B7XFx8fX5dfFtcXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZdKSspKil8KChcXHgyMikoKCgoXFx4MjB8XFx4MDkpKihcXHgwZFxceDBhKSk/KFxceDIwfFxceDA5KSspPygoW1xceDAxLVxceDA4XFx4MGJcXHgwY1xceDBlLVxceDFmXFx4N2ZdfFxceDIxfFtcXHgyMy1cXHg1Yl18W1xceDVkLVxceDdlXXxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSl8KFxcXFwoW1xceDAxLVxceDA5XFx4MGJcXHgwY1xceDBkLVxceDdmXXxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSkpKSkqKCgoXFx4MjB8XFx4MDkpKihcXHgwZFxceDBhKSk/KFxceDIwfFxceDA5KSspPyhcXHgyMikpKUAoKChbYS16XXxcXGR8W1xcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0pfCgoW2Etel18XFxkfFtcXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZdKShbYS16XXxcXGR8LXxcXC58X3x+fFtcXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZdKSooW2Etel18XFxkfFtcXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZdKSkpXFwuKSsoKFthLXpdfFtcXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZdKXwoKFthLXpdfFtcXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZdKShbYS16XXxcXGR8LXxcXC58X3x+fFtcXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZdKSooW2Etel18W1xcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0pKSkkL2kpO1xuICB9LFxuICAnaXNUcnVlJzogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgcmV0dXJuIHZhbHVlID09PSB0cnVlO1xuICB9LFxuICAnaXNOdW1lcmljJzogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgcmV0dXJuIHZhbHVlLm1hdGNoKC9eLT9bMC05XSskLylcbiAgfSxcbiAgJ2lzQWxwaGEnOiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICByZXR1cm4gdmFsdWUubWF0Y2goL15bYS16QS1aXSskLyk7XG4gIH0sXG4gICdpc1dvcmRzJzogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgcmV0dXJuIHZhbHVlLm1hdGNoKC9eW2EtekEtWlxcc10rJC8pO1xuICB9LFxuICAnaXNTcGVjaWFsV29yZHMnOiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICByZXR1cm4gdmFsdWUubWF0Y2goL15bYS16QS1aXFxzXFx1MDBDMC1cXHUwMTdGXSskLyk7XG4gIH0sXG4gIGlzTGVuZ3RoOiBmdW5jdGlvbiAodmFsdWUsIG1pbiwgbWF4KSB7XG4gICAgaWYgKG1heCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICByZXR1cm4gdmFsdWUubGVuZ3RoID49IG1pbiAmJiB2YWx1ZS5sZW5ndGggPD0gbWF4O1xuICAgIH1cbiAgICByZXR1cm4gdmFsdWUubGVuZ3RoID49IG1pbjtcbiAgfSxcbiAgZXF1YWxzOiBmdW5jdGlvbiAodmFsdWUsIGVxbCkge1xuICAgIHJldHVybiB2YWx1ZSA9PSBlcWw7XG4gIH1cbn07XG5cbnZhciB0b1VSTEVuY29kZWQgPSBmdW5jdGlvbiAoZWxlbWVudCwga2V5LCBsaXN0KSB7XG4gIHZhciBsaXN0ID0gbGlzdCB8fCBbXTtcbiAgaWYgKHR5cGVvZiAoZWxlbWVudCkgPT0gJ29iamVjdCcpIHtcbiAgICBmb3IgKHZhciBpZHggaW4gZWxlbWVudClcbiAgICAgIHRvVVJMRW5jb2RlZChlbGVtZW50W2lkeF0sIGtleSA/IGtleSArICdbJyArIGlkeCArICddJyA6IGlkeCwgbGlzdCk7XG4gIH0gZWxzZSB7XG4gICAgbGlzdC5wdXNoKGtleSArICc9JyArIGVuY29kZVVSSUNvbXBvbmVudChlbGVtZW50KSk7XG4gIH1cbiAgcmV0dXJuIGxpc3Quam9pbignJicpO1xufTtcblxudmFyIHJlcXVlc3QgPSBmdW5jdGlvbiAobWV0aG9kLCB1cmwsIGRhdGEsIGNvbnRlbnRUeXBlLCBoZWFkZXJzKSB7XG5cbiAgdmFyIGNvbnRlbnRUeXBlID0gY29udGVudFR5cGUgPT09ICd1cmxlbmNvZGVkJyA/ICdhcHBsaWNhdGlvbi8nICsgY29udGVudFR5cGUucmVwbGFjZSgndXJsZW5jb2RlZCcsICd4LXd3dy1mb3JtLXVybGVuY29kZWQnKSA6ICdhcHBsaWNhdGlvbi9qc29uJztcbiAgZGF0YSA9IGNvbnRlbnRUeXBlID09PSAnYXBwbGljYXRpb24vanNvbicgPyBKU09OLnN0cmluZ2lmeShkYXRhKSA6IHRvVVJMRW5jb2RlZChkYXRhKTtcblxuICByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24gKHJlc29sdmUsIHJlamVjdCkge1xuICAgIHRyeSB7XG4gICAgICB2YXIgeGhyID0gbmV3IFhNTEh0dHBSZXF1ZXN0KCk7XG4gICAgICB4aHIub3BlbihtZXRob2QsIHVybCwgdHJ1ZSk7XG4gICAgICB4aHIuc2V0UmVxdWVzdEhlYWRlcignQWNjZXB0JywgJ2FwcGxpY2F0aW9uL2pzb24nKTtcbiAgICAgIHhoci5zZXRSZXF1ZXN0SGVhZGVyKCdDb250ZW50LVR5cGUnLCBjb250ZW50VHlwZSk7XG5cbiAgICAgIC8vIEFkZCBwYXNzZWQgaGVhZGVyc1xuICAgICAgT2JqZWN0LmtleXMoaGVhZGVycykuZm9yRWFjaChmdW5jdGlvbiAoaGVhZGVyKSB7XG4gICAgICAgIHhoci5zZXRSZXF1ZXN0SGVhZGVyKGhlYWRlciwgaGVhZGVyc1toZWFkZXJdKTtcbiAgICAgIH0pO1xuXG4gICAgICB4aHIub25yZWFkeXN0YXRlY2hhbmdlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoeGhyLnJlYWR5U3RhdGUgPT09IDQpIHtcblxuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICB2YXIgcmVzcG9uc2UgPSB4aHIucmVzcG9uc2VUZXh0ID8gSlNPTi5wYXJzZSh4aHIucmVzcG9uc2VUZXh0KSA6IG51bGw7XG4gICAgICAgICAgICBpZiAoeGhyLnN0YXR1cyA+PSAyMDAgJiYgeGhyLnN0YXR1cyA8IDMwMCkge1xuICAgICAgICAgICAgICByZXNvbHZlKHJlc3BvbnNlKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHJlamVjdChyZXNwb25zZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgcmVqZWN0KGUpO1xuICAgICAgICAgIH1cblxuICAgICAgICB9XG4gICAgICB9O1xuICAgICAgeGhyLnNlbmQoZGF0YSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgcmVqZWN0KGUpO1xuICAgIH1cbiAgfSk7XG5cbn07XG52YXIgYWpheCA9IHtcbiAgcG9zdDogcmVxdWVzdC5iaW5kKG51bGwsICdQT1NUJyksXG4gIHB1dDogcmVxdWVzdC5iaW5kKG51bGwsICdQVVQnKVxufTtcbnZhciBvcHRpb25zID0ge307XG5cbkZvcm1zeS5kZWZhdWx0cyA9IGZ1bmN0aW9uIChwYXNzZWRPcHRpb25zKSB7XG4gIG9wdGlvbnMgPSBwYXNzZWRPcHRpb25zO1xufTtcblxuRm9ybXN5Lk1peGluID0ge1xuICBnZXRJbml0aWFsU3RhdGU6IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgX3ZhbHVlOiB0aGlzLnByb3BzLnZhbHVlID8gdGhpcy5wcm9wcy52YWx1ZSA6ICcnLFxuICAgICAgX2lzVmFsaWQ6IHRydWUsXG4gICAgICBfaXNQcmlzdGluZTogdHJ1ZVxuICAgIH07XG4gIH0sXG4gIGNvbXBvbmVudFdpbGxNb3VudDogZnVuY3Rpb24gKCkge1xuXG4gICAgaWYgKCF0aGlzLnByb3BzLm5hbWUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRm9ybSBJbnB1dCByZXF1aXJlcyBhIG5hbWUgcHJvcGVydHkgd2hlbiB1c2VkJyk7XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLnByb3BzLl9hdHRhY2hUb0Zvcm0pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRm9ybSBNaXhpbiByZXF1aXJlcyBjb21wb25lbnQgdG8gYmUgbmVzdGVkIGluIGEgRm9ybScpO1xuICAgIH1cblxuICAgIC8vIEFkZCB2YWxpZGF0aW9ucyB0byB0aGUgc3RvcmUgaXRzZWxmIGFzIHRoZSBwcm9wcyBvYmplY3QgY2FuIG5vdCBiZSBtb2RpZmllZFxuICAgIHRoaXMuX3ZhbGlkYXRpb25zID0gdGhpcy5wcm9wcy52YWxpZGF0aW9ucyB8fCAnJztcblxuICAgIGlmICh0aGlzLnByb3BzLnJlcXVpcmVkKSB7XG4gICAgICB0aGlzLl92YWxpZGF0aW9ucyA9IHRoaXMucHJvcHMudmFsaWRhdGlvbnMgPyB0aGlzLnByb3BzLnZhbGlkYXRpb25zICsgJywnIDogJyc7XG4gICAgICB0aGlzLl92YWxpZGF0aW9ucyArPSAnaXNWYWx1ZSc7XG4gICAgfVxuICAgIHRoaXMucHJvcHMuX2F0dGFjaFRvRm9ybSh0aGlzKTtcbiAgfSxcblxuICAvLyBXZSBoYXZlIHRvIG1ha2UgdGhlIHZhbGlkYXRlIG1ldGhvZCBpcyBrZXB0IHdoZW4gbmV3IHByb3BzIGFyZSBhZGRlZFxuICBjb21wb25lbnRXaWxsUmVjZWl2ZVByb3BzOiBmdW5jdGlvbiAobmV4dFByb3BzKSB7XG4gICAgbmV4dFByb3BzLl9hdHRhY2hUb0Zvcm0gPSB0aGlzLnByb3BzLl9hdHRhY2hUb0Zvcm07XG4gICAgbmV4dFByb3BzLl9kZXRhY2hGcm9tRm9ybSA9IHRoaXMucHJvcHMuX2RldGFjaEZyb21Gb3JtO1xuICAgIG5leHRQcm9wcy5fdmFsaWRhdGUgPSB0aGlzLnByb3BzLl92YWxpZGF0ZTtcbiAgfSxcblxuICAvLyBEZXRhY2ggaXQgd2hlbiBjb21wb25lbnQgdW5tb3VudHNcbiAgY29tcG9uZW50V2lsbFVubW91bnQ6IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnByb3BzLl9kZXRhY2hGcm9tRm9ybSh0aGlzKTtcbiAgfSxcblxuICAvLyBXZSB2YWxpZGF0ZSBhZnRlciB0aGUgdmFsdWUgaGFzIGJlZW4gc2V0XG4gIHNldFZhbHVlOiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgIF92YWx1ZTogdmFsdWUsXG4gICAgICBfaXNQcmlzdGluZTogZmFsc2VcbiAgICB9LCBmdW5jdGlvbiAoKSB7XG4gICAgICB0aGlzLnByb3BzLl92YWxpZGF0ZSh0aGlzKTtcbiAgICB9LmJpbmQodGhpcykpO1xuICB9LFxuICByZXNldFZhbHVlOiBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICBfdmFsdWU6ICcnLFxuICAgICAgX2lzUHJpc3RpbmU6IHRydWVcbiAgICB9LCBmdW5jdGlvbiAoKSB7XG4gICAgICB0aGlzLnByb3BzLl92YWxpZGF0ZSh0aGlzKTtcbiAgICB9KTtcbiAgfSxcbiAgZ2V0VmFsdWU6IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5zdGF0ZS5fdmFsdWU7XG4gIH0sXG4gIGhhc1ZhbHVlOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuc3RhdGUuX3ZhbHVlICE9PSAnJztcbiAgfSxcbiAgZ2V0RXJyb3JNZXNzYWdlOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuaXNWYWxpZCgpIHx8IHRoaXMuc2hvd1JlcXVpcmVkKCkgPyBudWxsIDogdGhpcy5zdGF0ZS5fc2VydmVyRXJyb3IgfHwgdGhpcy5wcm9wcy52YWxpZGF0aW9uRXJyb3I7XG4gIH0sXG4gIGlzVmFsaWQ6IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5zdGF0ZS5faXNWYWxpZDtcbiAgfSxcbiAgaXNQcmlzdGluZTogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLnN0YXRlLl9pc1ByaXN0aW5lO1xuICB9LFxuICBpc1JlcXVpcmVkOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuICEhdGhpcy5wcm9wcy5yZXF1aXJlZDtcbiAgfSxcbiAgc2hvd1JlcXVpcmVkOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuaXNSZXF1aXJlZCgpICYmIHRoaXMuc3RhdGUuX3ZhbHVlID09PSAnJztcbiAgfSxcbiAgc2hvd0Vycm9yOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuICF0aGlzLnNob3dSZXF1aXJlZCgpICYmICF0aGlzLnN0YXRlLl9pc1ZhbGlkO1xuICB9XG59O1xuXG5Gb3Jtc3kuYWRkVmFsaWRhdGlvblJ1bGUgPSBmdW5jdGlvbiAobmFtZSwgZnVuYykge1xuICB2YWxpZGF0aW9uUnVsZXNbbmFtZV0gPSBmdW5jO1xufTtcblxuRm9ybXN5LkZvcm0gPSBSZWFjdC5jcmVhdGVDbGFzcyh7ZGlzcGxheU5hbWU6IFwiRm9ybVwiLFxuICBnZXRJbml0aWFsU3RhdGU6IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgaXNWYWxpZDogdHJ1ZSxcbiAgICAgIGlzU3VibWl0dGluZzogZmFsc2VcbiAgICB9O1xuICB9LFxuICBnZXREZWZhdWx0UHJvcHM6IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgaGVhZGVyczoge30sXG4gICAgICBvblN1Y2Nlc3M6IGZ1bmN0aW9uICgpIHt9LFxuICAgICAgb25FcnJvcjogZnVuY3Rpb24gKCkge30sXG4gICAgICBvblN1Ym1pdDogZnVuY3Rpb24gKCkge30sXG4gICAgICBvblN1Ym1pdHRlZDogZnVuY3Rpb24gKCkge30sXG4gICAgICBvblZhbGlkOiBmdW5jdGlvbiAoKSB7fSxcbiAgICAgIG9uSW52YWxpZDogZnVuY3Rpb24gKCkge31cbiAgICB9O1xuICB9LFxuXG4gIC8vIEFkZCBhIG1hcCB0byBzdG9yZSB0aGUgaW5wdXRzIG9mIHRoZSBmb3JtLCBhIG1vZGVsIHRvIHN0b3JlXG4gIC8vIHRoZSB2YWx1ZXMgb2YgdGhlIGZvcm0gYW5kIHJlZ2lzdGVyIGNoaWxkIGlucHV0c1xuICBjb21wb25lbnRXaWxsTW91bnQ6IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmlucHV0cyA9IHt9O1xuICAgIHRoaXMubW9kZWwgPSB7fTtcbiAgICB0aGlzLnJlZ2lzdGVySW5wdXRzKHRoaXMucHJvcHMuY2hpbGRyZW4pO1xuICB9LFxuXG4gIGNvbXBvbmVudERpZE1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy52YWxpZGF0ZUZvcm0oKTtcbiAgfSxcblxuICAvLyBVcGRhdGUgbW9kZWwsIHN1Ym1pdCB0byB1cmwgcHJvcCBhbmQgc2VuZCB0aGUgbW9kZWxcbiAgc3VibWl0OiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG4gICAgLy8gVHJpZ2dlciBmb3JtIGFzIG5vdCBwcmlzdGluZS5cbiAgICAvLyBJZiBhbnkgaW5wdXRzIGhhdmUgbm90IGJlZW4gdG91Y2hlZCB5ZXQgdGhpcyB3aWxsIG1ha2UgdGhlbSBkaXJ0eVxuICAgIC8vIHNvIHZhbGlkYXRpb24gYmVjb21lcyB2aXNpYmxlIChpZiBiYXNlZCBvbiBpc1ByaXN0aW5lKVxuICAgIHRoaXMuc2V0Rm9ybVByaXN0aW5lKGZhbHNlKTtcblxuICAgIC8vIFRvIHN1cHBvcnQgdXNlIGNhc2VzIHdoZXJlIG5vIGFzeW5jIG9yIHJlcXVlc3Qgb3BlcmF0aW9uIGlzIG5lZWRlZC5cbiAgICAvLyBUaGUgXCJvblN1Ym1pdFwiIGNhbGxiYWNrIGlzIGNhbGxlZCB3aXRoIHRoZSBtb2RlbCBlLmcuIHtmaWVsZE5hbWU6IFwibXlWYWx1ZVwifSxcbiAgICAvLyBpZiB3YW50aW5nIHRvIHJlc2V0IHRoZSBlbnRpcmUgZm9ybSB0byBvcmlnaW5hbCBzdGF0ZSwgdGhlIHNlY29uZCBwYXJhbSBpcyBhIGNhbGxiYWNrIGZvciB0aGlzLlxuICAgIGlmICghdGhpcy5wcm9wcy51cmwpIHtcbiAgICAgIHRoaXMudXBkYXRlTW9kZWwoKTtcbiAgICAgIHRoaXMucHJvcHMub25TdWJtaXQodGhpcy5tYXBNb2RlbCgpLCB0aGlzLnJlc2V0TW9kZWwsIHRoaXMudXBkYXRlSW5wdXRzV2l0aEVycm9yKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLnVwZGF0ZU1vZGVsKCk7XG4gICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICBpc1N1Ym1pdHRpbmc6IHRydWVcbiAgICB9KTtcblxuICAgIHRoaXMucHJvcHMub25TdWJtaXQodGhpcy5tYXBNb2RlbCgpLCB0aGlzLnJlc2V0TW9kZWwsIHRoaXMudXBkYXRlSW5wdXRzV2l0aEVycm9yKTtcblxuICAgIHZhciBoZWFkZXJzID0gKE9iamVjdC5rZXlzKHRoaXMucHJvcHMuaGVhZGVycykubGVuZ3RoICYmIHRoaXMucHJvcHMuaGVhZGVycykgfHwgb3B0aW9ucy5oZWFkZXJzIHx8IHt9O1xuXG4gICAgdmFyIG1ldGhvZCA9IHRoaXMucHJvcHMubWV0aG9kICYmIGFqYXhbdGhpcy5wcm9wcy5tZXRob2QudG9Mb3dlckNhc2UoKV0gPyB0aGlzLnByb3BzLm1ldGhvZC50b0xvd2VyQ2FzZSgpIDogJ3Bvc3QnO1xuICAgIGFqYXhbbWV0aG9kXSh0aGlzLnByb3BzLnVybCwgdGhpcy5tYXBNb2RlbCgpLCB0aGlzLnByb3BzLmNvbnRlbnRUeXBlIHx8IG9wdGlvbnMuY29udGVudFR5cGUgfHwgJ2pzb24nLCBoZWFkZXJzKVxuICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgIHRoaXMucHJvcHMub25TdWNjZXNzKHJlc3BvbnNlKTtcbiAgICAgICAgdGhpcy5wcm9wcy5vblN1Ym1pdHRlZCgpO1xuICAgICAgfS5iaW5kKHRoaXMpKVxuICAgICAgLmNhdGNoKHRoaXMuZmFpbFN1Ym1pdCk7XG4gIH0sXG5cbiAgbWFwTW9kZWw6IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5wcm9wcy5tYXBwaW5nID8gdGhpcy5wcm9wcy5tYXBwaW5nKHRoaXMubW9kZWwpIDogdGhpcy5tb2RlbDtcbiAgfSxcblxuICAvLyBHb2VzIHRocm91Z2ggYWxsIHJlZ2lzdGVyZWQgY29tcG9uZW50cyBhbmRcbiAgLy8gdXBkYXRlcyB0aGUgbW9kZWwgdmFsdWVzXG4gIHVwZGF0ZU1vZGVsOiBmdW5jdGlvbiAoKSB7XG4gICAgT2JqZWN0LmtleXModGhpcy5pbnB1dHMpLmZvckVhY2goZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAgIHZhciBjb21wb25lbnQgPSB0aGlzLmlucHV0c1tuYW1lXTtcbiAgICAgIHRoaXMubW9kZWxbbmFtZV0gPSBjb21wb25lbnQuc3RhdGUuX3ZhbHVlO1xuICAgIH0uYmluZCh0aGlzKSk7XG4gIH0sXG5cbiAgLy8gUmVzZXQgZWFjaCBrZXkgaW4gdGhlIG1vZGVsIHRvIHRoZSBvcmlnaW5hbCAvIGluaXRpYWwgdmFsdWVcbiAgcmVzZXRNb2RlbDogZnVuY3Rpb24gKCkge1xuICAgIE9iamVjdC5rZXlzKHRoaXMuaW5wdXRzKS5mb3JFYWNoKGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgICB0aGlzLmlucHV0c1tuYW1lXS5yZXNldFZhbHVlKCk7XG4gICAgfS5iaW5kKHRoaXMpKTtcbiAgICB0aGlzLnZhbGlkYXRlRm9ybSgpO1xuICB9LFxuXG4gIC8vIEdvIHRocm91Z2ggZXJyb3JzIGZyb20gc2VydmVyIGFuZCBncmFiIHRoZSBjb21wb25lbnRzXG4gIC8vIHN0b3JlZCBpbiB0aGUgaW5wdXRzIG1hcC4gQ2hhbmdlIHRoZWlyIHN0YXRlIHRvIGludmFsaWRcbiAgLy8gYW5kIHNldCB0aGUgc2VydmVyRXJyb3IgbWVzc2FnZVxuICB1cGRhdGVJbnB1dHNXaXRoRXJyb3I6IGZ1bmN0aW9uIChlcnJvcnMpIHtcbiAgICBPYmplY3Qua2V5cyhlcnJvcnMpLmZvckVhY2goZnVuY3Rpb24gKG5hbWUsIGluZGV4KSB7XG4gICAgICB2YXIgY29tcG9uZW50ID0gdGhpcy5pbnB1dHNbbmFtZV07XG5cbiAgICAgIGlmICghY29tcG9uZW50KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignWW91IGFyZSB0cnlpbmcgdG8gdXBkYXRlIGFuIGlucHV0IHRoYXQgZG9lcyBub3QgZXhpc3RzLiBWZXJpZnkgZXJyb3JzIG9iamVjdCB3aXRoIGlucHV0IG5hbWVzLiAnICsgSlNPTi5zdHJpbmdpZnkoZXJyb3JzKSk7XG4gICAgICB9XG5cbiAgICAgIHZhciBhcmdzID0gW3tcbiAgICAgICAgX2lzVmFsaWQ6IGZhbHNlLFxuICAgICAgICBfc2VydmVyRXJyb3I6IGVycm9yc1tuYW1lXVxuICAgICAgfV07XG4gICAgICBjb21wb25lbnQuc2V0U3RhdGUuYXBwbHkoY29tcG9uZW50LCBhcmdzKTtcbiAgICB9LmJpbmQodGhpcykpO1xuICB9LFxuXG4gIGZhaWxTdWJtaXQ6IGZ1bmN0aW9uIChlcnJvcnMpIHtcbiAgICB0aGlzLnVwZGF0ZUlucHV0c1dpdGhFcnJvcihlcnJvcnMpO1xuICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgaXNTdWJtaXR0aW5nOiBmYWxzZVxuICAgIH0pO1xuICAgIHRoaXMucHJvcHMub25FcnJvcihlcnJvcnMpO1xuICAgIHRoaXMucHJvcHMub25TdWJtaXR0ZWQoKTtcbiAgfSxcblxuICAvLyBUcmF2ZXJzZSB0aGUgY2hpbGRyZW4gYW5kIGNoaWxkcmVuIG9mIGNoaWxkcmVuIHRvIGZpbmRcbiAgLy8gYWxsIGlucHV0cyBieSBjaGVja2luZyB0aGUgbmFtZSBwcm9wLiBNYXliZSBkbyBhIGJldHRlclxuICAvLyBjaGVjayBoZXJlXG4gIHJlZ2lzdGVySW5wdXRzOiBmdW5jdGlvbiAoY2hpbGRyZW4pIHtcbiAgICBSZWFjdC5DaGlsZHJlbi5mb3JFYWNoKGNoaWxkcmVuLCBmdW5jdGlvbiAoY2hpbGQpIHtcblxuICAgICAgaWYgKGNoaWxkLnByb3BzICYmIGNoaWxkLnByb3BzLm5hbWUpIHtcbiAgICAgICAgY2hpbGQucHJvcHMuX2F0dGFjaFRvRm9ybSA9IHRoaXMuYXR0YWNoVG9Gb3JtO1xuICAgICAgICBjaGlsZC5wcm9wcy5fZGV0YWNoRnJvbUZvcm0gPSB0aGlzLmRldGFjaEZyb21Gb3JtO1xuICAgICAgICBjaGlsZC5wcm9wcy5fdmFsaWRhdGUgPSB0aGlzLnZhbGlkYXRlO1xuICAgICAgfVxuXG4gICAgICBpZiAoY2hpbGQucHJvcHMgJiYgY2hpbGQucHJvcHMuY2hpbGRyZW4pIHtcbiAgICAgICAgdGhpcy5yZWdpc3RlcklucHV0cyhjaGlsZC5wcm9wcy5jaGlsZHJlbik7XG4gICAgICB9XG5cbiAgICB9LmJpbmQodGhpcykpO1xuICB9LFxuXG4gIGdldEN1cnJlbnRWYWx1ZXM6IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gT2JqZWN0LmtleXModGhpcy5pbnB1dHMpLnJlZHVjZShmdW5jdGlvbiAoZGF0YSwgbmFtZSkge1xuICAgICAgdmFyIGNvbXBvbmVudCA9IHRoaXMuaW5wdXRzW25hbWVdO1xuICAgICAgZGF0YVtuYW1lXSA9IGNvbXBvbmVudC5zdGF0ZS5fdmFsdWU7XG4gICAgICByZXR1cm4gZGF0YTtcbiAgICB9LmJpbmQodGhpcyksIHt9KTtcbiAgfSxcblxuICBzZXRGb3JtUHJpc3RpbmU6IGZ1bmN0aW9uKGlzUHJpc3RpbmUpIHtcbiAgICB2YXIgaW5wdXRzID0gdGhpcy5pbnB1dHM7XG4gICAgdmFyIGlucHV0S2V5cyA9IE9iamVjdC5rZXlzKGlucHV0cyk7XG5cbiAgICAvLyBJdGVyYXRlIHRocm91Z2ggZWFjaCBjb21wb25lbnQgYW5kIHNldCBpdCBhcyBwcmlzdGluZVxuICAgIC8vIG9yIFwiZGlydHlcIi5cbiAgICBpbnB1dEtleXMuZm9yRWFjaChmdW5jdGlvbiAobmFtZSwgaW5kZXgpIHtcbiAgICAgIHZhciBjb21wb25lbnQgPSBpbnB1dHNbbmFtZV07XG4gICAgICBjb21wb25lbnQuc2V0U3RhdGUoe1xuICAgICAgICBfaXNQcmlzdGluZTogaXNQcmlzdGluZVxuICAgICAgfSk7XG4gICAgfS5iaW5kKHRoaXMpKTtcbiAgfSxcblxuICAvLyBVc2UgdGhlIGJpbmRlZCB2YWx1ZXMgYW5kIHRoZSBhY3R1YWwgaW5wdXQgdmFsdWUgdG9cbiAgLy8gdmFsaWRhdGUgdGhlIGlucHV0IGFuZCBzZXQgaXRzIHN0YXRlLiBUaGVuIGNoZWNrIHRoZVxuICAvLyBzdGF0ZSBvZiB0aGUgZm9ybSBpdHNlbGZcbiAgdmFsaWRhdGU6IGZ1bmN0aW9uIChjb21wb25lbnQpIHtcblxuICAgIGlmICghY29tcG9uZW50LnByb3BzLnJlcXVpcmVkICYmICFjb21wb25lbnQuX3ZhbGlkYXRpb25zKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gUnVuIHRocm91Z2ggdGhlIHZhbGlkYXRpb25zLCBzcGxpdCB0aGVtIHVwIGFuZCBjYWxsXG4gICAgLy8gdGhlIHZhbGlkYXRvciBJRiB0aGVyZSBpcyBhIHZhbHVlIG9yIGl0IGlzIHJlcXVpcmVkXG4gICAgdmFyIGlzVmFsaWQgPSB0aGlzLnJ1blZhbGlkYXRpb24oY29tcG9uZW50KTtcblxuICAgIGNvbXBvbmVudC5zZXRTdGF0ZSh7XG4gICAgICBfaXNWYWxpZDogaXNWYWxpZCxcbiAgICAgIF9zZXJ2ZXJFcnJvcjogbnVsbFxuICAgIH0sIHRoaXMudmFsaWRhdGVGb3JtKTtcblxuICB9LFxuXG4gIHJ1blZhbGlkYXRpb246IGZ1bmN0aW9uIChjb21wb25lbnQpIHtcbiAgICB2YXIgaXNWYWxpZCA9IHRydWU7XG4gICAgaWYgKGNvbXBvbmVudC5fdmFsaWRhdGlvbnMubGVuZ3RoICYmIChjb21wb25lbnQucHJvcHMucmVxdWlyZWQgfHwgY29tcG9uZW50LnN0YXRlLl92YWx1ZSAhPT0gJycpKSB7XG4gICAgICBjb21wb25lbnQuX3ZhbGlkYXRpb25zLnNwbGl0KCcsJykuZm9yRWFjaChmdW5jdGlvbiAodmFsaWRhdGlvbikge1xuICAgICAgICB2YXIgYXJncyA9IHZhbGlkYXRpb24uc3BsaXQoJzonKTtcbiAgICAgICAgdmFyIHZhbGlkYXRlTWV0aG9kID0gYXJncy5zaGlmdCgpO1xuICAgICAgICBhcmdzID0gYXJncy5tYXAoZnVuY3Rpb24gKGFyZykge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShhcmcpO1xuICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIHJldHVybiBhcmc7IC8vIEl0IGlzIGEgc3RyaW5nIGlmIGl0IGNhbiBub3QgcGFyc2UgaXRcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICBhcmdzID0gW2NvbXBvbmVudC5zdGF0ZS5fdmFsdWVdLmNvbmNhdChhcmdzKTtcbiAgICAgICAgaWYgKCF2YWxpZGF0aW9uUnVsZXNbdmFsaWRhdGVNZXRob2RdKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdGb3Jtc3kgZG9lcyBub3QgaGF2ZSB0aGUgdmFsaWRhdGlvbiBydWxlOiAnICsgdmFsaWRhdGVNZXRob2QpO1xuICAgICAgICB9XG4gICAgICAgIGlmICghdmFsaWRhdGlvblJ1bGVzW3ZhbGlkYXRlTWV0aG9kXS5hcHBseSh0aGlzLmdldEN1cnJlbnRWYWx1ZXMoKSwgYXJncykpIHtcbiAgICAgICAgICBpc1ZhbGlkID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfVxuICAgIHJldHVybiBpc1ZhbGlkO1xuICB9LFxuXG4gIC8vIFZhbGlkYXRlIHRoZSBmb3JtIGJ5IGdvaW5nIHRocm91Z2ggYWxsIGNoaWxkIGlucHV0IGNvbXBvbmVudHNcbiAgLy8gYW5kIGNoZWNrIHRoZWlyIHN0YXRlXG4gIHZhbGlkYXRlRm9ybTogZnVuY3Rpb24gKCkge1xuICAgIHZhciBhbGxJc1ZhbGlkID0gdHJ1ZTtcbiAgICB2YXIgaW5wdXRzID0gdGhpcy5pbnB1dHM7XG4gICAgdmFyIGlucHV0S2V5cyA9IE9iamVjdC5rZXlzKGlucHV0cyk7XG5cbiAgICAvLyBXZSBuZWVkIGEgY2FsbGJhY2sgYXMgd2UgYXJlIHZhbGlkYXRpbmcgYWxsIGlucHV0cyBhZ2Fpbi4gVGhpcyB3aWxsXG4gICAgLy8gcnVuIHdoZW4gdGhlIGxhc3QgY29tcG9uZW50IGhhcyBzZXQgaXRzIHN0YXRlXG4gICAgdmFyIG9uVmFsaWRhdGlvbkNvbXBsZXRlID0gZnVuY3Rpb24gKCkge1xuICAgICAgaW5wdXRLZXlzLmZvckVhY2goZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAgICAgaWYgKCFpbnB1dHNbbmFtZV0uc3RhdGUuX2lzVmFsaWQpIHtcbiAgICAgICAgICBhbGxJc1ZhbGlkID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgIH0uYmluZCh0aGlzKSk7XG5cbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBpc1ZhbGlkOiBhbGxJc1ZhbGlkXG4gICAgICB9KTtcblxuICAgICAgYWxsSXNWYWxpZCAmJiB0aGlzLnByb3BzLm9uVmFsaWQoKTtcbiAgICAgICFhbGxJc1ZhbGlkICYmIHRoaXMucHJvcHMub25JbnZhbGlkKCk7XG5cbiAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAvLyBSdW4gdmFsaWRhdGlvbiBhZ2FpbiBpbiBjYXNlIGFmZmVjdGVkIGJ5IG90aGVyIGlucHV0cy4gVGhlXG4gICAgLy8gbGFzdCBjb21wb25lbnQgdmFsaWRhdGVkIHdpbGwgcnVuIHRoZSBvblZhbGlkYXRpb25Db21wbGV0ZSBjYWxsYmFja1xuICAgIGlucHV0S2V5cy5mb3JFYWNoKGZ1bmN0aW9uIChuYW1lLCBpbmRleCkge1xuICAgICAgdmFyIGNvbXBvbmVudCA9IGlucHV0c1tuYW1lXTtcbiAgICAgIHZhciBpc1ZhbGlkID0gdGhpcy5ydW5WYWxpZGF0aW9uKGNvbXBvbmVudCk7XG4gICAgICBjb21wb25lbnQuc2V0U3RhdGUoe1xuICAgICAgICBfaXNWYWxpZDogaXNWYWxpZCxcbiAgICAgICAgX3NlcnZlckVycm9yOiBudWxsXG4gICAgICB9LCBpbmRleCA9PT0gaW5wdXRLZXlzLmxlbmd0aCAtIDEgPyBvblZhbGlkYXRpb25Db21wbGV0ZSA6IG51bGwpO1xuICAgIH0uYmluZCh0aGlzKSk7XG5cbiAgfSxcblxuICAvLyBNZXRob2QgcHV0IG9uIGVhY2ggaW5wdXQgY29tcG9uZW50IHRvIHJlZ2lzdGVyXG4gIC8vIGl0c2VsZiB0byB0aGUgZm9ybVxuICBhdHRhY2hUb0Zvcm06IGZ1bmN0aW9uIChjb21wb25lbnQpIHtcbiAgICB0aGlzLmlucHV0c1tjb21wb25lbnQucHJvcHMubmFtZV0gPSBjb21wb25lbnQ7XG4gICAgdGhpcy5tb2RlbFtjb21wb25lbnQucHJvcHMubmFtZV0gPSBjb21wb25lbnQuc3RhdGUuX3ZhbHVlO1xuICAgIHRoaXMudmFsaWRhdGUoY29tcG9uZW50KTtcbiAgfSxcblxuICAvLyBNZXRob2QgcHV0IG9uIGVhY2ggaW5wdXQgY29tcG9uZW50IHRvIHVucmVnaXN0ZXJcbiAgLy8gaXRzZWxmIGZyb20gdGhlIGZvcm1cbiAgZGV0YWNoRnJvbUZvcm06IGZ1bmN0aW9uIChjb21wb25lbnQpIHtcbiAgICBkZWxldGUgdGhpcy5pbnB1dHNbY29tcG9uZW50LnByb3BzLm5hbWVdO1xuICAgIGRlbGV0ZSB0aGlzLm1vZGVsW2NvbXBvbmVudC5wcm9wcy5uYW1lXTtcbiAgfSxcbiAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG5cbiAgICByZXR1cm4gUmVhY3QuRE9NLmZvcm0oe1xuICAgICAgICBvblN1Ym1pdDogdGhpcy5zdWJtaXQsXG4gICAgICAgIGNsYXNzTmFtZTogdGhpcy5wcm9wcy5jbGFzc05hbWVcbiAgICAgIH0sXG4gICAgICB0aGlzLnByb3BzLmNoaWxkcmVuXG4gICAgKTtcblxuICB9XG59KTtcblxuaWYgKCFnbG9iYWwuZXhwb3J0cyAmJiAhZ2xvYmFsLm1vZHVsZSAmJiAoIWdsb2JhbC5kZWZpbmUgfHwgIWdsb2JhbC5kZWZpbmUuYW1kKSkge1xuICBnbG9iYWwuRm9ybXN5ID0gRm9ybXN5O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IEZvcm1zeTtcbiJdfQ==
+//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcmMvbWFpbi5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCJ2YXIgUmVhY3QgPSBnbG9iYWwuUmVhY3QgfHwgcmVxdWlyZSgncmVhY3QnKTtcbnZhciBGb3Jtc3kgPSB7fTtcbnZhciB2YWxpZGF0aW9uUnVsZXMgPSB7XG4gICdpc1ZhbHVlJzogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgcmV0dXJuIHZhbHVlICE9PSAnJztcbiAgfSxcbiAgJ2lzRW1haWwnOiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICByZXR1cm4gdmFsdWUubWF0Y2goL14oKChbYS16XXxcXGR8WyEjXFwkJSYnXFwqXFwrXFwtXFwvPVxcP1xcXl9ge1xcfH1+XXxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSkrKFxcLihbYS16XXxcXGR8WyEjXFwkJSYnXFwqXFwrXFwtXFwvPVxcP1xcXl9ge1xcfH1+XXxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSkrKSopfCgoXFx4MjIpKCgoKFxceDIwfFxceDA5KSooXFx4MGRcXHgwYSkpPyhcXHgyMHxcXHgwOSkrKT8oKFtcXHgwMS1cXHgwOFxceDBiXFx4MGNcXHgwZS1cXHgxZlxceDdmXXxcXHgyMXxbXFx4MjMtXFx4NWJdfFtcXHg1ZC1cXHg3ZV18W1xcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0pfChcXFxcKFtcXHgwMS1cXHgwOVxceDBiXFx4MGNcXHgwZC1cXHg3Zl18W1xcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0pKSkpKigoKFxceDIwfFxceDA5KSooXFx4MGRcXHgwYSkpPyhcXHgyMHxcXHgwOSkrKT8oXFx4MjIpKSlAKCgoW2Etel18XFxkfFtcXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZdKXwoKFthLXpdfFxcZHxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSkoW2Etel18XFxkfC18XFwufF98fnxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSkqKFthLXpdfFxcZHxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSkpKVxcLikrKChbYS16XXxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSl8KChbYS16XXxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSkoW2Etel18XFxkfC18XFwufF98fnxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSkqKFthLXpdfFtcXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZdKSkpJC9pKTtcbiAgfSxcbiAgJ2lzVHJ1ZSc6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgIHJldHVybiB2YWx1ZSA9PT0gdHJ1ZTtcbiAgfSxcbiAgJ2lzTnVtZXJpYyc6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHZhbHVlLm1hdGNoKC9eLT9bMC05XSskLyk7XG4gICAgfVxuICB9LFxuICAnaXNBbHBoYSc6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgIHJldHVybiB2YWx1ZS5tYXRjaCgvXlthLXpBLVpdKyQvKTtcbiAgfSxcbiAgJ2lzV29yZHMnOiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICByZXR1cm4gdmFsdWUubWF0Y2goL15bYS16QS1aXFxzXSskLyk7XG4gIH0sXG4gICdpc1NwZWNpYWxXb3Jkcyc6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgIHJldHVybiB2YWx1ZS5tYXRjaCgvXlthLXpBLVpcXHNcXHUwMEMwLVxcdTAxN0ZdKyQvKTtcbiAgfSxcbiAgaXNMZW5ndGg6IGZ1bmN0aW9uICh2YWx1ZSwgbWluLCBtYXgpIHtcbiAgICBpZiAobWF4ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiB2YWx1ZS5sZW5ndGggPj0gbWluICYmIHZhbHVlLmxlbmd0aCA8PSBtYXg7XG4gICAgfVxuICAgIHJldHVybiB2YWx1ZS5sZW5ndGggPj0gbWluO1xuICB9LFxuICBlcXVhbHM6IGZ1bmN0aW9uICh2YWx1ZSwgZXFsKSB7XG4gICAgcmV0dXJuIHZhbHVlID09IGVxbDtcbiAgfSxcbiAgZXF1YWxzRmllbGQ6IGZ1bmN0aW9uICh2YWx1ZSwgZmllbGQpIHtcbiAgICByZXR1cm4gdmFsdWUgPT09IHRoaXNbZmllbGRdO1xuICB9XG59O1xuXG52YXIgdG9VUkxFbmNvZGVkID0gZnVuY3Rpb24gKGVsZW1lbnQsIGtleSwgbGlzdCkge1xuICB2YXIgbGlzdCA9IGxpc3QgfHwgW107XG4gIGlmICh0eXBlb2YgKGVsZW1lbnQpID09ICdvYmplY3QnKSB7XG4gICAgZm9yICh2YXIgaWR4IGluIGVsZW1lbnQpXG4gICAgICB0b1VSTEVuY29kZWQoZWxlbWVudFtpZHhdLCBrZXkgPyBrZXkgKyAnWycgKyBpZHggKyAnXScgOiBpZHgsIGxpc3QpO1xuICB9IGVsc2Uge1xuICAgIGxpc3QucHVzaChrZXkgKyAnPScgKyBlbmNvZGVVUklDb21wb25lbnQoZWxlbWVudCkpO1xuICB9XG4gIHJldHVybiBsaXN0LmpvaW4oJyYnKTtcbn07XG5cbnZhciByZXF1ZXN0ID0gZnVuY3Rpb24gKG1ldGhvZCwgdXJsLCBkYXRhLCBjb250ZW50VHlwZSwgaGVhZGVycykge1xuXG4gIHZhciBjb250ZW50VHlwZSA9IGNvbnRlbnRUeXBlID09PSAndXJsZW5jb2RlZCcgPyAnYXBwbGljYXRpb24vJyArIGNvbnRlbnRUeXBlLnJlcGxhY2UoJ3VybGVuY29kZWQnLCAneC13d3ctZm9ybS11cmxlbmNvZGVkJykgOiAnYXBwbGljYXRpb24vanNvbic7XG4gIGRhdGEgPSBjb250ZW50VHlwZSA9PT0gJ2FwcGxpY2F0aW9uL2pzb24nID8gSlNPTi5zdHJpbmdpZnkoZGF0YSkgOiB0b1VSTEVuY29kZWQoZGF0YSk7XG5cbiAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcbiAgICB0cnkge1xuICAgICAgdmFyIHhociA9IG5ldyBYTUxIdHRwUmVxdWVzdCgpO1xuICAgICAgeGhyLm9wZW4obWV0aG9kLCB1cmwsIHRydWUpO1xuICAgICAgeGhyLnNldFJlcXVlc3RIZWFkZXIoJ0FjY2VwdCcsICdhcHBsaWNhdGlvbi9qc29uJyk7XG4gICAgICB4aHIuc2V0UmVxdWVzdEhlYWRlcignQ29udGVudC1UeXBlJywgY29udGVudFR5cGUpO1xuXG4gICAgICAvLyBBZGQgcGFzc2VkIGhlYWRlcnNcbiAgICAgIE9iamVjdC5rZXlzKGhlYWRlcnMpLmZvckVhY2goZnVuY3Rpb24gKGhlYWRlcikge1xuICAgICAgICB4aHIuc2V0UmVxdWVzdEhlYWRlcihoZWFkZXIsIGhlYWRlcnNbaGVhZGVyXSk7XG4gICAgICB9KTtcblxuICAgICAgeGhyLm9ucmVhZHlzdGF0ZWNoYW5nZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKHhoci5yZWFkeVN0YXRlID09PSA0KSB7XG5cbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgdmFyIHJlc3BvbnNlID0geGhyLnJlc3BvbnNlVGV4dCA/IEpTT04ucGFyc2UoeGhyLnJlc3BvbnNlVGV4dCkgOiBudWxsO1xuICAgICAgICAgICAgaWYgKHhoci5zdGF0dXMgPj0gMjAwICYmIHhoci5zdGF0dXMgPCAzMDApIHtcbiAgICAgICAgICAgICAgcmVzb2x2ZShyZXNwb25zZSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICByZWplY3QocmVzcG9uc2UpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIHJlamVjdChlKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgfVxuICAgICAgfTtcbiAgICAgIHhoci5zZW5kKGRhdGEpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJlamVjdChlKTtcbiAgICB9XG4gIH0pO1xuXG59O1xuXG52YXIgYXJyYXlzRGlmZmVyID0gZnVuY3Rpb24gKGFycmF5QSwgYXJyYXlCKSB7XG4gIHZhciBpc0RpZmZlcmVudCA9IGZhbHNlO1xuICBpZiAoYXJyYXlBLmxlbmd0aCAhPT0gYXJyYXlCLmxlbmd0aCkge1xuICAgIGlzRGlmZmVyZW50ID0gdHJ1ZTtcbiAgfSBlbHNlIHtcbiAgICBhcnJheUEuZm9yRWFjaChmdW5jdGlvbiAoaXRlbSwgaW5kZXgpIHtcbiAgICAgIGlmIChpdGVtICE9PSBhcnJheUJbaW5kZXhdKSB7XG4gICAgICAgIGlzRGlmZmVyZW50ID0gdHJ1ZTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuICByZXR1cm4gaXNEaWZmZXJlbnQ7XG59O1xuXG52YXIgYWpheCA9IHtcbiAgcG9zdDogcmVxdWVzdC5iaW5kKG51bGwsICdQT1NUJyksXG4gIHB1dDogcmVxdWVzdC5iaW5kKG51bGwsICdQVVQnKVxufTtcbnZhciBvcHRpb25zID0ge307XG5cbkZvcm1zeS5kZWZhdWx0cyA9IGZ1bmN0aW9uIChwYXNzZWRPcHRpb25zKSB7XG4gIG9wdGlvbnMgPSBwYXNzZWRPcHRpb25zO1xufTtcblxuRm9ybXN5Lk1peGluID0ge1xuICBnZXRJbml0aWFsU3RhdGU6IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgX3ZhbHVlOiB0aGlzLnByb3BzLnZhbHVlID8gdGhpcy5wcm9wcy52YWx1ZSA6ICcnLFxuICAgICAgX2lzVmFsaWQ6IHRydWUsXG4gICAgICBfaXNQcmlzdGluZTogdHJ1ZVxuICAgIH07XG4gIH0sXG4gIGNvbXBvbmVudFdpbGxNb3VudDogZnVuY3Rpb24gKCkge1xuXG4gICAgdmFyIGNvbmZpZ3VyZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgIC8vIEFkZCB2YWxpZGF0aW9ucyB0byB0aGUgc3RvcmUgaXRzZWxmIGFzIHRoZSBwcm9wcyBvYmplY3QgY2FuIG5vdCBiZSBtb2RpZmllZFxuICAgICAgdGhpcy5fdmFsaWRhdGlvbnMgPSB0aGlzLnByb3BzLnZhbGlkYXRpb25zIHx8ICcnO1xuXG4gICAgICBpZiAodGhpcy5wcm9wcy5yZXF1aXJlZCkge1xuICAgICAgICB0aGlzLl92YWxpZGF0aW9ucyA9IHRoaXMucHJvcHMudmFsaWRhdGlvbnMgPyB0aGlzLnByb3BzLnZhbGlkYXRpb25zICsgJywnIDogJyc7XG4gICAgICAgIHRoaXMuX3ZhbGlkYXRpb25zICs9ICdpc1ZhbHVlJztcbiAgICAgIH1cbiAgICAgIHRoaXMucHJvcHMuX2F0dGFjaFRvRm9ybSh0aGlzKTtcbiAgICB9LmJpbmQodGhpcyk7XG5cbiAgICBpZiAoIXRoaXMucHJvcHMubmFtZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdGb3JtIElucHV0IHJlcXVpcmVzIGEgbmFtZSBwcm9wZXJ0eSB3aGVuIHVzZWQnKTtcbiAgICB9XG5cbiAgICBpZiAoIXRoaXMucHJvcHMuX2F0dGFjaFRvRm9ybSkge1xuICAgICAgcmV0dXJuIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoIXRoaXMucHJvcHMuX2F0dGFjaFRvRm9ybSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignRm9ybSBNaXhpbiByZXF1aXJlcyBjb21wb25lbnQgdG8gYmUgbmVzdGVkIGluIGEgRm9ybScpO1xuICAgICAgICB9XG4gICAgICAgIGNvbmZpZ3VyZSgpO1xuICAgICAgfS5iaW5kKHRoaXMpLCAwKTtcbiAgICB9XG4gICAgY29uZmlndXJlKCk7XG5cbiAgfSxcblxuICAvLyBXZSBoYXZlIHRvIG1ha2UgdGhlIHZhbGlkYXRlIG1ldGhvZCBpcyBrZXB0IHdoZW4gbmV3IHByb3BzIGFyZSBhZGRlZFxuICBjb21wb25lbnRXaWxsUmVjZWl2ZVByb3BzOiBmdW5jdGlvbiAobmV4dFByb3BzKSB7XG4gICAgbmV4dFByb3BzLl9hdHRhY2hUb0Zvcm0gPSB0aGlzLnByb3BzLl9hdHRhY2hUb0Zvcm07XG4gICAgbmV4dFByb3BzLl9kZXRhY2hGcm9tRm9ybSA9IHRoaXMucHJvcHMuX2RldGFjaEZyb21Gb3JtO1xuICAgIG5leHRQcm9wcy5fdmFsaWRhdGUgPSB0aGlzLnByb3BzLl92YWxpZGF0ZTtcbiAgfSxcblxuICAvLyBEZXRhY2ggaXQgd2hlbiBjb21wb25lbnQgdW5tb3VudHNcbiAgY29tcG9uZW50V2lsbFVubW91bnQ6IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnByb3BzLl9kZXRhY2hGcm9tRm9ybSh0aGlzKTtcbiAgfSxcblxuICAvLyBXZSB2YWxpZGF0ZSBhZnRlciB0aGUgdmFsdWUgaGFzIGJlZW4gc2V0XG4gIHNldFZhbHVlOiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgIF92YWx1ZTogdmFsdWUsXG4gICAgICBfaXNQcmlzdGluZTogZmFsc2VcbiAgICB9LCBmdW5jdGlvbiAoKSB7XG4gICAgICB0aGlzLnByb3BzLl92YWxpZGF0ZSh0aGlzKTtcbiAgICB9LmJpbmQodGhpcykpO1xuICB9LFxuICByZXNldFZhbHVlOiBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICBfdmFsdWU6ICcnLFxuICAgICAgX2lzUHJpc3RpbmU6IHRydWVcbiAgICB9LCBmdW5jdGlvbiAoKSB7XG4gICAgICB0aGlzLnByb3BzLl92YWxpZGF0ZSh0aGlzKTtcbiAgICB9KTtcbiAgfSxcbiAgZ2V0VmFsdWU6IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5zdGF0ZS5fdmFsdWU7XG4gIH0sXG4gIGhhc1ZhbHVlOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuc3RhdGUuX3ZhbHVlICE9PSAnJztcbiAgfSxcbiAgZ2V0RXJyb3JNZXNzYWdlOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuaXNWYWxpZCgpIHx8IHRoaXMuc2hvd1JlcXVpcmVkKCkgPyBudWxsIDogdGhpcy5zdGF0ZS5fc2VydmVyRXJyb3IgfHwgdGhpcy5wcm9wcy52YWxpZGF0aW9uRXJyb3I7XG4gIH0sXG4gIGlzVmFsaWQ6IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5zdGF0ZS5faXNWYWxpZDtcbiAgfSxcbiAgaXNQcmlzdGluZTogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLnN0YXRlLl9pc1ByaXN0aW5lO1xuICB9LFxuICBpc1JlcXVpcmVkOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuICEhdGhpcy5wcm9wcy5yZXF1aXJlZDtcbiAgfSxcbiAgc2hvd1JlcXVpcmVkOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuaXNSZXF1aXJlZCgpICYmIHRoaXMuc3RhdGUuX3ZhbHVlID09PSAnJztcbiAgfSxcbiAgc2hvd0Vycm9yOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuICF0aGlzLnNob3dSZXF1aXJlZCgpICYmICF0aGlzLnN0YXRlLl9pc1ZhbGlkO1xuICB9XG59O1xuXG5Gb3Jtc3kuYWRkVmFsaWRhdGlvblJ1bGUgPSBmdW5jdGlvbiAobmFtZSwgZnVuYykge1xuICB2YWxpZGF0aW9uUnVsZXNbbmFtZV0gPSBmdW5jO1xufTtcblxuRm9ybXN5LkZvcm0gPSBSZWFjdC5jcmVhdGVDbGFzcyh7ZGlzcGxheU5hbWU6IFwiRm9ybVwiLFxuICBnZXRJbml0aWFsU3RhdGU6IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgaXNWYWxpZDogdHJ1ZSxcbiAgICAgIGlzU3VibWl0dGluZzogZmFsc2UsXG4gICAgICBjYW5DaGFuZ2U6IGZhbHNlXG4gICAgfTtcbiAgfSxcbiAgZ2V0RGVmYXVsdFByb3BzOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGhlYWRlcnM6IHt9LFxuICAgICAgb25TdWNjZXNzOiBmdW5jdGlvbiAoKSB7fSxcbiAgICAgIG9uRXJyb3I6IGZ1bmN0aW9uICgpIHt9LFxuICAgICAgb25TdWJtaXQ6IGZ1bmN0aW9uICgpIHt9LFxuICAgICAgb25TdWJtaXR0ZWQ6IGZ1bmN0aW9uICgpIHt9LFxuICAgICAgb25WYWxpZDogZnVuY3Rpb24gKCkge30sXG4gICAgICBvbkludmFsaWQ6IGZ1bmN0aW9uICgpIHt9LFxuICAgICAgb25DaGFuZ2U6IGZ1bmN0aW9uICgpIHt9XG4gICAgfTtcbiAgfSxcblxuICAvLyBBZGQgYSBtYXAgdG8gc3RvcmUgdGhlIGlucHV0cyBvZiB0aGUgZm9ybSwgYSBtb2RlbCB0byBzdG9yZVxuICAvLyB0aGUgdmFsdWVzIG9mIHRoZSBmb3JtIGFuZCByZWdpc3RlciBjaGlsZCBpbnB1dHNcbiAgY29tcG9uZW50V2lsbE1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5pbnB1dHMgPSB7fTtcbiAgICB0aGlzLm1vZGVsID0ge307XG4gICAgdGhpcy5yZWdpc3RlcklucHV0cyh0aGlzLnByb3BzLmNoaWxkcmVuKTtcbiAgfSxcblxuICBjb21wb25lbnREaWRNb3VudDogZnVuY3Rpb24gKCkge1xuICAgIHRoaXMudmFsaWRhdGVGb3JtKCk7XG4gIH0sXG5cbiAgY29tcG9uZW50V2lsbFVwZGF0ZTogZnVuY3Rpb24gKCkge1xuICAgIHZhciBpbnB1dEtleXMgPSBPYmplY3Qua2V5cyh0aGlzLmlucHV0cyk7XG5cbiAgICAvLyBUaGUgdXBkYXRlZCBjaGlsZHJlbiBhcnJheSBpcyBub3QgYXZhaWxhYmxlIGhlcmUgZm9yIHNvbWUgcmVhc29uLFxuICAgIC8vIHdlIG5lZWQgdG8gd2FpdCBmb3IgbmV4dCBldmVudCBsb29wXG4gICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICB0aGlzLnJlZ2lzdGVySW5wdXRzKHRoaXMucHJvcHMuY2hpbGRyZW4pO1xuXG4gICAgICB2YXIgbmV3SW5wdXRLZXlzID0gT2JqZWN0LmtleXModGhpcy5pbnB1dHMpO1xuICAgICAgaWYgKGFycmF5c0RpZmZlcihpbnB1dEtleXMsIG5ld0lucHV0S2V5cykpIHtcbiAgICAgICAgdGhpcy52YWxpZGF0ZUZvcm0oKTtcbiAgICAgIH1cbiAgICB9LmJpbmQodGhpcyksIDApO1xuICB9LFxuXG4gIC8vIFVwZGF0ZSBtb2RlbCwgc3VibWl0IHRvIHVybCBwcm9wIGFuZCBzZW5kIHRoZSBtb2RlbFxuICBzdWJtaXQ6IGZ1bmN0aW9uIChldmVudCkge1xuICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cbiAgICAvLyBUcmlnZ2VyIGZvcm0gYXMgbm90IHByaXN0aW5lLlxuICAgIC8vIElmIGFueSBpbnB1dHMgaGF2ZSBub3QgYmVlbiB0b3VjaGVkIHlldCB0aGlzIHdpbGwgbWFrZSB0aGVtIGRpcnR5XG4gICAgLy8gc28gdmFsaWRhdGlvbiBiZWNvbWVzIHZpc2libGUgKGlmIGJhc2VkIG9uIGlzUHJpc3RpbmUpXG4gICAgdGhpcy5zZXRGb3JtUHJpc3RpbmUoZmFsc2UpO1xuXG4gICAgLy8gVG8gc3VwcG9ydCB1c2UgY2FzZXMgd2hlcmUgbm8gYXN5bmMgb3IgcmVxdWVzdCBvcGVyYXRpb24gaXMgbmVlZGVkLlxuICAgIC8vIFRoZSBcIm9uU3VibWl0XCIgY2FsbGJhY2sgaXMgY2FsbGVkIHdpdGggdGhlIG1vZGVsIGUuZy4ge2ZpZWxkTmFtZTogXCJteVZhbHVlXCJ9LFxuICAgIC8vIGlmIHdhbnRpbmcgdG8gcmVzZXQgdGhlIGVudGlyZSBmb3JtIHRvIG9yaWdpbmFsIHN0YXRlLCB0aGUgc2Vjb25kIHBhcmFtIGlzIGEgY2FsbGJhY2sgZm9yIHRoaXMuXG4gICAgaWYgKCF0aGlzLnByb3BzLnVybCkge1xuICAgICAgdGhpcy51cGRhdGVNb2RlbCgpO1xuICAgICAgdGhpcy5wcm9wcy5vblN1Ym1pdCh0aGlzLm1hcE1vZGVsKCksIHRoaXMucmVzZXRNb2RlbCwgdGhpcy51cGRhdGVJbnB1dHNXaXRoRXJyb3IpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMudXBkYXRlTW9kZWwoKTtcbiAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgIGlzU3VibWl0dGluZzogdHJ1ZVxuICAgIH0pO1xuXG4gICAgdGhpcy5wcm9wcy5vblN1Ym1pdCh0aGlzLm1hcE1vZGVsKCksIHRoaXMucmVzZXRNb2RlbCwgdGhpcy51cGRhdGVJbnB1dHNXaXRoRXJyb3IpO1xuXG4gICAgdmFyIGhlYWRlcnMgPSAoT2JqZWN0LmtleXModGhpcy5wcm9wcy5oZWFkZXJzKS5sZW5ndGggJiYgdGhpcy5wcm9wcy5oZWFkZXJzKSB8fCBvcHRpb25zLmhlYWRlcnMgfHwge307XG5cbiAgICB2YXIgbWV0aG9kID0gdGhpcy5wcm9wcy5tZXRob2QgJiYgYWpheFt0aGlzLnByb3BzLm1ldGhvZC50b0xvd2VyQ2FzZSgpXSA/IHRoaXMucHJvcHMubWV0aG9kLnRvTG93ZXJDYXNlKCkgOiAncG9zdCc7XG4gICAgYWpheFttZXRob2RdKHRoaXMucHJvcHMudXJsLCB0aGlzLm1hcE1vZGVsKCksIHRoaXMucHJvcHMuY29udGVudFR5cGUgfHwgb3B0aW9ucy5jb250ZW50VHlwZSB8fCAnanNvbicsIGhlYWRlcnMpXG4gICAgICAudGhlbihmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgdGhpcy5wcm9wcy5vblN1Y2Nlc3MocmVzcG9uc2UpO1xuICAgICAgICB0aGlzLnByb3BzLm9uU3VibWl0dGVkKCk7XG4gICAgICB9LmJpbmQodGhpcykpXG4gICAgICAuY2F0Y2godGhpcy5mYWlsU3VibWl0KTtcbiAgfSxcblxuICBtYXBNb2RlbDogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLnByb3BzLm1hcHBpbmcgPyB0aGlzLnByb3BzLm1hcHBpbmcodGhpcy5tb2RlbCkgOiB0aGlzLm1vZGVsO1xuICB9LFxuXG4gIC8vIEdvZXMgdGhyb3VnaCBhbGwgcmVnaXN0ZXJlZCBjb21wb25lbnRzIGFuZFxuICAvLyB1cGRhdGVzIHRoZSBtb2RlbCB2YWx1ZXNcbiAgdXBkYXRlTW9kZWw6IGZ1bmN0aW9uICgpIHtcbiAgICBPYmplY3Qua2V5cyh0aGlzLmlucHV0cykuZm9yRWFjaChmdW5jdGlvbiAobmFtZSkge1xuICAgICAgdmFyIGNvbXBvbmVudCA9IHRoaXMuaW5wdXRzW25hbWVdO1xuICAgICAgdGhpcy5tb2RlbFtuYW1lXSA9IGNvbXBvbmVudC5zdGF0ZS5fdmFsdWU7XG4gICAgfS5iaW5kKHRoaXMpKTtcbiAgfSxcblxuICAvLyBSZXNldCBlYWNoIGtleSBpbiB0aGUgbW9kZWwgdG8gdGhlIG9yaWdpbmFsIC8gaW5pdGlhbCB2YWx1ZVxuICByZXNldE1vZGVsOiBmdW5jdGlvbiAoKSB7XG4gICAgT2JqZWN0LmtleXModGhpcy5pbnB1dHMpLmZvckVhY2goZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAgIHRoaXMuaW5wdXRzW25hbWVdLnJlc2V0VmFsdWUoKTtcbiAgICB9LmJpbmQodGhpcykpO1xuICAgIHRoaXMudmFsaWRhdGVGb3JtKCk7XG4gIH0sXG5cbiAgLy8gR28gdGhyb3VnaCBlcnJvcnMgZnJvbSBzZXJ2ZXIgYW5kIGdyYWIgdGhlIGNvbXBvbmVudHNcbiAgLy8gc3RvcmVkIGluIHRoZSBpbnB1dHMgbWFwLiBDaGFuZ2UgdGhlaXIgc3RhdGUgdG8gaW52YWxpZFxuICAvLyBhbmQgc2V0IHRoZSBzZXJ2ZXJFcnJvciBtZXNzYWdlXG4gIHVwZGF0ZUlucHV0c1dpdGhFcnJvcjogZnVuY3Rpb24gKGVycm9ycykge1xuICAgIE9iamVjdC5rZXlzKGVycm9ycykuZm9yRWFjaChmdW5jdGlvbiAobmFtZSwgaW5kZXgpIHtcbiAgICAgIHZhciBjb21wb25lbnQgPSB0aGlzLmlucHV0c1tuYW1lXTtcblxuICAgICAgaWYgKCFjb21wb25lbnQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdZb3UgYXJlIHRyeWluZyB0byB1cGRhdGUgYW4gaW5wdXQgdGhhdCBkb2VzIG5vdCBleGlzdHMuIFZlcmlmeSBlcnJvcnMgb2JqZWN0IHdpdGggaW5wdXQgbmFtZXMuICcgKyBKU09OLnN0cmluZ2lmeShlcnJvcnMpKTtcbiAgICAgIH1cblxuICAgICAgdmFyIGFyZ3MgPSBbe1xuICAgICAgICBfaXNWYWxpZDogZmFsc2UsXG4gICAgICAgIF9zZXJ2ZXJFcnJvcjogZXJyb3JzW25hbWVdXG4gICAgICB9XTtcbiAgICAgIGNvbXBvbmVudC5zZXRTdGF0ZS5hcHBseShjb21wb25lbnQsIGFyZ3MpO1xuICAgIH0uYmluZCh0aGlzKSk7XG4gIH0sXG5cbiAgZmFpbFN1Ym1pdDogZnVuY3Rpb24gKGVycm9ycykge1xuICAgIHRoaXMudXBkYXRlSW5wdXRzV2l0aEVycm9yKGVycm9ycyk7XG4gICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICBpc1N1Ym1pdHRpbmc6IGZhbHNlXG4gICAgfSk7XG4gICAgdGhpcy5wcm9wcy5vbkVycm9yKGVycm9ycyk7XG4gICAgdGhpcy5wcm9wcy5vblN1Ym1pdHRlZCgpO1xuICB9LFxuXG4gIC8vIFRyYXZlcnNlIHRoZSBjaGlsZHJlbiBhbmQgY2hpbGRyZW4gb2YgY2hpbGRyZW4gdG8gZmluZFxuICAvLyBhbGwgaW5wdXRzIGJ5IGNoZWNraW5nIHRoZSBuYW1lIHByb3AuIE1heWJlIGRvIGEgYmV0dGVyXG4gIC8vIGNoZWNrIGhlcmVcbiAgcmVnaXN0ZXJJbnB1dHM6IGZ1bmN0aW9uIChjaGlsZHJlbikge1xuICAgIFJlYWN0LkNoaWxkcmVuLmZvckVhY2goY2hpbGRyZW4sIGZ1bmN0aW9uIChjaGlsZCkge1xuXG4gICAgICBpZiAoY2hpbGQucHJvcHMgJiYgY2hpbGQucHJvcHMubmFtZSkge1xuICAgICAgICBjaGlsZC5wcm9wcy5fYXR0YWNoVG9Gb3JtID0gdGhpcy5hdHRhY2hUb0Zvcm07XG4gICAgICAgIGNoaWxkLnByb3BzLl9kZXRhY2hGcm9tRm9ybSA9IHRoaXMuZGV0YWNoRnJvbUZvcm07XG4gICAgICAgIGNoaWxkLnByb3BzLl92YWxpZGF0ZSA9IHRoaXMudmFsaWRhdGU7XG4gICAgICB9XG5cbiAgICAgIGlmIChjaGlsZC5wcm9wcyAmJiBjaGlsZC5wcm9wcy5jaGlsZHJlbikge1xuICAgICAgICB0aGlzLnJlZ2lzdGVySW5wdXRzKGNoaWxkLnByb3BzLmNoaWxkcmVuKTtcbiAgICAgIH1cblxuICAgIH0uYmluZCh0aGlzKSk7XG4gIH0sXG5cbiAgZ2V0Q3VycmVudFZhbHVlczogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBPYmplY3Qua2V5cyh0aGlzLmlucHV0cykucmVkdWNlKGZ1bmN0aW9uIChkYXRhLCBuYW1lKSB7XG4gICAgICB2YXIgY29tcG9uZW50ID0gdGhpcy5pbnB1dHNbbmFtZV07XG4gICAgICBkYXRhW25hbWVdID0gY29tcG9uZW50LnN0YXRlLl92YWx1ZTtcbiAgICAgIHJldHVybiBkYXRhO1xuICAgIH0uYmluZCh0aGlzKSwge30pO1xuICB9LFxuXG4gIHNldEZvcm1QcmlzdGluZTogZnVuY3Rpb24gKGlzUHJpc3RpbmUpIHtcbiAgICB2YXIgaW5wdXRzID0gdGhpcy5pbnB1dHM7XG4gICAgdmFyIGlucHV0S2V5cyA9IE9iamVjdC5rZXlzKGlucHV0cyk7XG5cbiAgICAvLyBJdGVyYXRlIHRocm91Z2ggZWFjaCBjb21wb25lbnQgYW5kIHNldCBpdCBhcyBwcmlzdGluZVxuICAgIC8vIG9yIFwiZGlydHlcIi5cbiAgICBpbnB1dEtleXMuZm9yRWFjaChmdW5jdGlvbiAobmFtZSwgaW5kZXgpIHtcbiAgICAgIHZhciBjb21wb25lbnQgPSBpbnB1dHNbbmFtZV07XG4gICAgICBjb21wb25lbnQuc2V0U3RhdGUoe1xuICAgICAgICBfaXNQcmlzdGluZTogaXNQcmlzdGluZVxuICAgICAgfSk7XG4gICAgfS5iaW5kKHRoaXMpKTtcbiAgfSxcblxuICAvLyBVc2UgdGhlIGJpbmRlZCB2YWx1ZXMgYW5kIHRoZSBhY3R1YWwgaW5wdXQgdmFsdWUgdG9cbiAgLy8gdmFsaWRhdGUgdGhlIGlucHV0IGFuZCBzZXQgaXRzIHN0YXRlLiBUaGVuIGNoZWNrIHRoZVxuICAvLyBzdGF0ZSBvZiB0aGUgZm9ybSBpdHNlbGZcbiAgdmFsaWRhdGU6IGZ1bmN0aW9uIChjb21wb25lbnQpIHtcblxuICAgIC8vIFRyaWdnZXIgb25DaGFuZ2VcbiAgICB0aGlzLnN0YXRlLmNhbkNoYW5nZSAmJiB0aGlzLnByb3BzLm9uQ2hhbmdlICYmIHRoaXMucHJvcHMub25DaGFuZ2UodGhpcy5nZXRDdXJyZW50VmFsdWVzKCkpO1xuXG4gICAgaWYgKCFjb21wb25lbnQucHJvcHMucmVxdWlyZWQgJiYgIWNvbXBvbmVudC5fdmFsaWRhdGlvbnMpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBSdW4gdGhyb3VnaCB0aGUgdmFsaWRhdGlvbnMsIHNwbGl0IHRoZW0gdXAgYW5kIGNhbGxcbiAgICAvLyB0aGUgdmFsaWRhdG9yIElGIHRoZXJlIGlzIGEgdmFsdWUgb3IgaXQgaXMgcmVxdWlyZWRcbiAgICB2YXIgaXNWYWxpZCA9IHRoaXMucnVuVmFsaWRhdGlvbihjb21wb25lbnQpO1xuXG4gICAgY29tcG9uZW50LnNldFN0YXRlKHtcbiAgICAgIF9pc1ZhbGlkOiBpc1ZhbGlkLFxuICAgICAgX3NlcnZlckVycm9yOiBudWxsXG4gICAgfSwgdGhpcy52YWxpZGF0ZUZvcm0pO1xuXG4gIH0sXG5cbiAgcnVuVmFsaWRhdGlvbjogZnVuY3Rpb24gKGNvbXBvbmVudCkge1xuICAgIHZhciBpc1ZhbGlkID0gdHJ1ZTtcbiAgICBpZiAoY29tcG9uZW50Ll92YWxpZGF0aW9ucy5sZW5ndGggJiYgKGNvbXBvbmVudC5wcm9wcy5yZXF1aXJlZCB8fCBjb21wb25lbnQuc3RhdGUuX3ZhbHVlICE9PSAnJykpIHtcbiAgICAgIGNvbXBvbmVudC5fdmFsaWRhdGlvbnMuc3BsaXQoJywnKS5mb3JFYWNoKGZ1bmN0aW9uICh2YWxpZGF0aW9uKSB7XG4gICAgICAgIHZhciBhcmdzID0gdmFsaWRhdGlvbi5zcGxpdCgnOicpO1xuICAgICAgICB2YXIgdmFsaWRhdGVNZXRob2QgPSBhcmdzLnNoaWZ0KCk7XG4gICAgICAgIGFyZ3MgPSBhcmdzLm1hcChmdW5jdGlvbiAoYXJnKSB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHJldHVybiBKU09OLnBhcnNlKGFyZyk7XG4gICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgcmV0dXJuIGFyZzsgLy8gSXQgaXMgYSBzdHJpbmcgaWYgaXQgY2FuIG5vdCBwYXJzZSBpdFxuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIGFyZ3MgPSBbY29tcG9uZW50LnN0YXRlLl92YWx1ZV0uY29uY2F0KGFyZ3MpO1xuICAgICAgICBpZiAoIXZhbGlkYXRpb25SdWxlc1t2YWxpZGF0ZU1ldGhvZF0pIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Zvcm1zeSBkb2VzIG5vdCBoYXZlIHRoZSB2YWxpZGF0aW9uIHJ1bGU6ICcgKyB2YWxpZGF0ZU1ldGhvZCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCF2YWxpZGF0aW9uUnVsZXNbdmFsaWRhdGVNZXRob2RdLmFwcGx5KHRoaXMuZ2V0Q3VycmVudFZhbHVlcygpLCBhcmdzKSkge1xuICAgICAgICAgIGlzVmFsaWQgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICB9XG4gICAgcmV0dXJuIGlzVmFsaWQ7XG4gIH0sXG5cbiAgLy8gVmFsaWRhdGUgdGhlIGZvcm0gYnkgZ29pbmcgdGhyb3VnaCBhbGwgY2hpbGQgaW5wdXQgY29tcG9uZW50c1xuICAvLyBhbmQgY2hlY2sgdGhlaXIgc3RhdGVcbiAgdmFsaWRhdGVGb3JtOiBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGFsbElzVmFsaWQgPSB0cnVlO1xuICAgIHZhciBpbnB1dHMgPSB0aGlzLmlucHV0cztcbiAgICB2YXIgaW5wdXRLZXlzID0gT2JqZWN0LmtleXMoaW5wdXRzKTtcblxuICAgIC8vIFdlIG5lZWQgYSBjYWxsYmFjayBhcyB3ZSBhcmUgdmFsaWRhdGluZyBhbGwgaW5wdXRzIGFnYWluLiBUaGlzIHdpbGxcbiAgICAvLyBydW4gd2hlbiB0aGUgbGFzdCBjb21wb25lbnQgaGFzIHNldCBpdHMgc3RhdGVcbiAgICB2YXIgb25WYWxpZGF0aW9uQ29tcGxldGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICBpbnB1dEtleXMuZm9yRWFjaChmdW5jdGlvbiAobmFtZSkge1xuICAgICAgICBpZiAoIWlucHV0c1tuYW1lXS5zdGF0ZS5faXNWYWxpZCkge1xuICAgICAgICAgIGFsbElzVmFsaWQgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgfS5iaW5kKHRoaXMpKTtcblxuICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgIGlzVmFsaWQ6IGFsbElzVmFsaWRcbiAgICAgIH0pO1xuXG4gICAgICBhbGxJc1ZhbGlkICYmIHRoaXMucHJvcHMub25WYWxpZCgpO1xuICAgICAgIWFsbElzVmFsaWQgJiYgdGhpcy5wcm9wcy5vbkludmFsaWQoKTtcblxuICAgICAgLy8gVGVsbCB0aGUgZm9ybSB0aGF0IGl0IGNhbiBzdGFydCB0byB0cmlnZ2VyIGNoYW5nZSBldmVudHNcbiAgICAgIHRoaXMuc2V0U3RhdGUoe2NhbkNoYW5nZTogdHJ1ZX0pO1xuXG4gICAgfS5iaW5kKHRoaXMpO1xuXG4gICAgLy8gUnVuIHZhbGlkYXRpb24gYWdhaW4gaW4gY2FzZSBhZmZlY3RlZCBieSBvdGhlciBpbnB1dHMuIFRoZVxuICAgIC8vIGxhc3QgY29tcG9uZW50IHZhbGlkYXRlZCB3aWxsIHJ1biB0aGUgb25WYWxpZGF0aW9uQ29tcGxldGUgY2FsbGJhY2tcbiAgICBpbnB1dEtleXMuZm9yRWFjaChmdW5jdGlvbiAobmFtZSwgaW5kZXgpIHtcbiAgICAgIHZhciBjb21wb25lbnQgPSBpbnB1dHNbbmFtZV07XG4gICAgICB2YXIgaXNWYWxpZCA9IHRoaXMucnVuVmFsaWRhdGlvbihjb21wb25lbnQpO1xuICAgICAgY29tcG9uZW50LnNldFN0YXRlKHtcbiAgICAgICAgX2lzVmFsaWQ6IGlzVmFsaWQsXG4gICAgICAgIF9zZXJ2ZXJFcnJvcjogbnVsbFxuICAgICAgfSwgaW5kZXggPT09IGlucHV0S2V5cy5sZW5ndGggLSAxID8gb25WYWxpZGF0aW9uQ29tcGxldGUgOiBudWxsKTtcbiAgICB9LmJpbmQodGhpcykpO1xuXG4gICAgLy8gSWYgdGhlcmUgYXJlIG5vIGlucHV0cywgaXQgaXMgcmVhZHkgdG8gdHJpZ2dlciBjaGFuZ2UgZXZlbnRzXG4gICAgaWYgKCFpbnB1dEtleXMubGVuZ3RoKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHtjYW5DaGFuZ2U6IHRydWV9KTtcbiAgICB9XG5cbiAgfSxcblxuICAvLyBNZXRob2QgcHV0IG9uIGVhY2ggaW5wdXQgY29tcG9uZW50IHRvIHJlZ2lzdGVyXG4gIC8vIGl0c2VsZiB0byB0aGUgZm9ybVxuICBhdHRhY2hUb0Zvcm06IGZ1bmN0aW9uIChjb21wb25lbnQpIHtcbiAgICB0aGlzLmlucHV0c1tjb21wb25lbnQucHJvcHMubmFtZV0gPSBjb21wb25lbnQ7XG4gICAgdGhpcy5tb2RlbFtjb21wb25lbnQucHJvcHMubmFtZV0gPSBjb21wb25lbnQuc3RhdGUuX3ZhbHVlO1xuICAgIHRoaXMudmFsaWRhdGUoY29tcG9uZW50KTtcbiAgfSxcblxuICAvLyBNZXRob2QgcHV0IG9uIGVhY2ggaW5wdXQgY29tcG9uZW50IHRvIHVucmVnaXN0ZXJcbiAgLy8gaXRzZWxmIGZyb20gdGhlIGZvcm1cbiAgZGV0YWNoRnJvbUZvcm06IGZ1bmN0aW9uIChjb21wb25lbnQpIHtcbiAgICBkZWxldGUgdGhpcy5pbnB1dHNbY29tcG9uZW50LnByb3BzLm5hbWVdO1xuICAgIGRlbGV0ZSB0aGlzLm1vZGVsW2NvbXBvbmVudC5wcm9wcy5uYW1lXTtcbiAgfSxcbiAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG5cbiAgICByZXR1cm4gUmVhY3QuRE9NLmZvcm0oe1xuICAgICAgICBvblN1Ym1pdDogdGhpcy5zdWJtaXQsXG4gICAgICAgIGNsYXNzTmFtZTogdGhpcy5wcm9wcy5jbGFzc05hbWVcbiAgICAgIH0sXG4gICAgICB0aGlzLnByb3BzLmNoaWxkcmVuXG4gICAgKTtcblxuICB9XG59KTtcblxuaWYgKCFnbG9iYWwuZXhwb3J0cyAmJiAhZ2xvYmFsLm1vZHVsZSAmJiAoIWdsb2JhbC5kZWZpbmUgfHwgIWdsb2JhbC5kZWZpbmUuYW1kKSkge1xuICBnbG9iYWwuRm9ybXN5ID0gRm9ybXN5O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IEZvcm1zeTtcbiJdfQ==
diff --git a/build/specs.js b/build/specs.js
index 1c97b92..d169a23 100644
--- a/build/specs.js
+++ b/build/specs.js
@@ -280,24 +280,287 @@ describe('Element', function() {
},{"./../src/main.js":"/Users/christianalfoni/Documents/dev/formsy-react/src/main.js"}],"./specs/Formsy-spec.js":[function(require,module,exports){
var Formsy = require('./../src/main.js');
-describe('Formsy', function() {
+describe('Formsy', function () {
describe('Setting up a form', function () {
-
- it('should render a form into the document', function() {
- var form = TestUtils.renderIntoDocument(
- React.createElement(Formsy.Form, null)
- );
+
+ it('should render a form into the document', function () {
+ var form = TestUtils.renderIntoDocument( React.createElement(Formsy.Form, null));
expect(form.getDOMNode().tagName).toEqual('FORM');
});
it('should set a class name if passed', function () {
- var form = TestUtils.renderIntoDocument(
- React.createElement(Formsy.Form, {className: "foo"})
- );
+ var form = TestUtils.renderIntoDocument( React.createElement(Formsy.Form, {className: "foo"}));
expect(form.getDOMNode().className).toEqual('foo');
});
+ it('should allow for inputs being added dynamically', function (done) {
+
+ var inputs = [];
+ var forceUpdate = null;
+ var model = null;
+ var TestInput = React.createClass({displayName: "TestInput",
+ mixins: [Formsy.Mixin],
+ render: function () {
+ return React.createElement("div", null)
+ }
+ });
+ var TestForm = React.createClass({displayName: "TestForm",
+ componentWillMount: function () {
+ forceUpdate = this.forceUpdate.bind(this);
+ },
+ onSubmit: function (formModel) {
+ model = formModel;
+ },
+ render: function () {
+ return (
+ React.createElement(Formsy.Form, {onSubmit: this.onSubmit},
+ inputs
+ ));
+ }
+ });
+ var form = TestUtils.renderIntoDocument(
+ React.createElement(TestForm, null)
+ );
+
+ // Wait before adding the input
+ setTimeout(function () {
+
+ inputs.push(TestInput({
+ name: 'test'
+ }));
+
+ forceUpdate(function () {
+
+ // Wait for next event loop, as that does the form
+ setTimeout(function () {
+ TestUtils.Simulate.submit(form.getDOMNode());
+ expect(model.test).toBeDefined();
+ done();
+ }, 0);
+
+ });
+
+ }, 10);
+
+ });
+
+ it('should allow dynamically added inputs to update the form-model', function (done) {
+
+ var inputs = [];
+ var forceUpdate = null;
+ var model = null;
+ var TestInput = React.createClass({displayName: "TestInput",
+ mixins: [Formsy.Mixin],
+ changeValue: function (event) {
+ this.setValue(event.target.value);
+ },
+ render: function () {
+ return React.createElement("input", {value: this.getValue(), onChange: this.changeValue})
+ }
+ });
+ var TestForm = React.createClass({displayName: "TestForm",
+ componentWillMount: function () {
+ forceUpdate = this.forceUpdate.bind(this);
+ },
+ onSubmit: function (formModel) {
+ model = formModel;
+ },
+ render: function () {
+ return (
+ React.createElement(Formsy.Form, {onSubmit: this.onSubmit},
+ inputs
+ ));
+ }
+ });
+ var form = TestUtils.renderIntoDocument(
+ React.createElement(TestForm, null)
+ );
+
+ // Wait before adding the input
+ setTimeout(function () {
+
+ inputs.push(TestInput({
+ name: 'test'
+ }));
+
+ forceUpdate(function () {
+
+ // Wait for next event loop, as that does the form
+ setTimeout(function () {
+ TestUtils.Simulate.change(TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT'), {target: {value: 'foo'}});
+ TestUtils.Simulate.submit(form.getDOMNode());
+ expect(model.test).toBe('foo');
+ done();
+ }, 0);
+
+ });
+
+ }, 10);
+
+ });
+
+ it('should invalidate a valid form if dynamically inserted input is invalid', function (done) {
+
+ var forceUpdate = null;
+ var isInvalid = false;
+ var TestInput = React.createClass({displayName: "TestInput",
+ mixins: [Formsy.Mixin],
+ changeValue: function (event) {
+ this.setValue(event.target.value);
+ },
+ render: function () {
+ return React.createElement("input", {value: this.getValue(), onChange: this.changeValue})
+ }
+ });
+
+
+ var inputs = [TestInput({
+ name: 'test',
+ validations: 'isEmail',
+ value: 'foo@bar.com'
+ })];
+
+ var TestForm = React.createClass({displayName: "TestForm",
+ componentWillMount: function () {
+ forceUpdate = this.forceUpdate.bind(this);
+ },
+ setInvalid: function () {
+ isInvalid = true;
+ },
+ render: function () {
+ return (
+ React.createElement(Formsy.Form, {onInvalid: this.setInvalid},
+ inputs
+ ));
+ }
+ });
+ var form = TestUtils.renderIntoDocument(
+ React.createElement(TestForm, null)
+ );
+
+ expect(isInvalid).toBe(false);
+
+ // Wait before adding the input
+ setTimeout(function () {
+
+
+ inputs.push(TestInput({
+ name: 'test2',
+ validations: 'isEmail',
+ value: 'foo@bar'
+ }));
+
+
+ forceUpdate(function () {
+
+ // Wait for next event loop, as that does the form
+ setTimeout(function () {
+ TestUtils.Simulate.submit(form.getDOMNode());
+ expect(isInvalid).toBe(true);
+ done();
+ }, 0);
+
+ });
+
+ }, 10);
+
+ });
+
+ it('should not trigger onChange when form is mounted', function () {
+ var hasChanged = jasmine.createSpy('onChange');
+ var TestForm = React.createClass({displayName: "TestForm",
+ onChange: function () {
+ hasChanged();
+ },
+ render: function () {
+ return React.createElement(Formsy.Form, {onChange: this.onChange});
+ }
+ });
+ var form = TestUtils.renderIntoDocument(React.createElement(TestForm, null));
+ expect(hasChanged).not.toHaveBeenCalled();
+ });
+
+ it('should trigger onChange when form element is changed', function () {
+ var hasChanged = jasmine.createSpy('onChange');
+ var MyInput = React.createClass({displayName: "MyInput",
+ mixins: [Formsy.Mixin],
+ onChange: function (event) {
+ this.setValue(event.target.value);
+ },
+ render: function () {
+ return React.createElement("input", {value: this.getValue(), onChange: this.onChange})
+ }
+ });
+ var TestForm = React.createClass({displayName: "TestForm",
+ onChange: function () {
+ hasChanged();
+ },
+ render: function () {
+ return (
+ React.createElement(Formsy.Form, {onChange: this.onChange},
+ React.createElement(MyInput, {name: "foo"})
+ )
+ );
+ }
+ });
+ var form = TestUtils.renderIntoDocument(React.createElement(TestForm, null));
+ TestUtils.Simulate.change(TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT'), {target: {value: 'bar'}});
+ expect(hasChanged).toHaveBeenCalled();
+ });
+
+ it('should trigger onChange when new input is added to form', function (done) {
+ var hasChanged = jasmine.createSpy('onChange');
+ var inputs = [];
+ var forceUpdate = null;
+ var TestInput = React.createClass({displayName: "TestInput",
+ mixins: [Formsy.Mixin],
+ changeValue: function (event) {
+ this.setValue(event.target.value);
+ },
+ render: function () {
+ return React.createElement("input", {value: this.getValue(), onChange: this.changeValue})
+ }
+ });
+ var TestForm = React.createClass({displayName: "TestForm",
+ componentWillMount: function () {
+ forceUpdate = this.forceUpdate.bind(this);
+ },
+ onChange: function () {
+ hasChanged();
+ },
+ render: function () {
+ return (
+ React.createElement(Formsy.Form, {onChange: this.onChange},
+ inputs
+ ));
+ }
+ });
+ var form = TestUtils.renderIntoDocument(
+ React.createElement(TestForm, null)
+ );
+
+ // Wait before adding the input
+ setTimeout(function () {
+
+ inputs.push(TestInput({
+ name: 'test'
+ }));
+
+ forceUpdate(function () {
+
+ // Wait for next event loop, as that does the form
+ setTimeout(function () {
+ expect(hasChanged).toHaveBeenCalled();
+ done();
+ }, 0);
+
+ });
+
+ }, 10);
+
+ });
+
});
});
@@ -563,6 +826,62 @@ describe('Validation', function() {
});
+ it('RULE: isNumeric', function () {
+
+ var isValid = jasmine.createSpy('valid');
+ var TestInput = React.createClass({displayName: "TestInput",
+ mixins: [Formsy.Mixin],
+ updateValue: function (event) {
+ this.setValue(event.target.value);
+ },
+ render: function () {
+ if (this.isValid()) {
+ isValid();
+ }
+ return React.createElement("input", {value: this.getValue(), onChange: this.updateValue})
+ }
+ });
+ var form = TestUtils.renderIntoDocument(
+ React.createElement(Formsy.Form, null,
+ React.createElement(TestInput, {name: "foo", value: "foo", validations: "isNumeric"})
+ )
+ );
+
+ var input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
+ expect(isValid).not.toHaveBeenCalled();
+ TestUtils.Simulate.change(input, {target: {value: '123'}});
+ expect(isValid).toHaveBeenCalled();
+
+ });
+
+ it('RULE: isNumeric (actual number)', function () {
+
+ var isValid = jasmine.createSpy('valid');
+ var TestInput = React.createClass({displayName: "TestInput",
+ mixins: [Formsy.Mixin],
+ updateValue: function (event) {
+ this.setValue(Number(event.target.value));
+ },
+ render: function () {
+ if (this.isValid()) {
+ isValid();
+ }
+ return React.createElement("input", {value: this.getValue(), onChange: this.updateValue})
+ }
+ });
+ var form = TestUtils.renderIntoDocument(
+ React.createElement(Formsy.Form, null,
+ React.createElement(TestInput, {name: "foo", value: "foo", validations: "isNumeric"})
+ )
+ );
+
+ var input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
+ expect(isValid).not.toHaveBeenCalled();
+ TestUtils.Simulate.change(input, {target: {value: '123'}});
+ expect(isValid).toHaveBeenCalled();
+
+ });
+
});
},{"./../src/main.js":"/Users/christianalfoni/Documents/dev/formsy-react/src/main.js"}],"/Users/christianalfoni/Documents/dev/formsy-react/src/main.js":[function(require,module,exports){
@@ -580,7 +899,11 @@ var validationRules = {
return value === true;
},
'isNumeric': function (value) {
- return value.match(/^-?[0-9]+$/)
+ if (typeof value === 'number') {
+ return true;
+ } else {
+ return value.match(/^-?[0-9]+$/);
+ }
},
'isAlpha': function (value) {
return value.match(/^[a-zA-Z]+$/);
@@ -599,6 +922,9 @@ var validationRules = {
},
equals: function (value, eql) {
return value == eql;
+ },
+ equalsField: function (value, field) {
+ return value === this[field];
}
};
@@ -653,6 +979,21 @@ var request = function (method, url, data, contentType, headers) {
});
};
+
+var arraysDiffer = function (arrayA, arrayB) {
+ var isDifferent = false;
+ if (arrayA.length !== arrayB.length) {
+ isDifferent = true;
+ } else {
+ arrayA.forEach(function (item, index) {
+ if (item !== arrayB[index]) {
+ isDifferent = true;
+ }
+ });
+ }
+ return isDifferent;
+};
+
var ajax = {
post: request.bind(null, 'POST'),
put: request.bind(null, 'PUT')
@@ -673,22 +1014,31 @@ Formsy.Mixin = {
},
componentWillMount: function () {
+ var configure = function () {
+ // Add validations to the store itself as the props object can not be modified
+ this._validations = this.props.validations || '';
+
+ if (this.props.required) {
+ this._validations = this.props.validations ? this.props.validations + ',' : '';
+ this._validations += 'isValue';
+ }
+ this.props._attachToForm(this);
+ }.bind(this);
+
if (!this.props.name) {
throw new Error('Form Input requires a name property when used');
}
if (!this.props._attachToForm) {
- throw new Error('Form Mixin requires component to be nested in a Form');
+ return setTimeout(function () {
+ if (!this.props._attachToForm) {
+ throw new Error('Form Mixin requires component to be nested in a Form');
+ }
+ configure();
+ }.bind(this), 0);
}
+ configure();
- // Add validations to the store itself as the props object can not be modified
- this._validations = this.props.validations || '';
-
- if (this.props.required) {
- this._validations = this.props.validations ? this.props.validations + ',' : '';
- this._validations += 'isValue';
- }
- this.props._attachToForm(this);
},
// We have to make the validate method is kept when new props are added
@@ -754,7 +1104,8 @@ Formsy.Form = React.createClass({displayName: "Form",
getInitialState: function () {
return {
isValid: true,
- isSubmitting: false
+ isSubmitting: false,
+ canChange: false
};
},
getDefaultProps: function () {
@@ -765,7 +1116,8 @@ Formsy.Form = React.createClass({displayName: "Form",
onSubmit: function () {},
onSubmitted: function () {},
onValid: function () {},
- onInvalid: function () {}
+ onInvalid: function () {},
+ onChange: function () {}
};
},
@@ -781,6 +1133,21 @@ Formsy.Form = React.createClass({displayName: "Form",
this.validateForm();
},
+ componentWillUpdate: function () {
+ var inputKeys = Object.keys(this.inputs);
+
+ // The updated children array is not available here for some reason,
+ // we need to wait for next event loop
+ setTimeout(function () {
+ this.registerInputs(this.props.children);
+
+ var newInputKeys = Object.keys(this.inputs);
+ if (arraysDiffer(inputKeys, newInputKeys)) {
+ this.validateForm();
+ }
+ }.bind(this), 0);
+ },
+
// Update model, submit to url prop and send the model
submit: function (event) {
event.preventDefault();
@@ -893,7 +1260,7 @@ Formsy.Form = React.createClass({displayName: "Form",
}.bind(this), {});
},
- setFormPristine: function(isPristine) {
+ setFormPristine: function (isPristine) {
var inputs = this.inputs;
var inputKeys = Object.keys(inputs);
@@ -912,6 +1279,9 @@ Formsy.Form = React.createClass({displayName: "Form",
// state of the form itself
validate: function (component) {
+ // Trigger onChange
+ this.state.canChange && this.props.onChange && this.props.onChange(this.getCurrentValues());
+
if (!component.props.required && !component._validations) {
return;
}
@@ -975,6 +1345,9 @@ Formsy.Form = React.createClass({displayName: "Form",
allIsValid && this.props.onValid();
!allIsValid && this.props.onInvalid();
+ // Tell the form that it can start to trigger change events
+ this.setState({canChange: true});
+
}.bind(this);
// Run validation again in case affected by other inputs. The
@@ -988,6 +1361,11 @@ Formsy.Form = React.createClass({displayName: "Form",
}, index === inputKeys.length - 1 ? onValidationComplete : null);
}.bind(this));
+ // If there are no inputs, it is ready to trigger change events
+ if (!inputKeys.length) {
+ this.setState({canChange: true});
+ }
+
},
// Method put on each input component to register
@@ -1025,4 +1403,4 @@ module.exports = Formsy;
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"react":"react"}]},{},["./specs/Element-spec.js","./specs/Formsy-spec.js","./specs/Submit-spec.js","./specs/Validation-spec.js"])
-//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcGVjcy9FbGVtZW50LXNwZWMuanMiLCJzcGVjcy9Gb3Jtc3ktc3BlYy5qcyIsInNwZWNzL1N1Ym1pdC1zcGVjLmpzIiwic3BlY3MvVmFsaWRhdGlvbi1zcGVjLmpzIiwic3JjL21haW4uanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbExBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUNqRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCJ2YXIgRm9ybXN5ID0gcmVxdWlyZSgnLi8uLi9zcmMvbWFpbi5qcycpO1xuXG5kZXNjcmliZSgnRWxlbWVudCcsIGZ1bmN0aW9uKCkge1xuXG4gIGl0KCdzaG91bGQgcmV0dXJuIHBhc3NlZCBhbmQgc2V0VmFsdWUoKSB2YWx1ZSB3aGVuIHVzaW5nIGdldFZhbHVlKCknLCBmdW5jdGlvbiAoKSB7XG4gICAgXG4gICAgdmFyIFRlc3RJbnB1dCA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtkaXNwbGF5TmFtZTogXCJUZXN0SW5wdXRcIixcbiAgICAgIG1peGluczogW0Zvcm1zeS5NaXhpbl0sXG4gICAgICB1cGRhdGVWYWx1ZTogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIHRoaXMuc2V0VmFsdWUoZXZlbnQudGFyZ2V0LnZhbHVlKTtcbiAgICAgIH0sXG4gICAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJpbnB1dFwiLCB7dmFsdWU6IHRoaXMuZ2V0VmFsdWUoKSwgb25DaGFuZ2U6IHRoaXMudXBkYXRlVmFsdWV9KVxuICAgICAgfVxuICAgIH0pO1xuICAgIHZhciBmb3JtID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudChcbiAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRm9ybXN5LkZvcm0sIG51bGwsIFxuICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFRlc3RJbnB1dCwge25hbWU6IFwiZm9vXCIsIHZhbHVlOiBcImZvb1wifSlcbiAgICAgIClcbiAgICApO1xuXG4gICAgdmFyIGlucHV0ID0gVGVzdFV0aWxzLmZpbmRSZW5kZXJlZERPTUNvbXBvbmVudFdpdGhUYWcoZm9ybSwgJ0lOUFVUJyk7XG4gICAgZXhwZWN0KGlucHV0LmdldERPTU5vZGUoKS52YWx1ZSkudG9CZSgnZm9vJyk7XG4gICAgVGVzdFV0aWxzLlNpbXVsYXRlLmNoYW5nZShpbnB1dCwge3RhcmdldDoge3ZhbHVlOiAnZm9vYmFyJ319KTtcbiAgICBleHBlY3QoaW5wdXQuZ2V0RE9NTm9kZSgpLnZhbHVlKS50b0JlKCdmb29iYXInKTtcblxuICB9KTtcblxuICBpdCgnc2hvdWxkIHJldHVybiB0cnVlIG9yIGZhbHNlIHdoZW4gY2FsbGluZyBoYXNWYWx1ZSgpIGRlcGVuZGluZyBvbiB2YWx1ZSBleGlzdGFuY2UnLCBmdW5jdGlvbiAoKSB7XG4gICAgXG4gICAgdmFyIHJlc2V0ID0gbnVsbDtcbiAgICB2YXIgVGVzdElucHV0ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIlRlc3RJbnB1dFwiLFxuICAgICAgbWl4aW5zOiBbRm9ybXN5Lk1peGluXSxcbiAgICAgIGNvbXBvbmVudERpZE1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJlc2V0ID0gdGhpcy5yZXNldFZhbHVlO1xuICAgICAgfSxcbiAgICAgIHVwZGF0ZVZhbHVlOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgdGhpcy5zZXRWYWx1ZShldmVudC50YXJnZXQudmFsdWUpO1xuICAgICAgfSxcbiAgICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gUmVhY3QuY3JlYXRlRWxlbWVudChcImlucHV0XCIsIHt2YWx1ZTogdGhpcy5nZXRWYWx1ZSgpLCBvbkNoYW5nZTogdGhpcy51cGRhdGVWYWx1ZX0pXG4gICAgICB9XG4gICAgfSk7XG4gICAgdmFyIGZvcm0gPSBUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50KFxuICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChGb3Jtc3kuRm9ybSwgbnVsbCwgXG4gICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoVGVzdElucHV0LCB7bmFtZTogXCJmb29cIiwgdmFsdWU6IFwiZm9vXCJ9KVxuICAgICAgKVxuICAgICk7XG5cbiAgICB2YXIgaW5wdXQgPSBUZXN0VXRpbHMuZmluZFJlbmRlcmVkRE9NQ29tcG9uZW50V2l0aFRhZyhmb3JtLCAnSU5QVVQnKTtcbiAgICByZXNldCgpO1xuICAgIGV4cGVjdChpbnB1dC5nZXRET01Ob2RlKCkudmFsdWUpLnRvQmUoJycpO1xuXG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgcmV0dXJuIGVycm9yIG1lc3NhZ2UgcGFzc2VkIHdoZW4gY2FsbGluZyBnZXRFcnJvck1lc3NhZ2UoKScsIGZ1bmN0aW9uICgpIHtcbiAgICBcbiAgICB2YXIgZ2V0RXJyb3JNZXNzYWdlID0gbnVsbDtcbiAgICB2YXIgVGVzdElucHV0ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIlRlc3RJbnB1dFwiLFxuICAgICAgbWl4aW5zOiBbRm9ybXN5Lk1peGluXSxcbiAgICAgIGNvbXBvbmVudERpZE1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGdldEVycm9yTWVzc2FnZSA9IHRoaXMuZ2V0RXJyb3JNZXNzYWdlO1xuICAgICAgfSxcbiAgICAgIHVwZGF0ZVZhbHVlOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgdGhpcy5zZXRWYWx1ZShldmVudC50YXJnZXQudmFsdWUpO1xuICAgICAgfSxcbiAgICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gUmVhY3QuY3JlYXRlRWxlbWVudChcImlucHV0XCIsIHt2YWx1ZTogdGhpcy5nZXRWYWx1ZSgpLCBvbkNoYW5nZTogdGhpcy51cGRhdGVWYWx1ZX0pXG4gICAgICB9XG4gICAgfSk7XG4gICAgdmFyIGZvcm0gPSBUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50KFxuICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChGb3Jtc3kuRm9ybSwgbnVsbCwgXG4gICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoVGVzdElucHV0LCB7bmFtZTogXCJmb29cIiwgdmFsdWU6IFwiZm9vXCIsIHZhbGlkYXRpb25zOiBcImlzRW1haWxcIiwgdmFsaWRhdGlvbkVycm9yOiBcIkhhcyB0byBiZSBlbWFpbFwifSlcbiAgICAgIClcbiAgICApO1xuXG4gICAgZXhwZWN0KGdldEVycm9yTWVzc2FnZSgpKS50b0JlKCdIYXMgdG8gYmUgZW1haWwnKTtcblxuICB9KTtcblxuICBpdCgnc2hvdWxkIHJldHVybiBzZXJ2ZXIgZXJyb3IgbWVzc2FnZSB3aGVuIGNhbGxpbmcgZ2V0RXJyb3JNZXNzYWdlKCknLCBmdW5jdGlvbiAoZG9uZSkge1xuICAgIFxuICAgIGphc21pbmUuQWpheC5pbnN0YWxsKCk7XG5cbiAgICB2YXIgZ2V0RXJyb3JNZXNzYWdlID0gbnVsbDtcbiAgICB2YXIgVGVzdElucHV0ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIlRlc3RJbnB1dFwiLFxuICAgICAgbWl4aW5zOiBbRm9ybXN5Lk1peGluXSxcbiAgICAgIGNvbXBvbmVudERpZE1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGdldEVycm9yTWVzc2FnZSA9IHRoaXMuZ2V0RXJyb3JNZXNzYWdlO1xuICAgICAgfSxcbiAgICAgIHVwZGF0ZVZhbHVlOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgdGhpcy5zZXRWYWx1ZShldmVudC50YXJnZXQudmFsdWUpO1xuICAgICAgfSxcbiAgICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gUmVhY3QuY3JlYXRlRWxlbWVudChcImlucHV0XCIsIHt2YWx1ZTogdGhpcy5nZXRWYWx1ZSgpLCBvbkNoYW5nZTogdGhpcy51cGRhdGVWYWx1ZX0pXG4gICAgICB9XG4gICAgfSk7XG4gICAgdmFyIGZvcm0gPSBUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50KFxuICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChGb3Jtc3kuRm9ybSwge3VybDogXCIvdXNlcnNcIn0sIFxuICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFRlc3RJbnB1dCwge25hbWU6IFwiZm9vXCIsIHZhbHVlOiBcImZvb1wiLCB2YWxpZGF0aW9uczogXCJpc0VtYWlsXCIsIHZhbGlkYXRpb25FcnJvcjogXCJIYXMgdG8gYmUgZW1haWxcIn0pXG4gICAgICApXG4gICAgKTtcblxuICAgIHZhciBmb3JtID0gVGVzdFV0aWxzLlNpbXVsYXRlLnN1Ym1pdChmb3JtLmdldERPTU5vZGUoKSk7XG5cbiAgICBqYXNtaW5lLkFqYXgucmVxdWVzdHMubW9zdFJlY2VudCgpLnJlc3BvbmRXaXRoKHtcbiAgICAgIHN0YXR1czogNTAwLFxuICAgICAgY29udGVudFR5cGU6ICdhcHBsaWNhdGlvbi9qc29uJyxcbiAgICAgIHJlc3BvbnNlVGV4dDogJ3tcImZvb1wiOiBcImJhclwifSdcbiAgICB9KVxuXG4gICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICBleHBlY3QoZ2V0RXJyb3JNZXNzYWdlKCkpLnRvQmUoJ2JhcicpO1xuICAgICAgamFzbWluZS5BamF4LnVuaW5zdGFsbCgpO1xuICAgICAgZG9uZSgpO1xuICAgIH0sIDApO1xuXG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgcmV0dXJuIHRydWUgb3IgZmFsc2Ugd2hlbiBjYWxsaW5nIGlzVmFsaWQoKSBkZXBlbmRpbmcgb24gdmFsaWQgc3RhdGUnLCBmdW5jdGlvbiAoKSB7XG4gICAgXG4gICAgdmFyIGlzVmFsaWQgPSBudWxsO1xuICAgIHZhciBUZXN0SW5wdXQgPSBSZWFjdC5jcmVhdGVDbGFzcyh7ZGlzcGxheU5hbWU6IFwiVGVzdElucHV0XCIsXG4gICAgICBtaXhpbnM6IFtGb3Jtc3kuTWl4aW5dLFxuICAgICAgY29tcG9uZW50RGlkTW91bnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaXNWYWxpZCA9IHRoaXMuaXNWYWxpZDtcbiAgICAgIH0sXG4gICAgICB1cGRhdGVWYWx1ZTogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdldmVudC50YXJnZXQudmFsdWUnLCBldmVudC50YXJnZXQudmFsdWUpO1xuICAgICAgICB0aGlzLnNldFZhbHVlKGV2ZW50LnRhcmdldC52YWx1ZSk7XG4gICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGNvbnNvbGUubG9nKCd0aGlzLmdldFZhbHVlKCknLCB0aGlzLmdldFZhbHVlKCkpO1xuICAgICAgICB9LmJpbmQodGhpcyksIDEwMCk7XG4gICAgICB9LFxuICAgICAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBSZWFjdC5jcmVhdGVFbGVtZW50KFwiaW5wdXRcIiwge3ZhbHVlOiB0aGlzLmdldFZhbHVlKCksIG9uQ2hhbmdlOiB0aGlzLnVwZGF0ZVZhbHVlfSlcbiAgICAgIH1cbiAgICB9KTtcbiAgICB2YXIgZm9ybSA9IFRlc3RVdGlscy5yZW5kZXJJbnRvRG9jdW1lbnQoXG4gICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KEZvcm1zeS5Gb3JtLCB7dXJsOiBcIi91c2Vyc1wifSwgXG4gICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoVGVzdElucHV0LCB7bmFtZTogXCJmb29cIiwgdmFsdWU6IFwiZm9vXCIsIHZhbGlkYXRpb25zOiBcImlzRW1haWxcIn0pXG4gICAgICApXG4gICAgKTtcblxuICAgIGV4cGVjdChpc1ZhbGlkKCkpLnRvQmUoZmFsc2UpO1xuICAgIHZhciBpbnB1dCA9IFRlc3RVdGlscy5maW5kUmVuZGVyZWRET01Db21wb25lbnRXaXRoVGFnKGZvcm0sICdJTlBVVCcpO1xuICAgIFRlc3RVdGlscy5TaW11bGF0ZS5jaGFuZ2UoaW5wdXQsIHt0YXJnZXQ6IHt2YWx1ZTogJ2Zvb0Bmb28uY29tJ319KTtcbiAgICBleHBlY3QoaXNWYWxpZCgpKS50b0JlKHRydWUpO1xuXG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgcmV0dXJuIHRydWUgb3IgZmFsc2Ugd2hlbiBjYWxsaW5nIGlzUmVxdWlyZWQoKSBkZXBlbmRpbmcgb24gcGFzc2VkIHJlcXVpcmVkIGF0dHJpYnV0ZScsIGZ1bmN0aW9uICgpIHtcbiAgICBcbiAgICB2YXIgaXNSZXF1aXJlZHMgPSBbXTtcbiAgICB2YXIgVGVzdElucHV0ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIlRlc3RJbnB1dFwiLFxuICAgICAgbWl4aW5zOiBbRm9ybXN5Lk1peGluXSxcbiAgICAgIGNvbXBvbmVudERpZE1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlzUmVxdWlyZWRzLnB1c2godGhpcy5pc1JlcXVpcmVkKTtcbiAgICAgIH0sXG4gICAgICB1cGRhdGVWYWx1ZTogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIHRoaXMuc2V0VmFsdWUoZXZlbnQudGFyZ2V0LnZhbHVlKTtcbiAgICAgIH0sXG4gICAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJpbnB1dFwiLCB7dmFsdWU6IHRoaXMuZ2V0VmFsdWUoKSwgb25DaGFuZ2U6IHRoaXMudXBkYXRlVmFsdWV9KVxuICAgICAgfVxuICAgIH0pO1xuICAgIHZhciBmb3JtID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudChcbiAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRm9ybXN5LkZvcm0sIHt1cmw6IFwiL3VzZXJzXCJ9LCBcbiAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChUZXN0SW5wdXQsIHtuYW1lOiBcImZvb1wiLCB2YWx1ZTogXCJmb29cIn0pLCBcbiAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChUZXN0SW5wdXQsIHtuYW1lOiBcImZvb1wiLCB2YWx1ZTogXCJmb29cIiwgcmVxdWlyZWQ6IHRydWV9KVxuICAgICAgKVxuICAgICk7XG5cbiAgICBleHBlY3QoaXNSZXF1aXJlZHNbMF0oKSkudG9CZShmYWxzZSk7XG4gICAgZXhwZWN0KGlzUmVxdWlyZWRzWzFdKCkpLnRvQmUodHJ1ZSk7XG5cbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCByZXR1cm4gdHJ1ZSBvciBmYWxzZSB3aGVuIGNhbGxpbmcgc2hvd1JlcXVpcmVkKCkgZGVwZW5kaW5nIG9uIGlucHV0IGJlaW5nIGVtcHR5IGFuZCByZXF1aXJlZCBpcyBwYXNzZWQsIG9yIG5vdCcsIGZ1bmN0aW9uICgpIHtcbiAgICBcbiAgICB2YXIgc2hvd1JlcXVpcmVkcyA9IFtdO1xuICAgIHZhciBUZXN0SW5wdXQgPSBSZWFjdC5jcmVhdGVDbGFzcyh7ZGlzcGxheU5hbWU6IFwiVGVzdElucHV0XCIsXG4gICAgICBtaXhpbnM6IFtGb3Jtc3kuTWl4aW5dLFxuICAgICAgY29tcG9uZW50RGlkTW91bnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgc2hvd1JlcXVpcmVkcy5wdXNoKHRoaXMuc2hvd1JlcXVpcmVkKTtcbiAgICAgIH0sXG4gICAgICB1cGRhdGVWYWx1ZTogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIHRoaXMuc2V0VmFsdWUoZXZlbnQudGFyZ2V0LnZhbHVlKTtcbiAgICAgIH0sXG4gICAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJpbnB1dFwiLCB7dmFsdWU6IHRoaXMuZ2V0VmFsdWUoKSwgb25DaGFuZ2U6IHRoaXMudXBkYXRlVmFsdWV9KVxuICAgICAgfVxuICAgIH0pO1xuICAgIHZhciBmb3JtID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudChcbiAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRm9ybXN5LkZvcm0sIHt1cmw6IFwiL3VzZXJzXCJ9LCBcbiAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChUZXN0SW5wdXQsIHtuYW1lOiBcIkFcIiwgdmFsdWU6IFwiZm9vXCJ9KSwgXG4gICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoVGVzdElucHV0LCB7bmFtZTogXCJCXCIsIHZhbHVlOiBcIlwiLCByZXF1aXJlZDogdHJ1ZX0pLCBcbiAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChUZXN0SW5wdXQsIHtuYW1lOiBcIkNcIiwgdmFsdWU6IFwiXCJ9KVxuICAgICAgKVxuICAgICk7XG5cbiAgICBleHBlY3Qoc2hvd1JlcXVpcmVkc1swXSgpKS50b0JlKGZhbHNlKTtcbiAgICBleHBlY3Qoc2hvd1JlcXVpcmVkc1sxXSgpKS50b0JlKHRydWUpO1xuICAgIGV4cGVjdChzaG93UmVxdWlyZWRzWzJdKCkpLnRvQmUoZmFsc2UpO1xuXG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgcmV0dXJuIHRydWUgb3IgZmFsc2Ugd2hlbiBjYWxsaW5nIHNob3dFcnJvcigpIGRlcGVuZGluZyBvbiB2YWx1ZSBpcyBpbnZhbGlkIG9yIGEgc2VydmVyIGVycm9yIGhhcyBhcnJpdmVkLCBvciBub3QnLCBmdW5jdGlvbiAoZG9uZSkge1xuXG4gICAgdmFyIHNob3dFcnJvciA9IG51bGw7XG4gICAgdmFyIFRlc3RJbnB1dCA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtkaXNwbGF5TmFtZTogXCJUZXN0SW5wdXRcIixcbiAgICAgIG1peGluczogW0Zvcm1zeS5NaXhpbl0sXG4gICAgICBjb21wb25lbnREaWRNb3VudDogZnVuY3Rpb24gKCkge1xuICAgICAgICBzaG93RXJyb3IgPSB0aGlzLnNob3dFcnJvcjtcbiAgICAgIH0sXG4gICAgICB1cGRhdGVWYWx1ZTogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIHRoaXMuc2V0VmFsdWUoZXZlbnQudGFyZ2V0LnZhbHVlKTtcbiAgICAgIH0sXG4gICAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJpbnB1dFwiLCB7dmFsdWU6IHRoaXMuZ2V0VmFsdWUoKSwgb25DaGFuZ2U6IHRoaXMudXBkYXRlVmFsdWV9KVxuICAgICAgfVxuICAgIH0pO1xuICAgIHZhciBmb3JtID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudChcbiAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRm9ybXN5LkZvcm0sIHt1cmw6IFwiL3VzZXJzXCJ9LCBcbiAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChUZXN0SW5wdXQsIHtuYW1lOiBcImZvb1wiLCB2YWx1ZTogXCJmb29cIiwgdmFsaWRhdGlvbnM6IFwiaXNFbWFpbFwiLCB2YWxpZGF0aW9uRXJyb3I6IFwiVGhpcyBpcyBub3QgYW4gZW1haWxcIn0pXG4gICAgICApXG4gICAgKTtcblxuICAgIGV4cGVjdChzaG93RXJyb3IoKSkudG9CZSh0cnVlKTtcblxuICAgIHZhciBpbnB1dCA9IFRlc3RVdGlscy5maW5kUmVuZGVyZWRET01Db21wb25lbnRXaXRoVGFnKGZvcm0sICdJTlBVVCcpO1xuICAgIFRlc3RVdGlscy5TaW11bGF0ZS5jaGFuZ2UoaW5wdXQsIHt0YXJnZXQ6IHt2YWx1ZTogJ2Zvb0Bmb28uY29tJ319KTtcbiAgICBleHBlY3Qoc2hvd0Vycm9yKCkpLnRvQmUoZmFsc2UpO1xuXG4gICAgamFzbWluZS5BamF4Lmluc3RhbGwoKTtcbiAgICBUZXN0VXRpbHMuU2ltdWxhdGUuc3VibWl0KGZvcm0uZ2V0RE9NTm9kZSgpKTsgICAgXG4gICAgamFzbWluZS5BamF4LnJlcXVlc3RzLm1vc3RSZWNlbnQoKS5yZXNwb25kV2l0aCh7XG4gICAgICBzdGF0dXM6IDUwMCxcbiAgICAgIHJlc3BvbnNlVHlwZTogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgcmVzcG9uc2VUZXh0OiAne1wiZm9vXCI6IFwiRW1haWwgYWxyZWFkeSBleGlzdHNcIn0nXG4gICAgfSk7XG4gICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICBleHBlY3Qoc2hvd0Vycm9yKCkpLnRvQmUodHJ1ZSk7XG4gICAgICBqYXNtaW5lLkFqYXgudW5pbnN0YWxsKCk7XG4gICAgICBkb25lKCk7XG4gICAgfSwgMCk7XG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgcmV0dXJuIHRydWUgb3IgZmFsc2Ugd2hlbiBjYWxsaW5nIGlzUHJlc3RpbmUoKSBkZXBlbmRpbmcgb24gaW5wdXQgaGFzIGJlZW4gXCJ0b3VjaGVkXCIgb3Igbm90JywgZnVuY3Rpb24gKCkge1xuICAgIFxuICAgIHZhciBpc1ByaXN0aW5lID0gbnVsbDtcbiAgICB2YXIgVGVzdElucHV0ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIlRlc3RJbnB1dFwiLFxuICAgICAgbWl4aW5zOiBbRm9ybXN5Lk1peGluXSxcbiAgICAgIGNvbXBvbmVudERpZE1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlzUHJpc3RpbmUgPSB0aGlzLmlzUHJpc3RpbmU7XG4gICAgICB9LFxuICAgICAgdXBkYXRlVmFsdWU6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICB0aGlzLnNldFZhbHVlKGV2ZW50LnRhcmdldC52YWx1ZSk7XG4gICAgICB9LFxuICAgICAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBSZWFjdC5jcmVhdGVFbGVtZW50KFwiaW5wdXRcIiwge3ZhbHVlOiB0aGlzLmdldFZhbHVlKCksIG9uQ2hhbmdlOiB0aGlzLnVwZGF0ZVZhbHVlfSlcbiAgICAgIH1cbiAgICB9KTtcbiAgICB2YXIgZm9ybSA9IFRlc3RVdGlscy5yZW5kZXJJbnRvRG9jdW1lbnQoXG4gICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KEZvcm1zeS5Gb3JtLCB7dXJsOiBcIi91c2Vyc1wifSwgXG4gICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoVGVzdElucHV0LCB7bmFtZTogXCJBXCIsIHZhbHVlOiBcImZvb1wifSlcbiAgICAgIClcbiAgICApO1xuXG4gICAgZXhwZWN0KGlzUHJpc3RpbmUoKSkudG9CZSh0cnVlKTtcbiAgICB2YXIgaW5wdXQgPSBUZXN0VXRpbHMuZmluZFJlbmRlcmVkRE9NQ29tcG9uZW50V2l0aFRhZyhmb3JtLCAnSU5QVVQnKTtcbiAgICBUZXN0VXRpbHMuU2ltdWxhdGUuY2hhbmdlKGlucHV0LCB7dGFyZ2V0OiB7dmFsdWU6ICdmb28nfX0pO1xuICAgIGV4cGVjdChpc1ByaXN0aW5lKCkpLnRvQmUoZmFsc2UpO1xuICAgIFxuICB9KTtcblxufSk7XG4iLCJ2YXIgRm9ybXN5ID0gcmVxdWlyZSgnLi8uLi9zcmMvbWFpbi5qcycpO1xuXG5kZXNjcmliZSgnRm9ybXN5JywgZnVuY3Rpb24oKSB7XG5cbiAgZGVzY3JpYmUoJ1NldHRpbmcgdXAgYSBmb3JtJywgZnVuY3Rpb24gKCkge1xuICAgIFxuICAgIGl0KCdzaG91bGQgcmVuZGVyIGEgZm9ybSBpbnRvIHRoZSBkb2N1bWVudCcsIGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIGZvcm0gPSBUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50KFxuICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KEZvcm1zeS5Gb3JtLCBudWxsKVxuICAgICAgKTtcbiAgICAgIGV4cGVjdChmb3JtLmdldERPTU5vZGUoKS50YWdOYW1lKS50b0VxdWFsKCdGT1JNJyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHNldCBhIGNsYXNzIG5hbWUgaWYgcGFzc2VkJywgZnVuY3Rpb24gKCkge1xuICAgICAgdmFyIGZvcm0gPSBUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50KFxuICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KEZvcm1zeS5Gb3JtLCB7Y2xhc3NOYW1lOiBcImZvb1wifSlcbiAgICAgICk7XG4gICAgICBleHBlY3QoZm9ybS5nZXRET01Ob2RlKCkuY2xhc3NOYW1lKS50b0VxdWFsKCdmb28nKTtcbiAgICB9KTtcblxuICB9KTtcblxufSk7XG4iLCJ2YXIgRm9ybXN5ID0gcmVxdWlyZSgnLi8uLi9zcmMvbWFpbi5qcycpO1xuXG5kZXNjcmliZSgnQWpheCcsIGZ1bmN0aW9uKCkge1xuXG4gIGJlZm9yZUVhY2goZnVuY3Rpb24gKCkge1xuICAgIGphc21pbmUuQWpheC5pbnN0YWxsKCk7XG4gIH0pO1xuXG4gIGFmdGVyRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgamFzbWluZS5BamF4LnVuaW5zdGFsbCgpO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHBvc3QgdG8gYSBnaXZlbiB1cmwgaWYgcGFzc2VkJywgZnVuY3Rpb24gKCkge1xuXG4gICAgdmFyIGZvcm0gPSBUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50KFxuICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChGb3Jtc3kuRm9ybSwge3VybDogXCIvdXNlcnNcIn1cbiAgICAgIClcbiAgICApO1xuICAgIFxuICAgIFRlc3RVdGlscy5TaW11bGF0ZS5zdWJtaXQoZm9ybS5nZXRET01Ob2RlKCkpO1xuICAgIGV4cGVjdChqYXNtaW5lLkFqYXgucmVxdWVzdHMubW9zdFJlY2VudCgpLnVybCkudG9CZSgnL3VzZXJzJyk7XG4gICAgZXhwZWN0KGphc21pbmUuQWpheC5yZXF1ZXN0cy5tb3N0UmVjZW50KCkubWV0aG9kKS50b0JlKCdQT1NUJyk7XG5cbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCBwdXQgdG8gYSBnaXZlbiB1cmwgaWYgcGFzc2VkIGEgbWV0aG9kIGF0dHJpYnV0ZScsIGZ1bmN0aW9uICgpIHtcblxuICAgIHZhciBmb3JtID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudChcbiAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRm9ybXN5LkZvcm0sIHt1cmw6IFwiL3VzZXJzXCIsIG1ldGhvZDogXCJQVVRcIn1cbiAgICAgIClcbiAgICApO1xuICAgIFxuICAgIFRlc3RVdGlscy5TaW11bGF0ZS5zdWJtaXQoZm9ybS5nZXRET01Ob2RlKCkpO1xuICAgIGV4cGVjdChqYXNtaW5lLkFqYXgucmVxdWVzdHMubW9zdFJlY2VudCgpLnVybCkudG9CZSgnL3VzZXJzJyk7XG4gICAgZXhwZWN0KGphc21pbmUuQWpheC5yZXF1ZXN0cy5tb3N0UmVjZW50KCkubWV0aG9kKS50b0JlKCdQVVQnKTtcblxuICB9KTtcblxuICBpdCgnc2hvdWxkIHBhc3MgeC13d3ctZm9ybS11cmxlbmNvZGVkIGFzIGNvbnRlbnRUeXBlIHdoZW4gdXJsZW5jb2RlZCBpcyBzZXQgYXMgY29udGVudFR5cGUnLCBmdW5jdGlvbiAoKSB7XG5cbiAgICB2YXIgZm9ybSA9IFRlc3RVdGlscy5yZW5kZXJJbnRvRG9jdW1lbnQoXG4gICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KEZvcm1zeS5Gb3JtLCB7dXJsOiBcIi91c2Vyc1wiLCBjb250ZW50VHlwZTogXCJ1cmxlbmNvZGVkXCJ9XG4gICAgICApXG4gICAgKTtcbiAgICBcbiAgICBUZXN0VXRpbHMuU2ltdWxhdGUuc3VibWl0KGZvcm0uZ2V0RE9NTm9kZSgpKTtcbiAgICBleHBlY3QoamFzbWluZS5BamF4LnJlcXVlc3RzLm1vc3RSZWNlbnQoKS5jb250ZW50VHlwZSgpKS50b0JlKCdhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQnKTtcblxuICB9KTtcblxuICBpdCgnc2hvdWxkIHJ1biBhbiBvblN1Y2Nlc3MgaGFuZGxlciwgaWYgcGFzc2VkIGFuZCBhamF4IGlzIHN1Y2Nlc3NmdWxsLiBGaXJzdCBhcmd1bWVudCBpcyBkYXRhIGZyb20gc2VydmVyJywgZnVuY3Rpb24gKGRvbmUpIHtcbiBcbiAgICB2YXIgb25TdWNjZXNzID0gamFzbWluZS5jcmVhdGVTcHkoXCJzdWNjZXNzXCIpO1xuICAgIHZhciBmb3JtID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudChcbiAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRm9ybXN5LkZvcm0sIHt1cmw6IFwiL3VzZXJzXCIsIG9uU3VjY2Vzczogb25TdWNjZXNzfVxuICAgICAgKVxuICAgICk7XG4gICAgXG4gICAgamFzbWluZS5BamF4LnN0dWJSZXF1ZXN0KCcvdXNlcnMnKS5hbmRSZXR1cm4oe1xuICAgICAgc3RhdHVzOiAyMDAsXG4gICAgICBjb250ZW50VHlwZTogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgcmVzcG9uc2VUZXh0OiAne30nXG4gICAgfSk7XG5cbiAgICBUZXN0VXRpbHMuU2ltdWxhdGUuc3VibWl0KGZvcm0uZ2V0RE9NTm9kZSgpKTtcblxuICAgIC8vIFNpbmNlIGFqYXggaXMgcmV0dXJuZWQgYXMgYSBwcm9taXNlIChhc3luYyksIG1vdmUgYXNzZXJ0aW9uXG4gICAgLy8gdG8gZW5kIG9mIGV2ZW50IGxvb3BcbiAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgIGV4cGVjdChvblN1Y2Nlc3MpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKHt9KTtcbiAgICAgIGRvbmUoKTtcbiAgICB9LCAwKTtcblxuICB9KTtcblxuICBpdCgnc2hvdWxkIG5vdCBkbyBhamF4IHJlcXVlc3QgaWYgb25TdWJtaXQgaGFuZGxlciBpcyBwYXNzZWQsIGJ1dCBwYXNzIHRoZSBtb2RlbCBhcyBmaXJzdCBhcmd1bWVudCB0byBvblN1Ym1pdCBoYW5kbGVyJywgZnVuY3Rpb24gKCkge1xuICAgIFxuICAgIHZhciBUZXN0SW5wdXQgPSBSZWFjdC5jcmVhdGVDbGFzcyh7ZGlzcGxheU5hbWU6IFwiVGVzdElucHV0XCIsXG4gICAgICBtaXhpbnM6IFtGb3Jtc3kuTWl4aW5dLFxuICAgICAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBSZWFjdC5jcmVhdGVFbGVtZW50KFwiaW5wdXRcIiwge3ZhbHVlOiB0aGlzLmdldFZhbHVlKCl9KVxuICAgICAgfVxuICAgIH0pO1xuICAgIHZhciBmb3JtID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudChcbiAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRm9ybXN5LkZvcm0sIHtvblN1Ym1pdDogb25TdWJtaXR9LCBcbiAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChUZXN0SW5wdXQsIHtuYW1lOiBcImZvb1wiLCB2YWx1ZTogXCJiYXJcIn0pXG4gICAgICApXG4gICAgKTtcblxuICAgIFRlc3RVdGlscy5TaW11bGF0ZS5zdWJtaXQoZm9ybS5nZXRET01Ob2RlKCkpO1xuXG4gICAgZXhwZWN0KGphc21pbmUuQWpheC5yZXF1ZXN0cy5jb3VudCgpKS50b0JlKDApO1xuXG4gICAgZnVuY3Rpb24gb25TdWJtaXQgKGRhdGEpIHtcbiAgICAgIGV4cGVjdChkYXRhKS50b0VxdWFsKHtcbiAgICAgICAgZm9vOiAnYmFyJ1xuICAgICAgfSk7XG4gICAgfVxuXG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgdHJpZ2dlciBhbiBvblN1Ym1pdHRlZCBoYW5kbGVyLCBpZiBwYXNzZWQgYW5kIHRoZSBzdWJtaXQgaGFzIHJlc3BvbmRlZCB3aXRoIFNVQ0NFU1MnLCBmdW5jdGlvbiAoZG9uZSkge1xuICAgIFxuICAgIHZhciBvblN1Ym1pdHRlZCA9IGphc21pbmUuY3JlYXRlU3B5KFwic3VibWl0dGVkXCIpO1xuICAgIHZhciBmb3JtID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudChcbiAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRm9ybXN5LkZvcm0sIHt1cmw6IFwiL3VzZXJzXCIsIG9uU3VibWl0dGVkOiBvblN1Ym1pdHRlZH1cbiAgICAgIClcbiAgICApO1xuICAgIFxuICAgIGphc21pbmUuQWpheC5zdHViUmVxdWVzdCgnL3VzZXJzJykuYW5kUmV0dXJuKHtcbiAgICAgIHN0YXR1czogMjAwLFxuICAgICAgY29udGVudFR5cGU6ICdhcHBsaWNhdGlvbi9qc29uJyxcbiAgICAgIHJlc3BvbnNlVGV4dDogJ3t9J1xuICAgIH0pO1xuXG4gICAgVGVzdFV0aWxzLlNpbXVsYXRlLnN1Ym1pdChmb3JtLmdldERPTU5vZGUoKSk7XG5cbiAgICAvLyBTaW5jZSBhamF4IGlzIHJldHVybmVkIGFzIGEgcHJvbWlzZSAoYXN5bmMpLCBtb3ZlIGFzc2VydGlvblxuICAgIC8vIHRvIGVuZCBvZiBldmVudCBsb29wXG4gICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICBleHBlY3Qob25TdWJtaXR0ZWQpLnRvSGF2ZUJlZW5DYWxsZWQoKTtcbiAgICAgIGRvbmUoKTtcbiAgICB9LCAwKTtcblxuICB9KTtcblxuICBpdCgnc2hvdWxkIHRyaWdnZXIgYW4gb25TdWJtaXR0ZWQgaGFuZGxlciwgaWYgcGFzc2VkIGFuZCB0aGUgc3VibWl0IGhhcyByZXNwb25kZWQgd2l0aCBFUlJPUicsIGZ1bmN0aW9uIChkb25lKSB7XG4gICAgXG4gICAgdmFyIG9uU3VibWl0dGVkID0gamFzbWluZS5jcmVhdGVTcHkoXCJzdWJtaXR0ZWRcIik7XG4gICAgdmFyIGZvcm0gPSBUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50KFxuICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChGb3Jtc3kuRm9ybSwge3VybDogXCIvdXNlcnNcIiwgb25TdWJtaXR0ZWQ6IG9uU3VibWl0dGVkfVxuICAgICAgKVxuICAgICk7XG4gICAgXG4gICAgamFzbWluZS5BamF4LnN0dWJSZXF1ZXN0KCcvdXNlcnMnKS5hbmRSZXR1cm4oe1xuICAgICAgc3RhdHVzOiA1MDAsXG4gICAgICBjb250ZW50VHlwZTogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgcmVzcG9uc2VUZXh0OiAne30nXG4gICAgfSk7XG5cbiAgICBUZXN0VXRpbHMuU2ltdWxhdGUuc3VibWl0KGZvcm0uZ2V0RE9NTm9kZSgpKTtcblxuICAgIC8vIFNpbmNlIGFqYXggaXMgcmV0dXJuZWQgYXMgYSBwcm9taXNlIChhc3luYyksIG1vdmUgYXNzZXJ0aW9uXG4gICAgLy8gdG8gZW5kIG9mIGV2ZW50IGxvb3BcbiAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgIGV4cGVjdChvblN1Ym1pdHRlZCkudG9IYXZlQmVlbkNhbGxlZCgpO1xuICAgICAgZG9uZSgpO1xuICAgIH0sIDApO1xuXG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgdHJpZ2dlciBhbiBvbkVycm9yIGhhbmRsZXIsIGlmIHBhc3NlZCBhbmQgdGhlIHN1Ym1pdCBoYXMgcmVzcG9uZGVkIHdpdGggRVJST1InLCBmdW5jdGlvbiAoZG9uZSkge1xuICAgIFxuICAgIHZhciBvbkVycm9yID0gamFzbWluZS5jcmVhdGVTcHkoXCJlcnJvclwiKTtcbiAgICB2YXIgZm9ybSA9IFRlc3RVdGlscy5yZW5kZXJJbnRvRG9jdW1lbnQoXG4gICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KEZvcm1zeS5Gb3JtLCB7dXJsOiBcIi91c2Vyc1wiLCBvbkVycm9yOiBvbkVycm9yfVxuICAgICAgKVxuICAgICk7XG4gICAgXG4gICAgLy8gRG8gbm90IHJldHVybiBhbnkgZXJyb3IgYmVjYXVzZSB0aGVyZSBhcmUgbm8gaW5wdXRzXG4gICAgamFzbWluZS5BamF4LnN0dWJSZXF1ZXN0KCcvdXNlcnMnKS5hbmRSZXR1cm4oe1xuICAgICAgc3RhdHVzOiA1MDAsXG4gICAgICBjb250ZW50VHlwZTogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgcmVzcG9uc2VUZXh0OiAne30nXG4gICAgfSk7XG5cbiAgICBUZXN0VXRpbHMuU2ltdWxhdGUuc3VibWl0KGZvcm0uZ2V0RE9NTm9kZSgpKTtcblxuICAgIC8vIFNpbmNlIGFqYXggaXMgcmV0dXJuZWQgYXMgYSBwcm9taXNlIChhc3luYyksIG1vdmUgYXNzZXJ0aW9uXG4gICAgLy8gdG8gZW5kIG9mIGV2ZW50IGxvb3BcbiAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgIGV4cGVjdChvbkVycm9yKS50b0hhdmVCZWVuQ2FsbGVkV2l0aCh7fSk7XG4gICAgICBkb25lKCk7XG4gICAgfSwgMCk7XG5cbiAgfSk7XG5cbn0pO1xuIiwidmFyIEZvcm1zeSA9IHJlcXVpcmUoJy4vLi4vc3JjL21haW4uanMnKTtcblxuZGVzY3JpYmUoJ1ZhbGlkYXRpb24nLCBmdW5jdGlvbigpIHtcblxuICBpdCgnc2hvdWxkIHRyaWdnZXIgYW4gb25WYWxpZCBoYW5kbGVyLCBpZiBwYXNzZWQsIHdoZW4gZm9ybSBpcyB2YWxpZCcsIGZ1bmN0aW9uICgpIHtcbiAgICBcbiAgICB2YXIgb25WYWxpZCA9IGphc21pbmUuY3JlYXRlU3B5KCd2YWxpZCcpO1xuICAgIHZhciBUZXN0SW5wdXQgPSBSZWFjdC5jcmVhdGVDbGFzcyh7ZGlzcGxheU5hbWU6IFwiVGVzdElucHV0XCIsXG4gICAgICBtaXhpbnM6IFtGb3Jtc3kuTWl4aW5dLFxuICAgICAgdXBkYXRlVmFsdWU6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICB0aGlzLnNldFZhbHVlKGV2ZW50LnRhcmdldC52YWx1ZSk7XG4gICAgICB9LFxuICAgICAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBSZWFjdC5jcmVhdGVFbGVtZW50KFwiaW5wdXRcIiwge3ZhbHVlOiB0aGlzLmdldFZhbHVlKCksIG9uQ2hhbmdlOiB0aGlzLnVwZGF0ZVZhbHVlfSlcbiAgICAgIH1cbiAgICB9KTtcbiAgICB2YXIgZm9ybSA9IFRlc3RVdGlscy5yZW5kZXJJbnRvRG9jdW1lbnQoXG4gICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KEZvcm1zeS5Gb3JtLCB7b25WYWxpZDogb25WYWxpZH0sIFxuICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFRlc3RJbnB1dCwge25hbWU6IFwiZm9vXCIsIHJlcXVpcmVkOiB0cnVlfSlcbiAgICAgIClcbiAgICApO1xuXG4gICAgdmFyIGlucHV0ID0gVGVzdFV0aWxzLmZpbmRSZW5kZXJlZERPTUNvbXBvbmVudFdpdGhUYWcoZm9ybSwgJ0lOUFVUJyk7XG4gICAgVGVzdFV0aWxzLlNpbXVsYXRlLmNoYW5nZShpbnB1dCwge3RhcmdldDoge3ZhbHVlOiAnZm9vJ319KTtcbiAgICBleHBlY3Qob25WYWxpZCkudG9IYXZlQmVlbkNhbGxlZCgpO1xuXG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgdHJpZ2dlciBhbiBvbkludmFsaWQgaGFuZGxlciwgaWYgcGFzc2VkLCB3aGVuIGZvcm0gaXMgaW52YWxpZCcsIGZ1bmN0aW9uICgpIHtcbiAgICBcbiAgICB2YXIgb25JbnZhbGlkID0gamFzbWluZS5jcmVhdGVTcHkoJ2ludmFsaWQnKTtcbiAgICB2YXIgVGVzdElucHV0ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIlRlc3RJbnB1dFwiLFxuICAgICAgbWl4aW5zOiBbRm9ybXN5Lk1peGluXSxcbiAgICAgIHVwZGF0ZVZhbHVlOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgdGhpcy5zZXRWYWx1ZShldmVudC50YXJnZXQudmFsdWUpO1xuICAgICAgfSxcbiAgICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gUmVhY3QuY3JlYXRlRWxlbWVudChcImlucHV0XCIsIHt2YWx1ZTogdGhpcy5nZXRWYWx1ZSgpLCBvbkNoYW5nZTogdGhpcy51cGRhdGVWYWx1ZX0pXG4gICAgICB9XG4gICAgfSk7XG4gICAgdmFyIGZvcm0gPSBUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50KFxuICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChGb3Jtc3kuRm9ybSwge29uVmFsaWQ6IG9uSW52YWxpZH0sIFxuICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFRlc3RJbnB1dCwge25hbWU6IFwiZm9vXCIsIHZhbHVlOiBcImZvb1wifSlcbiAgICAgIClcbiAgICApO1xuXG4gICAgdmFyIGlucHV0ID0gVGVzdFV0aWxzLmZpbmRSZW5kZXJlZERPTUNvbXBvbmVudFdpdGhUYWcoZm9ybSwgJ0lOUFVUJyk7XG4gICAgVGVzdFV0aWxzLlNpbXVsYXRlLmNoYW5nZShpbnB1dCwge3RhcmdldDoge3ZhbHVlOiAnJ319KTtcbiAgICBleHBlY3Qob25JbnZhbGlkKS50b0hhdmVCZWVuQ2FsbGVkKCk7XG5cbiAgfSk7XG5cbiAgaXQoJ1JVTEU6IGlzRW1haWwnLCBmdW5jdGlvbiAoKSB7XG4gICAgXG4gICAgdmFyIGlzVmFsaWQgPSBqYXNtaW5lLmNyZWF0ZVNweSgndmFsaWQnKTtcbiAgICB2YXIgVGVzdElucHV0ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIlRlc3RJbnB1dFwiLFxuICAgICAgbWl4aW5zOiBbRm9ybXN5Lk1peGluXSxcbiAgICAgIHVwZGF0ZVZhbHVlOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgdGhpcy5zZXRWYWx1ZShldmVudC50YXJnZXQudmFsdWUpO1xuICAgICAgfSxcbiAgICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAodGhpcy5pc1ZhbGlkKCkpIHtcbiAgICAgICAgICBpc1ZhbGlkKCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJpbnB1dFwiLCB7dmFsdWU6IHRoaXMuZ2V0VmFsdWUoKSwgb25DaGFuZ2U6IHRoaXMudXBkYXRlVmFsdWV9KVxuICAgICAgfVxuICAgIH0pO1xuICAgIHZhciBmb3JtID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudChcbiAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRm9ybXN5LkZvcm0sIG51bGwsIFxuICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFRlc3RJbnB1dCwge25hbWU6IFwiZm9vXCIsIHZhbHVlOiBcImZvb1wiLCB2YWxpZGF0aW9uczogXCJpc0VtYWlsXCJ9KVxuICAgICAgKVxuICAgICk7XG5cbiAgICB2YXIgaW5wdXQgPSBUZXN0VXRpbHMuZmluZFJlbmRlcmVkRE9NQ29tcG9uZW50V2l0aFRhZyhmb3JtLCAnSU5QVVQnKTtcbiAgICBleHBlY3QoaXNWYWxpZCkubm90LnRvSGF2ZUJlZW5DYWxsZWQoKTtcbiAgICBUZXN0VXRpbHMuU2ltdWxhdGUuY2hhbmdlKGlucHV0LCB7dGFyZ2V0OiB7dmFsdWU6ICdmb29AZm9vLmNvbSd9fSk7XG4gICAgZXhwZWN0KGlzVmFsaWQpLnRvSGF2ZUJlZW5DYWxsZWQoKTtcblxuICB9KTtcblxufSk7XG4iLCJ2YXIgUmVhY3QgPSBnbG9iYWwuUmVhY3QgfHwgcmVxdWlyZSgncmVhY3QnKTtcbnZhciBGb3Jtc3kgPSB7fTtcbnZhciB2YWxpZGF0aW9uUnVsZXMgPSB7XG4gICdpc1ZhbHVlJzogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgcmV0dXJuIHZhbHVlICE9PSAnJztcbiAgfSxcbiAgJ2lzRW1haWwnOiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICByZXR1cm4gdmFsdWUubWF0Y2goL14oKChbYS16XXxcXGR8WyEjXFwkJSYnXFwqXFwrXFwtXFwvPVxcP1xcXl9ge1xcfH1+XXxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSkrKFxcLihbYS16XXxcXGR8WyEjXFwkJSYnXFwqXFwrXFwtXFwvPVxcP1xcXl9ge1xcfH1+XXxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSkrKSopfCgoXFx4MjIpKCgoKFxceDIwfFxceDA5KSooXFx4MGRcXHgwYSkpPyhcXHgyMHxcXHgwOSkrKT8oKFtcXHgwMS1cXHgwOFxceDBiXFx4MGNcXHgwZS1cXHgxZlxceDdmXXxcXHgyMXxbXFx4MjMtXFx4NWJdfFtcXHg1ZC1cXHg3ZV18W1xcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0pfChcXFxcKFtcXHgwMS1cXHgwOVxceDBiXFx4MGNcXHgwZC1cXHg3Zl18W1xcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0pKSkpKigoKFxceDIwfFxceDA5KSooXFx4MGRcXHgwYSkpPyhcXHgyMHxcXHgwOSkrKT8oXFx4MjIpKSlAKCgoW2Etel18XFxkfFtcXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZdKXwoKFthLXpdfFxcZHxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSkoW2Etel18XFxkfC18XFwufF98fnxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSkqKFthLXpdfFxcZHxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSkpKVxcLikrKChbYS16XXxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSl8KChbYS16XXxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSkoW2Etel18XFxkfC18XFwufF98fnxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSkqKFthLXpdfFtcXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZdKSkpJC9pKTtcbiAgfSxcbiAgJ2lzVHJ1ZSc6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgIHJldHVybiB2YWx1ZSA9PT0gdHJ1ZTtcbiAgfSxcbiAgJ2lzTnVtZXJpYyc6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgIHJldHVybiB2YWx1ZS5tYXRjaCgvXi0/WzAtOV0rJC8pXG4gIH0sXG4gICdpc0FscGhhJzogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgcmV0dXJuIHZhbHVlLm1hdGNoKC9eW2EtekEtWl0rJC8pO1xuICB9LFxuICAnaXNXb3Jkcyc6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgIHJldHVybiB2YWx1ZS5tYXRjaCgvXlthLXpBLVpcXHNdKyQvKTtcbiAgfSxcbiAgJ2lzU3BlY2lhbFdvcmRzJzogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgcmV0dXJuIHZhbHVlLm1hdGNoKC9eW2EtekEtWlxcc1xcdTAwQzAtXFx1MDE3Rl0rJC8pO1xuICB9LFxuICBpc0xlbmd0aDogZnVuY3Rpb24gKHZhbHVlLCBtaW4sIG1heCkge1xuICAgIGlmIChtYXggIT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIHZhbHVlLmxlbmd0aCA+PSBtaW4gJiYgdmFsdWUubGVuZ3RoIDw9IG1heDtcbiAgICB9XG4gICAgcmV0dXJuIHZhbHVlLmxlbmd0aCA+PSBtaW47XG4gIH0sXG4gIGVxdWFsczogZnVuY3Rpb24gKHZhbHVlLCBlcWwpIHtcbiAgICByZXR1cm4gdmFsdWUgPT0gZXFsO1xuICB9XG59O1xuXG52YXIgdG9VUkxFbmNvZGVkID0gZnVuY3Rpb24gKGVsZW1lbnQsIGtleSwgbGlzdCkge1xuICB2YXIgbGlzdCA9IGxpc3QgfHwgW107XG4gIGlmICh0eXBlb2YgKGVsZW1lbnQpID09ICdvYmplY3QnKSB7XG4gICAgZm9yICh2YXIgaWR4IGluIGVsZW1lbnQpXG4gICAgICB0b1VSTEVuY29kZWQoZWxlbWVudFtpZHhdLCBrZXkgPyBrZXkgKyAnWycgKyBpZHggKyAnXScgOiBpZHgsIGxpc3QpO1xuICB9IGVsc2Uge1xuICAgIGxpc3QucHVzaChrZXkgKyAnPScgKyBlbmNvZGVVUklDb21wb25lbnQoZWxlbWVudCkpO1xuICB9XG4gIHJldHVybiBsaXN0LmpvaW4oJyYnKTtcbn07XG5cbnZhciByZXF1ZXN0ID0gZnVuY3Rpb24gKG1ldGhvZCwgdXJsLCBkYXRhLCBjb250ZW50VHlwZSwgaGVhZGVycykge1xuXG4gIHZhciBjb250ZW50VHlwZSA9IGNvbnRlbnRUeXBlID09PSAndXJsZW5jb2RlZCcgPyAnYXBwbGljYXRpb24vJyArIGNvbnRlbnRUeXBlLnJlcGxhY2UoJ3VybGVuY29kZWQnLCAneC13d3ctZm9ybS11cmxlbmNvZGVkJykgOiAnYXBwbGljYXRpb24vanNvbic7XG4gIGRhdGEgPSBjb250ZW50VHlwZSA9PT0gJ2FwcGxpY2F0aW9uL2pzb24nID8gSlNPTi5zdHJpbmdpZnkoZGF0YSkgOiB0b1VSTEVuY29kZWQoZGF0YSk7XG5cbiAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcbiAgICB0cnkge1xuICAgICAgdmFyIHhociA9IG5ldyBYTUxIdHRwUmVxdWVzdCgpO1xuICAgICAgeGhyLm9wZW4obWV0aG9kLCB1cmwsIHRydWUpO1xuICAgICAgeGhyLnNldFJlcXVlc3RIZWFkZXIoJ0FjY2VwdCcsICdhcHBsaWNhdGlvbi9qc29uJyk7XG4gICAgICB4aHIuc2V0UmVxdWVzdEhlYWRlcignQ29udGVudC1UeXBlJywgY29udGVudFR5cGUpO1xuXG4gICAgICAvLyBBZGQgcGFzc2VkIGhlYWRlcnNcbiAgICAgIE9iamVjdC5rZXlzKGhlYWRlcnMpLmZvckVhY2goZnVuY3Rpb24gKGhlYWRlcikge1xuICAgICAgICB4aHIuc2V0UmVxdWVzdEhlYWRlcihoZWFkZXIsIGhlYWRlcnNbaGVhZGVyXSk7XG4gICAgICB9KTtcblxuICAgICAgeGhyLm9ucmVhZHlzdGF0ZWNoYW5nZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKHhoci5yZWFkeVN0YXRlID09PSA0KSB7XG5cbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgdmFyIHJlc3BvbnNlID0geGhyLnJlc3BvbnNlVGV4dCA/IEpTT04ucGFyc2UoeGhyLnJlc3BvbnNlVGV4dCkgOiBudWxsO1xuICAgICAgICAgICAgaWYgKHhoci5zdGF0dXMgPj0gMjAwICYmIHhoci5zdGF0dXMgPCAzMDApIHtcbiAgICAgICAgICAgICAgcmVzb2x2ZShyZXNwb25zZSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICByZWplY3QocmVzcG9uc2UpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIHJlamVjdChlKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgfVxuICAgICAgfTtcbiAgICAgIHhoci5zZW5kKGRhdGEpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJlamVjdChlKTtcbiAgICB9XG4gIH0pO1xuXG59O1xudmFyIGFqYXggPSB7XG4gIHBvc3Q6IHJlcXVlc3QuYmluZChudWxsLCAnUE9TVCcpLFxuICBwdXQ6IHJlcXVlc3QuYmluZChudWxsLCAnUFVUJylcbn07XG52YXIgb3B0aW9ucyA9IHt9O1xuXG5Gb3Jtc3kuZGVmYXVsdHMgPSBmdW5jdGlvbiAocGFzc2VkT3B0aW9ucykge1xuICBvcHRpb25zID0gcGFzc2VkT3B0aW9ucztcbn07XG5cbkZvcm1zeS5NaXhpbiA9IHtcbiAgZ2V0SW5pdGlhbFN0YXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIF92YWx1ZTogdGhpcy5wcm9wcy52YWx1ZSA/IHRoaXMucHJvcHMudmFsdWUgOiAnJyxcbiAgICAgIF9pc1ZhbGlkOiB0cnVlLFxuICAgICAgX2lzUHJpc3RpbmU6IHRydWVcbiAgICB9O1xuICB9LFxuICBjb21wb25lbnRXaWxsTW91bnQ6IGZ1bmN0aW9uICgpIHtcblxuICAgIGlmICghdGhpcy5wcm9wcy5uYW1lKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Zvcm0gSW5wdXQgcmVxdWlyZXMgYSBuYW1lIHByb3BlcnR5IHdoZW4gdXNlZCcpO1xuICAgIH1cblxuICAgIGlmICghdGhpcy5wcm9wcy5fYXR0YWNoVG9Gb3JtKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Zvcm0gTWl4aW4gcmVxdWlyZXMgY29tcG9uZW50IHRvIGJlIG5lc3RlZCBpbiBhIEZvcm0nKTtcbiAgICB9XG5cbiAgICAvLyBBZGQgdmFsaWRhdGlvbnMgdG8gdGhlIHN0b3JlIGl0c2VsZiBhcyB0aGUgcHJvcHMgb2JqZWN0IGNhbiBub3QgYmUgbW9kaWZpZWRcbiAgICB0aGlzLl92YWxpZGF0aW9ucyA9IHRoaXMucHJvcHMudmFsaWRhdGlvbnMgfHwgJyc7XG5cbiAgICBpZiAodGhpcy5wcm9wcy5yZXF1aXJlZCkge1xuICAgICAgdGhpcy5fdmFsaWRhdGlvbnMgPSB0aGlzLnByb3BzLnZhbGlkYXRpb25zID8gdGhpcy5wcm9wcy52YWxpZGF0aW9ucyArICcsJyA6ICcnO1xuICAgICAgdGhpcy5fdmFsaWRhdGlvbnMgKz0gJ2lzVmFsdWUnO1xuICAgIH1cbiAgICB0aGlzLnByb3BzLl9hdHRhY2hUb0Zvcm0odGhpcyk7XG4gIH0sXG5cbiAgLy8gV2UgaGF2ZSB0byBtYWtlIHRoZSB2YWxpZGF0ZSBtZXRob2QgaXMga2VwdCB3aGVuIG5ldyBwcm9wcyBhcmUgYWRkZWRcbiAgY29tcG9uZW50V2lsbFJlY2VpdmVQcm9wczogZnVuY3Rpb24gKG5leHRQcm9wcykge1xuICAgIG5leHRQcm9wcy5fYXR0YWNoVG9Gb3JtID0gdGhpcy5wcm9wcy5fYXR0YWNoVG9Gb3JtO1xuICAgIG5leHRQcm9wcy5fZGV0YWNoRnJvbUZvcm0gPSB0aGlzLnByb3BzLl9kZXRhY2hGcm9tRm9ybTtcbiAgICBuZXh0UHJvcHMuX3ZhbGlkYXRlID0gdGhpcy5wcm9wcy5fdmFsaWRhdGU7XG4gIH0sXG5cbiAgLy8gRGV0YWNoIGl0IHdoZW4gY29tcG9uZW50IHVubW91bnRzXG4gIGNvbXBvbmVudFdpbGxVbm1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5wcm9wcy5fZGV0YWNoRnJvbUZvcm0odGhpcyk7XG4gIH0sXG5cbiAgLy8gV2UgdmFsaWRhdGUgYWZ0ZXIgdGhlIHZhbHVlIGhhcyBiZWVuIHNldFxuICBzZXRWYWx1ZTogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICBfdmFsdWU6IHZhbHVlLFxuICAgICAgX2lzUHJpc3RpbmU6IGZhbHNlXG4gICAgfSwgZnVuY3Rpb24gKCkge1xuICAgICAgdGhpcy5wcm9wcy5fdmFsaWRhdGUodGhpcyk7XG4gICAgfS5iaW5kKHRoaXMpKTtcbiAgfSxcbiAgcmVzZXRWYWx1ZTogZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgX3ZhbHVlOiAnJyxcbiAgICAgIF9pc1ByaXN0aW5lOiB0cnVlXG4gICAgfSwgZnVuY3Rpb24gKCkge1xuICAgICAgdGhpcy5wcm9wcy5fdmFsaWRhdGUodGhpcyk7XG4gICAgfSk7XG4gIH0sXG4gIGdldFZhbHVlOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuc3RhdGUuX3ZhbHVlO1xuICB9LFxuICBoYXNWYWx1ZTogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLnN0YXRlLl92YWx1ZSAhPT0gJyc7XG4gIH0sXG4gIGdldEVycm9yTWVzc2FnZTogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLmlzVmFsaWQoKSB8fCB0aGlzLnNob3dSZXF1aXJlZCgpID8gbnVsbCA6IHRoaXMuc3RhdGUuX3NlcnZlckVycm9yIHx8IHRoaXMucHJvcHMudmFsaWRhdGlvbkVycm9yO1xuICB9LFxuICBpc1ZhbGlkOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuc3RhdGUuX2lzVmFsaWQ7XG4gIH0sXG4gIGlzUHJpc3RpbmU6IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5zdGF0ZS5faXNQcmlzdGluZTtcbiAgfSxcbiAgaXNSZXF1aXJlZDogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiAhIXRoaXMucHJvcHMucmVxdWlyZWQ7XG4gIH0sXG4gIHNob3dSZXF1aXJlZDogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLmlzUmVxdWlyZWQoKSAmJiB0aGlzLnN0YXRlLl92YWx1ZSA9PT0gJyc7XG4gIH0sXG4gIHNob3dFcnJvcjogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiAhdGhpcy5zaG93UmVxdWlyZWQoKSAmJiAhdGhpcy5zdGF0ZS5faXNWYWxpZDtcbiAgfVxufTtcblxuRm9ybXN5LmFkZFZhbGlkYXRpb25SdWxlID0gZnVuY3Rpb24gKG5hbWUsIGZ1bmMpIHtcbiAgdmFsaWRhdGlvblJ1bGVzW25hbWVdID0gZnVuYztcbn07XG5cbkZvcm1zeS5Gb3JtID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIkZvcm1cIixcbiAgZ2V0SW5pdGlhbFN0YXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGlzVmFsaWQ6IHRydWUsXG4gICAgICBpc1N1Ym1pdHRpbmc6IGZhbHNlXG4gICAgfTtcbiAgfSxcbiAgZ2V0RGVmYXVsdFByb3BzOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGhlYWRlcnM6IHt9LFxuICAgICAgb25TdWNjZXNzOiBmdW5jdGlvbiAoKSB7fSxcbiAgICAgIG9uRXJyb3I6IGZ1bmN0aW9uICgpIHt9LFxuICAgICAgb25TdWJtaXQ6IGZ1bmN0aW9uICgpIHt9LFxuICAgICAgb25TdWJtaXR0ZWQ6IGZ1bmN0aW9uICgpIHt9LFxuICAgICAgb25WYWxpZDogZnVuY3Rpb24gKCkge30sXG4gICAgICBvbkludmFsaWQ6IGZ1bmN0aW9uICgpIHt9XG4gICAgfTtcbiAgfSxcblxuICAvLyBBZGQgYSBtYXAgdG8gc3RvcmUgdGhlIGlucHV0cyBvZiB0aGUgZm9ybSwgYSBtb2RlbCB0byBzdG9yZVxuICAvLyB0aGUgdmFsdWVzIG9mIHRoZSBmb3JtIGFuZCByZWdpc3RlciBjaGlsZCBpbnB1dHNcbiAgY29tcG9uZW50V2lsbE1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5pbnB1dHMgPSB7fTtcbiAgICB0aGlzLm1vZGVsID0ge307XG4gICAgdGhpcy5yZWdpc3RlcklucHV0cyh0aGlzLnByb3BzLmNoaWxkcmVuKTtcbiAgfSxcblxuICBjb21wb25lbnREaWRNb3VudDogZnVuY3Rpb24gKCkge1xuICAgIHRoaXMudmFsaWRhdGVGb3JtKCk7XG4gIH0sXG5cbiAgLy8gVXBkYXRlIG1vZGVsLCBzdWJtaXQgdG8gdXJsIHByb3AgYW5kIHNlbmQgdGhlIG1vZGVsXG4gIHN1Ym1pdDogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcblxuICAgIC8vIFRyaWdnZXIgZm9ybSBhcyBub3QgcHJpc3RpbmUuXG4gICAgLy8gSWYgYW55IGlucHV0cyBoYXZlIG5vdCBiZWVuIHRvdWNoZWQgeWV0IHRoaXMgd2lsbCBtYWtlIHRoZW0gZGlydHlcbiAgICAvLyBzbyB2YWxpZGF0aW9uIGJlY29tZXMgdmlzaWJsZSAoaWYgYmFzZWQgb24gaXNQcmlzdGluZSlcbiAgICB0aGlzLnNldEZvcm1QcmlzdGluZShmYWxzZSk7XG5cbiAgICAvLyBUbyBzdXBwb3J0IHVzZSBjYXNlcyB3aGVyZSBubyBhc3luYyBvciByZXF1ZXN0IG9wZXJhdGlvbiBpcyBuZWVkZWQuXG4gICAgLy8gVGhlIFwib25TdWJtaXRcIiBjYWxsYmFjayBpcyBjYWxsZWQgd2l0aCB0aGUgbW9kZWwgZS5nLiB7ZmllbGROYW1lOiBcIm15VmFsdWVcIn0sXG4gICAgLy8gaWYgd2FudGluZyB0byByZXNldCB0aGUgZW50aXJlIGZvcm0gdG8gb3JpZ2luYWwgc3RhdGUsIHRoZSBzZWNvbmQgcGFyYW0gaXMgYSBjYWxsYmFjayBmb3IgdGhpcy5cbiAgICBpZiAoIXRoaXMucHJvcHMudXJsKSB7XG4gICAgICB0aGlzLnVwZGF0ZU1vZGVsKCk7XG4gICAgICB0aGlzLnByb3BzLm9uU3VibWl0KHRoaXMubWFwTW9kZWwoKSwgdGhpcy5yZXNldE1vZGVsLCB0aGlzLnVwZGF0ZUlucHV0c1dpdGhFcnJvcik7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy51cGRhdGVNb2RlbCgpO1xuICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgaXNTdWJtaXR0aW5nOiB0cnVlXG4gICAgfSk7XG5cbiAgICB0aGlzLnByb3BzLm9uU3VibWl0KHRoaXMubWFwTW9kZWwoKSwgdGhpcy5yZXNldE1vZGVsLCB0aGlzLnVwZGF0ZUlucHV0c1dpdGhFcnJvcik7XG5cbiAgICB2YXIgaGVhZGVycyA9IChPYmplY3Qua2V5cyh0aGlzLnByb3BzLmhlYWRlcnMpLmxlbmd0aCAmJiB0aGlzLnByb3BzLmhlYWRlcnMpIHx8IG9wdGlvbnMuaGVhZGVycyB8fCB7fTtcblxuICAgIHZhciBtZXRob2QgPSB0aGlzLnByb3BzLm1ldGhvZCAmJiBhamF4W3RoaXMucHJvcHMubWV0aG9kLnRvTG93ZXJDYXNlKCldID8gdGhpcy5wcm9wcy5tZXRob2QudG9Mb3dlckNhc2UoKSA6ICdwb3N0JztcbiAgICBhamF4W21ldGhvZF0odGhpcy5wcm9wcy51cmwsIHRoaXMubWFwTW9kZWwoKSwgdGhpcy5wcm9wcy5jb250ZW50VHlwZSB8fCBvcHRpb25zLmNvbnRlbnRUeXBlIHx8ICdqc29uJywgaGVhZGVycylcbiAgICAgIC50aGVuKGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICB0aGlzLnByb3BzLm9uU3VjY2VzcyhyZXNwb25zZSk7XG4gICAgICAgIHRoaXMucHJvcHMub25TdWJtaXR0ZWQoKTtcbiAgICAgIH0uYmluZCh0aGlzKSlcbiAgICAgIC5jYXRjaCh0aGlzLmZhaWxTdWJtaXQpO1xuICB9LFxuXG4gIG1hcE1vZGVsOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMucHJvcHMubWFwcGluZyA/IHRoaXMucHJvcHMubWFwcGluZyh0aGlzLm1vZGVsKSA6IHRoaXMubW9kZWw7XG4gIH0sXG5cbiAgLy8gR29lcyB0aHJvdWdoIGFsbCByZWdpc3RlcmVkIGNvbXBvbmVudHMgYW5kXG4gIC8vIHVwZGF0ZXMgdGhlIG1vZGVsIHZhbHVlc1xuICB1cGRhdGVNb2RlbDogZnVuY3Rpb24gKCkge1xuICAgIE9iamVjdC5rZXlzKHRoaXMuaW5wdXRzKS5mb3JFYWNoKGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgICB2YXIgY29tcG9uZW50ID0gdGhpcy5pbnB1dHNbbmFtZV07XG4gICAgICB0aGlzLm1vZGVsW25hbWVdID0gY29tcG9uZW50LnN0YXRlLl92YWx1ZTtcbiAgICB9LmJpbmQodGhpcykpO1xuICB9LFxuXG4gIC8vIFJlc2V0IGVhY2gga2V5IGluIHRoZSBtb2RlbCB0byB0aGUgb3JpZ2luYWwgLyBpbml0aWFsIHZhbHVlXG4gIHJlc2V0TW9kZWw6IGZ1bmN0aW9uICgpIHtcbiAgICBPYmplY3Qua2V5cyh0aGlzLmlucHV0cykuZm9yRWFjaChmdW5jdGlvbiAobmFtZSkge1xuICAgICAgdGhpcy5pbnB1dHNbbmFtZV0ucmVzZXRWYWx1ZSgpO1xuICAgIH0uYmluZCh0aGlzKSk7XG4gICAgdGhpcy52YWxpZGF0ZUZvcm0oKTtcbiAgfSxcblxuICAvLyBHbyB0aHJvdWdoIGVycm9ycyBmcm9tIHNlcnZlciBhbmQgZ3JhYiB0aGUgY29tcG9uZW50c1xuICAvLyBzdG9yZWQgaW4gdGhlIGlucHV0cyBtYXAuIENoYW5nZSB0aGVpciBzdGF0ZSB0byBpbnZhbGlkXG4gIC8vIGFuZCBzZXQgdGhlIHNlcnZlckVycm9yIG1lc3NhZ2VcbiAgdXBkYXRlSW5wdXRzV2l0aEVycm9yOiBmdW5jdGlvbiAoZXJyb3JzKSB7XG4gICAgT2JqZWN0LmtleXMoZXJyb3JzKS5mb3JFYWNoKGZ1bmN0aW9uIChuYW1lLCBpbmRleCkge1xuICAgICAgdmFyIGNvbXBvbmVudCA9IHRoaXMuaW5wdXRzW25hbWVdO1xuXG4gICAgICBpZiAoIWNvbXBvbmVudCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1lvdSBhcmUgdHJ5aW5nIHRvIHVwZGF0ZSBhbiBpbnB1dCB0aGF0IGRvZXMgbm90IGV4aXN0cy4gVmVyaWZ5IGVycm9ycyBvYmplY3Qgd2l0aCBpbnB1dCBuYW1lcy4gJyArIEpTT04uc3RyaW5naWZ5KGVycm9ycykpO1xuICAgICAgfVxuXG4gICAgICB2YXIgYXJncyA9IFt7XG4gICAgICAgIF9pc1ZhbGlkOiBmYWxzZSxcbiAgICAgICAgX3NlcnZlckVycm9yOiBlcnJvcnNbbmFtZV1cbiAgICAgIH1dO1xuICAgICAgY29tcG9uZW50LnNldFN0YXRlLmFwcGx5KGNvbXBvbmVudCwgYXJncyk7XG4gICAgfS5iaW5kKHRoaXMpKTtcbiAgfSxcblxuICBmYWlsU3VibWl0OiBmdW5jdGlvbiAoZXJyb3JzKSB7XG4gICAgdGhpcy51cGRhdGVJbnB1dHNXaXRoRXJyb3IoZXJyb3JzKTtcbiAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgIGlzU3VibWl0dGluZzogZmFsc2VcbiAgICB9KTtcbiAgICB0aGlzLnByb3BzLm9uRXJyb3IoZXJyb3JzKTtcbiAgICB0aGlzLnByb3BzLm9uU3VibWl0dGVkKCk7XG4gIH0sXG5cbiAgLy8gVHJhdmVyc2UgdGhlIGNoaWxkcmVuIGFuZCBjaGlsZHJlbiBvZiBjaGlsZHJlbiB0byBmaW5kXG4gIC8vIGFsbCBpbnB1dHMgYnkgY2hlY2tpbmcgdGhlIG5hbWUgcHJvcC4gTWF5YmUgZG8gYSBiZXR0ZXJcbiAgLy8gY2hlY2sgaGVyZVxuICByZWdpc3RlcklucHV0czogZnVuY3Rpb24gKGNoaWxkcmVuKSB7XG4gICAgUmVhY3QuQ2hpbGRyZW4uZm9yRWFjaChjaGlsZHJlbiwgZnVuY3Rpb24gKGNoaWxkKSB7XG5cbiAgICAgIGlmIChjaGlsZC5wcm9wcyAmJiBjaGlsZC5wcm9wcy5uYW1lKSB7XG4gICAgICAgIGNoaWxkLnByb3BzLl9hdHRhY2hUb0Zvcm0gPSB0aGlzLmF0dGFjaFRvRm9ybTtcbiAgICAgICAgY2hpbGQucHJvcHMuX2RldGFjaEZyb21Gb3JtID0gdGhpcy5kZXRhY2hGcm9tRm9ybTtcbiAgICAgICAgY2hpbGQucHJvcHMuX3ZhbGlkYXRlID0gdGhpcy52YWxpZGF0ZTtcbiAgICAgIH1cblxuICAgICAgaWYgKGNoaWxkLnByb3BzICYmIGNoaWxkLnByb3BzLmNoaWxkcmVuKSB7XG4gICAgICAgIHRoaXMucmVnaXN0ZXJJbnB1dHMoY2hpbGQucHJvcHMuY2hpbGRyZW4pO1xuICAgICAgfVxuXG4gICAgfS5iaW5kKHRoaXMpKTtcbiAgfSxcblxuICBnZXRDdXJyZW50VmFsdWVzOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIE9iamVjdC5rZXlzKHRoaXMuaW5wdXRzKS5yZWR1Y2UoZnVuY3Rpb24gKGRhdGEsIG5hbWUpIHtcbiAgICAgIHZhciBjb21wb25lbnQgPSB0aGlzLmlucHV0c1tuYW1lXTtcbiAgICAgIGRhdGFbbmFtZV0gPSBjb21wb25lbnQuc3RhdGUuX3ZhbHVlO1xuICAgICAgcmV0dXJuIGRhdGE7XG4gICAgfS5iaW5kKHRoaXMpLCB7fSk7XG4gIH0sXG5cbiAgc2V0Rm9ybVByaXN0aW5lOiBmdW5jdGlvbihpc1ByaXN0aW5lKSB7XG4gICAgdmFyIGlucHV0cyA9IHRoaXMuaW5wdXRzO1xuICAgIHZhciBpbnB1dEtleXMgPSBPYmplY3Qua2V5cyhpbnB1dHMpO1xuXG4gICAgLy8gSXRlcmF0ZSB0aHJvdWdoIGVhY2ggY29tcG9uZW50IGFuZCBzZXQgaXQgYXMgcHJpc3RpbmVcbiAgICAvLyBvciBcImRpcnR5XCIuXG4gICAgaW5wdXRLZXlzLmZvckVhY2goZnVuY3Rpb24gKG5hbWUsIGluZGV4KSB7XG4gICAgICB2YXIgY29tcG9uZW50ID0gaW5wdXRzW25hbWVdO1xuICAgICAgY29tcG9uZW50LnNldFN0YXRlKHtcbiAgICAgICAgX2lzUHJpc3RpbmU6IGlzUHJpc3RpbmVcbiAgICAgIH0pO1xuICAgIH0uYmluZCh0aGlzKSk7XG4gIH0sXG5cbiAgLy8gVXNlIHRoZSBiaW5kZWQgdmFsdWVzIGFuZCB0aGUgYWN0dWFsIGlucHV0IHZhbHVlIHRvXG4gIC8vIHZhbGlkYXRlIHRoZSBpbnB1dCBhbmQgc2V0IGl0cyBzdGF0ZS4gVGhlbiBjaGVjayB0aGVcbiAgLy8gc3RhdGUgb2YgdGhlIGZvcm0gaXRzZWxmXG4gIHZhbGlkYXRlOiBmdW5jdGlvbiAoY29tcG9uZW50KSB7XG5cbiAgICBpZiAoIWNvbXBvbmVudC5wcm9wcy5yZXF1aXJlZCAmJiAhY29tcG9uZW50Ll92YWxpZGF0aW9ucykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIFJ1biB0aHJvdWdoIHRoZSB2YWxpZGF0aW9ucywgc3BsaXQgdGhlbSB1cCBhbmQgY2FsbFxuICAgIC8vIHRoZSB2YWxpZGF0b3IgSUYgdGhlcmUgaXMgYSB2YWx1ZSBvciBpdCBpcyByZXF1aXJlZFxuICAgIHZhciBpc1ZhbGlkID0gdGhpcy5ydW5WYWxpZGF0aW9uKGNvbXBvbmVudCk7XG5cbiAgICBjb21wb25lbnQuc2V0U3RhdGUoe1xuICAgICAgX2lzVmFsaWQ6IGlzVmFsaWQsXG4gICAgICBfc2VydmVyRXJyb3I6IG51bGxcbiAgICB9LCB0aGlzLnZhbGlkYXRlRm9ybSk7XG5cbiAgfSxcblxuICBydW5WYWxpZGF0aW9uOiBmdW5jdGlvbiAoY29tcG9uZW50KSB7XG4gICAgdmFyIGlzVmFsaWQgPSB0cnVlO1xuICAgIGlmIChjb21wb25lbnQuX3ZhbGlkYXRpb25zLmxlbmd0aCAmJiAoY29tcG9uZW50LnByb3BzLnJlcXVpcmVkIHx8IGNvbXBvbmVudC5zdGF0ZS5fdmFsdWUgIT09ICcnKSkge1xuICAgICAgY29tcG9uZW50Ll92YWxpZGF0aW9ucy5zcGxpdCgnLCcpLmZvckVhY2goZnVuY3Rpb24gKHZhbGlkYXRpb24pIHtcbiAgICAgICAgdmFyIGFyZ3MgPSB2YWxpZGF0aW9uLnNwbGl0KCc6Jyk7XG4gICAgICAgIHZhciB2YWxpZGF0ZU1ldGhvZCA9IGFyZ3Muc2hpZnQoKTtcbiAgICAgICAgYXJncyA9IGFyZ3MubWFwKGZ1bmN0aW9uIChhcmcpIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoYXJnKTtcbiAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICByZXR1cm4gYXJnOyAvLyBJdCBpcyBhIHN0cmluZyBpZiBpdCBjYW4gbm90IHBhcnNlIGl0XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgYXJncyA9IFtjb21wb25lbnQuc3RhdGUuX3ZhbHVlXS5jb25jYXQoYXJncyk7XG4gICAgICAgIGlmICghdmFsaWRhdGlvblJ1bGVzW3ZhbGlkYXRlTWV0aG9kXSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignRm9ybXN5IGRvZXMgbm90IGhhdmUgdGhlIHZhbGlkYXRpb24gcnVsZTogJyArIHZhbGlkYXRlTWV0aG9kKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXZhbGlkYXRpb25SdWxlc1t2YWxpZGF0ZU1ldGhvZF0uYXBwbHkodGhpcy5nZXRDdXJyZW50VmFsdWVzKCksIGFyZ3MpKSB7XG4gICAgICAgICAgaXNWYWxpZCA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgICB9LmJpbmQodGhpcykpO1xuICAgIH1cbiAgICByZXR1cm4gaXNWYWxpZDtcbiAgfSxcblxuICAvLyBWYWxpZGF0ZSB0aGUgZm9ybSBieSBnb2luZyB0aHJvdWdoIGFsbCBjaGlsZCBpbnB1dCBjb21wb25lbnRzXG4gIC8vIGFuZCBjaGVjayB0aGVpciBzdGF0ZVxuICB2YWxpZGF0ZUZvcm06IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgYWxsSXNWYWxpZCA9IHRydWU7XG4gICAgdmFyIGlucHV0cyA9IHRoaXMuaW5wdXRzO1xuICAgIHZhciBpbnB1dEtleXMgPSBPYmplY3Qua2V5cyhpbnB1dHMpO1xuXG4gICAgLy8gV2UgbmVlZCBhIGNhbGxiYWNrIGFzIHdlIGFyZSB2YWxpZGF0aW5nIGFsbCBpbnB1dHMgYWdhaW4uIFRoaXMgd2lsbFxuICAgIC8vIHJ1biB3aGVuIHRoZSBsYXN0IGNvbXBvbmVudCBoYXMgc2V0IGl0cyBzdGF0ZVxuICAgIHZhciBvblZhbGlkYXRpb25Db21wbGV0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgIGlucHV0S2V5cy5mb3JFYWNoKGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgICAgIGlmICghaW5wdXRzW25hbWVdLnN0YXRlLl9pc1ZhbGlkKSB7XG4gICAgICAgICAgYWxsSXNWYWxpZCA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgICB9LmJpbmQodGhpcykpO1xuXG4gICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgaXNWYWxpZDogYWxsSXNWYWxpZFxuICAgICAgfSk7XG5cbiAgICAgIGFsbElzVmFsaWQgJiYgdGhpcy5wcm9wcy5vblZhbGlkKCk7XG4gICAgICAhYWxsSXNWYWxpZCAmJiB0aGlzLnByb3BzLm9uSW52YWxpZCgpO1xuXG4gICAgfS5iaW5kKHRoaXMpO1xuXG4gICAgLy8gUnVuIHZhbGlkYXRpb24gYWdhaW4gaW4gY2FzZSBhZmZlY3RlZCBieSBvdGhlciBpbnB1dHMuIFRoZVxuICAgIC8vIGxhc3QgY29tcG9uZW50IHZhbGlkYXRlZCB3aWxsIHJ1biB0aGUgb25WYWxpZGF0aW9uQ29tcGxldGUgY2FsbGJhY2tcbiAgICBpbnB1dEtleXMuZm9yRWFjaChmdW5jdGlvbiAobmFtZSwgaW5kZXgpIHtcbiAgICAgIHZhciBjb21wb25lbnQgPSBpbnB1dHNbbmFtZV07XG4gICAgICB2YXIgaXNWYWxpZCA9IHRoaXMucnVuVmFsaWRhdGlvbihjb21wb25lbnQpO1xuICAgICAgY29tcG9uZW50LnNldFN0YXRlKHtcbiAgICAgICAgX2lzVmFsaWQ6IGlzVmFsaWQsXG4gICAgICAgIF9zZXJ2ZXJFcnJvcjogbnVsbFxuICAgICAgfSwgaW5kZXggPT09IGlucHV0S2V5cy5sZW5ndGggLSAxID8gb25WYWxpZGF0aW9uQ29tcGxldGUgOiBudWxsKTtcbiAgICB9LmJpbmQodGhpcykpO1xuXG4gIH0sXG5cbiAgLy8gTWV0aG9kIHB1dCBvbiBlYWNoIGlucHV0IGNvbXBvbmVudCB0byByZWdpc3RlclxuICAvLyBpdHNlbGYgdG8gdGhlIGZvcm1cbiAgYXR0YWNoVG9Gb3JtOiBmdW5jdGlvbiAoY29tcG9uZW50KSB7XG4gICAgdGhpcy5pbnB1dHNbY29tcG9uZW50LnByb3BzLm5hbWVdID0gY29tcG9uZW50O1xuICAgIHRoaXMubW9kZWxbY29tcG9uZW50LnByb3BzLm5hbWVdID0gY29tcG9uZW50LnN0YXRlLl92YWx1ZTtcbiAgICB0aGlzLnZhbGlkYXRlKGNvbXBvbmVudCk7XG4gIH0sXG5cbiAgLy8gTWV0aG9kIHB1dCBvbiBlYWNoIGlucHV0IGNvbXBvbmVudCB0byB1bnJlZ2lzdGVyXG4gIC8vIGl0c2VsZiBmcm9tIHRoZSBmb3JtXG4gIGRldGFjaEZyb21Gb3JtOiBmdW5jdGlvbiAoY29tcG9uZW50KSB7XG4gICAgZGVsZXRlIHRoaXMuaW5wdXRzW2NvbXBvbmVudC5wcm9wcy5uYW1lXTtcbiAgICBkZWxldGUgdGhpcy5tb2RlbFtjb21wb25lbnQucHJvcHMubmFtZV07XG4gIH0sXG4gIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuXG4gICAgcmV0dXJuIFJlYWN0LkRPTS5mb3JtKHtcbiAgICAgICAgb25TdWJtaXQ6IHRoaXMuc3VibWl0LFxuICAgICAgICBjbGFzc05hbWU6IHRoaXMucHJvcHMuY2xhc3NOYW1lXG4gICAgICB9LFxuICAgICAgdGhpcy5wcm9wcy5jaGlsZHJlblxuICAgICk7XG5cbiAgfVxufSk7XG5cbmlmICghZ2xvYmFsLmV4cG9ydHMgJiYgIWdsb2JhbC5tb2R1bGUgJiYgKCFnbG9iYWwuZGVmaW5lIHx8ICFnbG9iYWwuZGVmaW5lLmFtZCkpIHtcbiAgZ2xvYmFsLkZvcm1zeSA9IEZvcm1zeTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBGb3Jtc3k7XG4iXX0=
+//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcGVjcy9FbGVtZW50LXNwZWMuanMiLCJzcGVjcy9Gb3Jtc3ktc3BlYy5qcyIsInNwZWNzL1N1Ym1pdC1zcGVjLmpzIiwic3BlY3MvVmFsaWRhdGlvbi1zcGVjLmpzIiwic3JjL21haW4uanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ3pJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCJ2YXIgRm9ybXN5ID0gcmVxdWlyZSgnLi8uLi9zcmMvbWFpbi5qcycpO1xuXG5kZXNjcmliZSgnRWxlbWVudCcsIGZ1bmN0aW9uKCkge1xuXG4gIGl0KCdzaG91bGQgcmV0dXJuIHBhc3NlZCBhbmQgc2V0VmFsdWUoKSB2YWx1ZSB3aGVuIHVzaW5nIGdldFZhbHVlKCknLCBmdW5jdGlvbiAoKSB7XG4gICAgXG4gICAgdmFyIFRlc3RJbnB1dCA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtkaXNwbGF5TmFtZTogXCJUZXN0SW5wdXRcIixcbiAgICAgIG1peGluczogW0Zvcm1zeS5NaXhpbl0sXG4gICAgICB1cGRhdGVWYWx1ZTogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIHRoaXMuc2V0VmFsdWUoZXZlbnQudGFyZ2V0LnZhbHVlKTtcbiAgICAgIH0sXG4gICAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJpbnB1dFwiLCB7dmFsdWU6IHRoaXMuZ2V0VmFsdWUoKSwgb25DaGFuZ2U6IHRoaXMudXBkYXRlVmFsdWV9KVxuICAgICAgfVxuICAgIH0pO1xuICAgIHZhciBmb3JtID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudChcbiAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRm9ybXN5LkZvcm0sIG51bGwsIFxuICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFRlc3RJbnB1dCwge25hbWU6IFwiZm9vXCIsIHZhbHVlOiBcImZvb1wifSlcbiAgICAgIClcbiAgICApO1xuXG4gICAgdmFyIGlucHV0ID0gVGVzdFV0aWxzLmZpbmRSZW5kZXJlZERPTUNvbXBvbmVudFdpdGhUYWcoZm9ybSwgJ0lOUFVUJyk7XG4gICAgZXhwZWN0KGlucHV0LmdldERPTU5vZGUoKS52YWx1ZSkudG9CZSgnZm9vJyk7XG4gICAgVGVzdFV0aWxzLlNpbXVsYXRlLmNoYW5nZShpbnB1dCwge3RhcmdldDoge3ZhbHVlOiAnZm9vYmFyJ319KTtcbiAgICBleHBlY3QoaW5wdXQuZ2V0RE9NTm9kZSgpLnZhbHVlKS50b0JlKCdmb29iYXInKTtcblxuICB9KTtcblxuICBpdCgnc2hvdWxkIHJldHVybiB0cnVlIG9yIGZhbHNlIHdoZW4gY2FsbGluZyBoYXNWYWx1ZSgpIGRlcGVuZGluZyBvbiB2YWx1ZSBleGlzdGFuY2UnLCBmdW5jdGlvbiAoKSB7XG4gICAgXG4gICAgdmFyIHJlc2V0ID0gbnVsbDtcbiAgICB2YXIgVGVzdElucHV0ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIlRlc3RJbnB1dFwiLFxuICAgICAgbWl4aW5zOiBbRm9ybXN5Lk1peGluXSxcbiAgICAgIGNvbXBvbmVudERpZE1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJlc2V0ID0gdGhpcy5yZXNldFZhbHVlO1xuICAgICAgfSxcbiAgICAgIHVwZGF0ZVZhbHVlOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgdGhpcy5zZXRWYWx1ZShldmVudC50YXJnZXQudmFsdWUpO1xuICAgICAgfSxcbiAgICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gUmVhY3QuY3JlYXRlRWxlbWVudChcImlucHV0XCIsIHt2YWx1ZTogdGhpcy5nZXRWYWx1ZSgpLCBvbkNoYW5nZTogdGhpcy51cGRhdGVWYWx1ZX0pXG4gICAgICB9XG4gICAgfSk7XG4gICAgdmFyIGZvcm0gPSBUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50KFxuICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChGb3Jtc3kuRm9ybSwgbnVsbCwgXG4gICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoVGVzdElucHV0LCB7bmFtZTogXCJmb29cIiwgdmFsdWU6IFwiZm9vXCJ9KVxuICAgICAgKVxuICAgICk7XG5cbiAgICB2YXIgaW5wdXQgPSBUZXN0VXRpbHMuZmluZFJlbmRlcmVkRE9NQ29tcG9uZW50V2l0aFRhZyhmb3JtLCAnSU5QVVQnKTtcbiAgICByZXNldCgpO1xuICAgIGV4cGVjdChpbnB1dC5nZXRET01Ob2RlKCkudmFsdWUpLnRvQmUoJycpO1xuXG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgcmV0dXJuIGVycm9yIG1lc3NhZ2UgcGFzc2VkIHdoZW4gY2FsbGluZyBnZXRFcnJvck1lc3NhZ2UoKScsIGZ1bmN0aW9uICgpIHtcbiAgICBcbiAgICB2YXIgZ2V0RXJyb3JNZXNzYWdlID0gbnVsbDtcbiAgICB2YXIgVGVzdElucHV0ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIlRlc3RJbnB1dFwiLFxuICAgICAgbWl4aW5zOiBbRm9ybXN5Lk1peGluXSxcbiAgICAgIGNvbXBvbmVudERpZE1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGdldEVycm9yTWVzc2FnZSA9IHRoaXMuZ2V0RXJyb3JNZXNzYWdlO1xuICAgICAgfSxcbiAgICAgIHVwZGF0ZVZhbHVlOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgdGhpcy5zZXRWYWx1ZShldmVudC50YXJnZXQudmFsdWUpO1xuICAgICAgfSxcbiAgICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gUmVhY3QuY3JlYXRlRWxlbWVudChcImlucHV0XCIsIHt2YWx1ZTogdGhpcy5nZXRWYWx1ZSgpLCBvbkNoYW5nZTogdGhpcy51cGRhdGVWYWx1ZX0pXG4gICAgICB9XG4gICAgfSk7XG4gICAgdmFyIGZvcm0gPSBUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50KFxuICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChGb3Jtc3kuRm9ybSwgbnVsbCwgXG4gICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoVGVzdElucHV0LCB7bmFtZTogXCJmb29cIiwgdmFsdWU6IFwiZm9vXCIsIHZhbGlkYXRpb25zOiBcImlzRW1haWxcIiwgdmFsaWRhdGlvbkVycm9yOiBcIkhhcyB0byBiZSBlbWFpbFwifSlcbiAgICAgIClcbiAgICApO1xuXG4gICAgZXhwZWN0KGdldEVycm9yTWVzc2FnZSgpKS50b0JlKCdIYXMgdG8gYmUgZW1haWwnKTtcblxuICB9KTtcblxuICBpdCgnc2hvdWxkIHJldHVybiBzZXJ2ZXIgZXJyb3IgbWVzc2FnZSB3aGVuIGNhbGxpbmcgZ2V0RXJyb3JNZXNzYWdlKCknLCBmdW5jdGlvbiAoZG9uZSkge1xuICAgIFxuICAgIGphc21pbmUuQWpheC5pbnN0YWxsKCk7XG5cbiAgICB2YXIgZ2V0RXJyb3JNZXNzYWdlID0gbnVsbDtcbiAgICB2YXIgVGVzdElucHV0ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIlRlc3RJbnB1dFwiLFxuICAgICAgbWl4aW5zOiBbRm9ybXN5Lk1peGluXSxcbiAgICAgIGNvbXBvbmVudERpZE1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGdldEVycm9yTWVzc2FnZSA9IHRoaXMuZ2V0RXJyb3JNZXNzYWdlO1xuICAgICAgfSxcbiAgICAgIHVwZGF0ZVZhbHVlOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgdGhpcy5zZXRWYWx1ZShldmVudC50YXJnZXQudmFsdWUpO1xuICAgICAgfSxcbiAgICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gUmVhY3QuY3JlYXRlRWxlbWVudChcImlucHV0XCIsIHt2YWx1ZTogdGhpcy5nZXRWYWx1ZSgpLCBvbkNoYW5nZTogdGhpcy51cGRhdGVWYWx1ZX0pXG4gICAgICB9XG4gICAgfSk7XG4gICAgdmFyIGZvcm0gPSBUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50KFxuICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChGb3Jtc3kuRm9ybSwge3VybDogXCIvdXNlcnNcIn0sIFxuICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFRlc3RJbnB1dCwge25hbWU6IFwiZm9vXCIsIHZhbHVlOiBcImZvb1wiLCB2YWxpZGF0aW9uczogXCJpc0VtYWlsXCIsIHZhbGlkYXRpb25FcnJvcjogXCJIYXMgdG8gYmUgZW1haWxcIn0pXG4gICAgICApXG4gICAgKTtcblxuICAgIHZhciBmb3JtID0gVGVzdFV0aWxzLlNpbXVsYXRlLnN1Ym1pdChmb3JtLmdldERPTU5vZGUoKSk7XG5cbiAgICBqYXNtaW5lLkFqYXgucmVxdWVzdHMubW9zdFJlY2VudCgpLnJlc3BvbmRXaXRoKHtcbiAgICAgIHN0YXR1czogNTAwLFxuICAgICAgY29udGVudFR5cGU6ICdhcHBsaWNhdGlvbi9qc29uJyxcbiAgICAgIHJlc3BvbnNlVGV4dDogJ3tcImZvb1wiOiBcImJhclwifSdcbiAgICB9KVxuXG4gICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICBleHBlY3QoZ2V0RXJyb3JNZXNzYWdlKCkpLnRvQmUoJ2JhcicpO1xuICAgICAgamFzbWluZS5BamF4LnVuaW5zdGFsbCgpO1xuICAgICAgZG9uZSgpO1xuICAgIH0sIDApO1xuXG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgcmV0dXJuIHRydWUgb3IgZmFsc2Ugd2hlbiBjYWxsaW5nIGlzVmFsaWQoKSBkZXBlbmRpbmcgb24gdmFsaWQgc3RhdGUnLCBmdW5jdGlvbiAoKSB7XG4gICAgXG4gICAgdmFyIGlzVmFsaWQgPSBudWxsO1xuICAgIHZhciBUZXN0SW5wdXQgPSBSZWFjdC5jcmVhdGVDbGFzcyh7ZGlzcGxheU5hbWU6IFwiVGVzdElucHV0XCIsXG4gICAgICBtaXhpbnM6IFtGb3Jtc3kuTWl4aW5dLFxuICAgICAgY29tcG9uZW50RGlkTW91bnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaXNWYWxpZCA9IHRoaXMuaXNWYWxpZDtcbiAgICAgIH0sXG4gICAgICB1cGRhdGVWYWx1ZTogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdldmVudC50YXJnZXQudmFsdWUnLCBldmVudC50YXJnZXQudmFsdWUpO1xuICAgICAgICB0aGlzLnNldFZhbHVlKGV2ZW50LnRhcmdldC52YWx1ZSk7XG4gICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGNvbnNvbGUubG9nKCd0aGlzLmdldFZhbHVlKCknLCB0aGlzLmdldFZhbHVlKCkpO1xuICAgICAgICB9LmJpbmQodGhpcyksIDEwMCk7XG4gICAgICB9LFxuICAgICAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBSZWFjdC5jcmVhdGVFbGVtZW50KFwiaW5wdXRcIiwge3ZhbHVlOiB0aGlzLmdldFZhbHVlKCksIG9uQ2hhbmdlOiB0aGlzLnVwZGF0ZVZhbHVlfSlcbiAgICAgIH1cbiAgICB9KTtcbiAgICB2YXIgZm9ybSA9IFRlc3RVdGlscy5yZW5kZXJJbnRvRG9jdW1lbnQoXG4gICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KEZvcm1zeS5Gb3JtLCB7dXJsOiBcIi91c2Vyc1wifSwgXG4gICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoVGVzdElucHV0LCB7bmFtZTogXCJmb29cIiwgdmFsdWU6IFwiZm9vXCIsIHZhbGlkYXRpb25zOiBcImlzRW1haWxcIn0pXG4gICAgICApXG4gICAgKTtcblxuICAgIGV4cGVjdChpc1ZhbGlkKCkpLnRvQmUoZmFsc2UpO1xuICAgIHZhciBpbnB1dCA9IFRlc3RVdGlscy5maW5kUmVuZGVyZWRET01Db21wb25lbnRXaXRoVGFnKGZvcm0sICdJTlBVVCcpO1xuICAgIFRlc3RVdGlscy5TaW11bGF0ZS5jaGFuZ2UoaW5wdXQsIHt0YXJnZXQ6IHt2YWx1ZTogJ2Zvb0Bmb28uY29tJ319KTtcbiAgICBleHBlY3QoaXNWYWxpZCgpKS50b0JlKHRydWUpO1xuXG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgcmV0dXJuIHRydWUgb3IgZmFsc2Ugd2hlbiBjYWxsaW5nIGlzUmVxdWlyZWQoKSBkZXBlbmRpbmcgb24gcGFzc2VkIHJlcXVpcmVkIGF0dHJpYnV0ZScsIGZ1bmN0aW9uICgpIHtcbiAgICBcbiAgICB2YXIgaXNSZXF1aXJlZHMgPSBbXTtcbiAgICB2YXIgVGVzdElucHV0ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIlRlc3RJbnB1dFwiLFxuICAgICAgbWl4aW5zOiBbRm9ybXN5Lk1peGluXSxcbiAgICAgIGNvbXBvbmVudERpZE1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlzUmVxdWlyZWRzLnB1c2godGhpcy5pc1JlcXVpcmVkKTtcbiAgICAgIH0sXG4gICAgICB1cGRhdGVWYWx1ZTogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIHRoaXMuc2V0VmFsdWUoZXZlbnQudGFyZ2V0LnZhbHVlKTtcbiAgICAgIH0sXG4gICAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJpbnB1dFwiLCB7dmFsdWU6IHRoaXMuZ2V0VmFsdWUoKSwgb25DaGFuZ2U6IHRoaXMudXBkYXRlVmFsdWV9KVxuICAgICAgfVxuICAgIH0pO1xuICAgIHZhciBmb3JtID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudChcbiAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRm9ybXN5LkZvcm0sIHt1cmw6IFwiL3VzZXJzXCJ9LCBcbiAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChUZXN0SW5wdXQsIHtuYW1lOiBcImZvb1wiLCB2YWx1ZTogXCJmb29cIn0pLCBcbiAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChUZXN0SW5wdXQsIHtuYW1lOiBcImZvb1wiLCB2YWx1ZTogXCJmb29cIiwgcmVxdWlyZWQ6IHRydWV9KVxuICAgICAgKVxuICAgICk7XG5cbiAgICBleHBlY3QoaXNSZXF1aXJlZHNbMF0oKSkudG9CZShmYWxzZSk7XG4gICAgZXhwZWN0KGlzUmVxdWlyZWRzWzFdKCkpLnRvQmUodHJ1ZSk7XG5cbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCByZXR1cm4gdHJ1ZSBvciBmYWxzZSB3aGVuIGNhbGxpbmcgc2hvd1JlcXVpcmVkKCkgZGVwZW5kaW5nIG9uIGlucHV0IGJlaW5nIGVtcHR5IGFuZCByZXF1aXJlZCBpcyBwYXNzZWQsIG9yIG5vdCcsIGZ1bmN0aW9uICgpIHtcbiAgICBcbiAgICB2YXIgc2hvd1JlcXVpcmVkcyA9IFtdO1xuICAgIHZhciBUZXN0SW5wdXQgPSBSZWFjdC5jcmVhdGVDbGFzcyh7ZGlzcGxheU5hbWU6IFwiVGVzdElucHV0XCIsXG4gICAgICBtaXhpbnM6IFtGb3Jtc3kuTWl4aW5dLFxuICAgICAgY29tcG9uZW50RGlkTW91bnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgc2hvd1JlcXVpcmVkcy5wdXNoKHRoaXMuc2hvd1JlcXVpcmVkKTtcbiAgICAgIH0sXG4gICAgICB1cGRhdGVWYWx1ZTogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIHRoaXMuc2V0VmFsdWUoZXZlbnQudGFyZ2V0LnZhbHVlKTtcbiAgICAgIH0sXG4gICAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJpbnB1dFwiLCB7dmFsdWU6IHRoaXMuZ2V0VmFsdWUoKSwgb25DaGFuZ2U6IHRoaXMudXBkYXRlVmFsdWV9KVxuICAgICAgfVxuICAgIH0pO1xuICAgIHZhciBmb3JtID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudChcbiAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRm9ybXN5LkZvcm0sIHt1cmw6IFwiL3VzZXJzXCJ9LCBcbiAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChUZXN0SW5wdXQsIHtuYW1lOiBcIkFcIiwgdmFsdWU6IFwiZm9vXCJ9KSwgXG4gICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoVGVzdElucHV0LCB7bmFtZTogXCJCXCIsIHZhbHVlOiBcIlwiLCByZXF1aXJlZDogdHJ1ZX0pLCBcbiAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChUZXN0SW5wdXQsIHtuYW1lOiBcIkNcIiwgdmFsdWU6IFwiXCJ9KVxuICAgICAgKVxuICAgICk7XG5cbiAgICBleHBlY3Qoc2hvd1JlcXVpcmVkc1swXSgpKS50b0JlKGZhbHNlKTtcbiAgICBleHBlY3Qoc2hvd1JlcXVpcmVkc1sxXSgpKS50b0JlKHRydWUpO1xuICAgIGV4cGVjdChzaG93UmVxdWlyZWRzWzJdKCkpLnRvQmUoZmFsc2UpO1xuXG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgcmV0dXJuIHRydWUgb3IgZmFsc2Ugd2hlbiBjYWxsaW5nIHNob3dFcnJvcigpIGRlcGVuZGluZyBvbiB2YWx1ZSBpcyBpbnZhbGlkIG9yIGEgc2VydmVyIGVycm9yIGhhcyBhcnJpdmVkLCBvciBub3QnLCBmdW5jdGlvbiAoZG9uZSkge1xuXG4gICAgdmFyIHNob3dFcnJvciA9IG51bGw7XG4gICAgdmFyIFRlc3RJbnB1dCA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtkaXNwbGF5TmFtZTogXCJUZXN0SW5wdXRcIixcbiAgICAgIG1peGluczogW0Zvcm1zeS5NaXhpbl0sXG4gICAgICBjb21wb25lbnREaWRNb3VudDogZnVuY3Rpb24gKCkge1xuICAgICAgICBzaG93RXJyb3IgPSB0aGlzLnNob3dFcnJvcjtcbiAgICAgIH0sXG4gICAgICB1cGRhdGVWYWx1ZTogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIHRoaXMuc2V0VmFsdWUoZXZlbnQudGFyZ2V0LnZhbHVlKTtcbiAgICAgIH0sXG4gICAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJpbnB1dFwiLCB7dmFsdWU6IHRoaXMuZ2V0VmFsdWUoKSwgb25DaGFuZ2U6IHRoaXMudXBkYXRlVmFsdWV9KVxuICAgICAgfVxuICAgIH0pO1xuICAgIHZhciBmb3JtID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudChcbiAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRm9ybXN5LkZvcm0sIHt1cmw6IFwiL3VzZXJzXCJ9LCBcbiAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChUZXN0SW5wdXQsIHtuYW1lOiBcImZvb1wiLCB2YWx1ZTogXCJmb29cIiwgdmFsaWRhdGlvbnM6IFwiaXNFbWFpbFwiLCB2YWxpZGF0aW9uRXJyb3I6IFwiVGhpcyBpcyBub3QgYW4gZW1haWxcIn0pXG4gICAgICApXG4gICAgKTtcblxuICAgIGV4cGVjdChzaG93RXJyb3IoKSkudG9CZSh0cnVlKTtcblxuICAgIHZhciBpbnB1dCA9IFRlc3RVdGlscy5maW5kUmVuZGVyZWRET01Db21wb25lbnRXaXRoVGFnKGZvcm0sICdJTlBVVCcpO1xuICAgIFRlc3RVdGlscy5TaW11bGF0ZS5jaGFuZ2UoaW5wdXQsIHt0YXJnZXQ6IHt2YWx1ZTogJ2Zvb0Bmb28uY29tJ319KTtcbiAgICBleHBlY3Qoc2hvd0Vycm9yKCkpLnRvQmUoZmFsc2UpO1xuXG4gICAgamFzbWluZS5BamF4Lmluc3RhbGwoKTtcbiAgICBUZXN0VXRpbHMuU2ltdWxhdGUuc3VibWl0KGZvcm0uZ2V0RE9NTm9kZSgpKTsgICAgXG4gICAgamFzbWluZS5BamF4LnJlcXVlc3RzLm1vc3RSZWNlbnQoKS5yZXNwb25kV2l0aCh7XG4gICAgICBzdGF0dXM6IDUwMCxcbiAgICAgIHJlc3BvbnNlVHlwZTogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgcmVzcG9uc2VUZXh0OiAne1wiZm9vXCI6IFwiRW1haWwgYWxyZWFkeSBleGlzdHNcIn0nXG4gICAgfSk7XG4gICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICBleHBlY3Qoc2hvd0Vycm9yKCkpLnRvQmUodHJ1ZSk7XG4gICAgICBqYXNtaW5lLkFqYXgudW5pbnN0YWxsKCk7XG4gICAgICBkb25lKCk7XG4gICAgfSwgMCk7XG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgcmV0dXJuIHRydWUgb3IgZmFsc2Ugd2hlbiBjYWxsaW5nIGlzUHJlc3RpbmUoKSBkZXBlbmRpbmcgb24gaW5wdXQgaGFzIGJlZW4gXCJ0b3VjaGVkXCIgb3Igbm90JywgZnVuY3Rpb24gKCkge1xuICAgIFxuICAgIHZhciBpc1ByaXN0aW5lID0gbnVsbDtcbiAgICB2YXIgVGVzdElucHV0ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIlRlc3RJbnB1dFwiLFxuICAgICAgbWl4aW5zOiBbRm9ybXN5Lk1peGluXSxcbiAgICAgIGNvbXBvbmVudERpZE1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlzUHJpc3RpbmUgPSB0aGlzLmlzUHJpc3RpbmU7XG4gICAgICB9LFxuICAgICAgdXBkYXRlVmFsdWU6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICB0aGlzLnNldFZhbHVlKGV2ZW50LnRhcmdldC52YWx1ZSk7XG4gICAgICB9LFxuICAgICAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBSZWFjdC5jcmVhdGVFbGVtZW50KFwiaW5wdXRcIiwge3ZhbHVlOiB0aGlzLmdldFZhbHVlKCksIG9uQ2hhbmdlOiB0aGlzLnVwZGF0ZVZhbHVlfSlcbiAgICAgIH1cbiAgICB9KTtcbiAgICB2YXIgZm9ybSA9IFRlc3RVdGlscy5yZW5kZXJJbnRvRG9jdW1lbnQoXG4gICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KEZvcm1zeS5Gb3JtLCB7dXJsOiBcIi91c2Vyc1wifSwgXG4gICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoVGVzdElucHV0LCB7bmFtZTogXCJBXCIsIHZhbHVlOiBcImZvb1wifSlcbiAgICAgIClcbiAgICApO1xuXG4gICAgZXhwZWN0KGlzUHJpc3RpbmUoKSkudG9CZSh0cnVlKTtcbiAgICB2YXIgaW5wdXQgPSBUZXN0VXRpbHMuZmluZFJlbmRlcmVkRE9NQ29tcG9uZW50V2l0aFRhZyhmb3JtLCAnSU5QVVQnKTtcbiAgICBUZXN0VXRpbHMuU2ltdWxhdGUuY2hhbmdlKGlucHV0LCB7dGFyZ2V0OiB7dmFsdWU6ICdmb28nfX0pO1xuICAgIGV4cGVjdChpc1ByaXN0aW5lKCkpLnRvQmUoZmFsc2UpO1xuICAgIFxuICB9KTtcblxufSk7XG4iLCJ2YXIgRm9ybXN5ID0gcmVxdWlyZSgnLi8uLi9zcmMvbWFpbi5qcycpO1xuXG5kZXNjcmliZSgnRm9ybXN5JywgZnVuY3Rpb24gKCkge1xuXG4gIGRlc2NyaWJlKCdTZXR0aW5nIHVwIGEgZm9ybScsIGZ1bmN0aW9uICgpIHtcblxuICAgIGl0KCdzaG91bGQgcmVuZGVyIGEgZm9ybSBpbnRvIHRoZSBkb2N1bWVudCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgIHZhciBmb3JtID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudCggUmVhY3QuY3JlYXRlRWxlbWVudChGb3Jtc3kuRm9ybSwgbnVsbCkpO1xuICAgICAgZXhwZWN0KGZvcm0uZ2V0RE9NTm9kZSgpLnRhZ05hbWUpLnRvRXF1YWwoJ0ZPUk0nKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgc2V0IGEgY2xhc3MgbmFtZSBpZiBwYXNzZWQnLCBmdW5jdGlvbiAoKSB7XG4gICAgICB2YXIgZm9ybSA9IFRlc3RVdGlscy5yZW5kZXJJbnRvRG9jdW1lbnQoIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRm9ybXN5LkZvcm0sIHtjbGFzc05hbWU6IFwiZm9vXCJ9KSk7XG4gICAgICBleHBlY3QoZm9ybS5nZXRET01Ob2RlKCkuY2xhc3NOYW1lKS50b0VxdWFsKCdmb28nKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgYWxsb3cgZm9yIGlucHV0cyBiZWluZyBhZGRlZCBkeW5hbWljYWxseScsIGZ1bmN0aW9uIChkb25lKSB7XG5cbiAgICAgIHZhciBpbnB1dHMgPSBbXTtcbiAgICAgIHZhciBmb3JjZVVwZGF0ZSA9IG51bGw7XG4gICAgICB2YXIgbW9kZWwgPSBudWxsO1xuICAgICAgdmFyIFRlc3RJbnB1dCA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtkaXNwbGF5TmFtZTogXCJUZXN0SW5wdXRcIixcbiAgICAgICAgbWl4aW5zOiBbRm9ybXN5Lk1peGluXSxcbiAgICAgICAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJkaXZcIiwgbnVsbClcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICB2YXIgVGVzdEZvcm0gPSBSZWFjdC5jcmVhdGVDbGFzcyh7ZGlzcGxheU5hbWU6IFwiVGVzdEZvcm1cIixcbiAgICAgICAgY29tcG9uZW50V2lsbE1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgZm9yY2VVcGRhdGUgPSB0aGlzLmZvcmNlVXBkYXRlLmJpbmQodGhpcyk7XG4gICAgICAgIH0sXG4gICAgICAgIG9uU3VibWl0OiBmdW5jdGlvbiAoZm9ybU1vZGVsKSB7XG4gICAgICAgICAgbW9kZWwgPSBmb3JtTW9kZWw7XG4gICAgICAgIH0sXG4gICAgICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgIHJldHVybiAoIFxuICAgICAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChGb3Jtc3kuRm9ybSwge29uU3VibWl0OiB0aGlzLm9uU3VibWl0fSwgXG4gICAgICAgICAgICAgIGlucHV0c1xuICAgICAgICAgICAgKSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgdmFyIGZvcm0gPSBUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50KCBcbiAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChUZXN0Rm9ybSwgbnVsbCkgXG4gICAgICApO1xuXG4gICAgICAvLyBXYWl0IGJlZm9yZSBhZGRpbmcgdGhlIGlucHV0XG4gICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcblxuICAgICAgICBpbnB1dHMucHVzaChUZXN0SW5wdXQoe1xuICAgICAgICAgIG5hbWU6ICd0ZXN0J1xuICAgICAgICB9KSk7XG5cbiAgICAgICAgZm9yY2VVcGRhdGUoZnVuY3Rpb24gKCkge1xuXG4gICAgICAgICAgLy8gV2FpdCBmb3IgbmV4dCBldmVudCBsb29wLCBhcyB0aGF0IGRvZXMgdGhlIGZvcm1cbiAgICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIFRlc3RVdGlscy5TaW11bGF0ZS5zdWJtaXQoZm9ybS5nZXRET01Ob2RlKCkpO1xuICAgICAgICAgICAgZXhwZWN0KG1vZGVsLnRlc3QpLnRvQmVEZWZpbmVkKCk7XG4gICAgICAgICAgICBkb25lKCk7XG4gICAgICAgICAgfSwgMCk7XG5cbiAgICAgICAgfSk7XG5cbiAgICAgIH0sIDEwKTtcblxuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBhbGxvdyBkeW5hbWljYWxseSBhZGRlZCBpbnB1dHMgdG8gdXBkYXRlIHRoZSBmb3JtLW1vZGVsJywgZnVuY3Rpb24gKGRvbmUpIHtcblxuICAgICAgdmFyIGlucHV0cyA9IFtdO1xuICAgICAgdmFyIGZvcmNlVXBkYXRlID0gbnVsbDtcbiAgICAgIHZhciBtb2RlbCA9IG51bGw7XG4gICAgICB2YXIgVGVzdElucHV0ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIlRlc3RJbnB1dFwiLFxuICAgICAgICBtaXhpbnM6IFtGb3Jtc3kuTWl4aW5dLFxuICAgICAgICBjaGFuZ2VWYWx1ZTogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICAgdGhpcy5zZXRWYWx1ZShldmVudC50YXJnZXQudmFsdWUpO1xuICAgICAgICB9LFxuICAgICAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICByZXR1cm4gUmVhY3QuY3JlYXRlRWxlbWVudChcImlucHV0XCIsIHt2YWx1ZTogdGhpcy5nZXRWYWx1ZSgpLCBvbkNoYW5nZTogdGhpcy5jaGFuZ2VWYWx1ZX0pXG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgdmFyIFRlc3RGb3JtID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIlRlc3RGb3JtXCIsXG4gICAgICAgIGNvbXBvbmVudFdpbGxNb3VudDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGZvcmNlVXBkYXRlID0gdGhpcy5mb3JjZVVwZGF0ZS5iaW5kKHRoaXMpO1xuICAgICAgICB9LFxuICAgICAgICBvblN1Ym1pdDogZnVuY3Rpb24gKGZvcm1Nb2RlbCkge1xuICAgICAgICAgIG1vZGVsID0gZm9ybU1vZGVsO1xuICAgICAgICB9LFxuICAgICAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICByZXR1cm4gKCBcbiAgICAgICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRm9ybXN5LkZvcm0sIHtvblN1Ym1pdDogdGhpcy5vblN1Ym1pdH0sIFxuICAgICAgICAgICAgICBpbnB1dHNcbiAgICAgICAgICAgICkpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIHZhciBmb3JtID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudCggXG4gICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoVGVzdEZvcm0sIG51bGwpIFxuICAgICAgKTtcblxuICAgICAgLy8gV2FpdCBiZWZvcmUgYWRkaW5nIHRoZSBpbnB1dFxuICAgICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG5cbiAgICAgICAgaW5wdXRzLnB1c2goVGVzdElucHV0KHtcbiAgICAgICAgICBuYW1lOiAndGVzdCdcbiAgICAgICAgfSkpO1xuXG4gICAgICAgIGZvcmNlVXBkYXRlKGZ1bmN0aW9uICgpIHtcblxuICAgICAgICAgIC8vIFdhaXQgZm9yIG5leHQgZXZlbnQgbG9vcCwgYXMgdGhhdCBkb2VzIHRoZSBmb3JtXG4gICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBUZXN0VXRpbHMuU2ltdWxhdGUuY2hhbmdlKFRlc3RVdGlscy5maW5kUmVuZGVyZWRET01Db21wb25lbnRXaXRoVGFnKGZvcm0sICdJTlBVVCcpLCB7dGFyZ2V0OiB7dmFsdWU6ICdmb28nfX0pO1xuICAgICAgICAgICAgVGVzdFV0aWxzLlNpbXVsYXRlLnN1Ym1pdChmb3JtLmdldERPTU5vZGUoKSk7XG4gICAgICAgICAgICBleHBlY3QobW9kZWwudGVzdCkudG9CZSgnZm9vJyk7XG4gICAgICAgICAgICBkb25lKCk7XG4gICAgICAgICAgfSwgMCk7XG5cbiAgICAgICAgfSk7XG5cbiAgICAgIH0sIDEwKTtcblxuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBpbnZhbGlkYXRlIGEgdmFsaWQgZm9ybSBpZiBkeW5hbWljYWxseSBpbnNlcnRlZCBpbnB1dCBpcyBpbnZhbGlkJywgZnVuY3Rpb24gKGRvbmUpIHtcblxuICAgICAgdmFyIGZvcmNlVXBkYXRlID0gbnVsbDtcbiAgICAgIHZhciBpc0ludmFsaWQgPSBmYWxzZTtcbiAgICAgIHZhciBUZXN0SW5wdXQgPSBSZWFjdC5jcmVhdGVDbGFzcyh7ZGlzcGxheU5hbWU6IFwiVGVzdElucHV0XCIsXG4gICAgICAgIG1peGluczogW0Zvcm1zeS5NaXhpbl0sXG4gICAgICAgIGNoYW5nZVZhbHVlOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICB0aGlzLnNldFZhbHVlKGV2ZW50LnRhcmdldC52YWx1ZSk7XG4gICAgICAgIH0sXG4gICAgICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgIHJldHVybiBSZWFjdC5jcmVhdGVFbGVtZW50KFwiaW5wdXRcIiwge3ZhbHVlOiB0aGlzLmdldFZhbHVlKCksIG9uQ2hhbmdlOiB0aGlzLmNoYW5nZVZhbHVlfSlcbiAgICAgICAgfVxuICAgICAgfSk7XG5cblxuICAgICAgdmFyIGlucHV0cyA9IFtUZXN0SW5wdXQoe1xuICAgICAgICBuYW1lOiAndGVzdCcsXG4gICAgICAgIHZhbGlkYXRpb25zOiAnaXNFbWFpbCcsXG4gICAgICAgIHZhbHVlOiAnZm9vQGJhci5jb20nXG4gICAgICB9KV07XG5cbiAgICAgIHZhciBUZXN0Rm9ybSA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtkaXNwbGF5TmFtZTogXCJUZXN0Rm9ybVwiLFxuICAgICAgICBjb21wb25lbnRXaWxsTW91bnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBmb3JjZVVwZGF0ZSA9IHRoaXMuZm9yY2VVcGRhdGUuYmluZCh0aGlzKTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0SW52YWxpZDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGlzSW52YWxpZCA9IHRydWU7XG4gICAgICAgIH0sXG4gICAgICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgIHJldHVybiAoIFxuICAgICAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChGb3Jtc3kuRm9ybSwge29uSW52YWxpZDogdGhpcy5zZXRJbnZhbGlkfSwgXG4gICAgICAgICAgICAgIGlucHV0c1xuICAgICAgICAgICAgKSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgdmFyIGZvcm0gPSBUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50KCBcbiAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChUZXN0Rm9ybSwgbnVsbCkgXG4gICAgICApO1xuXG4gICAgICBleHBlY3QoaXNJbnZhbGlkKS50b0JlKGZhbHNlKTtcblxuICAgICAgLy8gV2FpdCBiZWZvcmUgYWRkaW5nIHRoZSBpbnB1dFxuICAgICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG5cbiAgICAgICAgXG4gICAgICAgIGlucHV0cy5wdXNoKFRlc3RJbnB1dCh7XG4gICAgICAgICAgbmFtZTogJ3Rlc3QyJyxcbiAgICAgICAgICB2YWxpZGF0aW9uczogJ2lzRW1haWwnLFxuICAgICAgICAgIHZhbHVlOiAnZm9vQGJhcidcbiAgICAgICAgfSkpO1xuXG5cbiAgICAgICAgZm9yY2VVcGRhdGUoZnVuY3Rpb24gKCkge1xuXG4gICAgICAgICAgLy8gV2FpdCBmb3IgbmV4dCBldmVudCBsb29wLCBhcyB0aGF0IGRvZXMgdGhlIGZvcm1cbiAgICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIFRlc3RVdGlscy5TaW11bGF0ZS5zdWJtaXQoZm9ybS5nZXRET01Ob2RlKCkpO1xuICAgICAgICAgICAgZXhwZWN0KGlzSW52YWxpZCkudG9CZSh0cnVlKTtcbiAgICAgICAgICAgIGRvbmUoKTtcbiAgICAgICAgICB9LCAwKTtcblxuICAgICAgICB9KTtcblxuICAgICAgfSwgMTApO1xuXG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIG5vdCB0cmlnZ2VyIG9uQ2hhbmdlIHdoZW4gZm9ybSBpcyBtb3VudGVkJywgZnVuY3Rpb24gKCkge1xuICAgICAgdmFyIGhhc0NoYW5nZWQgPSBqYXNtaW5lLmNyZWF0ZVNweSgnb25DaGFuZ2UnKTtcbiAgICAgIHZhciBUZXN0Rm9ybSA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtkaXNwbGF5TmFtZTogXCJUZXN0Rm9ybVwiLFxuICAgICAgICBvbkNoYW5nZTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGhhc0NoYW5nZWQoKTtcbiAgICAgICAgfSxcbiAgICAgICAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRm9ybXN5LkZvcm0sIHtvbkNoYW5nZTogdGhpcy5vbkNoYW5nZX0pO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIHZhciBmb3JtID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudChSZWFjdC5jcmVhdGVFbGVtZW50KFRlc3RGb3JtLCBudWxsKSk7XG4gICAgICBleHBlY3QoaGFzQ2hhbmdlZCkubm90LnRvSGF2ZUJlZW5DYWxsZWQoKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdHJpZ2dlciBvbkNoYW5nZSB3aGVuIGZvcm0gZWxlbWVudCBpcyBjaGFuZ2VkJywgZnVuY3Rpb24gKCkge1xuICAgICAgdmFyIGhhc0NoYW5nZWQgPSBqYXNtaW5lLmNyZWF0ZVNweSgnb25DaGFuZ2UnKTtcbiAgICAgIHZhciBNeUlucHV0ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIk15SW5wdXRcIixcbiAgICAgICAgbWl4aW5zOiBbRm9ybXN5Lk1peGluXSxcbiAgICAgICAgb25DaGFuZ2U6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAgIHRoaXMuc2V0VmFsdWUoZXZlbnQudGFyZ2V0LnZhbHVlKTtcbiAgICAgICAgfSxcbiAgICAgICAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJpbnB1dFwiLCB7dmFsdWU6IHRoaXMuZ2V0VmFsdWUoKSwgb25DaGFuZ2U6IHRoaXMub25DaGFuZ2V9KVxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIHZhciBUZXN0Rm9ybSA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtkaXNwbGF5TmFtZTogXCJUZXN0Rm9ybVwiLFxuICAgICAgICBvbkNoYW5nZTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGhhc0NoYW5nZWQoKTtcbiAgICAgICAgfSxcbiAgICAgICAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRm9ybXN5LkZvcm0sIHtvbkNoYW5nZTogdGhpcy5vbkNoYW5nZX0sIFxuICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KE15SW5wdXQsIHtuYW1lOiBcImZvb1wifSlcbiAgICAgICAgICAgIClcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIHZhciBmb3JtID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudChSZWFjdC5jcmVhdGVFbGVtZW50KFRlc3RGb3JtLCBudWxsKSk7XG4gICAgICBUZXN0VXRpbHMuU2ltdWxhdGUuY2hhbmdlKFRlc3RVdGlscy5maW5kUmVuZGVyZWRET01Db21wb25lbnRXaXRoVGFnKGZvcm0sICdJTlBVVCcpLCB7dGFyZ2V0OiB7dmFsdWU6ICdiYXInfX0pO1xuICAgICAgZXhwZWN0KGhhc0NoYW5nZWQpLnRvSGF2ZUJlZW5DYWxsZWQoKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdHJpZ2dlciBvbkNoYW5nZSB3aGVuIG5ldyBpbnB1dCBpcyBhZGRlZCB0byBmb3JtJywgZnVuY3Rpb24gKGRvbmUpIHtcbiAgICAgIHZhciBoYXNDaGFuZ2VkID0gamFzbWluZS5jcmVhdGVTcHkoJ29uQ2hhbmdlJyk7XG4gICAgICB2YXIgaW5wdXRzID0gW107XG4gICAgICB2YXIgZm9yY2VVcGRhdGUgPSBudWxsO1xuICAgICAgdmFyIFRlc3RJbnB1dCA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtkaXNwbGF5TmFtZTogXCJUZXN0SW5wdXRcIixcbiAgICAgICAgbWl4aW5zOiBbRm9ybXN5Lk1peGluXSxcbiAgICAgICAgY2hhbmdlVmFsdWU6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAgIHRoaXMuc2V0VmFsdWUoZXZlbnQudGFyZ2V0LnZhbHVlKTtcbiAgICAgICAgfSxcbiAgICAgICAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJpbnB1dFwiLCB7dmFsdWU6IHRoaXMuZ2V0VmFsdWUoKSwgb25DaGFuZ2U6IHRoaXMuY2hhbmdlVmFsdWV9KVxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIHZhciBUZXN0Rm9ybSA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtkaXNwbGF5TmFtZTogXCJUZXN0Rm9ybVwiLFxuICAgICAgICBjb21wb25lbnRXaWxsTW91bnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBmb3JjZVVwZGF0ZSA9IHRoaXMuZm9yY2VVcGRhdGUuYmluZCh0aGlzKTtcbiAgICAgICAgfSxcbiAgICAgICAgb25DaGFuZ2U6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBoYXNDaGFuZ2VkKCk7XG4gICAgICAgIH0sXG4gICAgICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgIHJldHVybiAoIFxuICAgICAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChGb3Jtc3kuRm9ybSwge29uQ2hhbmdlOiB0aGlzLm9uQ2hhbmdlfSwgXG4gICAgICAgICAgICAgIGlucHV0c1xuICAgICAgICAgICAgKSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgdmFyIGZvcm0gPSBUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50KCBcbiAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChUZXN0Rm9ybSwgbnVsbCkgXG4gICAgICApO1xuXG4gICAgICAvLyBXYWl0IGJlZm9yZSBhZGRpbmcgdGhlIGlucHV0XG4gICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcblxuICAgICAgICBpbnB1dHMucHVzaChUZXN0SW5wdXQoe1xuICAgICAgICAgIG5hbWU6ICd0ZXN0J1xuICAgICAgICB9KSk7XG5cbiAgICAgICAgZm9yY2VVcGRhdGUoZnVuY3Rpb24gKCkge1xuXG4gICAgICAgICAgLy8gV2FpdCBmb3IgbmV4dCBldmVudCBsb29wLCBhcyB0aGF0IGRvZXMgdGhlIGZvcm1cbiAgICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGV4cGVjdChoYXNDaGFuZ2VkKS50b0hhdmVCZWVuQ2FsbGVkKCk7XG4gICAgICAgICAgICBkb25lKCk7XG4gICAgICAgICAgfSwgMCk7XG5cbiAgICAgICAgfSk7XG5cbiAgICAgIH0sIDEwKTtcblxuICAgIH0pO1xuXG4gIH0pO1xuXG59KTtcbiIsInZhciBGb3Jtc3kgPSByZXF1aXJlKCcuLy4uL3NyYy9tYWluLmpzJyk7XG5cbmRlc2NyaWJlKCdBamF4JywgZnVuY3Rpb24oKSB7XG5cbiAgYmVmb3JlRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgamFzbWluZS5BamF4Lmluc3RhbGwoKTtcbiAgfSk7XG5cbiAgYWZ0ZXJFYWNoKGZ1bmN0aW9uICgpIHtcbiAgICBqYXNtaW5lLkFqYXgudW5pbnN0YWxsKCk7XG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgcG9zdCB0byBhIGdpdmVuIHVybCBpZiBwYXNzZWQnLCBmdW5jdGlvbiAoKSB7XG5cbiAgICB2YXIgZm9ybSA9IFRlc3RVdGlscy5yZW5kZXJJbnRvRG9jdW1lbnQoXG4gICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KEZvcm1zeS5Gb3JtLCB7dXJsOiBcIi91c2Vyc1wifVxuICAgICAgKVxuICAgICk7XG4gICAgXG4gICAgVGVzdFV0aWxzLlNpbXVsYXRlLnN1Ym1pdChmb3JtLmdldERPTU5vZGUoKSk7XG4gICAgZXhwZWN0KGphc21pbmUuQWpheC5yZXF1ZXN0cy5tb3N0UmVjZW50KCkudXJsKS50b0JlKCcvdXNlcnMnKTtcbiAgICBleHBlY3QoamFzbWluZS5BamF4LnJlcXVlc3RzLm1vc3RSZWNlbnQoKS5tZXRob2QpLnRvQmUoJ1BPU1QnKTtcblxuICB9KTtcblxuICBpdCgnc2hvdWxkIHB1dCB0byBhIGdpdmVuIHVybCBpZiBwYXNzZWQgYSBtZXRob2QgYXR0cmlidXRlJywgZnVuY3Rpb24gKCkge1xuXG4gICAgdmFyIGZvcm0gPSBUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50KFxuICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChGb3Jtc3kuRm9ybSwge3VybDogXCIvdXNlcnNcIiwgbWV0aG9kOiBcIlBVVFwifVxuICAgICAgKVxuICAgICk7XG4gICAgXG4gICAgVGVzdFV0aWxzLlNpbXVsYXRlLnN1Ym1pdChmb3JtLmdldERPTU5vZGUoKSk7XG4gICAgZXhwZWN0KGphc21pbmUuQWpheC5yZXF1ZXN0cy5tb3N0UmVjZW50KCkudXJsKS50b0JlKCcvdXNlcnMnKTtcbiAgICBleHBlY3QoamFzbWluZS5BamF4LnJlcXVlc3RzLm1vc3RSZWNlbnQoKS5tZXRob2QpLnRvQmUoJ1BVVCcpO1xuXG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgcGFzcyB4LXd3dy1mb3JtLXVybGVuY29kZWQgYXMgY29udGVudFR5cGUgd2hlbiB1cmxlbmNvZGVkIGlzIHNldCBhcyBjb250ZW50VHlwZScsIGZ1bmN0aW9uICgpIHtcblxuICAgIHZhciBmb3JtID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudChcbiAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRm9ybXN5LkZvcm0sIHt1cmw6IFwiL3VzZXJzXCIsIGNvbnRlbnRUeXBlOiBcInVybGVuY29kZWRcIn1cbiAgICAgIClcbiAgICApO1xuICAgIFxuICAgIFRlc3RVdGlscy5TaW11bGF0ZS5zdWJtaXQoZm9ybS5nZXRET01Ob2RlKCkpO1xuICAgIGV4cGVjdChqYXNtaW5lLkFqYXgucmVxdWVzdHMubW9zdFJlY2VudCgpLmNvbnRlbnRUeXBlKCkpLnRvQmUoJ2FwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCcpO1xuXG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgcnVuIGFuIG9uU3VjY2VzcyBoYW5kbGVyLCBpZiBwYXNzZWQgYW5kIGFqYXggaXMgc3VjY2Vzc2Z1bGwuIEZpcnN0IGFyZ3VtZW50IGlzIGRhdGEgZnJvbSBzZXJ2ZXInLCBmdW5jdGlvbiAoZG9uZSkge1xuIFxuICAgIHZhciBvblN1Y2Nlc3MgPSBqYXNtaW5lLmNyZWF0ZVNweShcInN1Y2Nlc3NcIik7XG4gICAgdmFyIGZvcm0gPSBUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50KFxuICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChGb3Jtc3kuRm9ybSwge3VybDogXCIvdXNlcnNcIiwgb25TdWNjZXNzOiBvblN1Y2Nlc3N9XG4gICAgICApXG4gICAgKTtcbiAgICBcbiAgICBqYXNtaW5lLkFqYXguc3R1YlJlcXVlc3QoJy91c2VycycpLmFuZFJldHVybih7XG4gICAgICBzdGF0dXM6IDIwMCxcbiAgICAgIGNvbnRlbnRUeXBlOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICByZXNwb25zZVRleHQ6ICd7fSdcbiAgICB9KTtcblxuICAgIFRlc3RVdGlscy5TaW11bGF0ZS5zdWJtaXQoZm9ybS5nZXRET01Ob2RlKCkpO1xuXG4gICAgLy8gU2luY2UgYWpheCBpcyByZXR1cm5lZCBhcyBhIHByb21pc2UgKGFzeW5jKSwgbW92ZSBhc3NlcnRpb25cbiAgICAvLyB0byBlbmQgb2YgZXZlbnQgbG9vcFxuICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgZXhwZWN0KG9uU3VjY2VzcykudG9IYXZlQmVlbkNhbGxlZFdpdGgoe30pO1xuICAgICAgZG9uZSgpO1xuICAgIH0sIDApO1xuXG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgbm90IGRvIGFqYXggcmVxdWVzdCBpZiBvblN1Ym1pdCBoYW5kbGVyIGlzIHBhc3NlZCwgYnV0IHBhc3MgdGhlIG1vZGVsIGFzIGZpcnN0IGFyZ3VtZW50IHRvIG9uU3VibWl0IGhhbmRsZXInLCBmdW5jdGlvbiAoKSB7XG4gICAgXG4gICAgdmFyIFRlc3RJbnB1dCA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtkaXNwbGF5TmFtZTogXCJUZXN0SW5wdXRcIixcbiAgICAgIG1peGluczogW0Zvcm1zeS5NaXhpbl0sXG4gICAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJpbnB1dFwiLCB7dmFsdWU6IHRoaXMuZ2V0VmFsdWUoKX0pXG4gICAgICB9XG4gICAgfSk7XG4gICAgdmFyIGZvcm0gPSBUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50KFxuICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChGb3Jtc3kuRm9ybSwge29uU3VibWl0OiBvblN1Ym1pdH0sIFxuICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFRlc3RJbnB1dCwge25hbWU6IFwiZm9vXCIsIHZhbHVlOiBcImJhclwifSlcbiAgICAgIClcbiAgICApO1xuXG4gICAgVGVzdFV0aWxzLlNpbXVsYXRlLnN1Ym1pdChmb3JtLmdldERPTU5vZGUoKSk7XG5cbiAgICBleHBlY3QoamFzbWluZS5BamF4LnJlcXVlc3RzLmNvdW50KCkpLnRvQmUoMCk7XG5cbiAgICBmdW5jdGlvbiBvblN1Ym1pdCAoZGF0YSkge1xuICAgICAgZXhwZWN0KGRhdGEpLnRvRXF1YWwoe1xuICAgICAgICBmb286ICdiYXInXG4gICAgICB9KTtcbiAgICB9XG5cbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCB0cmlnZ2VyIGFuIG9uU3VibWl0dGVkIGhhbmRsZXIsIGlmIHBhc3NlZCBhbmQgdGhlIHN1Ym1pdCBoYXMgcmVzcG9uZGVkIHdpdGggU1VDQ0VTUycsIGZ1bmN0aW9uIChkb25lKSB7XG4gICAgXG4gICAgdmFyIG9uU3VibWl0dGVkID0gamFzbWluZS5jcmVhdGVTcHkoXCJzdWJtaXR0ZWRcIik7XG4gICAgdmFyIGZvcm0gPSBUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50KFxuICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChGb3Jtc3kuRm9ybSwge3VybDogXCIvdXNlcnNcIiwgb25TdWJtaXR0ZWQ6IG9uU3VibWl0dGVkfVxuICAgICAgKVxuICAgICk7XG4gICAgXG4gICAgamFzbWluZS5BamF4LnN0dWJSZXF1ZXN0KCcvdXNlcnMnKS5hbmRSZXR1cm4oe1xuICAgICAgc3RhdHVzOiAyMDAsXG4gICAgICBjb250ZW50VHlwZTogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgcmVzcG9uc2VUZXh0OiAne30nXG4gICAgfSk7XG5cbiAgICBUZXN0VXRpbHMuU2ltdWxhdGUuc3VibWl0KGZvcm0uZ2V0RE9NTm9kZSgpKTtcblxuICAgIC8vIFNpbmNlIGFqYXggaXMgcmV0dXJuZWQgYXMgYSBwcm9taXNlIChhc3luYyksIG1vdmUgYXNzZXJ0aW9uXG4gICAgLy8gdG8gZW5kIG9mIGV2ZW50IGxvb3BcbiAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgIGV4cGVjdChvblN1Ym1pdHRlZCkudG9IYXZlQmVlbkNhbGxlZCgpO1xuICAgICAgZG9uZSgpO1xuICAgIH0sIDApO1xuXG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgdHJpZ2dlciBhbiBvblN1Ym1pdHRlZCBoYW5kbGVyLCBpZiBwYXNzZWQgYW5kIHRoZSBzdWJtaXQgaGFzIHJlc3BvbmRlZCB3aXRoIEVSUk9SJywgZnVuY3Rpb24gKGRvbmUpIHtcbiAgICBcbiAgICB2YXIgb25TdWJtaXR0ZWQgPSBqYXNtaW5lLmNyZWF0ZVNweShcInN1Ym1pdHRlZFwiKTtcbiAgICB2YXIgZm9ybSA9IFRlc3RVdGlscy5yZW5kZXJJbnRvRG9jdW1lbnQoXG4gICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KEZvcm1zeS5Gb3JtLCB7dXJsOiBcIi91c2Vyc1wiLCBvblN1Ym1pdHRlZDogb25TdWJtaXR0ZWR9XG4gICAgICApXG4gICAgKTtcbiAgICBcbiAgICBqYXNtaW5lLkFqYXguc3R1YlJlcXVlc3QoJy91c2VycycpLmFuZFJldHVybih7XG4gICAgICBzdGF0dXM6IDUwMCxcbiAgICAgIGNvbnRlbnRUeXBlOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICByZXNwb25zZVRleHQ6ICd7fSdcbiAgICB9KTtcblxuICAgIFRlc3RVdGlscy5TaW11bGF0ZS5zdWJtaXQoZm9ybS5nZXRET01Ob2RlKCkpO1xuXG4gICAgLy8gU2luY2UgYWpheCBpcyByZXR1cm5lZCBhcyBhIHByb21pc2UgKGFzeW5jKSwgbW92ZSBhc3NlcnRpb25cbiAgICAvLyB0byBlbmQgb2YgZXZlbnQgbG9vcFxuICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgZXhwZWN0KG9uU3VibWl0dGVkKS50b0hhdmVCZWVuQ2FsbGVkKCk7XG4gICAgICBkb25lKCk7XG4gICAgfSwgMCk7XG5cbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCB0cmlnZ2VyIGFuIG9uRXJyb3IgaGFuZGxlciwgaWYgcGFzc2VkIGFuZCB0aGUgc3VibWl0IGhhcyByZXNwb25kZWQgd2l0aCBFUlJPUicsIGZ1bmN0aW9uIChkb25lKSB7XG4gICAgXG4gICAgdmFyIG9uRXJyb3IgPSBqYXNtaW5lLmNyZWF0ZVNweShcImVycm9yXCIpO1xuICAgIHZhciBmb3JtID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudChcbiAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRm9ybXN5LkZvcm0sIHt1cmw6IFwiL3VzZXJzXCIsIG9uRXJyb3I6IG9uRXJyb3J9XG4gICAgICApXG4gICAgKTtcbiAgICBcbiAgICAvLyBEbyBub3QgcmV0dXJuIGFueSBlcnJvciBiZWNhdXNlIHRoZXJlIGFyZSBubyBpbnB1dHNcbiAgICBqYXNtaW5lLkFqYXguc3R1YlJlcXVlc3QoJy91c2VycycpLmFuZFJldHVybih7XG4gICAgICBzdGF0dXM6IDUwMCxcbiAgICAgIGNvbnRlbnRUeXBlOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICByZXNwb25zZVRleHQ6ICd7fSdcbiAgICB9KTtcblxuICAgIFRlc3RVdGlscy5TaW11bGF0ZS5zdWJtaXQoZm9ybS5nZXRET01Ob2RlKCkpO1xuXG4gICAgLy8gU2luY2UgYWpheCBpcyByZXR1cm5lZCBhcyBhIHByb21pc2UgKGFzeW5jKSwgbW92ZSBhc3NlcnRpb25cbiAgICAvLyB0byBlbmQgb2YgZXZlbnQgbG9vcFxuICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgZXhwZWN0KG9uRXJyb3IpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKHt9KTtcbiAgICAgIGRvbmUoKTtcbiAgICB9LCAwKTtcblxuICB9KTtcblxufSk7XG4iLCJ2YXIgRm9ybXN5ID0gcmVxdWlyZSgnLi8uLi9zcmMvbWFpbi5qcycpO1xuXG5kZXNjcmliZSgnVmFsaWRhdGlvbicsIGZ1bmN0aW9uKCkge1xuXG4gIGl0KCdzaG91bGQgdHJpZ2dlciBhbiBvblZhbGlkIGhhbmRsZXIsIGlmIHBhc3NlZCwgd2hlbiBmb3JtIGlzIHZhbGlkJywgZnVuY3Rpb24gKCkge1xuICAgIFxuICAgIHZhciBvblZhbGlkID0gamFzbWluZS5jcmVhdGVTcHkoJ3ZhbGlkJyk7XG4gICAgdmFyIFRlc3RJbnB1dCA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtkaXNwbGF5TmFtZTogXCJUZXN0SW5wdXRcIixcbiAgICAgIG1peGluczogW0Zvcm1zeS5NaXhpbl0sXG4gICAgICB1cGRhdGVWYWx1ZTogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIHRoaXMuc2V0VmFsdWUoZXZlbnQudGFyZ2V0LnZhbHVlKTtcbiAgICAgIH0sXG4gICAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJpbnB1dFwiLCB7dmFsdWU6IHRoaXMuZ2V0VmFsdWUoKSwgb25DaGFuZ2U6IHRoaXMudXBkYXRlVmFsdWV9KVxuICAgICAgfVxuICAgIH0pO1xuICAgIHZhciBmb3JtID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudChcbiAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRm9ybXN5LkZvcm0sIHtvblZhbGlkOiBvblZhbGlkfSwgXG4gICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoVGVzdElucHV0LCB7bmFtZTogXCJmb29cIiwgcmVxdWlyZWQ6IHRydWV9KVxuICAgICAgKVxuICAgICk7XG5cbiAgICB2YXIgaW5wdXQgPSBUZXN0VXRpbHMuZmluZFJlbmRlcmVkRE9NQ29tcG9uZW50V2l0aFRhZyhmb3JtLCAnSU5QVVQnKTtcbiAgICBUZXN0VXRpbHMuU2ltdWxhdGUuY2hhbmdlKGlucHV0LCB7dGFyZ2V0OiB7dmFsdWU6ICdmb28nfX0pO1xuICAgIGV4cGVjdChvblZhbGlkKS50b0hhdmVCZWVuQ2FsbGVkKCk7XG5cbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCB0cmlnZ2VyIGFuIG9uSW52YWxpZCBoYW5kbGVyLCBpZiBwYXNzZWQsIHdoZW4gZm9ybSBpcyBpbnZhbGlkJywgZnVuY3Rpb24gKCkge1xuICAgIFxuICAgIHZhciBvbkludmFsaWQgPSBqYXNtaW5lLmNyZWF0ZVNweSgnaW52YWxpZCcpO1xuICAgIHZhciBUZXN0SW5wdXQgPSBSZWFjdC5jcmVhdGVDbGFzcyh7ZGlzcGxheU5hbWU6IFwiVGVzdElucHV0XCIsXG4gICAgICBtaXhpbnM6IFtGb3Jtc3kuTWl4aW5dLFxuICAgICAgdXBkYXRlVmFsdWU6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICB0aGlzLnNldFZhbHVlKGV2ZW50LnRhcmdldC52YWx1ZSk7XG4gICAgICB9LFxuICAgICAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBSZWFjdC5jcmVhdGVFbGVtZW50KFwiaW5wdXRcIiwge3ZhbHVlOiB0aGlzLmdldFZhbHVlKCksIG9uQ2hhbmdlOiB0aGlzLnVwZGF0ZVZhbHVlfSlcbiAgICAgIH1cbiAgICB9KTtcbiAgICB2YXIgZm9ybSA9IFRlc3RVdGlscy5yZW5kZXJJbnRvRG9jdW1lbnQoXG4gICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KEZvcm1zeS5Gb3JtLCB7b25WYWxpZDogb25JbnZhbGlkfSwgXG4gICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoVGVzdElucHV0LCB7bmFtZTogXCJmb29cIiwgdmFsdWU6IFwiZm9vXCJ9KVxuICAgICAgKVxuICAgICk7XG5cbiAgICB2YXIgaW5wdXQgPSBUZXN0VXRpbHMuZmluZFJlbmRlcmVkRE9NQ29tcG9uZW50V2l0aFRhZyhmb3JtLCAnSU5QVVQnKTtcbiAgICBUZXN0VXRpbHMuU2ltdWxhdGUuY2hhbmdlKGlucHV0LCB7dGFyZ2V0OiB7dmFsdWU6ICcnfX0pO1xuICAgIGV4cGVjdChvbkludmFsaWQpLnRvSGF2ZUJlZW5DYWxsZWQoKTtcblxuICB9KTtcblxuICBpdCgnUlVMRTogaXNFbWFpbCcsIGZ1bmN0aW9uICgpIHtcbiAgICBcbiAgICB2YXIgaXNWYWxpZCA9IGphc21pbmUuY3JlYXRlU3B5KCd2YWxpZCcpO1xuICAgIHZhciBUZXN0SW5wdXQgPSBSZWFjdC5jcmVhdGVDbGFzcyh7ZGlzcGxheU5hbWU6IFwiVGVzdElucHV0XCIsXG4gICAgICBtaXhpbnM6IFtGb3Jtc3kuTWl4aW5dLFxuICAgICAgdXBkYXRlVmFsdWU6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICB0aGlzLnNldFZhbHVlKGV2ZW50LnRhcmdldC52YWx1ZSk7XG4gICAgICB9LFxuICAgICAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICh0aGlzLmlzVmFsaWQoKSkge1xuICAgICAgICAgIGlzVmFsaWQoKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gUmVhY3QuY3JlYXRlRWxlbWVudChcImlucHV0XCIsIHt2YWx1ZTogdGhpcy5nZXRWYWx1ZSgpLCBvbkNoYW5nZTogdGhpcy51cGRhdGVWYWx1ZX0pXG4gICAgICB9XG4gICAgfSk7XG4gICAgdmFyIGZvcm0gPSBUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50KFxuICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChGb3Jtc3kuRm9ybSwgbnVsbCwgXG4gICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoVGVzdElucHV0LCB7bmFtZTogXCJmb29cIiwgdmFsdWU6IFwiZm9vXCIsIHZhbGlkYXRpb25zOiBcImlzRW1haWxcIn0pXG4gICAgICApXG4gICAgKTtcblxuICAgIHZhciBpbnB1dCA9IFRlc3RVdGlscy5maW5kUmVuZGVyZWRET01Db21wb25lbnRXaXRoVGFnKGZvcm0sICdJTlBVVCcpO1xuICAgIGV4cGVjdChpc1ZhbGlkKS5ub3QudG9IYXZlQmVlbkNhbGxlZCgpO1xuICAgIFRlc3RVdGlscy5TaW11bGF0ZS5jaGFuZ2UoaW5wdXQsIHt0YXJnZXQ6IHt2YWx1ZTogJ2Zvb0Bmb28uY29tJ319KTtcbiAgICBleHBlY3QoaXNWYWxpZCkudG9IYXZlQmVlbkNhbGxlZCgpO1xuXG4gIH0pO1xuXG4gIGl0KCdSVUxFOiBpc051bWVyaWMnLCBmdW5jdGlvbiAoKSB7XG4gICAgXG4gICAgdmFyIGlzVmFsaWQgPSBqYXNtaW5lLmNyZWF0ZVNweSgndmFsaWQnKTtcbiAgICB2YXIgVGVzdElucHV0ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIlRlc3RJbnB1dFwiLFxuICAgICAgbWl4aW5zOiBbRm9ybXN5Lk1peGluXSxcbiAgICAgIHVwZGF0ZVZhbHVlOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgdGhpcy5zZXRWYWx1ZShldmVudC50YXJnZXQudmFsdWUpO1xuICAgICAgfSxcbiAgICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAodGhpcy5pc1ZhbGlkKCkpIHtcbiAgICAgICAgICBpc1ZhbGlkKCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJpbnB1dFwiLCB7dmFsdWU6IHRoaXMuZ2V0VmFsdWUoKSwgb25DaGFuZ2U6IHRoaXMudXBkYXRlVmFsdWV9KVxuICAgICAgfVxuICAgIH0pO1xuICAgIHZhciBmb3JtID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudChcbiAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoRm9ybXN5LkZvcm0sIG51bGwsIFxuICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFRlc3RJbnB1dCwge25hbWU6IFwiZm9vXCIsIHZhbHVlOiBcImZvb1wiLCB2YWxpZGF0aW9uczogXCJpc051bWVyaWNcIn0pXG4gICAgICApXG4gICAgKTtcblxuICAgIHZhciBpbnB1dCA9IFRlc3RVdGlscy5maW5kUmVuZGVyZWRET01Db21wb25lbnRXaXRoVGFnKGZvcm0sICdJTlBVVCcpO1xuICAgIGV4cGVjdChpc1ZhbGlkKS5ub3QudG9IYXZlQmVlbkNhbGxlZCgpO1xuICAgIFRlc3RVdGlscy5TaW11bGF0ZS5jaGFuZ2UoaW5wdXQsIHt0YXJnZXQ6IHt2YWx1ZTogJzEyMyd9fSk7XG4gICAgZXhwZWN0KGlzVmFsaWQpLnRvSGF2ZUJlZW5DYWxsZWQoKTtcblxuICB9KTtcblxuICBpdCgnUlVMRTogaXNOdW1lcmljIChhY3R1YWwgbnVtYmVyKScsIGZ1bmN0aW9uICgpIHtcbiAgICBcbiAgICB2YXIgaXNWYWxpZCA9IGphc21pbmUuY3JlYXRlU3B5KCd2YWxpZCcpO1xuICAgIHZhciBUZXN0SW5wdXQgPSBSZWFjdC5jcmVhdGVDbGFzcyh7ZGlzcGxheU5hbWU6IFwiVGVzdElucHV0XCIsXG4gICAgICBtaXhpbnM6IFtGb3Jtc3kuTWl4aW5dLFxuICAgICAgdXBkYXRlVmFsdWU6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICB0aGlzLnNldFZhbHVlKE51bWJlcihldmVudC50YXJnZXQudmFsdWUpKTtcbiAgICAgIH0sXG4gICAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKHRoaXMuaXNWYWxpZCgpKSB7XG4gICAgICAgICAgaXNWYWxpZCgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBSZWFjdC5jcmVhdGVFbGVtZW50KFwiaW5wdXRcIiwge3ZhbHVlOiB0aGlzLmdldFZhbHVlKCksIG9uQ2hhbmdlOiB0aGlzLnVwZGF0ZVZhbHVlfSlcbiAgICAgIH1cbiAgICB9KTtcbiAgICB2YXIgZm9ybSA9IFRlc3RVdGlscy5yZW5kZXJJbnRvRG9jdW1lbnQoXG4gICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KEZvcm1zeS5Gb3JtLCBudWxsLCBcbiAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChUZXN0SW5wdXQsIHtuYW1lOiBcImZvb1wiLCB2YWx1ZTogXCJmb29cIiwgdmFsaWRhdGlvbnM6IFwiaXNOdW1lcmljXCJ9KVxuICAgICAgKVxuICAgICk7XG5cbiAgICB2YXIgaW5wdXQgPSBUZXN0VXRpbHMuZmluZFJlbmRlcmVkRE9NQ29tcG9uZW50V2l0aFRhZyhmb3JtLCAnSU5QVVQnKTtcbiAgICBleHBlY3QoaXNWYWxpZCkubm90LnRvSGF2ZUJlZW5DYWxsZWQoKTtcbiAgICBUZXN0VXRpbHMuU2ltdWxhdGUuY2hhbmdlKGlucHV0LCB7dGFyZ2V0OiB7dmFsdWU6ICcxMjMnfX0pO1xuICAgIGV4cGVjdChpc1ZhbGlkKS50b0hhdmVCZWVuQ2FsbGVkKCk7XG5cbiAgfSk7XG5cbn0pO1xuIiwidmFyIFJlYWN0ID0gZ2xvYmFsLlJlYWN0IHx8IHJlcXVpcmUoJ3JlYWN0Jyk7XG52YXIgRm9ybXN5ID0ge307XG52YXIgdmFsaWRhdGlvblJ1bGVzID0ge1xuICAnaXNWYWx1ZSc6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgIHJldHVybiB2YWx1ZSAhPT0gJyc7XG4gIH0sXG4gICdpc0VtYWlsJzogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgcmV0dXJuIHZhbHVlLm1hdGNoKC9eKCgoW2Etel18XFxkfFshI1xcJCUmJ1xcKlxcK1xcLVxcLz1cXD9cXF5fYHtcXHx9fl18W1xcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0pKyhcXC4oW2Etel18XFxkfFshI1xcJCUmJ1xcKlxcK1xcLVxcLz1cXD9cXF5fYHtcXHx9fl18W1xcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0pKykqKXwoKFxceDIyKSgoKChcXHgyMHxcXHgwOSkqKFxceDBkXFx4MGEpKT8oXFx4MjB8XFx4MDkpKyk/KChbXFx4MDEtXFx4MDhcXHgwYlxceDBjXFx4MGUtXFx4MWZcXHg3Zl18XFx4MjF8W1xceDIzLVxceDViXXxbXFx4NWQtXFx4N2VdfFtcXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZdKXwoXFxcXChbXFx4MDEtXFx4MDlcXHgwYlxceDBjXFx4MGQtXFx4N2ZdfFtcXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZdKSkpKSooKChcXHgyMHxcXHgwOSkqKFxceDBkXFx4MGEpKT8oXFx4MjB8XFx4MDkpKyk/KFxceDIyKSkpQCgoKFthLXpdfFxcZHxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSl8KChbYS16XXxcXGR8W1xcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0pKFthLXpdfFxcZHwtfFxcLnxffH58W1xcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0pKihbYS16XXxcXGR8W1xcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0pKSlcXC4pKygoW2Etel18W1xcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0pfCgoW2Etel18W1xcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0pKFthLXpdfFxcZHwtfFxcLnxffH58W1xcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0pKihbYS16XXxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSkpKSQvaSk7XG4gIH0sXG4gICdpc1RydWUnOiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICByZXR1cm4gdmFsdWUgPT09IHRydWU7XG4gIH0sXG4gICdpc051bWVyaWMnOiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnbnVtYmVyJykge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiB2YWx1ZS5tYXRjaCgvXi0/WzAtOV0rJC8pO1xuICAgIH1cbiAgfSxcbiAgJ2lzQWxwaGEnOiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICByZXR1cm4gdmFsdWUubWF0Y2goL15bYS16QS1aXSskLyk7XG4gIH0sXG4gICdpc1dvcmRzJzogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgcmV0dXJuIHZhbHVlLm1hdGNoKC9eW2EtekEtWlxcc10rJC8pO1xuICB9LFxuICAnaXNTcGVjaWFsV29yZHMnOiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICByZXR1cm4gdmFsdWUubWF0Y2goL15bYS16QS1aXFxzXFx1MDBDMC1cXHUwMTdGXSskLyk7XG4gIH0sXG4gIGlzTGVuZ3RoOiBmdW5jdGlvbiAodmFsdWUsIG1pbiwgbWF4KSB7XG4gICAgaWYgKG1heCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICByZXR1cm4gdmFsdWUubGVuZ3RoID49IG1pbiAmJiB2YWx1ZS5sZW5ndGggPD0gbWF4O1xuICAgIH1cbiAgICByZXR1cm4gdmFsdWUubGVuZ3RoID49IG1pbjtcbiAgfSxcbiAgZXF1YWxzOiBmdW5jdGlvbiAodmFsdWUsIGVxbCkge1xuICAgIHJldHVybiB2YWx1ZSA9PSBlcWw7XG4gIH0sXG4gIGVxdWFsc0ZpZWxkOiBmdW5jdGlvbiAodmFsdWUsIGZpZWxkKSB7XG4gICAgcmV0dXJuIHZhbHVlID09PSB0aGlzW2ZpZWxkXTtcbiAgfVxufTtcblxudmFyIHRvVVJMRW5jb2RlZCA9IGZ1bmN0aW9uIChlbGVtZW50LCBrZXksIGxpc3QpIHtcbiAgdmFyIGxpc3QgPSBsaXN0IHx8IFtdO1xuICBpZiAodHlwZW9mIChlbGVtZW50KSA9PSAnb2JqZWN0Jykge1xuICAgIGZvciAodmFyIGlkeCBpbiBlbGVtZW50KVxuICAgICAgdG9VUkxFbmNvZGVkKGVsZW1lbnRbaWR4XSwga2V5ID8ga2V5ICsgJ1snICsgaWR4ICsgJ10nIDogaWR4LCBsaXN0KTtcbiAgfSBlbHNlIHtcbiAgICBsaXN0LnB1c2goa2V5ICsgJz0nICsgZW5jb2RlVVJJQ29tcG9uZW50KGVsZW1lbnQpKTtcbiAgfVxuICByZXR1cm4gbGlzdC5qb2luKCcmJyk7XG59O1xuXG52YXIgcmVxdWVzdCA9IGZ1bmN0aW9uIChtZXRob2QsIHVybCwgZGF0YSwgY29udGVudFR5cGUsIGhlYWRlcnMpIHtcblxuICB2YXIgY29udGVudFR5cGUgPSBjb250ZW50VHlwZSA9PT0gJ3VybGVuY29kZWQnID8gJ2FwcGxpY2F0aW9uLycgKyBjb250ZW50VHlwZS5yZXBsYWNlKCd1cmxlbmNvZGVkJywgJ3gtd3d3LWZvcm0tdXJsZW5jb2RlZCcpIDogJ2FwcGxpY2F0aW9uL2pzb24nO1xuICBkYXRhID0gY29udGVudFR5cGUgPT09ICdhcHBsaWNhdGlvbi9qc29uJyA/IEpTT04uc3RyaW5naWZ5KGRhdGEpIDogdG9VUkxFbmNvZGVkKGRhdGEpO1xuXG4gIHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbiAocmVzb2x2ZSwgcmVqZWN0KSB7XG4gICAgdHJ5IHtcbiAgICAgIHZhciB4aHIgPSBuZXcgWE1MSHR0cFJlcXVlc3QoKTtcbiAgICAgIHhoci5vcGVuKG1ldGhvZCwgdXJsLCB0cnVlKTtcbiAgICAgIHhoci5zZXRSZXF1ZXN0SGVhZGVyKCdBY2NlcHQnLCAnYXBwbGljYXRpb24vanNvbicpO1xuICAgICAgeGhyLnNldFJlcXVlc3RIZWFkZXIoJ0NvbnRlbnQtVHlwZScsIGNvbnRlbnRUeXBlKTtcblxuICAgICAgLy8gQWRkIHBhc3NlZCBoZWFkZXJzXG4gICAgICBPYmplY3Qua2V5cyhoZWFkZXJzKS5mb3JFYWNoKGZ1bmN0aW9uIChoZWFkZXIpIHtcbiAgICAgICAgeGhyLnNldFJlcXVlc3RIZWFkZXIoaGVhZGVyLCBoZWFkZXJzW2hlYWRlcl0pO1xuICAgICAgfSk7XG5cbiAgICAgIHhoci5vbnJlYWR5c3RhdGVjaGFuZ2UgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICh4aHIucmVhZHlTdGF0ZSA9PT0gNCkge1xuXG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHZhciByZXNwb25zZSA9IHhoci5yZXNwb25zZVRleHQgPyBKU09OLnBhcnNlKHhoci5yZXNwb25zZVRleHQpIDogbnVsbDtcbiAgICAgICAgICAgIGlmICh4aHIuc3RhdHVzID49IDIwMCAmJiB4aHIuc3RhdHVzIDwgMzAwKSB7XG4gICAgICAgICAgICAgIHJlc29sdmUocmVzcG9uc2UpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgcmVqZWN0KHJlc3BvbnNlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICByZWplY3QoZSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgICB4aHIuc2VuZChkYXRhKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICByZWplY3QoZSk7XG4gICAgfVxuICB9KTtcblxufTtcblxudmFyIGFycmF5c0RpZmZlciA9IGZ1bmN0aW9uIChhcnJheUEsIGFycmF5Qikge1xuICB2YXIgaXNEaWZmZXJlbnQgPSBmYWxzZTtcbiAgaWYgKGFycmF5QS5sZW5ndGggIT09IGFycmF5Qi5sZW5ndGgpIHtcbiAgICBpc0RpZmZlcmVudCA9IHRydWU7XG4gIH0gZWxzZSB7XG4gICAgYXJyYXlBLmZvckVhY2goZnVuY3Rpb24gKGl0ZW0sIGluZGV4KSB7XG4gICAgICBpZiAoaXRlbSAhPT0gYXJyYXlCW2luZGV4XSkge1xuICAgICAgICBpc0RpZmZlcmVudCA9IHRydWU7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cbiAgcmV0dXJuIGlzRGlmZmVyZW50O1xufTtcblxudmFyIGFqYXggPSB7XG4gIHBvc3Q6IHJlcXVlc3QuYmluZChudWxsLCAnUE9TVCcpLFxuICBwdXQ6IHJlcXVlc3QuYmluZChudWxsLCAnUFVUJylcbn07XG52YXIgb3B0aW9ucyA9IHt9O1xuXG5Gb3Jtc3kuZGVmYXVsdHMgPSBmdW5jdGlvbiAocGFzc2VkT3B0aW9ucykge1xuICBvcHRpb25zID0gcGFzc2VkT3B0aW9ucztcbn07XG5cbkZvcm1zeS5NaXhpbiA9IHtcbiAgZ2V0SW5pdGlhbFN0YXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIF92YWx1ZTogdGhpcy5wcm9wcy52YWx1ZSA/IHRoaXMucHJvcHMudmFsdWUgOiAnJyxcbiAgICAgIF9pc1ZhbGlkOiB0cnVlLFxuICAgICAgX2lzUHJpc3RpbmU6IHRydWVcbiAgICB9O1xuICB9LFxuICBjb21wb25lbnRXaWxsTW91bnQ6IGZ1bmN0aW9uICgpIHtcblxuICAgIHZhciBjb25maWd1cmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAvLyBBZGQgdmFsaWRhdGlvbnMgdG8gdGhlIHN0b3JlIGl0c2VsZiBhcyB0aGUgcHJvcHMgb2JqZWN0IGNhbiBub3QgYmUgbW9kaWZpZWRcbiAgICAgIHRoaXMuX3ZhbGlkYXRpb25zID0gdGhpcy5wcm9wcy52YWxpZGF0aW9ucyB8fCAnJztcblxuICAgICAgaWYgKHRoaXMucHJvcHMucmVxdWlyZWQpIHtcbiAgICAgICAgdGhpcy5fdmFsaWRhdGlvbnMgPSB0aGlzLnByb3BzLnZhbGlkYXRpb25zID8gdGhpcy5wcm9wcy52YWxpZGF0aW9ucyArICcsJyA6ICcnO1xuICAgICAgICB0aGlzLl92YWxpZGF0aW9ucyArPSAnaXNWYWx1ZSc7XG4gICAgICB9XG4gICAgICB0aGlzLnByb3BzLl9hdHRhY2hUb0Zvcm0odGhpcyk7XG4gICAgfS5iaW5kKHRoaXMpO1xuXG4gICAgaWYgKCF0aGlzLnByb3BzLm5hbWUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRm9ybSBJbnB1dCByZXF1aXJlcyBhIG5hbWUgcHJvcGVydHkgd2hlbiB1c2VkJyk7XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLnByb3BzLl9hdHRhY2hUb0Zvcm0pIHtcbiAgICAgIHJldHVybiBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKCF0aGlzLnByb3BzLl9hdHRhY2hUb0Zvcm0pIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Zvcm0gTWl4aW4gcmVxdWlyZXMgY29tcG9uZW50IHRvIGJlIG5lc3RlZCBpbiBhIEZvcm0nKTtcbiAgICAgICAgfVxuICAgICAgICBjb25maWd1cmUoKTtcbiAgICAgIH0uYmluZCh0aGlzKSwgMCk7XG4gICAgfVxuICAgIGNvbmZpZ3VyZSgpO1xuXG4gIH0sXG5cbiAgLy8gV2UgaGF2ZSB0byBtYWtlIHRoZSB2YWxpZGF0ZSBtZXRob2QgaXMga2VwdCB3aGVuIG5ldyBwcm9wcyBhcmUgYWRkZWRcbiAgY29tcG9uZW50V2lsbFJlY2VpdmVQcm9wczogZnVuY3Rpb24gKG5leHRQcm9wcykge1xuICAgIG5leHRQcm9wcy5fYXR0YWNoVG9Gb3JtID0gdGhpcy5wcm9wcy5fYXR0YWNoVG9Gb3JtO1xuICAgIG5leHRQcm9wcy5fZGV0YWNoRnJvbUZvcm0gPSB0aGlzLnByb3BzLl9kZXRhY2hGcm9tRm9ybTtcbiAgICBuZXh0UHJvcHMuX3ZhbGlkYXRlID0gdGhpcy5wcm9wcy5fdmFsaWRhdGU7XG4gIH0sXG5cbiAgLy8gRGV0YWNoIGl0IHdoZW4gY29tcG9uZW50IHVubW91bnRzXG4gIGNvbXBvbmVudFdpbGxVbm1vdW50OiBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5wcm9wcy5fZGV0YWNoRnJvbUZvcm0odGhpcyk7XG4gIH0sXG5cbiAgLy8gV2UgdmFsaWRhdGUgYWZ0ZXIgdGhlIHZhbHVlIGhhcyBiZWVuIHNldFxuICBzZXRWYWx1ZTogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICBfdmFsdWU6IHZhbHVlLFxuICAgICAgX2lzUHJpc3RpbmU6IGZhbHNlXG4gICAgfSwgZnVuY3Rpb24gKCkge1xuICAgICAgdGhpcy5wcm9wcy5fdmFsaWRhdGUodGhpcyk7XG4gICAgfS5iaW5kKHRoaXMpKTtcbiAgfSxcbiAgcmVzZXRWYWx1ZTogZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgX3ZhbHVlOiAnJyxcbiAgICAgIF9pc1ByaXN0aW5lOiB0cnVlXG4gICAgfSwgZnVuY3Rpb24gKCkge1xuICAgICAgdGhpcy5wcm9wcy5fdmFsaWRhdGUodGhpcyk7XG4gICAgfSk7XG4gIH0sXG4gIGdldFZhbHVlOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuc3RhdGUuX3ZhbHVlO1xuICB9LFxuICBoYXNWYWx1ZTogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLnN0YXRlLl92YWx1ZSAhPT0gJyc7XG4gIH0sXG4gIGdldEVycm9yTWVzc2FnZTogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLmlzVmFsaWQoKSB8fCB0aGlzLnNob3dSZXF1aXJlZCgpID8gbnVsbCA6IHRoaXMuc3RhdGUuX3NlcnZlckVycm9yIHx8IHRoaXMucHJvcHMudmFsaWRhdGlvbkVycm9yO1xuICB9LFxuICBpc1ZhbGlkOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuc3RhdGUuX2lzVmFsaWQ7XG4gIH0sXG4gIGlzUHJpc3RpbmU6IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5zdGF0ZS5faXNQcmlzdGluZTtcbiAgfSxcbiAgaXNSZXF1aXJlZDogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiAhIXRoaXMucHJvcHMucmVxdWlyZWQ7XG4gIH0sXG4gIHNob3dSZXF1aXJlZDogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLmlzUmVxdWlyZWQoKSAmJiB0aGlzLnN0YXRlLl92YWx1ZSA9PT0gJyc7XG4gIH0sXG4gIHNob3dFcnJvcjogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiAhdGhpcy5zaG93UmVxdWlyZWQoKSAmJiAhdGhpcy5zdGF0ZS5faXNWYWxpZDtcbiAgfVxufTtcblxuRm9ybXN5LmFkZFZhbGlkYXRpb25SdWxlID0gZnVuY3Rpb24gKG5hbWUsIGZ1bmMpIHtcbiAgdmFsaWRhdGlvblJ1bGVzW25hbWVdID0gZnVuYztcbn07XG5cbkZvcm1zeS5Gb3JtID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiBcIkZvcm1cIixcbiAgZ2V0SW5pdGlhbFN0YXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGlzVmFsaWQ6IHRydWUsXG4gICAgICBpc1N1Ym1pdHRpbmc6IGZhbHNlLFxuICAgICAgY2FuQ2hhbmdlOiBmYWxzZVxuICAgIH07XG4gIH0sXG4gIGdldERlZmF1bHRQcm9wczogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB7XG4gICAgICBoZWFkZXJzOiB7fSxcbiAgICAgIG9uU3VjY2VzczogZnVuY3Rpb24gKCkge30sXG4gICAgICBvbkVycm9yOiBmdW5jdGlvbiAoKSB7fSxcbiAgICAgIG9uU3VibWl0OiBmdW5jdGlvbiAoKSB7fSxcbiAgICAgIG9uU3VibWl0dGVkOiBmdW5jdGlvbiAoKSB7fSxcbiAgICAgIG9uVmFsaWQ6IGZ1bmN0aW9uICgpIHt9LFxuICAgICAgb25JbnZhbGlkOiBmdW5jdGlvbiAoKSB7fSxcbiAgICAgIG9uQ2hhbmdlOiBmdW5jdGlvbiAoKSB7fVxuICAgIH07XG4gIH0sXG5cbiAgLy8gQWRkIGEgbWFwIHRvIHN0b3JlIHRoZSBpbnB1dHMgb2YgdGhlIGZvcm0sIGEgbW9kZWwgdG8gc3RvcmVcbiAgLy8gdGhlIHZhbHVlcyBvZiB0aGUgZm9ybSBhbmQgcmVnaXN0ZXIgY2hpbGQgaW5wdXRzXG4gIGNvbXBvbmVudFdpbGxNb3VudDogZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuaW5wdXRzID0ge307XG4gICAgdGhpcy5tb2RlbCA9IHt9O1xuICAgIHRoaXMucmVnaXN0ZXJJbnB1dHModGhpcy5wcm9wcy5jaGlsZHJlbik7XG4gIH0sXG5cbiAgY29tcG9uZW50RGlkTW91bnQ6IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnZhbGlkYXRlRm9ybSgpO1xuICB9LFxuXG4gIGNvbXBvbmVudFdpbGxVcGRhdGU6IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgaW5wdXRLZXlzID0gT2JqZWN0LmtleXModGhpcy5pbnB1dHMpO1xuXG4gICAgLy8gVGhlIHVwZGF0ZWQgY2hpbGRyZW4gYXJyYXkgaXMgbm90IGF2YWlsYWJsZSBoZXJlIGZvciBzb21lIHJlYXNvbixcbiAgICAvLyB3ZSBuZWVkIHRvIHdhaXQgZm9yIG5leHQgZXZlbnQgbG9vcFxuICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgdGhpcy5yZWdpc3RlcklucHV0cyh0aGlzLnByb3BzLmNoaWxkcmVuKTtcblxuICAgICAgdmFyIG5ld0lucHV0S2V5cyA9IE9iamVjdC5rZXlzKHRoaXMuaW5wdXRzKTtcbiAgICAgIGlmIChhcnJheXNEaWZmZXIoaW5wdXRLZXlzLCBuZXdJbnB1dEtleXMpKSB7XG4gICAgICAgIHRoaXMudmFsaWRhdGVGb3JtKCk7XG4gICAgICB9XG4gICAgfS5iaW5kKHRoaXMpLCAwKTtcbiAgfSxcblxuICAvLyBVcGRhdGUgbW9kZWwsIHN1Ym1pdCB0byB1cmwgcHJvcCBhbmQgc2VuZCB0aGUgbW9kZWxcbiAgc3VibWl0OiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG4gICAgLy8gVHJpZ2dlciBmb3JtIGFzIG5vdCBwcmlzdGluZS5cbiAgICAvLyBJZiBhbnkgaW5wdXRzIGhhdmUgbm90IGJlZW4gdG91Y2hlZCB5ZXQgdGhpcyB3aWxsIG1ha2UgdGhlbSBkaXJ0eVxuICAgIC8vIHNvIHZhbGlkYXRpb24gYmVjb21lcyB2aXNpYmxlIChpZiBiYXNlZCBvbiBpc1ByaXN0aW5lKVxuICAgIHRoaXMuc2V0Rm9ybVByaXN0aW5lKGZhbHNlKTtcblxuICAgIC8vIFRvIHN1cHBvcnQgdXNlIGNhc2VzIHdoZXJlIG5vIGFzeW5jIG9yIHJlcXVlc3Qgb3BlcmF0aW9uIGlzIG5lZWRlZC5cbiAgICAvLyBUaGUgXCJvblN1Ym1pdFwiIGNhbGxiYWNrIGlzIGNhbGxlZCB3aXRoIHRoZSBtb2RlbCBlLmcuIHtmaWVsZE5hbWU6IFwibXlWYWx1ZVwifSxcbiAgICAvLyBpZiB3YW50aW5nIHRvIHJlc2V0IHRoZSBlbnRpcmUgZm9ybSB0byBvcmlnaW5hbCBzdGF0ZSwgdGhlIHNlY29uZCBwYXJhbSBpcyBhIGNhbGxiYWNrIGZvciB0aGlzLlxuICAgIGlmICghdGhpcy5wcm9wcy51cmwpIHtcbiAgICAgIHRoaXMudXBkYXRlTW9kZWwoKTtcbiAgICAgIHRoaXMucHJvcHMub25TdWJtaXQodGhpcy5tYXBNb2RlbCgpLCB0aGlzLnJlc2V0TW9kZWwsIHRoaXMudXBkYXRlSW5wdXRzV2l0aEVycm9yKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLnVwZGF0ZU1vZGVsKCk7XG4gICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICBpc1N1Ym1pdHRpbmc6IHRydWVcbiAgICB9KTtcblxuICAgIHRoaXMucHJvcHMub25TdWJtaXQodGhpcy5tYXBNb2RlbCgpLCB0aGlzLnJlc2V0TW9kZWwsIHRoaXMudXBkYXRlSW5wdXRzV2l0aEVycm9yKTtcblxuICAgIHZhciBoZWFkZXJzID0gKE9iamVjdC5rZXlzKHRoaXMucHJvcHMuaGVhZGVycykubGVuZ3RoICYmIHRoaXMucHJvcHMuaGVhZGVycykgfHwgb3B0aW9ucy5oZWFkZXJzIHx8IHt9O1xuXG4gICAgdmFyIG1ldGhvZCA9IHRoaXMucHJvcHMubWV0aG9kICYmIGFqYXhbdGhpcy5wcm9wcy5tZXRob2QudG9Mb3dlckNhc2UoKV0gPyB0aGlzLnByb3BzLm1ldGhvZC50b0xvd2VyQ2FzZSgpIDogJ3Bvc3QnO1xuICAgIGFqYXhbbWV0aG9kXSh0aGlzLnByb3BzLnVybCwgdGhpcy5tYXBNb2RlbCgpLCB0aGlzLnByb3BzLmNvbnRlbnRUeXBlIHx8IG9wdGlvbnMuY29udGVudFR5cGUgfHwgJ2pzb24nLCBoZWFkZXJzKVxuICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgIHRoaXMucHJvcHMub25TdWNjZXNzKHJlc3BvbnNlKTtcbiAgICAgICAgdGhpcy5wcm9wcy5vblN1Ym1pdHRlZCgpO1xuICAgICAgfS5iaW5kKHRoaXMpKVxuICAgICAgLmNhdGNoKHRoaXMuZmFpbFN1Ym1pdCk7XG4gIH0sXG5cbiAgbWFwTW9kZWw6IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5wcm9wcy5tYXBwaW5nID8gdGhpcy5wcm9wcy5tYXBwaW5nKHRoaXMubW9kZWwpIDogdGhpcy5tb2RlbDtcbiAgfSxcblxuICAvLyBHb2VzIHRocm91Z2ggYWxsIHJlZ2lzdGVyZWQgY29tcG9uZW50cyBhbmRcbiAgLy8gdXBkYXRlcyB0aGUgbW9kZWwgdmFsdWVzXG4gIHVwZGF0ZU1vZGVsOiBmdW5jdGlvbiAoKSB7XG4gICAgT2JqZWN0LmtleXModGhpcy5pbnB1dHMpLmZvckVhY2goZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAgIHZhciBjb21wb25lbnQgPSB0aGlzLmlucHV0c1tuYW1lXTtcbiAgICAgIHRoaXMubW9kZWxbbmFtZV0gPSBjb21wb25lbnQuc3RhdGUuX3ZhbHVlO1xuICAgIH0uYmluZCh0aGlzKSk7XG4gIH0sXG5cbiAgLy8gUmVzZXQgZWFjaCBrZXkgaW4gdGhlIG1vZGVsIHRvIHRoZSBvcmlnaW5hbCAvIGluaXRpYWwgdmFsdWVcbiAgcmVzZXRNb2RlbDogZnVuY3Rpb24gKCkge1xuICAgIE9iamVjdC5rZXlzKHRoaXMuaW5wdXRzKS5mb3JFYWNoKGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgICB0aGlzLmlucHV0c1tuYW1lXS5yZXNldFZhbHVlKCk7XG4gICAgfS5iaW5kKHRoaXMpKTtcbiAgICB0aGlzLnZhbGlkYXRlRm9ybSgpO1xuICB9LFxuXG4gIC8vIEdvIHRocm91Z2ggZXJyb3JzIGZyb20gc2VydmVyIGFuZCBncmFiIHRoZSBjb21wb25lbnRzXG4gIC8vIHN0b3JlZCBpbiB0aGUgaW5wdXRzIG1hcC4gQ2hhbmdlIHRoZWlyIHN0YXRlIHRvIGludmFsaWRcbiAgLy8gYW5kIHNldCB0aGUgc2VydmVyRXJyb3IgbWVzc2FnZVxuICB1cGRhdGVJbnB1dHNXaXRoRXJyb3I6IGZ1bmN0aW9uIChlcnJvcnMpIHtcbiAgICBPYmplY3Qua2V5cyhlcnJvcnMpLmZvckVhY2goZnVuY3Rpb24gKG5hbWUsIGluZGV4KSB7XG4gICAgICB2YXIgY29tcG9uZW50ID0gdGhpcy5pbnB1dHNbbmFtZV07XG5cbiAgICAgIGlmICghY29tcG9uZW50KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignWW91IGFyZSB0cnlpbmcgdG8gdXBkYXRlIGFuIGlucHV0IHRoYXQgZG9lcyBub3QgZXhpc3RzLiBWZXJpZnkgZXJyb3JzIG9iamVjdCB3aXRoIGlucHV0IG5hbWVzLiAnICsgSlNPTi5zdHJpbmdpZnkoZXJyb3JzKSk7XG4gICAgICB9XG5cbiAgICAgIHZhciBhcmdzID0gW3tcbiAgICAgICAgX2lzVmFsaWQ6IGZhbHNlLFxuICAgICAgICBfc2VydmVyRXJyb3I6IGVycm9yc1tuYW1lXVxuICAgICAgfV07XG4gICAgICBjb21wb25lbnQuc2V0U3RhdGUuYXBwbHkoY29tcG9uZW50LCBhcmdzKTtcbiAgICB9LmJpbmQodGhpcykpO1xuICB9LFxuXG4gIGZhaWxTdWJtaXQ6IGZ1bmN0aW9uIChlcnJvcnMpIHtcbiAgICB0aGlzLnVwZGF0ZUlucHV0c1dpdGhFcnJvcihlcnJvcnMpO1xuICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgaXNTdWJtaXR0aW5nOiBmYWxzZVxuICAgIH0pO1xuICAgIHRoaXMucHJvcHMub25FcnJvcihlcnJvcnMpO1xuICAgIHRoaXMucHJvcHMub25TdWJtaXR0ZWQoKTtcbiAgfSxcblxuICAvLyBUcmF2ZXJzZSB0aGUgY2hpbGRyZW4gYW5kIGNoaWxkcmVuIG9mIGNoaWxkcmVuIHRvIGZpbmRcbiAgLy8gYWxsIGlucHV0cyBieSBjaGVja2luZyB0aGUgbmFtZSBwcm9wLiBNYXliZSBkbyBhIGJldHRlclxuICAvLyBjaGVjayBoZXJlXG4gIHJlZ2lzdGVySW5wdXRzOiBmdW5jdGlvbiAoY2hpbGRyZW4pIHtcbiAgICBSZWFjdC5DaGlsZHJlbi5mb3JFYWNoKGNoaWxkcmVuLCBmdW5jdGlvbiAoY2hpbGQpIHtcblxuICAgICAgaWYgKGNoaWxkLnByb3BzICYmIGNoaWxkLnByb3BzLm5hbWUpIHtcbiAgICAgICAgY2hpbGQucHJvcHMuX2F0dGFjaFRvRm9ybSA9IHRoaXMuYXR0YWNoVG9Gb3JtO1xuICAgICAgICBjaGlsZC5wcm9wcy5fZGV0YWNoRnJvbUZvcm0gPSB0aGlzLmRldGFjaEZyb21Gb3JtO1xuICAgICAgICBjaGlsZC5wcm9wcy5fdmFsaWRhdGUgPSB0aGlzLnZhbGlkYXRlO1xuICAgICAgfVxuXG4gICAgICBpZiAoY2hpbGQucHJvcHMgJiYgY2hpbGQucHJvcHMuY2hpbGRyZW4pIHtcbiAgICAgICAgdGhpcy5yZWdpc3RlcklucHV0cyhjaGlsZC5wcm9wcy5jaGlsZHJlbik7XG4gICAgICB9XG5cbiAgICB9LmJpbmQodGhpcykpO1xuICB9LFxuXG4gIGdldEN1cnJlbnRWYWx1ZXM6IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gT2JqZWN0LmtleXModGhpcy5pbnB1dHMpLnJlZHVjZShmdW5jdGlvbiAoZGF0YSwgbmFtZSkge1xuICAgICAgdmFyIGNvbXBvbmVudCA9IHRoaXMuaW5wdXRzW25hbWVdO1xuICAgICAgZGF0YVtuYW1lXSA9IGNvbXBvbmVudC5zdGF0ZS5fdmFsdWU7XG4gICAgICByZXR1cm4gZGF0YTtcbiAgICB9LmJpbmQodGhpcyksIHt9KTtcbiAgfSxcblxuICBzZXRGb3JtUHJpc3RpbmU6IGZ1bmN0aW9uIChpc1ByaXN0aW5lKSB7XG4gICAgdmFyIGlucHV0cyA9IHRoaXMuaW5wdXRzO1xuICAgIHZhciBpbnB1dEtleXMgPSBPYmplY3Qua2V5cyhpbnB1dHMpO1xuXG4gICAgLy8gSXRlcmF0ZSB0aHJvdWdoIGVhY2ggY29tcG9uZW50IGFuZCBzZXQgaXQgYXMgcHJpc3RpbmVcbiAgICAvLyBvciBcImRpcnR5XCIuXG4gICAgaW5wdXRLZXlzLmZvckVhY2goZnVuY3Rpb24gKG5hbWUsIGluZGV4KSB7XG4gICAgICB2YXIgY29tcG9uZW50ID0gaW5wdXRzW25hbWVdO1xuICAgICAgY29tcG9uZW50LnNldFN0YXRlKHtcbiAgICAgICAgX2lzUHJpc3RpbmU6IGlzUHJpc3RpbmVcbiAgICAgIH0pO1xuICAgIH0uYmluZCh0aGlzKSk7XG4gIH0sXG5cbiAgLy8gVXNlIHRoZSBiaW5kZWQgdmFsdWVzIGFuZCB0aGUgYWN0dWFsIGlucHV0IHZhbHVlIHRvXG4gIC8vIHZhbGlkYXRlIHRoZSBpbnB1dCBhbmQgc2V0IGl0cyBzdGF0ZS4gVGhlbiBjaGVjayB0aGVcbiAgLy8gc3RhdGUgb2YgdGhlIGZvcm0gaXRzZWxmXG4gIHZhbGlkYXRlOiBmdW5jdGlvbiAoY29tcG9uZW50KSB7XG5cbiAgICAvLyBUcmlnZ2VyIG9uQ2hhbmdlXG4gICAgdGhpcy5zdGF0ZS5jYW5DaGFuZ2UgJiYgdGhpcy5wcm9wcy5vbkNoYW5nZSAmJiB0aGlzLnByb3BzLm9uQ2hhbmdlKHRoaXMuZ2V0Q3VycmVudFZhbHVlcygpKTtcblxuICAgIGlmICghY29tcG9uZW50LnByb3BzLnJlcXVpcmVkICYmICFjb21wb25lbnQuX3ZhbGlkYXRpb25zKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gUnVuIHRocm91Z2ggdGhlIHZhbGlkYXRpb25zLCBzcGxpdCB0aGVtIHVwIGFuZCBjYWxsXG4gICAgLy8gdGhlIHZhbGlkYXRvciBJRiB0aGVyZSBpcyBhIHZhbHVlIG9yIGl0IGlzIHJlcXVpcmVkXG4gICAgdmFyIGlzVmFsaWQgPSB0aGlzLnJ1blZhbGlkYXRpb24oY29tcG9uZW50KTtcblxuICAgIGNvbXBvbmVudC5zZXRTdGF0ZSh7XG4gICAgICBfaXNWYWxpZDogaXNWYWxpZCxcbiAgICAgIF9zZXJ2ZXJFcnJvcjogbnVsbFxuICAgIH0sIHRoaXMudmFsaWRhdGVGb3JtKTtcblxuICB9LFxuXG4gIHJ1blZhbGlkYXRpb246IGZ1bmN0aW9uIChjb21wb25lbnQpIHtcbiAgICB2YXIgaXNWYWxpZCA9IHRydWU7XG4gICAgaWYgKGNvbXBvbmVudC5fdmFsaWRhdGlvbnMubGVuZ3RoICYmIChjb21wb25lbnQucHJvcHMucmVxdWlyZWQgfHwgY29tcG9uZW50LnN0YXRlLl92YWx1ZSAhPT0gJycpKSB7XG4gICAgICBjb21wb25lbnQuX3ZhbGlkYXRpb25zLnNwbGl0KCcsJykuZm9yRWFjaChmdW5jdGlvbiAodmFsaWRhdGlvbikge1xuICAgICAgICB2YXIgYXJncyA9IHZhbGlkYXRpb24uc3BsaXQoJzonKTtcbiAgICAgICAgdmFyIHZhbGlkYXRlTWV0aG9kID0gYXJncy5zaGlmdCgpO1xuICAgICAgICBhcmdzID0gYXJncy5tYXAoZnVuY3Rpb24gKGFyZykge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShhcmcpO1xuICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIHJldHVybiBhcmc7IC8vIEl0IGlzIGEgc3RyaW5nIGlmIGl0IGNhbiBub3QgcGFyc2UgaXRcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICBhcmdzID0gW2NvbXBvbmVudC5zdGF0ZS5fdmFsdWVdLmNvbmNhdChhcmdzKTtcbiAgICAgICAgaWYgKCF2YWxpZGF0aW9uUnVsZXNbdmFsaWRhdGVNZXRob2RdKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdGb3Jtc3kgZG9lcyBub3QgaGF2ZSB0aGUgdmFsaWRhdGlvbiBydWxlOiAnICsgdmFsaWRhdGVNZXRob2QpO1xuICAgICAgICB9XG4gICAgICAgIGlmICghdmFsaWRhdGlvblJ1bGVzW3ZhbGlkYXRlTWV0aG9kXS5hcHBseSh0aGlzLmdldEN1cnJlbnRWYWx1ZXMoKSwgYXJncykpIHtcbiAgICAgICAgICBpc1ZhbGlkID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgfVxuICAgIHJldHVybiBpc1ZhbGlkO1xuICB9LFxuXG4gIC8vIFZhbGlkYXRlIHRoZSBmb3JtIGJ5IGdvaW5nIHRocm91Z2ggYWxsIGNoaWxkIGlucHV0IGNvbXBvbmVudHNcbiAgLy8gYW5kIGNoZWNrIHRoZWlyIHN0YXRlXG4gIHZhbGlkYXRlRm9ybTogZnVuY3Rpb24gKCkge1xuICAgIHZhciBhbGxJc1ZhbGlkID0gdHJ1ZTtcbiAgICB2YXIgaW5wdXRzID0gdGhpcy5pbnB1dHM7XG4gICAgdmFyIGlucHV0S2V5cyA9IE9iamVjdC5rZXlzKGlucHV0cyk7XG5cbiAgICAvLyBXZSBuZWVkIGEgY2FsbGJhY2sgYXMgd2UgYXJlIHZhbGlkYXRpbmcgYWxsIGlucHV0cyBhZ2Fpbi4gVGhpcyB3aWxsXG4gICAgLy8gcnVuIHdoZW4gdGhlIGxhc3QgY29tcG9uZW50IGhhcyBzZXQgaXRzIHN0YXRlXG4gICAgdmFyIG9uVmFsaWRhdGlvbkNvbXBsZXRlID0gZnVuY3Rpb24gKCkge1xuICAgICAgaW5wdXRLZXlzLmZvckVhY2goZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAgICAgaWYgKCFpbnB1dHNbbmFtZV0uc3RhdGUuX2lzVmFsaWQpIHtcbiAgICAgICAgICBhbGxJc1ZhbGlkID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgIH0uYmluZCh0aGlzKSk7XG5cbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICBpc1ZhbGlkOiBhbGxJc1ZhbGlkXG4gICAgICB9KTtcblxuICAgICAgYWxsSXNWYWxpZCAmJiB0aGlzLnByb3BzLm9uVmFsaWQoKTtcbiAgICAgICFhbGxJc1ZhbGlkICYmIHRoaXMucHJvcHMub25JbnZhbGlkKCk7XG5cbiAgICAgIC8vIFRlbGwgdGhlIGZvcm0gdGhhdCBpdCBjYW4gc3RhcnQgdG8gdHJpZ2dlciBjaGFuZ2UgZXZlbnRzXG4gICAgICB0aGlzLnNldFN0YXRlKHtjYW5DaGFuZ2U6IHRydWV9KTtcblxuICAgIH0uYmluZCh0aGlzKTtcblxuICAgIC8vIFJ1biB2YWxpZGF0aW9uIGFnYWluIGluIGNhc2UgYWZmZWN0ZWQgYnkgb3RoZXIgaW5wdXRzLiBUaGVcbiAgICAvLyBsYXN0IGNvbXBvbmVudCB2YWxpZGF0ZWQgd2lsbCBydW4gdGhlIG9uVmFsaWRhdGlvbkNvbXBsZXRlIGNhbGxiYWNrXG4gICAgaW5wdXRLZXlzLmZvckVhY2goZnVuY3Rpb24gKG5hbWUsIGluZGV4KSB7XG4gICAgICB2YXIgY29tcG9uZW50ID0gaW5wdXRzW25hbWVdO1xuICAgICAgdmFyIGlzVmFsaWQgPSB0aGlzLnJ1blZhbGlkYXRpb24oY29tcG9uZW50KTtcbiAgICAgIGNvbXBvbmVudC5zZXRTdGF0ZSh7XG4gICAgICAgIF9pc1ZhbGlkOiBpc1ZhbGlkLFxuICAgICAgICBfc2VydmVyRXJyb3I6IG51bGxcbiAgICAgIH0sIGluZGV4ID09PSBpbnB1dEtleXMubGVuZ3RoIC0gMSA/IG9uVmFsaWRhdGlvbkNvbXBsZXRlIDogbnVsbCk7XG4gICAgfS5iaW5kKHRoaXMpKTtcblxuICAgIC8vIElmIHRoZXJlIGFyZSBubyBpbnB1dHMsIGl0IGlzIHJlYWR5IHRvIHRyaWdnZXIgY2hhbmdlIGV2ZW50c1xuICAgIGlmICghaW5wdXRLZXlzLmxlbmd0aCkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7Y2FuQ2hhbmdlOiB0cnVlfSk7XG4gICAgfVxuXG4gIH0sXG5cbiAgLy8gTWV0aG9kIHB1dCBvbiBlYWNoIGlucHV0IGNvbXBvbmVudCB0byByZWdpc3RlclxuICAvLyBpdHNlbGYgdG8gdGhlIGZvcm1cbiAgYXR0YWNoVG9Gb3JtOiBmdW5jdGlvbiAoY29tcG9uZW50KSB7XG4gICAgdGhpcy5pbnB1dHNbY29tcG9uZW50LnByb3BzLm5hbWVdID0gY29tcG9uZW50O1xuICAgIHRoaXMubW9kZWxbY29tcG9uZW50LnByb3BzLm5hbWVdID0gY29tcG9uZW50LnN0YXRlLl92YWx1ZTtcbiAgICB0aGlzLnZhbGlkYXRlKGNvbXBvbmVudCk7XG4gIH0sXG5cbiAgLy8gTWV0aG9kIHB1dCBvbiBlYWNoIGlucHV0IGNvbXBvbmVudCB0byB1bnJlZ2lzdGVyXG4gIC8vIGl0c2VsZiBmcm9tIHRoZSBmb3JtXG4gIGRldGFjaEZyb21Gb3JtOiBmdW5jdGlvbiAoY29tcG9uZW50KSB7XG4gICAgZGVsZXRlIHRoaXMuaW5wdXRzW2NvbXBvbmVudC5wcm9wcy5uYW1lXTtcbiAgICBkZWxldGUgdGhpcy5tb2RlbFtjb21wb25lbnQucHJvcHMubmFtZV07XG4gIH0sXG4gIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuXG4gICAgcmV0dXJuIFJlYWN0LkRPTS5mb3JtKHtcbiAgICAgICAgb25TdWJtaXQ6IHRoaXMuc3VibWl0LFxuICAgICAgICBjbGFzc05hbWU6IHRoaXMucHJvcHMuY2xhc3NOYW1lXG4gICAgICB9LFxuICAgICAgdGhpcy5wcm9wcy5jaGlsZHJlblxuICAgICk7XG5cbiAgfVxufSk7XG5cbmlmICghZ2xvYmFsLmV4cG9ydHMgJiYgIWdsb2JhbC5tb2R1bGUgJiYgKCFnbG9iYWwuZGVmaW5lIHx8ICFnbG9iYWwuZGVmaW5lLmFtZCkpIHtcbiAgZ2xvYmFsLkZvcm1zeSA9IEZvcm1zeTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBGb3Jtc3k7XG4iXX0=
diff --git a/package.json b/package.json
index 0c66004..8930837 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "formsy-react",
- "version": "0.6.0",
+ "version": "0.7.0",
"description": "A form input builder and validator for React JS",
"main": "src/main.js",
"scripts": {
diff --git a/release/formsy-react.js b/release/formsy-react.js
index 71ae0ac..f60b79b 100644
--- a/release/formsy-react.js
+++ b/release/formsy-react.js
@@ -13,7 +13,11 @@ var validationRules = {
return value === true;
},
'isNumeric': function (value) {
- return value.match(/^-?[0-9]+$/)
+ if (typeof value === 'number') {
+ return true;
+ } else {
+ return value.match(/^-?[0-9]+$/);
+ }
},
'isAlpha': function (value) {
return value.match(/^[a-zA-Z]+$/);
@@ -32,6 +36,9 @@ var validationRules = {
},
equals: function (value, eql) {
return value == eql;
+ },
+ equalsField: function (value, field) {
+ return value === this[field];
}
};
@@ -86,6 +93,21 @@ var request = function (method, url, data, contentType, headers) {
});
};
+
+var arraysDiffer = function (arrayA, arrayB) {
+ var isDifferent = false;
+ if (arrayA.length !== arrayB.length) {
+ isDifferent = true;
+ } else {
+ arrayA.forEach(function (item, index) {
+ if (item !== arrayB[index]) {
+ isDifferent = true;
+ }
+ });
+ }
+ return isDifferent;
+};
+
var ajax = {
post: request.bind(null, 'POST'),
put: request.bind(null, 'PUT')
@@ -106,22 +128,31 @@ Formsy.Mixin = {
},
componentWillMount: function () {
+ var configure = function () {
+ // Add validations to the store itself as the props object can not be modified
+ this._validations = this.props.validations || '';
+
+ if (this.props.required) {
+ this._validations = this.props.validations ? this.props.validations + ',' : '';
+ this._validations += 'isValue';
+ }
+ this.props._attachToForm(this);
+ }.bind(this);
+
if (!this.props.name) {
throw new Error('Form Input requires a name property when used');
}
if (!this.props._attachToForm) {
- throw new Error('Form Mixin requires component to be nested in a Form');
+ return setTimeout(function () {
+ if (!this.props._attachToForm) {
+ throw new Error('Form Mixin requires component to be nested in a Form');
+ }
+ configure();
+ }.bind(this), 0);
}
+ configure();
- // Add validations to the store itself as the props object can not be modified
- this._validations = this.props.validations || '';
-
- if (this.props.required) {
- this._validations = this.props.validations ? this.props.validations + ',' : '';
- this._validations += 'isValue';
- }
- this.props._attachToForm(this);
},
// We have to make the validate method is kept when new props are added
@@ -187,7 +218,8 @@ Formsy.Form = React.createClass({displayName: "Form",
getInitialState: function () {
return {
isValid: true,
- isSubmitting: false
+ isSubmitting: false,
+ canChange: false
};
},
getDefaultProps: function () {
@@ -198,7 +230,8 @@ Formsy.Form = React.createClass({displayName: "Form",
onSubmit: function () {},
onSubmitted: function () {},
onValid: function () {},
- onInvalid: function () {}
+ onInvalid: function () {},
+ onChange: function () {}
};
},
@@ -214,6 +247,21 @@ Formsy.Form = React.createClass({displayName: "Form",
this.validateForm();
},
+ componentWillUpdate: function () {
+ var inputKeys = Object.keys(this.inputs);
+
+ // The updated children array is not available here for some reason,
+ // we need to wait for next event loop
+ setTimeout(function () {
+ this.registerInputs(this.props.children);
+
+ var newInputKeys = Object.keys(this.inputs);
+ if (arraysDiffer(inputKeys, newInputKeys)) {
+ this.validateForm();
+ }
+ }.bind(this), 0);
+ },
+
// Update model, submit to url prop and send the model
submit: function (event) {
event.preventDefault();
@@ -326,7 +374,7 @@ Formsy.Form = React.createClass({displayName: "Form",
}.bind(this), {});
},
- setFormPristine: function(isPristine) {
+ setFormPristine: function (isPristine) {
var inputs = this.inputs;
var inputKeys = Object.keys(inputs);
@@ -345,6 +393,9 @@ Formsy.Form = React.createClass({displayName: "Form",
// state of the form itself
validate: function (component) {
+ // Trigger onChange
+ this.state.canChange && this.props.onChange && this.props.onChange(this.getCurrentValues());
+
if (!component.props.required && !component._validations) {
return;
}
@@ -408,6 +459,9 @@ Formsy.Form = React.createClass({displayName: "Form",
allIsValid && this.props.onValid();
!allIsValid && this.props.onInvalid();
+ // Tell the form that it can start to trigger change events
+ this.setState({canChange: true});
+
}.bind(this);
// Run validation again in case affected by other inputs. The
@@ -421,6 +475,11 @@ Formsy.Form = React.createClass({displayName: "Form",
}, index === inputKeys.length - 1 ? onValidationComplete : null);
}.bind(this));
+ // If there are no inputs, it is ready to trigger change events
+ if (!inputKeys.length) {
+ this.setState({canChange: true});
+ }
+
},
// Method put on each input component to register
diff --git a/release/formsy-react.min.js b/release/formsy-react.min.js
index 2f8efb4..1ae4037 100644
--- a/release/formsy-react.min.js
+++ b/release/formsy-react.min.js
@@ -1 +1 @@
-!function t(i,e,n){function s(o,u){if(!e[o]){if(!i[o]){var a="function"==typeof require&&require;if(!u&&a)return a(o,!0);if(r)return r(o,!0);var p=new Error("Cannot find module '"+o+"'");throw p.code="MODULE_NOT_FOUND",p}var h=e[o]={exports:{}};i[o][0].call(h.exports,function(t){var e=i[o][1][t];return s(e?e:t)},h,h.exports,t,i,e,n)}return e[o].exports}for(var r="function"==typeof require&&require,o=0;o=i&&t.length<=e:t.length>=i},equals:function(t,i){return t==i}},o=function(t,i,e){var e=e||[];if("object"==typeof t)for(var n in t)o(t[n],i?i+"["+n+"]":n,e);else e.push(i+"="+encodeURIComponent(t));return e.join("&")},u=function(t,i,e,n,s){var n="urlencoded"===n?"application/"+n.replace("urlencoded","x-www-form-urlencoded"):"application/json";return e="application/json"===n?JSON.stringify(e):o(e),new Promise(function(r,o){try{var u=new XMLHttpRequest;u.open(t,i,!0),u.setRequestHeader("Accept","application/json"),u.setRequestHeader("Content-Type",n),Object.keys(s).forEach(function(t){u.setRequestHeader(t,s[t])}),u.onreadystatechange=function(){if(4===u.readyState)try{var t=u.responseText?JSON.parse(u.responseText):null;u.status>=200&&u.status<300?r(t):o(t)}catch(i){o(i)}},u.send(e)}catch(a){o(a)}})},a={post:u.bind(null,"POST"),put:u.bind(null,"PUT")},p={};s.defaults=function(t){p=t},s.Mixin={getInitialState:function(){return{_value:this.props.value?this.props.value:"",_isValid:!0,_isPristine:!0}},componentWillMount:function(){if(!this.props.name)throw new Error("Form Input requires a name property when used");if(!this.props._attachToForm)throw new Error("Form Mixin requires component to be nested in a Form");this._validations=this.props.validations||"",this.props.required&&(this._validations=this.props.validations?this.props.validations+",":"",this._validations+="isValue"),this.props._attachToForm(this)},componentWillReceiveProps:function(t){t._attachToForm=this.props._attachToForm,t._detachFromForm=this.props._detachFromForm,t._validate=this.props._validate},componentWillUnmount:function(){this.props._detachFromForm(this)},setValue:function(t){this.setState({_value:t,_isPristine:!1},function(){this.props._validate(this)}.bind(this))},resetValue:function(){this.setState({_value:"",_isPristine:!0},function(){this.props._validate(this)})},getValue:function(){return this.state._value},hasValue:function(){return""!==this.state._value},getErrorMessage:function(){return this.isValid()||this.showRequired()?null:this.state._serverError||this.props.validationError},isValid:function(){return this.state._isValid},isPristine:function(){return this.state._isPristine},isRequired:function(){return!!this.props.required},showRequired:function(){return this.isRequired()&&""===this.state._value},showError:function(){return!this.showRequired()&&!this.state._isValid}},s.addValidationRule=function(t,i){r[t]=i},s.Form=n.createClass({displayName:"Form",getInitialState:function(){return{isValid:!0,isSubmitting:!1}},getDefaultProps:function(){return{headers:{},onSuccess:function(){},onError:function(){},onSubmit:function(){},onSubmitted:function(){},onValid:function(){},onInvalid:function(){}}},componentWillMount:function(){this.inputs={},this.model={},this.registerInputs(this.props.children)},componentDidMount:function(){this.validateForm()},submit:function(t){if(t.preventDefault(),this.setFormPristine(!1),!this.props.url)return this.updateModel(),this.props.onSubmit(this.mapModel(),this.resetModel,this.updateInputsWithError),void 0;this.updateModel(),this.setState({isSubmitting:!0}),this.props.onSubmit(this.mapModel(),this.resetModel,this.updateInputsWithError);var i=Object.keys(this.props.headers).length&&this.props.headers||p.headers||{},e=this.props.method&&a[this.props.method.toLowerCase()]?this.props.method.toLowerCase():"post";a[e](this.props.url,this.mapModel(),this.props.contentType||p.contentType||"json",i).then(function(t){this.props.onSuccess(t),this.props.onSubmitted()}.bind(this)).catch(this.failSubmit)},mapModel:function(){return this.props.mapping?this.props.mapping(this.model):this.model},updateModel:function(){Object.keys(this.inputs).forEach(function(t){var i=this.inputs[t];this.model[t]=i.state._value}.bind(this))},resetModel:function(){Object.keys(this.inputs).forEach(function(t){this.inputs[t].resetValue()}.bind(this)),this.validateForm()},updateInputsWithError:function(t){Object.keys(t).forEach(function(i){var e=this.inputs[i];if(!e)throw new Error("You are trying to update an input that does not exists. Verify errors object with input names. "+JSON.stringify(t));var n=[{_isValid:!1,_serverError:t[i]}];e.setState.apply(e,n)}.bind(this))},failSubmit:function(t){this.updateInputsWithError(t),this.setState({isSubmitting:!1}),this.props.onError(t),this.props.onSubmitted()},registerInputs:function(t){n.Children.forEach(t,function(t){t.props&&t.props.name&&(t.props._attachToForm=this.attachToForm,t.props._detachFromForm=this.detachFromForm,t.props._validate=this.validate),t.props&&t.props.children&&this.registerInputs(t.props.children)}.bind(this))},getCurrentValues:function(){return Object.keys(this.inputs).reduce(function(t,i){var e=this.inputs[i];return t[i]=e.state._value,t}.bind(this),{})},setFormPristine:function(t){var i=this.inputs,e=Object.keys(i);e.forEach(function(e){var n=i[e];n.setState({_isPristine:t})}.bind(this))},validate:function(t){if(t.props.required||t._validations){var i=this.runValidation(t);t.setState({_isValid:i,_serverError:null},this.validateForm)}},runValidation:function(t){var i=!0;return t._validations.length&&(t.props.required||""!==t.state._value)&&t._validations.split(",").forEach(function(e){var n=e.split(":"),s=n.shift();if(n=n.map(function(t){try{return JSON.parse(t)}catch(i){return t}}),n=[t.state._value].concat(n),!r[s])throw new Error("Formsy does not have the validation rule: "+s);r[s].apply(this.getCurrentValues(),n)||(i=!1)}.bind(this)),i},validateForm:function(){var t=!0,i=this.inputs,e=Object.keys(i),n=function(){e.forEach(function(e){i[e].state._isValid||(t=!1)}.bind(this)),this.setState({isValid:t}),t&&this.props.onValid(),!t&&this.props.onInvalid()}.bind(this);e.forEach(function(t,s){var r=i[t],o=this.runValidation(r);r.setState({_isValid:o,_serverError:null},s===e.length-1?n:null)}.bind(this))},attachToForm:function(t){this.inputs[t.props.name]=t,this.model[t.props.name]=t.state._value,this.validate(t)},detachFromForm:function(t){delete this.inputs[t.props.name],delete this.model[t.props.name]},render:function(){return n.DOM.form({onSubmit:this.submit,className:this.props.className},this.props.children)}}),e.exports||e.module||e.define&&e.define.amd||(e.Formsy=s),i.exports=s}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{react:"react"}]},{},[1]);
\ No newline at end of file
+!function t(i,e,n){function s(o,u){if(!e[o]){if(!i[o]){var a="function"==typeof require&&require;if(!u&&a)return a(o,!0);if(r)return r(o,!0);var h=new Error("Cannot find module '"+o+"'");throw h.code="MODULE_NOT_FOUND",h}var p=e[o]={exports:{}};i[o][0].call(p.exports,function(t){var e=i[o][1][t];return s(e?e:t)},p,p.exports,t,i,e,n)}return e[o].exports}for(var r="function"==typeof require&&require,o=0;o=i&&t.length<=e:t.length>=i},equals:function(t,i){return t==i},equalsField:function(t,i){return t===this[i]}},o=function(t,i,e){var e=e||[];if("object"==typeof t)for(var n in t)o(t[n],i?i+"["+n+"]":n,e);else e.push(i+"="+encodeURIComponent(t));return e.join("&")},u=function(t,i,e,n,s){var n="urlencoded"===n?"application/"+n.replace("urlencoded","x-www-form-urlencoded"):"application/json";return e="application/json"===n?JSON.stringify(e):o(e),new Promise(function(r,o){try{var u=new XMLHttpRequest;u.open(t,i,!0),u.setRequestHeader("Accept","application/json"),u.setRequestHeader("Content-Type",n),Object.keys(s).forEach(function(t){u.setRequestHeader(t,s[t])}),u.onreadystatechange=function(){if(4===u.readyState)try{var t=u.responseText?JSON.parse(u.responseText):null;u.status>=200&&u.status<300?r(t):o(t)}catch(i){o(i)}},u.send(e)}catch(a){o(a)}})},a=function(t,i){var e=!1;return t.length!==i.length?e=!0:t.forEach(function(t,n){t!==i[n]&&(e=!0)}),e},h={post:u.bind(null,"POST"),put:u.bind(null,"PUT")},p={};s.defaults=function(t){p=t},s.Mixin={getInitialState:function(){return{_value:this.props.value?this.props.value:"",_isValid:!0,_isPristine:!0}},componentWillMount:function(){var t=function(){this._validations=this.props.validations||"",this.props.required&&(this._validations=this.props.validations?this.props.validations+",":"",this._validations+="isValue"),this.props._attachToForm(this)}.bind(this);if(!this.props.name)throw new Error("Form Input requires a name property when used");return this.props._attachToForm?(t(),void 0):setTimeout(function(){if(!this.props._attachToForm)throw new Error("Form Mixin requires component to be nested in a Form");t()}.bind(this),0)},componentWillReceiveProps:function(t){t._attachToForm=this.props._attachToForm,t._detachFromForm=this.props._detachFromForm,t._validate=this.props._validate},componentWillUnmount:function(){this.props._detachFromForm(this)},setValue:function(t){this.setState({_value:t,_isPristine:!1},function(){this.props._validate(this)}.bind(this))},resetValue:function(){this.setState({_value:"",_isPristine:!0},function(){this.props._validate(this)})},getValue:function(){return this.state._value},hasValue:function(){return""!==this.state._value},getErrorMessage:function(){return this.isValid()||this.showRequired()?null:this.state._serverError||this.props.validationError},isValid:function(){return this.state._isValid},isPristine:function(){return this.state._isPristine},isRequired:function(){return!!this.props.required},showRequired:function(){return this.isRequired()&&""===this.state._value},showError:function(){return!this.showRequired()&&!this.state._isValid}},s.addValidationRule=function(t,i){r[t]=i},s.Form=n.createClass({displayName:"Form",getInitialState:function(){return{isValid:!0,isSubmitting:!1,canChange:!1}},getDefaultProps:function(){return{headers:{},onSuccess:function(){},onError:function(){},onSubmit:function(){},onSubmitted:function(){},onValid:function(){},onInvalid:function(){},onChange:function(){}}},componentWillMount:function(){this.inputs={},this.model={},this.registerInputs(this.props.children)},componentDidMount:function(){this.validateForm()},componentWillUpdate:function(){var t=Object.keys(this.inputs);setTimeout(function(){this.registerInputs(this.props.children);var i=Object.keys(this.inputs);a(t,i)&&this.validateForm()}.bind(this),0)},submit:function(t){if(t.preventDefault(),this.setFormPristine(!1),!this.props.url)return this.updateModel(),this.props.onSubmit(this.mapModel(),this.resetModel,this.updateInputsWithError),void 0;this.updateModel(),this.setState({isSubmitting:!0}),this.props.onSubmit(this.mapModel(),this.resetModel,this.updateInputsWithError);var i=Object.keys(this.props.headers).length&&this.props.headers||p.headers||{},e=this.props.method&&h[this.props.method.toLowerCase()]?this.props.method.toLowerCase():"post";h[e](this.props.url,this.mapModel(),this.props.contentType||p.contentType||"json",i).then(function(t){this.props.onSuccess(t),this.props.onSubmitted()}.bind(this)).catch(this.failSubmit)},mapModel:function(){return this.props.mapping?this.props.mapping(this.model):this.model},updateModel:function(){Object.keys(this.inputs).forEach(function(t){var i=this.inputs[t];this.model[t]=i.state._value}.bind(this))},resetModel:function(){Object.keys(this.inputs).forEach(function(t){this.inputs[t].resetValue()}.bind(this)),this.validateForm()},updateInputsWithError:function(t){Object.keys(t).forEach(function(i){var e=this.inputs[i];if(!e)throw new Error("You are trying to update an input that does not exists. Verify errors object with input names. "+JSON.stringify(t));var n=[{_isValid:!1,_serverError:t[i]}];e.setState.apply(e,n)}.bind(this))},failSubmit:function(t){this.updateInputsWithError(t),this.setState({isSubmitting:!1}),this.props.onError(t),this.props.onSubmitted()},registerInputs:function(t){n.Children.forEach(t,function(t){t.props&&t.props.name&&(t.props._attachToForm=this.attachToForm,t.props._detachFromForm=this.detachFromForm,t.props._validate=this.validate),t.props&&t.props.children&&this.registerInputs(t.props.children)}.bind(this))},getCurrentValues:function(){return Object.keys(this.inputs).reduce(function(t,i){var e=this.inputs[i];return t[i]=e.state._value,t}.bind(this),{})},setFormPristine:function(t){var i=this.inputs,e=Object.keys(i);e.forEach(function(e){var n=i[e];n.setState({_isPristine:t})}.bind(this))},validate:function(t){if(this.state.canChange&&this.props.onChange&&this.props.onChange(this.getCurrentValues()),t.props.required||t._validations){var i=this.runValidation(t);t.setState({_isValid:i,_serverError:null},this.validateForm)}},runValidation:function(t){var i=!0;return t._validations.length&&(t.props.required||""!==t.state._value)&&t._validations.split(",").forEach(function(e){var n=e.split(":"),s=n.shift();if(n=n.map(function(t){try{return JSON.parse(t)}catch(i){return t}}),n=[t.state._value].concat(n),!r[s])throw new Error("Formsy does not have the validation rule: "+s);r[s].apply(this.getCurrentValues(),n)||(i=!1)}.bind(this)),i},validateForm:function(){var t=!0,i=this.inputs,e=Object.keys(i),n=function(){e.forEach(function(e){i[e].state._isValid||(t=!1)}.bind(this)),this.setState({isValid:t}),t&&this.props.onValid(),!t&&this.props.onInvalid(),this.setState({canChange:!0})}.bind(this);e.forEach(function(t,s){var r=i[t],o=this.runValidation(r);r.setState({_isValid:o,_serverError:null},s===e.length-1?n:null)}.bind(this)),e.length||this.setState({canChange:!0})},attachToForm:function(t){this.inputs[t.props.name]=t,this.model[t.props.name]=t.state._value,this.validate(t)},detachFromForm:function(t){delete this.inputs[t.props.name],delete this.model[t.props.name]},render:function(){return n.DOM.form({onSubmit:this.submit,className:this.props.className},this.props.children)}}),e.exports||e.module||e.define&&e.define.amd||(e.Formsy=s),i.exports=s}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{react:"react"}]},{},[1]);
\ No newline at end of file
diff --git a/specs/Formsy-spec.js b/specs/Formsy-spec.js
index c44ad01..c129b59 100755
--- a/specs/Formsy-spec.js
+++ b/specs/Formsy-spec.js
@@ -1,23 +1,286 @@
var Formsy = require('./../src/main.js');
-describe('Formsy', function() {
+describe('Formsy', function () {
describe('Setting up a form', function () {
-
- it('should render a form into the document', function() {
- var form = TestUtils.renderIntoDocument(
-
- );
+
+ it('should render a form into the document', function () {
+ var form = TestUtils.renderIntoDocument( );
expect(form.getDOMNode().tagName).toEqual('FORM');
});
it('should set a class name if passed', function () {
- var form = TestUtils.renderIntoDocument(
-
- );
+ var form = TestUtils.renderIntoDocument( );
expect(form.getDOMNode().className).toEqual('foo');
});
+ it('should allow for inputs being added dynamically', function (done) {
+
+ var inputs = [];
+ var forceUpdate = null;
+ var model = null;
+ var TestInput = React.createClass({
+ mixins: [Formsy.Mixin],
+ render: function () {
+ return
+ }
+ });
+ var TestForm = React.createClass({
+ componentWillMount: function () {
+ forceUpdate = this.forceUpdate.bind(this);
+ },
+ onSubmit: function (formModel) {
+ model = formModel;
+ },
+ render: function () {
+ return (
+
+ {inputs}
+ );
+ }
+ });
+ var form = TestUtils.renderIntoDocument(
+
+ );
+
+ // Wait before adding the input
+ setTimeout(function () {
+
+ inputs.push(TestInput({
+ name: 'test'
+ }));
+
+ forceUpdate(function () {
+
+ // Wait for next event loop, as that does the form
+ setTimeout(function () {
+ TestUtils.Simulate.submit(form.getDOMNode());
+ expect(model.test).toBeDefined();
+ done();
+ }, 0);
+
+ });
+
+ }, 10);
+
+ });
+
+ it('should allow dynamically added inputs to update the form-model', function (done) {
+
+ var inputs = [];
+ var forceUpdate = null;
+ var model = null;
+ var TestInput = React.createClass({
+ mixins: [Formsy.Mixin],
+ changeValue: function (event) {
+ this.setValue(event.target.value);
+ },
+ render: function () {
+ return
+ }
+ });
+ var TestForm = React.createClass({
+ componentWillMount: function () {
+ forceUpdate = this.forceUpdate.bind(this);
+ },
+ onSubmit: function (formModel) {
+ model = formModel;
+ },
+ render: function () {
+ return (
+
+ {inputs}
+ );
+ }
+ });
+ var form = TestUtils.renderIntoDocument(
+
+ );
+
+ // Wait before adding the input
+ setTimeout(function () {
+
+ inputs.push(TestInput({
+ name: 'test'
+ }));
+
+ forceUpdate(function () {
+
+ // Wait for next event loop, as that does the form
+ setTimeout(function () {
+ TestUtils.Simulate.change(TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT'), {target: {value: 'foo'}});
+ TestUtils.Simulate.submit(form.getDOMNode());
+ expect(model.test).toBe('foo');
+ done();
+ }, 0);
+
+ });
+
+ }, 10);
+
+ });
+
+ it('should invalidate a valid form if dynamically inserted input is invalid', function (done) {
+
+ var forceUpdate = null;
+ var isInvalid = false;
+ var TestInput = React.createClass({
+ mixins: [Formsy.Mixin],
+ changeValue: function (event) {
+ this.setValue(event.target.value);
+ },
+ render: function () {
+ return
+ }
+ });
+
+
+ var inputs = [TestInput({
+ name: 'test',
+ validations: 'isEmail',
+ value: 'foo@bar.com'
+ })];
+
+ var TestForm = React.createClass({
+ componentWillMount: function () {
+ forceUpdate = this.forceUpdate.bind(this);
+ },
+ setInvalid: function () {
+ isInvalid = true;
+ },
+ render: function () {
+ return (
+
+ {inputs}
+ );
+ }
+ });
+ var form = TestUtils.renderIntoDocument(
+
+ );
+
+ expect(isInvalid).toBe(false);
+
+ // Wait before adding the input
+ setTimeout(function () {
+
+
+ inputs.push(TestInput({
+ name: 'test2',
+ validations: 'isEmail',
+ value: 'foo@bar'
+ }));
+
+
+ forceUpdate(function () {
+
+ // Wait for next event loop, as that does the form
+ setTimeout(function () {
+ TestUtils.Simulate.submit(form.getDOMNode());
+ expect(isInvalid).toBe(true);
+ done();
+ }, 0);
+
+ });
+
+ }, 10);
+
+ });
+
+ it('should not trigger onChange when form is mounted', function () {
+ var hasChanged = jasmine.createSpy('onChange');
+ var TestForm = React.createClass({
+ onChange: function () {
+ hasChanged();
+ },
+ render: function () {
+ return ;
+ }
+ });
+ var form = TestUtils.renderIntoDocument();
+ expect(hasChanged).not.toHaveBeenCalled();
+ });
+
+ it('should trigger onChange when form element is changed', function () {
+ var hasChanged = jasmine.createSpy('onChange');
+ var MyInput = React.createClass({
+ mixins: [Formsy.Mixin],
+ onChange: function (event) {
+ this.setValue(event.target.value);
+ },
+ render: function () {
+ return
+ }
+ });
+ var TestForm = React.createClass({
+ onChange: function () {
+ hasChanged();
+ },
+ render: function () {
+ return (
+
+
+
+ );
+ }
+ });
+ var form = TestUtils.renderIntoDocument();
+ TestUtils.Simulate.change(TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT'), {target: {value: 'bar'}});
+ expect(hasChanged).toHaveBeenCalled();
+ });
+
+ it('should trigger onChange when new input is added to form', function (done) {
+ var hasChanged = jasmine.createSpy('onChange');
+ var inputs = [];
+ var forceUpdate = null;
+ var TestInput = React.createClass({
+ mixins: [Formsy.Mixin],
+ changeValue: function (event) {
+ this.setValue(event.target.value);
+ },
+ render: function () {
+ return
+ }
+ });
+ var TestForm = React.createClass({
+ componentWillMount: function () {
+ forceUpdate = this.forceUpdate.bind(this);
+ },
+ onChange: function () {
+ hasChanged();
+ },
+ render: function () {
+ return (
+
+ {inputs}
+ );
+ }
+ });
+ var form = TestUtils.renderIntoDocument(
+
+ );
+
+ // Wait before adding the input
+ setTimeout(function () {
+
+ inputs.push(TestInput({
+ name: 'test'
+ }));
+
+ forceUpdate(function () {
+
+ // Wait for next event loop, as that does the form
+ setTimeout(function () {
+ expect(hasChanged).toHaveBeenCalled();
+ done();
+ }, 0);
+
+ });
+
+ }, 10);
+
+ });
+
});
});
diff --git a/specs/Validation-spec.js b/specs/Validation-spec.js
index 1440ba1..446961f 100644
--- a/specs/Validation-spec.js
+++ b/specs/Validation-spec.js
@@ -78,4 +78,60 @@ describe('Validation', function() {
});
+ it('RULE: isNumeric', function () {
+
+ var isValid = jasmine.createSpy('valid');
+ var TestInput = React.createClass({
+ mixins: [Formsy.Mixin],
+ updateValue: function (event) {
+ this.setValue(event.target.value);
+ },
+ render: function () {
+ if (this.isValid()) {
+ isValid();
+ }
+ return
+ }
+ });
+ var form = TestUtils.renderIntoDocument(
+
+
+
+ );
+
+ var input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
+ expect(isValid).not.toHaveBeenCalled();
+ TestUtils.Simulate.change(input, {target: {value: '123'}});
+ expect(isValid).toHaveBeenCalled();
+
+ });
+
+ it('RULE: isNumeric (actual number)', function () {
+
+ var isValid = jasmine.createSpy('valid');
+ var TestInput = React.createClass({
+ mixins: [Formsy.Mixin],
+ updateValue: function (event) {
+ this.setValue(Number(event.target.value));
+ },
+ render: function () {
+ if (this.isValid()) {
+ isValid();
+ }
+ return
+ }
+ });
+ var form = TestUtils.renderIntoDocument(
+
+
+
+ );
+
+ var input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
+ expect(isValid).not.toHaveBeenCalled();
+ TestUtils.Simulate.change(input, {target: {value: '123'}});
+ expect(isValid).toHaveBeenCalled();
+
+ });
+
});
diff --git a/src/main.js b/src/main.js
index 58a8686..5052552 100644
--- a/src/main.js
+++ b/src/main.js
@@ -11,7 +11,11 @@ var validationRules = {
return value === true;
},
'isNumeric': function (value) {
- return value.match(/^-?[0-9]+$/)
+ if (typeof value === 'number') {
+ return true;
+ } else {
+ return value.match(/^-?[0-9]+$/);
+ }
},
'isAlpha': function (value) {
return value.match(/^[a-zA-Z]+$/);
@@ -87,6 +91,21 @@ var request = function (method, url, data, contentType, headers) {
});
};
+
+var arraysDiffer = function (arrayA, arrayB) {
+ var isDifferent = false;
+ if (arrayA.length !== arrayB.length) {
+ isDifferent = true;
+ } else {
+ arrayA.forEach(function (item, index) {
+ if (item !== arrayB[index]) {
+ isDifferent = true;
+ }
+ });
+ }
+ return isDifferent;
+};
+
var ajax = {
post: request.bind(null, 'POST'),
put: request.bind(null, 'PUT')
@@ -107,22 +126,31 @@ Formsy.Mixin = {
},
componentWillMount: function () {
+ var configure = function () {
+ // Add validations to the store itself as the props object can not be modified
+ this._validations = this.props.validations || '';
+
+ if (this.props.required) {
+ this._validations = this.props.validations ? this.props.validations + ',' : '';
+ this._validations += 'isValue';
+ }
+ this.props._attachToForm(this);
+ }.bind(this);
+
if (!this.props.name) {
throw new Error('Form Input requires a name property when used');
}
if (!this.props._attachToForm) {
- throw new Error('Form Mixin requires component to be nested in a Form');
+ return setTimeout(function () {
+ if (!this.props._attachToForm) {
+ throw new Error('Form Mixin requires component to be nested in a Form');
+ }
+ configure();
+ }.bind(this), 0);
}
+ configure();
- // Add validations to the store itself as the props object can not be modified
- this._validations = this.props.validations || '';
-
- if (this.props.required) {
- this._validations = this.props.validations ? this.props.validations + ',' : '';
- this._validations += 'isValue';
- }
- this.props._attachToForm(this);
},
// We have to make the validate method is kept when new props are added
@@ -188,7 +216,8 @@ Formsy.Form = React.createClass({
getInitialState: function () {
return {
isValid: true,
- isSubmitting: false
+ isSubmitting: false,
+ canChange: false
};
},
getDefaultProps: function () {
@@ -199,7 +228,8 @@ Formsy.Form = React.createClass({
onSubmit: function () {},
onSubmitted: function () {},
onValid: function () {},
- onInvalid: function () {}
+ onInvalid: function () {},
+ onChange: function () {}
};
},
@@ -215,6 +245,21 @@ Formsy.Form = React.createClass({
this.validateForm();
},
+ componentWillUpdate: function () {
+ var inputKeys = Object.keys(this.inputs);
+
+ // The updated children array is not available here for some reason,
+ // we need to wait for next event loop
+ setTimeout(function () {
+ this.registerInputs(this.props.children);
+
+ var newInputKeys = Object.keys(this.inputs);
+ if (arraysDiffer(inputKeys, newInputKeys)) {
+ this.validateForm();
+ }
+ }.bind(this), 0);
+ },
+
// Update model, submit to url prop and send the model
submit: function (event) {
event.preventDefault();
@@ -327,7 +372,7 @@ Formsy.Form = React.createClass({
}.bind(this), {});
},
- setFormPristine: function(isPristine) {
+ setFormPristine: function (isPristine) {
var inputs = this.inputs;
var inputKeys = Object.keys(inputs);
@@ -346,6 +391,9 @@ Formsy.Form = React.createClass({
// state of the form itself
validate: function (component) {
+ // Trigger onChange
+ this.state.canChange && this.props.onChange && this.props.onChange(this.getCurrentValues());
+
if (!component.props.required && !component._validations) {
return;
}
@@ -409,6 +457,9 @@ Formsy.Form = React.createClass({
allIsValid && this.props.onValid();
!allIsValid && this.props.onInvalid();
+ // Tell the form that it can start to trigger change events
+ this.setState({canChange: true});
+
}.bind(this);
// Run validation again in case affected by other inputs. The
@@ -422,6 +473,11 @@ Formsy.Form = React.createClass({
}, index === inputKeys.length - 1 ? onValidationComplete : null);
}.bind(this));
+ // If there are no inputs, it is ready to trigger change events
+ if (!inputKeys.length) {
+ this.setState({canChange: true});
+ }
+
},
// Method put on each input component to register