"use strict"; (self["webpackChunkramsey_plus_forms"] = self["webpackChunkramsey_plus_forms"] || []).push([[428],{ /***/ 7930: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ A: () => (/* binding */ Component) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6540); /* harmony import */ var classnames__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6942); /* harmony import */ var classnames__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(classnames__WEBPACK_IMPORTED_MODULE_1__); /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __rest(s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; } typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }; var getConditionalProps = function (disabled, isLink, href) { return ({ href: !disabled ? href : undefined, "aria-disabled": (isLink && disabled) || undefined, disabled: !isLink && disabled, }); }; var getLinkIconProps = function (iconPosition) { var _a; var iconClasses = classnames__WEBPACK_IMPORTED_MODULE_1___default()("rds-Link-icon", "rds-Link-icon--".concat(iconPosition)); return _a = { fill: "currentColor", className: iconClasses }, _a["aria-hidden"] = true, _a.focusable = false, _a; }; function Link(_a, ref) { var _b; var children = _a.children, className = _a.className, disabled = _a.disabled, element = _a.element, href = _a.href, LinkIcon = _a.icon, _c = _a.iconPosition, iconPosition = _c === void 0 ? "left" : _c, _d = _a.inheritColor, inheritColor = _d === void 0 ? false : _d, _e = _a.isOnDarkCanvas, isOnDarkCanvas = _e === void 0 ? false : _e, _f = _a.size, size = _f === void 0 ? "medium" : _f, text = _a.text, rest = __rest(_a, ["children", "className", "disabled", "element", "href", "icon", "iconPosition", "inheritColor", "isOnDarkCanvas", "size", "text"]); var isLink = element !== "button"; var Element = element || "a"; var linkClasses = classnames__WEBPACK_IMPORTED_MODULE_1___default()("rds-Link", (_b = {}, _b["rds-Link--".concat(size)] = size !== "medium", _b["rds-Link--inheritColor"] = inheritColor, _b["is-disabled"] = isLink && disabled, _b["on-darkCanvas"] = isOnDarkCanvas, _b), className); return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(Element, __assign({ className: linkClasses }, getConditionalProps(disabled, isLink, href), rest, { ref: ref }), LinkIcon && iconPosition === "left" && (react__WEBPACK_IMPORTED_MODULE_0__.createElement(LinkIcon, __assign({}, getLinkIconProps(iconPosition)))), children || text, LinkIcon && iconPosition === "right" && (react__WEBPACK_IMPORTED_MODULE_0__.createElement(LinkIcon, __assign({}, getLinkIconProps(iconPosition)))))); } var Component = (0,react__WEBPACK_IMPORTED_MODULE_0__.forwardRef)(Link); Component.displayName = "Link"; //# sourceMappingURL=Link.esm.js.map /***/ }), /***/ 9785: /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ mN: () => (/* binding */ useForm) /* harmony export */ }); /* unused harmony exports Controller, Form, FormProvider, Watch, appendErrors, createFormControl, get, set, useController, useFieldArray, useFormContext, useFormState, useWatch */ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6540); var isCheckBoxInput = (element) => element.type === 'checkbox'; var isDateObject = (value) => value instanceof Date; var isNullOrUndefined = (value) => value == null; const isObjectType = (value) => typeof value === 'object'; var isObject = (value) => !isNullOrUndefined(value) && !Array.isArray(value) && isObjectType(value) && !isDateObject(value); var getEventValue = (event) => isObject(event) && event.target ? isCheckBoxInput(event.target) ? event.target.checked : event.target.value : event; var getNodeParentName = (name) => name.substring(0, name.search(/\.\d+(\.|$)/)) || name; var isNameInFieldArray = (names, name) => names.has(getNodeParentName(name)); var isPlainObject = (tempObject) => { const prototypeCopy = tempObject.constructor && tempObject.constructor.prototype; return (isObject(prototypeCopy) && prototypeCopy.hasOwnProperty('isPrototypeOf')); }; var isWeb = typeof window !== 'undefined' && typeof window.HTMLElement !== 'undefined' && typeof document !== 'undefined'; function cloneObject(data) { let copy; const isArray = Array.isArray(data); const isFileListInstance = typeof FileList !== 'undefined' ? data instanceof FileList : false; if (data instanceof Date) { copy = new Date(data); } else if (!(isWeb && (data instanceof Blob || isFileListInstance)) && (isArray || isObject(data))) { copy = isArray ? [] : Object.create(Object.getPrototypeOf(data)); if (!isArray && !isPlainObject(data)) { copy = data; } else { for (const key in data) { if (data.hasOwnProperty(key)) { copy[key] = cloneObject(data[key]); } } } } else { return data; } return copy; } var isKey = (value) => /^\w*$/.test(value); var isUndefined = (val) => val === undefined; var compact = (value) => Array.isArray(value) ? value.filter(Boolean) : []; var stringToPath = (input) => compact(input.replace(/["|']|\]/g, '').split(/\.|\[/)); var get = (object, path, defaultValue) => { if (!path || !isObject(object)) { return defaultValue; } const result = (isKey(path) ? [path] : stringToPath(path)).reduce((result, key) => isNullOrUndefined(result) ? result : result[key], object); return isUndefined(result) || result === object ? isUndefined(object[path]) ? defaultValue : object[path] : result; }; var isBoolean = (value) => typeof value === 'boolean'; var set = (object, path, value) => { let index = -1; const tempPath = isKey(path) ? [path] : stringToPath(path); const length = tempPath.length; const lastIndex = length - 1; while (++index < length) { const key = tempPath[index]; let newValue = value; if (index !== lastIndex) { const objValue = object[key]; newValue = isObject(objValue) || Array.isArray(objValue) ? objValue : !isNaN(+tempPath[index + 1]) ? [] : {}; } if (key === '__proto__' || key === 'constructor' || key === 'prototype') { return; } object[key] = newValue; object = object[key]; } }; const EVENTS = { BLUR: 'blur', FOCUS_OUT: 'focusout', CHANGE: 'change', }; const VALIDATION_MODE = { onBlur: 'onBlur', onChange: 'onChange', onSubmit: 'onSubmit', onTouched: 'onTouched', all: 'all', }; const INPUT_VALIDATION_RULES = { max: 'max', min: 'min', maxLength: 'maxLength', minLength: 'minLength', pattern: 'pattern', required: 'required', validate: 'validate', }; const HookFormContext = react__WEBPACK_IMPORTED_MODULE_0__.createContext(null); HookFormContext.displayName = 'HookFormContext'; /** * This custom hook allows you to access the form context. useFormContext is intended to be used in deeply nested structures, where it would become inconvenient to pass the context as a prop. To be used with {@link FormProvider}. * * @remarks * [API](https://react-hook-form.com/docs/useformcontext) • [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi) * * @returns return all useForm methods * * @example * ```tsx * function App() { * const methods = useForm(); * const onSubmit = data => console.log(data); * * return ( * *
* * * *
* ); * } * * function NestedInput() { * const { register } = useFormContext(); // retrieve all hook methods * return ; * } * ``` */ const useFormContext = () => React.useContext(HookFormContext); /** * A provider component that propagates the `useForm` methods to all children components via [React Context](https://react.dev/reference/react/useContext) API. To be used with {@link useFormContext}. * * @remarks * [API](https://react-hook-form.com/docs/useformcontext) • [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi) * * @param props - all useForm methods * * @example * ```tsx * function App() { * const methods = useForm(); * const onSubmit = data => console.log(data); * * return ( * *
* * * *
* ); * } * * function NestedInput() { * const { register } = useFormContext(); // retrieve all hook methods * return ; * } * ``` */ const FormProvider = (props) => { const { children, ...data } = props; return (React.createElement(HookFormContext.Provider, { value: data }, children)); }; var getProxyFormState = (formState, control, localProxyFormState, isRoot = true) => { const result = { defaultValues: control._defaultValues, }; for (const key in formState) { Object.defineProperty(result, key, { get: () => { const _key = key; if (control._proxyFormState[_key] !== VALIDATION_MODE.all) { control._proxyFormState[_key] = !isRoot || VALIDATION_MODE.all; } localProxyFormState && (localProxyFormState[_key] = true); return formState[_key]; }, }); } return result; }; const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? react__WEBPACK_IMPORTED_MODULE_0__.useLayoutEffect : react__WEBPACK_IMPORTED_MODULE_0__.useEffect; /** * This custom hook allows you to subscribe to each form state, and isolate the re-render at the custom hook level. It has its scope in terms of form state subscription, so it would not affect other useFormState and useForm. Using this hook can reduce the re-render impact on large and complex form application. * * @remarks * [API](https://react-hook-form.com/docs/useformstate) • [Demo](https://codesandbox.io/s/useformstate-75xly) * * @param props - include options on specify fields to subscribe. {@link UseFormStateReturn} * * @example * ```tsx * function App() { * const { register, handleSubmit, control } = useForm({ * defaultValues: { * firstName: "firstName" * }}); * const { dirtyFields } = useFormState({ * control * }); * const onSubmit = (data) => console.log(data); * * return ( *
* * {dirtyFields.firstName &&

Field is dirty.

} * *
* ); * } * ``` */ function useFormState(props) { const methods = useFormContext(); const { control = methods.control, disabled, name, exact } = props || {}; const [formState, updateFormState] = React.useState(control._formState); const _localProxyFormState = React.useRef({ isDirty: false, isLoading: false, dirtyFields: false, touchedFields: false, validatingFields: false, isValidating: false, isValid: false, errors: false, }); useIsomorphicLayoutEffect(() => control._subscribe({ name, formState: _localProxyFormState.current, exact, callback: (formState) => { !disabled && updateFormState({ ...control._formState, ...formState, }); }, }), [name, disabled, exact]); React.useEffect(() => { _localProxyFormState.current.isValid && control._setValid(true); }, [control]); return React.useMemo(() => getProxyFormState(formState, control, _localProxyFormState.current, false), [formState, control]); } var isString = (value) => typeof value === 'string'; var generateWatchOutput = (names, _names, formValues, isGlobal, defaultValue) => { if (isString(names)) { isGlobal && _names.watch.add(names); return get(formValues, names, defaultValue); } if (Array.isArray(names)) { return names.map((fieldName) => (isGlobal && _names.watch.add(fieldName), get(formValues, fieldName))); } isGlobal && (_names.watchAll = true); return formValues; }; var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value); function deepEqual(object1, object2, _internal_visited = new WeakSet()) { if (isPrimitive(object1) || isPrimitive(object2)) { return Object.is(object1, object2); } if (isDateObject(object1) && isDateObject(object2)) { return object1.getTime() === object2.getTime(); } const keys1 = Object.keys(object1); const keys2 = Object.keys(object2); if (keys1.length !== keys2.length) { return false; } if (_internal_visited.has(object1) || _internal_visited.has(object2)) { return true; } _internal_visited.add(object1); _internal_visited.add(object2); for (const key of keys1) { const val1 = object1[key]; if (!keys2.includes(key)) { return false; } if (key !== 'ref') { const val2 = object2[key]; if ((isDateObject(val1) && isDateObject(val2)) || (isObject(val1) && isObject(val2)) || (Array.isArray(val1) && Array.isArray(val2)) ? !deepEqual(val1, val2, _internal_visited) : !Object.is(val1, val2)) { return false; } } } return true; } /** * Custom hook to subscribe to field change and isolate re-rendering at the component level. * * @remarks * * [API](https://react-hook-form.com/docs/usewatch) • [Demo](https://codesandbox.io/s/react-hook-form-v7-ts-usewatch-h9i5e) * * @example * ```tsx * const { control } = useForm(); * const values = useWatch({ * name: "fieldName" * control, * }) * ``` */ function useWatch(props) { const methods = useFormContext(); const { control = methods.control, name, defaultValue, disabled, exact, compute, } = props || {}; const _defaultValue = React.useRef(defaultValue); const _compute = React.useRef(compute); const _computeFormValues = React.useRef(undefined); const _prevControl = React.useRef(control); const _prevName = React.useRef(name); _compute.current = compute; const [value, updateValue] = React.useState(() => { const defaultValue = control._getWatch(name, _defaultValue.current); return _compute.current ? _compute.current(defaultValue) : defaultValue; }); const getCurrentOutput = React.useCallback((values) => { const formValues = generateWatchOutput(name, control._names, values || control._formValues, false, _defaultValue.current); return _compute.current ? _compute.current(formValues) : formValues; }, [control._formValues, control._names, name]); const refreshValue = React.useCallback((values) => { if (!disabled) { const formValues = generateWatchOutput(name, control._names, values || control._formValues, false, _defaultValue.current); if (_compute.current) { const computedFormValues = _compute.current(formValues); if (!deepEqual(computedFormValues, _computeFormValues.current)) { updateValue(computedFormValues); _computeFormValues.current = computedFormValues; } } else { updateValue(formValues); } } }, [control._formValues, control._names, disabled, name]); useIsomorphicLayoutEffect(() => { if (_prevControl.current !== control || !deepEqual(_prevName.current, name)) { _prevControl.current = control; _prevName.current = name; refreshValue(); } return control._subscribe({ name, formState: { values: true, }, exact, callback: (formState) => { refreshValue(formState.values); }, }); }, [control, exact, name, refreshValue]); React.useEffect(() => control._removeUnmounted()); // If name or control changed for this render, synchronously reflect the // latest value so callers (like useController) see the correct value // immediately on the same render. // Optimize: Check control reference first before expensive deepEqual const controlChanged = _prevControl.current !== control; const prevName = _prevName.current; // Cache the computed output to avoid duplicate calls within the same render // We include shouldReturnImmediate in deps to ensure proper recomputation const computedOutput = React.useMemo(() => { if (disabled) { return null; } const nameChanged = !controlChanged && !deepEqual(prevName, name); const shouldReturnImmediate = controlChanged || nameChanged; return shouldReturnImmediate ? getCurrentOutput() : null; }, [disabled, controlChanged, name, prevName, getCurrentOutput]); return computedOutput !== null ? computedOutput : value; } /** * Custom hook to work with controlled component, this function provide you with both form and field level state. Re-render is isolated at the hook level. * * @remarks * [API](https://react-hook-form.com/docs/usecontroller) • [Demo](https://codesandbox.io/s/usecontroller-0o8px) * * @param props - the path name to the form field value, and validation rules. * * @returns field properties, field and form state. {@link UseControllerReturn} * * @example * ```tsx * function Input(props) { * const { field, fieldState, formState } = useController(props); * return ( *
* *

{fieldState.isTouched && "Touched"}

*

{formState.isSubmitted ? "submitted" : ""}

*
* ); * } * ``` */ function useController(props) { const methods = useFormContext(); const { name, disabled, control = methods.control, shouldUnregister, defaultValue, } = props; const isArrayField = isNameInFieldArray(control._names.array, name); const defaultValueMemo = React.useMemo(() => get(control._formValues, name, get(control._defaultValues, name, defaultValue)), [control, name, defaultValue]); const value = useWatch({ control, name, defaultValue: defaultValueMemo, exact: true, }); const formState = useFormState({ control, name, exact: true, }); const _props = React.useRef(props); const _previousNameRef = React.useRef(undefined); const _registerProps = React.useRef(control.register(name, { ...props.rules, value, ...(isBoolean(props.disabled) ? { disabled: props.disabled } : {}), })); _props.current = props; const fieldState = React.useMemo(() => Object.defineProperties({}, { invalid: { enumerable: true, get: () => !!get(formState.errors, name), }, isDirty: { enumerable: true, get: () => !!get(formState.dirtyFields, name), }, isTouched: { enumerable: true, get: () => !!get(formState.touchedFields, name), }, isValidating: { enumerable: true, get: () => !!get(formState.validatingFields, name), }, error: { enumerable: true, get: () => get(formState.errors, name), }, }), [formState, name]); const onChange = React.useCallback((event) => _registerProps.current.onChange({ target: { value: getEventValue(event), name: name, }, type: EVENTS.CHANGE, }), [name]); const onBlur = React.useCallback(() => _registerProps.current.onBlur({ target: { value: get(control._formValues, name), name: name, }, type: EVENTS.BLUR, }), [name, control._formValues]); const ref = React.useCallback((elm) => { const field = get(control._fields, name); if (field && elm) { field._f.ref = { focus: () => elm.focus && elm.focus(), select: () => elm.select && elm.select(), setCustomValidity: (message) => elm.setCustomValidity(message), reportValidity: () => elm.reportValidity(), }; } }, [control._fields, name]); const field = React.useMemo(() => ({ name, value, ...(isBoolean(disabled) || formState.disabled ? { disabled: formState.disabled || disabled } : {}), onChange, onBlur, ref, }), [name, disabled, formState.disabled, onChange, onBlur, ref, value]); React.useEffect(() => { const _shouldUnregisterField = control._options.shouldUnregister || shouldUnregister; const previousName = _previousNameRef.current; if (previousName && previousName !== name && !isArrayField) { control.unregister(previousName); } control.register(name, { ..._props.current.rules, ...(isBoolean(_props.current.disabled) ? { disabled: _props.current.disabled } : {}), }); const updateMounted = (name, value) => { const field = get(control._fields, name); if (field && field._f) { field._f.mount = value; } }; updateMounted(name, true); if (_shouldUnregisterField) { const value = cloneObject(get(control._options.defaultValues, name, _props.current.defaultValue)); set(control._defaultValues, name, value); if (isUndefined(get(control._formValues, name))) { set(control._formValues, name, value); } } !isArrayField && control.register(name); _previousNameRef.current = name; return () => { (isArrayField ? _shouldUnregisterField && !control._state.action : _shouldUnregisterField) ? control.unregister(name) : updateMounted(name, false); }; }, [name, control, isArrayField, shouldUnregister]); React.useEffect(() => { control._setDisabledField({ disabled, name, }); }, [disabled, name, control]); return React.useMemo(() => ({ field, formState, fieldState, }), [field, formState, fieldState]); } /** * Component based on `useController` hook to work with controlled component. * * @remarks * [API](https://react-hook-form.com/docs/usecontroller/controller) • [Demo](https://codesandbox.io/s/react-hook-form-v6-controller-ts-jwyzw) • [Video](https://www.youtube.com/watch?v=N2UNk_UCVyA) * * @param props - the path name to the form field value, and validation rules. * * @returns provide field handler functions, field and form state. * * @example * ```tsx * function App() { * const { control } = useForm({ * defaultValues: { * test: "" * } * }); * * return ( *
* ( * <> * *

{formState.isSubmitted ? "submitted" : ""}

*

{fieldState.isTouched ? "touched" : ""}

* * )} * /> * * ); * } * ``` */ const Controller = (props) => props.render(useController(props)); const flatten = (obj) => { const output = {}; for (const key of Object.keys(obj)) { if (isObjectType(obj[key]) && obj[key] !== null) { const nested = flatten(obj[key]); for (const nestedKey of Object.keys(nested)) { output[`${key}.${nestedKey}`] = nested[nestedKey]; } } else { output[key] = obj[key]; } } return output; }; const POST_REQUEST = 'post'; /** * Form component to manage submission. * * @param props - to setup submission detail. {@link FormProps} * * @returns form component or headless render prop. * * @example * ```tsx * function App() { * const { control, formState: { errors } } = useForm(); * * return ( *
* *

{errors?.root?.server && 'Server error'}

* *
* ); * } * ``` */ function Form(props) { const methods = useFormContext(); const [mounted, setMounted] = React.useState(false); const { control = methods.control, onSubmit, children, action, method = POST_REQUEST, headers, encType, onError, render, onSuccess, validateStatus, ...rest } = props; const submit = async (event) => { let hasError = false; let type = ''; await control.handleSubmit(async (data) => { const formData = new FormData(); let formDataJson = ''; try { formDataJson = JSON.stringify(data); } catch (_a) { } const flattenFormValues = flatten(control._formValues); for (const key in flattenFormValues) { formData.append(key, flattenFormValues[key]); } if (onSubmit) { await onSubmit({ data, event, method, formData, formDataJson, }); } if (action) { try { const shouldStringifySubmissionData = [ headers && headers['Content-Type'], encType, ].some((value) => value && value.includes('json')); const response = await fetch(String(action), { method, headers: { ...headers, ...(encType && encType !== 'multipart/form-data' ? { 'Content-Type': encType } : {}), }, body: shouldStringifySubmissionData ? formDataJson : formData, }); if (response && (validateStatus ? !validateStatus(response.status) : response.status < 200 || response.status >= 300)) { hasError = true; onError && onError({ response }); type = String(response.status); } else { onSuccess && onSuccess({ response }); } } catch (error) { hasError = true; onError && onError({ error }); } } })(event); if (hasError && props.control) { props.control._subjects.state.next({ isSubmitSuccessful: false, }); props.control.setError('root.server', { type, }); } }; React.useEffect(() => { setMounted(true); }, []); return render ? (React.createElement(React.Fragment, null, render({ submit, }))) : (React.createElement("form", { noValidate: mounted, action: action, method: method, encType: encType, onSubmit: submit, ...rest }, children)); } var appendErrors = (name, validateAllFieldCriteria, errors, type, message) => validateAllFieldCriteria ? { ...errors[name], types: { ...(errors[name] && errors[name].types ? errors[name].types : {}), [type]: message || true, }, } : {}; var convertToArrayPayload = (value) => (Array.isArray(value) ? value : [value]); var createSubject = () => { let _observers = []; const next = (value) => { for (const observer of _observers) { observer.next && observer.next(value); } }; const subscribe = (observer) => { _observers.push(observer); return { unsubscribe: () => { _observers = _observers.filter((o) => o !== observer); }, }; }; const unsubscribe = () => { _observers = []; }; return { get observers() { return _observers; }, next, subscribe, unsubscribe, }; }; function extractFormValues(fieldsState, formValues) { const values = {}; for (const key in fieldsState) { if (fieldsState.hasOwnProperty(key)) { const fieldState = fieldsState[key]; const fieldValue = formValues[key]; if (fieldState && isObject(fieldState) && fieldValue) { const nestedFieldsState = extractFormValues(fieldState, fieldValue); if (isObject(nestedFieldsState)) { values[key] = nestedFieldsState; } } else if (fieldsState[key]) { values[key] = fieldValue; } } } return values; } var isEmptyObject = (value) => isObject(value) && !Object.keys(value).length; var isFileInput = (element) => element.type === 'file'; var isFunction = (value) => typeof value === 'function'; var isHTMLElement = (value) => { if (!isWeb) { return false; } const owner = value ? value.ownerDocument : 0; return (value instanceof (owner && owner.defaultView ? owner.defaultView.HTMLElement : HTMLElement)); }; var isMultipleSelect = (element) => element.type === `select-multiple`; var isRadioInput = (element) => element.type === 'radio'; var isRadioOrCheckbox = (ref) => isRadioInput(ref) || isCheckBoxInput(ref); var live = (ref) => isHTMLElement(ref) && ref.isConnected; function baseGet(object, updatePath) { const length = updatePath.slice(0, -1).length; let index = 0; while (index < length) { object = isUndefined(object) ? index++ : object[updatePath[index++]]; } return object; } function isEmptyArray(obj) { for (const key in obj) { if (obj.hasOwnProperty(key) && !isUndefined(obj[key])) { return false; } } return true; } function unset(object, path) { const paths = Array.isArray(path) ? path : isKey(path) ? [path] : stringToPath(path); const childObject = paths.length === 1 ? object : baseGet(object, paths); const index = paths.length - 1; const key = paths[index]; if (childObject) { delete childObject[key]; } if (index !== 0 && ((isObject(childObject) && isEmptyObject(childObject)) || (Array.isArray(childObject) && isEmptyArray(childObject)))) { unset(object, paths.slice(0, -1)); } return object; } var objectHasFunction = (data) => { for (const key in data) { if (isFunction(data[key])) { return true; } } return false; }; function isTraversable(value) { return Array.isArray(value) || (isObject(value) && !objectHasFunction(value)); } function markFieldsDirty(data, fields = {}) { for (const key in data) { const value = data[key]; if (isTraversable(value)) { fields[key] = Array.isArray(value) ? [] : {}; markFieldsDirty(value, fields[key]); } else if (!isUndefined(value)) { fields[key] = true; } } return fields; } function getDirtyFields(data, formValues, dirtyFieldsFromValues) { if (!dirtyFieldsFromValues) { dirtyFieldsFromValues = markFieldsDirty(formValues); } for (const key in data) { const value = data[key]; if (isTraversable(value)) { if (isUndefined(formValues) || isPrimitive(dirtyFieldsFromValues[key])) { dirtyFieldsFromValues[key] = markFieldsDirty(value, Array.isArray(value) ? [] : {}); } else { getDirtyFields(value, isNullOrUndefined(formValues) ? {} : formValues[key], dirtyFieldsFromValues[key]); } } else { const formValue = formValues[key]; dirtyFieldsFromValues[key] = !deepEqual(value, formValue); } } return dirtyFieldsFromValues; } const defaultResult = { value: false, isValid: false, }; const validResult = { value: true, isValid: true }; var getCheckboxValue = (options) => { if (Array.isArray(options)) { if (options.length > 1) { const values = options .filter((option) => option && option.checked && !option.disabled) .map((option) => option.value); return { value: values, isValid: !!values.length }; } return options[0].checked && !options[0].disabled ? // @ts-expect-error expected to work in the browser options[0].attributes && !isUndefined(options[0].attributes.value) ? isUndefined(options[0].value) || options[0].value === '' ? validResult : { value: options[0].value, isValid: true } : validResult : defaultResult; } return defaultResult; }; var getFieldValueAs = (value, { valueAsNumber, valueAsDate, setValueAs }) => isUndefined(value) ? value : valueAsNumber ? value === '' ? NaN : value ? +value : value : valueAsDate && isString(value) ? new Date(value) : setValueAs ? setValueAs(value) : value; const defaultReturn = { isValid: false, value: null, }; var getRadioValue = (options) => Array.isArray(options) ? options.reduce((previous, option) => option && option.checked && !option.disabled ? { isValid: true, value: option.value, } : previous, defaultReturn) : defaultReturn; function getFieldValue(_f) { const ref = _f.ref; if (isFileInput(ref)) { return ref.files; } if (isRadioInput(ref)) { return getRadioValue(_f.refs).value; } if (isMultipleSelect(ref)) { return [...ref.selectedOptions].map(({ value }) => value); } if (isCheckBoxInput(ref)) { return getCheckboxValue(_f.refs).value; } return getFieldValueAs(isUndefined(ref.value) ? _f.ref.value : ref.value, _f); } var getResolverOptions = (fieldsNames, _fields, criteriaMode, shouldUseNativeValidation) => { const fields = {}; for (const name of fieldsNames) { const field = get(_fields, name); field && set(fields, name, field._f); } return { criteriaMode, names: [...fieldsNames], fields, shouldUseNativeValidation, }; }; var isRegex = (value) => value instanceof RegExp; var getRuleValue = (rule) => isUndefined(rule) ? rule : isRegex(rule) ? rule.source : isObject(rule) ? isRegex(rule.value) ? rule.value.source : rule.value : rule; var getValidationModes = (mode) => ({ isOnSubmit: !mode || mode === VALIDATION_MODE.onSubmit, isOnBlur: mode === VALIDATION_MODE.onBlur, isOnChange: mode === VALIDATION_MODE.onChange, isOnAll: mode === VALIDATION_MODE.all, isOnTouch: mode === VALIDATION_MODE.onTouched, }); const ASYNC_FUNCTION = 'AsyncFunction'; var hasPromiseValidation = (fieldReference) => !!fieldReference && !!fieldReference.validate && !!((isFunction(fieldReference.validate) && fieldReference.validate.constructor.name === ASYNC_FUNCTION) || (isObject(fieldReference.validate) && Object.values(fieldReference.validate).find((validateFunction) => validateFunction.constructor.name === ASYNC_FUNCTION))); var hasValidation = (options) => options.mount && (options.required || options.min || options.max || options.maxLength || options.minLength || options.pattern || options.validate); var isWatched = (name, _names, isBlurEvent) => !isBlurEvent && (_names.watchAll || _names.watch.has(name) || [..._names.watch].some((watchName) => name.startsWith(watchName) && /^\.\w+/.test(name.slice(watchName.length)))); const iterateFieldsByAction = (fields, action, fieldsNames, abortEarly) => { for (const key of fieldsNames || Object.keys(fields)) { const field = get(fields, key); if (field) { const { _f, ...currentField } = field; if (_f) { if (_f.refs && _f.refs[0] && action(_f.refs[0], key) && !abortEarly) { return true; } else if (_f.ref && action(_f.ref, _f.name) && !abortEarly) { return true; } else { if (iterateFieldsByAction(currentField, action)) { break; } } } else if (isObject(currentField)) { if (iterateFieldsByAction(currentField, action)) { break; } } } } return; }; function schemaErrorLookup(errors, _fields, name) { const error = get(errors, name); if (error || isKey(name)) { return { error, name, }; } const names = name.split('.'); while (names.length) { const fieldName = names.join('.'); const field = get(_fields, fieldName); const foundError = get(errors, fieldName); if (field && !Array.isArray(field) && name !== fieldName) { return { name }; } if (foundError && foundError.type) { return { name: fieldName, error: foundError, }; } if (foundError && foundError.root && foundError.root.type) { return { name: `${fieldName}.root`, error: foundError.root, }; } names.pop(); } return { name, }; } var shouldRenderFormState = (formStateData, _proxyFormState, updateFormState, isRoot) => { updateFormState(formStateData); const { name, ...formState } = formStateData; return (isEmptyObject(formState) || Object.keys(formState).length >= Object.keys(_proxyFormState).length || Object.keys(formState).find((key) => _proxyFormState[key] === (!isRoot || VALIDATION_MODE.all))); }; var shouldSubscribeByName = (name, signalName, exact) => !name || !signalName || name === signalName || convertToArrayPayload(name).some((currentName) => currentName && (exact ? currentName === signalName : currentName.startsWith(signalName) || signalName.startsWith(currentName))); var skipValidation = (isBlurEvent, isTouched, isSubmitted, reValidateMode, mode) => { if (mode.isOnAll) { return false; } else if (!isSubmitted && mode.isOnTouch) { return !(isTouched || isBlurEvent); } else if (isSubmitted ? reValidateMode.isOnBlur : mode.isOnBlur) { return !isBlurEvent; } else if (isSubmitted ? reValidateMode.isOnChange : mode.isOnChange) { return isBlurEvent; } return true; }; var unsetEmptyArray = (ref, name) => !compact(get(ref, name)).length && unset(ref, name); var updateFieldArrayRootError = (errors, error, name) => { const fieldArrayErrors = convertToArrayPayload(get(errors, name)); set(fieldArrayErrors, 'root', error[name]); set(errors, name, fieldArrayErrors); return errors; }; function getValidateError(result, ref, type = 'validate') { if (isString(result) || (Array.isArray(result) && result.every(isString)) || (isBoolean(result) && !result)) { return { type, message: isString(result) ? result : '', ref, }; } } var getValueAndMessage = (validationData) => isObject(validationData) && !isRegex(validationData) ? validationData : { value: validationData, message: '', }; var validateField = async (field, disabledFieldNames, formValues, validateAllFieldCriteria, shouldUseNativeValidation, isFieldArray) => { const { ref, refs, required, maxLength, minLength, min, max, pattern, validate, name, valueAsNumber, mount, } = field._f; const inputValue = get(formValues, name); if (!mount || disabledFieldNames.has(name)) { return {}; } const inputRef = refs ? refs[0] : ref; const setCustomValidity = (message) => { if (shouldUseNativeValidation && inputRef.reportValidity) { inputRef.setCustomValidity(isBoolean(message) ? '' : message || ''); inputRef.reportValidity(); } }; const error = {}; const isRadio = isRadioInput(ref); const isCheckBox = isCheckBoxInput(ref); const isRadioOrCheckbox = isRadio || isCheckBox; const isEmpty = ((valueAsNumber || isFileInput(ref)) && isUndefined(ref.value) && isUndefined(inputValue)) || (isHTMLElement(ref) && ref.value === '') || inputValue === '' || (Array.isArray(inputValue) && !inputValue.length); const appendErrorsCurry = appendErrors.bind(null, name, validateAllFieldCriteria, error); const getMinMaxMessage = (exceedMax, maxLengthMessage, minLengthMessage, maxType = INPUT_VALIDATION_RULES.maxLength, minType = INPUT_VALIDATION_RULES.minLength) => { const message = exceedMax ? maxLengthMessage : minLengthMessage; error[name] = { type: exceedMax ? maxType : minType, message, ref, ...appendErrorsCurry(exceedMax ? maxType : minType, message), }; }; if (isFieldArray ? !Array.isArray(inputValue) || !inputValue.length : required && ((!isRadioOrCheckbox && (isEmpty || isNullOrUndefined(inputValue))) || (isBoolean(inputValue) && !inputValue) || (isCheckBox && !getCheckboxValue(refs).isValid) || (isRadio && !getRadioValue(refs).isValid))) { const { value, message } = isString(required) ? { value: !!required, message: required } : getValueAndMessage(required); if (value) { error[name] = { type: INPUT_VALIDATION_RULES.required, message, ref: inputRef, ...appendErrorsCurry(INPUT_VALIDATION_RULES.required, message), }; if (!validateAllFieldCriteria) { setCustomValidity(message); return error; } } } if (!isEmpty && (!isNullOrUndefined(min) || !isNullOrUndefined(max))) { let exceedMax; let exceedMin; const maxOutput = getValueAndMessage(max); const minOutput = getValueAndMessage(min); if (!isNullOrUndefined(inputValue) && !isNaN(inputValue)) { const valueNumber = ref.valueAsNumber || (inputValue ? +inputValue : inputValue); if (!isNullOrUndefined(maxOutput.value)) { exceedMax = valueNumber > maxOutput.value; } if (!isNullOrUndefined(minOutput.value)) { exceedMin = valueNumber < minOutput.value; } } else { const valueDate = ref.valueAsDate || new Date(inputValue); const convertTimeToDate = (time) => new Date(new Date().toDateString() + ' ' + time); const isTime = ref.type == 'time'; const isWeek = ref.type == 'week'; if (isString(maxOutput.value) && inputValue) { exceedMax = isTime ? convertTimeToDate(inputValue) > convertTimeToDate(maxOutput.value) : isWeek ? inputValue > maxOutput.value : valueDate > new Date(maxOutput.value); } if (isString(minOutput.value) && inputValue) { exceedMin = isTime ? convertTimeToDate(inputValue) < convertTimeToDate(minOutput.value) : isWeek ? inputValue < minOutput.value : valueDate < new Date(minOutput.value); } } if (exceedMax || exceedMin) { getMinMaxMessage(!!exceedMax, maxOutput.message, minOutput.message, INPUT_VALIDATION_RULES.max, INPUT_VALIDATION_RULES.min); if (!validateAllFieldCriteria) { setCustomValidity(error[name].message); return error; } } } if ((maxLength || minLength) && !isEmpty && (isString(inputValue) || (isFieldArray && Array.isArray(inputValue)))) { const maxLengthOutput = getValueAndMessage(maxLength); const minLengthOutput = getValueAndMessage(minLength); const exceedMax = !isNullOrUndefined(maxLengthOutput.value) && inputValue.length > +maxLengthOutput.value; const exceedMin = !isNullOrUndefined(minLengthOutput.value) && inputValue.length < +minLengthOutput.value; if (exceedMax || exceedMin) { getMinMaxMessage(exceedMax, maxLengthOutput.message, minLengthOutput.message); if (!validateAllFieldCriteria) { setCustomValidity(error[name].message); return error; } } } if (pattern && !isEmpty && isString(inputValue)) { const { value: patternValue, message } = getValueAndMessage(pattern); if (isRegex(patternValue) && !inputValue.match(patternValue)) { error[name] = { type: INPUT_VALIDATION_RULES.pattern, message, ref, ...appendErrorsCurry(INPUT_VALIDATION_RULES.pattern, message), }; if (!validateAllFieldCriteria) { setCustomValidity(message); return error; } } } if (validate) { if (isFunction(validate)) { const result = await validate(inputValue, formValues); const validateError = getValidateError(result, inputRef); if (validateError) { error[name] = { ...validateError, ...appendErrorsCurry(INPUT_VALIDATION_RULES.validate, validateError.message), }; if (!validateAllFieldCriteria) { setCustomValidity(validateError.message); return error; } } } else if (isObject(validate)) { let validationResult = {}; for (const key in validate) { if (!isEmptyObject(validationResult) && !validateAllFieldCriteria) { break; } const validateError = getValidateError(await validate[key](inputValue, formValues), inputRef, key); if (validateError) { validationResult = { ...validateError, ...appendErrorsCurry(key, validateError.message), }; setCustomValidity(validateError.message); if (validateAllFieldCriteria) { error[name] = validationResult; } } } if (!isEmptyObject(validationResult)) { error[name] = { ref: inputRef, ...validationResult, }; if (!validateAllFieldCriteria) { return error; } } } } setCustomValidity(true); return error; }; const defaultOptions = { mode: VALIDATION_MODE.onSubmit, reValidateMode: VALIDATION_MODE.onChange, shouldFocusError: true, }; function createFormControl(props = {}) { let _options = { ...defaultOptions, ...props, }; let _formState = { submitCount: 0, isDirty: false, isReady: false, isLoading: isFunction(_options.defaultValues), isValidating: false, isSubmitted: false, isSubmitting: false, isSubmitSuccessful: false, isValid: false, touchedFields: {}, dirtyFields: {}, validatingFields: {}, errors: _options.errors || {}, disabled: _options.disabled || false, }; let _fields = {}; let _defaultValues = isObject(_options.defaultValues) || isObject(_options.values) ? cloneObject(_options.defaultValues || _options.values) || {} : {}; let _formValues = _options.shouldUnregister ? {} : cloneObject(_defaultValues); let _state = { action: false, mount: false, watch: false, }; let _names = { mount: new Set(), disabled: new Set(), unMount: new Set(), array: new Set(), watch: new Set(), }; let delayErrorCallback; let timer = 0; const _proxyFormState = { isDirty: false, dirtyFields: false, validatingFields: false, touchedFields: false, isValidating: false, isValid: false, errors: false, }; let _proxySubscribeFormState = { ..._proxyFormState, }; const _subjects = { array: createSubject(), state: createSubject(), }; const shouldDisplayAllAssociatedErrors = _options.criteriaMode === VALIDATION_MODE.all; const debounce = (callback) => (wait) => { clearTimeout(timer); timer = setTimeout(callback, wait); }; const _setValid = async (shouldUpdateValid) => { if (!_options.disabled && (_proxyFormState.isValid || _proxySubscribeFormState.isValid || shouldUpdateValid)) { const isValid = _options.resolver ? isEmptyObject((await _runSchema()).errors) : await executeBuiltInValidation(_fields, true); if (isValid !== _formState.isValid) { _subjects.state.next({ isValid, }); } } }; const _updateIsValidating = (names, isValidating) => { if (!_options.disabled && (_proxyFormState.isValidating || _proxyFormState.validatingFields || _proxySubscribeFormState.isValidating || _proxySubscribeFormState.validatingFields)) { (names || Array.from(_names.mount)).forEach((name) => { if (name) { isValidating ? set(_formState.validatingFields, name, isValidating) : unset(_formState.validatingFields, name); } }); _subjects.state.next({ validatingFields: _formState.validatingFields, isValidating: !isEmptyObject(_formState.validatingFields), }); } }; const _setFieldArray = (name, values = [], method, args, shouldSetValues = true, shouldUpdateFieldsAndState = true) => { if (args && method && !_options.disabled) { _state.action = true; if (shouldUpdateFieldsAndState && Array.isArray(get(_fields, name))) { const fieldValues = method(get(_fields, name), args.argA, args.argB); shouldSetValues && set(_fields, name, fieldValues); } if (shouldUpdateFieldsAndState && Array.isArray(get(_formState.errors, name))) { const errors = method(get(_formState.errors, name), args.argA, args.argB); shouldSetValues && set(_formState.errors, name, errors); unsetEmptyArray(_formState.errors, name); } if ((_proxyFormState.touchedFields || _proxySubscribeFormState.touchedFields) && shouldUpdateFieldsAndState && Array.isArray(get(_formState.touchedFields, name))) { const touchedFields = method(get(_formState.touchedFields, name), args.argA, args.argB); shouldSetValues && set(_formState.touchedFields, name, touchedFields); } if (_proxyFormState.dirtyFields || _proxySubscribeFormState.dirtyFields) { _formState.dirtyFields = getDirtyFields(_defaultValues, _formValues); } _subjects.state.next({ name, isDirty: _getDirty(name, values), dirtyFields: _formState.dirtyFields, errors: _formState.errors, isValid: _formState.isValid, }); } else { set(_formValues, name, values); } }; const updateErrors = (name, error) => { set(_formState.errors, name, error); _subjects.state.next({ errors: _formState.errors, }); }; const _setErrors = (errors) => { _formState.errors = errors; _subjects.state.next({ errors: _formState.errors, isValid: false, }); }; const updateValidAndValue = (name, shouldSkipSetValueAs, value, ref) => { const field = get(_fields, name); if (field) { const defaultValue = get(_formValues, name, isUndefined(value) ? get(_defaultValues, name) : value); isUndefined(defaultValue) || (ref && ref.defaultChecked) || shouldSkipSetValueAs ? set(_formValues, name, shouldSkipSetValueAs ? defaultValue : getFieldValue(field._f)) : setFieldValue(name, defaultValue); _state.mount && !_state.action && _setValid(); } }; const updateTouchAndDirty = (name, fieldValue, isBlurEvent, shouldDirty, shouldRender) => { let shouldUpdateField = false; let isPreviousDirty = false; const output = { name, }; if (!_options.disabled) { if (!isBlurEvent || shouldDirty) { if (_proxyFormState.isDirty || _proxySubscribeFormState.isDirty) { isPreviousDirty = _formState.isDirty; _formState.isDirty = output.isDirty = _getDirty(); shouldUpdateField = isPreviousDirty !== output.isDirty; } const isCurrentFieldPristine = deepEqual(get(_defaultValues, name), fieldValue); isPreviousDirty = !!get(_formState.dirtyFields, name); isCurrentFieldPristine ? unset(_formState.dirtyFields, name) : set(_formState.dirtyFields, name, true); output.dirtyFields = _formState.dirtyFields; shouldUpdateField = shouldUpdateField || ((_proxyFormState.dirtyFields || _proxySubscribeFormState.dirtyFields) && isPreviousDirty !== !isCurrentFieldPristine); } if (isBlurEvent) { const isPreviousFieldTouched = get(_formState.touchedFields, name); if (!isPreviousFieldTouched) { set(_formState.touchedFields, name, isBlurEvent); output.touchedFields = _formState.touchedFields; shouldUpdateField = shouldUpdateField || ((_proxyFormState.touchedFields || _proxySubscribeFormState.touchedFields) && isPreviousFieldTouched !== isBlurEvent); } } shouldUpdateField && shouldRender && _subjects.state.next(output); } return shouldUpdateField ? output : {}; }; const shouldRenderByError = (name, isValid, error, fieldState) => { const previousFieldError = get(_formState.errors, name); const shouldUpdateValid = (_proxyFormState.isValid || _proxySubscribeFormState.isValid) && isBoolean(isValid) && _formState.isValid !== isValid; if (_options.delayError && error) { delayErrorCallback = debounce(() => updateErrors(name, error)); delayErrorCallback(_options.delayError); } else { clearTimeout(timer); delayErrorCallback = null; error ? set(_formState.errors, name, error) : unset(_formState.errors, name); } if ((error ? !deepEqual(previousFieldError, error) : previousFieldError) || !isEmptyObject(fieldState) || shouldUpdateValid) { const updatedFormState = { ...fieldState, ...(shouldUpdateValid && isBoolean(isValid) ? { isValid } : {}), errors: _formState.errors, name, }; _formState = { ..._formState, ...updatedFormState, }; _subjects.state.next(updatedFormState); } }; const _runSchema = async (name) => { _updateIsValidating(name, true); const result = await _options.resolver(_formValues, _options.context, getResolverOptions(name || _names.mount, _fields, _options.criteriaMode, _options.shouldUseNativeValidation)); _updateIsValidating(name); return result; }; const executeSchemaAndUpdateState = async (names) => { const { errors } = await _runSchema(names); if (names) { for (const name of names) { const error = get(errors, name); error ? set(_formState.errors, name, error) : unset(_formState.errors, name); } } else { _formState.errors = errors; } return errors; }; const executeBuiltInValidation = async (fields, shouldOnlyCheckValid, context = { valid: true, }) => { for (const name in fields) { const field = fields[name]; if (field) { const { _f, ...fieldValue } = field; if (_f) { const isFieldArrayRoot = _names.array.has(_f.name); const isPromiseFunction = field._f && hasPromiseValidation(field._f); if (isPromiseFunction && _proxyFormState.validatingFields) { _updateIsValidating([_f.name], true); } const fieldError = await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation && !shouldOnlyCheckValid, isFieldArrayRoot); if (isPromiseFunction && _proxyFormState.validatingFields) { _updateIsValidating([_f.name]); } if (fieldError[_f.name]) { context.valid = false; if (shouldOnlyCheckValid) { break; } } !shouldOnlyCheckValid && (get(fieldError, _f.name) ? isFieldArrayRoot ? updateFieldArrayRootError(_formState.errors, fieldError, _f.name) : set(_formState.errors, _f.name, fieldError[_f.name]) : unset(_formState.errors, _f.name)); } !isEmptyObject(fieldValue) && (await executeBuiltInValidation(fieldValue, shouldOnlyCheckValid, context)); } } return context.valid; }; const _removeUnmounted = () => { for (const name of _names.unMount) { const field = get(_fields, name); field && (field._f.refs ? field._f.refs.every((ref) => !live(ref)) : !live(field._f.ref)) && unregister(name); } _names.unMount = new Set(); }; const _getDirty = (name, data) => !_options.disabled && (name && data && set(_formValues, name, data), !deepEqual(getValues(), _defaultValues)); const _getWatch = (names, defaultValue, isGlobal) => generateWatchOutput(names, _names, { ...(_state.mount ? _formValues : isUndefined(defaultValue) ? _defaultValues : isString(names) ? { [names]: defaultValue } : defaultValue), }, isGlobal, defaultValue); const _getFieldArray = (name) => compact(get(_state.mount ? _formValues : _defaultValues, name, _options.shouldUnregister ? get(_defaultValues, name, []) : [])); const setFieldValue = (name, value, options = {}) => { const field = get(_fields, name); let fieldValue = value; if (field) { const fieldReference = field._f; if (fieldReference) { !fieldReference.disabled && set(_formValues, name, getFieldValueAs(value, fieldReference)); fieldValue = isHTMLElement(fieldReference.ref) && isNullOrUndefined(value) ? '' : value; if (isMultipleSelect(fieldReference.ref)) { [...fieldReference.ref.options].forEach((optionRef) => (optionRef.selected = fieldValue.includes(optionRef.value))); } else if (fieldReference.refs) { if (isCheckBoxInput(fieldReference.ref)) { fieldReference.refs.forEach((checkboxRef) => { if (!checkboxRef.defaultChecked || !checkboxRef.disabled) { if (Array.isArray(fieldValue)) { checkboxRef.checked = !!fieldValue.find((data) => data === checkboxRef.value); } else { checkboxRef.checked = fieldValue === checkboxRef.value || !!fieldValue; } } }); } else { fieldReference.refs.forEach((radioRef) => (radioRef.checked = radioRef.value === fieldValue)); } } else if (isFileInput(fieldReference.ref)) { fieldReference.ref.value = ''; } else { fieldReference.ref.value = fieldValue; if (!fieldReference.ref.type) { _subjects.state.next({ name, values: cloneObject(_formValues), }); } } } } (options.shouldDirty || options.shouldTouch) && updateTouchAndDirty(name, fieldValue, options.shouldTouch, options.shouldDirty, true); options.shouldValidate && trigger(name); }; const setValues = (name, value, options) => { for (const fieldKey in value) { if (!value.hasOwnProperty(fieldKey)) { return; } const fieldValue = value[fieldKey]; const fieldName = name + '.' + fieldKey; const field = get(_fields, fieldName); (_names.array.has(name) || isObject(fieldValue) || (field && !field._f)) && !isDateObject(fieldValue) ? setValues(fieldName, fieldValue, options) : setFieldValue(fieldName, fieldValue, options); } }; const setValue = (name, value, options = {}) => { const field = get(_fields, name); const isFieldArray = _names.array.has(name); const cloneValue = cloneObject(value); set(_formValues, name, cloneValue); if (isFieldArray) { _subjects.array.next({ name, values: cloneObject(_formValues), }); if ((_proxyFormState.isDirty || _proxyFormState.dirtyFields || _proxySubscribeFormState.isDirty || _proxySubscribeFormState.dirtyFields) && options.shouldDirty) { _subjects.state.next({ name, dirtyFields: getDirtyFields(_defaultValues, _formValues), isDirty: _getDirty(name, cloneValue), }); } } else { field && !field._f && !isNullOrUndefined(cloneValue) ? setValues(name, cloneValue, options) : setFieldValue(name, cloneValue, options); } isWatched(name, _names) && _subjects.state.next({ ..._formState, name }); _subjects.state.next({ name: _state.mount ? name : undefined, values: cloneObject(_formValues), }); }; const onChange = async (event) => { _state.mount = true; const target = event.target; let name = target.name; let isFieldValueUpdated = true; const field = get(_fields, name); const _updateIsFieldValueUpdated = (fieldValue) => { isFieldValueUpdated = Number.isNaN(fieldValue) || (isDateObject(fieldValue) && isNaN(fieldValue.getTime())) || deepEqual(fieldValue, get(_formValues, name, fieldValue)); }; const validationModeBeforeSubmit = getValidationModes(_options.mode); const validationModeAfterSubmit = getValidationModes(_options.reValidateMode); if (field) { let error; let isValid; const fieldValue = target.type ? getFieldValue(field._f) : getEventValue(event); const isBlurEvent = event.type === EVENTS.BLUR || event.type === EVENTS.FOCUS_OUT; const shouldSkipValidation = (!hasValidation(field._f) && !_options.resolver && !get(_formState.errors, name) && !field._f.deps) || skipValidation(isBlurEvent, get(_formState.touchedFields, name), _formState.isSubmitted, validationModeAfterSubmit, validationModeBeforeSubmit); const watched = isWatched(name, _names, isBlurEvent); set(_formValues, name, fieldValue); if (isBlurEvent) { if (!target || !target.readOnly) { field._f.onBlur && field._f.onBlur(event); delayErrorCallback && delayErrorCallback(0); } } else if (field._f.onChange) { field._f.onChange(event); } const fieldState = updateTouchAndDirty(name, fieldValue, isBlurEvent); const shouldRender = !isEmptyObject(fieldState) || watched; !isBlurEvent && _subjects.state.next({ name, type: event.type, values: cloneObject(_formValues), }); if (shouldSkipValidation) { if (_proxyFormState.isValid || _proxySubscribeFormState.isValid) { if (_options.mode === 'onBlur') { if (isBlurEvent) { _setValid(); } } else if (!isBlurEvent) { _setValid(); } } return (shouldRender && _subjects.state.next({ name, ...(watched ? {} : fieldState) })); } !isBlurEvent && watched && _subjects.state.next({ ..._formState }); if (_options.resolver) { const { errors } = await _runSchema([name]); _updateIsFieldValueUpdated(fieldValue); if (isFieldValueUpdated) { const previousErrorLookupResult = schemaErrorLookup(_formState.errors, _fields, name); const errorLookupResult = schemaErrorLookup(errors, _fields, previousErrorLookupResult.name || name); error = errorLookupResult.error; name = errorLookupResult.name; isValid = isEmptyObject(errors); } } else { _updateIsValidating([name], true); error = (await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation))[name]; _updateIsValidating([name]); _updateIsFieldValueUpdated(fieldValue); if (isFieldValueUpdated) { if (error) { isValid = false; } else if (_proxyFormState.isValid || _proxySubscribeFormState.isValid) { isValid = await executeBuiltInValidation(_fields, true); } } } if (isFieldValueUpdated) { field._f.deps && (!Array.isArray(field._f.deps) || field._f.deps.length > 0) && trigger(field._f.deps); shouldRenderByError(name, isValid, error, fieldState); } } }; const _focusInput = (ref, key) => { if (get(_formState.errors, key) && ref.focus) { ref.focus(); return 1; } return; }; const trigger = async (name, options = {}) => { let isValid; let validationResult; const fieldNames = convertToArrayPayload(name); if (_options.resolver) { const errors = await executeSchemaAndUpdateState(isUndefined(name) ? name : fieldNames); isValid = isEmptyObject(errors); validationResult = name ? !fieldNames.some((name) => get(errors, name)) : isValid; } else if (name) { validationResult = (await Promise.all(fieldNames.map(async (fieldName) => { const field = get(_fields, fieldName); return await executeBuiltInValidation(field && field._f ? { [fieldName]: field } : field); }))).every(Boolean); !(!validationResult && !_formState.isValid) && _setValid(); } else { validationResult = isValid = await executeBuiltInValidation(_fields); } _subjects.state.next({ ...(!isString(name) || ((_proxyFormState.isValid || _proxySubscribeFormState.isValid) && isValid !== _formState.isValid) ? {} : { name }), ...(_options.resolver || !name ? { isValid } : {}), errors: _formState.errors, }); options.shouldFocus && !validationResult && iterateFieldsByAction(_fields, _focusInput, name ? fieldNames : _names.mount); return validationResult; }; const getValues = (fieldNames, config) => { let values = { ...(_state.mount ? _formValues : _defaultValues), }; if (config) { values = extractFormValues(config.dirtyFields ? _formState.dirtyFields : _formState.touchedFields, values); } return isUndefined(fieldNames) ? values : isString(fieldNames) ? get(values, fieldNames) : fieldNames.map((name) => get(values, name)); }; const getFieldState = (name, formState) => ({ invalid: !!get((formState || _formState).errors, name), isDirty: !!get((formState || _formState).dirtyFields, name), error: get((formState || _formState).errors, name), isValidating: !!get(_formState.validatingFields, name), isTouched: !!get((formState || _formState).touchedFields, name), }); const clearErrors = (name) => { name && convertToArrayPayload(name).forEach((inputName) => unset(_formState.errors, inputName)); _subjects.state.next({ errors: name ? _formState.errors : {}, }); }; const setError = (name, error, options) => { const ref = (get(_fields, name, { _f: {} })._f || {}).ref; const currentError = get(_formState.errors, name) || {}; // Don't override existing error messages elsewhere in the object tree. const { ref: currentRef, message, type, ...restOfErrorTree } = currentError; set(_formState.errors, name, { ...restOfErrorTree, ...error, ref, }); _subjects.state.next({ name, errors: _formState.errors, isValid: false, }); options && options.shouldFocus && ref && ref.focus && ref.focus(); }; const watch = (name, defaultValue) => isFunction(name) ? _subjects.state.subscribe({ next: (payload) => 'values' in payload && name(_getWatch(undefined, defaultValue), payload), }) : _getWatch(name, defaultValue, true); const _subscribe = (props) => _subjects.state.subscribe({ next: (formState) => { if (shouldSubscribeByName(props.name, formState.name, props.exact) && shouldRenderFormState(formState, props.formState || _proxyFormState, _setFormState, props.reRenderRoot)) { props.callback({ values: { ..._formValues }, ..._formState, ...formState, defaultValues: _defaultValues, }); } }, }).unsubscribe; const subscribe = (props) => { _state.mount = true; _proxySubscribeFormState = { ..._proxySubscribeFormState, ...props.formState, }; return _subscribe({ ...props, formState: _proxySubscribeFormState, }); }; const unregister = (name, options = {}) => { for (const fieldName of name ? convertToArrayPayload(name) : _names.mount) { _names.mount.delete(fieldName); _names.array.delete(fieldName); if (!options.keepValue) { unset(_fields, fieldName); unset(_formValues, fieldName); } !options.keepError && unset(_formState.errors, fieldName); !options.keepDirty && unset(_formState.dirtyFields, fieldName); !options.keepTouched && unset(_formState.touchedFields, fieldName); !options.keepIsValidating && unset(_formState.validatingFields, fieldName); !_options.shouldUnregister && !options.keepDefaultValue && unset(_defaultValues, fieldName); } _subjects.state.next({ values: cloneObject(_formValues), }); _subjects.state.next({ ..._formState, ...(!options.keepDirty ? {} : { isDirty: _getDirty() }), }); !options.keepIsValid && _setValid(); }; const _setDisabledField = ({ disabled, name, }) => { if ((isBoolean(disabled) && _state.mount) || !!disabled || _names.disabled.has(name)) { disabled ? _names.disabled.add(name) : _names.disabled.delete(name); } }; const register = (name, options = {}) => { let field = get(_fields, name); const disabledIsDefined = isBoolean(options.disabled) || isBoolean(_options.disabled); set(_fields, name, { ...(field || {}), _f: { ...(field && field._f ? field._f : { ref: { name } }), name, mount: true, ...options, }, }); _names.mount.add(name); if (field) { _setDisabledField({ disabled: isBoolean(options.disabled) ? options.disabled : _options.disabled, name, }); } else { updateValidAndValue(name, true, options.value); } return { ...(disabledIsDefined ? { disabled: options.disabled || _options.disabled } : {}), ...(_options.progressive ? { required: !!options.required, min: getRuleValue(options.min), max: getRuleValue(options.max), minLength: getRuleValue(options.minLength), maxLength: getRuleValue(options.maxLength), pattern: getRuleValue(options.pattern), } : {}), name, onChange, onBlur: onChange, ref: (ref) => { if (ref) { register(name, options); field = get(_fields, name); const fieldRef = isUndefined(ref.value) ? ref.querySelectorAll ? ref.querySelectorAll('input,select,textarea')[0] || ref : ref : ref; const radioOrCheckbox = isRadioOrCheckbox(fieldRef); const refs = field._f.refs || []; if (radioOrCheckbox ? refs.find((option) => option === fieldRef) : fieldRef === field._f.ref) { return; } set(_fields, name, { _f: { ...field._f, ...(radioOrCheckbox ? { refs: [ ...refs.filter(live), fieldRef, ...(Array.isArray(get(_defaultValues, name)) ? [{}] : []), ], ref: { type: fieldRef.type, name }, } : { ref: fieldRef }), }, }); updateValidAndValue(name, false, undefined, fieldRef); } else { field = get(_fields, name, {}); if (field._f) { field._f.mount = false; } (_options.shouldUnregister || options.shouldUnregister) && !(isNameInFieldArray(_names.array, name) && _state.action) && _names.unMount.add(name); } }, }; }; const _focusError = () => _options.shouldFocusError && iterateFieldsByAction(_fields, _focusInput, _names.mount); const _disableForm = (disabled) => { if (isBoolean(disabled)) { _subjects.state.next({ disabled }); iterateFieldsByAction(_fields, (ref, name) => { const currentField = get(_fields, name); if (currentField) { ref.disabled = currentField._f.disabled || disabled; if (Array.isArray(currentField._f.refs)) { currentField._f.refs.forEach((inputRef) => { inputRef.disabled = currentField._f.disabled || disabled; }); } } }, 0, false); } }; const handleSubmit = (onValid, onInvalid) => async (e) => { let onValidError = undefined; if (e) { e.preventDefault && e.preventDefault(); e.persist && e.persist(); } let fieldValues = cloneObject(_formValues); _subjects.state.next({ isSubmitting: true, }); if (_options.resolver) { const { errors, values } = await _runSchema(); _formState.errors = errors; fieldValues = cloneObject(values); } else { await executeBuiltInValidation(_fields); } if (_names.disabled.size) { for (const name of _names.disabled) { unset(fieldValues, name); } } unset(_formState.errors, 'root'); if (isEmptyObject(_formState.errors)) { _subjects.state.next({ errors: {}, }); try { await onValid(fieldValues, e); } catch (error) { onValidError = error; } } else { if (onInvalid) { await onInvalid({ ..._formState.errors }, e); } _focusError(); setTimeout(_focusError); } _subjects.state.next({ isSubmitted: true, isSubmitting: false, isSubmitSuccessful: isEmptyObject(_formState.errors) && !onValidError, submitCount: _formState.submitCount + 1, errors: _formState.errors, }); if (onValidError) { throw onValidError; } }; const resetField = (name, options = {}) => { if (get(_fields, name)) { if (isUndefined(options.defaultValue)) { setValue(name, cloneObject(get(_defaultValues, name))); } else { setValue(name, options.defaultValue); set(_defaultValues, name, cloneObject(options.defaultValue)); } if (!options.keepTouched) { unset(_formState.touchedFields, name); } if (!options.keepDirty) { unset(_formState.dirtyFields, name); _formState.isDirty = options.defaultValue ? _getDirty(name, cloneObject(get(_defaultValues, name))) : _getDirty(); } if (!options.keepError) { unset(_formState.errors, name); _proxyFormState.isValid && _setValid(); } _subjects.state.next({ ..._formState }); } }; const _reset = (formValues, keepStateOptions = {}) => { const updatedValues = formValues ? cloneObject(formValues) : _defaultValues; const cloneUpdatedValues = cloneObject(updatedValues); const isEmptyResetValues = isEmptyObject(formValues); const values = isEmptyResetValues ? _defaultValues : cloneUpdatedValues; if (!keepStateOptions.keepDefaultValues) { _defaultValues = updatedValues; } if (!keepStateOptions.keepValues) { if (keepStateOptions.keepDirtyValues) { const fieldsToCheck = new Set([ ..._names.mount, ...Object.keys(getDirtyFields(_defaultValues, _formValues)), ]); for (const fieldName of Array.from(fieldsToCheck)) { get(_formState.dirtyFields, fieldName) ? set(values, fieldName, get(_formValues, fieldName)) : setValue(fieldName, get(values, fieldName)); } } else { if (isWeb && isUndefined(formValues)) { for (const name of _names.mount) { const field = get(_fields, name); if (field && field._f) { const fieldReference = Array.isArray(field._f.refs) ? field._f.refs[0] : field._f.ref; if (isHTMLElement(fieldReference)) { const form = fieldReference.closest('form'); if (form) { form.reset(); break; } } } } } if (keepStateOptions.keepFieldsRef) { for (const fieldName of _names.mount) { setValue(fieldName, get(values, fieldName)); } } else { _fields = {}; } } _formValues = _options.shouldUnregister ? keepStateOptions.keepDefaultValues ? cloneObject(_defaultValues) : {} : cloneObject(values); _subjects.array.next({ values: { ...values }, }); _subjects.state.next({ values: { ...values }, }); } _names = { mount: keepStateOptions.keepDirtyValues ? _names.mount : new Set(), unMount: new Set(), array: new Set(), disabled: new Set(), watch: new Set(), watchAll: false, focus: '', }; _state.mount = !_proxyFormState.isValid || !!keepStateOptions.keepIsValid || !!keepStateOptions.keepDirtyValues || (!_options.shouldUnregister && !isEmptyObject(values)); _state.watch = !!_options.shouldUnregister; _subjects.state.next({ submitCount: keepStateOptions.keepSubmitCount ? _formState.submitCount : 0, isDirty: isEmptyResetValues ? false : keepStateOptions.keepDirty ? _formState.isDirty : !!(keepStateOptions.keepDefaultValues && !deepEqual(formValues, _defaultValues)), isSubmitted: keepStateOptions.keepIsSubmitted ? _formState.isSubmitted : false, dirtyFields: isEmptyResetValues ? {} : keepStateOptions.keepDirtyValues ? keepStateOptions.keepDefaultValues && _formValues ? getDirtyFields(_defaultValues, _formValues) : _formState.dirtyFields : keepStateOptions.keepDefaultValues && formValues ? getDirtyFields(_defaultValues, formValues) : keepStateOptions.keepDirty ? _formState.dirtyFields : {}, touchedFields: keepStateOptions.keepTouched ? _formState.touchedFields : {}, errors: keepStateOptions.keepErrors ? _formState.errors : {}, isSubmitSuccessful: keepStateOptions.keepIsSubmitSuccessful ? _formState.isSubmitSuccessful : false, isSubmitting: false, defaultValues: _defaultValues, }); }; const reset = (formValues, keepStateOptions) => _reset(isFunction(formValues) ? formValues(_formValues) : formValues, keepStateOptions); const setFocus = (name, options = {}) => { const field = get(_fields, name); const fieldReference = field && field._f; if (fieldReference) { const fieldRef = fieldReference.refs ? fieldReference.refs[0] : fieldReference.ref; if (fieldRef.focus) { fieldRef.focus(); options.shouldSelect && isFunction(fieldRef.select) && fieldRef.select(); } } }; const _setFormState = (updatedFormState) => { _formState = { ..._formState, ...updatedFormState, }; }; const _resetDefaultValues = () => isFunction(_options.defaultValues) && _options.defaultValues().then((values) => { reset(values, _options.resetOptions); _subjects.state.next({ isLoading: false, }); }); const methods = { control: { register, unregister, getFieldState, handleSubmit, setError, _subscribe, _runSchema, _focusError, _getWatch, _getDirty, _setValid, _setFieldArray, _setDisabledField, _setErrors, _getFieldArray, _reset, _resetDefaultValues, _removeUnmounted, _disableForm, _subjects, _proxyFormState, get _fields() { return _fields; }, get _formValues() { return _formValues; }, get _state() { return _state; }, set _state(value) { _state = value; }, get _defaultValues() { return _defaultValues; }, get _names() { return _names; }, set _names(value) { _names = value; }, get _formState() { return _formState; }, get _options() { return _options; }, set _options(value) { _options = { ..._options, ...value, }; }, }, subscribe, trigger, register, handleSubmit, watch, setValue, getValues, reset, resetField, clearErrors, unregister, setError, setFocus, getFieldState, }; return { ...methods, formControl: methods, }; } var generateId = () => { if (typeof crypto !== 'undefined' && crypto.randomUUID) { return crypto.randomUUID(); } const d = typeof performance === 'undefined' ? Date.now() : performance.now() * 1000; return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { const r = (Math.random() * 16 + d) % 16 | 0; return (c == 'x' ? r : (r & 0x3) | 0x8).toString(16); }); }; var getFocusFieldName = (name, index, options = {}) => options.shouldFocus || isUndefined(options.shouldFocus) ? options.focusName || `${name}.${isUndefined(options.focusIndex) ? index : options.focusIndex}.` : ''; var appendAt = (data, value) => [ ...data, ...convertToArrayPayload(value), ]; var fillEmptyArray = (value) => Array.isArray(value) ? value.map(() => undefined) : undefined; function insert(data, index, value) { return [ ...data.slice(0, index), ...convertToArrayPayload(value), ...data.slice(index), ]; } var moveArrayAt = (data, from, to) => { if (!Array.isArray(data)) { return []; } if (isUndefined(data[to])) { data[to] = undefined; } data.splice(to, 0, data.splice(from, 1)[0]); return data; }; var prependAt = (data, value) => [ ...convertToArrayPayload(value), ...convertToArrayPayload(data), ]; function removeAtIndexes(data, indexes) { let i = 0; const temp = [...data]; for (const index of indexes) { temp.splice(index - i, 1); i++; } return compact(temp).length ? temp : []; } var removeArrayAt = (data, index) => isUndefined(index) ? [] : removeAtIndexes(data, convertToArrayPayload(index).sort((a, b) => a - b)); var swapArrayAt = (data, indexA, indexB) => { [data[indexA], data[indexB]] = [data[indexB], data[indexA]]; }; var updateAt = (fieldValues, index, value) => { fieldValues[index] = value; return fieldValues; }; /** * A custom hook that exposes convenient methods to perform operations with a list of dynamic inputs that need to be appended, updated, removed etc. • [Demo](https://codesandbox.io/s/react-hook-form-usefieldarray-ssugn) • [Video](https://youtu.be/4MrbfGSFY2A) * * @remarks * [API](https://react-hook-form.com/docs/usefieldarray) • [Demo](https://codesandbox.io/s/react-hook-form-usefieldarray-ssugn) * * @param props - useFieldArray props * * @returns methods - functions to manipulate with the Field Arrays (dynamic inputs) {@link UseFieldArrayReturn} * * @example * ```tsx * function App() { * const { register, control, handleSubmit, reset, trigger, setError } = useForm({ * defaultValues: { * test: [] * } * }); * const { fields, append } = useFieldArray({ * control, * name: "test" * }); * * return ( *
console.log(data))}> * {fields.map((item, index) => ( * * ))} * * *
* ); * } * ``` */ function useFieldArray(props) { const methods = useFormContext(); const { control = methods.control, name, keyName = 'id', shouldUnregister, rules, } = props; const [fields, setFields] = React.useState(control._getFieldArray(name)); const ids = React.useRef(control._getFieldArray(name).map(generateId)); const _actioned = React.useRef(false); control._names.array.add(name); React.useMemo(() => rules && fields.length >= 0 && control.register(name, rules), [control, name, fields.length, rules]); useIsomorphicLayoutEffect(() => control._subjects.array.subscribe({ next: ({ values, name: fieldArrayName, }) => { if (fieldArrayName === name || !fieldArrayName) { const fieldValues = get(values, name); if (Array.isArray(fieldValues)) { setFields(fieldValues); ids.current = fieldValues.map(generateId); } } }, }).unsubscribe, [control, name]); const updateValues = React.useCallback((updatedFieldArrayValues) => { _actioned.current = true; control._setFieldArray(name, updatedFieldArrayValues); }, [control, name]); const append = (value, options) => { const appendValue = convertToArrayPayload(cloneObject(value)); const updatedFieldArrayValues = appendAt(control._getFieldArray(name), appendValue); control._names.focus = getFocusFieldName(name, updatedFieldArrayValues.length - 1, options); ids.current = appendAt(ids.current, appendValue.map(generateId)); updateValues(updatedFieldArrayValues); setFields(updatedFieldArrayValues); control._setFieldArray(name, updatedFieldArrayValues, appendAt, { argA: fillEmptyArray(value), }); }; const prepend = (value, options) => { const prependValue = convertToArrayPayload(cloneObject(value)); const updatedFieldArrayValues = prependAt(control._getFieldArray(name), prependValue); control._names.focus = getFocusFieldName(name, 0, options); ids.current = prependAt(ids.current, prependValue.map(generateId)); updateValues(updatedFieldArrayValues); setFields(updatedFieldArrayValues); control._setFieldArray(name, updatedFieldArrayValues, prependAt, { argA: fillEmptyArray(value), }); }; const remove = (index) => { const updatedFieldArrayValues = removeArrayAt(control._getFieldArray(name), index); ids.current = removeArrayAt(ids.current, index); updateValues(updatedFieldArrayValues); setFields(updatedFieldArrayValues); !Array.isArray(get(control._fields, name)) && set(control._fields, name, undefined); control._setFieldArray(name, updatedFieldArrayValues, removeArrayAt, { argA: index, }); }; const insert$1 = (index, value, options) => { const insertValue = convertToArrayPayload(cloneObject(value)); const updatedFieldArrayValues = insert(control._getFieldArray(name), index, insertValue); control._names.focus = getFocusFieldName(name, index, options); ids.current = insert(ids.current, index, insertValue.map(generateId)); updateValues(updatedFieldArrayValues); setFields(updatedFieldArrayValues); control._setFieldArray(name, updatedFieldArrayValues, insert, { argA: index, argB: fillEmptyArray(value), }); }; const swap = (indexA, indexB) => { const updatedFieldArrayValues = control._getFieldArray(name); swapArrayAt(updatedFieldArrayValues, indexA, indexB); swapArrayAt(ids.current, indexA, indexB); updateValues(updatedFieldArrayValues); setFields(updatedFieldArrayValues); control._setFieldArray(name, updatedFieldArrayValues, swapArrayAt, { argA: indexA, argB: indexB, }, false); }; const move = (from, to) => { const updatedFieldArrayValues = control._getFieldArray(name); moveArrayAt(updatedFieldArrayValues, from, to); moveArrayAt(ids.current, from, to); updateValues(updatedFieldArrayValues); setFields(updatedFieldArrayValues); control._setFieldArray(name, updatedFieldArrayValues, moveArrayAt, { argA: from, argB: to, }, false); }; const update = (index, value) => { const updateValue = cloneObject(value); const updatedFieldArrayValues = updateAt(control._getFieldArray(name), index, updateValue); ids.current = [...updatedFieldArrayValues].map((item, i) => !item || i === index ? generateId() : ids.current[i]); updateValues(updatedFieldArrayValues); setFields([...updatedFieldArrayValues]); control._setFieldArray(name, updatedFieldArrayValues, updateAt, { argA: index, argB: updateValue, }, true, false); }; const replace = (value) => { const updatedFieldArrayValues = convertToArrayPayload(cloneObject(value)); ids.current = updatedFieldArrayValues.map(generateId); updateValues([...updatedFieldArrayValues]); setFields([...updatedFieldArrayValues]); control._setFieldArray(name, [...updatedFieldArrayValues], (data) => data, {}, true, false); }; React.useEffect(() => { control._state.action = false; isWatched(name, control._names) && control._subjects.state.next({ ...control._formState, }); if (_actioned.current && (!getValidationModes(control._options.mode).isOnSubmit || control._formState.isSubmitted) && !getValidationModes(control._options.reValidateMode).isOnSubmit) { if (control._options.resolver) { control._runSchema([name]).then((result) => { const error = get(result.errors, name); const existingError = get(control._formState.errors, name); if (existingError ? (!error && existingError.type) || (error && (existingError.type !== error.type || existingError.message !== error.message)) : error && error.type) { error ? set(control._formState.errors, name, error) : unset(control._formState.errors, name); control._subjects.state.next({ errors: control._formState.errors, }); } }); } else { const field = get(control._fields, name); if (field && field._f && !(getValidationModes(control._options.reValidateMode).isOnSubmit && getValidationModes(control._options.mode).isOnSubmit)) { validateField(field, control._names.disabled, control._formValues, control._options.criteriaMode === VALIDATION_MODE.all, control._options.shouldUseNativeValidation, true).then((error) => !isEmptyObject(error) && control._subjects.state.next({ errors: updateFieldArrayRootError(control._formState.errors, error, name), })); } } } control._subjects.state.next({ name, values: cloneObject(control._formValues), }); control._names.focus && iterateFieldsByAction(control._fields, (ref, key) => { if (control._names.focus && key.startsWith(control._names.focus) && ref.focus) { ref.focus(); return 1; } return; }); control._names.focus = ''; control._setValid(); _actioned.current = false; }, [fields, name, control]); React.useEffect(() => { !get(control._formValues, name) && control._setFieldArray(name); return () => { const updateMounted = (name, value) => { const field = get(control._fields, name); if (field && field._f) { field._f.mount = value; } }; control._options.shouldUnregister || shouldUnregister ? control.unregister(name) : updateMounted(name, false); }; }, [name, control, keyName, shouldUnregister]); return { swap: React.useCallback(swap, [updateValues, name, control]), move: React.useCallback(move, [updateValues, name, control]), prepend: React.useCallback(prepend, [updateValues, name, control]), append: React.useCallback(append, [updateValues, name, control]), remove: React.useCallback(remove, [updateValues, name, control]), insert: React.useCallback(insert$1, [updateValues, name, control]), update: React.useCallback(update, [updateValues, name, control]), replace: React.useCallback(replace, [updateValues, name, control]), fields: React.useMemo(() => fields.map((field, index) => ({ ...field, [keyName]: ids.current[index] || generateId(), })), [fields, keyName]), }; } /** * Custom hook to manage the entire form. * * @remarks * [API](https://react-hook-form.com/docs/useform) • [Demo](https://codesandbox.io/s/react-hook-form-get-started-ts-5ksmm) • [Video](https://www.youtube.com/watch?v=RkXv4AXXC_4) * * @param props - form configuration and validation parameters. * * @returns methods - individual functions to manage the form state. {@link UseFormReturn} * * @example * ```tsx * function App() { * const { register, handleSubmit, watch, formState: { errors } } = useForm(); * const onSubmit = data => console.log(data); * * console.log(watch("example")); * * return ( *
* * * {errors.exampleRequired && This field is required} * *
* ); * } * ``` */ function useForm(props = {}) { const _formControl = react__WEBPACK_IMPORTED_MODULE_0__.useRef(undefined); const _values = react__WEBPACK_IMPORTED_MODULE_0__.useRef(undefined); const [formState, updateFormState] = react__WEBPACK_IMPORTED_MODULE_0__.useState({ isDirty: false, isValidating: false, isLoading: isFunction(props.defaultValues), isSubmitted: false, isSubmitting: false, isSubmitSuccessful: false, isValid: false, submitCount: 0, dirtyFields: {}, touchedFields: {}, validatingFields: {}, errors: props.errors || {}, disabled: props.disabled || false, isReady: false, defaultValues: isFunction(props.defaultValues) ? undefined : props.defaultValues, }); if (!_formControl.current) { if (props.formControl) { _formControl.current = { ...props.formControl, formState, }; if (props.defaultValues && !isFunction(props.defaultValues)) { props.formControl.reset(props.defaultValues, props.resetOptions); } } else { const { formControl, ...rest } = createFormControl(props); _formControl.current = { ...rest, formState, }; } } const control = _formControl.current.control; control._options = props; useIsomorphicLayoutEffect(() => { const sub = control._subscribe({ formState: control._proxyFormState, callback: () => updateFormState({ ...control._formState }), reRenderRoot: true, }); updateFormState((data) => ({ ...data, isReady: true, })); control._formState.isReady = true; return sub; }, [control]); react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => control._disableForm(props.disabled), [control, props.disabled]); react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => { if (props.mode) { control._options.mode = props.mode; } if (props.reValidateMode) { control._options.reValidateMode = props.reValidateMode; } }, [control, props.mode, props.reValidateMode]); react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => { if (props.errors) { control._setErrors(props.errors); control._focusError(); } }, [control, props.errors]); react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => { props.shouldUnregister && control._subjects.state.next({ values: control._getWatch(), }); }, [control, props.shouldUnregister]); react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => { if (control._proxyFormState.isDirty) { const isDirty = control._getDirty(); if (isDirty !== formState.isDirty) { control._subjects.state.next({ isDirty, }); } } }, [control, formState.isDirty]); react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => { var _a; if (props.values && !deepEqual(props.values, _values.current)) { control._reset(props.values, { keepFieldsRef: true, ...control._options.resetOptions, }); if (!((_a = control._options.resetOptions) === null || _a === void 0 ? void 0 : _a.keepIsValid)) { control._setValid(); } _values.current = props.values; updateFormState((state) => ({ ...state })); } else { control._resetDefaultValues(); } }, [control, props.values]); react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => { if (!control._state.mount) { control._setValid(); control._state.mount = true; } if (control._state.watch) { control._state.watch = false; control._subjects.state.next({ ...control._formState }); } control._removeUnmounted(); }); _formControl.current.formState = getProxyFormState(formState, control); return _formControl.current; } /** * Watch component that subscribes to form field changes and re-renders when watched fields update. * * @param control - The form control object from useForm * @param names - Array of field names to watch for changes * @param render - The function that receives watched values and returns ReactNode * @returns The result of calling render function with watched values * * @example * The `Watch` component only re-render when the values of `foo`, `bar`, and `baz.qux` change. * The types of `foo`, `bar`, and `baz.qux` are precisely inferred. * * ```tsx * const { control } = useForm(); * *
{foo}{bar}{baz_qux}
} * /> * ``` */ const Watch = ({ control, names, render, }) => render(useWatch({ control, name: names })); //# sourceMappingURL=index.esm.mjs.map /***/ }) }]); //# sourceMappingURL=data:application/json;charset=utf-8;base64,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QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtDQUErQyxPQUFPO0FBQ3REO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvQkFBb0Isc0JBQXNCO0FBQzFDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxQkFBcUI7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUJBQXlCLFVBQVU7QUFDbkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxZQUFZLHFCQUFxQjtBQUNqQztBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLFlBQVksc0dBQXNHO0FBQ2xIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsaUJBQWlCO0FBQ2pDLGdCQUFnQjtBQUNoQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsK0JBQStCO0FBQy9DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUNBQXFDO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5QkFBeUI7QUFDekIsdUJBQXVCO0FBQ3ZCLDRCQUE0QjtBQUM1QixxQ0FBcUM7QUFDckM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdFQUFnRSxVQUFVLElBQUk7QUFDOUU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQixTQUFTO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSx3QkFBd0Isb0JBQW9CO0FBQzVDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNB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QTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUZBQXFGO0FBQ3JGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHlCQUF5QjtBQUN6QjtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHlCQUF5QjtBQUN6QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esc0VBQXNFO0FBQ3RFO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSw0Q0FBNEMsV0FBVztBQUNwRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUJBQXVCLHVCQUF1QjtBQUM5QyxxQ0FBcUMsd0JBQXdCO0FBQzdELGlCQUFpQixpQ0FBaUMsZ0JBQWdCLEdBQUc7QUFDckUsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJCQUEyQjtBQUMzQix5QkFBeUIseUNBQVk7QUFDckMsb0JBQW9CLHlDQUFZO0FBQ2hDLHlDQUF5QywyQ0FBYztBQUN2RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUJBQXVCO0FBQ3ZCLHlCQUF5QjtBQUN6Qiw0QkFBNEI7QUFDNUIsa0NBQWtDO0FBQ2xDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9CQUFvQix1QkFBdUI7QUFDM0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDhDQUE4Qyx1QkFBdUI7QUFDckU7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsSUFBSSw0Q0FBZTtBQUNuQixJQUFJLDRDQUFlO0FBQ25CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCxJQUFJLDRDQUFlO0FBQ25CO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMLElBQUksNENBQWU7QUFDbkI7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiLEtBQUs7QUFDTCxJQUFJLDRDQUFlO0FBQ25CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakI7QUFDQTtBQUNBLEtBQUs7QUFDTCxJQUFJLDRDQUFlO0FBQ25CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwQ0FBMEMsVUFBVTtBQUNwRDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCxJQUFJLDRDQUFlO0FBQ25CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJDQUEyQyx1QkFBdUI7QUFDbEU7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLFVBQVU7QUFDckI7QUFDQTtBQUNBLGNBQWM7QUFDZCxZQUFZO0FBQ1osYUFBYSwrQkFBK0IsS0FBSyxLQUFLLFFBQVE7QUFDOUQ7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCLHlCQUF5Qix1QkFBdUIsc0JBQXNCOztBQUVvRjtBQUMzSyIsInNvdXJjZXMiOlsid2VicGFjazovL3JhbXNleS1wbHVzLWZvcm1zLy4vbm9kZV9tb2R1bGVzL0ByYW1zZXktZGVzaWduLXN5c3RlbS9saW5rL2Rpc3QvTGluay5lc20uanMiLCJ3ZWJwYWNrOi8vcmFtc2V5LXBsdXMtZm9ybXMvLi9ub2RlX21vZHVsZXMvcmVhY3QtaG9vay1mb3JtL2Rpc3QvaW5kZXguZXNtLm1qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUmVhY3QsIHsgZm9yd2FyZFJlZiB9IGZyb20gJ3JlYWN0JztcbmltcG9ydCBjbGFzc05hbWVzIGZyb20gJ2NsYXNzbmFtZXMnO1xuXG4vKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcbkNvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLlxyXG5cclxuUGVybWlzc2lvbiB0byB1c2UsIGNvcHksIG1vZGlmeSwgYW5kL29yIGRpc3RyaWJ1dGUgdGhpcyBzb2Z0d2FyZSBmb3IgYW55XHJcbnB1cnBvc2Ugd2l0aCBvciB3aXRob3V0IGZlZSBpcyBoZXJlYnkgZ3JhbnRlZC5cclxuXHJcblRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCBcIkFTIElTXCIgQU5EIFRIRSBBVVRIT1IgRElTQ0xBSU1TIEFMTCBXQVJSQU5USUVTIFdJVEhcclxuUkVHQVJEIFRPIFRISVMgU09GVFdBUkUgSU5DTFVESU5HIEFMTCBJTVBMSUVEIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZXHJcbkFORCBGSVRORVNTLiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SIEJFIExJQUJMRSBGT1IgQU5ZIFNQRUNJQUwsIERJUkVDVCxcclxuSU5ESVJFQ1QsIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFUyBPUiBBTlkgREFNQUdFUyBXSEFUU09FVkVSIFJFU1VMVElORyBGUk9NXHJcbkxPU1MgT0YgVVNFLCBEQVRBIE9SIFBST0ZJVFMsIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBORUdMSUdFTkNFIE9SXHJcbk9USEVSIFRPUlRJT1VTIEFDVElPTiwgQVJJU0lORyBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBVU0UgT1JcclxuUEVSRk9STUFOQ0UgT0YgVEhJUyBTT0ZUV0FSRS5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiogKi9cclxuLyogZ2xvYmFsIFJlZmxlY3QsIFByb21pc2UsIFN1cHByZXNzZWRFcnJvciwgU3ltYm9sLCBJdGVyYXRvciAqL1xyXG5cclxuXHJcbnZhciBfX2Fzc2lnbiA9IGZ1bmN0aW9uKCkge1xyXG4gICAgX19hc3NpZ24gPSBPYmplY3QuYXNzaWduIHx8IGZ1bmN0aW9uIF9fYXNzaWduKHQpIHtcclxuICAgICAgICBmb3IgKHZhciBzLCBpID0gMSwgbiA9IGFyZ3VtZW50cy5sZW5ndGg7IGkgPCBuOyBpKyspIHtcclxuICAgICAgICAgICAgcyA9IGFyZ3VtZW50c1tpXTtcclxuICAgICAgICAgICAgZm9yICh2YXIgcCBpbiBzKSBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHMsIHApKSB0W3BdID0gc1twXTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHQ7XHJcbiAgICB9O1xyXG4gICAgcmV0dXJuIF9fYXNzaWduLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XHJcbn07XHJcblxyXG5mdW5jdGlvbiBfX3Jlc3QocywgZSkge1xyXG4gICAgdmFyIHQgPSB7fTtcclxuICAgIGZvciAodmFyIHAgaW4gcykgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChzLCBwKSAmJiBlLmluZGV4T2YocCkgPCAwKVxyXG4gICAgICAgIHRbcF0gPSBzW3BdO1xyXG4gICAgaWYgKHMgIT0gbnVsbCAmJiB0eXBlb2YgT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyA9PT0gXCJmdW5jdGlvblwiKVxyXG4gICAgICAgIGZvciAodmFyIGkgPSAwLCBwID0gT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyhzKTsgaSA8IHAubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICAgICAgaWYgKGUuaW5kZXhPZihwW2ldKSA8IDAgJiYgT2JqZWN0LnByb3RvdHlwZS5wcm9wZXJ0eUlzRW51bWVyYWJsZS5jYWxsKHMsIHBbaV0pKVxyXG4gICAgICAgICAgICAgICAgdFtwW2ldXSA9IHNbcFtpXV07XHJcbiAgICAgICAgfVxyXG4gICAgcmV0dXJuIHQ7XHJcbn1cclxuXHJcbnR5cGVvZiBTdXBwcmVzc2VkRXJyb3IgPT09IFwiZnVuY3Rpb25cIiA/IFN1cHByZXNzZWRFcnJvciA6IGZ1bmN0aW9uIChlcnJvciwgc3VwcHJlc3NlZCwgbWVzc2FnZSkge1xyXG4gICAgdmFyIGUgPSBuZXcgRXJyb3IobWVzc2FnZSk7XHJcbiAgICByZXR1cm4gZS5uYW1lID0gXCJTdXBwcmVzc2VkRXJyb3JcIiwgZS5lcnJvciA9IGVycm9yLCBlLnN1cHByZXNzZWQgPSBzdXBwcmVzc2VkLCBlO1xyXG59O1xuXG52YXIgZ2V0Q29uZGl0aW9uYWxQcm9wcyA9IGZ1bmN0aW9uIChkaXNhYmxlZCwgaXNMaW5rLCBocmVmKSB7IHJldHVybiAoe1xuICAgIGhyZWY6ICFkaXNhYmxlZCA/IGhyZWYgOiB1bmRlZmluZWQsXG4gICAgXCJhcmlhLWRpc2FibGVkXCI6IChpc0xpbmsgJiYgZGlzYWJsZWQpIHx8IHVuZGVmaW5lZCxcbiAgICBkaXNhYmxlZDogIWlzTGluayAmJiBkaXNhYmxlZCxcbn0pOyB9O1xudmFyIGdldExpbmtJY29uUHJvcHMgPSBmdW5jdGlvbiAoaWNvblBvc2l0aW9uKSB7XG4gICAgdmFyIF9hO1xuICAgIHZhciBpY29uQ2xhc3NlcyA9IGNsYXNzTmFtZXMoXCJyZHMtTGluay1pY29uXCIsIFwicmRzLUxpbmstaWNvbi0tXCIuY29uY2F0KGljb25Qb3NpdGlvbikpO1xuICAgIHJldHVybiBfYSA9IHtcbiAgICAgICAgICAgIGZpbGw6IFwiY3VycmVudENvbG9yXCIsXG4gICAgICAgICAgICBjbGFzc05hbWU6IGljb25DbGFzc2VzXG4gICAgICAgIH0sXG4gICAgICAgIF9hW1wiYXJpYS1oaWRkZW5cIl0gPSB0cnVlLFxuICAgICAgICBfYS5mb2N1c2FibGUgPSBmYWxzZSxcbiAgICAgICAgX2E7XG59O1xuZnVuY3Rpb24gTGluayhfYSwgcmVmKSB7XG4gICAgdmFyIF9iO1xuICAgIHZhciBjaGlsZHJlbiA9IF9hLmNoaWxkcmVuLCBjbGFzc05hbWUgPSBfYS5jbGFzc05hbWUsIGRpc2FibGVkID0gX2EuZGlzYWJsZWQsIGVsZW1lbnQgPSBfYS5lbGVtZW50LCBocmVmID0gX2EuaHJlZiwgTGlua0ljb24gPSBfYS5pY29uLCBfYyA9IF9hLmljb25Qb3NpdGlvbiwgaWNvblBvc2l0aW9uID0gX2MgPT09IHZvaWQgMCA/IFwibGVmdFwiIDogX2MsIF9kID0gX2EuaW5oZXJpdENvbG9yLCBpbmhlcml0Q29sb3IgPSBfZCA9PT0gdm9pZCAwID8gZmFsc2UgOiBfZCwgX2UgPSBfYS5pc09uRGFya0NhbnZhcywgaXNPbkRhcmtDYW52YXMgPSBfZSA9PT0gdm9pZCAwID8gZmFsc2UgOiBfZSwgX2YgPSBfYS5zaXplLCBzaXplID0gX2YgPT09IHZvaWQgMCA/IFwibWVkaXVtXCIgOiBfZiwgdGV4dCA9IF9hLnRleHQsIHJlc3QgPSBfX3Jlc3QoX2EsIFtcImNoaWxkcmVuXCIsIFwiY2xhc3NOYW1lXCIsIFwiZGlzYWJsZWRcIiwgXCJlbGVtZW50XCIsIFwiaHJlZlwiLCBcImljb25cIiwgXCJpY29uUG9zaXRpb25cIiwgXCJpbmhlcml0Q29sb3JcIiwgXCJpc09uRGFya0NhbnZhc1wiLCBcInNpemVcIiwgXCJ0ZXh0XCJdKTtcbiAgICB2YXIgaXNMaW5rID0gZWxlbWVudCAhPT0gXCJidXR0b25cIjtcbiAgICB2YXIgRWxlbWVudCA9IGVsZW1lbnQgfHwgXCJhXCI7XG4gICAgdmFyIGxpbmtDbGFzc2VzID0gY2xhc3NOYW1lcyhcInJkcy1MaW5rXCIsIChfYiA9IHt9LFxuICAgICAgICBfYltcInJkcy1MaW5rLS1cIi5jb25jYXQoc2l6ZSldID0gc2l6ZSAhPT0gXCJtZWRpdW1cIixcbiAgICAgICAgX2JbXCJyZHMtTGluay0taW5oZXJpdENvbG9yXCJdID0gaW5oZXJpdENvbG9yLFxuICAgICAgICBfYltcImlzLWRpc2FibGVkXCJdID0gaXNMaW5rICYmIGRpc2FibGVkLFxuICAgICAgICBfYltcIm9uLWRhcmtDYW52YXNcIl0gPSBpc09uRGFya0NhbnZhcyxcbiAgICAgICAgX2IpLCBjbGFzc05hbWUpO1xuICAgIHJldHVybiAoUmVhY3QuY3JlYXRlRWxlbWVudChFbGVtZW50LCBfX2Fzc2lnbih7IGNsYXNzTmFtZTogbGlua0NsYXNzZXMgfSwgZ2V0Q29uZGl0aW9uYWxQcm9wcyhkaXNhYmxlZCwgaXNMaW5rLCBocmVmKSwgcmVzdCwgeyByZWY6IHJlZiB9KSxcbiAgICAgICAgTGlua0ljb24gJiYgaWNvblBvc2l0aW9uID09PSBcImxlZnRcIiAmJiAoUmVhY3QuY3JlYXRlRWxlbWVudChMaW5rSWNvbiwgX19hc3NpZ24oe30sIGdldExpbmtJY29uUHJvcHMoaWNvblBvc2l0aW9uKSkpKSxcbiAgICAgICAgY2hpbGRyZW4gfHwgdGV4dCxcbiAgICAgICAgTGlua0ljb24gJiYgaWNvblBvc2l0aW9uID09PSBcInJpZ2h0XCIgJiYgKFJlYWN0LmNyZWF0ZUVsZW1lbnQoTGlua0ljb24sIF9fYXNzaWduKHt9LCBnZXRMaW5rSWNvblByb3BzKGljb25Qb3NpdGlvbikpKSkpKTtcbn1cbnZhciBDb21wb25lbnQgPSBmb3J3YXJkUmVmKExpbmspO1xuQ29tcG9uZW50LmRpc3BsYXlOYW1lID0gXCJMaW5rXCI7XG5cbmV4cG9ydCB7IENvbXBvbmVudCBhcyBkZWZhdWx0IH07XG4vLyMgc291cmNlTWFwcGluZ1VSTD1MaW5rLmVzbS5qcy5tYXBcbiIsImltcG9ydCBSZWFjdCBmcm9tICdyZWFjdCc7XG5cbnZhciBpc0NoZWNrQm94SW5wdXQgPSAoZWxlbWVudCkgPT4gZWxlbWVudC50eXBlID09PSAnY2hlY2tib3gnO1xuXG52YXIgaXNEYXRlT2JqZWN0ID0gKHZhbHVlKSA9PiB2YWx1ZSBpbnN0YW5jZW9mIERhdGU7XG5cbnZhciBpc051bGxPclVuZGVmaW5lZCA9ICh2YWx1ZSkgPT4gdmFsdWUgPT0gbnVsbDtcblxuY29uc3QgaXNPYmplY3RUeXBlID0gKHZhbHVlKSA9PiB0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnO1xudmFyIGlzT2JqZWN0ID0gKHZhbHVlKSA9PiAhaXNOdWxsT3JVbmRlZmluZWQodmFsdWUpICYmXG4gICAgIUFycmF5LmlzQXJyYXkodmFsdWUpICYmXG4gICAgaXNPYmplY3RUeXBlKHZhbHVlKSAmJlxuICAgICFpc0RhdGVPYmplY3QodmFsdWUpO1xuXG52YXIgZ2V0RXZlbnRWYWx1ZSA9IChldmVudCkgPT4gaXNPYmplY3QoZXZlbnQpICYmIGV2ZW50LnRhcmdldFxuICAgID8gaXNDaGVja0JveElucHV0KGV2ZW50LnRhcmdldClcbiAgICAgICAgPyBldmVudC50YXJnZXQuY2hlY2tlZFxuICAgICAgICA6IGV2ZW50LnRhcmdldC52YWx1ZVxuICAgIDogZXZlbnQ7XG5cbnZhciBnZXROb2RlUGFyZW50TmFtZSA9IChuYW1lKSA9PiBuYW1lLnN1YnN0cmluZygwLCBuYW1lLnNlYXJjaCgvXFwuXFxkKyhcXC58JCkvKSkgfHwgbmFtZTtcblxudmFyIGlzTmFtZUluRmllbGRBcnJheSA9IChuYW1lcywgbmFtZSkgPT4gbmFtZXMuaGFzKGdldE5vZGVQYXJlbnROYW1lKG5hbWUpKTtcblxudmFyIGlzUGxhaW5PYmplY3QgPSAodGVtcE9iamVjdCkgPT4ge1xuICAgIGNvbnN0IHByb3RvdHlwZUNvcHkgPSB0ZW1wT2JqZWN0LmNvbnN0cnVjdG9yICYmIHRlbXBPYmplY3QuY29uc3RydWN0b3IucHJvdG90eXBlO1xuICAgIHJldHVybiAoaXNPYmplY3QocHJvdG90eXBlQ29weSkgJiYgcHJvdG90eXBlQ29weS5oYXNPd25Qcm9wZXJ0eSgnaXNQcm90b3R5cGVPZicpKTtcbn07XG5cbnZhciBpc1dlYiA9IHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnICYmXG4gICAgdHlwZW9mIHdpbmRvdy5IVE1MRWxlbWVudCAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICB0eXBlb2YgZG9jdW1lbnQgIT09ICd1bmRlZmluZWQnO1xuXG5mdW5jdGlvbiBjbG9uZU9iamVjdChkYXRhKSB7XG4gICAgbGV0IGNvcHk7XG4gICAgY29uc3QgaXNBcnJheSA9IEFycmF5LmlzQXJyYXkoZGF0YSk7XG4gICAgY29uc3QgaXNGaWxlTGlzdEluc3RhbmNlID0gdHlwZW9mIEZpbGVMaXN0ICE9PSAndW5kZWZpbmVkJyA/IGRhdGEgaW5zdGFuY2VvZiBGaWxlTGlzdCA6IGZhbHNlO1xuICAgIGlmIChkYXRhIGluc3RhbmNlb2YgRGF0ZSkge1xuICAgICAgICBjb3B5ID0gbmV3IERhdGUoZGF0YSk7XG4gICAgfVxuICAgIGVsc2UgaWYgKCEoaXNXZWIgJiYgKGRhdGEgaW5zdGFuY2VvZiBCbG9iIHx8IGlzRmlsZUxpc3RJbnN0YW5jZSkpICYmXG4gICAgICAgIChpc0FycmF5IHx8IGlzT2JqZWN0KGRhdGEpKSkge1xuICAgICAgICBjb3B5ID0gaXNBcnJheSA/IFtdIDogT2JqZWN0LmNyZWF0ZShPYmplY3QuZ2V0UHJvdG90eXBlT2YoZGF0YSkpO1xuICAgICAgICBpZiAoIWlzQXJyYXkgJiYgIWlzUGxhaW5PYmplY3QoZGF0YSkpIHtcbiAgICAgICAgICAgIGNvcHkgPSBkYXRhO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgZm9yIChjb25zdCBrZXkgaW4gZGF0YSkge1xuICAgICAgICAgICAgICAgIGlmIChkYXRhLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgICAgICAgICAgICAgY29weVtrZXldID0gY2xvbmVPYmplY3QoZGF0YVtrZXldKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHJldHVybiBkYXRhO1xuICAgIH1cbiAgICByZXR1cm4gY29weTtcbn1cblxudmFyIGlzS2V5ID0gKHZhbHVlKSA9PiAvXlxcdyokLy50ZXN0KHZhbHVlKTtcblxudmFyIGlzVW5kZWZpbmVkID0gKHZhbCkgPT4gdmFsID09PSB1bmRlZmluZWQ7XG5cbnZhciBjb21wYWN0ID0gKHZhbHVlKSA9PiBBcnJheS5pc0FycmF5KHZhbHVlKSA/IHZhbHVlLmZpbHRlcihCb29sZWFuKSA6IFtdO1xuXG52YXIgc3RyaW5nVG9QYXRoID0gKGlucHV0KSA9PiBjb21wYWN0KGlucHV0LnJlcGxhY2UoL1tcInwnXXxcXF0vZywgJycpLnNwbGl0KC9cXC58XFxbLykpO1xuXG52YXIgZ2V0ID0gKG9iamVjdCwgcGF0aCwgZGVmYXVsdFZhbHVlKSA9PiB7XG4gICAgaWYgKCFwYXRoIHx8ICFpc09iamVjdChvYmplY3QpKSB7XG4gICAgICAgIHJldHVybiBkZWZhdWx0VmFsdWU7XG4gICAgfVxuICAgIGNvbnN0IHJlc3VsdCA9IChpc0tleShwYXRoKSA/IFtwYXRoXSA6IHN0cmluZ1RvUGF0aChwYXRoKSkucmVkdWNlKChyZXN1bHQsIGtleSkgPT4gaXNOdWxsT3JVbmRlZmluZWQocmVzdWx0KSA/IHJlc3VsdCA6IHJlc3VsdFtrZXldLCBvYmplY3QpO1xuICAgIHJldHVybiBpc1VuZGVmaW5lZChyZXN1bHQpIHx8IHJlc3VsdCA9PT0gb2JqZWN0XG4gICAgICAgID8gaXNVbmRlZmluZWQob2JqZWN0W3BhdGhdKVxuICAgICAgICAgICAgPyBkZWZhdWx0VmFsdWVcbiAgICAgICAgICAgIDogb2JqZWN0W3BhdGhdXG4gICAgICAgIDogcmVzdWx0O1xufTtcblxudmFyIGlzQm9vbGVhbiA9ICh2YWx1ZSkgPT4gdHlwZW9mIHZhbHVlID09PSAnYm9vbGVhbic7XG5cbnZhciBzZXQgPSAob2JqZWN0LCBwYXRoLCB2YWx1ZSkgPT4ge1xuICAgIGxldCBpbmRleCA9IC0xO1xuICAgIGNvbnN0IHRlbXBQYXRoID0gaXNLZXkocGF0aCkgPyBbcGF0aF0gOiBzdHJpbmdUb1BhdGgocGF0aCk7XG4gICAgY29uc3QgbGVuZ3RoID0gdGVtcFBhdGgubGVuZ3RoO1xuICAgIGNvbnN0IGxhc3RJbmRleCA9IGxlbmd0aCAtIDE7XG4gICAgd2hpbGUgKCsraW5kZXggPCBsZW5ndGgpIHtcbiAgICAgICAgY29uc3Qga2V5ID0gdGVtcFBhdGhbaW5kZXhdO1xuICAgICAgICBsZXQgbmV3VmFsdWUgPSB2YWx1ZTtcbiAgICAgICAgaWYgKGluZGV4ICE9PSBsYXN0SW5kZXgpIHtcbiAgICAgICAgICAgIGNvbnN0IG9ialZhbHVlID0gb2JqZWN0W2tleV07XG4gICAgICAgICAgICBuZXdWYWx1ZSA9XG4gICAgICAgICAgICAgICAgaXNPYmplY3Qob2JqVmFsdWUpIHx8IEFycmF5LmlzQXJyYXkob2JqVmFsdWUpXG4gICAgICAgICAgICAgICAgICAgID8gb2JqVmFsdWVcbiAgICAgICAgICAgICAgICAgICAgOiAhaXNOYU4oK3RlbXBQYXRoW2luZGV4ICsgMV0pXG4gICAgICAgICAgICAgICAgICAgICAgICA/IFtdXG4gICAgICAgICAgICAgICAgICAgICAgICA6IHt9O1xuICAgICAgICB9XG4gICAgICAgIGlmIChrZXkgPT09ICdfX3Byb3RvX18nIHx8IGtleSA9PT0gJ2NvbnN0cnVjdG9yJyB8fCBrZXkgPT09ICdwcm90b3R5cGUnKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgb2JqZWN0W2tleV0gPSBuZXdWYWx1ZTtcbiAgICAgICAgb2JqZWN0ID0gb2JqZWN0W2tleV07XG4gICAgfVxufTtcblxuY29uc3QgRVZFTlRTID0ge1xuICAgIEJMVVI6ICdibHVyJyxcbiAgICBGT0NVU19PVVQ6ICdmb2N1c291dCcsXG4gICAgQ0hBTkdFOiAnY2hhbmdlJyxcbn07XG5jb25zdCBWQUxJREFUSU9OX01PREUgPSB7XG4gICAgb25CbHVyOiAnb25CbHVyJyxcbiAgICBvbkNoYW5nZTogJ29uQ2hhbmdlJyxcbiAgICBvblN1Ym1pdDogJ29uU3VibWl0JyxcbiAgICBvblRvdWNoZWQ6ICdvblRvdWNoZWQnLFxuICAgIGFsbDogJ2FsbCcsXG59O1xuY29uc3QgSU5QVVRfVkFMSURBVElPTl9SVUxFUyA9IHtcbiAgICBtYXg6ICdtYXgnLFxuICAgIG1pbjogJ21pbicsXG4gICAgbWF4TGVuZ3RoOiAnbWF4TGVuZ3RoJyxcbiAgICBtaW5MZW5ndGg6ICdtaW5MZW5ndGgnLFxuICAgIHBhdHRlcm46ICdwYXR0ZXJuJyxcbiAgICByZXF1aXJlZDogJ3JlcXVpcmVkJyxcbiAgICB2YWxpZGF0ZTogJ3ZhbGlkYXRlJyxcbn07XG5cbmNvbnN0IEhvb2tGb3JtQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQobnVsbCk7XG5Ib29rRm9ybUNvbnRleHQuZGlzcGxheU5hbWUgPSAnSG9va0Zvcm1Db250ZXh0Jztcbi8qKlxuICogVGhpcyBjdXN0b20gaG9vayBhbGxvd3MgeW91IHRvIGFjY2VzcyB0aGUgZm9ybSBjb250ZXh0LiB1c2VGb3JtQ29udGV4dCBpcyBpbnRlbmRlZCB0byBiZSB1c2VkIGluIGRlZXBseSBuZXN0ZWQgc3RydWN0dXJlcywgd2hlcmUgaXQgd291bGQgYmVjb21lIGluY29udmVuaWVudCB0byBwYXNzIHRoZSBjb250ZXh0IGFzIGEgcHJvcC4gVG8gYmUgdXNlZCB3aXRoIHtAbGluayBGb3JtUHJvdmlkZXJ9LlxuICpcbiAqIEByZW1hcmtzXG4gKiBbQVBJXShodHRwczovL3JlYWN0LWhvb2stZm9ybS5jb20vZG9jcy91c2Vmb3JtY29udGV4dCkg4oCiIFtEZW1vXShodHRwczovL2NvZGVzYW5kYm94LmlvL3MvcmVhY3QtaG9vay1mb3JtLXY3LWZvcm0tY29udGV4dC15dHVkaSlcbiAqXG4gKiBAcmV0dXJucyByZXR1cm4gYWxsIHVzZUZvcm0gbWV0aG9kc1xuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0c3hcbiAqIGZ1bmN0aW9uIEFwcCgpIHtcbiAqICAgY29uc3QgbWV0aG9kcyA9IHVzZUZvcm0oKTtcbiAqICAgY29uc3Qgb25TdWJtaXQgPSBkYXRhID0+IGNvbnNvbGUubG9nKGRhdGEpO1xuICpcbiAqICAgcmV0dXJuIChcbiAqICAgICA8Rm9ybVByb3ZpZGVyIHsuLi5tZXRob2RzfSA+XG4gKiAgICAgICA8Zm9ybSBvblN1Ym1pdD17bWV0aG9kcy5oYW5kbGVTdWJtaXQob25TdWJtaXQpfT5cbiAqICAgICAgICAgPE5lc3RlZElucHV0IC8+XG4gKiAgICAgICAgIDxpbnB1dCB0eXBlPVwic3VibWl0XCIgLz5cbiAqICAgICAgIDwvZm9ybT5cbiAqICAgICA8L0Zvcm1Qcm92aWRlcj5cbiAqICAgKTtcbiAqIH1cbiAqXG4gKiAgZnVuY3Rpb24gTmVzdGVkSW5wdXQoKSB7XG4gKiAgIGNvbnN0IHsgcmVnaXN0ZXIgfSA9IHVzZUZvcm1Db250ZXh0KCk7IC8vIHJldHJpZXZlIGFsbCBob29rIG1ldGhvZHNcbiAqICAgcmV0dXJuIDxpbnB1dCB7Li4ucmVnaXN0ZXIoXCJ0ZXN0XCIpfSAvPjtcbiAqIH1cbiAqIGBgYFxuICovXG5jb25zdCB1c2VGb3JtQ29udGV4dCA9ICgpID0+IFJlYWN0LnVzZUNvbnRleHQoSG9va0Zvcm1Db250ZXh0KTtcbi8qKlxuICogQSBwcm92aWRlciBjb21wb25lbnQgdGhhdCBwcm9wYWdhdGVzIHRoZSBgdXNlRm9ybWAgbWV0aG9kcyB0byBhbGwgY2hpbGRyZW4gY29tcG9uZW50cyB2aWEgW1JlYWN0IENvbnRleHRdKGh0dHBzOi8vcmVhY3QuZGV2L3JlZmVyZW5jZS9yZWFjdC91c2VDb250ZXh0KSBBUEkuIFRvIGJlIHVzZWQgd2l0aCB7QGxpbmsgdXNlRm9ybUNvbnRleHR9LlxuICpcbiAqIEByZW1hcmtzXG4gKiBbQVBJXShodHRwczovL3JlYWN0LWhvb2stZm9ybS5jb20vZG9jcy91c2Vmb3JtY29udGV4dCkg4oCiIFtEZW1vXShodHRwczovL2NvZGVzYW5kYm94LmlvL3MvcmVhY3QtaG9vay1mb3JtLXY3LWZvcm0tY29udGV4dC15dHVkaSlcbiAqXG4gKiBAcGFyYW0gcHJvcHMgLSBhbGwgdXNlRm9ybSBtZXRob2RzXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHRzeFxuICogZnVuY3Rpb24gQXBwKCkge1xuICogICBjb25zdCBtZXRob2RzID0gdXNlRm9ybSgpO1xuICogICBjb25zdCBvblN1Ym1pdCA9IGRhdGEgPT4gY29uc29sZS5sb2coZGF0YSk7XG4gKlxuICogICByZXR1cm4gKFxuICogICAgIDxGb3JtUHJvdmlkZXIgey4uLm1ldGhvZHN9ID5cbiAqICAgICAgIDxmb3JtIG9uU3VibWl0PXttZXRob2RzLmhhbmRsZVN1Ym1pdChvblN1Ym1pdCl9PlxuICogICAgICAgICA8TmVzdGVkSW5wdXQgLz5cbiAqICAgICAgICAgPGlucHV0IHR5cGU9XCJzdWJtaXRcIiAvPlxuICogICAgICAgPC9mb3JtPlxuICogICAgIDwvRm9ybVByb3ZpZGVyPlxuICogICApO1xuICogfVxuICpcbiAqICBmdW5jdGlvbiBOZXN0ZWRJbnB1dCgpIHtcbiAqICAgY29uc3QgeyByZWdpc3RlciB9ID0gdXNlRm9ybUNvbnRleHQoKTsgLy8gcmV0cmlldmUgYWxsIGhvb2sgbWV0aG9kc1xuICogICByZXR1cm4gPGlucHV0IHsuLi5yZWdpc3RlcihcInRlc3RcIil9IC8+O1xuICogfVxuICogYGBgXG4gKi9cbmNvbnN0IEZvcm1Qcm92aWRlciA9IChwcm9wcykgPT4ge1xuICAgIGNvbnN0IHsgY2hpbGRyZW4sIC4uLmRhdGEgfSA9IHByb3BzO1xuICAgIHJldHVybiAoUmVhY3QuY3JlYXRlRWxlbWVudChIb29rRm9ybUNvbnRleHQuUHJvdmlkZXIsIHsgdmFsdWU6IGRhdGEgfSwgY2hpbGRyZW4pKTtcbn07XG5cbnZhciBnZXRQcm94eUZvcm1TdGF0ZSA9IChmb3JtU3RhdGUsIGNvbnRyb2wsIGxvY2FsUHJveHlGb3JtU3RhdGUsIGlzUm9vdCA9IHRydWUpID0+IHtcbiAgICBjb25zdCByZXN1bHQgPSB7XG4gICAgICAgIGRlZmF1bHRWYWx1ZXM6IGNvbnRyb2wuX2RlZmF1bHRWYWx1ZXMsXG4gICAgfTtcbiAgICBmb3IgKGNvbnN0IGtleSBpbiBmb3JtU3RhdGUpIHtcbiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHJlc3VsdCwga2V5LCB7XG4gICAgICAgICAgICBnZXQ6ICgpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBfa2V5ID0ga2V5O1xuICAgICAgICAgICAgICAgIGlmIChjb250cm9sLl9wcm94eUZvcm1TdGF0ZVtfa2V5XSAhPT0gVkFMSURBVElPTl9NT0RFLmFsbCkge1xuICAgICAgICAgICAgICAgICAgICBjb250cm9sLl9wcm94eUZvcm1TdGF0ZVtfa2V5XSA9ICFpc1Jvb3QgfHwgVkFMSURBVElPTl9NT0RFLmFsbDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgbG9jYWxQcm94eUZvcm1TdGF0ZSAmJiAobG9jYWxQcm94eUZvcm1TdGF0ZVtfa2V5XSA9IHRydWUpO1xuICAgICAgICAgICAgICAgIHJldHVybiBmb3JtU3RhdGVbX2tleV07XG4gICAgICAgICAgICB9LFxuICAgICAgICB9KTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbn07XG5cbmNvbnN0IHVzZUlzb21vcnBoaWNMYXlvdXRFZmZlY3QgPSB0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyA/IFJlYWN0LnVzZUxheW91dEVmZmVjdCA6IFJlYWN0LnVzZUVmZmVjdDtcblxuLyoqXG4gKiBUaGlzIGN1c3RvbSBob29rIGFsbG93cyB5b3UgdG8gc3Vic2NyaWJlIHRvIGVhY2ggZm9ybSBzdGF0ZSwgYW5kIGlzb2xhdGUgdGhlIHJlLXJlbmRlciBhdCB0aGUgY3VzdG9tIGhvb2sgbGV2ZWwuIEl0IGhhcyBpdHMgc2NvcGUgaW4gdGVybXMgb2YgZm9ybSBzdGF0ZSBzdWJzY3JpcHRpb24sIHNvIGl0IHdvdWxkIG5vdCBhZmZlY3Qgb3RoZXIgdXNlRm9ybVN0YXRlIGFuZCB1c2VGb3JtLiBVc2luZyB0aGlzIGhvb2sgY2FuIHJlZHVjZSB0aGUgcmUtcmVuZGVyIGltcGFjdCBvbiBsYXJnZSBhbmQgY29tcGxleCBmb3JtIGFwcGxpY2F0aW9uLlxuICpcbiAqIEByZW1hcmtzXG4gKiBbQVBJXShodHRwczovL3JlYWN0LWhvb2stZm9ybS5jb20vZG9jcy91c2Vmb3Jtc3RhdGUpIOKAoiBbRGVtb10oaHR0cHM6Ly9jb2Rlc2FuZGJveC5pby9zL3VzZWZvcm1zdGF0ZS03NXhseSlcbiAqXG4gKiBAcGFyYW0gcHJvcHMgLSBpbmNsdWRlIG9wdGlvbnMgb24gc3BlY2lmeSBmaWVsZHMgdG8gc3Vic2NyaWJlLiB7QGxpbmsgVXNlRm9ybVN0YXRlUmV0dXJufVxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0c3hcbiAqIGZ1bmN0aW9uIEFwcCgpIHtcbiAqICAgY29uc3QgeyByZWdpc3RlciwgaGFuZGxlU3VibWl0LCBjb250cm9sIH0gPSB1c2VGb3JtKHtcbiAqICAgICBkZWZhdWx0VmFsdWVzOiB7XG4gKiAgICAgZmlyc3ROYW1lOiBcImZpcnN0TmFtZVwiXG4gKiAgIH19KTtcbiAqICAgY29uc3QgeyBkaXJ0eUZpZWxkcyB9ID0gdXNlRm9ybVN0YXRlKHtcbiAqICAgICBjb250cm9sXG4gKiAgIH0pO1xuICogICBjb25zdCBvblN1Ym1pdCA9IChkYXRhKSA9PiBjb25zb2xlLmxvZyhkYXRhKTtcbiAqXG4gKiAgIHJldHVybiAoXG4gKiAgICAgPGZvcm0gb25TdWJtaXQ9e2hhbmRsZVN1Ym1pdChvblN1Ym1pdCl9PlxuICogICAgICAgPGlucHV0IHsuLi5yZWdpc3RlcihcImZpcnN0TmFtZVwiKX0gcGxhY2Vob2xkZXI9XCJGaXJzdCBOYW1lXCIgLz5cbiAqICAgICAgIHtkaXJ0eUZpZWxkcy5maXJzdE5hbWUgJiYgPHA+RmllbGQgaXMgZGlydHkuPC9wPn1cbiAqICAgICAgIDxpbnB1dCB0eXBlPVwic3VibWl0XCIgLz5cbiAqICAgICA8L2Zvcm0+XG4gKiAgICk7XG4gKiB9XG4gKiBgYGBcbiAqL1xuZnVuY3Rpb24gdXNlRm9ybVN0YXRlKHByb3BzKSB7XG4gICAgY29uc3QgbWV0aG9kcyA9IHVzZUZvcm1Db250ZXh0KCk7XG4gICAgY29uc3QgeyBjb250cm9sID0gbWV0aG9kcy5jb250cm9sLCBkaXNhYmxlZCwgbmFtZSwgZXhhY3QgfSA9IHByb3BzIHx8IHt9O1xuICAgIGNvbnN0IFtmb3JtU3RhdGUsIHVwZGF0ZUZvcm1TdGF0ZV0gPSBSZWFjdC51c2VTdGF0ZShjb250cm9sLl9mb3JtU3RhdGUpO1xuICAgIGNvbnN0IF9sb2NhbFByb3h5Rm9ybVN0YXRlID0gUmVhY3QudXNlUmVmKHtcbiAgICAgICAgaXNEaXJ0eTogZmFsc2UsXG4gICAgICAgIGlzTG9hZGluZzogZmFsc2UsXG4gICAgICAgIGRpcnR5RmllbGRzOiBmYWxzZSxcbiAgICAgICAgdG91Y2hlZEZpZWxkczogZmFsc2UsXG4gICAgICAgIHZhbGlkYXRpbmdGaWVsZHM6IGZhbHNlLFxuICAgICAgICBpc1ZhbGlkYXRpbmc6IGZhbHNlLFxuICAgICAgICBpc1ZhbGlkOiBmYWxzZSxcbiAgICAgICAgZXJyb3JzOiBmYWxzZSxcbiAgICB9KTtcbiAgICB1c2VJc29tb3JwaGljTGF5b3V0RWZmZWN0KCgpID0+IGNvbnRyb2wuX3N1YnNjcmliZSh7XG4gICAgICAgIG5hbWUsXG4gICAgICAgIGZvcm1TdGF0ZTogX2xvY2FsUHJveHlGb3JtU3RhdGUuY3VycmVudCxcbiAgICAgICAgZXhhY3QsXG4gICAgICAgIGNhbGxiYWNrOiAoZm9ybVN0YXRlKSA9PiB7XG4gICAgICAgICAgICAhZGlzYWJsZWQgJiZcbiAgICAgICAgICAgICAgICB1cGRhdGVGb3JtU3RhdGUoe1xuICAgICAgICAgICAgICAgICAgICAuLi5jb250cm9sLl9mb3JtU3RhdGUsXG4gICAgICAgICAgICAgICAgICAgIC4uLmZvcm1TdGF0ZSxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgfSxcbiAgICB9KSwgW25hbWUsIGRpc2FibGVkLCBleGFjdF0pO1xuICAgIFJlYWN0LnVzZUVmZmVjdCgoKSA9PiB7XG4gICAgICAgIF9sb2NhbFByb3h5Rm9ybVN0YXRlLmN1cnJlbnQuaXNWYWxpZCAmJiBjb250cm9sLl9zZXRWYWxpZCh0cnVlKTtcbiAgICB9LCBbY29udHJvbF0pO1xuICAgIHJldHVybiBSZWFjdC51c2VNZW1vKCgpID0+IGdldFByb3h5Rm9ybVN0YXRlKGZvcm1TdGF0ZSwgY29udHJvbCwgX2xvY2FsUHJveHlGb3JtU3RhdGUuY3VycmVudCwgZmFsc2UpLCBbZm9ybVN0YXRlLCBjb250cm9sXSk7XG59XG5cbnZhciBpc1N0cmluZyA9ICh2YWx1ZSkgPT4gdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJztcblxudmFyIGdlbmVyYXRlV2F0Y2hPdXRwdXQgPSAobmFtZXMsIF9uYW1lcywgZm9ybVZhbHVlcywgaXNHbG9iYWwsIGRlZmF1bHRWYWx1ZSkgPT4ge1xuICAgIGlmIChpc1N0cmluZyhuYW1lcykpIHtcbiAgICAgICAgaXNHbG9iYWwgJiYgX25hbWVzLndhdGNoLmFkZChuYW1lcyk7XG4gICAgICAgIHJldHVybiBnZXQoZm9ybVZhbHVlcywgbmFtZXMsIGRlZmF1bHRWYWx1ZSk7XG4gICAgfVxuICAgIGlmIChBcnJheS5pc0FycmF5KG5hbWVzKSkge1xuICAgICAgICByZXR1cm4gbmFtZXMubWFwKChmaWVsZE5hbWUpID0+IChpc0dsb2JhbCAmJiBfbmFtZXMud2F0Y2guYWRkKGZpZWxkTmFtZSksXG4gICAgICAgICAgICBnZXQoZm9ybVZhbHVlcywgZmllbGROYW1lKSkpO1xuICAgIH1cbiAgICBpc0dsb2JhbCAmJiAoX25hbWVzLndhdGNoQWxsID0gdHJ1ZSk7XG4gICAgcmV0dXJuIGZvcm1WYWx1ZXM7XG59O1xuXG52YXIgaXNQcmltaXRpdmUgPSAodmFsdWUpID0+IGlzTnVsbE9yVW5kZWZpbmVkKHZhbHVlKSB8fCAhaXNPYmplY3RUeXBlKHZhbHVlKTtcblxuZnVuY3Rpb24gZGVlcEVxdWFsKG9iamVjdDEsIG9iamVjdDIsIF9pbnRlcm5hbF92aXNpdGVkID0gbmV3IFdlYWtTZXQoKSkge1xuICAgIGlmIChpc1ByaW1pdGl2ZShvYmplY3QxKSB8fCBpc1ByaW1pdGl2ZShvYmplY3QyKSkge1xuICAgICAgICByZXR1cm4gT2JqZWN0LmlzKG9iamVjdDEsIG9iamVjdDIpO1xuICAgIH1cbiAgICBpZiAoaXNEYXRlT2JqZWN0KG9iamVjdDEpICYmIGlzRGF0ZU9iamVjdChvYmplY3QyKSkge1xuICAgICAgICByZXR1cm4gb2JqZWN0MS5nZXRUaW1lKCkgPT09IG9iamVjdDIuZ2V0VGltZSgpO1xuICAgIH1cbiAgICBjb25zdCBrZXlzMSA9IE9iamVjdC5rZXlzKG9iamVjdDEpO1xuICAgIGNvbnN0IGtleXMyID0gT2JqZWN0LmtleXMob2JqZWN0Mik7XG4gICAgaWYgKGtleXMxLmxlbmd0aCAhPT0ga2V5czIubGVuZ3RoKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgaWYgKF9pbnRlcm5hbF92aXNpdGVkLmhhcyhvYmplY3QxKSB8fCBfaW50ZXJuYWxfdmlzaXRlZC5oYXMob2JqZWN0MikpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIF9pbnRlcm5hbF92aXNpdGVkLmFkZChvYmplY3QxKTtcbiAgICBfaW50ZXJuYWxfdmlzaXRlZC5hZGQob2JqZWN0Mik7XG4gICAgZm9yIChjb25zdCBrZXkgb2Yga2V5czEpIHtcbiAgICAgICAgY29uc3QgdmFsMSA9IG9iamVjdDFba2V5XTtcbiAgICAgICAgaWYgKCFrZXlzMi5pbmNsdWRlcyhrZXkpKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGtleSAhPT0gJ3JlZicpIHtcbiAgICAgICAgICAgIGNvbnN0IHZhbDIgPSBvYmplY3QyW2tleV07XG4gICAgICAgICAgICBpZiAoKGlzRGF0ZU9iamVjdCh2YWwxKSAmJiBpc0RhdGVPYmplY3QodmFsMikpIHx8XG4gICAgICAgICAgICAgICAgKGlzT2JqZWN0KHZhbDEpICYmIGlzT2JqZWN0KHZhbDIpKSB8fFxuICAgICAgICAgICAgICAgIChBcnJheS5pc0FycmF5KHZhbDEpICYmIEFycmF5LmlzQXJyYXkodmFsMikpXG4gICAgICAgICAgICAgICAgPyAhZGVlcEVxdWFsKHZhbDEsIHZhbDIsIF9pbnRlcm5hbF92aXNpdGVkKVxuICAgICAgICAgICAgICAgIDogIU9iamVjdC5pcyh2YWwxLCB2YWwyKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbn1cblxuLyoqXG4gKiBDdXN0b20gaG9vayB0byBzdWJzY3JpYmUgdG8gZmllbGQgY2hhbmdlIGFuZCBpc29sYXRlIHJlLXJlbmRlcmluZyBhdCB0aGUgY29tcG9uZW50IGxldmVsLlxuICpcbiAqIEByZW1hcmtzXG4gKlxuICogW0FQSV0oaHR0cHM6Ly9yZWFjdC1ob29rLWZvcm0uY29tL2RvY3MvdXNld2F0Y2gpIOKAoiBbRGVtb10oaHR0cHM6Ly9jb2Rlc2FuZGJveC5pby9zL3JlYWN0LWhvb2stZm9ybS12Ny10cy11c2V3YXRjaC1oOWk1ZSlcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHN4XG4gKiBjb25zdCB7IGNvbnRyb2wgfSA9IHVzZUZvcm0oKTtcbiAqIGNvbnN0IHZhbHVlcyA9IHVzZVdhdGNoKHtcbiAqICAgbmFtZTogXCJmaWVsZE5hbWVcIlxuICogICBjb250cm9sLFxuICogfSlcbiAqIGBgYFxuICovXG5mdW5jdGlvbiB1c2VXYXRjaChwcm9wcykge1xuICAgIGNvbnN0IG1ldGhvZHMgPSB1c2VGb3JtQ29udGV4dCgpO1xuICAgIGNvbnN0IHsgY29udHJvbCA9IG1ldGhvZHMuY29udHJvbCwgbmFtZSwgZGVmYXVsdFZhbHVlLCBkaXNhYmxlZCwgZXhhY3QsIGNvbXB1dGUsIH0gPSBwcm9wcyB8fCB7fTtcbiAgICBjb25zdCBfZGVmYXVsdFZhbHVlID0gUmVhY3QudXNlUmVmKGRlZmF1bHRWYWx1ZSk7XG4gICAgY29uc3QgX2NvbXB1dGUgPSBSZWFjdC51c2VSZWYoY29tcHV0ZSk7XG4gICAgY29uc3QgX2NvbXB1dGVGb3JtVmFsdWVzID0gUmVhY3QudXNlUmVmKHVuZGVmaW5lZCk7XG4gICAgY29uc3QgX3ByZXZDb250cm9sID0gUmVhY3QudXNlUmVmKGNvbnRyb2wpO1xuICAgIGNvbnN0IF9wcmV2TmFtZSA9IFJlYWN0LnVzZVJlZihuYW1lKTtcbiAgICBfY29tcHV0ZS5jdXJyZW50ID0gY29tcHV0ZTtcbiAgICBjb25zdCBbdmFsdWUsIHVwZGF0ZVZhbHVlXSA9IFJlYWN0LnVzZVN0YXRlKCgpID0+IHtcbiAgICAgICAgY29uc3QgZGVmYXVsdFZhbHVlID0gY29udHJvbC5fZ2V0V2F0Y2gobmFtZSwgX2RlZmF1bHRWYWx1ZS5jdXJyZW50KTtcbiAgICAgICAgcmV0dXJuIF9jb21wdXRlLmN1cnJlbnQgPyBfY29tcHV0ZS5jdXJyZW50KGRlZmF1bHRWYWx1ZSkgOiBkZWZhdWx0VmFsdWU7XG4gICAgfSk7XG4gICAgY29uc3QgZ2V0Q3VycmVudE91dHB1dCA9IFJlYWN0LnVzZUNhbGxiYWNrKCh2YWx1ZXMpID0+IHtcbiAgICAgICAgY29uc3QgZm9ybVZhbHVlcyA9IGdlbmVyYXRlV2F0Y2hPdXRwdXQobmFtZSwgY29udHJvbC5fbmFtZXMsIHZhbHVlcyB8fCBjb250cm9sLl9mb3JtVmFsdWVzLCBmYWxzZSwgX2RlZmF1bHRWYWx1ZS5jdXJyZW50KTtcbiAgICAgICAgcmV0dXJuIF9jb21wdXRlLmN1cnJlbnQgPyBfY29tcHV0ZS5jdXJyZW50KGZvcm1WYWx1ZXMpIDogZm9ybVZhbHVlcztcbiAgICB9LCBbY29udHJvbC5fZm9ybVZhbHVlcywgY29udHJvbC5fbmFtZXMsIG5hbWVdKTtcbiAgICBjb25zdCByZWZyZXNoVmFsdWUgPSBSZWFjdC51c2VDYWxsYmFjaygodmFsdWVzKSA9PiB7XG4gICAgICAgIGlmICghZGlzYWJsZWQpIHtcbiAgICAgICAgICAgIGNvbnN0IGZvcm1WYWx1ZXMgPSBnZW5lcmF0ZVdhdGNoT3V0cHV0KG5hbWUsIGNvbnRyb2wuX25hbWVzLCB2YWx1ZXMgfHwgY29udHJvbC5fZm9ybVZhbHVlcywgZmFsc2UsIF9kZWZhdWx0VmFsdWUuY3VycmVudCk7XG4gICAgICAgICAgICBpZiAoX2NvbXB1dGUuY3VycmVudCkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGNvbXB1dGVkRm9ybVZhbHVlcyA9IF9jb21wdXRlLmN1cnJlbnQoZm9ybVZhbHVlcyk7XG4gICAgICAgICAgICAgICAgaWYgKCFkZWVwRXF1YWwoY29tcHV0ZWRGb3JtVmFsdWVzLCBfY29tcHV0ZUZvcm1WYWx1ZXMuY3VycmVudCkpIHtcbiAgICAgICAgICAgICAgICAgICAgdXBkYXRlVmFsdWUoY29tcHV0ZWRGb3JtVmFsdWVzKTtcbiAgICAgICAgICAgICAgICAgICAgX2NvbXB1dGVGb3JtVmFsdWVzLmN1cnJlbnQgPSBjb21wdXRlZEZvcm1WYWx1ZXM7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgdXBkYXRlVmFsdWUoZm9ybVZhbHVlcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9LCBbY29udHJvbC5fZm9ybVZhbHVlcywgY29udHJvbC5fbmFtZXMsIGRpc2FibGVkLCBuYW1lXSk7XG4gICAgdXNlSXNvbW9ycGhpY0xheW91dEVmZmVjdCgoKSA9PiB7XG4gICAgICAgIGlmIChfcHJldkNvbnRyb2wuY3VycmVudCAhPT0gY29udHJvbCB8fFxuICAgICAgICAgICAgIWRlZXBFcXVhbChfcHJldk5hbWUuY3VycmVudCwgbmFtZSkpIHtcbiAgICAgICAgICAgIF9wcmV2Q29udHJvbC5jdXJyZW50ID0gY29udHJvbDtcbiAgICAgICAgICAgIF9wcmV2TmFtZS5jdXJyZW50ID0gbmFtZTtcbiAgICAgICAgICAgIHJlZnJlc2hWYWx1ZSgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBjb250cm9sLl9zdWJzY3JpYmUoe1xuICAgICAgICAgICAgbmFtZSxcbiAgICAgICAgICAgIGZvcm1TdGF0ZToge1xuICAgICAgICAgICAgICAgIHZhbHVlczogdHJ1ZSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBleGFjdCxcbiAgICAgICAgICAgIGNhbGxiYWNrOiAoZm9ybVN0YXRlKSA9PiB7XG4gICAgICAgICAgICAgICAgcmVmcmVzaFZhbHVlKGZvcm1TdGF0ZS52YWx1ZXMpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgfSk7XG4gICAgfSwgW2NvbnRyb2wsIGV4YWN0LCBuYW1lLCByZWZyZXNoVmFsdWVdKTtcbiAgICBSZWFjdC51c2VFZmZlY3QoKCkgPT4gY29udHJvbC5fcmVtb3ZlVW5tb3VudGVkKCkpO1xuICAgIC8vIElmIG5hbWUgb3IgY29udHJvbCBjaGFuZ2VkIGZvciB0aGlzIHJlbmRlciwgc3luY2hyb25vdXNseSByZWZsZWN0IHRoZVxuICAgIC8vIGxhdGVzdCB2YWx1ZSBzbyBjYWxsZXJzIChsaWtlIHVzZUNvbnRyb2xsZXIpIHNlZSB0aGUgY29ycmVjdCB2YWx1ZVxuICAgIC8vIGltbWVkaWF0ZWx5IG9uIHRoZSBzYW1lIHJlbmRlci5cbiAgICAvLyBPcHRpbWl6ZTogQ2hlY2sgY29udHJvbCByZWZlcmVuY2UgZmlyc3QgYmVmb3JlIGV4cGVuc2l2ZSBkZWVwRXF1YWxcbiAgICBjb25zdCBjb250cm9sQ2hhbmdlZCA9IF9wcmV2Q29udHJvbC5jdXJyZW50ICE9PSBjb250cm9sO1xuICAgIGNvbnN0IHByZXZOYW1lID0gX3ByZXZOYW1lLmN1cnJlbnQ7XG4gICAgLy8gQ2FjaGUgdGhlIGNvbXB1dGVkIG91dHB1dCB0byBhdm9pZCBkdXBsaWNhdGUgY2FsbHMgd2l0aGluIHRoZSBzYW1lIHJlbmRlclxuICAgIC8vIFdlIGluY2x1ZGUgc2hvdWxkUmV0dXJuSW1tZWRpYXRlIGluIGRlcHMgdG8gZW5zdXJlIHByb3BlciByZWNvbXB1dGF0aW9uXG4gICAgY29uc3QgY29tcHV0ZWRPdXRwdXQgPSBSZWFjdC51c2VNZW1vKCgpID0+IHtcbiAgICAgICAgaWYgKGRpc2FibGVkKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBuYW1lQ2hhbmdlZCA9ICFjb250cm9sQ2hhbmdlZCAmJiAhZGVlcEVxdWFsKHByZXZOYW1lLCBuYW1lKTtcbiAgICAgICAgY29uc3Qgc2hvdWxkUmV0dXJuSW1tZWRpYXRlID0gY29udHJvbENoYW5nZWQgfHwgbmFtZUNoYW5nZWQ7XG4gICAgICAgIHJldHVybiBzaG91bGRSZXR1cm5JbW1lZGlhdGUgPyBnZXRDdXJyZW50T3V0cHV0KCkgOiBudWxsO1xuICAgIH0sIFtkaXNhYmxlZCwgY29udHJvbENoYW5nZWQsIG5hbWUsIHByZXZOYW1lLCBnZXRDdXJyZW50T3V0cHV0XSk7XG4gICAgcmV0dXJuIGNvbXB1dGVkT3V0cHV0ICE9PSBudWxsID8gY29tcHV0ZWRPdXRwdXQgOiB2YWx1ZTtcbn1cblxuLyoqXG4gKiBDdXN0b20gaG9vayB0byB3b3JrIHdpdGggY29udHJvbGxlZCBjb21wb25lbnQsIHRoaXMgZnVuY3Rpb24gcHJvdmlkZSB5b3Ugd2l0aCBib3RoIGZvcm0gYW5kIGZpZWxkIGxldmVsIHN0YXRlLiBSZS1yZW5kZXIgaXMgaXNvbGF0ZWQgYXQgdGhlIGhvb2sgbGV2ZWwuXG4gKlxuICogQHJlbWFya3NcbiAqIFtBUEldKGh0dHBzOi8vcmVhY3QtaG9vay1mb3JtLmNvbS9kb2NzL3VzZWNvbnRyb2xsZXIpIOKAoiBbRGVtb10oaHR0cHM6Ly9jb2Rlc2FuZGJveC5pby9zL3VzZWNvbnRyb2xsZXItMG84cHgpXG4gKlxuICogQHBhcmFtIHByb3BzIC0gdGhlIHBhdGggbmFtZSB0byB0aGUgZm9ybSBmaWVsZCB2YWx1ZSwgYW5kIHZhbGlkYXRpb24gcnVsZXMuXG4gKlxuICogQHJldHVybnMgZmllbGQgcHJvcGVydGllcywgZmllbGQgYW5kIGZvcm0gc3RhdGUuIHtAbGluayBVc2VDb250cm9sbGVyUmV0dXJufVxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0c3hcbiAqIGZ1bmN0aW9uIElucHV0KHByb3BzKSB7XG4gKiAgIGNvbnN0IHsgZmllbGQsIGZpZWxkU3RhdGUsIGZvcm1TdGF0ZSB9ID0gdXNlQ29udHJvbGxlcihwcm9wcyk7XG4gKiAgIHJldHVybiAoXG4gKiAgICAgPGRpdj5cbiAqICAgICAgIDxpbnB1dCB7Li4uZmllbGR9IHBsYWNlaG9sZGVyPXtwcm9wcy5uYW1lfSAvPlxuICogICAgICAgPHA+e2ZpZWxkU3RhdGUuaXNUb3VjaGVkICYmIFwiVG91Y2hlZFwifTwvcD5cbiAqICAgICAgIDxwPntmb3JtU3RhdGUuaXNTdWJtaXR0ZWQgPyBcInN1Ym1pdHRlZFwiIDogXCJcIn08L3A+XG4gKiAgICAgPC9kaXY+XG4gKiAgICk7XG4gKiB9XG4gKiBgYGBcbiAqL1xuZnVuY3Rpb24gdXNlQ29udHJvbGxlcihwcm9wcykge1xuICAgIGNvbnN0IG1ldGhvZHMgPSB1c2VGb3JtQ29udGV4dCgpO1xuICAgIGNvbnN0IHsgbmFtZSwgZGlzYWJsZWQsIGNvbnRyb2wgPSBtZXRob2RzLmNvbnRyb2wsIHNob3VsZFVucmVnaXN0ZXIsIGRlZmF1bHRWYWx1ZSwgfSA9IHByb3BzO1xuICAgIGNvbnN0IGlzQXJyYXlGaWVsZCA9IGlzTmFtZUluRmllbGRBcnJheShjb250cm9sLl9uYW1lcy5hcnJheSwgbmFtZSk7XG4gICAgY29uc3QgZGVmYXVsdFZhbHVlTWVtbyA9IFJlYWN0LnVzZU1lbW8oKCkgPT4gZ2V0KGNvbnRyb2wuX2Zvcm1WYWx1ZXMsIG5hbWUsIGdldChjb250cm9sLl9kZWZhdWx0VmFsdWVzLCBuYW1lLCBkZWZhdWx0VmFsdWUpKSwgW2NvbnRyb2wsIG5hbWUsIGRlZmF1bHRWYWx1ZV0pO1xuICAgIGNvbnN0IHZhbHVlID0gdXNlV2F0Y2goe1xuICAgICAgICBjb250cm9sLFxuICAgICAgICBuYW1lLFxuICAgICAgICBkZWZhdWx0VmFsdWU6IGRlZmF1bHRWYWx1ZU1lbW8sXG4gICAgICAgIGV4YWN0OiB0cnVlLFxuICAgIH0pO1xuICAgIGNvbnN0IGZvcm1TdGF0ZSA9IHVzZUZvcm1TdGF0ZSh7XG4gICAgICAgIGNvbnRyb2wsXG4gICAgICAgIG5hbWUsXG4gICAgICAgIGV4YWN0OiB0cnVlLFxuICAgIH0pO1xuICAgIGNvbnN0IF9wcm9wcyA9IFJlYWN0LnVzZVJlZihwcm9wcyk7XG4gICAgY29uc3QgX3ByZXZpb3VzTmFtZVJlZiA9IFJlYWN0LnVzZVJlZih1bmRlZmluZWQpO1xuICAgIGNvbnN0IF9yZWdpc3RlclByb3BzID0gUmVhY3QudXNlUmVmKGNvbnRyb2wucmVnaXN0ZXIobmFtZSwge1xuICAgICAgICAuLi5wcm9wcy5ydWxlcyxcbiAgICAgICAgdmFsdWUsXG4gICAgICAgIC4uLihpc0Jvb2xlYW4ocHJvcHMuZGlzYWJsZWQpID8geyBkaXNhYmxlZDogcHJvcHMuZGlzYWJsZWQgfSA6IHt9KSxcbiAgICB9KSk7XG4gICAgX3Byb3BzLmN1cnJlbnQgPSBwcm9wcztcbiAgICBjb25zdCBmaWVsZFN0YXRlID0gUmVhY3QudXNlTWVtbygoKSA9PiBPYmplY3QuZGVmaW5lUHJvcGVydGllcyh7fSwge1xuICAgICAgICBpbnZhbGlkOiB7XG4gICAgICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgZ2V0OiAoKSA9PiAhIWdldChmb3JtU3RhdGUuZXJyb3JzLCBuYW1lKSxcbiAgICAgICAgfSxcbiAgICAgICAgaXNEaXJ0eToge1xuICAgICAgICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgIGdldDogKCkgPT4gISFnZXQoZm9ybVN0YXRlLmRpcnR5RmllbGRzLCBuYW1lKSxcbiAgICAgICAgfSxcbiAgICAgICAgaXNUb3VjaGVkOiB7XG4gICAgICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgZ2V0OiAoKSA9PiAhIWdldChmb3JtU3RhdGUudG91Y2hlZEZpZWxkcywgbmFtZSksXG4gICAgICAgIH0sXG4gICAgICAgIGlzVmFsaWRhdGluZzoge1xuICAgICAgICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgIGdldDogKCkgPT4gISFnZXQoZm9ybVN0YXRlLnZhbGlkYXRpbmdGaWVsZHMsIG5hbWUpLFxuICAgICAgICB9LFxuICAgICAgICBlcnJvcjoge1xuICAgICAgICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgIGdldDogKCkgPT4gZ2V0KGZvcm1TdGF0ZS5lcnJvcnMsIG5hbWUpLFxuICAgICAgICB9LFxuICAgIH0pLCBbZm9ybVN0YXRlLCBuYW1lXSk7XG4gICAgY29uc3Qgb25DaGFuZ2UgPSBSZWFjdC51c2VDYWxsYmFjaygoZXZlbnQpID0+IF9yZWdpc3RlclByb3BzLmN1cnJlbnQub25DaGFuZ2Uoe1xuICAgICAgICB0YXJnZXQ6IHtcbiAgICAgICAgICAgIHZhbHVlOiBnZXRFdmVudFZhbHVlKGV2ZW50KSxcbiAgICAgICAgICAgIG5hbWU6IG5hbWUsXG4gICAgICAgIH0sXG4gICAgICAgIHR5cGU6IEVWRU5UUy5DSEFOR0UsXG4gICAgfSksIFtuYW1lXSk7XG4gICAgY29uc3Qgb25CbHVyID0gUmVhY3QudXNlQ2FsbGJhY2soKCkgPT4gX3JlZ2lzdGVyUHJvcHMuY3VycmVudC5vbkJsdXIoe1xuICAgICAgICB0YXJnZXQ6IHtcbiAgICAgICAgICAgIHZhbHVlOiBnZXQoY29udHJvbC5fZm9ybVZhbHVlcywgbmFtZSksXG4gICAgICAgICAgICBuYW1lOiBuYW1lLFxuICAgICAgICB9LFxuICAgICAgICB0eXBlOiBFVkVOVFMuQkxVUixcbiAgICB9KSwgW25hbWUsIGNvbnRyb2wuX2Zvcm1WYWx1ZXNdKTtcbiAgICBjb25zdCByZWYgPSBSZWFjdC51c2VDYWxsYmFjaygoZWxtKSA9PiB7XG4gICAgICAgIGNvbnN0IGZpZWxkID0gZ2V0KGNvbnRyb2wuX2ZpZWxkcywgbmFtZSk7XG4gICAgICAgIGlmIChmaWVsZCAmJiBlbG0pIHtcbiAgICAgICAgICAgIGZpZWxkLl9mLnJlZiA9IHtcbiAgICAgICAgICAgICAgICBmb2N1czogKCkgPT4gZWxtLmZvY3VzICYmIGVsbS5mb2N1cygpLFxuICAgICAgICAgICAgICAgIHNlbGVjdDogKCkgPT4gZWxtLnNlbGVjdCAmJiBlbG0uc2VsZWN0KCksXG4gICAgICAgICAgICAgICAgc2V0Q3VzdG9tVmFsaWRpdHk6IChtZXNzYWdlKSA9PiBlbG0uc2V0Q3VzdG9tVmFsaWRpdHkobWVzc2FnZSksXG4gICAgICAgICAgICAgICAgcmVwb3J0VmFsaWRpdHk6ICgpID0+IGVsbS5yZXBvcnRWYWxpZGl0eSgpLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH0sIFtjb250cm9sLl9maWVsZHMsIG5hbWVdKTtcbiAgICBjb25zdCBmaWVsZCA9IFJlYWN0LnVzZU1lbW8oKCkgPT4gKHtcbiAgICAgICAgbmFtZSxcbiAgICAgICAgdmFsdWUsXG4gICAgICAgIC4uLihpc0Jvb2xlYW4oZGlzYWJsZWQpIHx8IGZvcm1TdGF0ZS5kaXNhYmxlZFxuICAgICAgICAgICAgPyB7IGRpc2FibGVkOiBmb3JtU3RhdGUuZGlzYWJsZWQgfHwgZGlzYWJsZWQgfVxuICAgICAgICAgICAgOiB7fSksXG4gICAgICAgIG9uQ2hhbmdlLFxuICAgICAgICBvbkJsdXIsXG4gICAgICAgIHJlZixcbiAgICB9KSwgW25hbWUsIGRpc2FibGVkLCBmb3JtU3RhdGUuZGlzYWJsZWQsIG9uQ2hhbmdlLCBvbkJsdXIsIHJlZiwgdmFsdWVdKTtcbiAgICBSZWFjdC51c2VFZmZlY3QoKCkgPT4ge1xuICAgICAgICBjb25zdCBfc2hvdWxkVW5yZWdpc3RlckZpZWxkID0gY29udHJvbC5fb3B0aW9ucy5zaG91bGRVbnJlZ2lzdGVyIHx8IHNob3VsZFVucmVnaXN0ZXI7XG4gICAgICAgIGNvbnN0IHByZXZpb3VzTmFtZSA9IF9wcmV2aW91c05hbWVSZWYuY3VycmVudDtcbiAgICAgICAgaWYgKHByZXZpb3VzTmFtZSAmJiBwcmV2aW91c05hbWUgIT09IG5hbWUgJiYgIWlzQXJyYXlGaWVsZCkge1xuICAgICAgICAgICAgY29udHJvbC51bnJlZ2lzdGVyKHByZXZpb3VzTmFtZSk7XG4gICAgICAgIH1cbiAgICAgICAgY29udHJvbC5yZWdpc3RlcihuYW1lLCB7XG4gICAgICAgICAgICAuLi5fcHJvcHMuY3VycmVudC5ydWxlcyxcbiAgICAgICAgICAgIC4uLihpc0Jvb2xlYW4oX3Byb3BzLmN1cnJlbnQuZGlzYWJsZWQpXG4gICAgICAgICAgICAgICAgPyB7IGRpc2FibGVkOiBfcHJvcHMuY3VycmVudC5kaXNhYmxlZCB9XG4gICAgICAgICAgICAgICAgOiB7fSksXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCB1cGRhdGVNb3VudGVkID0gKG5hbWUsIHZhbHVlKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBmaWVsZCA9IGdldChjb250cm9sLl9maWVsZHMsIG5hbWUpO1xuICAgICAgICAgICAgaWYgKGZpZWxkICYmIGZpZWxkLl9mKSB7XG4gICAgICAgICAgICAgICAgZmllbGQuX2YubW91bnQgPSB2YWx1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdXBkYXRlTW91bnRlZChuYW1lLCB0cnVlKTtcbiAgICAgICAgaWYgKF9zaG91bGRVbnJlZ2lzdGVyRmllbGQpIHtcbiAgICAgICAgICAgIGNvbnN0IHZhbHVlID0gY2xvbmVPYmplY3QoZ2V0KGNvbnRyb2wuX29wdGlvbnMuZGVmYXVsdFZhbHVlcywgbmFtZSwgX3Byb3BzLmN1cnJlbnQuZGVmYXVsdFZhbHVlKSk7XG4gICAgICAgICAgICBzZXQoY29udHJvbC5fZGVmYXVsdFZhbHVlcywgbmFtZSwgdmFsdWUpO1xuICAgICAgICAgICAgaWYgKGlzVW5kZWZpbmVkKGdldChjb250cm9sLl9mb3JtVmFsdWVzLCBuYW1lKSkpIHtcbiAgICAgICAgICAgICAgICBzZXQoY29udHJvbC5fZm9ybVZhbHVlcywgbmFtZSwgdmFsdWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgICFpc0FycmF5RmllbGQgJiYgY29udHJvbC5yZWdpc3RlcihuYW1lKTtcbiAgICAgICAgX3ByZXZpb3VzTmFtZVJlZi5jdXJyZW50ID0gbmFtZTtcbiAgICAgICAgcmV0dXJuICgpID0+IHtcbiAgICAgICAgICAgIChpc0FycmF5RmllbGRcbiAgICAgICAgICAgICAgICA/IF9zaG91bGRVbnJlZ2lzdGVyRmllbGQgJiYgIWNvbnRyb2wuX3N0YXRlLmFjdGlvblxuICAgICAgICAgICAgICAgIDogX3Nob3VsZFVucmVnaXN0ZXJGaWVsZClcbiAgICAgICAgICAgICAgICA/IGNvbnRyb2wudW5yZWdpc3RlcihuYW1lKVxuICAgICAgICAgICAgICAgIDogdXBkYXRlTW91bnRlZChuYW1lLCBmYWxzZSk7XG4gICAgICAgIH07XG4gICAgfSwgW25hbWUsIGNvbnRyb2wsIGlzQXJyYXlGaWVsZCwgc2hvdWxkVW5yZWdpc3Rlcl0pO1xuICAgIFJlYWN0LnVzZUVmZmVjdCgoKSA9PiB7XG4gICAgICAgIGNvbnRyb2wuX3NldERpc2FibGVkRmllbGQoe1xuICAgICAgICAgICAgZGlzYWJsZWQsXG4gICAgICAgICAgICBuYW1lLFxuICAgICAgICB9KTtcbiAgICB9LCBbZGlzYWJsZWQsIG5hbWUsIGNvbnRyb2xdKTtcbiAgICByZXR1cm4gUmVhY3QudXNlTWVtbygoKSA9PiAoe1xuICAgICAgICBmaWVsZCxcbiAgICAgICAgZm9ybVN0YXRlLFxuICAgICAgICBmaWVsZFN0YXRlLFxuICAgIH0pLCBbZmllbGQsIGZvcm1TdGF0ZSwgZmllbGRTdGF0ZV0pO1xufVxuXG4vKipcbiAqIENvbXBvbmVudCBiYXNlZCBvbiBgdXNlQ29udHJvbGxlcmAgaG9vayB0byB3b3JrIHdpdGggY29udHJvbGxlZCBjb21wb25lbnQuXG4gKlxuICogQHJlbWFya3NcbiAqIFtBUEldKGh0dHBzOi8vcmVhY3QtaG9vay1mb3JtLmNvbS9kb2NzL3VzZWNvbnRyb2xsZXIvY29udHJvbGxlcikg4oCiIFtEZW1vXShodHRwczovL2NvZGVzYW5kYm94LmlvL3MvcmVhY3QtaG9vay1mb3JtLXY2LWNvbnRyb2xsZXItdHMtand5encpIOKAoiBbVmlkZW9dKGh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9TjJVTmtfVUNWeUEpXG4gKlxuICogQHBhcmFtIHByb3BzIC0gdGhlIHBhdGggbmFtZSB0byB0aGUgZm9ybSBmaWVsZCB2YWx1ZSwgYW5kIHZhbGlkYXRpb24gcnVsZXMuXG4gKlxuICogQHJldHVybnMgcHJvdmlkZSBmaWVsZCBoYW5kbGVyIGZ1bmN0aW9ucywgZmllbGQgYW5kIGZvcm0gc3RhdGUuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHRzeFxuICogZnVuY3Rpb24gQXBwKCkge1xuICogICBjb25zdCB7IGNvbnRyb2wgfSA9IHVzZUZvcm08Rm9ybVZhbHVlcz4oe1xuICogICAgIGRlZmF1bHRWYWx1ZXM6IHtcbiAqICAgICAgIHRlc3Q6IFwiXCJcbiAqICAgICB9XG4gKiAgIH0pO1xuICpcbiAqICAgcmV0dXJuIChcbiAqICAgICA8Zm9ybT5cbiAqICAgICAgIDxDb250cm9sbGVyXG4gKiAgICAgICAgIGNvbnRyb2w9e2NvbnRyb2x9XG4gKiAgICAgICAgIG5hbWU9XCJ0ZXN0XCJcbiAqICAgICAgICAgcmVuZGVyPXsoeyBmaWVsZDogeyBvbkNoYW5nZSwgb25CbHVyLCB2YWx1ZSwgcmVmIH0sIGZvcm1TdGF0ZSwgZmllbGRTdGF0ZSB9KSA9PiAoXG4gKiAgICAgICAgICAgPD5cbiAqICAgICAgICAgICAgIDxpbnB1dFxuICogICAgICAgICAgICAgICBvbkNoYW5nZT17b25DaGFuZ2V9IC8vIHNlbmQgdmFsdWUgdG8gaG9vayBmb3JtXG4gKiAgICAgICAgICAgICAgIG9uQmx1cj17b25CbHVyfSAvLyBub3RpZnkgd2hlbiBpbnB1dCBpcyB0b3VjaGVkXG4gKiAgICAgICAgICAgICAgIHZhbHVlPXt2YWx1ZX0gLy8gcmV0dXJuIHVwZGF0ZWQgdmFsdWVcbiAqICAgICAgICAgICAgICAgcmVmPXtyZWZ9IC8vIHNldCByZWYgZm9yIGZvY3VzIG1hbmFnZW1lbnRcbiAqICAgICAgICAgICAgIC8+XG4gKiAgICAgICAgICAgICA8cD57Zm9ybVN0YXRlLmlzU3VibWl0dGVkID8gXCJzdWJtaXR0ZWRcIiA6IFwiXCJ9PC9wPlxuICogICAgICAgICAgICAgPHA+e2ZpZWxkU3RhdGUuaXNUb3VjaGVkID8gXCJ0b3VjaGVkXCIgOiBcIlwifTwvcD5cbiAqICAgICAgICAgICA8Lz5cbiAqICAgICAgICAgKX1cbiAqICAgICAgIC8+XG4gKiAgICAgPC9mb3JtPlxuICogICApO1xuICogfVxuICogYGBgXG4gKi9cbmNvbnN0IENvbnRyb2xsZXIgPSAocHJvcHMpID0+IHByb3BzLnJlbmRlcih1c2VDb250cm9sbGVyKHByb3BzKSk7XG5cbmNvbnN0IGZsYXR0ZW4gPSAob2JqKSA9PiB7XG4gICAgY29uc3Qgb3V0cHV0ID0ge307XG4gICAgZm9yIChjb25zdCBrZXkgb2YgT2JqZWN0LmtleXMob2JqKSkge1xuICAgICAgICBpZiAoaXNPYmplY3RUeXBlKG9ialtrZXldKSAmJiBvYmpba2V5XSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgY29uc3QgbmVzdGVkID0gZmxhdHRlbihvYmpba2V5XSk7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IG5lc3RlZEtleSBvZiBPYmplY3Qua2V5cyhuZXN0ZWQpKSB7XG4gICAgICAgICAgICAgICAgb3V0cHV0W2Ake2tleX0uJHtuZXN0ZWRLZXl9YF0gPSBuZXN0ZWRbbmVzdGVkS2V5XTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIG91dHB1dFtrZXldID0gb2JqW2tleV07XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG91dHB1dDtcbn07XG5cbmNvbnN0IFBPU1RfUkVRVUVTVCA9ICdwb3N0Jztcbi8qKlxuICogRm9ybSBjb21wb25lbnQgdG8gbWFuYWdlIHN1Ym1pc3Npb24uXG4gKlxuICogQHBhcmFtIHByb3BzIC0gdG8gc2V0dXAgc3VibWlzc2lvbiBkZXRhaWwuIHtAbGluayBGb3JtUHJvcHN9XG4gKlxuICogQHJldHVybnMgZm9ybSBjb21wb25lbnQgb3IgaGVhZGxlc3MgcmVuZGVyIHByb3AuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHRzeFxuICogZnVuY3Rpb24gQXBwKCkge1xuICogICBjb25zdCB7IGNvbnRyb2wsIGZvcm1TdGF0ZTogeyBlcnJvcnMgfSB9ID0gdXNlRm9ybSgpO1xuICpcbiAqICAgcmV0dXJuIChcbiAqICAgICA8Rm9ybSBhY3Rpb249XCIvYXBpXCIgY29udHJvbD17Y29udHJvbH0+XG4gKiAgICAgICA8aW5wdXQgey4uLnJlZ2lzdGVyKFwibmFtZVwiKX0gLz5cbiAqICAgICAgIDxwPntlcnJvcnM/LnJvb3Q/LnNlcnZlciAmJiAnU2VydmVyIGVycm9yJ308L3A+XG4gKiAgICAgICA8YnV0dG9uPlN1Ym1pdDwvYnV0dG9uPlxuICogICAgIDwvRm9ybT5cbiAqICAgKTtcbiAqIH1cbiAqIGBgYFxuICovXG5mdW5jdGlvbiBGb3JtKHByb3BzKSB7XG4gICAgY29uc3QgbWV0aG9kcyA9IHVzZUZvcm1Db250ZXh0KCk7XG4gICAgY29uc3QgW21vdW50ZWQsIHNldE1vdW50ZWRdID0gUmVhY3QudXNlU3RhdGUoZmFsc2UpO1xuICAgIGNvbnN0IHsgY29udHJvbCA9IG1ldGhvZHMuY29udHJvbCwgb25TdWJtaXQsIGNoaWxkcmVuLCBhY3Rpb24sIG1ldGhvZCA9IFBPU1RfUkVRVUVTVCwgaGVhZGVycywgZW5jVHlwZSwgb25FcnJvciwgcmVuZGVyLCBvblN1Y2Nlc3MsIHZhbGlkYXRlU3RhdHVzLCAuLi5yZXN0IH0gPSBwcm9wcztcbiAgICBjb25zdCBzdWJtaXQgPSBhc3luYyAoZXZlbnQpID0+IHtcbiAgICAgICAgbGV0IGhhc0Vycm9yID0gZmFsc2U7XG4gICAgICAgIGxldCB0eXBlID0gJyc7XG4gICAgICAgIGF3YWl0IGNvbnRyb2wuaGFuZGxlU3VibWl0KGFzeW5jIChkYXRhKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBmb3JtRGF0YSA9IG5ldyBGb3JtRGF0YSgpO1xuICAgICAgICAgICAgbGV0IGZvcm1EYXRhSnNvbiA9ICcnO1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBmb3JtRGF0YUpzb24gPSBKU09OLnN0cmluZ2lmeShkYXRhKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhdGNoIChfYSkgeyB9XG4gICAgICAgICAgICBjb25zdCBmbGF0dGVuRm9ybVZhbHVlcyA9IGZsYXR0ZW4oY29udHJvbC5fZm9ybVZhbHVlcyk7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGtleSBpbiBmbGF0dGVuRm9ybVZhbHVlcykge1xuICAgICAgICAgICAgICAgIGZvcm1EYXRhLmFwcGVuZChrZXksIGZsYXR0ZW5Gb3JtVmFsdWVzW2tleV0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKG9uU3VibWl0KSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgb25TdWJtaXQoe1xuICAgICAgICAgICAgICAgICAgICBkYXRhLFxuICAgICAgICAgICAgICAgICAgICBldmVudCxcbiAgICAgICAgICAgICAgICAgICAgbWV0aG9kLFxuICAgICAgICAgICAgICAgICAgICBmb3JtRGF0YSxcbiAgICAgICAgICAgICAgICAgICAgZm9ybURhdGFKc29uLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGFjdGlvbikge1xuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHNob3VsZFN0cmluZ2lmeVN1Ym1pc3Npb25EYXRhID0gW1xuICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVycyAmJiBoZWFkZXJzWydDb250ZW50LVR5cGUnXSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGVuY1R5cGUsXG4gICAgICAgICAgICAgICAgICAgIF0uc29tZSgodmFsdWUpID0+IHZhbHVlICYmIHZhbHVlLmluY2x1ZGVzKCdqc29uJykpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKFN0cmluZyhhY3Rpb24pLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBtZXRob2QsXG4gICAgICAgICAgICAgICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uaGVhZGVycyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLi4oZW5jVHlwZSAmJiBlbmNUeXBlICE9PSAnbXVsdGlwYXJ0L2Zvcm0tZGF0YSdcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPyB7ICdDb250ZW50LVR5cGUnOiBlbmNUeXBlIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgOiB7fSksXG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgYm9keTogc2hvdWxkU3RyaW5naWZ5U3VibWlzc2lvbkRhdGEgPyBmb3JtRGF0YUpzb24gOiBmb3JtRGF0YSxcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChyZXNwb25zZSAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgKHZhbGlkYXRlU3RhdHVzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPyAhdmFsaWRhdGVTdGF0dXMocmVzcG9uc2Uuc3RhdHVzKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDogcmVzcG9uc2Uuc3RhdHVzIDwgMjAwIHx8IHJlc3BvbnNlLnN0YXR1cyA+PSAzMDApKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBoYXNFcnJvciA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgICAgICBvbkVycm9yICYmIG9uRXJyb3IoeyByZXNwb25zZSB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSBTdHJpbmcocmVzcG9uc2Uuc3RhdHVzKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uU3VjY2VzcyAmJiBvblN1Y2Nlc3MoeyByZXNwb25zZSB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgaGFzRXJyb3IgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICBvbkVycm9yICYmIG9uRXJyb3IoeyBlcnJvciB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pKGV2ZW50KTtcbiAgICAgICAgaWYgKGhhc0Vycm9yICYmIHByb3BzLmNvbnRyb2wpIHtcbiAgICAgICAgICAgIHByb3BzLmNvbnRyb2wuX3N1YmplY3RzLnN0YXRlLm5leHQoe1xuICAgICAgICAgICAgICAgIGlzU3VibWl0U3VjY2Vzc2Z1bDogZmFsc2UsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHByb3BzLmNvbnRyb2wuc2V0RXJyb3IoJ3Jvb3Quc2VydmVyJywge1xuICAgICAgICAgICAgICAgIHR5cGUsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgUmVhY3QudXNlRWZmZWN0KCgpID0+IHtcbiAgICAgICAgc2V0TW91bnRlZCh0cnVlKTtcbiAgICB9LCBbXSk7XG4gICAgcmV0dXJuIHJlbmRlciA/IChSZWFjdC5jcmVhdGVFbGVtZW50KFJlYWN0LkZyYWdtZW50LCBudWxsLCByZW5kZXIoe1xuICAgICAgICBzdWJtaXQsXG4gICAgfSkpKSA6IChSZWFjdC5jcmVhdGVFbGVtZW50KFwiZm9ybVwiLCB7IG5vVmFsaWRhdGU6IG1vdW50ZWQsIGFjdGlvbjogYWN0aW9uLCBtZXRob2Q6IG1ldGhvZCwgZW5jVHlwZTogZW5jVHlwZSwgb25TdWJtaXQ6IHN1Ym1pdCwgLi4ucmVzdCB9LCBjaGlsZHJlbikpO1xufVxuXG52YXIgYXBwZW5kRXJyb3JzID0gKG5hbWUsIHZhbGlkYXRlQWxsRmllbGRDcml0ZXJpYSwgZXJyb3JzLCB0eXBlLCBtZXNzYWdlKSA9PiB2YWxpZGF0ZUFsbEZpZWxkQ3JpdGVyaWFcbiAgICA/IHtcbiAgICAgICAgLi4uZXJyb3JzW25hbWVdLFxuICAgICAgICB0eXBlczoge1xuICAgICAgICAgICAgLi4uKGVycm9yc1tuYW1lXSAmJiBlcnJvcnNbbmFtZV0udHlwZXMgPyBlcnJvcnNbbmFtZV0udHlwZXMgOiB7fSksXG4gICAgICAgICAgICBbdHlwZV06IG1lc3NhZ2UgfHwgdHJ1ZSxcbiAgICAgICAgfSxcbiAgICB9XG4gICAgOiB7fTtcblxudmFyIGNvbnZlcnRUb0FycmF5UGF5bG9hZCA9ICh2YWx1ZSkgPT4gKEFycmF5LmlzQXJyYXkodmFsdWUpID8gdmFsdWUgOiBbdmFsdWVdKTtcblxudmFyIGNyZWF0ZVN1YmplY3QgPSAoKSA9PiB7XG4gICAgbGV0IF9vYnNlcnZlcnMgPSBbXTtcbiAgICBjb25zdCBuZXh0ID0gKHZhbHVlKSA9PiB7XG4gICAgICAgIGZvciAoY29uc3Qgb2JzZXJ2ZXIgb2YgX29ic2VydmVycykge1xuICAgICAgICAgICAgb2JzZXJ2ZXIubmV4dCAmJiBvYnNlcnZlci5uZXh0KHZhbHVlKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgY29uc3Qgc3Vic2NyaWJlID0gKG9ic2VydmVyKSA9PiB7XG4gICAgICAgIF9vYnNlcnZlcnMucHVzaChvYnNlcnZlcik7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICB1bnN1YnNjcmliZTogKCkgPT4ge1xuICAgICAgICAgICAgICAgIF9vYnNlcnZlcnMgPSBfb2JzZXJ2ZXJzLmZpbHRlcigobykgPT4gbyAhPT0gb2JzZXJ2ZXIpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgfTtcbiAgICB9O1xuICAgIGNvbnN0IHVuc3Vic2NyaWJlID0gKCkgPT4ge1xuICAgICAgICBfb2JzZXJ2ZXJzID0gW107XG4gICAgfTtcbiAgICByZXR1cm4ge1xuICAgICAgICBnZXQgb2JzZXJ2ZXJzKCkge1xuICAgICAgICAgICAgcmV0dXJuIF9vYnNlcnZlcnM7XG4gICAgICAgIH0sXG4gICAgICAgIG5leHQsXG4gICAgICAgIHN1YnNjcmliZSxcbiAgICAgICAgdW5zdWJzY3JpYmUsXG4gICAgfTtcbn07XG5cbmZ1bmN0aW9uIGV4dHJhY3RGb3JtVmFsdWVzKGZpZWxkc1N0YXRlLCBmb3JtVmFsdWVzKSB7XG4gICAgY29uc3QgdmFsdWVzID0ge307XG4gICAgZm9yIChjb25zdCBrZXkgaW4gZmllbGRzU3RhdGUpIHtcbiAgICAgICAgaWYgKGZpZWxkc1N0YXRlLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgICAgIGNvbnN0IGZpZWxkU3RhdGUgPSBmaWVsZHNTdGF0ZVtrZXldO1xuICAgICAgICAgICAgY29uc3QgZmllbGRWYWx1ZSA9IGZvcm1WYWx1ZXNba2V5XTtcbiAgICAgICAgICAgIGlmIChmaWVsZFN0YXRlICYmIGlzT2JqZWN0KGZpZWxkU3RhdGUpICYmIGZpZWxkVmFsdWUpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBuZXN0ZWRGaWVsZHNTdGF0ZSA9IGV4dHJhY3RGb3JtVmFsdWVzKGZpZWxkU3RhdGUsIGZpZWxkVmFsdWUpO1xuICAgICAgICAgICAgICAgIGlmIChpc09iamVjdChuZXN0ZWRGaWVsZHNTdGF0ZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWVzW2tleV0gPSBuZXN0ZWRGaWVsZHNTdGF0ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmIChmaWVsZHNTdGF0ZVtrZXldKSB7XG4gICAgICAgICAgICAgICAgdmFsdWVzW2tleV0gPSBmaWVsZFZhbHVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB2YWx1ZXM7XG59XG5cbnZhciBpc0VtcHR5T2JqZWN0ID0gKHZhbHVlKSA9PiBpc09iamVjdCh2YWx1ZSkgJiYgIU9iamVjdC5rZXlzKHZhbHVlKS5sZW5ndGg7XG5cbnZhciBpc0ZpbGVJbnB1dCA9IChlbGVtZW50KSA9PiBlbGVtZW50LnR5cGUgPT09ICdmaWxlJztcblxudmFyIGlzRnVuY3Rpb24gPSAodmFsdWUpID0+IHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJztcblxudmFyIGlzSFRNTEVsZW1lbnQgPSAodmFsdWUpID0+IHtcbiAgICBpZiAoIWlzV2ViKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgY29uc3Qgb3duZXIgPSB2YWx1ZSA/IHZhbHVlLm93bmVyRG9jdW1lbnQgOiAwO1xuICAgIHJldHVybiAodmFsdWUgaW5zdGFuY2VvZlxuICAgICAgICAob3duZXIgJiYgb3duZXIuZGVmYXVsdFZpZXcgPyBvd25lci5kZWZhdWx0Vmlldy5IVE1MRWxlbWVudCA6IEhUTUxFbGVtZW50KSk7XG59O1xuXG52YXIgaXNNdWx0aXBsZVNlbGVjdCA9IChlbGVtZW50KSA9PiBlbGVtZW50LnR5cGUgPT09IGBzZWxlY3QtbXVsdGlwbGVgO1xuXG52YXIgaXNSYWRpb0lucHV0ID0gKGVsZW1lbnQpID0+IGVsZW1lbnQudHlwZSA9PT0gJ3JhZGlvJztcblxudmFyIGlzUmFkaW9PckNoZWNrYm94ID0gKHJlZikgPT4gaXNSYWRpb0lucHV0KHJlZikgfHwgaXNDaGVja0JveElucHV0KHJlZik7XG5cbnZhciBsaXZlID0gKHJlZikgPT4gaXNIVE1MRWxlbWVudChyZWYpICYmIHJlZi5pc0Nvbm5lY3RlZDtcblxuZnVuY3Rpb24gYmFzZUdldChvYmplY3QsIHVwZGF0ZVBhdGgpIHtcbiAgICBjb25zdCBsZW5ndGggPSB1cGRhdGVQYXRoLnNsaWNlKDAsIC0xKS5sZW5ndGg7XG4gICAgbGV0IGluZGV4ID0gMDtcbiAgICB3aGlsZSAoaW5kZXggPCBsZW5ndGgpIHtcbiAgICAgICAgb2JqZWN0ID0gaXNVbmRlZmluZWQob2JqZWN0KSA/IGluZGV4KysgOiBvYmplY3RbdXBkYXRlUGF0aFtpbmRleCsrXV07XG4gICAgfVxuICAgIHJldHVybiBvYmplY3Q7XG59XG5mdW5jdGlvbiBpc0VtcHR5QXJyYXkob2JqKSB7XG4gICAgZm9yIChjb25zdCBrZXkgaW4gb2JqKSB7XG4gICAgICAgIGlmIChvYmouaGFzT3duUHJvcGVydHkoa2V5KSAmJiAhaXNVbmRlZmluZWQob2JqW2tleV0pKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG59XG5mdW5jdGlvbiB1bnNldChvYmplY3QsIHBhdGgpIHtcbiAgICBjb25zdCBwYXRocyA9IEFycmF5LmlzQXJyYXkocGF0aClcbiAgICAgICAgPyBwYXRoXG4gICAgICAgIDogaXNLZXkocGF0aClcbiAgICAgICAgICAgID8gW3BhdGhdXG4gICAgICAgICAgICA6IHN0cmluZ1RvUGF0aChwYXRoKTtcbiAgICBjb25zdCBjaGlsZE9iamVjdCA9IHBhdGhzLmxlbmd0aCA9PT0gMSA/IG9iamVjdCA6IGJhc2VHZXQob2JqZWN0LCBwYXRocyk7XG4gICAgY29uc3QgaW5kZXggPSBwYXRocy5sZW5ndGggLSAxO1xuICAgIGNvbnN0IGtleSA9IHBhdGhzW2luZGV4XTtcbiAgICBpZiAoY2hpbGRPYmplY3QpIHtcbiAgICAgICAgZGVsZXRlIGNoaWxkT2JqZWN0W2tleV07XG4gICAgfVxuICAgIGlmIChpbmRleCAhPT0gMCAmJlxuICAgICAgICAoKGlzT2JqZWN0KGNoaWxkT2JqZWN0KSAmJiBpc0VtcHR5T2JqZWN0KGNoaWxkT2JqZWN0KSkgfHxcbiAgICAgICAgICAgIChBcnJheS5pc0FycmF5KGNoaWxkT2JqZWN0KSAmJiBpc0VtcHR5QXJyYXkoY2hpbGRPYmplY3QpKSkpIHtcbiAgICAgICAgdW5zZXQob2JqZWN0LCBwYXRocy5zbGljZSgwLCAtMSkpO1xuICAgIH1cbiAgICByZXR1cm4gb2JqZWN0O1xufVxuXG52YXIgb2JqZWN0SGFzRnVuY3Rpb24gPSAoZGF0YSkgPT4ge1xuICAgIGZvciAoY29uc3Qga2V5IGluIGRhdGEpIHtcbiAgICAgICAgaWYgKGlzRnVuY3Rpb24oZGF0YVtrZXldKSkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xufTtcblxuZnVuY3Rpb24gaXNUcmF2ZXJzYWJsZSh2YWx1ZSkge1xuICAgIHJldHVybiBBcnJheS5pc0FycmF5KHZhbHVlKSB8fCAoaXNPYmplY3QodmFsdWUpICYmICFvYmplY3RIYXNGdW5jdGlvbih2YWx1ZSkpO1xufVxuZnVuY3Rpb24gbWFya0ZpZWxkc0RpcnR5KGRhdGEsIGZpZWxkcyA9IHt9KSB7XG4gICAgZm9yIChjb25zdCBrZXkgaW4gZGF0YSkge1xuICAgICAgICBjb25zdCB2YWx1ZSA9IGRhdGFba2V5XTtcbiAgICAgICAgaWYgKGlzVHJhdmVyc2FibGUodmFsdWUpKSB7XG4gICAgICAgICAgICBmaWVsZHNba2V5XSA9IEFycmF5LmlzQXJyYXkodmFsdWUpID8gW10gOiB7fTtcbiAgICAgICAgICAgIG1hcmtGaWVsZHNEaXJ0eSh2YWx1ZSwgZmllbGRzW2tleV0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKCFpc1VuZGVmaW5lZCh2YWx1ZSkpIHtcbiAgICAgICAgICAgIGZpZWxkc1trZXldID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gZmllbGRzO1xufVxuZnVuY3Rpb24gZ2V0RGlydHlGaWVsZHMoZGF0YSwgZm9ybVZhbHVlcywgZGlydHlGaWVsZHNGcm9tVmFsdWVzKSB7XG4gICAgaWYgKCFkaXJ0eUZpZWxkc0Zyb21WYWx1ZXMpIHtcbiAgICAgICAgZGlydHlGaWVsZHNGcm9tVmFsdWVzID0gbWFya0ZpZWxkc0RpcnR5KGZvcm1WYWx1ZXMpO1xuICAgIH1cbiAgICBmb3IgKGNvbnN0IGtleSBpbiBkYXRhKSB7XG4gICAgICAgIGNvbnN0IHZhbHVlID0gZGF0YVtrZXldO1xuICAgICAgICBpZiAoaXNUcmF2ZXJzYWJsZSh2YWx1ZSkpIHtcbiAgICAgICAgICAgIGlmIChpc1VuZGVmaW5lZChmb3JtVmFsdWVzKSB8fCBpc1ByaW1pdGl2ZShkaXJ0eUZpZWxkc0Zyb21WYWx1ZXNba2V5XSkpIHtcbiAgICAgICAgICAgICAgICBkaXJ0eUZpZWxkc0Zyb21WYWx1ZXNba2V5XSA9IG1hcmtGaWVsZHNEaXJ0eSh2YWx1ZSwgQXJyYXkuaXNBcnJheSh2YWx1ZSkgPyBbXSA6IHt9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGdldERpcnR5RmllbGRzKHZhbHVlLCBpc051bGxPclVuZGVmaW5lZChmb3JtVmFsdWVzKSA/IHt9IDogZm9ybVZhbHVlc1trZXldLCBkaXJ0eUZpZWxkc0Zyb21WYWx1ZXNba2V5XSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBjb25zdCBmb3JtVmFsdWUgPSBmb3JtVmFsdWVzW2tleV07XG4gICAgICAgICAgICBkaXJ0eUZpZWxkc0Zyb21WYWx1ZXNba2V5XSA9ICFkZWVwRXF1YWwodmFsdWUsIGZvcm1WYWx1ZSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGRpcnR5RmllbGRzRnJvbVZhbHVlcztcbn1cblxuY29uc3QgZGVmYXVsdFJlc3VsdCA9IHtcbiAgICB2YWx1ZTogZmFsc2UsXG4gICAgaXNWYWxpZDogZmFsc2UsXG59O1xuY29uc3QgdmFsaWRSZXN1bHQgPSB7IHZhbHVlOiB0cnVlLCBpc1ZhbGlkOiB0cnVlIH07XG52YXIgZ2V0Q2hlY2tib3hWYWx1ZSA9IChvcHRpb25zKSA9PiB7XG4gICAgaWYgKEFycmF5LmlzQXJyYXkob3B0aW9ucykpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgY29uc3QgdmFsdWVzID0gb3B0aW9uc1xuICAgICAgICAgICAgICAgIC5maWx0ZXIoKG9wdGlvbikgPT4gb3B0aW9uICYmIG9wdGlvbi5jaGVja2VkICYmICFvcHRpb24uZGlzYWJsZWQpXG4gICAgICAgICAgICAgICAgLm1hcCgob3B0aW9uKSA9PiBvcHRpb24udmFsdWUpO1xuICAgICAgICAgICAgcmV0dXJuIHsgdmFsdWU6IHZhbHVlcywgaXNWYWxpZDogISF2YWx1ZXMubGVuZ3RoIH07XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG9wdGlvbnNbMF0uY2hlY2tlZCAmJiAhb3B0aW9uc1swXS5kaXNhYmxlZFxuICAgICAgICAgICAgPyAvLyBAdHMtZXhwZWN0LWVycm9yIGV4cGVjdGVkIHRvIHdvcmsgaW4gdGhlIGJyb3dzZXJcbiAgICAgICAgICAgICAgICBvcHRpb25zWzBdLmF0dHJpYnV0ZXMgJiYgIWlzVW5kZWZpbmVkKG9wdGlvbnNbMF0uYXR0cmlidXRlcy52YWx1ZSlcbiAgICAgICAgICAgICAgICAgICAgPyBpc1VuZGVmaW5lZChvcHRpb25zWzBdLnZhbHVlKSB8fCBvcHRpb25zWzBdLnZhbHVlID09PSAnJ1xuICAgICAgICAgICAgICAgICAgICAgICAgPyB2YWxpZFJlc3VsdFxuICAgICAgICAgICAgICAgICAgICAgICAgOiB7IHZhbHVlOiBvcHRpb25zWzBdLnZhbHVlLCBpc1ZhbGlkOiB0cnVlIH1cbiAgICAgICAgICAgICAgICAgICAgOiB2YWxpZFJlc3VsdFxuICAgICAgICAgICAgOiBkZWZhdWx0UmVzdWx0O1xuICAgIH1cbiAgICByZXR1cm4gZGVmYXVsdFJlc3VsdDtcbn07XG5cbnZhciBnZXRGaWVsZFZhbHVlQXMgPSAodmFsdWUsIHsgdmFsdWVBc051bWJlciwgdmFsdWVBc0RhdGUsIHNldFZhbHVlQXMgfSkgPT4gaXNVbmRlZmluZWQodmFsdWUpXG4gICAgPyB2YWx1ZVxuICAgIDogdmFsdWVBc051bWJlclxuICAgICAgICA/IHZhbHVlID09PSAnJ1xuICAgICAgICAgICAgPyBOYU5cbiAgICAgICAgICAgIDogdmFsdWVcbiAgICAgICAgICAgICAgICA/ICt2YWx1ZVxuICAgICAgICAgICAgICAgIDogdmFsdWVcbiAgICAgICAgOiB2YWx1ZUFzRGF0ZSAmJiBpc1N0cmluZyh2YWx1ZSlcbiAgICAgICAgICAgID8gbmV3IERhdGUodmFsdWUpXG4gICAgICAgICAgICA6IHNldFZhbHVlQXNcbiAgICAgICAgICAgICAgICA/IHNldFZhbHVlQXModmFsdWUpXG4gICAgICAgICAgICAgICAgOiB2YWx1ZTtcblxuY29uc3QgZGVmYXVsdFJldHVybiA9IHtcbiAgICBpc1ZhbGlkOiBmYWxzZSxcbiAgICB2YWx1ZTogbnVsbCxcbn07XG52YXIgZ2V0UmFkaW9WYWx1ZSA9IChvcHRpb25zKSA9PiBBcnJheS5pc0FycmF5KG9wdGlvbnMpXG4gICAgPyBvcHRpb25zLnJlZHVjZSgocHJldmlvdXMsIG9wdGlvbikgPT4gb3B0aW9uICYmIG9wdGlvbi5jaGVja2VkICYmICFvcHRpb24uZGlzYWJsZWRcbiAgICAgICAgPyB7XG4gICAgICAgICAgICBpc1ZhbGlkOiB0cnVlLFxuICAgICAgICAgICAgdmFsdWU6IG9wdGlvbi52YWx1ZSxcbiAgICAgICAgfVxuICAgICAgICA6IHByZXZpb3VzLCBkZWZhdWx0UmV0dXJuKVxuICAgIDogZGVmYXVsdFJldHVybjtcblxuZnVuY3Rpb24gZ2V0RmllbGRWYWx1ZShfZikge1xuICAgIGNvbnN0IHJlZiA9IF9mLnJlZjtcbiAgICBpZiAoaXNGaWxlSW5wdXQocmVmKSkge1xuICAgICAgICByZXR1cm4gcmVmLmZpbGVzO1xuICAgIH1cbiAgICBpZiAoaXNSYWRpb0lucHV0KHJlZikpIHtcbiAgICAgICAgcmV0dXJuIGdldFJhZGlvVmFsdWUoX2YucmVmcykudmFsdWU7XG4gICAgfVxuICAgIGlmIChpc011bHRpcGxlU2VsZWN0KHJlZikpIHtcbiAgICAgICAgcmV0dXJuIFsuLi5yZWYuc2VsZWN0ZWRPcHRpb25zXS5tYXAoKHsgdmFsdWUgfSkgPT4gdmFsdWUpO1xuICAgIH1cbiAgICBpZiAoaXNDaGVja0JveElucHV0KHJlZikpIHtcbiAgICAgICAgcmV0dXJuIGdldENoZWNrYm94VmFsdWUoX2YucmVmcykudmFsdWU7XG4gICAgfVxuICAgIHJldHVybiBnZXRGaWVsZFZhbHVlQXMoaXNVbmRlZmluZWQocmVmLnZhbHVlKSA/IF9mLnJlZi52YWx1ZSA6IHJlZi52YWx1ZSwgX2YpO1xufVxuXG52YXIgZ2V0UmVzb2x2ZXJPcHRpb25zID0gKGZpZWxkc05hbWVzLCBfZmllbGRzLCBjcml0ZXJpYU1vZGUsIHNob3VsZFVzZU5hdGl2ZVZhbGlkYXRpb24pID0+IHtcbiAgICBjb25zdCBmaWVsZHMgPSB7fTtcbiAgICBmb3IgKGNvbnN0IG5hbWUgb2YgZmllbGRzTmFtZXMpIHtcbiAgICAgICAgY29uc3QgZmllbGQgPSBnZXQoX2ZpZWxkcywgbmFtZSk7XG4gICAgICAgIGZpZWxkICYmIHNldChmaWVsZHMsIG5hbWUsIGZpZWxkLl9mKTtcbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgICAgY3JpdGVyaWFNb2RlLFxuICAgICAgICBuYW1lczogWy4uLmZpZWxkc05hbWVzXSxcbiAgICAgICAgZmllbGRzLFxuICAgICAgICBzaG91bGRVc2VOYXRpdmVWYWxpZGF0aW9uLFxuICAgIH07XG59O1xuXG52YXIgaXNSZWdleCA9ICh2YWx1ZSkgPT4gdmFsdWUgaW5zdGFuY2VvZiBSZWdFeHA7XG5cbnZhciBnZXRSdWxlVmFsdWUgPSAocnVsZSkgPT4gaXNVbmRlZmluZWQocnVsZSlcbiAgICA/IHJ1bGVcbiAgICA6IGlzUmVnZXgocnVsZSlcbiAgICAgICAgPyBydWxlLnNvdXJjZVxuICAgICAgICA6IGlzT2JqZWN0KHJ1bGUpXG4gICAgICAgICAgICA/IGlzUmVnZXgocnVsZS52YWx1ZSlcbiAgICAgICAgICAgICAgICA/IHJ1bGUudmFsdWUuc291cmNlXG4gICAgICAgICAgICAgICAgOiBydWxlLnZhbHVlXG4gICAgICAgICAgICA6IHJ1bGU7XG5cbnZhciBnZXRWYWxpZGF0aW9uTW9kZXMgPSAobW9kZSkgPT4gKHtcbiAgICBpc09uU3VibWl0OiAhbW9kZSB8fCBtb2RlID09PSBWQUxJREFUSU9OX01PREUub25TdWJtaXQsXG4gICAgaXNPbkJsdXI6IG1vZGUgPT09IFZBTElEQVRJT05fTU9ERS5vbkJsdXIsXG4gICAgaXNPbkNoYW5nZTogbW9kZSA9PT0gVkFMSURBVElPTl9NT0RFLm9uQ2hhbmdlLFxuICAgIGlzT25BbGw6IG1vZGUgPT09IFZBTElEQVRJT05fTU9ERS5hbGwsXG4gICAgaXNPblRvdWNoOiBtb2RlID09PSBWQUxJREFUSU9OX01PREUub25Ub3VjaGVkLFxufSk7XG5cbmNvbnN0IEFTWU5DX0ZVTkNUSU9OID0gJ0FzeW5jRnVuY3Rpb24nO1xudmFyIGhhc1Byb21pc2VWYWxpZGF0aW9uID0gKGZpZWxkUmVmZXJlbmNlKSA9PiAhIWZpZWxkUmVmZXJlbmNlICYmXG4gICAgISFmaWVsZFJlZmVyZW5jZS52YWxpZGF0ZSAmJlxuICAgICEhKChpc0Z1bmN0aW9uKGZpZWxkUmVmZXJlbmNlLnZhbGlkYXRlKSAmJlxuICAgICAgICBmaWVsZFJlZmVyZW5jZS52YWxpZGF0ZS5jb25zdHJ1Y3Rvci5uYW1lID09PSBBU1lOQ19GVU5DVElPTikgfHxcbiAgICAgICAgKGlzT2JqZWN0KGZpZWxkUmVmZXJlbmNlLnZhbGlkYXRlKSAmJlxuICAgICAgICAgICAgT2JqZWN0LnZhbHVlcyhmaWVsZFJlZmVyZW5jZS52YWxpZGF0ZSkuZmluZCgodmFsaWRhdGVGdW5jdGlvbikgPT4gdmFsaWRhdGVGdW5jdGlvbi5jb25zdHJ1Y3Rvci5uYW1lID09PSBBU1lOQ19GVU5DVElPTikpKTtcblxudmFyIGhhc1ZhbGlkYXRpb24gPSAob3B0aW9ucykgPT4gb3B0aW9ucy5tb3VudCAmJlxuICAgIChvcHRpb25zLnJlcXVpcmVkIHx8XG4gICAgICAgIG9wdGlvbnMubWluIHx8XG4gICAgICAgIG9wdGlvbnMubWF4IHx8XG4gICAgICAgIG9wdGlvbnMubWF4TGVuZ3RoIHx8XG4gICAgICAgIG9wdGlvbnMubWluTGVuZ3RoIHx8XG4gICAgICAgIG9wdGlvbnMucGF0dGVybiB8fFxuICAgICAgICBvcHRpb25zLnZhbGlkYXRlKTtcblxudmFyIGlzV2F0Y2hlZCA9IChuYW1lLCBfbmFtZXMsIGlzQmx1ckV2ZW50KSA9PiAhaXNCbHVyRXZlbnQgJiZcbiAgICAoX25hbWVzLndhdGNoQWxsIHx8XG4gICAgICAgIF9uYW1lcy53YXRjaC5oYXMobmFtZSkgfHxcbiAgICAgICAgWy4uLl9uYW1lcy53YXRjaF0uc29tZSgod2F0Y2hOYW1lKSA9PiBuYW1lLnN0YXJ0c1dpdGgod2F0Y2hOYW1lKSAmJlxuICAgICAgICAgICAgL15cXC5cXHcrLy50ZXN0KG5hbWUuc2xpY2Uod2F0Y2hOYW1lLmxlbmd0aCkpKSk7XG5cbmNvbnN0IGl0ZXJhdGVGaWVsZHNCeUFjdGlvbiA9IChmaWVsZHMsIGFjdGlvbiwgZmllbGRzTmFtZXMsIGFib3J0RWFybHkpID0+IHtcbiAgICBmb3IgKGNvbnN0IGtleSBvZiBmaWVsZHNOYW1lcyB8fCBPYmplY3Qua2V5cyhmaWVsZHMpKSB7XG4gICAgICAgIGNvbnN0IGZpZWxkID0gZ2V0KGZpZWxkcywga2V5KTtcbiAgICAgICAgaWYgKGZpZWxkKSB7XG4gICAgICAgICAgICBjb25zdCB7IF9mLCAuLi5jdXJyZW50RmllbGQgfSA9IGZpZWxkO1xuICAgICAgICAgICAgaWYgKF9mKSB7XG4gICAgICAgICAgICAgICAgaWYgKF9mLnJlZnMgJiYgX2YucmVmc1swXSAmJiBhY3Rpb24oX2YucmVmc1swXSwga2V5KSAmJiAhYWJvcnRFYXJseSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAoX2YucmVmICYmIGFjdGlvbihfZi5yZWYsIF9mLm5hbWUpICYmICFhYm9ydEVhcmx5KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGl0ZXJhdGVGaWVsZHNCeUFjdGlvbihjdXJyZW50RmllbGQsIGFjdGlvbikpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoaXNPYmplY3QoY3VycmVudEZpZWxkKSkge1xuICAgICAgICAgICAgICAgIGlmIChpdGVyYXRlRmllbGRzQnlBY3Rpb24oY3VycmVudEZpZWxkLCBhY3Rpb24pKSB7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm47XG59O1xuXG5mdW5jdGlvbiBzY2hlbWFFcnJvckxvb2t1cChlcnJvcnMsIF9maWVsZHMsIG5hbWUpIHtcbiAgICBjb25zdCBlcnJvciA9IGdldChlcnJvcnMsIG5hbWUpO1xuICAgIGlmIChlcnJvciB8fCBpc0tleShuYW1lKSkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgZXJyb3IsXG4gICAgICAgICAgICBuYW1lLFxuICAgICAgICB9O1xuICAgIH1cbiAgICBjb25zdCBuYW1lcyA9IG5hbWUuc3BsaXQoJy4nKTtcbiAgICB3aGlsZSAobmFtZXMubGVuZ3RoKSB7XG4gICAgICAgIGNvbnN0IGZpZWxkTmFtZSA9IG5hbWVzLmpvaW4oJy4nKTtcbiAgICAgICAgY29uc3QgZmllbGQgPSBnZXQoX2ZpZWxkcywgZmllbGROYW1lKTtcbiAgICAgICAgY29uc3QgZm91bmRFcnJvciA9IGdldChlcnJvcnMsIGZpZWxkTmFtZSk7XG4gICAgICAgIGlmIChmaWVsZCAmJiAhQXJyYXkuaXNBcnJheShmaWVsZCkgJiYgbmFtZSAhPT0gZmllbGROYW1lKSB7XG4gICAgICAgICAgICByZXR1cm4geyBuYW1lIH07XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGZvdW5kRXJyb3IgJiYgZm91bmRFcnJvci50eXBlKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIG5hbWU6IGZpZWxkTmFtZSxcbiAgICAgICAgICAgICAgICBlcnJvcjogZm91bmRFcnJvcixcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGZvdW5kRXJyb3IgJiYgZm91bmRFcnJvci5yb290ICYmIGZvdW5kRXJyb3Iucm9vdC50eXBlKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIG5hbWU6IGAke2ZpZWxkTmFtZX0ucm9vdGAsXG4gICAgICAgICAgICAgICAgZXJyb3I6IGZvdW5kRXJyb3Iucm9vdCxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgbmFtZXMucG9wKCk7XG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICAgIG5hbWUsXG4gICAgfTtcbn1cblxudmFyIHNob3VsZFJlbmRlckZvcm1TdGF0ZSA9IChmb3JtU3RhdGVEYXRhLCBfcHJveHlGb3JtU3RhdGUsIHVwZGF0ZUZvcm1TdGF0ZSwgaXNSb290KSA9PiB7XG4gICAgdXBkYXRlRm9ybVN0YXRlKGZvcm1TdGF0ZURhdGEpO1xuICAgIGNvbnN0IHsgbmFtZSwgLi4uZm9ybVN0YXRlIH0gPSBmb3JtU3RhdGVEYXRhO1xuICAgIHJldHVybiAoaXNFbXB0eU9iamVjdChmb3JtU3RhdGUpIHx8XG4gICAgICAgIE9iamVjdC5rZXlzKGZvcm1TdGF0ZSkubGVuZ3RoID49IE9iamVjdC5rZXlzKF9wcm94eUZvcm1TdGF0ZSkubGVuZ3RoIHx8XG4gICAgICAgIE9iamVjdC5rZXlzKGZvcm1TdGF0ZSkuZmluZCgoa2V5KSA9PiBfcHJveHlGb3JtU3RhdGVba2V5XSA9PT1cbiAgICAgICAgICAgICghaXNSb290IHx8IFZBTElEQVRJT05fTU9ERS5hbGwpKSk7XG59O1xuXG52YXIgc2hvdWxkU3Vic2NyaWJlQnlOYW1lID0gKG5hbWUsIHNpZ25hbE5hbWUsIGV4YWN0KSA9PiAhbmFtZSB8fFxuICAgICFzaWduYWxOYW1lIHx8XG4gICAgbmFtZSA9PT0gc2lnbmFsTmFtZSB8fFxuICAgIGNvbnZlcnRUb0FycmF5UGF5bG9hZChuYW1lKS5zb21lKChjdXJyZW50TmFtZSkgPT4gY3VycmVudE5hbWUgJiZcbiAgICAgICAgKGV4YWN0XG4gICAgICAgICAgICA/IGN1cnJlbnROYW1lID09PSBzaWduYWxOYW1lXG4gICAgICAgICAgICA6IGN1cnJlbnROYW1lLnN0YXJ0c1dpdGgoc2lnbmFsTmFtZSkgfHxcbiAgICAgICAgICAgICAgICBzaWduYWxOYW1lLnN0YXJ0c1dpdGgoY3VycmVudE5hbWUpKSk7XG5cbnZhciBza2lwVmFsaWRhdGlvbiA9IChpc0JsdXJFdmVudCwgaXNUb3VjaGVkLCBpc1N1Ym1pdHRlZCwgcmVWYWxpZGF0ZU1vZGUsIG1vZGUpID0+IHtcbiAgICBpZiAobW9kZS5pc09uQWxsKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgZWxzZSBpZiAoIWlzU3VibWl0dGVkICYmIG1vZGUuaXNPblRvdWNoKSB7XG4gICAgICAgIHJldHVybiAhKGlzVG91Y2hlZCB8fCBpc0JsdXJFdmVudCk7XG4gICAgfVxuICAgIGVsc2UgaWYgKGlzU3VibWl0dGVkID8gcmVWYWxpZGF0ZU1vZGUuaXNPbkJsdXIgOiBtb2RlLmlzT25CbHVyKSB7XG4gICAgICAgIHJldHVybiAhaXNCbHVyRXZlbnQ7XG4gICAgfVxuICAgIGVsc2UgaWYgKGlzU3VibWl0dGVkID8gcmVWYWxpZGF0ZU1vZGUuaXNPbkNoYW5nZSA6IG1vZGUuaXNPbkNoYW5nZSkge1xuICAgICAgICByZXR1cm4gaXNCbHVyRXZlbnQ7XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xufTtcblxudmFyIHVuc2V0RW1wdHlBcnJheSA9IChyZWYsIG5hbWUpID0+ICFjb21wYWN0KGdldChyZWYsIG5hbWUpKS5sZW5ndGggJiYgdW5zZXQocmVmLCBuYW1lKTtcblxudmFyIHVwZGF0ZUZpZWxkQXJyYXlSb290RXJyb3IgPSAoZXJyb3JzLCBlcnJvciwgbmFtZSkgPT4ge1xuICAgIGNvbnN0IGZpZWxkQXJyYXlFcnJvcnMgPSBjb252ZXJ0VG9BcnJheVBheWxvYWQoZ2V0KGVycm9ycywgbmFtZSkpO1xuICAgIHNldChmaWVsZEFycmF5RXJyb3JzLCAncm9vdCcsIGVycm9yW25hbWVdKTtcbiAgICBzZXQoZXJyb3JzLCBuYW1lLCBmaWVsZEFycmF5RXJyb3JzKTtcbiAgICByZXR1cm4gZXJyb3JzO1xufTtcblxuZnVuY3Rpb24gZ2V0VmFsaWRhdGVFcnJvcihyZXN1bHQsIHJlZiwgdHlwZSA9ICd2YWxpZGF0ZScpIHtcbiAgICBpZiAoaXNTdHJpbmcocmVzdWx0KSB8fFxuICAgICAgICAoQXJyYXkuaXNBcnJheShyZXN1bHQpICYmIHJlc3VsdC5ldmVyeShpc1N0cmluZykpIHx8XG4gICAgICAgIChpc0Jvb2xlYW4ocmVzdWx0KSAmJiAhcmVzdWx0KSkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgdHlwZSxcbiAgICAgICAgICAgIG1lc3NhZ2U6IGlzU3RyaW5nKHJlc3VsdCkgPyByZXN1bHQgOiAnJyxcbiAgICAgICAgICAgIHJlZixcbiAgICAgICAgfTtcbiAgICB9XG59XG5cbnZhciBnZXRWYWx1ZUFuZE1lc3NhZ2UgPSAodmFsaWRhdGlvbkRhdGEpID0+IGlzT2JqZWN0KHZhbGlkYXRpb25EYXRhKSAmJiAhaXNSZWdleCh2YWxpZGF0aW9uRGF0YSlcbiAgICA/IHZhbGlkYXRpb25EYXRhXG4gICAgOiB7XG4gICAgICAgIHZhbHVlOiB2YWxpZGF0aW9uRGF0YSxcbiAgICAgICAgbWVzc2FnZTogJycsXG4gICAgfTtcblxudmFyIHZhbGlkYXRlRmllbGQgPSBhc3luYyAoZmllbGQsIGRpc2FibGVkRmllbGROYW1lcywgZm9ybVZhbHVlcywgdmFsaWRhdGVBbGxGaWVsZENyaXRlcmlhLCBzaG91bGRVc2VOYXRpdmVWYWxpZGF0aW9uLCBpc0ZpZWxkQXJyYXkpID0+IHtcbiAgICBjb25zdCB7IHJlZiwgcmVmcywgcmVxdWlyZWQsIG1heExlbmd0aCwgbWluTGVuZ3RoLCBtaW4sIG1heCwgcGF0dGVybiwgdmFsaWRhdGUsIG5hbWUsIHZhbHVlQXNOdW1iZXIsIG1vdW50LCB9ID0gZmllbGQuX2Y7XG4gICAgY29uc3QgaW5wdXRWYWx1ZSA9IGdldChmb3JtVmFsdWVzLCBuYW1lKTtcbiAgICBpZiAoIW1vdW50IHx8IGRpc2FibGVkRmllbGROYW1lcy5oYXMobmFtZSkpIHtcbiAgICAgICAgcmV0dXJuIHt9O1xuICAgIH1cbiAgICBjb25zdCBpbnB1dFJlZiA9IHJlZnMgPyByZWZzWzBdIDogcmVmO1xuICAgIGNvbnN0IHNldEN1c3RvbVZhbGlkaXR5ID0gKG1lc3NhZ2UpID0+IHtcbiAgICAgICAgaWYgKHNob3VsZFVzZU5hdGl2ZVZhbGlkYXRpb24gJiYgaW5wdXRSZWYucmVwb3J0VmFsaWRpdHkpIHtcbiAgICAgICAgICAgIGlucHV0UmVmLnNldEN1c3RvbVZhbGlkaXR5KGlzQm9vbGVhbihtZXNzYWdlKSA/ICcnIDogbWVzc2FnZSB8fCAnJyk7XG4gICAgICAgICAgICBpbnB1dFJlZi5yZXBvcnRWYWxpZGl0eSgpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICBjb25zdCBlcnJvciA9IHt9O1xuICAgIGNvbnN0IGlzUmFkaW8gPSBpc1JhZGlvSW5wdXQocmVmKTtcbiAgICBjb25zdCBpc0NoZWNrQm94ID0gaXNDaGVja0JveElucHV0KHJlZik7XG4gICAgY29uc3QgaXNSYWRpb09yQ2hlY2tib3ggPSBpc1JhZGlvIHx8IGlzQ2hlY2tCb3g7XG4gICAgY29uc3QgaXNFbXB0eSA9ICgodmFsdWVBc051bWJlciB8fCBpc0ZpbGVJbnB1dChyZWYpKSAmJlxuICAgICAgICBpc1VuZGVmaW5lZChyZWYudmFsdWUpICYmXG4gICAgICAgIGlzVW5kZWZpbmVkKGlucHV0VmFsdWUpKSB8fFxuICAgICAgICAoaXNIVE1MRWxlbWVudChyZWYpICYmIHJlZi52YWx1ZSA9PT0gJycpIHx8XG4gICAgICAgIGlucHV0VmFsdWUgPT09ICcnIHx8XG4gICAgICAgIChBcnJheS5pc0FycmF5KGlucHV0VmFsdWUpICYmICFpbnB1dFZhbHVlLmxlbmd0aCk7XG4gICAgY29uc3QgYXBwZW5kRXJyb3JzQ3VycnkgPSBhcHBlbmRFcnJvcnMuYmluZChudWxsLCBuYW1lLCB2YWxpZGF0ZUFsbEZpZWxkQ3JpdGVyaWEsIGVycm9yKTtcbiAgICBjb25zdCBnZXRNaW5NYXhNZXNzYWdlID0gKGV4Y2VlZE1heCwgbWF4TGVuZ3RoTWVzc2FnZSwgbWluTGVuZ3RoTWVzc2FnZSwgbWF4VHlwZSA9IElOUFVUX1ZBTElEQVRJT05fUlVMRVMubWF4TGVuZ3RoLCBtaW5UeXBlID0gSU5QVVRfVkFMSURBVElPTl9SVUxFUy5taW5MZW5ndGgpID0+IHtcbiAgICAgICAgY29uc3QgbWVzc2FnZSA9IGV4Y2VlZE1heCA/IG1heExlbmd0aE1lc3NhZ2UgOiBtaW5MZW5ndGhNZXNzYWdlO1xuICAgICAgICBlcnJvcltuYW1lXSA9IHtcbiAgICAgICAgICAgIHR5cGU6IGV4Y2VlZE1heCA/IG1heFR5cGUgOiBtaW5UeXBlLFxuICAgICAgICAgICAgbWVzc2FnZSxcbiAgICAgICAgICAgIHJlZixcbiAgICAgICAgICAgIC4uLmFwcGVuZEVycm9yc0N1cnJ5KGV4Y2VlZE1heCA/IG1heFR5cGUgOiBtaW5UeXBlLCBtZXNzYWdlKSxcbiAgICAgICAgfTtcbiAgICB9O1xuICAgIGlmIChpc0ZpZWxkQXJyYXlcbiAgICAgICAgPyAhQXJyYXkuaXNBcnJheShpbnB1dFZhbHVlKSB8fCAhaW5wdXRWYWx1ZS5sZW5ndGhcbiAgICAgICAgOiByZXF1aXJlZCAmJlxuICAgICAgICAgICAgKCghaXNSYWRpb09yQ2hlY2tib3ggJiYgKGlzRW1wdHkgfHwgaXNOdWxsT3JVbmRlZmluZWQoaW5wdXRWYWx1ZSkpKSB8fFxuICAgICAgICAgICAgICAgIChpc0Jvb2xlYW4oaW5wdXRWYWx1ZSkgJiYgIWlucHV0VmFsdWUpIHx8XG4gICAgICAgICAgICAgICAgKGlzQ2hlY2tCb3ggJiYgIWdldENoZWNrYm94VmFsdWUocmVmcykuaXNWYWxpZCkgfHxcbiAgICAgICAgICAgICAgICAoaXNSYWRpbyAmJiAhZ2V0UmFkaW9WYWx1ZShyZWZzKS5pc1ZhbGlkKSkpIHtcbiAgICAgICAgY29uc3QgeyB2YWx1ZSwgbWVzc2FnZSB9ID0gaXNTdHJpbmcocmVxdWlyZWQpXG4gICAgICAgICAgICA/IHsgdmFsdWU6ICEhcmVxdWlyZWQsIG1lc3NhZ2U6IHJlcXVpcmVkIH1cbiAgICAgICAgICAgIDogZ2V0VmFsdWVBbmRNZXNzYWdlKHJlcXVpcmVkKTtcbiAgICAgICAgaWYgKHZhbHVlKSB7XG4gICAgICAgICAgICBlcnJvcltuYW1lXSA9IHtcbiAgICAgICAgICAgICAgICB0eXBlOiBJTlBVVF9WQUxJREFUSU9OX1JVTEVTLnJlcXVpcmVkLFxuICAgICAgICAgICAgICAgIG1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgcmVmOiBpbnB1dFJlZixcbiAgICAgICAgICAgICAgICAuLi5hcHBlbmRFcnJvcnNDdXJyeShJTlBVVF9WQUxJREFUSU9OX1JVTEVTLnJlcXVpcmVkLCBtZXNzYWdlKSxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBpZiAoIXZhbGlkYXRlQWxsRmllbGRDcml0ZXJpYSkge1xuICAgICAgICAgICAgICAgIHNldEN1c3RvbVZhbGlkaXR5KG1lc3NhZ2UpO1xuICAgICAgICAgICAgICAgIHJldHVybiBlcnJvcjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICBpZiAoIWlzRW1wdHkgJiYgKCFpc051bGxPclVuZGVmaW5lZChtaW4pIHx8ICFpc051bGxPclVuZGVmaW5lZChtYXgpKSkge1xuICAgICAgICBsZXQgZXhjZWVkTWF4O1xuICAgICAgICBsZXQgZXhjZWVkTWluO1xuICAgICAgICBjb25zdCBtYXhPdXRwdXQgPSBnZXRWYWx1ZUFuZE1lc3NhZ2UobWF4KTtcbiAgICAgICAgY29uc3QgbWluT3V0cHV0ID0gZ2V0VmFsdWVBbmRNZXNzYWdlKG1pbik7XG4gICAgICAgIGlmICghaXNOdWxsT3JVbmRlZmluZWQoaW5wdXRWYWx1ZSkgJiYgIWlzTmFOKGlucHV0VmFsdWUpKSB7XG4gICAgICAgICAgICBjb25zdCB2YWx1ZU51bWJlciA9IHJlZi52YWx1ZUFzTnVtYmVyIHx8XG4gICAgICAgICAgICAgICAgKGlucHV0VmFsdWUgPyAraW5wdXRWYWx1ZSA6IGlucHV0VmFsdWUpO1xuICAgICAgICAgICAgaWYgKCFpc051bGxPclVuZGVmaW5lZChtYXhPdXRwdXQudmFsdWUpKSB7XG4gICAgICAgICAgICAgICAgZXhjZWVkTWF4ID0gdmFsdWVOdW1iZXIgPiBtYXhPdXRwdXQudmFsdWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIWlzTnVsbE9yVW5kZWZpbmVkKG1pbk91dHB1dC52YWx1ZSkpIHtcbiAgICAgICAgICAgICAgICBleGNlZWRNaW4gPSB2YWx1ZU51bWJlciA8IG1pbk91dHB1dC52YWx1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGNvbnN0IHZhbHVlRGF0ZSA9IHJlZi52YWx1ZUFzRGF0ZSB8fCBuZXcgRGF0ZShpbnB1dFZhbHVlKTtcbiAgICAgICAgICAgIGNvbnN0IGNvbnZlcnRUaW1lVG9EYXRlID0gKHRpbWUpID0+IG5ldyBEYXRlKG5ldyBEYXRlKCkudG9EYXRlU3RyaW5nKCkgKyAnICcgKyB0aW1lKTtcbiAgICAgICAgICAgIGNvbnN0IGlzVGltZSA9IHJlZi50eXBlID09ICd0aW1lJztcbiAgICAgICAgICAgIGNvbnN0IGlzV2VlayA9IHJlZi50eXBlID09ICd3ZWVrJztcbiAgICAgICAgICAgIGlmIChpc1N0cmluZyhtYXhPdXRwdXQudmFsdWUpICYmIGlucHV0VmFsdWUpIHtcbiAgICAgICAgICAgICAgICBleGNlZWRNYXggPSBpc1RpbWVcbiAgICAgICAgICAgICAgICAgICAgPyBjb252ZXJ0VGltZVRvRGF0ZShpbnB1dFZhbHVlKSA+IGNvbnZlcnRUaW1lVG9EYXRlKG1heE91dHB1dC52YWx1ZSlcbiAgICAgICAgICAgICAgICAgICAgOiBpc1dlZWtcbiAgICAgICAgICAgICAgICAgICAgICAgID8gaW5wdXRWYWx1ZSA+IG1heE91dHB1dC52YWx1ZVxuICAgICAgICAgICAgICAgICAgICAgICAgOiB2YWx1ZURhdGUgPiBuZXcgRGF0ZShtYXhPdXRwdXQudmFsdWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGlzU3RyaW5nKG1pbk91dHB1dC52YWx1ZSkgJiYgaW5wdXRWYWx1ZSkge1xuICAgICAgICAgICAgICAgIGV4Y2VlZE1pbiA9IGlzVGltZVxuICAgICAgICAgICAgICAgICAgICA/IGNvbnZlcnRUaW1lVG9EYXRlKGlucHV0VmFsdWUpIDwgY29udmVydFRpbWVUb0RhdGUobWluT3V0cHV0LnZhbHVlKVxuICAgICAgICAgICAgICAgICAgICA6IGlzV2Vla1xuICAgICAgICAgICAgICAgICAgICAgICAgPyBpbnB1dFZhbHVlIDwgbWluT3V0cHV0LnZhbHVlXG4gICAgICAgICAgICAgICAgICAgICAgICA6IHZhbHVlRGF0ZSA8IG5ldyBEYXRlKG1pbk91dHB1dC52YWx1ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGV4Y2VlZE1heCB8fCBleGNlZWRNaW4pIHtcbiAgICAgICAgICAgIGdldE1pbk1heE1lc3NhZ2UoISFleGNlZWRNYXgsIG1heE91dHB1dC5tZXNzYWdlLCBtaW5PdXRwdXQubWVzc2FnZSwgSU5QVVRfVkFMSURBVElPTl9SVUxFUy5tYXgsIElOUFVUX1ZBTElEQVRJT05fUlVMRVMubWluKTtcbiAgICAgICAgICAgIGlmICghdmFsaWRhdGVBbGxGaWVsZENyaXRlcmlhKSB7XG4gICAgICAgICAgICAgICAgc2V0Q3VzdG9tVmFsaWRpdHkoZXJyb3JbbmFtZV0ubWVzc2FnZSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGVycm9yO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIGlmICgobWF4TGVuZ3RoIHx8IG1pbkxlbmd0aCkgJiZcbiAgICAgICAgIWlzRW1wdHkgJiZcbiAgICAgICAgKGlzU3RyaW5nKGlucHV0VmFsdWUpIHx8IChpc0ZpZWxkQXJyYXkgJiYgQXJyYXkuaXNBcnJheShpbnB1dFZhbHVlKSkpKSB7XG4gICAgICAgIGNvbnN0IG1heExlbmd0aE91dHB1dCA9IGdldFZhbHVlQW5kTWVzc2FnZShtYXhMZW5ndGgpO1xuICAgICAgICBjb25zdCBtaW5MZW5ndGhPdXRwdXQgPSBnZXRWYWx1ZUFuZE1lc3NhZ2UobWluTGVuZ3RoKTtcbiAgICAgICAgY29uc3QgZXhjZWVkTWF4ID0gIWlzTnVsbE9yVW5kZWZpbmVkKG1heExlbmd0aE91dHB1dC52YWx1ZSkgJiZcbiAgICAgICAgICAgIGlucHV0VmFsdWUubGVuZ3RoID4gK21heExlbmd0aE91dHB1dC52YWx1ZTtcbiAgICAgICAgY29uc3QgZXhjZWVkTWluID0gIWlzTnVsbE9yVW5kZWZpbmVkKG1pbkxlbmd0aE91dHB1dC52YWx1ZSkgJiZcbiAgICAgICAgICAgIGlucHV0VmFsdWUubGVuZ3RoIDwgK21pbkxlbmd0aE91dHB1dC52YWx1ZTtcbiAgICAgICAgaWYgKGV4Y2VlZE1heCB8fCBleGNlZWRNaW4pIHtcbiAgICAgICAgICAgIGdldE1pbk1heE1lc3NhZ2UoZXhjZWVkTWF4LCBtYXhMZW5ndGhPdXRwdXQubWVzc2FnZSwgbWluTGVuZ3RoT3V0cHV0Lm1lc3NhZ2UpO1xuICAgICAgICAgICAgaWYgKCF2YWxpZGF0ZUFsbEZpZWxkQ3JpdGVyaWEpIHtcbiAgICAgICAgICAgICAgICBzZXRDdXN0b21WYWxpZGl0eShlcnJvcltuYW1lXS5tZXNzYWdlKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gZXJyb3I7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgaWYgKHBhdHRlcm4gJiYgIWlzRW1wdHkgJiYgaXNTdHJpbmcoaW5wdXRWYWx1ZSkpIHtcbiAgICAgICAgY29uc3QgeyB2YWx1ZTogcGF0dGVyblZhbHVlLCBtZXNzYWdlIH0gPSBnZXRWYWx1ZUFuZE1lc3NhZ2UocGF0dGVybik7XG4gICAgICAgIGlmIChpc1JlZ2V4KHBhdHRlcm5WYWx1ZSkgJiYgIWlucHV0VmFsdWUubWF0Y2gocGF0dGVyblZhbHVlKSkge1xuICAgICAgICAgICAgZXJyb3JbbmFtZV0gPSB7XG4gICAgICAgICAgICAgICAgdHlwZTogSU5QVVRfVkFMSURBVElPTl9SVUxFUy5wYXR0ZXJuLFxuICAgICAgICAgICAgICAgIG1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgcmVmLFxuICAgICAgICAgICAgICAgIC4uLmFwcGVuZEVycm9yc0N1cnJ5KElOUFVUX1ZBTElEQVRJT05fUlVMRVMucGF0dGVybiwgbWVzc2FnZSksXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgaWYgKCF2YWxpZGF0ZUFsbEZpZWxkQ3JpdGVyaWEpIHtcbiAgICAgICAgICAgICAgICBzZXRDdXN0b21WYWxpZGl0eShtZXNzYWdlKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gZXJyb3I7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgaWYgKHZhbGlkYXRlKSB7XG4gICAgICAgIGlmIChpc0Z1bmN0aW9uKHZhbGlkYXRlKSkge1xuICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdmFsaWRhdGUoaW5wdXRWYWx1ZSwgZm9ybVZhbHVlcyk7XG4gICAgICAgICAgICBjb25zdCB2YWxpZGF0ZUVycm9yID0gZ2V0VmFsaWRhdGVFcnJvcihyZXN1bHQsIGlucHV0UmVmKTtcbiAgICAgICAgICAgIGlmICh2YWxpZGF0ZUVycm9yKSB7XG4gICAgICAgICAgICAgICAgZXJyb3JbbmFtZV0gPSB7XG4gICAgICAgICAgICAgICAgICAgIC4uLnZhbGlkYXRlRXJyb3IsXG4gICAgICAgICAgICAgICAgICAgIC4uLmFwcGVuZEVycm9yc0N1cnJ5KElOUFVUX1ZBTElEQVRJT05fUlVMRVMudmFsaWRhdGUsIHZhbGlkYXRlRXJyb3IubWVzc2FnZSksXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICBpZiAoIXZhbGlkYXRlQWxsRmllbGRDcml0ZXJpYSkge1xuICAgICAgICAgICAgICAgICAgICBzZXRDdXN0b21WYWxpZGl0eSh2YWxpZGF0ZUVycm9yLm1lc3NhZ2UpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZXJyb3I7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGlzT2JqZWN0KHZhbGlkYXRlKSkge1xuICAgICAgICAgICAgbGV0IHZhbGlkYXRpb25SZXN1bHQgPSB7fTtcbiAgICAgICAgICAgIGZvciAoY29uc3Qga2V5IGluIHZhbGlkYXRlKSB7XG4gICAgICAgICAgICAgICAgaWYgKCFpc0VtcHR5T2JqZWN0KHZhbGlkYXRpb25SZXN1bHQpICYmICF2YWxpZGF0ZUFsbEZpZWxkQ3JpdGVyaWEpIHtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvbnN0IHZhbGlkYXRlRXJyb3IgPSBnZXRWYWxpZGF0ZUVycm9yKGF3YWl0IHZhbGlkYXRlW2tleV0oaW5wdXRWYWx1ZSwgZm9ybVZhbHVlcyksIGlucHV0UmVmLCBrZXkpO1xuICAgICAgICAgICAgICAgIGlmICh2YWxpZGF0ZUVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbGlkYXRpb25SZXN1bHQgPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAuLi52YWxpZGF0ZUVycm9yLFxuICAgICAgICAgICAgICAgICAgICAgICAgLi4uYXBwZW5kRXJyb3JzQ3Vycnkoa2V5LCB2YWxpZGF0ZUVycm9yLm1lc3NhZ2UpLFxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICBzZXRDdXN0b21WYWxpZGl0eSh2YWxpZGF0ZUVycm9yLm1lc3NhZ2UpO1xuICAgICAgICAgICAgICAgICAgICBpZiAodmFsaWRhdGVBbGxGaWVsZENyaXRlcmlhKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlcnJvcltuYW1lXSA9IHZhbGlkYXRpb25SZXN1bHQ7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIWlzRW1wdHlPYmplY3QodmFsaWRhdGlvblJlc3VsdCkpIHtcbiAgICAgICAgICAgICAgICBlcnJvcltuYW1lXSA9IHtcbiAgICAgICAgICAgICAgICAgICAgcmVmOiBpbnB1dFJlZixcbiAgICAgICAgICAgICAgICAgICAgLi4udmFsaWRhdGlvblJlc3VsdCxcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIGlmICghdmFsaWRhdGVBbGxGaWVsZENyaXRlcmlhKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBlcnJvcjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgc2V0Q3VzdG9tVmFsaWRpdHkodHJ1ZSk7XG4gICAgcmV0dXJuIGVycm9yO1xufTtcblxuY29uc3QgZGVmYXVsdE9wdGlvbnMgPSB7XG4gICAgbW9kZTogVkFMSURBVElPTl9NT0RFLm9uU3VibWl0LFxuICAgIHJlVmFsaWRhdGVNb2RlOiBWQUxJREFUSU9OX01PREUub25DaGFuZ2UsXG4gICAgc2hvdWxkRm9jdXNFcnJvcjogdHJ1ZSxcbn07XG5mdW5jdGlvbiBjcmVhdGVGb3JtQ29udHJvbChwcm9wcyA9IHt9KSB7XG4gICAgbGV0IF9vcHRpb25zID0ge1xuICAgICAgICAuLi5kZWZhdWx0T3B0aW9ucyxcbiAgICAgICAgLi4ucHJvcHMsXG4gICAgfTtcbiAgICBsZXQgX2Zvcm1TdGF0ZSA9IHtcbiAgICAgICAgc3VibWl0Q291bnQ6IDAsXG4gICAgICAgIGlzRGlydHk6IGZhbHNlLFxuICAgICAgICBpc1JlYWR5OiBmYWxzZSxcbiAgICAgICAgaXNMb2FkaW5nOiBpc0Z1bmN0aW9uKF9vcHRpb25zLmRlZmF1bHRWYWx1ZXMpLFxuICAgICAgICBpc1ZhbGlkYXRpbmc6IGZhbHNlLFxuICAgICAgICBpc1N1Ym1pdHRlZDogZmFsc2UsXG4gICAgICAgIGlzU3VibWl0dGluZzogZmFsc2UsXG4gICAgICAgIGlzU3VibWl0U3VjY2Vzc2Z1bDogZmFsc2UsXG4gICAgICAgIGlzVmFsaWQ6IGZhbHNlLFxuICAgICAgICB0b3VjaGVkRmllbGRzOiB7fSxcbiAgICAgICAgZGlydHlGaWVsZHM6IHt9LFxuICAgICAgICB2YWxpZGF0aW5nRmllbGRzOiB7fSxcbiAgICAgICAgZXJyb3JzOiBfb3B0aW9ucy5lcnJvcnMgfHwge30sXG4gICAgICAgIGRpc2FibGVkOiBfb3B0aW9ucy5kaXNhYmxlZCB8fCBmYWxzZSxcbiAgICB9O1xuICAgIGxldCBfZmllbGRzID0ge307XG4gICAgbGV0IF9kZWZhdWx0VmFsdWVzID0gaXNPYmplY3QoX29wdGlvbnMuZGVmYXVsdFZhbHVlcykgfHwgaXNPYmplY3QoX29wdGlvbnMudmFsdWVzKVxuICAgICAgICA/IGNsb25lT2JqZWN0KF9vcHRpb25zLmRlZmF1bHRWYWx1ZXMgfHwgX29wdGlvbnMudmFsdWVzKSB8fCB7fVxuICAgICAgICA6IHt9O1xuICAgIGxldCBfZm9ybVZhbHVlcyA9IF9vcHRpb25zLnNob3VsZFVucmVnaXN0ZXJcbiAgICAgICAgPyB7fVxuICAgICAgICA6IGNsb25lT2JqZWN0KF9kZWZhdWx0VmFsdWVzKTtcbiAgICBsZXQgX3N0YXRlID0ge1xuICAgICAgICBhY3Rpb246IGZhbHNlLFxuICAgICAgICBtb3VudDogZmFsc2UsXG4gICAgICAgIHdhdGNoOiBmYWxzZSxcbiAgICB9O1xuICAgIGxldCBfbmFtZXMgPSB7XG4gICAgICAgIG1vdW50OiBuZXcgU2V0KCksXG4gICAgICAgIGRpc2FibGVkOiBuZXcgU2V0KCksXG4gICAgICAgIHVuTW91bnQ6IG5ldyBTZXQoKSxcbiAgICAgICAgYXJyYXk6IG5ldyBTZXQoKSxcbiAgICAgICAgd2F0Y2g6IG5ldyBTZXQoKSxcbiAgICB9O1xuICAgIGxldCBkZWxheUVycm9yQ2FsbGJhY2s7XG4gICAgbGV0IHRpbWVyID0gMDtcbiAgICBjb25zdCBfcHJveHlGb3JtU3RhdGUgPSB7XG4gICAgICAgIGlzRGlydHk6IGZhbHNlLFxuICAgICAgICBkaXJ0eUZpZWxkczogZmFsc2UsXG4gICAgICAgIHZhbGlkYXRpbmdGaWVsZHM6IGZhbHNlLFxuICAgICAgICB0b3VjaGVkRmllbGRzOiBmYWxzZSxcbiAgICAgICAgaXNWYWxpZGF0aW5nOiBmYWxzZSxcbiAgICAgICAgaXNWYWxpZDogZmFsc2UsXG4gICAgICAgIGVycm9yczogZmFsc2UsXG4gICAgfTtcbiAgICBsZXQgX3Byb3h5U3Vic2NyaWJlRm9ybVN0YXRlID0ge1xuICAgICAgICAuLi5fcHJveHlGb3JtU3RhdGUsXG4gICAgfTtcbiAgICBjb25zdCBfc3ViamVjdHMgPSB7XG4gICAgICAgIGFycmF5OiBjcmVhdGVTdWJqZWN0KCksXG4gICAgICAgIHN0YXRlOiBjcmVhdGVTdWJqZWN0KCksXG4gICAgfTtcbiAgICBjb25zdCBzaG91bGREaXNwbGF5QWxsQXNzb2NpYXRlZEVycm9ycyA9IF9vcHRpb25zLmNyaXRlcmlhTW9kZSA9PT0gVkFMSURBVElPTl9NT0RFLmFsbDtcbiAgICBjb25zdCBkZWJvdW5jZSA9IChjYWxsYmFjaykgPT4gKHdhaXQpID0+IHtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVyKTtcbiAgICAgICAgdGltZXIgPSBzZXRUaW1lb3V0KGNhbGxiYWNrLCB3YWl0KTtcbiAgICB9O1xuICAgIGNvbnN0IF9zZXRWYWxpZCA9IGFzeW5jIChzaG91bGRVcGRhdGVWYWxpZCkgPT4ge1xuICAgICAgICBpZiAoIV9vcHRpb25zLmRpc2FibGVkICYmXG4gICAgICAgICAgICAoX3Byb3h5Rm9ybVN0YXRlLmlzVmFsaWQgfHxcbiAgICAgICAgICAgICAgICBfcHJveHlTdWJzY3JpYmVGb3JtU3RhdGUuaXNWYWxpZCB8fFxuICAgICAgICAgICAgICAgIHNob3VsZFVwZGF0ZVZhbGlkKSkge1xuICAgICAgICAgICAgY29uc3QgaXNWYWxpZCA9IF9vcHRpb25zLnJlc29sdmVyXG4gICAgICAgICAgICAgICAgPyBpc0VtcHR5T2JqZWN0KChhd2FpdCBfcnVuU2NoZW1hKCkpLmVycm9ycylcbiAgICAgICAgICAgICAgICA6IGF3YWl0IGV4ZWN1dGVCdWlsdEluVmFsaWRhdGlvbihfZmllbGRzLCB0cnVlKTtcbiAgICAgICAgICAgIGlmIChpc1ZhbGlkICE9PSBfZm9ybVN0YXRlLmlzVmFsaWQpIHtcbiAgICAgICAgICAgICAgICBfc3ViamVjdHMuc3RhdGUubmV4dCh7XG4gICAgICAgICAgICAgICAgICAgIGlzVmFsaWQsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuICAgIGNvbnN0IF91cGRhdGVJc1ZhbGlkYXRpbmcgPSAobmFtZXMsIGlzVmFsaWRhdGluZykgPT4ge1xuICAgICAgICBpZiAoIV9vcHRpb25zLmRpc2FibGVkICYmXG4gICAgICAgICAgICAoX3Byb3h5Rm9ybVN0YXRlLmlzVmFsaWRhdGluZyB8fFxuICAgICAgICAgICAgICAgIF9wcm94eUZvcm1TdGF0ZS52YWxpZGF0aW5nRmllbGRzIHx8XG4gICAgICAgICAgICAgICAgX3Byb3h5U3Vic2NyaWJlRm9ybVN0YXRlLmlzVmFsaWRhdGluZyB8fFxuICAgICAgICAgICAgICAgIF9wcm94eVN1YnNjcmliZUZvcm1TdGF0ZS52YWxpZGF0aW5nRmllbGRzKSkge1xuICAgICAgICAgICAgKG5hbWVzIHx8IEFycmF5LmZyb20oX25hbWVzLm1vdW50KSkuZm9yRWFjaCgobmFtZSkgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChuYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIGlzVmFsaWRhdGluZ1xuICAgICAgICAgICAgICAgICAgICAgICAgPyBzZXQoX2Zvcm1TdGF0ZS52YWxpZGF0aW5nRmllbGRzLCBuYW1lLCBpc1ZhbGlkYXRpbmcpXG4gICAgICAgICAgICAgICAgICAgICAgICA6IHVuc2V0KF9mb3JtU3RhdGUudmFsaWRhdGluZ0ZpZWxkcywgbmFtZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBfc3ViamVjdHMuc3RhdGUubmV4dCh7XG4gICAgICAgICAgICAgICAgdmFsaWRhdGluZ0ZpZWxkczogX2Zvcm1TdGF0ZS52YWxpZGF0aW5nRmllbGRzLFxuICAgICAgICAgICAgICAgIGlzVmFsaWRhdGluZzogIWlzRW1wdHlPYmplY3QoX2Zvcm1TdGF0ZS52YWxpZGF0aW5nRmllbGRzKSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfTtcbiAgICBjb25zdCBfc2V0RmllbGRBcnJheSA9IChuYW1lLCB2YWx1ZXMgPSBbXSwgbWV0aG9kLCBhcmdzLCBzaG91bGRTZXRWYWx1ZXMgPSB0cnVlLCBzaG91bGRVcGRhdGVGaWVsZHNBbmRTdGF0ZSA9IHRydWUpID0+IHtcbiAgICAgICAgaWYgKGFyZ3MgJiYgbWV0aG9kICYmICFfb3B0aW9ucy5kaXNhYmxlZCkge1xuICAgICAgICAgICAgX3N0YXRlLmFjdGlvbiA9IHRydWU7XG4gICAgICAgICAgICBpZiAoc2hvdWxkVXBkYXRlRmllbGRzQW5kU3RhdGUgJiYgQXJyYXkuaXNBcnJheShnZXQoX2ZpZWxkcywgbmFtZSkpKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZmllbGRWYWx1ZXMgPSBtZXRob2QoZ2V0KF9maWVsZHMsIG5hbWUpLCBhcmdzLmFyZ0EsIGFyZ3MuYXJnQik7XG4gICAgICAgICAgICAgICAgc2hvdWxkU2V0VmFsdWVzICYmIHNldChfZmllbGRzLCBuYW1lLCBmaWVsZFZhbHVlcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoc2hvdWxkVXBkYXRlRmllbGRzQW5kU3RhdGUgJiZcbiAgICAgICAgICAgICAgICBBcnJheS5pc0FycmF5KGdldChfZm9ybVN0YXRlLmVycm9ycywgbmFtZSkpKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZXJyb3JzID0gbWV0aG9kKGdldChfZm9ybVN0YXRlLmVycm9ycywgbmFtZSksIGFyZ3MuYXJnQSwgYXJncy5hcmdCKTtcbiAgICAgICAgICAgICAgICBzaG91bGRTZXRWYWx1ZXMgJiYgc2V0KF9mb3JtU3RhdGUuZXJyb3JzLCBuYW1lLCBlcnJvcnMpO1xuICAgICAgICAgICAgICAgIHVuc2V0RW1wdHlBcnJheShfZm9ybVN0YXRlLmVycm9ycywgbmFtZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoKF9wcm94eUZvcm1TdGF0ZS50b3VjaGVkRmllbGRzIHx8XG4gICAgICAgICAgICAgICAgX3Byb3h5U3Vic2NyaWJlRm9ybVN0YXRlLnRvdWNoZWRGaWVsZHMpICYmXG4gICAgICAgICAgICAgICAgc2hvdWxkVXBkYXRlRmllbGRzQW5kU3RhdGUgJiZcbiAgICAgICAgICAgICAgICBBcnJheS5pc0FycmF5KGdldChfZm9ybVN0YXRlLnRvdWNoZWRGaWVsZHMsIG5hbWUpKSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IHRvdWNoZWRGaWVsZHMgPSBtZXRob2QoZ2V0KF9mb3JtU3RhdGUudG91Y2hlZEZpZWxkcywgbmFtZSksIGFyZ3MuYXJnQSwgYXJncy5hcmdCKTtcbiAgICAgICAgICAgICAgICBzaG91bGRTZXRWYWx1ZXMgJiYgc2V0KF9mb3JtU3RhdGUudG91Y2hlZEZpZWxkcywgbmFtZSwgdG91Y2hlZEZpZWxkcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoX3Byb3h5Rm9ybVN0YXRlLmRpcnR5RmllbGRzIHx8IF9wcm94eVN1YnNjcmliZUZvcm1TdGF0ZS5kaXJ0eUZpZWxkcykge1xuICAgICAgICAgICAgICAgIF9mb3JtU3RhdGUuZGlydHlGaWVsZHMgPSBnZXREaXJ0eUZpZWxkcyhfZGVmYXVsdFZhbHVlcywgX2Zvcm1WYWx1ZXMpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgX3N1YmplY3RzLnN0YXRlLm5leHQoe1xuICAgICAgICAgICAgICAgIG5hbWUsXG4gICAgICAgICAgICAgICAgaXNEaXJ0eTogX2dldERpcnR5KG5hbWUsIHZhbHVlcyksXG4gICAgICAgICAgICAgICAgZGlydHlGaWVsZHM6IF9mb3JtU3RhdGUuZGlydHlGaWVsZHMsXG4gICAgICAgICAgICAgICAgZXJyb3JzOiBfZm9ybVN0YXRlLmVycm9ycyxcbiAgICAgICAgICAgICAgICBpc1ZhbGlkOiBfZm9ybVN0YXRlLmlzVmFsaWQsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHNldChfZm9ybVZhbHVlcywgbmFtZSwgdmFsdWVzKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgY29uc3QgdXBkYXRlRXJyb3JzID0gKG5hbWUsIGVycm9yKSA9PiB7XG4gICAgICAgIHNldChfZm9ybVN0YXRlLmVycm9ycywgbmFtZSwgZXJyb3IpO1xuICAgICAgICBfc3ViamVjdHMuc3RhdGUubmV4dCh7XG4gICAgICAgICAgICBlcnJvcnM6IF9mb3JtU3RhdGUuZXJyb3JzLFxuICAgICAgICB9KTtcbiAgICB9O1xuICAgIGNvbnN0IF9zZXRFcnJvcnMgPSAoZXJyb3JzKSA9PiB7XG4gICAgICAgIF9mb3JtU3RhdGUuZXJyb3JzID0gZXJyb3JzO1xuICAgICAgICBfc3ViamVjdHMuc3RhdGUubmV4dCh7XG4gICAgICAgICAgICBlcnJvcnM6IF9mb3JtU3RhdGUuZXJyb3JzLFxuICAgICAgICAgICAgaXNWYWxpZDogZmFsc2UsXG4gICAgICAgIH0pO1xuICAgIH07XG4gICAgY29uc3QgdXBkYXRlVmFsaWRBbmRWYWx1ZSA9IChuYW1lLCBzaG91bGRTa2lwU2V0VmFsdWVBcywgdmFsdWUsIHJlZikgPT4ge1xuICAgICAgICBjb25zdCBmaWVsZCA9IGdldChfZmllbGRzLCBuYW1lKTtcbiAgICAgICAgaWYgKGZpZWxkKSB7XG4gICAgICAgICAgICBjb25zdCBkZWZhdWx0VmFsdWUgPSBnZXQoX2Zvcm1WYWx1ZXMsIG5hbWUsIGlzVW5kZWZpbmVkKHZhbHVlKSA/IGdldChfZGVmYXVsdFZhbHVlcywgbmFtZSkgOiB2YWx1ZSk7XG4gICAgICAgICAgICBpc1VuZGVmaW5lZChkZWZhdWx0VmFsdWUpIHx8XG4gICAgICAgICAgICAgICAgKHJlZiAmJiByZWYuZGVmYXVsdENoZWNrZWQpIHx8XG4gICAgICAgICAgICAgICAgc2hvdWxkU2tpcFNldFZhbHVlQXNcbiAgICAgICAgICAgICAgICA/IHNldChfZm9ybVZhbHVlcywgbmFtZSwgc2hvdWxkU2tpcFNldFZhbHVlQXMgPyBkZWZhdWx0VmFsdWUgOiBnZXRGaWVsZFZhbHVlKGZpZWxkLl9mKSlcbiAgICAgICAgICAgICAgICA6IHNldEZpZWxkVmFsdWUobmFtZSwgZGVmYXVsdFZhbHVlKTtcbiAgICAgICAgICAgIF9zdGF0ZS5tb3VudCAmJiAhX3N0YXRlLmFjdGlvbiAmJiBfc2V0VmFsaWQoKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgY29uc3QgdXBkYXRlVG91Y2hBbmREaXJ0eSA9IChuYW1lLCBmaWVsZFZhbHVlLCBpc0JsdXJFdmVudCwgc2hvdWxkRGlydHksIHNob3VsZFJlbmRlcikgPT4ge1xuICAgICAgICBsZXQgc2hvdWxkVXBkYXRlRmllbGQgPSBmYWxzZTtcbiAgICAgICAgbGV0IGlzUHJldmlvdXNEaXJ0eSA9IGZhbHNlO1xuICAgICAgICBjb25zdCBvdXRwdXQgPSB7XG4gICAgICAgICAgICBuYW1lLFxuICAgICAgICB9O1xuICAgICAgICBpZiAoIV9vcHRpb25zLmRpc2FibGVkKSB7XG4gICAgICAgICAgICBpZiAoIWlzQmx1ckV2ZW50IHx8IHNob3VsZERpcnR5KSB7XG4gICAgICAgICAgICAgICAgaWYgKF9wcm94eUZvcm1TdGF0ZS5pc0RpcnR5IHx8IF9wcm94eVN1YnNjcmliZUZvcm1TdGF0ZS5pc0RpcnR5KSB7XG4gICAgICAgICAgICAgICAgICAgIGlzUHJldmlvdXNEaXJ0eSA9IF9mb3JtU3RhdGUuaXNEaXJ0eTtcbiAgICAgICAgICAgICAgICAgICAgX2Zvcm1TdGF0ZS5pc0RpcnR5ID0gb3V0cHV0LmlzRGlydHkgPSBfZ2V0RGlydHkoKTtcbiAgICAgICAgICAgICAgICAgICAgc2hvdWxkVXBkYXRlRmllbGQgPSBpc1ByZXZpb3VzRGlydHkgIT09IG91dHB1dC5pc0RpcnR5O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjb25zdCBpc0N1cnJlbnRGaWVsZFByaXN0aW5lID0gZGVlcEVxdWFsKGdldChfZGVmYXVsdFZhbHVlcywgbmFtZSksIGZpZWxkVmFsdWUpO1xuICAgICAgICAgICAgICAgIGlzUHJldmlvdXNEaXJ0eSA9ICEhZ2V0KF9mb3JtU3RhdGUuZGlydHlGaWVsZHMsIG5hbWUpO1xuICAgICAgICAgICAgICAgIGlzQ3VycmVudEZpZWxkUHJpc3RpbmVcbiAgICAgICAgICAgICAgICAgICAgPyB1bnNldChfZm9ybVN0YXRlLmRpcnR5RmllbGRzLCBuYW1lKVxuICAgICAgICAgICAgICAgICAgICA6IHNldChfZm9ybVN0YXRlLmRpcnR5RmllbGRzLCBuYW1lLCB0cnVlKTtcbiAgICAgICAgICAgICAgICBvdXRwdXQuZGlydHlGaWVsZHMgPSBfZm9ybVN0YXRlLmRpcnR5RmllbGRzO1xuICAgICAgICAgICAgICAgIHNob3VsZFVwZGF0ZUZpZWxkID1cbiAgICAgICAgICAgICAgICAgICAgc2hvdWxkVXBkYXRlRmllbGQgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICgoX3Byb3h5Rm9ybVN0YXRlLmRpcnR5RmllbGRzIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgX3Byb3h5U3Vic2NyaWJlRm9ybVN0YXRlLmRpcnR5RmllbGRzKSAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzUHJldmlvdXNEaXJ0eSAhPT0gIWlzQ3VycmVudEZpZWxkUHJpc3RpbmUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGlzQmx1ckV2ZW50KSB7XG4gICAgICAgICAgICAgICAgY29uc3QgaXNQcmV2aW91c0ZpZWxkVG91Y2hlZCA9IGdldChfZm9ybVN0YXRlLnRvdWNoZWRGaWVsZHMsIG5hbWUpO1xuICAgICAgICAgICAgICAgIGlmICghaXNQcmV2aW91c0ZpZWxkVG91Y2hlZCkge1xuICAgICAgICAgICAgICAgICAgICBzZXQoX2Zvcm1TdGF0ZS50b3VjaGVkRmllbGRzLCBuYW1lLCBpc0JsdXJFdmVudCk7XG4gICAgICAgICAgICAgICAgICAgIG91dHB1dC50b3VjaGVkRmllbGRzID0gX2Zvcm1TdGF0ZS50b3VjaGVkRmllbGRzO1xuICAgICAgICAgICAgICAgICAgICBzaG91bGRVcGRhdGVGaWVsZCA9XG4gICAgICAgICAgICAgICAgICAgICAgICBzaG91bGRVcGRhdGVGaWVsZCB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICgoX3Byb3h5Rm9ybVN0YXRlLnRvdWNoZWRGaWVsZHMgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgX3Byb3h5U3Vic2NyaWJlRm9ybVN0YXRlLnRvdWNoZWRGaWVsZHMpICYmXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzUHJldmlvdXNGaWVsZFRvdWNoZWQgIT09IGlzQmx1ckV2ZW50KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBzaG91bGRVcGRhdGVGaWVsZCAmJiBzaG91bGRSZW5kZXIgJiYgX3N1YmplY3RzLnN0YXRlLm5leHQob3V0cHV0KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc2hvdWxkVXBkYXRlRmllbGQgPyBvdXRwdXQgOiB7fTtcbiAgICB9O1xuICAgIGNvbnN0IHNob3VsZFJlbmRlckJ5RXJyb3IgPSAobmFtZSwgaXNWYWxpZCwgZXJyb3IsIGZpZWxkU3RhdGUpID0+IHtcbiAgICAgICAgY29uc3QgcHJldmlvdXNGaWVsZEVycm9yID0gZ2V0KF9mb3JtU3RhdGUuZXJyb3JzLCBuYW1lKTtcbiAgICAgICAgY29uc3Qgc2hvdWxkVXBkYXRlVmFsaWQgPSAoX3Byb3h5Rm9ybVN0YXRlLmlzVmFsaWQgfHwgX3Byb3h5U3Vic2NyaWJlRm9ybVN0YXRlLmlzVmFsaWQpICYmXG4gICAgICAgICAgICBpc0Jvb2xlYW4oaXNWYWxpZCkgJiZcbiAgICAgICAgICAgIF9mb3JtU3RhdGUuaXNWYWxpZCAhPT0gaXNWYWxpZDtcbiAgICAgICAgaWYgKF9vcHRpb25zLmRlbGF5RXJyb3IgJiYgZXJyb3IpIHtcbiAgICAgICAgICAgIGRlbGF5RXJyb3JDYWxsYmFjayA9IGRlYm91bmNlKCgpID0+IHVwZGF0ZUVycm9ycyhuYW1lLCBlcnJvcikpO1xuICAgICAgICAgICAgZGVsYXlFcnJvckNhbGxiYWNrKF9vcHRpb25zLmRlbGF5RXJyb3IpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVyKTtcbiAgICAgICAgICAgIGRlbGF5RXJyb3JDYWxsYmFjayA9IG51bGw7XG4gICAgICAgICAgICBlcnJvclxuICAgICAgICAgICAgICAgID8gc2V0KF9mb3JtU3RhdGUuZXJyb3JzLCBuYW1lLCBlcnJvcilcbiAgICAgICAgICAgICAgICA6IHVuc2V0KF9mb3JtU3RhdGUuZXJyb3JzLCBuYW1lKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoKGVycm9yID8gIWRlZXBFcXVhbChwcmV2aW91c0ZpZWxkRXJyb3IsIGVycm9yKSA6IHByZXZpb3VzRmllbGRFcnJvcikgfHxcbiAgICAgICAgICAgICFpc0VtcHR5T2JqZWN0KGZpZWxkU3RhdGUpIHx8XG4gICAgICAgICAgICBzaG91bGRVcGRhdGVWYWxpZCkge1xuICAgICAgICAgICAgY29uc3QgdXBkYXRlZEZvcm1TdGF0ZSA9IHtcbiAgICAgICAgICAgICAgICAuLi5maWVsZFN0YXRlLFxuICAgICAgICAgICAgICAgIC4uLihzaG91bGRVcGRhdGVWYWxpZCAmJiBpc0Jvb2xlYW4oaXNWYWxpZCkgPyB7IGlzVmFsaWQgfSA6IHt9KSxcbiAgICAgICAgICAgICAgICBlcnJvcnM6IF9mb3JtU3RhdGUuZXJyb3JzLFxuICAgICAgICAgICAgICAgIG5hbWUsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgX2Zvcm1TdGF0ZSA9IHtcbiAgICAgICAgICAgICAgICAuLi5fZm9ybVN0YXRlLFxuICAgICAgICAgICAgICAgIC4uLnVwZGF0ZWRGb3JtU3RhdGUsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgX3N1YmplY3RzLnN0YXRlLm5leHQodXBkYXRlZEZvcm1TdGF0ZSk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIGNvbnN0IF9ydW5TY2hlbWEgPSBhc3luYyAobmFtZSkgPT4ge1xuICAgICAgICBfdXBkYXRlSXNWYWxpZGF0aW5nKG5hbWUsIHRydWUpO1xuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBfb3B0aW9ucy5yZXNvbHZlcihfZm9ybVZhbHVlcywgX29wdGlvbnMuY29udGV4dCwgZ2V0UmVzb2x2ZXJPcHRpb25zKG5hbWUgfHwgX25hbWVzLm1vdW50LCBfZmllbGRzLCBfb3B0aW9ucy5jcml0ZXJpYU1vZGUsIF9vcHRpb25zLnNob3VsZFVzZU5hdGl2ZVZhbGlkYXRpb24pKTtcbiAgICAgICAgX3VwZGF0ZUlzVmFsaWRhdGluZyhuYW1lKTtcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9O1xuICAgIGNvbnN0IGV4ZWN1dGVTY2hlbWFBbmRVcGRhdGVTdGF0ZSA9IGFzeW5jIChuYW1lcykgPT4ge1xuICAgICAgICBjb25zdCB7IGVycm9ycyB9ID0gYXdhaXQgX3J1blNjaGVtYShuYW1lcyk7XG4gICAgICAgIGlmIChuYW1lcykge1xuICAgICAgICAgICAgZm9yIChjb25zdCBuYW1lIG9mIG5hbWVzKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZXJyb3IgPSBnZXQoZXJyb3JzLCBuYW1lKTtcbiAgICAgICAgICAgICAgICBlcnJvclxuICAgICAgICAgICAgICAgICAgICA/IHNldChfZm9ybVN0YXRlLmVycm9ycywgbmFtZSwgZXJyb3IpXG4gICAgICAgICAgICAgICAgICAgIDogdW5zZXQoX2Zvcm1TdGF0ZS5lcnJvcnMsIG5hbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgX2Zvcm1TdGF0ZS5lcnJvcnMgPSBlcnJvcnM7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGVycm9ycztcbiAgICB9O1xuICAgIGNvbnN0IGV4ZWN1dGVCdWlsdEluVmFsaWRhdGlvbiA9IGFzeW5jIChmaWVsZHMsIHNob3VsZE9ubHlDaGVja1ZhbGlkLCBjb250ZXh0ID0ge1xuICAgICAgICB2YWxpZDogdHJ1ZSxcbiAgICB9KSA9PiB7XG4gICAgICAgIGZvciAoY29uc3QgbmFtZSBpbiBmaWVsZHMpIHtcbiAgICAgICAgICAgIGNvbnN0IGZpZWxkID0gZmllbGRzW25hbWVdO1xuICAgICAgICAgICAgaWYgKGZpZWxkKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgeyBfZiwgLi4uZmllbGRWYWx1ZSB9ID0gZmllbGQ7XG4gICAgICAgICAgICAgICAgaWYgKF9mKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGlzRmllbGRBcnJheVJvb3QgPSBfbmFtZXMuYXJyYXkuaGFzKF9mLm5hbWUpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBpc1Byb21pc2VGdW5jdGlvbiA9IGZpZWxkLl9mICYmIGhhc1Byb21pc2VWYWxpZGF0aW9uKGZpZWxkLl9mKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGlzUHJvbWlzZUZ1bmN0aW9uICYmIF9wcm94eUZvcm1TdGF0ZS52YWxpZGF0aW5nRmllbGRzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBfdXBkYXRlSXNWYWxpZGF0aW5nKFtfZi5uYW1lXSwgdHJ1ZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZmllbGRFcnJvciA9IGF3YWl0IHZhbGlkYXRlRmllbGQoZmllbGQsIF9uYW1lcy5kaXNhYmxlZCwgX2Zvcm1WYWx1ZXMsIHNob3VsZERpc3BsYXlBbGxBc3NvY2lhdGVkRXJyb3JzLCBfb3B0aW9ucy5zaG91bGRVc2VOYXRpdmVWYWxpZGF0aW9uICYmICFzaG91bGRPbmx5Q2hlY2tWYWxpZCwgaXNGaWVsZEFycmF5Um9vdCk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChpc1Byb21pc2VGdW5jdGlvbiAmJiBfcHJveHlGb3JtU3RhdGUudmFsaWRhdGluZ0ZpZWxkcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgX3VwZGF0ZUlzVmFsaWRhdGluZyhbX2YubmFtZV0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGlmIChmaWVsZEVycm9yW19mLm5hbWVdKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb250ZXh0LnZhbGlkID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoc2hvdWxkT25seUNoZWNrVmFsaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAhc2hvdWxkT25seUNoZWNrVmFsaWQgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIChnZXQoZmllbGRFcnJvciwgX2YubmFtZSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA/IGlzRmllbGRBcnJheVJvb3RcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPyB1cGRhdGVGaWVsZEFycmF5Um9vdEVycm9yKF9mb3JtU3RhdGUuZXJyb3JzLCBmaWVsZEVycm9yLCBfZi5uYW1lKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IHNldChfZm9ybVN0YXRlLmVycm9ycywgX2YubmFtZSwgZmllbGRFcnJvcltfZi5uYW1lXSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IHVuc2V0KF9mb3JtU3RhdGUuZXJyb3JzLCBfZi5uYW1lKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICFpc0VtcHR5T2JqZWN0KGZpZWxkVmFsdWUpICYmXG4gICAgICAgICAgICAgICAgICAgIChhd2FpdCBleGVjdXRlQnVpbHRJblZhbGlkYXRpb24oZmllbGRWYWx1ZSwgc2hvdWxkT25seUNoZWNrVmFsaWQsIGNvbnRleHQpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gY29udGV4dC52YWxpZDtcbiAgICB9O1xuICAgIGNvbnN0IF9yZW1vdmVVbm1vdW50ZWQgPSAoKSA9PiB7XG4gICAgICAgIGZvciAoY29uc3QgbmFtZSBvZiBfbmFtZXMudW5Nb3VudCkge1xuICAgICAgICAgICAgY29uc3QgZmllbGQgPSBnZXQoX2ZpZWxkcywgbmFtZSk7XG4gICAgICAgICAgICBmaWVsZCAmJlxuICAgICAgICAgICAgICAgIChmaWVsZC5fZi5yZWZzXG4gICAgICAgICAgICAgICAgICAgID8gZmllbGQuX2YucmVmcy5ldmVyeSgocmVmKSA9PiAhbGl2ZShyZWYpKVxuICAgICAgICAgICAgICAgICAgICA6ICFsaXZlKGZpZWxkLl9mLnJlZikpICYmXG4gICAgICAgICAgICAgICAgdW5yZWdpc3RlcihuYW1lKTtcbiAgICAgICAgfVxuICAgICAgICBfbmFtZXMudW5Nb3VudCA9IG5ldyBTZXQoKTtcbiAgICB9O1xuICAgIGNvbnN0IF9nZXREaXJ0eSA9IChuYW1lLCBkYXRhKSA9PiAhX29wdGlvbnMuZGlzYWJsZWQgJiZcbiAgICAgICAgKG5hbWUgJiYgZGF0YSAmJiBzZXQoX2Zvcm1WYWx1ZXMsIG5hbWUsIGRhdGEpLFxuICAgICAgICAgICAgIWRlZXBFcXVhbChnZXRWYWx1ZXMoKSwgX2RlZmF1bHRWYWx1ZXMpKTtcbiAgICBjb25zdCBfZ2V0V2F0Y2ggPSAobmFtZXMsIGRlZmF1bHRWYWx1ZSwgaXNHbG9iYWwpID0+IGdlbmVyYXRlV2F0Y2hPdXRwdXQobmFtZXMsIF9uYW1lcywge1xuICAgICAgICAuLi4oX3N0YXRlLm1vdW50XG4gICAgICAgICAgICA/IF9mb3JtVmFsdWVzXG4gICAgICAgICAgICA6IGlzVW5kZWZpbmVkKGRlZmF1bHRWYWx1ZSlcbiAgICAgICAgICAgICAgICA/IF9kZWZhdWx0VmFsdWVzXG4gICAgICAgICAgICAgICAgOiBpc1N0cmluZyhuYW1lcylcbiAgICAgICAgICAgICAgICAgICAgPyB7IFtuYW1lc106IGRlZmF1bHRWYWx1ZSB9XG4gICAgICAgICAgICAgICAgICAgIDogZGVmYXVsdFZhbHVlKSxcbiAgICB9LCBpc0dsb2JhbCwgZGVmYXVsdFZhbHVlKTtcbiAgICBjb25zdCBfZ2V0RmllbGRBcnJheSA9IChuYW1lKSA9PiBjb21wYWN0KGdldChfc3RhdGUubW91bnQgPyBfZm9ybVZhbHVlcyA6IF9kZWZhdWx0VmFsdWVzLCBuYW1lLCBfb3B0aW9ucy5zaG91bGRVbnJlZ2lzdGVyID8gZ2V0KF9kZWZhdWx0VmFsdWVzLCBuYW1lLCBbXSkgOiBbXSkpO1xuICAgIGNvbnN0IHNldEZpZWxkVmFsdWUgPSAobmFtZSwgdmFsdWUsIG9wdGlvbnMgPSB7fSkgPT4ge1xuICAgICAgICBjb25zdCBmaWVsZCA9IGdldChfZmllbGRzLCBuYW1lKTtcbiAgICAgICAgbGV0IGZpZWxkVmFsdWUgPSB2YWx1ZTtcbiAgICAgICAgaWYgKGZpZWxkKSB7XG4gICAgICAgICAgICBjb25zdCBmaWVsZFJlZmVyZW5jZSA9IGZpZWxkLl9mO1xuICAgICAgICAgICAgaWYgKGZpZWxkUmVmZXJlbmNlKSB7XG4gICAgICAgICAgICAgICAgIWZpZWxkUmVmZXJlbmNlLmRpc2FibGVkICYmXG4gICAgICAgICAgICAgICAgICAgIHNldChfZm9ybVZhbHVlcywgbmFtZSwgZ2V0RmllbGRWYWx1ZUFzKHZhbHVlLCBmaWVsZFJlZmVyZW5jZSkpO1xuICAgICAgICAgICAgICAgIGZpZWxkVmFsdWUgPVxuICAgICAgICAgICAgICAgICAgICBpc0hUTUxFbGVtZW50KGZpZWxkUmVmZXJlbmNlLnJlZikgJiYgaXNOdWxsT3JVbmRlZmluZWQodmFsdWUpXG4gICAgICAgICAgICAgICAgICAgICAgICA/ICcnXG4gICAgICAgICAgICAgICAgICAgICAgICA6IHZhbHVlO1xuICAgICAgICAgICAgICAgIGlmIChpc011bHRpcGxlU2VsZWN0KGZpZWxkUmVmZXJlbmNlLnJlZikpIHtcbiAgICAgICAgICAgICAgICAgICAgWy4uLmZpZWxkUmVmZXJlbmNlLnJlZi5vcHRpb25zXS5mb3JFYWNoKChvcHRpb25SZWYpID0+IChvcHRpb25SZWYuc2VsZWN0ZWQgPSBmaWVsZFZhbHVlLmluY2x1ZGVzKG9wdGlvblJlZi52YWx1ZSkpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAoZmllbGRSZWZlcmVuY2UucmVmcykge1xuICAgICAgICAgICAgICAgICAgICBpZiAoaXNDaGVja0JveElucHV0KGZpZWxkUmVmZXJlbmNlLnJlZikpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZpZWxkUmVmZXJlbmNlLnJlZnMuZm9yRWFjaCgoY2hlY2tib3hSZWYpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWNoZWNrYm94UmVmLmRlZmF1bHRDaGVja2VkIHx8ICFjaGVja2JveFJlZi5kaXNhYmxlZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShmaWVsZFZhbHVlKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2hlY2tib3hSZWYuY2hlY2tlZCA9ICEhZmllbGRWYWx1ZS5maW5kKChkYXRhKSA9PiBkYXRhID09PSBjaGVja2JveFJlZi52YWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaGVja2JveFJlZi5jaGVja2VkID1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWVsZFZhbHVlID09PSBjaGVja2JveFJlZi52YWx1ZSB8fCAhIWZpZWxkVmFsdWU7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZpZWxkUmVmZXJlbmNlLnJlZnMuZm9yRWFjaCgocmFkaW9SZWYpID0+IChyYWRpb1JlZi5jaGVja2VkID0gcmFkaW9SZWYudmFsdWUgPT09IGZpZWxkVmFsdWUpKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIGlmIChpc0ZpbGVJbnB1dChmaWVsZFJlZmVyZW5jZS5yZWYpKSB7XG4gICAgICAgICAgICAgICAgICAgIGZpZWxkUmVmZXJlbmNlLnJlZi52YWx1ZSA9ICcnO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgZmllbGRSZWZlcmVuY2UucmVmLnZhbHVlID0gZmllbGRWYWx1ZTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFmaWVsZFJlZmVyZW5jZS5yZWYudHlwZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgX3N1YmplY3RzLnN0YXRlLm5leHQoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzOiBjbG9uZU9iamVjdChfZm9ybVZhbHVlcyksXG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICAob3B0aW9ucy5zaG91bGREaXJ0eSB8fCBvcHRpb25zLnNob3VsZFRvdWNoKSAmJlxuICAgICAgICAgICAgdXBkYXRlVG91Y2hBbmREaXJ0eShuYW1lLCBmaWVsZFZhbHVlLCBvcHRpb25zLnNob3VsZFRvdWNoLCBvcHRpb25zLnNob3VsZERpcnR5LCB0cnVlKTtcbiAgICAgICAgb3B0aW9ucy5zaG91bGRWYWxpZGF0ZSAmJiB0cmlnZ2VyKG5hbWUpO1xuICAgIH07XG4gICAgY29uc3Qgc2V0VmFsdWVzID0gKG5hbWUsIHZhbHVlLCBvcHRpb25zKSA9PiB7XG4gICAgICAgIGZvciAoY29uc3QgZmllbGRLZXkgaW4gdmFsdWUpIHtcbiAgICAgICAgICAgIGlmICghdmFsdWUuaGFzT3duUHJvcGVydHkoZmllbGRLZXkpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgZmllbGRWYWx1ZSA9IHZhbHVlW2ZpZWxkS2V5XTtcbiAgICAgICAgICAgIGNvbnN0IGZpZWxkTmFtZSA9IG5hbWUgKyAnLicgKyBmaWVsZEtleTtcbiAgICAgICAgICAgIGNvbnN0IGZpZWxkID0gZ2V0KF9maWVsZHMsIGZpZWxkTmFtZSk7XG4gICAgICAgICAgICAoX25hbWVzLmFycmF5LmhhcyhuYW1lKSB8fFxuICAgICAgICAgICAgICAgIGlzT2JqZWN0KGZpZWxkVmFsdWUpIHx8XG4gICAgICAgICAgICAgICAgKGZpZWxkICYmICFmaWVsZC5fZikpICYmXG4gICAgICAgICAgICAgICAgIWlzRGF0ZU9iamVjdChmaWVsZFZhbHVlKVxuICAgICAgICAgICAgICAgID8gc2V0VmFsdWVzKGZpZWxkTmFtZSwgZmllbGRWYWx1ZSwgb3B0aW9ucylcbiAgICAgICAgICAgICAgICA6IHNldEZpZWxkVmFsdWUoZmllbGROYW1lLCBmaWVsZFZhbHVlLCBvcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgY29uc3Qgc2V0VmFsdWUgPSAobmFtZSwgdmFsdWUsIG9wdGlvbnMgPSB7fSkgPT4ge1xuICAgICAgICBjb25zdCBmaWVsZCA9IGdldChfZmllbGRzLCBuYW1lKTtcbiAgICAgICAgY29uc3QgaXNGaWVsZEFycmF5ID0gX25hbWVzLmFycmF5LmhhcyhuYW1lKTtcbiAgICAgICAgY29uc3QgY2xvbmVWYWx1ZSA9IGNsb25lT2JqZWN0KHZhbHVlKTtcbiAgICAgICAgc2V0KF9mb3JtVmFsdWVzLCBuYW1lLCBjbG9uZVZhbHVlKTtcbiAgICAgICAgaWYgKGlzRmllbGRBcnJheSkge1xuICAgICAgICAgICAgX3N1YmplY3RzLmFycmF5Lm5leHQoe1xuICAgICAgICAgICAgICAgIG5hbWUsXG4gICAgICAgICAgICAgICAgdmFsdWVzOiBjbG9uZU9iamVjdChfZm9ybVZhbHVlcyksXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGlmICgoX3Byb3h5Rm9ybVN0YXRlLmlzRGlydHkgfHxcbiAgICAgICAgICAgICAgICBfcHJveHlGb3JtU3RhdGUuZGlydHlGaWVsZHMgfHxcbiAgICAgICAgICAgICAgICBfcHJveHlTdWJzY3JpYmVGb3JtU3RhdGUuaXNEaXJ0eSB8fFxuICAgICAgICAgICAgICAgIF9wcm94eVN1YnNjcmliZUZvcm1TdGF0ZS5kaXJ0eUZpZWxkcykgJiZcbiAgICAgICAgICAgICAgICBvcHRpb25zLnNob3VsZERpcnR5KSB7XG4gICAgICAgICAgICAgICAgX3N1YmplY3RzLnN0YXRlLm5leHQoe1xuICAgICAgICAgICAgICAgICAgICBuYW1lLFxuICAgICAgICAgICAgICAgICAgICBkaXJ0eUZpZWxkczogZ2V0RGlydHlGaWVsZHMoX2RlZmF1bHRWYWx1ZXMsIF9mb3JtVmFsdWVzKSxcbiAgICAgICAgICAgICAgICAgICAgaXNEaXJ0eTogX2dldERpcnR5KG5hbWUsIGNsb25lVmFsdWUpLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgZmllbGQgJiYgIWZpZWxkLl9mICYmICFpc051bGxPclVuZGVmaW5lZChjbG9uZVZhbHVlKVxuICAgICAgICAgICAgICAgID8gc2V0VmFsdWVzKG5hbWUsIGNsb25lVmFsdWUsIG9wdGlvbnMpXG4gICAgICAgICAgICAgICAgOiBzZXRGaWVsZFZhbHVlKG5hbWUsIGNsb25lVmFsdWUsIG9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgICAgIGlzV2F0Y2hlZChuYW1lLCBfbmFtZXMpICYmIF9zdWJqZWN0cy5zdGF0ZS5uZXh0KHsgLi4uX2Zvcm1TdGF0ZSwgbmFtZSB9KTtcbiAgICAgICAgX3N1YmplY3RzLnN0YXRlLm5leHQoe1xuICAgICAgICAgICAgbmFtZTogX3N0YXRlLm1vdW50ID8gbmFtZSA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIHZhbHVlczogY2xvbmVPYmplY3QoX2Zvcm1WYWx1ZXMpLFxuICAgICAgICB9KTtcbiAgICB9O1xuICAgIGNvbnN0IG9uQ2hhbmdlID0gYXN5bmMgKGV2ZW50KSA9PiB7XG4gICAgICAgIF9zdGF0ZS5tb3VudCA9IHRydWU7XG4gICAgICAgIGNvbnN0IHRhcmdldCA9IGV2ZW50LnRhcmdldDtcbiAgICAgICAgbGV0IG5hbWUgPSB0YXJnZXQubmFtZTtcbiAgICAgICAgbGV0IGlzRmllbGRWYWx1ZVVwZGF0ZWQgPSB0cnVlO1xuICAgICAgICBjb25zdCBmaWVsZCA9IGdldChfZmllbGRzLCBuYW1lKTtcbiAgICAgICAgY29uc3QgX3VwZGF0ZUlzRmllbGRWYWx1ZVVwZGF0ZWQgPSAoZmllbGRWYWx1ZSkgPT4ge1xuICAgICAgICAgICAgaXNGaWVsZFZhbHVlVXBkYXRlZCA9XG4gICAgICAgICAgICAgICAgTnVtYmVyLmlzTmFOKGZpZWxkVmFsdWUpIHx8XG4gICAgICAgICAgICAgICAgICAgIChpc0RhdGVPYmplY3QoZmllbGRWYWx1ZSkgJiYgaXNOYU4oZmllbGRWYWx1ZS5nZXRUaW1lKCkpKSB8fFxuICAgICAgICAgICAgICAgICAgICBkZWVwRXF1YWwoZmllbGRWYWx1ZSwgZ2V0KF9mb3JtVmFsdWVzLCBuYW1lLCBmaWVsZFZhbHVlKSk7XG4gICAgICAgIH07XG4gICAgICAgIGNvbnN0IHZhbGlkYXRpb25Nb2RlQmVmb3JlU3VibWl0ID0gZ2V0VmFsaWRhdGlvbk1vZGVzKF9vcHRpb25zLm1vZGUpO1xuICAgICAgICBjb25zdCB2YWxpZGF0aW9uTW9kZUFmdGVyU3VibWl0ID0gZ2V0VmFsaWRhdGlvbk1vZGVzKF9vcHRpb25zLnJlVmFsaWRhdGVNb2RlKTtcbiAgICAgICAgaWYgKGZpZWxkKSB7XG4gICAgICAgICAgICBsZXQgZXJyb3I7XG4gICAgICAgICAgICBsZXQgaXNWYWxpZDtcbiAgICAgICAgICAgIGNvbnN0IGZpZWxkVmFsdWUgPSB0YXJnZXQudHlwZVxuICAgICAgICAgICAgICAgID8gZ2V0RmllbGRWYWx1ZShmaWVsZC5fZilcbiAgICAgICAgICAgICAgICA6IGdldEV2ZW50VmFsdWUoZXZlbnQpO1xuICAgICAgICAgICAgY29uc3QgaXNCbHVyRXZlbnQgPSBldmVudC50eXBlID09PSBFVkVOVFMuQkxVUiB8fCBldmVudC50eXBlID09PSBFVkVOVFMuRk9DVVNfT1VUO1xuICAgICAgICAgICAgY29uc3Qgc2hvdWxkU2tpcFZhbGlkYXRpb24gPSAoIWhhc1ZhbGlkYXRpb24oZmllbGQuX2YpICYmXG4gICAgICAgICAgICAgICAgIV9vcHRpb25zLnJlc29sdmVyICYmXG4gICAgICAgICAgICAgICAgIWdldChfZm9ybVN0YXRlLmVycm9ycywgbmFtZSkgJiZcbiAgICAgICAgICAgICAgICAhZmllbGQuX2YuZGVwcykgfHxcbiAgICAgICAgICAgICAgICBza2lwVmFsaWRhdGlvbihpc0JsdXJFdmVudCwgZ2V0KF9mb3JtU3RhdGUudG91Y2hlZEZpZWxkcywgbmFtZSksIF9mb3JtU3RhdGUuaXNTdWJtaXR0ZWQsIHZhbGlkYXRpb25Nb2RlQWZ0ZXJTdWJtaXQsIHZhbGlkYXRpb25Nb2RlQmVmb3JlU3VibWl0KTtcbiAgICAgICAgICAgIGNvbnN0IHdhdGNoZWQgPSBpc1dhdGNoZWQobmFtZSwgX25hbWVzLCBpc0JsdXJFdmVudCk7XG4gICAgICAgICAgICBzZXQoX2Zvcm1WYWx1ZXMsIG5hbWUsIGZpZWxkVmFsdWUpO1xuICAgICAgICAgICAgaWYgKGlzQmx1ckV2ZW50KSB7XG4gICAgICAgICAgICAgICAgaWYgKCF0YXJnZXQgfHwgIXRhcmdldC5yZWFkT25seSkge1xuICAgICAgICAgICAgICAgICAgICBmaWVsZC5fZi5vbkJsdXIgJiYgZmllbGQuX2Yub25CbHVyKGV2ZW50KTtcbiAgICAgICAgICAgICAgICAgICAgZGVsYXlFcnJvckNhbGxiYWNrICYmIGRlbGF5RXJyb3JDYWxsYmFjaygwKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmIChmaWVsZC5fZi5vbkNoYW5nZSkge1xuICAgICAgICAgICAgICAgIGZpZWxkLl9mLm9uQ2hhbmdlKGV2ZW50KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IGZpZWxkU3RhdGUgPSB1cGRhdGVUb3VjaEFuZERpcnR5KG5hbWUsIGZpZWxkVmFsdWUsIGlzQmx1ckV2ZW50KTtcbiAgICAgICAgICAgIGNvbnN0IHNob3VsZFJlbmRlciA9ICFpc0VtcHR5T2JqZWN0KGZpZWxkU3RhdGUpIHx8IHdhdGNoZWQ7XG4gICAgICAgICAgICAhaXNCbHVyRXZlbnQgJiZcbiAgICAgICAgICAgICAgICBfc3ViamVjdHMuc3RhdGUubmV4dCh7XG4gICAgICAgICAgICAgICAgICAgIG5hbWUsXG4gICAgICAgICAgICAgICAgICAgIHR5cGU6IGV2ZW50LnR5cGUsXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlczogY2xvbmVPYmplY3QoX2Zvcm1WYWx1ZXMpLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgaWYgKHNob3VsZFNraXBWYWxpZGF0aW9uKSB7XG4gICAgICAgICAgICAgICAgaWYgKF9wcm94eUZvcm1TdGF0ZS5pc1ZhbGlkIHx8IF9wcm94eVN1YnNjcmliZUZvcm1TdGF0ZS5pc1ZhbGlkKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChfb3B0aW9ucy5tb2RlID09PSAnb25CbHVyJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzQmx1ckV2ZW50KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgX3NldFZhbGlkKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoIWlzQmx1ckV2ZW50KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBfc2V0VmFsaWQoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gKHNob3VsZFJlbmRlciAmJlxuICAgICAgICAgICAgICAgICAgICBfc3ViamVjdHMuc3RhdGUubmV4dCh7IG5hbWUsIC4uLih3YXRjaGVkID8ge30gOiBmaWVsZFN0YXRlKSB9KSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAhaXNCbHVyRXZlbnQgJiYgd2F0Y2hlZCAmJiBfc3ViamVjdHMuc3RhdGUubmV4dCh7IC4uLl9mb3JtU3RhdGUgfSk7XG4gICAgICAgICAgICBpZiAoX29wdGlvbnMucmVzb2x2ZXIpIHtcbiAgICAgICAgICAgICAgICBjb25zdCB7IGVycm9ycyB9ID0gYXdhaXQgX3J1blNjaGVtYShbbmFtZV0pO1xuICAgICAgICAgICAgICAgIF91cGRhdGVJc0ZpZWxkVmFsdWVVcGRhdGVkKGZpZWxkVmFsdWUpO1xuICAgICAgICAgICAgICAgIGlmIChpc0ZpZWxkVmFsdWVVcGRhdGVkKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHByZXZpb3VzRXJyb3JMb29rdXBSZXN1bHQgPSBzY2hlbWFFcnJvckxvb2t1cChfZm9ybVN0YXRlLmVycm9ycywgX2ZpZWxkcywgbmFtZSk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGVycm9yTG9va3VwUmVzdWx0ID0gc2NoZW1hRXJyb3JMb29rdXAoZXJyb3JzLCBfZmllbGRzLCBwcmV2aW91c0Vycm9yTG9va3VwUmVzdWx0Lm5hbWUgfHwgbmFtZSk7XG4gICAgICAgICAgICAgICAgICAgIGVycm9yID0gZXJyb3JMb29rdXBSZXN1bHQuZXJyb3I7XG4gICAgICAgICAgICAgICAgICAgIG5hbWUgPSBlcnJvckxvb2t1cFJlc3VsdC5uYW1lO1xuICAgICAgICAgICAgICAgICAgICBpc1ZhbGlkID0gaXNFbXB0eU9iamVjdChlcnJvcnMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIF91cGRhdGVJc1ZhbGlkYXRpbmcoW25hbWVdLCB0cnVlKTtcbiAgICAgICAgICAgICAgICBlcnJvciA9IChhd2FpdCB2YWxpZGF0ZUZpZWxkKGZpZWxkLCBfbmFtZXMuZGlzYWJsZWQsIF9mb3JtVmFsdWVzLCBzaG91bGREaXNwbGF5QWxsQXNzb2NpYXRlZEVycm9ycywgX29wdGlvbnMuc2hvdWxkVXNlTmF0aXZlVmFsaWRhdGlvbikpW25hbWVdO1xuICAgICAgICAgICAgICAgIF91cGRhdGVJc1ZhbGlkYXRpbmcoW25hbWVdKTtcbiAgICAgICAgICAgICAgICBfdXBkYXRlSXNGaWVsZFZhbHVlVXBkYXRlZChmaWVsZFZhbHVlKTtcbiAgICAgICAgICAgICAgICBpZiAoaXNGaWVsZFZhbHVlVXBkYXRlZCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzVmFsaWQgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNlIGlmIChfcHJveHlGb3JtU3RhdGUuaXNWYWxpZCB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgX3Byb3h5U3Vic2NyaWJlRm9ybVN0YXRlLmlzVmFsaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzVmFsaWQgPSBhd2FpdCBleGVjdXRlQnVpbHRJblZhbGlkYXRpb24oX2ZpZWxkcywgdHJ1ZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoaXNGaWVsZFZhbHVlVXBkYXRlZCkge1xuICAgICAgICAgICAgICAgIGZpZWxkLl9mLmRlcHMgJiZcbiAgICAgICAgICAgICAgICAgICAgKCFBcnJheS5pc0FycmF5KGZpZWxkLl9mLmRlcHMpIHx8IGZpZWxkLl9mLmRlcHMubGVuZ3RoID4gMCkgJiZcbiAgICAgICAgICAgICAgICAgICAgdHJpZ2dlcihmaWVsZC5fZi5kZXBzKTtcbiAgICAgICAgICAgICAgICBzaG91bGRSZW5kZXJCeUVycm9yKG5hbWUsIGlzVmFsaWQsIGVycm9yLCBmaWVsZFN0YXRlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG4gICAgY29uc3QgX2ZvY3VzSW5wdXQgPSAocmVmLCBrZXkpID0+IHtcbiAgICAgICAgaWYgKGdldChfZm9ybVN0YXRlLmVycm9ycywga2V5KSAmJiByZWYuZm9jdXMpIHtcbiAgICAgICAgICAgIHJlZi5mb2N1cygpO1xuICAgICAgICAgICAgcmV0dXJuIDE7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuO1xuICAgIH07XG4gICAgY29uc3QgdHJpZ2dlciA9IGFzeW5jIChuYW1lLCBvcHRpb25zID0ge30pID0+IHtcbiAgICAgICAgbGV0IGlzVmFsaWQ7XG4gICAgICAgIGxldCB2YWxpZGF0aW9uUmVzdWx0O1xuICAgICAgICBjb25zdCBmaWVsZE5hbWVzID0gY29udmVydFRvQXJyYXlQYXlsb2FkKG5hbWUpO1xuICAgICAgICBpZiAoX29wdGlvbnMucmVzb2x2ZXIpIHtcbiAgICAgICAgICAgIGNvbnN0IGVycm9ycyA9IGF3YWl0IGV4ZWN1dGVTY2hlbWFBbmRVcGRhdGVTdGF0ZShpc1VuZGVmaW5lZChuYW1lKSA/IG5hbWUgOiBmaWVsZE5hbWVzKTtcbiAgICAgICAgICAgIGlzVmFsaWQgPSBpc0VtcHR5T2JqZWN0KGVycm9ycyk7XG4gICAgICAgICAgICB2YWxpZGF0aW9uUmVzdWx0ID0gbmFtZVxuICAgICAgICAgICAgICAgID8gIWZpZWxkTmFtZXMuc29tZSgobmFtZSkgPT4gZ2V0KGVycm9ycywgbmFtZSkpXG4gICAgICAgICAgICAgICAgOiBpc1ZhbGlkO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKG5hbWUpIHtcbiAgICAgICAgICAgIHZhbGlkYXRpb25SZXN1bHQgPSAoYXdhaXQgUHJvbWlzZS5hbGwoZmllbGROYW1lcy5tYXAoYXN5bmMgKGZpZWxkTmFtZSkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IGZpZWxkID0gZ2V0KF9maWVsZHMsIGZpZWxkTmFtZSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGF3YWl0IGV4ZWN1dGVCdWlsdEluVmFsaWRhdGlvbihmaWVsZCAmJiBmaWVsZC5fZiA/IHsgW2ZpZWxkTmFtZV06IGZpZWxkIH0gOiBmaWVsZCk7XG4gICAgICAgICAgICB9KSkpLmV2ZXJ5KEJvb2xlYW4pO1xuICAgICAgICAgICAgISghdmFsaWRhdGlvblJlc3VsdCAmJiAhX2Zvcm1TdGF0ZS5pc1ZhbGlkKSAmJiBfc2V0VmFsaWQoKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHZhbGlkYXRpb25SZXN1bHQgPSBpc1ZhbGlkID0gYXdhaXQgZXhlY3V0ZUJ1aWx0SW5WYWxpZGF0aW9uKF9maWVsZHMpO1xuICAgICAgICB9XG4gICAgICAgIF9zdWJqZWN0cy5zdGF0ZS5uZXh0KHtcbiAgICAgICAgICAgIC4uLighaXNTdHJpbmcobmFtZSkgfHxcbiAgICAgICAgICAgICAgICAoKF9wcm94eUZvcm1TdGF0ZS5pc1ZhbGlkIHx8IF9wcm94eVN1YnNjcmliZUZvcm1TdGF0ZS5pc1ZhbGlkKSAmJlxuICAgICAgICAgICAgICAgICAgICBpc1ZhbGlkICE9PSBfZm9ybVN0YXRlLmlzVmFsaWQpXG4gICAgICAgICAgICAgICAgPyB7fVxuICAgICAgICAgICAgICAgIDogeyBuYW1lIH0pLFxuICAgICAgICAgICAgLi4uKF9vcHRpb25zLnJlc29sdmVyIHx8ICFuYW1lID8geyBpc1ZhbGlkIH0gOiB7fSksXG4gICAgICAgICAgICBlcnJvcnM6IF9mb3JtU3RhdGUuZXJyb3JzLFxuICAgICAgICB9KTtcbiAgICAgICAgb3B0aW9ucy5zaG91bGRGb2N1cyAmJlxuICAgICAgICAgICAgIXZhbGlkYXRpb25SZXN1bHQgJiZcbiAgICAgICAgICAgIGl0ZXJhdGVGaWVsZHNCeUFjdGlvbihfZmllbGRzLCBfZm9jdXNJbnB1dCwgbmFtZSA/IGZpZWxkTmFtZXMgOiBfbmFtZXMubW91bnQpO1xuICAgICAgICByZXR1cm4gdmFsaWRhdGlvblJlc3VsdDtcbiAgICB9O1xuICAgIGNvbnN0IGdldFZhbHVlcyA9IChmaWVsZE5hbWVzLCBjb25maWcpID0+IHtcbiAgICAgICAgbGV0IHZhbHVlcyA9IHtcbiAgICAgICAgICAgIC4uLihfc3RhdGUubW91bnQgPyBfZm9ybVZhbHVlcyA6IF9kZWZhdWx0VmFsdWVzKSxcbiAgICAgICAgfTtcbiAgICAgICAgaWYgKGNvbmZpZykge1xuICAgICAgICAgICAgdmFsdWVzID0gZXh0cmFjdEZvcm1WYWx1ZXMoY29uZmlnLmRpcnR5RmllbGRzID8gX2Zvcm1TdGF0ZS5kaXJ0eUZpZWxkcyA6IF9mb3JtU3RhdGUudG91Y2hlZEZpZWxkcywgdmFsdWVzKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gaXNVbmRlZmluZWQoZmllbGROYW1lcylcbiAgICAgICAgICAgID8gdmFsdWVzXG4gICAgICAgICAgICA6IGlzU3RyaW5nKGZpZWxkTmFtZXMpXG4gICAgICAgICAgICAgICAgPyBnZXQodmFsdWVzLCBmaWVsZE5hbWVzKVxuICAgICAgICAgICAgICAgIDogZmllbGROYW1lcy5tYXAoKG5hbWUpID0+IGdldCh2YWx1ZXMsIG5hbWUpKTtcbiAgICB9O1xuICAgIGNvbnN0IGdldEZpZWxkU3RhdGUgPSAobmFtZSwgZm9ybVN0YXRlKSA9PiAoe1xuICAgICAgICBpbnZhbGlkOiAhIWdldCgoZm9ybVN0YXRlIHx8IF9mb3JtU3RhdGUpLmVycm9ycywgbmFtZSksXG4gICAgICAgIGlzRGlydHk6ICEhZ2V0KChmb3JtU3RhdGUgfHwgX2Zvcm1TdGF0ZSkuZGlydHlGaWVsZHMsIG5hbWUpLFxuICAgICAgICBlcnJvcjogZ2V0KChmb3JtU3RhdGUgfHwgX2Zvcm1TdGF0ZSkuZXJyb3JzLCBuYW1lKSxcbiAgICAgICAgaXNWYWxpZGF0aW5nOiAhIWdldChfZm9ybVN0YXRlLnZhbGlkYXRpbmdGaWVsZHMsIG5hbWUpLFxuICAgICAgICBpc1RvdWNoZWQ6ICEhZ2V0KChmb3JtU3RhdGUgfHwgX2Zvcm1TdGF0ZSkudG91Y2hlZEZpZWxkcywgbmFtZSksXG4gICAgfSk7XG4gICAgY29uc3QgY2xlYXJFcnJvcnMgPSAobmFtZSkgPT4ge1xuICAgICAgICBuYW1lICYmXG4gICAgICAgICAgICBjb252ZXJ0VG9BcnJheVBheWxvYWQobmFtZSkuZm9yRWFjaCgoaW5wdXROYW1lKSA9PiB1bnNldChfZm9ybVN0YXRlLmVycm9ycywgaW5wdXROYW1lKSk7XG4gICAgICAgIF9zdWJqZWN0cy5zdGF0ZS5uZXh0KHtcbiAgICAgICAgICAgIGVycm9yczogbmFtZSA/IF9mb3JtU3RhdGUuZXJyb3JzIDoge30sXG4gICAgICAgIH0pO1xuICAgIH07XG4gICAgY29uc3Qgc2V0RXJyb3IgPSAobmFtZSwgZXJyb3IsIG9wdGlvbnMpID0+IHtcbiAgICAgICAgY29uc3QgcmVmID0gKGdldChfZmllbGRzLCBuYW1lLCB7IF9mOiB7fSB9KS5fZiB8fCB7fSkucmVmO1xuICAgICAgICBjb25zdCBjdXJyZW50RXJyb3IgPSBnZXQoX2Zvcm1TdGF0ZS5lcnJvcnMsIG5hbWUpIHx8IHt9O1xuICAgICAgICAvLyBEb24ndCBvdmVycmlkZSBleGlzdGluZyBlcnJvciBtZXNzYWdlcyBlbHNld2hlcmUgaW4gdGhlIG9iamVjdCB0cmVlLlxuICAgICAgICBjb25zdCB7IHJlZjogY3VycmVudFJlZiwgbWVzc2FnZSwgdHlwZSwgLi4ucmVzdE9mRXJyb3JUcmVlIH0gPSBjdXJyZW50RXJyb3I7XG4gICAgICAgIHNldChfZm9ybVN0YXRlLmVycm9ycywgbmFtZSwge1xuICAgICAgICAgICAgLi4ucmVzdE9mRXJyb3JUcmVlLFxuICAgICAgICAgICAgLi4uZXJyb3IsXG4gICAgICAgICAgICByZWYsXG4gICAgICAgIH0pO1xuICAgICAgICBfc3ViamVjdHMuc3RhdGUubmV4dCh7XG4gICAgICAgICAgICBuYW1lLFxuICAgICAgICAgICAgZXJyb3JzOiBfZm9ybVN0YXRlLmVycm9ycyxcbiAgICAgICAgICAgIGlzVmFsaWQ6IGZhbHNlLFxuICAgICAgICB9KTtcbiAgICAgICAgb3B0aW9ucyAmJiBvcHRpb25zLnNob3VsZEZvY3VzICYmIHJlZiAmJiByZWYuZm9jdXMgJiYgcmVmLmZvY3VzKCk7XG4gICAgfTtcbiAgICBjb25zdCB3YXRjaCA9IChuYW1lLCBkZWZhdWx0VmFsdWUpID0+IGlzRnVuY3Rpb24obmFtZSlcbiAgICAgICAgPyBfc3ViamVjdHMuc3RhdGUuc3Vic2NyaWJlKHtcbiAgICAgICAgICAgIG5leHQ6IChwYXlsb2FkKSA9PiAndmFsdWVzJyBpbiBwYXlsb2FkICYmXG4gICAgICAgICAgICAgICAgbmFtZShfZ2V0V2F0Y2godW5kZWZpbmVkLCBkZWZhdWx0VmFsdWUpLCBwYXlsb2FkKSxcbiAgICAgICAgfSlcbiAgICAgICAgOiBfZ2V0V2F0Y2gobmFtZSwgZGVmYXVsdFZhbHVlLCB0cnVlKTtcbiAgICBjb25zdCBfc3Vic2NyaWJlID0gKHByb3BzKSA9PiBfc3ViamVjdHMuc3RhdGUuc3Vic2NyaWJlKHtcbiAgICAgICAgbmV4dDogKGZvcm1TdGF0ZSkgPT4ge1xuICAgICAgICAgICAgaWYgKHNob3VsZFN1YnNjcmliZUJ5TmFtZShwcm9wcy5uYW1lLCBmb3JtU3RhdGUubmFtZSwgcHJvcHMuZXhhY3QpICYmXG4gICAgICAgICAgICAgICAgc2hvdWxkUmVuZGVyRm9ybVN0YXRlKGZvcm1TdGF0ZSwgcHJvcHMuZm9ybVN0YXRlIHx8IF9wcm94eUZvcm1TdGF0ZSwgX3NldEZvcm1TdGF0ZSwgcHJvcHMucmVSZW5kZXJSb290KSkge1xuICAgICAgICAgICAgICAgIHByb3BzLmNhbGxiYWNrKHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWVzOiB7IC4uLl9mb3JtVmFsdWVzIH0sXG4gICAgICAgICAgICAgICAgICAgIC4uLl9mb3JtU3RhdGUsXG4gICAgICAgICAgICAgICAgICAgIC4uLmZvcm1TdGF0ZSxcbiAgICAgICAgICAgICAgICAgICAgZGVmYXVsdFZhbHVlczogX2RlZmF1bHRWYWx1ZXMsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgfSkudW5zdWJzY3JpYmU7XG4gICAgY29uc3Qgc3Vic2NyaWJlID0gKHByb3BzKSA9PiB7XG4gICAgICAgIF9zdGF0ZS5tb3VudCA9IHRydWU7XG4gICAgICAgIF9wcm94eVN1YnNjcmliZUZvcm1TdGF0ZSA9IHtcbiAgICAgICAgICAgIC4uLl9wcm94eVN1YnNjcmliZUZvcm1TdGF0ZSxcbiAgICAgICAgICAgIC4uLnByb3BzLmZvcm1TdGF0ZSxcbiAgICAgICAgfTtcbiAgICAgICAgcmV0dXJuIF9zdWJzY3JpYmUoe1xuICAgICAgICAgICAgLi4ucHJvcHMsXG4gICAgICAgICAgICBmb3JtU3RhdGU6IF9wcm94eVN1YnNjcmliZUZvcm1TdGF0ZSxcbiAgICAgICAgfSk7XG4gICAgfTtcbiAgICBjb25zdCB1bnJlZ2lzdGVyID0gKG5hbWUsIG9wdGlvbnMgPSB7fSkgPT4ge1xuICAgICAgICBmb3IgKGNvbnN0IGZpZWxkTmFtZSBvZiBuYW1lID8gY29udmVydFRvQXJyYXlQYXlsb2FkKG5hbWUpIDogX25hbWVzLm1vdW50KSB7XG4gICAgICAgICAgICBfbmFtZXMubW91bnQuZGVsZXRlKGZpZWxkTmFtZSk7XG4gICAgICAgICAgICBfbmFtZXMuYXJyYXkuZGVsZXRlKGZpZWxkTmFtZSk7XG4gICAgICAgICAgICBpZiAoIW9wdGlvbnMua2VlcFZhbHVlKSB7XG4gICAgICAgICAgICAgICAgdW5zZXQoX2ZpZWxkcywgZmllbGROYW1lKTtcbiAgICAgICAgICAgICAgICB1bnNldChfZm9ybVZhbHVlcywgZmllbGROYW1lKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgICFvcHRpb25zLmtlZXBFcnJvciAmJiB1bnNldChfZm9ybVN0YXRlLmVycm9ycywgZmllbGROYW1lKTtcbiAgICAgICAgICAgICFvcHRpb25zLmtlZXBEaXJ0eSAmJiB1bnNldChfZm9ybVN0YXRlLmRpcnR5RmllbGRzLCBmaWVsZE5hbWUpO1xuICAgICAgICAgICAgIW9wdGlvbnMua2VlcFRvdWNoZWQgJiYgdW5zZXQoX2Zvcm1TdGF0ZS50b3VjaGVkRmllbGRzLCBmaWVsZE5hbWUpO1xuICAgICAgICAgICAgIW9wdGlvbnMua2VlcElzVmFsaWRhdGluZyAmJlxuICAgICAgICAgICAgICAgIHVuc2V0KF9mb3JtU3RhdGUudmFsaWRhdGluZ0ZpZWxkcywgZmllbGROYW1lKTtcbiAgICAgICAgICAgICFfb3B0aW9ucy5zaG91bGRVbnJlZ2lzdGVyICYmXG4gICAgICAgICAgICAgICAgIW9wdGlvbnMua2VlcERlZmF1bHRWYWx1ZSAmJlxuICAgICAgICAgICAgICAgIHVuc2V0KF9kZWZhdWx0VmFsdWVzLCBmaWVsZE5hbWUpO1xuICAgICAgICB9XG4gICAgICAgIF9zdWJqZWN0cy5zdGF0ZS5uZXh0KHtcbiAgICAgICAgICAgIHZhbHVlczogY2xvbmVPYmplY3QoX2Zvcm1WYWx1ZXMpLFxuICAgICAgICB9KTtcbiAgICAgICAgX3N1YmplY3RzLnN0YXRlLm5leHQoe1xuICAgICAgICAgICAgLi4uX2Zvcm1TdGF0ZSxcbiAgICAgICAgICAgIC4uLighb3B0aW9ucy5rZWVwRGlydHkgPyB7fSA6IHsgaXNEaXJ0eTogX2dldERpcnR5KCkgfSksXG4gICAgICAgIH0pO1xuICAgICAgICAhb3B0aW9ucy5rZWVwSXNWYWxpZCAmJiBfc2V0VmFsaWQoKTtcbiAgICB9O1xuICAgIGNvbnN0IF9zZXREaXNhYmxlZEZpZWxkID0gKHsgZGlzYWJsZWQsIG5hbWUsIH0pID0+IHtcbiAgICAgICAgaWYgKChpc0Jvb2xlYW4oZGlzYWJsZWQpICYmIF9zdGF0ZS5tb3VudCkgfHxcbiAgICAgICAgICAgICEhZGlzYWJsZWQgfHxcbiAgICAgICAgICAgIF9uYW1lcy5kaXNhYmxlZC5oYXMobmFtZSkpIHtcbiAgICAgICAgICAgIGRpc2FibGVkID8gX25hbWVzLmRpc2FibGVkLmFkZChuYW1lKSA6IF9uYW1lcy5kaXNhYmxlZC5kZWxldGUobmFtZSk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIGNvbnN0IHJlZ2lzdGVyID0gKG5hbWUsIG9wdGlvbnMgPSB7fSkgPT4ge1xuICAgICAgICBsZXQgZmllbGQgPSBnZXQoX2ZpZWxkcywgbmFtZSk7XG4gICAgICAgIGNvbnN0IGRpc2FibGVkSXNEZWZpbmVkID0gaXNCb29sZWFuKG9wdGlvbnMuZGlzYWJsZWQpIHx8IGlzQm9vbGVhbihfb3B0aW9ucy5kaXNhYmxlZCk7XG4gICAgICAgIHNldChfZmllbGRzLCBuYW1lLCB7XG4gICAgICAgICAgICAuLi4oZmllbGQgfHwge30pLFxuICAgICAgICAgICAgX2Y6IHtcbiAgICAgICAgICAgICAgICAuLi4oZmllbGQgJiYgZmllbGQuX2YgPyBmaWVsZC5fZiA6IHsgcmVmOiB7IG5hbWUgfSB9KSxcbiAgICAgICAgICAgICAgICBuYW1lLFxuICAgICAgICAgICAgICAgIG1vdW50OiB0cnVlLFxuICAgICAgICAgICAgICAgIC4uLm9wdGlvbnMsXG4gICAgICAgICAgICB9LFxuICAgICAgICB9KTtcbiAgICAgICAgX25hbWVzLm1vdW50LmFkZChuYW1lKTtcbiAgICAgICAgaWYgKGZpZWxkKSB7XG4gICAgICAgICAgICBfc2V0RGlzYWJsZWRGaWVsZCh7XG4gICAgICAgICAgICAgICAgZGlzYWJsZWQ6IGlzQm9vbGVhbihvcHRpb25zLmRpc2FibGVkKVxuICAgICAgICAgICAgICAgICAgICA/IG9wdGlvbnMuZGlzYWJsZWRcbiAgICAgICAgICAgICAgICAgICAgOiBfb3B0aW9ucy5kaXNhYmxlZCxcbiAgICAgICAgICAgICAgICBuYW1lLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB1cGRhdGVWYWxpZEFuZFZhbHVlKG5hbWUsIHRydWUsIG9wdGlvbnMudmFsdWUpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAuLi4oZGlzYWJsZWRJc0RlZmluZWRcbiAgICAgICAgICAgICAgICA/IHsgZGlzYWJsZWQ6IG9wdGlvbnMuZGlzYWJsZWQgfHwgX29wdGlvbnMuZGlzYWJsZWQgfVxuICAgICAgICAgICAgICAgIDoge30pLFxuICAgICAgICAgICAgLi4uKF9vcHRpb25zLnByb2dyZXNzaXZlXG4gICAgICAgICAgICAgICAgPyB7XG4gICAgICAgICAgICAgICAgICAgIHJlcXVpcmVkOiAhIW9wdGlvbnMucmVxdWlyZWQsXG4gICAgICAgICAgICAgICAgICAgIG1pbjogZ2V0UnVsZVZhbHVlKG9wdGlvbnMubWluKSxcbiAgICAgICAgICAgICAgICAgICAgbWF4OiBnZXRSdWxlVmFsdWUob3B0aW9ucy5tYXgpLFxuICAgICAgICAgICAgICAgICAgICBtaW5MZW5ndGg6IGdldFJ1bGVWYWx1ZShvcHRpb25zLm1pbkxlbmd0aCksXG4gICAgICAgICAgICAgICAgICAgIG1heExlbmd0aDogZ2V0UnVsZVZhbHVlKG9wdGlvbnMubWF4TGVuZ3RoKSxcbiAgICAgICAgICAgICAgICAgICAgcGF0dGVybjogZ2V0UnVsZVZhbHVlKG9wdGlvbnMucGF0dGVybiksXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIDoge30pLFxuICAgICAgICAgICAgbmFtZSxcbiAgICAgICAgICAgIG9uQ2hhbmdlLFxuICAgICAgICAgICAgb25CbHVyOiBvbkNoYW5nZSxcbiAgICAgICAgICAgIHJlZjogKHJlZikgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChyZWYpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVnaXN0ZXIobmFtZSwgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIGZpZWxkID0gZ2V0KF9maWVsZHMsIG5hbWUpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBmaWVsZFJlZiA9IGlzVW5kZWZpbmVkKHJlZi52YWx1ZSlcbiAgICAgICAgICAgICAgICAgICAgICAgID8gcmVmLnF1ZXJ5U2VsZWN0b3JBbGxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA/IHJlZi5xdWVyeVNlbGVjdG9yQWxsKCdpbnB1dCxzZWxlY3QsdGV4dGFyZWEnKVswXSB8fCByZWZcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IHJlZlxuICAgICAgICAgICAgICAgICAgICAgICAgOiByZWY7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHJhZGlvT3JDaGVja2JveCA9IGlzUmFkaW9PckNoZWNrYm94KGZpZWxkUmVmKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcmVmcyA9IGZpZWxkLl9mLnJlZnMgfHwgW107XG4gICAgICAgICAgICAgICAgICAgIGlmIChyYWRpb09yQ2hlY2tib3hcbiAgICAgICAgICAgICAgICAgICAgICAgID8gcmVmcy5maW5kKChvcHRpb24pID0+IG9wdGlvbiA9PT0gZmllbGRSZWYpXG4gICAgICAgICAgICAgICAgICAgICAgICA6IGZpZWxkUmVmID09PSBmaWVsZC5fZi5yZWYpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBzZXQoX2ZpZWxkcywgbmFtZSwge1xuICAgICAgICAgICAgICAgICAgICAgICAgX2Y6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLi5maWVsZC5fZixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLi4ocmFkaW9PckNoZWNrYm94XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID8ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVmczogW1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLnJlZnMuZmlsdGVyKGxpdmUpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpZWxkUmVmLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLihBcnJheS5pc0FycmF5KGdldChfZGVmYXVsdFZhbHVlcywgbmFtZSkpID8gW3t9XSA6IFtdKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWY6IHsgdHlwZTogZmllbGRSZWYudHlwZSwgbmFtZSB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDogeyByZWY6IGZpZWxkUmVmIH0pLFxuICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIHVwZGF0ZVZhbGlkQW5kVmFsdWUobmFtZSwgZmFsc2UsIHVuZGVmaW5lZCwgZmllbGRSZWYpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgZmllbGQgPSBnZXQoX2ZpZWxkcywgbmFtZSwge30pO1xuICAgICAgICAgICAgICAgICAgICBpZiAoZmllbGQuX2YpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZpZWxkLl9mLm1vdW50ID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgKF9vcHRpb25zLnNob3VsZFVucmVnaXN0ZXIgfHwgb3B0aW9ucy5zaG91bGRVbnJlZ2lzdGVyKSAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgIShpc05hbWVJbkZpZWxkQXJyYXkoX25hbWVzLmFycmF5LCBuYW1lKSAmJiBfc3RhdGUuYWN0aW9uKSAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgX25hbWVzLnVuTW91bnQuYWRkKG5hbWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgIH07XG4gICAgfTtcbiAgICBjb25zdCBfZm9jdXNFcnJvciA9ICgpID0+IF9vcHRpb25zLnNob3VsZEZvY3VzRXJyb3IgJiZcbiAgICAgICAgaXRlcmF0ZUZpZWxkc0J5QWN0aW9uKF9maWVsZHMsIF9mb2N1c0lucHV0LCBfbmFtZXMubW91bnQpO1xuICAgIGNvbnN0IF9kaXNhYmxlRm9ybSA9IChkaXNhYmxlZCkgPT4ge1xuICAgICAgICBpZiAoaXNCb29sZWFuKGRpc2FibGVkKSkge1xuICAgICAgICAgICAgX3N1YmplY3RzLnN0YXRlLm5leHQoeyBkaXNhYmxlZCB9KTtcbiAgICAgICAgICAgIGl0ZXJhdGVGaWVsZHNCeUFjdGlvbihfZmllbGRzLCAocmVmLCBuYW1lKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgY3VycmVudEZpZWxkID0gZ2V0KF9maWVsZHMsIG5hbWUpO1xuICAgICAgICAgICAgICAgIGlmIChjdXJyZW50RmllbGQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVmLmRpc2FibGVkID0gY3VycmVudEZpZWxkLl9mLmRpc2FibGVkIHx8IGRpc2FibGVkO1xuICAgICAgICAgICAgICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShjdXJyZW50RmllbGQuX2YucmVmcykpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnRGaWVsZC5fZi5yZWZzLmZvckVhY2goKGlucHV0UmVmKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5wdXRSZWYuZGlzYWJsZWQgPSBjdXJyZW50RmllbGQuX2YuZGlzYWJsZWQgfHwgZGlzYWJsZWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sIDAsIGZhbHNlKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgY29uc3QgaGFuZGxlU3VibWl0ID0gKG9uVmFsaWQsIG9uSW52YWxpZCkgPT4gYXN5bmMgKGUpID0+IHtcbiAgICAgICAgbGV0IG9uVmFsaWRFcnJvciA9IHVuZGVmaW5lZDtcbiAgICAgICAgaWYgKGUpIHtcbiAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQgJiYgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgZS5wZXJzaXN0ICYmXG4gICAgICAgICAgICAgICAgZS5wZXJzaXN0KCk7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IGZpZWxkVmFsdWVzID0gY2xvbmVPYmplY3QoX2Zvcm1WYWx1ZXMpO1xuICAgICAgICBfc3ViamVjdHMuc3RhdGUubmV4dCh7XG4gICAgICAgICAgICBpc1N1Ym1pdHRpbmc6IHRydWUsXG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoX29wdGlvbnMucmVzb2x2ZXIpIHtcbiAgICAgICAgICAgIGNvbnN0IHsgZXJyb3JzLCB2YWx1ZXMgfSA9IGF3YWl0IF9ydW5TY2hlbWEoKTtcbiAgICAgICAgICAgIF9mb3JtU3RhdGUuZXJyb3JzID0gZXJyb3JzO1xuICAgICAgICAgICAgZmllbGRWYWx1ZXMgPSBjbG9uZU9iamVjdCh2YWx1ZXMpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgYXdhaXQgZXhlY3V0ZUJ1aWx0SW5WYWxpZGF0aW9uKF9maWVsZHMpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChfbmFtZXMuZGlzYWJsZWQuc2l6ZSkge1xuICAgICAgICAgICAgZm9yIChjb25zdCBuYW1lIG9mIF9uYW1lcy5kaXNhYmxlZCkge1xuICAgICAgICAgICAgICAgIHVuc2V0KGZpZWxkVmFsdWVzLCBuYW1lKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB1bnNldChfZm9ybVN0YXRlLmVycm9ycywgJ3Jvb3QnKTtcbiAgICAgICAgaWYgKGlzRW1wdHlPYmplY3QoX2Zvcm1TdGF0ZS5lcnJvcnMpKSB7XG4gICAgICAgICAgICBfc3ViamVjdHMuc3RhdGUubmV4dCh7XG4gICAgICAgICAgICAgICAgZXJyb3JzOiB7fSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBhd2FpdCBvblZhbGlkKGZpZWxkVmFsdWVzLCBlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgICAgIG9uVmFsaWRFcnJvciA9IGVycm9yO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgaWYgKG9uSW52YWxpZCkge1xuICAgICAgICAgICAgICAgIGF3YWl0IG9uSW52YWxpZCh7IC4uLl9mb3JtU3RhdGUuZXJyb3JzIH0sIGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgX2ZvY3VzRXJyb3IoKTtcbiAgICAgICAgICAgIHNldFRpbWVvdXQoX2ZvY3VzRXJyb3IpO1xuICAgICAgICB9XG4gICAgICAgIF9zdWJqZWN0cy5zdGF0ZS5uZXh0KHtcbiAgICAgICAgICAgIGlzU3VibWl0dGVkOiB0cnVlLFxuICAgICAgICAgICAgaXNTdWJtaXR0aW5nOiBmYWxzZSxcbiAgICAgICAgICAgIGlzU3VibWl0U3VjY2Vzc2Z1bDogaXNFbXB0eU9iamVjdChfZm9ybVN0YXRlLmVycm9ycykgJiYgIW9uVmFsaWRFcnJvcixcbiAgICAgICAgICAgIHN1Ym1pdENvdW50OiBfZm9ybVN0YXRlLnN1Ym1pdENvdW50ICsgMSxcbiAgICAgICAgICAgIGVycm9yczogX2Zvcm1TdGF0ZS5lcnJvcnMsXG4gICAgICAgIH0pO1xuICAgICAgICBpZiAob25WYWxpZEVycm9yKSB7XG4gICAgICAgICAgICB0aHJvdyBvblZhbGlkRXJyb3I7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIGNvbnN0IHJlc2V0RmllbGQgPSAobmFtZSwgb3B0aW9ucyA9IHt9KSA9PiB7XG4gICAgICAgIGlmIChnZXQoX2ZpZWxkcywgbmFtZSkpIHtcbiAgICAgICAgICAgIGlmIChpc1VuZGVmaW5lZChvcHRpb25zLmRlZmF1bHRWYWx1ZSkpIHtcbiAgICAgICAgICAgICAgICBzZXRWYWx1ZShuYW1lLCBjbG9uZU9iamVjdChnZXQoX2RlZmF1bHRWYWx1ZXMsIG5hbWUpKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBzZXRWYWx1ZShuYW1lLCBvcHRpb25zLmRlZmF1bHRWYWx1ZSk7XG4gICAgICAgICAgICAgICAgc2V0KF9kZWZhdWx0VmFsdWVzLCBuYW1lLCBjbG9uZU9iamVjdChvcHRpb25zLmRlZmF1bHRWYWx1ZSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFvcHRpb25zLmtlZXBUb3VjaGVkKSB7XG4gICAgICAgICAgICAgICAgdW5zZXQoX2Zvcm1TdGF0ZS50b3VjaGVkRmllbGRzLCBuYW1lKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghb3B0aW9ucy5rZWVwRGlydHkpIHtcbiAgICAgICAgICAgICAgICB1bnNldChfZm9ybVN0YXRlLmRpcnR5RmllbGRzLCBuYW1lKTtcbiAgICAgICAgICAgICAgICBfZm9ybVN0YXRlLmlzRGlydHkgPSBvcHRpb25zLmRlZmF1bHRWYWx1ZVxuICAgICAgICAgICAgICAgICAgICA/IF9nZXREaXJ0eShuYW1lLCBjbG9uZU9iamVjdChnZXQoX2RlZmF1bHRWYWx1ZXMsIG5hbWUpKSlcbiAgICAgICAgICAgICAgICAgICAgOiBfZ2V0RGlydHkoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghb3B0aW9ucy5rZWVwRXJyb3IpIHtcbiAgICAgICAgICAgICAgICB1bnNldChfZm9ybVN0YXRlLmVycm9ycywgbmFtZSk7XG4gICAgICAgICAgICAgICAgX3Byb3h5Rm9ybVN0YXRlLmlzVmFsaWQgJiYgX3NldFZhbGlkKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBfc3ViamVjdHMuc3RhdGUubmV4dCh7IC4uLl9mb3JtU3RhdGUgfSk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIGNvbnN0IF9yZXNldCA9IChmb3JtVmFsdWVzLCBrZWVwU3RhdGVPcHRpb25zID0ge30pID0+IHtcbiAgICAgICAgY29uc3QgdXBkYXRlZFZhbHVlcyA9IGZvcm1WYWx1ZXMgPyBjbG9uZU9iamVjdChmb3JtVmFsdWVzKSA6IF9kZWZhdWx0VmFsdWVzO1xuICAgICAgICBjb25zdCBjbG9uZVVwZGF0ZWRWYWx1ZXMgPSBjbG9uZU9iamVjdCh1cGRhdGVkVmFsdWVzKTtcbiAgICAgICAgY29uc3QgaXNFbXB0eVJlc2V0VmFsdWVzID0gaXNFbXB0eU9iamVjdChmb3JtVmFsdWVzKTtcbiAgICAgICAgY29uc3QgdmFsdWVzID0gaXNFbXB0eVJlc2V0VmFsdWVzID8gX2RlZmF1bHRWYWx1ZXMgOiBjbG9uZVVwZGF0ZWRWYWx1ZXM7XG4gICAgICAgIGlmICgha2VlcFN0YXRlT3B0aW9ucy5rZWVwRGVmYXVsdFZhbHVlcykge1xuICAgICAgICAgICAgX2RlZmF1bHRWYWx1ZXMgPSB1cGRhdGVkVmFsdWVzO1xuICAgICAgICB9XG4gICAgICAgIGlmICgha2VlcFN0YXRlT3B0aW9ucy5rZWVwVmFsdWVzKSB7XG4gICAgICAgICAgICBpZiAoa2VlcFN0YXRlT3B0aW9ucy5rZWVwRGlydHlWYWx1ZXMpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBmaWVsZHNUb0NoZWNrID0gbmV3IFNldChbXG4gICAgICAgICAgICAgICAgICAgIC4uLl9uYW1lcy5tb3VudCxcbiAgICAgICAgICAgICAgICAgICAgLi4uT2JqZWN0LmtleXMoZ2V0RGlydHlGaWVsZHMoX2RlZmF1bHRWYWx1ZXMsIF9mb3JtVmFsdWVzKSksXG4gICAgICAgICAgICAgICAgXSk7XG4gICAgICAgICAgICAgICAgZm9yIChjb25zdCBmaWVsZE5hbWUgb2YgQXJyYXkuZnJvbShmaWVsZHNUb0NoZWNrKSkge1xuICAgICAgICAgICAgICAgICAgICBnZXQoX2Zvcm1TdGF0ZS5kaXJ0eUZpZWxkcywgZmllbGROYW1lKVxuICAgICAgICAgICAgICAgICAgICAgICAgPyBzZXQodmFsdWVzLCBmaWVsZE5hbWUsIGdldChfZm9ybVZhbHVlcywgZmllbGROYW1lKSlcbiAgICAgICAgICAgICAgICAgICAgICAgIDogc2V0VmFsdWUoZmllbGROYW1lLCBnZXQodmFsdWVzLCBmaWVsZE5hbWUpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAoaXNXZWIgJiYgaXNVbmRlZmluZWQoZm9ybVZhbHVlcykpIHtcbiAgICAgICAgICAgICAgICAgICAgZm9yIChjb25zdCBuYW1lIG9mIF9uYW1lcy5tb3VudCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZmllbGQgPSBnZXQoX2ZpZWxkcywgbmFtZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoZmllbGQgJiYgZmllbGQuX2YpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBmaWVsZFJlZmVyZW5jZSA9IEFycmF5LmlzQXJyYXkoZmllbGQuX2YucmVmcylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPyBmaWVsZC5fZi5yZWZzWzBdXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDogZmllbGQuX2YucmVmO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpc0hUTUxFbGVtZW50KGZpZWxkUmVmZXJlbmNlKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBmb3JtID0gZmllbGRSZWZlcmVuY2UuY2xvc2VzdCgnZm9ybScpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZm9ybSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9ybS5yZXNldCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKGtlZXBTdGF0ZU9wdGlvbnMua2VlcEZpZWxkc1JlZikge1xuICAgICAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IGZpZWxkTmFtZSBvZiBfbmFtZXMubW91bnQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNldFZhbHVlKGZpZWxkTmFtZSwgZ2V0KHZhbHVlcywgZmllbGROYW1lKSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIF9maWVsZHMgPSB7fTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBfZm9ybVZhbHVlcyA9IF9vcHRpb25zLnNob3VsZFVucmVnaXN0ZXJcbiAgICAgICAgICAgICAgICA/IGtlZXBTdGF0ZU9wdGlvbnMua2VlcERlZmF1bHRWYWx1ZXNcbiAgICAgICAgICAgICAgICAgICAgPyBjbG9uZU9iamVjdChfZGVmYXVsdFZhbHVlcylcbiAgICAgICAgICAgICAgICAgICAgOiB7fVxuICAgICAgICAgICAgICAgIDogY2xvbmVPYmplY3QodmFsdWVzKTtcbiAgICAgICAgICAgIF9zdWJqZWN0cy5hcnJheS5uZXh0KHtcbiAgICAgICAgICAgICAgICB2YWx1ZXM6IHsgLi4udmFsdWVzIH0sXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIF9zdWJqZWN0cy5zdGF0ZS5uZXh0KHtcbiAgICAgICAgICAgICAgICB2YWx1ZXM6IHsgLi4udmFsdWVzIH0sXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBfbmFtZXMgPSB7XG4gICAgICAgICAgICBtb3VudDoga2VlcFN0YXRlT3B0aW9ucy5rZWVwRGlydHlWYWx1ZXMgPyBfbmFtZXMubW91bnQgOiBuZXcgU2V0KCksXG4gICAgICAgICAgICB1bk1vdW50OiBuZXcgU2V0KCksXG4gICAgICAgICAgICBhcnJheTogbmV3IFNldCgpLFxuICAgICAgICAgICAgZGlzYWJsZWQ6IG5ldyBTZXQoKSxcbiAgICAgICAgICAgIHdhdGNoOiBuZXcgU2V0KCksXG4gICAgICAgICAgICB3YXRjaEFsbDogZmFsc2UsXG4gICAgICAgICAgICBmb2N1czogJycsXG4gICAgICAgIH07XG4gICAgICAgIF9zdGF0ZS5tb3VudCA9XG4gICAgICAgICAgICAhX3Byb3h5Rm9ybVN0YXRlLmlzVmFsaWQgfHxcbiAgICAgICAgICAgICAgICAhIWtlZXBTdGF0ZU9wdGlvbnMua2VlcElzVmFsaWQgfHxcbiAgICAgICAgICAgICAgICAhIWtlZXBTdGF0ZU9wdGlvbnMua2VlcERpcnR5VmFsdWVzIHx8XG4gICAgICAgICAgICAgICAgKCFfb3B0aW9ucy5zaG91bGRVbnJlZ2lzdGVyICYmICFpc0VtcHR5T2JqZWN0KHZhbHVlcykpO1xuICAgICAgICBfc3RhdGUud2F0Y2ggPSAhIV9vcHRpb25zLnNob3VsZFVucmVnaXN0ZXI7XG4gICAgICAgIF9zdWJqZWN0cy5zdGF0ZS5uZXh0KHtcbiAgICAgICAgICAgIHN1Ym1pdENvdW50OiBrZWVwU3RhdGVPcHRpb25zLmtlZXBTdWJtaXRDb3VudFxuICAgICAgICAgICAgICAgID8gX2Zvcm1TdGF0ZS5zdWJtaXRDb3VudFxuICAgICAgICAgICAgICAgIDogMCxcbiAgICAgICAgICAgIGlzRGlydHk6IGlzRW1wdHlSZXNldFZhbHVlc1xuICAgICAgICAgICAgICAgID8gZmFsc2VcbiAgICAgICAgICAgICAgICA6IGtlZXBTdGF0ZU9wdGlvbnMua2VlcERpcnR5XG4gICAgICAgICAgICAgICAgICAgID8gX2Zvcm1TdGF0ZS5pc0RpcnR5XG4gICAgICAgICAgICAgICAgICAgIDogISEoa2VlcFN0YXRlT3B0aW9ucy5rZWVwRGVmYXVsdFZhbHVlcyAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgIWRlZXBFcXVhbChmb3JtVmFsdWVzLCBfZGVmYXVsdFZhbHVlcykpLFxuICAgICAgICAgICAgaXNTdWJtaXR0ZWQ6IGtlZXBTdGF0ZU9wdGlvbnMua2VlcElzU3VibWl0dGVkXG4gICAgICAgICAgICAgICAgPyBfZm9ybVN0YXRlLmlzU3VibWl0dGVkXG4gICAgICAgICAgICAgICAgOiBmYWxzZSxcbiAgICAgICAgICAgIGRpcnR5RmllbGRzOiBpc0VtcHR5UmVzZXRWYWx1ZXNcbiAgICAgICAgICAgICAgICA/IHt9XG4gICAgICAgICAgICAgICAgOiBrZWVwU3RhdGVPcHRpb25zLmtlZXBEaXJ0eVZhbHVlc1xuICAgICAgICAgICAgICAgICAgICA/IGtlZXBTdGF0ZU9wdGlvbnMua2VlcERlZmF1bHRWYWx1ZXMgJiYgX2Zvcm1WYWx1ZXNcbiAgICAgICAgICAgICAgICAgICAgICAgID8gZ2V0RGlydHlGaWVsZHMoX2RlZmF1bHRWYWx1ZXMsIF9mb3JtVmFsdWVzKVxuICAgICAgICAgICAgICAgICAgICAgICAgOiBfZm9ybVN0YXRlLmRpcnR5RmllbGRzXG4gICAgICAgICAgICAgICAgICAgIDoga2VlcFN0YXRlT3B0aW9ucy5rZWVwRGVmYXVsdFZhbHVlcyAmJiBmb3JtVmFsdWVzXG4gICAgICAgICAgICAgICAgICAgICAgICA/IGdldERpcnR5RmllbGRzKF9kZWZhdWx0VmFsdWVzLCBmb3JtVmFsdWVzKVxuICAgICAgICAgICAgICAgICAgICAgICAgOiBrZWVwU3RhdGVPcHRpb25zLmtlZXBEaXJ0eVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gX2Zvcm1TdGF0ZS5kaXJ0eUZpZWxkc1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDoge30sXG4gICAgICAgICAgICB0b3VjaGVkRmllbGRzOiBrZWVwU3RhdGVPcHRpb25zLmtlZXBUb3VjaGVkXG4gICAgICAgICAgICAgICAgPyBfZm9ybVN0YXRlLnRvdWNoZWRGaWVsZHNcbiAgICAgICAgICAgICAgICA6IHt9LFxuICAgICAgICAgICAgZXJyb3JzOiBrZWVwU3RhdGVPcHRpb25zLmtlZXBFcnJvcnMgPyBfZm9ybVN0YXRlLmVycm9ycyA6IHt9LFxuICAgICAgICAgICAgaXNTdWJtaXRTdWNjZXNzZnVsOiBrZWVwU3RhdGVPcHRpb25zLmtlZXBJc1N1Ym1pdFN1Y2Nlc3NmdWxcbiAgICAgICAgICAgICAgICA/IF9mb3JtU3RhdGUuaXNTdWJtaXRTdWNjZXNzZnVsXG4gICAgICAgICAgICAgICAgOiBmYWxzZSxcbiAgICAgICAgICAgIGlzU3VibWl0dGluZzogZmFsc2UsXG4gICAgICAgICAgICBkZWZhdWx0VmFsdWVzOiBfZGVmYXVsdFZhbHVlcyxcbiAgICAgICAgfSk7XG4gICAgfTtcbiAgICBjb25zdCByZXNldCA9IChmb3JtVmFsdWVzLCBrZWVwU3RhdGVPcHRpb25zKSA9PiBfcmVzZXQoaXNGdW5jdGlvbihmb3JtVmFsdWVzKVxuICAgICAgICA/IGZvcm1WYWx1ZXMoX2Zvcm1WYWx1ZXMpXG4gICAgICAgIDogZm9ybVZhbHVlcywga2VlcFN0YXRlT3B0aW9ucyk7XG4gICAgY29uc3Qgc2V0Rm9jdXMgPSAobmFtZSwgb3B0aW9ucyA9IHt9KSA9PiB7XG4gICAgICAgIGNvbnN0IGZpZWxkID0gZ2V0KF9maWVsZHMsIG5hbWUpO1xuICAgICAgICBjb25zdCBmaWVsZFJlZmVyZW5jZSA9IGZpZWxkICYmIGZpZWxkLl9mO1xuICAgICAgICBpZiAoZmllbGRSZWZlcmVuY2UpIHtcbiAgICAgICAgICAgIGNvbnN0IGZpZWxkUmVmID0gZmllbGRSZWZlcmVuY2UucmVmc1xuICAgICAgICAgICAgICAgID8gZmllbGRSZWZlcmVuY2UucmVmc1swXVxuICAgICAgICAgICAgICAgIDogZmllbGRSZWZlcmVuY2UucmVmO1xuICAgICAgICAgICAgaWYgKGZpZWxkUmVmLmZvY3VzKSB7XG4gICAgICAgICAgICAgICAgZmllbGRSZWYuZm9jdXMoKTtcbiAgICAgICAgICAgICAgICBvcHRpb25zLnNob3VsZFNlbGVjdCAmJlxuICAgICAgICAgICAgICAgICAgICBpc0Z1bmN0aW9uKGZpZWxkUmVmLnNlbGVjdCkgJiZcbiAgICAgICAgICAgICAgICAgICAgZmllbGRSZWYuc2VsZWN0KCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuICAgIGNvbnN0IF9zZXRGb3JtU3RhdGUgPSAodXBkYXRlZEZvcm1TdGF0ZSkgPT4ge1xuICAgICAgICBfZm9ybVN0YXRlID0ge1xuICAgICAgICAgICAgLi4uX2Zvcm1TdGF0ZSxcbiAgICAgICAgICAgIC4uLnVwZGF0ZWRGb3JtU3RhdGUsXG4gICAgICAgIH07XG4gICAgfTtcbiAgICBjb25zdCBfcmVzZXREZWZhdWx0VmFsdWVzID0gKCkgPT4gaXNGdW5jdGlvbihfb3B0aW9ucy5kZWZhdWx0VmFsdWVzKSAmJlxuICAgICAgICBfb3B0aW9ucy5kZWZhdWx0VmFsdWVzKCkudGhlbigodmFsdWVzKSA9PiB7XG4gICAgICAgICAgICByZXNldCh2YWx1ZXMsIF9vcHRpb25zLnJlc2V0T3B0aW9ucyk7XG4gICAgICAgICAgICBfc3ViamVjdHMuc3RhdGUubmV4dCh7XG4gICAgICAgICAgICAgICAgaXNMb2FkaW5nOiBmYWxzZSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICBjb25zdCBtZXRob2RzID0ge1xuICAgICAgICBjb250cm9sOiB7XG4gICAgICAgICAgICByZWdpc3RlcixcbiAgICAgICAgICAgIHVucmVnaXN0ZXIsXG4gICAgICAgICAgICBnZXRGaWVsZFN0YXRlLFxuICAgICAgICAgICAgaGFuZGxlU3VibWl0LFxuICAgICAgICAgICAgc2V0RXJyb3IsXG4gICAgICAgICAgICBfc3Vic2NyaWJlLFxuICAgICAgICAgICAgX3J1blNjaGVtYSxcbiAgICAgICAgICAgIF9mb2N1c0Vycm9yLFxuICAgICAgICAgICAgX2dldFdhdGNoLFxuICAgICAgICAgICAgX2dldERpcnR5LFxuICAgICAgICAgICAgX3NldFZhbGlkLFxuICAgICAgICAgICAgX3NldEZpZWxkQXJyYXksXG4gICAgICAgICAgICBfc2V0RGlzYWJsZWRGaWVsZCxcbiAgICAgICAgICAgIF9zZXRFcnJvcnMsXG4gICAgICAgICAgICBfZ2V0RmllbGRBcnJheSxcbiAgICAgICAgICAgIF9yZXNldCxcbiAgICAgICAgICAgIF9yZXNldERlZmF1bHRWYWx1ZXMsXG4gICAgICAgICAgICBfcmVtb3ZlVW5tb3VudGVkLFxuICAgICAgICAgICAgX2Rpc2FibGVGb3JtLFxuICAgICAgICAgICAgX3N1YmplY3RzLFxuICAgICAgICAgICAgX3Byb3h5Rm9ybVN0YXRlLFxuICAgICAgICAgICAgZ2V0IF9maWVsZHMoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIF9maWVsZHM7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZ2V0IF9mb3JtVmFsdWVzKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBfZm9ybVZhbHVlcztcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBnZXQgX3N0YXRlKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBfc3RhdGU7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgc2V0IF9zdGF0ZSh2YWx1ZSkge1xuICAgICAgICAgICAgICAgIF9zdGF0ZSA9IHZhbHVlO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGdldCBfZGVmYXVsdFZhbHVlcygpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gX2RlZmF1bHRWYWx1ZXM7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZ2V0IF9uYW1lcygpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gX25hbWVzO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHNldCBfbmFtZXModmFsdWUpIHtcbiAgICAgICAgICAgICAgICBfbmFtZXMgPSB2YWx1ZTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBnZXQgX2Zvcm1TdGF0ZSgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gX2Zvcm1TdGF0ZTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBnZXQgX29wdGlvbnMoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIF9vcHRpb25zO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHNldCBfb3B0aW9ucyh2YWx1ZSkge1xuICAgICAgICAgICAgICAgIF9vcHRpb25zID0ge1xuICAgICAgICAgICAgICAgICAgICAuLi5fb3B0aW9ucyxcbiAgICAgICAgICAgICAgICAgICAgLi4udmFsdWUsXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICAgIHN1YnNjcmliZSxcbiAgICAgICAgdHJpZ2dlcixcbiAgICAgICAgcmVnaXN0ZXIsXG4gICAgICAgIGhhbmRsZVN1Ym1pdCxcbiAgICAgICAgd2F0Y2gsXG4gICAgICAgIHNldFZhbHVlLFxuICAgICAgICBnZXRWYWx1ZXMsXG4gICAgICAgIHJlc2V0LFxuICAgICAgICByZXNldEZpZWxkLFxuICAgICAgICBjbGVhckVycm9ycyxcbiAgICAgICAgdW5yZWdpc3RlcixcbiAgICAgICAgc2V0RXJyb3IsXG4gICAgICAgIHNldEZvY3VzLFxuICAgICAgICBnZXRGaWVsZFN0YXRlLFxuICAgIH07XG4gICAgcmV0dXJuIHtcbiAgICAgICAgLi4ubWV0aG9kcyxcbiAgICAgICAgZm9ybUNvbnRyb2w6IG1ldGhvZHMsXG4gICAgfTtcbn1cblxudmFyIGdlbmVyYXRlSWQgPSAoKSA9PiB7XG4gICAgaWYgKHR5cGVvZiBjcnlwdG8gIT09ICd1bmRlZmluZWQnICYmIGNyeXB0by5yYW5kb21VVUlEKSB7XG4gICAgICAgIHJldHVybiBjcnlwdG8ucmFuZG9tVVVJRCgpO1xuICAgIH1cbiAgICBjb25zdCBkID0gdHlwZW9mIHBlcmZvcm1hbmNlID09PSAndW5kZWZpbmVkJyA/IERhdGUubm93KCkgOiBwZXJmb3JtYW5jZS5ub3coKSAqIDEwMDA7XG4gICAgcmV0dXJuICd4eHh4eHh4eC14eHh4LTR4eHgteXh4eC14eHh4eHh4eHh4eHgnLnJlcGxhY2UoL1t4eV0vZywgKGMpID0+IHtcbiAgICAgICAgY29uc3QgciA9IChNYXRoLnJhbmRvbSgpICogMTYgKyBkKSAlIDE2IHwgMDtcbiAgICAgICAgcmV0dXJuIChjID09ICd4JyA/IHIgOiAociAmIDB4MykgfCAweDgpLnRvU3RyaW5nKDE2KTtcbiAgICB9KTtcbn07XG5cbnZhciBnZXRGb2N1c0ZpZWxkTmFtZSA9IChuYW1lLCBpbmRleCwgb3B0aW9ucyA9IHt9KSA9PiBvcHRpb25zLnNob3VsZEZvY3VzIHx8IGlzVW5kZWZpbmVkKG9wdGlvbnMuc2hvdWxkRm9jdXMpXG4gICAgPyBvcHRpb25zLmZvY3VzTmFtZSB8fFxuICAgICAgICBgJHtuYW1lfS4ke2lzVW5kZWZpbmVkKG9wdGlvbnMuZm9jdXNJbmRleCkgPyBpbmRleCA6IG9wdGlvbnMuZm9jdXNJbmRleH0uYFxuICAgIDogJyc7XG5cbnZhciBhcHBlbmRBdCA9IChkYXRhLCB2YWx1ZSkgPT4gW1xuICAgIC4uLmRhdGEsXG4gICAgLi4uY29udmVydFRvQXJyYXlQYXlsb2FkKHZhbHVlKSxcbl07XG5cbnZhciBmaWxsRW1wdHlBcnJheSA9ICh2YWx1ZSkgPT4gQXJyYXkuaXNBcnJheSh2YWx1ZSkgPyB2YWx1ZS5tYXAoKCkgPT4gdW5kZWZpbmVkKSA6IHVuZGVmaW5lZDtcblxuZnVuY3Rpb24gaW5zZXJ0KGRhdGEsIGluZGV4LCB2YWx1ZSkge1xuICAgIHJldHVybiBbXG4gICAgICAgIC4uLmRhdGEuc2xpY2UoMCwgaW5kZXgpLFxuICAgICAgICAuLi5jb252ZXJ0VG9BcnJheVBheWxvYWQodmFsdWUpLFxuICAgICAgICAuLi5kYXRhLnNsaWNlKGluZGV4KSxcbiAgICBdO1xufVxuXG52YXIgbW92ZUFycmF5QXQgPSAoZGF0YSwgZnJvbSwgdG8pID0+IHtcbiAgICBpZiAoIUFycmF5LmlzQXJyYXkoZGF0YSkpIHtcbiAgICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgICBpZiAoaXNVbmRlZmluZWQoZGF0YVt0b10pKSB7XG4gICAgICAgIGRhdGFbdG9dID0gdW5kZWZpbmVkO1xuICAgIH1cbiAgICBkYXRhLnNwbGljZSh0bywgMCwgZGF0YS5zcGxpY2UoZnJvbSwgMSlbMF0pO1xuICAgIHJldHVybiBkYXRhO1xufTtcblxudmFyIHByZXBlbmRBdCA9IChkYXRhLCB2YWx1ZSkgPT4gW1xuICAgIC4uLmNvbnZlcnRUb0FycmF5UGF5bG9hZCh2YWx1ZSksXG4gICAgLi4uY29udmVydFRvQXJyYXlQYXlsb2FkKGRhdGEpLFxuXTtcblxuZnVuY3Rpb24gcmVtb3ZlQXRJbmRleGVzKGRhdGEsIGluZGV4ZXMpIHtcbiAgICBsZXQgaSA9IDA7XG4gICAgY29uc3QgdGVtcCA9IFsuLi5kYXRhXTtcbiAgICBmb3IgKGNvbnN0IGluZGV4IG9mIGluZGV4ZXMpIHtcbiAgICAgICAgdGVtcC5zcGxpY2UoaW5kZXggLSBpLCAxKTtcbiAgICAgICAgaSsrO1xuICAgIH1cbiAgICByZXR1cm4gY29tcGFjdCh0ZW1wKS5sZW5ndGggPyB0ZW1wIDogW107XG59XG52YXIgcmVtb3ZlQXJyYXlBdCA9IChkYXRhLCBpbmRleCkgPT4gaXNVbmRlZmluZWQoaW5kZXgpXG4gICAgPyBbXVxuICAgIDogcmVtb3ZlQXRJbmRleGVzKGRhdGEsIGNvbnZlcnRUb0FycmF5UGF5bG9hZChpbmRleCkuc29ydCgoYSwgYikgPT4gYSAtIGIpKTtcblxudmFyIHN3YXBBcnJheUF0ID0gKGRhdGEsIGluZGV4QSwgaW5kZXhCKSA9PiB7XG4gICAgW2RhdGFbaW5kZXhBXSwgZGF0YVtpbmRleEJdXSA9IFtkYXRhW2luZGV4Ql0sIGRhdGFbaW5kZXhBXV07XG59O1xuXG52YXIgdXBkYXRlQXQgPSAoZmllbGRWYWx1ZXMsIGluZGV4LCB2YWx1ZSkgPT4ge1xuICAgIGZpZWxkVmFsdWVzW2luZGV4XSA9IHZhbHVlO1xuICAgIHJldHVybiBmaWVsZFZhbHVlcztcbn07XG5cbi8qKlxuICogQSBjdXN0b20gaG9vayB0aGF0IGV4cG9zZXMgY29udmVuaWVudCBtZXRob2RzIHRvIHBlcmZvcm0gb3BlcmF0aW9ucyB3aXRoIGEgbGlzdCBvZiBkeW5hbWljIGlucHV0cyB0aGF0IG5lZWQgdG8gYmUgYXBwZW5kZWQsIHVwZGF0ZWQsIHJlbW92ZWQgZXRjLiDigKIgW0RlbW9dKGh0dHBzOi8vY29kZXNhbmRib3guaW8vcy9yZWFjdC1ob29rLWZvcm0tdXNlZmllbGRhcnJheS1zc3Vnbikg4oCiIFtWaWRlb10oaHR0cHM6Ly95b3V0dS5iZS80TXJiZkdTRlkyQSlcbiAqXG4gKiBAcmVtYXJrc1xuICogW0FQSV0oaHR0cHM6Ly9yZWFjdC1ob29rLWZvcm0uY29tL2RvY3MvdXNlZmllbGRhcnJheSkg4oCiIFtEZW1vXShodHRwczovL2NvZGVzYW5kYm94LmlvL3MvcmVhY3QtaG9vay1mb3JtLXVzZWZpZWxkYXJyYXktc3N1Z24pXG4gKlxuICogQHBhcmFtIHByb3BzIC0gdXNlRmllbGRBcnJheSBwcm9wc1xuICpcbiAqIEByZXR1cm5zIG1ldGhvZHMgLSBmdW5jdGlvbnMgdG8gbWFuaXB1bGF0ZSB3aXRoIHRoZSBGaWVsZCBBcnJheXMgKGR5bmFtaWMgaW5wdXRzKSB7QGxpbmsgVXNlRmllbGRBcnJheVJldHVybn1cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHN4XG4gKiBmdW5jdGlvbiBBcHAoKSB7XG4gKiAgIGNvbnN0IHsgcmVnaXN0ZXIsIGNvbnRyb2wsIGhhbmRsZVN1Ym1pdCwgcmVzZXQsIHRyaWdnZXIsIHNldEVycm9yIH0gPSB1c2VGb3JtKHtcbiAqICAgICBkZWZhdWx0VmFsdWVzOiB7XG4gKiAgICAgICB0ZXN0OiBbXVxuICogICAgIH1cbiAqICAgfSk7XG4gKiAgIGNvbnN0IHsgZmllbGRzLCBhcHBlbmQgfSA9IHVzZUZpZWxkQXJyYXkoe1xuICogICAgIGNvbnRyb2wsXG4gKiAgICAgbmFtZTogXCJ0ZXN0XCJcbiAqICAgfSk7XG4gKlxuICogICByZXR1cm4gKFxuICogICAgIDxmb3JtIG9uU3VibWl0PXtoYW5kbGVTdWJtaXQoZGF0YSA9PiBjb25zb2xlLmxvZyhkYXRhKSl9PlxuICogICAgICAge2ZpZWxkcy5tYXAoKGl0ZW0sIGluZGV4KSA9PiAoXG4gKiAgICAgICAgICA8aW5wdXQga2V5PXtpdGVtLmlkfSB7Li4ucmVnaXN0ZXIoYHRlc3QuJHtpbmRleH0uZmlyc3ROYW1lYCl9ICAvPlxuICogICAgICAgKSl9XG4gKiAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBvbkNsaWNrPXsoKSA9PiBhcHBlbmQoeyBmaXJzdE5hbWU6IFwiYmlsbFwiIH0pfT5cbiAqICAgICAgICAgYXBwZW5kXG4gKiAgICAgICA8L2J1dHRvbj5cbiAqICAgICAgIDxpbnB1dCB0eXBlPVwic3VibWl0XCIgLz5cbiAqICAgICA8L2Zvcm0+XG4gKiAgICk7XG4gKiB9XG4gKiBgYGBcbiAqL1xuZnVuY3Rpb24gdXNlRmllbGRBcnJheShwcm9wcykge1xuICAgIGNvbnN0IG1ldGhvZHMgPSB1c2VGb3JtQ29udGV4dCgpO1xuICAgIGNvbnN0IHsgY29udHJvbCA9IG1ldGhvZHMuY29udHJvbCwgbmFtZSwga2V5TmFtZSA9ICdpZCcsIHNob3VsZFVucmVnaXN0ZXIsIHJ1bGVzLCB9ID0gcHJvcHM7XG4gICAgY29uc3QgW2ZpZWxkcywgc2V0RmllbGRzXSA9IFJlYWN0LnVzZVN0YXRlKGNvbnRyb2wuX2dldEZpZWxkQXJyYXkobmFtZSkpO1xuICAgIGNvbnN0IGlkcyA9IFJlYWN0LnVzZVJlZihjb250cm9sLl9nZXRGaWVsZEFycmF5KG5hbWUpLm1hcChnZW5lcmF0ZUlkKSk7XG4gICAgY29uc3QgX2FjdGlvbmVkID0gUmVhY3QudXNlUmVmKGZhbHNlKTtcbiAgICBjb250cm9sLl9uYW1lcy5hcnJheS5hZGQobmFtZSk7XG4gICAgUmVhY3QudXNlTWVtbygoKSA9PiBydWxlcyAmJlxuICAgICAgICBmaWVsZHMubGVuZ3RoID49IDAgJiZcbiAgICAgICAgY29udHJvbC5yZWdpc3RlcihuYW1lLCBydWxlcyksIFtjb250cm9sLCBuYW1lLCBmaWVsZHMubGVuZ3RoLCBydWxlc10pO1xuICAgIHVzZUlzb21vcnBoaWNMYXlvdXRFZmZlY3QoKCkgPT4gY29udHJvbC5fc3ViamVjdHMuYXJyYXkuc3Vic2NyaWJlKHtcbiAgICAgICAgbmV4dDogKHsgdmFsdWVzLCBuYW1lOiBmaWVsZEFycmF5TmFtZSwgfSkgPT4ge1xuICAgICAgICAgICAgaWYgKGZpZWxkQXJyYXlOYW1lID09PSBuYW1lIHx8ICFmaWVsZEFycmF5TmFtZSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGZpZWxkVmFsdWVzID0gZ2V0KHZhbHVlcywgbmFtZSk7XG4gICAgICAgICAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkoZmllbGRWYWx1ZXMpKSB7XG4gICAgICAgICAgICAgICAgICAgIHNldEZpZWxkcyhmaWVsZFZhbHVlcyk7XG4gICAgICAgICAgICAgICAgICAgIGlkcy5jdXJyZW50ID0gZmllbGRWYWx1ZXMubWFwKGdlbmVyYXRlSWQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICB9KS51bnN1YnNjcmliZSwgW2NvbnRyb2wsIG5hbWVdKTtcbiAgICBjb25zdCB1cGRhdGVWYWx1ZXMgPSBSZWFjdC51c2VDYWxsYmFjaygodXBkYXRlZEZpZWxkQXJyYXlWYWx1ZXMpID0+IHtcbiAgICAgICAgX2FjdGlvbmVkLmN1cnJlbnQgPSB0cnVlO1xuICAgICAgICBjb250cm9sLl9zZXRGaWVsZEFycmF5KG5hbWUsIHVwZGF0ZWRGaWVsZEFycmF5VmFsdWVzKTtcbiAgICB9LCBbY29udHJvbCwgbmFtZV0pO1xuICAgIGNvbnN0IGFwcGVuZCA9ICh2YWx1ZSwgb3B0aW9ucykgPT4ge1xuICAgICAgICBjb25zdCBhcHBlbmRWYWx1ZSA9IGNvbnZlcnRUb0FycmF5UGF5bG9hZChjbG9uZU9iamVjdCh2YWx1ZSkpO1xuICAgICAgICBjb25zdCB1cGRhdGVkRmllbGRBcnJheVZhbHVlcyA9IGFwcGVuZEF0KGNvbnRyb2wuX2dldEZpZWxkQXJyYXkobmFtZSksIGFwcGVuZFZhbHVlKTtcbiAgICAgICAgY29udHJvbC5fbmFtZXMuZm9jdXMgPSBnZXRGb2N1c0ZpZWxkTmFtZShuYW1lLCB1cGRhdGVkRmllbGRBcnJheVZhbHVlcy5sZW5ndGggLSAxLCBvcHRpb25zKTtcbiAgICAgICAgaWRzLmN1cnJlbnQgPSBhcHBlbmRBdChpZHMuY3VycmVudCwgYXBwZW5kVmFsdWUubWFwKGdlbmVyYXRlSWQpKTtcbiAgICAgICAgdXBkYXRlVmFsdWVzKHVwZGF0ZWRGaWVsZEFycmF5VmFsdWVzKTtcbiAgICAgICAgc2V0RmllbGRzKHVwZGF0ZWRGaWVsZEFycmF5VmFsdWVzKTtcbiAgICAgICAgY29udHJvbC5fc2V0RmllbGRBcnJheShuYW1lLCB1cGRhdGVkRmllbGRBcnJheVZhbHVlcywgYXBwZW5kQXQsIHtcbiAgICAgICAgICAgIGFyZ0E6IGZpbGxFbXB0eUFycmF5KHZhbHVlKSxcbiAgICAgICAgfSk7XG4gICAgfTtcbiAgICBjb25zdCBwcmVwZW5kID0gKHZhbHVlLCBvcHRpb25zKSA9PiB7XG4gICAgICAgIGNvbnN0IHByZXBlbmRWYWx1ZSA9IGNvbnZlcnRUb0FycmF5UGF5bG9hZChjbG9uZU9iamVjdCh2YWx1ZSkpO1xuICAgICAgICBjb25zdCB1cGRhdGVkRmllbGRBcnJheVZhbHVlcyA9IHByZXBlbmRBdChjb250cm9sLl9nZXRGaWVsZEFycmF5KG5hbWUpLCBwcmVwZW5kVmFsdWUpO1xuICAgICAgICBjb250cm9sLl9uYW1lcy5mb2N1cyA9IGdldEZvY3VzRmllbGROYW1lKG5hbWUsIDAsIG9wdGlvbnMpO1xuICAgICAgICBpZHMuY3VycmVudCA9IHByZXBlbmRBdChpZHMuY3VycmVudCwgcHJlcGVuZFZhbHVlLm1hcChnZW5lcmF0ZUlkKSk7XG4gICAgICAgIHVwZGF0ZVZhbHVlcyh1cGRhdGVkRmllbGRBcnJheVZhbHVlcyk7XG4gICAgICAgIHNldEZpZWxkcyh1cGRhdGVkRmllbGRBcnJheVZhbHVlcyk7XG4gICAgICAgIGNvbnRyb2wuX3NldEZpZWxkQXJyYXkobmFtZSwgdXBkYXRlZEZpZWxkQXJyYXlWYWx1ZXMsIHByZXBlbmRBdCwge1xuICAgICAgICAgICAgYXJnQTogZmlsbEVtcHR5QXJyYXkodmFsdWUpLFxuICAgICAgICB9KTtcbiAgICB9O1xuICAgIGNvbnN0IHJlbW92ZSA9IChpbmRleCkgPT4ge1xuICAgICAgICBjb25zdCB1cGRhdGVkRmllbGRBcnJheVZhbHVlcyA9IHJlbW92ZUFycmF5QXQoY29udHJvbC5fZ2V0RmllbGRBcnJheShuYW1lKSwgaW5kZXgpO1xuICAgICAgICBpZHMuY3VycmVudCA9IHJlbW92ZUFycmF5QXQoaWRzLmN1cnJlbnQsIGluZGV4KTtcbiAgICAgICAgdXBkYXRlVmFsdWVzKHVwZGF0ZWRGaWVsZEFycmF5VmFsdWVzKTtcbiAgICAgICAgc2V0RmllbGRzKHVwZGF0ZWRGaWVsZEFycmF5VmFsdWVzKTtcbiAgICAgICAgIUFycmF5LmlzQXJyYXkoZ2V0KGNvbnRyb2wuX2ZpZWxkcywgbmFtZSkpICYmXG4gICAgICAgICAgICBzZXQoY29udHJvbC5fZmllbGRzLCBuYW1lLCB1bmRlZmluZWQpO1xuICAgICAgICBjb250cm9sLl9zZXRGaWVsZEFycmF5KG5hbWUsIHVwZGF0ZWRGaWVsZEFycmF5VmFsdWVzLCByZW1vdmVBcnJheUF0LCB7XG4gICAgICAgICAgICBhcmdBOiBpbmRleCxcbiAgICAgICAgfSk7XG4gICAgfTtcbiAgICBjb25zdCBpbnNlcnQkMSA9IChpbmRleCwgdmFsdWUsIG9wdGlvbnMpID0+IHtcbiAgICAgICAgY29uc3QgaW5zZXJ0VmFsdWUgPSBjb252ZXJ0VG9BcnJheVBheWxvYWQoY2xvbmVPYmplY3QodmFsdWUpKTtcbiAgICAgICAgY29uc3QgdXBkYXRlZEZpZWxkQXJyYXlWYWx1ZXMgPSBpbnNlcnQoY29udHJvbC5fZ2V0RmllbGRBcnJheShuYW1lKSwgaW5kZXgsIGluc2VydFZhbHVlKTtcbiAgICAgICAgY29udHJvbC5fbmFtZXMuZm9jdXMgPSBnZXRGb2N1c0ZpZWxkTmFtZShuYW1lLCBpbmRleCwgb3B0aW9ucyk7XG4gICAgICAgIGlkcy5jdXJyZW50ID0gaW5zZXJ0KGlkcy5jdXJyZW50LCBpbmRleCwgaW5zZXJ0VmFsdWUubWFwKGdlbmVyYXRlSWQpKTtcbiAgICAgICAgdXBkYXRlVmFsdWVzKHVwZGF0ZWRGaWVsZEFycmF5VmFsdWVzKTtcbiAgICAgICAgc2V0RmllbGRzKHVwZGF0ZWRGaWVsZEFycmF5VmFsdWVzKTtcbiAgICAgICAgY29udHJvbC5fc2V0RmllbGRBcnJheShuYW1lLCB1cGRhdGVkRmllbGRBcnJheVZhbHVlcywgaW5zZXJ0LCB7XG4gICAgICAgICAgICBhcmdBOiBpbmRleCxcbiAgICAgICAgICAgIGFyZ0I6IGZpbGxFbXB0eUFycmF5KHZhbHVlKSxcbiAgICAgICAgfSk7XG4gICAgfTtcbiAgICBjb25zdCBzd2FwID0gKGluZGV4QSwgaW5kZXhCKSA9PiB7XG4gICAgICAgIGNvbnN0IHVwZGF0ZWRGaWVsZEFycmF5VmFsdWVzID0gY29udHJvbC5fZ2V0RmllbGRBcnJheShuYW1lKTtcbiAgICAgICAgc3dhcEFycmF5QXQodXBkYXRlZEZpZWxkQXJyYXlWYWx1ZXMsIGluZGV4QSwgaW5kZXhCKTtcbiAgICAgICAgc3dhcEFycmF5QXQoaWRzLmN1cnJlbnQsIGluZGV4QSwgaW5kZXhCKTtcbiAgICAgICAgdXBkYXRlVmFsdWVzKHVwZGF0ZWRGaWVsZEFycmF5VmFsdWVzKTtcbiAgICAgICAgc2V0RmllbGRzKHVwZGF0ZWRGaWVsZEFycmF5VmFsdWVzKTtcbiAgICAgICAgY29udHJvbC5fc2V0RmllbGRBcnJheShuYW1lLCB1cGRhdGVkRmllbGRBcnJheVZhbHVlcywgc3dhcEFycmF5QXQsIHtcbiAgICAgICAgICAgIGFyZ0E6IGluZGV4QSxcbiAgICAgICAgICAgIGFyZ0I6IGluZGV4QixcbiAgICAgICAgfSwgZmFsc2UpO1xuICAgIH07XG4gICAgY29uc3QgbW92ZSA9IChmcm9tLCB0bykgPT4ge1xuICAgICAgICBjb25zdCB1cGRhdGVkRmllbGRBcnJheVZhbHVlcyA9IGNvbnRyb2wuX2dldEZpZWxkQXJyYXkobmFtZSk7XG4gICAgICAgIG1vdmVBcnJheUF0KHVwZGF0ZWRGaWVsZEFycmF5VmFsdWVzLCBmcm9tLCB0byk7XG4gICAgICAgIG1vdmVBcnJheUF0KGlkcy5jdXJyZW50LCBmcm9tLCB0byk7XG4gICAgICAgIHVwZGF0ZVZhbHVlcyh1cGRhdGVkRmllbGRBcnJheVZhbHVlcyk7XG4gICAgICAgIHNldEZpZWxkcyh1cGRhdGVkRmllbGRBcnJheVZhbHVlcyk7XG4gICAgICAgIGNvbnRyb2wuX3NldEZpZWxkQXJyYXkobmFtZSwgdXBkYXRlZEZpZWxkQXJyYXlWYWx1ZXMsIG1vdmVBcnJheUF0LCB7XG4gICAgICAgICAgICBhcmdBOiBmcm9tLFxuICAgICAgICAgICAgYXJnQjogdG8sXG4gICAgICAgIH0sIGZhbHNlKTtcbiAgICB9O1xuICAgIGNvbnN0IHVwZGF0ZSA9IChpbmRleCwgdmFsdWUpID0+IHtcbiAgICAgICAgY29uc3QgdXBkYXRlVmFsdWUgPSBjbG9uZU9iamVjdCh2YWx1ZSk7XG4gICAgICAgIGNvbnN0IHVwZGF0ZWRGaWVsZEFycmF5VmFsdWVzID0gdXBkYXRlQXQoY29udHJvbC5fZ2V0RmllbGRBcnJheShuYW1lKSwgaW5kZXgsIHVwZGF0ZVZhbHVlKTtcbiAgICAgICAgaWRzLmN1cnJlbnQgPSBbLi4udXBkYXRlZEZpZWxkQXJyYXlWYWx1ZXNdLm1hcCgoaXRlbSwgaSkgPT4gIWl0ZW0gfHwgaSA9PT0gaW5kZXggPyBnZW5lcmF0ZUlkKCkgOiBpZHMuY3VycmVudFtpXSk7XG4gICAgICAgIHVwZGF0ZVZhbHVlcyh1cGRhdGVkRmllbGRBcnJheVZhbHVlcyk7XG4gICAgICAgIHNldEZpZWxkcyhbLi4udXBkYXRlZEZpZWxkQXJyYXlWYWx1ZXNdKTtcbiAgICAgICAgY29udHJvbC5fc2V0RmllbGRBcnJheShuYW1lLCB1cGRhdGVkRmllbGRBcnJheVZhbHVlcywgdXBkYXRlQXQsIHtcbiAgICAgICAgICAgIGFyZ0E6IGluZGV4LFxuICAgICAgICAgICAgYXJnQjogdXBkYXRlVmFsdWUsXG4gICAgICAgIH0sIHRydWUsIGZhbHNlKTtcbiAgICB9O1xuICAgIGNvbnN0IHJlcGxhY2UgPSAodmFsdWUpID0+IHtcbiAgICAgICAgY29uc3QgdXBkYXRlZEZpZWxkQXJyYXlWYWx1ZXMgPSBjb252ZXJ0VG9BcnJheVBheWxvYWQoY2xvbmVPYmplY3QodmFsdWUpKTtcbiAgICAgICAgaWRzLmN1cnJlbnQgPSB1cGRhdGVkRmllbGRBcnJheVZhbHVlcy5tYXAoZ2VuZXJhdGVJZCk7XG4gICAgICAgIHVwZGF0ZVZhbHVlcyhbLi4udXBkYXRlZEZpZWxkQXJyYXlWYWx1ZXNdKTtcbiAgICAgICAgc2V0RmllbGRzKFsuLi51cGRhdGVkRmllbGRBcnJheVZhbHVlc10pO1xuICAgICAgICBjb250cm9sLl9zZXRGaWVsZEFycmF5KG5hbWUsIFsuLi51cGRhdGVkRmllbGRBcnJheVZhbHVlc10sIChkYXRhKSA9PiBkYXRhLCB7fSwgdHJ1ZSwgZmFsc2UpO1xuICAgIH07XG4gICAgUmVhY3QudXNlRWZmZWN0KCgpID0+IHtcbiAgICAgICAgY29udHJvbC5fc3RhdGUuYWN0aW9uID0gZmFsc2U7XG4gICAgICAgIGlzV2F0Y2hlZChuYW1lLCBjb250cm9sLl9uYW1lcykgJiZcbiAgICAgICAgICAgIGNvbnRyb2wuX3N1YmplY3RzLnN0YXRlLm5leHQoe1xuICAgICAgICAgICAgICAgIC4uLmNvbnRyb2wuX2Zvcm1TdGF0ZSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICBpZiAoX2FjdGlvbmVkLmN1cnJlbnQgJiZcbiAgICAgICAgICAgICghZ2V0VmFsaWRhdGlvbk1vZGVzKGNvbnRyb2wuX29wdGlvbnMubW9kZSkuaXNPblN1Ym1pdCB8fFxuICAgICAgICAgICAgICAgIGNvbnRyb2wuX2Zvcm1TdGF0ZS5pc1N1Ym1pdHRlZCkgJiZcbiAgICAgICAgICAgICFnZXRWYWxpZGF0aW9uTW9kZXMoY29udHJvbC5fb3B0aW9ucy5yZVZhbGlkYXRlTW9kZSkuaXNPblN1Ym1pdCkge1xuICAgICAgICAgICAgaWYgKGNvbnRyb2wuX29wdGlvbnMucmVzb2x2ZXIpIHtcbiAgICAgICAgICAgICAgICBjb250cm9sLl9ydW5TY2hlbWEoW25hbWVdKS50aGVuKChyZXN1bHQpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZXJyb3IgPSBnZXQocmVzdWx0LmVycm9ycywgbmFtZSk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGV4aXN0aW5nRXJyb3IgPSBnZXQoY29udHJvbC5fZm9ybVN0YXRlLmVycm9ycywgbmFtZSk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChleGlzdGluZ0Vycm9yXG4gICAgICAgICAgICAgICAgICAgICAgICA/ICghZXJyb3IgJiYgZXhpc3RpbmdFcnJvci50eXBlKSB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChlcnJvciAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZXhpc3RpbmdFcnJvci50eXBlICE9PSBlcnJvci50eXBlIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGlzdGluZ0Vycm9yLm1lc3NhZ2UgIT09IGVycm9yLm1lc3NhZ2UpKVxuICAgICAgICAgICAgICAgICAgICAgICAgOiBlcnJvciAmJiBlcnJvci50eXBlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlcnJvclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gc2V0KGNvbnRyb2wuX2Zvcm1TdGF0ZS5lcnJvcnMsIG5hbWUsIGVycm9yKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDogdW5zZXQoY29udHJvbC5fZm9ybVN0YXRlLmVycm9ycywgbmFtZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb250cm9sLl9zdWJqZWN0cy5zdGF0ZS5uZXh0KHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvcnM6IGNvbnRyb2wuX2Zvcm1TdGF0ZS5lcnJvcnMsXG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZmllbGQgPSBnZXQoY29udHJvbC5fZmllbGRzLCBuYW1lKTtcbiAgICAgICAgICAgICAgICBpZiAoZmllbGQgJiZcbiAgICAgICAgICAgICAgICAgICAgZmllbGQuX2YgJiZcbiAgICAgICAgICAgICAgICAgICAgIShnZXRWYWxpZGF0aW9uTW9kZXMoY29udHJvbC5fb3B0aW9ucy5yZVZhbGlkYXRlTW9kZSkuaXNPblN1Ym1pdCAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgZ2V0VmFsaWRhdGlvbk1vZGVzKGNvbnRyb2wuX29wdGlvbnMubW9kZSkuaXNPblN1Ym1pdCkpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsaWRhdGVGaWVsZChmaWVsZCwgY29udHJvbC5fbmFtZXMuZGlzYWJsZWQsIGNvbnRyb2wuX2Zvcm1WYWx1ZXMsIGNvbnRyb2wuX29wdGlvbnMuY3JpdGVyaWFNb2RlID09PSBWQUxJREFUSU9OX01PREUuYWxsLCBjb250cm9sLl9vcHRpb25zLnNob3VsZFVzZU5hdGl2ZVZhbGlkYXRpb24sIHRydWUpLnRoZW4oKGVycm9yKSA9PiAhaXNFbXB0eU9iamVjdChlcnJvcikgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2wuX3N1YmplY3RzLnN0YXRlLm5leHQoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yczogdXBkYXRlRmllbGRBcnJheVJvb3RFcnJvcihjb250cm9sLl9mb3JtU3RhdGUuZXJyb3JzLCBlcnJvciwgbmFtZSksXG4gICAgICAgICAgICAgICAgICAgICAgICB9KSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGNvbnRyb2wuX3N1YmplY3RzLnN0YXRlLm5leHQoe1xuICAgICAgICAgICAgbmFtZSxcbiAgICAgICAgICAgIHZhbHVlczogY2xvbmVPYmplY3QoY29udHJvbC5fZm9ybVZhbHVlcyksXG4gICAgICAgIH0pO1xuICAgICAgICBjb250cm9sLl9uYW1lcy5mb2N1cyAmJlxuICAgICAgICAgICAgaXRlcmF0ZUZpZWxkc0J5QWN0aW9uKGNvbnRyb2wuX2ZpZWxkcywgKHJlZiwga2V5KSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKGNvbnRyb2wuX25hbWVzLmZvY3VzICYmXG4gICAgICAgICAgICAgICAgICAgIGtleS5zdGFydHNXaXRoKGNvbnRyb2wuX25hbWVzLmZvY3VzKSAmJlxuICAgICAgICAgICAgICAgICAgICByZWYuZm9jdXMpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVmLmZvY3VzKCk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgY29udHJvbC5fbmFtZXMuZm9jdXMgPSAnJztcbiAgICAgICAgY29udHJvbC5fc2V0VmFsaWQoKTtcbiAgICAgICAgX2FjdGlvbmVkLmN1cnJlbnQgPSBmYWxzZTtcbiAgICB9LCBbZmllbGRzLCBuYW1lLCBjb250cm9sXSk7XG4gICAgUmVhY3QudXNlRWZmZWN0KCgpID0+IHtcbiAgICAgICAgIWdldChjb250cm9sLl9mb3JtVmFsdWVzLCBuYW1lKSAmJiBjb250cm9sLl9zZXRGaWVsZEFycmF5KG5hbWUpO1xuICAgICAgICByZXR1cm4gKCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgdXBkYXRlTW91bnRlZCA9IChuYW1lLCB2YWx1ZSkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IGZpZWxkID0gZ2V0KGNvbnRyb2wuX2ZpZWxkcywgbmFtZSk7XG4gICAgICAgICAgICAgICAgaWYgKGZpZWxkICYmIGZpZWxkLl9mKSB7XG4gICAgICAgICAgICAgICAgICAgIGZpZWxkLl9mLm1vdW50ID0gdmFsdWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGNvbnRyb2wuX29wdGlvbnMuc2hvdWxkVW5yZWdpc3RlciB8fCBzaG91bGRVbnJlZ2lzdGVyXG4gICAgICAgICAgICAgICAgPyBjb250cm9sLnVucmVnaXN0ZXIobmFtZSlcbiAgICAgICAgICAgICAgICA6IHVwZGF0ZU1vdW50ZWQobmFtZSwgZmFsc2UpO1xuICAgICAgICB9O1xuICAgIH0sIFtuYW1lLCBjb250cm9sLCBrZXlOYW1lLCBzaG91bGRVbnJlZ2lzdGVyXSk7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgc3dhcDogUmVhY3QudXNlQ2FsbGJhY2soc3dhcCwgW3VwZGF0ZVZhbHVlcywgbmFtZSwgY29udHJvbF0pLFxuICAgICAgICBtb3ZlOiBSZWFjdC51c2VDYWxsYmFjayhtb3ZlLCBbdXBkYXRlVmFsdWVzLCBuYW1lLCBjb250cm9sXSksXG4gICAgICAgIHByZXBlbmQ6IFJlYWN0LnVzZUNhbGxiYWNrKHByZXBlbmQsIFt1cGRhdGVWYWx1ZXMsIG5hbWUsIGNvbnRyb2xdKSxcbiAgICAgICAgYXBwZW5kOiBSZWFjdC51c2VDYWxsYmFjayhhcHBlbmQsIFt1cGRhdGVWYWx1ZXMsIG5hbWUsIGNvbnRyb2xdKSxcbiAgICAgICAgcmVtb3ZlOiBSZWFjdC51c2VDYWxsYmFjayhyZW1vdmUsIFt1cGRhdGVWYWx1ZXMsIG5hbWUsIGNvbnRyb2xdKSxcbiAgICAgICAgaW5zZXJ0OiBSZWFjdC51c2VDYWxsYmFjayhpbnNlcnQkMSwgW3VwZGF0ZVZhbHVlcywgbmFtZSwgY29udHJvbF0pLFxuICAgICAgICB1cGRhdGU6IFJlYWN0LnVzZUNhbGxiYWNrKHVwZGF0ZSwgW3VwZGF0ZVZhbHVlcywgbmFtZSwgY29udHJvbF0pLFxuICAgICAgICByZXBsYWNlOiBSZWFjdC51c2VDYWxsYmFjayhyZXBsYWNlLCBbdXBkYXRlVmFsdWVzLCBuYW1lLCBjb250cm9sXSksXG4gICAgICAgIGZpZWxkczogUmVhY3QudXNlTWVtbygoKSA9PiBmaWVsZHMubWFwKChmaWVsZCwgaW5kZXgpID0+ICh7XG4gICAgICAgICAgICAuLi5maWVsZCxcbiAgICAgICAgICAgIFtrZXlOYW1lXTogaWRzLmN1cnJlbnRbaW5kZXhdIHx8IGdlbmVyYXRlSWQoKSxcbiAgICAgICAgfSkpLCBbZmllbGRzLCBrZXlOYW1lXSksXG4gICAgfTtcbn1cblxuLyoqXG4gKiBDdXN0b20gaG9vayB0byBtYW5hZ2UgdGhlIGVudGlyZSBmb3JtLlxuICpcbiAqIEByZW1hcmtzXG4gKiBbQVBJXShodHRwczovL3JlYWN0LWhvb2stZm9ybS5jb20vZG9jcy91c2Vmb3JtKSDigKIgW0RlbW9dKGh0dHBzOi8vY29kZXNhbmRib3guaW8vcy9yZWFjdC1ob29rLWZvcm0tZ2V0LXN0YXJ0ZWQtdHMtNWtzbW0pIOKAoiBbVmlkZW9dKGh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9UmtYdjRBWFhDXzQpXG4gKlxuICogQHBhcmFtIHByb3BzIC0gZm9ybSBjb25maWd1cmF0aW9uIGFuZCB2YWxpZGF0aW9uIHBhcmFtZXRlcnMuXG4gKlxuICogQHJldHVybnMgbWV0aG9kcyAtIGluZGl2aWR1YWwgZnVuY3Rpb25zIHRvIG1hbmFnZSB0aGUgZm9ybSBzdGF0ZS4ge0BsaW5rIFVzZUZvcm1SZXR1cm59XG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHRzeFxuICogZnVuY3Rpb24gQXBwKCkge1xuICogICBjb25zdCB7IHJlZ2lzdGVyLCBoYW5kbGVTdWJtaXQsIHdhdGNoLCBmb3JtU3RhdGU6IHsgZXJyb3JzIH0gfSA9IHVzZUZvcm0oKTtcbiAqICAgY29uc3Qgb25TdWJtaXQgPSBkYXRhID0+IGNvbnNvbGUubG9nKGRhdGEpO1xuICpcbiAqICAgY29uc29sZS5sb2cod2F0Y2goXCJleGFtcGxlXCIpKTtcbiAqXG4gKiAgIHJldHVybiAoXG4gKiAgICAgPGZvcm0gb25TdWJtaXQ9e2hhbmRsZVN1Ym1pdChvblN1Ym1pdCl9PlxuICogICAgICAgPGlucHV0IGRlZmF1bHRWYWx1ZT1cInRlc3RcIiB7Li4ucmVnaXN0ZXIoXCJleGFtcGxlXCIpfSAvPlxuICogICAgICAgPGlucHV0IHsuLi5yZWdpc3RlcihcImV4YW1wbGVSZXF1aXJlZFwiLCB7IHJlcXVpcmVkOiB0cnVlIH0pfSAvPlxuICogICAgICAge2Vycm9ycy5leGFtcGxlUmVxdWlyZWQgJiYgPHNwYW4+VGhpcyBmaWVsZCBpcyByZXF1aXJlZDwvc3Bhbj59XG4gKiAgICAgICA8YnV0dG9uPlN1Ym1pdDwvYnV0dG9uPlxuICogICAgIDwvZm9ybT5cbiAqICAgKTtcbiAqIH1cbiAqIGBgYFxuICovXG5mdW5jdGlvbiB1c2VGb3JtKHByb3BzID0ge30pIHtcbiAgICBjb25zdCBfZm9ybUNvbnRyb2wgPSBSZWFjdC51c2VSZWYodW5kZWZpbmVkKTtcbiAgICBjb25zdCBfdmFsdWVzID0gUmVhY3QudXNlUmVmKHVuZGVmaW5lZCk7XG4gICAgY29uc3QgW2Zvcm1TdGF0ZSwgdXBkYXRlRm9ybVN0YXRlXSA9IFJlYWN0LnVzZVN0YXRlKHtcbiAgICAgICAgaXNEaXJ0eTogZmFsc2UsXG4gICAgICAgIGlzVmFsaWRhdGluZzogZmFsc2UsXG4gICAgICAgIGlzTG9hZGluZzogaXNGdW5jdGlvbihwcm9wcy5kZWZhdWx0VmFsdWVzKSxcbiAgICAgICAgaXNTdWJtaXR0ZWQ6IGZhbHNlLFxuICAgICAgICBpc1N1Ym1pdHRpbmc6IGZhbHNlLFxuICAgICAgICBpc1N1Ym1pdFN1Y2Nlc3NmdWw6IGZhbHNlLFxuICAgICAgICBpc1ZhbGlkOiBmYWxzZSxcbiAgICAgICAgc3VibWl0Q291bnQ6IDAsXG4gICAgICAgIGRpcnR5RmllbGRzOiB7fSxcbiAgICAgICAgdG91Y2hlZEZpZWxkczoge30sXG4gICAgICAgIHZhbGlkYXRpbmdGaWVsZHM6IHt9LFxuICAgICAgICBlcnJvcnM6IHByb3BzLmVycm9ycyB8fCB7fSxcbiAgICAgICAgZGlzYWJsZWQ6IHByb3BzLmRpc2FibGVkIHx8IGZhbHNlLFxuICAgICAgICBpc1JlYWR5OiBmYWxzZSxcbiAgICAgICAgZGVmYXVsdFZhbHVlczogaXNGdW5jdGlvbihwcm9wcy5kZWZhdWx0VmFsdWVzKVxuICAgICAgICAgICAgPyB1bmRlZmluZWRcbiAgICAgICAgICAgIDogcHJvcHMuZGVmYXVsdFZhbHVlcyxcbiAgICB9KTtcbiAgICBpZiAoIV9mb3JtQ29udHJvbC5jdXJyZW50KSB7XG4gICAgICAgIGlmIChwcm9wcy5mb3JtQ29udHJvbCkge1xuICAgICAgICAgICAgX2Zvcm1Db250cm9sLmN1cnJlbnQgPSB7XG4gICAgICAgICAgICAgICAgLi4ucHJvcHMuZm9ybUNvbnRyb2wsXG4gICAgICAgICAgICAgICAgZm9ybVN0YXRlLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGlmIChwcm9wcy5kZWZhdWx0VmFsdWVzICYmICFpc0Z1bmN0aW9uKHByb3BzLmRlZmF1bHRWYWx1ZXMpKSB7XG4gICAgICAgICAgICAgICAgcHJvcHMuZm9ybUNvbnRyb2wucmVzZXQocHJvcHMuZGVmYXVsdFZhbHVlcywgcHJvcHMucmVzZXRPcHRpb25zKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGNvbnN0IHsgZm9ybUNvbnRyb2wsIC4uLnJlc3QgfSA9IGNyZWF0ZUZvcm1Db250cm9sKHByb3BzKTtcbiAgICAgICAgICAgIF9mb3JtQ29udHJvbC5jdXJyZW50ID0ge1xuICAgICAgICAgICAgICAgIC4uLnJlc3QsXG4gICAgICAgICAgICAgICAgZm9ybVN0YXRlLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBjb25zdCBjb250cm9sID0gX2Zvcm1Db250cm9sLmN1cnJlbnQuY29udHJvbDtcbiAgICBjb250cm9sLl9vcHRpb25zID0gcHJvcHM7XG4gICAgdXNlSXNvbW9ycGhpY0xheW91dEVmZmVjdCgoKSA9PiB7XG4gICAgICAgIGNvbnN0IHN1YiA9IGNvbnRyb2wuX3N1YnNjcmliZSh7XG4gICAgICAgICAgICBmb3JtU3RhdGU6IGNvbnRyb2wuX3Byb3h5Rm9ybVN0YXRlLFxuICAgICAgICAgICAgY2FsbGJhY2s6ICgpID0+IHVwZGF0ZUZvcm1TdGF0ZSh7IC4uLmNvbnRyb2wuX2Zvcm1TdGF0ZSB9KSxcbiAgICAgICAgICAgIHJlUmVuZGVyUm9vdDogdHJ1ZSxcbiAgICAgICAgfSk7XG4gICAgICAgIHVwZGF0ZUZvcm1TdGF0ZSgoZGF0YSkgPT4gKHtcbiAgICAgICAgICAgIC4uLmRhdGEsXG4gICAgICAgICAgICBpc1JlYWR5OiB0cnVlLFxuICAgICAgICB9KSk7XG4gICAgICAgIGNvbnRyb2wuX2Zvcm1TdGF0ZS5pc1JlYWR5ID0gdHJ1ZTtcbiAgICAgICAgcmV0dXJuIHN1YjtcbiAgICB9LCBbY29udHJvbF0pO1xuICAgIFJlYWN0LnVzZUVmZmVjdCgoKSA9PiBjb250cm9sLl9kaXNhYmxlRm9ybShwcm9wcy5kaXNhYmxlZCksIFtjb250cm9sLCBwcm9wcy5kaXNhYmxlZF0pO1xuICAgIFJlYWN0LnVzZUVmZmVjdCgoKSA9PiB7XG4gICAgICAgIGlmIChwcm9wcy5tb2RlKSB7XG4gICAgICAgICAgICBjb250cm9sLl9vcHRpb25zLm1vZGUgPSBwcm9wcy5tb2RlO1xuICAgICAgICB9XG4gICAgICAgIGlmIChwcm9wcy5yZVZhbGlkYXRlTW9kZSkge1xuICAgICAgICAgICAgY29udHJvbC5fb3B0aW9ucy5yZVZhbGlkYXRlTW9kZSA9IHByb3BzLnJlVmFsaWRhdGVNb2RlO1xuICAgICAgICB9XG4gICAgfSwgW2NvbnRyb2wsIHByb3BzLm1vZGUsIHByb3BzLnJlVmFsaWRhdGVNb2RlXSk7XG4gICAgUmVhY3QudXNlRWZmZWN0KCgpID0+IHtcbiAgICAgICAgaWYgKHByb3BzLmVycm9ycykge1xuICAgICAgICAgICAgY29udHJvbC5fc2V0RXJyb3JzKHByb3BzLmVycm9ycyk7XG4gICAgICAgICAgICBjb250cm9sLl9mb2N1c0Vycm9yKCk7XG4gICAgICAgIH1cbiAgICB9LCBbY29udHJvbCwgcHJvcHMuZXJyb3JzXSk7XG4gICAgUmVhY3QudXNlRWZmZWN0KCgpID0+IHtcbiAgICAgICAgcHJvcHMuc2hvdWxkVW5yZWdpc3RlciAmJlxuICAgICAgICAgICAgY29udHJvbC5fc3ViamVjdHMuc3RhdGUubmV4dCh7XG4gICAgICAgICAgICAgICAgdmFsdWVzOiBjb250cm9sLl9nZXRXYXRjaCgpLFxuICAgICAgICAgICAgfSk7XG4gICAgfSwgW2NvbnRyb2wsIHByb3BzLnNob3VsZFVucmVnaXN0ZXJdKTtcbiAgICBSZWFjdC51c2VFZmZlY3QoKCkgPT4ge1xuICAgICAgICBpZiAoY29udHJvbC5fcHJveHlGb3JtU3RhdGUuaXNEaXJ0eSkge1xuICAgICAgICAgICAgY29uc3QgaXNEaXJ0eSA9IGNvbnRyb2wuX2dldERpcnR5KCk7XG4gICAgICAgICAgICBpZiAoaXNEaXJ0eSAhPT0gZm9ybVN0YXRlLmlzRGlydHkpIHtcbiAgICAgICAgICAgICAgICBjb250cm9sLl9zdWJqZWN0cy5zdGF0ZS5uZXh0KHtcbiAgICAgICAgICAgICAgICAgICAgaXNEaXJ0eSxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0sIFtjb250cm9sLCBmb3JtU3RhdGUuaXNEaXJ0eV0pO1xuICAgIFJlYWN0LnVzZUVmZmVjdCgoKSA9PiB7XG4gICAgICAgIHZhciBfYTtcbiAgICAgICAgaWYgKHByb3BzLnZhbHVlcyAmJiAhZGVlcEVxdWFsKHByb3BzLnZhbHVlcywgX3ZhbHVlcy5jdXJyZW50KSkge1xuICAgICAgICAgICAgY29udHJvbC5fcmVzZXQocHJvcHMudmFsdWVzLCB7XG4gICAgICAgICAgICAgICAga2VlcEZpZWxkc1JlZjogdHJ1ZSxcbiAgICAgICAgICAgICAgICAuLi5jb250cm9sLl9vcHRpb25zLnJlc2V0T3B0aW9ucyxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgaWYgKCEoKF9hID0gY29udHJvbC5fb3B0aW9ucy5yZXNldE9wdGlvbnMpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5rZWVwSXNWYWxpZCkpIHtcbiAgICAgICAgICAgICAgICBjb250cm9sLl9zZXRWYWxpZCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgX3ZhbHVlcy5jdXJyZW50ID0gcHJvcHMudmFsdWVzO1xuICAgICAgICAgICAgdXBkYXRlRm9ybVN0YXRlKChzdGF0ZSkgPT4gKHsgLi4uc3RhdGUgfSkpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgY29udHJvbC5fcmVzZXREZWZhdWx0VmFsdWVzKCk7XG4gICAgICAgIH1cbiAgICB9LCBbY29udHJvbCwgcHJvcHMudmFsdWVzXSk7XG4gICAgUmVhY3QudXNlRWZmZWN0KCgpID0+IHtcbiAgICAgICAgaWYgKCFjb250cm9sLl9zdGF0ZS5tb3VudCkge1xuICAgICAgICAgICAgY29udHJvbC5fc2V0VmFsaWQoKTtcbiAgICAgICAgICAgIGNvbnRyb2wuX3N0YXRlLm1vdW50ID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoY29udHJvbC5fc3RhdGUud2F0Y2gpIHtcbiAgICAgICAgICAgIGNvbnRyb2wuX3N0YXRlLndhdGNoID0gZmFsc2U7XG4gICAgICAgICAgICBjb250cm9sLl9zdWJqZWN0cy5zdGF0ZS5uZXh0KHsgLi4uY29udHJvbC5fZm9ybVN0YXRlIH0pO1xuICAgICAgICB9XG4gICAgICAgIGNvbnRyb2wuX3JlbW92ZVVubW91bnRlZCgpO1xuICAgIH0pO1xuICAgIF9mb3JtQ29udHJvbC5jdXJyZW50LmZvcm1TdGF0ZSA9IGdldFByb3h5Rm9ybVN0YXRlKGZvcm1TdGF0ZSwgY29udHJvbCk7XG4gICAgcmV0dXJuIF9mb3JtQ29udHJvbC5jdXJyZW50O1xufVxuXG4vKipcbiAqIFdhdGNoIGNvbXBvbmVudCB0aGF0IHN1YnNjcmliZXMgdG8gZm9ybSBmaWVsZCBjaGFuZ2VzIGFuZCByZS1yZW5kZXJzIHdoZW4gd2F0Y2hlZCBmaWVsZHMgdXBkYXRlLlxuICpcbiAqIEBwYXJhbSBjb250cm9sIC0gVGhlIGZvcm0gY29udHJvbCBvYmplY3QgZnJvbSB1c2VGb3JtXG4gKiBAcGFyYW0gbmFtZXMgLSBBcnJheSBvZiBmaWVsZCBuYW1lcyB0byB3YXRjaCBmb3IgY2hhbmdlc1xuICogQHBhcmFtIHJlbmRlciAtIFRoZSBmdW5jdGlvbiB0aGF0IHJlY2VpdmVzIHdhdGNoZWQgdmFsdWVzIGFuZCByZXR1cm5zIFJlYWN0Tm9kZVxuICogQHJldHVybnMgVGhlIHJlc3VsdCBvZiBjYWxsaW5nIHJlbmRlciBmdW5jdGlvbiB3aXRoIHdhdGNoZWQgdmFsdWVzXG4gKlxuICogQGV4YW1wbGVcbiAqIFRoZSBgV2F0Y2hgIGNvbXBvbmVudCBvbmx5IHJlLXJlbmRlciB3aGVuIHRoZSB2YWx1ZXMgb2YgYGZvb2AsIGBiYXJgLCBhbmQgYGJhei5xdXhgIGNoYW5nZS5cbiAqIFRoZSB0eXBlcyBvZiBgZm9vYCwgYGJhcmAsIGFuZCBgYmF6LnF1eGAgYXJlIHByZWNpc2VseSBpbmZlcnJlZC5cbiAqXG4gKiBgYGB0c3hcbiAqIGNvbnN0IHsgY29udHJvbCB9ID0gdXNlRm9ybSgpO1xuICpcbiAqIDxXYXRjaFxuICogICBjb250cm9sPXtjb250cm9sfVxuICogICBuYW1lcz17Wydmb28nLCAnYmFyJywgJ2Jhei5xdXgnXX1cbiAqICAgcmVuZGVyPXsoW2ZvbywgYmFyLCBiYXpfcXV4XSkgPT4gPGRpdj57Zm9vfXtiYXJ9e2Jhel9xdXh9PC9kaXY+fVxuICogLz5cbiAqIGBgYFxuICovXG5jb25zdCBXYXRjaCA9ICh7IGNvbnRyb2wsIG5hbWVzLCByZW5kZXIsIH0pID0+IHJlbmRlcih1c2VXYXRjaCh7IGNvbnRyb2wsIG5hbWU6IG5hbWVzIH0pKTtcblxuZXhwb3J0IHsgQ29udHJvbGxlciwgRm9ybSwgRm9ybVByb3ZpZGVyLCBXYXRjaCwgYXBwZW5kRXJyb3JzLCBjcmVhdGVGb3JtQ29udHJvbCwgZ2V0LCBzZXQsIHVzZUNvbnRyb2xsZXIsIHVzZUZpZWxkQXJyYXksIHVzZUZvcm0sIHVzZUZvcm1Db250ZXh0LCB1c2VGb3JtU3RhdGUsIHVzZVdhdGNoIH07XG4vLyMgc291cmNlTWFwcGluZ1VSTD1pbmRleC5lc20ubWpzLm1hcFxuIl0sIm5hbWVzIjpbXSwiaWdub3JlTGlzdCI6W10sInNvdXJjZVJvb3QiOiIifQ==