Files
speckle-server/scratch/edge-debug-selection/Default/Cache/Cache_Data/f_000041
T

369 lines
48 KiB
Plaintext

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==