@angular/core
Version:
Angular - the core framework
324 lines • 43.3 kB
JavaScript
import { setStylingMapsSyncFn } from './bindings';
import { getBindingValue, getValuesCount, isStylingValueDefined } from './util';
/**
* --------
*
* This file contains the algorithm logic for applying map-based bindings
* such as `[style]` and `[class]`.
*
* --------
*/
/**
* Used to apply styling values presently within any map-based bindings on an element.
*
* Angular supports map-based styling bindings which can be applied via the
* `[style]` and `[class]` bindings which can be placed on any HTML element.
* These bindings can work independently, together or alongside prop-based
* styling bindings (e.g. `<div [style]="x" [style.width]="w">`).
*
* If a map-based styling binding is detected by the compiler, the following
* AOT code is produced:
*
* ```typescript
* styleMap(ctx.styles); // styles = {key:value}
* classMap(ctx.classes); // classes = {key:value}|string
* ```
*
* If and when either of the instructions above are evaluated, then the code
* present in this file is included into the bundle. The mechanism used, to
* activate support for map-based bindings at runtime is possible via the
* `activeStylingMapFeature` function (which is also present in this file).
*
* # The Algorithm
* Whenever a map-based binding updates (which is when the identity of the
* map-value changes) then the map is iterated over and a `LStylingMap` array
* is produced. The `LStylingMap` instance is stored in the binding location
* where the `BINDING_INDEX` is situated when the `styleMap()` or `classMap()`
* instruction were called. Once the binding changes, then the internal `bitMask`
* value is marked as dirty.
*
* Styling values are applied once CD exits the element (which happens when
* the `select(n)` instruction is called or the template function exits). When
* this occurs, all prop-based bindings are applied. If a map-based binding is
* present then a special flushing function (called a sync function) is made
* available and it will be called each time a styling property is flushed.
*
* The flushing algorithm is designed to apply styling for a property (which is
* a CSS property or a className value) one by one. If map-based bindings
* are present, then the flushing algorithm will keep calling the maps styling
* sync function each time a property is visited. This way, the flushing
* behavior of map-based bindings will always be at the same property level
* as the current prop-based property being iterated over (because everything
* is alphabetically sorted).
*
* Let's imagine we have the following HTML template code:
*
* ```html
* <div [style]="{width:'100px', height:'200px', 'z-index':'10'}"
* [style.width.px]="200">...</div>
* ```
*
* When CD occurs, both the `[style]` and `[style.width]` bindings
* are evaluated. Then when the styles are flushed on screen, the
* following operations happen:
*
* 1. `[style.width]` is attempted to be written to the element.
*
* 2. Once that happens, the algorithm instructs the map-based
* entries (`[style]` in this case) to "catch up" and apply
* all values up to the `width` value. When this happens the
* `height` value is applied to the element (since it is
* alphabetically situated before the `width` property).
*
* 3. Since there are no more prop-based entries anymore, the
* loop exits and then, just before the flushing ends, it
* instructs all map-based bindings to "finish up" applying
* their values.
*
* 4. The only remaining value within the map-based entries is
* the `z-index` value (`width` got skipped because it was
* successfully applied via the prop-based `[style.width]`
* binding). Since all map-based entries are told to "finish up",
* the `z-index` value is iterated over and it is then applied
* to the element.
*
* The most important thing to take note of here is that prop-based
* bindings are evaluated in order alongside map-based bindings.
* This allows all styling across an element to be applied in O(n)
* time (a similar algorithm is that of the array merge algorithm
* in merge sort).
*/
export var syncStylingMap = function (context, renderer, element, data, applyStylingFn, sanitizer, mode, targetProp, defaultValue) {
var targetPropValueWasApplied = false;
// once the map-based styling code is activate it is never deactivated. For this reason a
// check to see if the current styling context has any map based bindings is required.
var totalMaps = getValuesCount(context, 2 /* MapBindingsPosition */);
if (totalMaps) {
var runTheSyncAlgorithm = true;
var loopUntilEnd = !targetProp;
// If the code is told to finish up (run until the end), but the mode
// hasn't been flagged to apply values (it only traverses values) then
// there is no point in iterating over the array because nothing will
// be applied to the element.
if (loopUntilEnd && (mode & ~1 /* ApplyAllValues */)) {
runTheSyncAlgorithm = false;
targetPropValueWasApplied = true;
}
if (runTheSyncAlgorithm) {
targetPropValueWasApplied = innerSyncStylingMap(context, renderer, element, data, applyStylingFn, sanitizer, mode, targetProp || null, 0, defaultValue || null);
}
if (loopUntilEnd) {
resetSyncCursors();
}
}
return targetPropValueWasApplied;
};
/**
* Recursive function designed to apply map-based styling to an element one map at a time.
*
* This function is designed to be called from the `syncStylingMap` function and will
* apply map-based styling data one map at a time to the provided `element`.
*
* This function is recursive and it will call itself if a follow-up map value is to be
* processed. To learn more about how the algorithm works, see `syncStylingMap`.
*/
function innerSyncStylingMap(context, renderer, element, data, applyStylingFn, sanitizer, mode, targetProp, currentMapIndex, defaultValue) {
var targetPropValueWasApplied = false;
var totalMaps = getValuesCount(context, 2 /* MapBindingsPosition */);
if (currentMapIndex < totalMaps) {
var bindingIndex = getBindingValue(context, 2 /* MapBindingsPosition */, currentMapIndex);
var lStylingMap = data[bindingIndex];
var cursor = getCurrentSyncCursor(currentMapIndex);
while (cursor < lStylingMap.length) {
var prop = getMapProp(lStylingMap, cursor);
var iteratedTooFar = targetProp && prop > targetProp;
var isTargetPropMatched = !iteratedTooFar && prop === targetProp;
var value = getMapValue(lStylingMap, cursor);
var valueIsDefined = isStylingValueDefined(value);
// the recursive code is designed to keep applying until
// it reaches or goes past the target prop. If and when
// this happens then it will stop processing values, but
// all other map values must also catch up to the same
// point. This is why a recursive call is still issued
// even if the code has iterated too far.
var innerMode = iteratedTooFar ? mode : resolveInnerMapMode(mode, valueIsDefined, isTargetPropMatched);
var innerProp = iteratedTooFar ? targetProp : prop;
var valueApplied = innerSyncStylingMap(context, renderer, element, data, applyStylingFn, sanitizer, innerMode, innerProp, currentMapIndex + 1, defaultValue);
if (iteratedTooFar) {
break;
}
if (!valueApplied && isValueAllowedToBeApplied(mode, isTargetPropMatched)) {
var useDefault = isTargetPropMatched && !valueIsDefined;
var valueToApply = useDefault ? defaultValue : value;
var bindingIndexToApply = useDefault ? bindingIndex : null;
var finalValue = sanitizer ?
sanitizer(prop, valueToApply, 3 /* ValidateAndSanitize */) :
valueToApply;
applyStylingFn(renderer, element, prop, finalValue, bindingIndexToApply);
valueApplied = true;
}
targetPropValueWasApplied = valueApplied && isTargetPropMatched;
cursor += 2 /* TupleSize */;
}
setCurrentSyncCursor(currentMapIndex, cursor);
}
return targetPropValueWasApplied;
}
/**
* Enables support for map-based styling bindings (e.g. `[style]` and `[class]` bindings).
*/
export function activeStylingMapFeature() {
setStylingMapsSyncFn(syncStylingMap);
}
/**
* Used to determine the mode for the inner recursive call.
*
* If an inner map is iterated on then this is done so for one
* of two reasons:
*
* - The target property was detected and the inner map
* must now "catch up" (pointer-wise) up to where the current
* map's cursor is situated.
*
* - The target property was not detected in the current map
* and must be found in an inner map. This can only be allowed
* if the current map iteration is not set to skip the target
* property.
*/
function resolveInnerMapMode(currentMode, valueIsDefined, isExactMatch) {
var innerMode = currentMode;
if (!valueIsDefined && isExactMatch && !(currentMode & 4 /* SkipTargetProp */)) {
// case 1: set the mode to apply the targeted prop value if it
// ends up being encountered in another map value
innerMode |= 2 /* ApplyTargetProp */;
innerMode &= ~4 /* SkipTargetProp */;
}
else {
// case 2: set the mode to skip the targeted prop value if it
// ends up being encountered in another map value
innerMode |= 4 /* SkipTargetProp */;
innerMode &= ~2 /* ApplyTargetProp */;
}
return innerMode;
}
/**
* Decides whether or not a prop/value entry will be applied to an element.
*
* To determine whether or not a value is to be applied,
* the following procedure is evaluated:
*
* First check to see the current `mode` status:
* 1. If the mode value permits all props to be applied then allow.
* - But do not allow if the current prop is set to be skipped.
* 2. Otherwise if the current prop is permitted then allow.
*/
function isValueAllowedToBeApplied(mode, isTargetPropMatched) {
var doApplyValue = (mode & 1 /* ApplyAllValues */) > 0;
if (!doApplyValue) {
if (mode & 2 /* ApplyTargetProp */) {
doApplyValue = isTargetPropMatched;
}
}
else if ((mode & 4 /* SkipTargetProp */) && isTargetPropMatched) {
doApplyValue = false;
}
return doApplyValue;
}
/**
* Used to keep track of concurrent cursor values for multiple map-based styling bindings present on
* an element.
*/
var MAP_CURSORS = [];
/**
* Used to reset the state of each cursor value being used to iterate over map-based styling
* bindings.
*/
function resetSyncCursors() {
for (var i = 0; i < MAP_CURSORS.length; i++) {
MAP_CURSORS[i] = 1 /* ValuesStartPosition */;
}
}
/**
* Returns an active cursor value at a given mapIndex location.
*/
function getCurrentSyncCursor(mapIndex) {
if (mapIndex >= MAP_CURSORS.length) {
MAP_CURSORS.push(1 /* ValuesStartPosition */);
}
return MAP_CURSORS[mapIndex];
}
/**
* Sets a cursor value at a given mapIndex location.
*/
function setCurrentSyncCursor(mapIndex, indexValue) {
MAP_CURSORS[mapIndex] = indexValue;
}
/**
* Used to convert a {key:value} map into a `LStylingMap` array.
*
* This function will either generate a new `LStylingMap` instance
* or it will patch the provided `newValues` map value into an
* existing `LStylingMap` value (this only happens if `bindingValue`
* is an instance of `LStylingMap`).
*
* If a new key/value map is provided with an old `LStylingMap`
* value then all properties will be overwritten with their new
* values or with `null`. This means that the array will never
* shrink in size (but it will also not be created and thrown
* away whenever the {key:value} map entries change).
*/
export function normalizeIntoStylingMap(bindingValue, newValues) {
var lStylingMap = Array.isArray(bindingValue) ? bindingValue : [null];
lStylingMap[0 /* RawValuePosition */] = newValues || null;
// because the new values may not include all the properties
// that the old ones had, all values are set to `null` before
// the new values are applied. This way, when flushed, the
// styling algorithm knows exactly what style/class values
// to remove from the element (since they are `null`).
for (var j = 1 /* ValuesStartPosition */; j < lStylingMap.length; j += 2 /* TupleSize */) {
setMapValue(lStylingMap, j, null);
}
var props = null;
var map;
var allValuesTrue = false;
if (typeof newValues === 'string') { // [class] bindings allow string values
if (newValues.length) {
props = newValues.split(/\s+/);
allValuesTrue = true;
}
}
else {
props = newValues ? Object.keys(newValues) : null;
map = newValues;
}
if (props) {
outer: for (var i = 0; i < props.length; i++) {
var prop = props[i];
var value = allValuesTrue ? true : map[prop];
for (var j = 1 /* ValuesStartPosition */; j < lStylingMap.length; j += 2 /* TupleSize */) {
var propAtIndex = getMapProp(lStylingMap, j);
if (prop <= propAtIndex) {
if (propAtIndex === prop) {
setMapValue(lStylingMap, j, value);
}
else {
lStylingMap.splice(j, 0, prop, value);
}
continue outer;
}
}
lStylingMap.push(prop, value);
}
}
return lStylingMap;
}
export function getMapProp(map, index) {
return map[index + 0 /* PropOffset */];
}
export function setMapValue(map, index, value) {
map[index + 1 /* ValueOffset */] = value;
}
export function getMapValue(map, index) {
return map[index + 1 /* ValueOffset */];
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFwX2Jhc2VkX2JpbmRpbmdzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvY29yZS9zcmMvcmVuZGVyMy9zdHlsaW5nX25leHQvbWFwX2Jhc2VkX2JpbmRpbmdzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQVVBLE9BQU8sRUFBQyxvQkFBb0IsRUFBQyxNQUFNLFlBQVksQ0FBQztBQUVoRCxPQUFPLEVBQUMsZUFBZSxFQUFFLGNBQWMsRUFBRSxxQkFBcUIsRUFBQyxNQUFNLFFBQVEsQ0FBQztBQUc5RTs7Ozs7OztHQU9HO0FBRUg7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0ErRUc7QUFDSCxNQUFNLENBQUMsSUFBTSxjQUFjLEdBQ3ZCLFVBQUMsT0FBd0IsRUFBRSxRQUFnRCxFQUFFLE9BQWlCLEVBQzdGLElBQWtCLEVBQUUsY0FBOEIsRUFBRSxTQUFpQyxFQUNyRixJQUF5QixFQUFFLFVBQTBCLEVBQ3JELFlBQTRCO0lBQzNCLElBQUkseUJBQXlCLEdBQUcsS0FBSyxDQUFDO0lBRXRDLHlGQUF5RjtJQUN6RixzRkFBc0Y7SUFDdEYsSUFBTSxTQUFTLEdBQUcsY0FBYyxDQUFDLE9BQU8sOEJBQTJDLENBQUM7SUFDcEYsSUFBSSxTQUFTLEVBQUU7UUFDYixJQUFJLG1CQUFtQixHQUFHLElBQUksQ0FBQztRQUMvQixJQUFNLFlBQVksR0FBRyxDQUFDLFVBQVUsQ0FBQztRQUVqQyxxRUFBcUU7UUFDckUsc0VBQXNFO1FBQ3RFLHFFQUFxRTtRQUNyRSw2QkFBNkI7UUFDN0IsSUFBSSxZQUFZLElBQUksQ0FBQyxJQUFJLEdBQUcsdUJBQW1DLENBQUMsRUFBRTtZQUNoRSxtQkFBbUIsR0FBRyxLQUFLLENBQUM7WUFDNUIseUJBQXlCLEdBQUcsSUFBSSxDQUFDO1NBQ2xDO1FB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LElBQUksSUFBSSxXQUFXLEVBQUU7b0JBQ3ZCLElBQUksV0FBVyxLQUFLLElBQUksRUFBRTt3QkFDeEIsV0FBVyxDQUFDLFdBQVcsRUFBRSxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUM7cUJBQ3BDO3lCQUFNO3dCQUNMLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUM7cUJBQ3ZDO29CQUNELFNBQVMsS0FBSyxDQUFDO2lCQUNoQjthQUNGO1lBQ0QsV0FBVyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUM7U0FDL0I7S0FDRjtJQUVELE9BQU8sV0FBVyxDQUFDO0FBQ3JCLENBQUM7QUFFRCxNQUFNLFVBQVUsVUFBVSxDQUFDLEdBQWdCLEVBQUUsS0FBYTtJQUN4RCxPQUFPLEdBQUcsQ0FBQyxLQUFLLHFCQUE4QixDQUFXLENBQUM7QUFDNUQsQ0FBQztBQUVELE1BQU0sVUFBVSxXQUFXLENBQUMsR0FBZ0IsRUFBRSxLQUFhLEVBQUUsS0FBb0I7SUFDL0UsR0FBRyxDQUFDLEtBQUssc0JBQStCLENBQUMsR0FBRyxLQUFLLENBQUM7QUFDcEQsQ0FBQztBQUVELE1BQU0sVUFBVSxXQUFXLENBQUMsR0FBZ0IsRUFBRSxLQUFhO0lBQ3pELE9BQU8sR0FBRyxDQUFDLEtBQUssc0JBQStCLENBQWtCLENBQUM7QUFDcEUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuKiBAbGljZW5zZVxuKiBDb3B5cmlnaHQgR29vZ2xlIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbipcbiogVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlIGxpY2Vuc2UgdGhhdCBjYW4gYmVcbiogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuKi9cbmltcG9ydCB7U3R5bGVTYW5pdGl6ZUZuLCBTdHlsZVNhbml0aXplTW9kZX0gZnJvbSAnLi4vLi4vc2FuaXRpemF0aW9uL3N0eWxlX3Nhbml0aXplcic7XG5pbXBvcnQge1Byb2NlZHVyYWxSZW5kZXJlcjMsIFJFbGVtZW50LCBSZW5kZXJlcjN9IGZyb20gJy4uL2ludGVyZmFjZXMvcmVuZGVyZXInO1xuXG5pbXBvcnQge3NldFN0eWxpbmdNYXBzU3luY0ZufSBmcm9tICcuL2JpbmRpbmdzJztcbmltcG9ydCB7QXBwbHlTdHlsaW5nRm4sIExTdHlsaW5nRGF0YSwgTFN0eWxpbmdNYXAsIExTdHlsaW5nTWFwSW5kZXgsIFN0eWxpbmdNYXBzU3luY01vZGUsIFN5bmNTdHlsaW5nTWFwc0ZuLCBUU3R5bGluZ0NvbnRleHQsIFRTdHlsaW5nQ29udGV4dEluZGV4fSBmcm9tICcuL2ludGVyZmFjZXMnO1xuaW1wb3J0IHtnZXRCaW5kaW5nVmFsdWUsIGdldFZhbHVlc0NvdW50LCBpc1N0eWxpbmdWYWx1ZURlZmluZWR9IGZyb20gJy4vdXRpbCc7XG5cblxuLyoqXG4gKiAtLS0tLS0tLVxuICpcbiAqIFRoaXMgZmlsZSBjb250YWlucyB0aGUgYWxnb3JpdGhtIGxvZ2ljIGZvciBhcHBseWluZyBtYXAtYmFzZWQgYmluZGluZ3NcbiAqIHN1Y2ggYXMgYFtzdHlsZV1gIGFuZCBgW2NsYXNzXWAuXG4gKlxuICogLS0tLS0tLS1cbiAqL1xuXG4vKipcbiAqIFVzZWQgdG8gYXBwbHkgc3R5bGluZyB2YWx1ZXMgcHJlc2VudGx5IHdpdGhpbiBhbnkgbWFwLWJhc2VkIGJpbmRpbmdzIG9uIGFuIGVsZW1lbnQuXG4gKlxuICogQW5ndWxhciBzdXBwb3J0cyBtYXAtYmFzZWQgc3R5bGluZyBiaW5kaW5ncyB3aGljaCBjYW4gYmUgYXBwbGllZCB2aWEgdGhlXG4gKiBgW3N0eWxlXWAgYW5kIGBbY2xhc3NdYCBiaW5kaW5ncyB3aGljaCBjYW4gYmUgcGxhY2VkIG9uIGFueSBIVE1MIGVsZW1lbnQuXG4gKiBUaGVzZSBiaW5kaW5ncyBjYW4gd29yayBpbmRlcGVuZGVudGx5LCB0b2dldGhlciBvciBhbG9uZ3NpZGUgcHJvcC1iYXNlZFxuICogc3R5bGluZyBiaW5kaW5ncyAoZS5nLiBgPGRpdiBbc3R5bGVdPVwieFwiIFtzdHlsZS53aWR0aF09XCJ3XCI+YCkuXG4gKlxuICogSWYgYSBtYXAtYmFzZWQgc3R5bGluZyBiaW5kaW5nIGlzIGRldGVjdGVkIGJ5IHRoZSBjb21waWxlciwgdGhlIGZvbGxvd2luZ1xuICogQU9UIGNvZGUgaXMgcHJvZHVjZWQ6XG4gKlxuICogYGBgdHlwZXNjcmlwdFxuICogc3R5bGVNYXAoY3R4LnN0eWxlcyk7IC8vIHN0eWxlcyA9IHtrZXk6dmFsdWV9XG4gKiBjbGFzc01hcChjdHguY2xhc3Nlcyk7IC8vIGNsYXNzZXMgPSB7a2V5OnZhbHVlfXxzdHJpbmdcbiAqIGBgYFxuICpcbiAqIElmIGFuZCB3aGVuIGVpdGhlciBvZiB0aGUgaW5zdHJ1Y3Rpb25zIGFib3ZlIGFyZSBldmFsdWF0ZWQsIHRoZW4gdGhlIGNvZGVcbiAqIHByZXNlbnQgaW4gdGhpcyBmaWxlIGlzIGluY2x1ZGVkIGludG8gdGhlIGJ1bmRsZS4gVGhlIG1lY2hhbmlzbSB1c2VkLCB0b1xuICogYWN0aXZhdGUgc3VwcG9ydCBmb3IgbWFwLWJhc2VkIGJpbmRpbmdzIGF0IHJ1bnRpbWUgaXMgcG9zc2libGUgdmlhIHRoZVxuICogYGFjdGl2ZVN0eWxpbmdNYXBGZWF0dXJlYCBmdW5jdGlvbiAod2hpY2ggaXMgYWxzbyBwcmVzZW50IGluIHRoaXMgZmlsZSkuXG4gKlxuICogIyBUaGUgQWxnb3JpdGhtXG4gKiBXaGVuZXZlciBhIG1hcC1iYXNlZCBiaW5kaW5nIHVwZGF0ZXMgKHdoaWNoIGlzIHdoZW4gdGhlIGlkZW50aXR5IG9mIHRoZVxuICogbWFwLXZhbHVlIGNoYW5nZXMpIHRoZW4gdGhlIG1hcCBpcyBpdGVyYXRlZCBvdmVyIGFuZCBhIGBMU3R5bGluZ01hcGAgYXJyYXlcbiAqIGlzIHByb2R1Y2VkLiBUaGUgYExTdHlsaW5nTWFwYCBpbnN0YW5jZSBpcyBzdG9yZWQgaW4gdGhlIGJpbmRpbmcgbG9jYXRpb25cbiAqIHdoZXJlIHRoZSBgQklORElOR19JTkRFWGAgaXMgc2l0dWF0ZWQgd2hlbiB0aGUgYHN0eWxlTWFwKClgIG9yIGBjbGFzc01hcCgpYFxuICogaW5zdHJ1Y3Rpb24gd2VyZSBjYWxsZWQuIE9uY2UgdGhlIGJpbmRpbmcgY2hhbmdlcywgdGhlbiB0aGUgaW50ZXJuYWwgYGJpdE1hc2tgXG4gKiB2YWx1ZSBpcyBtYXJrZWQgYXMgZGlydHkuXG4gKlxuICogU3R5bGluZyB2YWx1ZXMgYXJlIGFwcGxpZWQgb25jZSBDRCBleGl0cyB0aGUgZWxlbWVudCAod2hpY2ggaGFwcGVucyB3aGVuXG4gKiB0aGUgYHNlbGVjdChuKWAgaW5zdHJ1Y3Rpb24gaXMgY2FsbGVkIG9yIHRoZSB0ZW1wbGF0ZSBmdW5jdGlvbiBleGl0cykuIFdoZW5cbiAqIHRoaXMgb2NjdXJzLCBhbGwgcHJvcC1iYXNlZCBiaW5kaW5ncyBhcmUgYXBwbGllZC4gSWYgYSBtYXAtYmFzZWQgYmluZGluZyBpc1xuICogcHJlc2VudCB0aGVuIGEgc3BlY2lhbCBmbHVzaGluZyBmdW5jdGlvbiAoY2FsbGVkIGEgc3luYyBmdW5jdGlvbikgaXMgbWFkZVxuICogYXZhaWxhYmxlIGFuZCBpdCB3aWxsIGJlIGNhbGxlZCBlYWNoIHRpbWUgYSBzdHlsaW5nIHByb3BlcnR5IGlzIGZsdXNoZWQuXG4gKlxuICogVGhlIGZsdXNoaW5nIGFsZ29yaXRobSBpcyBkZXNpZ25lZCB0byBhcHBseSBzdHlsaW5nIGZvciBhIHByb3BlcnR5ICh3aGljaCBpc1xuICogYSBDU1MgcHJvcGVydHkgb3IgYSBjbGFzc05hbWUgdmFsdWUpIG9uZSBieSBvbmUuIElmIG1hcC1iYXNlZCBiaW5kaW5nc1xuICogYXJlIHByZXNlbnQsIHRoZW4gdGhlIGZsdXNoaW5nIGFsZ29yaXRobSB3aWxsIGtlZXAgY2FsbGluZyB0aGUgbWFwcyBzdHlsaW5nXG4gKiBzeW5jIGZ1bmN0aW9uIGVhY2ggdGltZSBhIHByb3BlcnR5IGlzIHZpc2l0ZWQuIFRoaXMgd2F5LCB0aGUgZmx1c2hpbmdcbiAqIGJlaGF2aW9yIG9mIG1hcC1iYXNlZCBiaW5kaW5ncyB3aWxsIGFsd2F5cyBiZSBhdCB0aGUgc2FtZSBwcm9wZXJ0eSBsZXZlbFxuICogYXMgdGhlIGN1cnJlbnQgcHJvcC1iYXNlZCBwcm9wZXJ0eSBiZWluZyBpdGVyYXRlZCBvdmVyIChiZWNhdXNlIGV2ZXJ5dGhpbmdcbiAqIGlzIGFscGhhYmV0aWNhbGx5IHNvcnRlZCkuXG4gKlxuICogTGV0J3MgaW1hZ2luZSB3ZSBoYXZlIHRoZSBmb2xsb3dpbmcgSFRNTCB0ZW1wbGF0ZSBjb2RlOlxuICpcbiAqIGBgYGh0bWxcbiAqIDxkaXYgW3N0eWxlXT1cInt3aWR0aDonMTAwcHgnLCBoZWlnaHQ6JzIwMHB4JywgJ3otaW5kZXgnOicxMCd9XCJcbiAqICAgICAgW3N0eWxlLndpZHRoLnB4XT1cIjIwMFwiPi4uLjwvZGl2PlxuICogYGBgXG4gKlxuICogV2hlbiBDRCBvY2N1cnMsIGJvdGggdGhlIGBbc3R5bGVdYCBhbmQgYFtzdHlsZS53aWR0aF1gIGJpbmRpbmdzXG4gKiBhcmUgZXZhbHVhdGVkLiBUaGVuIHdoZW4gdGhlIHN0eWxlcyBhcmUgZmx1c2hlZCBvbiBzY3JlZW4sIHRoZVxuICogZm9sbG93aW5nIG9wZXJhdGlvbnMgaGFwcGVuOlxuICpcbiAqIDEuIGBbc3R5bGUud2lkdGhdYCBpcyBhdHRlbXB0ZWQgdG8gYmUgd3JpdHRlbiB0byB0aGUgZWxlbWVudC5cbiAqXG4gKiAyLiAgT25jZSB0aGF0IGhhcHBlbnMsIHRoZSBhbGdvcml0aG0gaW5zdHJ1Y3RzIHRoZSBtYXAtYmFzZWRcbiAqICAgICBlbnRyaWVzIChgW3N0eWxlXWAgaW4gdGhpcyBjYXNlKSB0byBcImNhdGNoIHVwXCIgYW5kIGFwcGx5XG4gKiAgICAgYWxsIHZhbHVlcyB1cCB0byB0aGUgYHdpZHRoYCB2YWx1ZS4gV2hlbiB0aGlzIGhhcHBlbnMgdGhlXG4gKiAgICAgYGhlaWdodGAgdmFsdWUgaXMgYXBwbGllZCB0byB0aGUgZWxlbWVudCAoc2luY2UgaXQgaXNcbiAqICAgICBhbHBoYWJldGljYWxseSBzaXR1YXRlZCBiZWZvcmUgdGhlIGB3aWR0aGAgcHJvcGVydHkpLlxuICpcbiAqIDMuIFNpbmNlIHRoZXJlIGFyZSBubyBtb3JlIHByb3AtYmFzZWQgZW50cmllcyBhbnltb3JlLCB0aGVcbiAqICAgIGxvb3AgZXhpdHMgYW5kIHRoZW4sIGp1c3QgYmVmb3JlIHRoZSBmbHVzaGluZyBlbmRzLCBpdFxuICogICAgaW5zdHJ1Y3RzIGFsbCBtYXAtYmFzZWQgYmluZGluZ3MgdG8gXCJmaW5pc2ggdXBcIiBhcHBseWluZ1xuICogICAgdGhlaXIgdmFsdWVzLlxuICpcbiAqIDQuIFRoZSBvbmx5IHJlbWFpbmluZyB2YWx1ZSB3aXRoaW4gdGhlIG1hcC1iYXNlZCBlbnRyaWVzIGlzXG4gKiAgICB0aGUgYHotaW5kZXhgIHZhbHVlIChgd2lkdGhgIGdvdCBza2lwcGVkIGJlY2F1c2UgaXQgd2FzXG4gKiAgICBzdWNjZXNzZnVsbHkgYXBwbGllZCB2aWEgdGhlIHByb3AtYmFzZWQgYFtzdHlsZS53aWR0aF1gXG4gKiAgICBiaW5kaW5nKS4gU2luY2UgYWxsIG1hcC1iYXNlZCBlbnRyaWVzIGFyZSB0b2xkIHRvIFwiZmluaXNoIHVwXCIsXG4gKiAgICB0aGUgYHotaW5kZXhgIHZhbHVlIGlzIGl0ZXJhdGVkIG92ZXIgYW5kIGl0IGlzIHRoZW4gYXBwbGllZFxuICogICAgdG8gdGhlIGVsZW1lbnQuXG4gKlxuICogVGhlIG1vc3QgaW1wb3J0YW50IHRoaW5nIHRvIHRha2Ugbm90ZSBvZiBoZXJlIGlzIHRoYXQgcHJvcC1iYXNlZFxuICogYmluZGluZ3MgYXJlIGV2YWx1YXRlZCBpbiBvcmRlciBhbG9uZ3NpZGUgbWFwLWJhc2VkIGJpbmRpbmdzLlxuICogVGhpcyBhbGxvd3MgYWxsIHN0eWxpbmcgYWNyb3NzIGFuIGVsZW1lbnQgdG8gYmUgYXBwbGllZCBpbiBPKG4pXG4gKiB0aW1lIChhIHNpbWlsYXIgYWxnb3JpdGhtIGlzIHRoYXQgb2YgdGhlIGFycmF5IG1lcmdlIGFsZ29yaXRobVxuICogaW4gbWVyZ2Ugc29ydCkuXG4gKi9cbmV4cG9ydCBjb25zdCBzeW5jU3R5bGluZ01hcDogU3luY1N0eWxpbmdNYXBzRm4gPVxuICAgIChjb250ZXh0OiBUU3R5bGluZ0NvbnRleHQsIHJlbmRlcmVyOiBSZW5kZXJlcjMgfCBQcm9jZWR1cmFsUmVuZGVyZXIzIHwgbnVsbCwgZWxlbWVudDogUkVsZW1lbnQsXG4gICAgIGRhdGE6IExTdHlsaW5nRGF0YSwgYXBwbHlTdHlsaW5nRm46IEFwcGx5U3R5bGluZ0ZuLCBzYW5pdGl6ZXI6IFN0eWxlU2FuaXRpemVGbiB8IG51bGwsXG4gICAgIG1vZGU6IFN0eWxpbmdNYXBzU3luY01vZGUsIHRhcmdldFByb3A/OiBzdHJpbmcgfCBudWxsLFxuICAgICBkZWZhdWx0VmFsdWU/OiBzdHJpbmcgfCBudWxsKTogYm9vbGVhbiA9PiB7XG4gICAgICBsZXQgdGFyZ2V0UHJvcFZhbHVlV2FzQXBwbGllZCA9IGZhbHNlO1xuXG4gICAgICAvLyBvbmNlIHRoZSBtYXAtYmFzZWQgc3R5bGluZyBjb2RlIGlzIGFjdGl2YXRlIGl0IGlzIG5ldmVyIGRlYWN0aXZhdGVkLiBGb3IgdGhpcyByZWFzb24gYVxuICAgICAgLy8gY2hlY2sgdG8gc2VlIGlmIHRoZSBjdXJyZW50IHN0eWxpbmcgY29udGV4dCBoYXMgYW55IG1hcCBiYXNlZCBiaW5kaW5ncyBpcyByZXF1aXJlZC5cbiAgICAgIGNvbnN0IHRvdGFsTWFwcyA9IGdldFZhbHVlc0NvdW50KGNvbnRleHQsIFRTdHlsaW5nQ29udGV4dEluZGV4Lk1hcEJpbmRpbmdzUG9zaXRpb24pO1xuICAgICAgaWYgKHRvdGFsTWFwcykge1xuICAgICAgICBsZXQgcnVuVGhlU3luY0FsZ29yaXRobSA9IHRydWU7XG4gICAgICAgIGNvbnN0IGxvb3BVbnRpbEVuZCA9ICF0YXJnZXRQcm9wO1xuXG4gICAgICAgIC8vIElmIHRoZSBjb2RlIGlzIHRvbGQgdG8gZmluaXNoIHVwIChydW4gdW50aWwgdGhlIGVuZCksIGJ1dCB0aGUgbW9kZVxuICAgICAgICAvLyBoYXNuJ3QgYmVlbiBmbGFnZ2VkIHRvIGFwcGx5IHZhbHVlcyAoaXQgb25seSB0cmF2ZXJzZXMgdmFsdWVzKSB0aGVuXG4gICAgICAgIC8vIHRoZXJlIGlzIG5vIHBvaW50IGluIGl0ZXJhdGluZyBvdmVyIHRoZSBhcnJheSBiZWNhdXNlIG5vdGhpbmcgd2lsbFxuICAgICAgICAvLyBiZSBhcHBsaWVkIHRvIHRoZSBlbGVtZW50LlxuICAgICAgICBpZiAobG9vcFVudGlsRW5kICYmIChtb2RlICYgflN0eWxpbmdNYXBzU3luY01vZGUuQXBwbHlBbGxWYWx1ZXMpKSB7XG4gICAgICAgICAgcnVuVGhlU3luY0FsZ29yaXRobSA9IGZhbHNlO1xuICAgICAgICAgIHRhcmdldFByb3BWYWx1ZVdhc0FwcGxpZWQgPSB0cnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHJ1blRoZVN5bmNBbGdvcml0aG0pIHtcbiAgICAgICAgICB0YXJnZXRQcm9wVmFsdWVXYXNBcHBsaWVkID0gaW5uZXJTeW5jU3R5bGluZ01hcChcbiAgICAgICAgICAgICAgY29udGV4dCwgcmVuZGVyZXIsIGVsZW1lbnQsIGRhdGEsIGFwcGx5U3R5bGluZ0ZuLCBzYW5pdGl6ZXIsIG1vZGUsIHRhcmdldFByb3AgfHwgbnVsbCxcbiAgICAgICAgICAgICAgMCwgZGVmYXVsdFZhbHVlIHx8IG51bGwpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGxvb3BVbnRpbEVuZCkge1xuICAgICAgICAgIHJlc2V0U3luY0N1cnNvcnMoKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGFyZ2V0UHJvcFZhbHVlV2FzQXBwbGllZDtcbiAgICB9O1xuXG4vKipcbiAqIFJlY3Vyc2l2ZSBmdW5jdGlvbiBkZXNpZ25lZCB0byBhcHBseSBtYXAtYmFzZWQgc3R5bGluZyB0byBhbiBlbGVtZW50IG9uZSBtYXAgYXQgYSB0aW1lLlxuICpcbiAqIFRoaXMgZnVuY3Rpb24gaXMgZGVzaWduZWQgdG8gYmUgY2FsbGVkIGZyb20gdGhlIGBzeW5jU3R5bGluZ01hcGAgZnVuY3Rpb24gYW5kIHdpbGxcbiAqIGFwcGx5IG1hcC1iYXNlZCBzdHlsaW5nIGRhdGEgb25lIG1hcCBhdCBhIHRpbWUgdG8gdGhlIHByb3ZpZGVkIGBlbGVtZW50YC5cbiAqXG4gKiBUaGlzIGZ1bmN0aW9uIGlzIHJlY3Vyc2l2ZSBhbmQgaXQgd2lsbCBjYWxsIGl0c2VsZiBpZiBhIGZvbGxvdy11cCBtYXAgdmFsdWUgaXMgdG8gYmVcbiAqIHByb2Nlc3NlZC4gVG8gbGVhcm4gbW9yZSBhYm91dCBob3cgdGhlIGFsZ29yaXRobSB3b3Jrcywgc2VlIGBzeW5jU3R5bGluZ01hcGAuXG4gKi9cbmZ1bmN0aW9uIGlubmVyU3luY1N0eWxpbmdNYXAoXG4gICAgY29udGV4dDogVFN0eWxpbmdDb250ZXh0LCByZW5kZXJlcjogUmVuZGVyZXIzIHwgUHJvY2VkdXJhbFJlbmRlcmVyMyB8IG51bGwsIGVsZW1lbnQ6IFJFbGVtZW50LFxuICAgIGRhdGE6IExTdHlsaW5nRGF0YSwgYXBwbHlTdHlsaW5nRm46IEFwcGx5U3R5bGluZ0ZuLCBzYW5pdGl6ZXI6IFN0eWxlU2FuaXRpemVGbiB8IG51bGwsXG4gICAgbW9kZTogU3R5bGluZ01hcHNTeW5jTW9kZSwgdGFyZ2V0UHJvcDogc3RyaW5nIHwgbnVsbCwgY3VycmVudE1hcEluZGV4OiBudW1iZXIsXG4gICAgZGVmYXVsdFZhbHVlOiBzdHJpbmcgfCBudWxsKTogYm9vbGVhbiB7XG4gIGxldCB0YXJnZXRQcm9wVmFsdWVXYXNBcHBsaWVkID0gZmFsc2U7XG5cbiAgY29uc3QgdG90YWxNYXBzID0gZ2V0VmFsdWVzQ291bnQoY29udGV4dCwgVFN0eWxpbmdDb250ZXh0SW5kZXguTWFwQmluZGluZ3NQb3NpdGlvbik7XG4gIGlmIChjdXJyZW50TWFwSW5kZXggPCB0b3RhbE1hcHMpIHtcbiAgICBjb25zdCBiaW5kaW5nSW5kZXggPSBnZXRCaW5kaW5nVmFsdWUoXG4gICAgICAgIGNvbnRleHQsIFRTdHlsaW5nQ29udGV4dEluZGV4Lk1hcEJpbmRpbmdzUG9zaXRpb24sIGN1cnJlbnRNYXBJbmRleCkgYXMgbnVtYmVyO1xuICAgIGNvbnN0IGxTdHlsaW5nTWFwID0gZGF0YVtiaW5kaW5nSW5kZXhdIGFzIExTdHlsaW5nTWFwO1xuXG4gICAgbGV0IGN1cnNvciA9IGdldEN1cnJlbnRTeW5jQ3Vyc29yKGN1cnJlbnRNYXBJbmRleCk7XG4gICAgd2hpbGUgKGN1cnNvciA8IGxTdHlsaW5nTWFwLmxlbmd0aCkge1xuICAgICAgY29uc3QgcHJvcCA9IGdldE1hcFByb3AobFN0eWxpbmdNYXAsIGN1cnNvcik7XG4gICAgICBjb25zdCBpdGVyYXRlZFRvb0ZhciA9IHRhcmdldFByb3AgJiYgcHJvcCA+IHRhcmdldFByb3A7XG4gICAgICBjb25zdCBpc1RhcmdldFByb3BNYXRjaGVkID0gIWl0ZXJhdGVkVG9vRmFyICYmIHByb3AgPT09IHRhcmdldFByb3A7XG4gICAgICBjb25zdCB2YWx1ZSA9IGdldE1hcFZhbHVlKGxTdHlsaW5nTWFwLCBjdXJzb3IpO1xuICAgICAgY29uc3QgdmFsdWVJc0RlZmluZWQgPSBpc1N0eWxpbmdWYWx1ZURlZmluZWQodmFsdWUpO1xuXG4gICAgICAvLyB0aGUgcmVjdXJzaXZlIGNvZGUgaXMgZGVzaWduZWQgdG8ga2VlcCBhcHBseWluZyB1bnRpbFxuICAgICAgLy8gaXQgcmVhY2hlcyBvciBnb2VzIHBhc3QgdGhlIHRhcmdldCBwcm9wLiBJZiBhbmQgd2hlblxuICAgICAgLy8gdGhpcyBoYXBwZW5zIHRoZW4gaXQgd2lsbCBzdG9wIHByb2Nlc3NpbmcgdmFsdWVzLCBidXRcbiAgICAgIC8vIGFsbCBvdGhlciBtYXAgdmFsdWVzIG11c3QgYWxzbyBjYXRjaCB1cCB0byB0aGUgc2FtZVxuICAgICAgLy8gcG9pbnQuIFRoaXMgaXMgd2h5IGEgcmVjdXJzaXZlIGNhbGwgaXMgc3RpbGwgaXNzdWVkXG4gICAgICAvLyBldmVuIGlmIHRoZSBjb2RlIGhhcyBpdGVyYXRlZCB0b28gZmFyLlxuICAgICAgY29uc3QgaW5uZXJNb2RlID1cbiAgICAgICAgICBpdGVyYXRlZFRvb0ZhciA/IG1vZGUgOiByZXNvbHZlSW5uZXJNYXBNb2RlKG1vZGUsIHZhbHVlSXNEZWZpbmVkLCBpc1RhcmdldFByb3BNYXRjaGVkKTtcbiAgICAgIGNvbnN0IGlubmVyUHJvcCA9IGl0ZXJhdGVkVG9vRmFyID8gdGFyZ2V0UHJvcCA6IHByb3A7XG4gICAgICBsZXQgdmFsdWVBcHBsaWVkID0gaW5uZXJTeW5jU3R5bGluZ01hcChcbiAgICAgICAgICBjb250ZXh0LCByZW5kZXJlciwgZWxlbWVudCwgZGF0YSwgYXBwbHlTdHlsaW5nRm4sIHNhbml0aXplciwgaW5uZXJNb2RlLCBpbm5lclByb3AsXG4gICAgICAgICAgY3VycmVudE1hcEluZGV4ICsgMSwgZGVmYXVsdFZhbHVlKTtcblxuICAgICAgaWYgKGl0ZXJhdGVkVG9vRmFyKSB7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuXG4gICAgICBpZiAoIXZhbHVlQXBwbGllZCAmJiBpc1ZhbHVlQWxsb3dlZFRvQmVBcHBsaWVkKG1vZGUsIGlzVGFyZ2V0UHJvcE1hdGNoZWQpKSB7XG4gICAgICAgIGNvbnN0IHVzZURlZmF1bHQgPSBpc1RhcmdldFByb3BNYXRjaGVkICYmICF2YWx1ZUlzRGVmaW5lZDtcbiAgICAgICAgY29uc3QgdmFsdWVUb0FwcGx5ID0gdXNlRGVmYXVsdCA/IGRlZmF1bHRWYWx1ZSA6IHZhbHVlO1xuICAgICAgICBjb25zdCBiaW5kaW5nSW5kZXhUb0FwcGx5ID0gdXNlRGVmYXVsdCA/IGJpbmRpbmdJbmRleCA6IG51bGw7XG4gICAgICAgIGNvbnN0IGZpbmFsVmFsdWUgPSBzYW5pdGl6ZXIgP1xuICAgICAgICAgICAgc2FuaXRpemVyKHByb3AsIHZhbHVlVG9BcHBseSwgU3R5bGVTYW5pdGl6ZU1vZGUuVmFsaWRhdGVBbmRTYW5pdGl6ZSkgOlxuICAgICAgICAgICAgdmFsdWVUb0FwcGx5O1xuICAgICAgICBhcHBseVN0eWxpbmdGbihyZW5kZXJlciwgZWxlbWVudCwgcHJvcCwgZmluYWxWYWx1ZSwgYmluZGluZ0luZGV4VG9BcHBseSk7XG4gICAgICAgIHZhbHVlQXBwbGllZCA9IHRydWU7XG4gICAgICB9XG5cbiAgICAgIHRhcmdldFByb3BWYWx1ZVdhc0FwcGxpZWQgPSB2YWx1ZUFwcGxpZWQgJiYgaXNUYXJnZXRQcm9wTWF0Y2hlZDtcbiAgICAgIGN1cnNvciArPSBMU3R5bGluZ01hcEluZGV4LlR1cGxlU2l6ZTtcbiAgICB9XG4gICAgc2V0Q3VycmVudFN5bmNDdXJzb3IoY3VycmVudE1hcEluZGV4LCBjdXJzb3IpO1xuICB9XG5cbiAgcmV0dXJuIHRhcmdldFByb3BWYWx1ZVdhc0FwcGxpZWQ7XG59XG5cblxuLyoqXG4gKiBFbmFibGVzIHN1cHBvcnQgZm9yIG1hcC1iYXNlZCBzdHlsaW5nIGJpbmRpbmdzIChlLmcuIGBbc3R5bGVdYCBhbmQgYFtjbGFzc11gIGJpbmRpbmdzKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFjdGl2ZVN0eWxpbmdNYXBGZWF0dXJlKCkge1xuICBzZXRTdHlsaW5nTWFwc1N5bmNGbihzeW5jU3R5bGluZ01hcCk7XG59XG5cbi8qKlxuICogVXNlZCB0byBkZXRlcm1pbmUgdGhlIG1vZGUgZm9yIHRoZSBpbm5lciByZWN1cnNpdmUgY2FsbC5cbiAqXG4gKiBJZiBhbiBpbm5lciBtYXAgaXMgaXRlcmF0ZWQgb24gdGhlbiB0aGlzIGlzIGRvbmUgc28gZm9yIG9uZVxuICogb2YgdHdvIHJlYXNvbnM6XG4gKlxuICogLSBUaGUgdGFyZ2V0IHByb3BlcnR5IHdhcyBkZXRlY3RlZCBhbmQgdGhlIGlubmVyIG1hcFxuICogICBtdXN0IG5vdyBcImNhdGNoIHVwXCIgKHBvaW50ZXItd2lzZSkgdXAgdG8gd2hlcmUgdGhlIGN1cnJlbnRcbiAqICAgbWFwJ3MgY3Vyc29yIGlzIHNpdHVhdGVkLlxuICpcbiAqIC0gVGhlIHRhcmdldCBwcm9wZXJ0eSB3YXMgbm90IGRldGVjdGVkIGluIHRoZSBjdXJyZW50IG1hcFxuICogICBhbmQgbXVzdCBiZSBmb3VuZCBpbiBhbiBpbm5lciBtYXAuIFRoaXMgY2FuIG9ubHkgYmUgYWxsb3dlZFxuICogICBpZiB0aGUgY3VycmVudCBtYXAgaXRlcmF0aW9uIGlzIG5vdCBzZXQgdG8gc2tpcCB0aGUgdGFyZ2V0XG4gKiAgIHByb3BlcnR5LlxuICovXG5mdW5jdGlvbiByZXNvbHZlSW5uZXJNYXBNb2RlKFxuICAgIGN1cnJlbnRNb2RlOiBudW1iZXIsIHZhbHVlSXNEZWZpbmVkOiBib29sZWFuLCBpc0V4YWN0TWF0Y2g6IGJvb2xlYW4pOiBudW1iZXIge1xuICBsZXQgaW5uZXJNb2RlID0gY3VycmVudE1vZGU7XG4gIGlmICghdmFsdWVJc0RlZmluZWQgJiYgaXNFeGFjdE1hdGNoICYmICEoY3VycmVudE1vZGUgJiBTdHlsaW5nTWFwc1N5bmNNb2RlLlNraXBUYXJnZXRQcm9wKSkge1xuICAgIC8vIGNhc2UgMTogc2V0IHRoZSBtb2RlIHRvIGFwcGx5IHRoZSB0YXJnZXRlZCBwcm9wIHZhbHVlIGlmIGl0XG4gICAgLy8gZW5kcyB1cCBiZWluZyBlbmNvdW50ZXJlZCBpbiBhbm90aGVyIG1hcCB2YWx1ZVxuICAgIGlubmVyTW9kZSB8PSBTdHlsaW5nTWFwc1N5bmNNb2RlLkFwcGx5VGFyZ2V0UHJvcDtcbiAgICBpbm5lck1vZGUgJj0gflN0eWxpbmdNYXBzU3luY01vZGUuU2tpcFRhcmdldFByb3A7XG4gIH0gZWxzZSB7XG4gICAgLy8gY2FzZSAyOiBzZXQgdGhlIG1vZGUgdG8gc2tpcCB0aGUgdGFyZ2V0ZWQgcHJvcCB2YWx1ZSBpZiBpdFxuICAgIC8vIGVuZHMgdXAgYmVpbmcgZW5jb3VudGVyZWQgaW4gYW5vdGhlciBtYXAgdmFsdWVcbiAgICBpbm5lck1vZGUgfD0gU3R5bGluZ01hcHNTeW5jTW9kZS5Ta2lwVGFyZ2V0UHJvcDtcbiAgICBpbm5lck1vZGUgJj0gflN0eWxpbmdNYXBzU3luY01vZGUuQXBwbHlUYXJnZXRQcm9wO1xuICB9XG4gIHJldHVybiBpbm5lck1vZGU7XG59XG5cbi8qKlxuICogRGVjaWRlcyB3aGV0aGVyIG9yIG5vdCBhIHByb3AvdmFsdWUgZW50cnkgd2lsbCBiZSBhcHBsaWVkIHRvIGFuIGVsZW1lbnQuXG4gKlxuICogVG8gZGV0ZXJtaW5lIHdoZXRoZXIgb3Igbm90IGEgdmFsdWUgaXMgdG8gYmUgYXBwbGllZCxcbiAqIHRoZSBmb2xsb3dpbmcgcHJvY2VkdXJlIGlzIGV2YWx1YXRlZDpcbiAqXG4gKiBGaXJzdCBjaGVjayB0byBzZWUgdGhlIGN1cnJlbnQgYG1vZGVgIHN0YXR1czpcbiAqICAxLiBJZiB0aGUgbW9kZSB2YWx1ZSBwZXJtaXRzIGFsbCBwcm9wcyB0byBiZSBhcHBsaWVkIHRoZW4gYWxsb3cuXG4gKiAgICAtIEJ1dCBkbyBub3QgYWxsb3cgaWYgdGhlIGN1cnJlbnQgcHJvcCBpcyBzZXQgdG8gYmUgc2tpcHBlZC5cbiAqICAyLiBPdGhlcndpc2UgaWYgdGhlIGN1cnJlbnQgcHJvcCBpcyBwZXJtaXR0ZWQgdGhlbiBhbGxvdy5cbiAqL1xuZnVuY3Rpb24gaXNWYWx1ZUFsbG93ZWRUb0JlQXBwbGllZChtb2RlOiBudW1iZXIsIGlzVGFyZ2V0UHJvcE1hdGNoZWQ6IGJvb2xlYW4pIHtcbiAgbGV0IGRvQXBwbHlWYWx1ZSA9IChtb2RlICYgU3R5bGluZ01hcHNTeW5jTW9kZS5BcHBseUFsbFZhbHVlcykgPiAwO1xuICBpZiAoIWRvQXBwbHlWYWx1ZSkge1xuICAgIGlmIChtb2RlICYgU3R5bGluZ01hcHNTeW5jTW9kZS5BcHBseVRhcmdldFByb3ApIHtcbiAgICAgIGRvQXBwbHlWYWx1ZSA9IGlzVGFyZ2V0UHJvcE1hdGNoZWQ7XG4gICAgfVxuICB9IGVsc2UgaWYgKChtb2RlICYgU3R5bGluZ01hcHNTeW5jTW9kZS5Ta2lwVGFyZ2V0UHJvcCkgJiYgaXNUYXJnZXRQcm9wTWF0Y2hlZCkge1xuICAgIGRvQXBwbHlWYWx1ZSA9IGZhbHNlO1xuICB9XG4gIHJldHVybiBkb0FwcGx5VmFsdWU7XG59XG5cbi8qKlxuICogVXNlZCB0byBrZWVwIHRyYWNrIG9mIGNvbmN1cnJlbnQgY3Vyc29yIHZhbHVlcyBmb3IgbXVsdGlwbGUgbWFwLWJhc2VkIHN0eWxpbmcgYmluZGluZ3MgcHJlc2VudCBvblxuICogYW4gZWxlbWVudC5cbiAqL1xuY29uc3QgTUFQX0NVUlNPUlM6IG51bWJlcltdID0gW107XG5cbi8qKlxuICogVXNlZCB0byByZXNldCB0aGUgc3RhdGUgb2YgZWFjaCBjdXJzb3IgdmFsdWUgYmVpbmcgdXNlZCB0byBpdGVyYXRlIG92ZXIgbWFwLWJhc2VkIHN0eWxpbmdcbiAqIGJpbmRpbmdzLlxuICovXG5mdW5jdGlvbiByZXNldFN5bmNDdXJzb3JzKCkge1xuICBmb3IgKGxldCBpID0gMDsgaSA8IE1BUF9DVVJTT1JTLmxlbmd0aDsgaSsrKSB7XG4gICAgTUFQX0NVUlNPUlNbaV0gPSBMU3R5bGluZ01hcEluZGV4LlZhbHVlc1N0YXJ0UG9zaXRpb247XG4gIH1cbn1cblxuLyoqXG4gKiBSZXR1cm5zIGFuIGFjdGl2ZSBjdXJzb3IgdmFsdWUgYXQgYSBnaXZlbiBtYXBJbmRleCBsb2NhdGlvbi5cbiAqL1xuZnVuY3Rpb24gZ2V0Q3VycmVudFN5bmNDdXJzb3IobWFwSW5kZXg6IG51bWJlcikge1xuICBpZiAobWFwSW5kZXggPj0gTUFQX0NVUlNPUlMubGVuZ3RoKSB7XG4gICAgTUFQX0NVUlNPUlMucHVzaChMU3R5bGluZ01hcEluZGV4LlZhbHVlc1N0YXJ0UG9zaXRpb24pO1xuICB9XG4gIHJldHVybiBNQVBfQ1VSU09SU1ttYXBJbmRleF07XG59XG5cbi8qKlxuICogU2V0cyBhIGN1cnNvciB2YWx1ZSBhdCBhIGdpdmVuIG1hcEluZGV4IGxvY2F0aW9uLlxuICovXG5mdW5jdGlvbiBzZXRDdXJyZW50U3luY0N1cnNvcihtYXBJbmRleDogbnVtYmVyLCBpbmRleFZhbHVlOiBudW1iZXIpIHtcbiAgTUFQX0NVUlNPUlNbbWFwSW5kZXhdID0gaW5kZXhWYWx1ZTtcbn1cblxuLyoqXG4gKiBVc2VkIHRvIGNvbnZlcnQgYSB7a2V5OnZhbHVlfSBtYXAgaW50byBhIGBMU3R5bGluZ01hcGAgYXJyYXkuXG4gKlxuICogVGhpcyBmdW5jdGlvbiB3aWxsIGVpdGhlciBnZW5lcmF0ZSBhIG5ldyBgTFN0eWxpbmdNYXBgIGluc3RhbmNlXG4gKiBvciBpdCB3aWxsIHBhdGNoIHRoZSBwcm92aWRlZCBgbmV3VmFsdWVzYCBtYXAgdmFsdWUgaW50byBhblxuICogZXhpc3RpbmcgYExTdHlsaW5nTWFwYCB2YWx1ZSAodGhpcyBvbmx5IGhhcHBlbnMgaWYgYGJpbmRpbmdWYWx1ZWBcbiAqIGlzIGFuIGluc3RhbmNlIG9mIGBMU3R5bGluZ01hcGApLlxuICpcbiAqIElmIGEgbmV3IGtleS92YWx1ZSBtYXAgaXMgcHJvdmlkZWQgd2l0aCBhbiBvbGQgYExTdHlsaW5nTWFwYFxuICogdmFsdWUgdGhlbiBhbGwgcHJvcGVydGllcyB3aWxsIGJlIG92ZXJ3cml0dGVuIHdpdGggdGhlaXIgbmV3XG4gKiB2YWx1ZXMgb3Igd2l0aCBgbnVsbGAuIFRoaXMgbWVhbnMgdGhhdCB0aGUgYXJyYXkgd2lsbCBuZXZlclxuICogc2hyaW5rIGluIHNpemUgKGJ1dCBpdCB3aWxsIGFsc28gbm90IGJlIGNyZWF0ZWQgYW5kIHRocm93blxuICogYXdheSB3aGVuZXZlciB0aGUge2tleTp2YWx1ZX0gbWFwIGVudHJpZXMgY2hhbmdlKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG5vcm1hbGl6ZUludG9TdHlsaW5nTWFwKFxuICAgIGJpbmRpbmdWYWx1ZTogbnVsbCB8IExTdHlsaW5nTWFwLFxuICAgIG5ld1ZhbHVlczoge1trZXk6IHN0cmluZ106IGFueX0gfCBzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkKTogTFN0eWxpbmdNYXAge1xuICBjb25zdCBsU3R5bGluZ01hcDogTFN0eWxpbmdNYXAgPSBBcnJheS5pc0FycmF5KGJpbmRpbmdWYWx1ZSkgPyBiaW5kaW5nVmFsdWUgOiBbbnVsbF07XG4gIGxTdHlsaW5nTWFwW0xTdHlsaW5nTWFwSW5kZXguUmF3VmFsdWVQb3NpdGlvbl0gPSBuZXdWYWx1ZXMgfHwgbnVsbDtcblxuICAvLyBiZWNhdXNlIHRoZSBuZXcgdmFsdWVzIG1heSBub3QgaW5jbHVkZSBhbGwgdGhlIHByb3BlcnRpZXNcbiAgLy8gdGhhdCB0aGUgb2xkIG9uZXMgaGFkLCBhbGwgdmFsdWVzIGFyZSBzZXQgdG8gYG51bGxgIGJlZm9yZVxuICAvLyB0aGUgbmV3IHZhbHVlcyBhcmUgYXBwbGllZC4gVGhpcyB3YXksIHdoZW4gZmx1c2hlZCwgdGhlXG4gIC8vIHN0eWxpbmcgYWxnb3JpdGhtIGtub3dzIGV4YWN0bHkgd2hhdCBzdHlsZS9jbGFzcyB2YWx1ZXNcbiAgLy8gdG8gcmVtb3ZlIGZyb20gdGhlIGVsZW1lbnQgKHNpbmNlIHRoZXkgYXJlIGBudWxsYCkuXG4gIGZvciAobGV0IGogPSBMU3R5bGluZ01hcEluZGV4LlZhbHVlc1N0YXJ0UG9zaXRpb247IGogPCBsU3R5bGluZ01hcC5sZW5ndGg7XG4gICAgICAgaiArPSBMU3R5bGluZ01hcEluZGV4LlR1cGxlU2l6ZSkge1xuICAgIHNldE1hcFZhbHVlKGxTdHlsaW5nTWFwLCBqLCBudWxsKTtcbiAgfVxuXG4gIGxldCBwcm9wczogc3RyaW5nW118bnVsbCA9IG51bGw7XG4gIGxldCBtYXA6IHtba2V5OiBzdHJpbmddOiBhbnl9fHVuZGVmaW5lZHxudWxsO1xuICBsZXQgYWxsVmFsdWVzVHJ1ZSA9IGZhbHNlO1xuICBpZiAodHlwZW9mIG5ld1ZhbHVlcyA9PT0gJ3N0cmluZycpIHsgIC8vIFtjbGFzc10gYmluZGluZ3MgYWxsb3cgc3RyaW5nIHZhbHVlc1xuICAgIGlmIChuZXdWYWx1ZXMubGVuZ3RoKSB7XG4gICAgICBwcm9wcyA9IG5ld1ZhbHVlcy5zcGxpdCgvXFxzKy8pO1xuICAgICAgYWxsVmFsdWVzVHJ1ZSA9IHRydWU7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHByb3BzID0gbmV3VmFsdWVzID8gT2JqZWN0LmtleXMobmV3VmFsdWVzKSA6IG51bGw7XG4gICAgbWFwID0gbmV3VmFsdWVzO1xuICB9XG5cbiAgaWYgKHByb3BzKSB7XG4gICAgb3V0ZXI6IGZvciAobGV0IGkgPSAwOyBpIDwgcHJvcHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IHByb3AgPSBwcm9wc1tpXSBhcyBzdHJpbmc7XG4gICAgICBjb25zdCB2YWx1ZSA9IGFsbFZhbHVlc1RydWUgPyB0cnVlIDogbWFwICFbcHJvcF07XG4gICAgICBmb3IgKGxldCBqID0gTFN0eWxpbmdNYXBJbmRleC5WYWx1ZXNTdGFydFBvc2l0aW9uOyBqIDwgbFN0eWxpbmdNYXAubGVuZ3RoO1xuICAgICAgICAgICBqICs9IExTdHlsaW5nTWFwSW5kZXguVHVwbGVTaXplKSB7XG4gICAgICAgIGNvbnN0IHByb3BBdEluZGV4ID0gZ2V0TWFwUHJvcChsU3R5bGluZ01hcCwgaik7XG4gICAgICAgIGlmIChwcm9wIDw9IHByb3BBdEluZGV4KSB7XG4gICAgICAgICAgaWYgKHByb3BBdEluZGV4ID09PSBwcm9wKSB7XG4gICAgICAgICAgICBzZXRNYXBWYWx1ZShsU3R5bGluZ01hcCwgaiwgdmFsdWUpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBsU3R5bGluZ01hcC5zcGxpY2UoaiwgMCwgcHJvcCwgdmFsdWUpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjb250aW51ZSBvdXRlcjtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgbFN0eWxpbmdNYXAucHVzaChwcm9wLCB2YWx1ZSk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGxTdHlsaW5nTWFwO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0TWFwUHJvcChtYXA6IExTdHlsaW5nTWFwLCBpbmRleDogbnVtYmVyKTogc3RyaW5nIHtcbiAgcmV0dXJuIG1hcFtpbmRleCArIExTdHlsaW5nTWFwSW5kZXguUHJvcE9mZnNldF0gYXMgc3RyaW5nO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gc2V0TWFwVmFsdWUobWFwOiBMU3R5bGluZ01hcCwgaW5kZXg6IG51bWJlciwgdmFsdWU6IHN0cmluZyB8IG51bGwpOiB2b2lkIHtcbiAgbWFwW2luZGV4ICsgTFN0eWxpbmdNYXBJbmRleC5WYWx1ZU9mZnNldF0gPSB2YWx1ZTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldE1hcFZhbHVlKG1hcDogTFN0eWxpbmdNYXAsIGluZGV4OiBudW1iZXIpOiBzdHJpbmd8bnVsbCB7XG4gIHJldHVybiBtYXBbaW5kZXggKyBMU3R5bGluZ01hcEluZGV4LlZhbHVlT2Zmc2V0XSBhcyBzdHJpbmcgfCBudWxsO1xufVxuIl19