321 lines
62 KiB
JavaScript
321 lines
62 KiB
JavaScript
|
/*
|
||
|
THIS IS A GENERATED/BUNDLED FILE BY ROLLUP
|
||
|
if you want to view the source visit the plugins github repository
|
||
|
*/
|
||
|
|
||
|
'use strict';
|
||
|
|
||
|
var obsidian = require('obsidian');
|
||
|
|
||
|
/*! *****************************************************************************
|
||
|
Copyright (c) Microsoft Corporation.
|
||
|
|
||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||
|
purpose with or without fee is hereby granted.
|
||
|
|
||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||
|
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||
|
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||
|
PERFORMANCE OF THIS SOFTWARE.
|
||
|
***************************************************************************** */
|
||
|
|
||
|
function __awaiter(thisArg, _arguments, P, generator) {
|
||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||
|
});
|
||
|
}
|
||
|
|
||
|
const DEFAULT_SETTINGS = {
|
||
|
findText: '',
|
||
|
replaceText: '',
|
||
|
useRegEx: true,
|
||
|
selOnly: false,
|
||
|
caseInsensitive: false,
|
||
|
processLineBreak: false,
|
||
|
processTab: false,
|
||
|
prefillFind: false
|
||
|
};
|
||
|
// logThreshold: 0 ... only error messages
|
||
|
// 9 ... verbose output
|
||
|
const logThreshold = 9;
|
||
|
const logger = (logString, logLevel = 0) => { if (logLevel <= logThreshold)
|
||
|
console.log('RegexFiRe: ' + logString); };
|
||
|
class RegexFindReplacePlugin extends obsidian.Plugin {
|
||
|
onload() {
|
||
|
return __awaiter(this, void 0, void 0, function* () {
|
||
|
logger('Loading Plugin...', 9);
|
||
|
yield this.loadSettings();
|
||
|
this.addSettingTab(new RegexFindReplaceSettingTab(this.app, this));
|
||
|
this.addCommand({
|
||
|
id: 'obsidian-regex-replace',
|
||
|
name: 'Find and Replace using regular expressions',
|
||
|
editorCallback: (editor) => {
|
||
|
new FindAndReplaceModal(this.app, editor, this.settings, this).open();
|
||
|
},
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
onunload() {
|
||
|
logger('Bye!', 9);
|
||
|
}
|
||
|
loadSettings() {
|
||
|
return __awaiter(this, void 0, void 0, function* () {
|
||
|
logger('Loading Settings...', 6);
|
||
|
this.settings = Object.assign({}, DEFAULT_SETTINGS, yield this.loadData());
|
||
|
logger(' findVal: ' + this.settings.findText, 6);
|
||
|
logger(' replaceText: ' + this.settings.replaceText, 6);
|
||
|
logger(' caseInsensitive: ' + this.settings.caseInsensitive, 6);
|
||
|
logger(' processLineBreak: ' + this.settings.processLineBreak, 6);
|
||
|
});
|
||
|
}
|
||
|
saveSettings() {
|
||
|
return __awaiter(this, void 0, void 0, function* () {
|
||
|
yield this.saveData(this.settings);
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
class FindAndReplaceModal extends obsidian.Modal {
|
||
|
constructor(app, editor, settings, plugin) {
|
||
|
super(app);
|
||
|
this.editor = editor;
|
||
|
this.settings = settings;
|
||
|
this.plugin = plugin;
|
||
|
}
|
||
|
onOpen() {
|
||
|
const { contentEl, titleEl, editor, modalEl } = this;
|
||
|
modalEl.addClass('find-replace-modal');
|
||
|
titleEl.setText('Regex Find/Replace');
|
||
|
const rowClass = 'row';
|
||
|
const divClass = 'div';
|
||
|
const noSelection = editor.getSelection() === '';
|
||
|
let regexFlags = 'gm';
|
||
|
if (this.settings.caseInsensitive)
|
||
|
regexFlags = regexFlags.concat('i');
|
||
|
logger('No text selected?: ' + noSelection, 9);
|
||
|
const addTextComponent = (label, placeholder, postfix = '') => {
|
||
|
const containerEl = document.createElement(divClass);
|
||
|
containerEl.addClass(rowClass);
|
||
|
const targetEl = document.createElement(divClass);
|
||
|
targetEl.addClass('input-wrapper');
|
||
|
const labelEl = document.createElement(divClass);
|
||
|
labelEl.addClass('input-label');
|
||
|
labelEl.setText(label);
|
||
|
const labelEl2 = document.createElement(divClass);
|
||
|
labelEl2.addClass('postfix-label');
|
||
|
labelEl2.setText(postfix);
|
||
|
containerEl.appendChild(labelEl);
|
||
|
containerEl.appendChild(targetEl);
|
||
|
containerEl.appendChild(labelEl2);
|
||
|
const component = new obsidian.TextComponent(targetEl);
|
||
|
component.setPlaceholder(placeholder);
|
||
|
contentEl.append(containerEl);
|
||
|
return [component, labelEl2];
|
||
|
};
|
||
|
const addToggleComponent = (label, tooltip, hide = false) => {
|
||
|
const containerEl = document.createElement(divClass);
|
||
|
containerEl.addClass(rowClass);
|
||
|
const targetEl = document.createElement(divClass);
|
||
|
targetEl.addClass(rowClass);
|
||
|
const component = new obsidian.ToggleComponent(targetEl);
|
||
|
component.setTooltip(tooltip);
|
||
|
const labelEl = document.createElement(divClass);
|
||
|
labelEl.addClass('check-label');
|
||
|
labelEl.setText(label);
|
||
|
containerEl.appendChild(labelEl);
|
||
|
containerEl.appendChild(targetEl);
|
||
|
if (!hide)
|
||
|
contentEl.appendChild(containerEl);
|
||
|
return component;
|
||
|
};
|
||
|
// Create input fields
|
||
|
const findRow = addTextComponent('Find:', 'e.g. (.*)', '/' + regexFlags);
|
||
|
const findInputComponent = findRow[0];
|
||
|
const findRegexFlags = findRow[1];
|
||
|
const replaceRow = addTextComponent('Replace:', 'e.g. $1', this.settings.processLineBreak ? '\\n=LF' : '');
|
||
|
const replaceWithInputComponent = replaceRow[0];
|
||
|
// Create and show regular expression toggle switch
|
||
|
const regToggleComponent = addToggleComponent('Use regular expressions', 'If enabled, regular expressions in the find field are processed as such, and regex groups might be addressed in the replace field');
|
||
|
// Update regex-flags label if regular expressions are enabled or disabled
|
||
|
regToggleComponent.onChange(regNew => {
|
||
|
if (regNew) {
|
||
|
findRegexFlags.setText('/' + regexFlags);
|
||
|
}
|
||
|
else {
|
||
|
findRegexFlags.setText('');
|
||
|
}
|
||
|
});
|
||
|
// Create and show selection toggle switch only if any text is selected
|
||
|
const selToggleComponent = addToggleComponent('Replace only in selection', 'If enabled, replaces only occurances in the currently selected text', noSelection);
|
||
|
// Create Buttons
|
||
|
const buttonContainerEl = document.createElement(divClass);
|
||
|
buttonContainerEl.addClass(rowClass);
|
||
|
const submitButtonTarget = document.createElement(divClass);
|
||
|
submitButtonTarget.addClass('button-wrapper');
|
||
|
submitButtonTarget.addClass(rowClass);
|
||
|
const cancelButtonTarget = document.createElement(divClass);
|
||
|
cancelButtonTarget.addClass('button-wrapper');
|
||
|
cancelButtonTarget.addClass(rowClass);
|
||
|
const submitButtonComponent = new obsidian.ButtonComponent(submitButtonTarget);
|
||
|
const cancelButtonComponent = new obsidian.ButtonComponent(cancelButtonTarget);
|
||
|
cancelButtonComponent.setButtonText('Cancel');
|
||
|
cancelButtonComponent.onClick(() => {
|
||
|
logger('Action cancelled.', 8);
|
||
|
this.close();
|
||
|
});
|
||
|
submitButtonComponent.setButtonText('Replace All');
|
||
|
submitButtonComponent.setCta();
|
||
|
submitButtonComponent.onClick(() => {
|
||
|
let resultString = 'No match';
|
||
|
let scope = '';
|
||
|
const searchString = findInputComponent.getValue();
|
||
|
let replaceString = replaceWithInputComponent.getValue();
|
||
|
const selectedText = editor.getSelection();
|
||
|
if (searchString === '') {
|
||
|
new obsidian.Notice('Nothing to search for!');
|
||
|
return;
|
||
|
}
|
||
|
// Replace line breaks in find-field if option is enabled
|
||
|
if (this.settings.processLineBreak) {
|
||
|
logger('Replacing linebreaks in replace-field', 9);
|
||
|
logger(' old: ' + replaceString, 9);
|
||
|
replaceString = replaceString.replace(/\\n/gm, '\n');
|
||
|
logger(' new: ' + replaceString, 9);
|
||
|
}
|
||
|
// Replace line breaks in find-field if option is enabled
|
||
|
if (this.settings.processTab) {
|
||
|
logger('Replacing tabs in replace-field', 9);
|
||
|
logger(' old: ' + replaceString, 9);
|
||
|
replaceString = replaceString.replace(/\\t/gm, '\t');
|
||
|
logger(' new: ' + replaceString, 9);
|
||
|
}
|
||
|
// Check if regular expressions should be used
|
||
|
if (regToggleComponent.getValue()) {
|
||
|
logger('USING regex with flags: ' + regexFlags, 8);
|
||
|
const searchRegex = new RegExp(searchString, regexFlags);
|
||
|
if (!selToggleComponent.getValue()) {
|
||
|
logger(' SCOPE: Full document', 9);
|
||
|
const documentText = editor.getValue();
|
||
|
const rresult = documentText.match(searchRegex);
|
||
|
if (rresult) {
|
||
|
editor.setValue(documentText.replace(searchRegex, replaceString));
|
||
|
resultString = `Made ${rresult.length} replacement(s) in document`;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
logger(' SCOPE: Selection', 9);
|
||
|
const rresult = selectedText.match(searchRegex);
|
||
|
if (rresult) {
|
||
|
editor.replaceSelection(selectedText.replace(searchRegex, replaceString));
|
||
|
resultString = `Made ${rresult.length} replacement(s) in selection`;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
logger('NOT using regex', 8);
|
||
|
let nrOfHits = 0;
|
||
|
if (!selToggleComponent.getValue()) {
|
||
|
logger(' SCOPE: Full document', 9);
|
||
|
scope = 'selection';
|
||
|
const documentText = editor.getValue();
|
||
|
const documentSplit = documentText.split(searchString);
|
||
|
nrOfHits = documentSplit.length - 1;
|
||
|
editor.setValue(documentSplit.join(replaceString));
|
||
|
}
|
||
|
else {
|
||
|
logger(' SCOPE: Selection', 9);
|
||
|
scope = 'document';
|
||
|
const selectedSplit = selectedText.split(searchString);
|
||
|
nrOfHits = selectedSplit.length - 1;
|
||
|
editor.replaceSelection(selectedSplit.join(replaceString));
|
||
|
}
|
||
|
resultString = `Made ${nrOfHits} replacement(s) in ${scope}`;
|
||
|
}
|
||
|
// Saving settings (find/replace text and toggle switch states)
|
||
|
this.settings.findText = searchString;
|
||
|
this.settings.replaceText = replaceString;
|
||
|
this.settings.useRegEx = regToggleComponent.getValue();
|
||
|
this.settings.selOnly = selToggleComponent.getValue();
|
||
|
this.plugin.saveData(this.settings);
|
||
|
this.close();
|
||
|
new obsidian.Notice(resultString);
|
||
|
});
|
||
|
// Apply settings
|
||
|
regToggleComponent.setValue(this.settings.useRegEx);
|
||
|
selToggleComponent.setValue(this.settings.selOnly);
|
||
|
replaceWithInputComponent.setValue(this.settings.replaceText);
|
||
|
// Check if the prefill find option is enabled and the selection does not contain linebreaks
|
||
|
if (this.settings.prefillFind && editor.getSelection().indexOf('\n') < 0 && !noSelection) {
|
||
|
logger('Found selection without linebreaks and option is enabled -> fill', 9);
|
||
|
findInputComponent.setValue(editor.getSelection());
|
||
|
selToggleComponent.setValue(false);
|
||
|
}
|
||
|
else {
|
||
|
logger('Restore find text', 9);
|
||
|
findInputComponent.setValue(this.settings.findText);
|
||
|
}
|
||
|
// Add button row to dialog
|
||
|
buttonContainerEl.appendChild(submitButtonTarget);
|
||
|
buttonContainerEl.appendChild(cancelButtonTarget);
|
||
|
contentEl.appendChild(buttonContainerEl);
|
||
|
// If no text is selected, disable selection-toggle-switch
|
||
|
if (noSelection)
|
||
|
selToggleComponent.setValue(false);
|
||
|
}
|
||
|
onClose() {
|
||
|
const { contentEl } = this;
|
||
|
contentEl.empty();
|
||
|
}
|
||
|
}
|
||
|
class RegexFindReplaceSettingTab extends obsidian.PluginSettingTab {
|
||
|
constructor(app, plugin) {
|
||
|
super(app, plugin);
|
||
|
this.plugin = plugin;
|
||
|
}
|
||
|
display() {
|
||
|
const { containerEl } = this;
|
||
|
containerEl.empty();
|
||
|
containerEl.createEl('h4', { text: 'Regular Expression Settings' });
|
||
|
new obsidian.Setting(containerEl)
|
||
|
.setName('Case Insensitive')
|
||
|
.setDesc('When using regular expressions, apply the \'/i\' modifier for case insensitive search)')
|
||
|
.addToggle(toggle => toggle
|
||
|
.setValue(this.plugin.settings.caseInsensitive)
|
||
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
||
|
logger('Settings update: caseInsensitive: ' + value);
|
||
|
this.plugin.settings.caseInsensitive = value;
|
||
|
yield this.plugin.saveSettings();
|
||
|
})));
|
||
|
containerEl.createEl('h4', { text: 'General Settings' });
|
||
|
new obsidian.Setting(containerEl)
|
||
|
.setName('Process \\n as line break')
|
||
|
.setDesc('When \'\\n\' is used in the replace field, a \'line break\' will be inserted accordingly')
|
||
|
.addToggle(toggle => toggle
|
||
|
.setValue(this.plugin.settings.processLineBreak)
|
||
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
||
|
logger('Settings update: processLineBreak: ' + value);
|
||
|
this.plugin.settings.processLineBreak = value;
|
||
|
yield this.plugin.saveSettings();
|
||
|
})));
|
||
|
new obsidian.Setting(containerEl)
|
||
|
.setName('Prefill Find Field')
|
||
|
.setDesc('Copy the currently selected text (if any) into the \'Find\' text field. This setting is only applied if the selection does not contain linebreaks')
|
||
|
.addToggle(toggle => toggle
|
||
|
.setValue(this.plugin.settings.prefillFind)
|
||
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
||
|
logger('Settings update: prefillFind: ' + value);
|
||
|
this.plugin.settings.prefillFind = value;
|
||
|
yield this.plugin.saveSettings();
|
||
|
})));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
module.exports = RegexFindReplacePlugin;
|
||
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZXMiOlsibm9kZV9tb2R1bGVzL3RzbGliL3RzbGliLmVzNi5qcyIsInNyYy9tYWluLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qISAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5Db3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi5cclxuXHJcblBlcm1pc3Npb24gdG8gdXNlLCBjb3B5LCBtb2RpZnksIGFuZC9vciBkaXN0cmlidXRlIHRoaXMgc29mdHdhcmUgZm9yIGFueVxyXG5wdXJwb3NlIHdpdGggb3Igd2l0aG91dCBmZWUgaXMgaGVyZWJ5IGdyYW50ZWQuXHJcblxyXG5USEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiIEFORCBUSEUgQVVUSE9SIERJU0NMQUlNUyBBTEwgV0FSUkFOVElFUyBXSVRIXHJcblJFR0FSRCBUTyBUSElTIFNPRlRXQVJFIElOQ0xVRElORyBBTEwgSU1QTElFRCBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWVxyXG5BTkQgRklUTkVTUy4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUiBCRSBMSUFCTEUgRk9SIEFOWSBTUEVDSUFMLCBESVJFQ1QsXHJcbklORElSRUNULCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVMgT1IgQU5ZIERBTUFHRVMgV0hBVFNPRVZFUiBSRVNVTFRJTkcgRlJPTVxyXG5MT1NTIE9GIFVTRSwgREFUQSBPUiBQUk9GSVRTLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgTkVHTElHRU5DRSBPUlxyXG5PVEhFUiBUT1JUSU9VUyBBQ1RJT04sIEFSSVNJTkcgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgVVNFIE9SXHJcblBFUkZPUk1BTkNFIE9GIFRISVMgU09GVFdBUkUuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICovXHJcbi8qIGdsb2JhbCBSZWZsZWN0LCBQcm9taXNlICovXHJcblxyXG52YXIgZXh0ZW5kU3RhdGljcyA9IGZ1bmN0aW9uKGQsIGIpIHtcclxuICAgIGV4dGVuZFN0YXRpY3MgPSBPYmplY3Quc2V0UHJvdG90eXBlT2YgfHxcclxuICAgICAgICAoeyBfX3Byb3RvX186IFtdIH0gaW5zdGFuY2VvZiBBcnJheSAmJiBmdW5jdGlvbiAoZCwgYikgeyBkLl9fcHJvdG9fXyA9IGI7IH0pIHx8XHJcbiAgICAgICAgZnVuY3Rpb24gKGQsIGIpIHsgZm9yICh2YXIgcCBpbiBiKSBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGIsIHApKSBkW3BdID0gYltwXTsgfTtcclxuICAgIHJldHVybiBleHRlbmRTdGF0aWNzKGQsIGIpO1xyXG59O1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZXh0ZW5kcyhkLCBiKSB7XHJcbiAgICBpZiAodHlwZW9mIGIgIT09IFwiZnVuY3Rpb25cIiAmJiBiICE9PSBudWxsKVxyXG4gICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJDbGFzcyBleHRlbmRzIHZhbHVlIFwiICsgU3RyaW5nKGIpICsgXCIgaXMgbm90IGEgY29uc3RydWN0b3Igb3IgbnVsbFwiKTtcclxuICAgIGV4dGVuZFN0YXRpY3MoZCwgYik7XHJcbiAgICBmdW5jdGlvbiBfXygpIHsgdGhpcy5jb25zdHJ1Y3RvciA9IGQ7IH1cclxuICAgIGQucHJvdG90eXBlID0gYiA9PT0gbnVsbCA/IE9iamVjdC5jcmVhdGUoYikgOiAoX18ucHJvdG90eXBlID0gYi5wcm90b3R5cGUsIG5ldyBfXygpKTtcclxufVxyXG5cclxuZXhwb3J0IHZhciBfX2Fzc2lnbiA9IGZ1bmN0aW9uKCkge1xyXG4gICAgX19hc3NpZ24gPSBPYmplY3QuYXNzaWduIHx8IGZ1bmN0aW9uIF9fYXNzaWduKHQpIHtcclxuICAgICAgICBmb3IgKHZhciBzLCBpID0gMSwgbiA9IGFyZ3VtZW50cy5sZW5ndGg7IGkgPCBuOyBpKyspIHtcclxuICAgICAgICAgICAgcyA9IGFyZ3VtZW50c1tpXTtcclxuICAgICAgICAgICAgZm9yICh2YXIgcCBpbiBzKSBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHMsIHApKSB0W3BdID0gc1twXTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHQ7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gX19hc3NpZ24uYXBwbHkodGhpcywgYXJndW1lbnRzKTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fcmVzdChzLCBlKSB7XHJcbiAgICB2YXIgdCA9IHt9O1xyXG4gICAgZm9yICh2YXIgcCBpbiBzKSBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHMsIHApICYmIGUuaW5kZXhPZihwKSA8IDApXHJcbiAgICAgICAgdFtwXSA9IHNbcF07XHJcbiAgICBpZiAocyAhPSBudWxsICYmIHR5cGVvZiBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzID09PSBcImZ1bmN0aW9uXCIpXHJcbiAgICAgICAgZm9yICh2YXIgaSA9IDAsIHAgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzKHMpOyBpIDwgcC5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgICAgICBpZiAoZS5pbmRleE9mKHBbaV0pIDwgMCAmJiBPYmplY3QucHJvdG90eXBlLnByb3BlcnR5SXNFbnVtZXJhYmxlLmNhbGwocywgcFtpXSkpXHJcbiAgICAgICAgICAgICAgICB0W3BbaV1dID0gc1twW2ldXTtcclxuICAgICAgICB9XHJcbiAgICByZXR1cm4gdDtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZGVjb3JhdGUoZGVjb3JhdG9ycywgdGFyZ2V0LCBrZXksIGRlc2MpIHtcclxuICAgIHZhciBjID0gYXJndW1lbnRzLmxlbmd0aCwgciA9IGMgPCAzID8gdGFyZ2V0IDogZGVzYyA9PT0gbnVsbCA/IGRlc2MgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHRhcmdldCwga2V5KSA6IGRlc2MsIGQ7XHJcbiAgICBpZiAodHlwZW9mIFJlZmxlY3QgPT09IFwib2JqZWN0XCIgJiYgdHlwZW9mIFJlZmxlY3QuZGVjb3JhdGUgPT09IFwiZnVuY3Rpb25cIikgciA9IFJlZmxlY3QuZGVjb3JhdGUoZGVjb3JhdG9ycywgdGFyZ2V0LCBrZXksIGRlc2MpO1xyXG4gICAgZWxzZSBmb3IgKHZhciBpID0gZGVjb3JhdG9ycy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkgaWYgKGQgPSBkZWNvcmF0b3JzW2ldKSByID0gKGMgPCAzID8
|