<!DOCTYPE html>
<html>
<head>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.css" rel="stylesheet" data-semver="3.3.6" data-require="bootstrap-css@*" />
<link data-require="font-awesome@*" data-semver="4.5.0" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.css" />
<script data-require="jquery@1.11.3" data-semver="1.11.3" src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<script data-require="angular.js@1.5.0" data-semver="1.5.0" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.js"></script>
<script data-require="ui-bootstrap@*" data-semver="1.1.1" src="//cdn.rawgit.com/angular-ui/bootstrap/gh-pages/ui-bootstrap-1.1.1.js"></script>
<link href="style.css" rel="stylesheet" />
<!--<script src="abv.js"></script>-->
<script src="//rawgit.com/trajano/angular-bootstrap-validator/master/angular-bootstrap-validator.js"></script>
<script src="script.js"></script>
</head>
<body ng-app="myapp">
<h1>Hello Plunker!</h1>
<form name="myForm" abv-form="">
<fieldset class="form-group has-feedback">
<label for="email">E-mail</label>
<input class="form-control " type="email" required="" id="email" />
<div class="help-block with-errors" data-abv-error="required">E-mail is required</div>
<div class="help-block with-errors" data-abv-error="email">E-mail not valid</div>
</fieldset>
<fieldset class="form-group has-feedback">
<label for="password">Password</label>
<input class="form-control" type="password" required="" id="password" />
<div class="help-block with-errors" data-abv-error="required">Password is required</div>
</fieldset>
<fieldset class="form-group has-feedback">
<label for="confirmPassword">Confirm Password</label>
<input class="form-control" type="password" required="" id="confirmPassword" abv-identical="password" ng-model="confirmPassword"/>
<div class="help-block with-errors" data-abv-error="required">Confirmation password is required</div>
<div class="help-block with-errors" data-abv-error="abvIdentical">Confirmation does not match</div>
</fieldset>
<div class="form-group">
<button class="btn btn-primary" type="submit">Register</button>
</div>
</form>
<pre>{{ myForm | json }}</pre>
</body>
</html>
angular.module('myapp', ['ui.bootstrap', 'angular.bootstrap.validator'])
/* Styles go here */
This is an example of doing validation using Angular and Bootstrap.
"use strict";
;(function () {
"use strict";
angular.module('angular.bootstrap.validator', []);
})();
;(function () {
"use strict";
angular.module('angular.bootstrap.validator').directive('abvDifferent', function () {
return {
restrict: 'A',
scope: {
targetModel: '=abvDifferent'
},
require: 'ngModel',
link: function link(scope, element, attributes, ngModel) {
ngModel.$validators.abvDifferent = function (modelValue) {
return modelValue !== scope.targetModel;
};
scope.$watch('targetModel', function () {
ngModel.$validate();
});
}
};
});
})();
;(function () {
"use strict";
angular.module('angular.bootstrap.validator').directive('abvError', function ($animate, $log) {
return {
restrict: 'A',
scope: {
validatorName: '@abvError',
oldControlName: '@abvModel',
controlName: '@abvFor'
},
require: '^form',
terminal: true,
link: function link(scope, element, attrs, form) {
console.log('hello')
var controlName;
if (scope.oldControlName) {
$log.warn('abv-model is deprecated use abv-for');
scope.controlName = scope.oldControlName;
}
if (scope.controlName) {
controlName = scope.controlName;
} else {
if (element.siblings('.form-control')[0]) {
controlName = element.siblings('.form-control')[0].name;
} else {
controlName = element.parent().find('input[type="checkbox"]')[0].name;
}
}
var formName = "$parent." + form.$name;
var watchExpr = formName + ".$submitted && " + formName + "." + controlName + ".$error." + scope.validatorName;
scope.$watch(watchExpr, function (value) {
$animate[value ? 'removeClass' : 'addClass'](element, 'ng-hide', {
tempClasses: 'ng-hide-animate'
});
});
}
};
});
})();
;(function () {
"use strict";
/* globals $ */
angular.module('angular.bootstrap.validator').directive('abvForm', function ($compile) {
function addNameNgModelToControlAndGetControlName(controlElement) {
var control = $(controlElement);
var controlName = control.attr('name');
if (!controlName) {
controlName = control.attr('id');
control.attr('name', controlName);
}
if (!control.attr('ng-model') && !control.data('ng-model')) {
control.attr('ng-model', controlName);
}
return controlName;
}
function ngClassAttribute(formName, controlName) {
return "{'has-success': " + formName + ".$submitted && " + formName + "." + controlName + ".$valid, 'has-error': " + formName + ".$submitted && " + formName + "." + controlName + ".$invalid }";
}
return {
require: 'form',
restrict: 'A',
terminal: true,
compile: function compile() {
return function (scope, element, attr, controller) {
// reset form function
scope.resetForm = function () {
controller.$commitViewValue();
controller.$setPristine();
};
var formName = controller.$name;
// disable submit buttons when the form is invalid after submit
element.find('button[type="submit"]').attr('ng-disabled', formName + ".$submitted && " + formName + ".$invalid");
// associate the reset button with the reset form function
element.find('button[type="reset"]').attr('ng-click', 'resetForm()');
// disable native form validation because the validation is handled by Angular
element.attr('novalidate', 'novalidate');
// for each form-control in a form group
element.find('.form-group').each(function (index, formGroup) {
var controls = $(formGroup).find('.form-control');
// Only input text areas should have feedback, textarea must not have feedback
// only support one control per form-group as per Bootstrap CSS examples
controls.each(function (index,control) {
// set the name. and ng-model appropriately
var controlName = addNameNgModelToControlAndGetControlName(control);
// add feedback icons
if ($(formGroup).hasClass('has-feedback')) {
angular.element(control).after("<span class=\"glyphicon form-control-feedback\" ng-class=\"{'glyphicon-ok' : " + formName + "." + controlName + ".$valid, 'glyphicon-remove' : " + formName + "." + controlName + ".$invalid }\" ng-if=\"" + formName + ".$submitted\" aria-hidden=\"true\"></span>");
}
// set the has-error CSS if the form has been submitted
$(formGroup).attr('ng-class', ngClassAttribute(formName, controlName));
});
});
// for each checkbox, wrap in a container div
element.find('.checkbox').each(function (index, checkbox) {
var controls = $(checkbox).find('input[type="checkbox"]');
if (controls.length === 1) {
// set the name. and ng-model appropriately
var controlName = addNameNgModelToControlAndGetControlName(controls[0]);
$(checkbox).wrap("<div ng-class=\"" + ngClassAttribute(formName, controlName) + "\"></div>");
}
});
$compile(element.contents())(scope);
};
}
};
});
})();
;(function () {
"use strict";
angular.module('angular.bootstrap.validator').directive('abvIdentical', function () {
return {
restrict: 'A',
scope: {
targetModel: '=abvIdentical'
},
require: 'ngModel',
link: function link(scope, element, attributes, ngModel) {
ngModel.$validators.abvIdentical = function (modelValue) {
return modelValue === scope.targetModel;
};
scope.$watch('targetModel', function () {
ngModel.$validate();
});
}
};
});
})();
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImFuZ3VsYXItYm9vdHN0cmFwLXZhbGlkYXRvci5qcyIsImRpcmVjdGl2ZXMvYWJ2RGlmZmVyZW50LmpzIiwiZGlyZWN0aXZlcy9hYnZFcnJvci5qcyIsImRpcmVjdGl2ZXMvYWJ2Rm9ybS5qcyIsImRpcmVjdGl2ZXMvYWJ2SWRlbnRpY2FsLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsQ0FBQSxDQUFBLFlBQUE7QUFDQSxlQURBOztBQUdBLFVBQUEsTUFBQSxDQUFBLDZCQUFBLEVBQUEsRUFBQSxFQUhBO0NBQUEsR0FBQTs7QUNBQSxDQUFBLENBQUEsWUFBQTtBQUNBLGVBREE7O0FBR0EsVUFBQSxNQUFBLENBQUEsNkJBQUEsRUFDQSxTQURBLENBQ0EsY0FEQSxFQUNBO1dBQUE7QURPSSxnQkFBVSxHQUFWO0FBQ0EsYUFBTztBQUNMLHFCQUFhLGVBQWI7T0FERjtBQUdBLGVBQVMsU0FBVDtBQUNBLFlBQU0sY0FBUyxLQUFULEVBQWdCLE9BQWhCLEVBQXlCLFVBQXpCLEVBQXFDLE9BQXJDLEVBQThDOztBQUVsRCxnQkFBUSxXQUFSLENBQW9CLFlBQXBCLEdBQW1DO2lCQUFjLGVBQWUsTUFBTSxXQUFOO1NBQTdCLENBRmU7O0FBSWxELGNBQU0sTUFBTixDQUFhLGFBQWIsRUFBNEIsWUFBTTtBQUNoQyxrQkFBUSxTQUFSLEdBRGdDO1NBQU4sQ0FBNUIsQ0FKa0Q7T0FBOUM7O0dDWlYsQ0FEQSxDQUhBO0NBQUEsR0FBQTs7QUNBQSxDQUFBLENBQUEsWUFBQTtBQUNBLGVBREE7O0FBR0EsVUFBQSxNQUFBLENBQUEsNkJBQUEsRUFDQSxTQURBLENBQ0EsVUFEQSxFQUNBLFVBQUEsUUFBQSxFQUFBLElBQUE7V0FBQTtBRjRCSSxnQkFBVSxHQUFWO0FBQ0EsYUFBTztBQUNMLHVCQUFlLFdBQWY7QUFDQSx3QkFBZ0IsV0FBaEI7QUFDQSxxQkFBYSxTQUFiO09BSEY7QUFLQSxlQUFTLE9BQVQ7QUFDQSxnQkFBVSxJQUFWO0FBQ0EsWUFBTSxjQUFDLEtB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U0FEQSxDQUNBLGNBREEsRUFDQTtXQUFBO0FKbUpJLGdCQUFVLEdBQVY7QUFDQSxhQUFPO0FBQ0wscUJBQWEsZUFBYjtPQURGO0FBR0EsZUFBUyxTQUFUO0FBQ0EsWUFBTSxjQUFTLEtBQVQsRUFBZ0IsT0FBaEIsRUFBeUIsVUFBekIsRUFBcUMsT0FBckMsRUFBOEM7O0FBRWxELGdCQUFRLFdBQVIsQ0FBb0IsWUFBcEIsR0FBbUM7aUJBQWMsZUFBZSxNQUFNLFdBQU47U0FBN0IsQ0FGZTs7QUFJbEQsY0FBTSxNQUFOLENBQWEsYUFBYixFQUE0QixZQUFNO0FBQ2hDLGtCQUFRLFNBQVIsR0FEZ0M7U0FBTixDQUE1QixDQUprRDtPQUE5Qzs7R0l4SlYsQ0FEQSxDQUhBO0NBQUEsR0FBQSIsImZpbGUiOiJhbmd1bGFyLWJvb3RzdHJhcC12YWxpZGF0b3IuanMiLCJzb3VyY2VzQ29udGVudCI6WyJhbmd1bGFyLm1vZHVsZSgnYW5ndWxhci5ib290c3RyYXAudmFsaWRhdG9yJywgW10pXHJcbiIsImFuZ3VsYXIubW9kdWxlKCdhbmd1bGFyLmJvb3RzdHJhcC52YWxpZGF0b3InKVxyXG4gIC5kaXJlY3RpdmUoJ2FidkRpZmZlcmVudCcsICgpID0+ICh7XHJcbiAgICByZXN0cmljdDogJ0EnLFxyXG4gICAgc2NvcGU6IHtcclxuICAgICAgdGFyZ2V0TW9kZWw6ICc9YWJ2RGlmZmVyZW50J1xyXG4gICAgfSxcclxuICAgIHJlcXVpcmU6ICduZ01vZGVsJyxcclxuICAgIGxpbms6IGZ1bmN0aW9uKHNjb3BlLCBlbGVtZW50LCBhdHRyaWJ1dGVzLCBuZ01vZGVsKSB7XHJcblxyXG4gICAgICBuZ01vZGVsLiR2YWxpZGF0b3JzLmFidkRpZmZlcmVudCA9IG1vZGVsVmFsdWUgPT4gbW9kZWxWYWx1ZSAhPT0gc2NvcGUudGFyZ2V0TW9kZWxcclxuXHJcbiAgICAgIHNjb3BlLiR3YXRjaCgndGFyZ2V0TW9kZWwnLCAoKSA9PiB7XHJcbiAgICAgICAgbmdNb2RlbC4kdmFsaWRhdGUoKVxyXG4gICAgICB9KVxyXG4gICAgfVxyXG4gIH0pKVxyXG4iLCJhbmd1bGFyLm1vZHVsZSgnYW5ndWxhci5ib290c3RyYXAudmFsaWRhdG9yJylcclxuICAuZGlyZWN0aXZlKCdhYnZFcnJvcicsICgkYW5pbWF0ZSwgJGxvZykgPT4gKHtcclxuICAgIHJlc3RyaWN0OiAnQScsXHJcbiAgICBzY29wZToge1xyXG4gICAgICB2YWxpZGF0b3JOYW1lOiAnQGFidkVycm9yJyxcclxuICAgICAgb2xkQ29udHJvbE5hbWU6ICdAYWJ2TW9kZWwnLFxyXG4gICAgICBjb250cm9sTmFtZTogJ0BhYnZGb3InXHJcbiAgICB9LFxyXG4gICAgcmVxdWlyZTogJ15mb3JtJyxcclxuICAgIHRlcm1pbmFsOiB0cnVlLFxyXG4gICAgbGluazogKHNjb3BlLCBlbGVtZW50LCBhdHRycywgZm9ybSkgPT4ge1xyXG4gICAgICB2YXIgY29udHJvbE5hbWVcclxuICAgICAgaWYgKHNjb3BlLm9sZENvbnRyb2xOYW1lKSB7XHJcbiAgICAgICAgJGxvZy53YXJuKCdhYnYtbW9kZWwgaXMgZGVwcmVjYXRlZCB1c2UgYWJ2LWZvcicpXHJcbiAgICAgICAgc2NvcGUuY29udHJvbE5hbWUgPSBzY29wZS5vbGRDb250cm9sTmFtZVxyXG4gICAgICB9XHJcbiAgICAgIGlmIChzY29wZS5jb250cm9sTmFtZSkge1xyXG4gICAgICAgIGNvbnRyb2xOYW1lID0gc2NvcGUuY29udHJvbE5hbWVcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBpZiAoZWxlbWVudC5zaWJsaW5ncygnLmZvcm0tY29udHJvbCcpWzBdKSB7XHJcbiAgICAgICAgICBjb250cm9sTmFtZSA9IGVsZW1lbnQuc2libGluZ3MoJy5mb3JtLWNvbnRyb2wnKVswXS5uYW1lXHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGNvbnRyb2xOYW1lID0gZWxlbWVudC5wYXJlbnQoKS5maW5kKCdpbnB1dFt0eXBlPVwiY2hlY2tib3hcIl0nKVswXS5uYW1lXHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIHZhciBmb3JtTmFtZSA9IGAkcGFyZW50LiR7Zm9ybS4kbmFtZX1gXHJcbiAgICAgIHZhciB3YXRjaEV4cHIgPSBgJHtmb3JtTmFtZX0uJHN1Ym1pdHRlZCAmJiAke2Zvcm1OYW1lfS4ke2NvbnRyb2xOYW1lfS4kZXJyb3IuJHtzY29wZS52YWxpZGF0b3JOYW1lfWBcclxuICAgICAgc2NvcGUuJHdhdGNoKHdhdGNoRXhwciwgdmFsdWUgPT4ge1xyXG4gICAgICAgICRhbmltYXRlW3ZhbHVlID8gJ3JlbW92ZUNsYXNzJyA6ICdhZGRDbGFzcyddKGVsZW1lbnQsICduZy1oaWRlJywge1xyXG4gICAgICAgICAgdGVtcENsYXNzZXM6ICduZy1oaWRlLWFuaW1hdGUnXHJcbiAgICAgICAgfSlcclxuICAgICAgfSlcclxuICAgIH1cclxuICB9KSlcclxuIiwiLyogZ2xvYmFscyAkICovXHJcbmFuZ3VsYXIubW9kdWxlKCdhbmd1bGFyLmJvb3RzdHJhcC52YWxpZGF0b3InKVxyXG4gIC5kaXJlY3RpdmUoJ2FidkZvcm0nLCAkY29tcGlsZSA9PiB7XHJcbiAgICBmdW5jdGlvbiBhZGROYW1lTmdNb2RlbFRvQ29udHJvbEFuZEdldENvbnRyb2xOYW1lKGNvbnRyb2xFbGVtZW50KSB7XHJcbiAgICAgIHZhciBjb250cm9sID0gJChjb250cm9sRWxlbWVudClcclxuICAgICAgdmFyIGNvbnRyb2xOYW1lID0gY29udHJvbC5hdHRyKCduYW1lJylcclxuICAgICAgaWYgKCFjb250cm9sTmFtZSkge1xyXG4gICAgICAgIGNvbnRyb2xOYW1lID0gY29udHJvbC5hdHRyKCdpZCcpXHJcbiAgICAgICAgY29udHJvbC5hdHRyKCduYW1lJywgY29udHJvbE5hbWUpXHJcbiAgICAgIH1cclxuICAgICAgaWYgKCFjb250cm9sLmF0dHIoJ25nLW1vZGVsJykgJiYgIWNvbnRyb2wuZGF0YSgnbmctbW9kZWwnKSkge1xyXG4gICAgICAgIGNvbnRyb2wuYXR0cignbmctbW9kZWwnLCBjb250cm9sTmFtZSlcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gY29udHJvbE5hbWVcclxuXHJcbiAgICB9XHJcblxyXG4gICAgZnVuY3Rpb24gbmdDbGFzc0F0dHJpYnV0ZShmb3JtTmFtZSwgY29udHJvbE5hbWUpIHtcclxuICAgICAgcmV0dXJuIGB7J2hhcy1zdWNjZXNzJzogJHtmb3JtTmFtZX0uJHN1Ym1pdHRlZCAmJiAke2Zvcm1OYW1lfS4ke2NvbnRyb2xOYW1lfS4kdmFsaWQsICdoYXMtZXJyb3InOiAke2Zvcm1OYW1lfS4kc3VibWl0dGVkICYmICR7Zm9ybU5hbWV9LiR7Y29udHJvbE5hbWV9LiRpbnZhbGlkIH1gXHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgcmVxdWlyZTogJ2Zvcm0nLFxyXG4gICAgICByZXN0cmljdDogJ0EnLFxyXG4gICAgICB0ZXJtaW5hbDogdHJ1ZSxcclxuICAgICAgY29tcGlsZTogKCkgPT4gKHNjb3BlLCBlbGVtZW50LCBhdHRyLCBjb250cm9sbGVyKSA9PiB7XHJcbiAgICAgICAgLy8gcmVzZXQgZm9ybSBmdW5jdGlvblxyXG4gICAgICAgIHNjb3BlLnJlc2V0Rm9ybSA9IGZ1bmN0aW9uKCkge1xyXG4gICAgICAgICAgY29udHJvbGxlci4kY29tbWl0Vmlld1ZhbHVlKClcclxuICAgICAgICAgIGNvbnRyb2xsZXIuJHNldFByaXN0aW5lKClcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHZhciBmb3JtTmFtZSA9IGNvbnRyb2xsZXIuJG5hbWVcclxuXHJcbiAgICAgICAgLy8gZGlzYWJsZSBzdWJtaXQgYnV0dG9ucyB3aGVuIHRoZSBmb3JtIGlzIGludmFsaWQgYWZ0ZXIgc3VibWl0XHJcbiAgICAgICAgZWxlbWVudC5maW5kKCdidXR0b25bdHlwZT1cInN1Ym1pdFwiXScpLmF0dHIoJ25nLWRpc2FibGVkJywgYCR7Zm9ybU5hbWV9LiRzdWJtaXR0ZWQgJiYgJHtmb3JtTmFtZX0uJGludmFsaWRgKVxyXG5cclxuICAgICAgICAvLyBhc3NvY2lhdGUgdGhlIHJlc2V0IGJ1dHRvbiB3aXRoIHRoZSByZXNldCBmb3JtIGZ1bmN0aW9uXHJcbiAgICAgICAgZWxlbWVudC5maW5kKCdidXR0b25bdHlwZT1cInJlc2V0XCJdJykuYXR0cignbmctY2xpY2snLCAncmVzZXRGb3JtKCknKVxyXG5cclxuICAgICAgICAvLyBkaXNhYmxlIG5hdGl2ZSBmb3JtIHZhbGlkYXRpb24gYmVjYXVzZSB0aGUgdmFsaWRhdGlvbiBpcyBoYW5kbGVkIGJ5IEFuZ3VsYXJcclxuICAgICAgICBlbGVtZW50LmF0dHIoJ25vdmFsaWRhdGUnLCAnbm92YWxpZGF0ZScpXHJcblxyXG4gICAgICAgIC8vIGZvciBlYWNoIGZvcm0tY29udHJvbCBpbiBhIGZvcm0gZ3JvdXBcclxuICAgICAgICBlbGVtZW50LmZpbmQoJy5mb3JtLWdyb3VwJykuZWFjaCgoaW5kZXgsIGZvcm1Hcm91cCkgPT4ge1xyXG4gICAgICAgICAgdmFyIGNvbnRyb2xzID0gJChmb3JtR3JvdXApLmZpbmQoJy5mb3JtLWNvbnRyb2wnKVxyXG4gICAgICAgICAgLy8gT25seSBpbnB1dCB0ZXh0IGFyZWFzIHNob3VsZCBoYXZlIGZlZWRiYWNrLCB0ZXh0YXJlYSBtdXN0IG5vdCBoYXZlIGZlZWRiYWNrXHJcbiAgICAgICAgICAvLyBvbmx5IHN1cHBvcnQgb25lIGNvbnRyb2wgcGVyIGZvcm0tZ3JvdXAgYXMgcGVyIEJvb3RzdHJhcCBDU1MgZXhhbXBsZXNcclxuICAgICAgICAgIGNvbnRyb2xzLmZvckVhY2goY29udHJvbCA9PiB7XHJcbiAgICAgICAgICAgIC8vIHNldCB0aGUgbmFtZS4gYW5kIG5nLW1vZGVsIGFwcHJvcHJpYXRlbHlcclxuICAgICAgICAgICAgdmFyIGNvbnRyb2xOYW1lID0gYWRkTmFtZU5nTW9kZWxUb0NvbnRyb2xBbmRHZXRDb250cm9sTmFtZShjb250cm9sKVxyXG5cclxuICAgICAgICAgICAgLy8gYWRkIGZlZWRiYWNrIGljb25zXHJcbiAgICAgICAgICAgIGlmICgkKGZvcm1Hcm91cCkuaGFzQ2xhc3MoJ2hhcy1mZWVkYmFjaycpKSB7XHJcbiAgICAgICAgICAgICAgY29udHJvbC5hZnRlcihgPHNwYW4gY2xhc3M9XCJnbHlwaGljb24gZm9ybS1jb250cm9sLWZlZWRiYWNrXCIgbmctY2xhc3M9XCJ7J2dseXBoaWNvbi1vaycgOiAke2Zvcm1OYW1lfS4ke2NvbnRyb2xOYW1lfS4kdmFsaWQsICdnbHlwaGljb24tcmVtb3ZlJyA6ICR7Zm9ybU5hbWV9LiR7Y29udHJvbE5hbWV9LiRpbnZhbGlkIH1cIiBuZy1pZj1cIiR7Zm9ybU5hbWV9LiRzdWJtaXR0ZWRcIiBhcmlhLWhpZGRlbj1cInRydWVcIj48L3NwYW4+YClcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gc2V0IHRoZSBoYXMtZXJyb3IgQ1NTIGlmIHRoZSBmb3JtIGhhcyBiZWVuIHN1Ym1pdHRlZFxyXG4gICAgICAgICAgICAkKGZvcm1Hcm91cCkuYXR0cignbmctY2xhc3MnLCBuZ0NsYXNzQXR0cmlidXRlKGZvcm1OYW1lLCBjb250cm9sTmFtZSkpXHJcbiAgICAgICAgICB9KVxyXG4gICAgICAgIH0pXHJcblxyXG4gICAgICAgIC8vIGZvciBlYWNoIGNoZWNrYm94LCB3cmFwIGluIGEgY29udGFpbmVyIGRpdlxyXG4gICAgICAgIGVsZW1lbnQuZmluZCgnLmNoZWNrYm94JykuZWFjaCgoaW5kZXgsIGNoZWNrYm94KSA9PiB7XHJcbiAgICAgICAgICB2YXIgY29udHJvbHMgPSAkKGNoZWNrYm94KS5maW5kKCdpbnB1dFt0eXBlPVwiY2hlY2tib3hcIl0nKVxyXG4gICAgICAgICAgaWYgKGNvbnRyb2xzLmxlbmd0aCA9PT0gMSkge1xyXG4gICAgICAgICAgICAvLyBzZXQgdGhlIG5hbWUuIGFuZCBuZy1tb2RlbCBhcHByb3ByaWF0ZWx5XHJcbiAgICAgICAgICAgIHZhciBjb250cm9sTmFtZSA9IGFkZE5hbWVOZ01vZGVsVG9Db250cm9sQW5kR2V0Q29udHJvbE5hbWUoY29udHJvbHNbMF0pXHJcbiAgICAgICAgICAgICQoY2hlY2tib3gpLndyYXAoYDxkaXYgbmctY2xhc3M9XCIke25nQ2xhc3NBdHRyaWJ1dGUoZm9ybU5hbWUsIGNvbnRyb2xOYW1lKX1cIj48L2Rpdj5gKVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pXHJcbiAgICAgICAgJGNvbXBpbGUoZWxlbWVudC5jb250ZW50cygpKShzY29wZSlcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pXHJcbiIsImFuZ3VsYXIubW9kdWxlKCdhbmd1bGFyLmJvb3RzdHJhcC52YWxpZGF0b3InKVxyXG4gIC5kaXJlY3RpdmUoJ2FidklkZW50aWNhbCcsICgpID0+ICh7XHJcbiAgICByZXN0cmljdDogJ0EnLFxyXG4gICAgc2NvcGU6IHtcclxuICAgICAgdGFyZ2V0TW9kZWw6ICc9YWJ2SWRlbnRpY2FsJ1xyXG4gICAgfSxcclxuICAgIHJlcXVpcmU6ICduZ01vZGVsJyxcclxuICAgIGxpbms6IGZ1bmN0aW9uKHNjb3BlLCBlbGVtZW50LCBhdHRyaWJ1dGVzLCBuZ01vZGVsKSB7XHJcblxyXG4gICAgICBuZ01vZGVsLiR2YWxpZGF0b3JzLmFidklkZW50aWNhbCA9IG1vZGVsVmFsdWUgPT4gbW9kZWxWYWx1ZSA9PT0gc2NvcGUudGFyZ2V0TW9kZWxcclxuXHJcbiAgICAgIHNjb3BlLiR3YXRjaCgndGFyZ2V0TW9kZWwnLCAoKSA9PiB7XHJcbiAgICAgICAgbmdNb2RlbC4kdmFsaWRhdGUoKVxyXG4gICAgICB9KVxyXG4gICAgfVxyXG4gIH0pKVxyXG4iXSwic291cmNlUm9vdCI6Ii9zb3VyY2UvIn0=