import { getAccessCode, getTokenFromAccessCode, registerAndGetAccessCode } from "/_nuxt/lib/auth/services/auth.ts"; import { ensureError, SafeLocalStorage } from "/_nuxt/@fs/D:/speckle-server/packages/shared/dist/esm/index.js"; import { CookieKeys, LocalStorageKeys } from "/_nuxt/lib/common/helpers/constants.ts"; import { useSynchronizedCookie } from "/_nuxt/lib/common/composables/reactiveCookie.ts"; import { loginRoute, useNavigateToHome, useNavigateToLogin } from "/_nuxt/lib/common/helpers/route.ts"; import { useApolloClient } from "/_nuxt/node_modules/@vue/apollo-composable/dist/index.mjs?v=e4f18c29"; import { speckleWebAppId } from "/_nuxt/lib/auth/helpers/strategies.ts"; import { randomString } from "/_nuxt/lib/common/helpers/random.ts"; import { ToastNotificationType, useGlobalToast } from "/_nuxt/lib/common/composables/toast.ts"; import { useDeferredMixpanel } from "/_nuxt/lib/core/composables/mp.ts"; import { activeUserQuery, useResolveUserDistinctId, useWaitForActiveUser } from "/_nuxt/lib/auth/composables/activeUser.ts"; import { usePostAuthRedirect } from "/_nuxt/lib/auth/composables/postAuthRedirect.ts"; import { useScopedState } from "/_nuxt/lib/common/composables/scopedState.ts"; import { AuthFailedError } from "/_nuxt/lib/auth/errors/errors.ts"; import { useAppErrorState } from "/_nuxt/lib/core/composables/error.ts"; import { getCurrentInstance, onUnmounted, computed, watch, ref, onMounted } from "/_nuxt/node_modules/vue/dist/vue.runtime.esm-bundler.js?v=e4f18c29"; import { useSafeLogger } from "/_nuxt/composables/logging.ts"; import { modifyObjectField, ROOT_QUERY, convertThrowIntoFetchResult } from "/_nuxt/utils/globals.ts"; import { useRequestEvent } from "/_nuxt/node_modules/nuxt/dist/app/composables/ssr.js?v=e4f18c29"; import { useApiOrigin } from "/_nuxt/composables/env.ts"; import { useRoute, navigateTo } from "/_nuxt/node_modules/nuxt/dist/app/composables/router.js?v=e4f18c29"; import { useState } from "/_nuxt/node_modules/nuxt/dist/app/composables/state.js?v=e4f18c29"; const useOnAuthStateChangeState = () => useScopedState("useOnAuthStateChange", () => ({ cbs: [] })); const useJustLoggedOutInSSRCookie = () => useSynchronizedCookie("justLoggedOutInSSR"); export const useJustLoggedOutTracking = () => { const flag = useJustLoggedOutInSSRCookie(); return { markLoggedOut: () => { flag.value = true; }, wasJustLoggedOut: () => { const ret = !!flag.value; if (ret) { flag.value = void 0; } return ret; } }; }; export const useOnAuthStateChange = () => { const { cbs } = useOnAuthStateChangeState(); const waitForUser = useWaitForActiveUser(); const activeVueInstance = getCurrentInstance(); const resolveDistinctId = useResolveUserDistinctId(); return async (cb, options) => { cbs.push(cb); if (options?.immediate) { const awaitedUser = await waitForUser(); await cb(awaitedUser?.data?.activeUser, { resolveDistinctId }); } const remove = () => { const idx = cbs.indexOf(cb); if (idx > -1) cbs.splice(idx, 1); }; if (activeVueInstance) { onUnmounted(() => { remove(); }, activeVueInstance); } return remove; }; }; export const useGetInitialAuthState = () => { const waitForUser = useWaitForActiveUser(); const resolveDistinctId = useResolveUserDistinctId(); return async () => { const user = await waitForUser(); return { user: user?.data?.activeUser, distinctId: resolveDistinctId(user?.data?.activeUser) }; }; }; const useResetAuthState = (options) => { const apollo = options?.deferredApollo ? void 0 : useApolloClient().client; const resolveDistinctId = useResolveUserDistinctId(); const { cbs } = useOnAuthStateChangeState(); const authToken = useAuthCookie(); const { logger } = useSafeLogger(); return async (resetOptions) => { const client = apollo || await options?.deferredApollo?.(); const isLoggedIn = !!authToken.value; let user = null; let resetPromise = Promise.resolve(); if (client) { modifyObjectField( client.cache, ROOT_QUERY, "activeUser", ({ helpers: { evict } }) => isLoggedIn ? ( // if we just logged in, we want to evict so that activeUser query retriggers evict() ) : ( // if we logged out, we don't want to reload activeUser query yet, just // mark it as if it's resolved to be null null ) ); resetPromise = (async () => { if (false) { logger().error("attempting to resetStore from SSR"); } else { await client.resetStore(); } const { data: activeUserRes } = await client.query({ query: activeUserQuery, fetchPolicy: "network-only" }).catch(convertThrowIntoFetchResult); user = activeUserRes?.activeUser; })(); } resetPromise = resetPromise.then(() => { cbs.forEach((cb) => cb(user, { resolveDistinctId, isReset: true })); }); if (!resetOptions?.lazyReset) { await resetPromise; } }; }; export const useAuthCookie = () => useSynchronizedCookie(CookieKeys.AuthToken, { maxAge: 60 * 60 * 24 * 30 // 30 days }); export const useAuthManager = (options) => { const { deferredApollo } = options || {}; const ssrEvent = useRequestEvent(); const apiOrigin = useApiOrigin(); const resetAuthState = useResetAuthState({ deferredApollo }); const route = useRoute(); const goHome = useNavigateToHome(); const goToLogin = useNavigateToLogin(); const { triggerNotification } = useGlobalToast(); const getMixpanel = useDeferredMixpanel(); const postAuthRedirect = usePostAuthRedirect(); const { markLoggedOut } = useJustLoggedOutTracking(); const { logger } = useSafeLogger(); const { isFullRedirectState } = useAppErrorState(); const inviteToken = computed(() => route.query.token); const authToken = useAuthCookie(); const embedToken = computed(() => route.query.embedToken); const dashboardToken = computed(() => route.query.dashboardToken); const presentationToken = computed( () => route.query.presentationToken ); const effectiveAuthToken = computed( () => dashboardToken.value || embedToken.value || presentationToken.value || authToken.value ); const sendFullRedirect = async (relativeUrl, clearAuth) => { if (isFullRedirectState.value) return; isFullRedirectState.value = true; if (true) { window.location.href = relativeUrl; } else if (ssrEvent) { const { sendRedirect, deleteCookie } = await import("/_nuxt/node_modules/h3/dist/index.mjs?v=e4f18c29"); if (clearAuth) deleteCookie(ssrEvent, CookieKeys.AuthToken); await sendRedirect(ssrEvent, relativeUrl); } else { logger().fatal("Failed to send full redirect"); } }; const saveNewToken = async (newToken, options2) => { const skipStateReset = options2?.skipStateReset; const skipRedirect = skipStateReset ? true : options2?.skipRedirect; authToken.value = newToken; SafeLocalStorage.remove(LocalStorageKeys.AuthAppChallenge); if (!skipStateReset) { await resetAuthState({ lazyReset: options2?.lazyStateReset }); } if (!skipRedirect) goHome({ query: {} }); }; const finalizeLoginWithAccessCode = async (options2) => { const accessCode = route.query["access_code"]; try { const challenge = SafeLocalStorage.get(LocalStorageKeys.AuthAppChallenge) || ""; if (!challenge.length) { throw new AuthFailedError( "Empty challenge, cannot finalize login. Please reload the page and try again or contact support." ); } if (!accessCode) return; const newToken = await getTokenFromAccessCode({ accessCode, challenge, apiOrigin }); await saveNewToken(newToken, options2); } catch (error) { await saveNewToken(void 0); throw error; } }; const watchEmailVerificationStatus = () => { if (false) return; watch( () => [ route.query["emailverifiedstatus"], route.query["emailverifiederror"] ], (newVals, oldVals) => { const [newStatus, newError] = newVals; const [oldStatus, oldError] = oldVals || []; const isNewStatus = newStatus && newStatus !== oldStatus; const isNewError = newError && newError !== oldError; if (isNewStatus && newStatus === "true") { triggerNotification({ type: ToastNotificationType.Success, title: "Email successfully verified!" }); goHome({ query: {} }); } else if (isNewError) { triggerNotification({ type: ToastNotificationType.Danger, title: "Email verification failed", description: newError }); goHome({ query: {} }); } }, { immediate: true } ); }; const watchLoginAccessCode = () => { if (false) return; watch( () => route.query["access_code"], async (newVal, oldVal) => { if (newVal && newVal !== oldVal) { try { await finalizeLoginWithAccessCode({ skipRedirect: postAuthRedirect.hadPendingRedirect.value }); postAuthRedirect.popAndFollowRedirect(); } catch (e) { const err = ensureError(e); triggerNotification({ type: ToastNotificationType.Danger, title: "Authentication failed", description: err.message }); logger().error({ err }, "Failed to finalize login with access code"); } } }, { immediate: true } ); }; const watchAuthQueryString = () => { watchLoginAccessCode(); watchEmailVerificationStatus(); }; const loginWithEmail = async (params) => { const { email, password, challenge } = params; const { accessCode } = await getAccessCode({ email, password, apiOrigin, challenge }); goHome({ query: { access_code: accessCode } }); getMixpanel()?.track("Log In", { type: "action" }); }; const signUpWithEmail = async (params) => { const { user, challenge, inviteToken: inviteToken2, newsletter } = params; const { accessCode } = await registerAndGetAccessCode({ apiOrigin, challenge, user, inviteToken: inviteToken2, newsletter }); const registeredThisSession = useRegisteredThisSession(); registeredThisSession.value = true; goHome({ query: { access_code: accessCode } }); }; const signInOrSignUpWithSso = (params) => { postAuthRedirect.set(`/workspaces/${params.workspaceSlug}`); const authUrl = new URL( `/api/v1/workspaces/${params.workspaceSlug}/sso/auth`, apiOrigin ); authUrl.searchParams.set("challenge", params.challenge); if (params.newsletterConsent) { authUrl.searchParams.set("newsletter_consent", "true"); } navigateTo(authUrl.toString(), { external: true }); }; const logout = async (options2) => { const isServer = false; await saveNewToken(void 0, { skipRedirect: true, lazyStateReset: true }); if (!options2?.skipToast) { triggerNotification({ type: ToastNotificationType.Info, title: "Goodbye!", description: "You've been logged out" }); } postAuthRedirect.deleteState(); if (isServer) { markLoggedOut(); } if (!options2?.skipRedirect) { if (!options2?.forceFullReload) { await goToLogin(); } else { await sendFullRedirect(loginRoute, true); } } }; return { authToken, embedToken, presentationToken, effectiveAuthToken, loginWithEmail, signUpWithEmail, signInOrSignUpWithSso, logout, watchAuthQueryString, inviteToken, dashboardToken }; }; const useAuthAppIdAndChallenge = () => { const route = useRoute(); const appId = ref(""); const challenge = ref(""); onMounted(() => { const queryChallenge = route.query.challenge || SafeLocalStorage.get(LocalStorageKeys.AuthAppChallenge); const queryAppId = route.query.appId; appId.value = queryAppId || speckleWebAppId; if (queryChallenge) { challenge.value = queryChallenge; } else if (appId.value === speckleWebAppId) { const newChallenge = randomString(10); SafeLocalStorage.set(LocalStorageKeys.AuthAppChallenge, newChallenge); challenge.value = newChallenge; } }); return { appId, challenge }; }; export const useRegisteredThisSession = () => useState("registered-this-session", () => false); export const useLoginOrRegisterUtils = () => { const appIdAndChallenge = useAuthAppIdAndChallenge(); const route = useRoute(); const inviteToken = computed(() => route.query.token); return { ...appIdAndChallenge, inviteToken }; }; //# sourceMappingURL=data:application/json;base64,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QUFNLEtBQXlCO0FBRXhFLFNBQU87QUFBQSxJQUNMLEdBQUc7QUFBQSxJQUNIO0FBQUEsRUFDRjtBQUNGIiwibmFtZXMiOlsib3B0aW9ucyIsImludml0ZVRva2VuIl0sImlnbm9yZUxpc3QiOltdLCJzb3VyY2VzIjpbImF1dGgudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcclxuICBnZXRBY2Nlc3NDb2RlLFxyXG4gIGdldFRva2VuRnJvbUFjY2Vzc0NvZGUsXHJcbiAgcmVnaXN0ZXJBbmRHZXRBY2Nlc3NDb2RlXHJcbn0gZnJvbSAnfn4vbGliL2F1dGgvc2VydmljZXMvYXV0aCdcclxuaW1wb3J0IHsgZW5zdXJlRXJyb3IsIFNhZmVMb2NhbFN0b3JhZ2UgfSBmcm9tICdAc3BlY2tsZS9zaGFyZWQnXHJcbmltcG9ydCB0eXBlIHsgTWF5YmVBc3luYywgTWF5YmVOdWxsT3JVbmRlZmluZWQsIE9wdGlvbmFsIH0gZnJvbSAnQHNwZWNrbGUvc2hhcmVkJ1xyXG5pbXBvcnQgeyBDb29raWVLZXlzLCBMb2NhbFN0b3JhZ2VLZXlzIH0gZnJvbSAnfn4vbGliL2NvbW1vbi9oZWxwZXJzL2NvbnN0YW50cydcclxuaW1wb3J0IHsgdXNlU3luY2hyb25pemVkQ29va2llIH0gZnJvbSAnfn4vbGliL2NvbW1vbi9jb21wb3NhYmxlcy9yZWFjdGl2ZUNvb2tpZSdcclxuaW1wb3J0IHtcclxuICBsb2dpblJvdXRlLFxyXG4gIHVzZU5hdmlnYXRlVG9Ib21lLFxyXG4gIHVzZU5hdmlnYXRlVG9Mb2dpblxyXG59IGZyb20gJ35+L2xpYi9jb21tb24vaGVscGVycy9yb3V0ZSdcclxuaW1wb3J0IHsgdXNlQXBvbGxvQ2xpZW50IH0gZnJvbSAnQHZ1ZS9hcG9sbG8tY29tcG9zYWJsZSdcclxuaW1wb3J0IHsgc3BlY2tsZVdlYkFwcElkIH0gZnJvbSAnfn4vbGliL2F1dGgvaGVscGVycy9zdHJhdGVnaWVzJ1xyXG5pbXBvcnQgeyByYW5kb21TdHJpbmcgfSBmcm9tICd+fi9saWIvY29tbW9uL2hlbHBlcnMvcmFuZG9tJ1xyXG5pbXBvcnQgeyBUb2FzdE5vdGlmaWNhdGlvblR5cGUsIHVzZUdsb2JhbFRvYXN0IH0gZnJvbSAnfn4vbGliL2NvbW1vbi9jb21wb3NhYmxlcy90b2FzdCdcclxuaW1wb3J0IHsgdXNlRGVmZXJyZWRNaXhwYW5lbCB9IGZyb20gJ35+L2xpYi9jb3JlL2NvbXBvc2FibGVzL21wJ1xyXG5pbXBvcnQge1xyXG4gIGFjdGl2ZVVzZXJRdWVyeSxcclxuICB1c2VSZXNvbHZlVXNlckRpc3RpbmN0SWQsXHJcbiAgdXNlV2FpdEZvckFjdGl2ZVVzZXJcclxufSBmcm9tICd+fi9saWIvYXV0aC9jb21wb3NhYmxlcy9hY3RpdmVVc2VyJ1xyXG5pbXBvcnQgeyB1c2VQb3N0QXV0aFJlZGlyZWN0IH0gZnJvbSAnfn4vbGliL2F1dGgvY29tcG9zYWJsZXMvcG9zdEF1dGhSZWRpcmVjdCdcclxuaW1wb3J0IHR5cGUgeyBBY3RpdmVVc2VyTWFpbk1ldGFkYXRhUXVlcnkgfSBmcm9tICd+fi9saWIvY29tbW9uL2dlbmVyYXRlZC9ncWwvZ3JhcGhxbCdcclxuaW1wb3J0IHsgdXNlU2NvcGVkU3RhdGUgfSBmcm9tICd+L2xpYi9jb21tb24vY29tcG9zYWJsZXMvc2NvcGVkU3RhdGUnXHJcbmltcG9ydCB0eXBlIHsgQXBvbGxvQ2xpZW50IH0gZnJvbSAnQGFwb2xsby9jbGllbnQvY29yZSdcclxuaW1wb3J0IHsgQXV0aEZhaWxlZEVycm9yIH0gZnJvbSAnfi9saWIvYXV0aC9lcnJvcnMvZXJyb3JzJ1xyXG5pbXBvcnQgeyB1c2VBcHBFcnJvclN0YXRlIH0gZnJvbSAnfi9saWIvY29yZS9jb21wb3NhYmxlcy9lcnJvcidcclxuXHJcbnR5cGUgVXNlT25BdXRoU3RhdGVDaGFuZ2VDYWxsYmFjayA9IChcclxuICB1c2VyOiBNYXliZU51bGxPclVuZGVmaW5lZDxBY3RpdmVVc2VyTWFpbk1ldGFkYXRhUXVlcnlbJ2FjdGl2ZVVzZXInXT4sXHJcbiAgZXh0cmFzOiB7XHJcbiAgICByZXNvbHZlRGlzdGluY3RJZDogUmV0dXJuVHlwZTx0eXBlb2YgdXNlUmVzb2x2ZVVzZXJEaXN0aW5jdElkPlxyXG4gICAgLyoqXHJcbiAgICAgKiBXaGV0aGVyIHRoZSBhdXRoIGNoYW5nZSB3YXMgdHJpZ2dlcmVkIGJ5IGFuIGF1dGggc3RhdGUgcmVzZXQuIFRoZSBvbmx5IG90aGVyIHNjZW5hcmlvIGlzIHVzZU9uQXV0aFN0YXRlQ2hhbmdlIGJlaW5nIGNhbGxlZCB3aXRoIGBpbW1lZGlhdGU6IHRydWVgXHJcbiAgICAgKi9cclxuICAgIGlzUmVzZXQ/OiBib29sZWFuXHJcbiAgfVxyXG4pID0+IE1heWJlQXN5bmM8dm9pZD5cclxuXHJcbmNvbnN0IHVzZU9uQXV0aFN0YXRlQ2hhbmdlU3RhdGUgPSAoKSA9PlxyXG4gIHVzZVNjb3BlZFN0YXRlKCd1c2VPbkF1dGhTdGF0ZUNoYW5nZScsICgpID0+ICh7XHJcbiAgICBjYnM6IFtdIGFzIEFycmF5PFVzZU9uQXV0aFN0YXRlQ2hhbmdlQ2FsbGJhY2s+XHJcbiAgfSkpXHJcblxyXG5jb25zdCB1c2VKdXN0TG9nZ2VkT3V0SW5TU1JDb29raWUgPSAoKSA9PlxyXG4gIHVzZVN5bmNocm9uaXplZENvb2tpZTxPcHRpb25hbDxib29sZWFuPj4oJ2p1c3RMb2dnZWRPdXRJblNTUicpXHJcblxyXG4vKipcclxuICogVGhlcmUncyBzb21lIHRoaW5nIHdlIGNhbiBvbmx5IGRvIGZyb20gQ1NSIChlLmcuIGRvIG1wLnJlc2V0KCkpLCBzbyB3ZSBuZWVkIHRvIHRyYWNrIGlmIGxvZ291dCgpXHJcbiAqIGhhcHBlbmVkIGluIFNTUiBhbmQgdGhlbiByZWFjdCBpbiBDU1JcclxuICovXHJcbmV4cG9ydCBjb25zdCB1c2VKdXN0TG9nZ2VkT3V0VHJhY2tpbmcgPSAoKSA9PiB7XHJcbiAgY29uc3QgZmxhZyA9IHVzZUp1c3RMb2dnZWRPdXRJblNTUkNvb2tpZSgpXHJcblxyXG4gIHJldHVybiB7XHJcbiAgICBtYXJrTG9nZ2VkT3V0OiAoKSA9PiB7XHJcbiAgICAgIGZsYWcudmFsdWUgPSB0cnVlXHJcbiAgICB9LFxyXG4gICAgd2FzSnVzdExvZ2dlZE91dDogKCkgPT4ge1xyXG4gICAgICBjb25zdCByZXQgPSAhIWZsYWcudmFsdWVcclxuICAgICAgaWYgKHJldCkge1xyXG4gICAgICAgIGZsYWcudmFsdWUgPSB1bmRlZmluZWQgLy8gcG9wXHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHJldHVybiByZXRcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBEbyBzb21ldGhpbmcgd2hlbiB0aGUgYXBwIGF1dGggc3RhdGUgY2hhbmdlcyAodXNlciBsb2dnZWQgaW4gb3Igbm90KS4gVXNlZnVsIGZvciBpbXBlcmF0aXZlbHlcclxuICogaWRlbnRpZnlpbmcvdW5pZGVudGlmeWluZyB1c2VycyBvbiBtaXhwYW5lbCAmIG90aGVyIG9ic2VydmFiaWxpdHkgdG9vbHMuXHJcbiAqXHJcbiAqIFVzZSB0aGUgcmV0dXJuIHRvIG1hbnVhbGx5IHJlbW92ZSB0aGUgY2FsbGJhY2tcclxuICovXHJcbmV4cG9ydCBjb25zdCB1c2VPbkF1dGhTdGF0ZUNoYW5nZSA9ICgpID0+IHtcclxuICBjb25zdCB7IGNicyB9ID0gdXNlT25BdXRoU3RhdGVDaGFuZ2VTdGF0ZSgpXHJcbiAgY29uc3Qgd2FpdEZvclVzZXIgPSB1c2VXYWl0Rm9yQWN0aXZlVXNlcigpXHJcbiAgY29uc3QgYWN0aXZlVnVlSW5zdGFuY2UgPSBnZXRDdXJyZW50SW5zdGFuY2UoKVxyXG4gIGNvbnN0IHJlc29sdmVEaXN0aW5jdElkID0gdXNlUmVzb2x2ZVVzZXJEaXN0aW5jdElkKClcclxuXHJcbiAgcmV0dXJuIGFzeW5jIChcclxuICAgIGNiOiBVc2VPbkF1dGhTdGF0ZUNoYW5nZUNhbGxiYWNrLFxyXG4gICAgb3B0aW9ucz86IFBhcnRpYWw8eyBpbW1lZGlhdGU6IGJvb2xlYW4gfT5cclxuICApID0+IHtcclxuICAgIGNicy5wdXNoKGNiKVxyXG5cclxuICAgIGlmIChvcHRpb25zPy5pbW1lZGlhdGUpIHtcclxuICAgICAgY29uc3QgYXdhaXRlZFVzZXIgPSBhd2FpdCB3YWl0Rm9yVXNlcigpXHJcbiAgICAgIGF3YWl0IGNiKGF3YWl0ZWRVc2VyPy5kYXRhPy5hY3RpdmVVc2VyLCB7IHJlc29sdmVEaXN0aW5jdElkIH0pXHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgcmVtb3ZlID0gKCkgPT4ge1xyXG4gICAgICBjb25zdCBpZHggPSBjYnMuaW5kZXhPZihjYilcclxuICAgICAgaWYgKGlkeCA+IC0xKSBjYnMuc3BsaWNlKGlkeCwgMSlcclxuICAgIH1cclxuXHJcbiAgICBpZiAoYWN0aXZlVnVlSW5zdGFuY2UpIHtcclxuICAgICAgb25Vbm1vdW50ZWQoKCkgPT4ge1xyXG4gICAgICAgIHJlbW92ZSgpXHJcbiAgICAgIH0sIGFjdGl2ZVZ1ZUluc3RhbmNlKVxyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiByZW1vdmVcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBjb25zdCB1c2VHZXRJbml0aWFsQXV0aFN0YXRlID0gKCkgPT4ge1xyXG4gIGNvbnN0IHdhaXRGb3JVc2VyID0gdXNlV2FpdEZvckFjdGl2ZVVzZXIoKVxyXG4gIGNvbnN0IHJlc29sdmVEaXN0aW5jdElkID0gdXNlUmVzb2x2ZVVzZXJEaXN0aW5jdElkKClcclxuXHJcbiAgcmV0dXJuIGFzeW5jICgpID0+IHtcclxuICAgIGNvbnN0IHVzZXIgPSBhd2FpdCB3YWl0Rm9yVXNlcigpXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICB1c2VyOiB1c2VyPy5kYXRhPy5hY3RpdmVVc2VyLFxyXG4gICAgICBkaXN0aW5jdElkOiByZXNvbHZlRGlzdGluY3RJZCh1c2VyPy5kYXRhPy5hY3RpdmVVc2VyKVxyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENvbXBvc2FibGUgdGhhdCBidWlsZHMgYSBmdW5jdGlvbiBmb3IgcmVzZXR0aW5nIHRoZSBhY3RpdmUgYXBvbGxvIGF1dGggc3RhdGVcclxuICogYW5kIGludm9raW5nIGFueSBjYWxsYmFja3MgdGhhdCBhcmUgcmVnaXN0ZXJlZCB0byBsaXN0ZW4gdG8gYXV0aCBzdGF0ZSBjaGFuZ2VzXHJcbiAqL1xyXG5jb25zdCB1c2VSZXNldEF1dGhTdGF0ZSA9IChcclxuICBvcHRpb25zPzogUGFydGlhbDx7XHJcbiAgICAvKipcclxuICAgICAqIFRoaXMgY29tcG9zYWJsZSBtYXkgYmUgaW52b2tlZCBiZWZvcmUgQXBvbGxvIGlzIGV2ZW4gc2V0IHVwLCBzbyB3ZSBtYXkgbmVlZCB0byBkZWZlclxyXG4gICAgICogdGhlIGluamVjdGlvbiBvZiB0aGUgQXBvbGxvIGNsaWVudC5cclxuICAgICAqXHJcbiAgICAgKiBOb3RlOiBJZiBkZWZlcnJlbmNlIGlzIGVuYWJsZWQsIGJ1dCBubyBBcG9sbG9DbGllbnQgY2FuIGJlIHJlc29sdmVkLCB0aGUgcmVzZXQgd2lsbFxyXG4gICAgICogYXNzdW1lIHRoZXJlIGlzIG5vIGxvZ2dlZCBpbiB1c2VyXHJcbiAgICAgKi9cclxuICAgIGRlZmVycmVkQXBvbGxvPzogKCkgPT4gTWF5YmVBc3luYzxPcHRpb25hbDxBcG9sbG9DbGllbnQ8dW5rbm93bj4+PlxyXG4gIH0+XHJcbikgPT4ge1xyXG4gIGNvbnN0IGFwb2xsbyA9IG9wdGlvbnM/LmRlZmVycmVkQXBvbGxvID8gdW5kZWZpbmVkIDogdXNlQXBvbGxvQ2xpZW50KCkuY2xpZW50XHJcbiAgY29uc3QgcmVzb2x2ZURpc3RpbmN0SWQgPSB1c2VSZXNvbHZlVXNlckRpc3RpbmN0SWQoKVxyXG4gIGNvbnN0IHsgY2JzIH0gPSB1c2VPbkF1dGhTdGF0ZUNoYW5nZVN0YXRlKClcclxuICBjb25zdCBhdXRoVG9rZW4gPSB1c2VBdXRoQ29va2llKClcclxuICBjb25zdCB7IGxvZ2dlciB9ID0gdXNlU2FmZUxvZ2dlcigpXHJcblxyXG4gIHJldHVybiBhc3luYyAoXHJcbiAgICByZXNldE9wdGlvbnM/OiBQYXJ0aWFsPHtcclxuICAgICAgLyoqXHJcbiAgICAgICAqIElmIHRydWUsIHdvbid0IGF3YWl0IHRoZSBmdWxsIHJlc2V0IGFuZCByZXR1cm4gZWFybHkgYWZ0ZXIgcmVzZXQgaGFzIHN0YXJ0ZWRcclxuICAgICAgICovXHJcbiAgICAgIGxhenlSZXNldDogYm9vbGVhblxyXG4gICAgfT5cclxuICApID0+IHtcclxuICAgIGNvbnN0IGNsaWVudCA9IGFwb2xsbyB8fCAoYXdhaXQgb3B0aW9ucz8uZGVmZXJyZWRBcG9sbG8/LigpKVxyXG4gICAgY29uc3QgaXNMb2dnZWRJbiA9ICEhYXV0aFRva2VuLnZhbHVlXHJcblxyXG4gICAgbGV0IHVzZXI6IE1heWJlTnVsbE9yVW5kZWZpbmVkPEFjdGl2ZVVzZXJNYWluTWV0YWRhdGFRdWVyeVsnYWN0aXZlVXNlciddPiA9IG51bGxcclxuICAgIGxldCByZXNldFByb21pc2U6IFByb21pc2U8dW5rbm93bj4gPSBQcm9taXNlLnJlc29sdmUoKVxyXG4gICAgaWYgKGNsaWVudCkge1xyXG4gICAgICAvLyBldmljdCB1c2VyIGVhcmx5IChpbiBjYXNlIHdlJ3JlIG5vdCB3YWl0aW5nIGZvciBmdWxsIHJlc2V0KSwgYXMgdGhhdCdzIHdoYXQgbW9zdCBwYWdlcyByZWx5IG9uXHJcbiAgICAgIG1vZGlmeU9iamVjdEZpZWxkKFxyXG4gICAgICAgIGNsaWVudC5jYWNoZSxcclxuICAgICAgICBST09UX1FVRVJZLFxyXG4gICAgICAgICdhY3RpdmVVc2VyJyxcclxuICAgICAgICAoeyBoZWxwZXJzOiB7IGV2aWN0IH0gfSkgPT5cclxuICAgICAgICAgIGlzTG9nZ2VkSW5cclxuICAgICAgICAgICAgPyAvLyBpZiB3ZSBqdXN0IGxvZ2dlZCBpbiwgd2Ugd2FudCB0byBldmljdCBzbyB0aGF0IGFjdGl2ZVVzZXIgcXVlcnkgcmV0cmlnZ2Vyc1xyXG4gICAgICAgICAgICAgIGV2aWN0KClcclxuICAgICAgICAgICAgOiAvLyBpZiB3ZSBsb2dnZWQgb3V0LCB3ZSBkb24ndCB3YW50IHRvIHJlbG9hZCBhY3RpdmVVc2VyIHF1ZXJ5IHlldCwganVzdFxyXG4gICAgICAgICAgICAgIC8vIG1hcmsgaXQgYXMgaWYgaXQncyByZXNvbHZlZCB0byBiZSBudWxsXHJcbiAgICAgICAgICAgICAgbnVsbFxyXG4gICAgICApXHJcblxyXG4gICAgICAvLyBldmljdCBlbnRpcmUgY2FjaGUgKG5vdCBlbm91Z2ggdG8ganVzdCBldmljdCB1c2VyLCB2YXJpb3VzIG90aGVyIGZpZWxkc1xyXG4gICAgICAvLyBhbHNvIGRlcGVuZCBvbiBhY3RpdmUgdXNlciAoZS5nLiBXb3Jrc3BhY2Uuc2VhdFR5cGUpKVxyXG4gICAgICByZXNldFByb21pc2UgPSAoYXN5bmMgKCkgPT4ge1xyXG4gICAgICAgIGlmIChpbXBvcnQubWV0YS5zZXJ2ZXIpIHtcclxuICAgICAgICAgIGxvZ2dlcigpLmVycm9yKCdhdHRlbXB0aW5nIHRvIHJlc2V0U3RvcmUgZnJvbSBTU1InKVxyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBhd2FpdCBjbGllbnQucmVzZXRTdG9yZSgpXHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyB3YWl0IHRpbGwgYWN0aXZlIHVzZXIgaXMgcmVsb2FkZWRcclxuICAgICAgICBjb25zdCB7IGRhdGE6IGFjdGl2ZVVzZXJSZXMgfSA9IGF3YWl0IGNsaWVudFxyXG4gICAgICAgICAgLnF1ZXJ5KHtcclxuICAgICAgICAgICAgcXVlcnk6IGFjdGl2ZVVzZXJRdWVyeSxcclxuICAgICAgICAgICAgZmV0Y2hQb2xpY3k6ICduZXR3b3JrLW9ubHknXHJcbiAgICAgICAgICB9KVxyXG4gICAgICAgICAgLmNhdGNoKGNvbnZlcnRUaHJvd0ludG9GZXRjaFJlc3VsdClcclxuICAgICAgICB1c2VyID0gYWN0aXZlVXNlclJlcz8uYWN0aXZlVXNlclxyXG4gICAgICB9KSgpXHJcbiAgICB9XHJcblxyXG4gICAgcmVzZXRQcm9taXNlID0gcmVzZXRQcm9taXNlLnRoZW4oKCkgPT4ge1xyXG4gICAgICAvLyBwcm9jZXNzIHN0YXRlIGNoYW5nZSBjYWxsYmFja3NcclxuICAgICAgY2JzLmZvckVhY2goKGNiKSA9PiBjYih1c2VyLCB7IHJlc29sdmVEaXN0aW5jdElkLCBpc1Jlc2V0OiB0cnVlIH0pKVxyXG4gICAgfSlcclxuXHJcbiAgICBpZiAoIXJlc2V0T3B0aW9ucz8ubGF6eVJlc2V0KSB7XHJcbiAgICAgIGF3YWl0IHJlc2V0UHJvbWlzZVxyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGNvbnN0IHVzZUF1dGhDb29raWUgPSAoKSA9PlxyXG4gIHVzZVN5bmNocm9uaXplZENvb2tpZTxPcHRpb25hbDxzdHJpbmc+PihDb29raWVLZXlzLkF1dGhUb2tlbiwge1xyXG4gICAgbWF4QWdlOiA2MCAqIDYwICogMjQgKiAzMCAvLyAzMCBkYXlzXHJcbiAgfSlcclxuXHJcbmV4cG9ydCBjb25zdCB1c2VBdXRoTWFuYWdlciA9IChcclxuICBvcHRpb25zPzogUGFydGlhbDx7XHJcbiAgICAvKipcclxuICAgICAqIFRoaXMgY29tcG9zYWJsZSBtYXkgYmUgaW52b2tlZCBiZWZvcmUgQXBvbGxvIGlzIGV2ZW4gc2V0IHVwLCBzbyB3ZSBtYXkgbmVlZCB0byBkZWZlclxyXG4gICAgICogdGhlIGluamVjdGlvbiBvZiB0aGUgQXBvbGxvIGNsaWVudC5cclxuICAgICAqXHJcbiAgICAgKiBOb3RlOiBJZiBkZWZlcnJlbmNlIGlzIGVuYWJsZWQsIGJ1dCBubyBBcG9sbG9DbGllbnQgY2FuIGJlIHJlc29sdmVkLCB0aGUgcmVzZXQgd2lsbFxyXG4gICAgICogYXNzdW1lIHRoZXJlIGlzIG5vIGxvZ2dlZCBpbiB1c2VyXHJcbiAgICAgKi9cclxuICAgIGRlZmVycmVkQXBvbGxvPzogKCkgPT4gTWF5YmVBc3luYzxPcHRpb25hbDxBcG9sbG9DbGllbnQ8dW5rbm93bj4+PlxyXG4gIH0+XHJcbikgPT4ge1xyXG4gIGNvbnN0IHsgZGVmZXJyZWRBcG9sbG8gfSA9IG9wdGlvbnMgfHwge31cclxuXHJcbiAgY29uc3Qgc3NyRXZlbnQgPSB1c2VSZXF1ZXN0RXZlbnQoKVxyXG4gIGNvbnN0IGFwaU9yaWdpbiA9IHVzZUFwaU9yaWdpbigpXHJcbiAgY29uc3QgcmVzZXRBdXRoU3RhdGUgPSB1c2VSZXNldEF1dGhTdGF0ZSh7IGRlZmVycmVkQXBvbGxvIH0pXHJcbiAgY29uc3Qgcm91dGUgPSB1c2VSb3V0ZSgpXHJcbiAgY29uc3QgZ29Ib21lID0gdXNlTmF2aWdhdGVUb0hvbWUoKVxyXG4gIGNvbnN0IGdvVG9Mb2dpbiA9IHVzZU5hdmlnYXRlVG9Mb2dpbigpXHJcbiAgY29uc3QgeyB0cmlnZ2VyTm90aWZpY2F0aW9uIH0gPSB1c2VHbG9iYWxUb2FzdCgpXHJcbiAgY29uc3QgZ2V0TWl4cGFuZWwgPSB1c2VEZWZlcnJlZE1peHBhbmVsKClcclxuICBjb25zdCBwb3N0QXV0aFJlZGlyZWN0ID0gdXNlUG9zdEF1dGhSZWRpcmVjdCgpXHJcbiAgY29uc3QgeyBtYXJrTG9nZ2VkT3V0IH0gPSB1c2VKdXN0TG9nZ2VkT3V0VHJhY2tpbmcoKVxyXG4gIGNvbnN0IHsgbG9nZ2VyIH0gPSB1c2VTYWZlTG9nZ2VyKClcclxuICBjb25zdCB7IGlzRnVsbFJlZGlyZWN0U3RhdGUgfSA9IHVzZUFwcEVycm9yU3RhdGUoKVxyXG5cclxuICAvKipcclxuICAgKiBJbnZpdGUgdG9rZW4sIGlmIGFueVxyXG4gICAqL1xyXG4gIGNvbnN0IGludml0ZVRva2VuID0gY29tcHV0ZWQoKCkgPT4gcm91dGUucXVlcnkudG9rZW4gYXMgT3B0aW9uYWw8c3RyaW5nPilcclxuXHJcbiAgLyoqXHJcbiAgICogT2JzZXJ2YWJsZSBhdXRoIGNvb2tpZVxyXG4gICAqL1xyXG4gIGNvbnN0IGF1dGhUb2tlbiA9IHVzZUF1dGhDb29raWUoKVxyXG5cclxuICAvLyBOT1RFOiBSZWZyYWluIGZyb20gdXNpbmcgdGhlIG5hbWUgdG9rZW4gYXMgaXQgb3ZlcnJpZGVzIHRoZSBhdXRoVG9rZW5cclxuICAvKipcclxuICAgKiBUb2tlbiB1c2VkIGZvciBlbWJlZGRpbmdcclxuICAgKi9cclxuICBjb25zdCBlbWJlZFRva2VuID0gY29tcHV0ZWQoKCkgPT4gcm91dGUucXVlcnkuZW1iZWRUb2tlbiBhcyBPcHRpb25hbDxzdHJpbmc+KVxyXG5cclxuICAvKipcclxuICAgKiBUb2tlbiB1c2VkIGZvciBkYXNoYm9hcmQgc2hhcmluZ1xyXG4gICAqL1xyXG4gIGNvbnN0IGRhc2hib2FyZFRva2VuID0gY29tcHV0ZWQoKCkgPT4gcm91dGUucXVlcnkuZGFzaGJvYXJkVG9rZW4gYXMgT3B0aW9uYWw8c3RyaW5nPilcclxuXHJcbiAgLyoqXHJcbiAgICogVG9rZW4gdXNlZCBmb3IgcHJlc2VudGF0aW9uIHNoYXJpbmdcclxuICAgKi9cclxuICBjb25zdCBwcmVzZW50YXRpb25Ub2tlbiA9IGNvbXB1dGVkKFxyXG4gICAgKCkgPT4gcm91dGUucXVlcnkucHJlc2VudGF0aW9uVG9rZW4gYXMgT3B0aW9uYWw8c3RyaW5nPlxyXG4gIClcclxuXHJcbiAgLyoqXHJcbiAgICogR2V0IHRoZSBlZmZlY3RpdmUgYXV0aCB0b2tlblxyXG4gICAqL1xyXG4gIGNvbnN0IGVmZmVjdGl2ZUF1dGhUb2tlbiA9IGNvbXB1dGVkKFxyXG4gICAgKCkgPT5cclxuICAgICAgZGFzaGJvYXJkVG9rZW4udmFsdWUgfHxcclxuICAgICAgZW1iZWRUb2tlbi52YWx1ZSB8fFxyXG4gICAgICBwcmVzZW50YXRpb25Ub2tlbi52YWx1ZSB8fFxyXG4gICAgICBhdXRoVG9rZW4udmFsdWVcclxuICApXHJcblxyXG4gIC8qKlxyXG4gICAqIFRyaWdnZXIgZnVsbCByZWRpcmVjdCB0aGF0IGNhdXNlcyBhIGZ1bGwgcmVsb2FkLCBpbnN0ZWFkIG9mIGFuIGluLXNlc3Npb24gbmF2aWdhdGlvblxyXG4gICAqL1xyXG4gIGNvbnN0IHNlbmRGdWxsUmVkaXJlY3QgPSBhc3luYyAocmVsYXRpdmVVcmw6IHN0cmluZywgY2xlYXJBdXRoOiBib29sZWFuKSA9PiB7XHJcbiAgICBpZiAoaXNGdWxsUmVkaXJlY3RTdGF0ZS52YWx1ZSkgcmV0dXJuXHJcblxyXG4gICAgaXNGdWxsUmVkaXJlY3RTdGF0ZS52YWx1ZSA9IHRydWVcclxuXHJcbiAgICBpZiAoaW1wb3J0Lm1ldGEuY2xpZW50KSB7XHJcbiAgICAgIHdpbmRvdy5sb2NhdGlvbi5ocmVmID0gcmVsYXRpdmVVcmxcclxuICAgIH0gZWxzZSBpZiAoc3NyRXZlbnQpIHtcclxuICAgICAgLy8gU29ydCBvZiBoYWNreSwgYnV0IG90aGVyd2lzZSBpdCBkb2VzbnQgcmVhbGx5IGRvIGEgZnVsbC9jbGVhbiByZWRpcmVjdFxyXG4gICAgICAvLyBXZSBtYXkgYWxzbyBuZWVkIHRvIGZvcmNlZnVsbHkgY2xlYXIgc29tZSBzZXJ2ZXIgY29va2llcyAoYXV0aCBjb29raWUpIHRvIGVuc3VyZSB3ZSBkb250XHJcbiAgICAgIC8vIGdldCBzdHVjayBpbiBhIHJlZGlyZWN0IGxvb3AsIGNhdXNlIHRoZXkgb25seSBnZXQgd3JpdHRlbiBvbiBzZXJ2ZXIgcmVzcG9uc2UgZW5kIHVzdWFsbHlcclxuICAgICAgY29uc3QgeyBzZW5kUmVkaXJlY3QsIGRlbGV0ZUNvb2tpZSB9ID0gYXdhaXQgaW1wb3J0KCdoMycpXHJcbiAgICAgIGlmIChjbGVhckF1dGgpIGRlbGV0ZUNvb2tpZShzc3JFdmVudCwgQ29va2llS2V5cy5BdXRoVG9rZW4pXHJcbiAgICAgIGF3YWl0IHNlbmRSZWRpcmVjdChzc3JFdmVudCwgcmVsYXRpdmVVcmwpXHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBsb2dnZXIoKS5mYXRhbCgnRmFpbGVkIHRvIHNlbmQgZnVsbCByZWRpcmVjdCcpXHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBTZXQvY2xlYXIgbmV3IHRva2VuIHZhbHVlIGFuZCByZWRpcmVjdCB0byBob21lXHJcbiAgICovXHJcbiAgY29uc3Qgc2F2ZU5ld1Rva2VuID0gYXN5bmMgKFxyXG4gICAgbmV3VG9rZW4/OiBzdHJpbmcsXHJcbiAgICBvcHRpb25zPzogUGFydGlhbDx7XHJcbiAgICAgIHNraXBSZWRpcmVjdDogYm9vbGVhblxyXG4gICAgICBza2lwU3RhdGVSZXNldDogYm9vbGVhblxyXG4gICAgICBsYXp5U3RhdGVSZXNldDogYm9vbGVhblxyXG4gICAgfT5cclxuICApID0+IHtcclxuICAgIGNvbnN0IHNraXBTdGF0ZVJlc2V0ID0gb3B0aW9ucz8uc2tpcFN0YXRlUmVzZXRcclxuICAgIGNvbnN0IHNraXBSZWRpcmVjdCA9IHNraXBTdGF0ZVJlc2V0ID8gdHJ1ZSA6IG9wdGlvbnM/LnNraXBSZWRpcmVjdFxyXG5cclxuICAgIC8vIHdyaXRlIHRvIGNvb2tpZVxyXG4gICAgYXV0aFRva2VuLnZhbHVlID0gbmV3VG9rZW5cclxuXHJcbiAgICAvLyByZXNldCBjaGFsbGVuZ2VcclxuICAgIFNhZmVMb2NhbFN0b3JhZ2UucmVtb3ZlKExvY2FsU3RvcmFnZUtleXMuQXV0aEFwcENoYWxsZW5nZSlcclxuXHJcbiAgICAvLyBXaXBlIGF1dGggc3RhdGVcclxuICAgIGlmICghc2tpcFN0YXRlUmVzZXQpIHtcclxuICAgICAgYXdhaXQgcmVzZXRBdXRoU3RhdGUoe1xyXG4gICAgICAgIGxhenlSZXNldDogb3B0aW9ucz8ubGF6eVN0YXRlUmVzZXRcclxuICAgICAgfSlcclxuICAgIH1cclxuXHJcbiAgICAvLyByZWRpcmVjdCBob21lICYgd2lwZSBhY2Nlc3MgY29kZSBmcm9tIHF1ZXJ5c3RyaW5nXHJcbiAgICBpZiAoIXNraXBSZWRpcmVjdCkgZ29Ib21lKHsgcXVlcnk6IHt9IH0pXHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBDaGVjayBmb3IgYWNjZXNzX2NvZGUgaW4gcXVlcnkgc3RyaW5nIGFuZCBhdHRlbXB0IHRvIGZpbmFsaXplIGxvZ2luXHJcbiAgICovXHJcbiAgY29uc3QgZmluYWxpemVMb2dpbldpdGhBY2Nlc3NDb2RlID0gYXN5bmMgKFxyXG4gICAgb3B0aW9ucz86IFBhcnRpYWw8eyBza2lwUmVkaXJlY3Q6IGJvb2xlYW4gfT5cclxuICApID0+IHtcclxuICAgIGNvbnN0IGFjY2Vzc0NvZGUgPSByb3V0ZS5xdWVyeVsnYWNjZXNzX2NvZGUnXSBhcyBPcHRpb25hbDxzdHJpbmc+XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgY29uc3QgY2hhbGxlbmdlID0gU2FmZUxvY2FsU3RvcmFnZS5nZXQoTG9jYWxTdG9yYWdlS2V5cy5BdXRoQXBwQ2hhbGxlbmdlKSB8fCAnJ1xyXG4gICAgICBpZiAoIWNoYWxsZW5nZS5sZW5ndGgpIHtcclxuICAgICAgICB0aHJvdyBuZXcgQXV0aEZhaWxlZEVycm9yKFxyXG4gICAgICAgICAgJ0VtcHR5IGNoYWxsZW5nZSwgY2Fubm90IGZpbmFsaXplIGxvZ2luLiBQbGVhc2UgcmVsb2FkIHRoZSBwYWdlIGFuZCB0cnkgYWdhaW4gb3IgY29udGFjdCBzdXBwb3J0LidcclxuICAgICAgICApXHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmICghYWNjZXNzQ29kZSkgcmV0dXJuXHJcblxyXG4gICAgICBjb25zdCBuZXdUb2tlbiA9IGF3YWl0IGdldFRva2VuRnJvbUFjY2Vzc0NvZGUoe1xyXG4gICAgICAgIGFjY2Vzc0NvZGUsXHJcbiAgICAgICAgY2hhbGxlbmdlLFxyXG4gICAgICAgIGFwaU9yaWdpblxyXG4gICAgICB9KVxyXG5cclxuICAgICAgYXdhaXQgc2F2ZU5ld1Rva2VuKG5ld1Rva2VuLCBvcHRpb25zKVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgYXdhaXQgc2F2ZU5ld1Rva2VuKHVuZGVmaW5lZClcclxuICAgICAgdGhyb3cgZXJyb3JcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIENoZWNrIGZvciAnZW1haWx2ZXJpZmllZHN0YXR1cycgaW4gcXVlcnkgc3RyaW5nIGFuZCByZXBvcnQgaXQgdG8gdXNlclxyXG4gICAqL1xyXG4gIGNvbnN0IHdhdGNoRW1haWxWZXJpZmljYXRpb25TdGF0dXMgPSAoKSA9PiB7XHJcbiAgICBpZiAoaW1wb3J0Lm1ldGEuc2VydmVyKSByZXR1cm5cclxuXHJcbiAgICB3YXRjaChcclxuICAgICAgKCkgPT5cclxuICAgICAgICA8Y29uc3Q+W1xyXG4gICAgICAgICAgcm91dGUucXVlcnlbJ2VtYWlsdmVyaWZpZWRzdGF0dXMnXSBhcyBPcHRpb25hbDxzdHJpbmc+LFxyXG4gICAgICAgICAgcm91dGUucXVlcnlbJ2VtYWlsdmVyaWZpZWRlcnJvciddIGFzIE9wdGlvbmFsPHN0cmluZz5cclxuICAgICAgICBdLFxyXG4gICAgICAobmV3VmFscywgb2xkVmFscykgPT4ge1xyXG4gICAgICAgIGNvbnN0IFtuZXdTdGF0dXMsIG5ld0Vycm9yXSA9IG5ld1ZhbHNcclxuICAgICAgICBjb25zdCBbb2xkU3RhdHVzLCBvbGRFcnJvcl0gPSBvbGRWYWxzIHx8IFtdXHJcblxyXG4gICAgICAgIGNvbnN0IGlzTmV3U3RhdHVzID0gbmV3U3RhdHVzICYmIG5ld1N0YXR1cyAhPT0gb2xkU3RhdHVzXHJcbiAgICAgICAgY29uc3QgaXNOZXdFcnJvciA9IG5ld0Vycm9yICYmIG5ld0Vycm9yICE9PSBvbGRFcnJvclxyXG5cclxuICAgICAgICBpZiAoaXNOZXdTdGF0dXMgJiYgbmV3U3RhdHVzID09PSAndHJ1ZScpIHtcclxuICAgICAgICAgIHRyaWdnZXJOb3RpZmljYXRpb24oe1xyXG4gICAgICAgICAgICB0eXBlOiBUb2FzdE5vdGlmaWNhdGlvblR5cGUuU3VjY2VzcyxcclxuICAgICAgICAgICAgdGl0bGU6ICdFbWFpbCBzdWNjZXNzZnVsbHkgdmVyaWZpZWQhJ1xyXG4gICAgICAgICAgfSlcclxuXHJcbiAgICAgICAgICAvLyB3aXBlIHJlcG9ydFxyXG4gICAgICAgICAgZ29Ib21lKHsgcXVlcnk6IHt9IH0pXHJcbiAgICAgICAgfSBlbHNlIGlmIChpc05ld0Vycm9yKSB7XHJcbiAgICAgICAgICB0cmlnZ2VyTm90aWZpY2F0aW9uKHtcclxuICAgICAgICAgICAgdHlwZTogVG9hc3ROb3RpZmljYXRpb25UeXBlLkRhbmdlcixcclxuICAgICAgICAgICAgdGl0bGU6ICdFbWFpbCB2ZXJpZmljYXRpb24gZmFpbGVkJyxcclxuICAgICAgICAgICAgZGVzY3JpcHRpb246IG5ld0Vycm9yXHJcbiAgICAgICAgICB9KVxyXG5cclxuICAgICAgICAgIC8vIHdpcGUgcmVwb3J0XHJcbiAgICAgICAgICBnb0hvbWUoeyBxdWVyeToge30gfSlcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHsgaW1tZWRpYXRlOiB0cnVlIH1cclxuICAgIClcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFdhdGNoIGZvciBjaGFuZ2VzIHRvIHF1ZXJ5IHN0cmluZyBhbmQgd2hlbiBhY2Nlc3NfY29kZSBpcyBzZXQgdHJpZ2dlciBsb2dpbiBmaW5hbGl6YXRpb25cclxuICAgKiAoZWl0aGVyIHVzZWQganVzdCBsb2dnZWQgaW4gb3IgcmVnaXN0ZXJlZClcclxuICAgKi9cclxuICBjb25zdCB3YXRjaExvZ2luQWNjZXNzQ29kZSA9ICgpID0+IHtcclxuICAgIGlmIChpbXBvcnQubWV0YS5zZXJ2ZXIpIHJldHVyblxyXG5cclxuICAgIHdhdGNoKFxyXG4gICAgICAoKSA9PiByb3V0ZS5xdWVyeVsnYWNjZXNzX2NvZGUnXSBhcyBPcHRpb25hbDxzdHJpbmc+LFxyXG4gICAgICBhc3luYyAobmV3VmFsLCBvbGRWYWwpID0+IHtcclxuICAgICAgICBpZiAobmV3VmFsICYmIG5ld1ZhbCAhPT0gb2xkVmFsKSB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBhd2FpdCBmaW5hbGl6ZUxvZ2luV2l0aEFjY2Vzc0NvZGUoe1xyXG4gICAgICAgICAgICAgIHNraXBSZWRpcmVjdDogcG9zdEF1dGhSZWRpcmVjdC5oYWRQZW5kaW5nUmVkaXJlY3QudmFsdWVcclxuICAgICAgICAgICAgfSlcclxuXHJcbiAgICAgICAgICAgIHBvc3RBdXRoUmVkaXJlY3QucG9wQW5kRm9sbG93UmVkaXJlY3QoKVxyXG4gICAgICAgICAgfSBjYXRjaCAoZSkge1xyXG4gICAgICAgICAgICBjb25zdCBlcnIgPSBlbnN1cmVFcnJvcihlKVxyXG4gICAgICAgICAgICB0cmlnZ2VyTm90aWZpY2F0aW9uKHtcclxuICAgICAgICAgICAgICB0eXBlOiBUb2FzdE5vdGlmaWNhdGlvblR5cGUuRGFuZ2VyLFxyXG4gICAgICAgICAgICAgIHRpdGxlOiAnQXV0aGVudGljYXRpb24gZmFpbGVkJyxcclxuICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogZXJyLm1lc3NhZ2VcclxuICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgbG9nZ2VyKCkuZXJyb3IoeyBlcnIgfSwgJ0ZhaWxlZCB0byBmaW5hbGl6ZSBsb2dpbiB3aXRoIGFjY2VzcyBjb2RlJylcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHsgaW1tZWRpYXRlOiB0cnVlIH1cclxuICAgIClcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFNldHMgdXAgcXVlcnlzdHJpbmcgd2F0Y2hlcnMgdGhhdCB0cmlnZ2VyIHZhcmlvdXMgYXV0aCByZWxhdGVkIGFjdGl2aXRpZXMgbGlrZSBlbWFpbCB2ZXJpZmljYXRpb24gc3RhdHVzIHJlcG9ydHMgZXRjLlxyXG4gICAqL1xyXG4gIGNvbnN0IHdhdGNoQXV0aFF1ZXJ5U3RyaW5nID0gKCkgPT4ge1xyXG4gICAgd2F0Y2hMb2dpbkFjY2Vzc0NvZGUoKVxyXG4gICAgd2F0Y2hFbWFpbFZlcmlmaWNhdGlvblN0YXR1cygpXHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBUcmlnZ2VyIGxvZ2luIHRocm91Z2ggZW1haWwgJiBwYXNzd29yZFxyXG4gICAqL1xyXG4gIGNvbnN0IGxvZ2luV2l0aEVtYWlsID0gYXN5bmMgKHBhcmFtczoge1xyXG4gICAgZW1haWw6IHN0cmluZ1xyXG4gICAgcGFzc3dvcmQ6IHN0cmluZ1xyXG4gICAgY2hhbGxlbmdlOiBzdHJpbmdcclxuICB9KSA9PiB7XHJcbiAgICBjb25zdCB7IGVtYWlsLCBwYXNzd29yZCwgY2hhbGxlbmdlIH0gPSBwYXJhbXNcclxuXHJcbiAgICBjb25zdCB7IGFjY2Vzc0NvZGUgfSA9IGF3YWl0IGdldEFjY2Vzc0NvZGUoe1xyXG4gICAgICBlbWFpbCxcclxuICAgICAgcGFzc3dvcmQsXHJcbiAgICAgIGFwaU9yaWdpbixcclxuICAgICAgY2hhbGxlbmdlXHJcbiAgICB9KVxyXG5cclxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBjYW1lbGNhc2VcclxuICAgIGdvSG9tZSh7IHF1ZXJ5OiB7IGFjY2Vzc19jb2RlOiBhY2Nlc3NDb2RlIH0gfSlcclxuXHJcbiAgICBnZXRNaXhwYW5lbCgpPy50cmFjaygnTG9nIEluJywgeyB0eXBlOiAnYWN0aW9uJyB9KVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogVHJpZ2dlciByZWdpc3RyYXRpb24gcHJvY2VkdXJlIHdpdGggZW1haWwgJiBwYXNzd29yZFxyXG4gICAqL1xyXG4gIGNvbnN0IHNpZ25VcFdpdGhFbWFpbCA9IGFzeW5jIChwYXJhbXM6IHtcclxuICAgIHVzZXI6IHtcclxuICAgICAgZW1haWw6IHN0cmluZ1xyXG4gICAgICBwYXNzd29yZDogc3RyaW5nXHJcbiAgICAgIG5hbWU6IHN0cmluZ1xyXG4gICAgICBjb21wYW55Pzogc3RyaW5nXHJcbiAgICB9XHJcbiAgICBjaGFsbGVuZ2U6IHN0cmluZ1xyXG4gICAgaW52aXRlVG9rZW4/OiBzdHJpbmdcclxuICAgIG5ld3NsZXR0ZXI/OiBib29sZWFuXHJcbiAgfSkgPT4ge1xyXG4gICAgY29uc3QgeyB1c2VyLCBjaGFsbGVuZ2UsIGludml0ZVRva2VuLCBuZXdzbGV0dGVyIH0gPSBwYXJhbXNcclxuXHJcbiAgICBjb25zdCB7IGFjY2Vzc0NvZGUgfSA9IGF3YWl0IHJlZ2lzdGVyQW5kR2V0QWNjZXNzQ29kZSh7XHJcbiAgICAgIGFwaU9yaWdpbixcclxuICAgICAgY2hhbGxlbmdlLFxyXG4gICAgICB1c2VyLFxyXG4gICAgICBpbnZpdGVUb2tlbixcclxuICAgICAgbmV3c2xldHRlclxyXG4gICAgfSlcclxuXHJcbiAgICBjb25zdCByZWdpc3RlcmVkVGhpc1Nlc3Npb24gPSB1c2VSZWdpc3RlcmVkVGhpc1Nlc3Npb24oKVxyXG4gICAgcmVnaXN0ZXJlZFRoaXNTZXNzaW9uLnZhbHVlID0gdHJ1ZVxyXG5cclxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBjYW1lbGNhc2VcclxuICAgIGdvSG9tZSh7IHF1ZXJ5OiB7IGFjY2Vzc19jb2RlOiBhY2Nlc3NDb2RlIH0gfSlcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEluaXRpYXRlIFNTTyBmbG93LiBXaWxsIGNyZWF0ZSBhIHVzZXIgaWYgb25lIGRvZXMgbm90IGFscmVhZHkgZXhpc3QuXHJcbiAgICovXHJcbiAgY29uc3Qgc2lnbkluT3JTaWduVXBXaXRoU3NvID0gKHBhcmFtczoge1xyXG4gICAgY2hhbGxlbmdlOiBzdHJpbmdcclxuICAgIHdvcmtzcGFjZVNsdWc6IHN0cmluZ1xyXG4gICAgbmV3c2xldHRlckNvbnNlbnQ/OiBib29sZWFuXHJcbiAgfSkgPT4ge1xyXG4gICAgcG9zdEF1dGhSZWRpcmVjdC5zZXQoYC93b3Jrc3BhY2VzLyR7cGFyYW1zLndvcmtzcGFjZVNsdWd9YClcclxuXHJcbiAgICBjb25zdCBhdXRoVXJsID0gbmV3IFVSTChcclxuICAgICAgYC9hcGkvdjEvd29ya3NwYWNlcy8ke3BhcmFtcy53b3Jrc3BhY2VTbHVnfS9zc28vYXV0aGAsXHJcbiAgICAgIGFwaU9yaWdpblxyXG4gICAgKVxyXG4gICAgYXV0aFVybC5zZWFyY2hQYXJhbXMuc2V0KCdjaGFsbGVuZ2UnLCBwYXJhbXMuY2hhbGxlbmdlKVxyXG4gICAgaWYgKHBhcmFtcy5uZXdzbGV0dGVyQ29uc2VudCkge1xyXG4gICAgICBhdXRoVXJsLnNlYXJjaFBhcmFtcy5zZXQoJ25ld3NsZXR0ZXJfY29uc2VudCcsICd0cnVlJylcclxuICAgIH1cclxuICAgIG5hdmlnYXRlVG8oYXV0aFVybC50b1N0cmluZygpLCB7IGV4dGVybmFsOiB0cnVlIH0pXHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBMb2cgb3V0XHJcbiAgICovXHJcbiAgY29uc3QgbG9nb3V0ID0gYXN5bmMgKFxyXG4gICAgb3B0aW9ucz86IFBhcnRpYWw8e1xyXG4gICAgICBza2lwVG9hc3Q6IGJvb2xlYW5cclxuICAgICAgc2tpcFJlZGlyZWN0OiBib29sZWFuXHJcbiAgICAgIC8qKlxyXG4gICAgICAgKiBJZiB0cnVlLCB3aWxsIHRyaWdnZXIgYSBmdWxsIHBhZ2UgbG9hZCB0byAvYXV0aG4vbG9naW4gaW4gQ1NSLCBpbnN0ZWFkIG9mIGp1c3QgZG9pbmcgYSBDU1JcclxuICAgICAgICogcmVkaXJlY3QgdG8gdGhlIHBhZ2UuIFVzZWZ1bCB3aGVuIHlvdSB3YW50IHRvIGZ1bGx5IHJlc3RhcnQgdGhlIGFwcCBhZnRlciBsb2dnaW5nIG91dC5cclxuICAgICAgICovXHJcbiAgICAgIGZvcmNlRnVsbFJlbG9hZDogYm9vbGVhblxyXG4gICAgfT5cclxuICApID0+IHtcclxuICAgIGNvbnN0IGlzU2VydmVyID0gaW1wb3J0Lm1ldGEuc2VydmVyXHJcblxyXG4gICAgLy8gbGF6eSByZXNldCwgd2UgZG9udCBuZWVkIGl0IHRvIGZpbmlzaCBiZWZvcmUgd2UgY2FuIHJlZGlyZWN0IHRvIGxvZ2luIHBhZ2VcclxuICAgIC8vIChhbmQgd2Ugd2FubmEgYXZvaWQgZmxhc2hlcyBvZiBicm9rZW4gY29udGVudClcclxuICAgIGF3YWl0IHNhdmVOZXdUb2tlbih1bmRlZmluZWQsIHsgc2tpcFJlZGlyZWN0OiB0cnVlLCBsYXp5U3RhdGVSZXNldDogdHJ1ZSB9KVxyXG5cclxuICAgIGlmICghb3B0aW9ucz8uc2tpcFRvYXN0KSB7XHJcbiAgICAgIHRyaWdnZXJOb3RpZmljYXRpb24oe1xyXG4gICAgICAgIHR5cGU6IFRvYXN0Tm90aWZpY2F0aW9uVHlwZS5JbmZvLFxyXG4gICAgICAgIHRpdGxlOiAnR29vZGJ5ZSEnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiBcIllvdSd2ZSBiZWVuIGxvZ2dlZCBvdXRcIlxyXG4gICAgICB9KVxyXG4gICAgfVxyXG5cclxuICAgIHBvc3RBdXRoUmVkaXJlY3QuZGVsZXRlU3RhdGUoKVxyXG5cclxuICAgIGlmIChpc1NlcnZlcikge1xyXG4gICAgICBtYXJrTG9nZ2VkT3V0KClcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIW9wdGlvbnM/LnNraXBSZWRpcmVjdCkge1xyXG4gICAgICBpZiAoIW9wdGlvbnM/LmZvcmNlRnVsbFJlbG9hZCkge1xyXG4gICAgICAgIGF3YWl0IGdvVG9Mb2dpbigpXHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgYXdhaXQgc2VuZEZ1bGxSZWRpcmVjdChsb2dpblJvdXRlLCB0cnVlKVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICByZXR1cm4ge1xyXG4gICAgYXV0aFRva2VuLFxyXG4gICAgZW1iZWRUb2tlbixcclxuICAgIHByZXNlbnRhdGlvblRva2VuLFxyXG4gICAgZWZmZWN0aXZlQXV0aFRva2VuLFxyXG4gICAgbG9naW5XaXRoRW1haWwsXHJcbiAgICBzaWduVXBXaXRoRW1haWwsXHJcbiAgICBzaWduSW5PclNpZ25VcFdpdGhTc28sXHJcbiAgICBsb2dvdXQsXHJcbiAgICB3YXRjaEF1dGhRdWVyeVN0cmluZyxcclxuICAgIGludml0ZVRva2VuLFxyXG4gICAgZGFzaGJvYXJkVG9rZW5cclxuICB9XHJcbn1cclxuXHJcbmNvbnN0IHVzZUF1dGhBcHBJZEFuZENoYWxsZW5nZSA9ICgpID0+IHtcclxuICBjb25zdCByb3V0ZSA9IHVzZVJvdXRlKClcclxuICBjb25zdCBhcHBJZCA9IHJlZignJylcclxuICBjb25zdCBjaGFsbGVuZ2UgPSByZWYoJycpXHJcblxyXG4gIG9uTW91bnRlZCgoKSA9PiB7XHJcbiAgICAvLyBSZXNvbHZlIGNoYWxsZW5nZSAmIGFwcElkIGZyb20gcXVlcnlzdHJpbmcgb3IgZ2VuZXJhdGUgdGhlbVxyXG4gICAgY29uc3QgcXVlcnlDaGFsbGVuZ2UgPVxyXG4gICAgICAocm91dGUucXVlcnkuY2hhbGxlbmdlIGFzIE9wdGlvbmFsPHN0cmluZz4pIHx8XHJcbiAgICAgIFNhZmVMb2NhbFN0b3JhZ2UuZ2V0KExvY2FsU3RvcmFnZUtleXMuQXV0aEFwcENoYWxsZW5nZSlcclxuICAgIGNvbnN0IHF1ZXJ5QXBwSWQgPSByb3V0ZS5xdWVyeS5hcHBJZCBhcyBPcHRpb25hbDxzdHJpbmc+XHJcblxyXG4gICAgYXBwSWQudmFsdWUgPSBxdWVyeUFwcElkIHx8IHNwZWNrbGVXZWJBcHBJZFxyXG5cclxuICAgIGlmIChxdWVyeUNoYWxsZW5nZSkge1xyXG4gICAgICBjaGFsbGVuZ2UudmFsdWUgPSBxdWVyeUNoYWxsZW5nZVxyXG4gICAgfSBlbHNlIGlmIChhcHBJZC52YWx1ZSA9PT0gc3BlY2tsZVdlYkFwcElkKSB7XHJcbiAgICAgIGNvbnN0IG5ld0NoYWxsZW5nZSA9IHJhbmRvbVN0cmluZygxMClcclxuXHJcbiAgICAgIFNhZmVMb2NhbFN0b3JhZ2Uuc2V0KExvY2FsU3RvcmFnZUtleXMuQXV0aEFwcENoYWxsZW5nZSwgbmV3Q2hhbGxlbmdlKVxyXG4gICAgICBjaGFsbGVuZ2UudmFsdWUgPSBuZXdDaGFsbGVuZ2VcclxuICAgIH1cclxuICB9KVxyXG5cclxuICByZXR1cm4geyBhcHBJZCwgY2hhbGxlbmdlIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEluZGljYXRlcyB3aGV0aGVyIHRoZSB1c2VyIGp1c3QgY29tcGxldGVkIHJlZ2lzdHJhdGlvblxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHVzZVJlZ2lzdGVyZWRUaGlzU2Vzc2lvbiA9ICgpID0+XHJcbiAgdXNlU3RhdGU8Ym9vbGVhbj4oJ3JlZ2lzdGVyZWQtdGhpcy1zZXNzaW9uJywgKCkgPT4gZmFsc2UpXHJcblxyXG5leHBvcnQgY29uc3QgdXNlTG9naW5PclJlZ2lzdGVyVXRpbHMgPSAoKSA9PiB7XHJcbiAgY29uc3QgYXBwSWRBbmRDaGFsbGVuZ2UgPSB1c2VBdXRoQXBwSWRBbmRDaGFsbGVuZ2UoKVxyXG4gIGNvbnN0IHJvdXRlID0gdXNlUm91dGUoKVxyXG5cclxuICAvKipcclxuICAgKiBJbnZpdGUgdG9rZW4sIGlmIGFueVxyXG4gICAqL1xyXG4gIGNvbnN0IGludml0ZVRva2VuID0gY29tcHV0ZWQoKCkgPT4gcm91dGUucXVlcnkudG9rZW4gYXMgT3B0aW9uYWw8c3RyaW5nPilcclxuXHJcbiAgcmV0dXJuIHtcclxuICAgIC4uLmFwcElkQW5kQ2hhbGxlbmdlLFxyXG4gICAgaW52aXRlVG9rZW5cclxuICB9XHJcbn1cclxuIl0sImZpbGUiOiJEOi9zcGVja2xlLXNlcnZlci9wYWNrYWdlcy9mcm9udGVuZC0yL2xpYi9hdXRoL2NvbXBvc2FibGVzL2F1dGgudHMifQ==