Skip to content

Instantly share code, notes, and snippets.

@xh3n1
Created August 15, 2017 20:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xh3n1/1fac4dd92356340ce68d9b7b5e6fda0b to your computer and use it in GitHub Desktop.
Save xh3n1/1fac4dd92356340ce68d9b7b5e6fda0b to your computer and use it in GitHub Desktop.
public js
/**
* Nextcloud - contacts
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Hendrik Leppelsack <hendrik@leppelsack.de>
* @copyright Hendrik Leppelsack 2015
*/
angular.module('contactsApp', ['uuid4', 'angular-cache', 'ngRoute', 'ui.bootstrap', 'ui.select', 'ngSanitize', 'angular-click-outside', 'ngclipboard'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/:gid', {
template: '<contactdetails></contactdetails>'
});
$routeProvider.when('/contact/:uid', {
redirectTo: function(parameters) {
return '/' + t('contacts', 'All contacts') + '/' + parameters.uid;
}
});
$routeProvider.when('/:gid/:uid', {
template: '<contactdetails></contactdetails>'
});
$routeProvider.otherwise('/' + t('contacts', 'All contacts'));
}]);
angular.module('contactsApp')
.directive('datepicker', ['$timeout', function($timeout) {
var loadDatepicker = function (scope, element, attrs, ngModelCtrl) {
$timeout(function() {
element.datepicker({
dateFormat:'yy-mm-dd',
minDate: null,
maxDate: null,
constrainInput: false,
onSelect:function (date, dp) {
if (dp.selectedYear < 1000) {
date = '0' + date;
}
if (dp.selectedYear < 100) {
date = '0' + date;
}
if (dp.selectedYear < 10) {
date = '0' + date;
}
ngModelCtrl.$setViewValue(date);
scope.$apply();
}
});
});
};
return {
restrict: 'A',
require : 'ngModel',
transclude: true,
link : loadDatepicker
};
}]);
angular.module('contactsApp')
.directive('focusExpression', ['$timeout', function ($timeout) {
return {
restrict: 'A',
link: {
post: function postLink(scope, element, attrs) {
scope.$watch(attrs.focusExpression, function () {
if (attrs.focusExpression) {
if (scope.$eval(attrs.focusExpression)) {
$timeout(function () {
if (element.is('input')) {
element.focus();
} else {
element.find('input').focus();
}
}, 100); //need some delay to work with ng-disabled
}
}
});
}
}
};
}]);
angular.module('contactsApp')
.directive('inputresize', function() {
return {
restrict: 'A',
link : function (scope, element) {
var elInput = element.val();
element.bind('keydown keyup load focus', function() {
elInput = element.val();
// If set to 0, the min-width css data is ignored
var length = elInput.length > 1 ? elInput.length : 1;
element.attr('size', length);
});
}
};
});
angular.module('contactsApp')
.directive('selectExpression', ['$timeout', function ($timeout) {
return {
restrict: 'A',
link: {
post: function postLink(scope, element, attrs) {
scope.$watch(attrs.selectExpression, function () {
if (attrs.selectExpression) {
if (scope.$eval(attrs.selectExpression)) {
$timeout(function () {
if (element.is('input')) {
element.select();
} else {
element.find('input').select();
}
}, 100); //need some delay to work with ng-disabled
}
}
});
}
}
};
}]);
angular.module('contactsApp')
.controller('addressbookCtrl', ['$scope', 'AddressBookService', function($scope, AddressBookService) {
var ctrl = this;
ctrl.t = {
download: t('contacts', 'Download'),
copyURL: t('contacts', 'Copy link'),
clickToCopy: t('contacts', 'Click to copy the link to your clipboard'),
shareAddressbook: t('contacts', 'Toggle sharing'),
deleteAddressbook: t('contacts', 'Delete'),
renameAddressbook: t('contacts', 'Rename'),
shareInputPlaceHolder: t('contacts', 'Share with users or groups'),
delete: t('contacts', 'Delete'),
canEdit: t('contacts', 'can edit'),
close: t('contacts', 'Close')
};
ctrl.editing = false;
ctrl.tooltipIsOpen = false;
ctrl.tooltipTitle = ctrl.t.clickToCopy;
ctrl.showInputUrl = false;
ctrl.clipboardSuccess = function() {
ctrl.tooltipIsOpen = true;
ctrl.tooltipTitle = t('core', 'Copied!');
_.delay(function() {
ctrl.tooltipIsOpen = false;
ctrl.tooltipTitle = ctrl.t.clickToCopy;
}, 3000);
};
ctrl.clipboardError = function() {
ctrl.showInputUrl = true;
if (/iPhone|iPad/i.test(navigator.userAgent)) {
ctrl.InputUrlTooltip = t('core', 'Not supported!');
} else if (/Mac/i.test(navigator.userAgent)) {
ctrl.InputUrlTooltip = t('core', 'Press ⌘-C to copy.');
} else {
ctrl.InputUrlTooltip = t('core', 'Press Ctrl-C to copy.');
}
$('#addressBookUrl_'+ctrl.addressBook.ctag).select();
};
ctrl.renameAddressBook = function() {
AddressBookService.rename(ctrl.addressBook, ctrl.addressBook.displayName);
ctrl.editing = false;
};
ctrl.edit = function() {
ctrl.editing = true;
};
/* globals oc_config */
function compareVersion(version1, version2) {
for (var i = 0; i < Math.max(version1.length, version2.length); i++) {
var a = version1[i] || 0;
var b = version2[i] || 0;
if (Number(a) < Number(b)) {
return true;
}
if (version1[i] !== version2[i]) {
return false;
}
}
return false;
}
/* eslint-disable camelcase */
ctrl.canExport = compareVersion([9, 0, 2, 0], oc_config.version.split('.'));
/* eslint-enable camelcase */
ctrl.closeMenus = function() {
$scope.$parent.ctrl.openedMenu = false;
};
ctrl.openMenu = function(index) {
ctrl.closeMenus();
$scope.$parent.ctrl.openedMenu = index;
};
ctrl.toggleMenu = function(index) {
if ($scope.$parent.ctrl.openedMenu === index) {
ctrl.closeMenus();
} else {
ctrl.openMenu(index);
}
};
ctrl.toggleSharesEditor = function() {
ctrl.editingShares = !ctrl.editingShares;
ctrl.selectedSharee = null;
};
/* From Calendar-Rework - js/app/controllers/calendarlistcontroller.js */
ctrl.findSharee = function (val) {
return $.get(
OC.linkToOCS('apps/files_sharing/api/v1') + 'sharees',
{
format: 'json',
search: val.trim(),
perPage: 200,
itemType: 'principals'
}
).then(function(result) {
// Todo - filter out current user, existing sharees
var users = result.ocs.data.exact.users.concat(result.ocs.data.users);
var groups = result.ocs.data.exact.groups.concat(result.ocs.data.groups);
var userShares = ctrl.addressBook.sharedWith.users;
var userSharesLength = userShares.length;
var i, j;
// Filter out current user
var usersLength = users.length;
for (i = 0 ; i < usersLength; i++) {
if (users[i].value.shareWith === OC.currentUser) {
users.splice(i, 1);
break;
}
}
// Now filter out all sharees that are already shared with
for (i = 0; i < userSharesLength; i++) {
var share = userShares[i];
usersLength = users.length;
for (j = 0; j < usersLength; j++) {
if (users[j].value.shareWith === share.id) {
users.splice(j, 1);
break;
}
}
}
// Combine users and groups
users = users.map(function(item) {
return {
display: item.value.shareWith,
type: OC.Share.SHARE_TYPE_USER,
identifier: item.value.shareWith
};
});
groups = groups.map(function(item) {
return {
display: item.value.shareWith + ' (group)',
type: OC.Share.SHARE_TYPE_GROUP,
identifier: item.value.shareWith
};
});
return groups.concat(users);
});
};
ctrl.onSelectSharee = function (item) {
// Prevent settings to slide down
$('#app-settings-header > button').data('apps-slide-toggle', false);
_.delay(function() {
$('#app-settings-header > button').data('apps-slide-toggle', '#app-settings-content');
}, 500);
ctrl.selectedSharee = null;
AddressBookService.share(ctrl.addressBook, item.type, item.identifier, false, false).then(function() {
$scope.$apply();
});
};
ctrl.updateExistingUserShare = function(userId, writable) {
AddressBookService.share(ctrl.addressBook, OC.Share.SHARE_TYPE_USER, userId, writable, true).then(function() {
$scope.$apply();
});
};
ctrl.updateExistingGroupShare = function(groupId, writable) {
AddressBookService.share(ctrl.addressBook, OC.Share.SHARE_TYPE_GROUP, groupId, writable, true).then(function() {
$scope.$apply();
});
};
ctrl.unshareFromUser = function(userId) {
AddressBookService.unshare(ctrl.addressBook, OC.Share.SHARE_TYPE_USER, userId).then(function() {
$scope.$apply();
});
};
ctrl.unshareFromGroup = function(groupId) {
AddressBookService.unshare(ctrl.addressBook, OC.Share.SHARE_TYPE_GROUP, groupId).then(function() {
$scope.$apply();
});
};
ctrl.deleteAddressBook = function() {
AddressBookService.delete(ctrl.addressBook).then(function() {
$scope.$apply();
});
};
}]);
angular.module('contactsApp')
.directive('addressbook', function() {
return {
restrict: 'A', // has to be an attribute to work with core css
scope: {},
controller: 'addressbookCtrl',
controllerAs: 'ctrl',
bindToController: {
addressBook: '=data',
list: '='
},
templateUrl: OC.linkTo('contacts', 'templates/addressBook.html')
};
});
angular.module('contactsApp')
.controller('addressbooklistCtrl', ['$scope', 'AddressBookService', function($scope, AddressBookService) {
var ctrl = this;
ctrl.loading = true;
ctrl.openedMenu = false;
AddressBookService.getAll().then(function(addressBooks) {
ctrl.addressBooks = addressBooks;
ctrl.loading = false;
if(ctrl.addressBooks.length === 0) {
AddressBookService.create(t('contacts', 'Contacts')).then(function() {
AddressBookService.getAddressBook(t('contacts', 'Contacts')).then(function(addressBook) {
ctrl.addressBooks.push(addressBook);
$scope.$apply();
});
});
}
});
ctrl.t = {
addressBookName : t('contacts', 'Address book name')
};
ctrl.createAddressBook = function() {
if(ctrl.newAddressBookName) {
AddressBookService.create(ctrl.newAddressBookName).then(function() {
AddressBookService.getAddressBook(ctrl.newAddressBookName).then(function(addressBook) {
ctrl.addressBooks.push(addressBook);
$scope.$apply();
});
});
}
};
}]);
angular.module('contactsApp')
.directive('addressbooklist', function() {
return {
restrict: 'EA', // has to be an attribute to work with core css
scope: {},
controller: 'addressbooklistCtrl',
controllerAs: 'ctrl',
bindToController: {},
templateUrl: OC.linkTo('contacts', 'templates/addressBookList.html')
};
});
angular.module('contactsApp')
.controller('avatarCtrl', ['ContactService', function(ContactService) {
var ctrl = this;
ctrl.import = ContactService.import.bind(ContactService);
ctrl.removePhoto = function() {
ctrl.contact.removeProperty('photo', ctrl.contact.getProperty('photo'));
ContactService.update(ctrl.contact);
$('avatar').removeClass('maximized');
};
ctrl.downloadPhoto = function() {
/* globals ArrayBuffer, Uint8Array */
var img = document.getElementById('contact-avatar');
// atob to base64_decode the data-URI
var imageSplit = img.src.split(',');
// "data:image/png;base64" -> "png"
var extension = '.' + imageSplit[0].split(';')[0].split('/')[1];
var imageData = atob(imageSplit[1]);
// Use typed arrays to convert the binary data to a Blob
var arrayBuffer = new ArrayBuffer(imageData.length);
var view = new Uint8Array(arrayBuffer);
for (var i=0; i<imageData.length; i++) {
view[i] = imageData.charCodeAt(i) & 0xff;
}
var blob = new Blob([arrayBuffer], {type: 'application/octet-stream'});
// Use the URL object to create a temporary URL
var url = (window.webkitURL || window.URL).createObjectURL(blob);
var a = document.createElement('a');
document.body.appendChild(a);
a.style = 'display: none';
a.href = url;
a.download = ctrl.contact.uid() + extension;
a.click();
window.URL.revokeObjectURL(url);
a.remove();
};
ctrl.openPhoto = function() {
$('avatar').toggleClass('maximized');
};
// Quit avatar preview
$('avatar').click(function() {
$('avatar').removeClass('maximized');
});
$('avatar img, avatar .avatar-options').click(function(e) {
e.stopPropagation();
});
$(document).keyup(function(e) {
if (e.keyCode === 27) {
$('avatar').removeClass('maximized');
}
});
}]);
angular.module('contactsApp')
.directive('avatar', ['ContactService', function(ContactService) {
return {
scope: {
contact: '=data'
},
controller: 'avatarCtrl',
controllerAs: 'ctrl',
bindToController: {
contact: '=data'
},
link: function(scope, element) {
var importText = t('contacts', 'Import');
scope.importText = importText;
var input = element.find('input');
input.bind('change', function() {
var file = input.get(0).files[0];
if (file.size > 1024*1024) { // 1 MB
OC.Notification.showTemporary(t('contacts', 'The selected image is too big (max 1MB)'));
} else {
var reader = new FileReader();
reader.addEventListener('load', function () {
scope.$apply(function() {
scope.contact.photo(reader.result);
ContactService.update(scope.contact);
});
}, false);
if (file) {
reader.readAsDataURL(file);
}
}
});
},
templateUrl: OC.linkTo('contacts', 'templates/avatar.html')
};
}]);
angular.module('contactsApp')
.controller('contactCtrl', ['$route', '$routeParams', 'SortByService', function($route, $routeParams, SortByService) {
var ctrl = this;
ctrl.t = {
errorMessage : t('contacts', 'This card is corrupted and has been fixed. Please check the data and trigger a save to make the changes permanent.'),
};
ctrl.openContact = function() {
$route.updateParams({
gid: $routeParams.gid,
uid: ctrl.contact.uid()});
};
ctrl.getName = function() {
// If lastName equals to firstName then none of them is set
if (ctrl.contact.lastName() === ctrl.contact.firstName()) {
return ctrl.contact.displayName();
}
if (SortByService.getSortBy() === 'sortLastName') {
return (
ctrl.contact.lastName() + ', '
+ ctrl.contact.firstName() + ' '
+ ctrl.contact.additionalNames()
).trim();
}
if (SortByService.getSortBy() === 'sortFirstName') {
return (
ctrl.contact.firstName() + ' '
+ ctrl.contact.additionalNames() + ' '
+ ctrl.contact.lastName()
).trim();
}
return ctrl.contact.displayName();
};
}]);
angular.module('contactsApp')
.directive('contact', function() {
return {
scope: {},
controller: 'contactCtrl',
controllerAs: 'ctrl',
bindToController: {
contact: '=data'
},
templateUrl: OC.linkTo('contacts', 'templates/contact.html')
};
});
angular.module('contactsApp')
.controller('contactdetailsCtrl', ['ContactService', 'AddressBookService', 'vCardPropertiesService', '$route', '$routeParams', '$scope', function(ContactService, AddressBookService, vCardPropertiesService, $route, $routeParams, $scope) {
var ctrl = this;
ctrl.loading = true;
ctrl.show = false;
ctrl.clearContact = function() {
$route.updateParams({
gid: $routeParams.gid,
uid: undefined
});
ctrl.show = false;
ctrl.contact = undefined;
};
ctrl.uid = $routeParams.uid;
ctrl.t = {
noContacts : t('contacts', 'No contacts in here'),
placeholderName : t('contacts', 'Name'),
placeholderOrg : t('contacts', 'Organization'),
placeholderTitle : t('contacts', 'Title'),
selectField : t('contacts', 'Add field ...'),
download : t('contacts', 'Download'),
delete : t('contacts', 'Delete'),
save : t('contacts', 'Save changes'),
addressBook : t('contacts', 'Address book')
};
ctrl.fieldDefinitions = vCardPropertiesService.fieldDefinitions;
ctrl.focus = undefined;
ctrl.field = undefined;
ctrl.addressBooks = [];
AddressBookService.getAll().then(function(addressBooks) {
ctrl.addressBooks = addressBooks;
if (!_.isUndefined(ctrl.contact)) {
ctrl.addressBook = _.find(ctrl.addressBooks, function(book) {
return book.displayName === ctrl.contact.addressBookId;
});
}
ctrl.loading = false;
// Start watching for ctrl.uid when we have addressBooks, as they are needed for fetching
// full details.
$scope.$watch('ctrl.uid', function(newValue) {
ctrl.changeContact(newValue);
});
});
ctrl.changeContact = function(uid) {
if (typeof uid === 'undefined') {
ctrl.show = false;
$('#app-navigation-toggle').removeClass('showdetails');
return;
}
ContactService.getById(ctrl.addressBooks, uid).then(function(contact) {
if (angular.isUndefined(contact)) {
ctrl.clearContact();
return;
}
ctrl.contact = contact;
ctrl.show = true;
$('#app-navigation-toggle').addClass('showdetails');
ctrl.addressBook = _.find(ctrl.addressBooks, function(book) {
return book.displayName === ctrl.contact.addressBookId;
});
});
};
ctrl.updateContact = function() {
ContactService.update(ctrl.contact);
};
ctrl.deleteContact = function() {
ContactService.delete(ctrl.contact);
};
ctrl.addField = function(field) {
var defaultValue = vCardPropertiesService.getMeta(field).defaultValue || {value: ''};
ctrl.contact.addProperty(field, defaultValue);
ctrl.focus = field;
ctrl.field = '';
};
ctrl.deleteField = function (field, prop) {
ctrl.contact.removeProperty(field, prop);
ctrl.focus = undefined;
};
ctrl.changeAddressBook = function (addressBook) {
ContactService.moveContact(ctrl.contact, addressBook);
};
}]);
angular.module('contactsApp')
.directive('contactdetails', function() {
return {
priority: 1,
scope: {},
controller: 'contactdetailsCtrl',
controllerAs: 'ctrl',
bindToController: {},
templateUrl: OC.linkTo('contacts', 'templates/contactDetails.html')
};
});
angular.module('contactsApp')
.controller('contactimportCtrl', ['ContactService', function(ContactService) {
var ctrl = this;
ctrl.import = ContactService.import.bind(ContactService);
}]);
angular.module('contactsApp')
.directive('contactimport', ['ContactService', function(ContactService) {
return {
link: function(scope, element) {
var importText = t('contacts', 'Import');
scope.importText = importText;
var input = element.find('input');
input.bind('change', function() {
angular.forEach(input.get(0).files, function(file) {
var reader = new FileReader();
reader.addEventListener('load', function () {
scope.$apply(function () {
ContactService.import.call(ContactService, reader.result, file.type, null, function (progress) {
if (progress === 1) {
scope.importText = importText;
} else {
scope.importText = parseInt(Math.floor(progress * 100)) + '%';
}
});
});
}, false);
if (file) {
reader.readAsText(file);
}
});
input.get(0).value = '';
});
},
templateUrl: OC.linkTo('contacts', 'templates/contactImport.html')
};
}]);
angular.module('contactsApp')
.controller('contactlistCtrl', ['$scope', '$filter', '$route', '$routeParams', '$timeout', 'ContactService', 'SortByService', 'vCardPropertiesService', 'SearchService', function($scope, $filter, $route, $routeParams, $timeout, ContactService, SortByService, vCardPropertiesService, SearchService) {
var ctrl = this;
ctrl.routeParams = $routeParams;
ctrl.contactList = [];
ctrl.searchTerm = '';
ctrl.show = true;
ctrl.invalid = false;
ctrl.limitTo = 25;
ctrl.sortBy = SortByService.getSortBy();
ctrl.t = {
emptySearch : t('contacts', 'No search result for {query}', {query: ctrl.searchTerm})
};
ctrl.resetLimitTo = function () {
ctrl.limitTo = 25;
clearInterval(ctrl.intervalId);
ctrl.intervalId = setInterval(
function () {
if (!ctrl.loading && ctrl.contacts && ctrl.contacts.length > ctrl.limitTo) {
ctrl.limitTo += 25;
$scope.$apply();
}
}, 300);
};
$scope.query = function(contact) {
return contact.matches(SearchService.getSearchTerm());
};
SortByService.subscribe(function(newValue) {
ctrl.sortBy = newValue;
});
SearchService.registerObserverCallback(function(ev) {
if (ev.event === 'submitSearch') {
var uid = !_.isEmpty(ctrl.contactList) ? ctrl.contactList[0].uid() : undefined;
ctrl.setSelectedId(uid);
$scope.$apply();
}
if (ev.event === 'changeSearch') {
ctrl.resetLimitTo();
ctrl.searchTerm = ev.searchTerm;
ctrl.t.emptySearch = t('contacts',
'No search result for {query}',
{query: ctrl.searchTerm}
);
$scope.$apply();
}
});
ctrl.loading = true;
ContactService.registerObserverCallback(function(ev) {
$timeout(function () { $scope.$apply(function() {
if (ev.event === 'delete') {
if (ctrl.contactList.length === 1) {
$route.updateParams({
gid: $routeParams.gid,
uid: undefined
});
} else {
for (var i = 0, length = ctrl.contactList.length; i < length; i++) {
if (ctrl.contactList[i].uid() === ev.uid) {
$route.updateParams({
gid: $routeParams.gid,
uid: (ctrl.contactList[i+1]) ? ctrl.contactList[i+1].uid() : ctrl.contactList[i-1].uid()
});
break;
}
}
}
}
else if (ev.event === 'create') {
$route.updateParams({
gid: $routeParams.gid,
uid: ev.uid
});
}
ctrl.contacts = ev.contacts;
}); });
});
// Get contacts
ContactService.getAll().then(function(contacts) {
if(contacts.length>0) {
$scope.$apply(function() {
ctrl.contacts = contacts;
});
} else {
ctrl.loading = false;
}
});
var getVisibleNames = function getVisibleNames() {
function isScrolledIntoView(el) {
var elemTop = el.getBoundingClientRect().top;
var elemBottom = el.getBoundingClientRect().bottom;
var bothAboveViewport = elemBottom < 0;
var bothBelowViewPort = elemTop > window.innerHeight;
var isVisible = !bothAboveViewport && !bothBelowViewPort;
return isVisible;
}
var elements = Array.prototype.slice.call(document.querySelectorAll('.contact__icon:not(.ng-hide)'));
var names = elements
.filter(isScrolledIntoView)
.map(function (el) {
var siblings = Array.prototype.slice.call(el.parentElement.children);
var nameElement = siblings.find(function (sibling) {
return sibling.getAttribute('class').indexOf('content-list-item-line-one') !== -1;
});
return nameElement.innerText;
});
return names;
};
var timeoutId = null;
document.querySelector('.app-content-list').addEventListener('scroll', function () {
clearTimeout(timeoutId);
timeoutId = setTimeout(function () {
var names = getVisibleNames();
ContactService.getFullContacts(names);
}, 250);
});
// Wait for ctrl.contactList to be updated, load the contact requested in the URL if any, and
// load full details for the probably initially visible contacts.
// Then kill the watch.
var unbindListWatch = $scope.$watch('ctrl.contactList', function() {
if(ctrl.contactList && ctrl.contactList.length > 0) {
// Check if a specific uid is requested
if($routeParams.uid && $routeParams.gid) {
ctrl.contactList.forEach(function(contact) {
if(contact.uid() === $routeParams.uid) {
ctrl.setSelectedId($routeParams.uid);
ctrl.loading = false;
}
});
}
// No contact previously loaded, let's load the first of the list if not in mobile mode
if(ctrl.loading && $(window).width() > 768) {
ctrl.setSelectedId(ctrl.contactList[0].uid());
}
var firstNames = ctrl.contactList.slice(0, 20).map(function (c) { return c.displayName(); });
ContactService.getFullContacts(firstNames);
ctrl.loading = false;
unbindListWatch();
}
});
$scope.$watch('ctrl.routeParams.uid', function(newValue, oldValue) {
// Used for mobile view to clear the url
if(typeof oldValue != 'undefined' && typeof newValue == 'undefined' && $(window).width() <= 768) {
// no contact selected
ctrl.show = true;
return;
}
if(newValue === undefined) {
// we might have to wait until ng-repeat filled the contactList
if(ctrl.contactList && ctrl.contactList.length > 0) {
$route.updateParams({
gid: $routeParams.gid,
uid: ctrl.contactList[0].uid()
});
} else {
// watch for next contactList update
var unbindWatch = $scope.$watch('ctrl.contactList', function() {
if(ctrl.contactList && ctrl.contactList.length > 0) {
$route.updateParams({
gid: $routeParams.gid,
uid: ctrl.contactList[0].uid()
});
}
unbindWatch(); // unbind as we only want one update
});
}
} else {
// displaying contact details
ctrl.show = false;
}
});
$scope.$watch('ctrl.routeParams.gid', function() {
// we might have to wait until ng-repeat filled the contactList
ctrl.contactList = [];
ctrl.resetLimitTo();
// not in mobile mode
if($(window).width() > 768) {
// watch for next contactList update
var unbindWatch = $scope.$watch('ctrl.contactList', function() {
if(ctrl.contactList && ctrl.contactList.length > 0) {
$route.updateParams({
gid: $routeParams.gid,
uid: $routeParams.uid || ctrl.contactList[0].uid()
});
}
unbindWatch(); // unbind as we only want one update
});
}
});
// Watch if we have an invalid contact
$scope.$watch('ctrl.contactList[0].displayName()', function(displayName) {
ctrl.invalid = (displayName === '');
});
ctrl.hasContacts = function () {
if (!ctrl.contacts) {
return false;
}
return ctrl.contacts.length > 0;
};
ctrl.setSelectedId = function (contactId) {
$route.updateParams({
uid: contactId
});
};
ctrl.getSelectedId = function() {
return $routeParams.uid;
};
}]);
angular.module('contactsApp')
.directive('contactlist', function() {
return {
priority: 1,
scope: {},
controller: 'contactlistCtrl',
controllerAs: 'ctrl',
bindToController: {
addressbook: '=adrbook'
},
templateUrl: OC.linkTo('contacts', 'templates/contactList.html')
};
});
angular.module('contactsApp')
.controller('detailsItemCtrl', ['$templateRequest', 'vCardPropertiesService', 'ContactService', function($templateRequest, vCardPropertiesService, ContactService) {
var ctrl = this;
ctrl.meta = vCardPropertiesService.getMeta(ctrl.name);
ctrl.type = undefined;
ctrl.isPreferred = false;
ctrl.t = {
poBox : t('contacts', 'Post office box'),
postalCode : t('contacts', 'Postal code'),
city : t('contacts', 'City'),
state : t('contacts', 'State or province'),
country : t('contacts', 'Country'),
address: t('contacts', 'Address'),
newGroup: t('contacts', '(new group)'),
familyName: t('contacts', 'Last name'),
firstName: t('contacts', 'First name'),
additionalNames: t('contacts', 'Additional names'),
honorificPrefix: t('contacts', 'Prefix'),
honorificSuffix: t('contacts', 'Suffix'),
delete: t('contacts', 'Delete')
};
ctrl.availableOptions = ctrl.meta.options || [];
if (!_.isUndefined(ctrl.data) && !_.isUndefined(ctrl.data.meta) && !_.isUndefined(ctrl.data.meta.type)) {
// parse type of the property
var array = ctrl.data.meta.type[0].split(',');
array = array.map(function (elem) {
return elem.trim().replace(/\/+$/, '').replace(/\\+$/, '').trim().toUpperCase();
});
// the pref value is handled on its own so that we can add some favorite icon to the ui if we want
if (array.indexOf('PREF') >= 0) {
ctrl.isPreferred = true;
array.splice(array.indexOf('PREF'), 1);
}
// simply join the upper cased types together as key
ctrl.type = array.join(',');
var displayName = array.map(function (element) {
return element.charAt(0).toUpperCase() + element.slice(1).toLowerCase();
}).join(' ');
// in case the type is not yet in the default list of available options we add it
if (!ctrl.availableOptions.some(function(e) { return e.id === ctrl.type; } )) {
ctrl.availableOptions = ctrl.availableOptions.concat([{id: ctrl.type, name: displayName}]);
}
}
if (!_.isUndefined(ctrl.data) && !_.isUndefined(ctrl.data.namespace)) {
if (!_.isUndefined(ctrl.model.contact.props['X-ABLABEL'])) {
var val = _.find(this.model.contact.props['X-ABLABEL'], function(x) { return x.namespace === ctrl.data.namespace; });
ctrl.type = val.value;
if (!_.isUndefined(val)) {
// in case the type is not yet in the default list of available options we add it
if (!ctrl.availableOptions.some(function(e) { return e.id === val.value; } )) {
ctrl.availableOptions = ctrl.availableOptions.concat([{id: val.value, name: val.value}]);
}
}
}
}
ctrl.availableGroups = [];
ContactService.getGroups().then(function(groups) {
ctrl.availableGroups = _.unique(groups);
});
ctrl.changeType = function (val) {
if (ctrl.isPreferred) {
val += ',PREF';
}
ctrl.data.meta = ctrl.data.meta || {};
ctrl.data.meta.type = ctrl.data.meta.type || [];
ctrl.data.meta.type[0] = val;
ctrl.model.updateContact();
};
ctrl.dateInputChanged = function () {
ctrl.data.meta = ctrl.data.meta || {};
var match = ctrl.data.value.match(/^(\d{4})-(\d{2})-(\d{2})$/);
if (match) {
ctrl.data.meta.value = [];
} else {
ctrl.data.meta.value = ctrl.data.meta.value || [];
ctrl.data.meta.value[0] = 'text';
}
ctrl.model.updateContact();
};
ctrl.updateDetailedName = function () {
var fn = '';
if (ctrl.data.value[3]) {
fn += ctrl.data.value[3] + ' ';
}
if (ctrl.data.value[1]) {
fn += ctrl.data.value[1] + ' ';
}
if (ctrl.data.value[2]) {
fn += ctrl.data.value[2] + ' ';
}
if (ctrl.data.value[0]) {
fn += ctrl.data.value[0] + ' ';
}
if (ctrl.data.value[4]) {
fn += ctrl.data.value[4];
}
ctrl.model.contact.fullName(fn);
ctrl.model.updateContact();
};
ctrl.getTemplate = function() {
var templateUrl = OC.linkTo('contacts', 'templates/detailItems/' + ctrl.meta.template + '.html');
return $templateRequest(templateUrl);
};
ctrl.deleteField = function () {
ctrl.model.deleteField(ctrl.name, ctrl.data);
ctrl.model.updateContact();
};
}]);
angular.module('contactsApp')
.directive('detailsitem', ['$compile', function($compile) {
return {
scope: {},
controller: 'detailsItemCtrl',
controllerAs: 'ctrl',
bindToController: {
name: '=',
data: '=',
model: '=',
index: '='
},
link: function(scope, element, attrs, ctrl) {
ctrl.getTemplate().then(function(html) {
var template = angular.element(html);
element.append(template);
$compile(template)(scope);
});
}
};
}]);
angular.module('contactsApp')
.controller('groupCtrl', function() {
// eslint-disable-next-line no-unused-vars
var ctrl = this;
});
angular.module('contactsApp')
.directive('group', function() {
return {
restrict: 'A', // has to be an attribute to work with core css
scope: {},
controller: 'groupCtrl',
controllerAs: 'ctrl',
bindToController: {
group: '=groupName',
groupCount: '=groupCount'
},
templateUrl: OC.linkTo('contacts', 'templates/group.html')
};
});
angular.module('contactsApp')
.controller('grouplistCtrl', ['$scope', 'ContactService', 'SearchService', '$routeParams', function($scope, ContactService, SearchService, $routeParams) {
var ctrl = this;
ctrl.groups = [];
ContactService.getGroupList().then(function(groups) {
ctrl.groups = groups;
});
ctrl.getSelected = function() {
return $routeParams.gid;
};
// Update groupList on contact add/delete/update
ContactService.registerObserverCallback(function(ev) {
if (ev.event !== 'getFullContacts') {
$scope.$apply(function() {
ContactService.getGroupList().then(function(groups) {
ctrl.groups = groups;
});
});
}
});
ctrl.setSelected = function (selectedGroup) {
SearchService.cleanSearch();
$routeParams.gid = selectedGroup;
};
}]);
angular.module('contactsApp')
.directive('grouplist', function() {
return {
restrict: 'EA', // has to be an attribute to work with core css
scope: {},
controller: 'grouplistCtrl',
controllerAs: 'ctrl',
bindToController: {},
templateUrl: OC.linkTo('contacts', 'templates/groupList.html')
};
});
angular.module('contactsApp')
.controller('newContactButtonCtrl', ['$scope', 'ContactService', '$routeParams', 'vCardPropertiesService', function($scope, ContactService, $routeParams, vCardPropertiesService) {
var ctrl = this;
ctrl.t = {
addContact : t('contacts', 'New contact')
};
ctrl.createContact = function() {
ContactService.create().then(function(contact) {
['tel', 'adr', 'email'].forEach(function(field) {
var defaultValue = vCardPropertiesService.getMeta(field).defaultValue || {value: ''};
contact.addProperty(field, defaultValue);
} );
ContactService.updateNewContactJustAdded();
if ([t('contacts', 'All contacts'), t('contacts', 'Not grouped')].indexOf($routeParams.gid) === -1) {
contact.categories([ $routeParams.gid ]);
} else {
contact.categories([]);
}
$('#details-fullName').focus();
});
};
}]);
angular.module('contactsApp')
.directive('newcontactbutton', function() {
return {
restrict: 'EA', // has to be an attribute to work with core css
scope: {},
controller: 'newContactButtonCtrl',
controllerAs: 'ctrl',
bindToController: {},
templateUrl: OC.linkTo('contacts', 'templates/newContactButton.html')
};
});
angular.module('contactsApp')
.directive('telModel', function() {
return{
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attr, ngModel) {
ngModel.$formatters.push(function(value) {
return value;
});
ngModel.$parsers.push(function(value) {
return value;
});
}
};
});
angular.module('contactsApp')
.controller('sortbyCtrl', ['SortByService', function(SortByService) {
var ctrl = this;
var sortText = t('contacts', 'Sort by');
ctrl.sortText = sortText;
var sortList = SortByService.getSortByList();
ctrl.sortList = sortList;
ctrl.defaultOrder = SortByService.getSortBy();
ctrl.updateSortBy = function() {
SortByService.setSortBy(ctrl.defaultOrder);
};
}]);
angular.module('contactsApp')
.directive('sortby', function() {
return {
priority: 1,
scope: {},
controller: 'sortbyCtrl',
controllerAs: 'ctrl',
bindToController: {},
templateUrl: OC.linkTo('contacts', 'templates/sortBy.html')
};
});
angular.module('contactsApp')
.factory('AddressBook', function()
{
return function AddressBook(data) {
angular.extend(this, {
displayName: '',
contacts: [],
groups: data.data.props.groups,
getContact: function(uid) {
for(var i in this.contacts) {
if(this.contacts[i].uid() === uid) {
return this.contacts[i];
}
}
return undefined;
},
sharedWith: {
users: [],
groups: []
}
});
angular.extend(this, data);
angular.extend(this, {
owner: data.url.split('/').slice(-3, -2)[0]
});
var shares = this.data.props.invite;
if (typeof shares !== 'undefined') {
for (var j = 0; j < shares.length; j++) {
var href = shares[j].href;
if (href.length === 0) {
continue;
}
var access = shares[j].access;
if (access.length === 0) {
continue;
}
var readWrite = (typeof access.readWrite !== 'undefined');
if (href.startsWith('principal:principals/users/')) {
this.sharedWith.users.push({
id: href.substr(27),
displayname: href.substr(27),
writable: readWrite
});
} else if (href.startsWith('principal:principals/groups/')) {
this.sharedWith.groups.push({
id: href.substr(28),
displayname: href.substr(28),
writable: readWrite
});
}
}
}
//var owner = this.data.props.owner;
//if (typeof owner !== 'undefined' && owner.length !== 0) {
// owner = owner.trim();
// if (owner.startsWith('/remote.php/dav/principals/users/')) {
// this._properties.owner = owner.substr(33);
// }
//}
};
});
angular.module('contactsApp')
.factory('Contact', ['$filter', 'MimeService', function($filter, MimeService) {
return function Contact(addressBook, vCard) {
angular.extend(this, {
data: {},
props: {},
failedProps: [],
dateProperties: ['bday', 'anniversary', 'deathdate'],
addressBookId: addressBook.displayName,
version: function() {
var property = this.getProperty('version');
if(property) {
return property.value;
}
return undefined;
},
uid: function(value) {
var model = this;
if (angular.isDefined(value)) {
// setter
return model.setProperty('uid', { value: value });
} else {
// getter
return model.getProperty('uid').value;
}
},
sortFirstName: function() {
return [this.firstName(), this.lastName()];
},
sortLastName: function() {
return [this.lastName(), this.firstName()];
},
sortDisplayName: function() {
return this.displayName();
},
displayName: function() {
var displayName = this.fullName() || this.org() || '';
if(angular.isArray(displayName)) {
return displayName.join(' ');
}
return displayName;
},
readableFilename: function() {
if(this.displayName()) {
return (this.displayName()) + '.vcf';
} else {
// fallback to default filename (see download attribute)
return '';
}
},
firstName: function() {
var property = this.getProperty('n');
if (property) {
return property.value[1];
} else {
return this.displayName();
}
},
lastName: function() {
var property = this.getProperty('n');
if (property) {
return property.value[0];
} else {
return this.displayName();
}
},
additionalNames: function() {
var property = this.getProperty('n');
if (property) {
return property.value[2];
} else {
return '';
}
},
fullName: function(value) {
var model = this;
if (angular.isDefined(value)) {
// setter
return this.setProperty('fn', { value: value });
} else {
// getter
var property = model.getProperty('fn');
if(property) {
return property.value;
}
property = model.getProperty('n');
if(property) {
return property.value.filter(function(elem) {
return elem;
}).join(' ');
}
return undefined;
}
},
title: function(value) {
if (angular.isDefined(value)) {
// setter
return this.setProperty('title', { value: value });
} else {
// getter
var property = this.getProperty('title');
if(property) {
return property.value;
} else {
return undefined;
}
}
},
org: function(value) {
var property = this.getProperty('org');
if (angular.isDefined(value)) {
var val = value;
// setter
if(property && Array.isArray(property.value)) {
val = property.value;
val[0] = value;
}
return this.setProperty('org', { value: val });
} else {
// getter
if(property) {
if (Array.isArray(property.value)) {
return property.value[0];
}
return property.value;
} else {
return undefined;
}
}
},
email: function() {
// getter
var property = this.getProperty('email');
if(property) {
return property.value;
} else {
return undefined;
}
},
photo: function(value) {
if (angular.isDefined(value)) {
// setter
// splits image data into "data:image/jpeg" and base 64 encoded image
var imageData = value.split(';base64,');
var imageType = imageData[0].slice('data:'.length);
if (!imageType.startsWith('image/')) {
return;
}
imageType = imageType.substring(6).toUpperCase();
return this.setProperty('photo', { value: imageData[1], meta: {type: [imageType], encoding: ['b']} });
} else {
var property = this.validate('photo', this.getProperty('photo'));
if(property) {
var type = property.meta.type;
if (angular.isArray(type)) {
type = type[0];
}
if (!type.startsWith('image/')) {
type = 'image/' + type.toLowerCase();
}
return 'data:' + type + ';base64,' + property.value;
} else {
return undefined;
}
}
},
categories: function(value) {
if (angular.isDefined(value)) {
// setter
if (angular.isString(value)) {
/* check for empty string */
this.setProperty('categories', { value: !value.length ? [] : [value] });
} else if (angular.isArray(value)) {
this.setProperty('categories', { value: value });
}
} else {
// getter
var property = this.validate('categories', this.getProperty('categories'));
if(!property) {
return [];
}
if (angular.isArray(property.value)) {
return property.value;
}
return [property.value];
}
},
formatDateAsRFC6350: function(name, data) {
if (angular.isUndefined(data) || angular.isUndefined(data.value)) {
return data;
}
if (this.dateProperties.indexOf(name) !== -1) {
var match = data.value.match(/^(\d{4})-(\d{2})-(\d{2})$/);
if (match) {
data.value = match[1] + match[2] + match[3];
}
}
return data;
},
formatDateForDisplay: function(name, data) {
if (angular.isUndefined(data) || angular.isUndefined(data.value)) {
return data;
}
if (this.dateProperties.indexOf(name) !== -1) {
var match = data.value.match(/^(\d{4})(\d{2})(\d{2})$/);
if (match) {
data.value = match[1] + '-' + match[2] + '-' + match[3];
}
}
return data;
},
getProperty: function(name) {
if (this.props[name]) {
return this.formatDateForDisplay(name, this.props[name][0]);
} else {
return undefined;
}
},
addProperty: function(name, data) {
data = angular.copy(data);
data = this.formatDateAsRFC6350(name, data);
if(!this.props[name]) {
this.props[name] = [];
}
var idx = this.props[name].length;
this.props[name][idx] = data;
// keep vCard in sync
this.data.addressData = $filter('JSON2vCard')(this.props);
return idx;
},
setProperty: function(name, data) {
if(!this.props[name]) {
this.props[name] = [];
}
data = this.formatDateAsRFC6350(name, data);
this.props[name][0] = data;
// keep vCard in sync
this.data.addressData = $filter('JSON2vCard')(this.props);
},
removeProperty: function (name, prop) {
angular.copy(_.without(this.props[name], prop), this.props[name]);
this.data.addressData = $filter('JSON2vCard')(this.props);
},
setETag: function(etag) {
this.data.etag = etag;
},
setUrl: function(addressBook, uid) {
this.data.url = addressBook.url + uid + '.vcf';
},
getISODate: function(date) {
function pad(number) {
if (number < 10) {
return '0' + number;
}
return '' + number;
}
return date.getUTCFullYear() + '' +
pad(date.getUTCMonth() + 1) +
pad(date.getUTCDate()) +
'T' + pad(date.getUTCHours()) +
pad(date.getUTCMinutes()) +
pad(date.getUTCSeconds()) + 'Z';
},
syncVCard: function() {
this.setProperty('rev', { value: this.getISODate(new Date()) });
var self = this;
_.each(this.dateProperties, function(name) {
if (!angular.isUndefined(self.props[name]) && !angular.isUndefined(self.props[name][0])) {
// Set dates again to make sure they are in RFC-6350 format
self.setProperty(name, self.props[name][0]);
}
});
// force fn to be set
this.fullName(this.fullName());
// keep vCard in sync
self.data.addressData = $filter('JSON2vCard')(self.props);
// Revalidate all props
_.each(self.failedProps, function(name, index) {
if (!angular.isUndefined(self.props[name]) && !angular.isUndefined(self.props[name][0])) {
// Reset previously failed properties
self.failedProps.splice(index, 1);
// And revalidate them again
self.validate(name, self.props[name][0]);
} else if(angular.isUndefined(self.props[name]) || angular.isUndefined(self.props[name][0])) {
// Property has been removed
self.failedProps.splice(index, 1);
}
});
},
matches: function(pattern) {
if (angular.isUndefined(pattern) || pattern.length === 0) {
return true;
}
var model = this;
var matchingProps = ['fn', 'title', 'org', 'email', 'nickname', 'note', 'url', 'cloud', 'adr', 'impp', 'tel'].filter(function (propName) {
if (model.props[propName]) {
return model.props[propName].filter(function (property) {
if (!property.value) {
return false;
}
if (angular.isString(property.value)) {
return property.value.toLowerCase().indexOf(pattern.toLowerCase()) !== -1;
}
if (angular.isArray(property.value)) {
return property.value.filter(function(v) {
return v.toLowerCase().indexOf(pattern.toLowerCase()) !== -1;
}).length > 0;
}
return false;
}).length > 0;
}
return false;
});
return matchingProps.length > 0;
},
/* eslint-disable no-console */
validate: function(prop, property) {
switch(prop) {
case 'categories':
// Avoid unescaped commas
if (angular.isArray(property.value)) {
if(property.value.join(';').indexOf(',') !== -1) {
this.failedProps.push(prop);
property.value = property.value.join(',').split(',');
//console.warn(this.uid()+': Categories split: ' + property.value);
}
} else if (angular.isString(property.value)) {
if(property.value.indexOf(',') !== -1) {
this.failedProps.push(prop);
property.value = property.value.split(',');
//console.warn(this.uid()+': Categories split: ' + property.value);
}
}
if(property.value.length !== 0) {
// Remove duplicate categories
var uniqueCategories = _.unique(property.value);
if(!angular.equals(uniqueCategories, property.value)) {
this.failedProps.push(prop);
property.value = uniqueCategories;
//console.warn(this.uid()+': Categories duplicate: ' + property.value);
}
}
break;
case 'photo':
// Avoid undefined photo type
if (angular.isDefined(property)) {
if (angular.isUndefined(property.meta.type)) {
var mime = MimeService.b64mime(property.value);
if (mime) {
this.failedProps.push(prop);
property.meta.type=[mime];
this.setProperty('photo', {value:property.value,
meta:{type:property.meta.type,
encoding:property.meta.encoding}});
console.warn(this.uid()+': Photo detected as ' + property.meta.type);
} else {
this.failedProps.push(prop);
this.removeProperty('photo', property);
property = undefined;
console.warn(this.uid()+': Photo removed');
}
}
}
break;
}
return property;
}
/* eslint-enable no-console */
});
if(angular.isDefined(vCard)) {
angular.extend(this.data, vCard);
angular.extend(this.props, $filter('vCard2JSON')(this.data.addressData));
} else {
angular.extend(this.props, {
version: [{value: '3.0'}],
fn: [{value: ''}]
});
this.data.addressData = $filter('JSON2vCard')(this.props);
}
var property = this.getProperty('categories');
if(!property) {
// categories should always have the same type (an array)
this.categories([]);
} else {
if (angular.isString(property.value)) {
this.categories([property.value]);
}
}
};
}]);
angular.module('contactsApp')
.factory('AddressBookService', ['DavClient', 'DavService', 'SettingsService', 'AddressBook', '$q', function(DavClient, DavService, SettingsService, AddressBook, $q) {
var addressBooks = [];
var loadPromise = undefined;
var loadAll = function() {
if (addressBooks.length > 0) {
return $q.when(addressBooks);
}
if (_.isUndefined(loadPromise)) {
loadPromise = DavService.then(function(account) {
loadPromise = undefined;
addressBooks = account.addressBooks.map(function(addressBook) {
return new AddressBook(addressBook);
});
});
}
return loadPromise;
};
return {
getAll: function() {
return loadAll().then(function() {
return addressBooks;
});
},
getGroups: function () {
return this.getAll().then(function(addressBooks) {
return addressBooks.map(function (element) {
return element.groups;
}).reduce(function(a, b) {
return a.concat(b);
});
});
},
getDefaultAddressBook: function() {
return addressBooks[0];
},
getAddressBook: function(displayName) {
return DavService.then(function(account) {
return DavClient.getAddressBook({displayName:displayName, url:account.homeUrl}).then(function(addressBook) {
addressBook = new AddressBook({
url: account.homeUrl+displayName+'/',
data: addressBook[0]
});
addressBook.displayName = displayName;
return addressBook;
});
});
},
create: function(displayName) {
return DavService.then(function(account) {
return DavClient.createAddressBook({displayName:displayName, url:account.homeUrl});
});
},
delete: function(addressBook) {
return DavService.then(function() {
return DavClient.deleteAddressBook(addressBook).then(function() {
var index = addressBooks.indexOf(addressBook);
addressBooks.splice(index, 1);
});
});
},
rename: function(addressBook, displayName) {
return DavService.then(function(account) {
return DavClient.renameAddressBook(addressBook, {displayName:displayName, url:account.homeUrl});
});
},
get: function(displayName) {
return this.getAll().then(function(addressBooks) {
return addressBooks.filter(function (element) {
return element.displayName === displayName;
})[0];
});
},
sync: function(addressBook) {
return DavClient.syncAddressBook(addressBook);
},
share: function(addressBook, shareType, shareWith, writable, existingShare) {
var xmlDoc = document.implementation.createDocument('', '', null);
var oShare = xmlDoc.createElement('o:share');
oShare.setAttribute('xmlns:d', 'DAV:');
oShare.setAttribute('xmlns:o', 'http://owncloud.org/ns');
xmlDoc.appendChild(oShare);
var oSet = xmlDoc.createElement('o:set');
oShare.appendChild(oSet);
var dHref = xmlDoc.createElement('d:href');
if (shareType === OC.Share.SHARE_TYPE_USER) {
dHref.textContent = 'principal:principals/users/';
} else if (shareType === OC.Share.SHARE_TYPE_GROUP) {
dHref.textContent = 'principal:principals/groups/';
}
dHref.textContent += shareWith;
oSet.appendChild(dHref);
var oSummary = xmlDoc.createElement('o:summary');
oSummary.textContent = t('contacts', '{addressbook} shared by {owner}', {
addressbook: addressBook.displayName,
owner: addressBook.owner
});
oSet.appendChild(oSummary);
if (writable) {
var oRW = xmlDoc.createElement('o:read-write');
oSet.appendChild(oRW);
}
var body = oShare.outerHTML;
return DavClient.xhr.send(
dav.request.basic({method: 'POST', data: body}),
addressBook.url
).then(function(response) {
if (response.status === 200) {
if (!existingShare) {
if (shareType === OC.Share.SHARE_TYPE_USER) {
addressBook.sharedWith.users.push({
id: shareWith,
displayname: shareWith,
writable: writable
});
} else if (shareType === OC.Share.SHARE_TYPE_GROUP) {
addressBook.sharedWith.groups.push({
id: shareWith,
displayname: shareWith,
writable: writable
});
}
}
}
});
},
unshare: function(addressBook, shareType, shareWith) {
var xmlDoc = document.implementation.createDocument('', '', null);
var oShare = xmlDoc.createElement('o:share');
oShare.setAttribute('xmlns:d', 'DAV:');
oShare.setAttribute('xmlns:o', 'http://owncloud.org/ns');
xmlDoc.appendChild(oShare);
var oRemove = xmlDoc.createElement('o:remove');
oShare.appendChild(oRemove);
var dHref = xmlDoc.createElement('d:href');
if (shareType === OC.Share.SHARE_TYPE_USER) {
dHref.textContent = 'principal:principals/users/';
} else if (shareType === OC.Share.SHARE_TYPE_GROUP) {
dHref.textContent = 'principal:principals/groups/';
}
dHref.textContent += shareWith;
oRemove.appendChild(dHref);
var body = oShare.outerHTML;
return DavClient.xhr.send(
dav.request.basic({method: 'POST', data: body}),
addressBook.url
).then(function(response) {
if (response.status === 200) {
if (shareType === OC.Share.SHARE_TYPE_USER) {
addressBook.sharedWith.users = addressBook.sharedWith.users.filter(function(user) {
return user.id !== shareWith;
});
} else if (shareType === OC.Share.SHARE_TYPE_GROUP) {
addressBook.sharedWith.groups = addressBook.sharedWith.groups.filter(function(groups) {
return groups.id !== shareWith;
});
}
//todo - remove entry from addressbook object
return true;
} else {
return false;
}
});
}
};
}]);
angular.module('contactsApp')
.service('ContactService', ['DavClient', 'AddressBookService', 'Contact', '$routeParams', '$q', 'CacheFactory', 'uuid4', 'vCardPropertiesService', function(DavClient, AddressBookService, Contact, $routeParams, $q, CacheFactory, uuid4, vCardPropertiesService ) {
var cacheFilled = false;
var contacts = CacheFactory('contacts');
var urlsByDisplayname = CacheFactory('urlsByDisplayname');
var observerCallbacks = [];
var loadPromise = undefined;
var newContactJustAdded = false;
this.registerObserverCallback = function(callback) {
observerCallbacks.push(callback);
};
var notifyObservers = function(eventName, uid) {
var ev = {
event: eventName,
uid: uid,
contacts: contacts.values()
};
angular.forEach(observerCallbacks, function(callback) {
callback(ev);
});
};
this.getFullContacts = function getFullContacts(names) {
AddressBookService.getAll().then(function (enabledAddressBooks) {
var promises = [];
enabledAddressBooks.forEach(function (addressBook) {
var urlLists = names.map(function (name) { return urlsByDisplayname.get(name); });
var urls = [].concat.apply([], urlLists);
var promise = DavClient.getContacts(addressBook, {}, urls)
.then(
function (vcards) {
return vcards.map(function (vcard) {
return new Contact(addressBook, vcard);
});
})
.then(function (contacts_) {
contacts_.map(function (contact) {
contacts.put(contact.uid(), contact);
});
});
promises.push(promise);
});
$q.all(promises).then(function () {
notifyObservers('getFullContacts', '');
});
});
};
this.fillCache = function() {
if (_.isUndefined(loadPromise)) {
loadPromise = AddressBookService.getAll().then(function (enabledAddressBooks) {
var promises = [];
enabledAddressBooks.forEach(function (addressBook) {
promises.push(
AddressBookService.sync(addressBook).then(function (addressBook) {
for (var i in addressBook.objects) {
if (addressBook.objects[i].addressData) {
var contact = new Contact(addressBook, addressBook.objects[i]);
contacts.put(contact.uid(), contact);
var oldList = urlsByDisplayname.get(contact.displayName()) || [];
urlsByDisplayname.put(contact.displayName(), oldList.concat(contact.data.url));
} else {
// eslint-disable-next-line no-console
console.log('Invalid contact received: ' + addressBook.objects[i].url);
}
}
})
);
});
return $q.all(promises).then(function () {
cacheFilled = true;
});
});
}
return loadPromise;
};
this.getAll = function() {
if(cacheFilled === false) {
return this.fillCache().then(function() {
return contacts.values();
});
} else {
return $q.when(contacts.values());
}
};
// get list of groups and the count of contacts in said groups
this.getGroupList = function () {
return this.getAll().then(function(contacts) {
// the translated names for all and not-grouped are used in filtering, they must be exactly like this
var allContacts = [t('contacts', 'All contacts'), contacts.length];
var notGrouped =
[t('contacts', 'Not grouped'),
contacts.filter(
function (contact) {
return contact.categories().length === 0;
}).length
];
// allow groups with names such as toString
var otherGroups = Object.create(null);
// collect categories and their associated counts
contacts.forEach(function (contact) {
contact.categories().forEach(function (category) {
otherGroups[category] = otherGroups[category] ? otherGroups[category] + 1 : 1;
});
});
return [allContacts, notGrouped]
.concat(_.keys(otherGroups).map(
function (key) {
return [key, otherGroups[key]];
}));
});
};
this.getGroups = function () {
return this.getAll().then(function(contacts) {
return _.uniq(contacts.map(function (element) {
return element.categories();
}).reduce(function(a, b) {
return a.concat(b);
}, []).sort(), true);
});
};
this.updateNewContactJustAdded = function () {
newContactJustAdded = true;
};
this.getById = function(addressBooks, uid) {
return (function () {
if(cacheFilled === false) {
return this.fillCache().then(function() {
return contacts.get(uid);
});
} else {
return $q.when(contacts.get(uid));
}
}).call(this)
.then(function (contact) {
var addressBook = _.find(addressBooks, function(book) {
return book.displayName === contact.addressBookId;
});
return addressBook
? DavClient.getContacts(addressBook, {}, [ contact.data.url ]).then(
function (vcards) {
var newContact = new Contact(addressBook, vcards[0]);
if(newContactJustAdded === true) {
['tel', 'adr', 'email'].forEach(function(field) {
var defaultValue = vCardPropertiesService.getMeta(field).defaultValue || {value: ''};
newContact.addProperty(field, defaultValue);
} );
if ([t('contacts', 'All contacts'), t('contacts', 'Not grouped')].indexOf($routeParams.gid) === -1) {
newContact.categories([ $routeParams.gid ]);
} else {
newContact.categories([]);
}
newContactJustAdded = false;
}
return newContact;
}
//function (vcards) { return new Contact(addressBook, vcards[0]); }
).then(function (contact) {
contacts.put(contact.uid(), contact);
notifyObservers('getFullContacts', contact.uid());
return contact;
}) : contact;
});
};
this.create = function(newContact, addressBook, uid) {
addressBook = addressBook || AddressBookService.getDefaultAddressBook();
try {
newContact = newContact || new Contact(addressBook);
} catch(error) {
OC.Notification.showTemporary(t('contacts', 'Contact could not be created.'));
}
var newUid = '';
if(uuid4.validate(uid)) {
newUid = uid;
} else {
newUid = uuid4.generate();
}
newContact.uid(newUid);
newContact.setUrl(addressBook, newUid);
newContact.addressBookId = addressBook.displayName;
if (_.isUndefined(newContact.fullName()) || newContact.fullName() === '') {
newContact.fullName(t('contacts', 'New contact'));
}
return DavClient.createCard(
addressBook,
{
data: newContact.data.addressData,
filename: newUid + '.vcf'
}
).then(function(xhr) {
if (!(_.isUndefined(newContact.fullName()) || newContact.fullName() === '')) {
newContact.setETag(xhr.getResponseHeader('ETag'));
contacts.put(newUid, newContact);
notifyObservers('create', newUid);
$('#details-fullName').select();
return newContact;
}
}).catch(function() {
OC.Notification.showTemporary(t('contacts', 'Contact could not be created.'));
});
};
this.import = function(data, type, addressBook, progressCallback) {
addressBook = addressBook || AddressBookService.getDefaultAddressBook();
var regexp = /BEGIN:VCARD[\s\S]*?END:VCARD/mgi;
var singleVCards = data.match(regexp);
if (!singleVCards) {
OC.Notification.showTemporary(t('contacts', 'No contacts in file. Only vCard files are allowed.'));
if (progressCallback) {
progressCallback(1);
}
return;
}
var num = 1;
for(var i in singleVCards) {
var newContact = new Contact(addressBook, {addressData: singleVCards[i]});
if (['3.0', '4.0'].indexOf(newContact.version()) < 0) {
if (progressCallback) {
progressCallback(num / singleVCards.length);
}
OC.Notification.showTemporary(t('contacts', 'Only vCard version 4.0 (RFC6350) or version 3.0 (RFC2426) are supported.'));
num++;
continue;
}
this.create(newContact, addressBook).then(function() {
// Update the progress indicator
if (progressCallback) {
progressCallback(num / singleVCards.length);
}
num++;
});
}
};
this.moveContact = function (contact, addressbook) {
if (contact.addressBookId === addressbook.displayName) {
return;
}
contact.syncVCard();
var clone = angular.copy(contact);
var uid = contact.uid();
// delete the old one before to avoid conflict
this.delete(contact);
// create the contact in the new target addressbook
this.create(clone, addressbook, uid);
};
this.update = function(contact) {
// update rev field
contact.syncVCard();
// update contact on server
return DavClient.updateCard(contact.data, {json: true}).then(function(xhr) {
var newEtag = xhr.getResponseHeader('ETag');
contact.setETag(newEtag);
notifyObservers('update', contact.uid());
}).catch(function() {
OC.Notification.showTemporary(t('contacts', 'Contact could not be saved.'));
});
};
this.delete = function(contact) {
// delete contact from server
return DavClient.deleteCard(contact.data).then(function() {
contacts.remove(contact.uid());
notifyObservers('delete', contact.uid());
});
};
}]);
angular.module('contactsApp')
.service('DavClient', function() {
var xhr = new dav.transport.Basic(
new dav.Credentials()
);
return new dav.Client(xhr);
});
angular.module('contactsApp')
.service('DavService', ['DavClient', function(DavClient) {
return DavClient.createAccount({
server: OC.linkToRemote('dav/addressbooks'),
accountType: 'carddav',
useProvidedPath: true
});
}]);
angular.module('contactsApp')
.service('MimeService', function() {
var magicNumbers = {
'/9j/' : 'JPEG',
'R0lGOD' : 'GIF',
'iVBORw0KGgo' : 'PNG'
};
this.b64mime = function(b64string) {
for (var mn in magicNumbers) {
if(b64string.startsWith(mn)) return magicNumbers[mn];
}
return null;
};
});
angular.module('contactsApp')
.service('SearchService', function() {
var searchTerm = '';
var observerCallbacks = [];
this.registerObserverCallback = function(callback) {
observerCallbacks.push(callback);
};
var notifyObservers = function(eventName) {
var ev = {
event:eventName,
searchTerm:searchTerm
};
angular.forEach(observerCallbacks, function(callback) {
callback(ev);
});
};
var SearchProxy = {
attach: function(search) {
search.setFilter('contacts', this.filterProxy);
},
filterProxy: function(query) {
searchTerm = query;
notifyObservers('changeSearch');
}
};
this.getSearchTerm = function() {
return searchTerm;
};
this.cleanSearch = function() {
if (!_.isUndefined($('.searchbox'))) {
$('.searchbox')[0].reset();
}
searchTerm = '';
};
if (!_.isUndefined(OC.Plugins)) {
OC.Plugins.register('OCA.Search', SearchProxy);
if (!_.isUndefined(OCA.Search)) {
OC.Search = new OCA.Search($('#searchbox'), $('#searchresults'));
$('#searchbox').show();
}
}
if (!_.isUndefined($('.searchbox'))) {
$('.searchbox')[0].addEventListener('keypress', function(e) {
if(e.keyCode === 13) {
notifyObservers('submitSearch');
}
});
}
});
angular.module('contactsApp')
.service('SettingsService', function() {
var settings = {
addressBooks: [
'testAddr'
]
};
this.set = function(key, value) {
settings[key] = value;
};
this.get = function(key) {
return settings[key];
};
this.getAll = function() {
return settings;
};
});
angular.module('contactsApp')
.service('SortByService', function () {
var subscriptions = [];
var sortBy = 'sortDisplayName';
var defaultOrder = window.localStorage.getItem('contacts_default_order');
if (defaultOrder) {
sortBy = defaultOrder;
}
function notifyObservers () {
angular.forEach(subscriptions, function (subscription) {
if (typeof subscription === 'function') {
subscription(sortBy);
}
});
}
return {
subscribe: function (callback) {
subscriptions.push (callback);
},
setSortBy: function (value) {
sortBy = value;
window.localStorage.setItem ('contacts_default_order', value);
notifyObservers ();
},
getSortBy: function () {
return sortBy;
},
getSortByList: function () {
return {
sortDisplayName: t('contacts', 'Display name'),
sortFirstName: t('contacts', 'First name'),
sortLastName: t('contacts', 'Last name')
};
}
};
});
angular.module('contactsApp')
.service('vCardPropertiesService', function() {
/**
* map vCard attributes to internal attributes
*
* propName: {
* multiple: [Boolean], // is this prop allowed more than once? (default = false)
* readableName: [String], // internationalized readable name of prop
* template: [String], // template name found in /templates/detailItems
* [...] // optional additional information which might get used by the template
* }
*/
this.vCardMeta = {
nickname: {
readableName: t('contacts', 'Nickname'),
template: 'text'
},
n: {
readableName: t('contacts', 'Detailed name'),
defaultValue: {
value:['', '', '', '', '']
},
template: 'n'
},
note: {
readableName: t('contacts', 'Notes'),
template: 'textarea'
},
url: {
multiple: true,
readableName: t('contacts', 'Website'),
template: 'url'
},
cloud: {
multiple: true,
readableName: t('contacts', 'Federated Cloud ID'),
template: 'text',
defaultValue: {
value:[''],
meta:{type:['HOME']}
},
options: [
{id: 'HOME', name: t('contacts', 'Home')},
{id: 'WORK', name: t('contacts', 'Work')},
{id: 'OTHER', name: t('contacts', 'Other')}
] },
adr: {
multiple: true,
readableName: t('contacts', 'Address'),
template: 'adr',
defaultValue: {
value:['', '', '', '', '', '', ''],
meta:{type:['HOME']}
},
options: [
{id: 'HOME', name: t('contacts', 'Home')},
{id: 'WORK', name: t('contacts', 'Work')},
{id: 'OTHER', name: t('contacts', 'Other')}
]
},
categories: {
readableName: t('contacts', 'Groups'),
template: 'groups'
},
bday: {
readableName: t('contacts', 'Birthday'),
template: 'date'
},
anniversary: {
readableName: t('contacts', 'Anniversary'),
template: 'date'
},
deathdate: {
readableName: t('contacts', 'Date of death'),
template: 'date'
},
email: {
multiple: true,
readableName: t('contacts', 'Email'),
template: 'email',
defaultValue: {
value:'',
meta:{type:['HOME']}
},
options: [
{id: 'HOME', name: t('contacts', 'Home')},
{id: 'WORK', name: t('contacts', 'Work')},
{id: 'OTHER', name: t('contacts', 'Other')}
]
},
impp: {
multiple: true,
readableName: t('contacts', 'Instant messaging'),
template: 'username',
defaultValue: {
value:[''],
meta:{type:['SKYPE']}
},
options: [
{id: 'IRC', name: 'IRC'},
{id: 'SKYPE', name:'Skype'},
{id: 'TELEGRAM', name:'Telegram'}
]
},
tel: {
multiple: true,
readableName: t('contacts', 'Phone'),
template: 'tel',
defaultValue: {
value:'',
meta:{type:['HOME,VOICE']}
},
options: [
{id: 'HOME,VOICE', name: t('contacts', 'Home')},
{id: 'WORK,VOICE', name: t('contacts', 'Work')},
{id: 'CELL', name: t('contacts', 'Mobile')},
{id: 'FAX', name: t('contacts', 'Fax')},
{id: 'HOME,FAX', name: t('contacts', 'Fax home')},
{id: 'WORK,FAX', name: t('contacts', 'Fax work')},
{id: 'PAGER', name: t('contacts', 'Pager')},
{id: 'VOICE', name: t('contacts', 'Voice')}
]
},
'X-SOCIALPROFILE': {
multiple: true,
readableName: t('contacts', 'Social network'),
template: 'username',
defaultValue: {
value:[''],
meta:{type:['facebook']}
},
options: [
{id: 'FACEBOOK', name: 'Facebook'},
{id: 'GOOGLEPLUS', name: 'Google+'},
{id: 'INSTAGRAM', name: 'Instagram'},
{id: 'LINKEDIN', name: 'LinkedIn'},
{id: 'PINTEREST', name: 'Pinterest'},
{id: 'TWITTER', name: 'Twitter'}
]
}
};
this.fieldOrder = [
'org',
'title',
'tel',
'email',
'adr',
'impp',
'nick',
'bday',
'anniversary',
'deathdate',
'url',
'X-SOCIALPROFILE',
'note',
'categories',
'role'
];
this.fieldDefinitions = [];
for (var prop in this.vCardMeta) {
this.fieldDefinitions.push({id: prop, name: this.vCardMeta[prop].readableName, multiple: !!this.vCardMeta[prop].multiple});
}
this.fallbackMeta = function(property) {
function capitalize(string) { return string.charAt(0).toUpperCase() + string.slice(1); }
return {
name: 'unknown-' + property,
readableName: capitalize(property),
template: 'hidden',
necessity: 'optional'
};
};
this.getMeta = function(property) {
return this.vCardMeta[property] || this.fallbackMeta(property);
};
});
angular.module('contactsApp')
.filter('JSON2vCard', function() {
return function(input) {
return vCard.generate(input);
};
});
angular.module('contactsApp')
.filter('contactColor', function() {
return function(input) {
// Check if core has the new color generator
if(typeof input.toHsl === 'function') {
var hsl = input.toHsl();
return 'hsl('+hsl[0]+', '+hsl[1]+'%, '+hsl[2]+'%)';
} else {
// If not, we use the old one
/* global md5 */
var hash = md5(input).substring(0, 4),
maxRange = parseInt('ffff', 16),
hue = parseInt(hash, 16) / maxRange * 256;
return 'hsl(' + hue + ', 90%, 65%)';
}
};
});
angular.module('contactsApp')
.filter('contactGroupFilter', function() {
'use strict';
return function (contacts, group) {
if (typeof contacts === 'undefined') {
return contacts;
}
if (typeof group === 'undefined' || group.toLowerCase() === t('contacts', 'All contacts').toLowerCase()) {
return contacts;
}
var filter = [];
if (contacts.length > 0) {
for (var i = 0; i < contacts.length; i++) {
if (group.toLowerCase() === t('contacts', 'Not grouped').toLowerCase()) {
if (contacts[i].categories().length === 0) {
filter.push(contacts[i]);
}
} else {
if (contacts[i].categories().indexOf(group) >= 0) {
filter.push(contacts[i]);
}
}
}
}
return filter;
};
});
// from https://docs.nextcloud.com/server/11/developer_manual/app/css.html#menus
angular.module('contactsApp')
.filter('counterFormatter', function () {
'use strict';
return function (count) {
if (count > 999) {
return '999+';
}
return count;
};
});
angular.module('contactsApp')
.filter('fieldFilter', function() {
'use strict';
return function (fields, contact) {
if (typeof fields === 'undefined') {
return fields;
}
if (typeof contact === 'undefined') {
return fields;
}
var filter = [];
if (fields.length > 0) {
for (var i = 0; i < fields.length; i++) {
if (fields[i].multiple ) {
filter.push(fields[i]);
continue;
}
if (_.isUndefined(contact.getProperty(fields[i].id))) {
filter.push(fields[i]);
}
}
}
return filter;
};
});
angular.module('contactsApp')
.filter('firstCharacter', function() {
return function(input) {
return input.charAt(0);
};
});
angular.module('contactsApp')
.filter('localeOrderBy', [function () {
return function (array, sortPredicate, reverseOrder) {
if (!Array.isArray(array)) return array;
if (!sortPredicate) return array;
var arrayCopy = [];
angular.forEach(array, function (item) {
arrayCopy.push(item);
});
arrayCopy.sort(function (a, b) {
var valueA = a[sortPredicate];
if (angular.isFunction(valueA)) {
valueA = a[sortPredicate]();
}
var valueB = b[sortPredicate];
if (angular.isFunction(valueB)) {
valueB = b[sortPredicate]();
}
if (angular.isString(valueA)) {
return !reverseOrder ? valueA.localeCompare(valueB) : valueB.localeCompare(valueA);
}
if (angular.isNumber(valueA) || typeof valueA === 'boolean') {
return !reverseOrder ? valueA - valueB : valueB - valueA;
}
if (angular.isArray(valueA)) {
if (valueA[0] === valueB[0]) {
return !reverseOrder ? valueA[1].localeCompare(valueB[1]) : valueB[1].localeCompare(valueA[1]);
}
return !reverseOrder ? valueA[0].localeCompare(valueB[0]) : valueB[0].localeCompare(valueA[0]);
}
return 0;
});
return arrayCopy;
};
}]);
angular.module('contactsApp')
.filter('newContact', function() {
return function(input) {
return input !== '' ? input : t('contacts', 'New contact');
};
});
angular.module('contactsApp')
.filter('orderDetailItems', ['vCardPropertiesService', function(vCardPropertiesService) {
'use strict';
return function(items, field, reverse) {
var filtered = [];
angular.forEach(items, function(item) {
filtered.push(item);
});
var fieldOrder = angular.copy(vCardPropertiesService.fieldOrder);
// reverse to move custom items to the end (indexOf == -1)
fieldOrder.reverse();
filtered.sort(function (a, b) {
if(fieldOrder.indexOf(a[field]) < fieldOrder.indexOf(b[field])) {
return 1;
}
if(fieldOrder.indexOf(a[field]) > fieldOrder.indexOf(b[field])) {
return -1;
}
return 0;
});
if(reverse) filtered.reverse();
return filtered;
};
}]);
angular.module('contactsApp')
.filter('toArray', function() {
return function(obj) {
if (!(obj instanceof Object)) return obj;
return _.map(obj, function(val, key) {
return Object.defineProperty(val, '$key', {value: key});
});
};
});
angular.module('contactsApp')
.filter('vCard2JSON', function() {
return function(input) {
return vCard.parse(input);
};
});
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm1haW4uanMiLCJkYXRlcGlja2VyX2RpcmVjdGl2ZS5qcyIsImZvY3VzX2RpcmVjdGl2ZS5qcyIsImlucHV0cmVzaXplX2RpcmVjdGl2ZS5qcyIsInNlbGVjdF9kaXJlY3RpdmUuanMiLCJhZGRyZXNzQm9vay9hZGRyZXNzQm9va19jb250cm9sbGVyLmpzIiwiYWRkcmVzc0Jvb2svYWRkcmVzc0Jvb2tfZGlyZWN0aXZlLmpzIiwiYWRkcmVzc0Jvb2tMaXN0L2FkZHJlc3NCb29rTGlzdF9jb250cm9sbGVyLmpzIiwiYWRkcmVzc0Jvb2tMaXN0L2FkZHJlc3NCb29rTGlzdF9kaXJlY3RpdmUuanMiLCJhdmF0YXIvYXZhdGFyX2NvbnRyb2xsZXIuanMiLCJhdmF0YXIvYXZhdGFyX2RpcmVjdGl2ZS5qcyIsImNvbnRhY3QvY29udGFjdF9jb250cm9sbGVyLmpzIiwiY29udGFjdC9jb250YWN0X2RpcmVjdGl2ZS5qcyIsImNvbnRhY3REZXRhaWxzL2NvbnRhY3REZXRhaWxzX2NvbnRyb2xsZXIuanMiLCJjb250YWN0RGV0YWlscy9jb250YWN0RGV0YWlsc19kaXJlY3RpdmUuanMiLCJjb250YWN0SW1wb3J0L2NvbnRhY3RJbXBvcnRfY29udHJvbGxlci5qcyIsImNvbnRhY3RJbXBvcnQvY29udGFjdEltcG9ydF9kaXJlY3RpdmUuanMiLCJjb250YWN0TGlzdC9jb250YWN0TGlzdF9jb250cm9sbGVyLmpzIiwiY29udGFjdExpc3QvY29udGFjdExpc3RfZGlyZWN0aXZlLmpzIiwiZGV0YWlsc0l0ZW0vZGV0YWlsc0l0ZW1fY29udHJvbGxlci5qcyIsImRldGFpbHNJdGVtL2RldGFpbHNJdGVtX2RpcmVjdGl2ZS5qcyIsImdyb3VwL2dyb3VwX2NvbnRyb2xsZXIuanMiLCJncm91cC9ncm91cF9kaXJlY3RpdmUuanMiLCJncm91cExpc3QvZ3JvdXBMaXN0X2NvbnRyb2xsZXIuanMiLCJncm91cExpc3QvZ3JvdXBMaXN0X2RpcmVjdGl2ZS5qcyIsIm5ld0NvbnRhY3RCdXR0b24vbmV3Q29udGFjdEJ1dHRvbl9jb250cm9sbGVyLmpzIiwibmV3Q29udGFjdEJ1dHRvbi9uZXdDb250YWN0QnV0dG9uX2RpcmVjdGl2ZS5qcyIsInBhcnNlcnMvdGVsTW9kZWxfZGlyZWN0aXZlLmpzIiwic29ydEJ5L3NvcnRCeV9jb250cm9sbGVyLmpzIiwic29ydEJ5L3NvcnRCeV9kaXJlY3RpdmUuanMiLCJhZGRyZXNzQm9va19tb2RlbC5qcyIsImNvbnRhY3RfbW9kZWwuanMiLCJhZGRyZXNzQm9va19zZXJ2aWNlLmpzIiwiY29udGFjdF9zZXJ2aWNlLmpzIiwiZGF2Q2xpZW50X3NlcnZpY2UuanMiLCJkYXZfc2VydmljZS5qcyIsIm1pbWVfc2VydmljZS5qcyIsInNlYXJjaF9zZXJ2aWNlLmpzIiwic2V0dGluZ3Nfc2VydmljZS5qcyIsInNvcnRCeV9zZXJ2aWNlLmpzIiwidkNhcmRQcm9wZXJ0aWVzLmpzIiwiSlNPTjJ2Q2FyZF9maWx0ZXIuanMiLCJjb250YWN0Q29sb3JfZmlsdGVyLmpzIiwiY29udGFjdEdyb3VwX2ZpbHRlci5qcyIsImNvdW50ZXJGb3JtYXR0ZXJfZmlsdGVyLmpzIiwiZmllbGRfZmlsdGVyLmpzIiwiZmlyc3RDaGFyYWN0ZXJfZmlsdGVyLmpzIiwibG9jYWxlT3JkZXJCeV9maWx0ZXIuanMiLCJuZXdDb250YWN0X2ZpbHRlci5qcyIsIm9yZGVyRGV0YWlsSXRlbXNfZmlsdGVyLmpzIiwidG9BcnJheV9maWx0ZXIuanMiLCJ2Q2FyZDJKU09OX2ZpbHRlci5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7OztBQVVBLFFBQVEsT0FBTyxlQUFlLENBQUMsU0FBUyxpQkFBaUIsV0FBVyxnQkFBZ0IsYUFBYSxjQUFjLHlCQUF5QjtDQUN2SSwwQkFBTyxTQUFTLGdCQUFnQjs7Q0FFaEMsZUFBZSxLQUFLLFNBQVM7RUFDNUIsVUFBVTs7O0NBR1gsZUFBZSxLQUFLLGlCQUFpQjtFQUNwQyxZQUFZLFNBQVMsWUFBWTtHQUNoQyxPQUFPLE1BQU0sRUFB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LE9BQU87Q0FDZCxPQUFPLGNBQWMsV0FBVztDQUNoQyxPQUFPLFNBQVMsT0FBTztFQUN0QixPQUFPLE1BQU0sTUFBTTs7O0FBR3JCIiwiZmlsZSI6InNjcmlwdC5qcyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogTmV4dGNsb3VkIC0gY29udGFjdHNcbiAqXG4gKiBUaGlzIGZpbGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEFmZmVybyBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIHZlcnNpb24gMyBvclxuICogbGF0ZXIuIFNlZSB0aGUgQ09QWUlORyBmaWxlLlxuICpcbiAqIEBhdXRob3IgSGVuZHJpayBMZXBwZWxzYWNrIDxoZW5kcmlrQGxlcHBlbHNhY2suZGU+XG4gKiBAY29weXJpZ2h0IEhlbmRyaWsgTGVwcGVsc2FjayAyMDE1XG4gKi9cblxuYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJywgWyd1dWlkNCcsICdhbmd1bGFyLWNhY2hlJywgJ25nUm91dGUnLCAndWkuYm9vdHN0cmFwJywgJ3VpLnNlbGVjdCcsICduZ1Nhbml0aXplJywgJ2FuZ3VsYXItY2xpY2stb3V0c2lkZScsICduZ2NsaXBib2FyZCddKVxuLmNvbmZpZyhmdW5jdGlvbigkcm91dGVQcm92aWRlcikge1xuXG5cdCRyb3V0ZVByb3ZpZGVyLndoZW4oJy86Z2lkJywge1xuXHRcdHRlbXBsYXRlOiAnPGNvbnRhY3RkZXRhaWxzPjwvY29udGFjdGRldGFpbHM+J1xuXHR9KTtcblxuXHQkcm91dGVQcm92aWRlci53aGVuKCcvY29udGFjdC86dWlkJywge1xuXHRcdHJlZGlyZWN0VG86IGZ1bmN0aW9uKHBhcmFtZXRlcnMpIHtcblx0XHRcdHJldHVybiAnLycgKyB0KCdjb250YWN0cycsICdBbGwgY29udGFjdHMnKSArICcvJyArIHBhcmFtZXRlcnMudWlkO1xuXHRcdH1cblx0fSk7XG5cblx0JHJvdXRlUHJvdmlkZXIud2hlbignLzpnaWQvOnVpZCcsIHtcblx0XHR0ZW1wbGF0ZTogJzxjb250YWN0ZGV0YWlscz48L2NvbnRhY3RkZXRhaWxzPidcblx0fSk7XG5cblx0JHJvdXRlUHJvdmlkZXIub3RoZXJ3aXNlKCcvJyArIHQoJ2NvbnRhY3RzJywgJ0FsbCBjb250YWN0cycpKTtcblxufSk7XG4iLCJhbmd1bGFyLm1vZHVsZSgnY29udGFjdHNBcHAnKVxuLmRpcmVjdGl2ZSgnZGF0ZXBpY2tlcicsIGZ1bmN0aW9uKCR0aW1lb3V0KSB7XG5cdHZhciBsb2FkRGF0ZXBpY2tlciA9IGZ1bmN0aW9uIChzY29wZSwgZWxlbWVudCwgYXR0cnMsIG5nTW9kZWxDdHJsKSB7XG5cdFx0JHRpbWVvdXQoZnVuY3Rpb24oKSB7XG5cdFx0XHRlbGVtZW50LmRhdGVwaWNrZXIoe1xuXHRcdFx0XHRkYXRlRm9ybWF0Oid5eS1tbS1kZCcsXG5cdFx0XHRcdG1pbkRhdGU6IG51bGwsXG5cdFx0XHRcdG1heERhdGU6IG51bGwsXG5cdFx0XHRcdGNvbnN0cmFpbklucHV0OiBmYWxzZSxcblx0XHRcdFx0b25TZWxlY3Q6ZnVuY3Rpb24gKGRhdGUsIGRwKSB7XG5cdFx0XHRcdFx0aWYgKGRwLnNlbGVjdGVkWWVhciA8IDEwMDApIHtcblx0XHRcdFx0XHRcdGRhdGUgPSAnMCcgKyBkYXRlO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRpZiAoZHAuc2VsZWN0ZWRZZWFyIDwgMTAwKSB7XG5cdFx0XHRcdFx0XHRkYXRlID0gJzAnICsgZGF0ZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aWYgKGRwLnNlbGVjdGVkWWVhciA8IDEwKSB7XG5cdFx0XHRcdFx0XHRkYXRlID0gJzAnICsgZGF0ZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0bmdNb2RlbEN0cmwuJHNldFZpZXdWYWx1ZShkYXRlKTtcblx0XHRcdFx0XHRzY29wZS4kYXBwbHkoKTtcblx0XHRcdFx0fVxuXHRcdFx0fSk7XG5cdFx0fSk7XG5cdH07XG5cdHJldHVybiB7XG5cdFx0cmVzdHJpY3Q6ICdBJyxcblx0XHRyZXF1aXJlIDogJ25nTW9kZWwnLFxuXHRcdHRyYW5zY2x1ZGU6IHRydWUsXG5cdFx0bGluayA6IGxvYWREYXRlcGlja2VyXG5cdH07XG59KTtcbiIsImFuZ3VsYXIubW9kdWxlKCdjb250YWN0c0FwcCcpXG4uZGlyZWN0aXZlKCdmb2N1c0V4cHJlc3Npb24nLCBmdW5jdGlvbiAoJHRpbWVvdXQpIHtcblx0cmV0dXJuIHtcblx0XHRyZXN0cmljdDogJ0EnLFxuXHRcdGxpbms6IHtcblx0XHRcdHBvc3Q6IGZ1bmN0aW9uIHBvc3RMaW5rKHNjb3BlLCBlbGVtZW50LCBhdHRycykge1xuXHRcdFx0XHRzY29wZS4kd2F0Y2goYXR0cnMuZm9jdXNFeHByZXNzaW9uLCBmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdFx0aWYgKGF0dHJzLmZvY3VzRXhwcmVzc2lvbikge1xuXHRcdFx0XHRcdFx0aWYgKHNjb3BlLiRldmFsKGF0dHJzLmZvY3VzRXhwcmVzc2lvbikpIHtcblx0XHRcdFx0XHRcdFx0JHRpbWVvdXQoZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRcdFx0XHRcdGlmIChlbGVtZW50LmlzKCdpbnB1dCcpKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRlbGVtZW50LmZvY3VzKCk7XG5cdFx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdFx0XHRcdGVsZW1lbnQuZmluZCgnaW5wdXQnKS5mb2N1cygpO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fSwgMTAwKTsgLy9uZWVkIHNvbWUgZGVsYXkgdG8gd29yayB3aXRoIG5nLWRpc2FibGVkXG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9KTtcblx0XHRcdH1cblx0XHR9XG5cdH07XG59KTtcbiIsImFuZ3VsYXIubW9kdWxlKCdjb250YWN0c0FwcCcpXG4uZGlyZWN0aXZlKCdpbnB1dHJlc2l6ZScsIGZ1bmN0aW9uKCkge1xuXHRyZXR1cm4ge1xuXHRcdHJlc3RyaWN0OiAnQScsXG5cdFx0bGluayA6IGZ1bmN0aW9uIChzY29wZSwgZWxlbWVudCkge1xuXHRcdFx0dmFyIGVsSW5wdXQgPSBlbGVtZW50LnZhbCgpO1xuXHRcdFx0ZWxlbWVudC5iaW5kKCdrZXlkb3duIGtleXVwIGxvYWQgZm9jdXMnLCBmdW5jdGlvbigpIHtcblx0XHRcdFx0ZWxJbnB1dCA9IGVsZW1lbnQudmFsKCk7XG5cdFx0XHRcdC8vIElmIHNldCB0byAwLCB0aGUgbWluLXdpZHRoIGNzcyBkYXRhIGlzIGlnbm9yZWRcblx0XHRcdFx0dmFyIGxlbmd0aCA9IGVsSW5wdXQubGVuZ3RoID4gMSA/IGVsSW5wdXQubGVuZ3RoIDogMTtcblx0XHRcdFx0ZWxlbWVudC5hdHRyKCdzaXplJywgbGVuZ3RoKTtcblx0XHRcdH0pO1xuXHRcdH1cblx0fTtcbn0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5kaXJlY3RpdmUoJ3NlbGVjdEV4cHJlc3Npb24nLCBmdW5jdGlvbiAoJHRpbWVvdXQpIHtcblx0cmV0dXJuIHtcblx0XHRyZXN0cmljdDogJ0EnLFxuXHRcdGxpbms6IHtcblx0XHRcdHBvc3Q6IGZ1bmN0aW9uIHBvc3RMaW5rKHNjb3BlLCBlbGVtZW50LCBhdHRycykge1xuXHRcdFx0XHRzY29wZS4kd2F0Y2goYXR0cnMuc2VsZWN0RXhwcmVzc2lvbiwgZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRcdGlmIChhdHRycy5zZWxlY3RFeHByZXNzaW9uKSB7XG5cdFx0XHRcdFx0XHRpZiAoc2NvcGUuJGV2YWwoYXR0cnMuc2VsZWN0RXhwcmVzc2lvbikpIHtcblx0XHRcdFx0XHRcdFx0JHRpbWVvdXQoZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRcdFx0XHRcdGlmIChlbGVtZW50LmlzKCdpbnB1dCcpKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRlbGVtZW50LnNlbGVjdCgpO1xuXHRcdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRlbGVtZW50LmZpbmQoJ2lucHV0Jykuc2VsZWN0KCk7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR9LCAxMDApOyAvL25lZWQgc29tZSBkZWxheSB0byB3b3JrIHdpdGggbmctZGlzYWJsZWRcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0pO1xuXHRcdFx0fVxuXHRcdH1cblx0fTtcbn0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5jb250cm9sbGVyKCdhZGRyZXNzYm9va0N0cmwnLCBmdW5jdGlvbigkc2NvcGUsIEFkZHJlc3NCb29rU2VydmljZSkge1xuXHR2YXIgY3RybCA9IHRoaXM7XG5cblx0Y3RybC50ID0ge1xuXHRcdGRvd25sb2FkOiB0KCdjb250YWN0cycsICdEb3dubG9hZCcpLFxuXHRcdGNvcHlVUkw6IHQoJ2NvbnRhY3RzJywgJ0NvcHkgbGluaycpLFxuXHRcdGNsaWNrVG9Db3B5OiB0KCdjb250YWN0cycsICdDbGljayB0byBjb3B5IHRoZSBsaW5rIHRvIHlvdXIgY2xpcGJvYXJkJyksXG5cdFx0c2hhcmVBZGRyZXNzYm9vazogdCgnY29udGFjdHMnLCAnVG9nZ2xlIHNoYXJpbmcnKSxcblx0XHRkZWxldGVBZGRyZXNzYm9vazogdCgnY29udGFjdHMnLCAnRGVsZXRlJyksXG5cdFx0cmVuYW1lQWRkcmVzc2Jvb2s6IHQoJ2NvbnRhY3RzJywgJ1JlbmFtZScpLFxuXHRcdHNoYXJlSW5wdXRQbGFjZUhvbGRlcjogdCgnY29udGFjdHMnLCAnU2hhcmUgd2l0aCB1c2VycyBvciBncm91cHMnKSxcblx0XHRkZWxldGU6IHQoJ2NvbnRhY3RzJywgJ0RlbGV0ZScpLFxuXHRcdGNhbkVkaXQ6IHQoJ2NvbnRhY3RzJywgJ2NhbiBlZGl0JyksXG5cdFx0Y2xvc2U6IHQoJ2NvbnRhY3RzJywgJ0Nsb3NlJylcblx0fTtcblxuXHRjdHJsLmVkaXRpbmcgPSBmYWxzZTtcblxuXHRjdHJsLnRvb2x0aXBJc09wZW4gPSBmYWxzZTtcblx0Y3RybC50b29sdGlwVGl0bGUgPSBjdHJsLnQuY2xpY2tUb0NvcHk7XG5cdGN0cmwuc2hvd0lucHV0VXJsID0gZmFsc2U7XG5cblx0Y3RybC5jbGlwYm9hcmRTdWNjZXNzID0gZnVuY3Rpb24oKSB7XG5cdFx0Y3RybC50b29sdGlwSXNPcGVuID0gdHJ1ZTtcblx0XHRjdHJsLnRvb2x0aXBUaXRsZSA9IHQoJ2NvcmUnLCAnQ29waWVkIScpO1xuXHRcdF8uZGVsYXkoZnVuY3Rpb24oKSB7XG5cdFx0XHRjdHJsLnRvb2x0aXBJc09wZW4gPSBmYWxzZTtcblx0XHRcdGN0cmwudG9vbHRpcFRpdGxlID0gY3RybC50LmNsaWNrVG9Db3B5O1xuXHRcdH0sIDMwMDApO1xuXHR9O1xuXG5cdGN0cmwuY2xpcGJvYXJkRXJyb3IgPSBmdW5jdGlvbigpIHtcblx0XHRjdHJsLnNob3dJbnB1dFVybCA9IHRydWU7XG5cdFx0aWYgKC9pUGhvbmV8aVBhZC9pLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCkpIHtcblx0XHRcdGN0cmwuSW5wdXRVcmxUb29sdGlwID0gdCgnY29yZScsICdOb3Qgc3VwcG9ydGVkIScpO1xuXHRcdH0gZWxzZSBpZiAoL01hYy9pLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCkpIHtcblx0XHRcdGN0cmwuSW5wdXRVcmxUb29sdGlwID0gdCgnY29yZScsICdQcmVzcyDijJgtQyB0byBjb3B5LicpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRjdHJsLklucHV0VXJsVG9vbHRpcCA9IHQoJ2NvcmUnLCAnUHJlc3MgQ3RybC1DIHRvIGNvcHkuJyk7XG5cdFx0fVxuXHRcdCQoJyNhZGRyZXNzQm9va1VybF8nK2N0cmwuYWRkcmVzc0Jvb2suY3RhZykuc2VsZWN0KCk7XG5cdH07XG5cblx0Y3RybC5yZW5hbWVBZGRyZXNzQm9vayA9IGZ1bmN0aW9uKCkge1xuXHRcdEFkZHJlc3NCb29rU2VydmljZS5yZW5hbWUoY3RybC5hZGRyZXNzQm9vaywgY3RybC5hZGRyZXNzQm9vay5kaXNwbGF5TmFtZSk7XG5cdFx0Y3RybC5lZGl0aW5nID0gZmFsc2U7XG5cdH07XG5cblx0Y3RybC5lZGl0ID0gZnVuY3Rpb24oKSB7XG5cdFx0Y3RybC5lZGl0aW5nID0gdHJ1ZTtcblx0fTtcblxuXHQvKiBnbG9iYWxzIG9jX2NvbmZpZyAqL1xuXHRmdW5jdGlvbiBjb21wYXJlVmVyc2lvbih2ZXJzaW9uMSwgdmVyc2lvbjIpIHtcblx0XHRmb3IgKHZhciBpID0gMDsgaSA8IE1hdGgubWF4KHZlcnNpb24xLmxlbmd0aCwgdmVyc2lvbjIubGVuZ3RoKTsgaSsrKSB7XG5cdFx0XHR2YXIgYSA9IHZlcnNpb24xW2ldIHx8IDA7XG5cdFx0XHR2YXIgYiA9IHZlcnNpb24yW2ldIHx8IDA7XG5cdFx0XHRpZiAoTnVtYmVyKGEpIDwgTnVtYmVyKGIpKSB7XG5cdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0fVxuXHRcdFx0aWYgKHZlcnNpb24xW2ldICE9PSB2ZXJzaW9uMltpXSkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHJldHVybiBmYWxzZTtcblx0fVxuXHQvKiBlc2xpbnQtZGlzYWJsZSBjYW1lbGNhc2UgKi9cblx0Y3RybC5jYW5FeHBvcnQgPSBjb21wYXJlVmVyc2lvbihbOSwgMCwgMiwgMF0sIG9jX2NvbmZpZy52ZXJzaW9uLnNwbGl0KCcuJykpO1xuXHQvKiBlc2xpbnQtZW5hYmxlIGNhbWVsY2FzZSAqL1xuXG5cdGN0cmwuY2xvc2VNZW51cyA9IGZ1bmN0aW9uKCkge1xuXHRcdCRzY29wZS4kcGFyZW50LmN0cmwub3BlbmVkTWVudSA9IGZhbHNlO1xuXHR9O1xuXG5cdGN0cmwub3Blbk1lbnUgPSBmdW5jdGlvbihpbmRleCkge1xuXHRcdGN0cmwuY2xvc2VNZW51cygpO1xuXHRcdCRzY29wZS4kcGFyZW50LmN0cmwub3BlbmVkTWVudSA9IGluZGV4O1xuXHR9O1xuXG5cdGN0cmwudG9nZ2xlTWVudSA9IGZ1bmN0aW9uKGluZGV4KSB7XG5cdFx0aWYgKCRzY29wZS4kcGFyZW50LmN0cmwub3BlbmVkTWVudSA9PT0gaW5kZXgpIHtcblx0XHRcdGN0cmwuY2xvc2VNZW51cygpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRjdHJsLm9wZW5NZW51KGluZGV4KTtcblx0XHR9XG5cdH07XG5cblx0Y3RybC50b2dnbGVTaGFyZXNFZGl0b3IgPSBmdW5jdGlvbigpIHtcblx0XHRjdHJsLmVkaXRpbmdTaGFyZXMgPSAhY3RybC5lZGl0aW5nU2hhcmVzO1xuXHRcdGN0cmwuc2VsZWN0ZWRTaGFyZWUgPSBudWxsO1xuXHR9O1xuXG5cdC8qIEZyb20gQ2FsZW5kYXItUmV3b3JrIC0ganMvYXBwL2NvbnRyb2xsZXJzL2NhbGVuZGFybGlzdGNvbnRyb2xsZXIuanMgKi9cblx0Y3RybC5maW5kU2hhcmVlID0gZnVuY3Rpb24gKHZhbCkge1xuXHRcdHJldHVybiAkLmdldChcblx0XHRcdE9DLmxpbmtUb09DUygnYXBwcy9maWxlc19zaGFyaW5nL2FwaS92MScpICsgJ3NoYXJlZXMnLFxuXHRcdFx0e1xuXHRcdFx0XHRmb3JtYXQ6ICdqc29uJyxcblx0XHRcdFx0c2VhcmNoOiB2YWwudHJpbSgpLFxuXHRcdFx0XHRwZXJQYWdlOiAyMDAsXG5cdFx0XHRcdGl0ZW1UeXBlOiAncHJpbmNpcGFscydcblx0XHRcdH1cblx0XHQpLnRoZW4oZnVuY3Rpb24ocmVzdWx0KSB7XG5cdFx0XHQvLyBUb2RvIC0gZmlsdGVyIG91dCBjdXJyZW50IHVzZXIsIGV4aXN0aW5nIHNoYXJlZXNcblx0XHRcdHZhciB1c2VycyAgID0gcmVzdWx0Lm9jcy5kYXRhLmV4YWN0LnVzZXJzLmNvbmNhdChyZXN1bHQub2NzLmRhdGEudXNlcnMpO1xuXHRcdFx0dmFyIGdyb3VwcyAgPSByZXN1bHQub2NzLmRhdGEuZXhhY3QuZ3JvdXBzLmNvbmNhdChyZXN1bHQub2NzLmRhdGEuZ3JvdXBzKTtcblxuXHRcdFx0dmFyIHVzZXJTaGFyZXMgPSBjdHJsLmFkZHJlc3NCb29rLnNoYXJlZFdpdGgudXNlcnM7XG5cdFx0XHR2YXIgdXNlclNoYXJlc0xlbmd0aCA9IHVzZXJTaGFyZXMubGVuZ3RoO1xuXHRcdFx0dmFyIGksIGo7XG5cblx0XHRcdC8vIEZpbHRlciBvdXQgY3VycmVudCB1c2VyXG5cdFx0XHR2YXIgdXNlcnNMZW5ndGggPSB1c2Vycy5sZW5ndGg7XG5cdFx0XHRmb3IgKGkgPSAwIDsgaSA8IHVzZXJzTGVuZ3RoOyBpKyspIHtcblx0XHRcdFx0aWYgKHVzZXJzW2ldLnZhbHVlLnNoYXJlV2l0aCA9PT0gT0MuY3VycmVudFVzZXIpIHtcblx0XHRcdFx0XHR1c2Vycy5zcGxpY2UoaSwgMSk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0Ly8gTm93IGZpbHRlciBvdXQgYWxsIHNoYXJlZXMgdGhhdCBhcmUgYWxyZWFkeSBzaGFyZWQgd2l0aFxuXHRcdFx0Zm9yIChpID0gMDsgaSA8IHVzZXJTaGFyZXNMZW5ndGg7IGkrKykge1xuXHRcdFx0XHR2YXIgc2hhcmUgPSB1c2VyU2hhcmVzW2ldO1xuXHRcdFx0XHR1c2Vyc0xlbmd0aCA9IHVzZXJzLmxlbmd0aDtcblx0XHRcdFx0Zm9yIChqID0gMDsgaiA8IHVzZXJzTGVuZ3RoOyBqKyspIHtcblx0XHRcdFx0XHRpZiAodXNlcnNbal0udmFsdWUuc2hhcmVXaXRoID09PSBzaGFyZS5pZCkge1xuXHRcdFx0XHRcdFx0dXNlcnMuc3BsaWNlKGosIDEpO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdC8vIENvbWJpbmUgdXNlcnMgYW5kIGdyb3Vwc1xuXHRcdFx0dXNlcnMgPSB1c2Vycy5tYXAoZnVuY3Rpb24oaXRlbSkge1xuXHRcdFx0XHRyZXR1cm4ge1xuXHRcdFx0XHRcdGRpc3BsYXk6IGl0ZW0udmFsdWUuc2hhcmVXaXRoLFxuXHRcdFx0XHRcdHR5cGU6IE9DLlNoYXJlLlNIQVJFX1RZUEVfVVNFUixcblx0XHRcdFx0XHRpZGVudGlmaWVyOiBpdGVtLnZhbHVlLnNoYXJlV2l0aFxuXHRcdFx0XHR9O1xuXHRcdFx0fSk7XG5cblx0XHRcdGdyb3VwcyA9IGdyb3Vwcy5tYXAoZnVuY3Rpb24oaXRlbSkge1xuXHRcdFx0XHRyZXR1cm4ge1xuXHRcdFx0XHRcdGRpc3BsYXk6IGl0ZW0udmFsdWUuc2hhcmVXaXRoICsgJyAoZ3JvdXApJyxcblx0XHRcdFx0XHR0eXBlOiBPQy5TaGFyZS5TSEFSRV9UWVBFX0dST1VQLFxuXHRcdFx0XHRcdGlkZW50aWZpZXI6IGl0ZW0udmFsdWUuc2hhcmVXaXRoXG5cdFx0XHRcdH07XG5cdFx0XHR9KTtcblxuXHRcdFx0cmV0dXJuIGdyb3Vwcy5jb25jYXQodXNlcnMpO1xuXHRcdH0pO1xuXHR9O1xuXG5cdGN0cmwub25TZWxlY3RTaGFyZWUgPSBmdW5jdGlvbiAoaXRlbSkge1xuXHRcdC8vIFByZXZlbnQgc2V0dGluZ3MgdG8gc2xpZGUgZG93blxuXHRcdCQoJyNhcHAtc2V0dGluZ3MtaGVhZGVyID4gYnV0dG9uJykuZGF0YSgnYXBwcy1zbGlkZS10b2dnbGUnLCBmYWxzZSk7XG5cdFx0Xy5kZWxheShmdW5jdGlvbigpIHtcblx0XHRcdCQoJyNhcHAtc2V0dGluZ3MtaGVhZGVyID4gYnV0dG9uJykuZGF0YSgnYXBwcy1zbGlkZS10b2dnbGUnLCAnI2FwcC1zZXR0aW5ncy1jb250ZW50Jyk7XG5cdFx0fSwgNTAwKTtcblxuXHRcdGN0cmwuc2VsZWN0ZWRTaGFyZWUgPSBudWxsO1xuXHRcdEFkZHJlc3NCb29rU2VydmljZS5zaGFyZShjdHJsLmFkZHJlc3NCb29rLCBpdGVtLnR5cGUsIGl0ZW0uaWRlbnRpZmllciwgZmFsc2UsIGZhbHNlKS50aGVuKGZ1bmN0aW9uKCkge1xuXHRcdFx0JHNjb3BlLiRhcHBseSgpO1xuXHRcdH0pO1xuXG5cdH07XG5cblx0Y3RybC51cGRhdGVFeGlzdGluZ1VzZXJTaGFyZSA9IGZ1bmN0aW9uKHVzZXJJZCwgd3JpdGFibGUpIHtcblx0XHRBZGRyZXNzQm9va1NlcnZpY2Uuc2hhcmUoY3RybC5hZGRyZXNzQm9vaywgT0MuU2hhcmUuU0hBUkVfVFlQRV9VU0VSLCB1c2VySWQsIHdyaXRhYmxlLCB0cnVlKS50aGVuKGZ1bmN0aW9uKCkge1xuXHRcdFx0JHNjb3BlLiRhcHBseSgpO1xuXHRcdH0pO1xuXHR9O1xuXG5cdGN0cmwudXBkYXRlRXhpc3RpbmdHcm91cFNoYXJlID0gZnVuY3Rpb24oZ3JvdXBJZCwgd3JpdGFibGUpIHtcblx0XHRBZGRyZXNzQm9va1NlcnZpY2Uuc2hhcmUoY3RybC5hZGRyZXNzQm9vaywgT0MuU2hhcmUuU0hBUkVfVFlQRV9HUk9VUCwgZ3JvdXBJZCwgd3JpdGFibGUsIHRydWUpLnRoZW4oZnVuY3Rpb24oKSB7XG5cdFx0XHQkc2NvcGUuJGFwcGx5KCk7XG5cdFx0fSk7XG5cdH07XG5cblx0Y3RybC51bnNoYXJlRnJvbVVzZXIgPSBmdW5jdGlvbih1c2VySWQpIHtcblx0XHRBZGRyZXNzQm9va1NlcnZpY2UudW5zaGFyZShjdHJsLmFkZHJlc3NCb29rLCBPQy5TaGFyZS5TSEFSRV9UWVBFX1VTRVIsIHVzZXJJZCkudGhlbihmdW5jdGlvbigpIHtcblx0XHRcdCRzY29wZS4kYXBwbHkoKTtcblx0XHR9KTtcblx0fTtcblxuXHRjdHJsLnVuc2hhcmVGcm9tR3JvdXAgPSBmdW5jdGlvbihncm91cElkKSB7XG5cdFx0QWRkcmVzc0Jvb2tTZXJ2aWNlLnVuc2hhcmUoY3RybC5hZGRyZXNzQm9vaywgT0MuU2hhcmUuU0hBUkVfVFlQRV9HUk9VUCwgZ3JvdXBJZCkudGhlbihmdW5jdGlvbigpIHtcblx0XHRcdCRzY29wZS4kYXBwbHkoKTtcblx0XHR9KTtcblx0fTtcblxuXHRjdHJsLmRlbGV0ZUFkZHJlc3NCb29rID0gZnVuY3Rpb24oKSB7XG5cdFx0QWRkcmVzc0Jvb2tTZXJ2aWNlLmRlbGV0ZShjdHJsLmFkZHJlc3NCb29rKS50aGVuKGZ1bmN0aW9uKCkge1xuXHRcdFx0JHNjb3BlLiRhcHBseSgpO1xuXHRcdH0pO1xuXHR9O1xuXG59KTtcbiIsImFuZ3VsYXIubW9kdWxlKCdjb250YWN0c0FwcCcpXG4uZGlyZWN0aXZlKCdhZGRyZXNzYm9vaycsIGZ1bmN0aW9uKCkge1xuXHRyZXR1cm4ge1xuXHRcdHJlc3RyaWN0OiAnQScsIC8vIGhhcyB0byBiZSBhbiBhdHRyaWJ1dGUgdG8gd29yayB3aXRoIGNvcmUgY3NzXG5cdFx0c2NvcGU6IHt9LFxuXHRcdGNvbnRyb2xsZXI6ICdhZGRyZXNzYm9va0N0cmwnLFxuXHRcdGNvbnRyb2xsZXJBczogJ2N0cmwnLFxuXHRcdGJpbmRUb0NvbnRyb2xsZXI6IHtcblx0XHRcdGFkZHJlc3NCb29rOiAnPWRhdGEnLFxuXHRcdFx0bGlzdDogJz0nXG5cdFx0fSxcblx0XHR0ZW1wbGF0ZVVybDogT0MubGlua1RvKCdjb250YWN0cycsICd0ZW1wbGF0ZXMvYWRkcmVzc0Jvb2suaHRtbCcpXG5cdH07XG59KTtcbiIsImFuZ3VsYXIubW9kdWxlKCdjb250YWN0c0FwcCcpXG4uY29udHJvbGxlcignYWRkcmVzc2Jvb2tsaXN0Q3RybCcsIGZ1bmN0aW9uKCRzY29wZSwgQWRkcmVzc0Jvb2tTZXJ2aWNlKSB7XG5cdHZhciBjdHJsID0gdGhpcztcblxuXHRjdHJsLmxvYWRpbmcgPSB0cnVlO1xuXHRjdHJsLm9wZW5lZE1lbnUgPSBmYWxzZTtcblxuXHRBZGRyZXNzQm9va1NlcnZpY2UuZ2V0QWxsKCkudGhlbihmdW5jdGlvbihhZGRyZXNzQm9va3MpIHtcblx0XHRjdHJsLmFkZHJlc3NCb29rcyA9IGFkZHJlc3NCb29rcztcblx0XHRjdHJsLmxvYWRpbmcgPSBmYWxzZTtcblx0XHRpZihjdHJsLmFkZHJlc3NCb29rcy5sZW5ndGggPT09IDApIHtcblx0XHRcdEFkZHJlc3NCb29rU2VydmljZS5jcmVhdGUodCgnY29udGFjdHMnLCAnQ29udGFjdHMnKSkudGhlbihmdW5jdGlvbigpIHtcblx0XHRcdFx0QWRkcmVzc0Jvb2tTZXJ2aWNlLmdldEFkZHJlc3NCb29rKHQoJ2NvbnRhY3RzJywgJ0NvbnRhY3RzJykpLnRoZW4oZnVuY3Rpb24oYWRkcmVzc0Jvb2spIHtcblx0XHRcdFx0XHRjdHJsLmFkZHJlc3NCb29rcy5wdXNoKGFkZHJlc3NCb29rKTtcblx0XHRcdFx0XHQkc2NvcGUuJGFwcGx5KCk7XG5cdFx0XHRcdH0pO1xuXHRcdFx0fSk7XG5cdFx0fVxuXHR9KTtcblxuXHRjdHJsLnQgPSB7XG5cdFx0YWRkcmVzc0Jvb2tOYW1lIDogdCgnY29udGFjdHMnLCAnQWRkcmVzcyBib29rIG5hbWUnKVxuXHR9O1xuXG5cdGN0cmwuY3JlYXRlQWRkcmVzc0Jvb2sgPSBmdW5jdGlvbigpIHtcblx0XHRpZihjdHJsLm5ld0FkZHJlc3NCb29rTmFtZSkge1xuXHRcdFx0QWRkcmVzc0Jvb2tTZXJ2aWNlLmNyZWF0ZShjdHJsLm5ld0FkZHJlc3NCb29rTmFtZSkudGhlbihmdW5jdGlvbigpIHtcblx0XHRcdFx0QWRkcmVzc0Jvb2tTZXJ2aWNlLmdldEFkZHJlc3NCb29rKGN0cmwubmV3QWRkcmVzc0Jvb2tOYW1lKS50aGVuKGZ1bmN0aW9uKGFkZHJlc3NCb29rKSB7XG5cdFx0XHRcdFx0Y3RybC5hZGRyZXNzQm9va3MucHVzaChhZGRyZXNzQm9vayk7XG5cdFx0XHRcdFx0JHNjb3BlLiRhcHBseSgpO1xuXHRcdFx0XHR9KTtcblx0XHRcdH0pO1xuXHRcdH1cblx0fTtcbn0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5kaXJlY3RpdmUoJ2FkZHJlc3Nib29rbGlzdCcsIGZ1bmN0aW9uKCkge1xuXHRyZXR1cm4ge1xuXHRcdHJlc3RyaWN0OiAnRUEnLCAvLyBoYXMgdG8gYmUgYW4gYXR0cmlidXRlIHRvIHdvcmsgd2l0aCBjb3JlIGNzc1xuXHRcdHNjb3BlOiB7fSxcblx0XHRjb250cm9sbGVyOiAnYWRkcmVzc2Jvb2tsaXN0Q3RybCcsXG5cdFx0Y29udHJvbGxlckFzOiAnY3RybCcsXG5cdFx0YmluZFRvQ29udHJvbGxlcjoge30sXG5cdFx0dGVtcGxhdGVVcmw6IE9DLmxpbmtUbygnY29udGFjdHMnLCAndGVtcGxhdGVzL2FkZHJlc3NCb29rTGlzdC5odG1sJylcblx0fTtcbn0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5jb250cm9sbGVyKCdhdmF0YXJDdHJsJywgZnVuY3Rpb24oQ29udGFjdFNlcnZpY2UpIHtcblx0dmFyIGN0cmwgPSB0aGlzO1xuXG5cdGN0cmwuaW1wb3J0ID0gQ29udGFjdFNlcnZpY2UuaW1wb3J0LmJpbmQoQ29udGFjdFNlcnZpY2UpO1xuXG5cdGN0cmwucmVtb3ZlUGhvdG8gPSBmdW5jdGlvbigpIHtcblx0XHRjdHJsLmNvbnRhY3QucmVtb3ZlUHJvcGVydHkoJ3Bob3RvJywgY3RybC5jb250YWN0LmdldFByb3BlcnR5KCdwaG90bycpKTtcblx0XHRDb250YWN0U2VydmljZS51cGRhdGUoY3RybC5jb250YWN0KTtcblx0XHQkKCdhdmF0YXInKS5yZW1vdmVDbGFzcygnbWF4aW1pemVkJyk7XG5cdH07XG5cblx0Y3RybC5kb3dubG9hZFBob3RvID0gZnVuY3Rpb24oKSB7XG5cdFx0LyogZ2xvYmFscyBBcnJheUJ1ZmZlciwgVWludDhBcnJheSAqL1xuXHRcdHZhciBpbWcgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnY29udGFjdC1hdmF0YXInKTtcblx0XHQvLyBhdG9iIHRvIGJhc2U2NF9kZWNvZGUgdGhlIGRhdGEtVVJJXG5cdFx0dmFyIGltYWdlU3BsaXQgPSBpbWcuc3JjLnNwbGl0KCcsJyk7XG5cdFx0Ly8gXCJkYXRhOmltYWdlL3BuZztiYXNlNjRcIiAtPiBcInBuZ1wiXG5cdFx0dmFyIGV4dGVuc2lvbiA9ICcuJyArIGltYWdlU3BsaXRbMF0uc3BsaXQoJzsnKVswXS5zcGxpdCgnLycpWzFdO1xuXHRcdHZhciBpbWFnZURhdGEgPSBhdG9iKGltYWdlU3BsaXRbMV0pO1xuXHRcdC8vIFVzZSB0eXBlZCBhcnJheXMgdG8gY29udmVydCB0aGUgYmluYXJ5IGRhdGEgdG8gYSBCbG9iXG5cdFx0dmFyIGFycmF5QnVmZmVyID0gbmV3IEFycmF5QnVmZmVyKGltYWdlRGF0YS5sZW5ndGgpO1xuXHRcdHZhciB2aWV3ID0gbmV3IFVpbnQ4QXJyYXkoYXJyYXlCdWZmZXIpO1xuXHRcdGZvciAodmFyIGk9MDsgaTxpbWFnZURhdGEubGVuZ3RoOyBpKyspIHtcblx0XHRcdHZpZXdbaV0gPSBpbWFnZURhdGEuY2hhckNvZGVBdChpKSAmIDB4ZmY7XG5cdFx0fVxuXHRcdHZhciBibG9iID0gbmV3IEJsb2IoW2FycmF5QnVmZmVyXSwge3R5cGU6ICdhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0nfSk7XG5cblx0XHQvLyBVc2UgdGhlIFVSTCBvYmplY3QgdG8gY3JlYXRlIGEgdGVtcG9yYXJ5IFVSTFxuXHRcdHZhciB1cmwgPSAod2luZG93LndlYmtpdFVSTCB8fCB3aW5kb3cuVVJMKS5jcmVhdGVPYmplY3RVUkwoYmxvYik7XG5cblx0XHR2YXIgYSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2EnKTtcblx0XHRkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKGEpO1xuXHRcdGEuc3R5bGUgPSAnZGlzcGxheTogbm9uZSc7XG5cdFx0YS5ocmVmID0gdXJsO1xuXHRcdGEuZG93bmxvYWQgPSBjdHJsLmNvbnRhY3QudWlkKCkgKyBleHRlbnNpb247XG5cdFx0YS5jbGljaygpO1xuXHRcdHdpbmRvdy5VUkwucmV2b2tlT2JqZWN0VVJMKHVybCk7XG5cdFx0YS5yZW1vdmUoKTtcblx0fTtcblxuXHRjdHJsLm9wZW5QaG90byA9IGZ1bmN0aW9uKCkge1xuXHRcdCQoJ2F2YXRhcicpLnRvZ2dsZUNsYXNzKCdtYXhpbWl6ZWQnKTtcblx0fTtcblxuXHQvLyBRdWl0IGF2YXRhciBwcmV2aWV3XG5cdCQoJ2F2YXRhcicpLmNsaWNrKGZ1bmN0aW9uKCkge1xuXHRcdCQoJ2F2YXRhcicpLnJlbW92ZUNsYXNzKCdtYXhpbWl6ZWQnKTtcblx0fSk7XG5cdCQoJ2F2YXRhciBpbWcsIGF2YXRhciAuYXZhdGFyLW9wdGlvbnMnKS5jbGljayhmdW5jdGlvbihlKSB7XG5cdFx0ZS5zdG9wUHJvcGFnYXRpb24oKTtcblx0fSk7XG5cdCQoZG9jdW1lbnQpLmtleXVwKGZ1bmN0aW9uKGUpIHtcblx0XHRpZiAoZS5rZXlDb2RlID09PSAyNykge1xuXHRcdFx0JCgnYXZhdGFyJykucmVtb3ZlQ2xhc3MoJ21heGltaXplZCcpO1xuXHRcdH1cblx0fSk7XG5cbn0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5kaXJlY3RpdmUoJ2F2YXRhcicsIGZ1bmN0aW9uKENvbnRhY3RTZXJ2aWNlKSB7XG5cdHJldHVybiB7XG5cdFx0c2NvcGU6IHtcblx0XHRcdGNvbnRhY3Q6ICc9ZGF0YSdcblx0XHR9LFxuXHRcdGNvbnRyb2xsZXI6ICdhdmF0YXJDdHJsJyxcblx0XHRjb250cm9sbGVyQXM6ICdjdHJsJyxcblx0XHRiaW5kVG9Db250cm9sbGVyOiB7XG5cdFx0XHRjb250YWN0OiAnPWRhdGEnXG5cdFx0fSxcblx0XHRsaW5rOiBmdW5jdGlvbihzY29wZSwgZWxlbWVudCkge1xuXHRcdFx0dmFyIGltcG9ydFRleHQgPSB0KCdjb250YWN0cycsICdJbXBvcnQnKTtcblx0XHRcdHNjb3BlLmltcG9ydFRleHQgPSBpbXBvcnRUZXh0O1xuXG5cdFx0XHR2YXIgaW5wdXQgPSBlbGVtZW50LmZpbmQoJ2lucHV0Jyk7XG5cdFx0XHRpbnB1dC5iaW5kKCdjaGFuZ2UnLCBmdW5jdGlvbigpIHtcblx0XHRcdFx0dmFyIGZpbGUgPSBpbnB1dC5nZXQoMCkuZmlsZXNbMF07XG5cdFx0XHRcdGlmIChmaWxlLnNpemUgPiAxMDI0KjEwMjQpIHsgLy8gMSBNQlxuXHRcdFx0XHRcdE9DLk5vdGlmaWNhdGlvbi5zaG93VGVtcG9yYXJ5KHQoJ2NvbnRhY3RzJywgJ1RoZSBzZWxlY3RlZCBpbWFnZSBpcyB0b28gYmlnIChtYXggMU1CKScpKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHR2YXIgcmVhZGVyID0gbmV3IEZpbGVSZWFkZXIoKTtcblxuXHRcdFx0XHRcdHJlYWRlci5hZGRFdmVudExpc3RlbmVyKCdsb2FkJywgZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRcdFx0c2NvcGUuJGFwcGx5KGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdFx0XHRzY29wZS5jb250YWN0LnBob3RvKHJlYWRlci5yZXN1bHQpO1xuXHRcdFx0XHRcdFx0XHRDb250YWN0U2VydmljZS51cGRhdGUoc2NvcGUuY29udGFjdCk7XG5cdFx0XHRcdFx0XHR9KTtcblx0XHRcdFx0XHR9LCBmYWxzZSk7XG5cblx0XHRcdFx0XHRpZiAoZmlsZSkge1xuXHRcdFx0XHRcdFx0cmVhZGVyLnJlYWRBc0RhdGFVUkwoZmlsZSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblx0XHR9LFxuXHRcdHRlbXBsYXRlVXJsOiBPQy5saW5rVG8oJ2NvbnRhY3RzJywgJ3RlbXBsYXRlcy9hdmF0YXIuaHRtbCcpXG5cdH07XG59KTtcbiIsImFuZ3VsYXIubW9kdWxlKCdjb250YWN0c0FwcCcpXG4uY29udHJvbGxlcignY29udGFjdEN0cmwnLCBmdW5jdGlvbigkcm91dGUsICRyb3V0ZVBhcmFtcywgU29ydEJ5U2VydmljZSkge1xuXHR2YXIgY3RybCA9IHRoaXM7XG5cblx0Y3RybC50ID0ge1xuXHRcdGVycm9yTWVzc2FnZSA6IHQoJ2NvbnRhY3RzJywgJ1RoaXMgY2FyZCBpcyBjb3JydXB0ZWQgYW5kIGhhcyBiZWVuIGZpeGVkLiBQbGVhc2UgY2hlY2sgdGhlIGRhdGEgYW5kIHRyaWdnZXIgYSBzYXZlIHRvIG1ha2UgdGhlIGNoYW5nZXMgcGVybWFuZW50LicpLFxuXHR9O1xuXG5cdGN0cmwub3BlbkNvbnRhY3QgPSBmdW5jdGlvbigpIHtcblx0XHQkcm91dGUudXBkYXRlUGFyYW1zKHtcblx0XHRcdGdpZDogJHJvdXRlUGFyYW1zLmdpZCxcblx0XHRcdHVpZDogY3RybC5jb250YWN0LnVpZCgpfSk7XG5cdH07XG5cblx0Y3RybC5nZXROYW1lID0gZnVuY3Rpb24oKSB7XG5cdFx0Ly8gSWYgbGFzdE5hbWUgZXF1YWxzIHRvIGZpcnN0TmFtZSB0aGVuIG5vbmUgb2YgdGhlbSBpcyBzZXRcblx0XHRpZiAoY3RybC5jb250YWN0Lmxhc3ROYW1lKCkgPT09IGN0cmwuY29udGFjdC5maXJzdE5hbWUoKSkge1xuXHRcdFx0cmV0dXJuIGN0cmwuY29udGFjdC5kaXNwbGF5TmFtZSgpO1xuXHRcdH1cblxuXHRcdGlmIChTb3J0QnlTZXJ2aWNlLmdldFNvcnRCeSgpID09PSAnc29ydExhc3ROYW1lJykge1xuXHRcdFx0cmV0dXJuIChcblx0XHRcdFx0Y3RybC5jb250YWN0Lmxhc3ROYW1lKCkgKyAnLCAnXG5cdFx0XHRcdCsgY3RybC5jb250YWN0LmZpcnN0TmFtZSgpICsgJyAnXG5cdFx0XHRcdCsgY3RybC5jb250YWN0LmFkZGl0aW9uYWxOYW1lcygpXG5cdFx0XHQpLnRyaW0oKTtcblx0XHR9XG5cblx0XHRpZiAoU29ydEJ5U2VydmljZS5nZXRTb3J0QnkoKSA9PT0gJ3NvcnRGaXJzdE5hbWUnKSB7XG5cdFx0XHRyZXR1cm4gKFxuXHRcdFx0XHRjdHJsLmNvbnRhY3QuZmlyc3ROYW1lKCkgKyAnICdcblx0XHRcdFx0KyBjdHJsLmNvbnRhY3QuYWRkaXRpb25hbE5hbWVzKCkgKyAnICdcblx0XHRcdFx0KyBjdHJsLmNvbnRhY3QubGFzdE5hbWUoKVxuXHRcdFx0KS50cmltKCk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGN0cmwuY29udGFjdC5kaXNwbGF5TmFtZSgpO1xuXHR9O1xufSk7XG4iLCJhbmd1bGFyLm1vZHVsZSgnY29udGFjdHNBcHAnKVxuLmRpcmVjdGl2ZSgnY29udGFjdCcsIGZ1bmN0aW9uKCkge1xuXHRyZXR1cm4ge1xuXHRcdHNjb3BlOiB7fSxcblx0XHRjb250cm9sbGVyOiAnY29udGFjdEN0cmwnLFxuXHRcdGNvbnRyb2xsZXJBczogJ2N0cmwnLFxuXHRcdGJpbmRUb0NvbnRyb2xsZXI6IHtcblx0XHRcdGNvbnRhY3Q6ICc9ZGF0YSdcblx0XHR9LFxuXHRcdHRlbXBsYXRlVXJsOiBPQy5saW5rVG8oJ2NvbnRhY3RzJywgJ3RlbXBsYXRlcy9jb250YWN0Lmh0bWwnKVxuXHR9O1xufSk7XG4iLCJhbmd1bGFyLm1vZHVsZSgnY29udGFjdHNBcHAnKVxuLmNvbnRyb2xsZXIoJ2NvbnRhY3RkZXRhaWxzQ3RybCcsIGZ1bmN0aW9uKENvbnRhY3RTZXJ2aWNlLCBBZGRyZXNzQm9va1NlcnZpY2UsIHZDYXJkUHJvcGVydGllc1NlcnZpY2UsICRyb3V0ZSwgJHJvdXRlUGFyYW1zLCAkc2NvcGUpIHtcblxuXHR2YXIgY3RybCA9IHRoaXM7XG5cblx0Y3RybC5sb2FkaW5nID0gdHJ1ZTtcblx0Y3RybC5zaG93ID0gZmFsc2U7XG5cblx0Y3RybC5jbGVhckNvbnRhY3QgPSBmdW5jdGlvbigpIHtcblx0XHQkcm91dGUudXBkYXRlUGFyYW1zKHtcblx0XHRcdGdpZDogJHJvdXRlUGFyYW1zLmdpZCxcblx0XHRcdHVpZDogdW5kZWZpbmVkXG5cdFx0fSk7XG5cdFx0Y3RybC5zaG93ID0gZmFsc2U7XG5cdFx0Y3RybC5jb250YWN0ID0gdW5kZWZpbmVkO1xuXHR9O1xuXG5cdGN0cmwudWlkID0gJHJvdXRlUGFyYW1zLnVpZDtcblx0Y3RybC50ID0ge1xuXHRcdG5vQ29udGFjdHMgOiB0KCdjb250YWN0cycsICdObyBjb250YWN0cyBpbiBoZXJlJyksXG5cdFx0cGxhY2Vob2xkZXJOYW1lIDogdCgnY29udGFjdHMnLCAnTmFtZScpLFxuXHRcdHBsYWNlaG9sZGVyT3JnIDogdCgnY29udGFjdHMnLCAnT3JnYW5pemF0aW9uJyksXG5cdFx0cGxhY2Vob2xkZXJUaXRsZSA6IHQoJ2NvbnRhY3RzJywgJ1RpdGxlJyksXG5cdFx0c2VsZWN0RmllbGQgOiB0KCdjb250YWN0cycsICdBZGQgZmllbGQgLi4uJyksXG5cdFx0ZG93bmxvYWQgOiB0KCdjb250YWN0cycsICdEb3dubG9hZCcpLFxuXHRcdGRlbGV0ZSA6IHQoJ2NvbnRhY3RzJywgJ0RlbGV0ZScpLFxuXHRcdHNhdmUgOiB0KCdjb250YWN0cycsICdTYXZlIGNoYW5nZXMnKSxcblx0XHRhZGRyZXNzQm9vayA6IHQoJ2NvbnRhY3RzJywgJ0FkZHJlc3MgYm9vaycpXG5cdH07XG5cblx0Y3RybC5maWVsZERlZmluaXRpb25zID0gdkNhcmRQcm9wZXJ0aWVzU2VydmljZS5maWVsZERlZmluaXRpb25zO1xuXHRjdHJsLmZvY3VzID0gdW5kZWZpbmVkO1xuXHRjdHJsLmZpZWxkID0gdW5kZWZpbmVkO1xuXHRjdHJsLmFkZHJlc3NCb29rcyA9IFtdO1xuXG5cdEFkZHJlc3NCb29rU2VydmljZS5nZXRBbGwoKS50aGVuKGZ1bmN0aW9uKGFkZHJlc3NCb29rcykge1xuXHRcdGN0cmwuYWRkcmVzc0Jvb2tzID0gYWRkcmVzc0Jvb2tzO1xuXG5cdFx0aWYgKCFfLmlzVW5kZWZpbmVkKGN0cmwuY29udGFjdCkpIHtcblx0XHRcdGN0cmwuYWRkcmVzc0Jvb2sgPSBfLmZpbmQoY3RybC5hZGRyZXNzQm9va3MsIGZ1bmN0aW9uKGJvb2spIHtcblx0XHRcdFx0cmV0dXJuIGJvb2suZGlzcGxheU5hbWUgPT09IGN0cmwuY29udGFjdC5hZGRyZXNzQm9va0lkO1xuXHRcdFx0fSk7XG5cdFx0fVxuXHRcdGN0cmwubG9hZGluZyA9IGZhbHNlO1xuXHRcdC8vIFN0YXJ0IHdhdGNoaW5nIGZvciBjdHJsLnVpZCB3aGVuIHdlIGhhdmUgYWRkcmVzc0Jvb2tzLCBhcyB0aGV5IGFyZSBuZWVkZWQgZm9yIGZldGNoaW5nXG5cdFx0Ly8gZnVsbCBkZXRhaWxzLlxuXHRcdCRzY29wZS4kd2F0Y2goJ2N0cmwudWlkJywgZnVuY3Rpb24obmV3VmFsdWUpIHtcblx0XHRcdGN0cmwuY2hhbmdlQ29udGFjdChuZXdWYWx1ZSk7XG5cdFx0fSk7XG5cdH0pO1xuXG5cblx0Y3RybC5jaGFuZ2VDb250YWN0ID0gZnVuY3Rpb24odWlkKSB7XG5cdFx0aWYgKHR5cGVvZiB1aWQgPT09ICd1bmRlZmluZWQnKSB7XG5cdFx0XHRjdHJsLnNob3cgPSBmYWxzZTtcblx0XHRcdCQoJyNhcHAtbmF2aWdhdGlvbi10b2dnbGUnKS5yZW1vdmVDbGFzcygnc2hvd2RldGFpbHMnKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0Q29udGFjdFNlcnZpY2UuZ2V0QnlJZChjdHJsLmFkZHJlc3NCb29rcywgdWlkKS50aGVuKGZ1bmN0aW9uKGNvbnRhY3QpIHtcblx0XHRcdGlmIChhbmd1bGFyLmlzVW5kZWZpbmVkKGNvbnRhY3QpKSB7XG5cdFx0XHRcdGN0cmwuY2xlYXJDb250YWN0KCk7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblx0XHRcdGN0cmwuY29udGFjdCA9IGNvbnRhY3Q7XG5cdFx0XHRjdHJsLnNob3cgPSB0cnVlO1xuXHRcdFx0JCgnI2FwcC1uYXZpZ2F0aW9uLXRvZ2dsZScpLmFkZENsYXNzKCdzaG93ZGV0YWlscycpO1xuXG5cdFx0XHRjdHJsLmFkZHJlc3NCb29rID0gXy5maW5kKGN0cmwuYWRkcmVzc0Jvb2tzLCBmdW5jdGlvbihib29rKSB7XG5cdFx0XHRcdHJldHVybiBib29rLmRpc3BsYXlOYW1lID09PSBjdHJsLmNvbnRhY3QuYWRkcmVzc0Jvb2tJZDtcblx0XHRcdH0pO1xuXHRcdH0pO1xuXHR9O1xuXG5cdGN0cmwudXBkYXRlQ29udGFjdCA9IGZ1bmN0aW9uKCkge1xuXHRcdENvbnRhY3RTZXJ2aWNlLnVwZGF0ZShjdHJsLmNvbnRhY3QpO1xuXHR9O1xuXG5cdGN0cmwuZGVsZXRlQ29udGFjdCA9IGZ1bmN0aW9uKCkge1xuXHRcdENvbnRhY3RTZXJ2aWNlLmRlbGV0ZShjdHJsLmNvbnRhY3QpO1xuXHR9O1xuXG5cdGN0cmwuYWRkRmllbGQgPSBmdW5jdGlvbihmaWVsZCkge1xuXHRcdHZhciBkZWZhdWx0VmFsdWUgPSB2Q2FyZFByb3BlcnRpZXNTZXJ2aWNlLmdldE1ldGEoZmllbGQpLmRlZmF1bHRWYWx1ZSB8fCB7dmFsdWU6ICcnfTtcblx0XHRjdHJsLmNvbnRhY3QuYWRkUHJvcGVydHkoZmllbGQsIGRlZmF1bHRWYWx1ZSk7XG5cdFx0Y3RybC5mb2N1cyA9IGZpZWxkO1xuXHRcdGN0cmwuZmllbGQgPSAnJztcblx0fTtcblxuXHRjdHJsLmRlbGV0ZUZpZWxkID0gZnVuY3Rpb24gKGZpZWxkLCBwcm9wKSB7XG5cdFx0Y3RybC5jb250YWN0LnJlbW92ZVByb3BlcnR5KGZpZWxkLCBwcm9wKTtcblx0XHRjdHJsLmZvY3VzID0gdW5kZWZpbmVkO1xuXHR9O1xuXG5cdGN0cmwuY2hhbmdlQWRkcmVzc0Jvb2sgPSBmdW5jdGlvbiAoYWRkcmVzc0Jvb2spIHtcblx0XHRDb250YWN0U2VydmljZS5tb3ZlQ29udGFjdChjdHJsLmNvbnRhY3QsIGFkZHJlc3NCb29rKTtcblx0fTtcbn0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5kaXJlY3RpdmUoJ2NvbnRhY3RkZXRhaWxzJywgZnVuY3Rpb24oKSB7XG5cdHJldHVybiB7XG5cdFx0cHJpb3JpdHk6IDEsXG5cdFx0c2NvcGU6IHt9LFxuXHRcdGNvbnRyb2xsZXI6ICdjb250YWN0ZGV0YWlsc0N0cmwnLFxuXHRcdGNvbnRyb2xsZXJBczogJ2N0cmwnLFxuXHRcdGJpbmRUb0NvbnRyb2xsZXI6IHt9LFxuXHRcdHRlbXBsYXRlVXJsOiBPQy5saW5rVG8oJ2NvbnRhY3RzJywgJ3RlbXBsYXRlcy9jb250YWN0RGV0YWlscy5odG1sJylcblx0fTtcbn0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5jb250cm9sbGVyKCdjb250YWN0aW1wb3J0Q3RybCcsIGZ1bmN0aW9uKENvbnRhY3RTZXJ2aWNlKSB7XG5cdHZhciBjdHJsID0gdGhpcztcblxuXHRjdHJsLmltcG9ydCA9IENvbnRhY3RTZXJ2aWNlLmltcG9ydC5iaW5kKENvbnRhY3RTZXJ2aWNlKTtcblxufSk7XG4iLCJhbmd1bGFyLm1vZHVsZSgnY29udGFjdHNBcHAnKVxuLmRpcmVjdGl2ZSgnY29udGFjdGltcG9ydCcsIGZ1bmN0aW9uKENvbnRhY3RTZXJ2aWNlKSB7XG5cdHJldHVybiB7XG5cdFx0bGluazogZnVuY3Rpb24oc2NvcGUsIGVsZW1lbnQpIHtcblx0XHRcdHZhciBpbXBvcnRUZXh0ID0gdCgnY29udGFjdHMnLCAnSW1wb3J0Jyk7XG5cdFx0XHRzY29wZS5pbXBvcnRUZXh0ID0gaW1wb3J0VGV4dDtcblxuXHRcdFx0dmFyIGlucHV0ID0gZWxlbWVudC5maW5kKCdpbnB1dCcpO1xuXHRcdFx0aW5wdXQuYmluZCgnY2hhbmdlJywgZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGFuZ3VsYXIuZm9yRWFjaChpbnB1dC5nZXQoMCkuZmlsZXMsIGZ1bmN0aW9uKGZpbGUpIHtcblx0XHRcdFx0XHR2YXIgcmVhZGVyID0gbmV3IEZpbGVSZWFkZXIoKTtcblxuXHRcdFx0XHRcdHJlYWRlci5hZGRFdmVudExpc3RlbmVyKCdsb2FkJywgZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRcdFx0c2NvcGUuJGFwcGx5KGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0XHRcdFx0Q29udGFjdFNlcnZpY2UuaW1wb3J0LmNhbGwoQ29udGFjdFNlcnZpY2UsIHJlYWRlci5yZXN1bHQsIGZpbGUudHlwZSwgbnVsbCwgZnVuY3Rpb24gKHByb2dyZXNzKSB7XG5cdFx0XHRcdFx0XHRcdFx0aWYgKHByb2dyZXNzID09PSAxKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRzY29wZS5pbXBvcnRUZXh0ID0gaW1wb3J0VGV4dDtcblx0XHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRcdFx0c2NvcGUuaW1wb3J0VGV4dCA9IHBhcnNlSW50KE1hdGguZmxvb3IocHJvZ3Jlc3MgKiAxMDApKSArICclJztcblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdH0pO1xuXHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0fSwgZmFsc2UpO1xuXG5cdFx0XHRcdFx0aWYgKGZpbGUpIHtcblx0XHRcdFx0XHRcdHJlYWRlci5yZWFkQXNUZXh0KGZpbGUpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSk7XG5cdFx0XHRcdGlucHV0LmdldCgwKS52YWx1ZSA9ICcnO1xuXHRcdFx0fSk7XG5cdFx0fSxcblx0XHR0ZW1wbGF0ZVVybDogT0MubGlua1RvKCdjb250YWN0cycsICd0ZW1wbGF0ZXMvY29udGFjdEltcG9ydC5odG1sJylcblx0fTtcbn0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5jb250cm9sbGVyKCdjb250YWN0bGlzdEN0cmwnLCBmdW5jdGlvbigkc2NvcGUsICRmaWx0ZXIsICRyb3V0ZSwgJHJvdXRlUGFyYW1zLCAkdGltZW91dCwgQ29udGFjdFNlcnZpY2UsIFNvcnRCeVNlcnZpY2UsIHZDYXJkUHJvcGVydGllc1NlcnZpY2UsIFNlYXJjaFNlcnZpY2UpIHtcblx0dmFyIGN0cmwgPSB0aGlzO1xuXG5cdGN0cmwucm91dGVQYXJhbXMgPSAkcm91dGVQYXJhbXM7XG5cblx0Y3RybC5jb250YWN0TGlzdCA9IFtdO1xuXHRjdHJsLnNlYXJjaFRlcm0gPSAnJztcblx0Y3RybC5zaG93ID0gdHJ1ZTtcblx0Y3RybC5pbnZhbGlkID0gZmFsc2U7XG5cdGN0cmwubGltaXRUbyA9IDI1O1xuXG5cdGN0cmwuc29ydEJ5ID0gU29ydEJ5U2VydmljZS5nZXRTb3J0QnkoKTtcblxuXHRjdHJsLnQgPSB7XG5cdFx0ZW1wdHlTZWFyY2ggOiB0KCdjb250YWN0cycsICdObyBzZWFyY2ggcmVzdWx0IGZvciB7cXVlcnl9Jywge3F1ZXJ5OiBjdHJsLnNlYXJjaFRlcm19KVxuXHR9O1xuXG5cdGN0cmwucmVzZXRMaW1pdFRvID0gZnVuY3Rpb24gKCkge1xuXHRcdGN0cmwubGltaXRUbyA9IDI1O1xuXHRcdGNsZWFySW50ZXJ2YWwoY3RybC5pbnRlcnZhbElkKTtcblx0XHRjdHJsLmludGVydmFsSWQgPSBzZXRJbnRlcnZhbChcblx0XHRcdGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0aWYgKCFjdHJsLmxvYWRpbmcgJiYgY3RybC5jb250YWN0cyAmJiBjdHJsLmNvbnRhY3RzLmxlbmd0aCA+IGN0cmwubGltaXRUbykge1xuXHRcdFx0XHRcdGN0cmwubGltaXRUbyArPSAyNTtcblx0XHRcdFx0XHQkc2NvcGUuJGFwcGx5KCk7XG5cdFx0XHRcdH1cblx0XHRcdH0sIDMwMCk7XG5cdH07XG5cblx0JHNjb3BlLnF1ZXJ5ID0gZnVuY3Rpb24oY29udGFjdCkge1xuXHRcdHJldHVybiBjb250YWN0Lm1hdGNoZXMoU2VhcmNoU2VydmljZS5nZXRTZWFyY2hUZXJtKCkpO1xuXHR9O1xuXG5cdFNvcnRCeVNlcnZpY2Uuc3Vic2NyaWJlKGZ1bmN0aW9uKG5ld1ZhbHVlKSB7XG5cdFx0Y3RybC5zb3J0QnkgPSBuZXdWYWx1ZTtcblx0fSk7XG5cblx0U2VhcmNoU2VydmljZS5yZWdpc3Rlck9ic2VydmVyQ2FsbGJhY2soZnVuY3Rpb24oZXYpIHtcblx0XHRpZiAoZXYuZXZlbnQgPT09ICdzdWJtaXRTZWFyY2gnKSB7XG5cdFx0XHR2YXIgdWlkID0gIV8uaXNFbXB0eShjdHJsLmNvbnRhY3RMaXN0KSA/IGN0cmwuY29udGFjdExpc3RbMF0udWlkKCkgOiB1bmRlZmluZWQ7XG5cdFx0XHRjdHJsLnNldFNlbGVjdGVkSWQodWlkKTtcblx0XHRcdCRzY29wZS4kYXBwbHkoKTtcblx0XHR9XG5cdFx0aWYgKGV2LmV2ZW50ID09PSAnY2hhbmdlU2VhcmNoJykge1xuXHRcdFx0Y3RybC5yZXNldExpbWl0VG8oKTtcblx0XHRcdGN0cmwuc2VhcmNoVGVybSA9IGV2LnNlYXJjaFRlcm07XG5cdFx0XHRjdHJsLnQuZW1wdHlTZWFyY2ggPSB0KCdjb250YWN0cycsXG5cdFx0XHRcdFx0XHRcdFx0ICAgJ05vIHNlYXJjaCByZXN1bHQgZm9yIHtxdWVyeX0nLFxuXHRcdFx0XHRcdFx0XHRcdCAgIHtxdWVyeTogY3RybC5zZWFyY2hUZXJtfVxuXHRcdFx0XHRcdFx0XHRcdCAgKTtcblx0XHRcdCRzY29wZS4kYXBwbHkoKTtcblx0XHR9XG5cdH0pO1xuXG5cdGN0cmwubG9hZGluZyA9IHRydWU7XG5cblx0Q29udGFjdFNlcnZpY2UucmVnaXN0ZXJPYnNlcnZlckNhbGxiYWNrKGZ1bmN0aW9uKGV2KSB7XG5cdFx0JHRpbWVvdXQoZnVuY3Rpb24gKCkgeyAkc2NvcGUuJGFwcGx5KGZ1bmN0aW9uKCkge1xuXHRcdFx0aWYgKGV2LmV2ZW50ID09PSAnZGVsZXRlJykge1xuXHRcdFx0XHRpZiAoY3RybC5jb250YWN0TGlzdC5sZW5ndGggPT09IDEpIHtcblx0XHRcdFx0XHQkcm91dGUudXBkYXRlUGFyYW1zKHtcblx0XHRcdFx0XHRcdGdpZDogJHJvdXRlUGFyYW1zLmdpZCxcblx0XHRcdFx0XHRcdHVpZDogdW5kZWZpbmVkXG5cdFx0XHRcdFx0fSk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0Zm9yICh2YXIgaSA9IDAsIGxlbmd0aCA9IGN0cmwuY29udGFjdExpc3QubGVuZ3RoOyBpIDwgbGVuZ3RoOyBpKyspIHtcblx0XHRcdFx0XHRcdGlmIChjdHJsLmNvbnRhY3RMaXN0W2ldLnVpZCgpID09PSBldi51aWQpIHtcblx0XHRcdFx0XHRcdFx0JHJvdXRlLnVwZGF0ZVBhcmFtcyh7XG5cdFx0XHRcdFx0XHRcdFx0Z2lkOiAkcm91dGVQYXJhbXMuZ2lkLFxuXHRcdFx0XHRcdFx0XHRcdHVpZDogKGN0cmwuY29udGFjdExpc3RbaSsxXSkgPyBjdHJsLmNvbnRhY3RMaXN0W2krMV0udWlkKCkgOiBjdHJsLmNvbnRhY3RMaXN0W2ktMV0udWlkKClcblx0XHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0ZWxzZSBpZiAoZXYuZXZlbnQgPT09ICdjcmVhdGUnKSB7XG5cdFx0XHRcdCRyb3V0ZS51cGRhdGVQYXJhbXMoe1xuXHRcdFx0XHRcdGdpZDogJHJvdXRlUGFyYW1zLmdpZCxcblx0XHRcdFx0XHR1aWQ6IGV2LnVpZFxuXHRcdFx0XHR9KTtcblx0XHRcdH1cblx0XHRcdGN0cmwuY29udGFjdHMgPSBldi5jb250YWN0cztcblx0XHR9KTsgfSk7XG5cdH0pO1xuXG5cdC8vIEdldCBjb250YWN0c1xuXHRDb250YWN0U2VydmljZS5nZXRBbGwoKS50aGVuKGZ1bmN0aW9uKGNvbnRhY3RzKSB7XG5cdFx0aWYoY29udGFjdHMubGVuZ3RoPjApIHtcblx0XHRcdCRzY29wZS4kYXBwbHkoZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGN0cmwuY29udGFjdHMgPSBjb250YWN0cztcblx0XHRcdH0pO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRjdHJsLmxvYWRpbmcgPSBmYWxzZTtcblx0XHR9XG5cdH0pO1xuXG5cdHZhciBnZXRWaXNpYmxlTmFtZXMgPSBmdW5jdGlvbiBnZXRWaXNpYmxlTmFtZXMoKSB7XG5cdFx0ZnVuY3Rpb24gaXNTY3JvbGxlZEludG9WaWV3KGVsKSB7XG5cdFx0XHR2YXIgZWxlbVRvcCA9IGVsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcDtcblx0XHRcdHZhciBlbGVtQm90dG9tID0gZWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkuYm90dG9tO1xuXG5cdFx0XHR2YXIgYm90aEFib3ZlVmlld3BvcnQgPSBlbGVtQm90dG9tIDwgMDtcblx0XHRcdHZhciBib3RoQmVsb3dWaWV3UG9ydCA9IGVsZW1Ub3AgPiB3aW5kb3cuaW5uZXJIZWlnaHQ7XG5cdFx0XHR2YXIgaXNWaXNpYmxlID0gIWJvdGhBYm92ZVZpZXdwb3J0ICYmICFib3RoQmVsb3dWaWV3UG9ydDtcblx0XHRcdHJldHVybiBpc1Zpc2libGU7XG5cdFx0fVxuXG5cdFx0dmFyIGVsZW1lbnRzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnLmNvbnRhY3RfX2ljb246bm90KC5uZy1oaWRlKScpKTtcblx0XHR2YXIgbmFtZXMgPSBlbGVtZW50c1xuXHRcdFx0XHQuZmlsdGVyKGlzU2Nyb2xsZWRJbnRvVmlldylcblx0XHRcdFx0Lm1hcChmdW5jdGlvbiAoZWwpIHtcblx0XHRcdFx0XHR2YXIgc2libGluZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChlbC5wYXJlbnRFbGVtZW50LmNoaWxkcmVuKTtcblx0XHRcdFx0XHR2YXIgbmFtZUVsZW1lbnQgPSBzaWJsaW5ncy5maW5kKGZ1bmN0aW9uIChzaWJsaW5nKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gc2libGluZy5nZXRBdHRyaWJ1dGUoJ2NsYXNzJykuaW5kZXhPZignY29udGVudC1saXN0LWl0ZW0tbGluZS1vbmUnKSAhPT0gLTE7XG5cdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0cmV0dXJuIG5hbWVFbGVtZW50LmlubmVyVGV4dDtcblxuXHRcdFx0XHR9KTtcblx0XHRyZXR1cm4gbmFtZXM7XG5cdH07XG5cblx0dmFyIHRpbWVvdXRJZCA9IG51bGw7XG5cdGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5hcHAtY29udGVudC1saXN0JykuYWRkRXZlbnRMaXN0ZW5lcignc2Nyb2xsJywgZnVuY3Rpb24gKCkge1xuXHRcdGNsZWFyVGltZW91dCh0aW1lb3V0SWQpO1xuXHRcdHRpbWVvdXRJZCA9IHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuXHRcdFx0dmFyIG5hbWVzID0gZ2V0VmlzaWJsZU5hbWVzKCk7XG5cdFx0XHRDb250YWN0U2VydmljZS5nZXRGdWxsQ29udGFjdHMobmFtZXMpO1xuXHRcdH0sIDI1MCk7XG5cdH0pO1xuXG5cdC8vIFdhaXQgZm9yIGN0cmwuY29udGFjdExpc3QgdG8gYmUgdXBkYXRlZCwgbG9hZCB0aGUgY29udGFjdCByZXF1ZXN0ZWQgaW4gdGhlIFVSTCBpZiBhbnksIGFuZFxuXHQvLyBsb2FkIGZ1bGwgZGV0YWlscyBmb3IgdGhlIHByb2JhYmx5IGluaXRpYWxseSB2aXNpYmxlIGNvbnRhY3RzLlxuXHQvLyBUaGVuIGtpbGwgdGhlIHdhdGNoLlxuXHR2YXIgdW5iaW5kTGlzdFdhdGNoID0gJHNjb3BlLiR3YXRjaCgnY3RybC5jb250YWN0TGlzdCcsIGZ1bmN0aW9uKCkge1xuXHRcdGlmKGN0cmwuY29udGFjdExpc3QgJiYgY3RybC5jb250YWN0TGlzdC5sZW5ndGggPiAwKSB7XG5cdFx0XHQvLyBDaGVjayBpZiBhIHNwZWNpZmljIHVpZCBpcyByZXF1ZXN0ZWRcblx0XHRcdGlmKCRyb3V0ZVBhcmFtcy51aWQgJiYgJHJvdXRlUGFyYW1zLmdpZCkge1xuXHRcdFx0XHRjdHJsLmNvbnRhY3RMaXN0LmZvckVhY2goZnVuY3Rpb24oY29udGFjdCkge1xuXHRcdFx0XHRcdGlmKGNvbnRhY3QudWlkKCkgPT09ICRyb3V0ZVBhcmFtcy51aWQpIHtcblx0XHRcdFx0XHRcdGN0cmwuc2V0U2VsZWN0ZWRJZCgkcm91dGVQYXJhbXMudWlkKTtcblx0XHRcdFx0XHRcdGN0cmwubG9hZGluZyA9IGZhbHNlO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSk7XG5cdFx0XHR9XG5cdFx0XHQvLyBObyBjb250YWN0IHByZXZpb3VzbHkgbG9hZGVkLCBsZXQncyBsb2FkIHRoZSBmaXJzdCBvZiB0aGUgbGlzdCBpZiBub3QgaW4gbW9iaWxlIG1vZGVcblx0XHRcdGlmKGN0cmwubG9hZGluZyAmJiAkKHdpbmRvdykud2lkdGgoKSA+IDc2OCkge1xuXHRcdFx0XHRjdHJsLnNldFNlbGVjdGVkSWQoY3RybC5jb250YWN0TGlzdFswXS51aWQoKSk7XG5cdFx0XHR9XG5cdFx0XHR2YXIgZmlyc3ROYW1lcyA9IGN0cmwuY29udGFjdExpc3Quc2xpY2UoMCwgMjApLm1hcChmdW5jdGlvbiAoYykgeyByZXR1cm4gYy5kaXNwbGF5TmFtZSgpOyB9KTtcblx0XHRcdENvbnRhY3RTZXJ2aWNlLmdldEZ1bGxDb250YWN0cyhmaXJzdE5hbWVzKTtcblx0XHRcdGN0cmwubG9hZGluZyA9IGZhbHNlO1xuXHRcdFx0dW5iaW5kTGlzdFdhdGNoKCk7XG5cdFx0fVxuXHR9KTtcblxuXHQkc2NvcGUuJHdhdGNoKCdjdHJsLnJvdXRlUGFyYW1zLnVpZCcsIGZ1bmN0aW9uKG5ld1ZhbHVlLCBvbGRWYWx1ZSkge1xuXHRcdC8vIFVzZWQgZm9yIG1vYmlsZSB2aWV3IHRvIGNsZWFyIHRoZSB1cmxcblx0XHRpZih0eXBlb2Ygb2xkVmFsdWUgIT0gJ3VuZGVmaW5lZCcgJiYgdHlwZW9mIG5ld1ZhbHVlID09ICd1bmRlZmluZWQnICYmICQod2luZG93KS53aWR0aCgpIDw9IDc2OCkge1xuXHRcdFx0Ly8gbm8gY29udGFjdCBzZWxlY3RlZFxuXHRcdFx0Y3RybC5zaG93ID0gdHJ1ZTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0aWYobmV3VmFsdWUgPT09IHVuZGVmaW5lZCkge1xuXHRcdFx0Ly8gd2UgbWlnaHQgaGF2ZSB0byB3YWl0IHVudGlsIG5nLXJlcGVhdCBmaWxsZWQgdGhlIGNvbnRhY3RMaXN0XG5cdFx0XHRpZihjdHJsLmNvbnRhY3RMaXN0ICYmIGN0cmwuY29udGFjdExpc3QubGVuZ3RoID4gMCkge1xuXHRcdFx0XHQkcm91dGUudXBkYXRlUGFyYW1zKHtcblx0XHRcdFx0XHRnaWQ6ICRyb3V0ZVBhcmFtcy5naWQsXG5cdFx0XHRcdFx0dWlkOiBjdHJsLmNvbnRhY3RMaXN0WzBdLnVpZCgpXG5cdFx0XHRcdH0pO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Ly8gd2F0Y2ggZm9yIG5leHQgY29udGFjdExpc3QgdXBkYXRlXG5cdFx0XHRcdHZhciB1bmJpbmRXYXRjaCA9ICRzY29wZS4kd2F0Y2goJ2N0cmwuY29udGFjdExpc3QnLCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRpZihjdHJsLmNvbnRhY3RMaXN0ICYmIGN0cmwuY29udGFjdExpc3QubGVuZ3RoID4gMCkge1xuXHRcdFx0XHRcdFx0JHJvdXRlLnVwZGF0ZVBhcmFtcyh7XG5cdFx0XHRcdFx0XHRcdGdpZDogJHJvdXRlUGFyYW1zLmdpZCxcblx0XHRcdFx0XHRcdFx0dWlkOiBjdHJsLmNvbnRhY3RMaXN0WzBdLnVpZCgpXG5cdFx0XHRcdFx0XHR9KTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0dW5iaW5kV2F0Y2goKTsgLy8gdW5iaW5kIGFzIHdlIG9ubHkgd2FudCBvbmUgdXBkYXRlXG5cdFx0XHRcdH0pO1xuXHRcdFx0fVxuXHRcdH0gZWxzZSB7XG5cdFx0XHQvLyBkaXNwbGF5aW5nIGNvbnRhY3QgZGV0YWlsc1xuXHRcdFx0Y3RybC5zaG93ID0gZmFsc2U7XG5cdFx0fVxuXHR9KTtcblxuXHQkc2NvcGUuJHdhdGNoKCdjdHJsLnJvdXRlUGFyYW1zLmdpZCcsIGZ1bmN0aW9uKCkge1xuXHRcdC8vIHdlIG1pZ2h0IGhhdmUgdG8gd2FpdCB1bnRpbCBuZy1yZXBlYXQgZmlsbGVkIHRoZSBjb250YWN0TGlzdFxuXHRcdGN0cmwuY29udGFjdExpc3QgPSBbXTtcblx0XHRjdHJsLnJlc2V0TGltaXRUbygpO1xuXHRcdC8vIG5vdCBpbiBtb2JpbGUgbW9kZVxuXHRcdGlmKCQod2luZG93KS53aWR0aCgpID4gNzY4KSB7XG5cdFx0XHQvLyB3YXRjaCBmb3IgbmV4dCBjb250YWN0TGlzdCB1cGRhdGVcblx0XHRcdHZhciB1bmJpbmRXYXRjaCA9ICRzY29wZS4kd2F0Y2goJ2N0cmwuY29udGFjdExpc3QnLCBmdW5jdGlvbigpIHtcblx0XHRcdFx0aWYoY3RybC5jb250YWN0TGlzdCAmJiBjdHJsLmNvbnRhY3RMaXN0Lmxlbmd0aCA+IDApIHtcblx0XHRcdFx0XHQkcm91dGUudXBkYXRlUGFyYW1zKHtcblx0XHRcdFx0XHRcdGdpZDogJHJvdXRlUGFyYW1zLmdpZCxcblx0XHRcdFx0XHRcdHVpZDogJHJvdXRlUGFyYW1zLnVpZCB8fCBjdHJsLmNvbnRhY3RMaXN0WzBdLnVpZCgpXG5cdFx0XHRcdFx0fSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0dW5iaW5kV2F0Y2goKTsgLy8gdW5iaW5kIGFzIHdlIG9ubHkgd2FudCBvbmUgdXBkYXRlXG5cdFx0XHR9KTtcblx0XHR9XG5cdH0pO1xuXG5cdC8vIFdhdGNoIGlmIHdlIGhhdmUgYW4gaW52YWxpZCBjb250YWN0XG5cdCRzY29wZS4kd2F0Y2goJ2N0cmwuY29udGFjdExpc3RbMF0uZGlzcGxheU5hbWUoKScsIGZ1bmN0aW9uKGRpc3BsYXlOYW1lKSB7XG5cdFx0Y3RybC5pbnZhbGlkID0gKGRpc3BsYXlOYW1lID09PSAnJyk7XG5cdH0pO1xuXG5cdGN0cmwuaGFzQ29udGFjdHMgPSBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKCFjdHJsLmNvbnRhY3RzKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXHRcdHJldHVybiBjdHJsLmNvbnRhY3RzLmxlbmd0aCA+IDA7XG5cdH07XG5cblx0Y3RybC5zZXRTZWxlY3RlZElkID0gZnVuY3Rpb24gKGNvbnRhY3RJZCkge1xuXHRcdCRyb3V0ZS51cGRhdGVQYXJhbXMoe1xuXHRcdFx0dWlkOiBjb250YWN0SWRcblx0XHR9KTtcblx0fTtcblxuXHRjdHJsLmdldFNlbGVjdGVkSWQgPSBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gJHJvdXRlUGFyYW1zLnVpZDtcblx0fTtcblxufSk7XG4iLCJhbmd1bGFyLm1vZHVsZSgnY29udGFjdHNBcHAnKVxuLmRpcmVjdGl2ZSgnY29udGFjdGxpc3QnLCBmdW5jdGlvbigpIHtcblx0cmV0dXJuIHtcblx0XHRwcmlvcml0eTogMSxcblx0XHRzY29wZToge30sXG5cdFx0Y29udHJvbGxlcjogJ2NvbnRhY3RsaXN0Q3RybCcsXG5cdFx0Y29udHJvbGxlckFzOiAnY3RybCcsXG5cdFx0YmluZFRvQ29udHJvbGxlcjoge1xuXHRcdFx0YWRkcmVzc2Jvb2s6ICc9YWRyYm9vaydcblx0XHR9LFxuXHRcdHRlbXBsYXRlVXJsOiBPQy5saW5rVG8oJ2NvbnRhY3RzJywgJ3RlbXBsYXRlcy9jb250YWN0TGlzdC5odG1sJylcblx0fTtcbn0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5jb250cm9sbGVyKCdkZXRhaWxzSXRlbUN0cmwnLCBmdW5jdGlvbigkdGVtcGxhdGVSZXF1ZXN0LCB2Q2FyZFByb3BlcnRpZXNTZXJ2aWNlLCBDb250YWN0U2VydmljZSkge1xuXHR2YXIgY3RybCA9IHRoaXM7XG5cblx0Y3RybC5tZXRhID0gdkNhcmRQcm9wZXJ0aWVzU2VydmljZS5nZXRNZXRhKGN0cmwubmFtZSk7XG5cdGN0cmwudHlwZSA9IHVuZGVmaW5lZDtcblx0Y3RybC5pc1ByZWZlcnJlZCA9IGZhbHNlO1xuXHRjdHJsLnQgPSB7XG5cdFx0cG9Cb3ggOiB0KCdjb250YWN0cycsICdQb3N0IG9mZmljZSBib3gnKSxcblx0XHRwb3N0YWxDb2RlIDogdCgnY29udGFjdHMnLCAnUG9zdGFsIGNvZGUnKSxcblx0XHRjaXR5IDogdCgnY29udGFjdHMnLCAnQ2l0eScpLFxuXHRcdHN0YXRlIDogdCgnY29udGFjdHMnLCAnU3RhdGUgb3IgcHJvdmluY2UnKSxcblx0XHRjb3VudHJ5IDogdCgnY29udGFjdHMnLCAnQ291bnRyeScpLFxuXHRcdGFkZHJlc3M6IHQoJ2NvbnRhY3RzJywgJ0FkZHJlc3MnKSxcblx0XHRuZXdHcm91cDogdCgnY29udGFjdHMnLCAnKG5ldyBncm91cCknKSxcblx0XHRmYW1pbHlOYW1lOiB0KCdjb250YWN0cycsICdMYXN0IG5hbWUnKSxcblx0XHRmaXJzdE5hbWU6IHQoJ2NvbnRhY3RzJywgJ0ZpcnN0IG5hbWUnKSxcblx0XHRhZGRpdGlvbmFsTmFtZXM6IHQoJ2NvbnRhY3RzJywgJ0FkZGl0aW9uYWwgbmFtZXMnKSxcblx0XHRob25vcmlmaWNQcmVmaXg6IHQoJ2NvbnRhY3RzJywgJ1ByZWZpeCcpLFxuXHRcdGhvbm9yaWZpY1N1ZmZpeDogdCgnY29udGFjdHMnLCAnU3VmZml4JyksXG5cdFx0ZGVsZXRlOiB0KCdjb250YWN0cycsICdEZWxldGUnKVxuXHR9O1xuXG5cdGN0cmwuYXZhaWxhYmxlT3B0aW9ucyA9IGN0cmwubWV0YS5vcHRpb25zIHx8IFtdO1xuXHRpZiAoIV8uaXNVbmRlZmluZWQoY3RybC5kYXRhKSAmJiAhXy5pc1VuZGVmaW5lZChjdHJsLmRhdGEubWV0YSkgJiYgIV8uaXNVbmRlZmluZWQoY3RybC5kYXRhLm1ldGEudHlwZSkpIHtcblx0XHQvLyBwYXJzZSB0eXBlIG9mIHRoZSBwcm9wZXJ0eVxuXHRcdHZhciBhcnJheSA9IGN0cmwuZGF0YS5tZXRhLnR5cGVbMF0uc3BsaXQoJywnKTtcblx0XHRhcnJheSA9IGFycmF5Lm1hcChmdW5jdGlvbiAoZWxlbSkge1xuXHRcdFx0cmV0dXJuIGVsZW0udHJpbSgpLnJlcGxhY2UoL1xcLyskLywgJycpLnJlcGxhY2UoL1xcXFwrJC8sICcnKS50cmltKCkudG9VcHBlckNhc2UoKTtcblx0XHR9KTtcblx0XHQvLyB0aGUgcHJlZiB2YWx1ZSBpcyBoYW5kbGVkIG9uIGl0cyBvd24gc28gdGhhdCB3ZSBjYW4gYWRkIHNvbWUgZmF2b3JpdGUgaWNvbiB0byB0aGUgdWkgaWYgd2Ugd2FudFxuXHRcdGlmIChhcnJheS5pbmRleE9mKCdQUkVGJykgPj0gMCkge1xuXHRcdFx0Y3RybC5pc1ByZWZlcnJlZCA9IHRydWU7XG5cdFx0XHRhcnJheS5zcGxpY2UoYXJyYXkuaW5kZXhPZignUFJFRicpLCAxKTtcblx0XHR9XG5cdFx0Ly8gc2ltcGx5IGpvaW4gdGhlIHVwcGVyIGNhc2VkIHR5cGVzIHRvZ2V0aGVyIGFzIGtleVxuXHRcdGN0cmwudHlwZSA9IGFycmF5LmpvaW4oJywnKTtcblx0XHR2YXIgZGlzcGxheU5hbWUgPSBhcnJheS5tYXAoZnVuY3Rpb24gKGVsZW1lbnQpIHtcblx0XHRcdHJldHVybiBlbGVtZW50LmNoYXJBdCgwKS50b1VwcGVyQ2FzZSgpICsgZWxlbWVudC5zbGljZSgxKS50b0xvd2VyQ2FzZSgpO1xuXHRcdH0pLmpvaW4oJyAnKTtcblxuXHRcdC8vIGluIGNhc2UgdGhlIHR5cGUgaXMgbm90IHlldCBpbiB0aGUgZGVmYXVsdCBsaXN0IG9mIGF2YWlsYWJsZSBvcHRpb25zIHdlIGFkZCBpdFxuXHRcdGlmICghY3RybC5hdmFpbGFibGVPcHRpb25zLnNvbWUoZnVuY3Rpb24oZSkgeyByZXR1cm4gZS5pZCA9PT0gY3RybC50eXBlOyB9ICkpIHtcblx0XHRcdGN0cmwuYXZhaWxhYmxlT3B0aW9ucyA9IGN0cmwuYXZhaWxhYmxlT3B0aW9ucy5jb25jYXQoW3tpZDogY3RybC50eXBlLCBuYW1lOiBkaXNwbGF5TmFtZX1dKTtcblx0XHR9XG5cdH1cblx0aWYgKCFfLmlzVW5kZWZpbmVkKGN0cmwuZGF0YSkgJiYgIV8uaXNVbmRlZmluZWQoY3RybC5kYXRhLm5hbWVzcGFjZSkpIHtcblx0XHRpZiAoIV8uaXNVbmRlZmluZWQoY3RybC5tb2RlbC5jb250YWN0LnByb3BzWydYLUFCTEFCRUwnXSkpIHtcblx0XHRcdHZhciB2YWwgPSBfLmZpbmQodGhpcy5tb2RlbC5jb250YWN0LnByb3BzWydYLUFCTEFCRUwnXSwgZnVuY3Rpb24oeCkgeyByZXR1cm4geC5uYW1lc3BhY2UgPT09IGN0cmwuZGF0YS5uYW1lc3BhY2U7IH0pO1xuXHRcdFx0Y3RybC50eXBlID0gdmFsLnZhbHVlO1xuXHRcdFx0aWYgKCFfLmlzVW5kZWZpbmVkKHZhbCkpIHtcblx0XHRcdFx0Ly8gaW4gY2FzZSB0aGUgdHlwZSBpcyBub3QgeWV0IGluIHRoZSBkZWZhdWx0IGxpc3Qgb2YgYXZhaWxhYmxlIG9wdGlvbnMgd2UgYWRkIGl0XG5cdFx0XHRcdGlmICghY3RybC5hdmFpbGFibGVPcHRpb25zLnNvbWUoZnVuY3Rpb24oZSkgeyByZXR1cm4gZS5pZCA9PT0gdmFsLnZhbHVlOyB9ICkpIHtcblx0XHRcdFx0XHRjdHJsLmF2YWlsYWJsZU9wdGlvbnMgPSBjdHJsLmF2YWlsYWJsZU9wdGlvbnMuY29uY2F0KFt7aWQ6IHZhbC52YWx1ZSwgbmFtZTogdmFsLnZhbHVlfV0pO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cdGN0cmwuYXZhaWxhYmxlR3JvdXBzID0gW107XG5cblx0Q29udGFjdFNlcnZpY2UuZ2V0R3JvdXBzKCkudGhlbihmdW5jdGlvbihncm91cHMpIHtcblx0XHRjdHJsLmF2YWlsYWJsZUdyb3VwcyA9IF8udW5pcXVlKGdyb3Vwcyk7XG5cdH0pO1xuXG5cdGN0cmwuY2hhbmdlVHlwZSA9IGZ1bmN0aW9uICh2YWwpIHtcblx0XHRpZiAoY3RybC5pc1ByZWZlcnJlZCkge1xuXHRcdFx0dmFsICs9ICcsUFJFRic7XG5cdFx0fVxuXHRcdGN0cmwuZGF0YS5tZXRhID0gY3RybC5kYXRhLm1ldGEgfHwge307XG5cdFx0Y3RybC5kYXRhLm1ldGEudHlwZSA9IGN0cmwuZGF0YS5tZXRhLnR5cGUgfHwgW107XG5cdFx0Y3RybC5kYXRhLm1ldGEudHlwZVswXSA9IHZhbDtcblx0XHRjdHJsLm1vZGVsLnVwZGF0ZUNvbnRhY3QoKTtcblx0fTtcblxuXHRjdHJsLmRhdGVJbnB1dENoYW5nZWQgPSBmdW5jdGlvbiAoKSB7XG5cdFx0Y3RybC5kYXRhLm1ldGEgPSBjdHJsLmRhdGEubWV0YSB8fCB7fTtcblxuXHRcdHZhciBtYXRjaCA9IGN0cmwuZGF0YS52YWx1ZS5tYXRjaCgvXihcXGR7NH0pLShcXGR7Mn0pLShcXGR7Mn0pJC8pO1xuXHRcdGlmIChtYXRjaCkge1xuXHRcdFx0Y3RybC5kYXRhLm1ldGEudmFsdWUgPSBbXTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Y3RybC5kYXRhLm1ldGEudmFsdWUgPSBjdHJsLmRhdGEubWV0YS52YWx1ZSB8fCBbXTtcblx0XHRcdGN0cmwuZGF0YS5tZXRhLnZhbHVlWzBdID0gJ3RleHQnO1xuXHRcdH1cblx0XHRjdHJsLm1vZGVsLnVwZGF0ZUNvbnRhY3QoKTtcblx0fTtcblxuXHRjdHJsLnVwZGF0ZURldGFpbGVkTmFtZSA9IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgZm4gPSAnJztcblx0XHRpZiAoY3RybC5kYXRhLnZhbHVlWzNdKSB7XG5cdFx0XHRmbiArPSBjdHJsLmRhdGEudmFsdWVbM10gKyAnICc7XG5cdFx0fVxuXHRcdGlmIChjdHJsLmRhdGEudmFsdWVbMV0pIHtcblx0XHRcdGZuICs9IGN0cmwuZGF0YS52YWx1ZVsxXSArICcgJztcblx0XHR9XG5cdFx0aWYgKGN0cmwuZGF0YS52YWx1ZVsyXSkge1xuXHRcdFx0Zm4gKz0gY3RybC5kYXRhLnZhbHVlWzJdICsgJyAnO1xuXHRcdH1cblx0XHRpZiAoY3RybC5kYXRhLnZhbHVlWzBdKSB7XG5cdFx0XHRmbiArPSBjdHJsLmRhdGEudmFsdWVbMF0gKyAnICc7XG5cdFx0fVxuXHRcdGlmIChjdHJsLmRhdGEudmFsdWVbNF0pIHtcblx0XHRcdGZuICs9IGN0cmwuZGF0YS52YWx1ZVs0XTtcblx0XHR9XG5cblx0XHRjdHJsLm1vZGVsLmNvbnRhY3QuZnVsbE5hbWUoZm4pO1xuXHRcdGN0cmwubW9kZWwudXBkYXRlQ29udGFjdCgpO1xuXHR9O1xuXG5cdGN0cmwuZ2V0VGVtcGxhdGUgPSBmdW5jdGlvbigpIHtcblx0XHR2YXIgdGVtcGxhdGVVcmwgPSBPQy5saW5rVG8oJ2NvbnRhY3RzJywgJ3RlbXBsYXRlcy9kZXRhaWxJdGVtcy8nICsgY3RybC5tZXRhLnRlbXBsYXRlICsgJy5odG1sJyk7XG5cdFx0cmV0dXJuICR0ZW1wbGF0ZVJlcXVlc3QodGVtcGxhdGVVcmwpO1xuXHR9O1xuXG5cdGN0cmwuZGVsZXRlRmllbGQgPSBmdW5jdGlvbiAoKSB7XG5cdFx0Y3RybC5tb2RlbC5kZWxldGVGaWVsZChjdHJsLm5hbWUsIGN0cmwuZGF0YSk7XG5cdFx0Y3RybC5tb2RlbC51cGRhdGVDb250YWN0KCk7XG5cdH07XG59KTtcbiIsImFuZ3VsYXIubW9kdWxlKCdjb250YWN0c0FwcCcpXG4uZGlyZWN0aXZlKCdkZXRhaWxzaXRlbScsIFsnJGNvbXBpbGUnLCBmdW5jdGlvbigkY29tcGlsZSkge1xuXHRyZXR1cm4ge1xuXHRcdHNjb3BlOiB7fSxcblx0XHRjb250cm9sbGVyOiAnZGV0YWlsc0l0ZW1DdHJsJyxcblx0XHRjb250cm9sbGVyQXM6ICdjdHJsJyxcblx0XHRiaW5kVG9Db250cm9sbGVyOiB7XG5cdFx0XHRuYW1lOiAnPScsXG5cdFx0XHRkYXRhOiAnPScsXG5cdFx0XHRtb2RlbDogJz0nLFxuXHRcdFx0aW5kZXg6ICc9J1xuXHRcdH0sXG5cdFx0bGluazogZnVuY3Rpb24oc2NvcGUsIGVsZW1lbnQsIGF0dHJzLCBjdHJsKSB7XG5cdFx0XHRjdHJsLmdldFRlbXBsYXRlKCkudGhlbihmdW5jdGlvbihodG1sKSB7XG5cdFx0XHRcdHZhciB0ZW1wbGF0ZSA9IGFuZ3VsYXIuZWxlbWVudChodG1sKTtcblx0XHRcdFx0ZWxlbWVudC5hcHBlbmQodGVtcGxhdGUpO1xuXHRcdFx0XHQkY29tcGlsZSh0ZW1wbGF0ZSkoc2NvcGUpO1xuXHRcdFx0fSk7XG5cdFx0fVxuXHR9O1xufV0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5jb250cm9sbGVyKCdncm91cEN0cmwnLCBmdW5jdGlvbigpIHtcblx0Ly8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVudXNlZC12YXJzXG5cdHZhciBjdHJsID0gdGhpcztcbn0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5kaXJlY3RpdmUoJ2dyb3VwJywgZnVuY3Rpb24oKSB7XG5cdHJldHVybiB7XG5cdFx0cmVzdHJpY3Q6ICdBJywgLy8gaGFzIHRvIGJlIGFuIGF0dHJpYnV0ZSB0byB3b3JrIHdpdGggY29yZSBjc3Ncblx0XHRzY29wZToge30sXG5cdFx0Y29udHJvbGxlcjogJ2dyb3VwQ3RybCcsXG5cdFx0Y29udHJvbGxlckFzOiAnY3RybCcsXG5cdFx0YmluZFRvQ29udHJvbGxlcjoge1xuXHRcdFx0Z3JvdXA6ICc9Z3JvdXBOYW1lJyxcblx0XHRcdGdyb3VwQ291bnQ6ICc9Z3JvdXBDb3VudCdcblx0XHR9LFxuXHRcdHRlbXBsYXRlVXJsOiBPQy5saW5rVG8oJ2NvbnRhY3RzJywgJ3RlbXBsYXRlcy9ncm91cC5odG1sJylcblx0fTtcbn0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5jb250cm9sbGVyKCdncm91cGxpc3RDdHJsJywgZnVuY3Rpb24oJHNjb3BlLCBDb250YWN0U2VydmljZSwgU2VhcmNoU2VydmljZSwgJHJvdXRlUGFyYW1zKSB7XG5cdHZhciBjdHJsID0gdGhpcztcblxuXHRjdHJsLmdyb3VwcyA9IFtdO1xuXG5cdENvbnRhY3RTZXJ2aWNlLmdldEdyb3VwTGlzdCgpLnRoZW4oZnVuY3Rpb24oZ3JvdXBzKSB7XG5cdFx0Y3RybC5ncm91cHMgPSBncm91cHM7XG5cdH0pO1xuXG5cdGN0cmwuZ2V0U2VsZWN0ZWQgPSBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gJHJvdXRlUGFyYW1zLmdpZDtcblx0fTtcblxuXHQvLyBVcGRhdGUgZ3JvdXBMaXN0IG9uIGNvbnRhY3QgYWRkL2RlbGV0ZS91cGRhdGVcblx0Q29udGFjdFNlcnZpY2UucmVnaXN0ZXJPYnNlcnZlckNhbGxiYWNrKGZ1bmN0aW9uKGV2KSB7XG5cdFx0aWYgKGV2LmV2ZW50ICE9PSAnZ2V0RnVsbENvbnRhY3RzJykge1xuXHRcdFx0JHNjb3BlLiRhcHBseShmdW5jdGlvbigpIHtcblx0XHRcdFx0Q29udGFjdFNlcnZpY2UuZ2V0R3JvdXBMaXN0KCkudGhlbihmdW5jdGlvbihncm91cHMpIHtcblx0XHRcdFx0XHRjdHJsLmdyb3VwcyA9IGdyb3Vwcztcblx0XHRcdFx0fSk7XG5cdFx0XHR9KTtcblx0XHR9XG5cdH0pO1xuXG5cdGN0cmwuc2V0U2VsZWN0ZWQgPSBmdW5jdGlvbiAoc2VsZWN0ZWRHcm91cCkge1xuXHRcdFNlYXJjaFNlcnZpY2UuY2xlYW5TZWFyY2goKTtcblx0XHQkcm91dGVQYXJhbXMuZ2lkID0gc2VsZWN0ZWRHcm91cDtcblx0fTtcbn0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5kaXJlY3RpdmUoJ2dyb3VwbGlzdCcsIGZ1bmN0aW9uKCkge1xuXHRyZXR1cm4ge1xuXHRcdHJlc3RyaWN0OiAnRUEnLCAvLyBoYXMgdG8gYmUgYW4gYXR0cmlidXRlIHRvIHdvcmsgd2l0aCBjb3JlIGNzc1xuXHRcdHNjb3BlOiB7fSxcblx0XHRjb250cm9sbGVyOiAnZ3JvdXBsaXN0Q3RybCcsXG5cdFx0Y29udHJvbGxlckFzOiAnY3RybCcsXG5cdFx0YmluZFRvQ29udHJvbGxlcjoge30sXG5cdFx0dGVtcGxhdGVVcmw6IE9DLmxpbmtUbygnY29udGFjdHMnLCAndGVtcGxhdGVzL2dyb3VwTGlzdC5odG1sJylcblx0fTtcbn0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5jb250cm9sbGVyKCduZXdDb250YWN0QnV0dG9uQ3RybCcsIGZ1bmN0aW9uKCRzY29wZSwgQ29udGFjdFNlcnZpY2UsICRyb3V0ZVBhcmFtcywgdkNhcmRQcm9wZXJ0aWVzU2VydmljZSkge1xuXHR2YXIgY3RybCA9IHRoaXM7XG5cblx0Y3RybC50ID0ge1xuXHRcdGFkZENvbnRhY3QgOiB0KCdjb250YWN0cycsICdOZXcgY29udGFjdCcpXG5cdH07XG5cblx0Y3RybC5jcmVhdGVDb250YWN0ID0gZnVuY3Rpb24oKSB7XG5cdFx0Q29udGFjdFNlcnZpY2UuY3JlYXRlKCkudGhlbihmdW5jdGlvbihjb250YWN0KSB7XG5cdFx0XHRbJ3RlbCcsICdhZHInLCAnZW1haWwnXS5mb3JFYWNoKGZ1bmN0aW9uKGZpZWxkKSB7XG5cdFx0XHRcdHZhciBkZWZhdWx0VmFsdWUgPSB2Q2FyZFByb3BlcnRpZXNTZXJ2aWNlLmdldE1ldGEoZmllbGQpLmRlZmF1bHRWYWx1ZSB8fCB7dmFsdWU6ICcnfTtcblx0XHRcdFx0Y29udGFjdC5hZGRQcm9wZXJ0eShmaWVsZCwgZGVmYXVsdFZhbHVlKTtcblx0XHRcdH0gKTtcblx0XHRcdENvbnRhY3RTZXJ2aWNlLnVwZGF0ZU5ld0NvbnRhY3RKdXN0QWRkZWQoKTtcblx0XHRcdGlmIChbdCgnY29udGFjdHMnLCAnQWxsIGNvbnRhY3RzJyksIHQoJ2NvbnRhY3RzJywgJ05vdCBncm91cGVkJyldLmluZGV4T2YoJHJvdXRlUGFyYW1zLmdpZCkgPT09IC0xKSB7XG5cdFx0XHRcdGNvbnRhY3QuY2F0ZWdvcmllcyhbICRyb3V0ZVBhcmFtcy5naWQgXSk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRjb250YWN0LmNhdGVnb3JpZXMoW10pO1xuXHRcdFx0fVxuXHRcdFx0JCgnI2RldGFpbHMtZnVsbE5hbWUnKS5mb2N1cygpO1xuXHRcdH0pO1xuXHR9O1xufSk7XG4iLCJhbmd1bGFyLm1vZHVsZSgnY29udGFjdHNBcHAnKVxuLmRpcmVjdGl2ZSgnbmV3Y29udGFjdGJ1dHRvbicsIGZ1bmN0aW9uKCkge1xuXHRyZXR1cm4ge1xuXHRcdHJlc3RyaWN0OiAnRUEnLCAvLyBoYXMgdG8gYmUgYW4gYXR0cmlidXRlIHRvIHdvcmsgd2l0aCBjb3JlIGNzc1xuXHRcdHNjb3BlOiB7fSxcblx0XHRjb250cm9sbGVyOiAnbmV3Q29udGFjdEJ1dHRvbkN0cmwnLFxuXHRcdGNvbnRyb2xsZXJBczogJ2N0cmwnLFxuXHRcdGJpbmRUb0NvbnRyb2xsZXI6IHt9LFxuXHRcdHRlbXBsYXRlVXJsOiBPQy5saW5rVG8oJ2NvbnRhY3RzJywgJ3RlbXBsYXRlcy9uZXdDb250YWN0QnV0dG9uLmh0bWwnKVxuXHR9O1xufSk7XG4iLCJhbmd1bGFyLm1vZHVsZSgnY29udGFjdHNBcHAnKVxuLmRpcmVjdGl2ZSgndGVsTW9kZWwnLCBmdW5jdGlvbigpIHtcblx0cmV0dXJue1xuXHRcdHJlc3RyaWN0OiAnQScsXG5cdFx0cmVxdWlyZTogJ25nTW9kZWwnLFxuXHRcdGxpbms6IGZ1bmN0aW9uKHNjb3BlLCBlbGVtZW50LCBhdHRyLCBuZ01vZGVsKSB7XG5cdFx0XHRuZ01vZGVsLiRmb3JtYXR0ZXJzLnB1c2goZnVuY3Rpb24odmFsdWUpIHtcblx0XHRcdFx0cmV0dXJuIHZhbHVlO1xuXHRcdFx0fSk7XG5cdFx0XHRuZ01vZGVsLiRwYXJzZXJzLnB1c2goZnVuY3Rpb24odmFsdWUpIHtcblx0XHRcdFx0cmV0dXJuIHZhbHVlO1xuXHRcdFx0fSk7XG5cdFx0fVxuXHR9O1xufSk7XG4iLCJhbmd1bGFyLm1vZHVsZSgnY29udGFjdHNBcHAnKVxuLmNvbnRyb2xsZXIoJ3NvcnRieUN0cmwnLCBmdW5jdGlvbihTb3J0QnlTZXJ2aWNlKSB7XG5cdHZhciBjdHJsID0gdGhpcztcblxuXHR2YXIgc29ydFRleHQgPSB0KCdjb250YWN0cycsICdTb3J0IGJ5Jyk7XG5cdGN0cmwuc29ydFRleHQgPSBzb3J0VGV4dDtcblxuXHR2YXIgc29ydExpc3QgPSBTb3J0QnlTZXJ2aWNlLmdldFNvcnRCeUxpc3QoKTtcblx0Y3RybC5zb3J0TGlzdCA9IHNvcnRMaXN0O1xuXG5cdGN0cmwuZGVmYXVsdE9yZGVyID0gU29ydEJ5U2VydmljZS5nZXRTb3J0QnkoKTtcblxuXHRjdHJsLnVwZGF0ZVNvcnRCeSA9IGZ1bmN0aW9uKCkge1xuXHRcdFNvcnRCeVNlcnZpY2Uuc2V0U29ydEJ5KGN0cmwuZGVmYXVsdE9yZGVyKTtcblx0fTtcbn0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5kaXJlY3RpdmUoJ3NvcnRieScsIGZ1bmN0aW9uKCkge1xuXHRyZXR1cm4ge1xuXHRcdHByaW9yaXR5OiAxLFxuXHRcdHNjb3BlOiB7fSxcblx0XHRjb250cm9sbGVyOiAnc29ydGJ5Q3RybCcsXG5cdFx0Y29udHJvbGxlckFzOiAnY3RybCcsXG5cdFx0YmluZFRvQ29udHJvbGxlcjoge30sXG5cdFx0dGVtcGxhdGVVcmw6IE9DLmxpbmtUbygnY29udGFjdHMnLCAndGVtcGxhdGVzL3NvcnRCeS5odG1sJylcblx0fTtcbn0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5mYWN0b3J5KCdBZGRyZXNzQm9vaycsIGZ1bmN0aW9uKClcbntcblx0cmV0dXJuIGZ1bmN0aW9uIEFkZHJlc3NCb29rKGRhdGEpIHtcblx0XHRhbmd1bGFyLmV4dGVuZCh0aGlzLCB7XG5cblx0XHRcdGRpc3BsYXlOYW1lOiAnJyxcblx0XHRcdGNvbnRhY3RzOiBbXSxcblx0XHRcdGdyb3VwczogZGF0YS5kYXRhLnByb3BzLmdyb3VwcyxcblxuXHRcdFx0Z2V0Q29udGFjdDogZnVuY3Rpb24odWlkKSB7XG5cdFx0XHRcdGZvcih2YXIgaSBpbiB0aGlzLmNvbnRhY3RzKSB7XG5cdFx0XHRcdFx0aWYodGhpcy5jb250YWN0c1tpXS51aWQoKSA9PT0gdWlkKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gdGhpcy5jb250YWN0c1tpXTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIHVuZGVmaW5lZDtcblx0XHRcdH0sXG5cblx0XHRcdHNoYXJlZFdpdGg6IHtcblx0XHRcdFx0dXNlcnM6IFtdLFxuXHRcdFx0XHRncm91cHM6IFtdXG5cdFx0XHR9XG5cblx0XHR9KTtcblx0XHRhbmd1bGFyLmV4dGVuZCh0aGlzLCBkYXRhKTtcblx0XHRhbmd1bGFyLmV4dGVuZCh0aGlzLCB7XG5cdFx0XHRvd25lcjogZGF0YS51cmwuc3BsaXQoJy8nKS5zbGljZSgtMywgLTIpWzBdXG5cdFx0fSk7XG5cblx0XHR2YXIgc2hhcmVzID0gdGhpcy5kYXRhLnByb3BzLmludml0ZTtcblx0XHRpZiAodHlwZW9mIHNoYXJlcyAhPT0gJ3VuZGVmaW5lZCcpIHtcblx0XHRcdGZvciAodmFyIGogPSAwOyBqIDwgc2hhcmVzLmxlbmd0aDsgaisrKSB7XG5cdFx0XHRcdHZhciBocmVmID0gc2hhcmVzW2pdLmhyZWY7XG5cdFx0XHRcdGlmIChocmVmLmxlbmd0aCA9PT0gMCkge1xuXHRcdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHZhciBhY2Nlc3MgPSBzaGFyZXNbal0uYWNjZXNzO1xuXHRcdFx0XHRpZiAoYWNjZXNzLmxlbmd0aCA9PT0gMCkge1xuXHRcdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0dmFyIHJlYWRXcml0ZSA9ICh0eXBlb2YgYWNjZXNzLnJlYWRXcml0ZSAhPT0gJ3VuZGVmaW5lZCcpO1xuXG5cdFx0XHRcdGlmIChocmVmLnN0YXJ0c1dpdGgoJ3ByaW5jaXBhbDpwcmluY2lwYWxzL3VzZXJzLycpKSB7XG5cdFx0XHRcdFx0dGhpcy5zaGFyZWRXaXRoLnVzZXJzLnB1c2goe1xuXHRcdFx0XHRcdFx0aWQ6IGhyZWYuc3Vic3RyKDI3KSxcblx0XHRcdFx0XHRcdGRpc3BsYXluYW1lOiBocmVmLnN1YnN0cigyNyksXG5cdFx0XHRcdFx0XHR3cml0YWJsZTogcmVhZFdyaXRlXG5cdFx0XHRcdFx0fSk7XG5cdFx0XHRcdH0gZWxzZSBpZiAoaHJlZi5zdGFydHNXaXRoKCdwcmluY2lwYWw6cHJpbmNpcGFscy9ncm91cHMvJykpIHtcblx0XHRcdFx0XHR0aGlzLnNoYXJlZFdpdGguZ3JvdXBzLnB1c2goe1xuXHRcdFx0XHRcdFx0aWQ6IGhyZWYuc3Vic3RyKDI4KSxcblx0XHRcdFx0XHRcdGRpc3BsYXluYW1lOiBocmVmLnN1YnN0cigyOCksXG5cdFx0XHRcdFx0XHR3cml0YWJsZTogcmVhZFdyaXRlXG5cdFx0XHRcdFx0fSk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHQvL3ZhciBvd25lciA9IHRoaXMuZGF0YS5wcm9wcy5vd25lcjtcblx0XHQvL2lmICh0eXBlb2Ygb3duZXIgIT09ICd1bmRlZmluZWQnICYmIG93bmVyLmxlbmd0aCAhPT0gMCkge1xuXHRcdC8vXHRvd25lciA9IG93bmVyLnRyaW0oKTtcblx0XHQvL1x0aWYgKG93bmVyLnN0YXJ0c1dpdGgoJy9yZW1vdGUucGhwL2Rhdi9wcmluY2lwYWxzL3VzZXJzLycpKSB7XG5cdFx0Ly9cdFx0dGhpcy5fcHJvcGVydGllcy5vd25lciA9IG93bmVyLnN1YnN0cigzMyk7XG5cdFx0Ly9cdH1cblx0XHQvL31cblxuXHR9O1xufSk7XG4iLCJhbmd1bGFyLm1vZHVsZSgnY29udGFjdHNBcHAnKVxuLmZhY3RvcnkoJ0NvbnRhY3QnLCBmdW5jdGlvbigkZmlsdGVyLCBNaW1lU2VydmljZSkge1xuXHRyZXR1cm4gZnVuY3Rpb24gQ29udGFjdChhZGRyZXNzQm9vaywgdkNhcmQpIHtcblx0XHRhbmd1bGFyLmV4dGVuZCh0aGlzLCB7XG5cblx0XHRcdGRhdGE6IHt9LFxuXHRcdFx0cHJvcHM6IHt9LFxuXHRcdFx0ZmFpbGVkUHJvcHM6IFtdLFxuXG5cdFx0XHRkYXRlUHJvcGVydGllczogWydiZGF5JywgJ2Fubml2ZXJzYXJ5JywgJ2RlYXRoZGF0ZSddLFxuXG5cdFx0XHRhZGRyZXNzQm9va0lkOiBhZGRyZXNzQm9vay5kaXNwbGF5TmFtZSxcblxuXHRcdFx0dmVyc2lvbjogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHZhciBwcm9wZXJ0eSA9IHRoaXMuZ2V0UHJvcGVydHkoJ3ZlcnNpb24nKTtcblx0XHRcdFx0aWYocHJvcGVydHkpIHtcblx0XHRcdFx0XHRyZXR1cm4gcHJvcGVydHkudmFsdWU7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRyZXR1cm4gdW5kZWZpbmVkO1xuXHRcdFx0fSxcblxuXHRcdFx0dWlkOiBmdW5jdGlvbih2YWx1ZSkge1xuXHRcdFx0XHR2YXIgbW9kZWwgPSB0aGlzO1xuXHRcdFx0XHRpZiAoYW5ndWxhci5pc0RlZmluZWQodmFsdWUpKSB7XG5cdFx0XHRcdFx0Ly8gc2V0dGVyXG5cdFx0XHRcdFx0cmV0dXJuIG1vZGVsLnNldFByb3BlcnR5KCd1aWQnLCB7IHZhbHVlOiB2YWx1ZSB9KTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHQvLyBnZXR0ZXJcblx0XHRcdFx0XHRyZXR1cm4gbW9kZWwuZ2V0UHJvcGVydHkoJ3VpZCcpLnZhbHVlO1xuXHRcdFx0XHR9XG5cdFx0XHR9LFxuXG5cdFx0XHRzb3J0Rmlyc3ROYW1lOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0cmV0dXJuIFt0aGlzLmZpcnN0TmFtZSgpLCB0aGlzLmxhc3ROYW1lKCldO1xuXHRcdFx0fSxcblxuXHRcdFx0c29ydExhc3ROYW1lOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0cmV0dXJuIFt0aGlzLmxhc3ROYW1lKCksIHRoaXMuZmlyc3ROYW1lKCldO1xuXHRcdFx0fSxcblxuXHRcdFx0c29ydERpc3BsYXlOYW1lOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0cmV0dXJuIHRoaXMuZGlzcGxheU5hbWUoKTtcblx0XHRcdH0sXG5cblx0XHRcdGRpc3BsYXlOYW1lOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0dmFyIGRpc3BsYXlOYW1lID0gdGhpcy5mdWxsTmFtZSgpIHx8IHRoaXMub3JnKCkgfHwgJyc7XG5cdFx0XHRcdGlmKGFuZ3VsYXIuaXNBcnJheShkaXNwbGF5TmFtZSkpIHtcblx0XHRcdFx0XHRyZXR1cm4gZGlzcGxheU5hbWUuam9pbignICcpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiBkaXNwbGF5TmFtZTtcblx0XHRcdH0sXG5cblx0XHRcdHJlYWRhYmxlRmlsZW5hbWU6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRpZih0aGlzLmRpc3BsYXlOYW1lKCkpIHtcblx0XHRcdFx0XHRyZXR1cm4gKHRoaXMuZGlzcGxheU5hbWUoKSkgKyAnLnZjZic7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0Ly8gZmFsbGJhY2sgdG8gZGVmYXVsdCBmaWxlbmFtZSAoc2VlIGRvd25sb2FkIGF0dHJpYnV0ZSlcblx0XHRcdFx0XHRyZXR1cm4gJyc7XG5cdFx0XHRcdH1cblxuXHRcdFx0fSxcblxuXHRcdFx0Zmlyc3ROYW1lOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0dmFyIHByb3BlcnR5ID0gdGhpcy5nZXRQcm9wZXJ0eSgnbicpO1xuXHRcdFx0XHRpZiAocHJvcGVydHkpIHtcblx0XHRcdFx0XHRyZXR1cm4gcHJvcGVydHkudmFsdWVbMV07XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0cmV0dXJuIHRoaXMuZGlzcGxheU5hbWUoKTtcblx0XHRcdFx0fVxuXHRcdFx0fSxcblxuXHRcdFx0bGFzdE5hbWU6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR2YXIgcHJvcGVydHkgPSB0aGlzLmdldFByb3BlcnR5KCduJyk7XG5cdFx0XHRcdGlmIChwcm9wZXJ0eSkge1xuXHRcdFx0XHRcdHJldHVybiBwcm9wZXJ0eS52YWx1ZVswXTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRyZXR1cm4gdGhpcy5kaXNwbGF5TmFtZSgpO1xuXHRcdFx0XHR9XG5cdFx0XHR9LFxuXG5cdFx0XHRhZGRpdGlvbmFsTmFtZXM6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR2YXIgcHJvcGVydHkgPSB0aGlzLmdldFByb3BlcnR5KCduJyk7XG5cdFx0XHRcdGlmIChwcm9wZXJ0eSkge1xuXHRcdFx0XHRcdHJldHVybiBwcm9wZXJ0eS52YWx1ZVsyXTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRyZXR1cm4gJyc7XG5cdFx0XHRcdH1cblx0XHRcdH0sXG5cblx0XHRcdGZ1bGxOYW1lOiBmdW5jdGlvbih2YWx1ZSkge1xuXHRcdFx0XHR2YXIgbW9kZWwgPSB0aGlzO1xuXHRcdFx0XHRpZiAoYW5ndWxhci5pc0RlZmluZWQodmFsdWUpKSB7XG5cdFx0XHRcdFx0Ly8gc2V0dGVyXG5cdFx0XHRcdFx0cmV0dXJuIHRoaXMuc2V0UHJvcGVydHkoJ2ZuJywgeyB2YWx1ZTogdmFsdWUgfSk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0Ly8gZ2V0dGVyXG5cdFx0XHRcdFx0dmFyIHByb3BlcnR5ID0gbW9kZWwuZ2V0UHJvcGVydHkoJ2ZuJyk7XG5cdFx0XHRcdFx0aWYocHJvcGVydHkpIHtcblx0XHRcdFx0XHRcdHJldHVybiBwcm9wZXJ0eS52YWx1ZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0cHJvcGVydHkgPSBtb2RlbC5nZXRQcm9wZXJ0eSgnbicpO1xuXHRcdFx0XHRcdGlmKHByb3BlcnR5KSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gcHJvcGVydHkudmFsdWUuZmlsdGVyKGZ1bmN0aW9uKGVsZW0pIHtcblx0XHRcdFx0XHRcdFx0cmV0dXJuIGVsZW07XG5cdFx0XHRcdFx0XHR9KS5qb2luKCcgJyk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHJldHVybiB1bmRlZmluZWQ7XG5cdFx0XHRcdH1cblx0XHRcdH0sXG5cblx0XHRcdHRpdGxlOiBmdW5jdGlvbih2YWx1ZSkge1xuXHRcdFx0XHRpZiAoYW5ndWxhci5pc0RlZmluZWQodmFsdWUpKSB7XG5cdFx0XHRcdFx0Ly8gc2V0dGVyXG5cdFx0XHRcdFx0cmV0dXJuIHRoaXMuc2V0UHJvcGVydHkoJ3RpdGxlJywgeyB2YWx1ZTogdmFsdWUgfSk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0Ly8gZ2V0dGVyXG5cdFx0XHRcdFx0dmFyIHByb3BlcnR5ID0gdGhpcy5nZXRQcm9wZXJ0eSgndGl0bGUnKTtcblx0XHRcdFx0XHRpZihwcm9wZXJ0eSkge1xuXHRcdFx0XHRcdFx0cmV0dXJuIHByb3BlcnR5LnZhbHVlO1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gdW5kZWZpbmVkO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fSxcblxuXHRcdFx0b3JnOiBmdW5jdGlvbih2YWx1ZSkge1xuXHRcdFx0XHR2YXIgcHJvcGVydHkgPSB0aGlzLmdldFByb3BlcnR5KCdvcmcnKTtcblx0XHRcdFx0aWYgKGFuZ3VsYXIuaXNEZWZpbmVkKHZhbHVlKSkge1xuXHRcdFx0XHRcdHZhciB2YWwgPSB2YWx1ZTtcblx0XHRcdFx0XHQvLyBzZXR0ZXJcblx0XHRcdFx0XHRpZihwcm9wZXJ0eSAmJiBBcnJheS5pc0FycmF5KHByb3BlcnR5LnZhbHVlKSkge1xuXHRcdFx0XHRcdFx0dmFsID0gcHJvcGVydHkudmFsdWU7XG5cdFx0XHRcdFx0XHR2YWxbMF0gPSB2YWx1ZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0cmV0dXJuIHRoaXMuc2V0UHJvcGVydHkoJ29yZycsIHsgdmFsdWU6IHZhbCB9KTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHQvLyBnZXR0ZXJcblx0XHRcdFx0XHRpZihwcm9wZXJ0eSkge1xuXHRcdFx0XHRcdFx0aWYgKEFycmF5LmlzQXJyYXkocHJvcGVydHkudmFsdWUpKSB7XG5cdFx0XHRcdFx0XHRcdHJldHVybiBwcm9wZXJ0eS52YWx1ZVswXTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdHJldHVybiBwcm9wZXJ0eS52YWx1ZTtcblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0cmV0dXJuIHVuZGVmaW5lZDtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH0sXG5cblx0XHRcdGVtYWlsOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0Ly8gZ2V0dGVyXG5cdFx0XHRcdHZhciBwcm9wZXJ0eSA9IHRoaXMuZ2V0UHJvcGVydHkoJ2VtYWlsJyk7XG5cdFx0XHRcdGlmKHByb3BlcnR5KSB7XG5cdFx0XHRcdFx0cmV0dXJuIHByb3BlcnR5LnZhbHVlO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHJldHVybiB1bmRlZmluZWQ7XG5cdFx0XHRcdH1cblx0XHRcdH0sXG5cblx0XHRcdHBob3RvOiBmdW5jdGlvbih2YWx1ZSkge1xuXHRcdFx0XHRpZiAoYW5ndWxhci5pc0RlZmluZWQodmFsdWUpKSB7XG5cdFx0XHRcdFx0Ly8gc2V0dGVyXG5cdFx0XHRcdFx0Ly8gc3BsaXRzIGltYWdlIGRhdGEgaW50byBcImRhdGE6aW1hZ2UvanBlZ1wiIGFuZCBiYXNlIDY0IGVuY29kZWQgaW1hZ2Vcblx0XHRcdFx0XHR2YXIgaW1hZ2VEYXRhID0gdmFsdWUuc3BsaXQoJztiYXNlNjQsJyk7XG5cdFx0XHRcdFx0dmFyIGltYWdlVHlwZSA9IGltYWdlRGF0YVswXS5zbGljZSgnZGF0YTonLmxlbmd0aCk7XG5cdFx0XHRcdFx0aWYgKCFpbWFnZVR5cGUuc3RhcnRzV2l0aCgnaW1hZ2UvJykpIHtcblx0XHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aW1hZ2VUeXBlID0gaW1hZ2VUeXBlLnN1YnN0cmluZyg2KS50b1VwcGVyQ2FzZSgpO1xuXG5cdFx0XHRcdFx0cmV0dXJuIHRoaXMuc2V0UHJvcGVydHkoJ3Bob3RvJywgeyB2YWx1ZTogaW1hZ2VEYXRhWzFdLCBtZXRhOiB7dHlwZTogW2ltYWdlVHlwZV0sIGVuY29kaW5nOiBbJ2InXX0gfSk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0dmFyIHByb3BlcnR5ID0gdGhpcy52YWxpZGF0ZSgncGhvdG8nLCB0aGlzLmdldFByb3BlcnR5KCdwaG90bycpKTtcblx0XHRcdFx0XHRpZihwcm9wZXJ0eSkge1xuXHRcdFx0XHRcdFx0dmFyIHR5cGUgPSBwcm9wZXJ0eS5tZXRhLnR5cGU7XG5cdFx0XHRcdFx0XHRpZiAoYW5ndWxhci5pc0FycmF5KHR5cGUpKSB7XG5cdFx0XHRcdFx0XHRcdHR5cGUgPSB0eXBlWzBdO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0aWYgKCF0eXBlLnN0YXJ0c1dpdGgoJ2ltYWdlLycpKSB7XG5cdFx0XHRcdFx0XHRcdHR5cGUgPSAnaW1hZ2UvJyArIHR5cGUudG9Mb3dlckNhc2UoKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdHJldHVybiAnZGF0YTonICsgdHlwZSArICc7YmFzZTY0LCcgKyBwcm9wZXJ0eS52YWx1ZTtcblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0cmV0dXJuIHVuZGVmaW5lZDtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH0sXG5cblx0XHRcdGNhdGVnb3JpZXM6IGZ1bmN0aW9uKHZhbHVlKSB7XG5cdFx0XHRcdGlmIChhbmd1bGFyLmlzRGVmaW5lZCh2YWx1ZSkpIHtcblx0XHRcdFx0XHQvLyBzZXR0ZXJcblx0XHRcdFx0XHRpZiAoYW5ndWxhci5pc1N0cmluZyh2YWx1ZSkpIHtcblx0XHRcdFx0XHRcdC8qIGNoZWNrIGZvciBlbXB0eSBzdHJpbmcgKi9cblx0XHRcdFx0XHRcdHRoaXMuc2V0UHJvcGVydHkoJ2NhdGVnb3JpZXMnLCB7IHZhbHVlOiAhdmFsdWUubGVuZ3RoID8gW10gOiBbdmFsdWVdIH0pO1xuXHRcdFx0XHRcdH0gZWxzZSBpZiAoYW5ndWxhci5pc0FycmF5KHZhbHVlKSkge1xuXHRcdFx0XHRcdFx0dGhpcy5zZXRQcm9wZXJ0eSgnY2F0ZWdvcmllcycsIHsgdmFsdWU6IHZhbHVlIH0pO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHQvLyBnZXR0ZXJcblx0XHRcdFx0XHR2YXIgcHJvcGVydHkgPSB0aGlzLnZhbGlkYXRlKCdjYXRlZ29yaWVzJywgdGhpcy5nZXRQcm9wZXJ0eSgnY2F0ZWdvcmllcycpKTtcblx0XHRcdFx0XHRpZighcHJvcGVydHkpIHtcblx0XHRcdFx0XHRcdHJldHVybiBbXTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aWYgKGFuZ3VsYXIuaXNBcnJheShwcm9wZXJ0eS52YWx1ZSkpIHtcblx0XHRcdFx0XHRcdHJldHVybiBwcm9wZXJ0eS52YWx1ZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0cmV0dXJuIFtwcm9wZXJ0eS52YWx1ZV07XG5cdFx0XHRcdH1cblx0XHRcdH0sXG5cblx0XHRcdGZvcm1hdERhdGVBc1JGQzYzNTA6IGZ1bmN0aW9uKG5hbWUsIGRhdGEpIHtcblx0XHRcdFx0aWYgKGFuZ3VsYXIuaXNVbmRlZmluZWQoZGF0YSkgfHwgYW5ndWxhci5pc1VuZGVmaW5lZChkYXRhLnZhbHVlKSkge1xuXHRcdFx0XHRcdHJldHVybiBkYXRhO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICh0aGlzLmRhdGVQcm9wZXJ0aWVzLmluZGV4T2YobmFtZSkgIT09IC0xKSB7XG5cdFx0XHRcdFx0dmFyIG1hdGNoID0gZGF0YS52YWx1ZS5tYXRjaCgvXihcXGR7NH0pLShcXGR7Mn0pLShcXGR7Mn0pJC8pO1xuXHRcdFx0XHRcdGlmIChtYXRjaCkge1xuXHRcdFx0XHRcdFx0ZGF0YS52YWx1ZSA9IG1hdGNoWzFdICsgbWF0Y2hbMl0gKyBtYXRjaFszXTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRyZXR1cm4gZGF0YTtcblx0XHRcdH0sXG5cblx0XHRcdGZvcm1hdERhdGVGb3JEaXNwbGF5OiBmdW5jdGlvbihuYW1lLCBkYXRhKSB7XG5cdFx0XHRcdGlmIChhbmd1bGFyLmlzVW5kZWZpbmVkKGRhdGEpIHx8IGFuZ3VsYXIuaXNVbmRlZmluZWQoZGF0YS52YWx1ZSkpIHtcblx0XHRcdFx0XHRyZXR1cm4gZGF0YTtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAodGhpcy5kYXRlUHJvcGVydGllcy5pbmRleE9mKG5hbWUpICE9PSAtMSkge1xuXHRcdFx0XHRcdHZhciBtYXRjaCA9IGRhdGEudmFsdWUubWF0Y2goL14oXFxkezR9KShcXGR7Mn0pKFxcZHsyfSkkLyk7XG5cdFx0XHRcdFx0aWYgKG1hdGNoKSB7XG5cdFx0XHRcdFx0XHRkYXRhLnZhbHVlID0gbWF0Y2hbMV0gKyAnLScgKyBtYXRjaFsyXSArICctJyArIG1hdGNoWzNdO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHJldHVybiBkYXRhO1xuXHRcdFx0fSxcblxuXHRcdFx0Z2V0UHJvcGVydHk6IGZ1bmN0aW9uKG5hbWUpIHtcblx0XHRcdFx0aWYgKHRoaXMucHJvcHNbbmFtZV0pIHtcblx0XHRcdFx0XHRyZXR1cm4gdGhpcy5mb3JtYXREYXRlRm9yRGlzcGxheShuYW1lLCB0aGlzLnByb3BzW25hbWVdWzBdKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRyZXR1cm4gdW5kZWZpbmVkO1xuXHRcdFx0XHR9XG5cdFx0XHR9LFxuXHRcdFx0YWRkUHJvcGVydHk6IGZ1bmN0aW9uKG5hbWUsIGRhdGEpIHtcblx0XHRcdFx0ZGF0YSA9IGFuZ3VsYXIuY29weShkYXRhKTtcblx0XHRcdFx0ZGF0YSA9IHRoaXMuZm9ybWF0RGF0ZUFzUkZDNjM1MChuYW1lLCBkYXRhKTtcblx0XHRcdFx0aWYoIXRoaXMucHJvcHNbbmFtZV0pIHtcblx0XHRcdFx0XHR0aGlzLnByb3BzW25hbWVdID0gW107XG5cdFx0XHRcdH1cblx0XHRcdFx0dmFyIGlkeCA9IHRoaXMucHJvcHNbbmFtZV0ubGVuZ3RoO1xuXHRcdFx0XHR0aGlzLnByb3BzW25hbWVdW2lkeF0gPSBkYXRhO1xuXG5cdFx0XHRcdC8vIGtlZXAgdkNhcmQgaW4gc3luY1xuXHRcdFx0XHR0aGlzLmRhdGEuYWRkcmVzc0RhdGEgPSAkZmlsdGVyKCdKU09OMnZDYXJkJykodGhpcy5wcm9wcyk7XG5cdFx0XHRcdHJldHVybiBpZHg7XG5cdFx0XHR9LFxuXHRcdFx0c2V0UHJvcGVydHk6IGZ1bmN0aW9uKG5hbWUsIGRhdGEpIHtcblx0XHRcdFx0aWYoIXRoaXMucHJvcHNbbmFtZV0pIHtcblx0XHRcdFx0XHR0aGlzLnByb3BzW25hbWVdID0gW107XG5cdFx0XHRcdH1cblx0XHRcdFx0ZGF0YSA9IHRoaXMuZm9ybWF0RGF0ZUFzUkZDNjM1MChuYW1lLCBkYXRhKTtcblx0XHRcdFx0dGhpcy5wcm9wc1tuYW1lXVswXSA9IGRhdGE7XG5cblx0XHRcdFx0Ly8ga2VlcCB2Q2FyZCBpbiBzeW5jXG5cdFx0XHRcdHRoaXMuZGF0YS5hZGRyZXNzRGF0YSA9ICRmaWx0ZXIoJ0pTT04ydkNhcmQnKSh0aGlzLnByb3BzKTtcblx0XHRcdH0sXG5cdFx0XHRyZW1vdmVQcm9wZXJ0eTogZnVuY3Rpb24gKG5hbWUsIHByb3ApIHtcblx0XHRcdFx0YW5ndWxhci5jb3B5KF8ud2l0aG91dCh0aGlzLnByb3BzW25hbWVdLCBwcm9wKSwgdGhpcy5wcm9wc1tuYW1lXSk7XG5cdFx0XHRcdHRoaXMuZGF0YS5hZGRyZXNzRGF0YSA9ICRmaWx0ZXIoJ0pTT04ydkNhcmQnKSh0aGlzLnByb3BzKTtcblx0XHRcdH0sXG5cdFx0XHRzZXRFVGFnOiBmdW5jdGlvbihldGFnKSB7XG5cdFx0XHRcdHRoaXMuZGF0YS5ldGFnID0gZXRhZztcblx0XHRcdH0sXG5cdFx0XHRzZXRVcmw6IGZ1bmN0aW9uKGFkZHJlc3NCb29rLCB1aWQpIHtcblx0XHRcdFx0dGhpcy5kYXRhLnVybCA9IGFkZHJlc3NCb29rLnVybCArIHVpZCArICcudmNmJztcblx0XHRcdH0sXG5cblx0XHRcdGdldElTT0RhdGU6IGZ1bmN0aW9uKGRhdGUpIHtcblx0XHRcdFx0ZnVuY3Rpb24gcGFkKG51bWJlcikge1xuXHRcdFx0XHRcdGlmIChudW1iZXIgPCAxMCkge1xuXHRcdFx0XHRcdFx0cmV0dXJuICcwJyArIG51bWJlcjtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0cmV0dXJuICcnICsgbnVtYmVyO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0cmV0dXJuIGRhdGUuZ2V0VVRDRnVsbFllYXIoKSArICcnICtcblx0XHRcdFx0XHRcdHBhZChkYXRlLmdldFVUQ01vbnRoKCkgKyAxKSArXG5cdFx0XHRcdFx0XHRwYWQoZGF0ZS5nZXRVVENEYXRlKCkpICtcblx0XHRcdFx0XHRcdCdUJyArIHBhZChkYXRlLmdldFVUQ0hvdXJzKCkpICtcblx0XHRcdFx0XHRcdHBhZChkYXRlLmdldFVUQ01pbnV0ZXMoKSkgK1xuXHRcdFx0XHRcdFx0cGFkKGRhdGUuZ2V0VVRDU2Vjb25kcygpKSArICdaJztcblx0XHRcdH0sXG5cblx0XHRcdHN5bmNWQ2FyZDogZnVuY3Rpb24oKSB7XG5cblx0XHRcdFx0dGhpcy5zZXRQcm9wZXJ0eSgncmV2JywgeyB2YWx1ZTogdGhpcy5nZXRJU09EYXRlKG5ldyBEYXRlKCkpIH0pO1xuXHRcdFx0XHR2YXIgc2VsZiA9IHRoaXM7XG5cblx0XHRcdFx0Xy5lYWNoKHRoaXMuZGF0ZVByb3BlcnRpZXMsIGZ1bmN0aW9uKG5hbWUpIHtcblx0XHRcdFx0XHRpZiAoIWFuZ3VsYXIuaXNVbmRlZmluZWQoc2VsZi5wcm9wc1tuYW1lXSkgJiYgIWFuZ3VsYXIuaXNVbmRlZmluZWQoc2VsZi5wcm9wc1tuYW1lXVswXSkpIHtcblx0XHRcdFx0XHRcdC8vIFNldCBkYXRlcyBhZ2FpbiB0byBtYWtlIHN1cmUgdGhleSBhcmUgaW4gUkZDLTYzNTAgZm9ybWF0XG5cdFx0XHRcdFx0XHRzZWxmLnNldFByb3BlcnR5KG5hbWUsIHNlbGYucHJvcHNbbmFtZV1bMF0pO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSk7XG5cdFx0XHRcdC8vIGZvcmNlIGZuIHRvIGJlIHNldFxuXHRcdFx0XHR0aGlzLmZ1bGxOYW1lKHRoaXMuZnVsbE5hbWUoKSk7XG5cblx0XHRcdFx0Ly8ga2VlcCB2Q2FyZCBpbiBzeW5jXG5cdFx0XHRcdHNlbGYuZGF0YS5hZGRyZXNzRGF0YSA9ICRmaWx0ZXIoJ0pTT04ydkNhcmQnKShzZWxmLnByb3BzKTtcblxuXHRcdFx0XHQvLyBSZXZhbGlkYXRlIGFsbCBwcm9wc1xuXHRcdFx0XHRfLmVhY2goc2VsZi5mYWlsZWRQcm9wcywgZnVuY3Rpb24obmFtZSwgaW5kZXgpIHtcblx0XHRcdFx0XHRpZiAoIWFuZ3VsYXIuaXNVbmRlZmluZWQoc2VsZi5wcm9wc1tuYW1lXSkgJiYgIWFuZ3VsYXIuaXNVbmRlZmluZWQoc2VsZi5wcm9wc1tuYW1lXVswXSkpIHtcblx0XHRcdFx0XHRcdC8vIFJlc2V0IHByZXZpb3VzbHkgZmFpbGVkIHByb3BlcnRpZXNcblx0XHRcdFx0XHRcdHNlbGYuZmFpbGVkUHJvcHMuc3BsaWNlKGluZGV4LCAxKTtcblx0XHRcdFx0XHRcdC8vIEFuZCByZXZhbGlkYXRlIHRoZW0gYWdhaW5cblx0XHRcdFx0XHRcdHNlbGYudmFsaWRhdGUobmFtZSwgc2VsZi5wcm9wc1tuYW1lXVswXSk7XG5cblx0XHRcdFx0XHR9IGVsc2UgaWYoYW5ndWxhci5pc1VuZGVmaW5lZChzZWxmLnByb3BzW25hbWVdKSB8fCBhbmd1bGFyLmlzVW5kZWZpbmVkKHNlbGYucHJvcHNbbmFtZV1bMF0pKSB7XG5cdFx0XHRcdFx0XHQvLyBQcm9wZXJ0eSBoYXMgYmVlbiByZW1vdmVkXG5cdFx0XHRcdFx0XHRzZWxmLmZhaWxlZFByb3BzLnNwbGljZShpbmRleCwgMSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9KTtcblxuXHRcdFx0fSxcblxuXHRcdFx0bWF0Y2hlczogZnVuY3Rpb24ocGF0dGVybikge1xuXHRcdFx0XHRpZiAoYW5ndWxhci5pc1VuZGVmaW5lZChwYXR0ZXJuKSB8fCBwYXR0ZXJuLmxlbmd0aCA9PT0gMCkge1xuXHRcdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHZhciBtb2RlbCA9IHRoaXM7XG5cdFx0XHRcdHZhciBtYXRjaGluZ1Byb3BzID0gWydmbicsICd0aXRsZScsICdvcmcnLCAnZW1haWwnLCAnbmlja25hbWUnLCAnbm90ZScsICd1cmwnLCAnY2xvdWQnLCAnYWRyJywgJ2ltcHAnLCAndGVsJ10uZmlsdGVyKGZ1bmN0aW9uIChwcm9wTmFtZSkge1xuXHRcdFx0XHRcdGlmIChtb2RlbC5wcm9wc1twcm9wTmFtZV0pIHtcblx0XHRcdFx0XHRcdHJldHVybiBtb2RlbC5wcm9wc1twcm9wTmFtZV0uZmlsdGVyKGZ1bmN0aW9uIChwcm9wZXJ0eSkge1xuXHRcdFx0XHRcdFx0XHRpZiAoIXByb3BlcnR5LnZhbHVlKSB7XG5cdFx0XHRcdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdGlmIChhbmd1bGFyLmlzU3RyaW5nKHByb3BlcnR5LnZhbHVlKSkge1xuXHRcdFx0XHRcdFx0XHRcdHJldHVybiBwcm9wZXJ0eS52YWx1ZS50b0xvd2VyQ2FzZSgpLmluZGV4T2YocGF0dGVybi50b0xvd2VyQ2FzZSgpKSAhPT0gLTE7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0aWYgKGFuZ3VsYXIuaXNBcnJheShwcm9wZXJ0eS52YWx1ZSkpIHtcblx0XHRcdFx0XHRcdFx0XHRyZXR1cm4gcHJvcGVydHkudmFsdWUuZmlsdGVyKGZ1bmN0aW9uKHYpIHtcblx0XHRcdFx0XHRcdFx0XHRcdHJldHVybiB2LnRvTG93ZXJDYXNlKCkuaW5kZXhPZihwYXR0ZXJuLnRvTG93ZXJDYXNlKCkpICE9PSAtMTtcblx0XHRcdFx0XHRcdFx0XHR9KS5sZW5ndGggPiAwO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdFx0XHRcdH0pLmxlbmd0aCA+IDA7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdFx0fSk7XG5cdFx0XHRcdHJldHVybiBtYXRjaGluZ1Byb3BzLmxlbmd0aCA+IDA7XG5cdFx0XHR9LFxuXG5cdFx0XHQvKiBlc2xpbnQtZGlzYWJsZSBuby1jb25zb2xlICovXG5cdFx0XHR2YWxpZGF0ZTogZnVuY3Rpb24ocHJvcCwgcHJvcGVydHkpIHtcblx0XHRcdFx0c3dpdGNoKHByb3ApIHtcblx0XHRcdFx0Y2FzZSAnY2F0ZWdvcmllcyc6XG5cdFx0XHRcdFx0Ly8gQXZvaWQgdW5lc2NhcGVkIGNvbW1hc1xuXHRcdFx0XHRcdGlmIChhbmd1bGFyLmlzQXJyYXkocHJvcGVydHkudmFsdWUpKSB7XG5cdFx0XHRcdFx0XHRpZihwcm9wZXJ0eS52YWx1ZS5qb2luKCc7JykuaW5kZXhPZignLCcpICE9PSAtMSkge1xuXHRcdFx0XHRcdFx0XHR0aGlzLmZhaWxlZFByb3BzLnB1c2gocHJvcCk7XG5cdFx0XHRcdFx0XHRcdHByb3BlcnR5LnZhbHVlID0gcHJvcGVydHkudmFsdWUuam9pbignLCcpLnNwbGl0KCcsJyk7XG5cdFx0XHRcdFx0XHRcdC8vY29uc29sZS53YXJuKHRoaXMudWlkKCkrJzogQ2F0ZWdvcmllcyBzcGxpdDogJyArIHByb3BlcnR5LnZhbHVlKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9IGVsc2UgaWYgKGFuZ3VsYXIuaXNTdHJpbmcocHJvcGVydHkudmFsdWUpKSB7XG5cdFx0XHRcdFx0XHRpZihwcm9wZXJ0eS52YWx1ZS5pbmRleE9mKCcsJykgIT09IC0xKSB7XG5cdFx0XHRcdFx0XHRcdHRoaXMuZmFpbGVkUHJvcHMucHVzaChwcm9wKTtcblx0XHRcdFx0XHRcdFx0cHJvcGVydHkudmFsdWUgPSBwcm9wZXJ0eS52YWx1ZS5zcGxpdCgnLCcpO1xuXHRcdFx0XHRcdFx0XHQvL2NvbnNvbGUud2Fybih0aGlzLnVpZCgpKyc6IENhdGVnb3JpZXMgc3BsaXQ6ICcgKyBwcm9wZXJ0eS52YWx1ZSk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGlmKHByb3BlcnR5LnZhbHVlLmxlbmd0aCAhPT0gMCkge1xuXHRcdFx0XHRcdFx0Ly8gUmVtb3ZlIGR1cGxpY2F0ZSBjYXRlZ29yaWVzXG5cdFx0XHRcdFx0XHR2YXIgdW5pcXVlQ2F0ZWdvcmllcyA9IF8udW5pcXVlKHByb3BlcnR5LnZhbHVlKTtcblx0XHRcdFx0XHRcdGlmKCFhbmd1bGFyLmVxdWFscyh1bmlxdWVDYXRlZ29yaWVzLCBwcm9wZXJ0eS52YWx1ZSkpIHtcblx0XHRcdFx0XHRcdFx0dGhpcy5mYWlsZWRQcm9wcy5wdXNoKHByb3ApO1xuXHRcdFx0XHRcdFx0XHRwcm9wZXJ0eS52YWx1ZSA9IHVuaXF1ZUNhdGVnb3JpZXM7XG5cdFx0XHRcdFx0XHRcdC8vY29uc29sZS53YXJuKHRoaXMudWlkKCkrJzogQ2F0ZWdvcmllcyBkdXBsaWNhdGU6ICcgKyBwcm9wZXJ0eS52YWx1ZSk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlICdwaG90byc6XG5cdFx0XHRcdFx0Ly8gQXZvaWQgdW5kZWZpbmVkIHBob3RvIHR5cGVcblx0XHRcdFx0XHRpZiAoYW5ndWxhci5pc0RlZmluZWQocHJvcGVydHkpKSB7XG5cdFx0XHRcdFx0XHRpZiAoYW5ndWxhci5pc1VuZGVmaW5lZChwcm9wZXJ0eS5tZXRhLnR5cGUpKSB7XG5cdFx0XHRcdFx0XHRcdHZhciBtaW1lID0gTWltZVNlcnZpY2UuYjY0bWltZShwcm9wZXJ0eS52YWx1ZSk7XG5cdFx0XHRcdFx0XHRcdGlmIChtaW1lKSB7XG5cdFx0XHRcdFx0XHRcdFx0dGhpcy5mYWlsZWRQcm9wcy5wdXNoKHByb3ApO1xuXHRcdFx0XHRcdFx0XHRcdHByb3BlcnR5Lm1ldGEudHlwZT1bbWltZV07XG5cdFx0XHRcdFx0XHRcdFx0dGhpcy5zZXRQcm9wZXJ0eSgncGhvdG8nLCB7dmFsdWU6cHJvcGVydHkudmFsdWUsXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICAgbWV0YTp7dHlwZTpwcm9wZXJ0eS5tZXRhLnR5cGUsXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCBlbmNvZGluZzpwcm9wZXJ0eS5tZXRhLmVuY29kaW5nfX0pO1xuXHRcdFx0XHRcdFx0XHRcdGNvbnNvbGUud2Fybih0aGlzLnVpZCgpKyc6IFBob3RvIGRldGVjdGVkIGFzICcgKyBwcm9wZXJ0eS5tZXRhLnR5cGUpO1xuXHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRcdHRoaXMuZmFpbGVkUHJvcHMucHVzaChwcm9wKTtcblx0XHRcdFx0XHRcdFx0XHR0aGlzLnJlbW92ZVByb3BlcnR5KCdwaG90bycsIHByb3BlcnR5KTtcblx0XHRcdFx0XHRcdFx0XHRwcm9wZXJ0eSA9IHVuZGVmaW5lZDtcblx0XHRcdFx0XHRcdFx0XHRjb25zb2xlLndhcm4odGhpcy51aWQoKSsnOiBQaG90byByZW1vdmVkJyk7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIHByb3BlcnR5O1xuXHRcdFx0fVxuXHRcdFx0LyogZXNsaW50LWVuYWJsZSBuby1jb25zb2xlICovXG5cblx0XHR9KTtcblxuXHRcdGlmKGFuZ3VsYXIuaXNEZWZpbmVkKHZDYXJkKSkge1xuXHRcdFx0YW5ndWxhci5leHRlbmQodGhpcy5kYXRhLCB2Q2FyZCk7XG5cdFx0XHRhbmd1bGFyLmV4dGVuZCh0aGlzLnByb3BzLCAkZmlsdGVyKCd2Q2FyZDJKU09OJykodGhpcy5kYXRhLmFkZHJlc3NEYXRhKSk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGFuZ3VsYXIuZXh0ZW5kKHRoaXMucHJvcHMsIHtcblx0XHRcdFx0dmVyc2lvbjogW3t2YWx1ZTogJzMuMCd9XSxcblx0XHRcdFx0Zm46IFt7dmFsdWU6ICcnfV1cblx0XHRcdH0pO1xuXHRcdFx0dGhpcy5kYXRhLmFkZHJlc3NEYXRhID0gJGZpbHRlcignSlNPTjJ2Q2FyZCcpKHRoaXMucHJvcHMpO1xuXHRcdH1cblxuXHRcdHZhciBwcm9wZXJ0eSA9IHRoaXMuZ2V0UHJvcGVydHkoJ2NhdGVnb3JpZXMnKTtcblx0XHRpZighcHJvcGVydHkpIHtcblx0XHRcdC8vIGNhdGVnb3JpZXMgc2hvdWxkIGFsd2F5cyBoYXZlIHRoZSBzYW1lIHR5cGUgKGFuIGFycmF5KVxuXHRcdFx0dGhpcy5jYXRlZ29yaWVzKFtdKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0aWYgKGFuZ3VsYXIuaXNTdHJpbmcocHJvcGVydHkudmFsdWUpKSB7XG5cdFx0XHRcdHRoaXMuY2F0ZWdvcmllcyhbcHJvcGVydHkudmFsdWVdKTtcblx0XHRcdH1cblx0XHR9XG5cdH07XG59KTtcbiIsImFuZ3VsYXIubW9kdWxlKCdjb250YWN0c0FwcCcpXG4uZmFjdG9yeSgnQWRkcmVzc0Jvb2tTZXJ2aWNlJywgZnVuY3Rpb24oRGF2Q2xpZW50LCBEYXZTZXJ2aWNlLCBTZXR0aW5nc1NlcnZpY2UsIEFkZHJlc3NCb29rLCAkcSkge1xuXG5cdHZhciBhZGRyZXNzQm9va3MgPSBbXTtcblx0dmFyIGxvYWRQcm9taXNlID0gdW5kZWZpbmVkO1xuXG5cdHZhciBsb2FkQWxsID0gZnVuY3Rpb24oKSB7XG5cdFx0aWYgKGFkZHJlc3NCb29rcy5sZW5ndGggPiAwKSB7XG5cdFx0XHRyZXR1cm4gJHEud2hlbihhZGRyZXNzQm9va3MpO1xuXHRcdH1cblx0XHRpZiAoXy5pc1VuZGVmaW5lZChsb2FkUHJvbWlzZSkpIHtcblx0XHRcdGxvYWRQcm9taXNlID0gRGF2U2VydmljZS50aGVuKGZ1bmN0aW9uKGFjY291bnQpIHtcblx0XHRcdFx0bG9hZFByb21pc2UgPSB1bmRlZmluZWQ7XG5cdFx0XHRcdGFkZHJlc3NCb29rcyA9IGFjY291bnQuYWRkcmVzc0Jvb2tzLm1hcChmdW5jdGlvbihhZGRyZXNzQm9vaykge1xuXHRcdFx0XHRcdHJldHVybiBuZXcgQWRkcmVzc0Jvb2soYWRkcmVzc0Jvb2spO1xuXHRcdFx0XHR9KTtcblx0XHRcdH0pO1xuXHRcdH1cblx0XHRyZXR1cm4gbG9hZFByb21pc2U7XG5cdH07XG5cblx0cmV0dXJuIHtcblx0XHRnZXRBbGw6IGZ1bmN0aW9uKCkge1xuXHRcdFx0cmV0dXJuIGxvYWRBbGwoKS50aGVuKGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRyZXR1cm4gYWRkcmVzc0Jvb2tzO1xuXHRcdFx0fSk7XG5cdFx0fSxcblxuXHRcdGdldEdyb3VwczogZnVuY3Rpb24gKCkge1xuXHRcdFx0cmV0dXJuIHRoaXMuZ2V0QWxsKCkudGhlbihmdW5jdGlvbihhZGRyZXNzQm9va3MpIHtcblx0XHRcdFx0cmV0dXJuIGFkZHJlc3NCb29rcy5tYXAoZnVuY3Rpb24gKGVsZW1lbnQpIHtcblx0XHRcdFx0XHRyZXR1cm4gZWxlbWVudC5ncm91cHM7XG5cdFx0XHRcdH0pLnJlZHVjZShmdW5jdGlvbihhLCBiKSB7XG5cdFx0XHRcdFx0cmV0dXJuIGEuY29uY2F0KGIpO1xuXHRcdFx0XHR9KTtcblx0XHRcdH0pO1xuXHRcdH0sXG5cblx0XHRnZXREZWZhdWx0QWRkcmVzc0Jvb2s6IGZ1bmN0aW9uKCkge1xuXHRcdFx0cmV0dXJuIGFkZHJlc3NCb29rc1swXTtcblx0XHR9LFxuXG5cdFx0Z2V0QWRkcmVzc0Jvb2s6IGZ1bmN0aW9uKGRpc3BsYXlOYW1lKSB7XG5cdFx0XHRyZXR1cm4gRGF2U2VydmljZS50aGVuKGZ1bmN0aW9uKGFjY291bnQpIHtcblx0XHRcdFx0cmV0dXJuIERhdkNsaWVudC5nZXRBZGRyZXNzQm9vayh7ZGlzcGxheU5hbWU6ZGlzcGxheU5hbWUsIHVybDphY2NvdW50LmhvbWVVcmx9KS50aGVuKGZ1bmN0aW9uKGFkZHJlc3NCb29rKSB7XG5cdFx0XHRcdFx0YWRkcmVzc0Jvb2sgPSBuZXcgQWRkcmVzc0Jvb2soe1xuXHRcdFx0XHRcdFx0dXJsOiBhY2NvdW50LmhvbWVVcmwrZGlzcGxheU5hbWUrJy8nLFxuXHRcdFx0XHRcdFx0ZGF0YTogYWRkcmVzc0Jvb2tbMF1cblx0XHRcdFx0XHR9KTtcblx0XHRcdFx0XHRhZGRyZXNzQm9vay5kaXNwbGF5TmFtZSA9IGRpc3BsYXlOYW1lO1xuXHRcdFx0XHRcdHJldHVybiBhZGRyZXNzQm9vaztcblx0XHRcdFx0fSk7XG5cdFx0XHR9KTtcblx0XHR9LFxuXG5cdFx0Y3JlYXRlOiBmdW5jdGlvbihkaXNwbGF5TmFtZSkge1xuXHRcdFx0cmV0dXJuIERhdlNlcnZpY2UudGhlbihmdW5jdGlvbihhY2NvdW50KSB7XG5cdFx0XHRcdHJldHVybiBEYXZDbGllbnQuY3JlYXRlQWRkcmVzc0Jvb2soe2Rpc3BsYXlOYW1lOmRpc3BsYXlOYW1lLCB1cmw6YWNjb3VudC5ob21lVXJsfSk7XG5cdFx0XHR9KTtcblx0XHR9LFxuXG5cdFx0ZGVsZXRlOiBmdW5jdGlvbihhZGRyZXNzQm9vaykge1xuXHRcdFx0cmV0dXJuIERhdlNlcnZpY2UudGhlbihmdW5jdGlvbigpIHtcblx0XHRcdFx0cmV0dXJuIERhdkNsaWVudC5kZWxldGVBZGRyZXNzQm9vayhhZGRyZXNzQm9vaykudGhlbihmdW5jdGlvbigpIHtcblx0XHRcdFx0XHR2YXIgaW5kZXggPSBhZGRyZXNzQm9va3MuaW5kZXhPZihhZGRyZXNzQm9vayk7XG5cdFx0XHRcdFx0YWRkcmVzc0Jvb2tzLnNwbGljZShpbmRleCwgMSk7XG5cdFx0XHRcdH0pO1xuXHRcdFx0fSk7XG5cdFx0fSxcblxuXHRcdHJlbmFtZTogZnVuY3Rpb24oYWRkcmVzc0Jvb2ssIGRpc3BsYXlOYW1lKSB7XG5cdFx0XHRyZXR1cm4gRGF2U2VydmljZS50aGVuKGZ1bmN0aW9uKGFjY291bnQpIHtcblx0XHRcdFx0cmV0dXJuIERhdkNsaWVudC5yZW5hbWVBZGRyZXNzQm9vayhhZGRyZXNzQm9vaywge2Rpc3BsYXlOYW1lOmRpc3BsYXlOYW1lLCB1cmw6YWNjb3VudC5ob21lVXJsfSk7XG5cdFx0XHR9KTtcblx0XHR9LFxuXG5cdFx0Z2V0OiBmdW5jdGlvbihkaXNwbGF5TmFtZSkge1xuXHRcdFx0cmV0dXJuIHRoaXMuZ2V0QWxsKCkudGhlbihmdW5jdGlvbihhZGRyZXNzQm9va3MpIHtcblx0XHRcdFx0cmV0dXJuIGFkZHJlc3NCb29rcy5maWx0ZXIoZnVuY3Rpb24gKGVsZW1lbnQpIHtcblx0XHRcdFx0XHRyZXR1cm4gZWxlbWVudC5kaXNwbGF5TmFtZSA9PT0gZGlzcGxheU5hbWU7XG5cdFx0XHRcdH0pWzBdO1xuXHRcdFx0fSk7XG5cdFx0fSxcblxuXHRcdHN5bmM6IGZ1bmN0aW9uKGFkZHJlc3NCb29rKSB7XG5cdFx0XHRyZXR1cm4gRGF2Q2xpZW50LnN5bmNBZGRyZXNzQm9vayhhZGRyZXNzQm9vayk7XG5cdFx0fSxcblxuXHRcdHNoYXJlOiBmdW5jdGlvbihhZGRyZXNzQm9vaywgc2hhcmVUeXBlLCBzaGFyZVdpdGgsIHdyaXRhYmxlLCBleGlzdGluZ1NoYXJlKSB7XG5cdFx0XHR2YXIgeG1sRG9jID0gZG9jdW1lbnQuaW1wbGVtZW50YXRpb24uY3JlYXRlRG9jdW1lbnQoJycsICcnLCBudWxsKTtcblx0XHRcdHZhciBvU2hhcmUgPSB4bWxEb2MuY3JlYXRlRWxlbWVudCgnbzpzaGFyZScpO1xuXHRcdFx0b1NoYXJlLnNldEF0dHJpYnV0ZSgneG1sbnM6ZCcsICdEQVY6Jyk7XG5cdFx0XHRvU2hhcmUuc2V0QXR0cmlidXRlKCd4bWxuczpvJywgJ2h0dHA6Ly9vd25jbG91ZC5vcmcvbnMnKTtcblx0XHRcdHhtbERvYy5hcHBlbmRDaGlsZChvU2hhcmUpO1xuXG5cdFx0XHR2YXIgb1NldCA9IHhtbERvYy5jcmVhdGVFbGVtZW50KCdvOnNldCcpO1xuXHRcdFx0b1NoYXJlLmFwcGVuZENoaWxkKG9TZXQpO1xuXG5cdFx0XHR2YXIgZEhyZWYgPSB4bWxEb2MuY3JlYXRlRWxlbWVudCgnZDpocmVmJyk7XG5cdFx0XHRpZiAoc2hhcmVUeXBlID09PSBPQy5TaGFyZS5TSEFSRV9UWVBFX1VTRVIpIHtcblx0XHRcdFx0ZEhyZWYudGV4dENvbnRlbnQgPSAncHJpbmNpcGFsOnByaW5jaXBhbHMvdXNlcnMvJztcblx0XHRcdH0gZWxzZSBpZiAoc2hhcmVUeXBlID09PSBPQy5TaGFyZS5TSEFSRV9UWVBFX0dST1VQKSB7XG5cdFx0XHRcdGRIcmVmLnRleHRDb250ZW50ID0gJ3ByaW5jaXBhbDpwcmluY2lwYWxzL2dyb3Vwcy8nO1xuXHRcdFx0fVxuXHRcdFx0ZEhyZWYudGV4dENvbnRlbnQgKz0gc2hhcmVXaXRoO1xuXHRcdFx0b1NldC5hcHBlbmRDaGlsZChkSHJlZik7XG5cblx0XHRcdHZhciBvU3VtbWFyeSA9IHhtbERvYy5jcmVhdGVFbGVtZW50KCdvOnN1bW1hcnknKTtcblx0XHRcdG9TdW1tYXJ5LnRleHRDb250ZW50ID0gdCgnY29udGFjdHMnLCAne2FkZHJlc3Nib29rfSBzaGFyZWQgYnkge293bmVyfScsIHtcblx0XHRcdFx0YWRkcmVzc2Jvb2s6IGFkZHJlc3NCb29rLmRpc3BsYXlOYW1lLFxuXHRcdFx0XHRvd25lcjogYWRkcmVzc0Jvb2sub3duZXJcblx0XHRcdH0pO1xuXHRcdFx0b1NldC5hcHBlbmRDaGlsZChvU3VtbWFyeSk7XG5cblx0XHRcdGlmICh3cml0YWJsZSkge1xuXHRcdFx0XHR2YXIgb1JXID0geG1sRG9jLmNyZWF0ZUVsZW1lbnQoJ286cmVhZC13cml0ZScpO1xuXHRcdFx0XHRvU2V0LmFwcGVuZENoaWxkKG9SVyk7XG5cdFx0XHR9XG5cblx0XHRcdHZhciBib2R5ID0gb1NoYXJlLm91dGVySFRNTDtcblxuXHRcdFx0cmV0dXJuIERhdkNsaWVudC54aHIuc2VuZChcblx0XHRcdFx0ZGF2LnJlcXVlc3QuYmFzaWMoe21ldGhvZDogJ1BPU1QnLCBkYXRhOiBib2R5fSksXG5cdFx0XHRcdGFkZHJlc3NCb29rLnVybFxuXHRcdFx0KS50aGVuKGZ1bmN0aW9uKHJlc3BvbnNlKSB7XG5cdFx0XHRcdGlmIChyZXNwb25zZS5zdGF0dXMgPT09IDIwMCkge1xuXHRcdFx0XHRcdGlmICghZXhpc3RpbmdTaGFyZSkge1xuXHRcdFx0XHRcdFx0aWYgKHNoYXJlVHlwZSA9PT0gT0MuU2hhcmUuU0hBUkVfVFlQRV9VU0VSKSB7XG5cdFx0XHRcdFx0XHRcdGFkZHJlc3NCb29rLnNoYXJlZFdpdGgudXNlcnMucHVzaCh7XG5cdFx0XHRcdFx0XHRcdFx0aWQ6IHNoYXJlV2l0aCxcblx0XHRcdFx0XHRcdFx0XHRkaXNwbGF5bmFtZTogc2hhcmVXaXRoLFxuXHRcdFx0XHRcdFx0XHRcdHdyaXRhYmxlOiB3cml0YWJsZVxuXHRcdFx0XHRcdFx0XHR9KTtcblx0XHRcdFx0XHRcdH0gZWxzZSBpZiAoc2hhcmVUeXBlID09PSBPQy5TaGFyZS5TSEFSRV9UWVBFX0dST1VQKSB7XG5cdFx0XHRcdFx0XHRcdGFkZHJlc3NCb29rLnNoYXJlZFdpdGguZ3JvdXBzLnB1c2goe1xuXHRcdFx0XHRcdFx0XHRcdGlkOiBzaGFyZVdpdGgsXG5cdFx0XHRcdFx0XHRcdFx0ZGlzcGxheW5hbWU6IHNoYXJlV2l0aCxcblx0XHRcdFx0XHRcdFx0XHR3cml0YWJsZTogd3JpdGFibGVcblx0XHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblxuXHRcdH0sXG5cblx0XHR1bnNoYXJlOiBmdW5jdGlvbihhZGRyZXNzQm9vaywgc2hhcmVUeXBlLCBzaGFyZVdpdGgpIHtcblx0XHRcdHZhciB4bWxEb2MgPSBkb2N1bWVudC5pbXBsZW1lbnRhdGlvbi5jcmVhdGVEb2N1bWVudCgnJywgJycsIG51bGwpO1xuXHRcdFx0dmFyIG9TaGFyZSA9IHhtbERvYy5jcmVhdGVFbGVtZW50KCdvOnNoYXJlJyk7XG5cdFx0XHRvU2hhcmUuc2V0QXR0cmlidXRlKCd4bWxuczpkJywgJ0RBVjonKTtcblx0XHRcdG9TaGFyZS5zZXRBdHRyaWJ1dGUoJ3htbG5zOm8nLCAnaHR0cDovL293bmNsb3VkLm9yZy9ucycpO1xuXHRcdFx0eG1sRG9jLmFwcGVuZENoaWxkKG9TaGFyZSk7XG5cblx0XHRcdHZhciBvUmVtb3ZlID0geG1sRG9jLmNyZWF0ZUVsZW1lbnQoJ286cmVtb3ZlJyk7XG5cdFx0XHRvU2hhcmUuYXBwZW5kQ2hpbGQob1JlbW92ZSk7XG5cblx0XHRcdHZhciBkSHJlZiA9IHhtbERvYy5jcmVhdGVFbGVtZW50KCdkOmhyZWYnKTtcblx0XHRcdGlmIChzaGFyZVR5cGUgPT09IE9DLlNoYXJlLlNIQVJFX1RZUEVfVVNFUikge1xuXHRcdFx0XHRkSHJlZi50ZXh0Q29udGVudCA9ICdwcmluY2lwYWw6cHJpbmNpcGFscy91c2Vycy8nO1xuXHRcdFx0fSBlbHNlIGlmIChzaGFyZVR5cGUgPT09IE9DLlNoYXJlLlNIQVJFX1RZUEVfR1JPVVApIHtcblx0XHRcdFx0ZEhyZWYudGV4dENvbnRlbnQgPSAncHJpbmNpcGFsOnByaW5jaXBhbHMvZ3JvdXBzLyc7XG5cdFx0XHR9XG5cdFx0XHRkSHJlZi50ZXh0Q29udGVudCArPSBzaGFyZVdpdGg7XG5cdFx0XHRvUmVtb3ZlLmFwcGVuZENoaWxkKGRIcmVmKTtcblx0XHRcdHZhciBib2R5ID0gb1NoYXJlLm91dGVySFRNTDtcblxuXG5cdFx0XHRyZXR1cm4gRGF2Q2xpZW50Lnhoci5zZW5kKFxuXHRcdFx0XHRkYXYucmVxdWVzdC5iYXNpYyh7bWV0aG9kOiAnUE9TVCcsIGRhdGE6IGJvZHl9KSxcblx0XHRcdFx0YWRkcmVzc0Jvb2sudXJsXG5cdFx0XHQpLnRoZW4oZnVuY3Rpb24ocmVzcG9uc2UpIHtcblx0XHRcdFx0aWYgKHJlc3BvbnNlLnN0YXR1cyA9PT0gMjAwKSB7XG5cdFx0XHRcdFx0aWYgKHNoYXJlVHlwZSA9PT0gT0MuU2hhcmUuU0hBUkVfVFlQRV9VU0VSKSB7XG5cdFx0XHRcdFx0XHRhZGRyZXNzQm9vay5zaGFyZWRXaXRoLnVzZXJzID0gYWRkcmVzc0Jvb2suc2hhcmVkV2l0aC51c2Vycy5maWx0ZXIoZnVuY3Rpb24odXNlcikge1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4gdXNlci5pZCAhPT0gc2hhcmVXaXRoO1xuXHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0fSBlbHNlIGlmIChzaGFyZVR5cGUgPT09IE9DLlNoYXJlLlNIQVJFX1RZUEVfR1JPVVApIHtcblx0XHRcdFx0XHRcdGFkZHJlc3NCb29rLnNoYXJlZFdpdGguZ3JvdXBzID0gYWRkcmVzc0Jvb2suc2hhcmVkV2l0aC5ncm91cHMuZmlsdGVyKGZ1bmN0aW9uKGdyb3Vwcykge1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4gZ3JvdXBzLmlkICE9PSBzaGFyZVdpdGg7XG5cdFx0XHRcdFx0XHR9KTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0Ly90b2RvIC0gcmVtb3ZlIGVudHJ5IGZyb20gYWRkcmVzc2Jvb2sgb2JqZWN0XG5cdFx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblxuXHRcdH1cblxuXG5cdH07XG5cbn0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5zZXJ2aWNlKCdDb250YWN0U2VydmljZScsIGZ1bmN0aW9uKERhdkNsaWVudCwgQWRkcmVzc0Jvb2tTZXJ2aWNlLCBDb250YWN0LCAkcm91dGVQYXJhbXMsICRxLCBDYWNoZUZhY3RvcnksIHV1aWQ0LCB2Q2FyZFByb3BlcnRpZXNTZXJ2aWNlICkge1xuXG5cdHZhciBjYWNoZUZpbGxlZCA9IGZhbHNlO1xuXG5cdHZhciBjb250YWN0cyA9IENhY2hlRmFjdG9yeSgnY29udGFjdHMnKTtcblx0dmFyIHVybHNCeURpc3BsYXluYW1lID0gQ2FjaGVGYWN0b3J5KCd1cmxzQnlEaXNwbGF5bmFtZScpO1xuXG5cdHZhciBvYnNlcnZlckNhbGxiYWNrcyA9IFtdO1xuXG5cdHZhciBsb2FkUHJvbWlzZSA9IHVuZGVmaW5lZDtcblxuXHR2YXIgbmV3Q29udGFjdEp1c3RBZGRlZCA9IGZhbHNlO1xuXG5cblx0dGhpcy5yZWdpc3Rlck9ic2VydmVyQ2FsbGJhY2sgPSBmdW5jdGlvbihjYWxsYmFjaykge1xuXHRcdG9ic2VydmVyQ2FsbGJhY2tzLnB1c2goY2FsbGJhY2spO1xuXHR9O1xuXG5cdHZhciBub3RpZnlPYnNlcnZlcnMgPSBmdW5jdGlvbihldmVudE5hbWUsIHVpZCkge1xuXHRcdHZhciBldiA9IHtcblx0XHRcdGV2ZW50OiBldmVudE5hbWUsXG5cdFx0XHR1aWQ6IHVpZCxcblx0XHRcdGNvbnRhY3RzOiBjb250YWN0cy52YWx1ZXMoKVxuXHRcdH07XG5cdFx0YW5ndWxhci5mb3JFYWNoKG9ic2VydmVyQ2FsbGJhY2tzLCBmdW5jdGlvbihjYWxsYmFjaykge1xuXHRcdFx0Y2FsbGJhY2soZXYpO1xuXHRcdH0pO1xuXHR9O1xuXG5cdHRoaXMuZ2V0RnVsbENvbnRhY3RzID0gZnVuY3Rpb24gZ2V0RnVsbENvbnRhY3RzKG5hbWVzKSB7XG5cdFx0QWRkcmVzc0Jvb2tTZXJ2aWNlLmdldEFsbCgpLnRoZW4oZnVuY3Rpb24gKGVuYWJsZWRBZGRyZXNzQm9va3MpIHtcblx0XHRcdHZhciBwcm9taXNlcyA9IFtdO1xuXHRcdFx0ZW5hYmxlZEFkZHJlc3NCb29rcy5mb3JFYWNoKGZ1bmN0aW9uIChhZGRyZXNzQm9vaykge1xuXHRcdFx0XHR2YXIgdXJsTGlzdHMgPSBuYW1lcy5tYXAoZnVuY3Rpb24gKG5hbWUpIHsgcmV0dXJuIHVybHNCeURpc3BsYXluYW1lLmdldChuYW1lKTsgfSk7XG5cdFx0XHRcdHZhciB1cmxzID0gW10uY29uY2F0LmFwcGx5KFtdLCB1cmxMaXN0cyk7XG5cdFx0XHRcdHZhciBwcm9taXNlID0gRGF2Q2xpZW50LmdldENvbnRhY3RzKGFkZHJlc3NCb29rLCB7fSwgdXJscylcblx0XHRcdFx0XHRcdC50aGVuKFxuXHRcdFx0XHRcdFx0XHRmdW5jdGlvbiAodmNhcmRzKSB7XG5cdFx0XHRcdFx0XHRcdFx0cmV0dXJuIHZjYXJkcy5tYXAoZnVuY3Rpb24gKHZjYXJkKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRyZXR1cm4gbmV3IENvbnRhY3QoYWRkcmVzc0Jvb2ssIHZjYXJkKTtcblx0XHRcdFx0XHRcdFx0XHR9KTtcblx0XHRcdFx0XHRcdFx0fSlcblx0XHRcdFx0XHRcdC50aGVuKGZ1bmN0aW9uIChjb250YWN0c18pIHtcblx0XHRcdFx0XHRcdFx0Y29udGFjdHNfLm1hcChmdW5jdGlvbiAoY29udGFjdCkge1xuXHRcdFx0XHRcdFx0XHRcdGNvbnRhY3RzLnB1dChjb250YWN0LnVpZCgpLCBjb250YWN0KTtcblx0XHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0XHR9KTtcblx0XHRcdFx0cHJvbWlzZXMucHVzaChwcm9taXNlKTtcblx0XHRcdH0pO1xuXHRcdFx0JHEuYWxsKHByb21pc2VzKS50aGVuKGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0bm90aWZ5T2JzZXJ2ZXJzKCdnZXRGdWxsQ29udGFjdHMnLCAnJyk7XG5cdFx0XHR9KTtcblx0XHR9KTtcblx0fTtcblxuXHR0aGlzLmZpbGxDYWNoZSA9IGZ1bmN0aW9uKCkge1xuXHRcdGlmIChfLmlzVW5kZWZpbmVkKGxvYWRQcm9taXNlKSkge1xuXHRcdFx0bG9hZFByb21pc2UgPSBBZGRyZXNzQm9va1NlcnZpY2UuZ2V0QWxsKCkudGhlbihmdW5jdGlvbiAoZW5hYmxlZEFkZHJlc3NCb29rcykge1xuXHRcdFx0XHR2YXIgcHJvbWlzZXMgPSBbXTtcblx0XHRcdFx0ZW5hYmxlZEFkZHJlc3NCb29rcy5mb3JFYWNoKGZ1bmN0aW9uIChhZGRyZXNzQm9vaykge1xuXHRcdFx0XHRcdHByb21pc2VzLnB1c2goXG5cdFx0XHRcdFx0XHRBZGRyZXNzQm9va1NlcnZpY2Uuc3luYyhhZGRyZXNzQm9vaykudGhlbihmdW5jdGlvbiAoYWRkcmVzc0Jvb2spIHtcblx0XHRcdFx0XHRcdFx0Zm9yICh2YXIgaSBpbiBhZGRyZXNzQm9vay5vYmplY3RzKSB7XG5cdFx0XHRcdFx0XHRcdFx0aWYgKGFkZHJlc3NCb29rLm9iamVjdHNbaV0uYWRkcmVzc0RhdGEpIHtcblx0XHRcdFx0XHRcdFx0XHRcdHZhciBjb250YWN0ID0gbmV3IENvbnRhY3QoYWRkcmVzc0Jvb2ssIGFkZHJlc3NCb29rLm9iamVjdHNbaV0pO1xuXHRcdFx0XHRcdFx0XHRcdFx0Y29udGFjdHMucHV0KGNvbnRhY3QudWlkKCksIGNvbnRhY3QpO1xuXHRcdFx0XHRcdFx0XHRcdFx0dmFyIG9sZExpc3QgPSB1cmxzQnlEaXNwbGF5bmFtZS5nZXQoY29udGFjdC5kaXNwbGF5TmFtZSgpKSB8fCBbXTtcblx0XHRcdFx0XHRcdFx0XHRcdHVybHNCeURpc3BsYXluYW1lLnB1dChjb250YWN0LmRpc3BsYXlOYW1lKCksIG9sZExpc3QuY29uY2F0KGNvbnRhY3QuZGF0YS51cmwpKTtcblx0XHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRcdFx0Ly8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWNvbnNvbGVcblx0XHRcdFx0XHRcdFx0XHRcdGNvbnNvbGUubG9nKCdJbnZhbGlkIGNvbnRhY3QgcmVjZWl2ZWQ6ICcgKyBhZGRyZXNzQm9vay5vYmplY3RzW2ldLnVybCk7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9KVxuXHRcdFx0XHRcdCk7XG5cdFx0XHRcdH0pO1xuXHRcdFx0XHRyZXR1cm4gJHEuYWxsKHByb21pc2VzKS50aGVuKGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0XHRjYWNoZUZpbGxlZCA9IHRydWU7XG5cdFx0XHRcdH0pO1xuXHRcdFx0fSk7XG5cdFx0fVxuXHRcdHJldHVybiBsb2FkUHJvbWlzZTtcblx0fTtcblxuXHR0aGlzLmdldEFsbCA9IGZ1bmN0aW9uKCkge1xuXHRcdGlmKGNhY2hlRmlsbGVkID09PSBmYWxzZSkge1xuXHRcdFx0cmV0dXJuIHRoaXMuZmlsbENhY2hlKCkudGhlbihmdW5jdGlvbigpIHtcblx0XHRcdFx0cmV0dXJuIGNvbnRhY3RzLnZhbHVlcygpO1xuXHRcdFx0fSk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHJldHVybiAkcS53aGVuKGNvbnRhY3RzLnZhbHVlcygpKTtcblx0XHR9XG5cdH07XG5cblx0Ly8gZ2V0IGxpc3Qgb2YgZ3JvdXBzIGFuZCB0aGUgY291bnQgb2YgY29udGFjdHMgaW4gc2FpZCBncm91cHNcblx0dGhpcy5nZXRHcm91cExpc3QgPSBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuZ2V0QWxsKCkudGhlbihmdW5jdGlvbihjb250YWN0cykge1xuXHRcdFx0Ly8gdGhlIHRyYW5zbGF0ZWQgbmFtZXMgZm9yIGFsbCBhbmQgbm90LWdyb3VwZWQgYXJlIHVzZWQgaW4gZmlsdGVyaW5nLCB0aGV5IG11c3QgYmUgZXhhY3RseSBsaWtlIHRoaXNcblx0XHRcdHZhciBhbGxDb250YWN0cyA9IFt0KCdjb250YWN0cycsICdBbGwgY29udGFjdHMnKSwgY29udGFjdHMubGVuZ3RoXTtcblx0XHRcdHZhciBub3RHcm91cGVkID1cblx0XHRcdFx0W3QoJ2NvbnRhY3RzJywgJ05vdCBncm91cGVkJyksXG5cdFx0XHRcdFx0Y29udGFjdHMuZmlsdGVyKFxuXHRcdFx0XHRcdFx0ZnVuY3Rpb24gKGNvbnRhY3QpIHtcblx0XHRcdFx0XHRcdFx0IHJldHVybiBjb250YWN0LmNhdGVnb3JpZXMoKS5sZW5ndGggPT09IDA7XG5cdFx0XHRcdFx0XHR9KS5sZW5ndGhcblx0XHRcdFx0XTtcblxuXHRcdFx0Ly8gYWxsb3cgZ3JvdXBzIHdpdGggbmFtZXMgc3VjaCBhcyB0b1N0cmluZ1xuXHRcdFx0dmFyIG90aGVyR3JvdXBzID0gT2JqZWN0LmNyZWF0ZShudWxsKTtcblxuXHRcdFx0Ly8gY29sbGVjdCBjYXRlZ29yaWVzIGFuZCB0aGVpciBhc3NvY2lhdGVkIGNvdW50c1xuXHRcdFx0Y29udGFjdHMuZm9yRWFjaChmdW5jdGlvbiAoY29udGFjdCkge1xuXHRcdFx0XHRjb250YWN0LmNhdGVnb3JpZXMoKS5mb3JFYWNoKGZ1bmN0aW9uIChjYXRlZ29yeSkge1xuXHRcdFx0XHRcdG90aGVyR3JvdXBzW2NhdGVnb3J5XSA9IG90aGVyR3JvdXBzW2NhdGVnb3J5XSA/IG90aGVyR3JvdXBzW2NhdGVnb3J5XSArIDEgOiAxO1xuXHRcdFx0XHR9KTtcblx0XHRcdH0pO1xuXG5cdFx0XHRyZXR1cm4gW2FsbENvbnRhY3RzLCBub3RHcm91cGVkXVxuXHRcdFx0XHQuY29uY2F0KF8ua2V5cyhvdGhlckdyb3VwcykubWFwKFxuXHRcdFx0XHRcdGZ1bmN0aW9uIChrZXkpIHtcblx0XHRcdFx0XHRcdHJldHVybiBba2V5LCBvdGhlckdyb3Vwc1trZXldXTtcblx0XHRcdFx0XHR9KSk7XG5cblxuXHRcdH0pO1xuXHR9O1xuXG5cdHRoaXMuZ2V0R3JvdXBzID0gZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLmdldEFsbCgpLnRoZW4oZnVuY3Rpb24oY29udGFjdHMpIHtcblx0XHRcdHJldHVybiBfLnVuaXEoY29udGFjdHMubWFwKGZ1bmN0aW9uIChlbGVtZW50KSB7XG5cdFx0XHRcdHJldHVybiBlbGVtZW50LmNhdGVnb3JpZXMoKTtcblx0XHRcdH0pLnJlZHVjZShmdW5jdGlvbihhLCBiKSB7XG5cdFx0XHRcdHJldHVybiBhLmNvbmNhdChiKTtcblx0XHRcdH0sIFtdKS5zb3J0KCksIHRydWUpO1xuXHRcdH0pO1xuXHR9O1xuXG5cdHRoaXMudXBkYXRlTmV3Q29udGFjdEp1c3RBZGRlZCA9IGZ1bmN0aW9uICgpIHtcblx0XHRuZXdDb250YWN0SnVzdEFkZGVkID0gdHJ1ZTtcblx0fTtcblxuXHR0aGlzLmdldEJ5SWQgPSBmdW5jdGlvbihhZGRyZXNzQm9va3MsIHVpZCkge1xuXHRcdHJldHVybiAoZnVuY3Rpb24gKCkge1xuXHRcdFx0aWYoY2FjaGVGaWxsZWQgPT09IGZhbHNlKSB7XG5cdFx0XHRcdHJldHVybiB0aGlzLmZpbGxDYWNoZSgpLnRoZW4oZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0cmV0dXJuIGNvbnRhY3RzLmdldCh1aWQpO1xuXHRcdFx0XHR9KTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHJldHVybiAkcS53aGVuKGNvbnRhY3RzLmdldCh1aWQpKTtcblx0XHRcdH1cblx0XHR9KS5jYWxsKHRoaXMpXG5cdFx0XHQudGhlbihmdW5jdGlvbiAoY29udGFjdCkge1xuXHRcdFx0XHR2YXIgYWRkcmVzc0Jvb2sgPSBfLmZpbmQoYWRkcmVzc0Jvb2tzLCBmdW5jdGlvbihib29rKSB7XG5cdFx0XHRcdFx0cmV0dXJuIGJvb2suZGlzcGxheU5hbWUgPT09IGNvbnRhY3QuYWRkcmVzc0Jvb2tJZDtcblx0XHRcdFx0fSk7XG5cdFx0XHRcdHJldHVybiBhZGRyZXNzQm9va1xuXHRcdFx0XHRcdD8gRGF2Q2xpZW50LmdldENvbnRhY3RzKGFkZHJlc3NCb29rLCB7fSwgWyBjb250YWN0LmRhdGEudXJsIF0pLnRoZW4oXG5cdFx0XHRcdFx0XHRmdW5jdGlvbiAodmNhcmRzKSB7XG5cblxuXHRcdFx0XHRcdFx0XHR2YXIgbmV3Q29udGFjdCA9IG5ldyBDb250YWN0KGFkZHJlc3NCb29rLCB2Y2FyZHNbMF0pO1xuXHRcdFx0XHRcdFx0XHRpZihuZXdDb250YWN0SnVzdEFkZGVkID09PSB0cnVlKSB7XG5cdFx0XHRcdFx0XHRcdFx0Wyd0ZWwnLCAnYWRyJywgJ2VtYWlsJ10uZm9yRWFjaChmdW5jdGlvbihmaWVsZCkge1xuXHRcdFx0XHRcdFx0XHRcdFx0dmFyIGRlZmF1bHRWYWx1ZSA9IHZDYXJkUHJvcGVydGllc1NlcnZpY2UuZ2V0TWV0YShmaWVsZCkuZGVmYXVsdFZhbHVlIHx8IHt2YWx1ZTogJyd9O1xuXHRcdFx0XHRcdFx0XHRcdFx0bmV3Q29udGFjdC5hZGRQcm9wZXJ0eShmaWVsZCwgZGVmYXVsdFZhbHVlKTtcblx0XHRcdFx0XHRcdFx0XHR9ICk7XG5cdFx0XHRcdFx0XHRcdFx0aWYgKFt0KCdjb250YWN0cycsICdBbGwgY29udGFjdHMnKSwgdCgnY29udGFjdHMnLCAnTm90IGdyb3VwZWQnKV0uaW5kZXhPZigkcm91dGVQYXJhbXMuZ2lkKSA9PT0gLTEpIHtcblx0XHRcdFx0XHRcdFx0XHRcdG5ld0NvbnRhY3QuY2F0ZWdvcmllcyhbICRyb3V0ZVBhcmFtcy5naWQgXSk7XG5cdFx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdFx0XHRcdG5ld0NvbnRhY3QuY2F0ZWdvcmllcyhbXSk7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdG5ld0NvbnRhY3RKdXN0QWRkZWQgPSBmYWxzZTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRyZXR1cm4gbmV3Q29udGFjdDtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdC8vZnVuY3Rpb24gKHZjYXJkcykgeyByZXR1cm4gbmV3IENvbnRhY3QoYWRkcmVzc0Jvb2ssIHZjYXJkc1swXSk7IH1cblx0XHRcdFx0XHQpLnRoZW4oZnVuY3Rpb24gKGNvbnRhY3QpIHtcblx0XHRcdFx0XHRcdGNvbnRhY3RzLnB1dChjb250YWN0LnVpZCgpLCBjb250YWN0KTtcblx0XHRcdFx0XHRcdG5vdGlmeU9ic2VydmVycygnZ2V0RnVsbENvbnRhY3RzJywgY29udGFjdC51aWQoKSk7XG5cdFx0XHRcdFx0XHRyZXR1cm4gY29udGFjdDtcblx0XHRcdFx0XHR9KSA6IGNvbnRhY3Q7XG5cdFx0XHR9KTtcblx0fTtcblxuXHR0aGlzLmNyZWF0ZSA9IGZ1bmN0aW9uKG5ld0NvbnRhY3QsIGFkZHJlc3NCb29rLCB1aWQpIHtcblx0XHRhZGRyZXNzQm9vayA9IGFkZHJlc3NCb29rIHx8IEFkZHJlc3NCb29rU2VydmljZS5nZXREZWZhdWx0QWRkcmVzc0Jvb2soKTtcblx0XHR0cnkge1xuXHRcdFx0bmV3Q29udGFjdCA9IG5ld0NvbnRhY3QgfHwgbmV3IENvbnRhY3QoYWRkcmVzc0Jvb2spO1xuXHRcdH0gY2F0Y2goZXJyb3IpIHtcblx0XHRcdE9DLk5vdGlmaWNhdGlvbi5zaG93VGVtcG9yYXJ5KHQoJ2NvbnRhY3RzJywgJ0NvbnRhY3QgY291bGQgbm90IGJlIGNyZWF0ZWQuJykpO1xuXHRcdH1cblx0XHR2YXIgbmV3VWlkID0gJyc7XG5cdFx0aWYodXVpZDQudmFsaWRhdGUodWlkKSkge1xuXHRcdFx0bmV3VWlkID0gdWlkO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRuZXdVaWQgPSB1dWlkNC5nZW5lcmF0ZSgpO1xuXHRcdH1cblx0XHRuZXdDb250YWN0LnVpZChuZXdVaWQpO1xuXHRcdG5ld0NvbnRhY3Quc2V0VXJsKGFkZHJlc3NCb29rLCBuZXdVaWQpO1xuXHRcdG5ld0NvbnRhY3QuYWRkcmVzc0Jvb2tJZCA9IGFkZHJlc3NCb29rLmRpc3BsYXlOYW1lO1xuXHRcdGlmIChfLmlzVW5kZWZpbmVkKG5ld0NvbnRhY3QuZnVsbE5hbWUoKSkgfHwgbmV3Q29udGFjdC5mdWxsTmFtZSgpID09PSAnJykge1xuXHRcdFx0bmV3Q29udGFjdC5mdWxsTmFtZSh0KCdjb250YWN0cycsICdOZXcgY29udGFjdCcpKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gRGF2Q2xpZW50LmNyZWF0ZUNhcmQoXG5cdFx0XHRhZGRyZXNzQm9vayxcblx0XHRcdHtcblx0XHRcdFx0ZGF0YTogbmV3Q29udGFjdC5kYXRhLmFkZHJlc3NEYXRhLFxuXHRcdFx0XHRmaWxlbmFtZTogbmV3VWlkICsgJy52Y2YnXG5cdFx0XHR9XG5cdFx0KS50aGVuKGZ1bmN0aW9uKHhocikge1xuXHRcdFx0aWYgKCEoXy5pc1VuZGVmaW5lZChuZXdDb250YWN0LmZ1bGxOYW1lKCkpIHx8IG5ld0NvbnRhY3QuZnVsbE5hbWUoKSA9PT0gJycpKSB7XG5cdFx0XHRcdG5ld0NvbnRhY3Quc2V0RVRhZyh4aHIuZ2V0UmVzcG9uc2VIZWFkZXIoJ0VUYWcnKSk7XG5cdFx0XHRcdGNvbnRhY3RzLnB1dChuZXdVaWQsIG5ld0NvbnRhY3QpO1xuXHRcdFx0XHRub3RpZnlPYnNlcnZlcnMoJ2NyZWF0ZScsIG5ld1VpZCk7XG5cdFx0XHRcdCQoJyNkZXRhaWxzLWZ1bGxOYW1lJykuc2VsZWN0KCk7XG5cdFx0XHRcdHJldHVybiBuZXdDb250YWN0O1xuXHRcdFx0fVxuXHRcdH0pLmNhdGNoKGZ1bmN0aW9uKCkge1xuXHRcdFx0T0MuTm90aWZpY2F0aW9uLnNob3dUZW1wb3JhcnkodCgnY29udGFjdHMnLCAnQ29udGFjdCBjb3VsZCBub3QgYmUgY3JlYXRlZC4nKSk7XG5cdFx0fSk7XG5cblx0fTtcblxuXHR0aGlzLmltcG9ydCA9IGZ1bmN0aW9uKGRhdGEsIHR5cGUsIGFkZHJlc3NCb29rLCBwcm9ncmVzc0NhbGxiYWNrKSB7XG5cdFx0YWRkcmVzc0Jvb2sgPSBhZGRyZXNzQm9vayB8fCBBZGRyZXNzQm9va1NlcnZpY2UuZ2V0RGVmYXVsdEFkZHJlc3NCb29rKCk7XG5cblx0XHR2YXIgcmVnZXhwID0gL0JFR0lOOlZDQVJEW1xcc1xcU10qP0VORDpWQ0FSRC9tZ2k7XG5cdFx0dmFyIHNpbmdsZVZDYXJkcyA9IGRhdGEubWF0Y2gocmVnZXhwKTtcblxuXHRcdGlmICghc2luZ2xlVkNhcmRzKSB7XG5cdFx0XHRPQy5Ob3RpZmljYXRpb24uc2hvd1RlbXBvcmFyeSh0KCdjb250YWN0cycsICdObyBjb250YWN0cyBpbiBmaWxlLiBPbmx5IHZDYXJkIGZpbGVzIGFyZSBhbGxvd2VkLicpKTtcblx0XHRcdGlmIChwcm9ncmVzc0NhbGxiYWNrKSB7XG5cdFx0XHRcdHByb2dyZXNzQ2FsbGJhY2soMSk7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdHZhciBudW0gPSAxO1xuXHRcdGZvcih2YXIgaSBpbiBzaW5nbGVWQ2FyZHMpIHtcblx0XHRcdHZhciBuZXdDb250YWN0ID0gbmV3IENvbnRhY3QoYWRkcmVzc0Jvb2ssIHthZGRyZXNzRGF0YTogc2luZ2xlVkNhcmRzW2ldfSk7XG5cdFx0XHRpZiAoWyczLjAnLCAnNC4wJ10uaW5kZXhPZihuZXdDb250YWN0LnZlcnNpb24oKSkgPCAwKSB7XG5cdFx0XHRcdGlmIChwcm9ncmVzc0NhbGxiYWNrKSB7XG5cdFx0XHRcdFx0cHJvZ3Jlc3NDYWxsYmFjayhudW0gLyBzaW5nbGVWQ2FyZHMubGVuZ3RoKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRPQy5Ob3RpZmljYXRpb24uc2hvd1RlbXBvcmFyeSh0KCdjb250YWN0cycsICdPbmx5IHZDYXJkIHZlcnNpb24gNC4wIChSRkM2MzUwKSBvciB2ZXJzaW9uIDMuMCAoUkZDMjQyNikgYXJlIHN1cHBvcnRlZC4nKSk7XG5cdFx0XHRcdG51bSsrO1xuXHRcdFx0XHRjb250aW51ZTtcblx0XHRcdH1cblx0XHRcdHRoaXMuY3JlYXRlKG5ld0NvbnRhY3QsIGFkZHJlc3NCb29rKS50aGVuKGZ1bmN0aW9uKCkge1xuXHRcdFx0XHQvLyBVcGRhdGUgdGhlIHByb2dyZXNzIGluZGljYXRvclxuXHRcdFx0XHRpZiAocHJvZ3Jlc3NDYWxsYmFjaykge1xuXHRcdFx0XHRcdHByb2dyZXNzQ2FsbGJhY2sobnVtIC8gc2luZ2xlVkNhcmRzLmxlbmd0aCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0bnVtKys7XG5cdFx0XHR9KTtcblx0XHR9XG5cdH07XG5cblx0dGhpcy5tb3ZlQ29udGFjdCA9IGZ1bmN0aW9uIChjb250YWN0LCBhZGRyZXNzYm9vaykge1xuXHRcdGlmIChjb250YWN0LmFkZHJlc3NCb29rSWQgPT09IGFkZHJlc3Nib29rLmRpc3BsYXlOYW1lKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdGNvbnRhY3Quc3luY1ZDYXJkKCk7XG5cdFx0dmFyIGNsb25lID0gYW5ndWxhci5jb3B5KGNvbnRhY3QpO1xuXHRcdHZhciB1aWQgPSBjb250YWN0LnVpZCgpO1xuXG5cdFx0Ly8gZGVsZXRlIHRoZSBvbGQgb25lIGJlZm9yZSB0byBhdm9pZCBjb25mbGljdFxuXHRcdHRoaXMuZGVsZXRlKGNvbnRhY3QpO1xuXG5cdFx0Ly8gY3JlYXRlIHRoZSBjb250YWN0IGluIHRoZSBuZXcgdGFyZ2V0IGFkZHJlc3Nib29rXG5cdFx0dGhpcy5jcmVhdGUoY2xvbmUsIGFkZHJlc3Nib29rLCB1aWQpO1xuXHR9O1xuXG5cdHRoaXMudXBkYXRlID0gZnVuY3Rpb24oY29udGFjdCkge1xuXHRcdC8vIHVwZGF0ZSByZXYgZmllbGRcblx0XHRjb250YWN0LnN5bmNWQ2FyZCgpO1xuXG5cdFx0Ly8gdXBkYXRlIGNvbnRhY3Qgb24gc2VydmVyXG5cdFx0cmV0dXJuIERhdkNsaWVudC51cGRhdGVDYXJkKGNvbnRhY3QuZGF0YSwge2pzb246IHRydWV9KS50aGVuKGZ1bmN0aW9uKHhocikge1xuXHRcdFx0dmFyIG5ld0V0YWcgPSB4aHIuZ2V0UmVzcG9uc2VIZWFkZXIoJ0VUYWcnKTtcblx0XHRcdGNvbnRhY3Quc2V0RVRhZyhuZXdFdGFnKTtcblx0XHRcdG5vdGlmeU9ic2VydmVycygndXBkYXRlJywgY29udGFjdC51aWQoKSk7XG5cdFx0fSkuY2F0Y2goZnVuY3Rpb24oKSB7XG5cdFx0XHRPQy5Ob3RpZmljYXRpb24uc2hvd1RlbXBvcmFyeSh0KCdjb250YWN0cycsICdDb250YWN0IGNvdWxkIG5vdCBiZSBzYXZlZC4nKSk7XG5cdFx0fSk7XG5cdH07XG5cblx0dGhpcy5kZWxldGUgPSBmdW5jdGlvbihjb250YWN0KSB7XG5cdFx0Ly8gZGVsZXRlIGNvbnRhY3QgZnJvbSBzZXJ2ZXJcblx0XHRyZXR1cm4gRGF2Q2xpZW50LmRlbGV0ZUNhcmQoY29udGFjdC5kYXRhKS50aGVuKGZ1bmN0aW9uKCkge1xuXHRcdFx0Y29udGFjdHMucmVtb3ZlKGNvbnRhY3QudWlkKCkpO1xuXHRcdFx0bm90aWZ5T2JzZXJ2ZXJzKCdkZWxldGUnLCBjb250YWN0LnVpZCgpKTtcblx0XHR9KTtcblx0fTtcbn0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5zZXJ2aWNlKCdEYXZDbGllbnQnLCBmdW5jdGlvbigpIHtcblx0dmFyIHhociA9IG5ldyBkYXYudHJhbnNwb3J0LkJhc2ljKFxuXHRcdG5ldyBkYXYuQ3JlZGVudGlhbHMoKVxuXHQpO1xuXHRyZXR1cm4gbmV3IGRhdi5DbGllbnQoeGhyKTtcbn0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5zZXJ2aWNlKCdEYXZTZXJ2aWNlJywgZnVuY3Rpb24oRGF2Q2xpZW50KSB7XG5cdHJldHVybiBEYXZDbGllbnQuY3JlYXRlQWNjb3VudCh7XG5cdFx0c2VydmVyOiBPQy5saW5rVG9SZW1vdGUoJ2Rhdi9hZGRyZXNzYm9va3MnKSxcblx0XHRhY2NvdW50VHlwZTogJ2NhcmRkYXYnLFxuXHRcdHVzZVByb3ZpZGVkUGF0aDogdHJ1ZVxuXHR9KTtcbn0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcblx0LnNlcnZpY2UoJ01pbWVTZXJ2aWNlJywgZnVuY3Rpb24oKSB7XG5cdFx0dmFyIG1hZ2ljTnVtYmVycyA9IHtcblx0XHRcdCcvOWovJyA6ICdKUEVHJyxcblx0XHRcdCdSMGxHT0QnIDogJ0dJRicsXG5cdFx0XHQnaVZCT1J3MEtHZ28nIDogJ1BORydcblx0XHR9O1xuXG5cdFx0dGhpcy5iNjRtaW1lID0gZnVuY3Rpb24oYjY0c3RyaW5nKSB7XG5cdFx0XHRmb3IgKHZhciBtbiBpbiBtYWdpY051bWJlcnMpIHtcblx0XHRcdFx0aWYoYjY0c3RyaW5nLnN0YXJ0c1dpdGgobW4pKSByZXR1cm4gbWFnaWNOdW1iZXJzW21uXTtcblx0XHRcdH1cblx0XHRcdHJldHVybiBudWxsO1xuXHRcdH07XG5cdH0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5zZXJ2aWNlKCdTZWFyY2hTZXJ2aWNlJywgZnVuY3Rpb24oKSB7XG5cdHZhciBzZWFyY2hUZXJtID0gJyc7XG5cblx0dmFyIG9ic2VydmVyQ2FsbGJhY2tzID0gW107XG5cblx0dGhpcy5yZWdpc3Rlck9ic2VydmVyQ2FsbGJhY2sgPSBmdW5jdGlvbihjYWxsYmFjaykge1xuXHRcdG9ic2VydmVyQ2FsbGJhY2tzLnB1c2goY2FsbGJhY2spO1xuXHR9O1xuXG5cdHZhciBub3RpZnlPYnNlcnZlcnMgPSBmdW5jdGlvbihldmVudE5hbWUpIHtcblx0XHR2YXIgZXYgPSB7XG5cdFx0XHRldmVudDpldmVudE5hbWUsXG5cdFx0XHRzZWFyY2hUZXJtOnNlYXJjaFRlcm1cblx0XHR9O1xuXHRcdGFuZ3VsYXIuZm9yRWFjaChvYnNlcnZlckNhbGxiYWNrcywgZnVuY3Rpb24oY2FsbGJhY2spIHtcblx0XHRcdGNhbGxiYWNrKGV2KTtcblx0XHR9KTtcblx0fTtcblxuXHR2YXIgU2VhcmNoUHJveHkgPSB7XG5cdFx0YXR0YWNoOiBmdW5jdGlvbihzZWFyY2gpIHtcblx0XHRcdHNlYXJjaC5zZXRGaWx0ZXIoJ2NvbnRhY3RzJywgdGhpcy5maWx0ZXJQcm94eSk7XG5cdFx0fSxcblx0XHRmaWx0ZXJQcm94eTogZnVuY3Rpb24ocXVlcnkpIHtcblx0XHRcdHNlYXJjaFRlcm0gPSBxdWVyeTtcblx0XHRcdG5vdGlmeU9ic2VydmVycygnY2hhbmdlU2VhcmNoJyk7XG5cdFx0fVxuXHR9O1xuXG5cdHRoaXMuZ2V0U2VhcmNoVGVybSA9IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiBzZWFyY2hUZXJtO1xuXHR9O1xuXG5cdHRoaXMuY2xlYW5TZWFyY2ggPSBmdW5jdGlvbigpIHtcblx0XHRpZiAoIV8uaXNVbmRlZmluZWQoJCgnLnNlYXJjaGJveCcpKSkge1xuXHRcdFx0JCgnLnNlYXJjaGJveCcpWzBdLnJlc2V0KCk7XG5cdFx0fVxuXHRcdHNlYXJjaFRlcm0gPSAnJztcblx0fTtcblxuXHRpZiAoIV8uaXNVbmRlZmluZWQoT0MuUGx1Z2lucykpIHtcblx0XHRPQy5QbHVnaW5zLnJlZ2lzdGVyKCdPQ0EuU2VhcmNoJywgU2VhcmNoUHJveHkpO1xuXHRcdGlmICghXy5pc1VuZGVmaW5lZChPQ0EuU2VhcmNoKSkge1xuXHRcdFx0T0MuU2VhcmNoID0gbmV3IE9DQS5TZWFyY2goJCgnI3NlYXJjaGJveCcpLCAkKCcjc2VhcmNocmVzdWx0cycpKTtcblx0XHRcdCQoJyNzZWFyY2hib3gnKS5zaG93KCk7XG5cdFx0fVxuXHR9XG5cblx0aWYgKCFfLmlzVW5kZWZpbmVkKCQoJy5zZWFyY2hib3gnKSkpIHtcblx0XHQkKCcuc2VhcmNoYm94JylbMF0uYWRkRXZlbnRMaXN0ZW5lcigna2V5cHJlc3MnLCBmdW5jdGlvbihlKSB7XG5cdFx0XHRpZihlLmtleUNvZGUgPT09IDEzKSB7XG5cdFx0XHRcdG5vdGlmeU9ic2VydmVycygnc3VibWl0U2VhcmNoJyk7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH1cbn0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5zZXJ2aWNlKCdTZXR0aW5nc1NlcnZpY2UnLCBmdW5jdGlvbigpIHtcblx0dmFyIHNldHRpbmdzID0ge1xuXHRcdGFkZHJlc3NCb29rczogW1xuXHRcdFx0J3Rlc3RBZGRyJ1xuXHRcdF1cblx0fTtcblxuXHR0aGlzLnNldCA9IGZ1bmN0aW9uKGtleSwgdmFsdWUpIHtcblx0XHRzZXR0aW5nc1trZXldID0gdmFsdWU7XG5cdH07XG5cblx0dGhpcy5nZXQgPSBmdW5jdGlvbihrZXkpIHtcblx0XHRyZXR1cm4gc2V0dGluZ3Nba2V5XTtcblx0fTtcblxuXHR0aGlzLmdldEFsbCA9IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiBzZXR0aW5ncztcblx0fTtcbn0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5zZXJ2aWNlKCdTb3J0QnlTZXJ2aWNlJywgZnVuY3Rpb24gKCkge1xuXHR2YXIgc3Vic2NyaXB0aW9ucyA9IFtdO1xuXHR2YXIgc29ydEJ5ID0gJ3NvcnREaXNwbGF5TmFtZSc7XG5cblx0dmFyIGRlZmF1bHRPcmRlciA9IHdpbmRvdy5sb2NhbFN0b3JhZ2UuZ2V0SXRlbSgnY29udGFjdHNfZGVmYXVsdF9vcmRlcicpO1xuXHRpZiAoZGVmYXVsdE9yZGVyKSB7XG5cdFx0c29ydEJ5ID0gZGVmYXVsdE9yZGVyO1xuXHR9XG5cblx0ZnVuY3Rpb24gbm90aWZ5T2JzZXJ2ZXJzICgpIHtcblx0XHRhbmd1bGFyLmZvckVhY2goc3Vic2NyaXB0aW9ucywgZnVuY3Rpb24gKHN1YnNjcmlwdGlvbikge1xuXHRcdFx0aWYgKHR5cGVvZiBzdWJzY3JpcHRpb24gPT09ICdmdW5jdGlvbicpIHtcblx0XHRcdFx0c3Vic2NyaXB0aW9uKHNvcnRCeSk7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH1cblxuXHRyZXR1cm4ge1xuXHRcdHN1YnNjcmliZTogZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG5cdFx0XHRzdWJzY3JpcHRpb25zLnB1c2ggKGNhbGxiYWNrKTtcblx0XHR9LFxuXHRcdHNldFNvcnRCeTogZnVuY3Rpb24gKHZhbHVlKSB7XG5cdFx0XHRzb3J0QnkgPSB2YWx1ZTtcblx0XHRcdHdpbmRvdy5sb2NhbFN0b3JhZ2Uuc2V0SXRlbSAoJ2NvbnRhY3RzX2RlZmF1bHRfb3JkZXInLCB2YWx1ZSk7XG5cdFx0XHRub3RpZnlPYnNlcnZlcnMgKCk7XG5cdFx0fSxcblx0XHRnZXRTb3J0Qnk6IGZ1bmN0aW9uICgpIHtcblx0XHRcdHJldHVybiBzb3J0Qnk7XG5cdFx0fSxcblx0XHRnZXRTb3J0QnlMaXN0OiBmdW5jdGlvbiAoKSB7XG5cdFx0XHRyZXR1cm4ge1xuXHRcdFx0XHRzb3J0RGlzcGxheU5hbWU6IHQoJ2NvbnRhY3RzJywgJ0Rpc3BsYXkgbmFtZScpLFxuXHRcdFx0XHRzb3J0Rmlyc3ROYW1lOiB0KCdjb250YWN0cycsICdGaXJzdCBuYW1lJyksXG5cdFx0XHRcdHNvcnRMYXN0TmFtZTogdCgnY29udGFjdHMnLCAnTGFzdCBuYW1lJylcblx0XHRcdH07XG5cdFx0fVxuXHR9O1xufSk7XG4iLCJhbmd1bGFyLm1vZHVsZSgnY29udGFjdHNBcHAnKVxuLnNlcnZpY2UoJ3ZDYXJkUHJvcGVydGllc1NlcnZpY2UnLCBmdW5jdGlvbigpIHtcblx0LyoqXG5cdCAqIG1hcCB2Q2FyZCBhdHRyaWJ1dGVzIHRvIGludGVybmFsIGF0dHJpYnV0ZXNcblx0ICpcblx0ICogcHJvcE5hbWU6IHtcblx0ICogXHRcdG11bHRpcGxlOiBbQm9vbGVhbl0sIC8vIGlzIHRoaXMgcHJvcCBhbGxvd2VkIG1vcmUgdGhhbiBvbmNlPyAoZGVmYXVsdCA9IGZhbHNlKVxuXHQgKiBcdFx0cmVhZGFibGVOYW1lOiBbU3RyaW5nXSwgLy8gaW50ZXJuYXRpb25hbGl6ZWQgcmVhZGFibGUgbmFtZSBvZiBwcm9wXG5cdCAqIFx0XHR0ZW1wbGF0ZTogW1N0cmluZ10sIC8vIHRlbXBsYXRlIG5hbWUgZm91bmQgaW4gL3RlbXBsYXRlcy9kZXRhaWxJdGVtc1xuXHQgKiBcdFx0Wy4uLl0gLy8gb3B0aW9uYWwgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiB3aGljaCBtaWdodCBnZXQgdXNlZCBieSB0aGUgdGVtcGxhdGVcblx0ICogfVxuXHQgKi9cblx0dGhpcy52Q2FyZE1ldGEgPSB7XG5cdFx0bmlja25hbWU6IHtcblx0XHRcdHJlYWRhYmxlTmFtZTogdCgnY29udGFjdHMnLCAnTmlja25hbWUnKSxcblx0XHRcdHRlbXBsYXRlOiAndGV4dCdcblx0XHR9LFxuXHRcdG46IHtcblx0XHRcdHJlYWRhYmxlTmFtZTogdCgnY29udGFjdHMnLCAnRGV0YWlsZWQgbmFtZScpLFxuXHRcdFx0ZGVmYXVsdFZhbHVlOiB7XG5cdFx0XHRcdHZhbHVlOlsnJywgJycsICcnLCAnJywgJyddXG5cdFx0XHR9LFxuXHRcdFx0dGVtcGxhdGU6ICduJ1xuXHRcdH0sXG5cdFx0bm90ZToge1xuXHRcdFx0cmVhZGFibGVOYW1lOiB0KCdjb250YWN0cycsICdOb3RlcycpLFxuXHRcdFx0dGVtcGxhdGU6ICd0ZXh0YXJlYSdcblx0XHR9LFxuXHRcdHVybDoge1xuXHRcdFx0bXVsdGlwbGU6IHRydWUsXG5cdFx0XHRyZWFkYWJsZU5hbWU6IHQoJ2NvbnRhY3RzJywgJ1dlYnNpdGUnKSxcblx0XHRcdHRlbXBsYXRlOiAndXJsJ1xuXHRcdH0sXG5cdFx0Y2xvdWQ6IHtcblx0XHRcdG11bHRpcGxlOiB0cnVlLFxuXHRcdFx0cmVhZGFibGVOYW1lOiB0KCdjb250YWN0cycsICdGZWRlcmF0ZWQgQ2xvdWQgSUQnKSxcblx0XHRcdHRlbXBsYXRlOiAndGV4dCcsXG5cdFx0XHRkZWZhdWx0VmFsdWU6IHtcblx0XHRcdFx0dmFsdWU6WycnXSxcblx0XHRcdFx0bWV0YTp7dHlwZTpbJ0hPTUUnXX1cblx0XHRcdH0sXG5cdFx0XHRvcHRpb25zOiBbXG5cdFx0XHRcdHtpZDogJ0hPTUUnLCBuYW1lOiB0KCdjb250YWN0cycsICdIb21lJyl9LFxuXHRcdFx0XHR7aWQ6ICdXT1JLJywgbmFtZTogdCgnY29udGFjdHMnLCAnV29yaycpfSxcblx0XHRcdFx0e2lkOiAnT1RIRVInLCBuYW1lOiB0KCdjb250YWN0cycsICdPdGhlcicpfVxuXHRcdFx0XVx0XHR9LFxuXHRcdGFkcjoge1xuXHRcdFx0bXVsdGlwbGU6IHRydWUsXG5cdFx0XHRyZWFkYWJsZU5hbWU6IHQoJ2NvbnRhY3RzJywgJ0FkZHJlc3MnKSxcblx0XHRcdHRlbXBsYXRlOiAnYWRyJyxcblx0XHRcdGRlZmF1bHRWYWx1ZToge1xuXHRcdFx0XHR2YWx1ZTpbJycsICcnLCAnJywgJycsICcnLCAnJywgJyddLFxuXHRcdFx0XHRtZXRhOnt0eXBlOlsnSE9NRSddfVxuXHRcdFx0fSxcblx0XHRcdG9wdGlvbnM6IFtcblx0XHRcdFx0e2lkOiAnSE9NRScsIG5hbWU6IHQoJ2NvbnRhY3RzJywgJ0hvbWUnKX0sXG5cdFx0XHRcdHtpZDogJ1dPUksnLCBuYW1lOiB0KCdjb250YWN0cycsICdXb3JrJyl9LFxuXHRcdFx0XHR7aWQ6ICdPVEhFUicsIG5hbWU6IHQoJ2NvbnRhY3RzJywgJ090aGVyJyl9XG5cdFx0XHRdXG5cdFx0fSxcblx0XHRjYXRlZ29yaWVzOiB7XG5cdFx0XHRyZWFkYWJsZU5hbWU6IHQoJ2NvbnRhY3RzJywgJ0dyb3VwcycpLFxuXHRcdFx0dGVtcGxhdGU6ICdncm91cHMnXG5cdFx0fSxcblx0XHRiZGF5OiB7XG5cdFx0XHRyZWFkYWJsZU5hbWU6IHQoJ2NvbnRhY3RzJywgJ0JpcnRoZGF5JyksXG5cdFx0XHR0ZW1wbGF0ZTogJ2RhdGUnXG5cdFx0fSxcblx0XHRhbm5pdmVyc2FyeToge1xuXHRcdFx0cmVhZGFibGVOYW1lOiB0KCdjb250YWN0cycsICdBbm5pdmVyc2FyeScpLFxuXHRcdFx0dGVtcGxhdGU6ICdkYXRlJ1xuXHRcdH0sXG5cdFx0ZGVhdGhkYXRlOiB7XG5cdFx0XHRyZWFkYWJsZU5hbWU6IHQoJ2NvbnRhY3RzJywgJ0RhdGUgb2YgZGVhdGgnKSxcblx0XHRcdHRlbXBsYXRlOiAnZGF0ZSdcblx0XHR9LFxuXHRcdGVtYWlsOiB7XG5cdFx0XHRtdWx0aXBsZTogdHJ1ZSxcblx0XHRcdHJlYWRhYmxlTmFtZTogdCgnY29udGFjdHMnLCAnRW1haWwnKSxcblx0XHRcdHRlbXBsYXRlOiAnZW1haWwnLFxuXHRcdFx0ZGVmYXVsdFZhbHVlOiB7XG5cdFx0XHRcdHZhbHVlOicnLFxuXHRcdFx0XHRtZXRhOnt0eXBlOlsnSE9NRSddfVxuXHRcdFx0fSxcblx0XHRcdG9wdGlvbnM6IFtcblx0XHRcdFx0e2lkOiAnSE9NRScsIG5hbWU6IHQoJ2NvbnRhY3RzJywgJ0hvbWUnKX0sXG5cdFx0XHRcdHtpZDogJ1dPUksnLCBuYW1lOiB0KCdjb250YWN0cycsICdXb3JrJyl9LFxuXHRcdFx0XHR7aWQ6ICdPVEhFUicsIG5hbWU6IHQoJ2NvbnRhY3RzJywgJ090aGVyJyl9XG5cdFx0XHRdXG5cdFx0fSxcblx0XHRpbXBwOiB7XG5cdFx0XHRtdWx0aXBsZTogdHJ1ZSxcblx0XHRcdHJlYWRhYmxlTmFtZTogdCgnY29udGFjdHMnLCAnSW5zdGFudCBtZXNzYWdpbmcnKSxcblx0XHRcdHRlbXBsYXRlOiAndXNlcm5hbWUnLFxuXHRcdFx0ZGVmYXVsdFZhbHVlOiB7XG5cdFx0XHRcdHZhbHVlOlsnJ10sXG5cdFx0XHRcdG1ldGE6e3R5cGU6WydTS1lQRSddfVxuXHRcdFx0fSxcblx0XHRcdG9wdGlvbnM6IFtcblx0XHRcdFx0e2lkOiAnSVJDJywgbmFtZTogICdJUkMnfSxcblx0XHRcdFx0e2lkOiAnU0tZUEUnLCBuYW1lOidTa3lwZSd9LFxuXHRcdFx0XHR7aWQ6ICdURUxFR1JBTScsIG5hbWU6J1RlbGVncmFtJ31cblx0XHRcdF1cblx0XHR9LFxuXHRcdHRlbDoge1xuXHRcdFx0bXVsdGlwbGU6IHRydWUsXG5cdFx0XHRyZWFkYWJsZU5hbWU6IHQoJ2NvbnRhY3RzJywgJ1Bob25lJyksXG5cdFx0XHR0ZW1wbGF0ZTogJ3RlbCcsXG5cdFx0XHRkZWZhdWx0VmFsdWU6IHtcblx0XHRcdFx0dmFsdWU6JycsXG5cdFx0XHRcdG1ldGE6e3R5cGU6WydIT01FLFZPSUNFJ119XG5cdFx0XHR9LFxuXHRcdFx0b3B0aW9uczogW1xuXHRcdFx0XHR7aWQ6ICdIT01FLFZPSUNFJywgbmFtZTogdCgnY29udGFjdHMnLCAnSG9tZScpfSxcblx0XHRcdFx0e2lkOiAnV09SSyxWT0lDRScsIG5hbWU6IHQoJ2NvbnRhY3RzJywgJ1dvcmsnKX0sXG5cdFx0XHRcdHtpZDogJ0NFTEwnLCBuYW1lOiB0KCdjb250YWN0cycsICdNb2JpbGUnKX0sXG5cdFx0XHRcdHtpZDogJ0ZBWCcsIG5hbWU6IHQoJ2NvbnRhY3RzJywgJ0ZheCcpfSxcblx0XHRcdFx0e2lkOiAnSE9NRSxGQVgnLCBuYW1lOiB0KCdjb250YWN0cycsICdGYXggaG9tZScpfSxcblx0XHRcdFx0e2lkOiAnV09SSyxGQVgnLCBuYW1lOiB0KCdjb250YWN0cycsICdGYXggd29yaycpfSxcblx0XHRcdFx0e2lkOiAnUEFHRVInLCBuYW1lOiB0KCdjb250YWN0cycsICdQYWdlcicpfSxcblx0XHRcdFx0e2lkOiAnVk9JQ0UnLCBuYW1lOiB0KCdjb250YWN0cycsICdWb2ljZScpfVxuXHRcdFx0XVxuXHRcdH0sXG5cdFx0J1gtU09DSUFMUFJPRklMRSc6IHtcblx0XHRcdG11bHRpcGxlOiB0cnVlLFxuXHRcdFx0cmVhZGFibGVOYW1lOiB0KCdjb250YWN0cycsICdTb2NpYWwgbmV0d29yaycpLFxuXHRcdFx0dGVtcGxhdGU6ICd1c2VybmFtZScsXG5cdFx0XHRkZWZhdWx0VmFsdWU6IHtcblx0XHRcdFx0dmFsdWU6WycnXSxcblx0XHRcdFx0bWV0YTp7dHlwZTpbJ2ZhY2Vib29rJ119XG5cdFx0XHR9LFxuXHRcdFx0b3B0aW9uczogW1xuXHRcdFx0XHR7aWQ6ICdGQUNFQk9PSycsIG5hbWU6ICdGYWNlYm9vayd9LFxuXHRcdFx0XHR7aWQ6ICdHT09HTEVQTFVTJywgbmFtZTogJ0dvb2dsZSsnfSxcblx0XHRcdFx0e2lkOiAnSU5TVEFHUkFNJywgbmFtZTogJ0luc3RhZ3JhbSd9LFxuXHRcdFx0XHR7aWQ6ICdMSU5LRURJTicsIG5hbWU6ICdMaW5rZWRJbid9LFxuXHRcdFx0XHR7aWQ6ICdQSU5URVJFU1QnLCBuYW1lOiAnUGludGVyZXN0J30sXG5cdFx0XHRcdHtpZDogJ1RXSVRURVInLCBuYW1lOiAnVHdpdHRlcid9XG5cblx0XHRcdF1cblxuXHRcdH1cblx0fTtcblxuXHR0aGlzLmZpZWxkT3JkZXIgPSBbXG5cdFx0J29yZycsXG5cdFx0J3RpdGxlJyxcblx0XHQndGVsJyxcblx0XHQnZW1haWwnLFxuXHRcdCdhZHInLFxuXHRcdCdpbXBwJyxcblx0XHQnbmljaycsXG5cdFx0J2JkYXknLFxuXHRcdCdhbm5pdmVyc2FyeScsXG5cdFx0J2RlYXRoZGF0ZScsXG5cdFx0J3VybCcsXG5cdFx0J1gtU09DSUFMUFJPRklMRScsXG5cdFx0J25vdGUnLFxuXHRcdCdjYXRlZ29yaWVzJyxcblx0XHQncm9sZSdcblx0XTtcblxuXHR0aGlzLmZpZWxkRGVmaW5pdGlvbnMgPSBbXTtcblx0Zm9yICh2YXIgcHJvcCBpbiB0aGlzLnZDYXJkTWV0YSkge1xuXHRcdHRoaXMuZmllbGREZWZpbml0aW9ucy5wdXNoKHtpZDogcHJvcCwgbmFtZTogdGhpcy52Q2FyZE1ldGFbcHJvcF0ucmVhZGFibGVOYW1lLCBtdWx0aXBsZTogISF0aGlzLnZDYXJkTWV0YVtwcm9wXS5tdWx0aXBsZX0pO1xuXHR9XG5cblx0dGhpcy5mYWxsYmFja01ldGEgPSBmdW5jdGlvbihwcm9wZXJ0eSkge1xuXHRcdGZ1bmN0aW9uIGNhcGl0YWxpemUoc3RyaW5nKSB7IHJldHVybiBzdHJpbmcuY2hhckF0KDApLnRvVXBwZXJDYXNlKCkgKyBzdHJpbmcuc2xpY2UoMSk7IH1cblx0XHRyZXR1cm4ge1xuXHRcdFx0bmFtZTogJ3Vua25vd24tJyArIHByb3BlcnR5LFxuXHRcdFx0cmVhZGFibGVOYW1lOiBjYXBpdGFsaXplKHByb3BlcnR5KSxcblx0XHRcdHRlbXBsYXRlOiAnaGlkZGVuJyxcblx0XHRcdG5lY2Vzc2l0eTogJ29wdGlvbmFsJ1xuXHRcdH07XG5cdH07XG5cblx0dGhpcy5nZXRNZXRhID0gZnVuY3Rpb24ocHJvcGVydHkpIHtcblx0XHRyZXR1cm4gdGhpcy52Q2FyZE1ldGFbcHJvcGVydHldIHx8IHRoaXMuZmFsbGJhY2tNZXRhKHByb3BlcnR5KTtcblx0fTtcblxufSk7XG4iLCJhbmd1bGFyLm1vZHVsZSgnY29udGFjdHNBcHAnKVxuLmZpbHRlcignSlNPTjJ2Q2FyZCcsIGZ1bmN0aW9uKCkge1xuXHRyZXR1cm4gZnVuY3Rpb24oaW5wdXQpIHtcblx0XHRyZXR1cm4gdkNhcmQuZ2VuZXJhdGUoaW5wdXQpO1xuXHR9O1xufSk7XG4iLCJhbmd1bGFyLm1vZHVsZSgnY29udGFjdHNBcHAnKVxuLmZpbHRlcignY29udGFjdENvbG9yJywgZnVuY3Rpb24oKSB7XG5cdHJldHVybiBmdW5jdGlvbihpbnB1dCkge1xuXHRcdC8vIENoZWNrIGlmIGNvcmUgaGFzIHRoZSBuZXcgY29sb3IgZ2VuZXJhdG9yXG5cdFx0aWYodHlwZW9mIGlucHV0LnRvSHNsID09PSAnZnVuY3Rpb24nKSB7XG5cdFx0XHR2YXIgaHNsID0gaW5wdXQudG9Ic2woKTtcblx0XHRcdHJldHVybiAnaHNsKCcraHNsWzBdKycsICcraHNsWzFdKyclLCAnK2hzbFsyXSsnJSknO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHQvLyBJZiBub3QsIHdlIHVzZSB0aGUgb2xkIG9uZVxuXHRcdFx0LyogZ2xvYmFsIG1kNSAqL1xuXHRcdFx0dmFyIGhhc2ggPSBtZDUoaW5wdXQpLnN1YnN0cmluZygwLCA0KSxcblx0XHRcdFx0bWF4UmFuZ2UgPSBwYXJzZUludCgnZmZmZicsIDE2KSxcblx0XHRcdFx0aHVlID0gcGFyc2VJbnQoaGFzaCwgMTYpIC8gbWF4UmFuZ2UgKiAyNTY7XG5cdFx0XHRyZXR1cm4gJ2hzbCgnICsgaHVlICsgJywgOTAlLCA2NSUpJztcblx0XHR9XG5cdH07XG59KTsiLCJhbmd1bGFyLm1vZHVsZSgnY29udGFjdHNBcHAnKVxuLmZpbHRlcignY29udGFjdEdyb3VwRmlsdGVyJywgZnVuY3Rpb24oKSB7XG5cdCd1c2Ugc3RyaWN0Jztcblx0cmV0dXJuIGZ1bmN0aW9uIChjb250YWN0cywgZ3JvdXApIHtcblx0XHRpZiAodHlwZW9mIGNvbnRhY3RzID09PSAndW5kZWZpbmVkJykge1xuXHRcdFx0cmV0dXJuIGNvbnRhY3RzO1xuXHRcdH1cblx0XHRpZiAodHlwZW9mIGdyb3VwID09PSAndW5kZWZpbmVkJyB8fCBncm91cC50b0xvd2VyQ2FzZSgpID09PSB0KCdjb250YWN0cycsICdBbGwgY29udGFjdHMnKS50b0xvd2VyQ2FzZSgpKSB7XG5cdFx0XHRyZXR1cm4gY29udGFjdHM7XG5cdFx0fVxuXHRcdHZhciBmaWx0ZXIgPSBbXTtcblx0XHRpZiAoY29udGFjdHMubGVuZ3RoID4gMCkge1xuXHRcdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCBjb250YWN0cy5sZW5ndGg7IGkrKykge1xuXHRcdFx0XHRpZiAoZ3JvdXAudG9Mb3dlckNhc2UoKSA9PT0gdCgnY29udGFjdHMnLCAnTm90IGdyb3VwZWQnKS50b0xvd2VyQ2FzZSgpKSB7XG5cdFx0XHRcdFx0aWYgKGNvbnRhY3RzW2ldLmNhdGVnb3JpZXMoKS5sZW5ndGggPT09IDApIHtcblx0XHRcdFx0XHRcdGZpbHRlci5wdXNoKGNvbnRhY3RzW2ldKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0aWYgKGNvbnRhY3RzW2ldLmNhdGVnb3JpZXMoKS5pbmRleE9mKGdyb3VwKSA+PSAwKSB7XG5cdFx0XHRcdFx0XHRmaWx0ZXIucHVzaChjb250YWN0c1tpXSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHJldHVybiBmaWx0ZXI7XG5cdH07XG59KTtcbiIsIi8vIGZyb20gaHR0cHM6Ly9kb2NzLm5leHRjbG91ZC5jb20vc2VydmVyLzExL2RldmVsb3Blcl9tYW51YWwvYXBwL2Nzcy5odG1sI21lbnVzXG5hbmd1bGFyLm1vZHVsZSgnY29udGFjdHNBcHAnKVxuLmZpbHRlcignY291bnRlckZvcm1hdHRlcicsIGZ1bmN0aW9uICgpIHtcblx0J3VzZSBzdHJpY3QnO1xuXHRyZXR1cm4gZnVuY3Rpb24gKGNvdW50KSB7XG5cdFx0aWYgKGNvdW50ID4gOTk5KSB7XG5cdFx0XHRyZXR1cm4gJzk5OSsnO1xuXHRcdH1cblx0XHRyZXR1cm4gY291bnQ7XG5cdH07XG59KTtcblxuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5maWx0ZXIoJ2ZpZWxkRmlsdGVyJywgZnVuY3Rpb24oKSB7XG5cdCd1c2Ugc3RyaWN0Jztcblx0cmV0dXJuIGZ1bmN0aW9uIChmaWVsZHMsIGNvbnRhY3QpIHtcblx0XHRpZiAodHlwZW9mIGZpZWxkcyA9PT0gJ3VuZGVmaW5lZCcpIHtcblx0XHRcdHJldHVybiBmaWVsZHM7XG5cdFx0fVxuXHRcdGlmICh0eXBlb2YgY29udGFjdCA9PT0gJ3VuZGVmaW5lZCcpIHtcblx0XHRcdHJldHVybiBmaWVsZHM7XG5cdFx0fVxuXHRcdHZhciBmaWx0ZXIgPSBbXTtcblx0XHRpZiAoZmllbGRzLmxlbmd0aCA+IDApIHtcblx0XHRcdGZvciAodmFyIGkgPSAwOyBpIDwgZmllbGRzLmxlbmd0aDsgaSsrKSB7XG5cdFx0XHRcdGlmIChmaWVsZHNbaV0ubXVsdGlwbGUgKSB7XG5cdFx0XHRcdFx0ZmlsdGVyLnB1c2goZmllbGRzW2ldKTtcblx0XHRcdFx0XHRjb250aW51ZTtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoXy5pc1VuZGVmaW5lZChjb250YWN0LmdldFByb3BlcnR5KGZpZWxkc1tpXS5pZCkpKSB7XG5cdFx0XHRcdFx0ZmlsdGVyLnB1c2goZmllbGRzW2ldKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0XHRyZXR1cm4gZmlsdGVyO1xuXHR9O1xufSk7XG4iLCJhbmd1bGFyLm1vZHVsZSgnY29udGFjdHNBcHAnKVxuLmZpbHRlcignZmlyc3RDaGFyYWN0ZXInLCBmdW5jdGlvbigpIHtcblx0cmV0dXJuIGZ1bmN0aW9uKGlucHV0KSB7XG5cdFx0cmV0dXJuIGlucHV0LmNoYXJBdCgwKTtcblx0fTtcbn0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5maWx0ZXIoJ2xvY2FsZU9yZGVyQnknLCBbZnVuY3Rpb24gKCkge1xuXHRyZXR1cm4gZnVuY3Rpb24gKGFycmF5LCBzb3J0UHJlZGljYXRlLCByZXZlcnNlT3JkZXIpIHtcblx0XHRpZiAoIUFycmF5LmlzQXJyYXkoYXJyYXkpKSByZXR1cm4gYXJyYXk7XG5cdFx0aWYgKCFzb3J0UHJlZGljYXRlKSByZXR1cm4gYXJyYXk7XG5cblx0XHR2YXIgYXJyYXlDb3B5ID0gW107XG5cdFx0YW5ndWxhci5mb3JFYWNoKGFycmF5LCBmdW5jdGlvbiAoaXRlbSkge1xuXHRcdFx0YXJyYXlDb3B5LnB1c2goaXRlbSk7XG5cdFx0fSk7XG5cblx0XHRhcnJheUNvcHkuc29ydChmdW5jdGlvbiAoYSwgYikge1xuXHRcdFx0dmFyIHZhbHVlQSA9IGFbc29ydFByZWRpY2F0ZV07XG5cdFx0XHRpZiAoYW5ndWxhci5pc0Z1bmN0aW9uKHZhbHVlQSkpIHtcblx0XHRcdFx0dmFsdWVBID0gYVtzb3J0UHJlZGljYXRlXSgpO1xuXHRcdFx0fVxuXHRcdFx0dmFyIHZhbHVlQiA9IGJbc29ydFByZWRpY2F0ZV07XG5cdFx0XHRpZiAoYW5ndWxhci5pc0Z1bmN0aW9uKHZhbHVlQikpIHtcblx0XHRcdFx0dmFsdWVCID0gYltzb3J0UHJlZGljYXRlXSgpO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoYW5ndWxhci5pc1N0cmluZyh2YWx1ZUEpKSB7XG5cdFx0XHRcdHJldHVybiAhcmV2ZXJzZU9yZGVyID8gdmFsdWVBLmxvY2FsZUNvbXBhcmUodmFsdWVCKSA6IHZhbHVlQi5sb2NhbGVDb21wYXJlKHZhbHVlQSk7XG5cdFx0XHR9XG5cblx0XHRcdGlmIChhbmd1bGFyLmlzTnVtYmVyKHZhbHVlQSkgfHwgdHlwZW9mIHZhbHVlQSA9PT0gJ2Jvb2xlYW4nKSB7XG5cdFx0XHRcdHJldHVybiAhcmV2ZXJzZU9yZGVyID8gdmFsdWVBIC0gdmFsdWVCIDogdmFsdWVCIC0gdmFsdWVBO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoYW5ndWxhci5pc0FycmF5KHZhbHVlQSkpIHtcblx0XHRcdFx0aWYgKHZhbHVlQVswXSA9PT0gdmFsdWVCWzBdKSB7XG5cdFx0XHRcdFx0cmV0dXJuICFyZXZlcnNlT3JkZXIgPyB2YWx1ZUFbMV0ubG9jYWxlQ29tcGFyZSh2YWx1ZUJbMV0pIDogdmFsdWVCWzFdLmxvY2FsZUNvbXBhcmUodmFsdWVBWzFdKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gIXJldmVyc2VPcmRlciA/IHZhbHVlQVswXS5sb2NhbGVDb21wYXJlKHZhbHVlQlswXSkgOiB2YWx1ZUJbMF0ubG9jYWxlQ29tcGFyZSh2YWx1ZUFbMF0pO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gMDtcblx0XHR9KTtcblxuXHRcdHJldHVybiBhcnJheUNvcHk7XG5cdH07XG59XSk7XG4iLCJhbmd1bGFyLm1vZHVsZSgnY29udGFjdHNBcHAnKVxuLmZpbHRlcignbmV3Q29udGFjdCcsIGZ1bmN0aW9uKCkge1xuXHRyZXR1cm4gZnVuY3Rpb24oaW5wdXQpIHtcblx0XHRyZXR1cm4gaW5wdXQgIT09ICcnID8gaW5wdXQgOiB0KCdjb250YWN0cycsICdOZXcgY29udGFjdCcpO1xuXHR9O1xufSk7XG4iLCJhbmd1bGFyLm1vZHVsZSgnY29udGFjdHNBcHAnKVxuLmZpbHRlcignb3JkZXJEZXRhaWxJdGVtcycsIGZ1bmN0aW9uKHZDYXJkUHJvcGVydGllc1NlcnZpY2UpIHtcblx0J3VzZSBzdHJpY3QnO1xuXHRyZXR1cm4gZnVuY3Rpb24oaXRlbXMsIGZpZWxkLCByZXZlcnNlKSB7XG5cblx0XHR2YXIgZmlsdGVyZWQgPSBbXTtcblx0XHRhbmd1bGFyLmZvckVhY2goaXRlbXMsIGZ1bmN0aW9uKGl0ZW0pIHtcblx0XHRcdGZpbHRlcmVkLnB1c2goaXRlbSk7XG5cdFx0fSk7XG5cblx0XHR2YXIgZmllbGRPcmRlciA9IGFuZ3VsYXIuY29weSh2Q2FyZFByb3BlcnRpZXNTZXJ2aWNlLmZpZWxkT3JkZXIpO1xuXHRcdC8vIHJldmVyc2UgdG8gbW92ZSBjdXN0b20gaXRlbXMgdG8gdGhlIGVuZCAoaW5kZXhPZiA9PSAtMSlcblx0XHRmaWVsZE9yZGVyLnJldmVyc2UoKTtcblxuXHRcdGZpbHRlcmVkLnNvcnQoZnVuY3Rpb24gKGEsIGIpIHtcblx0XHRcdGlmKGZpZWxkT3JkZXIuaW5kZXhPZihhW2ZpZWxkXSkgPCBmaWVsZE9yZGVyLmluZGV4T2YoYltmaWVsZF0pKSB7XG5cdFx0XHRcdHJldHVybiAxO1xuXHRcdFx0fVxuXHRcdFx0aWYoZmllbGRPcmRlci5pbmRleE9mKGFbZmllbGRdKSA+IGZpZWxkT3JkZXIuaW5kZXhPZihiW2ZpZWxkXSkpIHtcblx0XHRcdFx0cmV0dXJuIC0xO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIDA7XG5cdFx0fSk7XG5cblx0XHRpZihyZXZlcnNlKSBmaWx0ZXJlZC5yZXZlcnNlKCk7XG5cdFx0cmV0dXJuIGZpbHRlcmVkO1xuXHR9O1xufSk7XG4iLCJhbmd1bGFyLm1vZHVsZSgnY29udGFjdHNBcHAnKVxuLmZpbHRlcigndG9BcnJheScsIGZ1bmN0aW9uKCkge1xuXHRyZXR1cm4gZnVuY3Rpb24ob2JqKSB7XG5cdFx0aWYgKCEob2JqIGluc3RhbmNlb2YgT2JqZWN0KSkgcmV0dXJuIG9iajtcblx0XHRyZXR1cm4gXy5tYXAob2JqLCBmdW5jdGlvbih2YWwsIGtleSkge1xuXHRcdFx0cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh2YWwsICcka2V5Jywge3ZhbHVlOiBrZXl9KTtcblx0XHR9KTtcblx0fTtcbn0pO1xuIiwiYW5ndWxhci5tb2R1bGUoJ2NvbnRhY3RzQXBwJylcbi5maWx0ZXIoJ3ZDYXJkMkpTT04nLCBmdW5jdGlvbigpIHtcblx0cmV0dXJuIGZ1bmN0aW9uKGlucHV0KSB7XG5cdFx0cmV0dXJuIHZDYXJkLnBhcnNlKGlucHV0KTtcblx0fTtcbn0pO1xuIl19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment