UNPKG

@acrodata/gradient-picker

Version:

A powerful and beautiful gradient picker.

232 lines 28.2 kB
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=