804 lines
93 KiB
Plaintext
804 lines
93 KiB
Plaintext
import { difference, flatten, isEqual, uniq } from "/_nuxt/node_modules/.cache/vite/client/deps/lodash-es.js?v=e4f18c29";
|
|
import {
|
|
useThrottleFn,
|
|
watchTriggerable,
|
|
useMagicKeys,
|
|
useEventListener
|
|
} from "/_nuxt/node_modules/@vueuse/core/index.mjs?v=e4f18c29";
|
|
import {
|
|
ViewerEvent,
|
|
VisualDiffMode,
|
|
CameraController,
|
|
DiffExtension,
|
|
UpdateFlags,
|
|
SectionOutlines,
|
|
SectionToolEvent,
|
|
SectionTool,
|
|
SpeckleLoader,
|
|
LargeModelStreamingLoader,
|
|
ExplodeEvent,
|
|
ExplodeExtension,
|
|
LoaderEvent,
|
|
SelectionExtension
|
|
} from "/_nuxt/@fs/D:/speckle-server/packages/viewer/dist/index.js";
|
|
import { Vector3 } from "/_nuxt/node_modules/.cache/vite/client/deps/three.js?v=e4f18c29";
|
|
import { useAuthManager } from "/_nuxt/lib/auth/composables/auth.ts";
|
|
import { ProjectCommentsUpdatedMessageType } from "/_nuxt/lib/common/generated/gql/graphql.ts";
|
|
import {
|
|
useInjectedViewerState,
|
|
useInjectedViewerInterfaceState
|
|
} from "/_nuxt/lib/viewer/composables/setup.ts";
|
|
import { useViewerSelectionEventHandler } from "/_nuxt/lib/viewer/composables/setup/selection.ts";
|
|
import {
|
|
useGetObjectUrl,
|
|
useOnViewerLoadComplete,
|
|
useViewerCameraControlStartTracker,
|
|
useViewerCameraTracker,
|
|
useViewerEventListener
|
|
} from "/_nuxt/lib/viewer/composables/viewer.ts";
|
|
import {
|
|
useCommentContext,
|
|
useViewerCommentUpdateTracking
|
|
} from "/_nuxt/lib/viewer/composables/commentManagement.ts";
|
|
import { getCacheId } from "/_nuxt/lib/common/helpers/graphql.ts";
|
|
import {
|
|
useViewerOpenedThreadUpdateEmitter,
|
|
useViewerThreadTracking
|
|
} from "/_nuxt/lib/viewer/composables/commentBubbles.ts";
|
|
import { useGeneralProjectPageUpdateTracking } from "/_nuxt/lib/projects/composables/projectPages.ts";
|
|
import { arraysEqual, isNonNullable } from "/_nuxt/lib/common/helpers/utils.ts";
|
|
import { getTargetObjectIds } from "/_nuxt/lib/object-sidebar/helpers.ts";
|
|
import { areVectorsLooselyEqual } from "/_nuxt/lib/viewer/helpers/three.ts";
|
|
import { SafeLocalStorage } from "/_nuxt/@fs/D:/speckle-server/packages/shared/dist/esm/index.js";
|
|
import {
|
|
useCameraUtilities,
|
|
useSectionBoxUtilities
|
|
} from "/_nuxt/lib/viewer/composables/ui.ts";
|
|
import { ToastNotificationType, useGlobalToast } from "/_nuxt/lib/common/composables/toast.ts";
|
|
import { setupDebugMode } from "/_nuxt/lib/viewer/composables/setup/dev.ts";
|
|
import { useEmbed } from "/_nuxt/lib/viewer/composables/setup/embed.ts";
|
|
import { useMixpanel } from "/_nuxt/lib/core/composables/mp.ts";
|
|
import { graphql } from "/_nuxt/lib/common/generated/gql/index.ts";
|
|
import { useTreeManagement } from "/_nuxt/lib/viewer/composables/tree.ts";
|
|
import { useViewerSavedViewIntegration } from "/_nuxt/lib/viewer/composables/savedViews/state.ts";
|
|
import { useViewModesPostSetup } from "/_nuxt/lib/viewer/composables/setup/viewMode.ts";
|
|
import { useMeasurementsPostSetup } from "/_nuxt/lib/viewer/composables/setup/measurements.ts";
|
|
import { useFilterColoringPostSetup } from "/_nuxt/lib/viewer/composables/setup/coloring.ts";
|
|
import {
|
|
usePropertyFilteringPostSetup,
|
|
useManualFilteringPostSetup
|
|
} from "/_nuxt/lib/viewer/composables/setup/filters.ts";
|
|
import { useFilterUtilities } from "/_nuxt/lib/viewer/composables/filtering/filtering.ts";
|
|
import { useFilteringSetup } from "/_nuxt/lib/viewer/composables/filtering/setup.ts";
|
|
import {
|
|
useHighlightingPostSetup,
|
|
HighlightExtension
|
|
} from "/_nuxt/lib/viewer/composables/setup/highlighting.ts";
|
|
import { useProjectSavedViewsUpdateTracking } from "/_nuxt/lib/viewer/composables/savedViews/subscriptions.ts";
|
|
|
|
import { onMounted, onBeforeUnmount, watch, computed, ref } from "/_nuxt/node_modules/vue/dist/vue.runtime.esm-bundler.js?v=e4f18c29";
|
|
import { useApiOrigin } from "/_nuxt/composables/env.ts";
|
|
import { useActiveUser } from "/_nuxt/composables/globals.ts";
|
|
import { modifyObjectField } from "/_nuxt/utils/globals.ts";
|
|
function useViewerLoadCompleteEventHandler() {
|
|
const state = useInjectedViewerState();
|
|
const callback = () => {
|
|
state.ui.loading.value = false;
|
|
};
|
|
onMounted(() => {
|
|
state.viewer.instance.on(ViewerEvent.LoadComplete, callback);
|
|
});
|
|
onBeforeUnmount(() => {
|
|
state.viewer.instance.removeListener(ViewerEvent.LoadComplete, callback);
|
|
});
|
|
}
|
|
function useViewerObjectAutoLoading() {
|
|
if (false) return;
|
|
const disableViewerCache = SafeLocalStorage.get("FE2_FORCE_DISABLE_VIEWER_CACHE") === "true";
|
|
const { effectiveAuthToken } = useAuthManager();
|
|
const { triggerNotification } = useGlobalToast();
|
|
const getObjectUrl = useGetObjectUrl();
|
|
const apiOrigin = useApiOrigin({ forcePublic: true });
|
|
const {
|
|
projectId,
|
|
viewer: {
|
|
instance: viewer,
|
|
init: { ref: isInitialized },
|
|
hasDoneInitialLoad
|
|
},
|
|
resources: {
|
|
request: {
|
|
savedView: { id: savedViewId }
|
|
},
|
|
response: { resourceItems, savedView }
|
|
},
|
|
ui: { loadProgress, loading, spotlightUserSessionId, hasLoadedQueuedUpModels },
|
|
urlHashState: { focusedThreadId }
|
|
} = useInjectedViewerState();
|
|
const loadingProgressMap = {};
|
|
const derivativeNotificationKeys = /* @__PURE__ */ new Set();
|
|
viewer.on(ViewerEvent.LoadComplete, (id) => {
|
|
delete loadingProgressMap[id];
|
|
consolidateProgressInternal({ id, progress: 1 });
|
|
});
|
|
const consolidateProgressInternal = (args) => {
|
|
loadingProgressMap[args.id] = args.progress;
|
|
const values = Object.values(loadingProgressMap);
|
|
const min = values.length ? Math.min(...values) : 1;
|
|
loadProgress.value = min;
|
|
loading.value = min < 1;
|
|
};
|
|
const consolidateProgressThorttled = useThrottleFn(consolidateProgressInternal, 250);
|
|
const getViewerDerivativeManifest = async (versionId) => {
|
|
const res = await fetch(
|
|
new URL(
|
|
`/api/viewer-derivatives/${projectId.value}/${versionId}/manifest`,
|
|
apiOrigin
|
|
),
|
|
{
|
|
headers: effectiveAuthToken.value ? { Authorization: `Bearer ${effectiveAuthToken.value}` } : void 0,
|
|
cache: "no-store"
|
|
}
|
|
);
|
|
if (res.status === 404) return void 0;
|
|
if (!res.ok) return void 0;
|
|
return await res.json();
|
|
};
|
|
const maybeLoadViewerDerivative = async (objectId, options) => {
|
|
const resourceItem = resourceItems.value.find(
|
|
(item) => item.objectId === objectId && item.versionId
|
|
);
|
|
if (!resourceItem?.versionId) return false;
|
|
const derivative = await getViewerDerivativeManifest(resourceItem.versionId);
|
|
if (!derivative || derivative.status === "missing") return false;
|
|
const notificationKey = `${resourceItem.versionId}:${derivative.status}`;
|
|
if (!derivativeNotificationKeys.has(notificationKey)) {
|
|
derivativeNotificationKeys.add(notificationKey);
|
|
triggerNotification({
|
|
type: derivative.status === "failed" ? ToastNotificationType.Danger : ToastNotificationType.Info,
|
|
title: "Large model streaming",
|
|
description: derivative.status === "ready" ? "Loading viewer derivative." : derivative.status === "failed" ? derivative.errorMessage || "Viewer derivative generation failed." : "Viewer derivative generation is still processing."
|
|
});
|
|
}
|
|
if (derivative.status === "ready" && derivative.manifest) {
|
|
const objectUrl = getObjectUrl(projectId.value, objectId);
|
|
const artifactBaseUrl = new URL(
|
|
`/api/viewer-derivatives/${projectId.value}/${resourceItem.versionId}/artifacts`,
|
|
apiOrigin
|
|
).toString();
|
|
const loader = new LargeModelStreamingLoader(
|
|
viewer.getWorldTree(),
|
|
objectUrl,
|
|
derivative.manifest,
|
|
artifactBaseUrl,
|
|
effectiveAuthToken.value || void 0
|
|
);
|
|
loader.on(LoaderEvent.LoadProgress, (args) => {
|
|
consolidateProgressThorttled(args);
|
|
});
|
|
loader.on(LoaderEvent.LoadCancelled, (id) => {
|
|
delete loadingProgressMap[id];
|
|
consolidateProgressInternal({ id, progress: 1 });
|
|
});
|
|
await viewer.loadObject(loader, options?.zoomToObject);
|
|
consolidateProgressInternal({ id: objectUrl, progress: 1 });
|
|
return true;
|
|
}
|
|
consolidateProgressInternal({ id: objectId, progress: 1 });
|
|
return true;
|
|
};
|
|
const loadObject = async (objectId, unload, options) => {
|
|
const objectUrl = getObjectUrl(projectId.value, objectId);
|
|
if (unload) {
|
|
return viewer.unloadObject(objectUrl);
|
|
} else {
|
|
if (await maybeLoadViewerDerivative(objectId, options)) return;
|
|
const loader = new SpeckleLoader(
|
|
viewer.getWorldTree(),
|
|
objectUrl,
|
|
effectiveAuthToken.value || void 0,
|
|
disableViewerCache ? false : void 0,
|
|
void 0
|
|
);
|
|
loader.on(LoaderEvent.LoadProgress, (args) => {
|
|
consolidateProgressThorttled(args);
|
|
});
|
|
loader.on(LoaderEvent.LoadCancelled, (id) => {
|
|
delete loadingProgressMap[id];
|
|
consolidateProgressInternal({ id, progress: 1 });
|
|
});
|
|
loader.on(LoaderEvent.LoadWarning, ({ message }) => {
|
|
if (!message.startsWith("Viewer full-load guard:")) return;
|
|
triggerNotification({
|
|
type: ToastNotificationType.Danger,
|
|
title: "Large model needs streaming",
|
|
description: message
|
|
});
|
|
});
|
|
return viewer.loadObject(loader, options?.zoomToObject);
|
|
}
|
|
};
|
|
const getUniqueObjectIds = (resourceItems2) => uniq(resourceItems2.map((i) => i.objectId));
|
|
const activeLoads = /* @__PURE__ */ new Set();
|
|
watch(
|
|
() => [resourceItems.value, isInitialized.value, hasDoneInitialLoad.value],
|
|
async ([newResources, newIsInitialized, newHasDoneInitialLoad], oldData) => {
|
|
if (!newIsInitialized) return;
|
|
const [oldResources] = oldData || [[], false];
|
|
const preventZooming = focusedThreadId.value || savedViewId.value || savedView.value || spotlightUserSessionId.value;
|
|
const zoomToObject = !preventZooming;
|
|
if (!newHasDoneInitialLoad) {
|
|
const allObjectIds = getUniqueObjectIds(newResources);
|
|
if (allObjectIds.length) {
|
|
hasLoadedQueuedUpModels.value = false;
|
|
}
|
|
const res = [];
|
|
const loadAll = async () => {
|
|
for (const i of allObjectIds) {
|
|
res.push(await loadObject(i, false, { zoomToObject }));
|
|
}
|
|
};
|
|
const promise2 = loadAll().then(() => {
|
|
activeLoads.delete(promise2);
|
|
});
|
|
activeLoads.add(promise2);
|
|
await promise2;
|
|
if (res.length) {
|
|
hasDoneInitialLoad.value = true;
|
|
if (!activeLoads.size) hasLoadedQueuedUpModels.value = true;
|
|
}
|
|
return;
|
|
}
|
|
const loadAndUnloadChanged = async () => {
|
|
const newObjectIds = getUniqueObjectIds(newResources);
|
|
const oldObjectIds = getUniqueObjectIds(oldResources);
|
|
const removableObjectIds = difference(oldObjectIds, newObjectIds);
|
|
const addableObjectIds = difference(newObjectIds, oldObjectIds);
|
|
if (addableObjectIds.length) {
|
|
hasLoadedQueuedUpModels.value = false;
|
|
}
|
|
await Promise.all(removableObjectIds.map((i) => loadObject(i, true)));
|
|
await Promise.all(
|
|
addableObjectIds.map((i) => loadObject(i, false, { zoomToObject: false }))
|
|
);
|
|
};
|
|
const promise = loadAndUnloadChanged().then(() => {
|
|
activeLoads.delete(promise);
|
|
});
|
|
activeLoads.add(promise);
|
|
await promise;
|
|
if (!activeLoads.size) hasLoadedQueuedUpModels.value = true;
|
|
},
|
|
{ deep: true, immediate: true }
|
|
);
|
|
onBeforeUnmount(async () => {
|
|
await viewer.unloadAll();
|
|
});
|
|
}
|
|
function useViewerReceiveTracking() {
|
|
const {
|
|
resources: {
|
|
response: { modelsAndVersionIds }
|
|
}
|
|
} = useInjectedViewerState();
|
|
const mixpanel = useMixpanel();
|
|
const { userId } = useActiveUser();
|
|
const receivedVersions = /* @__PURE__ */ new Set();
|
|
watch(modelsAndVersionIds, (newVal) => {
|
|
for (const { model, versionId } of newVal) {
|
|
if (receivedVersions.has(versionId)) {
|
|
continue;
|
|
}
|
|
receivedVersions.add(versionId);
|
|
mixpanel.track("Receive", {
|
|
hostApp: "viewer",
|
|
sourceHostApp: model.loadedVersion.items[0].sourceApplication,
|
|
isMultiplayer: model.loadedVersion.items[0].authorUser?.id !== userId.value
|
|
});
|
|
}
|
|
});
|
|
}
|
|
function useViewerSubscriptionEventTracker() {
|
|
if (false) return;
|
|
const {
|
|
projectId,
|
|
resources: {
|
|
request: { resourceIdString, threadFilters }
|
|
}
|
|
} = useInjectedViewerState();
|
|
useGeneralProjectPageUpdateTracking({
|
|
projectId
|
|
});
|
|
useProjectSavedViewsUpdateTracking({ projectId });
|
|
useViewerCommentUpdateTracking(
|
|
{
|
|
projectId,
|
|
resourceIdString,
|
|
loadedVersionsOnly: computed(() => threadFilters.value.loadedVersionsOnly)
|
|
},
|
|
(event, cache) => {
|
|
const isArchived = event.type === ProjectCommentsUpdatedMessageType.Archived;
|
|
const isNew = event.type === ProjectCommentsUpdatedMessageType.Created;
|
|
const comment = event.comment;
|
|
if (isArchived) {
|
|
cache.modify({
|
|
id: getCacheId("Comment", event.id),
|
|
fields: {
|
|
archived: () => true
|
|
}
|
|
});
|
|
modifyObjectField(
|
|
cache,
|
|
getCacheId("Project", projectId.value),
|
|
"commentThreads",
|
|
({ variables, helpers: { createUpdatedValue, readField } }) => {
|
|
if (variables.filter?.includeArchived) return;
|
|
return createUpdatedValue(({ update }) => {
|
|
update("totalCount", (totalCount) => totalCount - 1);
|
|
update(
|
|
"items",
|
|
(items) => items.filter((i) => readField(i, "id") !== event.id)
|
|
);
|
|
});
|
|
}
|
|
);
|
|
} else if (isNew && comment) {
|
|
const parentId = comment.parent?.id;
|
|
if (parentId) {
|
|
modifyObjectField(
|
|
cache,
|
|
getCacheId("Comment", parentId),
|
|
"replies",
|
|
({ helpers: { createUpdatedValue, ref: ref2 } }) => createUpdatedValue(({ update }) => {
|
|
update("totalCount", (totalCount) => totalCount + 1);
|
|
update("items", (items) => [ref2("Comment", comment.id), ...items]);
|
|
})
|
|
);
|
|
} else {
|
|
modifyObjectField(
|
|
cache,
|
|
getCacheId("Project", projectId.value),
|
|
"commentThreads",
|
|
({ helpers: { ref: ref2, createUpdatedValue, readField }, value }) => {
|
|
const includesItem = value.items?.find(
|
|
(i) => readField(i, "id") === comment.id
|
|
);
|
|
if (includesItem) return;
|
|
return createUpdatedValue(({ update }) => {
|
|
update("totalCount", (totalCount) => totalCount + 1);
|
|
update("items", (items) => [ref2("Comment", comment.id), ...items]);
|
|
});
|
|
}
|
|
);
|
|
}
|
|
}
|
|
}
|
|
);
|
|
}
|
|
function useViewerSectionBoxIntegration() {
|
|
const {
|
|
ui: {
|
|
sectionBox,
|
|
sectionBoxContext: { visible, edited }
|
|
},
|
|
viewer: { instance }
|
|
} = useInjectedViewerState();
|
|
const { sectionBoxDataToBox3, sectionBoxDataEquals } = useSectionBoxUtilities();
|
|
const sectionTool = instance.getExtension(SectionTool);
|
|
const onDragStart = () => {
|
|
edited.value = true;
|
|
};
|
|
sectionTool.on(SectionToolEvent.DragStart, onDragStart);
|
|
watch(
|
|
sectionBox,
|
|
(newVal, oldVal) => {
|
|
if (newVal && oldVal && sectionBoxDataEquals(newVal, oldVal)) return;
|
|
if (!newVal && !oldVal) return;
|
|
if (oldVal && !newVal) {
|
|
visible.value = false;
|
|
edited.value = false;
|
|
sectionTool.enabled = false;
|
|
instance.requestRender(UpdateFlags.RENDER_RESET);
|
|
return;
|
|
}
|
|
if (newVal && (!oldVal || !sectionBoxDataEquals(newVal, oldVal))) {
|
|
visible.value = true;
|
|
edited.value = false;
|
|
const box3 = sectionBoxDataToBox3(newVal);
|
|
sectionTool.setBox(box3);
|
|
sectionTool.enabled = true;
|
|
const outlines = instance.getExtension(SectionOutlines);
|
|
if (outlines) outlines.requestUpdate();
|
|
instance.requestRender(UpdateFlags.RENDER_RESET);
|
|
}
|
|
},
|
|
{ immediate: true, deep: true, flush: "sync" }
|
|
);
|
|
watch(
|
|
visible,
|
|
(newVal, oldVal) => {
|
|
if (newVal && oldVal) return;
|
|
if (!newVal && !oldVal) return;
|
|
if (newVal) {
|
|
sectionTool.visible = true;
|
|
} else {
|
|
sectionTool.visible = false;
|
|
}
|
|
instance.requestRender();
|
|
},
|
|
{ immediate: true, deep: true, flush: "sync" }
|
|
);
|
|
onBeforeUnmount(() => {
|
|
sectionTool.enabled = false;
|
|
sectionTool.removeListener(SectionToolEvent.DragStart, onDragStart);
|
|
});
|
|
}
|
|
function useViewerCameraIntegration() {
|
|
const {
|
|
viewer: { instance },
|
|
ui: {
|
|
camera: { isOrthoProjection, position, target },
|
|
spotlightUserSessionId
|
|
}
|
|
} = useInjectedViewerState();
|
|
const { forceViewToViewerSync, setView, cameraController } = useCameraUtilities();
|
|
const hasInitialLoadFired = ref(false);
|
|
const loadCameraDataFromViewer = () => {
|
|
const extension = instance.getExtension(CameraController);
|
|
const viewerPos = new Vector3().copy(extension.getPosition());
|
|
const viewerTarget = new Vector3().copy(extension.getTarget());
|
|
if (hasInitialLoadFired.value) {
|
|
if (!areVectorsLooselyEqual(position.value, viewerPos)) {
|
|
position.value = viewerPos.clone();
|
|
}
|
|
if (!areVectorsLooselyEqual(target.value, viewerTarget)) {
|
|
target.value = viewerTarget.clone();
|
|
}
|
|
}
|
|
};
|
|
useViewerCameraTracker(
|
|
() => {
|
|
loadCameraDataFromViewer();
|
|
},
|
|
{ throttleWait: 100 }
|
|
);
|
|
useOnViewerLoadComplete(({ isInitial }) => {
|
|
if (isInitial) {
|
|
hasInitialLoadFired.value = true;
|
|
const hasInitCoords = position.value.equals(new Vector3()) && target.value.equals(new Vector3());
|
|
if (hasInitCoords) {
|
|
loadCameraDataFromViewer();
|
|
} else {
|
|
forceViewToViewerSync();
|
|
}
|
|
orthoProjectionUpdate(isOrthoProjection.value);
|
|
} else {
|
|
loadCameraDataFromViewer();
|
|
}
|
|
});
|
|
useViewerCameraControlStartTracker(() => {
|
|
if (spotlightUserSessionId.value) {
|
|
spotlightUserSessionId.value = null;
|
|
}
|
|
});
|
|
const orthoProjectionUpdate = (newVal) => {
|
|
if (!hasInitialLoadFired.value) {
|
|
throw new Error("Attempting to set projection too early");
|
|
}
|
|
if (newVal) {
|
|
cameraController.setOrthoCameraOn();
|
|
} else {
|
|
cameraController.setPerspectiveCameraOn();
|
|
}
|
|
forceViewToViewerSync();
|
|
};
|
|
watch(
|
|
isOrthoProjection,
|
|
(newVal, oldVal) => {
|
|
if (newVal === oldVal || !hasInitialLoadFired.value) return;
|
|
orthoProjectionUpdate(newVal);
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
watch(
|
|
position,
|
|
(newVal, oldVal) => {
|
|
if (!newVal && !oldVal || oldVal && areVectorsLooselyEqual(newVal, oldVal)) {
|
|
return;
|
|
}
|
|
setView({
|
|
position: newVal,
|
|
target: target.value
|
|
});
|
|
}
|
|
// { immediate: true }
|
|
);
|
|
watch(
|
|
target,
|
|
(newVal, oldVal) => {
|
|
if (!newVal && !oldVal || oldVal && areVectorsLooselyEqual(newVal, oldVal)) {
|
|
return;
|
|
}
|
|
setView({
|
|
position: position.value,
|
|
target: newVal
|
|
});
|
|
}
|
|
// { immediate: true }
|
|
);
|
|
}
|
|
function useViewerFiltersIntegration() {
|
|
const state = useInjectedViewerState();
|
|
const {
|
|
viewer: { instance },
|
|
ui: { filters }
|
|
} = state;
|
|
useFilteringSetup();
|
|
useFilterUtilities({ state });
|
|
watch(
|
|
filters.selectedObjects,
|
|
(newVal, oldVal) => {
|
|
const newIds = flatten(
|
|
newVal.map((v) => getTargetObjectIds(v))
|
|
).filter(isNonNullable);
|
|
const oldIds = flatten(
|
|
(oldVal || []).map((v) => getTargetObjectIds(v))
|
|
).filter(isNonNullable);
|
|
if (arraysEqual(newIds, oldIds)) return;
|
|
const selectionExtension = instance.getExtension(SelectionExtension);
|
|
const currentViewerSelection = selectionExtension.getSelectedObjects().map((obj) => obj.id);
|
|
if (currentViewerSelection.length === newIds.length && difference(currentViewerSelection, newIds).length === 0) {
|
|
return;
|
|
}
|
|
state.ui.highlightedObjectIds.value = [];
|
|
const highlightExtension = instance.getExtension(HighlightExtension);
|
|
if (highlightExtension) {
|
|
highlightExtension.clearSelection();
|
|
}
|
|
selectionExtension.clearSelection();
|
|
if (newVal.length > 0) {
|
|
selectionExtension.selectObjects(newIds);
|
|
}
|
|
},
|
|
{
|
|
immediate: true,
|
|
flush: "sync"
|
|
}
|
|
);
|
|
}
|
|
function useLightConfigIntegration() {
|
|
const {
|
|
ui: { lightConfig },
|
|
viewer: { instance }
|
|
} = useInjectedViewerState();
|
|
useViewerEventListener(
|
|
ViewerEvent.LightConfigUpdated,
|
|
(config) => {
|
|
if (isEqual(lightConfig.value, config)) return;
|
|
lightConfig.value = config;
|
|
}
|
|
);
|
|
watch(
|
|
lightConfig,
|
|
(newVal, oldVal) => {
|
|
if (newVal && oldVal && isEqual(newVal, oldVal)) return;
|
|
instance.setLightConfiguration(newVal);
|
|
},
|
|
{
|
|
immediate: true,
|
|
deep: true,
|
|
flush: "sync"
|
|
}
|
|
);
|
|
useOnViewerLoadComplete(
|
|
() => {
|
|
instance.setLightConfiguration(lightConfig.value);
|
|
},
|
|
{ initialOnly: true }
|
|
);
|
|
}
|
|
function useExplodeFactorIntegration() {
|
|
const {
|
|
ui: { explodeFactor },
|
|
viewer: { instance }
|
|
} = useInjectedViewerState();
|
|
const explodeExtension = instance.getExtension(ExplodeExtension);
|
|
const updateOutlines = () => {
|
|
const sectionOutlines = instance.getExtension(SectionOutlines);
|
|
if (sectionOutlines && sectionOutlines.enabled) sectionOutlines.requestUpdate(true);
|
|
};
|
|
onMounted(() => {
|
|
explodeExtension.on(ExplodeEvent.Finshed, updateOutlines);
|
|
});
|
|
onBeforeUnmount(() => {
|
|
explodeExtension.removeListener(ExplodeEvent.Finshed, updateOutlines);
|
|
});
|
|
watch(
|
|
explodeFactor,
|
|
(newVal) => {
|
|
explodeExtension.setExplode(newVal);
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
useOnViewerLoadComplete(
|
|
() => {
|
|
explodeExtension.setExplode(explodeFactor.value);
|
|
},
|
|
{ initialOnly: true }
|
|
);
|
|
}
|
|
function useDiffingIntegration() {
|
|
const state = useInjectedViewerState();
|
|
const { effectiveAuthToken } = useAuthManager();
|
|
const getObjectUrl = useGetObjectUrl();
|
|
const hasInitialLoadFired = ref(false);
|
|
const diffExtension = state.viewer.instance.getExtension(DiffExtension);
|
|
const { trigger: triggerDiffCommandWatch } = watchTriggerable(
|
|
() => [state.ui.diff.oldVersion.value, state.ui.diff.newVersion.value],
|
|
async (newVal, oldVal) => {
|
|
if (!hasInitialLoadFired.value) return;
|
|
const [oldVersion, newVersion] = newVal;
|
|
const [oldOldVersion, oldNewVersion] = oldVal || [null, null];
|
|
const versionId = (version) => version?.id || null;
|
|
const commandId = (oldVersion2, newVersion2) => {
|
|
const oldId = versionId(oldVersion2);
|
|
const newId = versionId(newVersion2);
|
|
return oldId && newId ? `${oldId}->${newId}` : null;
|
|
};
|
|
const newCommand = commandId(oldVersion, newVersion);
|
|
const oldCommand = commandId(oldOldVersion, oldNewVersion);
|
|
if (newCommand && oldCommand === newCommand || !!newCommand === !!oldCommand)
|
|
return;
|
|
if (!newCommand || oldVal) {
|
|
await diffExtension.undiff();
|
|
if (!newCommand) return;
|
|
}
|
|
const oldObjUrl = getObjectUrl(
|
|
state.projectId.value,
|
|
oldVersion?.referencedObject
|
|
);
|
|
const newObjUrl = getObjectUrl(
|
|
state.projectId.value,
|
|
newVersion?.referencedObject
|
|
);
|
|
state.ui.diff.result.value = await diffExtension.diff(
|
|
oldObjUrl,
|
|
newObjUrl,
|
|
state.ui.diff.mode.value,
|
|
effectiveAuthToken.value
|
|
);
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
watch(state.ui.diff.result, (val) => {
|
|
if (!val) return;
|
|
ignoreDiffModeUpdates(() => {
|
|
ignoreDiffTimeUpdates(() => {
|
|
state.ui.diff.time.value = 0.5;
|
|
state.ui.diff.mode.value = VisualDiffMode.COLORED;
|
|
triggerDiffModeWatch();
|
|
});
|
|
});
|
|
});
|
|
const { ignoreUpdates: ignoreDiffTimeUpdates } = watchTriggerable(
|
|
state.ui.diff.time,
|
|
(val) => {
|
|
if (!hasInitialLoadFired.value) return;
|
|
if (!state.ui.diff.result.value) return;
|
|
diffExtension.updateVisualDiff(val, state.ui.diff.mode.value);
|
|
}
|
|
);
|
|
const { trigger: triggerDiffModeWatch, ignoreUpdates: ignoreDiffModeUpdates } = watchTriggerable(state.ui.diff.mode, (val) => {
|
|
if (!hasInitialLoadFired.value) return;
|
|
if (!state.ui.diff.result.value) return;
|
|
diffExtension.updateVisualDiff(state.ui.diff.time.value, val);
|
|
});
|
|
useOnViewerLoadComplete(({ isInitial }) => {
|
|
if (!isInitial) return;
|
|
hasInitialLoadFired.value = true;
|
|
triggerDiffCommandWatch();
|
|
});
|
|
}
|
|
function useDisableZoomOnEmbed() {
|
|
const { viewer } = useInjectedViewerState();
|
|
const embedOptions = useEmbed();
|
|
watch(
|
|
() => embedOptions.noScroll.value,
|
|
(newNoScrollValue) => {
|
|
const cameraController = viewer.instance.getExtension(CameraController);
|
|
if (newNoScrollValue) {
|
|
cameraController.options = { enableZoom: false };
|
|
} else {
|
|
cameraController.options = { enableZoom: true };
|
|
}
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
}
|
|
function useViewerTreeIntegration() {
|
|
const { viewer } = useInjectedViewerState();
|
|
const { treeStateManager } = useTreeManagement();
|
|
onMounted(() => treeStateManager.initialize(viewer.instance));
|
|
}
|
|
graphql(`
|
|
fragment UseViewerSavedViewSetup_SavedView on SavedView {
|
|
id
|
|
viewerState
|
|
...ViewerPageSetup_SavedView
|
|
}
|
|
`);
|
|
function useViewerCursorIntegration() {
|
|
const {
|
|
viewer: { container }
|
|
} = useInjectedViewerState();
|
|
const {
|
|
filters: { selectedObjects }
|
|
} = useInjectedViewerInterfaceState();
|
|
const { shift } = useMagicKeys();
|
|
const isDragging = ref(false);
|
|
const handlePointerDown = (_event) => {
|
|
if (shift.value && selectedObjects.value.length === 0) {
|
|
isDragging.value = true;
|
|
}
|
|
};
|
|
const handlePointerUp = () => {
|
|
isDragging.value = false;
|
|
};
|
|
watch(
|
|
[shift, selectedObjects, isDragging],
|
|
() => {
|
|
if (!container) return;
|
|
const hasSelection = selectedObjects.value.length > 0;
|
|
const shouldShowDrag = shift.value && !hasSelection;
|
|
if (shouldShowDrag) {
|
|
container.style.cursor = isDragging.value ? "grabbing" : "grab";
|
|
} else {
|
|
container.style.cursor = "";
|
|
}
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
useEventListener(container, "pointerdown", handlePointerDown, { passive: true });
|
|
useEventListener(document, "pointerup", handlePointerUp, { passive: true });
|
|
onBeforeUnmount(() => {
|
|
if (container) {
|
|
container.style.cursor = "";
|
|
}
|
|
});
|
|
}
|
|
const useCommentContextIntegration = () => {
|
|
const { cleanupThreadContext } = useCommentContext();
|
|
onBeforeUnmount(() => {
|
|
cleanupThreadContext();
|
|
});
|
|
};
|
|
export function useViewerPostSetup() {
|
|
if (false) return;
|
|
useViewerObjectAutoLoading();
|
|
useViewerSavedViewIntegration();
|
|
useViewerReceiveTracking();
|
|
useViewerSelectionEventHandler();
|
|
useViewerLoadCompleteEventHandler();
|
|
useViewerSubscriptionEventTracker();
|
|
useViewerThreadTracking();
|
|
useViewerOpenedThreadUpdateEmitter();
|
|
useViewerSectionBoxIntegration();
|
|
useViewerCameraIntegration();
|
|
useViewerFiltersIntegration();
|
|
useLightConfigIntegration();
|
|
useExplodeFactorIntegration();
|
|
useDiffingIntegration();
|
|
useMeasurementsPostSetup();
|
|
useFilterColoringPostSetup();
|
|
usePropertyFilteringPostSetup();
|
|
useManualFilteringPostSetup();
|
|
useDisableZoomOnEmbed();
|
|
useViewerCursorIntegration();
|
|
useViewerTreeIntegration();
|
|
useViewModesPostSetup();
|
|
useHighlightingPostSetup();
|
|
useCommentContextIntegration();
|
|
setupDebugMode();
|
|
}
|
|
|
|
//# sourceMappingURL=data:application/json;base64,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LDJCQUF5QjtBQUN6QixpQ0FBK0I7QUFDL0Isb0NBQWtDO0FBQ2xDLG9DQUFrQztBQUNsQywwQkFBd0I7QUFDeEIscUNBQW1DO0FBQ25DLGlDQUErQjtBQUMvQiw2QkFBMkI7QUFDM0IsOEJBQTRCO0FBQzVCLDRCQUEwQjtBQUMxQiw4QkFBNEI7QUFDNUIsd0JBQXNCO0FBQ3RCLDJCQUF5QjtBQUN6Qiw2QkFBMkI7QUFDM0IsZ0NBQThCO0FBQzlCLDhCQUE0QjtBQUM1Qix3QkFBc0I7QUFDdEIsNkJBQTJCO0FBQzNCLDJCQUF5QjtBQUN6Qix3QkFBc0I7QUFDdEIsMkJBQXlCO0FBQ3pCLCtCQUE2QjtBQUM3QixpQkFBZTtBQUNqQiIsIm5hbWVzIjpbInJlc291cmNlSXRlbXMiLCJwcm9taXNlIiwicmVmIiwib2xkVmVyc2lvbiIsIm5ld1ZlcnNpb24iXSwiaWdub3JlTGlzdCI6W10sInNvdXJjZXMiOlsicG9zdFNldHVwLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGRpZmZlcmVuY2UsIGZsYXR0ZW4sIGlzRXF1YWwsIHVuaXEgfSBmcm9tICdsb2Rhc2gtZXMnXHJcbmltcG9ydCB7XHJcbiAgdXNlVGhyb3R0bGVGbixcclxuICB3YXRjaFRyaWdnZXJhYmxlLFxyXG4gIHVzZU1hZ2ljS2V5cyxcclxuICB1c2VFdmVudExpc3RlbmVyXHJcbn0gZnJvbSAnQHZ1ZXVzZS9jb3JlJ1xyXG5pbXBvcnQge1xyXG4gIFZpZXdlckV2ZW50LFxyXG4gIFZpc3VhbERpZmZNb2RlLFxyXG4gIENhbWVyYUNvbnRyb2xsZXIsXHJcbiAgRGlmZkV4dGVuc2lvbixcclxuICBVcGRhdGVGbGFncyxcclxuICBTZWN0aW9uT3V0bGluZXMsXHJcbiAgU2VjdGlvblRvb2xFdmVudCxcclxuICBTZWN0aW9uVG9vbCxcclxuICBTcGVja2xlTG9hZGVyLFxyXG4gIExhcmdlTW9kZWxTdHJlYW1pbmdMb2FkZXIsXHJcbiAgRXhwbG9kZUV2ZW50LFxyXG4gIEV4cGxvZGVFeHRlbnNpb24sXHJcbiAgTG9hZGVyRXZlbnQsXHJcbiAgU2VsZWN0aW9uRXh0ZW5zaW9uLFxyXG4gIHR5cGUgU3VuTGlnaHRDb25maWd1cmF0aW9uXHJcbn0gZnJvbSAnQHNwZWNrbGUvdmlld2VyJ1xyXG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAndGhyZWUnXHJcbmltcG9ydCB7IHVzZUF1dGhNYW5hZ2VyIH0gZnJvbSAnfn4vbGliL2F1dGgvY29tcG9zYWJsZXMvYXV0aCdcclxuaW1wb3J0IHR5cGUgeyBWaWV3ZXJSZXNvdXJjZUl0ZW0gfSBmcm9tICd+fi9saWIvY29tbW9uL2dlbmVyYXRlZC9ncWwvZ3JhcGhxbCdcclxuaW1wb3J0IHsgUHJvamVjdENvbW1lbnRzVXBkYXRlZE1lc3NhZ2VUeXBlIH0gZnJvbSAnfn4vbGliL2NvbW1vbi9nZW5lcmF0ZWQvZ3FsL2dyYXBocWwnXHJcbmltcG9ydCB7XHJcbiAgdXNlSW5qZWN0ZWRWaWV3ZXJTdGF0ZSxcclxuICB1c2VJbmplY3RlZFZpZXdlckludGVyZmFjZVN0YXRlXHJcbn0gZnJvbSAnfn4vbGliL3ZpZXdlci9jb21wb3NhYmxlcy9zZXR1cCdcclxuaW1wb3J0IHsgdXNlVmlld2VyU2VsZWN0aW9uRXZlbnRIYW5kbGVyIH0gZnJvbSAnfn4vbGliL3ZpZXdlci9jb21wb3NhYmxlcy9zZXR1cC9zZWxlY3Rpb24nXHJcbmltcG9ydCB7XHJcbiAgdXNlR2V0T2JqZWN0VXJsLFxyXG4gIHVzZU9uVmlld2VyTG9hZENvbXBsZXRlLFxyXG4gIHVzZVZpZXdlckNhbWVyYUNvbnRyb2xTdGFydFRyYWNrZXIsXHJcbiAgdXNlVmlld2VyQ2FtZXJhVHJhY2tlcixcclxuICB1c2VWaWV3ZXJFdmVudExpc3RlbmVyXHJcbn0gZnJvbSAnfn4vbGliL3ZpZXdlci9jb21wb3NhYmxlcy92aWV3ZXInXHJcbmltcG9ydCB7XHJcbiAgdXNlQ29tbWVudENvbnRleHQsXHJcbiAgdXNlVmlld2VyQ29tbWVudFVwZGF0ZVRyYWNraW5nXHJcbn0gZnJvbSAnfn4vbGliL3ZpZXdlci9jb21wb3NhYmxlcy9jb21tZW50TWFuYWdlbWVudCdcclxuaW1wb3J0IHsgZ2V0Q2FjaGVJZCB9IGZyb20gJ35+L2xpYi9jb21tb24vaGVscGVycy9ncmFwaHFsJ1xyXG5pbXBvcnQge1xyXG4gIHVzZVZpZXdlck9wZW5lZFRocmVhZFVwZGF0ZUVtaXR0ZXIsXHJcbiAgdXNlVmlld2VyVGhyZWFkVHJhY2tpbmdcclxufSBmcm9tICd+fi9saWIvdmlld2VyL2NvbXBvc2FibGVzL2NvbW1lbnRCdWJibGVzJ1xyXG5pbXBvcnQgeyB1c2VHZW5lcmFsUHJvamVjdFBhZ2VVcGRhdGVUcmFja2luZyB9IGZyb20gJ35+L2xpYi9wcm9qZWN0cy9jb21wb3NhYmxlcy9wcm9qZWN0UGFnZXMnXHJcbmltcG9ydCB7IGFycmF5c0VxdWFsLCBpc05vbk51bGxhYmxlIH0gZnJvbSAnfn4vbGliL2NvbW1vbi9oZWxwZXJzL3V0aWxzJ1xyXG5pbXBvcnQgeyBnZXRUYXJnZXRPYmplY3RJZHMgfSBmcm9tICd+fi9saWIvb2JqZWN0LXNpZGViYXIvaGVscGVycydcclxuaW1wb3J0IHsgYXJlVmVjdG9yc0xvb3NlbHlFcXVhbCB9IGZyb20gJ35+L2xpYi92aWV3ZXIvaGVscGVycy90aHJlZSdcclxuaW1wb3J0IHsgU2FmZUxvY2FsU3RvcmFnZSB9IGZyb20gJ0BzcGVja2xlL3NoYXJlZCdcclxuaW1wb3J0IHtcclxuICB1c2VDYW1lcmFVdGlsaXRpZXMsXHJcbiAgdXNlU2VjdGlvbkJveFV0aWxpdGllc1xyXG59IGZyb20gJ35+L2xpYi92aWV3ZXIvY29tcG9zYWJsZXMvdWknXHJcbmltcG9ydCB7IFRvYXN0Tm90aWZpY2F0aW9uVHlwZSwgdXNlR2xvYmFsVG9hc3QgfSBmcm9tICd+fi9saWIvY29tbW9uL2NvbXBvc2FibGVzL3RvYXN0J1xyXG5pbXBvcnQgeyBzZXR1cERlYnVnTW9kZSB9IGZyb20gJ35+L2xpYi92aWV3ZXIvY29tcG9zYWJsZXMvc2V0dXAvZGV2J1xyXG5pbXBvcnQgeyB1c2VFbWJlZCB9IGZyb20gJ34vbGliL3ZpZXdlci9jb21wb3NhYmxlcy9zZXR1cC9lbWJlZCdcclxuaW1wb3J0IHsgdXNlTWl4cGFuZWwgfSBmcm9tICd+fi9saWIvY29yZS9jb21wb3NhYmxlcy9tcCdcclxuaW1wb3J0IHsgZ3JhcGhxbCB9IGZyb20gJ34vbGliL2NvbW1vbi9nZW5lcmF0ZWQvZ3FsJ1xyXG5pbXBvcnQgeyB1c2VUcmVlTWFuYWdlbWVudCB9IGZyb20gJ35+L2xpYi92aWV3ZXIvY29tcG9zYWJsZXMvdHJlZSdcclxuaW1wb3J0IHsgdXNlVmlld2VyU2F2ZWRWaWV3SW50ZWdyYXRpb24gfSBmcm9tICd+L2xpYi92aWV3ZXIvY29tcG9zYWJsZXMvc2F2ZWRWaWV3cy9zdGF0ZSdcclxuaW1wb3J0IHsgdXNlVmlld01vZGVzUG9zdFNldHVwIH0gZnJvbSAnfi9saWIvdmlld2VyL2NvbXBvc2FibGVzL3NldHVwL3ZpZXdNb2RlJ1xyXG5pbXBvcnQgeyB1c2VNZWFzdXJlbWVudHNQb3N0U2V0dXAgfSBmcm9tICd+L2xpYi92aWV3ZXIvY29tcG9zYWJsZXMvc2V0dXAvbWVhc3VyZW1lbnRzJ1xyXG5pbXBvcnQgeyB1c2VGaWx0ZXJDb2xvcmluZ1Bvc3RTZXR1cCB9IGZyb20gJ34vbGliL3ZpZXdlci9jb21wb3NhYmxlcy9zZXR1cC9jb2xvcmluZydcclxuaW1wb3J0IHtcclxuICB1c2VQcm9wZXJ0eUZpbHRlcmluZ1Bvc3RTZXR1cCxcclxuICB1c2VNYW51YWxGaWx0ZXJpbmdQb3N0U2V0dXBcclxufSBmcm9tICd+L2xpYi92aWV3ZXIvY29tcG9zYWJsZXMvc2V0dXAvZmlsdGVycydcclxuaW1wb3J0IHsgdXNlRmlsdGVyVXRpbGl0aWVzIH0gZnJvbSAnfi9saWIvdmlld2VyL2NvbXBvc2FibGVzL2ZpbHRlcmluZy9maWx0ZXJpbmcnXHJcbmltcG9ydCB7IHVzZUZpbHRlcmluZ1NldHVwIH0gZnJvbSAnfi9saWIvdmlld2VyL2NvbXBvc2FibGVzL2ZpbHRlcmluZy9zZXR1cCdcclxuaW1wb3J0IHtcclxuICB1c2VIaWdobGlnaHRpbmdQb3N0U2V0dXAsXHJcbiAgSGlnaGxpZ2h0RXh0ZW5zaW9uXHJcbn0gZnJvbSAnfi9saWIvdmlld2VyL2NvbXBvc2FibGVzL3NldHVwL2hpZ2hsaWdodGluZydcclxuaW1wb3J0IHsgdXNlUHJvamVjdFNhdmVkVmlld3NVcGRhdGVUcmFja2luZyB9IGZyb20gJ34vbGliL3ZpZXdlci9jb21wb3NhYmxlcy9zYXZlZFZpZXdzL3N1YnNjcmlwdGlvbnMnXHJcblxyXG5mdW5jdGlvbiB1c2VWaWV3ZXJMb2FkQ29tcGxldGVFdmVudEhhbmRsZXIoKSB7XHJcbiAgY29uc3Qgc3RhdGUgPSB1c2VJbmplY3RlZFZpZXdlclN0YXRlKClcclxuXHJcbiAgY29uc3QgY2FsbGJhY2sgPSAoKSA9PiB7XHJcbiAgICBzdGF0ZS51aS5sb2FkaW5nLnZhbHVlID0gZmFsc2VcclxuICB9XHJcbiAgb25Nb3VudGVkKCgpID0+IHtcclxuICAgIHN0YXRlLnZpZXdlci5pbnN0YW5jZS5vbihWaWV3ZXJFdmVudC5Mb2FkQ29tcGxldGUsIGNhbGxiYWNrKVxyXG4gIH0pXHJcblxyXG4gIG9uQmVmb3JlVW5tb3VudCgoKSA9PiB7XHJcbiAgICBzdGF0ZS52aWV3ZXIuaW5zdGFuY2UucmVtb3ZlTGlzdGVuZXIoVmlld2VyRXZlbnQuTG9hZENvbXBsZXRlLCBjYWxsYmFjaylcclxuICB9KVxyXG59XHJcblxyXG4vKipcclxuICogQXV0b21hdGljYWxseSBsb2FkcyAmIHVubG9hZHMgb2JqZWN0cyBpbnRvIHRoZSB2aWV3ZXIgZGVwZW5kaW5nIG9uIHRoZSBnbG9iYWwgVVJMIHJlc291cmNlIGlkZW50aWZpZXIgc3RhdGVcclxuICovXHJcbmZ1bmN0aW9uIHVzZVZpZXdlck9iamVjdEF1dG9Mb2FkaW5nKCkge1xyXG4gIGlmIChpbXBvcnQubWV0YS5zZXJ2ZXIpIHJldHVyblxyXG5cclxuICB0eXBlIFZpZXdlckRlcml2YXRpdmVNYW5pZmVzdFJlc3BvbnNlID0ge1xyXG4gICAgc3RhdHVzOiAnbWlzc2luZycgfCAncXVldWVkJyB8ICdwcm9jZXNzaW5nJyB8ICdyZWFkeScgfCAnZmFpbGVkJ1xyXG4gICAgc3RhZ2U/OiBzdHJpbmcgfCBudWxsXHJcbiAgICBwcm9ncmVzcz86IG51bWJlciB8IG51bGxcclxuICAgIGVycm9yTWVzc2FnZT86IHN0cmluZyB8IG51bGxcbiAgICBtYW5pZmVzdD86IHtcbiAgICAgIGJvdW5kcz86IG51bWJlcltdXG4gICAgICB0aWxlczogQXJyYXk8e1xuICAgICAgICBpZD86IHN0cmluZ1xuICAgICAgICBiYm94PzogbnVtYmVyW11cbiAgICAgICAgbG9kczogQXJyYXk8e1xuICAgICAgICAgIGxldmVsPzogbnVtYmVyXG4gICAgICAgICAgdXJsOiBzdHJpbmdcbiAgICAgICAgICBieXRlcz86IG51bWJlclxuICAgICAgICAgIG1lc2hlcz86IG51bWJlclxuICAgICAgICAgIHZlcnRleENvdW50PzogbnVtYmVyXG4gICAgICAgICAgaW5kZXhDb3VudD86IG51bWJlclxuICAgICAgICAgIHRyaWFuZ2xlQ291bnQ/OiBudW1iZXJcbiAgICAgICAgfT5cbiAgICAgIH0+XG4gICAgfVxuICB9XHJcblxyXG4gIGNvbnN0IGRpc2FibGVWaWV3ZXJDYWNoZSA9XHJcbiAgICBTYWZlTG9jYWxTdG9yYWdlLmdldCgnRkUyX0ZPUkNFX0RJU0FCTEVfVklFV0VSX0NBQ0hFJykgPT09ICd0cnVlJ1xyXG4gIGNvbnN0IHsgZWZmZWN0aXZlQXV0aFRva2VuIH0gPSB1c2VBdXRoTWFuYWdlcigpXG4gIGNvbnN0IHsgdHJpZ2dlck5vdGlmaWNhdGlvbiB9ID0gdXNlR2xvYmFsVG9hc3QoKVxuICBjb25zdCBnZXRPYmplY3RVcmwgPSB1c2VHZXRPYmplY3RVcmwoKVxuICBjb25zdCBhcGlPcmlnaW4gPSB1c2VBcGlPcmlnaW4oeyBmb3JjZVB1YmxpYzogdHJ1ZSB9KVxuICBjb25zdCB7XHJcbiAgICBwcm9qZWN0SWQsXHJcbiAgICB2aWV3ZXI6IHtcclxuICAgICAgaW5zdGFuY2U6IHZpZXdlcixcclxuICAgICAgaW5pdDogeyByZWY6IGlzSW5pdGlhbGl6ZWQgfSxcclxuICAgICAgaGFzRG9uZUluaXRpYWxMb2FkXHJcbiAgICB9LFxyXG4gICAgcmVzb3VyY2VzOiB7XHJcbiAgICAgIHJlcXVlc3Q6IHtcclxuICAgICAgICBzYXZlZFZpZXc6IHsgaWQ6IHNhdmVkVmlld0lkIH1cclxuICAgICAgfSxcclxuICAgICAgcmVzcG9uc2U6IHsgcmVzb3VyY2VJdGVtcywgc2F2ZWRWaWV3IH1cclxuICAgIH0sXHJcbiAgICB1aTogeyBsb2FkUHJvZ3Jlc3MsIGxvYWRpbmcsIHNwb3RsaWdodFVzZXJTZXNzaW9uSWQsIGhhc0xvYWRlZFF1ZXVlZFVwTW9kZWxzIH0sXHJcbiAgICB1cmxIYXNoU3RhdGU6IHsgZm9jdXNlZFRocmVhZElkIH1cclxuICB9ID0gdXNlSW5qZWN0ZWRWaWV3ZXJTdGF0ZSgpXHJcblxyXG4gIGNvbnN0IGxvYWRpbmdQcm9ncmVzc01hcDogeyBbaWQ6IHN0cmluZ106IG51bWJlciB9ID0ge31cclxuICBjb25zdCBkZXJpdmF0aXZlTm90aWZpY2F0aW9uS2V5cyA9IG5ldyBTZXQ8c3RyaW5nPigpXHJcblxyXG4gIHZpZXdlci5vbihWaWV3ZXJFdmVudC5Mb2FkQ29tcGxldGUsIChpZCkgPT4ge1xyXG4gICAgZGVsZXRlIGxvYWRpbmdQcm9ncmVzc01hcFtpZF1cclxuICAgIGNvbnNvbGlkYXRlUHJvZ3Jlc3NJbnRlcm5hbCh7IGlkLCBwcm9ncmVzczogMSB9KVxyXG4gIH0pXHJcblxyXG4gIGNvbnN0IGNvbnNvbGlkYXRlUHJvZ3Jlc3NJbnRlcm5hbCA9IChhcmdzOiB7IHByb2dyZXNzOiBudW1iZXI7IGlkOiBzdHJpbmcgfSkgPT4ge1xyXG4gICAgbG9hZGluZ1Byb2dyZXNzTWFwW2FyZ3MuaWRdID0gYXJncy5wcm9ncmVzc1xyXG4gICAgY29uc3QgdmFsdWVzID0gT2JqZWN0LnZhbHVlcyhsb2FkaW5nUHJvZ3Jlc3NNYXApXHJcbiAgICBjb25zdCBtaW4gPSB2YWx1ZXMubGVuZ3RoID8gTWF0aC5taW4oLi4udmFsdWVzKSA6IDFcclxuXHJcbiAgICBsb2FkUHJvZ3Jlc3MudmFsdWUgPSBtaW5cclxuICAgIGxvYWRpbmcudmFsdWUgPSBtaW4gPCAxXHJcbiAgfVxyXG5cclxuICBjb25zdCBjb25zb2xpZGF0ZVByb2dyZXNzVGhvcnR0bGVkID0gdXNlVGhyb3R0bGVGbihjb25zb2xpZGF0ZVByb2dyZXNzSW50ZXJuYWwsIDI1MClcclxuXHJcbiAgY29uc3QgZ2V0Vmlld2VyRGVyaXZhdGl2ZU1hbmlmZXN0ID0gYXN5bmMgKFxuICAgIHZlcnNpb25JZDogc3RyaW5nXG4gICk6IFByb21pc2U8Vmlld2VyRGVyaXZhdGl2ZU1hbmlmZXN0UmVzcG9uc2UgfCB1bmRlZmluZWQ+ID0+IHtcbiAgICBjb25zdCByZXMgPSBhd2FpdCBmZXRjaChcbiAgICAgIG5ldyBVUkwoXG4gICAgICAgIGAvYXBpL3ZpZXdlci1kZXJpdmF0aXZlcy8ke3Byb2plY3RJZC52YWx1ZX0vJHt2ZXJzaW9uSWR9L21hbmlmZXN0YCxcbiAgICAgICAgYXBpT3JpZ2luXG4gICAgICApLFxuICAgICAge1xuICAgICAgICBoZWFkZXJzOiBlZmZlY3RpdmVBdXRoVG9rZW4udmFsdWVcbiAgICAgICAgICA/IHsgQXV0aG9yaXphdGlvbjogYEJlYXJlciAke2VmZmVjdGl2ZUF1dGhUb2tlbi52YWx1ZX1gIH1cbiAgICAgICAgICA6IHVuZGVmaW5lZCxcbiAgICAgICAgY2FjaGU6ICduby1zdG9yZSdcbiAgICAgIH1cbiAgICApXG5cclxuICAgIGlmIChyZXMuc3RhdHVzID09PSA0MDQpIHJldHVybiB1bmRlZmluZWRcclxuICAgIGlmICghcmVzLm9rKSByZXR1cm4gdW5kZWZpbmVkXHJcblxyXG4gICAgcmV0dXJuIChhd2FpdCByZXMuanNvbigpKSBhcyBWaWV3ZXJEZXJpdmF0aXZlTWFuaWZlc3RSZXNwb25zZVxyXG4gIH1cclxuXHJcbiAgY29uc3QgbWF5YmVMb2FkVmlld2VyRGVyaXZhdGl2ZSA9IGFzeW5jIChcclxuICAgIG9iamVjdElkOiBzdHJpbmcsXHJcbiAgICBvcHRpb25zPzogUGFydGlhbDx7IHpvb21Ub09iamVjdDogYm9vbGVhbiB9PlxyXG4gICkgPT4ge1xyXG4gICAgY29uc3QgcmVzb3VyY2VJdGVtID0gcmVzb3VyY2VJdGVtcy52YWx1ZS5maW5kKFxyXG4gICAgICAoaXRlbSkgPT4gaXRlbS5vYmplY3RJZCA9PT0gb2JqZWN0SWQgJiYgaXRlbS52ZXJzaW9uSWRcclxuICAgIClcclxuICAgIGlmICghcmVzb3VyY2VJdGVtPy52ZXJzaW9uSWQpIHJldHVybiBmYWxzZVxyXG5cclxuICAgIGNvbnN0IGRlcml2YXRpdmUgPSBhd2FpdCBnZXRWaWV3ZXJEZXJpdmF0aXZlTWFuaWZlc3QocmVzb3VyY2VJdGVtLnZlcnNpb25JZClcclxuICAgIGlmICghZGVyaXZhdGl2ZSB8fCBkZXJpdmF0aXZlLnN0YXR1cyA9PT0gJ21pc3NpbmcnKSByZXR1cm4gZmFsc2VcclxuXHJcbiAgICBjb25zdCBub3RpZmljYXRpb25LZXkgPSBgJHtyZXNvdXJjZUl0ZW0udmVyc2lvbklkfToke2Rlcml2YXRpdmUuc3RhdHVzfWBcclxuICAgIGlmICghZGVyaXZhdGl2ZU5vdGlmaWNhdGlvbktleXMuaGFzKG5vdGlmaWNhdGlvbktleSkpIHtcclxuICAgICAgZGVyaXZhdGl2ZU5vdGlmaWNhdGlvbktleXMuYWRkKG5vdGlmaWNhdGlvbktleSlcclxuICAgICAgdHJpZ2dlck5vdGlmaWNhdGlvbih7XHJcbiAgICAgICAgdHlwZTpcclxuICAgICAgICAgIGRlcml2YXRpdmUuc3RhdHVzID09PSAnZmFpbGVkJ1xyXG4gICAgICAgICAgICA/IFRvYXN0Tm90aWZpY2F0aW9uVHlwZS5EYW5nZXJcclxuICAgICAgICAgICAgOiBUb2FzdE5vdGlmaWNhdGlvblR5cGUuSW5mbyxcclxuICAgICAgICB0aXRsZTogJ0xhcmdlIG1vZGVsIHN0cmVhbWluZycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICBkZXJpdmF0aXZlLnN0YXR1cyA9PT0gJ3JlYWR5J1xyXG4gICAgICAgICAgICA/ICdMb2FkaW5nIHZpZXdlciBkZXJpdmF0aXZlLidcclxuICAgICAgICAgICAgOiBkZXJpdmF0aXZlLnN0YXR1cyA9PT0gJ2ZhaWxlZCdcclxuICAgICAgICAgICAgPyBkZXJpdmF0aXZlLmVycm9yTWVzc2FnZSB8fCAnVmlld2VyIGRlcml2YXRpdmUgZ2VuZXJhdGlvbiBmYWlsZWQuJ1xyXG4gICAgICAgICAgICA6ICdWaWV3ZXIgZGVyaXZhdGl2ZSBnZW5lcmF0aW9uIGlzIHN0aWxsIHByb2Nlc3NpbmcuJ1xyXG4gICAgICB9KVxyXG4gICAgfVxyXG5cclxuICAgIGlmIChkZXJpdmF0aXZlLnN0YXR1cyA9PT0gJ3JlYWR5JyAmJiBkZXJpdmF0aXZlLm1hbmlmZXN0KSB7XHJcbiAgICAgIGNvbnN0IG9iamVjdFVybCA9IGdldE9iamVjdFVybChwcm9qZWN0SWQudmFsdWUsIG9iamVjdElkKVxuICAgICAgY29uc3QgYXJ0aWZhY3RCYXNlVXJsID0gbmV3IFVSTChcbiAgICAgICAgYC9hcGkvdmlld2VyLWRlcml2YXRpdmVzLyR7cHJvamVjdElkLnZhbHVlfS8ke3Jlc291cmNlSXRlbS52ZXJzaW9uSWR9L2FydGlmYWN0c2AsXG4gICAgICAgIGFwaU9yaWdpblxuICAgICAgKS50b1N0cmluZygpXG4gICAgICBjb25zdCBsb2FkZXIgPSBuZXcgTGFyZ2VNb2RlbFN0cmVhbWluZ0xvYWRlcihcbiAgICAgICAgdmlld2VyLmdldFdvcmxkVHJlZSgpLFxuICAgICAgICBvYmplY3RVcmwsXG4gICAgICAgIGRlcml2YXRpdmUubWFuaWZlc3QsXG4gICAgICAgIGFydGlmYWN0QmFzZVVybCxcbiAgICAgICAgZWZmZWN0aXZlQXV0aFRva2VuLnZhbHVlIHx8IHVuZGVmaW5lZFxuICAgICAgKVxuICAgICAgbG9hZGVyLm9uKExvYWRlckV2ZW50LkxvYWRQcm9ncmVzcywgKGFyZ3MpID0+IHtcclxuICAgICAgICBjb25zb2xpZGF0ZVByb2dyZXNzVGhvcnR0bGVkKGFyZ3MpXHJcbiAgICAgIH0pXHJcbiAgICAgIGxvYWRlci5vbihMb2FkZXJFdmVudC5Mb2FkQ2FuY2VsbGVkLCAoaWQpID0+IHtcclxuICAgICAgICBkZWxldGUgbG9hZGluZ1Byb2dyZXNzTWFwW2lkXVxyXG4gICAgICAgIGNvbnNvbGlkYXRlUHJvZ3Jlc3NJbnRlcm5hbCh7IGlkLCBwcm9ncmVzczogMSB9KVxyXG4gICAgICB9KVxyXG4gICAgICBhd2FpdCB2aWV3ZXIubG9hZE9iamVjdChsb2FkZXIsIG9wdGlvbnM/Lnpvb21Ub09iamVjdClcbiAgICAgIGNvbnNvbGlkYXRlUHJvZ3Jlc3NJbnRlcm5hbCh7IGlkOiBvYmplY3RVcmwsIHByb2dyZXNzOiAxIH0pXG4gICAgICByZXR1cm4gdHJ1ZVxuICAgIH1cblxyXG4gICAgY29uc29saWRhdGVQcm9ncmVzc0ludGVybmFsKHsgaWQ6IG9iamVjdElkLCBwcm9ncmVzczogMSB9KVxyXG4gICAgcmV0dXJuIHRydWVcclxuICB9XHJcblxyXG4gIGNvbnN0IGxvYWRPYmplY3QgPSBhc3luYyAoXHJcbiAgICBvYmplY3RJZDogc3RyaW5nLFxyXG4gICAgdW5sb2FkPzogYm9vbGVhbixcclxuICAgIG9wdGlvbnM/OiBQYXJ0aWFsPHsgem9vbVRvT2JqZWN0OiBib29sZWFuIH0+XHJcbiAgKSA9PiB7XHJcbiAgICBjb25zdCBvYmplY3RVcmwgPSBnZXRPYmplY3RVcmwocHJvamVjdElkLnZhbHVlLCBvYmplY3RJZClcclxuXHJcbiAgICBpZiAodW5sb2FkKSB7XHJcbiAgICAgIHJldHVybiB2aWV3ZXIudW5sb2FkT2JqZWN0KG9iamVjdFVybClcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGlmIChhd2FpdCBtYXliZUxvYWRWaWV3ZXJEZXJpdmF0aXZlKG9iamVjdElkLCBvcHRpb25zKSkgcmV0dXJuXHJcblxyXG4gICAgICBjb25zdCBsb2FkZXIgPSBuZXcgU3BlY2tsZUxvYWRlcihcclxuICAgICAgICB2aWV3ZXIuZ2V0V29ybGRUcmVlKCksXHJcbiAgICAgICAgb2JqZWN0VXJsLFxyXG4gICAgICAgIGVmZmVjdGl2ZUF1dGhUb2tlbi52YWx1ZSB8fCB1bmRlZmluZWQsXHJcbiAgICAgICAgZGlzYWJsZVZpZXdlckNhY2hlID8gZmFsc2UgOiB1bmRlZmluZWQsXHJcbiAgICAgICAgdW5kZWZpbmVkXHJcbiAgICAgIClcclxuXHJcbiAgICAgIGxvYWRlci5vbihMb2FkZXJFdmVudC5Mb2FkUHJvZ3Jlc3MsIChhcmdzKSA9PiB7XHJcbiAgICAgICAgY29uc29saWRhdGVQcm9ncmVzc1Rob3J0dGxlZChhcmdzKVxyXG4gICAgICB9KVxyXG4gICAgICBsb2FkZXIub24oTG9hZGVyRXZlbnQuTG9hZENhbmNlbGxlZCwgKGlkKSA9PiB7XHJcbiAgICAgICAgZGVsZXRlIGxvYWRpbmdQcm9ncmVzc01hcFtpZF1cclxuICAgICAgICBjb25zb2xpZGF0ZVByb2dyZXNzSW50ZXJuYWwoeyBpZCwgcHJvZ3Jlc3M6IDEgfSlcclxuICAgICAgfSlcclxuICAgICAgbG9hZGVyLm9uKExvYWRlckV2ZW50LkxvYWRXYXJuaW5nLCAoeyBtZXNzYWdlIH0pID0+IHtcclxuICAgICAgICBpZiAoIW1lc3NhZ2Uuc3RhcnRzV2l0aCgnVmlld2VyIGZ1bGwtbG9hZCBndWFyZDonKSkgcmV0dXJuXHJcblxyXG4gICAgICAgIHRyaWdnZXJOb3RpZmljYXRpb24oe1xyXG4gICAgICAgICAgdHlwZTogVG9hc3ROb3RpZmljYXRpb25UeXBlLkRhbmdlcixcclxuICAgICAgICAgIHRpdGxlOiAnTGFyZ2UgbW9kZWwgbmVlZHMgc3RyZWFtaW5nJyxcclxuICAgICAgICAgIGRlc2NyaXB0aW9uOiBtZXNzYWdlXHJcbiAgICAgICAgfSlcclxuICAgICAgfSlcclxuXHJcbiAgICAgIHJldHVybiB2aWV3ZXIubG9hZE9iamVjdChsb2FkZXIsIG9wdGlvbnM/Lnpvb21Ub09iamVjdClcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGNvbnN0IGdldFVuaXF1ZU9iamVjdElkcyA9IChyZXNvdXJjZUl0ZW1zOiBWaWV3ZXJSZXNvdXJjZUl0ZW1bXSkgPT5cclxuICAgIHVuaXEocmVzb3VyY2VJdGVtcy5tYXAoKGkpID0+IGkub2JqZWN0SWQpKVxyXG5cclxuICBjb25zdCBhY3RpdmVMb2FkcyA9IG5ldyBTZXQ8UHJvbWlzZTx2b2lkPj4oKVxyXG4gIHdhdGNoKFxyXG4gICAgKCkgPT4gPGNvbnN0PltyZXNvdXJjZUl0ZW1zLnZhbHVlLCBpc0luaXRpYWxpemVkLnZhbHVlLCBoYXNEb25lSW5pdGlhbExvYWQudmFsdWVdLFxyXG4gICAgYXN5bmMgKFtuZXdSZXNvdXJjZXMsIG5ld0lzSW5pdGlhbGl6ZWQsIG5ld0hhc0RvbmVJbml0aWFsTG9hZF0sIG9sZERhdGEpID0+IHtcclxuICAgICAgLy8gV2FpdCB0aWxsIHZpZXdlciBsb2FkZWQgaW5cclxuICAgICAgaWYgKCFuZXdJc0luaXRpYWxpemVkKSByZXR1cm5cclxuXHJcbiAgICAgIGNvbnN0IFtvbGRSZXNvdXJjZXNdID0gb2xkRGF0YSB8fCBbW10sIGZhbHNlXVxyXG5cclxuICAgICAgLy8gd2UgZG9udCB3YW50IHRvIHpvb20gdG8gb2JqZWN0LCBpZiB3ZSdyZSBsb2FkaW5nIHNwZWNpZmljIGNvb3JkcyBiZWNhdXNlIG9mIGEgdGhyZWFkLFxyXG4gICAgICAvLyBvciBzcG90bGlnaHQgbW9kZSBvciBhIHNhdmVkIHZpZXcgZXRjLlxyXG4gICAgICBjb25zdCBwcmV2ZW50Wm9vbWluZyA9XHJcbiAgICAgICAgZm9jdXNlZFRocmVhZElkLnZhbHVlIHx8XHJcbiAgICAgICAgc2F2ZWRWaWV3SWQudmFsdWUgfHxcclxuICAgICAgICBzYXZlZFZpZXcudmFsdWUgfHxcclxuICAgICAgICBzcG90bGlnaHRVc2VyU2Vzc2lvbklkLnZhbHVlXHJcbiAgICAgIGNvbnN0IHpvb21Ub09iamVjdCA9ICFwcmV2ZW50Wm9vbWluZ1xyXG5cclxuICAgICAgLy8gVmlld2VyIGluaXRpYWxpemVkIC0gbG9hZCBpbiBhbGwgcmVzb3VyY2VzXHJcbiAgICAgIGlmICghbmV3SGFzRG9uZUluaXRpYWxMb2FkKSB7XHJcbiAgICAgICAgY29uc3QgYWxsT2JqZWN0SWRzID0gZ2V0VW5pcXVlT2JqZWN0SWRzKG5ld1Jlc291cmNlcylcclxuICAgICAgICBpZiAoYWxsT2JqZWN0SWRzLmxlbmd0aCkge1xyXG4gICAgICAgICAgLy8gb25seSBtYXJrLCBpZiBhbnl0aGluZyB0byBsb2FkXHJcbiAgICAgICAgICBoYXNMb2FkZWRRdWV1ZWRVcE1vZGVscy52YWx1ZSA9IGZhbHNlXHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvKiogTG9hZCBzZXF1ZW50aWFsbHkgKi9cclxuICAgICAgICBjb25zdCByZXMgPSBbXVxyXG4gICAgICAgIGNvbnN0IGxvYWRBbGwgPSBhc3luYyAoKSA9PiB7XHJcbiAgICAgICAgICBmb3IgKGNvbnN0IGkgb2YgYWxsT2JqZWN0SWRzKSB7XHJcbiAgICAgICAgICAgIHJlcy5wdXNoKGF3YWl0IGxvYWRPYmplY3QoaSwgZmFsc2UsIHsgem9vbVRvT2JqZWN0IH0pKVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gUmVnaXN0ZXIgZm9yIGFjY3VyYXRlICdpcyBhbnl0aGluZyBsb2FkaW5nJyByZXBvcnRpbmdcclxuICAgICAgICBjb25zdCBwcm9taXNlID0gbG9hZEFsbCgpLnRoZW4oKCkgPT4ge1xyXG4gICAgICAgICAgYWN0aXZlTG9hZHMuZGVsZXRlKHByb21pc2UpXHJcbiAgICAgICAgfSlcclxuICAgICAgICBhY3RpdmVMb2Fkcy5hZGQocHJvbWlzZSlcclxuICAgICAgICBhd2FpdCBwcm9taXNlXHJcblxyXG4gICAgICAgIGlmIChyZXMubGVuZ3RoKSB7XHJcbiAgICAgICAgICBoYXNEb25lSW5pdGlhbExvYWQudmFsdWUgPSB0cnVlXHJcbiAgICAgICAgICBpZiAoIWFjdGl2ZUxvYWRzLnNpemUpIGhhc0xvYWRlZFF1ZXVlZFVwTW9kZWxzLnZhbHVlID0gdHJ1ZVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgcmV0dXJuXHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFJlc291cmNlcyBjaGFuZ2VkP1xyXG4gICAgICBjb25zdCBsb2FkQW5kVW5sb2FkQ2hhbmdlZCA9IGFzeW5jICgpID0+IHtcclxuICAgICAgICBjb25zdCBuZXdPYmplY3RJZHMgPSBnZXRVbmlxdWVPYmplY3RJZHMobmV3UmVzb3VyY2VzKVxyXG4gICAgICAgIGNvbnN0IG9sZE9iamVjdElkcyA9IGdldFVuaXF1ZU9iamVjdElkcyhvbGRSZXNvdXJjZXMpXHJcbiAgICAgICAgY29uc3QgcmVtb3ZhYmxlT2JqZWN0SWRzID0gZGlmZmVyZW5jZShvbGRPYmplY3RJZHMsIG5ld09iamVjdElkcylcclxuICAgICAgICBjb25zdCBhZGRhYmxlT2JqZWN0SWRzID0gZGlmZmVyZW5jZShuZXdPYmplY3RJZHMsIG9sZE9iamVjdElkcylcclxuXHJcbiAgICAgICAgaWYgKGFkZGFibGVPYmplY3RJZHMubGVuZ3RoKSB7XHJcbiAgICAgICAgICAvLyBvbmx5IG1hcmssIGlmIGFueXRoaW5nIHRvIGxvYWRcclxuICAgICAgICAgIGhhc0xvYWRlZFF1ZXVlZFVwTW9kZWxzLnZhbHVlID0gZmFsc2VcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGF3YWl0IFByb21pc2UuYWxsKHJlbW92YWJsZU9iamVjdElkcy5tYXAoKGkpID0+IGxvYWRPYmplY3QoaSwgdHJ1ZSkpKVxyXG4gICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxyXG4gICAgICAgICAgYWRkYWJsZU9iamVjdElkcy5tYXAoKGkpID0+IGxvYWRPYmplY3QoaSwgZmFsc2UsIHsgem9vbVRvT2JqZWN0OiBmYWxzZSB9KSlcclxuICAgICAgICApXHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFJlZ2lzdGVyIGZvciBhY2N1cmF0ZSAnaXMgYW55dGhpbmcgbG9hZGluZycgcmVwb3J0aW5nXHJcbiAgICAgIGNvbnN0IHByb21pc2UgPSBsb2FkQW5kVW5sb2FkQ2hhbmdlZCgpLnRoZW4oKCkgPT4ge1xyXG4gICAgICAgIGFjdGl2ZUxvYWRzLmRlbGV0ZShwcm9taXNlKVxyXG4gICAgICB9KVxyXG4gICAgICBhY3RpdmVMb2Fkcy5hZGQocHJvbWlzZSlcclxuICAgICAgYXdhaXQgcHJvbWlzZVxyXG5cclxuICAgICAgaWYgKCFhY3RpdmVMb2Fkcy5zaXplKSBoYXNMb2FkZWRRdWV1ZWRVcE1vZGVscy52YWx1ZSA9IHRydWVcclxuICAgIH0sXHJcbiAgICB7IGRlZXA6IHRydWUsIGltbWVkaWF0ZTogdHJ1ZSB9XHJcbiAgKVxyXG5cclxuICBvbkJlZm9yZVVubW91bnQoYXN5bmMgKCkgPT4ge1xyXG4gICAgYXdhaXQgdmlld2VyLnVubG9hZEFsbCgpXHJcbiAgfSlcclxufVxyXG5cclxuLyoqXHJcbiAqIEhlcmUgd2UgbWFrZSB0aGUgdmlld2VyIHByZXRlbmQgaXQncyBhIGNvbm5lY3RvciBhbmQgc2VuZCBvdXQgcmVjZWl2ZSBldmVudHMuIE5vdGUsIHRoaXMgaXMgaW1wb3J0YW50IGZvciB1cyB0byB0cmFjayB0byBiZSBhYmxlIHRvIGdldCBhIHBpY3R1cmUgb2YgaG93IG11Y2ggZGF0YSBpcyBjb25zdW1lZFxyXG4gKiBpbiBvdXIgdmlld2VyLlxyXG4gKi9cclxuZnVuY3Rpb24gdXNlVmlld2VyUmVjZWl2ZVRyYWNraW5nKCkge1xyXG4gIC8vXHJcbiAgY29uc3Qge1xyXG4gICAgcmVzb3VyY2VzOiB7XHJcbiAgICAgIHJlc3BvbnNlOiB7IG1vZGVsc0FuZFZlcnNpb25JZHMgfVxyXG4gICAgfVxyXG4gIH0gPSB1c2VJbmplY3RlZFZpZXdlclN0YXRlKClcclxuICBjb25zdCBtaXhwYW5lbCA9IHVzZU1peHBhbmVsKClcclxuICBjb25zdCB7IHVzZXJJZCB9ID0gdXNlQWN0aXZlVXNlcigpXHJcbiAgY29uc3QgcmVjZWl2ZWRWZXJzaW9ucyA9IG5ldyBTZXQ8c3RyaW5nPigpXHJcbiAgd2F0Y2gobW9kZWxzQW5kVmVyc2lvbklkcywgKG5ld1ZhbCkgPT4ge1xyXG4gICAgZm9yIChjb25zdCB7IG1vZGVsLCB2ZXJzaW9uSWQgfSBvZiBuZXdWYWwpIHtcclxuICAgICAgaWYgKHJlY2VpdmVkVmVyc2lvbnMuaGFzKHZlcnNpb25JZCkpIHtcclxuICAgICAgICBjb250aW51ZVxyXG4gICAgICB9XHJcbiAgICAgIHJlY2VpdmVkVmVyc2lvbnMuYWRkKHZlcnNpb25JZClcclxuICAgICAgbWl4cGFuZWwudHJhY2soJ1JlY2VpdmUnLCB7XHJcbiAgICAgICAgaG9zdEFwcDogJ3ZpZXdlcicsXHJcbiAgICAgICAgc291cmNlSG9zdEFwcDogbW9kZWwubG9hZGVkVmVyc2lvbi5pdGVtc1swXS5zb3VyY2VBcHBsaWNhdGlvbixcclxuICAgICAgICBpc011bHRpcGxheWVyOiBtb2RlbC5sb2FkZWRWZXJzaW9uLml0ZW1zWzBdLmF1dGhvclVzZXI/LmlkICE9PSB1c2VySWQudmFsdWVcclxuICAgICAgfSlcclxuICAgIH1cclxuICB9KVxyXG59XHJcblxyXG4vKipcclxuICogTGlzdGVuaW5nIHRvIG1vZGVsL3ZlcnNpb24gdXBkYXRlcyB0aHJvdWdoIHN1YnNjcmlwdGlvbnMgYW5kIG1ha2luZyB2YXJpb3VzXHJcbiAqIGNhY2hlIHVwZGF0ZXMgc28gdGhhdCB3ZSBkb24ndCBuZWVkIHRvIGFsd2F5cyByZWZldGNoIHF1ZXJpZXNcclxuICovXHJcbmZ1bmN0aW9uIHVzZVZpZXdlclN1YnNjcmlwdGlvbkV2ZW50VHJhY2tlcigpIHtcclxuICBpZiAoaW1wb3J0Lm1ldGEuc2VydmVyKSByZXR1cm5cclxuXHJcbiAgY29uc3Qge1xyXG4gICAgcHJvamVjdElkLFxyXG4gICAgcmVzb3VyY2VzOiB7XHJcbiAgICAgIHJlcXVlc3Q6IHsgcmVzb3VyY2VJZFN0cmluZywgdGhyZWFkRmlsdGVycyB9XHJcbiAgICB9XHJcbiAgfSA9IHVzZUluamVjdGVkVmlld2VyU3RhdGUoKVxyXG5cclxuICAvLyBUcmFjayBhbGwgcHJvamVjdC9tb2RlbC92ZXJzaW9uIHVwZGF0ZXNcclxuICB1c2VHZW5lcmFsUHJvamVjdFBhZ2VVcGRhdGVUcmFja2luZyh7XHJcbiAgICBwcm9qZWN0SWRcclxuICB9KVxyXG5cclxuICAvLyBUcmFjayBzYXZlZCB2aWV3c1xyXG4gIHVzZVByb2plY3RTYXZlZFZpZXdzVXBkYXRlVHJhY2tpbmcoeyBwcm9qZWN0SWQgfSlcclxuXHJcbiAgLy8gQWxzbyB0cmFjayB1cGRhdGVzIHRvIGNvbW1lbnRzXHJcbiAgdXNlVmlld2VyQ29tbWVudFVwZGF0ZVRyYWNraW5nKFxyXG4gICAge1xyXG4gICAgICBwcm9qZWN0SWQsXHJcbiAgICAgIHJlc291cmNlSWRTdHJpbmcsXHJcbiAgICAgIGxvYWRlZFZlcnNpb25zT25seTogY29tcHV0ZWQoKCkgPT4gdGhyZWFkRmlsdGVycy52YWx1ZS5sb2FkZWRWZXJzaW9uc09ubHkpXHJcbiAgICB9LFxyXG4gICAgKGV2ZW50LCBjYWNoZSkgPT4ge1xyXG4gICAgICBjb25zdCBpc0FyY2hpdmVkID0gZXZlbnQudHlwZSA9PT0gUHJvamVjdENvbW1lbnRzVXBkYXRlZE1lc3NhZ2VUeXBlLkFyY2hpdmVkXHJcbiAgICAgIGNvbnN0IGlzTmV3ID0gZXZlbnQudHlwZSA9PT0gUHJvamVjdENvbW1lbnRzVXBkYXRlZE1lc3NhZ2VUeXBlLkNyZWF0ZWRcclxuICAgICAgY29uc3QgY29tbWVudCA9IGV2ZW50LmNvbW1lbnRcclxuXHJcbiAgICAgIGlmIChpc0FyY2hpdmVkKSB7XHJcbiAgICAgICAgLy8gTWFyayBhcyBhcmNoaXZlZFxyXG4gICAgICAgIGNhY2hlLm1vZGlmeSh7XHJcbiAgICAgICAgICBpZDogZ2V0Q2FjaGVJZCgnQ29tbWVudCcsIGV2ZW50LmlkKSxcclxuICAgICAgICAgIGZpZWxkczoge1xyXG4gICAgICAgICAgICBhcmNoaXZlZDogKCkgPT4gdHJ1ZVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pXHJcblxyXG4gICAgICAgIC8vIFJlbW92ZSBmcm9tIHByb2plY3QuY29tbWVudFRocmVhZHNcclxuICAgICAgICBtb2RpZnlPYmplY3RGaWVsZChcclxuICAgICAgICAgIGNhY2hlLFxyXG4gICAgICAgICAgZ2V0Q2FjaGVJZCgnUHJvamVjdCcsIHByb2plY3RJZC52YWx1ZSksXHJcbiAgICAgICAgICAnY29tbWVudFRocmVhZHMnLFxyXG4gICAgICAgICAgKHsgdmFyaWFibGVzLCBoZWxwZXJzOiB7IGNyZWF0ZVVwZGF0ZWRWYWx1ZSwgcmVhZEZpZWxkIH0gfSkgPT4ge1xyXG4gICAgICAgICAgICBpZiAodmFyaWFibGVzLmZpbHRlcj8uaW5jbHVkZUFyY2hpdmVkKSByZXR1cm4gLy8gd2Ugd2FudCBpdCBpbiB0aGF0IGxpc3RcclxuXHJcbiAgICAgICAgICAgIHJldHVybiBjcmVhdGVVcGRhdGVkVmFsdWUoKHsgdXBkYXRlIH0pID0+IHtcclxuICAgICAgICAgICAgICB1cGRhdGUoJ3RvdGFsQ291bnQnLCAodG90YWxDb3VudCkgPT4gdG90YWxDb3VudCAtIDEpXHJcbiAgICAgICAgICAgICAgdXBkYXRlKCdpdGVtcycsIChpdGVtcykgPT5cclxuICAgICAgICAgICAgICAgIGl0ZW1zLmZpbHRlcigoaSkgPT4gcmVhZEZpZWxkKGksICdpZCcpICE9PSBldmVudC5pZClcclxuICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgKVxyXG4gICAgICB9IGVsc2UgaWYgKGlzTmV3ICYmIGNvbW1lbnQpIHtcclxuICAgICAgICBjb25zdCBwYXJlbnRJZCA9IGNvbW1lbnQucGFyZW50Py5pZFxyXG5cclxuICAgICAgICAvLyBBZGQgcmVwbHkgdG8gcGFyZW50XHJcbiAgICAgICAgaWYgKHBhcmVudElkKSB7XHJcbiAgICAgICAgICBtb2RpZnlPYmplY3RGaWVsZChcclxuICAgICAgICAgICAgY2FjaGUsXHJcbiAgICAgICAgICAgIGdldENhY2hlSWQoJ0NvbW1lbnQnLCBwYXJlbnRJZCksXHJcbiAgICAgICAgICAgICdyZXBsaWVzJyxcclxuICAgICAgICAgICAgKHsgaGVscGVyczogeyBjcmVhdGVVcGRhdGVkVmFsdWUsIHJlZiB9IH0pID0+XHJcbiAgICAgICAgICAgICAgY3JlYXRlVXBkYXRlZFZhbHVlKCh7IHVwZGF0ZSB9KSA9PiB7XHJcbiAgICAgICAgICAgICAgICB1cGRhdGUoJ3RvdGFsQ291bnQnLCAodG90YWxDb3VudCkgPT4gdG90YWxDb3VudCArIDEpXHJcbiAgICAgICAgICAgICAgICB1cGRhdGUoJ2l0ZW1zJywgKGl0ZW1zKSA9PiBbcmVmKCdDb21tZW50JywgY29tbWVudC5pZCksIC4uLml0ZW1zXSlcclxuICAgICAgICAgICAgICB9KVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAvLyBBZGQgY29tbWVudCB0aHJlYWRcclxuICAgICAgICAgIG1vZGlmeU9iamVjdEZpZWxkKFxyXG4gICAgICAgICAgICBjYWNoZSxcclxuICAgICAgICAgICAgZ2V0Q2FjaGVJZCgnUHJvamVjdCcsIHByb2plY3RJZC52YWx1ZSksXHJcbiAgICAgICAgICAgICdjb21tZW50VGhyZWFkcycsXHJcbiAgICAgICAgICAgICh7IGhlbHBlcnM6IHsgcmVmLCBjcmVhdGVVcGRhdGVkVmFsdWUsIHJlYWRGaWVsZCB9LCB2YWx1ZSB9KSA9PiB7XHJcbiAgICAgICAgICAgICAgLy8gSW4gY2FzZSB0aGlzIGlzIGFjdHVhbGx5IGFuIHVuYXJjaGl2ZWQgY29tbWVudCwgd2Ugb25seSB3YW50IHRvIGFkZCBpdCBpZiBpdCBkb2VzbnRcclxuICAgICAgICAgICAgICAvLyBleGlzdCBpbiB0aGUgaW5jbHVkZXNBcmNoaXZlZCBsaXN0IGFscmVhZHlcclxuICAgICAgICAgICAgICBjb25zdCBpbmNsdWRlc0l0ZW0gPSB2YWx1ZS5pdGVtcz8uZmluZChcclxuICAgICAgICAgICAgICAgIChpKSA9PiByZWFkRmllbGQoaSwgJ2lkJykgPT09IGNvbW1lbnQuaWRcclxuICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICAgaWYgKGluY2x1ZGVzSXRlbSkgcmV0dXJuXHJcblxyXG4gICAgICAgICAgICAgIHJldHVybiBjcmVhdGVVcGRhdGVkVmFsdWUoKHsgdXBkYXRlIH0pID0+IHtcclxuICAgICAgICAgICAgICAgIHVwZGF0ZSgndG90YWxDb3VudCcsICh0b3RhbENvdW50KSA9PiB0b3RhbENvdW50ICsgMSlcclxuICAgICAgICAgICAgICAgIHVwZGF0ZSgnaXRlbXMnLCAoaXRlbXMpID0+IFtyZWYoJ0NvbW1lbnQnLCBjb21tZW50LmlkKSwgLi4uaXRlbXNdKVxyXG4gICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICApXHJcbn1cclxuXHJcbmZ1bmN0aW9uIHVzZVZpZXdlclNlY3Rpb25Cb3hJbnRlZ3JhdGlvbigpIHtcclxuICBjb25zdCB7XHJcbiAgICB1aToge1xyXG4gICAgICBzZWN0aW9uQm94LFxyXG4gICAgICBzZWN0aW9uQm94Q29udGV4dDogeyB2aXNpYmxlLCBlZGl0ZWQgfVxyXG4gICAgfSxcclxuICAgIHZpZXdlcjogeyBpbnN0YW5jZSB9XHJcbiAgfSA9IHVzZUluamVjdGVkVmlld2VyU3RhdGUoKVxyXG5cclxuICBjb25zdCB7IHNlY3Rpb25Cb3hEYXRhVG9Cb3gzLCBzZWN0aW9uQm94RGF0YUVxdWFscyB9ID0gdXNlU2VjdGlvbkJveFV0aWxpdGllcygpXHJcblxyXG4gIC8vIENoYW5nZSBlZGl0ZWQ9dHJ1ZSB3aGVuIHVzZXIgc3RhcnRzIGNoYW5naW5nIHRoZSBzZWN0aW9uIGJveCBieSBkcmFnZ2luZyBpdFxyXG4gIGNvbnN0IHNlY3Rpb25Ub29sID0gaW5zdGFuY2UuZ2V0RXh0ZW5zaW9uKFNlY3Rpb25Ub29sKVxyXG4gIGNvbnN0IG9uRHJhZ1N0YXJ0ID0gKCkgPT4ge1xyXG4gICAgZWRpdGVkLnZhbHVlID0gdHJ1ZVxyXG4gIH1cclxuICBzZWN0aW9uVG9vbC5vbihTZWN0aW9uVG9vbEV2ZW50LkRyYWdTdGFydCwgb25EcmFnU3RhcnQpXHJcblxyXG4gIC8vIE5vIHR3by13YXkgc3luYyBmb3Igc2VjdGlvbiBib3hlcywgYmVjYXVzZSBvbmNlIHlvdSBzZXQgYSBCb3gzIGludG8gdGhlIHZpZXdlclxyXG4gIC8vIHRoZSB2aWV3ZXIgdHJhbnNmb3JtcyBpdCBpbnRvIHNvbWV0aGluZyBlbHNlIGNhdXNpbmcgdGhlIHVwZGF0ZXMgZ29pbmcgaW50byBhbiBpbmZpbml0ZSBsb29wXHJcblxyXG4gIC8vIHN0YXRlIC0+IHZpZXdlclxyXG4gIHdhdGNoKFxyXG4gICAgc2VjdGlvbkJveCxcclxuICAgIChuZXdWYWwsIG9sZFZhbCkgPT4ge1xyXG4gICAgICBpZiAobmV3VmFsICYmIG9sZFZhbCAmJiBzZWN0aW9uQm94RGF0YUVxdWFscyhuZXdWYWwsIG9sZFZhbCkpIHJldHVyblxyXG4gICAgICBpZiAoIW5ld1ZhbCAmJiAhb2xkVmFsKSByZXR1cm5cclxuXHJcbiAgICAgIGlmIChvbGRWYWwgJiYgIW5ld1ZhbCkge1xyXG4gICAgICAgIHZpc2libGUudmFsdWUgPSBmYWxzZVxyXG4gICAgICAgIGVkaXRlZC52YWx1ZSA9IGZhbHNlXHJcblxyXG4gICAgICAgIHNlY3Rpb25Ub29sLmVuYWJsZWQgPSBmYWxzZVxyXG4gICAgICAgIGluc3RhbmNlLnJlcXVlc3RSZW5kZXIoVXBkYXRlRmxhZ3MuUkVOREVSX1JFU0VUKVxyXG4gICAgICAgIHJldHVyblxyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAobmV3VmFsICYmICghb2xkVmFsIHx8ICFzZWN0aW9uQm94RGF0YUVxdWFscyhuZXdWYWwsIG9sZFZhbCkpKSB7XHJcbiAgICAgICAgdmlzaWJsZS52YWx1ZSA9IHRydWVcclxuICAgICAgICBlZGl0ZWQudmFsdWUgPSBmYWxzZVxyXG5cclxuICAgICAgICBjb25zdCBib3gzID0gc2VjdGlvbkJveERhdGFUb0JveDMobmV3VmFsKVxyXG4gICAgICAgIHNlY3Rpb25Ub29sLnNldEJveChib3gzKVxyXG4gICAgICAgIHNlY3Rpb25Ub29sLmVuYWJsZWQgPSB0cnVlXHJcbiAgICAgICAgY29uc3Qgb3V0bGluZXMgPSBpbnN0YW5jZS5nZXRFeHRlbnNpb24oU2VjdGlvbk91dGxpbmVzKVxyXG4gICAgICAgIGlmIChvdXRsaW5lcykgb3V0bGluZXMucmVxdWVzdFVwZGF0ZSgpXHJcbiAgICAgICAgaW5zdGFuY2UucmVxdWVzdFJlbmRlcihVcGRhdGVGbGFncy5SRU5ERVJfUkVTRVQpXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB7IGltbWVkaWF0ZTogdHJ1ZSwgZGVlcDogdHJ1ZSwgZmx1c2g6ICdzeW5jJyB9XHJcbiAgKVxyXG5cclxuICB3YXRjaChcclxuICAgIHZpc2libGUsXHJcbiAgICAobmV3VmFsLCBvbGRWYWwpID0+IHtcclxuICAgICAgaWYgKG5ld1ZhbCAmJiBvbGRWYWwpIHJldHVyblxyXG4gICAgICBpZiAoIW5ld1ZhbCAmJiAhb2xkVmFsKSByZXR1cm5cclxuXHJcbiAgICAgIGlmIChuZXdWYWwpIHtcclxuICAgICAgICBzZWN0aW9uVG9vbC52aXNpYmxlID0gdHJ1ZVxyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHNlY3Rpb25Ub29sLnZpc2libGUgPSBmYWxzZVxyXG4gICAgICB9XHJcbiAgICAgIGluc3RhbmNlLnJlcXVlc3RSZW5kZXIoKVxyXG4gICAgfSxcclxuICAgIHsgaW1tZWRpYXRlOiB0cnVlLCBkZWVwOiB0cnVlLCBmbHVzaDogJ3N5bmMnIH1cclxuICApXHJcblxyXG4gIG9uQmVmb3JlVW5tb3VudCgoKSA9PiB7XHJcbiAgICBzZWN0aW9uVG9vbC5lbmFibGVkID0gZmFsc2VcclxuICAgIHNlY3Rpb25Ub29sLnJlbW92ZUxpc3RlbmVyKFNlY3Rpb25Ub29sRXZlbnQuRHJhZ1N0YXJ0LCBvbkRyYWdTdGFydClcclxuICB9KVxyXG59XHJcblxyXG5mdW5jdGlvbiB1c2VWaWV3ZXJDYW1lcmFJbnRlZ3JhdGlvbigpIHtcclxuICBjb25zdCB7XHJcbiAgICB2aWV3ZXI6IHsgaW5zdGFuY2UgfSxcclxuICAgIHVpOiB7XHJcbiAgICAgIGNhbWVyYTogeyBpc09ydGhvUHJvamVjdGlvbiwgcG9zaXRpb24sIHRhcmdldCB9LFxyXG4gICAgICBzcG90bGlnaHRVc2VyU2Vzc2lvbklkXHJcbiAgICB9XHJcbiAgfSA9IHVzZUluamVjdGVkVmlld2VyU3RhdGUoKVxyXG4gIGNvbnN0IHsgZm9yY2VWaWV3VG9WaWV3ZXJTeW5jLCBzZXRWaWV3LCBjYW1lcmFDb250cm9sbGVyIH0gPSB1c2VDYW1lcmFVdGlsaXRpZXMoKVxyXG5cclxuICBjb25zdCBoYXNJbml0aWFsTG9hZEZpcmVkID0gcmVmKGZhbHNlKVxyXG5cclxuICBjb25zdCBsb2FkQ2FtZXJhRGF0YUZyb21WaWV3ZXIgPSAoKSA9PiB7XHJcbiAgICBjb25zdCBleHRlbnNpb246IENhbWVyYUNvbnRyb2xsZXIgPSBpbnN0YW5jZS5nZXRFeHRlbnNpb24oQ2FtZXJhQ29udHJvbGxlcilcclxuXHJcbiAgICBjb25zdCB2aWV3ZXJQb3MgPSBuZXcgVmVjdG9yMygpLmNvcHkoZXh0ZW5zaW9uLmdldFBvc2l0aW9uKCkpXHJcbiAgICBjb25zdCB2aWV3ZXJUYXJnZXQgPSBuZXcgVmVjdG9yMygpLmNvcHkoZXh0ZW5zaW9uLmdldFRhcmdldCgpKVxyXG5cclxuICAgIGlmIChoYXNJbml0aWFsTG9hZEZpcmVkLnZhbHVlKSB7XHJcbiAgICAgIGlmICghYXJlVmVjdG9yc0xvb3NlbHlFcXVhbChwb3NpdGlvbi52YWx1ZSwgdmlld2VyUG9zKSkge1xyXG4gICAgICAgIHBvc2l0aW9uLnZhbHVlID0gdmlld2VyUG9zLmNsb25lKClcclxuICAgICAgfVxyXG4gICAgICBpZiAoIWFyZVZlY3RvcnNMb29zZWx5RXF1YWwodGFyZ2V0LnZhbHVlLCB2aWV3ZXJUYXJnZXQpKSB7XHJcbiAgICAgICAgdGFyZ2V0LnZhbHVlID0gdmlld2VyVGFyZ2V0LmNsb25lKClcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gdmlld2VyIC0+IHN0YXRlXHJcbiAgLy8gZGVib3VuY2luZyBwb3MvdGFyZ2V0IHVwZGF0ZXMgdG8gYXZvaWQgaml0dGVyaW5lc3MgKyBzcG90bGlnaHQgbW9kZSB1bm5lY2Vzc2FyaWx5IGRpc2FibGluZ1xyXG4gIHVzZVZpZXdlckNhbWVyYVRyYWNrZXIoXHJcbiAgICAoKSA9PiB7XHJcbiAgICAgIGxvYWRDYW1lcmFEYXRhRnJvbVZpZXdlcigpXHJcbiAgICB9LFxyXG4gICAgeyB0aHJvdHRsZVdhaXQ6IDEwMCB9XHJcbiAgKVxyXG5cclxuICB1c2VPblZpZXdlckxvYWRDb21wbGV0ZSgoeyBpc0luaXRpYWwgfSkgPT4ge1xyXG4gICAgaWYgKGlzSW5pdGlhbCkge1xyXG4gICAgICBoYXNJbml0aWFsTG9hZEZpcmVkLnZhbHVlID0gdHJ1ZVxyXG5cclxuICAgICAgLy8gTG9hZCBjYW1lcmEgcG9zaXRpb24gc28gd2UgY2FuIHJldHVybiB0byBpdCBjb3JyZWN0bHlcclxuICAgICAgLy8gT05MWSBpZiB3ZSBkb24ndCBhbHJlYWR5IGhhdmUgc3BlY2lmaWMgY29vcmRpbmF0ZXMgKGUuZy4gZnJvbSBvcGVuZWQgdGhyZWFkKVxyXG4gICAgICAvLyBvdGhlcndpc2UgLSBsb2FkIGN1cnJlbnQgcG9zL3RhcmdldCBpbnRvIHZpZXdlclxyXG4gICAgICBjb25zdCBoYXNJbml0Q29vcmRzID1cclxuICAgICAgICBwb3NpdGlvbi52YWx1ZS5lcXVhbHMobmV3IFZlY3RvcjMoKSkgJiYgdGFyZ2V0LnZhbHVlLmVxdWFscyhuZXcgVmVjdG9yMygpKVxyXG4gICAgICBpZiAoaGFzSW5pdENvb3Jkcykge1xyXG4gICAgICAgIGxvYWRDYW1lcmFEYXRhRnJvbVZpZXdlcigpXHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgZm9yY2VWaWV3VG9WaWV3ZXJTeW5jKClcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gT25seSBub3cgc2V0IHByb2plY3Rpb24sIHdlIGNhbid0IGRvIGl0IHRvbyBlYXJseVxyXG4gICAgICBvcnRob1Byb2plY3Rpb25VcGRhdGUoaXNPcnRob1Byb2plY3Rpb24udmFsdWUpXHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBsb2FkQ2FtZXJhRGF0YUZyb21WaWV3ZXIoKVxyXG4gICAgfVxyXG4gIH0pXHJcblxyXG4gIHVzZVZpZXdlckNhbWVyYUNvbnRyb2xTdGFydFRyYWNrZXIoKCkgPT4ge1xyXG4gICAgaWYgKHNwb3RsaWdodFVzZXJTZXNzaW9uSWQudmFsdWUpIHtcclxuICAgICAgc3BvdGxpZ2h0VXNlclNlc3Npb25JZC52YWx1ZSA9IG51bGwgLy8gY2FuY2VsXHJcbiAgICB9XHJcbiAgfSlcclxuXHJcbiAgY29uc3Qgb3J0aG9Qcm9qZWN0aW9uVXBkYXRlID0gKG5ld1ZhbDogYm9vbGVhbikgPT4ge1xyXG4gICAgaWYgKCFoYXNJbml0aWFsTG9hZEZpcmVkLnZhbHVlKSB7XHJcbiAgICAgIHRocm93IG5ldyBFcnJvcignQXR0ZW1wdGluZyB0byBzZXQgcHJvamVjdGlvbiB0b28gZWFybHknKVxyXG4gICAgfVxyXG5cclxuICAgIGlmIChuZXdWYWwpIHtcclxuICAgICAgY2FtZXJhQ29udHJvbGxlci5zZXRPcnRob0NhbWVyYU9uKClcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGNhbWVyYUNvbnRyb2xsZXIuc2V0UGVyc3BlY3RpdmVDYW1lcmFPbigpXHJcbiAgICB9XHJcblxyXG4gICAgLy8gcmVzZXQgY2FtZXJhIHBvcywgY2F1c2Ugd2UndmUgc3dpdGNoZWQgY2FtZXJhcyBub3cgYW5kIGl0IG1pZ2h0IG5vdCBoYXZlIHRoZSBuZXcgb25lc1xyXG4gICAgZm9yY2VWaWV3VG9WaWV3ZXJTeW5jKClcclxuICB9XHJcblxyXG4gIC8vIHN0YXRlIC0+IHZpZXdlclxyXG4gIHdhdGNoKFxyXG4gICAgaXNPcnRob1Byb2plY3Rpb24sXHJcbiAgICAobmV3VmFsLCBvbGRWYWwpID0+IHtcclxuICAgICAgaWYgKG5ld1ZhbCA9PT0gb2xkVmFsIHx8ICFoYXNJbml0aWFsTG9hZEZpcmVkLnZhbHVlKSByZXR1cm5cclxuICAgICAgb3J0aG9Qcm9qZWN0aW9uVXBkYXRlKG5ld1ZhbClcclxuICAgIH0sXHJcbiAgICB7IGltbWVkaWF0ZTogdHJ1ZSB9XHJcbiAgKVxyXG5cclxuICB3YXRjaChcclxuICAgIHBvc2l0aW9uLFxyXG4gICAgKG5ld1ZhbCwgb2xkVmFsKSA9PiB7XHJcbiAgICAgIGlmICgoIW5ld1ZhbCAmJiAhb2xkVmFsKSB8fCAob2xkVmFsICYmIGFyZVZlY3RvcnNMb29zZWx5RXF1YWwobmV3VmFsLCBvbGRWYWwpKSkge1xyXG4gICAgICAgIHJldHVyblxyXG4gICAgICB9XHJcbiAgICAgIHNldFZpZXcoe1xyXG4gICAgICAgIHBvc2l0aW9uOiBuZXdWYWwsXHJcbiAgICAgICAgdGFyZ2V0OiB0YXJnZXQudmFsdWVcclxuICAgICAgfSlcclxuICAgIH1cclxuICAgIC8vIHsgaW1tZWRpYXRlOiB0cnVlIH1cclxuICApXHJcblxyXG4gIHdhdGNoKFxyXG4gICAgdGFyZ2V0LFxyXG4gICAgKG5ld1ZhbCwgb2xkVmFsKSA9PiB7XHJcbiAgICAgIGlmICgoIW5ld1ZhbCAmJiAhb2xkVmFsKSB8fCAob2xkVmFsICYmIGFyZVZlY3RvcnNMb29zZWx5RXF1YWwobmV3VmFsLCBvbGRWYWwpKSkge1xyXG4gICAgICAgIHJldHVyblxyXG4gICAgICB9XHJcblxyXG4gICAgICBzZXRWaWV3KHtcclxuICAgICAgICBwb3NpdGlvbjogcG9zaXRpb24udmFsdWUsXHJcbiAgICAgICAgdGFyZ2V0OiBuZXdWYWxcclxuICAgICAgfSlcclxuICAgIH1cclxuICAgIC8vIHsgaW1tZWRpYXRlOiB0cnVlIH1cclxuICApXHJcbn1cclxuXHJcbmZ1bmN0aW9uIHVzZVZpZXdlckZpbHRlcnNJbnRlZ3JhdGlvbigpIHtcclxuICBjb25zdCBzdGF0ZSA9IHVzZUluamVjdGVkVmlld2VyU3RhdGUoKVxyXG4gIGNvbnN0IHtcclxuICAgIHZpZXdlcjogeyBpbnN0YW5jZSB9LFxyXG4gICAgdWk6IHsgZmlsdGVycyB9XHJcbiAgfSA9IHN0YXRlXHJcblxyXG4gIHVzZUZpbHRlcmluZ1NldHVwKClcclxuICB1c2VGaWx0ZXJVdGlsaXRpZXMoeyBzdGF0ZSB9KVxyXG5cclxuICB3YXRjaChcclxuICAgIGZpbHRlcnMuc2VsZWN0ZWRPYmplY3RzLFxyXG4gICAgKG5ld1ZhbCwgb2xkVmFsKSA9PiB7XHJcbiAgICAgIGNvbnN0IG5ld0lkcyA9IGZsYXR0ZW4oXG4gICAgICAgIG5ld1ZhbC5tYXAoKHYpID0+IGdldFRhcmdldE9iamVjdElkcyh2IGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KSlcbiAgICAgICkuZmlsdGVyKGlzTm9uTnVsbGFibGUpXG4gICAgICBjb25zdCBvbGRJZHMgPSBmbGF0dGVuKFxuICAgICAgICAob2xkVmFsIHx8IFtdKS5tYXAoKHYpID0+IGdldFRhcmdldE9iamVjdElkcyh2IGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KSlcbiAgICAgICkuZmlsdGVyKGlzTm9uTnVsbGFibGUpXG4gICAgICBpZiAoYXJyYXlzRXF1YWwobmV3SWRzLCBvbGRJZHMpKSByZXR1cm5cclxuXHJcbiAgICAgIGNvbnN0IHNlbGVjdGlvbkV4dGVuc2lvbiA9IGluc3RhbmNlLmdldEV4dGVuc2lvbihTZWxlY3Rpb25FeHRlbnNpb24pXHJcbiAgICAgIGNvbnN0IGN1cnJlbnRWaWV3ZXJTZWxlY3Rpb24gPSBzZWxlY3Rpb25FeHRlbnNpb25cclxuICAgICAgICAuZ2V0U2VsZWN0ZWRPYmplY3RzKClcclxuICAgICAgICAubWFwKChvYmopID0+IG9iai5pZCBhcyBzdHJpbmcpXHJcblxyXG4gICAgICBpZiAoXHJcbiAgICAgICAgY3VycmVudFZpZXdlclNlbGVjdGlvbi5sZW5ndGggPT09IG5ld0lkcy5sZW5ndGggJiZcclxuICAgICAgICBkaWZmZXJlbmNlKGN1cnJlbnRWaWV3ZXJTZWxlY3Rpb24sIG5ld0lkcykubGVuZ3RoID09PSAwXHJcbiAgICAgICkge1xyXG4gICAgICAgIHJldHVyblxyXG4gICAgICB9XHJcblxyXG4gICAgICBzdGF0ZS51aS5oaWdobGlnaHRlZE9iamVjdElkcy52YWx1ZSA9IFtdXHJcbiAgICAgIGNvbnN0IGhpZ2hsaWdodEV4dGVuc2lvbiA9IGluc3RhbmNlLmdldEV4dGVuc2lvbihIaWdobGlnaHRFeHRlbnNpb24pXHJcbiAgICAgIGlmIChoaWdobGlnaHRFeHRlbnNpb24pIHtcclxuICAgICAgICBoaWdobGlnaHRFeHRlbnNpb24uY2xlYXJTZWxlY3Rpb24oKVxyXG4gICAgICB9XHJcblxyXG4gICAgICBzZWxlY3Rpb25FeHRlbnNpb24uY2xlYXJTZWxlY3Rpb24oKVxyXG4gICAgICBpZiAobmV3VmFsLmxlbmd0aCA+IDApIHtcclxuICAgICAgICBzZWxlY3Rpb25FeHRlbnNpb24uc2VsZWN0T2JqZWN0cyhuZXdJZHMpXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIGltbWVkaWF0ZTogdHJ1ZSxcclxuICAgICAgZmx1c2g6ICdzeW5jJ1xyXG4gICAgfVxyXG4gIClcclxufVxyXG5cclxuZnVuY3Rpb24gdXNlTGlnaHRDb25maWdJbnRlZ3JhdGlvbigpIHtcclxuICBjb25zdCB7XHJcbiAgICB1aTogeyBsaWdodENvbmZpZyB9LFxyXG4gICAgdmlld2VyOiB7IGluc3RhbmNlIH1cclxuICB9ID0gdXNlSW5qZWN0ZWRWaWV3ZXJTdGF0ZSgpXHJcblxyXG4gIC8vIHZpZXdlciAtPiBzdGF0ZVxyXG4gIHVzZVZpZXdlckV2ZW50TGlzdGVuZXIoXHJcbiAgICBWaWV3ZXJFdmVudC5MaWdodENvbmZpZ1VwZGF0ZWQsXHJcbiAgICAoY29uZmlnOiBTdW5MaWdodENvbmZpZ3VyYXRpb24pID0+IHtcclxuICAgICAgaWYgKGlzRXF1YWwobGlnaHRDb25maWcudmFsdWUsIGNvbmZpZykpIHJldHVyblxyXG4gICAgICBsaWdodENvbmZpZy52YWx1ZSA9IGNvbmZpZ1xyXG4gICAgfVxyXG4gIClcclxuXHJcbiAgLy8gc3RhdGUgLT4gdmlld2VyXHJcbiAgd2F0Y2goXHJcbiAgICBsaWdodENvbmZpZyxcclxuICAgIChuZXdWYWwsIG9sZFZhbCkgPT4ge1xyXG4gICAgICBpZiAobmV3VmFsICYmIG9sZFZhbCAmJiBpc0VxdWFsKG5ld1ZhbCwgb2xkVmFsKSkgcmV0dXJuXHJcbiAgICAgIGluc3RhbmNlLnNldExpZ2h0Q29uZmlndXJhdGlvbihuZXdWYWwpXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICBpbW1lZGlhdGU6IHRydWUsXHJcbiAgICAgIGRlZXA6IHRydWUsXHJcbiAgICAgIGZsdXNoOiAnc3luYydcclxuICAgIH1cclxuICApXHJcblxyXG4gIHVzZU9uVmlld2VyTG9hZENvbXBsZXRlKFxyXG4gICAgKCkgPT4ge1xyXG4gICAgICBpbnN0YW5jZS5zZXRMaWdodENvbmZpZ3VyYXRpb24obGlnaHRDb25maWcudmFsdWUpXHJcbiAgICB9LFxyXG4gICAgeyBpbml0aWFsT25seTogdHJ1ZSB9XHJcbiAgKVxyXG59XHJcblxyXG5mdW5jdGlvbiB1c2VFeHBsb2RlRmFjdG9ySW50ZWdyYXRpb24oKSB7XHJcbiAgY29uc3Qge1xyXG4gICAgdWk6IHsgZXhwbG9kZUZhY3RvciB9LFxyXG4gICAgdmlld2VyOiB7IGluc3RhbmNlIH1cclxuICB9ID0gdXNlSW5qZWN0ZWRWaWV3ZXJTdGF0ZSgpXHJcblxyXG4gIGNvbnN0IGV4cGxvZGVFeHRlbnNpb24gPSBpbnN0YW5jZS5nZXRFeHRlbnNpb24oRXhwbG9kZUV4dGVuc2lvbilcclxuXHJcbiAgY29uc3QgdXBkYXRlT3V0bGluZXMgPSAoKSA9PiB7XHJcbiAgICBjb25zdCBzZWN0aW9uT3V0bGluZXMgPSBpbnN0YW5jZS5nZXRFeHRlbnNpb24oU2VjdGlvbk91dGxpbmVzKVxyXG4gICAgaWYgKHNlY3Rpb25PdXRsaW5lcyAmJiBzZWN0aW9uT3V0bGluZXMuZW5hYmxlZCkgc2VjdGlvbk91dGxpbmVzLnJlcXVlc3RVcGRhdGUodHJ1ZSlcclxuICB9XHJcbiAgb25Nb3VudGVkKCgpID0+IHtcclxuICAgIGV4cGxvZGVFeHRlbnNpb24ub24oRXhwbG9kZUV2ZW50LkZpbnNoZWQsIHVwZGF0ZU91dGxpbmVzKVxyXG4gIH0pXHJcblxyXG4gIG9uQmVmb3JlVW5tb3VudCgoKSA9PiB7XHJcbiAgICBleHBsb2RlRXh0ZW5zaW9uLnJlbW92ZUxpc3RlbmVyKEV4cGxvZGVFdmVudC5GaW5zaGVkLCB1cGRhdGVPdXRsaW5lcylcclxuICB9KVxyXG5cclxuICAvLyBzdGF0ZSAtPiB2aWV3ZXIgb25seS4gd2UgZG9uJ3QgbmVlZCB0aGUgcmV2ZXJzZS5cclxuICB3YXRjaChcclxuICAgIGV4cGxvZGVGYWN0b3IsXHJcbiAgICAobmV3VmFsKSA9PiB7XHJcbiAgICAgIGV4cGxvZGVFeHRlbnNpb24uc2V0RXhwbG9kZShuZXdWYWwpXHJcbiAgICB9LFxyXG4gICAgeyBpbW1lZGlhdGU6IHRydWUgfVxyXG4gIClcclxuXHJcbiAgdXNlT25WaWV3ZXJMb2FkQ29tcGxldGUoXHJcbiAgICAoKSA9PiB7XHJcbiAgICAgIGV4cGxvZGVFeHRlbnNpb24uc2V0RXhwbG9kZShleHBsb2RlRmFjdG9yLnZhbHVlKVxyXG4gICAgfSxcclxuICAgIHsgaW5pdGlhbE9ubHk6IHRydWUgfVxyXG4gIClcclxufVxyXG5cclxuZnVuY3Rpb24gdXNlRGlmZmluZ0ludGVncmF0aW9uKCkge1xyXG4gIGNvbnN0IHN0YXRlID0gdXNlSW5qZWN0ZWRWaWV3ZXJTdGF0ZSgpXHJcbiAgY29uc3QgeyBlZmZlY3RpdmVBdXRoVG9rZW4gfSA9IHVzZUF1dGhNYW5hZ2VyKClcclxuICBjb25zdCBnZXRPYmplY3RVcmwgPSB1c2VHZXRPYmplY3RVcmwoKVxyXG5cclxuICBjb25zdCBoYXNJbml0aWFsTG9hZEZpcmVkID0gcmVmKGZhbHNlKVxyXG4gIGNvbnN0IGRpZmZFeHRlbnNpb24gPSBzdGF0ZS52aWV3ZXIuaW5zdGFuY2UuZ2V0RXh0ZW5zaW9uKERpZmZFeHRlbnNpb24pXHJcblxyXG4gIGNvbnN0IHsgdHJpZ2dlcjogdHJpZ2dlckRpZmZDb21tYW5kV2F0Y2ggfSA9IHdhdGNoVHJpZ2dlcmFibGUoXHJcbiAgICAoKSA9PiA8Y29uc3Q+W3N0YXRlLnVpLmRpZmYub2xkVmVyc2lvbi52YWx1ZSwgc3RhdGUudWkuZGlmZi5uZXdWZXJzaW9uLnZhbHVlXSxcclxuICAgIGFzeW5jIChuZXdWYWwsIG9sZFZhbCkgPT4ge1xyXG4gICAgICBpZiAoIWhhc0luaXRpYWxMb2FkRmlyZWQudmFsdWUpIHJldHVyblxyXG4gICAgICBjb25zdCBbb2xkVmVyc2lvbiwgbmV3VmVyc2lvbl0gPSBuZXdWYWxcclxuICAgICAgY29uc3QgW29sZE9sZFZlcnNpb24sIG9sZE5ld1ZlcnNpb25dID0gb2xkVmFsIHx8IFtudWxsLCBudWxsXVxyXG5cclxuICAgICAgY29uc3QgdmVyc2lvbklkID0gKHZlcnNpb246IHR5cGVvZiBvbGRPbGRWZXJzaW9uKSA9PiB2ZXJzaW9uPy5pZCB8fCBudWxsXHJcbiAgICAgIGNvbnN0IGNvbW1hbmRJZCA9IChcclxuICAgICAgICBvbGRWZXJzaW9uOiB0eXBlb2Ygb2xkT2xkVmVyc2lvbixcclxuICAgICAgICBuZXdWZXJzaW9uOiB0eXBlb2Ygb2xkT2xkVmVyc2lvblxyXG4gICAgICApID0+IHtcclxuICAgICAgICBjb25zdCBvbGRJZCA9IHZlcnNpb25JZChvbGRWZXJzaW9uKVxyXG4gICAgICAgIGNvbnN0IG5ld0lkID0gdmVyc2lvbklkKG5ld1ZlcnNpb24pXHJcbiAgICAgICAgcmV0dXJuIG9sZElkICYmIG5ld0lkID8gYCR7b2xkSWR9LT4ke25ld0lkfWAgOiBudWxsXHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGNvbnN0IG5ld0NvbW1hbmQgPSBjb21tYW5kSWQob2xkVmVyc2lvbiwgbmV3VmVyc2lvbilcclxuICAgICAgY29uc3Qgb2xkQ29tbWFuZCA9IGNvbW1hbmRJZChvbGRPbGRWZXJzaW9uLCBvbGROZXdWZXJzaW9uKVxyXG5cclxuICAgICAgaWYgKChuZXdDb21tYW5kICYmIG9sZENvbW1hbmQgPT09IG5ld0NvbW1hbmQpIHx8ICEhbmV3Q29tbWFuZCA9PT0gISFvbGRDb21tYW5kKVxyXG4gICAgICAgIHJldHVyblxyXG5cclxuICAgICAgaWYgKCFuZXdDb21tYW5kIHx8IG9sZFZhbCkge1xyXG4gICAgICAgIGF3YWl0IGRpZmZFeHRlbnNpb24udW5kaWZmKClcclxuICAgICAgICBpZiAoIW5ld0NvbW1hbmQpIHJldHVyblxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyB2YWx1ZXMgc2hvdWxkbid0IGJlIHVuZGVmaW5lZCBjYXVzZSBjb21tYW5kSWQoKSBnZW5lcmF0aW9uIHN1Y2NlZWRlZFxyXG4gICAgICBjb25zdCBvbGRPYmpVcmwgPSBnZXRPYmplY3RVcmwoXHJcbiAgICAgICAgc3RhdGUucHJvamVjdElkLnZhbHVlLFxyXG4gICAgICAgIG9sZFZlcnNpb24/LnJlZmVyZW5jZWRPYmplY3QgYXMgc3RyaW5nXHJcbiAgICAgIClcclxuICAgICAgY29uc3QgbmV3T2JqVXJsID0gZ2V0T2JqZWN0VXJsKFxyXG4gICAgICAgIHN0YXRlLnByb2plY3RJZC52YWx1ZSxcclxuICAgICAgICBuZXdWZXJzaW9uPy5yZWZlcmVuY2VkT2JqZWN0IGFzIHN0cmluZ1xyXG4gICAgICApXHJcblxyXG4gICAgICBzdGF0ZS51aS5kaWZmLnJlc3VsdC52YWx1ZSA9IGF3YWl0IGRpZmZFeHRlbnNpb24uZGlmZihcclxuICAgICAgICBvbGRPYmpVcmwsXHJcbiAgICAgICAgbmV3T2JqVXJsLFxyXG4gICAgICAgIHN0YXRlLnVpLmRpZmYubW9kZS52YWx1ZSxcclxuICAgICAgICBlZmZlY3RpdmVBdXRoVG9rZW4udmFsdWVcclxuICAgICAgKVxyXG4gICAgfSxcclxuICAgIHsgaW1tZWRpYXRlOiB0cnVlIH1cclxuICApXHJcblxyXG4gIC8vIGNvbnN0IHByZXZlbnRXYXRjaGVycyA9IDBcclxuICB3YXRjaChzdGF0ZS51aS5kaWZmLnJlc3VsdCwgKHZhbCkgPT4ge1xyXG4gICAgaWYgKCF2YWwpIHJldHVyblxyXG4gICAgLy8gcmVzZXQgdmlzdWFsIGRpZmYgdGltZSBhbmQgbW9kZSBvbiBuZXcgZGlmZiByZXN1bHRcclxuICAgIC8vIHNvbWV0aW1lcyB0aGUgd2F0Y2hlciB3b24ndCBmaXJlIGV2ZW4gd2hlbiB0aGUgdmFsdWVzIGFyZSB1cGRhdGVkLCBiZWNhdXNlIHRoZXkncmUgdXBkYXRlZCB0b1xyXG4gICAgLy8gdGhlIHNhbWUgdmFsdWVzIHRoYXQgdGhleSB3ZXJlIGFscmVhZHkuIGJlY2F1c2Ugb2YgdGhhdCB3ZSdyZSBtYW51YWxseSAmIGZvcmNlZnVsbHkgcnVubmluZ1xyXG4gICAgLy8gdGhlIHJlbGV2YW50IHdhdGNoZXJzIHdoZW4gZGlmZlJlc3VsdCBjaGFuZ2VzXHJcbiAgICBpZ25vcmVEaWZmTW9kZVVwZGF0ZXMoKCkgPT4ge1xyXG4gICAgICBpZ25vcmVEaWZmVGltZVVwZGF0ZXMoKCkgPT4ge1xyXG4gICAgICAgIHN0YXRlLnVpLmRpZmYudGltZS52YWx1ZSA9IDAuNVxyXG4gICAgICAgIHN0YXRlLnVpLmRpZmYubW9kZS52YWx1ZSA9IFZpc3VhbERpZmZNb2RlLkNPTE9SRURcclxuXHJcbiAgICAgICAgLy8gdGhpcyB3YXRjaGVyIGFsc28gdXBkYXRlcyBkaWZmVGltZSwgc28gbm8gbmVlZCB0byBpbnZva2UgdGhhdCBzZXBhcmF0ZWx5XHJcbiAgICAgICAgdHJpZ2dlckRpZmZNb2RlV2F0Y2goKVxyXG4gICAgICB9KVxyXG4gICAgfSlcclxuICB9KVxyXG5cclxuICBjb25zdCB7IGlnbm9yZVVwZGF0ZXM6IGlnbm9yZURpZmZUaW1lVXBkYXRlcyB9ID0gd2F0Y2hUcmlnZ2VyYWJsZShcclxuICAgIHN0YXRlLnVpLmRpZmYudGltZSxcclxuICAgICh2YWwpID0+IHtcclxuICAgICAgaWYgKCFoYXNJbml0aWFsTG9hZEZpcmVkLnZhbHVlKSByZXR1cm5cclxuICAgICAgaWYgKCFzdGF0ZS51aS5kaWZmLnJlc3VsdC52YWx1ZSkgcmV0dXJuXHJcblxyXG4gICAgICBkaWZmRXh0ZW5zaW9uLnVwZGF0ZVZpc3VhbERpZmYodmFsLCBzdGF0ZS51aS5kaWZmLm1vZGUudmFsdWUpXHJcbiAgICB9XHJcbiAgKVxyXG5cclxuICBjb25zdCB7IHRyaWdnZXI6IHRyaWdnZXJEaWZmTW9kZVdhdGNoLCBpZ25vcmVVcGRhdGVzOiBpZ25vcmVEaWZmTW9kZVVwZGF0ZXMgfSA9XHJcbiAgICB3YXRjaFRyaWdnZXJhYmxlKHN0YXRlLnVpLmRpZmYubW9kZSwgKHZhbCkgPT4ge1xyXG4gICAgICBpZiAoIWhhc0luaXRpYWxMb2FkRmlyZWQudmFsdWUpIHJldHVyblxyXG4gICAgICBpZiAoIXN0YXRlLnVpLmRpZmYucmVzdWx0LnZhbHVlKSByZXR1cm5cclxuXHJcbiAgICAgIGRpZmZFeHRlbnNpb24udXBkYXRlVmlzdWFsRGlmZihzdGF0ZS51aS5kaWZmLnRpbWUudmFsdWUsIHZhbClcclxuICAgIH0pXHJcblxyXG4gIHVzZU9uVmlld2VyTG9hZENvbXBsZXRlKCh7IGlzSW5pdGlhbCB9KSA9PiB7XHJcbiAgICBpZiAoIWlzSW5pdGlhbCkgcmV0dXJuXHJcbiAgICBoYXNJbml0aWFsTG9hZEZpcmVkLnZhbHVlID0gdHJ1ZVxyXG5cclxuICAgIHRyaWdnZXJEaWZmQ29tbWFuZFdhdGNoKClcclxuICB9KVxyXG59XHJcblxyXG5mdW5jdGlvbiB1c2VEaXNhYmxlWm9vbU9uRW1iZWQoKSB7XHJcbiAgY29uc3QgeyB2aWV3ZXIgfSA9IHVzZUluamVjdGVkVmlld2VyU3RhdGUoKVxyXG4gIGNvbnN0IGVtYmVkT3B0aW9ucyA9IHVzZUVtYmVkKClcclxuXHJcbiAgd2F0Y2goXHJcbiAgICAoKSA9PiBlbWJlZE9wdGlvbnMubm9TY3JvbGwudmFsdWUsXHJcbiAgICAobmV3Tm9TY3JvbGxWYWx1ZSkgPT4ge1xyXG4gICAgICBjb25zdCBjYW1lcmFDb250cm9sbGVyOiBDYW1lcmFDb250cm9sbGVyID1cclxuICAgICAgICB2aWV3ZXIuaW5zdGFuY2UuZ2V0RXh0ZW5zaW9uKENhbWVyYUNvbnRyb2xsZXIpXHJcblxyXG4gICAgICBpZiAobmV3Tm9TY3JvbGxWYWx1ZSkge1xyXG4gICAgICAgIGNhbWVyYUNvbnRyb2xsZXIub3B0aW9ucyA9IHsgZW5hYmxlWm9vbTogZmFsc2UgfVxyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGNhbWVyYUNvbnRyb2xsZXIub3B0aW9ucyA9IHsgZW5hYmxlWm9vbTogdHJ1ZSB9XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB7IGltbWVkaWF0ZTogdHJ1ZSB9XHJcbiAgKVxyXG59XHJcblxyXG5mdW5jdGlvbiB1c2VWaWV3ZXJUcmVlSW50ZWdyYXRpb24oKSB7XHJcbiAgY29uc3QgeyB2aWV3ZXIgfSA9IHVzZUluamVjdGVkVmlld2VyU3RhdGUoKVxyXG4gIGNvbnN0IHsgdHJlZVN0YXRlTWFuYWdlciB9ID0gdXNlVHJlZU1hbmFnZW1lbnQoKVxyXG5cclxuICAvLyBJbml0aWFsaXplIHRoZSB0cmVlIHN0YXRlIG1hbmFnZXIgd2l0aCB2aWV3ZXIgaW5zdGFuY2VcclxuICBvbk1vdW50ZWQoKCkgPT4gdHJlZVN0YXRlTWFuYWdlci5pbml0aWFsaXplKHZpZXdlci5pbnN0YW5jZSkpXHJcbn1cclxuXHJcbmdyYXBocWwoYFxyXG4gIGZyYWdtZW50IFVzZVZpZXdlclNhdmVkVmlld1NldHVwX1NhdmVkVmlldyBvbiBTYXZlZFZpZXcge1xyXG4gICAgaWRcclxuICAgIHZpZXdlclN0YXRlXHJcbiAgICAuLi5WaWV3ZXJQYWdlU2V0dXBfU2F2ZWRWaWV3XHJcbiAgfVxyXG5gKVxyXG5cclxuZnVuY3Rpb24gdXNlVmlld2VyQ3Vyc29ySW50ZWdyYXRpb24oKSB7XHJcbiAgY29uc3Qge1xyXG4gICAgdmlld2VyOiB7IGNvbnRhaW5lciB9XHJcbiAgfSA9IHVzZUluamVjdGVkVmlld2VyU3RhdGUoKVxyXG5cclxuICBjb25zdCB7XHJcbiAgICBmaWx0ZXJzOiB7IHNlbGVjdGVkT2JqZWN0cyB9XHJcbiAgfSA9IHVzZUluamVjdGVkVmlld2VySW50ZXJmYWNlU3RhdGUoKVxyXG5cclxuICBjb25zdCB7IHNoaWZ0IH0gPSB1c2VNYWdpY0tleXMoKVxyXG4gIGNvbnN0IGlzRHJhZ2dpbmcgPSByZWYoZmFsc2UpXHJcblxyXG4gIC8vIEhhbmRsZSBtb3VzZSBkb3duL3VwIHRvIHRyYWNrIGRyYWdnaW5nIHN0YXRlXHJcbiAgY29uc3QgaGFuZGxlUG9pbnRlckRvd24gPSAoX2V2ZW50OiBQb2ludGVyRXZlbnQpID0+IHtcclxuICAgIGlmIChzaGlmdC52YWx1ZSAmJiBzZWxlY3RlZE9iamVjdHMudmFsdWUubGVuZ3RoID09PSAwKSB7XHJcbiAgICAgIGlzRHJhZ2dpbmcudmFsdWUgPSB0cnVlXHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBjb25zdCBoYW5kbGVQb2ludGVyVXAgPSAoKSA9PiB7XHJcbiAgICBpc0RyYWdnaW5nLnZhbHVlID0gZmFsc2VcclxuICB9XHJcblxyXG4gIC8vIFNob3cgZGlmZmVyZW50IGN1cnNvcnM6IGdyYWIgKHJlYWR5IHRvIGRyYWcpIHZzIGdyYWJiaW5nIChhY3RpdmVseSBkcmFnZ2luZylcclxuICB3YXRjaChcclxuICAgIFtzaGlmdCwgc2VsZWN0ZWRPYmplY3RzLCBpc0RyYWdnaW5nXSxcclxuICAgICgpID0+IHtcclxuICAgICAgaWYgKCFjb250YWluZXIpIHJldHVyblxyXG5cclxuICAgICAgY29uc3QgaGFzU2VsZWN0aW9uID0gc2VsZWN0ZWRPYmplY3RzLnZhbHVlLmxlbmd0aCA+IDBcclxuICAgICAgY29uc3Qgc2hvdWxkU2hvd0RyYWcgPSBzaGlmdC52YWx1ZSAmJiAhaGFzU2VsZWN0aW9uXHJcblxyXG4gICAgICBpZiAoc2hvdWxkU2hvd0RyYWcpIHtcclxuICAgICAgICBjb250YWluZXIuc3R5bGUuY3Vyc29yID0gaXNEcmFnZ2luZy52YWx1ZSA/ICdncmFiYmluZycgOiAnZ3JhYidcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBjb250YWluZXIuc3R5bGUuY3Vyc29yID0gJydcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHsgaW1tZWRpYXRlOiB0cnVlIH1cclxuICApXHJcblxyXG4gIHVzZUV2ZW50TGlzdGVuZXIoY29udGFpbmVyLCAncG9pbnRlcmRvd24nLCBoYW5kbGVQb2ludGVyRG93biwgeyBwYXNzaXZlOiB0cnVlIH0pXHJcbiAgdXNlRXZlbnRMaXN0ZW5lcihkb2N1bWVudCwgJ3BvaW50ZXJ1cCcsIGhhbmRsZVBvaW50ZXJVcCwgeyBwYXNzaXZlOiB0cnVlIH0pXHJcblxyXG4gIG9uQmVmb3JlVW5tb3VudCgoKSA9PiB7XHJcbiAgICBpZiAoY29udGFpbmVyKSB7XHJcbiAgICAgIGNvbnRhaW5lci5zdHlsZS5jdXJzb3IgPSAnJ1xyXG4gICAgfVxyXG4gIH0pXHJcbn1cclxuXHJcbmNvbnN0IHVzZUNvbW1lbnRDb250ZXh0SW50ZWdyYXRpb24gPSAoKSA9PiB7XHJcbiAgY29uc3QgeyBjbGVhbnVwVGhyZWFkQ29udGV4dCB9ID0gdXNlQ29tbWVudENvbnRleHQoKVxyXG5cclxuICBvbkJlZm9yZVVubW91bnQoKCkgPT4ge1xyXG4gICAgY2xlYW51cFRocmVhZENvbnRleHQoKVxyXG4gIH0pXHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiB1c2VWaWV3ZXJQb3N0U2V0dXAoKSB7XHJcbiAgaWYgKGltcG9ydC5tZXRhLnNlcnZlcikgcmV0dXJuXHJcbiAgdXNlVmlld2VyT2JqZWN0QXV0b0xvYWRpbmcoKVxyXG4gIHVzZVZpZXdlclNhdmVkVmlld0ludGVncmF0aW9uKClcclxuICB1c2VWaWV3ZXJSZWNlaXZlVHJhY2tpbmcoKVxyXG4gIHVzZVZpZXdlclNlbGVjdGlvbkV2ZW50SGFuZGxlcigpXHJcbiAgdXNlVmlld2VyTG9hZENvbXBsZXRlRXZlbnRIYW5kbGVyKClcclxuICB1c2VWaWV3ZXJTdWJzY3JpcHRpb25FdmVudFRyYWNrZXIoKVxyXG4gIHVzZVZpZXdlclRocmVhZFRyYWNraW5nKClcclxuICB1c2VWaWV3ZXJPcGVuZWRUaHJlYWRVcGRhdGVFbWl0dGVyKClcclxuICB1c2VWaWV3ZXJTZWN0aW9uQm94SW50ZWdyYXRpb24oKVxyXG4gIHVzZVZpZXdlckNhbWVyYUludGVncmF0aW9uKClcclxuICB1c2VWaWV3ZXJGaWx0ZXJzSW50ZWdyYXRpb24oKVxyXG4gIHVzZUxpZ2h0Q29uZmlnSW50ZWdyYXRpb24oKVxyXG4gIHVzZUV4cGxvZGVGYWN0b3JJbnRlZ3JhdGlvbigpXHJcbiAgdXNlRGlmZmluZ0ludGVncmF0aW9uKClcclxuICB1c2VNZWFzdXJlbWVudHNQb3N0U2V0dXAoKVxyXG4gIHVzZUZpbHRlckNvbG9yaW5nUG9zdFNldHVwKClcclxuICB1c2VQcm9wZXJ0eUZpbHRlcmluZ1Bvc3RTZXR1cCgpXHJcbiAgdXNlTWFudWFsRmlsdGVyaW5nUG9zdFNldHVwKClcclxuICB1c2VEaXNhYmxlWm9vbU9uRW1iZWQoKVxyXG4gIHVzZVZpZXdlckN1cnNvckludGVncmF0aW9uKClcclxuICB1c2VWaWV3ZXJUcmVlSW50ZWdyYXRpb24oKVxyXG4gIHVzZVZpZXdNb2Rlc1Bvc3RTZXR1cCgpXHJcbiAgdXNlSGlnaGxpZ2h0aW5nUG9zdFNldHVwKClcclxuICB1c2VDb21tZW50Q29udGV4dEludGVncmF0aW9uKClcclxuICBzZXR1cERlYnVnTW9kZSgpXHJcbn1cclxuIl0sImZpbGUiOiJEOi9zcGVja2xlLXNlcnZlci9wYWNrYWdlcy9mcm9udGVuZC0yL2xpYi92aWV3ZXIvY29tcG9zYWJsZXMvc2V0dXAvcG9zdFNldHVwLnRzIn0= |