From 4b6166dc4f66730809c65a5ecdd810a110de9054 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Thu, 20 Mar 2025 08:30:11 +1100 Subject: [PATCH] fix no profile errors (#5877) * fix no profile errors * add test and tweak a couple things * quick fix * fix animation * add another test * Use actor.getSnapshot in the debug function So we don't have to rebuild that listener every time that the state changes. * try fix tests --------- Co-authored-by: Frank Noirot --- e2e/playwright/fixtures/editorFixture.ts | 10 ++- e2e/playwright/sketch-tests.spec.ts | 90 ++++++++++++++++++++++ e2e/playwright/testing-selections.spec.ts | 1 + src/clientSideScene/sceneEntities.ts | 5 +- src/components/ModelingMachineProvider.tsx | 63 +++++++++++++-- src/lang/queryAst.ts | 17 +++- src/lang/std/artifactGraph.ts | 3 + src/lang/std/sketch.ts | 2 +- src/machines/modelingMachine.ts | 35 +++++---- 9 files changed, 195 insertions(+), 31 deletions(-) diff --git a/e2e/playwright/fixtures/editorFixture.ts b/e2e/playwright/fixtures/editorFixture.ts index 41e3a679b..f4719f0a4 100644 --- a/e2e/playwright/fixtures/editorFixture.ts +++ b/e2e/playwright/fixtures/editorFixture.ts @@ -152,9 +152,15 @@ export class EditorFixture { } replaceCode = async (findCode: string, replaceCode: string) => { const lines = await this.page.locator('.cm-line').all() + let code = (await Promise.all(lines.map((c) => c.textContent()))).join('\n') - if (!lines) return - code = code.replace(findCode, replaceCode) + if (!findCode) { + // nuke everything + code = replaceCode + } else { + if (!lines) return + code = code.replace(findCode, replaceCode) + } await this.codeContent.fill(code) } checkIfPaneIsOpen() { diff --git a/e2e/playwright/sketch-tests.spec.ts b/e2e/playwright/sketch-tests.spec.ts index 884b5a6eb..4d8b41594 100644 --- a/e2e/playwright/sketch-tests.spec.ts +++ b/e2e/playwright/sketch-tests.spec.ts @@ -1662,6 +1662,96 @@ profile003 = startProfileAt([206.63, -56.73], sketch001) }) } ) + test('can enter sketch mode for sketch with no profiles', async ({ + scene, + toolbar, + editor, + cmdBar, + page, + homePage, + }) => { + await page.addInitScript(async () => { + localStorage.setItem( + 'persistCode', + `sketch001 = startSketchOn('XY') +` + ) + }) + await page.setBodyDimensions({ width: 1000, height: 500 }) + await homePage.goToModelingScene() + await scene.connectionEstablished() + await scene.settled(cmdBar) + await expect( + page.getByRole('button', { name: 'Start Sketch' }) + ).not.toBeDisabled() + + // open feature tree and double click the first sketch + await (await toolbar.getFeatureTreeOperation('Sketch', 0)).dblclick() + await page.waitForTimeout(600) + + // click in the scene twice to add a segment + const [startProfile1] = scene.makeMouseHelpers(658, 140) + const [segment1Clk] = scene.makeMouseHelpers(701, 200) + + // wait for line to be aria pressed + await expect + .poll(async () => toolbar.lineBtn.getAttribute('aria-pressed')) + .toBe('true') + + await startProfile1() + await editor.expectEditor.toContain(`profile001 = startProfileAt`) + await segment1Clk() + await editor.expectEditor.toContain(`|> line(end`) + }) + test('can delete all profiles in sketch mode and user can still equip a tool and draw something', async ({ + scene, + toolbar, + editor, + page, + homePage, + }) => { + await page.setBodyDimensions({ width: 1000, height: 500 }) + await homePage.goToModelingScene() + await scene.connectionEstablished() + await expect( + page.getByRole('button', { name: 'Start Sketch' }) + ).not.toBeDisabled() + + const [selectXZPlane] = scene.makeMouseHelpers(650, 150) + + await toolbar.startSketchPlaneSelection() + await selectXZPlane() + // timeout wait for engine animation is unavoidable + await page.waitForTimeout(600) + await editor.expectEditor.toContain(`sketch001 = startSketchOn('XZ')`) + + const [startProfile1] = scene.makeMouseHelpers(568, 70) + const [segment1Clk] = scene.makeMouseHelpers(701, 78) + const [segment2Clk] = scene.makeMouseHelpers(745, 189) + + await test.step('add two segments', async () => { + await startProfile1() + await editor.expectEditor.toContain( + `profile001 = startProfileAt([4.61, 12.21], sketch001)` + ) + await segment1Clk() + await editor.expectEditor.toContain(`|> line(end`) + await segment2Clk() + await editor.expectEditor.toContain(`|> line(end = [2.98, -7.52])`) + }) + + await test.step('delete all profiles', async () => { + await editor.replaceCode('', "sketch001 = startSketchOn('XZ')\n") + await page.waitForTimeout(600) // wait for deferred execution + }) + + await test.step('equip circle and draw it', async () => { + await toolbar.circleBtn.click() + await page.mouse.click(700, 200) + await page.mouse.click(750, 200) + await editor.expectEditor.toContain('circle(sketch001, center = [') + }) + }) test('Can add multiple profiles to a sketch (all tool types)', async ({ scene, toolbar, diff --git a/e2e/playwright/testing-selections.spec.ts b/e2e/playwright/testing-selections.spec.ts index 3a55091e5..6519071e7 100644 --- a/e2e/playwright/testing-selections.spec.ts +++ b/e2e/playwright/testing-selections.spec.ts @@ -353,6 +353,7 @@ profile003 = startProfileAt([40.16, -120.48], sketch006) await page.setBodyDimensions({ width: 1000, height: 500 }) await homePage.goToModelingScene() + await scene.connectionEstablished() await scene.settled(cmdBar) const camPosition1 = async () => { diff --git a/src/clientSideScene/sceneEntities.ts b/src/clientSideScene/sceneEntities.ts index 0ff4636bb..ec68f01e0 100644 --- a/src/clientSideScene/sceneEntities.ts +++ b/src/clientSideScene/sceneEntities.ts @@ -580,8 +580,7 @@ export class SceneEntities { if (interaction !== 'none') return if (args.mouseEvent.which !== 1) return const { intersectionPoint } = args - if (!intersectionPoint?.twoD || !sketchDetails?.sketchEntryNodePath) - return + if (!intersectionPoint?.twoD) return const parent = getParentGroup( args?.intersects?.[0]?.object, @@ -616,7 +615,7 @@ export class SceneEntities { const inserted = insertNewStartProfileAt( kclManager.ast, - sketchDetails.sketchEntryNodePath, + sketchDetails.sketchEntryNodePath || [], sketchDetails.sketchNodePaths, sketchDetails.planeNodePath, [snappedClickPoint.x, snappedClickPoint.y], diff --git a/src/components/ModelingMachineProvider.tsx b/src/components/ModelingMachineProvider.tsx index f4e5d33c4..6fba7602e 100644 --- a/src/components/ModelingMachineProvider.tsx +++ b/src/components/ModelingMachineProvider.tsx @@ -114,10 +114,11 @@ import { useToken } from 'machines/appMachine' import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils' import { useSettings } from 'machines/appMachine' import { IndexLoaderData } from 'lib/types' -import { OutputFormat3d } from '@rust/kcl-lib/bindings/ModelingCmd' +import { OutputFormat3d, Point3d } from '@rust/kcl-lib/bindings/ModelingCmd' import { EXPORT_TOAST_MESSAGES, MAKE_TOAST_MESSAGES } from 'lib/constants' import { exportMake } from 'lib/exportMake' import { exportSave } from 'lib/exportSave' +import { Plane } from '@rust/kcl-lib/bindings/Plane' export const ModelingMachineContext = createContext( {} as { @@ -573,8 +574,9 @@ export const ModelingMachineProvider = ({ kclManager.ast, selectionRanges.graphSelections[0] ) - ) + ) { return false + } return !!isCursorInSketchCommandRange( engineCommandManager.artifactGraph, selectionRanges @@ -602,7 +604,6 @@ export const ModelingMachineProvider = ({ } let fileName = file?.name?.replace('.kcl', `.${input.type}`) || '' - console.log('fileName', fileName) // Ensure the file has an extension. if (!fileName.includes('.')) { fileName += `.${input.type}` @@ -852,6 +853,7 @@ export const ModelingMachineProvider = ({ ? artifact?.pathId : plane?.pathIds[0] let sketch: KclValue | null = null + let planeVar: Plane | null = null for (const variable of Object.values( kclManager.execState.variables )) { @@ -875,13 +877,43 @@ export const ModelingMachineProvider = ({ } break } + if ( + variable?.type === 'Plane' && + plane.id === variable.value.id + ) { + planeVar = variable.value + } } - if (!sketch || sketch.type !== 'Sketch') - return Promise.reject(new Error('No sketch')) - if (!sketch || sketch.type !== 'Sketch') + if (!sketch || sketch.type !== 'Sketch') { + if (artifact?.type !== 'plane') + return Promise.reject(new Error('No sketch')) + const planeCodeRef = getFaceCodeRef(artifact) + if (planeVar && planeCodeRef) { + const toTuple = (point: Point3d): [number, number, number] => [ + point.x, + point.y, + point.z, + ] + const planPath = getNodePathFromSourceRange( + kclManager.ast, + planeCodeRef.range + ) + await letEngineAnimateAndSyncCamAfter( + engineCommandManager, + artifact.id + ) + return { + sketchEntryNodePath: [], + planeNodePath: planPath, + sketchNodePaths: [], + zAxis: toTuple(planeVar.zAxis), + yAxis: toTuple(planeVar.yAxis), + origin: toTuple(planeVar.origin), + } + } return Promise.reject(new Error('No sketch')) + } const info = await getSketchOrientationDetails(sketch.value) - await letEngineAnimateAndSyncCamAfter( engineCommandManager, info?.sketchDetails?.faceId || '' @@ -1576,7 +1608,7 @@ export const ModelingMachineProvider = ({ 'setup-client-side-sketch-segments': fromPromise( async ({ input: { sketchDetails, selectionRanges } }) => { if (!sketchDetails) return - if (!sketchDetails.sketchEntryNodePath.length) return + if (!sketchDetails.sketchEntryNodePath?.length) return if (Object.keys(sceneEntitiesManager.activeSegments).length > 0) { sceneEntitiesManager.tearDownSketch({ removeAxis: false }) } @@ -1617,6 +1649,9 @@ export const ModelingMachineProvider = ({ updatedPlaneNodePath: sketchDetails.planeNodePath, expressionIndexToDelete: -1, } as const + if (!sketchDetails?.sketchEntryNodePath?.length) { + return existingSketchInfoNoOp + } if ( !sketchDetails.sketchNodePaths.length && sketchDetails.planeNodePath.length @@ -1727,6 +1762,18 @@ export const ModelingMachineProvider = ({ } ) + // Add debug function to window object + useEffect(() => { + // @ts-ignore - we're intentionally adding this to window + window.getModelingState = () => { + const modelingState = modelingActor.getSnapshot() + return { + modelingState, + id: modelingState._nodes[modelingState._nodes.length - 1].id, + } + } + }, [modelingActor]) + useSetupEngineManager( streamRef, modelingSend, diff --git a/src/lang/queryAst.ts b/src/lang/queryAst.ts index f5cf85011..67c2ccc5f 100644 --- a/src/lang/queryAst.ts +++ b/src/lang/queryAst.ts @@ -61,6 +61,7 @@ export function getNodeFromPath( path: PathToNode, stopAt?: SyntaxType | SyntaxType[], returnEarly = false, + suppressNoise = false, replacement?: any ): | { @@ -105,9 +106,11 @@ export function getNodeFromPath( .filter((a) => a) .join(' > ')}` ) - console.error(tree) - console.error(sourceCode) - console.error(error.stack) + if (!suppressNoise) { + console.error(tree) + console.error(sourceCode) + console.error(error.stack) + } return error } parent = currentNode @@ -967,3 +970,11 @@ export function getSettingsAnnotation( return settings } + +function pathToNodeKeys(pathToNode: PathToNode): (string | number)[] { + return pathToNode.map(([key]) => key) +} + +export function stringifyPathToNode(pathToNode: PathToNode): string { + return JSON.stringify(pathToNodeKeys(pathToNode)) +} diff --git a/src/lang/std/artifactGraph.ts b/src/lang/std/artifactGraph.ts index f3d4dd307..b13b2c81c 100644 --- a/src/lang/std/artifactGraph.ts +++ b/src/lang/std/artifactGraph.ts @@ -748,6 +748,9 @@ export function getPathsFromPlaneArtifact( ) } } + if (nodePaths.length === 0) { + return [] + } return onlyConsecutivePaths(nodePaths, nodePaths[0], ast) } diff --git a/src/lang/std/sketch.ts b/src/lang/std/sketch.ts index 61dd2e105..0ab4671c7 100644 --- a/src/lang/std/sketch.ts +++ b/src/lang/std/sketch.ts @@ -3541,7 +3541,7 @@ function addTagKw(): addTagFn { // If we changed the node, we must replace the old node with the new node in the AST. const mustReplaceNode = primaryCallExp.type !== callExpr.node.type if (mustReplaceNode) { - getNodeFromPath(_node, pathToNode, ['CallExpression'], false, { + getNodeFromPath(_node, pathToNode, ['CallExpression'], false, false, { ...primaryCallExp, start: callExpr.node.start, end: callExpr.node.end, diff --git a/src/machines/modelingMachine.ts b/src/machines/modelingMachine.ts index 74eec2223..94ad569f1 100644 --- a/src/machines/modelingMachine.ts +++ b/src/machines/modelingMachine.ts @@ -17,7 +17,7 @@ import { } from 'lib/selections' import { assign, fromPromise, setup } from 'xstate' import { SidebarType } from 'components/ModelingSidebar/ModelingPanes' -import { isNodeSafeToReplacePath } from 'lang/queryAst' +import { isNodeSafeToReplacePath, stringifyPathToNode } from 'lang/queryAst' import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils' import { kclManager, @@ -776,6 +776,7 @@ export const modelingMachine = setup({ sceneEntitiesManager.tearDownSketch({ removeAxis: false }) } sceneInfra.resetMouseListeners() + if (!sketchDetails?.sketchEntryNodePath) return await sceneEntitiesManager.setupSketch({ sketchEntryNodePath: sketchDetails?.sketchEntryNodePath || [], sketchNodePaths: sketchDetails.sketchNodePaths, @@ -945,8 +946,7 @@ export const modelingMachine = setup({ if (!args) return if (args.mouseEvent.which !== 1) return const { intersectionPoint } = args - if (!intersectionPoint?.twoD || !sketchDetails?.sketchEntryNodePath) - return + if (!intersectionPoint?.twoD) return const twoD = args.intersectionPoint?.twoD if (twoD) { sceneInfra.modelingSend({ @@ -980,8 +980,7 @@ export const modelingMachine = setup({ if (!args) return if (args.mouseEvent.which !== 1) return const { intersectionPoint } = args - if (!intersectionPoint?.twoD || !sketchDetails?.sketchEntryNodePath) - return + if (!intersectionPoint?.twoD) return const twoD = args.intersectionPoint?.twoD if (twoD) { sceneInfra.modelingSend({ @@ -1034,8 +1033,7 @@ export const modelingMachine = setup({ if (!args) return if (args.mouseEvent.which !== 1) return const { intersectionPoint } = args - if (!intersectionPoint?.twoD || !sketchDetails?.sketchEntryNodePath) - return + if (!intersectionPoint?.twoD) return const twoD = args.intersectionPoint?.twoD if (twoD) { sceneInfra.modelingSend({ @@ -1095,8 +1093,8 @@ export const modelingMachine = setup({ ].find( (artifact) => artifact.type === 'plane' && - JSON.stringify(artifact.codeRef.pathToNode) === - JSON.stringify(sketchDetails.planeNodePath) + stringifyPathToNode(artifact.codeRef.pathToNode) === + stringifyPathToNode(sketchDetails.planeNodePath) ) if (planeArtifact?.type !== 'plane') return {} const newPaths = getPathsFromPlaneArtifact( @@ -1108,7 +1106,7 @@ export const modelingMachine = setup({ sketchDetails: { ...sketchDetails, sketchNodePaths: newPaths, - sketchEntryNodePath: newPaths[0], + sketchEntryNodePath: newPaths[0] || [], }, selectionRanges: { otherSelections: [], @@ -1297,6 +1295,9 @@ export const modelingMachine = setup({ 'Submit to Text-to-CAD API': () => {}, 'Set sketchDetails': () => {}, 'sketch exit execute': () => {}, + 'debug-action': (data) => { + console.log('re-eval debug-action', data) + }, }, // end actions actors: { @@ -2515,7 +2516,7 @@ export const modelingMachine = setup({ }, // end actors }).createMachine({ - /** @xstate-layout N4IgpgJg5mDOIC5QFkD2EwBsCWA7KAxAMICGuAxlgNoAMAuoqAA6qzYAu2qujIAHogC0ANhoBWAHQAOAMwB2KQEY5AFgCcGqWqkAaEAE9Ew0RLEqa64TIBMKmTUXCAvk71oMOfAQDKYdgAJYLDByTm5aBiQQFjYwniiBBEFFGjUVUxoZKTEZMSkLRTVrPUMEDQk5a1FctTFFFRVrWxc3dCw8Ql8AgFtUAFcgwPYSdjAI3hiOLnjQROTFRWtpdQc1Rbk5NWE5EsQZbYkVOqyaOXEz60UxFpB3dq8u-3JuUb52cajJuN45lK2JBz2bZqLIKay6AxGFSKCSOS7WOrGFRSLQ3O6eTp+fy+KDdMC4AIAeQAbmAAE6YEj6WAfZisKbcH5CBZ5CS1ORiDZiNRyYQqDa7BB1JaZYRiUSVay5MVotoY4j40Zkp4kPFkkj+biBYKhaa06L074JZnKKQSezrdQ1FTCCGlfI0CTCaw0JQaHKKKSyjwdCTYCCYMAEACiBPJgQA1n5yAALfVfaZMpIImFW4QpT22IpiQWVNQVKQKQsKPmLa6uW5y33+wMhsPK2BR9ixqiKSJ02KJ43J2wFqpSS48lFi4qQhDGGFiKcLPmc7Rrb33KB+gNB4NvMl9DDxw1d2ZCblm52pNa2YQ8tSC6y8pYyT287Y5ZwV9HV1cEABKYGJqEwpJ3naMt2gjivmDRXCedjSpeY7KFO5obGeORNEoz6tD6+ArrW3gAO5gGATAAQyMz8AeaTSDy4hXFsNqFleYgIoc5hpIs9j5NYi4YlhQYADKoAAZu89ATLuQH7kkeTpIhmS2LyKTZFe8Kwp6YrcoUMhZConFvthMZYJgRFGuJIEorCNAOMYGmXKIihXgsjqqNYQ6OA0Z7aZhNZBgAYtgmCBkJ7YGoBJFzHkcjSDIRz7CiqEqFe5jpFYFhnFI5hORY7nLp5xAxqq-HkoZe6kUkNlOuZVzIg4Ui2nFY5VJFbLaMitRiOZYpoZWGFZe+64sGSAUicFSYgZUEgoVsLoDq1jSClc8GnLalnCpyHWvh577ICQUaFWJxUjTI5q2os56pc6IKzQ0B1mCmGwghpq1VuttYACLBKM2qBrq4TCZ8okhUI2SOhoRTXvUA42IK9jmKYU53RcRwPV13EEAAKmAbyCOwqCCEQACCz07f9EmqAW2iKDIaR2DNsGRY6WjZnk4oNNCmXI4S-H8UEARMJSuBjD9HbEcN6bpIDVxiosKTiLNGhLPOCz2JsGxyDIrPZQAEu0fCE8NeRmnYhY0LYU7iLkV4ovmmRqDQlmejyWkvo93W1gACmSqDdEw7CY9jkAcDrwHOukaQU9e4IclUtl1fYkgggixuFK5quO0j2W40wTBgCQ6oUPzgUJrtczOpIpv8jyZzHDmY53loFSVOTCxrJTaurhIMb+mALu83ABC4-12D8SQoT+FA6pMDG-gsEwfSUqMEAB8ZoiSHy+SqGcyJh7NNvpNFCj1E+iwO+hS7cRIsAxqgOFd2QPd95wg-D6PJDj-4YCe5wkAL3th4VJyjQbMdC4s1LhHgsLUEG2wVaIxPt4JssZiBkEoJgWB0Y4wCyCkLbsKQGo2DOrkcykVZoLHCk+NYUEzCpTkKzFBzYYwEFev5MA2pcSKi-okSwY08hOSik0Kwo5Sj7DZEoa8qV9iS35NQuBdDngYFfhADg-gIB9DJB0SMqC2GIEbgdM4hRUr5FqKkfhiB9GmClIWem1UmhqEkagiQNDYwAEkNpbSYUEFhBJ-Ckn7uQEgBl0EFyJgrMCFkQTYJ5PIWakV8xyE9IsbISJFA2NoXYqRTjaybSjMwvEHiL4qIAF4vF8RohACwmjSGvEcU2oNaqlEPuFLYJwbR8ltBxFOMCpEpNQWkoMRBuCwHYOqPA-hcnYAKQSXxijsD9MQXnQamDxL2SWJHOaCJkTtSvFZQ4UDMjqAqUk2MnTaHdOIH0gZJAhleM4D4zAkzpm52KQsZQsIYnnjOOmTIUdShNFSGyRo4clCuiKNAri9iYyHMce+XpuB+mDNwP4XGAAhbw-gAAaDzyYHXavsTIwoKbmzWAhZEshxBbHMuWY+IKOmguOVCmF5y4WIuRQATXRRpQ47zTggnFJkSGRtJD1H2GYPkUoYn7LBdSyFpzYX+DIFAQM6KCWiCqCrTQZYdh1Uuk6B8q9rb-zFeCmMNKpX0v8IGfA7A0H5z+kmBY2RTCpSOEcBikc7SIARPBe8DFUgKBtEfTq7TbEStrLSs5QzM5kkzrgeR5AZ7Z1ucMe5-jrVYIWhUWJnIByelODUt1HIYTkwdKcPI2aqFtMpYG1JkroWhrhSMsZww-L6BlTgKAuB0ULABBsDSC0cg5AugxNNFNWpyUKPqoNPTjUXPJFc3xmAm2+OwK29F14nR1EqGmSKRiSnihFJyhwLyRZjsrcGydcLYC4Gfv4LGqL0XpkOAOMUdgybZFdSUocTo7C8gaWkDQwLfSgoNUa6t0rz2XuvSypNQ0sGOBhE5REd5OTiFSFeV0B0tgtK0HUVI9Qj1dKrXSoZYAACOfQJlmqgBa9F0IKj3RTPHcyOaSnGGEMsVKmRUirD-ZhAD46TnAZNUwbOs7qCQfmcVYhkhjY2n2Lswos0UTpCNkoO2lwYl5Fw0c-DNb-BkjfqgUkTxT3sBpKJoy4nUgsdkOTfdBRpawV5OFOwrUpRNJiXeDTELaxfkEOjEIfRRgPJyOkX1g4EQonBFXUoXLYSFnqnUHIkVS0Uv-VS49QYZFML9gEJRKj8BqNoQq7Rqw9GpFakUQUhtYRNHqMrdMdsPOGq09KnCHAJ4XrxBATxvi+izN+lBhZh8mKuiuG6Cm6qBHKEs9CJoRxPScga8c2MsqmFY1-MUqolwKi2CfcoIoEMxypSWDZGuRsKbW0SWWlLtjcY4XOQEOthSbnyLuZQfweB+KoAIBAbgYA-S4B-FGCQMBvYPfGZgQQ73UDrauEdkc05uRFEY1KcUY0zhApdOCVK+qbt3eGagfJj340zLe7gD7BByTuzJBIHmIwPtkm6EDvwghQcNoh6TqHpmiqJEuDkc0VlxS8gYoKjZnpDhhUyFkKwKJse3YUZc7A1yie5xJ2T77fM-sA9+8DwQ8vrls4+9Dkw0pVIKDc7URSLoxp3WnMYTYIIZe491xM57CbXuQ-J2SSn1PZ504Z9rp34PIeG5hEbG0FhuQZvG26009r5DiEaIUOaDuFGMtRSrz7avft4E14z72JAABGsBBB8H1xzq1-XirWWDvkSh2xchVGEPis0U5siJ2MKsv1a1lwAZxynpFaf3cU-x972n+O-dM4L0XkvQfOeF2j2KVdYdztgJtObAdGxHzpiyPILj3eOm94CKnpl6evs-Y16gQH2vJ+CH0KXw36Q-7HatJcGQvLMhsmUKbdMxglDJ8P-34-QfT3YfGndgX3XPQQa-W-GfcvMTbnRwSTX1B9SxFEV-auKWe9DfBiVKYGP-GVfAQME-TPc-S-CfAgsAO-WfImaySQOoTQG2TYLQV9LMA6SKaqAoLQdQclf1ctZJA-fAuVJhIAr3UA8Aq-cgyg2AszeA4wNkKxFWMwVDBSDVXnD0OvcEaEMwbHDOOdU1fECjCeZ4fjPAdgU-dXbPC-X7XGbwFGQQIwgjXAQQcjSjKgpMayTFXFcBaELgq8Z0VMJQRoK2BLIobQnmJtZwwwozD3EQn3MfCQaw2w+wmtJw-QlwqQrnefHeQoF0XIBTOTOqOcAEfIbkBEVIcwZOZLbjffWXbmckSNaNWNZUF3Ynd3Ygiw0g72cNeohXRowQZo3OSQuZaQ6PDtZQGJM4CwDbc6OqOSUmUCKwBDBEPAro-EBoykJoqZV3IQ9naIkA2I+nCAlYqNHo9YvozYmZQYvrOAkY-NABCYxoPBK8NzOY88BYmHbgrvA1CQHiPAFbVAX8AgJbfAP4tbVw7sP5ByW0XI2wU4WwLeIoJ0CmY6VyZQfVH4vmK9f4zACQBxXADgXuCATraZfqSeVAEw4pVqGwLZb-EWU6RvWCDAtIM4RyOwBwdQNE34zE38HEvE0w0gXOPxdIufBABEPkc0cwVQIXKxCwLefkOQ7w6EPkWmCongq7ZJdEkE7E3AMfXxYgTAVgVxKRYpLgyQfkMosUV0UGSLTRa8cKDkOwe8aqC8TvJ2L4jUrk7EnyPE8+Sed2fiXyIMNo-7Sws+PwPoJgOwnARUQQNgDAGMqRGMsAdxYzOQY0p1KrcxcUewTSYBVkK4B8RuG0WwL0S7Ko2xd01bT0vAKZCeJgP0gM3YqnUQuIrmcMyM7AaM2MigxsVBRM5M2AVMsE8SIs00z0NZJ0wsa0kpayKrecPhIs+3UsvfWxXE-E4pa2TFZEREG0TkDYRjYhGESoRmRyBaV0fVVc0w1sIUomEEFjR5R8U4DSPIT5G0ldc8FIZ0eEJYpcr4lGZbAkbACZbOcgTEwE3KYEj0404sqrGrKEswQhWCBiFjMbY2XBJQLHH8gDP84EgCoCskECrGHk-EqFTgXAHrV+PgTY1ROsgSAMik8yfWT0btLgpQWaNSc0KiVKFaEEAcfVbCmAXCm5YCzEiQbU+nXUogfUwYHsgrIc4qZzfMRYWoM8ElMUWaPc6QO3CwI6ddXfX8-8zgPCgi1ACQL0ms302i2sIMnPVsiM8gKMgkGMjueM3stxbJYzYQY0uoM0WmHRSWLILdRwQsAEMY5THclmTCjpfixUQCoS-CkSsyn0mi-02sIfJs-YhnWy9szs5ymS2MPs9y2ATyuS9hWQWgwXGwJE20GCWpc8RTF0FeKwbQJofVPoKNVAIYbOdgUFQkXAMwrPYMwHBIwQNq77GM4YfqHqttEqzRcGWEOqvkabNTF8kpKqNkZay4T9WLfVL8UIWVQgyssC5bSCmahAcwAdGcdMZHFIFzK8H9K3SadHdMEsyo5c5JXahNQQj0+Imo1RIIIwzrZ4MkPmMkAgRKieXTPa8g405qxqZEfYEcFEFau8eQaQKzFKCaBvHakIT6g6rEn6u7VRfHRdPAQEnAcgCMEnQISgPmGGkEAEPlM8ZjNfR0CU+ocyZyG0bGqGr6ys0y6s8+SAfwD6-awMs-do37LK+yjsxyrsly2hAqxUEza8pMRoJQIolWLgsEHkXlc8AEZERONSK2PSgDEW8g76kgQk1RCAdUQSHTHG0W-qkgyWpnNsm2kgQSQQSG3G3rQWYYs6+607GOQ7BYRjKGZC6ycmFiEOJLVUss96h282vmy2+RPLd2u272x2tKkfMAls12iM9O72TO6G061kmEaKaEV0eCyoO604LVJya2HIDczIfVIgRUcMM23mrEo6iCys40wEOQwoNIfIBoBQFDTkaQbDSSOJeLVu9u5UTuvG7kg-VRIGkGsGgWww+e+2nm+VU6ykx0Q8eocwR8FalCA6B1FicEDjcQOe+sYWxOru5e36vLYmqAUm3GQkp4be4ur6t+vAei+oaQZ0XI8wQoPkFDWufM7kJzFaF0pGADNu++xezU-m70vSTrJBpUB+3esW8wwal29gNs6WnKuMvKmMRWgkWAawKCmJD-fkJ0miKcDZQRe4wcRoWGeBgNZJLBjux+pe7ElOxRW2gIGm7B3+qy8Wgh0M72N2kRuw+er2-h32jBf21qIBs07taqTYCJOqT0M0WE9DT-MYu+7BlBi2r+wu7+++iRoMbO5sg4rmEagu+RsR8kJR3BqC+mmoBpXIpeOyJ5cUFeazBjXkfVeyrOM9WeIMB5DbcpBoK2aEM7GqzRMBQ4WweEJQOSF6uOt6g5KFeXPLa9drIW4kbrPBganPEgfpENWFAAOVVEgAADVynocpRzQnINIigHAGLIY5onQasywmg81Y7PjEHuBCmoBMT-ASnOsynMAetGyc7wDqn2Ban6UGmOsWmFmVGAk3CMUYsyi0hjAGJkazE01zqGIihVBUTIrrsajDNjC4VdNegDMkjYVjMnaJaJAxr3n6UlHXmKC-nyTTqvyBnhnKh5BmJ1K70mKzANBxZ3y8DgXa1ib61Z19AvnpHfnT1mc0XHs51od1BpARsLBwZsV9zznFgQFthsMGlkXT1PFp0FcMWsWc8cWnmddmXrlCXQX8zTB7Jh6a4mhIlchlgTwmhdyxQVSxnqjccUW8cCcwddCF1W02WQyOWHC8WlWG051ICW1pqVbuxNqHJIp5AbqxEx7YIGhJB9gKlxABwn0PjXSe8HmFWA8VWDX1XAdNXkiPXb9VXDWhiMiRTqWtV7AyiXQwoo9t1oY95aJwRHl1M7m+C3XGXQMmBpmUVvXftfXYUYyL0IysZi8iWzRsgnUtBcFytYIeRJxzq1k8wbAcnZX7n5X03C3pmmUc2fnsYUWC3n4fYb9oczAnRrYXkmhaZmCbYlhVAgj4tuQNIGWnnX4SMyNUi6FrKNXe3cXiNSNwcIiiXHQBVuR3yFAbB9yRxTBbQVYKpNgcMU2Dl+CFXBN1Q-IsBu283-mX3hNBTg3hSedwoyxnQlZOQER5MSZVIVgGgyEtCH2wUiBwKYB-AUYsS3tOYCBilQR8xqpSxrZHWIHYJSimJJcPlERm2XWOkEPjqUPfw0PYAMO2w-2iYsPgHcPLTfVIlXRiP2CEMgrW7EOmEaObkB56OqBrAjXxIWOcPoQ8Ozx9yEbuPqgrg+O4OJAqOIKhO6OMOZAJPiopOElZOOPrXexLoePlPbR+PqPUOROMOVBdPEh9O2P8P9yN5FPSOVPXqvj1OkPNObOqAxB7O9hCxsODP2OCPalFC3PeOapLONPrP0OqBhBAuEBHOZOwv9yf5TOlOyOuHeD8mBPkP4vRO5BkvQQ7yVga4nTuRZoxQzRbUHAEdKZWlPPEGCvfOEupBSvCxyuNz9Hzxqv7NGhlIR6HBbS+FW7sB8KBGe6kO+7S6B6ihMw-CC00CBEnxzR2Rcgpx0xEcJupvUGV7X6VF36+rP7AbJuInNRjuAH962pTBagtaqhoRIYf5OnFpAYGhsg9vLu+bDupmPxLbsABgN70GngLu97kvh1bxJRMNeQoJIZDtzRsg1Itgsm+RvuBG0GayhaiBweKnnaZHiGHLvY5byHKHjMVBaH6kbAGlyolYEexWFDtBNh3VVATbKO8eLHU6pmrHyA8fu2nG5GPbvY+f9v6KrANvNCGN+Q7BIYUoKhThUhCwzSecMfUGU7raRGwf9ulmHHMr86+jXG8e0zUaa97IbZ9EpyxFgs-C9ZahXj2fbFvPBP8bYAeYOBSKpnyHJ5sBM4Bf3eSeEymBfeKCB5BA+ZIBP5Tq7ZD6oEVgysVYt1nQzRJX5ABxMgcDRmKOne2vXeA-Pf8tYwfe-f7GMqz4A-5b8rg-M4Id+Jw-8IMB55o-IpaCWoEQkSnxBRuRAOTYjgwso6LsWvKPc-uTbLC+J46cPSBewy7LienKyGEy3Klav5Shdl7VwQNAtut8YJuc1MMhAZxi9E7BYufPXeZ-x--BJ-DrS-R9HGZ-srZbcrF+kzCqV-EA1+uF6Yt+o69Bd+rh9-h0poZEMf1U6499uV6GMLpiYQsATCU-IErNyxL90jg61R8LLHMT0lV+jQRKEbCSgcMh0avCAVANJKwDfuL9KZv6TJD9JiBBIAkp1goFUCYBBIGGuIHX4xInI9pbMIKH-hSR48dJdQLlzVL5NOeFqIgYwICCkDCaeWf6twE6xiDaB2oAGtQIGhXF-aRKZCsUSyAQQGkXAzZMUWFQY1UQoA4QZAPwhKCuemvYXtrx+4mDoBZJGgZu0ByC8XGwvOwnj0xg2DBAYgmGneAohaBHItgKFlwISaIlyYIDABC3SMHgCRBpgsQd9T+4QDJusguwaYXBpWCDqNgpQcaSYJlQkM4gSyBoC4HihaCFMK0E+SNgEDohtgkgfjXBpC1Re1g0QckOn5ENZ+MtEnk-1cov8laYgKnh+m3gG1xAlwQobaABBhDpQtMZ1gg33zxVDq8AzUv3WCqqBagk5dSNsC77gM+cdQRoGdmRzY4Zh+NeIcSW5hNCzunVEkl4NLr0wKgNESbKEnTBcDmeAzDkIrAHA-o9hxlZ+pIPIH440hTCNxqDWloU0qasAGmrs2TTDlKYAIeLPgjSAIgY2uKX5MpSogedcmXxPuB8OxJncLBdtYCs0OcaG8XBwFGGrzjsC2hKScPG2F30uD5p+QXaFzBoHeFxCyBr8KNLjHIIg9zKRI0uheDZAMRtuckGuF300jsoBc2jbIKKlU7ojvq4NVRLiIcGEMiebQ+ft2Wf79kpAxpSKDCEarAwzAXCIUXegsjKANI8kGVtnz4IzCMhsQ2YQVzm7JcJSrNGwLyF8q2p4R4We1AbWOh5Cs+Uw67BaMaHVDPhUwKQRNWOEmF5BRwzIdyIl6LRoQKsWQPDzHBzhtEbA-IBTCfICD46j7P0TEOSFMivhl-H4fUMIL-CyaCuSmkMhBH4gwRFedhDyEkylZzw14VqLqK754d70sWSqjkFUCMjKhZg37lbTTpa9hKvYuQfKJkb4jC6kBfCu4KgGeDkhMNS3JtQRa7YVYgoJVOFCsxKAUasgQsD2MtG5iJBQYqZhakSFKCORPpLkXaMhEOhgQBQc6muLhCHA+uzoJKOCD3H+iPEfNGUXljlFSMbK9-Eho-wX6dD+yagDUY4DGgJR9066VQA+JtCmB8EIqZQNeDFQzMOqD8IML4E+jZYwAg8GeNzG7jFJkgtQGGNv2aSnMkcshZVFtynDwgoErMMgNgG6AjBVE16GnHzG7aMTmJowQdhhKyEsY1g2GO3DJz7R1QDgDmc1u3w-IZjlwXEliUUw6rsS7GwBdKrfwZxySeJxbPidH0YhPcNgqY14fyAwF7AeQiJFEs1TYF6UNJrEjqujCopSCpEnEvEtxIoLFtyG-Ej-KVgBSIstga450PrSogY5sCt9H8tZIUkUV7JXvRyTf1zoHENJrk7GO5NBYWAGafwE5nkCuoVZiWzMJmqbGyDNdUR6cMIqonRgDItw+Pb5qVM3AYBcY-SdwP3TGg2wPy+weQHDCeJANZIynGwBZFg6ecipc6EqRuHKm68y+VU8qbVPYD1T5ujU95FYCsA6NdGXyLtFCKYrhYepMk+IjoX0BE0OYXMSeN3G7YCROYfga+HzAmlTTSuscazJLhtDnZjJb6M4KYALKrJN0elfqdtNfq7SsQSkkaWpIkBHSuYp0sAOdPQCYcWMkkNYK1ENjaAUQKGFIIdDjzStJWKsVmO9NUR6QcAfAbthjOwB8AQZTfSHkDBsAph8pRKIYXVG64dMqg4eT8vIFNFIw0ZeWHGVjJingFmZ+M+imyGJneUGIZMs+tFnWBOQGqE7FGT+UZle88IBEAXpLKYAczS6tBW6RTCurHBKRGqemjVkFwxIiUaQVGVtL+oyzfpsUzKjLLll2iWMICVCIMJiRKZ6IWQQ4HeFLBgMsB9Mk+OLNNQCRTCY4-UoJFNlMckw3IMaMn1pHbcEsdkR6WSw0AKBhsSeMWXrLyzezTCrMuIgnN9kqCQ2C+O6LsknKST7p1WeqkcHrgDCZQsc4qVIIxmYABe5c1OX7RDYo4YoZCSunh05AoYRhKQNKPXFkBVBdZpcr3uXMNngFBafkauao3Tlai7Wa8FEIn0WABMlgT4S0iLHb7ejXZcc8gb5H8jdsUq-kYeXs27AT0NA4eJWKxAKAbJUoUIxXsTIVjbBu5A0vLJvL8D9y4id89gNvPBHyUjwIDSKNCHqDXg1KGqewFbhrinhjg1iEuTfKmZLZug+UUGmOIgVQKX5NYoLmyFq6LVpJe2Xwh2g2yME-gE0a+R9PAW5RIF5IB+QcVgXkh4F1xFLvmHmmztAYp0J1L4RHbwgJWyEDYLgtURuwPYXsQdllgF59B883QDgJ4PdjvwfM8iZQTXOFJisPkVgRwOmCbq9pFI1UAsBvDWAShUMbCvLBwpEXFseFScxxnwoEWdFhFXCrLJh0kBnB8E3kqBLyA2RlJumZrDQjhyXlcQ3ZDCPwK4h1BxAP2b0MAFhJxrTByF-tcuhzScgWlEMXYlJil3MiH1Ueq8LQEFTekrz-Abi96EEGwnTBiFDODwO4r8VfRcAgSkNsEsMRbBmxFcVqbrUdAWYUQpweJYtA0VTNn4mcITLnE4kZws4OcSgAUuFKCADo4DH1NUBxTVQ8gfTFWJ2gRrJ8woV80BXgplRtLmllATJRIEaXtKZkXSomD0thBbB+l7GPxsMurhShZ5UCdvC+gczvicxAYzEcyJPFkgkhYYySgaXH4w1eQWqDKYUCfD3SrAI7cYiCFrZDMzlVQz8TUM3oWUUqFU6RlLTn6k9VRhVFIF40A44CHUSNBYGuJsDl1RAfgpStkGTgVhtSGAeAFEC7x+zgI2Q4GMMzBgHLBQggOhmsBShI0LS4IF2VxE8hErF4E9VIF03T4cY9l9oa2AWDmiggEo3Yn8p5DbgdwgZ+KiRestECWw7ozVDmg6yISFBNKQKJ0omwpgtxAwZ8C+FfG7gSqR53S+vKTDSAZ9FYBQ2CHyjGhKAFKzJbanBxZXFQVUvI9gRBEFRHA2K6-MhELJgaZgFsq4e1YkDLCThHA57deEhXukKxD6C7e6HXkZWCCwU-BFnM7nOLK5Ic-qzRC8lXTNUkmoMGNgcrNBOjyiFwJghtNdaO5uWSal7NsQ+xpqSkKsR0GnxfT28RUzBFSExBQiVJ905HH0am1xyp4UU6eGtcoGowWh7YYIZKLnO0aaVtZYCMkSWrlZ95mUA6tOcKSHUOR+QtpGbPUDWHVxyoH6BGjbHPbig8CotJdZKptSqAL6RKGKGORsUapkBtgN5dVGmzDpQiuhCIo8wcLsBB1cYp0JutYihIEKXyTkAdEuDyq3MqGOda2wURHE1icafom7nZzfqWBDXXIAFXUBn0YkdXVqX4U4JSgOSGJSsjWoSaAd-kWZDPoxnCS-JqqgkyoHvHw2oMLyRGlvBUB3IxJHA1sR8EQhYHdNs0n8xPs4rjXfFOSfNMSsxMwA1rEQ+YKGcjxdCPJgEGwJ8buTtwN4OQ9G6UcCuSoBkmNouNnjo1pEgh5OGjG2JSWYpbBzyvJGtabidW1tKSj6KcjOBFC7INyzPV5HxQMqxUZU+wojWaXFKK9SkBaQKlTAZqR1QYqitzThUMpxVjKRFL9cuqJg2gnkmkDjZgo0hsUDRFkYRKxHkAFSW2ySaKoJU83RbRNviCTTzgqCWQo2XYt1fZgXwb9LSiebQOUNU75bIthWhKhpvrKBgiNO3MZZ+ThGRKh1Wo8CPaQVg3hWq7VM4d1SkS9Ua18IYOL2k-waBpMW8Ourom-kDgtxOWs0QcnMaEa4tqtKUAdFdCa12Qrw3Nde1hBZBQO4WEcI7wTq4M8xR4hQTIMMzA1yQ3WtlLwhchXafUfTaGO8mGYWYTo3NH2o9oL7-0SIO84cqIBYx98Jie2DPk8Qg5JaTm7GxwCDpPVfjN6QtFBkxuCpZpNa2aUpFb2qyHBSUs4OtciAx1J18aGvQcZYNsZ47ISp2KmMfSnIb98wzpG2EiGeGmM+GD2vbWevBITt6GJYX9PQpraW47wqPAxFBBaqgDt6u2g4cyLXrvb9t4JeXmAwYLyAEsuan+TFkjnh5nUGFIfk70V3KMwdRNa7pDtfnsIZF9smbNbLHLm46o5kDcYUGViwkXQGUBXcgwt1Y70GOPc3bgyY3kQJYxWUQAXI2R1AnxI9WGLkQE2Zj4Owe0HcnUsZa9-hO9H2qHsShlYNtLUhiHZBwTKBjoT5R1uE0DBkBAg0TQdShCvZBNrMMOZQIKAMSbLtUdsbYPLtN08MJmzLcKbMy6w7MkNJcdSJkDzTqArWE2FHNJFhgs8JEkotNsuxeb6Y-hRmPVVDvEyNjlIkmnnNKvs1LCnxbJaVQCkXYL622y7RNY2kHVb6WQ7G3fStWpbIUG22jJ1E1u72PtF9DhJlt4gxbX6ESt+xseLAf0aR0gBy7YGDGM0+7398az-dpkv2etF0NuhBUxn-0w4yWLU2bBdDZR5AQYRQc7J-KXZf7-WzaRA3-qWAsgXQ8NKwAjDYpOQGaLPJeI60XLQGCaCiBVhmyzbD6QqawJiiXpkgywA5DmMfScGA6J68mMB8-V-o4PgYuDqwW1HeGtn7Yvk28X+EbAUKSlxYhB7TLuzXbmoYwZB7fZQdkDUG6gNXNlEfzyB2tQ4W27tR-skPaZv2b7cTeroWQWKEZuiLJvElfQqQlg4WY6AEVKSxqk9anEfsJ05g1rrDCE1vHNFnZmAiE-klfDgbWBPqQFLBsAT9yxJEarEXM0JRGxXGQxR6MWKUGKDvaTExDXnYQcrvzEQ7utJE4zUFlyD2QY2qGxKI6wSw4GFgFQqo09oB7yIBgRGtngWDiXiBpwr6NPhfVkh3gXQ7IPDZEIyPclahmDPHt1pHYWZXQ6FSumHRRDmL44SlPDsxi6Pck6dPPDPcsZcPFRpMppRJvdGNXI1VIEUc8FkELCKxVNoA0I9foOB8pNgGaA2uCEhhUlLSqixgqhuMAn8Xeo-fPn9SkTF8wA36--l8dO2-HX06gTnXWq9TYZFqd2-LlZ1H7n9veV-TI+ce5yDgAB2lYAalAeGzyNtm-bblHQqH7iLlWRug3yH6EApTmXA10JZlkA-K3lahekx+PEHdGC+9A0MQSDx3pAwYuolSBOC4Gk7t8q8KHl3LmPpCBTluqQSEBe1iCmNzyhrsYDjiNAdaY4B0pzrJTxjK25RxBsYNVNp7uewjSwUWJWwMmxTRJ9-rzLb3WwmoUSF3ZgPBDSA5wt0J9Fav5PnLAVgYgvtctuXOmhd0O3sA3RQUchm5RpoJleylBGwKk0q4MwCsFMLHsd53KIU6di3RmLjbptbeYCNjsbGMvqRzBtsW2HqexhJos+wk6YfpGGD3PUUaZrwrTyzZG0E5KP2Fhm-qIYpQUxrZQS5koNLCk0aeixIYzALqolPWYHO3zCxnPf4UxqG7bZAY7K+wFulagL5AiipUJF9z7MYj4iA4k45YOApMaWBAQ6qKdACGRK6ClsRpAjkQw2HuGWYk8-ENWJsjBCoe8xdoEbEOB1I8IhumLlDhrAm2WJ+Nf2arLoNZR+Fbzf8HQqyaOQR0RjLOcOU7pi4ffQfqiJ7zZiszHpLI8Sxuo1QiUcmxMQuyqwSgoWCxVI3hemEEUCzapr3kOa1MumzqTMd05VBryiTSgoHcKC+M-zgapo-yvsUKdUST8HT1jJUHjoEnYpvkoEBwF31bxo0AiCGE8Lhdy0fnCBIZ7M5iLPN2mcRBF4cxxcqQh5tdHpzMK+kPC0FqIiEfzVpe23QWmL1piS0U3bg3LTLjZ9-lLkDlrwGIumj5TOA25sbcgExIVSwalEjiDxQKuCz+IQtmXsCT0k5sYcRBTljw2HfSY+sWqTD3zbWdCUPFhMcXBA8cJ0I+mV7fI0xkMemkMu6mnNSVeVriGFOPGKTu4Na4KiAz8KkjjDUoBhWTtDgomSjXNUKc5PkmtWIp-SKE6gks3RI0g23KEhoUcBrilF3yViGzXJj1KKKZUjADWsEAOkSWxcW6LojMBI4f1nIZCHylZ1NXfQbsgGd9PaslXHUT0oLMXHFDTya2etZqKHkzTFGtrzMvawnifEKBUefhVQEjiGVW53rZMGzeUbdmwAZZgNkzmKHCTK9Z1uc9Rr8mGwwMrViSnue7MEiA2UpZMK6rOFYjKEvkcECiDro5pjFRZfUpJYPOcM+WkgCUdakyUxoAo+rrujkEgpnD3gIWG0t2U-KJtHaUgNzY0XXg2T-7ooQ63ZFYC2ukKyQgNhqM2IKBBZth6C1MABcj1KpnQW1rRVwp0ViLAbxLE9nXgp1cokc4IJYHYGvCHqoWQtpJSko8XpLdoG+uYEWQFayKm6h-MY27phiMw9EdY+i58TdnLL5lxVlm-tYXzGAOaUJN3UbD6YkS4RM4DSAESVNRWTLVouK+ZU01dakrvpuBlZnZqJnSgc05CtLt1uHaLsLgIAA */ + /** @xstate-layout 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-CCDR4EgH2Ogd6fMmVBEx1HAghs6kew-IrzgjNAOdQU5NBrOR2d3xM7sC3IxznLHOPnuCzex91733BDXLF9TwHwOsiwjDpsGDbznK2ydOhU4Gw1hbCF6o5X4vrsJtu4D3HZJ8eE7niTsniuLeq9p+rnnEprwgl2dlxA9H23qFqPkRaiwzcBHhYipFUvHsy9e3geX5OfYkAAEawEEHwGnD3geNGkCzklDgOS1Dxe22wMk3nSwj7S6Pse7cO6J+wZ3yfBBp4z1ntX9PSqJGfQ6tt2QpRmHFFD0o4IpSwjsDZCORvk5Td9Iak7wuo8Mrr-HuXqBPuK7b4IfQ2e6c2va4zswSwu2VBtBsrQ-vuWO34bIIETR+Vejn4g8ri-VHL-pXXvHqACeN+b1v9PHfPfXPAdAcP1TITIcUHNUoFWG6MwIvLQcaU3Z-A1V-FHAIaVQMVfF7dfTfCnTAsAYArvAuAPMwB1aUFILKO9YwZKKwCoSGcUGzJWcsOxefNA4XAgr-e3H-R3YnH-F3fA-AQMIgg-fTHvMwaSH1fzTKW2bYZKcfRA7Mb9M2Fg0rNg9JNOfmetQjK1LTFTPAdgJ7HAxPDfV7QmbwDGQQZ4fQ3AQQHQ61eZBncQ6EVdOBLVAcU0RiNYZYIVcuDYfYY7dOedc1fEIjSeawqrQw7-X-J3fgiQcwywiIytOw0I4jYgsmZ9JYK4YRHrWwQsLlZ9fMBoEhYUZQd0avcNSNaNWNZUK3THW3NfEwvAn2So-EaoykMkQQOonOEQxw7vAPFqAEeJC-WhXkK8caLIqcAcJoNCdQCo8kKosXGoiXG3WnevHgv-OIxXVoqNJYjoro6Za3QgzvUQpwgYrQIYg9bScCc8MY5SEhWEKYz9WYtQclXiPARbVAX8AgebfAT45bdIpMI4bQSqaJYTfkEEeCfbV5HITYe6YlN4j48DX8CQFxXADgPuCARrGZQaKeVAAw8pMwFIc0RYQFdQJnK-FIVLO8eyW0dNBYJ-Vgl-dJd4wWZEzAVE9Eww0gHOIJU4-o6-PPZQW0Ok3kUdaAihWqFlG2WBbYeQBzFAo1CQVk-4jk3AfgwJYgTAVgXJeRQk7Scg04CuAfSCcBZEWEJ1MbUTMUxEtkpbDkwKdEq+KeD2ASIKIMRo97Uwy+PwPoJgKwnARUQQNgDAYM+RYMsAfJdgWAOQcpTFJYOiW2RAhoHIcBcEUwKUDtNeE2ZQW01UiQR06ZSeJgV0909YmIvg0nH09gP0gM7AIMkMwgxsLBCMqMmMwkgrfhMwBSS4GTEfChdSQ4LYSGEEC4Z0clNEjEp5cEVMCjO9fIbQI4ajHeeoEUIoFyYdYrErBBVA9JScww1sfkkgipGktkUbRc5QaCF9AckE84VCXnPkbc-VJUjGBbAkbASZLOcgcDH4gqP49kuMjbNkTkUQIvWoMBOJPhMU9QOudcnIclV8v498z8skb8vGTkjEiFTgXAFrD+PgQ4rREswSd0-U8CLslM+ubQBQeCPZJ0ElWTB2bSJiBCt8zgFCtC1ACQdU0nTUogbUwYZs5LQE7seA8RLYVmTYNqHzeCVQSQM8YrdyaES4VQncl81ij8u5L88DAsvAIsl04i2sT0pPXmWs8gQMgkYMzuMMlsvJbxaM4QOM79WEXkXnBjI4eCDCc0fLRGPIVnFipCtizS1C7Sws50oit02saI3gpvOIky-0sy+siyxs6y5hVsuy2ABy4SiSJiFCQ4EBRjExPIDyveQ7Q9eOCBV4xUw1PoKNCDHE9gZxQkXAIw2XJoswiwwQGq57YM4YQaRqltLKgzKGWEc8G0BodYMJKExpVlUo2TfI8lL8UITg+038hbACwa3hRofMWoa8aUcCxDZSE3A3WQGaDkBwWRKq8rRahNGVfMt-bCqAbUawxrZ4MkQWMkAgUKyeNTJaoQ1rEWM4oUfYG6cbbkDQUayuGAyhfhKCQfX1KUWfJk3czpa65ar4jk+6rRH-JtPAH4nAcgCMLHQISgQWfUs4WKcCGqXeW0S2BJfwu9CGHMlCBakIG6rA+0nSp04yRrVGv6lqhPL0z7OKushsqywS2MNKxUXTI8smBjMvSCPMJofYK-ewO9PKtmSoHzA7Fm36269kiQEgLErRCAdUISfwH6tmj04wwW17XmTq-0k2kgISQQC2gg-UqoaQbkLa9STMGGRwSaEsDSWmHKS69JXmvWjmw2lRRLR2s212vmqKzYqsu22s2On2eO26wC8xF0I4SCQoTKa87lNdAEBmuwMJIBclIgRUcMcO9m9G1a-8+0uM3rABZJJQZEbspDdM5QIkrdJiZEU+VSw1Ku+sfwWuu69ArRV696z63S50kmpUc21mt2jaxAeAw2ZVbYQlTkALblZ9fhBYLSLQA9J8gNcrEexe8e-WzGxLbGqAXGwmLEp4au5UDOrAu+vAfUooJ0RcpQVQaoBEJDbkDMnSc8W0KxSul+se5ev6-Wr6yAfwC+mumB26-m3A2230+K8yn2ZK8WmMSWnTawQC9QABVIFIBmfurZGKO2YzF48USB0eq+yOp+tO5+0et+q21qm26s+2ro02n2Be8kF2lB2VVeoG7+oEVNeEGyKcZyVkUOCBMEQBBhy+kR-MqOtRfhthxejh8s6K5vFOh2-hqwl+4R3W0RmWoE7YGEQoUQcCMc8aJDKhGwcaXrWwBoRGtQ5kzpMyzOGFWAOeIMJ5PkKpZeLeKTGmuJVYJCCwMUSfc60+v9c+7gZXRLa9erBB4kZrThgWpPEgAZENaFAAOVVEgAADVsngcHARruzn02peQVayxFZUgy46gB7K6UnRc0mIMMnGssnMAWs9Gk6yd8n2BCnJUSmGsKmBn-rcFAaUwYQi9TgZzxAtAFoXRrZQ9TggsUJMpq8kiaU1NehNMDnJVoy0G2qJBurTm8BhHjnCCbmCQqnHRolzBVnDMOQZLjozBtATYmJ8hjB9ntMRlsaa0519ALnuHrntNKdQXLt51gdrwDdCgZyt7wRlyKEXRDYURQ4bBaIbAgWbCRd-FwXIWk9oWbCldRdbkEWxGKTzR+QIEe6tAIKd4gRhsz9kQzg4QuJQ7Ol7q9CqsQXil4WF0cBm0yXvSKWqtYWRW-t51W9xWBrLHuwv1TAN40hHoRS+0rgKhAUQRE5ZA+RCWhW3c60G0lXJXPtpXkizWFXF1lW+jjyEQbIMgO1usGMJSKk0UJ8K9j7hRGSvHkbHEBXHnz1L1r0kUrXXsbXoVgzQNfZM9EXYdZDpihUvXE4YRU2HBwRhEyU+WQ30DBWz0QMI2IN6Vo2rn8ZHn4235E39B1clhI5ZBagt67jR9h1rIkQlAfdbZeWkalTQ3gXcN8M7l7DK3Y3JUXM8Nqd7DgdwkLxNaqhCh2oPKmg2RIILzqgj0C2QUh2iWuN1RgosAJ3q2YXD2eM+SnWMj5M2R0wOQ2ULx+yKlMpJAczVAgRqopRK6-yYB-AMZ0a7seYCA4yEQYomNGhoJhE0yboMxFgw5xQVLnzh7f2OEAPfwgPYAQO2xr2gSwOKg-nIOqhoO4lrwec4P3JrxEOf21r0O7lB4sOqBrAVWJJGhOQCPMioPoY4ltJxFZozoEOf0B2UPaPAOGOQOZAWOyo2PwPCPbBiPuO2XKJ+P4OqOhOg2lSiBUP-2xPgOqAVApPeF8OIP5OxRFOKEjglgVPKOOR1Oh7z7tO6PMOQOxBDPEAZOOPj8uPt06hYP4MbPEPPH7P0ktPROMPxOqBhA3OEAPOTPvOaLbR89-PBP4Ld2JBQv-ynOIu5Bou2OHVdlsipQt0MWKlnRsXoJwIGTCsaPMvdPGOpBcumdFY6hVo7wTYSvlBVIB6bPzAGE0uiBsBUK67vjfi-2m6xHQ4YQORNg+d006gFo2pxFeR87EpshUR+vBvfHr7J7b7NF77mrH6XrNv369vP6xGchMoFUrF+V0psgFvEuxRRM0gyujhK7juJ6zstEPxDbsABhZ6uanh3vCSjhHQsWlKihxAHAFoe2AFPQUz8gak3uhv8z4HGsBvkfK3haErRbQy8GCHoyVBAKpwKhzxfU4objoe7ZrIZjzZVZmaNvkf9ao7jatHyB3vMeKdU7jG2fkfgeXCpR2vriUQFgxFzFTgmKiU2JA3gvOl0etvmHo7HrWGeffGhnYjk7OejGnaBGgeJulAV4k486HJn3R0JZwRt7B0Nkau-26PL5+YOAHqktYwp5sAM5Mf7ecHwymBXfjiBJBBBZIAf46X+xDgVlKg71TNlBBR-5NI0pEozwkOz6QvHP0a7ecB2BHe8GXe3fE71eydYAPeUqJbveM4Ac-eA+MAF4xHlBx8y7V5vUYJn3iUMz4OFAzgchuRre0PU+4qnfJ4Sd2SOeaysHEqcGxbwzbKpbylxtyDiiY4mhVor8bQEz1Awl-MHBTgu+dOUTe+s+B+Vrc-Kz8-MGRakrx+bLIz0rp+t0LE3kJiqhC7C0LSWlCwRwRMkf5eYw1MOEWADDB-RvVScZftPnm5wuNc2hdUOE1FtAohVaxufthp2Hrvcr0X-QiHiT-4c0b6j1N0mSAGRoCCQmJRrNgNwG-8nm53cEH3k9BGs7wrbCTKUEg5vsSUVmVpIjA-7s0UBP-fEj4gwE7dHqQQZ6ngMMKHcnq3ARrCQKGhtYxCa9B-gfWMDixwKd4QUJPgdSddL8eLQ7KwMWzsCBBTPI2jHVZ5ICrU3-AQUP14Zp0rC73XGOwMEBiD9SqQCoLkBWSMEvIigrtGyB5ByDL8Gg5AUYLEHbdPuaTDuGSFEGcDDCX1QHoz0MGoCbBZA3kAqmMCZlKCj4RQR3zZDnBgSsEXMgz0-4+CQhcDOetzXCHZCohIQofqZWwaWVceE-S-lLTEBE9JA8kFytVF8rJCNcGaZ0PezyB-NjswVFagAPWq5cGMpgbIIXimh2Ar8iIJboCHAozgbAifJJhoR6Gp9MBQwLOHzBKFCD6qAgwkq0hOjPpyGkoSGu53ZCKxIk2kbFDaG6EcUUSywgfirywKCMPqCVAmkTVgAk1ZmISJMMIhhAogGmSSWYdH27QklnUd4WwEbkuHX1dBSvLRl+RMFc9tereVCvqWOhbwlUmtWCOMM9CTh6gfzTKONAjjgjuB-gx6m0UJh80whX5fUuxyLC2gN+F3L1h3wljUCQRtsfzASNT5fUtEMIoyt6Sx7lDcGVQtslIDjIkoii66AFNoGljR9ToXleTsxhsCKY0u-cNCloN8G9DtO43AYeaX7DDgH294aPgPmAq7xQQpcQesh1fw9CVRuQwkVMESybCxBBAlYbiWiHRd5Mk4BfuYFWRtRaBa9XkOkBQgchtIMjB9gSMtHoClhPA-wLcKQEPC8aYuQmsBjeGUiB0yMIoOmFPBN9i6UmHkFJDVgKlhO5o5UTkLDHXDIRmjbXg2gtFFj8B3IoWprz4bwivylg7-tYJCHbDbyaKI+FKE2C70waZofOnbFAhvJTRSfflpWOKHFiMaEYq1IN2CEGF-uelCked3lEnQaRUoKTI4zHAQQlgayBkhHDY4hiqxAQa0Y72nFBDjBfFHUn30pFpoEMA+HkHmEFAlw32mUFFjYH2BzFFRY4jgROM5pFlORqFUoSPxx5NkBR6VNQIBUoinARwaKOJlynTD+0yqYpUuJNnzELDCx44rgeyPyH6UIqOTdBtWTKGj8KhIEi-m2RSBZ0mohWN5Hi02CPj3IU3CGDBUaAIhgU-gdUpGOHiGQdQcWMAEPFnh8we45SZILyj2TUEGM9GBqOIiqDep4Y8IOBLlDIDYBugIwLRNeiJyCxK2ik5SaMETbPx3hyaVjmRTWBkNNgbEbFA1HA5ylOUHoJuApPRLaTVJEGdSUGEP4xUqyWkkYIQTxiCA9J05OSo+QUCZBBE8kBaDyBOheR86EMKoHZKUkqTumeFAiraPkSaT7JnkxNng0cpiU-geQDMFAS2CPjEIHyRYH80RxzDsIHkk8RBmxiJTeByU1yc3gqleT8YGUulhYFeR-BjAUxdMFyhkIsRIOxgc2APlyiaF50WibGIMi3B4TLm40zcBgEJgDJ3AcZUHnbCNG0YNkJXRiTDTkzxJbIZgYaUEX0BjSNwk0tXkfwkAzTJp809gItIm7LSFIVgNaYjHGLjQAQdQWQCiBdCOA9pipEaYdNvrcxeYU8HuJW0Eg8w-Ad8QWFdJunRdcgbIFCEFL5Ck9HA8scmiBW6lkFoI+0rQljQBlYhnJp0tyWTlBm8wIZYAKGegGn7iIpIawNqMbG0AogkMxJA7GcDM4L91YP0g6VomMg4A+AlbbmdgD4Dkyq+Lo0GPKLen90Pp3oourEPlEwRxQStdmQO1+lcydYBM5vPzMFkLSKZ53UWQv09ASyPCV4EEJIHWCUc7YCsoLs+WVm2iCIRETHrbKYBCy4ywWc-NQTLDwyvWWYZQaNgwiQxboWM0aTbMIhMA1ZsVB2U7Im5STKBjgcQIzXBCMRWhNCdVOdVsCWyXY1sx6tqSEiVss57ACOS6PzBVBzeXIQLs+0uDk0LAWgIcBlmyIBy-pmcwSFEW4IVlCZEgXOfnNw7dgxQG7Tdui1hIgIuc9QAEKbDzRmYBxdcrRFfBMiY9uZmADuRIMBrihpAVseoF2iTKcgkMiXSgu1wgQw4J5to2eaHOTqzz55ANAUvigenXh+QPwvFgUTOhpY7Gy7PLok2wgZzIxQUEKJWwiohRT5czAUuxw0AWA5wnKDnFLLXEap6mmQFSChBQkac3538vwEfLJwIK85Ws4WZ3OypHhnQ00QlEAjFDJQJoWqB2O7LvT7zHq82boEVA+o1jXsFCqhb-I+HdgNc4lSml2j5CQ4GozKIud2L+BbB4BqlN+XQvJBIKJAQiskAwoMllQ1atGVQIpFdBjVZG9xMwAfQ2bZgXGL830G-PdiexvYibWLJjz6Cp5ugHAawR7C-guYVE4gs+ceVhmZA+sCEYxNiivxNAyKCgTeGsAlCug05rcLRWYt0XeT9F9U2KoYuMUtE-FPsWLNP0kBnAHB-HOBO2wDzLiIei0c3jcQ0X6Q35bCPwLkm4nTAJ2n0MAL4B+hxAJFh+RIDCHLhFBxK5wWnocIQDlw4Y0hN5B4vAhkL-AWSr6EEGKV5KglVZDwNkqKWs1pgpSyQRUm8xVK4Me2WEnUqBDLImlLqRwK0o5nYzEsb8DONxhziaT04mcbOJQBGWA1GkWqecnE35Di9Gm5NGkWsHAiuhwa0vK2ZzNWXbKNllAERWsp2WzJ9lApQ5RsglESE2kFsKuAL1hALl1INy1kYqXXADQHqlbbGFCv8hmLQw+3fSWUoDwihaYZmIoIWBN6DCUWxU5JLE1yiQqf80K3pWTlhXEr4VnsRFR8RWzbiEcs0ejA+32ALRoQ0GHFqznlnGzcoHiDoJW2UlRhKV3QalaTTpYrxbQEfU8LYGEzrMwpSgU6PU20AEtFSPKrwKSokD8qwAgq4VcitGUe0GYV8nkJcHqDOgroDQV6bsxODnhjVLgCsOqQwDwAogO5DBYdC0DtomYjEqGFymSDVMzYdcNcT1lS4Ds-IzqwuOx3ZzzkXQqQVZoKBZYFhDMcFJMvwufIXwO4GAUmQ6usVkwRAdg8NdoEjVBZd6h9fMIWFTEiYZypCxUhfCvg3x01IaoQLkG3FVzzA9cbZnUr7q35G47kNpPNV3Z1qKkCwcDiyzSC4jJQJXZIBAqNxqxaZ-hO5SOOOQAYwAfauEPen7o1QO6b6eCLLDZDMxwIPuVZNXipxXZDi9RWnH2o2bpA+cdCBoXd2Ug8oLS4lKwAjlqDV4zWKxDhIDjPXQ16Mea8uECDkZ8dFI8pMsByGrzL4Y8H6heQKSNXQYTgVMZdsjOUjvSYaCwYhMeAHCga6Un+CDZmqTBGqzQeQBmOtA8LOLDVryDQPEmiRMR0lwbPdkW04LYa-5zrGWJNC9EORn0DQZKLq0flnQnwsEQIloRCKWpwi2mdgJ+v9pHBsg5Pa4ghtHxkF1WjUeyGYFnXzD+WRbHYu0TjTdFViD2M9WQk9ofNFlQ4QutqIyA9oqaboajUqRVLsk+118qASsGTK51BQiq-PKdDyLH0Q6qEzpNZo5r7lbNIIKmWASERspmVUTWIbBhhzsh4O-qFTY4h82p9uKykzAH2vTQxRIIMFKTHUDWRmlB1skO2JDz5DDjYtIKeLSiTCHhV3StmpynkHom2gmgNkQBqR0u4yQOQXtQFN4umydI-NkG48jOGiVDqB6Mka8JupsB5V00FoGcICzS6IUYAyFIKhxSq3mlhSrlOJpSQ8bSBYE94yHmOmm3qV2K2lbrThu7DB45Ka0UuHbBsyUkPQ+8OuFkHLyQR-Ks2wKhWI4pcUNSyWnrWTH5wOpRA7jLIB5GfbmYV4nqSCDEi9RJq51IKGbYqA0ovaQq2EirYGH83-AWRslRyP5hkqqQN+GaE2F6g63qFOkXVOqr1QaryImqZ6zrJTBCYeMPQhde8cXFDgSFY5KIHWpbRs2farGxJSHIy3BjK0Go7HUzBBFXnjUypBOxxEw3DFEjhBUaLTG9XJApb4MAIZ0OizzAD5BsXO30arCjV0JWdaNa4RGI-pkRGFrHRcrfg+nQRC8ns2Sq8lgipjzAMA3XbAw5qo9oG5jRdRzuO3iUhiopGaJiMGzeFd1d4ElFJgaCWbDUEulEszz0HliOG-m1kOhBMR0ljglscmnFEe6tJnkou7xo4iQbKgI9H2o7axwqhnVjJFDWwPBFjV0l-W7CrPTRvS5QN898RCMdPXl0e7sqvqCJCKNOCJw7YXOG0KYHlkC9tgG2FRsgzd1+CbRj1Q3QrrsH9gi0KZK5SjL7HXLS4r7JVKPrz1qM8hXNBBrntd2W1-NlQVwvUGuiWdPZeLAsFtXeSHgsgG+-fXro5IaNleUDWPW3uk6kauWu8T0JqjAWUFJoiMW6NMU35pdfGZAQIIEyXV+pQ+poBRdyGc0JJh8EPTiBXA6bvYumj1dJqUz6bZNdNA4T2sfjOCtQaCVcdYLCBbXZAPFdgGLZ1sLbC4w2RzDTBwkebRldN8qZCJR35ywJC1IoioGKSor7IGtJrM9IevnSsHtqwobMOhGopxJbG9BK0IsBEz8g8xCA9gqojDZ2tSghexnBXENEcGpDhajnKYHnCgiQQ6UfHdnto10HgWIhsVk2iN2SKe8Oh5CGJm-3QhTSkFTIMBSU0rsmc9PLzbQbUPAsNDFrOw2IcNEuHN0hdZ5Pej3QlgWZy-IQzSlLZgZI2uBqzqtFQ0Dqrg8sCaChDExgx7A3kRUUWzDbJHwMDKNI-galUThOuziyAmpBHDpgRMICRI2ahHYEZUiMYMI84ZnKbp3DO8GCAfSUMrJr5lVfw5YcCMHtuMx7AvYxoyIZZNcccByCi0pJ34YasgGbsR1SAQ7it6XFPuFx5i2by4tcG0JuwSZRH4kY2klDHOgiegvB9pWzRKBJ5JlGoeQYgzAWhAxQlNcqkxEzFr2acDBkuyfZqFO72GUVQoZZqkK+m8hkInzKuG1DfZctxArKFWMppoMgo5ew3ScVLu+4qIBgKWk+MtEaBTCQ8XreQMopXaKqPCWwMYyoZC6Amyt+Q3fe9wV3HQljLIGcpUGh5LyyGnrKBVYHMN17MT6jUscrxZNv7EgXoh1KCJoZjZz8YiD2rJEKAMFYIOx9E3sbC6zHjd2hs1ZVxNwKGUQroGGCfnJJVArAqYkClv1t4F90+mfeRNn3d1aHHD39PU8qe5xKBFBqeu9BzmdBSx1gVpnvpgz76Rif87Op06QTCnpaNofxyhmOGX5nkaZtjNnGHvPoGDQxmE38I8dOCHB02+vCTXUvMDscswmwXNi+MFMAmIh6Zo8UCcd5EC1hBhfzfikXLGBJNyzAs8qdIb5aEM2C+41WYn2Z8QgIggQXHodRFYSzLZvnXGeyj8IJzCkYUimfpOVnDxOgxXmWLNp3DNBh4-zdsh8ybls0u9UOIXPk4xxh8mwXs8uePGqTAhs4gkDPqyKJ6H2rqAs0+G3XZBvjZwO2OeYwnVnGTO+o7kue-PbmRQm9XjiBS5Q2hwkMhCuO3z5Bqmxde7RYZmYlPudrGq6TeAenAjzc4zf9OGZ1NMnYK0T8F+IohexPAm7RIQ-zcSWaMwWqOjWugUFjyrAht6KIf4wvhItN6pdUYxng8P80JJLe40WTPKQBGwzA654CQuXjZEljVzrDL8lVtkAAhTJVygcUabHCIgiimqCUZb1pMy8Q27F5YSSL+qH6ftoOzLKBXpFVBi1n0v+pZ05CSWHS+Q-8eQCq1GYyCKYKfAOHGF3azy94YcFasIsWHiL6E78Rma1MOGULHtVnGvFkDly6lU4OguST5Aqwes5Zti0Fe0GXnbRJO4c8hZi5pBgLHo1cuSSllkYYoTMftLMORAHjvz-ZrRFxa248WcrlgaSKPPgItNYr0xcihHzFLVdPxaV1UUsNFPQivx2V8MzF0zFtDU5vlErtyGJ4fSH8uqV0FVeCs-nSLJ468yNbmOfDbI1kGoJV0LAcbNxHe7qxOF5wkolr6VrCVzUcvbnxESlQ+IQYRqPjv9MND0YOBxZwWArSo7wdVed0I7SySOxq7ITypVAm4OUui0YF44-0PCKsRlv5Zo1sSIMekvtYIHjhOg4m+1+rd6dCmjnWZsc0lNmBikOT4pzkvtTXGwW+mqDRrKUPzqHKl1wagCag76AqmOSEpAySefIj7XmIZucV8Vebxk1GAyK9W9iAVb8NwKHlxI46RgGRtl188G2Y3PnQkLjENcoEa6L3mhD-G35xMvGT3GlvKKVby-OK4sHljyo7oeReEAEWWWBzHqGs6W5cDyouoRS5cg66Pkwsso9kVMGapZrfmwAHZtti9Y9zxH-0ImjEapmkAyxe19ejNjJeLfNSNzpbbUqmN1NnDsQb1o+HulRHJM2Q1gascs97dnnx2moM3TYMroZVlzTgsceCU0dHWqA2lKC+OwOipJuGaEG40fAzTIPgNVACV3OzHbEXS3IIGQSPvJn7ScL0UNxWJibHHKW365-gbReYoCWWLpbJDdCHKVnB1wzAXOPA3YF2qmx5ADQNpR0pyXdKDo2puYPGZglmdWURYGGNmfhhrcWoxeNpW8ueWOnNrwENmCNXI0mIEQD0-3VZ0Ssikk7CogdkSoHj4BF7Ylc2A5Eh7-MVanxgBF2sOzrRuVu0DoH3fzACowmuQJiBNiuieHWIsg0OB+aeguAgAA */ id: 'Modeling', context: ({ input }) => ({ @@ -3439,9 +3440,12 @@ export const modelingMachine = setup({ }, initial: 'splitting sketch pipe', - entry: ['assign tool in context', 'reset selections'], + entry: [ + 'assign tool in context', + 'reset selections', + 'tear down client sketch', + ], }, - 'Circle three point tool': { states: { 'Awaiting first point': { @@ -4026,7 +4030,10 @@ export function isEditingExistingSketch({ const variableDeclaration = getNodeFromPath( kclManager.ast, sketchDetails.sketchEntryNodePath, - 'VariableDeclarator' + 'VariableDeclarator', + false, + true // suppress noise because we know sketchEntryNodePath might not match up to the ast if the user changed the code + // and is dealt with in `re-eval nodePaths` ) if (variableDeclaration instanceof Error) return false if (variableDeclaration.node.type !== 'VariableDeclarator') return false