Created
August 15, 2017 20:03
-
-
Save xh3n1/1fac4dd92356340ce68d9b7b5e6fda0b to your computer and use it in GitHub Desktop.
public js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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