unitspan
Version:
Create differential spans for units of measurement, including time measurements, digital (binary) measurements, and more.
727 lines (724 loc) • 81.6 kB
JavaScript
// src/unitspan.js
var UnitSpan = class {
/**
* An object with values of numbers or functions. At least one property should map to the value of `1` and that property should
* be the base unit of measurement in this class (i.o.w., `__baseUnitValue` should store this unit of measurement.)
* @type {T}
*/
#converter;
/**
* An object with the same keys as the `converter` object, but with values being objects holding
* configurations for how the formatted strings should be handled.
* @type {{[K in keyof T]: { padStart: number }}}
*/
#formatter;
/** @type {number} */
#precision;
/**
* Stored value of units, this should always be in one type of unit.
*
* For example, in the `TempSpan` class, this value will always be measured in units of `Kelvin`.
* @protected
* @type {number}
*/
__baseUnitValue;
/**
* @protected
* @param {number} quantity
* @param {T} converter
* @param {{[K in keyof T]: { padStart: number }}} formatter
* @param {number} precision
*/
constructor(quantity, converter, formatter, precision = 5) {
this.#converter = converter;
this.#formatter = formatter;
this.#precision = 10 ** precision;
this.__baseUnitValue = quantity;
}
/**
* @param {(obj: {[K in keyof T]: (quantity: number) => void}) => void} callback
* @returns {this}
*/
add(callback) {
const clone = this.#clone();
const t = new Proxy(
/** @type {any} */
{ ...clone.#converter },
{
get: (t2, p, r) => {
if (typeof p !== "string") {
throw new Error(`Property "${String(p)}" is not of type string.`);
}
return (quantity) => {
const converter = clone.#converter[p];
if (Array.isArray(converter)) {
const [convertToBaseUnits, convertFromBaseUnits] = converter;
clone.__baseUnitValue = convertToBaseUnits(convertFromBaseUnits(clone.__baseUnitValue) + quantity);
} else if (typeof converter === "number") {
clone.__baseUnitValue += quantity / converter;
}
};
}
}
);
callback(t);
return (
/** @type {any} */
clone
);
}
/**
* @param {(obj: {[K in keyof T]: (quantity: number) => void}) => void} callback
* @returns {this}
*/
sub(callback) {
const clone = this.#clone();
const t = new Proxy(
/** @type {any} */
{ ...clone.#converter },
{
get: (t2, p, r) => {
if (typeof p !== "string") {
throw new Error(`Property "${String(p)}" is not of type string.`);
}
return (quantity) => {
const converter = clone.#converter[p];
if (Array.isArray(converter)) {
const [convertToBaseUnits, convertFromBaseUnits] = converter;
console.log(p, clone.__baseUnitValue, convertToBaseUnits(quantity));
clone.__baseUnitValue = convertToBaseUnits(convertFromBaseUnits(clone.__baseUnitValue) - quantity);
} else if (typeof converter === "number") {
clone.__baseUnitValue -= quantity / converter;
}
};
}
}
);
callback(t);
return (
/** @type {any} */
clone
);
}
/**
* @overload Overload 1
* @param {(model: PropertyRetriever<T>) => keyof T} callback
* Callback used to get the type of conversion (or otherwise, the key of conversion) to use when converting.
* @returns {number}
* The converted number from the unit quantity held by this UnitSpan class object.
*
* @overload
* @param {(model: PropertyRetriever<T>) => string} callback
* Callback used to get the type of conversion (or otherwise, the key of conversion) to use when converting.
* @returns {string}
* The converted number from the unit quantity held by this UnitSpan class object.
*
* @overload
* @param {keyof T} key
* Some string property of the conversion object to use when converting.
* @returns {number}
*
* @overload
* @param {string} key
* @returns {string}
* The converted number from the unit quantity held by this UnitSpan class object.
*
* Get the conversion of units as specified from the property reference (and return value) from the `model` parameter used in `callback`.
* @param {((model: PropertyRetriever<T>) => keyof T|string)|keyof T|string} callback
* @returns {string|number}
*/
to(callback) {
let val = 0;
if (typeof callback === "function") {
const t = new Proxy(
/** @type {any} */
{ ...this.#converter },
{
get: (t2, p, r) => {
return `{{${String(p)}}}`;
}
}
);
let keyOrString = callback(t);
if (typeof keyOrString !== "string") {
throw new Error(`Expected a string, but got "${typeof keyOrString}".`);
}
const replacedKeyOrString = keyOrString.replace(/\{\{([^\{\}]*)\}\}/, "$1");
if (replacedKeyOrString in this.#converter) {
return handleOverload1_3.bind(this)(replacedKeyOrString);
} else {
return handleOverload2_4.bind(this)(keyOrString);
}
} else {
if (typeof callback !== "string") {
callback = String(callback);
}
if (callback in this.#converter) {
return handleOverload1_3.bind(this)(callback);
} else {
return handleOverload2_4.bind(this)(callback);
}
}
function handleOverload1_3(key) {
const converter = this.#converter[key];
if (Array.isArray(converter)) {
const [, convertFromBaseUnits] = converter;
const { decimal, fraction } = convertFromBaseUnits(this.__baseUnitValue);
val = decimal + Math.floor(fraction * this.#precision) / this.#precision;
} else if (typeof converter === "number") {
val = converter * this.__baseUnitValue;
}
return Math.round(val * this.#precision) / this.#precision;
}
function handleOverload2_4(formatString) {
const entries = Object.entries(this.#converter).sort(([k1, v1], [k2, v2]) => {
if (typeof v1 === "number" && typeof v2 === "number") {
return v1 - v2;
}
if (typeof v1 !== "number") {
const [, convertFromBaseUnits] = v1;
const { decimal, fraction, remainder } = convertFromBaseUnits(this.__baseUnitValue);
v1 = decimal + Math.floor(fraction * this.#precision) / this.#precision;
}
if (typeof v2 !== "number") {
const [, convertFromBaseUnits] = v2;
const { decimal, fraction, remainder } = convertFromBaseUnits(this.__baseUnitValue);
v2 = decimal + Math.floor(fraction * this.#precision) / this.#precision;
}
return v2 - v1;
});
let currentBaseUnitValue = this.__baseUnitValue;
for (const [key, converter] of entries) {
if (!formatString.includes(key)) {
continue;
}
if (Array.isArray(converter)) {
const [, convertFromBaseUnits] = converter;
const { decimal, remainder } = convertFromBaseUnits(currentBaseUnitValue);
formatString = formatString.replaceAll(`{{${key}}}`, Math.floor(decimal).toString().padStart(this.#formatter[key].padStart, "0"));
currentBaseUnitValue = remainder;
} else if (typeof converter === "number") {
let val2 = converter * currentBaseUnitValue;
if (Number.isInteger(val2)) {
currentBaseUnitValue = 0;
} else {
if (Math.floor(val2) === 0) {
val2 = 0;
} else {
const frac = val2 - Math.floor(val2);
const remainder = Math.floor(frac * this.#precision) / this.#precision;
currentBaseUnitValue = remainder / val2 * currentBaseUnitValue;
val2 = Math.floor(val2);
}
}
formatString = formatString.replaceAll(`{{${key}}}`, val2.toString().padStart(this.#formatter[key].padStart, "0"));
}
}
return formatString;
}
}
/**
* Set the precision of the resulting conversions.
* @param {number} numDigits
* @returns {this}
*/
precision(numDigits) {
const clone = this.#clone();
clone.#precision = 10 ** numDigits;
return (
/** @type {any} */
clone
);
}
/**
*
*/
#clone() {
const clone = new /** @type {any} */
this.constructor(this.#converter);
clone.__baseUnitValue = this.__baseUnitValue;
return clone;
}
};
// src/digi.js
var DigiSpan = class _DigiSpan extends UnitSpan {
/**
* @param {number} numBits
*/
static fromBits(numBits) {
return new _DigiSpan(numBits);
}
/**
* @param {number} numBytes
*/
static fromBytes(numBytes) {
return new _DigiSpan(numBytes / DigitalSpanUnitsConverter.Bytes);
}
/**
* @param {number} numKibiBytes
*/
static fromKibiBytes(numKibiBytes) {
return new _DigiSpan(numKibiBytes / DigitalSpanUnitsConverter.Kibibytes);
}
/**
* @param {number} numMebiBytes
*/
static fromMebiBytes(numMebiBytes) {
return new _DigiSpan(numMebiBytes / DigitalSpanUnitsConverter.Mebibytes);
}
/**
* @param {number} numGibiBytes
*/
static fromGibiBytes(numGibiBytes) {
return new _DigiSpan(numGibiBytes / DigitalSpanUnitsConverter.Gibibytes);
}
/**
* @param {number} numTebiBytes
*/
static fromTebibytes(numTebiBytes) {
return new _DigiSpan(numTebiBytes / DigitalSpanUnitsConverter.Tebibytes);
}
/**
* @param {number} numKiloBytes
*/
static fromKiloBytes(numKiloBytes) {
return new _DigiSpan(numKiloBytes / DigitalSpanUnitsConverter.Kilobytes);
}
/**
* @param {number} numMegaBytes
*/
static fromMegaBytes(numMegaBytes) {
return new _DigiSpan(numMegaBytes / DigitalSpanUnitsConverter.Megabytes);
}
/**
* @param {number} numGigaBytes
*/
static fromGigaBytes(numGigaBytes) {
return new _DigiSpan(numGigaBytes / DigitalSpanUnitsConverter.Gigabytes);
}
/**
* @param {number} numTeraBytes
*/
static fromTeraBytes(numTeraBytes) {
return new _DigiSpan(numTeraBytes / DigitalSpanUnitsConverter.Terabytes);
}
/**
*
* @param {Uint8Array|Buffer} buffer
*/
static fromBuffer(buffer) {
return new _DigiSpan(buffer.byteLength / DigitalSpanUnitsConverter.Bytes);
}
/**
* @param {number} quantity
* @protected
*/
constructor(quantity) {
super(
quantity,
DigitalSpanUnitsConverter,
DigitalSpanUnitsFormatter
);
}
buffer() {
return new Uint8Array(Math.ceil(this.to((m) => m.Bytes)));
}
};
var DigitalSpanUnitsConverter = Object.freeze({
Bits: 1,
Bytes: 1 / 8,
Kibibytes: 1 / 1024 / 8,
Mebibytes: 1 / 1024 / 1024 / 8,
Gibibytes: 1 / 1024 / 1024 / 1024 / 8,
Tebibytes: 1 / 1024 / 1024 / 1024 / 1024 / 8,
Kilobytes: 1 / 1e3 / 8,
Megabytes: 1 / 1e3 / 1e3 / 8,
Gigabytes: 1 / 1e3 / 1e3 / 1e3 / 8,
Terabytes: 1 / 1e3 / 1e3 / 1e3 / 1e3 / 8
});
var DigitalSpanUnitsFormatter = Object.freeze({
Bits: {
padStart: 1
},
Bytes: {
padStart: 1
},
Kibibytes: {
padStart: 1
},
Mebibytes: {
padStart: 1
},
Gibibytes: {
padStart: 1
},
Tebibytes: {
padStart: 1
},
Kilobytes: {
padStart: 1
},
Megabytes: {
padStart: 1
},
Gigabytes: {
padStart: 1
},
Terabytes: {
padStart: 1
}
});
// src/time.js
var TimeSpan = class _TimeSpan extends UnitSpan {
/**
* Create a differential time span between two dates, `date1` and `date2`.
* @param {Date} date1
* Start date
* @param {Date} date2
* End date
* @returns {TimeSpan}
* New {@link TimeSpan} class object that can convert between other units of measurement per {@link TimeSpanUnitsConverter}
*/
static between(date1, date2) {
return new _TimeSpan((date1.getTime() - date2.getTime()) / TimeSpanUnitsConverter.Milliseconds);
}
/**
* Create a differential time span between `January 1st, 1970 00:00:00 UTC` and now.
* @returns {TimeSpan}
* New {@link TimeSpan} class object that can convert between other units of measurement per {@link TimeSpanUnitsConverter}
*/
static sinceEpoch() {
return new _TimeSpan(Date.now() / TimeSpanUnitsConverter.Milliseconds);
}
/**
* Create a differential time span between a given date, `date`, and now.
* @param {Date} date
* Date to differentiate between now.
* @returns {TimeSpan}
* New {@link TimeSpan} class object that can convert between other units of measurement per {@link TimeSpanUnitsConverter}
*/
static since(date) {
const time = Date.now() - date.getTime();
return new _TimeSpan(time / TimeSpanUnitsConverter.Milliseconds);
}
/**
* Create a differential time span between now and a date in the future.
* @param {Date} date
* Date to differentiate between now. (This can be in the past, it will just have negative units)
* @returns {TimeSpan}
* New {@link TimeSpan} class object that can convert between other units of measurement per {@link TimeSpanUnitsConverter}
*/
static until(date) {
const time = date.getTime() - Date.now();
return new _TimeSpan(time / TimeSpanUnitsConverter.Milliseconds);
}
/**
* Create a TimeSpan class with the initial number of nanoseconds.
* @param {number} numNanoseconds
* Number of nanoseconds to initialize with.
* @returns {TimeSpan}
* New {@link TimeSpan} class object that can convert between other units of measurement per {@link TimeSpanUnitsConverter}
*/
static fromNanoseconds(numNanoseconds) {
return new _TimeSpan(numNanoseconds);
}
/**
* Create a TimeSpan class with the initial number of microseconds.
* @param {number} numMicroseconds
* Number of microseconds to initialize with.
* @returns {TimeSpan}
* New {@link TimeSpan} class object that can convert between other units of measurement per {@link TimeSpanUnitsConverter}
*/
static fromMicroseconds(numMicroseconds) {
return new _TimeSpan(numMicroseconds / TimeSpanUnitsConverter.Microseconds);
}
/**
* Create a TimeSpan class with the initial number of milliseconds.
* @param {number} numMilliseconds
* Number of milliseconds to initialize with.
* @returns {TimeSpan}
* New {@link TimeSpan} class object that can convert between other units of measurement per {@link TimeSpanUnitsConverter}
*/
static fromMilliseconds(numMilliseconds) {
return new _TimeSpan(numMilliseconds / TimeSpanUnitsConverter.Milliseconds);
}
/**
* Create a TimeSpan class with the initial number of seconds.
* @param {number} numSeconds
* Number of seconds to initialize with.
* @returns {TimeSpan}
* New {@link TimeSpan} class object that can convert between other units of measurement per {@link TimeSpanUnitsConverter}
*/
static fromSeconds(numSeconds) {
return new _TimeSpan(numSeconds / TimeSpanUnitsConverter.Seconds);
}
/**
* Create a TimeSpan class with the initial number of minutes.
* @param {number} numMinutes
* Number of minutes to initialize with.
* @returns {TimeSpan}
* New {@link TimeSpan} class object that can convert between other units of measurement per {@link TimeSpanUnitsConverter}
*/
static fromMinutes(numMinutes) {
return new _TimeSpan(numMinutes / TimeSpanUnitsConverter.Minutes);
}
/**
* Create a TimeSpan class with the initial number of hours.
* @param {number} numHours
* Number of hours to initialize with.
* @returns {TimeSpan}
* New {@link TimeSpan} class object that can convert between other units of measurement per {@link TimeSpanUnitsConverter}
*/
static fromHours(numHours) {
return new _TimeSpan(numHours / TimeSpanUnitsConverter.Hours);
}
/**
* Create a TimeSpan class with the initial number of days.
* @param {number} numDays
* Number of days to initialize with.
* @returns {TimeSpan}
* New {@link TimeSpan} class object that can convert between other units of measurement per {@link TimeSpanUnitsConverter}
*/
static fromDays(numDays) {
return new _TimeSpan(numDays / TimeSpanUnitsConverter.Days);
}
/**
* Create a TimeSpan class with the initial number of weeks.
* @param {number} numWeeks
* Number of weeks to initialize with.
* @returns {TimeSpan}
* New {@link TimeSpan} class object that can convert between other units of measurement per {@link TimeSpanUnitsConverter}
*/
static fromWeeks(numWeeks) {
return new _TimeSpan(numWeeks / TimeSpanUnitsConverter.Weeks);
}
/**
* Create a TimeSpan class with the initial number of months.
* @param {number} numMonths
* Number of months to initialize with.
* @returns {TimeSpan}
* New {@link TimeSpan} class object that can convert between other units of measurement per {@link TimeSpanUnitsConverter}
*/
static fromMonths(numMonths) {
return new _TimeSpan(numMonths / TimeSpanUnitsConverter.Months);
}
/**
* @protected
* @param {number} quantity
*/
constructor(quantity) {
super(
quantity,
TimeSpanUnitsConverter,
TimeSpanUnitsFormatter
);
}
/**
* Create a timeout where `callback` is ran only after the time that this TimeSpan object holds has passed.
* @usage
* ```js
* TimeSpan.fromSeconds(10).timeout(() => {
* console.log(`This will only print after 10 seconds`);
* });
* ```
* @param {() => void|Promise<void>} callback
* Function
* @returns {TimeoutController}
* Object with `clear` and `refresh` functions to control the timeout.
*
*/
timeout(callback) {
let timeout = setTimeout(callback, Math.floor(this.to((m) => m.Milliseconds)));
const timeoutController = {
cancel: () => {
clearTimeout(timeout);
},
refresh: () => {
clearTimeout(timeout);
timeout = setTimeout(callback, Math.floor(this.to((m) => m.Milliseconds)));
return timeoutController;
}
};
return timeoutController;
}
/**
* Create an interval where `callback` is ran for every time after the time that this TimeSpan object holds has passed.
* @usage
* ```js
* let i = 0;
* const unsubscribe = TimeSpan.fromSeconds(10).interval(() => {
* console.log(`Printing ${i}/3`);
* if(++i === 3) {
* unsubscribe();
* }
* });
*
* // will print each line every 10 seconds:
* // Printing 1/3
* // Printing 2/3
* // Printing 3/3
* ```
* @param {() => void|Promise<void>} callback
* @returns {IntervalController} Function to unsubscribe from the interval.
*/
interval(callback) {
let interval = setInterval(callback, Math.floor(this.to((m) => m.Milliseconds)));
const intervalController = {
cancel: () => {
clearInterval(interval);
interval = void 0;
},
start: () => {
if (interval) {
clearInterval(interval);
}
interval = setInterval(callback, Math.floor(this.to((m) => m.Milliseconds)));
return intervalController;
},
get isStarted() {
return interval !== void 0;
},
get isStopped() {
return interval === void 0;
}
};
return intervalController;
}
/**
* Create a Promise that will only resolve after the time that this TimeSpan object holds has passed.
* @returns {Promise<void>}
*/
delay() {
return new Promise((resolve) => this.timeout(resolve));
}
toYears() {
return this.to((m) => m.Years);
}
toMonths() {
return this.to((m) => m.Months);
}
toWeeks() {
return this.to((m) => m.Weeks);
}
toDays() {
return this.to((m) => m.Days);
}
toHours() {
return this.to((m) => m.Hours);
}
toMinutes() {
return this.to((m) => m.Minutes);
}
toSeconds() {
return this.to((m) => m.Seconds);
}
toMilliseconds() {
return this.to((m) => m.Milliseconds);
}
toMicroseconds() {
return this.to((m) => m.Microseconds);
}
toNanoseconds() {
return this.to((m) => m.Nanoseconds);
}
toString() {
return this.to((m) => `${m.hours}:${m.minutes}:${m.seconds}.${m.milliseconds}`);
}
};
var TimeSpanUnitsConverter = Object.freeze({
/** @deprecated */
Nanoseconds: 1,
/** @deprecated */
Microseconds: 1 / 1e3,
/** @deprecated */
Milliseconds: 1 / 1e3 / 1e3,
/** @deprecated */
Seconds: 1 / 1e3 / 1e3 / 1e3,
/** @deprecated */
Minutes: 1 / 60 / 1e3 / 1e3 / 1e3,
/** @deprecated */
Hours: 1 / 60 / 60 / 1e3 / 1e3 / 1e3,
/** @deprecated */
Days: 1 / 24 / 60 / 60 / 1e3 / 1e3 / 1e3,
/** @deprecated */
Weeks: 1 / 7 / 24 / 60 / 60 / 1e3 / 1e3 / 1e3,
/** @deprecated */
Months: 1 / 30.437 / 24 / 60 / 60 / 1e3 / 1e3 / 1e3,
/** @deprecated */
Years: 1 / 365.2425 / 24 / 60 / 60 / 1e3 / 1e3 / 1e3,
nanoseconds: 1,
microseconds: 1 / 1e3,
milliseconds: 1 / 1e3 / 1e3,
seconds: 1 / 1e3 / 1e3 / 1e3,
minutes: 1 / 60 / 1e3 / 1e3 / 1e3,
hours: 1 / 60 / 60 / 1e3 / 1e3 / 1e3,
days: 1 / 24 / 60 / 60 / 1e3 / 1e3 / 1e3,
weeks: 1 / 7 / 24 / 60 / 60 / 1e3 / 1e3 / 1e3,
months: 1 / 30.437 / 24 / 60 / 60 / 1e3 / 1e3 / 1e3,
years: 1 / 365.2425 / 24 / 60 / 60 / 1e3 / 1e3 / 1e3
});
var TimeSpanUnitsFormatter = {
Nanoseconds: {
padStart: 3
},
Microseconds: {
padStart: 3
},
Milliseconds: {
padStart: 3
},
Seconds: {
padStart: 2
},
Minutes: {
padStart: 2
},
Hours: {
padStart: 2
},
Days: {
padStart: 2
},
Weeks: {
padStart: 2
},
Months: {
padStart: 2
},
Years: {
padStart: 0
},
nanoseconds: {
padStart: 3
},
microseconds: {
padStart: 3
},
milliseconds: {
padStart: 3
},
seconds: {
padStart: 2
},
minutes: {
padStart: 2
},
hours: {
padStart: 2
},
days: {
padStart: 2
},
weeks: {
padStart: 2
},
months: {
padStart: 2
},
years: {
padStart: 0
}
};
export { DigiSpan, TimeSpan };
//# sourceMappingURL=index.js.map
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy91bml0c3Bhbi5qcyIsIi4uL3NyYy9kaWdpLmpzIiwiLi4vc3JjL3RpbWUuanMiXSwibmFtZXMiOlsidCIsInZhbCJdLCJtYXBwaW5ncyI6IjtBQU9PLElBQU0sV0FBTixNQUFlO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLEVBTWxCLFVBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsRUFNQSxVQUFBO0FBQUE7QUFBQSxFQUVBLFVBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLEVBUUEsZUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsRUFTQSxXQUFZLENBQUEsUUFBQSxFQUFVLFNBQVcsRUFBQSxTQUFBLEVBQVcsWUFBVSxDQUFHLEVBQUE7QUFDckQsSUFBQSxJQUFBLENBQUssVUFBYSxHQUFBLFNBQUE7QUFDbEIsSUFBQSxJQUFBLENBQUssVUFBYSxHQUFBLFNBQUE7QUFDbEIsSUFBQSxJQUFBLENBQUssYUFBYSxFQUFNLElBQUEsU0FBQTtBQUN4QixJQUFBLElBQUEsQ0FBSyxlQUFrQixHQUFBLFFBQUE7QUFBQTtBQUMzQjtBQUFBO0FBQUE7QUFBQTtBQUFBLEVBTUEsSUFBSSxRQUFVLEVBQUE7QUFDVixJQUFNLE1BQUEsS0FBQSxHQUFRLEtBQUssTUFBTyxFQUFBO0FBQzFCLElBQUEsTUFBTSxJQUFJLElBQUksS0FBQTtBQUFBO0FBQUEsTUFBeUIsRUFBQyxHQUFHLEtBQUEsQ0FBTSxVQUFVLEVBQUE7QUFBQSxNQUFJO0FBQUEsUUFDM0QsR0FBSyxFQUFBLENBQUNBLEVBQUUsRUFBQSxDQUFBLEVBQUUsQ0FBTSxLQUFBO0FBQ1osVUFBRyxJQUFBLE9BQU8sTUFBTSxRQUFVLEVBQUE7QUFDdEIsWUFBQSxNQUFNLElBQUksS0FBTSxDQUFBLENBQUEsVUFBQSxFQUFhLE1BQU8sQ0FBQSxDQUFDLENBQUMsQ0FBMEIsd0JBQUEsQ0FBQSxDQUFBO0FBQUE7QUFF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QUFBQSxFQUNBLE9BQVMsRUFBQTtBQUFBLElBQ0wsUUFBVSxFQUFBO0FBQUEsR0FDZDtBQUFBLEVBQ0EsS0FBTyxFQUFBO0FBQUEsSUFDSCxRQUFVLEVBQUE7QUFBQSxHQUNkO0FBQUEsRUFDQSxJQUFNLEVBQUE7QUFBQSxJQUNGLFFBQVUsRUFBQTtBQUFBLEdBQ2Q7QUFBQSxFQUNBLEtBQU8sRUFBQTtBQUFBLElBQ0gsUUFBVSxFQUFBO0FBQUEsR0FDZDtBQUFBLEVBQ0EsTUFBUSxFQUFBO0FBQUEsSUFDSixRQUFVLEVBQUE7QUFBQSxHQUNkO0FBQUEsRUFDQSxLQUFPLEVBQUE7QUFBQSxJQUNILFFBQVUsRUFBQTtBQUFBLEdBQ2Q7QUFBQSxFQUVBLFdBQWEsRUFBQTtBQUFBLElBQ1QsUUFBVSxFQUFBO0FBQUEsR0FDZDtBQUFBLEVBQ0EsWUFBYyxFQUFBO0FBQUEsSUFDVixRQUFVLEVBQUE7QUFBQSxHQUNkO0FBQUEsRUFDQSxZQUFjLEVBQUE7QUFBQSxJQUNWLFFBQVUsRUFBQTtBQUFBLEdBQ2Q7QUFBQSxFQUNBLE9BQVMsRUFBQTtBQUFBLElBQ0wsUUFBVSxFQUFBO0FBQUEsR0FDZDtBQUFBLEVBQ0EsT0FBUyxFQUFBO0FBQUEsSUFDTCxRQUFVLEVBQUE7QUFBQSxHQUNkO0FBQUEsRUFDQSxLQUFPLEVBQUE7QUFBQSxJQUNILFFBQVUsRUFBQTtBQUFBLEdBQ2Q7QUFBQSxFQUNBLElBQU0sRUFBQTtBQUFBLElBQ0YsUUFBVSxFQUFBO0FBQUEsR0FDZDtBQUFBLEVBQ0EsS0FBTyxFQUFBO0FBQUEsSUFDSCxRQUFVLEVBQUE7QUFBQSxHQUNkO0FBQUEsRUFDQSxNQUFRLEVBQUE7QUFBQSxJQUNKLFFBQVUsRUFBQTtBQUFBLEdBQ2Q7QUFBQSxFQUNBLEtBQU8sRUFBQTtBQUFBLElBQ0gsUUFBVSxFQUFBO0FBQUE7QUFFbEIsQ0FBQSIsImZpbGUiOiJpbmRleC5qcyIsInNvdXJjZXNDb250ZW50IjpbIi8vQHRzLWNoZWNrXHJcblxyXG4vKiogQHR5cGVkZWYge1JlY29yZDxzdHJpbmcsIG51bWJlcnxbY29udmVydFRvQmFzZVVuaXQ6ICh1bml0czogbnVtYmVyKSA9PiBudW1iZXIsIGNvbnZlcnRGcm9tQmFzZVVuaXQ6IChiYXNlVW5pdHM6IG51bWJlcikgPT4geyBkZWNpbWFsOiBudW1iZXIsIHJlbWFpbmRlcjogbnVtYmVyLCBmcmFjdGlvbjogbnVtYmVyIH1dPn0gQ29udmVydGVyICovXHJcblxyXG4vKipcclxuICogQHRlbXBsYXRlIHtSZWNvcmQ8c3RyaW5nLCBudW1iZXJ8W2NvbnZlcnRUb0Jhc2VVbml0OiAodW5pdHM6IG51bWJlcikgPT4gbnVtYmVyLCBjb252ZXJ0RnJvbUJhc2VVbml0OiAoYmFzZVVuaXRzOiBudW1iZXIpID0+IHsgZGVjaW1hbDogbnVtYmVyLCByZW1haW5kZXI6IG51bWJlciwgZnJhY3Rpb246IG51bWJlciB9XT59IFRcclxuICovXHJcbmV4cG9ydCBjbGFzcyBVbml0U3BhbiB7XHJcbiAgICAvKiogXHJcbiAgICAgKiBBbiBvYmplY3Qgd2l0aCB2YWx1ZXMgb2YgbnVtYmVycyBvciBmdW5jdGlvbnMuIEF0IGxlYXN0IG9uZSBwcm9wZXJ0eSBzaG91bGQgbWFwIHRvIHRoZSB2YWx1ZSBvZiBgMWAgYW5kIHRoYXQgcHJvcGVydHkgc2hvdWxkXHJcbiAgICAgKiBiZSB0aGUgYmFzZSB1bml0IG9mIG1lYXN1cmVtZW50IGluIHRoaXMgY2xhc3MgKGkuby53LiwgYF9fYmFzZVVuaXRWYWx1ZWAgc2hvdWxkIHN0b3JlIHRoaXMgdW5pdCBvZiBtZWFzdXJlbWVudC4pICBcclxuICAgICAqIEB0eXBlIHtUfSBcclxuICAgICAqL1xyXG4gICAgI2NvbnZlcnRlcjtcclxuICAgIC8qKlxyXG4gICAgICogQW4gb2JqZWN0IHdpdGggdGhlIHNhbWUga2V5cyBhcyB0aGUgYGNvbnZlcnRlcmAgb2JqZWN0LCBidXQgd2l0aCB2YWx1ZXMgYmVpbmcgb2JqZWN0cyBob2xkaW5nXHJcbiAgICAgKiBjb25maWd1cmF0aW9ucyBmb3IgaG93IHRoZSBmb3JtYXR0ZWQgc3RyaW5ncyBzaG91bGQgYmUgaGFuZGxlZC5cclxuICAgICAqIEB0eXBlIHt7W0sgaW4ga2V5b2YgVF06IHsgcGFkU3RhcnQ6IG51bWJlciB9fX1cclxuICAgICAqL1xyXG4gICAgI2Zvcm1hdHRlcjtcclxuICAgIC8qKiBAdHlwZSB7bnVtYmVyfSAqL1xyXG4gICAgI3ByZWNpc2lvbjtcclxuICAgIC8qKiBcclxuICAgICAqIFN0b3JlZCB2YWx1ZSBvZiB1bml0cywgdGhpcyBzaG91bGQgYWx3YXlzIGJlIGluIG9uZSB0eXBlIG9mIHVuaXQuICBcclxuICAgICAqIFxyXG4gICAgICogRm9yIGV4YW1wbGUsIGluIHRoZSBgVGVtcFNwYW5gIGNsYXNzLCB0aGlzIHZhbHVlIHdpbGwgYWx3YXlzIGJlIG1lYXN1cmVkIGluIHVuaXRzIG9mIGBLZWx2aW5gLlxyXG4gICAgICogQHByb3RlY3RlZCBcclxuICAgICAqIEB0eXBlIHtudW1iZXJ9IFxyXG4gICAgICovXHJcbiAgICBfX2Jhc2VVbml0VmFsdWU7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBAcHJvdGVjdGVkXHJcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gcXVhbnRpdHlcclxuICAgICAqIEBwYXJhbSB7VH0gY29udmVydGVyIFxyXG4gICAgICogQHBhcmFtIHt7W0sgaW4ga2V5b2YgVF06IHsgcGFkU3RhcnQ6IG51bWJlciB9fX0gZm9ybWF0dGVyXHJcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gcHJlY2lzaW9uXHJcbiAgICAgKi9cclxuICAgIGNvbnN0cnVjdG9yKHF1YW50aXR5LCBjb252ZXJ0ZXIsIGZvcm1hdHRlciwgcHJlY2lzaW9uPTUpIHtcclxuICAgICAgICB0aGlzLiNjb252ZXJ0ZXIgPSBjb252ZXJ0ZXI7XHJcbiAgICAgICAgdGhpcy4jZm9ybWF0dGVyID0gZm9ybWF0dGVyO1xyXG4gICAgICAgIHRoaXMuI3ByZWNpc2lvbiA9IDEwICoqIHByZWNpc2lvbjtcclxuICAgICAgICB0aGlzLl9fYmFzZVVuaXRWYWx1ZSA9IHF1YW50aXR5O1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogQHBhcmFtIHsob2JqOiB7W0sgaW4ga2V5b2YgVF06IChxdWFudGl0eTogbnVtYmVyKSA9PiB2b2lkfSkgPT4gdm9pZH0gY2FsbGJhY2tcclxuICAgICAqIEByZXR1cm5zIHt0aGlzfVxyXG4gICAgICovXHJcbiAgICBhZGQoY2FsbGJhY2spIHtcclxuICAgICAgICBjb25zdCBjbG9uZSA9IHRoaXMuI2Nsb25lKCk7XHJcbiAgICAgICAgY29uc3QgdCA9IG5ldyBQcm94eSgvKiogQHR5cGUge2FueX0gKi8oey4uLmNsb25lLiNjb252ZXJ0ZXJ9KSwge1xyXG4gICAgICAgICAgICBnZXQ6ICh0LHAscikgPT4ge1xyXG4gICAgICAgICAgICAgICAgaWYodHlwZW9mIHAgIT09IFwic3RyaW5nXCIpIHtcclxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFByb3BlcnR5IFwiJHtTdHJpbmcocCl9XCIgaXMgbm90IG9mIHR5cGUgc3RyaW5nLmApO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuIChxdWFudGl0eSkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGNvbnZlcnRlciA9IGNsb25lLiNjb252ZXJ0ZXJbcF07XHJcbiAgICAgICAgICAgICAgICAgICAgaWYoQXJyYXkuaXNBcnJheShjb252ZXJ0ZXIpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IFtjb252ZXJ0VG9CYXNlVW5pdHMsIGNvbnZlcnRGcm9tQmFzZVVuaXRzXSA9IGNvbnZlcnRlcjtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY2xvbmUuX19iYXNlVW5pdFZhbHVlID0gY29udmVydFRvQmFzZVVuaXRzKGNvbnZlcnRGcm9tQmFzZVVuaXRzKGNsb25lLl9fYmFzZVVuaXRWYWx1ZSkgKyBxdWFudGl0eSk7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIGVsc2VcclxuICAgICAgICAgICAgICAgICAgICBpZih0eXBlb2YgY29udmVydGVyID09PSBcIm51bWJlclwiKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNsb25lLl9fYmFzZVVuaXRWYWx1ZSArPSBxdWFudGl0eSAvIGNvbnZlcnRlcjtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgICAgICBjYWxsYmFjayh0KTtcclxuICAgICAgICByZXR1cm4gLyoqIEB0eXBlIHthbnl9ICovIChjbG9uZSk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBAcGFyYW0geyhvYmo6IHtbSyBpbiBrZXlvZiBUXTogKHF1YW50aXR5OiBudW1iZXIpID0+IHZvaWR9KSA9PiB2b2lkfSBjYWxsYmFja1xyXG4gICAgICogQHJldHVybnMge3RoaXN9XHJcbiAgICAgKi9cclxuICAgIHN1YihjYWxsYmFjaykge1xyXG4gICAgICAgIGNvbnN0IGNsb25lID0gdGhpcy4jY2xvbmUoKTtcclxuICAgICAgICBjb25zdCB0ID0gbmV3IFByb3h5KC8qKiBAdHlwZSB7YW55fSAqLyh7Li4uY2xvbmUuI2NvbnZlcnRlcn0pLCB7XHJcbiAgICAgICAgICAgIGdldDogKHQscCxyKSA9PiB7XHJcbiAgICAgICAgICAgICAgICBpZih0eXBlb2YgcCAhPT0gXCJzdHJpbmdcIikge1xyXG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgUHJvcGVydHkgXCIke1N0cmluZyhwKX1cIiBpcyBub3Qgb2YgdHlwZSBzdHJpbmcuYCk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gKHF1YW50aXR5KSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgY29udmVydGVyID0gY2xvbmUuI2NvbnZlcnRlcltwXTtcclxuICAgICAgICAgICAgICAgICAgICBpZihBcnJheS5pc0FycmF5KGNvbnZlcnRlcikpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgW2NvbnZlcnRUb0Jhc2VVbml0cywgY29udmVydEZyb21CYXNlVW5pdHNdID0gY29udmVydGVyO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhwLCBjbG9uZS5fX2Jhc2VVbml0VmFsdWUsIGNvbnZlcnRUb0Jhc2VVbml0cyhxdWFudGl0eSkpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjbG9uZS5fX2Jhc2VVbml0VmFsdWUgPSBjb252ZXJ0VG9CYXNlVW5pdHMoY29udmVydEZyb21CYXNlVW5pdHMoY2xvbmUuX19iYXNlVW5pdFZhbHVlKSAtIHF1YW50aXR5KTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgZWxzZVxyXG4gICAgICAgICAgICAgICAgICAgIGlmKHR5cGVvZiBjb252ZXJ0ZXIgPT09IFwibnVtYmVyXCIpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY2xvbmUuX19iYXNlVW5pdFZhbHVlIC09IHF1YW50aXR5IC8gY29udmVydGVyO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIGNhbGxiYWNrKHQpO1xyXG4gICAgICAgIHJldHVybiAvKiogQHR5cGUge2FueX0gKi8gKGNsb25lKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEBvdmVybG9hZCBPdmVybG9hZCAxXHJcbiAgICAgKiBAcGFyYW0geyhtb2RlbDogUHJvcGVydHlSZXRyaWV2ZXI8VD4pID0+IGtleW9mIFR9IGNhbGxiYWNrXHJcbiAgICAgKiBDYWxsYmFjayB1c2VkIHRvIGdldCB0aGUgdHlwZSBvZiBjb252ZXJzaW9uIChvciBvdGhlcndpc2UsIHRoZSBrZXkgb2YgY29udmVyc2lvbikgdG8gdXNlIHdoZW4gY29udmVydGluZy5cclxuICAgICAqIEByZXR1cm5zIHtudW1iZXJ9XHJcbiAgICAgKiBUaGUgY29udmVydGVkIG51bWJlciBmcm9tIHRoZSB1bml0IHF1YW50aXR5IGhlbGQgYnkgdGhpcyBVbml0U3BhbiBjbGFzcyBvYmplY3QuXHJcbiAgICAgKiBcclxuICAgICAqIEBvdmVybG9hZFxyXG4gICAgICogQHBhcmFtIHsobW9kZWw6IFByb3BlcnR5UmV0cmlldmVyPFQ+KSA9PiBzdHJpbmd9IGNhbGxiYWNrX