@acrodata/gradient-picker
Version:
A powerful and beautiful gradient picker.
232 lines • 28.2 kB
JavaScript
import { TinyColor } from '@ctrl/tinycolor';
import { parseConicGradient, parseLinearGradient, parseRadialGradient } from './parser';
/**
* Reorder an element at a specified index by condition
*
* @param array The original array
* @param index The element at this index will be checked and moved to its correct sorted location.
* @param compareWith1 The comparison function used to determine if the element needs to move left.
* @param compareWith2 The comparison function used to determine if the element needs to move right.
* @param callback The callback function after the elements have been swapped.
* @returns
*/
export function reorderElementByCondition(array = [], index = 0, compareWith1 = (a, b) => a < b, compareWith2 = (a, b) => a > b, callback) {
// Make a copy to avoid modifying the original array reference
const newArr = [...array];
if (index < 0 || index >= newArr.length) {
return array;
}
// Now, we need to move this potentially out-of-place element
// to its correct sorted position.
// This is essentially an insertion sort pass for a single element.
let i = index;
while (i > 0 && compareWith1(newArr[i], newArr[i - 1])) {
// Swap elements
[newArr[i], newArr[i - 1]] = [newArr[i - 1], newArr[i]];
i--;
callback?.(i);
}
while (i < newArr.length - 1 && compareWith2(newArr[i], newArr[i + 1])) {
// Swap elements
[newArr[i], newArr[i + 1]] = [newArr[i + 1], newArr[i]];
i++;
callback?.(i);
}
return newArr;
}
/**
* Linearly interpolate between two colors.
*
* @param fromColor The starting color in any format supported by TinyColor.
* @param toColor The ending color in any format supported by TinyColor.
* @param percentage The interpolation percentage between 0 (`fromColor`) and 1 (`toColor`)
* @returns
*/
export function interpolateColor(fromColor, toColor, percentage = 0.5) {
const c1 = new TinyColor(fromColor);
const c2 = new TinyColor(toColor);
// Convert to premultiplied alpha
const c1_pre = {
r: c1.r * c1.a,
g: c1.g * c1.a,
b: c1.b * c1.a,
a: c1.a,
};
const c2_pre = {
r: c2.r * c2.a,
g: c2.g * c2.a,
b: c2.b * c2.a,
a: c2.a,
};
// Linearly interpolate the premultiplied RGBA components
const interpolatedR_pre = c1_pre.r * (1 - percentage) + c2_pre.r * percentage;
const interpolatedG_pre = c1_pre.g * (1 - percentage) + c2_pre.g * percentage;
const interpolatedB_pre = c1_pre.b * (1 - percentage) + c2_pre.b * percentage;
const interpolatedA = c1_pre.a * (1 - percentage) + c2_pre.a * percentage;
// Convert back to non-premultiplied alpha format (if alpha is not 0)
const finalR = interpolatedA > 0 ? interpolatedR_pre / interpolatedA : 0;
const finalG = interpolatedA > 0 ? interpolatedG_pre / interpolatedA : 0;
const finalB = interpolatedA > 0 ? interpolatedB_pre / interpolatedA : 0;
const finalColor = new TinyColor({
r: Math.round(finalR),
g: Math.round(finalG),
b: Math.round(finalB),
a: interpolatedA,
});
return interpolatedA === 1 ? finalColor.toHexString() : finalColor.toRgbString();
}
/**
* Fill undefined offset in stops.
*
* @param stops
* @returns
*/
export function fillUndefinedOffsets(stops) {
if (stops.length === 0)
return stops;
// Ensure the start and end positions are defined.
if (!stops[0] || stops[0].offset == null) {
stops[0].offset = { value: 0, unit: '%' };
}
const lastIndex = stops.length - 1;
if (!stops[lastIndex] || stops[lastIndex].offset == null) {
stops[lastIndex].offset = { value: 100, unit: '%' };
}
stops.forEach((item, index) => {
if (item.offset != null)
return;
// Find the nearest defined offset to the left of the current item by using
// findIndex to search backward from the current index.
const startIndex = stops
.slice(0, index)
.reverse()
.findIndex(x => x.offset != null);
const prevDefinedIndex = index - 1 - startIndex;
const startOffsetValue = stops[prevDefinedIndex].offset.value;
// Find the nearest defined offset to the right of the current item by using
// findIndex to search forward from the current index.
const endIndex = stops.slice(index + 1).findIndex(x => x.offset != null);
const nextDefinedIndex = index + 1 + endIndex;
const endOffsetValue = stops[nextDefinedIndex].offset.value;
// Calculate the number of gaps between two defined values.
const totalGaps = nextDefinedIndex - prevDefinedIndex;
const totalDifference = endOffsetValue - startOffsetValue;
// Calculate the index of the current undefined value within the entire gaps.
const gapIndex = index - prevDefinedIndex;
const newOffsetValue = startOffsetValue + (gapIndex / totalGaps) * totalDifference;
item.offset = { value: newOffsetValue, unit: '%' };
});
return stops;
}
/**
* Reverse the color stops array.
*
* @param stops
* @returns
*/
export function reverseColorStops(stops) {
return stops.reverse().map(stop => {
if (stop.offset?.value != null) {
stop.offset.value = 100 - stop.offset.value;
}
return stop;
});
}
/**
* Convert angle to percentage (e.g. `45deg`, `0.25turn`, `3.14rad`, `100grad`).
*
* @param value
* @param unit
* @returns
*/
export function angleToPercentage(value, unit) {
let degrees;
switch (unit) {
case 'deg':
degrees = value;
break;
case 'rad':
degrees = value * (180 / Math.PI);
break;
case 'turn':
degrees = value * 360;
break;
case 'grad':
degrees = value * 0.9;
break;
default:
return value;
}
// Calculate the percentage within 360 degrees and ensure the
// percentage value is between 0 and 100.
let percentage = (degrees / 360) * 100;
// Handle negative values or values exceeding 360 degrees by using
// the modulo operator to constrain the angle within [0, 360).
if (percentage < 0) {
percentage = (percentage % 100) + 100;
}
else if (percentage >= 100) {
percentage = percentage % 100;
}
return percentage;
}
/**
* Convert angle values in the gradient stops array to percentages.
*
* @param stops
* @returns
*/
export function convertAngleToPercentage(stops) {
return stops.map(stop => {
if (stop.offset && angleUnits.includes(stop.offset.unit)) {
const { value, unit } = stop.offset;
stop.offset.value = angleToPercentage(value, unit);
stop.offset.unit = '%';
}
return stop;
});
}
/**
* A unified function for parsing all gradient types.
*
* @param input
*/
export function parseGradient(input) {
if (input.includes('linear')) {
return parseLinearGradient(input);
}
else if (input.includes('radial')) {
return parseRadialGradient(input);
}
else if (input.includes('conic')) {
return parseConicGradient(input);
}
else {
return null;
}
}
export const angleUnits = ['deg', 'rad', 'turn', 'grad'];
export const lengthUnits = ['%', 'px', 'em', 'rem', 'vw', 'vh', 'ch'];
export const positionXKeywords = ['left', 'center', 'right'];
export const positionYKeywords = ['top', 'center', 'bottom'];
export const rectangularColorSpaces = [
'srgb',
'srgb-linear',
'display-p3',
'a98-rgb',
'prophoto-rgb',
'rec2020',
'lab',
'oklab',
'xyz',
'xyz-d50',
'xyz-d65',
];
export const polarColorSpaces = ['hsl', 'hwb', 'lch', 'oklch'];
export const hueInterpolationMethods = [
'shorter hue',
'longer hue',
'increasing hue',
'decreasing hue',
];
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9ncmFkaWVudC1waWNrZXIvc3JjL2xpYi91dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDNUMsT0FBTyxFQUFhLGtCQUFrQixFQUFFLG1CQUFtQixFQUFFLG1CQUFtQixFQUFFLE1BQU0sVUFBVSxDQUFDO0FBRW5HOzs7Ozs7Ozs7R0FTRztBQUNILE1BQU0sVUFBVSx5QkFBeUIsQ0FDdkMsUUFBYSxFQUFFLEVBQ2YsS0FBSyxHQUFHLENBQUMsRUFDVCxlQUF3QyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQ3ZELGVBQXdDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFDdkQsUUFBcUM7SUFFckMsOERBQThEO0lBQzlELE1BQU0sTUFBTSxHQUFHLENBQUMsR0FBRyxLQUFLLENBQUMsQ0FBQztJQUUxQixJQUFJLEtBQUssR0FBRyxDQUFDLElBQUksS0FBSyxJQUFJLE1BQU0sQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUN4QyxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCw2REFBNkQ7SUFDN0Qsa0NBQWtDO0lBQ2xDLG1FQUFtRTtJQUVuRSxJQUFJLENBQUMsR0FBRyxLQUFLLENBQUM7SUFFZCxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksWUFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUN2RCxnQkFBZ0I7UUFDaEIsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENB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QGN0cmwvdGlueWNvbG9yJztcbmltcG9ydCB7IENvbG9yU3RvcCwgcGFyc2VDb25pY0dyYWRpZW50LCBwYXJzZUxpbmVhckdyYWRpZW50LCBwYXJzZVJhZGlhbEdyYWRpZW50IH0gZnJvbSAnLi9wYXJzZXInO1xuXG4vKipcbiAqIFJlb3JkZXIgYW4gZWxlbWVudCBhdCBhIHNwZWNpZmllZCBpbmRleCBieSBjb25kaXRpb25cbiAqXG4gKiBAcGFyYW0gYXJyYXkgVGhlIG9yaWdpbmFsIGFycmF5XG4gKiBAcGFyYW0gaW5kZXggVGhlIGVsZW1lbnQgYXQgdGhpcyBpbmRleCB3aWxsIGJlIGNoZWNrZWQgYW5kIG1vdmVkIHRvIGl0cyBjb3JyZWN0IHNvcnRlZCBsb2NhdGlvbi5cbiAqIEBwYXJhbSBjb21wYXJlV2l0aDEgVGhlIGNvbXBhcmlzb24gZnVuY3Rpb24gdXNlZCB0byBkZXRlcm1pbmUgaWYgdGhlIGVsZW1lbnQgbmVlZHMgdG8gbW92ZSBsZWZ0LlxuICogQHBhcmFtIGNvbXBhcmVXaXRoMiBUaGUgY29tcGFyaXNvbiBmdW5jdGlvbiB1c2VkIHRvIGRldGVybWluZSBpZiB0aGUgZWxlbWVudCBuZWVkcyB0byBtb3ZlIHJpZ2h0LlxuICogQHBhcmFtIGNhbGxiYWNrIFRoZSBjYWxsYmFjayBmdW5jdGlvbiBhZnRlciB0aGUgZWxlbWVudHMgaGF2ZSBiZWVuIHN3YXBwZWQuXG4gKiBAcmV0dXJuc1xuICovXG5leHBvcnQgZnVuY3Rpb24gcmVvcmRlckVsZW1lbnRCeUNvbmRpdGlvbjxUID0gYW55PihcbiAgYXJyYXk6IFRbXSA9IFtdLFxuICBpbmRleCA9IDAsXG4gIGNvbXBhcmVXaXRoMTogKGE6IFQsIGI6IFQpID0+IGJvb2xlYW4gPSAoYSwgYikgPT4gYSA8IGIsXG4gIGNvbXBhcmVXaXRoMjogKGE6IFQsIGI6IFQpID0+IGJvb2xlYW4gPSAoYSwgYikgPT4gYSA+IGIsXG4gIGNhbGxiYWNrPzogKG5ld0luZGV4OiBudW1iZXIpID0+IHZvaWRcbik6IFRbXSB7XG4gIC8vIE1ha2UgYSBjb3B5IHRvIGF2b2lkIG1vZGlmeWluZyB0aGUgb3JpZ2luYWwgYXJyYXkgcmVmZXJlbmNlXG4gIGNvbnN0IG5ld0FyciA9IFsuLi5hcnJheV07XG5cbiAgaWYgKGluZGV4IDwgMCB8fCBpbmRleCA+PSBuZXdBcnIubGVuZ3RoKSB7XG4gICAgcmV0dXJuIGFycmF5O1xuICB9XG5cbiAgLy8gTm93LCB3ZSBuZWVkIHRvIG1vdmUgdGhpcyBwb3RlbnRpYWxseSBvdXQtb2YtcGxhY2UgZWxlbWVudFxuICAvLyB0byBpdHMgY29ycmVjdCBzb3J0ZWQgcG9zaXRpb24uXG4gIC8vIFRoaXMgaXMgZXNzZW50aWFsbHkgYW4gaW5zZXJ0aW9uIHNvcnQgcGFzcyBmb3IgYSBzaW5nbGUgZWxlbWVudC5cblxuICBsZXQgaSA9IGluZGV4O1xuXG4gIHdoaWxlIChpID4gMCAmJiBjb21wYXJlV2l0aDEobmV3QXJyW2ldLCBuZXdBcnJbaSAtIDFdKSkge1xuICAgIC8vIFN3YXAgZWxlbWVudHNcbiAgICBbbmV3QXJyW2ldLCBuZXdBcnJbaSAtIDFdXSA9IFtuZXdBcnJbaSAtIDFdLCBuZXdBcnJbaV1dO1xuICAgIGktLTtcbiAgICBjYWxsYmFjaz8uKGkpO1xuICB9XG5cbiAgd2hpbGUgKGkgPCBuZXdBcnIubGVuZ3RoIC0gMSAmJiBjb21wYXJlV2l0aDIobmV3QXJyW2ldLCBuZXdBcnJbaSArIDFdKSkge1xuICAgIC8vIFN3YXAgZWxlbWVudHNcbiAgICBbbmV3QXJyW2ldLCBuZXdBcnJbaSArIDFdXSA9IFtuZXdBcnJbaSArIDFdLCBuZXdBcnJbaV1dO1xuICAgIGkrKztcbiAgICBjYWxsYmFjaz8uKGkpO1xuICB9XG5cbiAgcmV0dXJuIG5ld0Fycjtcbn1cblxuLyoqXG4gKiBMaW5lYXJseSBpbnRlcnBvbGF0ZSBiZXR3ZWVuIHR3byBjb2xvcnMuXG4gKlxuICogQHBhcmFtIGZyb21Db2xvciBUaGUgc3RhcnRpbmcgY29sb3IgaW4gYW55IGZvcm1hdCBzdXBwb3J0ZWQgYnkgVGlueUNvbG9yLlxuICogQHBhcmFtIHRvQ29sb3IgVGhlIGVuZGluZyBjb2xvciBpbiBhbnkgZm9ybWF0IHN1cHBvcnRlZCBieSBUaW55Q29sb3IuXG4gKiBAcGFyYW0gcGVyY2VudGFnZSBUaGUgaW50ZXJwb2xhdGlvbiBwZXJjZW50YWdlIGJldHdlZW4gMCAoYGZyb21Db2xvcmApIGFuZCAxIChgdG9Db2xvcmApXG4gKiBAcmV0dXJuc1xuICovXG5leHBvcnQgZnVuY3Rpb24gaW50ZXJwb2xhdGVDb2xvcihmcm9tQ29sb3I6IHN0cmluZywgdG9Db2xvcjogc3RyaW5nLCBwZXJjZW50YWdlID0gMC41KSB7XG4gIGNvbnN0IGMxID0gbmV3IFRpbnlDb2xvcihmcm9tQ29sb3IpO1xuICBjb25zdCBjMiA9IG5ldyBUaW55Q29sb3IodG9Db2xvcik7XG5cbiAgLy8gQ29udmVydCB0byBwcmVtdWx0aXBsaWVkIGFscGhhXG4gIGNvbnN0IGMxX3ByZSA9IHtcbiAgICByOiBjMS5yICogYzEuYSxcbiAgICBnOiBjMS5nICogYzEuYSxcbiAgICBiOiBjMS5iICogYzEuYSxcbiAgICBhOiBjMS5hLFxuICB9O1xuICBjb25zdCBjMl9wcmUgPSB7XG4gICAgcjogYzIuciAqIGMyLmEsXG4gICAgZzogYzIuZyAqIGMyLmEsXG4gICAgYjogYzIuYiAqIGMyLmEsXG4gICAgYTogYzIuYSxcbiAgfTtcblxuICAvLyBMaW5lYXJseSBpbnRlcnBvbGF0ZSB0aGUgcHJlbXVsdGlwbGllZCBSR0JBIGNvbXBvbmVudHNcbiAgY29uc3QgaW50ZXJwb2xhdGVkUl9wcmUgPSBjMV9wcmUuciAqICgxIC0gcGVyY2VudGFnZSkgKyBjMl9wcmUuciAqIHBlcmNlbnRhZ2U7XG4gIGNvbnN0IGludGVycG9sYXRlZEdfcHJlID0gYzFfcHJlLmcgKiAoMSAtIHBlcmNlbnRhZ2UpICsgYzJfcHJlLmcgKiBwZXJjZW50YWdlO1xuICBjb25zdCBpbnRlcnBvbGF0ZWRCX3ByZSA9IGMxX3ByZS5iICogKDEgLSBwZXJjZW50YWdlKSArIGMyX3ByZS5iICogcGVyY2VudGFnZTtcbiAgY29uc3QgaW50ZXJwb2xhdGVkQSA9IGMxX3ByZS5hICogKDEgLSBwZXJjZW50YWdlKSArIGMyX3ByZS5hICogcGVyY2VudGFnZTtcblxuICAvLyBDb252ZXJ0IGJhY2sgdG8gbm9uLXByZW11bHRpcGxpZWQgYWxwaGEgZm9ybWF0IChpZiBhbHBoYSBpcyBub3QgMClcbiAgY29uc3QgZmluYWxSID0gaW50ZXJwb2xhdGVkQSA+IDAgPyBpbnRlcnBvbGF0ZWRSX3ByZSAvIGludGVycG9sYXRlZEEgOiAwO1xuICBjb25zdCBmaW5hbEcgPSBpbnRlcnBvbGF0ZWRBID4gMCA/IGludGVycG9sYXRlZEdfcHJlIC8gaW50ZXJwb2xhdGVkQSA6IDA7XG4gIGNvbnN0IGZpbmFsQiA9IGludGVycG9sYXRlZEEgPiAwID8gaW50ZXJwb2xhdGVkQl9wcmUgLyBpbnRlcnBvbGF0ZWRBIDogMDtcblxuICBjb25zdCBmaW5hbENvbG9yID0gbmV3IFRpbnlDb2xvcih7XG4gICAgcjogTWF0aC5yb3VuZChmaW5hbFIpLFxuICAgIGc6IE1hdGgucm91bmQoZmluYWxHKSxcbiAgICBiOiBNYXRoLnJvdW5kKGZpbmFsQiksXG4gICAgYTogaW50ZXJwb2xhdGVkQSxcbiAgfSk7XG5cbiAgcmV0dXJuIGludGVycG9sYXRlZEEgPT09IDEgPyBmaW5hbENvbG9yLnRvSGV4U3RyaW5nKCkgOiBmaW5hbENvbG9yLnRvUmdiU3RyaW5nKCk7XG59XG5cbi8qKlxuICogRmlsbCB1bmRlZmluZWQgb2Zmc2V0IGluIHN0b3BzLlxuICpcbiAqIEBwYXJhbSBzdG9wc1xuICogQHJldHVybnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbGxVbmRlZmluZWRPZmZzZXRzKHN0b3BzOiBDb2xvclN0b3BbXSk6IENvbG9yU3RvcFtdIHtcbiAgaWYgKHN0b3BzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHN0b3BzO1xuXG4gIC8vIEVuc3VyZSB0aGUgc3RhcnQgYW5kIGVuZCBwb3NpdGlvbnMgYXJlIGRlZmluZWQuXG4gIGlmICghc3RvcHNbMF0gfHwgc3RvcHNbMF0ub2Zmc2V0ID09IG51bGwpIHtcbiAgICBzdG9wc1swXS5vZmZzZXQgPSB7IHZhbHVlOiAwLCB1bml0OiAnJScgfTtcbiAgfVxuICBjb25zdCBsYXN0SW5kZXggPSBzdG9wcy5sZW5ndGggLSAxO1xuICBpZiAoIXN0b3BzW2xhc3RJbmRleF0gfHwgc3RvcHNbbGFzdEluZGV4XS5vZmZzZXQgPT0gbnVsbCkge1xuICAgIHN0b3BzW2xhc3RJbmRleF0ub2Zmc2V0ID0geyB2YWx1ZTogMTAwLCB1bml0OiAnJScgfTtcbiAgfVxuXG4gIHN0b3BzLmZvckVhY2goKGl0ZW0sIGluZGV4KSA9PiB7XG4gICAgaWYgKGl0ZW0ub2Zmc2V0ICE9IG51bGwpIHJldHVybjtcblxuICAgIC8vIEZpbmQgdGhlIG5lYXJlc3QgZGVmaW5lZCBvZmZzZXQgdG8gdGhlIGxlZnQgb2YgdGhlIGN1cnJlbnQgaXRlbSBieSB1c2luZ1xuICAgIC8vIGZpbmRJbmRleCB0byBzZWFyY2ggYmFja3dhcmQgZnJvbSB0aGUgY3VycmVudCBpbmRleC5cbiAgICBjb25zdCBzdGFydEluZGV4ID0gc3RvcHNcbiAgICAgIC5zbGljZSgwLCBpbmRleClcbiAgICAgIC5yZXZlcnNlKClcbiAgICAgIC5maW5kSW5kZXgoeCA9PiB4Lm9mZnNldCAhPSBudWxsKTtcbiAgICBjb25zdCBwcmV2RGVmaW5lZEluZGV4ID0gaW5kZXggLSAxIC0gc3RhcnRJbmRleDtcbiAgICBjb25zdCBzdGFydE9mZnNldFZhbHVlID0gc3RvcHNbcHJldkRlZmluZWRJbmRleF0ub2Zmc2V0IS52YWx1ZTtcblxuICAgIC8vIEZpbmQgdGhlIG5lYXJlc3QgZGVmaW5lZCBvZmZzZXQgdG8gdGhlIHJpZ2h0IG9mIHRoZSBjdXJyZW50IGl0ZW0gYnkgdXNpbmdcbiAgICAvLyBmaW5kSW5kZXggdG8gc2VhcmNoIGZvcndhcmQgZnJvbSB0aGUgY3VycmVudCBpbmRleC5cbiAgICBjb25zdCBlbmRJbmRleCA9IHN0b3BzLnNsaWNlKGluZGV4ICsgMSkuZmluZEluZGV4KHggPT4geC5vZmZzZXQgIT0gbnVsbCk7XG4gICAgY29uc3QgbmV4dERlZmluZWRJbmRleCA9IGluZGV4ICsgMSArIGVuZEluZGV4O1xuICAgIGNvbnN0IGVuZE9mZnNldFZhbHVlID0gc3RvcHNbbmV4dERlZmluZWRJbmRleF0ub2Zmc2V0IS52YWx1ZTtcblxuICAgIC8vIENhbGN1bGF0ZSB0aGUgbnVtYmVyIG9mIGdhcHMgYmV0d2VlbiB0d28gZGVmaW5lZCB2YWx1ZXMuXG4gICAgY29uc3QgdG90YWxHYXBzID0gbmV4dERlZmluZWRJbmRleCAtIHByZXZEZWZpbmVkSW5kZXg7XG4gICAgY29uc3QgdG90YWxEaWZmZXJlbmNlID0gZW5kT2Zmc2V0VmFsdWUgLSBzdGFydE9mZnNldFZhbHVlO1xuXG4gICAgLy8gQ2FsY3VsYXRlIHRoZSBpbmRleCBvZiB0aGUgY3VycmVudCB1bmRlZmluZWQgdmFsdWUgd2l0aGluIHRoZSBlbnRpcmUgZ2Fwcy5cbiAgICBjb25zdCBnYXBJbmRleCA9IGluZGV4IC0gcHJldkRlZmluZWRJbmRleDtcbiAgICBjb25zdCBuZXdPZmZzZXRWYWx1ZSA9IHN0YXJ0T2Zmc2V0VmFsdWUgKyAoZ2FwSW5kZXggLyB0b3RhbEdhcHMpICogdG90YWxEaWZmZXJlbmNlO1xuXG4gICAgaXRlbS5vZmZzZXQgPSB7IHZhbHVlOiBuZXdPZmZzZXRWYWx1ZSwgdW5pdDogJyUnIH07XG4gIH0pO1xuXG4gIHJldHVybiBzdG9wcztcbn1cblxuLyoqXG4gKiBSZXZlcnNlIHRoZSBjb2xvciBzdG9wcyBhcnJheS5cbiAqXG4gKiBAcGFyYW0gc3RvcHNcbiAqIEByZXR1cm5zXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXZlcnNlQ29sb3JTdG9wcyhzdG9wczogQ29sb3JTdG9wW10pIHtcbiAgcmV0dXJuIHN0b3BzLnJldmVyc2UoKS5tYXAoc3RvcCA9PiB7XG4gICAgaWYgKHN0b3Aub2Zmc2V0Py52YWx1ZSAhPSBudWxsKSB7XG4gICAgICBzdG9wLm9mZnNldC52YWx1ZSA9IDEwMCAtIHN0b3Aub2Zmc2V0LnZhbHVlO1xuICAgIH1cbiAgICByZXR1cm4gc3RvcDtcbiAgfSk7XG59XG5cbi8qKlxuICogQ29udmVydCBhbmdsZSB0byBwZXJjZW50YWdlIChlLmcuIGA0NWRlZ2AsIGAwLjI1dHVybmAsIGAzLjE0cmFkYCwgYDEwMGdyYWRgKS5cbiAqXG4gKiBAcGFyYW0gdmFsdWVcbiAqIEBwYXJhbSB1bml0XG4gKiBAcmV0dXJuc1xuICovXG5leHBvcnQgZnVuY3Rpb24gYW5nbGVUb1BlcmNlbnRhZ2UodmFsdWU6IG51bWJlciwgdW5pdDogc3RyaW5nKSB7XG4gIGxldCBkZWdyZWVzO1xuICBzd2l0Y2ggKHVuaXQpIHtcbiAgICBjYXNlICdkZWcnOlxuICAgICAgZGVncmVlcyA9IHZhbHVlO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSAncmFkJzpcbiAgICAgIGRlZ3JlZXMgPSB2YWx1ZSAqICgxODAgLyBNYXRoLlBJKTtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgJ3R1cm4nOlxuICAgICAgZGVncmVlcyA9IHZhbHVlICogMzYwO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSAnZ3JhZCc6XG4gICAgICBkZWdyZWVzID0gdmFsdWUgKiAwLjk7XG4gICAgICBicmVhaztcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIHZhbHVlO1xuICB9XG5cbiAgLy8gQ2FsY3VsYXRlIHRoZSBwZXJjZW50YWdlIHdpdGhpbiAzNjAgZGVncmVlcyBhbmQgZW5zdXJlIHRoZVxuICAvLyBwZXJjZW50YWdlIHZhbHVlIGlzIGJldHdlZW4gMCBhbmQgMTAwLlxuICBsZXQgcGVyY2VudGFnZSA9IChkZWdyZWVzIC8gMzYwKSAqIDEwMDtcblxuICAvLyBIYW5kbGUgbmVnYXRpdmUgdmFsdWVzIG9yIHZhbHVlcyBleGNlZWRpbmcgMzYwIGRlZ3JlZXMgYnkgdXNpbmdcbiAgLy8gdGhlIG1vZHVsbyBvcGVyYXRvciB0byBjb25zdHJhaW4gdGhlIGFuZ2xlIHdpdGhpbiBbMCwgMzYwKS5cbiAgaWYgKHBlcmNlbnRhZ2UgPCAwKSB7XG4gICAgcGVyY2VudGFnZSA9IChwZXJjZW50YWdlICUgMTAwKSArIDEwMDtcbiAgfSBlbHNlIGlmIChwZXJjZW50YWdlID49IDEwMCkge1xuICAgIHBlcmNlbnRhZ2UgPSBwZXJjZW50YWdlICUgMTAwO1xuICB9XG5cbiAgcmV0dXJuIHBlcmNlbnRhZ2U7XG59XG5cbi8qKlxuICogQ29udmVydCBhbmdsZSB2YWx1ZXMgaW4gdGhlIGdyYWRpZW50IHN0b3BzIGFycmF5IHRvIHBlcmNlbnRhZ2VzLlxuICpcbiAqIEBwYXJhbSBzdG9wc1xuICogQHJldHVybnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbnZlcnRBbmdsZVRvUGVyY2VudGFnZShzdG9wczogQ29sb3JTdG9wW10pIHtcbiAgcmV0dXJuIHN0b3BzLm1hcChzdG9wID0+IHtcbiAgICBpZiAoc3RvcC5vZmZzZXQgJiYgYW5nbGVVbml0cy5pbmNsdWRlcyhzdG9wLm9mZnNldC51bml0KSkge1xuICAgICAgY29uc3QgeyB2YWx1ZSwgdW5pdCB9ID0gc3RvcC5vZmZzZXQ7XG4gICAgICBzdG9wLm9mZnNldC52YWx1ZSA9IGFuZ2xlVG9QZXJjZW50YWdlKHZhbHVlLCB1bml0KTtcbiAgICAgIHN0b3Aub2Zmc2V0LnVuaXQgPSAnJSc7XG4gICAgfVxuICAgIHJldHVybiBzdG9wO1xuICB9KTtcbn1cblxuLyoqXG4gKiBBIHVuaWZpZWQgZnVuY3Rpb24gZm9yIHBhcnNpbmcgYWxsIGdyYWRpZW50IHR5cGVzLlxuICpcbiAqIEBwYXJhbSBpbnB1dFxuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VHcmFkaWVudChpbnB1dDogc3RyaW5nKSB7XG4gIGlmIChpbnB1dC5pbmNsdWRlcygnbGluZWFyJykpIHtcbiAgICByZXR1cm4gcGFyc2VMaW5lYXJHcmFkaWVudChpbnB1dCk7XG4gIH0gZWxzZSBpZiAoaW5wdXQuaW5jbHVkZXMoJ3JhZGlhbCcpKSB7XG4gICAgcmV0dXJuIHBhcnNlUmFkaWFsR3JhZGllbnQoaW5wdXQpO1xuICB9IGVsc2UgaWYgKGlucHV0LmluY2x1ZGVzKCdjb25pYycpKSB7XG4gICAgcmV0dXJuIHBhcnNlQ29uaWNHcmFkaWVudChpbnB1dCk7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbn1cblxuZXhwb3J0IGNvbnN0IGFuZ2xlVW5pdHMgPSBbJ2RlZycsICdyYWQnLCAndHVybicsICdncmFkJ107XG5leHBvcnQgY29uc3QgbGVuZ3RoVW5pdHMgPSBbJyUnLCAncHgnLCAnZW0nLCAncmVtJywgJ3Z3JywgJ3ZoJywgJ2NoJ107XG5cbmV4cG9ydCBjb25zdCBwb3NpdGlvblhLZXl3b3JkcyA9IFsnbGVmdCcsICdjZW50ZXInLCAncmlnaHQnXTtcbmV4cG9ydCBjb25zdCBwb3NpdGlvbllLZXl3b3JkcyA9IFsndG9wJywgJ2NlbnRlcicsICdib3R0b20nXTtcblxuZXhwb3J0IGNvbnN0IHJlY3Rhbmd1bGFyQ29sb3JTcGFjZXMgPSBbXG4gICdzcmdiJyxcbiAgJ3NyZ2ItbGluZWFyJyxcbiAgJ2Rpc3BsYXktcDMnLFxuICAnYTk4LXJnYicsXG4gICdwcm9waG90by1yZ2InLFxuICAncmVjMjAyMCcsXG4gICdsYWInLFxuICAnb2tsYWInLFxuICAneHl6JyxcbiAgJ3h5ei1kNTAnLFxuICAneHl6LWQ2NScsXG5dO1xuZXhwb3J0IGNvbnN0IHBvbGFyQ29sb3JTcGFjZXMgPSBbJ2hzbCcsICdod2InLCAnbGNoJywgJ29rbGNoJ107XG5leHBvcnQgY29uc3QgaHVlSW50ZXJwb2xhdGlvbk1ldGhvZHMgPSBbXG4gICdzaG9ydGVyIGh1ZScsXG4gICdsb25nZXIgaHVlJyxcbiAgJ2luY3JlYXNpbmcgaHVlJyxcbiAgJ2RlY3JlYXNpbmcgaHVlJyxcbl07XG4iXX0=