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

230 lines
38 KiB
Plaintext

import { err, ok } from "/_nuxt/node_modules/.cache/vite/client/deps/true-myth_result.js?v=e4f18c29";
import { hasAnyWorkspaceRole, hasMinimumWorkspaceRole } from "/_nuxt/@fs/D:/speckle-server/packages/shared/dist/esm/authz/checks/workspaceRole.js";
import { PersonalProjectsLimitedError, ProjectNotFoundError, WorkspaceLimitsReachedError, WorkspaceNoAccessError, WorkspaceNoEditorSeatError, WorkspaceNotEnoughPermissionsError, WorkspacePlanNoFeatureAccessError, WorkspaceReadOnlyError, WorkspacesNotEnabledError, WorkspaceSsoSessionNoAccessError } from "/_nuxt/@fs/D:/speckle-server/packages/shared/dist/esm/authz/domain/authErrors.js";
import { Roles } from "/_nuxt/@fs/D:/speckle-server/packages/shared/dist/esm/core/constants.js";
import { isWorkspacePlanStatusReadOnly } from "/_nuxt/@fs/D:/speckle-server/packages/shared/dist/esm/workspaces/helpers/plans.js";
import { hasEditorSeat } from "/_nuxt/@fs/D:/speckle-server/packages/shared/dist/esm/authz/checks/workspaceSeat.js";
import { ensureMinimumServerRoleFragment } from "/_nuxt/@fs/D:/speckle-server/packages/shared/dist/esm/authz/fragments/server.js";
import { workspacePlanHasAccessToFeature } from "/_nuxt/@fs/D:/speckle-server/packages/shared/dist/esm/workspaces/helpers/features.js";
/**
* Ensure user has a workspace role, and a valid SSO session (if SSO is configured)
*/
export const ensureWorkspaceRoleAndSessionFragment = (loaders) => async ({ userId, workspaceId, role }) => {
const testedRole = role ?? Roles.Workspace.Guest;
const testingForMinimumRole = testedRole === Roles.Workspace.Guest;
// Get workspace, so we can resolve its slug for error scenarios
const workspace = await loaders.getWorkspace({ workspaceId });
// hides the fact, that the workspace does not exist
if (!workspace)
return err(new WorkspaceNoAccessError());
const hasMinimumRole = await hasMinimumWorkspaceRole(loaders)({
userId,
workspaceId,
role: testedRole
});
if (!hasMinimumRole)
return err(testingForMinimumRole
? new WorkspaceNoAccessError()
: new WorkspaceNotEnoughPermissionsError());
const hasMinimumMemberRole = await hasMinimumWorkspaceRole(loaders)({
userId,
workspaceId,
role: 'workspace:member'
});
// only members and above need to use sso
if (!hasMinimumMemberRole)
return ok();
const workspaceSsoProvider = await loaders.getWorkspaceSsoProvider({
workspaceId
});
if (!workspaceSsoProvider)
return ok();
const workspaceSsoSession = await loaders.getWorkspaceSsoSession({
userId,
workspaceId
});
if (!workspaceSsoSession)
return err(new WorkspaceSsoSessionNoAccessError({
payload: { workspaceSlug: workspace.slug }
}));
const isExpiredSession = new Date().getTime() > workspaceSsoSession.validUntil.getTime();
if (isExpiredSession)
return err(new WorkspaceSsoSessionNoAccessError({
payload: { workspaceSlug: workspace.slug }
}));
return ok();
};
/**
* Ensure the workspaces module is enabled
*/
export const ensureWorkspacesEnabledFragment = (loaders) => async () => {
const env = await loaders.getEnv();
if (!env.FF_WORKSPACES_MODULE_ENABLED)
return err(new WorkspacesNotEnabledError());
return ok();
};
/**
* Ensure workspace is not read-only
*/
export const ensureWorkspaceNotReadOnlyFragment = (loaders) => async ({ workspaceId }) => {
const workspacePlan = await loaders.getWorkspacePlan({ workspaceId });
if (!workspacePlan)
return err(new WorkspaceNoAccessError());
if (isWorkspacePlanStatusReadOnly(workspacePlan.status))
return err(new WorkspaceReadOnlyError());
return ok();
};
/**
* Ensure workspace can accept new project (not read-only, limits not reached).
* If userId is specified, will also check for user role & seat
*/
export const ensureWorkspaceProjectCanBeCreatedFragment = (loaders) => async ({ workspaceId, userId }) => {
// First check user even has access
if (userId) {
// Is Member+
const isNotGuest = await hasMinimumWorkspaceRole(loaders)({
userId,
workspaceId,
role: Roles.Workspace.Member
});
if (!isNotGuest) {
return err(new WorkspaceNotEnoughPermissionsError('Guests cannot create projects in the workspace'));
}
}
const ensuredNotReadOnly = await ensureWorkspaceNotReadOnlyFragment(loaders)({
workspaceId
});
if (ensuredNotReadOnly.isErr)
return err(ensuredNotReadOnly.error);
const workspacePlan = await loaders.getWorkspacePlan({ workspaceId });
if (!workspacePlan)
return err(new WorkspaceNoAccessError());
// Now check editor seat
if (userId) {
const isEditor = await hasEditorSeat(loaders)({
userId,
workspaceId
});
if (!isEditor)
return err(new WorkspaceNoEditorSeatError());
}
const workspaceLimits = await loaders.getWorkspaceLimits({ workspaceId });
if (!workspaceLimits)
return err(new WorkspaceNoAccessError());
// no limits imposed
if (workspaceLimits.projectCount === null)
return ok();
const currentProjectCount = await loaders.getWorkspaceProjectCount({
workspaceId
});
// this will not happen in practice
if (currentProjectCount === null)
return err(new WorkspaceNoAccessError());
return currentProjectCount < workspaceLimits.projectCount
? ok()
: err(new WorkspaceLimitsReachedError({
message: 'You have reached the maximum number of projects for your plan. Upgrade to increase it.',
payload: { limit: 'projectCount' }
}));
};
/**
* Ensure model can be created (workspace not read-only, limits not reached).
* If userId is specified, will also check for appropriate user role & seat
*/
export const ensureModelCanBeCreatedFragment = (loaders) => async ({ projectId, userId, addedModelCount, workspaceId }) => {
addedModelCount = addedModelCount ?? 1;
const { FF_WORKSPACES_MODULE_ENABLED, FF_PERSONAL_PROJECTS_LIMITS_ENABLED } = await loaders.getEnv();
const project = await loaders.getProject({ projectId });
if (!project)
return err(new ProjectNotFoundError());
// Project may not be attached to a workspace yet, then we use the specified workspaceId
workspaceId = workspaceId || project.workspaceId || undefined;
// If workspace
if (workspaceId && FF_WORKSPACES_MODULE_ENABLED) {
if (userId) {
// Has workspace role
const isInWorkspace = await hasAnyWorkspaceRole(loaders)({
userId,
workspaceId
});
if (!isInWorkspace) {
return err(new WorkspaceNoAccessError());
}
}
const ensuredNotReadOnly = await ensureWorkspaceNotReadOnlyFragment(loaders)({
workspaceId
});
if (ensuredNotReadOnly.isErr)
return err(ensuredNotReadOnly.error);
const workspacePlan = await loaders.getWorkspacePlan({ workspaceId });
if (!workspacePlan)
return err(new WorkspaceNoAccessError());
const workspaceLimits = await loaders.getWorkspaceLimits({ workspaceId });
if (!workspaceLimits)
return err(new WorkspaceNoAccessError());
if (workspaceLimits.modelCount === null)
return ok();
const currentModelCount = await loaders.getWorkspaceModelCount({ workspaceId });
if (currentModelCount === null)
return err(new WorkspaceNoAccessError());
return currentModelCount + addedModelCount <= workspaceLimits.modelCount
? ok()
: err(new WorkspaceLimitsReachedError({
message: 'You have reached the maximum number of models for your plan. Upgrade to increase it.',
payload: {
limit: 'modelCount'
}
}));
}
else {
// If not - check personal project limits
if (FF_PERSONAL_PROJECTS_LIMITS_ENABLED) {
return err(new PersonalProjectsLimitedError('No new models can be added to personal projects'));
}
return ok();
}
};
export const ensureUserIsWorkspaceAdminFragment = (loaders) => async ({ userId, workspaceId }) => {
const ensuredWorkspacesEnabled = await ensureWorkspacesEnabledFragment(loaders)({});
if (ensuredWorkspacesEnabled.isErr)
return err(ensuredWorkspacesEnabled.error);
const ensuredServerRole = await ensureMinimumServerRoleFragment(loaders)({
userId,
role: Roles.Server.User
});
if (ensuredServerRole.isErr)
return err(ensuredServerRole.error);
const ensuredWorkspaceAccess = await ensureWorkspaceRoleAndSessionFragment(loaders)({
userId: userId,
workspaceId,
role: Roles.Workspace.Admin
});
if (ensuredWorkspaceAccess.isErr)
return err(ensuredWorkspaceAccess.error);
return ok();
};
/**
* Check if workspace has access to a specific feature
*/
export const ensureCanUseWorkspacePlanFeatureFragment = (loaders) => async ({ workspaceId, feature }) => {
const ensuredWorkspacesEnabled = await ensureWorkspacesEnabledFragment(loaders)({});
if (ensuredWorkspacesEnabled.isErr)
return err(ensuredWorkspacesEnabled.error);
const ensuredNotReadOnly = await ensureWorkspaceNotReadOnlyFragment(loaders)({
workspaceId
});
if (ensuredNotReadOnly.isErr)
return err(ensuredNotReadOnly.error);
const workspacePlan = await loaders.getWorkspacePlan({ workspaceId });
if (!workspacePlan)
return err(new WorkspaceNoAccessError());
const featureFlags = await loaders.getEnv();
const canUseFeature = workspacePlanHasAccessToFeature({
plan: workspacePlan.name,
feature,
featureFlags
});
return canUseFeature ? ok() : err(new WorkspacePlanNoFeatureAccessError());
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya3NwYWNlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9hdXRoei9mcmFnbWVudHMvd29ya3NwYWNlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsR0FBRyxFQUFFLEVBQUUsRUFBRSxNQUFNLGtCQUFrQixDQUFBO0FBRTFDLE9BQU8sRUFDTCxtQkFBbUIsRUFDbkIsdUJBQXVCLEVBQ3hCLE1BQU0sNEJBQTRCLENBQUE7QUFDbkMsT0FBTyxFQUNMLDRCQUE0QixFQUM1QixvQkFBb0IsRUFJcEIsMkJBQTJCLEVBQzNCLHNCQUFzQixFQUN0QiwwQkFBMEIsRUFDMUIsa0NBQWtDLEVBQ2xDLGlDQUFpQyxFQUNqQyxzQkFBc0IsRUFDdEIseUJBQXlCLEVBQ3pCLGdDQUFnQyxFQUNqQyxNQUFNLHlCQUF5QixDQUFBO0FBRWhDLE9BQU8sRUFBRSxLQUFLLEVBQWtCLE1BQU0seUJBQXlCLENBQUE7QUFPL0QsT0FBTyxFQUFFLDZCQUE2QixFQUFFLE1BQU0sbUNBQW1DLENBQUE7QUFDakYsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLDRCQUE0QixDQUFBO0FBQzFELE9BQU8sRUFBRSwrQkFBK0IsRUFBRSxNQUFNLGFBQWEsQ0FBQTtBQUM3RCxPQUFPLEVBRUwsK0JBQStCLEVBQ2hDLE1BQU0sc0NBQXNDLENBQUE7QUFFN0M7O0dBRUc7QUFDSCxNQUFNLENBQUMsTUFBTSxxQ0FBcUMsR0FZaEQsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUNaLEtBQUssRUFBRSxFQUFFLE1BQU0sRUFBRSxXQUFXLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRTtJQUN0QyxNQUFNLFVBQVUsR0FBRyxJQUFJLElBQUksS0FBSyxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUE7SUFDaEQsTUFBTSxxQkFBcUIsR0FBRyxVQUFVLEtBQUssS0FBSyxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUE7SUFFbEUsZ0VBQWdFO0lBQ2hFLE1B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QUU1RCxNQUFNLFlBQVksR0FBRyxNQUFNLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQTtJQUMzQyxNQUFNLGFBQWEsR0FBRywrQkFBK0IsQ0FBQztRQUNwRCxJQUFJLEVBQUUsYUFBYSxDQUFDLElBQUk7UUFDeEIsT0FBTztRQUNQLFlBQVk7S0FDYixDQUFDLENBQUE7SUFDRixPQUFPLGFBQWEsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLGlDQUFpQyxFQUFFLENBQUMsQ0FBQTtBQUM1RSxDQUFDLENBQUEiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBlcnIsIG9rIH0gZnJvbSAndHJ1ZS1teXRoL3Jlc3VsdCdcclxuaW1wb3J0IHsgQXV0aFBvbGljeUVuc3VyZUZyYWdtZW50IH0gZnJvbSAnLi4vZG9tYWluL3BvbGljaWVzLmpzJ1xyXG5pbXBvcnQge1xyXG4gIGhhc0FueVdvcmtzcGFjZVJvbGUsXHJcbiAgaGFzTWluaW11bVdvcmtzcGFjZVJvbGVcclxufSBmcm9tICcuLi9jaGVja3Mvd29ya3NwYWNlUm9sZS5qcydcclxuaW1wb3J0IHtcclxuICBQZXJzb25hbFByb2plY3RzTGltaXRlZEVycm9yLFxyXG4gIFByb2plY3ROb3RGb3VuZEVycm9yLFxyXG4gIFNlcnZlck5vQWNjZXNzRXJyb3IsXHJcbiAgU2VydmVyTm9TZXNzaW9uRXJyb3IsXHJcbiAgU2VydmVyTm90RW5vdWdoUGVybWlzc2lvbnNFcnJvcixcclxuICBXb3Jrc3BhY2VMaW1pdHNSZWFjaGVkRXJyb3IsXHJcbiAgV29ya3NwYWNlTm9BY2Nlc3NFcnJvcixcclxuICBXb3Jrc3BhY2VOb0VkaXRvclNlYXRFcnJvcixcclxuICBXb3Jrc3BhY2VOb3RFbm91Z2hQZXJtaXNzaW9uc0Vycm9yLFxyXG4gIFdvcmtzcGFjZVBsYW5Ob0ZlYXR1cmVBY2Nlc3NFcnJvcixcclxuICBXb3Jrc3BhY2VSZWFkT25seUVycm9yLFxyXG4gIFdvcmtzcGFjZXNOb3RFbmFibGVkRXJyb3IsXHJcbiAgV29ya3NwYWNlU3NvU2Vzc2lvbk5vQWNjZXNzRXJyb3JcclxufSBmcm9tICcuLi9kb21haW4vYXV0aEVycm9ycy5qcydcclxuaW1wb3J0IHsgTG9hZGVycyB9IGZyb20gJy4uL2RvbWFpbi9sb2FkZXJzLmpzJ1xyXG5pbXBvcnQgeyBSb2xlcywgV29ya3NwYWNlUm9sZXMgfSBmcm9tICcuLi8uLi9jb3JlL2NvbnN0YW50cy5qcydcclxuaW1wb3J0IHtcclxuICBNYXliZVVzZXJDb250ZXh0LFxyXG4gIE1heWJlV29ya3NwYWNlQ29udGV4dCxcclxuICBQcm9qZWN0Q29udGV4dCxcclxuICBXb3Jrc3BhY2VDb250ZXh0XHJcbn0gZnJvbSAnLi4vZG9tYWluL2NvbnRleHQuanMnXHJcbmltcG9ydCB7IGlzV29ya3NwYWNlUGxhblN0YXR1c1JlYWRPbmx5IH0gZnJvbSAnLi4vLi4vd29ya3NwYWNlcy9oZWxwZXJzL3BsYW5zLmpzJ1xyXG5pbXBvcnQgeyBoYXNFZGl0b3JTZWF0IH0gZnJvbSAnLi4vY2hlY2tzL3dvcmtzcGFjZVNlYXQuanMnXHJcbmltcG9ydCB7IGVuc3VyZU1pbmltdW1TZXJ2ZXJSb2xlRnJhZ21lbnQgfSBmcm9tICcuL3NlcnZlci5qcydcclxuaW1wb3J0IHtcclxuICBXb3Jrc3BhY2VQbGFuRmVhdHVyZXMsXHJcbiAgd29ya3NwYWNlUGxhbkhhc0FjY2Vzc1RvRmVhdHVyZVxyXG59IGZyb20gJy4uLy4uL3dvcmtzcGFjZXMvaGVscGVycy9mZWF0dXJlcy5qcydcclxuXHJcbi8qKlxyXG4gKiBFbnN1cmUgdXNlciBoYXMgYSB3b3Jrc3BhY2Ugcm9sZSwgYW5kIGEgdmFsaWQgU1NPIHNlc3Npb24gKGlmIFNTTyBpcyBjb25maWd1cmVkKVxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGVuc3VyZVdvcmtzcGFjZVJvbGVBbmRTZXNzaW9uRnJhZ21lbnQ6IEF1dGhQb2xpY3lFbnN1cmVGcmFnbWVudDxcclxuICB8ICdnZXRXb3Jrc3BhY2VSb2xlJ1xyXG4gIHwgJ2dldFdvcmtzcGFjZVNzb1Byb3ZpZGVyJ1xyXG4gIHwgJ2dldFdvcmtzcGFjZVNzb1Nlc3Npb24nXHJcbiAgfCAnZ2V0V29ya3NwYWNlJyxcclxuICB7IHVzZXJJZDogc3RyaW5nOyB3b3Jrc3BhY2VJZDogc3RyaW5nOyByb2xlPzogV29ya3NwYWNlUm9sZXMgfSxcclxuICBJbnN0YW5jZVR5cGU8XHJcbiAgICB8IHR5cGVvZiBXb3Jrc3BhY2VTc29TZXNzaW9uTm9BY2Nlc3NFcnJvclxyXG4gICAgfCB0eXBlb2YgV29ya3NwYWNlTm9BY2Nlc3NFcnJvclxyXG4gICAgfCB0eXBlb2YgV29ya3NwYWNlTm90RW5vdWdoUGVybWlzc2lvbnNFcnJvclxyXG4gID5cclxuPiA9XHJcbiAgKGxvYWRlcnMpID0+XHJcbiAgYXN5bmMgKHsgdXNlcklkLCB3b3Jrc3BhY2VJZCwgcm9sZSB9KSA9PiB7XHJcbiAgICBjb25zdCB0ZXN0ZWRSb2xlID0gcm9sZSA/PyBSb2xlcy5Xb3Jrc3BhY2UuR3Vlc3RcclxuICAgIGNvbnN0IHRlc3RpbmdGb3JNaW5pbXVtUm9sZSA9IHRlc3RlZFJvbGUgPT09IFJvbGVzLldvcmtzcGFjZS5HdWVzdFxyXG5cclxuICAgIC8vIEdldCB3b3Jrc3BhY2UsIHNvIHdlIGNhbiByZXNvbHZlIGl0cyBzbHVnIGZvciBlcnJvciBzY2VuYXJpb3NcclxuICAgIGNvbnN0IHdvcmtzcGFjZSA9IGF3YWl0IGxvYWRlcnMuZ2V0V29ya3NwYWNlKHsgd29ya3NwYWNlSWQgfSlcclxuICAgIC8vIGhpZGVzIHRoZSBmYWN0LCB0aGF0IHRoZSB3b3Jrc3BhY2UgZG9lcyBub3QgZXhpc3RcclxuICAgIGlmICghd29ya3NwYWNlKSByZXR1cm4gZXJyKG5ldyBXb3Jrc3BhY2VOb0FjY2Vzc0Vycm9yKCkpXHJcblxyXG4gICAgY29uc3QgaGFzTWluaW11bVJvbGUgPSBhd2FpdCBoYXNNaW5pbXVtV29ya3NwYWNlUm9sZShsb2FkZXJzKSh7XHJcbiAgICAgIHVzZXJJZCxcclxuICAgICAgd29ya3NwYWNlSWQsXHJcbiAgICAgIHJvbGU6IHRlc3RlZFJvbGVcclxuICAgIH0pXHJcbiAgICBpZiAoIWhhc01pbmltdW1Sb2xlKVxyXG4gICAgICByZXR1cm4gZXJyKFxyXG4gICAgICAgIHRlc3RpbmdGb3JNaW5pbXVtUm9sZVxyXG4gICAgICAgICAgPyBuZXcgV29ya3NwYWNlTm9BY2Nlc3NFcnJvcigpXHJcbiAgICAgICAgICA6IG5ldyBXb3Jrc3BhY2VOb3RFbm91Z2hQZXJtaXNzaW9uc0Vycm9yKClcclxuICAgICAgKVxyXG5cclxuICAgIGNvbnN0IGhhc01pbmltdW1NZW1iZXJSb2xlID0gYXdhaXQgaGFzTWluaW11bVdvcmtzcGFjZVJvbGUobG9hZGVycykoe1xyXG4gICAgICB1c2VySWQsXHJcbiAgICAgIHdvcmtzcGFjZUlkLFxyXG4gICAgICByb2xlOiAnd29ya3NwYWNlOm1lbWJlcidcclxuICAgIH0pXHJcbiAgICAvLyBvbmx5IG1lbWJlcnMgYW5kIGFib3ZlIG5lZWQgdG8gdXNlIHNzb1xyXG4gICAgaWYgKCFoYXNNaW5pbXVtTWVtYmVyUm9sZSkgcmV0dXJuIG9rKClcclxuXHJcbiAgICBjb25zdCB3b3Jrc3BhY2VTc29Qcm92aWRlciA9IGF3YWl0IGxvYWRlcnMuZ2V0V29ya3NwYWNlU3NvUHJvdmlkZXIoe1xyXG4gICAgICB3b3Jrc3BhY2VJZFxyXG4gICAgfSlcclxuICAgIGlmICghd29ya3NwYWNlU3NvUHJvdmlkZXIpIHJldHVybiBvaygpXHJcblxyXG4gICAgY29uc3Qgd29ya3NwYWNlU3NvU2Vzc2lvbiA9IGF3YWl0IGxvYWRlcnMuZ2V0V29ya3NwYWNlU3NvU2Vzc2lvbih7XHJcbiAgICAgIHVzZXJJZCxcclxuICAgICAgd29ya3NwYWNlSWRcclxuICAgIH0pXHJcbiAgICBpZiAoIXdvcmtzcGFjZVNzb1Nlc3Npb24pXHJcbiAgICAgIHJldHVybiBlcnIoXHJcbiAgICAgICAgbmV3IFdvcmtzcGFjZVNzb1Nlc3Npb25Ob0FjY2Vzc0Vycm9yKHtcclxuICAgICAgICAgIHBheWxvYWQ6IHsgd29ya3NwYWNlU2x1Zzogd29ya3NwYWNlLnNsdWcgfVxyXG4gICAgICAgIH0pXHJcbiAgICAgIClcclxuXHJcbiAgICBjb25zdCBpc0V4cGlyZWRTZXNzaW9uID1cclxuICAgICAgbmV3IERhdGUoKS5nZXRUaW1lKCkgPiB3b3Jrc3BhY2VTc29TZXNzaW9uLnZhbGlkVW50aWwuZ2V0VGltZSgpXHJcblxyXG4gICAgaWYgKGlzRXhwaXJlZFNlc3Npb24pXHJcbiAgICAgIHJldHVybiBlcnIoXHJcbiAgICAgICAgbmV3IFdvcmtzcGFjZVNzb1Nlc3Npb25Ob0FjY2Vzc0Vycm9yKHtcclxuICAgICAgICAgIHBheWxvYWQ6IHsgd29ya3NwYWNlU2x1Zzogd29ya3NwYWNlLnNsdWcgfVxyXG4gICAgICAgIH0pXHJcbiAgICAgIClcclxuXHJcbiAgICByZXR1cm4gb2soKVxyXG4gIH1cclxuXHJcbi8qKlxyXG4gKiBFbnN1cmUgdGhlIHdvcmtzcGFjZXMgbW9kdWxlIGlzIGVuYWJsZWRcclxuICovXHJcbmV4cG9ydCBjb25zdCBlbnN1cmVXb3Jrc3BhY2VzRW5hYmxlZEZyYWdtZW50OiBBdXRoUG9saWN5RW5zdXJlRnJhZ21lbnQ8XHJcbiAgdHlwZW9mIExvYWRlcnMuZ2V0RW52LFxyXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZW1wdHktb2JqZWN0LXR5cGVcclxuICB7fSxcclxuICBJbnN0YW5jZVR5cGU8dHlwZW9mIFdvcmtzcGFjZXNOb3RFbmFibGVkRXJyb3I+XHJcbj4gPSAobG9hZGVycykgPT4gYXN5bmMgKCkgPT4ge1xyXG4gIGNvbnN0IGVudiA9IGF3YWl0IGxvYWRlcnMuZ2V0RW52KClcclxuICBpZiAoIWVudi5GRl9XT1JLU1BBQ0VTX01PRFVMRV9FTkFCTEVEKSByZXR1cm4gZXJyKG5ldyBXb3Jrc3BhY2VzTm90RW5hYmxlZEVycm9yKCkpXHJcbiAgcmV0dXJuIG9rKClcclxufVxyXG5cclxuLyoqXHJcbiAqIEVuc3VyZSB3b3Jrc3BhY2UgaXMgbm90IHJlYWQtb25seVxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGVuc3VyZVdvcmtzcGFjZU5vdFJlYWRPbmx5RnJhZ21lbnQ6IEF1dGhQb2xpY3lFbnN1cmVGcmFnbWVudDxcclxuICB0eXBlb2YgTG9hZGVycy5nZXRXb3Jrc3BhY2VQbGFuLFxyXG4gIFdvcmtzcGFjZUNvbnRleHQsXHJcbiAgSW5zdGFuY2VUeXBlPHR5cGVvZiBXb3Jrc3BhY2VOb0FjY2Vzc0Vycm9yIHwgdHlwZW9mIFdvcmtzcGFjZVJlYWRPbmx5RXJyb3I+XHJcbj4gPVxyXG4gIChsb2FkZXJzKSA9PlxyXG4gIGFzeW5jICh7IHdvcmtzcGFjZUlkIH0pID0+IHtcclxuICAgIGNvbnN0IHdvcmtzcGFjZVBsYW4gPSBhd2FpdCBsb2FkZXJzLmdldFdvcmtzcGFjZVBsYW4oeyB3b3Jrc3BhY2VJZCB9KVxyXG4gICAgaWYgKCF3b3Jrc3BhY2VQbGFuKSByZXR1cm4gZXJyKG5ldyBXb3Jrc3BhY2VOb0FjY2Vzc0Vycm9yKCkpXHJcbiAgICBpZiAoaXNXb3Jrc3BhY2VQbGFuU3RhdHVzUmVhZE9ubHkod29ya3NwYWNlUGxhbi5zdGF0dXMpKVxyXG4gICAgICByZXR1cm4gZXJyKG5ldyBXb3Jrc3BhY2VSZWFkT25seUVycm9yKCkpXHJcblxyXG4gICAgcmV0dXJuIG9rKClcclxuICB9XHJcblxyXG4vKipcclxuICogRW5zdXJlIHdvcmtzcGFjZSBjYW4gYWNjZXB0IG5ldyBwcm9qZWN0IChub3QgcmVhZC1vbmx5LCBsaW1pdHMgbm90IHJlYWNoZWQpLlxyXG4gKiBJZiB1c2VySWQgaXMgc3BlY2lmaWVkLCB3aWxsIGFsc28gY2hlY2sgZm9yIHVzZXIgcm9sZSAmIHNlYXRcclxuICovXHJcbmV4cG9ydCBjb25zdCBlbnN1cmVXb3Jrc3BhY2VQcm9qZWN0Q2FuQmVDcmVhdGVkRnJhZ21lbnQ6IEF1dGhQb2xpY3lFbnN1cmVGcmFnbWVudDxcclxuICB8IHR5cGVvZiBMb2FkZXJzLmdldFdvcmtzcGFjZVBsYW5cclxuICB8IHR5cGVvZiBMb2FkZXJzLmdldFdvcmtzcGFjZVNlYXRcclxuICB8IHR5cGVvZiBMb2FkZXJzLmdldFdvcmtzcGFjZVJvbGVcclxuICB8IHR5cGVvZiBMb2FkZXJzLmdldFdvcmtzcGFjZUxpbWl0c1xyXG4gIHwgdHlwZW9mIExvYWRlcnMuZ2V0V29ya3NwYWNlUHJvamVjdENvdW50LFxyXG4gIFdvcmtzcGFjZUNvbnRleHQgJiBNYXliZVVzZXJDb250ZXh0LFxyXG4gIEluc3RhbmNlVHlwZTxcclxuICAgIHwgdHlwZW9mIFdvcmtzcGFjZU5vQWNjZXNzRXJyb3JcclxuICAgIHwgdHlwZW9mIFdvcmtzcGFjZVJlYWRPbmx5RXJyb3JcclxuICAgIHwgdHlwZW9mIFdvcmtzcGFjZUxpbWl0c1JlYWNoZWRFcnJvclxyXG4gICAgfCB0eXBlb2YgV29ya3NwYWNlTm9FZGl0b3JTZWF0RXJyb3JcclxuICAgIHwgdHlwZW9mIFdvcmtzcGFjZU5vdEVub3VnaFBlcm1pc3Npb25zRXJyb3JcclxuICA+XHJcbj4gPVxyXG4gIChsb2FkZXJzKSA9PlxyXG4gIGFzeW5jICh7IHdvcmtzcGFjZUlkLCB1c2VySWQgfSkgPT4ge1xyXG4gICAgLy8gRmlyc3QgY2hlY2sgdXNlciBldmVuIGhhcyBhY2Nlc3NcclxuICAgIGlmICh1c2VySWQpIHtcclxuICAgICAgLy8gSXMgTWVtYmVyK1xyXG4gICAgICBjb25zdCBpc05vdEd1ZXN0ID0gYXdhaXQgaGFzTWluaW11bVdvcmtzcGFjZVJvbGUobG9hZGVycykoe1xyXG4gICAgICAgIHVzZXJJZCxcclxuICAgICAgICB3b3Jrc3BhY2VJZCxcclxuICAgICAgICByb2xlOiBSb2xlcy5Xb3Jrc3BhY2UuTWVtYmVyXHJcbiAgICAgIH0pXHJcbiAgICAgIGlmICghaXNOb3RHdWVzdCkge1xyXG4gICAgICAgIHJldHVybiBlcnIoXHJcbiAgICAgICAgICBuZXcgV29ya3NwYWNlTm90RW5vdWdoUGVybWlzc2lvbnNFcnJvcihcclxuICAgICAgICAgICAgJ0d1ZXN0cyBjYW5ub3QgY3JlYXRlIHByb2plY3RzIGluIHRoZSB3b3Jrc3BhY2UnXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgKVxyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgZW5zdXJlZE5vdFJlYWRPbmx5ID0gYXdhaXQgZW5zdXJlV29ya3NwYWNlTm90UmVhZE9ubHlGcmFnbWVudChsb2FkZXJzKSh7XHJcbiAgICAgIHdvcmtzcGFjZUlkXHJcbiAgICB9KVxyXG4gICAgaWYgKGVuc3VyZWROb3RSZWFkT25seS5pc0VycikgcmV0dXJuIGVycihlbnN1cmVkTm90UmVhZE9ubHkuZXJyb3IpXHJcblxyXG4gICAgY29uc3Qgd29ya3NwYWNlUGxhbiA9IGF3YWl0IGxvYWRlcnMuZ2V0V29ya3NwYWNlUGxhbih7IHdvcmtzcGFjZUlkIH0pXHJcbiAgICBpZiAoIXdvcmtzcGFjZVBsYW4pIHJldHVybiBlcnIobmV3IFdvcmtzcGFjZU5vQWNjZXNzRXJyb3IoKSlcclxuXHJcbiAgICAvLyBOb3cgY2hlY2sgZWRpdG9yIHNlYXRcclxuICAgIGlmICh1c2VySWQpIHtcclxuICAgICAgY29uc3QgaXNFZGl0b3IgPSBhd2FpdCBoYXNFZGl0b3JTZWF0KGxvYWRlcnMpKHtcclxuICAgICAgICB1c2VySWQsXHJcbiAgICAgICAgd29ya3NwYWNlSWRcclxuICAgICAgfSlcclxuICAgICAgaWYgKCFpc0VkaXRvcikgcmV0dXJuIGVycihuZXcgV29ya3NwYWNlTm9FZGl0b3JTZWF0RXJyb3IoKSlcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB3b3Jrc3BhY2VMaW1pdHMgPSBhd2FpdCBsb2FkZXJzLmdldFdvcmtzcGFjZUxpbWl0cyh7IHdvcmtzcGFjZUlkIH0pXHJcbiAgICBpZiAoIXdvcmtzcGFjZUxpbWl0cykgcmV0dXJuIGVycihuZXcgV29ya3NwYWNlTm9BY2Nlc3NFcnJvcigpKVxyXG5cclxuICAgIC8vIG5vIGxpbWl0cyBpbXBvc2VkXHJcbiAgICBpZiAod29ya3NwYWNlTGltaXRzLnByb2plY3RDb3VudCA9PT0gbnVsbCkgcmV0dXJuIG9rKClcclxuICAgIGNvbnN0IGN1cnJlbnRQcm9qZWN0Q291bnQgPSBhd2FpdCBsb2FkZXJzLmdldFdvcmtzcGFjZVByb2plY3RDb3VudCh7XHJcbiAgICAgIHdvcmtzcGFjZUlkXHJcbiAgICB9KVxyXG5cclxuICAgIC8vIHRoaXMgd2lsbCBub3QgaGFwcGVuIGluIHByYWN0aWNlXHJcbiAgICBpZiAoY3VycmVudFByb2plY3RDb3VudCA9PT0gbnVsbCkgcmV0dXJuIGVycihuZXcgV29ya3NwYWNlTm9BY2Nlc3NFcnJvcigpKVxyXG5cclxuICAgIHJldHVybiBjdXJyZW50UHJvamVjdENvdW50IDwgd29ya3NwYWNlTGltaXRzLnByb2plY3RDb3VudFxyXG4gICAgICA/IG9rKClcclxuICAgICAgOiBlcnIoXHJcbiAgICAgICAgICBuZXcgV29ya3NwYWNlTGltaXRzUmVhY2hlZEVycm9yKHtcclxuICAgICAgICAgICAgbWVzc2FnZTpcclxuICAgICAgICAgICAgICAnWW91IGhhdmUgcmVhY2hlZCB0aGUgbWF4aW11bSBudW1iZXIgb2YgcHJvamVjdHMgZm9yIHlvdXIgcGxhbi4gVXBncmFkZSB0byBpbmNyZWFzZSBpdC4nLFxyXG4gICAgICAgICAgICBwYXlsb2FkOiB7IGxpbWl0OiAncHJvamVjdENvdW50JyB9XHJcbiAgICAgICAgICB9KVxyXG4gICAgICAgIClcclxuICB9XHJcblxyXG4vKipcclxuICogRW5zdXJlIG1vZGVsIGNhbiBiZSBjcmVhdGVkICh3b3Jrc3BhY2Ugbm90IHJlYWQtb25seSwgbGltaXRzIG5vdCByZWFjaGVkKS5cclxuICogSWYgdXNlcklkIGlzIHNwZWNpZmllZCwgd2lsbCBhbHNvIGNoZWNrIGZvciBhcHByb3ByaWF0ZSB1c2VyIHJvbGUgJiBzZWF0XHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZW5zdXJlTW9kZWxDYW5CZUNyZWF0ZWRGcmFnbWVudDogQXV0aFBvbGljeUVuc3VyZUZyYWdtZW50PFxyXG4gIHwgdHlwZW9mIExvYWRlcnMuZ2V0RW52XHJcbiAgfCB0eXBlb2YgTG9hZGVycy5nZXRXb3Jrc3BhY2VQbGFuXHJcbiAgfCB0eXBlb2YgTG9hZGVycy5nZXRXb3Jrc3BhY2VSb2xlXHJcbiAgfCB0eXBlb2YgTG9hZGVycy5nZXRXb3Jrc3BhY2VMaW1pdHNcclxuICB8IHR5cGVvZiBMb2FkZXJzLmdldFByb2plY3RcclxuICB8IHR5cGVvZiBMb2FkZXJzLmdldFdvcmtzcGFjZU1vZGVsQ291bnQsXHJcbiAgUHJvamVjdENvbnRleHQgJlxyXG4gICAgTWF5YmVXb3Jrc3BhY2VDb250ZXh0ICZcclxuICAgIE1heWJlVXNlckNvbnRleHQgJiB7XHJcbiAgICAgIC8qKlxyXG4gICAgICAgKiBIb3cgbWFueSBtb2RlbHMgd2UncmUgdGVzdGluZyBiZWluZyBhZGRlZC4gRGVmYXVsdHMgdG8gMVxyXG4gICAgICAgKi9cclxuICAgICAgYWRkZWRNb2RlbENvdW50PzogbnVtYmVyXHJcbiAgICB9LFxyXG4gIEluc3RhbmNlVHlwZTxcclxuICAgIHwgdHlwZW9mIFdvcmtzcGFjZU5vQWNjZXNzRXJyb3JcclxuICAgIHwgdHlwZW9mIFdvcmtzcGFjZVJlYWRPbmx5RXJyb3JcclxuICAgIHwgdHlwZW9mIFdvcmtzcGFjZUxpbWl0c1JlYWNoZWRFcnJvclxyXG4gICAgfCB0eXBlb2YgUHJvamVjdE5vdEZvdW5kRXJyb3JcclxuICAgIHwgdHlwZW9mIFBlcnNvbmFsUHJvamVjdHNMaW1pdGVkRXJyb3JcclxuICA+XHJcbj4gPVxyXG4gIChsb2FkZXJzKSA9PlxyXG4gIGFzeW5jICh7IHByb2plY3RJZCwgdXNlcklkLCBhZGRlZE1vZGVsQ291bnQsIHdvcmtzcGFjZUlkIH0pID0+IHtcclxuICAgIGFkZGVkTW9kZWxDb3VudCA9IGFkZGVkTW9kZWxDb3VudCA/PyAxXHJcblxyXG4gICAgY29uc3QgeyBGRl9XT1JLU1BBQ0VTX01PRFVMRV9FTkFCTEVELCBGRl9QRVJTT05BTF9QUk9KRUNUU19MSU1JVFNfRU5BQkxFRCB9ID1cclxuICAgICAgYXdhaXQgbG9hZGVycy5nZXRFbnYoKVxyXG4gICAgY29uc3QgcHJvamVjdCA9IGF3YWl0IGxvYWRlcnMuZ2V0UHJvamVjdCh7IHByb2plY3RJZCB9KVxyXG4gICAgaWYgKCFwcm9qZWN0KSByZXR1cm4gZXJyKG5ldyBQcm9qZWN0Tm90Rm91bmRFcnJvcigpKVxyXG5cclxuICAgIC8vIFByb2plY3QgbWF5IG5vdCBiZSBhdHRhY2hlZCB0byBhIHdvcmtzcGFjZSB5ZXQsIHRoZW4gd2UgdXNlIHRoZSBzcGVjaWZpZWQgd29ya3NwYWNlSWRcclxuICAgIHdvcmtzcGFjZUlkID0gd29ya3NwYWNlSWQgfHwgcHJvamVjdC53b3Jrc3BhY2VJZCB8fCB1bmRlZmluZWRcclxuXHJcbiAgICAvLyBJZiB3b3Jrc3BhY2VcclxuICAgIGlmICh3b3Jrc3BhY2VJZCAmJiBGRl9XT1JLU1BBQ0VTX01PRFVMRV9FTkFCTEVEKSB7XHJcbiAgICAgIGlmICh1c2VySWQpIHtcclxuICAgICAgICAvLyBIYXMgd29ya3NwYWNlIHJvbGVcclxuICAgICAgICBjb25zdCBpc0luV29ya3NwYWNlID0gYXdhaXQgaGFzQW55V29ya3NwYWNlUm9sZShsb2FkZXJzKSh7XHJcbiAgICAgICAgICB1c2VySWQsXHJcbiAgICAgICAgICB3b3Jrc3BhY2VJZFxyXG4gICAgICAgIH0pXHJcbiAgICAgICAgaWYgKCFpc0luV29ya3NwYWNlKSB7XHJcbiAgICAgICAgICByZXR1cm4gZXJyKG5ldyBXb3Jrc3BhY2VOb0FjY2Vzc0Vycm9yKCkpXHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBjb25zdCBlbnN1cmVkTm90UmVhZE9ubHkgPSBhd2FpdCBlbnN1cmVXb3Jrc3BhY2VOb3RSZWFkT25seUZyYWdtZW50KGxvYWRlcnMpKHtcclxuICAgICAgICB3b3Jrc3BhY2VJZFxyXG4gICAgICB9KVxyXG4gICAgICBpZiAoZW5zdXJlZE5vdFJlYWRPbmx5LmlzRXJyKSByZXR1cm4gZXJyKGVuc3VyZWROb3RSZWFkT25seS5lcnJvcilcclxuXHJcbiAgICAgIGNvbnN0IHdvcmtzcGFjZVBsYW4gPSBhd2FpdCBsb2FkZXJzLmdldFdvcmtzcGFjZVBsYW4oeyB3b3Jrc3BhY2VJZCB9KVxyXG4gICAgICBpZiAoIXdvcmtzcGFjZVBsYW4pIHJldHVybiBlcnIobmV3IFdvcmtzcGFjZU5vQWNjZXNzRXJyb3IoKSlcclxuXHJcbiAgICAgIGNvbnN0IHdvcmtzcGFjZUxpbWl0cyA9IGF3YWl0IGxvYWRlcnMuZ2V0V29ya3NwYWNlTGltaXRzKHsgd29ya3NwYWNlSWQgfSlcclxuICAgICAgaWYgKCF3b3Jrc3BhY2VMaW1pdHMpIHJldHVybiBlcnIobmV3IFdvcmtzcGFjZU5vQWNjZXNzRXJyb3IoKSlcclxuXHJcbiAgICAgIGlmICh3b3Jrc3BhY2VMaW1pdHMubW9kZWxDb3VudCA9PT0gbnVsbCkgcmV0dXJuIG9rKClcclxuXHJcbiAgICAgIGNvbnN0IGN1cnJlbnRNb2RlbENvdW50ID0gYXdhaXQgbG9hZGVycy5nZXRXb3Jrc3BhY2VNb2RlbENvdW50KHsgd29ya3NwYWNlSWQgfSlcclxuXHJcbiAgICAgIGlmIChjdXJyZW50TW9kZWxDb3VudCA9PT0gbnVsbCkgcmV0dXJuIGVycihuZXcgV29ya3NwYWNlTm9BY2Nlc3NFcnJvcigpKVxyXG5cclxuICAgICAgcmV0dXJuIGN1cnJlbnRNb2RlbENvdW50ICsgYWRkZWRNb2RlbENvdW50IDw9IHdvcmtzcGFjZUxpbWl0cy5tb2RlbENvdW50XHJcbiAgICAgICAgPyBvaygpXHJcbiAgICAgICAgOiBlcnIoXHJcbiAgICAgICAgICAgIG5ldyBXb3Jrc3BhY2VMaW1pdHNSZWFjaGVkRXJyb3Ioe1xyXG4gICAgICAgICAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAnWW91IGhhdmUgcmVhY2hlZCB0aGUgbWF4aW11bSBudW1iZXIgb2YgbW9kZWxzIGZvciB5b3VyIHBsYW4uIFVwZ3JhZGUgdG8gaW5jcmVhc2UgaXQuJyxcclxuICAgICAgICAgICAgICBwYXlsb2FkOiB7XHJcbiAgICAgICAgICAgICAgICBsaW1pdDogJ21vZGVsQ291bnQnXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9KVxyXG4gICAgICAgICAgKVxyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSWYgbm90IC0gY2hlY2sgcGVyc29uYWwgcHJvamVjdCBsaW1pdHNcclxuICAgICAgaWYgKEZGX1BFUlNPTkFMX1BST0pFQ1RTX0xJTUlUU19FTkFCTEVEKSB7XHJcbiAgICAgICAgcmV0dXJuIGVycihcclxuICAgICAgICAgIG5ldyBQZXJzb25hbFByb2plY3RzTGltaXRlZEVycm9yKFxyXG4gICAgICAgICAgICAnTm8gbmV3IG1vZGVscyBjYW4gYmUgYWRkZWQgdG8gcGVyc29uYWwgcHJvamVjdHMnXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgKVxyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gb2soKVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbmV4cG9ydCBjb25zdCBlbnN1cmVVc2VySXNXb3Jrc3BhY2VBZG1pbkZyYWdtZW50OiBBdXRoUG9saWN5RW5zdXJlRnJhZ21lbnQ8XHJcbiAgfCB0eXBlb2YgTG9hZGVycy5nZXRFbnZcclxuICB8IHR5cGVvZiBMb2FkZXJzLmdldFNlcnZlclJvbGVcclxuICB8IHR5cGVvZiBMb2FkZXJzLmdldFdvcmtzcGFjZVxyXG4gIHwgdHlwZW9mIExvYWRlcnMuZ2V0V29ya3NwYWNlUm9sZVxyXG4gIHwgdHlwZW9mIExvYWRlcnMuZ2V0V29ya3NwYWNlU3NvUHJvdmlkZXJcclxuICB8IHR5cGVvZiBMb2FkZXJzLmdldFdvcmtzcGFjZVNzb1Nlc3Npb25cclxuICB8IHR5cGVvZiBMb2FkZXJzLmdldFdvcmtzcGFjZVBsYW4sXHJcbiAgV29ya3NwYWNlQ29udGV4dCAmIE1heWJlVXNlckNvbnRleHQsXHJcbiAgSW5zdGFuY2VUeXBlPFxyXG4gICAgfCB0eXBlb2YgV29ya3NwYWNlTm9BY2Nlc3NFcnJvclxyXG4gICAgfCB0eXBlb2YgV29ya3NwYWNlU3NvU2Vzc2lvbk5vQWNjZXNzRXJyb3JcclxuICAgIHwgdHlwZW9mIFdvcmtzcGFjZXNOb3RFbmFibGVkRXJyb3JcclxuICAgIHwgdHlwZW9mIFNlcnZlck5vU2Vzc2lvbkVycm9yXHJcbiAgICB8IHR5cGVvZiBTZXJ2ZXJOb0FjY2Vzc0Vycm9yXHJcbiAgICB8IHR5cGVvZiBTZXJ2ZXJOb3RFbm91Z2hQZXJtaXNzaW9uc0Vycm9yXHJcbiAgICB8IHR5cGVvZiBXb3Jrc3BhY2VOb3RFbm91Z2hQZXJtaXNzaW9uc0Vycm9yXHJcbiAgPlxyXG4+ID1cclxuICAobG9hZGVycykgPT5cclxuICBhc3luYyAoeyB1c2VySWQsIHdvcmtzcGFjZUlkIH0pID0+IHtcclxuICAgIGNvbnN0IGVuc3VyZWRXb3Jrc3BhY2VzRW5hYmxlZCA9IGF3YWl0IGVuc3VyZVdvcmtzcGFjZXNFbmFibGVkRnJhZ21lbnQobG9hZGVycykoe30pXHJcbiAgICBpZiAoZW5zdXJlZFdvcmtzcGFjZXNFbmFibGVkLmlzRXJyKSByZXR1cm4gZXJyKGVuc3VyZWRXb3Jrc3BhY2VzRW5hYmxlZC5lcnJvcilcclxuXHJcbiAgICBjb25zdCBlbnN1cmVkU2VydmVyUm9sZSA9IGF3YWl0IGVuc3VyZU1pbmltdW1TZXJ2ZXJSb2xlRnJhZ21lbnQobG9hZGVycykoe1xyXG4gICAgICB1c2VySWQsXHJcbiAgICAgIHJvbGU6IFJvbGVzLlNlcnZlci5Vc2VyXHJcbiAgICB9KVxyXG5cclxuICAgIGlmIChlbnN1cmVkU2VydmVyUm9sZS5pc0VycikgcmV0dXJuIGVycihlbnN1cmVkU2VydmVyUm9sZS5lcnJvcilcclxuXHJcbiAgICBjb25zdCBlbnN1cmVkV29ya3NwYWNlQWNjZXNzID0gYXdhaXQgZW5zdXJlV29ya3NwYWNlUm9sZUFuZFNlc3Npb25GcmFnbWVudChsb2FkZXJzKShcclxuICAgICAge1xyXG4gICAgICAgIHVzZXJJZDogdXNlcklkISxcclxuICAgICAgICB3b3Jrc3BhY2VJZCxcclxuICAgICAgICByb2xlOiBSb2xlcy5Xb3Jrc3BhY2UuQWRtaW5cclxuICAgICAgfVxyXG4gICAgKVxyXG4gICAgaWYgKGVuc3VyZWRXb3Jrc3BhY2VBY2Nlc3MuaXNFcnIpIHJldHVybiBlcnIoZW5zdXJlZFdvcmtzcGFjZUFjY2Vzcy5lcnJvcilcclxuICAgIHJldHVybiBvaygpXHJcbiAgfVxyXG5cclxuLyoqXHJcbiAqIENoZWNrIGlmIHdvcmtzcGFjZSBoYXMgYWNjZXNzIHRvIGEgc3BlY2lmaWMgZmVhdHVyZVxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGVuc3VyZUNhblVzZVdvcmtzcGFjZVBsYW5GZWF0dXJlRnJhZ21lbnQ6IEF1dGhQb2xpY3lFbnN1cmVGcmFnbWVudDxcclxuICB0eXBlb2YgTG9hZGVycy5nZXRXb3Jrc3BhY2VQbGFuIHwgdHlwZW9mIExvYWRlcnMuZ2V0RW52LFxyXG4gIFdvcmtzcGFjZUNvbnRleHQgJiB7IGZlYXR1cmU6IFdvcmtzcGFjZVBsYW5GZWF0dXJlcyB9LFxyXG4gIHwgSW5zdGFuY2VUeXBlPHR5cGVvZiBXb3Jrc3BhY2VOb0FjY2Vzc0Vycm9yPlxyXG4gIHwgSW5zdGFuY2VUeXBlPHR5cGVvZiBXb3Jrc3BhY2VSZWFkT25seUVycm9yPlxyXG4gIHwgSW5zdGFuY2VUeXBlPHR5cGVvZiBXb3Jrc3BhY2VQbGFuTm9GZWF0dXJlQWNjZXNzRXJyb3I+XHJcbiAgfCBJbnN0YW5jZVR5cGU8dHlwZW9mIFdvcmtzcGFjZXNOb3RFbmFibGVkRXJyb3I+XHJcbj4gPVxyXG4gIChsb2FkZXJzKSA9PlxyXG4gIGFzeW5jICh7IHdvcmtzcGFjZUlkLCBmZWF0dXJlIH0pID0+IHtcclxuICAgIGNvbnN0IGVuc3VyZWRXb3Jrc3BhY2VzRW5hYmxlZCA9IGF3YWl0IGVuc3VyZVdvcmtzcGFjZXNFbmFibGVkRnJhZ21lbnQobG9hZGVycykoe30pXHJcbiAgICBpZiAoZW5zdXJlZFdvcmtzcGFjZXNFbmFibGVkLmlzRXJyKSByZXR1cm4gZXJyKGVuc3VyZWRXb3Jrc3BhY2VzRW5hYmxlZC5lcnJvcilcclxuXHJcbiAgICBjb25zdCBlbnN1cmVkTm90UmVhZE9ubHkgPSBhd2FpdCBlbnN1cmVXb3Jrc3BhY2VOb3RSZWFkT25seUZyYWdtZW50KGxvYWRlcnMpKHtcclxuICAgICAgd29ya3NwYWNlSWRcclxuICAgIH0pXHJcbiAgICBpZiAoZW5zdXJlZE5vdFJlYWRPbmx5LmlzRXJyKSByZXR1cm4gZXJyKGVuc3VyZWROb3RSZWFkT25seS5lcnJvcilcclxuXHJcbiAgICBjb25zdCB3b3Jrc3BhY2VQbGFuID0gYXdhaXQgbG9hZGVycy5nZXRXb3Jrc3BhY2VQbGFuKHsgd29ya3NwYWNlSWQgfSlcclxuICAgIGlmICghd29ya3NwYWNlUGxhbikgcmV0dXJuIGVycihuZXcgV29ya3NwYWNlTm9BY2Nlc3NFcnJvcigpKVxyXG5cclxuICAgIGNvbnN0IGZlYXR1cmVGbGFncyA9IGF3YWl0IGxvYWRlcnMuZ2V0RW52KClcclxuICAgIGNvbnN0IGNhblVzZUZlYXR1cmUgPSB3b3Jrc3BhY2VQbGFuSGFzQWNjZXNzVG9GZWF0dXJlKHtcclxuICAgICAgcGxhbjogd29ya3NwYWNlUGxhbi5uYW1lLFxyXG4gICAgICBmZWF0dXJlLFxyXG4gICAgICBmZWF0dXJlRmxhZ3NcclxuICAgIH0pXHJcbiAgICByZXR1cm4gY2FuVXNlRmVhdHVyZSA/IG9rKCkgOiBlcnIobmV3IFdvcmtzcGFjZVBsYW5Ob0ZlYXR1cmVBY2Nlc3NFcnJvcigpKVxyXG4gIH1cclxuIl19