Remove unused blade settings pages not linked from UI Convert remaining frontend pages to SPA actions Convert settings user_settings and general to SPA actions Convert settings profile pages to SPA actions Convert contacts and projects add/edit pages to SPA actions Convert clients add/edit page to SPA action with loading pattern Refactor component scoped IDs from $id to $sid Fix jqhtml comment syntax and implement universal error component system Update all application code to use new unified error system Remove all backwards compatibility - unified error system complete Phase 5: Remove old response classes Phase 3-4: Ajax response handler sends new format, old helpers deprecated Phase 2: Add client-side unified error foundation Phase 1: Add server-side unified error foundation Add unified Ajax error response system with constants 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
248 lines
28 KiB
JavaScript
Executable File
248 lines
28 KiB
JavaScript
Executable File
"use strict";
|
|
|
|
/**
|
|
* Currency_Input
|
|
*
|
|
* Extends Text_Input to provide automatic currency formatting.
|
|
*
|
|
* Features:
|
|
* - Adds thousands separators (commas) every 3 digits
|
|
* - Optional currency symbol prefix (default: hidden)
|
|
* - Optional decimal support (default: disabled)
|
|
* - Smart backspace over formatting characters
|
|
* - No mid-string formatting (waits for blur)
|
|
*
|
|
* Arguments:
|
|
* - $allow_decimals - Allow 2 decimal places (default: false)
|
|
* - $show_symbol - Show currency symbol (default: false)
|
|
* - $currency_symbol - Currency symbol to use (default: "$")
|
|
*
|
|
* Usage:
|
|
* <Currency_Input />
|
|
* <Currency_Input $show_symbol=true />
|
|
* <Currency_Input $allow_decimals=true />
|
|
* <Currency_Input $show_symbol=true $allow_decimals=true $currency_symbol="€" />
|
|
*
|
|
* Behavior:
|
|
* - Type "1234567" -> displays "1,234,567", val() returns "1234567"
|
|
* - Type "1234567.89" (with decimals) -> displays "1,234,567.89", val() returns "1234567.89"
|
|
* - With symbol: displays "$1,234,567", val() still returns "1234567"
|
|
*/
|
|
class Currency_Input extends Text_Input {
|
|
on_create() {
|
|
super.on_create();
|
|
|
|
// Set defaults for options
|
|
if (this.args.allow_decimals === undefined) {
|
|
this.args.allow_decimals = false;
|
|
}
|
|
if (this.args.show_symbol === undefined) {
|
|
this.args.show_symbol = false;
|
|
}
|
|
if (this.args.currency_symbol === undefined) {
|
|
this.args.currency_symbol = '$';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Format currency with commas and optional symbol
|
|
* @param {string} value - Numeric value (may include decimal)
|
|
* @returns {string} Formatted currency string
|
|
*/
|
|
_format_currency(value) {
|
|
if (!value) {
|
|
return '';
|
|
}
|
|
|
|
// Split into integer and decimal parts
|
|
let parts = value.split('.');
|
|
let integer_part = parts[0];
|
|
let decimal_part = parts[1];
|
|
|
|
// Add commas to integer part
|
|
integer_part = integer_part.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
|
|
|
// Reconstruct with decimal if allowed
|
|
let formatted = integer_part;
|
|
if (this.args.allow_decimals && decimal_part !== undefined) {
|
|
// Limit to 2 decimal places
|
|
decimal_part = decimal_part.substr(0, 2);
|
|
formatted += '.' + decimal_part;
|
|
}
|
|
|
|
// Add currency symbol if enabled
|
|
if (this.args.show_symbol) {
|
|
formatted = this.args.currency_symbol + formatted;
|
|
}
|
|
return formatted;
|
|
}
|
|
|
|
/**
|
|
* Extract numeric value from formatted string
|
|
* @param {string} formatted - Formatted currency string
|
|
* @returns {string} Clean numeric value (digits and decimal only)
|
|
*/
|
|
_get_numeric_value(formatted) {
|
|
if (!formatted) {
|
|
return '';
|
|
}
|
|
|
|
// Remove currency symbol and commas
|
|
let cleaned = formatted.replace(/[^0-9.]/g, '');
|
|
|
|
// Ensure only one decimal point
|
|
const decimal_count = (cleaned.match(/\./g) || []).length;
|
|
if (decimal_count > 1) {
|
|
// Keep only first decimal point
|
|
const first_decimal = cleaned.indexOf('.');
|
|
cleaned = cleaned.substr(0, first_decimal + 1) + cleaned.substr(first_decimal + 1).replace(/\./g, '');
|
|
}
|
|
return cleaned;
|
|
}
|
|
|
|
/**
|
|
* val() - Get or set the currency value
|
|
* Getter returns numeric string (no commas, no symbol)
|
|
* Setter accepts anything and formats with commas/symbol
|
|
* @param {string} [value]
|
|
* @returns {string}
|
|
*/
|
|
val(value) {
|
|
if (arguments.length === 0) {
|
|
// Getter - return numeric value only
|
|
const raw = this.$sid('input').val();
|
|
return this._get_numeric_value(raw);
|
|
} else {
|
|
// Setter - format and display
|
|
if (!value) {
|
|
this.data.value = '';
|
|
if (this.$sid('input').exists()) {
|
|
this.$sid('input').val('');
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Clean the input value
|
|
const numeric = this._get_numeric_value(str(value));
|
|
const formatted = this._format_currency(numeric);
|
|
this.data.value = formatted;
|
|
if (this.$sid('input').exists()) {
|
|
this.$sid('input').val(formatted);
|
|
}
|
|
}
|
|
}
|
|
on_ready() {
|
|
super.on_ready();
|
|
const $input = this.$sid('input');
|
|
|
|
// Handle keydown to intercept backspace at end of string
|
|
$input.on('keydown', e => {
|
|
const raw = $input.val();
|
|
|
|
// Only handle backspace key
|
|
if (e.key !== 'Backspace') {
|
|
return;
|
|
}
|
|
const input_element = $input[0];
|
|
const cursor_pos = input_element.selectionStart;
|
|
const cursor_end = input_element.selectionEnd;
|
|
const value_length = raw.length;
|
|
|
|
// Only handle if cursor is at the end and no selection
|
|
if (cursor_pos === value_length && cursor_pos === cursor_end) {
|
|
// Check if character before cursor is non-numeric
|
|
if (cursor_pos > 0) {
|
|
const char_before = raw.charAt(cursor_pos - 1);
|
|
if (!/[0-9]/.test(char_before)) {
|
|
// Character before cursor is not a digit
|
|
// Delete the last digit instead
|
|
e.preventDefault();
|
|
const numeric = this._get_numeric_value(raw);
|
|
if (numeric.length > 0) {
|
|
// Remove last character from numeric value
|
|
const new_numeric = numeric.substr(0, numeric.length - 1);
|
|
const formatted = this._format_currency(new_numeric);
|
|
$input.val(formatted);
|
|
|
|
// Place cursor at end
|
|
setTimeout(() => {
|
|
const new_length = $input.val().length;
|
|
input_element.setSelectionRange(new_length, new_length);
|
|
}, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Handle input event for live formatting
|
|
$input.on('input', () => {
|
|
const raw = $input.val();
|
|
const input_element = $input[0];
|
|
const cursor_pos = input_element.selectionStart;
|
|
const value_length = raw.length;
|
|
|
|
// Only apply live formatting if cursor is at the end
|
|
if (cursor_pos === value_length) {
|
|
// Extract numeric value
|
|
let numeric = this._get_numeric_value(raw);
|
|
|
|
// Limit decimal places to 2 if decimals allowed
|
|
if (this.args.allow_decimals) {
|
|
const parts = numeric.split('.');
|
|
if (parts[1] && parts[1].length > 2) {
|
|
numeric = parts[0] + '.' + parts[1].substr(0, 2);
|
|
}
|
|
}
|
|
|
|
// Format the numeric value
|
|
const formatted = this._format_currency(numeric);
|
|
$input.val(formatted);
|
|
} else {
|
|
// Cursor is not at end - user is editing in the middle
|
|
// Don't format, just clean invalid characters
|
|
const numeric = this._get_numeric_value(raw);
|
|
|
|
// Only update if we removed invalid characters
|
|
if (this._format_currency(numeric) !== raw) {
|
|
// Preserve just the numeric characters
|
|
const symbol_offset = this.args.show_symbol ? this.args.currency_symbol.length : 0;
|
|
const cleaned = (this.args.show_symbol ? this.args.currency_symbol : '') + numeric;
|
|
if (cleaned !== raw) {
|
|
$input.val(cleaned);
|
|
// Restore cursor position (approximately)
|
|
const new_cursor = Math.min(cursor_pos, cleaned.length);
|
|
input_element.setSelectionRange(new_cursor, new_cursor);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Handle blur to reformat when done editing
|
|
$input.on('blur', () => {
|
|
const raw = $input.val();
|
|
if (!raw) {
|
|
return;
|
|
}
|
|
|
|
// Reformat the entire value on blur
|
|
const numeric = this._get_numeric_value(raw);
|
|
const formatted = this._format_currency(numeric);
|
|
$input.val(formatted);
|
|
});
|
|
|
|
// Handle focus to select all for easy replacement
|
|
$input.on('focus', () => {
|
|
setTimeout(() => {
|
|
$input[0].select();
|
|
}, 0);
|
|
});
|
|
|
|
// Initialize formatting if there's a value
|
|
const initial_value = $input.val();
|
|
if (initial_value) {
|
|
this.val(initial_value);
|
|
}
|
|
}
|
|
}
|
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJDdXJyZW5jeV9JbnB1dCIsIlRleHRfSW5wdXQiLCJvbl9jcmVhdGUiLCJhcmdzIiwiYWxsb3dfZGVjaW1hbHMiLCJ1bmRlZmluZWQiLCJzaG93X3N5bWJvbCIsImN1cnJlbmN5X3N5bWJvbCIsIl9mb3JtYXRfY3VycmVuY3kiLCJ2YWx1ZSIsInBhcnRzIiwic3BsaXQiLCJpbnRlZ2VyX3BhcnQiLCJkZWNpbWFsX3BhcnQiLCJyZXBsYWNlIiwiZm9ybWF0dGVkIiwic3Vic3RyIiwiX2dldF9udW1lcmljX3ZhbHVlIiwiY2xlYW5lZCIsImRlY2ltYWxfY291bnQiLCJtYXRjaCIsImxlbmd0aCIsImZpcnN0X2RlY2ltYWwiLCJpbmRleE9mIiwidmFsIiwiYXJndW1lbnRzIiwicmF3IiwiJGlkIiwiZGF0YSIsImV4aXN0cyIsIm51bWVyaWMiLCJzdHIiLCJvbl9yZWFkeSIsIiRpbnB1dCIsIm9uIiwiZSIsImtleSIsImlucHV0X2VsZW1lbnQiLCJjdXJzb3JfcG9zIiwic2VsZWN0aW9uU3RhcnQiLCJjdXJzb3JfZW5kIiwic2VsZWN0aW9uRW5kIiwidmFsdWVfbGVuZ3RoIiwiY2hhcl9iZWZvcmUiLCJjaGFyQXQiLCJ0ZXN0IiwicHJldmVudERlZmF1bHQiLCJuZXdfbnVtZXJpYyIsInNldFRpbWVvdXQiLCJuZXdfbGVuZ3RoIiwic2V0U2VsZWN0aW9uUmFuZ2UiLCJzeW1ib2xfb2Zmc2V0IiwibmV3X2N1cnNvciIsIk1hdGgiLCJtaW4iLCJzZWxlY3QiLCJpbml0aWFsX3ZhbHVlIl0sInNvdXJjZXMiOlsicnN4L3RoZW1lL2NvbXBvbmVudHMvaW5wdXRzL2N1cnJlbmN5X2lucHV0LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ3VycmVuY3lfSW5wdXRcbiAqXG4gKiBFeHRlbmRzIFRleHRfSW5wdXQgdG8gcHJvdmlkZSBhdXRvbWF0aWMgY3VycmVuY3kgZm9ybWF0dGluZy5cbiAqXG4gKiBGZWF0dXJlczpcbiAqIC0gQWRkcyB0aG91c2FuZHMgc2VwYXJhdG9ycyAoY29tbWFzKSBldmVyeSAzIGRpZ2l0c1xuICogLSBPcHRpb25hbCBjdXJyZW5jeSBzeW1ib2wgcHJlZml4IChkZWZhdWx0OiBoaWRkZW4pXG4gKiAtIE9wdGlvbmFsIGRlY2ltYWwgc3VwcG9ydCAoZGVmYXVsdDogZGlzYWJsZWQpXG4gKiAtIFNtYXJ0IGJhY2tzcGFjZSBvdmVyIGZvcm1hdHRpbmcgY2hhcmFjdGVyc1xuICogLSBObyBtaWQtc3RyaW5nIGZvcm1hdHRpbmcgKHdhaXRzIGZvciBibHVyKVxuICpcbiAqIEFyZ3VtZW50czpcbiAqIC0gJGFsbG93X2RlY2ltYWxzIC0gQWxsb3cgMiBkZWNpbWFsIHBsYWNlcyAoZGVmYXVsdDogZmFsc2UpXG4gKiAtICRzaG93X3N5bWJvbCAtIFNob3cgY3VycmVuY3kgc3ltYm9sIChkZWZhdWx0OiBmYWxzZSlcbiAqIC0gJGN1cnJlbmN5X3N5bWJvbCAtIEN1cnJlbmN5IHN5bWJvbCB0byB1c2UgKGRlZmF1bHQ6IFwiJFwiKVxuICpcbiAqIFVzYWdlOlxuICogICA8Q3VycmVuY3lfSW5wdXQgLz5cbiAqICAgPEN1cnJlbmN5X0lucHV0ICRzaG93X3N5bWJvbD10cnVlIC8+XG4gKiAgIDxDdXJyZW5jeV9JbnB1dCAkYWxsb3dfZGVjaW1hbHM9dHJ1ZSAvPlxuICogICA8Q3VycmVuY3lfSW5wdXQgJHNob3dfc3ltYm9sPXRydWUgJGFsbG93X2RlY2ltYWxzPXRydWUgJGN1cnJlbmN5X3N5bWJvbD1cIuKCrFwiIC8+XG4gKlxuICogQmVoYXZpb3I6XG4gKiAtIFR5cGUgXCIxMjM0NTY3XCIgLT4gZGlzcGxheXMgXCIxLDIzNCw1NjdcIiwgdmFsKCkgcmV0dXJucyBcIjEyMzQ1NjdcIlxuICogLSBUeXBlIFwiMTIzNDU2Ny44OVwiICh3aXRoIGRlY2ltYWxzKSAtPiBkaXNwbGF5cyBcIjEsMjM0LDU2Ny44OVwiLCB2YWwoKSByZXR1cm5zIFwiMTIzNDU2Ny44OVwiXG4gKiAtIFdpdGggc3ltYm9sOiBkaXNwbGF5cyBcIiQxLDIzNCw1NjdcIiwgdmFsKCkgc3RpbGwgcmV0dXJucyBcIjEyMzQ1NjdcIlxuICovXG5jbGFzcyBDdXJyZW5jeV9JbnB1dCBleHRlbmRzIFRleHRfSW5wdXQge1xuICAgIG9uX2NyZWF0ZSgpIHtcbiAgICAgICAgc3VwZXIub25fY3JlYXRlKCk7XG5cbiAgICAgICAgLy8gU2V0IGRlZmF1bHRzIGZvciBvcHRpb25zXG4gICAgICAgIGlmICh0aGlzLmFyZ3MuYWxsb3dfZGVjaW1hbHMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgdGhpcy5hcmdzLmFsbG93X2RlY2ltYWxzID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuYXJncy5zaG93X3N5bWJvbCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICB0aGlzLmFyZ3Muc2hvd19zeW1ib2wgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5hcmdzLmN1cnJlbmN5X3N5bWJvbCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICB0aGlzLmFyZ3MuY3VycmVuY3lfc3ltYm9sID0gJyQnO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRm9ybWF0IGN1cnJlbmN5IHdpdGggY29tbWFzIGFuZCBvcHRpb25hbCBzeW1ib2xcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdmFsdWUgLSBOdW1lcmljIHZhbHVlIChtYXkgaW5jbHVkZSBkZWNpbWFsKVxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IEZvcm1hdHRlZCBjdXJyZW5jeSBzdHJpbmdcbiAgICAgKi9cbiAgICBfZm9ybWF0X2N1cnJlbmN5KHZhbHVlKSB7XG4gICAgICAgIGlmICghdmFsdWUpIHtcbiAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFNwbGl0IGludG8gaW50ZWdlciBhbmQgZGVjaW1hbCBwYXJ0c1xuICAgICAgICBsZXQgcGFydHMgPSB2YWx1ZS5zcGxpdCgnLicpO1xuICAgICAgICBsZXQgaW50ZWdlcl9wYXJ0ID0gcGFydHNbMF07XG4gICAgICAgIGxldCBkZWNpbWFsX3BhcnQgPSBwYXJ0c1sxXTtcblxuICAgICAgICAvLyBBZGQgY29tbWFzIHRvIGludGVnZXIgcGFydFxuICAgICAgICBpbnRlZ2VyX3BhcnQgPSBpbnRlZ2VyX3BhcnQucmVwbGFjZSgvXFxCKD89KFxcZHszfSkrKD8hXFxkKSkvZywgJywnKTtcblxuICAgICAgICAvLyBSZWNvbnN0cnVjdCB3aXRoIGRlY2ltYWwgaWYgYWxsb3dlZFxuICAgICAgICBsZXQgZm9ybWF0dGVkID0gaW50ZWdlcl9wYXJ0O1xuICAgICAgICBpZiAodGhpcy5hcmdzLmFsbG93X2RlY2ltYWxzICYmIGRlY2ltYWxfcGFydCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAvLyBMaW1pdCB0byAyIGRlY2ltYWwgcGxhY2VzXG4gICAgICAgICAgICBkZWNpbWFsX3BhcnQgPSBkZWNpbWFsX3BhcnQuc3Vic3RyKDAsIDIpO1xuICAgICAgICAgICAgZm9ybWF0dGVkICs9ICcuJyArIGRlY2ltYWxfcGFydDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEFkZCBjdXJyZW5jeSBzeW1ib2wgaWYgZW5hYmxlZFxuICAgICAgICBpZiAodGhpcy5hcmdzLnNob3dfc3ltYm9sKSB7XG4gICAgICAgICAgICBmb3JtYXR0ZWQgPSB0aGlzLmFyZ3MuY3VycmVuY3lfc3ltYm9sICsgZm9ybWF0dGVkO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGZvcm1hdHRlZDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBFeHRyYWN0IG51bWVyaWMgdmFsdWUgZnJvbSBmb3JtYXR0ZWQgc3RyaW5nXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGZvcm1hdHRlZCAtIEZvcm1hdHRlZCBjdXJyZW5jeSBzdHJpbmdcbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nfSBDbGVhbiBudW1lcmljIHZhbHVlIChkaWdpdHMgYW5kIGRlY2ltYWwgb25seSlcbiAgICAgKi9cbiAgICBfZ2V0X251bWVyaWNfdmFsdWUoZm9ybWF0dGVkKSB7XG4gICAgICAgIGlmICghZm9ybWF0dGVkKSB7XG4gICAgICAgICAgICByZXR1cm4gJyc7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBSZW1vdmUgY3VycmVuY3kgc3ltYm9sIGFuZCBjb21tYXNcbiAgICAgICAgbGV0IGNsZWFuZWQgPSBmb3JtYXR0ZWQucmVwbGFjZSgvW14wLTkuXS9nLCAnJyk7XG5cbiAgICAgICAgLy8gRW5zdXJlIG9ubHkgb25lIGRlY2ltYWwgcG9pbnRcbiAgICAgICAgY29uc3QgZGVjaW1hbF9jb3VudCA9IChjbGVhbmVkLm1hdGNoKC9cXC4vZykgfHwgW10pLmxlbmd0aDtcbiAgICAgICAgaWYgKGRlY2ltYWxfY291bnQgPiAxKSB7XG4gICAgICAgICAgICAvLyBLZWVwIG9ubHkgZmlyc3QgZGVjaW1hbCBwb2ludFxuICAgICAgICAgICAgY29uc3QgZmlyc3RfZGVjaW1hbCA9IGNsZWFuZWQuaW5kZXhPZignLicpO1xuICAgICAgICAgICAgY2xlYW5lZCA9IGNsZWFuZWQuc3Vic3RyKDAsIGZpcnN0X2RlY2ltYWwgKyAxKSArIGNsZWFuZWQuc3Vic3RyKGZpcnN0X2RlY2ltYWwgKyAxKS5yZXBsYWNlKC9cXC4vZywgJycpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNsZWFuZWQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogdmFsKCkgLSBHZXQgb3Igc2V0IHRoZSBjdXJyZW5jeSB2YWx1ZVxuICAgICAqIEdldHRlciByZXR1cm5zIG51bWVyaWMgc3RyaW5nIChubyBjb21tYXMsIG5vIHN5bWJvbClcbiAgICAgKiBTZXR0ZXIgYWNjZXB0cyBhbnl0aGluZyBhbmQgZm9ybWF0cyB3aXRoIGNvbW1hcy9zeW1ib2xcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW3ZhbHVlXVxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9XG4gICAgICovXG4gICAgdmFsKHZhbHVlKSB7XG4gICAgICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAvLyBHZXR0ZXIgLSByZXR1cm4gbnVtZXJpYyB2YWx1ZSBvbmx5XG4gICAgICAgICAgICBjb25zdCByYXcgPSB0aGlzLiRpZCgnaW5wdXQnKS52YWwoKTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9nZXRfbnVtZXJpY192YWx1ZShyYXcpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gU2V0dGVyIC0gZm9ybWF0IGFuZCBkaXNwbGF5XG4gICAgICAgICAgICBpZiAoIXZhbHVlKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5kYXRhLnZhbHVlID0gJyc7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuJGlkKCdpbnB1dCcpLmV4aXN0cygpKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuJGlkKCdpbnB1dCcpLnZhbCgnJyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gQ2xlYW4gdGhlIGlucHV0IHZhbHVlXG4gICAgICAgICAgICBjb25zdCBudW1lcmljID0gdGhpcy5fZ2V0X251bWVyaWNfdmFsdWUoc3RyKHZhbHVlKSk7XG4gICAgICAgICAgICBjb25zdCBmb3JtYXR0ZWQgPSB0aGlzLl9mb3JtYXRfY3VycmVuY3kobnVtZXJpYyk7XG5cbiAgICAgICAgICAgIHRoaXMuZGF0YS52YWx1ZSA9IGZvcm1hdHRlZDtcbiAgICAgICAgICAgIGlmICh0aGlzLiRpZCgnaW5wdXQnKS5leGlzdHMoKSkge1xuICAgICAgICAgICAgICAgIHRoaXMuJGlkKCdpbnB1dCcpLnZhbChmb3JtYXR0ZWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgb25fcmVhZHkoKSB7XG4gICAgICAgIHN1cGVyLm9uX3JlYWR5KCk7XG5cbiAgICAgICAgY29uc3QgJGlucHV0ID0gdGhpcy4kaWQoJ2lucHV0Jyk7XG5cbiAgICAgICAgLy8gSGFuZGxlIGtleWRvd24gdG8gaW50ZXJjZXB0IGJhY2tzcGFjZSBhdCBlbmQgb2Ygc3RyaW5nXG4gICAgICAgICRpbnB1dC5vbigna2V5ZG93bicsIChlKSA9PiB7XG4gICAgICAgICAgICBjb25zdCByYXcgPSAkaW5wdXQudmFsKCk7XG5cbiAgICAgICAgICAgIC8vIE9ubHkgaGFuZGxlIGJhY2tzcGFjZSBrZXlcbiAgICAgICAgICAgIGlmIChlLmtleSAhPT0gJ0JhY2tzcGFjZScpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnN0IGlucHV0X2VsZW1lbnQgPSAkaW5wdXRbMF07XG4gICAgICAgICAgICBjb25zdCBjdXJzb3JfcG9zID0gaW5wdXRfZWxlbWVudC5zZWxlY3Rpb25TdGFydDtcbiAgICAgICAgICAgIGNvbnN0IGN1cnNvcl9lbmQgPSBpbnB1dF9lbGVtZW50LnNlbGVjdGlvbkVuZDtcbiAgICAgICAgICAgIGNvbnN0IHZhbHVlX2xlbmd0aCA9IHJhdy5sZW5ndGg7XG5cbiAgICAgICAgICAgIC8vIE9ubHkgaGFuZGxlIGlmIGN1cnNvciBpcyBhdCB0aGUgZW5kIGFuZCBubyBzZWxlY3Rpb25cbiAgICAgICAgICAgIGlmIChjdXJzb3JfcG9zID09PSB2YWx1ZV9sZW5ndGggJiYgY3Vyc29yX3BvcyA9PT0gY3Vyc29yX2VuZCkge1xuICAgICAgICAgICAgICAgIC8vIENoZWNrIGlmIGNoYXJhY3RlciBiZWZvcmUgY3Vyc29yIGlzIG5vbi1udW1lcmljXG4gICAgICAgICAgICAgICAgaWYgKGN1cnNvcl9wb3MgPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGNoYXJfYmVmb3JlID0gcmF3LmNoYXJBdChjdXJzb3JfcG9zIC0gMSk7XG4gICAgICAgICAgICAgICAgICAgIGlmICghL1swLTldLy50ZXN0KGNoYXJfYmVmb3JlKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gQ2hhcmFjdGVyIGJlZm9yZSBjdXJzb3IgaXMgbm90IGEgZGlnaXRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIERlbGV0ZSB0aGUgbGFzdCBkaWdpdCBpbnN0ZWFkXG4gICAgICAgICAgICAgICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IG51bWVyaWMgPSB0aGlzLl9nZXRfbnVtZXJpY192YWx1ZShyYXcpO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG51bWVyaWMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFJlbW92ZSBsYXN0IGNoYXJhY3RlciBmcm9tIG51bWVyaWMgdmFsdWVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBuZXdfbnVtZXJpYyA9IG51bWVyaWMuc3Vic3RyKDAsIG51bWVyaWMubGVuZ3RoIC0gMSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZm9ybWF0dGVkID0gdGhpcy5fZm9ybWF0X2N1cnJlbmN5KG5ld19udW1lcmljKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkaW5wdXQudmFsKGZvcm1hdHRlZCk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBQbGFjZSBjdXJzb3IgYXQgZW5kXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IG5ld19sZW5ndGggPSAkaW5wdXQudmFsKCkubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnB1dF9lbGVtZW50LnNldFNlbGVjdGlvblJhbmdlKG5ld19sZW5ndGgsIG5ld19sZW5ndGgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sIDApO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBIYW5kbGUgaW5wdXQgZXZlbnQgZm9yIGxpdmUgZm9ybWF0dGluZ1xuICAgICAgICAkaW5wdXQub24oJ2lucHV0JywgKCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgcmF3ID0gJGlucHV0LnZhbCgpO1xuICAgICAgICAgICAgY29uc3QgaW5wdXRfZWxlbWVudCA9ICRpbnB1dFswXTtcbiAgICAgICAgICAgIGNvbnN0IGN1cnNvcl9wb3MgPSBpbnB1dF9lbGVtZW50LnNlbGVjdGlvblN0YXJ0O1xuICAgICAgICAgICAgY29uc3QgdmFsdWVfbGVuZ3RoID0gcmF3Lmxlbmd0aDtcblxuICAgICAgICAgICAgLy8gT25seSBhcHBseSBsaXZlIGZvcm1hdHRpbmcgaWYgY3Vyc29yIGlzIGF0IHRoZSBlbmRcbiAgICAgICAgICAgIGlmIChjdXJzb3JfcG9zID09PSB2YWx1ZV9sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAvLyBFeHRyYWN0IG51bWVyaWMgdmFsdWVcbiAgICAgICAgICAgICAgICBsZXQgbnVtZXJpYyA9IHRoaXMuX2dldF9udW1lcmljX3ZhbHVlKHJhdyk7XG5cbiAgICAgICAgICAgICAgICAvLyBMaW1pdCBkZWNpbWFsIHBsYWNlcyB0byAyIGlmIGRlY2ltYWxzIGFsbG93ZWRcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5hcmdzLmFsbG93X2RlY2ltYWxzKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHBhcnRzID0gbnVtZXJpYy5zcGxpdCgnLicpO1xuICAgICAgICAgICAgICAgICAgICBpZiAocGFydHNbMV0gJiYgcGFydHNbMV0ubGVuZ3RoID4gMikge1xuICAgICAgICAgICAgICAgICAgICAgICAgbnVtZXJpYyA9IHBhcnRzWzBdICsgJy4nICsgcGFydHNbMV0uc3Vic3RyKDAsIDIpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gRm9ybWF0IHRoZSBudW1lcmljIHZhbHVlXG4gICAgICAgICAgICAgICAgY29uc3QgZm9ybWF0dGVkID0gdGhpcy5fZm9ybWF0X2N1cnJlbmN5KG51bWVyaWMpO1xuICAgICAgICAgICAgICAgICRpbnB1dC52YWwoZm9ybWF0dGVkKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gQ3Vyc29yIGlzIG5vdCBhdCBlbmQgLSB1c2VyIGlzIGVkaXRpbmcgaW4gdGhlIG1pZGRsZVxuICAgICAgICAgICAgICAgIC8vIERvbid0IGZvcm1hdCwganVzdCBjbGVhbiBpbnZhbGlkIGNoYXJhY3RlcnNcbiAgICAgICAgICAgICAgICBjb25zdCBudW1lcmljID0gdGhpcy5fZ2V0X251bWVyaWNfdmFsdWUocmF3KTtcblxuICAgICAgICAgICAgICAgIC8vIE9ubHkgdXBkYXRlIGlmIHdlIHJlbW92ZWQgaW52YWxpZCBjaGFyYWN0ZXJzXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuX2Zvcm1hdF9jdXJyZW5jeShudW1lcmljKSAhPT0gcmF3KSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFByZXNlcnZlIGp1c3QgdGhlIG51bWVyaWMgY2hhcmFjdGVyc1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBzeW1ib2xfb2Zmc2V0ID0gdGhpcy5hcmdzLnNob3dfc3ltYm9sID8gdGhpcy5hcmdzLmN1cnJlbmN5X3N5bWJvbC5sZW5ndGggOiAwO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBjbGVhbmVkID0gKHRoaXMuYXJncy5zaG93X3N5bWJvbCA/IHRoaXMuYXJncy5jdXJyZW5jeV9zeW1ib2wgOiAnJykgKyBudW1lcmljO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmIChjbGVhbmVkICE9PSByYXcpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICRpbnB1dC52YWwoY2xlYW5lZCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBSZXN0b3JlIGN1cnNvciBwb3NpdGlvbiAoYXBwcm94aW1hdGVseSlcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IG5ld19jdXJzb3IgPSBNYXRoLm1pbihjdXJzb3JfcG9zLCBjbGVhbmVkLmxlbmd0aCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpbnB1dF9lbGVtZW50LnNldFNlbGVjdGlvblJhbmdlKG5ld19jdXJzb3IsIG5ld19jdXJzb3IpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBIYW5kbGUgYmx1ciB0byByZWZvcm1hdCB3aGVuIGRvbmUgZWRpdGluZ1xuICAgICAgICAkaW5wdXQub24oJ2JsdXInLCAoKSA9PiB7XG4gICAgICAgICAgICBjb25zdCByYXcgPSAkaW5wdXQudmFsKCk7XG5cbiAgICAgICAgICAgIGlmICghcmF3KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBSZWZvcm1hdCB0aGUgZW50aXJlIHZhbHVlIG9uIGJsdXJcbiAgICAgICAgICAgIGNvbnN0IG51bWVyaWMgPSB0aGlzLl9nZXRfbnVtZXJpY192YWx1ZShyYXcpO1xuICAgICAgICAgICAgY29uc3QgZm9ybWF0dGVkID0gdGhpcy5fZm9ybWF0X2N1cnJlbmN5KG51bWVyaWMpO1xuICAgICAgICAgICAgJGlucHV0LnZhbChmb3JtYXR0ZWQpO1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBIYW5kbGUgZm9jdXMgdG8gc2VsZWN0IGFsbCBmb3IgZWFzeSByZXBsYWNlbWVudFxuICAgICAgICAkaW5wdXQub24oJ2ZvY3VzJywgKCkgPT4ge1xuICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgJGlucHV0WzBdLnNlbGVjdCgpO1xuICAgICAgICAgICAgfSwgMCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIEluaXRpYWxpemUgZm9ybWF0dGluZyBpZiB0aGVyZSdzIGEgdmFsdWVcbiAgICAgICAgY29uc3QgaW5pdGlhbF92YWx1ZSA9ICRpbnB1dC52YWwoKTtcbiAgICAgICAgaWYgKGluaXRpYWxfdmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudmFsKGluaXRpYWxfdmFsdWUpO1xuICAgICAgICB9XG4gICAgfVxufVxuIl0sIm1hcHBpbmdzIjoiOztBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTUEsY0FBYyxTQUFTQyxVQUFVLENBQUM7RUFDcENDLFNBQVNBLENBQUEsRUFBRztJQUNSLEtBQUssQ0FBQ0EsU0FBUyxDQUFDLENBQUM7O0lBRWpCO0lBQ0EsSUFBSSxJQUFJLENBQUNDLElBQUksQ0FBQ0MsY0FBYyxLQUFLQyxTQUFTLEVBQUU7TUFDeEMsSUFBSSxDQUFDRixJQUFJLENBQUNDLGNBQWMsR0FBRyxLQUFLO0lBQ3BDO0lBQ0EsSUFBSSxJQUFJLENBQUNELElBQUksQ0FBQ0csV0FBVyxLQUFLRCxTQUFTLEVBQUU7TUFDckMsSUFBSSxDQUFDRixJQUFJLENBQUNHLFdBQVcsR0FBRyxLQUFLO0lBQ2pDO0lBQ0EsSUFBSSxJQUFJLENBQUNILElBQUksQ0FBQ0ksZUFBZSxLQUFLRixTQUFTLEVBQUU7TUFDekMsSUFBSSxDQUFDRixJQUFJLENBQUNJLGVBQWUsR0FBRyxHQUFHO0lBQ25DO0VBQ0o7O0VBRUE7QUFDSjtBQUNBO0FBQ0E7QUFDQTtFQUNJQyxnQkFBZ0JBLENBQUNDLEtBQUssRUFBRTtJQUNwQixJQUFJLENBQUNBLEtBQUssRUFBRTtNQUNSLE9BQU8sRUFBRTtJQUNiOztJQUVBO0lBQ0EsSUFBSUMsS0FBSyxHQUFHRCxLQUFLLENBQUNFLEtBQUssQ0FBQyxHQUFHLENBQUM7SUFD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
|