diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 445abea9..2ae33597 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -21,6 +21,8 @@ jobs: NODE_ENV: production MONGO_URI: ${{ secrets.MONGO_URI }} JWT_SECRET: ${{ secrets.JWT_SECRET }} + JWT_REFRESH_SECRET: ${{ secrets.JWT_REFRESH_SECRET }} + VITE_API_URL: ${{ secrets.VITE_API_URL }} run: | docker-compose up -d --build diff --git a/.github/workflows/lint_and_test.yml b/.github/workflows/lint_and_test.yml index 0985250e..6baef532 100644 --- a/.github/workflows/lint_and_test.yml +++ b/.github/workflows/lint_and_test.yml @@ -38,7 +38,10 @@ jobs: - name: Run Unit Tests run: pnpm test env: + NODE_ENV: development JWT_SECRET: ${{ secrets.JWT_SECRET }} + JWT_REFRESH_SECRET: ${{ secrets.JWT_REFRESH_SECRET }} + VITE_API_URL: ${{ secrets.VITE_API_URL }} test_building_docker_image: name: Test Building Docker Image @@ -71,5 +74,7 @@ jobs: NODE_ENV: production MONGO_URI: ${{ secrets.MONGO_URI }} JWT_SECRET: ${{ secrets.JWT_SECRET }} + JWT_REFRESH_SECRET: ${{ secrets.JWT_REFRESH_SECRET }} + VITE_API_URL: ${{ secrets.VITE_API_URL }} run: | docker-compose build frontend backend diff --git a/.github/workflows/lint_and_unit_test.yml b/.github/workflows/lint_and_unit_test.yml index 2965a2e1..936b05be 100644 --- a/.github/workflows/lint_and_unit_test.yml +++ b/.github/workflows/lint_and_unit_test.yml @@ -44,4 +44,7 @@ jobs: - name: Run Unit Tests run: pnpm test env: + NODE_ENV: development JWT_SECRET: ${{ secrets.JWT_SECRET }} + JWT_REFRESH_SECRET: ${{ secrets.JWT_REFRESH_SECRET }} + VITE_API_URL: ${{ secrets.VITE_API_URL }} diff --git a/.gitignore b/.gitignore index 21167b85..6bc492a0 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,7 @@ .DS_Store .env +tsconfig.tsbuildinfo + # Jest globalConfig file ../globalConfig.json \ No newline at end of file diff --git a/@noctaCrdt/Crdt.ts b/@noctaCrdt/Crdt.ts index 60ff30ee..ae7686ca 100644 --- a/@noctaCrdt/Crdt.ts +++ b/@noctaCrdt/Crdt.ts @@ -1,11 +1,14 @@ -import { LinkedList } from "./LinkedList"; +import { LinkedList, BlockLinkedList, TextLinkedList } from "./LinkedList"; import { CharId, BlockId, NodeId } from "./NodeId"; import { Node, Char, Block } from "./Node"; import { - RemoteDeleteOperation, - RemoteInsertOperation, - SerializedProps, + RemoteBlockDeleteOperation, + RemoteCharDeleteOperation, + RemoteBlockInsertOperation, + RemoteCharInsertOperation, + CRDTSerializedProps, RemoteReorderOperation, + RemoteBlockUpdateOperation, } from "./Interfaces"; export class CRDT> { @@ -13,24 +16,72 @@ export class CRDT> { client: number; LinkedList: LinkedList; - constructor(client: number) { + constructor(client: number, LinkedListClass: new () => LinkedList) { this.clock = 0; this.client = client; - this.LinkedList = new LinkedList(); + this.LinkedList = new LinkedListClass(); + } + + localInsert(index: number, value: string, blockId?: BlockId, pageId?: string): any { + // 기본 CRDT에서는 구현하지 않고, 하위 클래스에서 구현 + throw new Error("Method not implemented."); + } + + localDelete(index: number, blockId?: BlockId, pageId?: string): any { + // 기본 CRDT에서는 구현하지 않고, 하위 클래스에서 구현 + throw new Error("Method not implemented."); + } + + remoteInsert(operation: any): void { + // 기본 CRDT에서는 구현하지 않고, 하위 클래스에서 구현 + throw new Error("Method not implemented."); + } + + remoteDelete(operation: any): void { + // 기본 CRDT에서는 구현하지 않고, 하위 클래스에서 구현 + throw new Error("Method not implemented."); + } + + read(): string { + return this.LinkedList.stringify(); } - localInsert(index: number, value: string): RemoteInsertOperation { - const id = - this instanceof BlockCRDT - ? new CharId(this.clock + 1, this.client) - : new BlockId(this.clock + 1, this.client); + spread(): T[] { + return this.LinkedList.spread(); + } + + serialize(): CRDTSerializedProps { + return { + clock: this.clock, + client: this.client, + LinkedList: this.LinkedList.serialize(), + }; + } + + deserialize(data: any): void { + this.clock = data.clock; + this.client = data.client; + this.LinkedList.deserialize(data.LinkedList); + } +} + +// EditorCRDT 클래스: 블록을 관리 +export class EditorCRDT extends CRDT { + currentBlock: Block | null; + constructor(client: number) { + super(client, BlockLinkedList); + this.currentBlock = null; + } + + localInsert(index: number, value: string): RemoteBlockInsertOperation { + const id = new BlockId(this.clock + 1, this.client); const remoteInsertion = this.LinkedList.insertAtIndex(index, value, id); this.clock += 1; - return { node: remoteInsertion.node }; + return { node: remoteInsertion.node } as RemoteBlockInsertOperation; } - localDelete(index: number): RemoteDeleteOperation { + localDelete(index: number, blockId: undefined, pageId: string): RemoteBlockDeleteOperation { if (index < 0 || index >= this.LinkedList.spread().length) { throw new Error(`Invalid index: ${index}`); } @@ -40,9 +91,10 @@ export class CRDT> { throw new Error(`Node not found at index: ${index}`); } - const operation: RemoteDeleteOperation = { + const operation: RemoteBlockDeleteOperation = { targetId: nodeToDelete.id, - clock: this.clock + 1, + clock: this.clock, + pageId, }; this.LinkedList.deleteNode(nodeToDelete.id); @@ -51,40 +103,56 @@ export class CRDT> { return operation; } - remoteInsert(operation: RemoteInsertOperation): void { - const NodeIdClass = this instanceof BlockCRDT ? CharId : BlockId; - const NodeClass = this instanceof BlockCRDT ? Char : Block; + remoteUpdate(block: Block, pageId: string): RemoteBlockUpdateOperation { + const updatedBlock = this.LinkedList.nodeMap[JSON.stringify(block.id)]; + updatedBlock.animation = block.animation; + updatedBlock.icon = block.icon; + updatedBlock.indent = block.indent; + updatedBlock.style = block.style; + updatedBlock.type = block.type; + // this.LinkedList.nodeMap[JSON.stringify(block.id)] = block; + return { node: updatedBlock, pageId }; + } + + remoteInsert(operation: RemoteBlockInsertOperation): void { + const newNodeId = new BlockId(operation.node.id.clock, operation.node.id.client); + const newNode = new Block(operation.node.value, newNodeId); - const newNodeId = new NodeIdClass(operation.node.id.clock, operation.node.id.client); - const newNode = new NodeClass(operation.node.value, newNodeId) as T; newNode.next = operation.node.next; newNode.prev = operation.node.prev; this.LinkedList.insertById(newNode); + this.clock = Math.max(this.clock, operation.node.id.clock) + 1; + /* if (this.clock <= newNode.id.clock) { this.clock = newNode.id.clock + 1; } + */ } - remoteDelete(operation: RemoteDeleteOperation): void { + remoteDelete(operation: RemoteBlockDeleteOperation): void { const { targetId, clock } = operation; if (targetId) { - this.LinkedList.deleteNode(targetId); + const targetNodeId = new BlockId(operation.targetId.clock, operation.targetId.client); + this.LinkedList.deleteNode(targetNodeId); } + this.clock = Math.max(this.clock, clock) + 1; + /* if (this.clock <= clock) { this.clock = clock + 1; } + */ } localReorder(params: { - targetId: NodeId; - beforeId: NodeId | null; - afterId: NodeId | null; + targetId: BlockId; + beforeId: BlockId | null; + afterId: BlockId | null; }): RemoteReorderOperation { const operation: RemoteReorderOperation = { ...params, - clock: this.clock + 1, + clock: this.clock, client: this.client, }; @@ -108,40 +176,111 @@ export class CRDT> { } } - read(): string { - return this.LinkedList.stringify(); - } - - spread(): T[] { - return this.LinkedList.spread(); - } - - serialize(): SerializedProps { + serialize(): CRDTSerializedProps { return { - clock: this.clock, - client: this.client, - LinkedList: { - head: this.LinkedList.head, - nodeMap: this.LinkedList.nodeMap || {}, - }, + ...super.serialize(), + currentBlock: this.currentBlock ? this.currentBlock.serialize() : null, }; } -} - -export class EditorCRDT extends CRDT { - currentBlock: Block | null; - constructor(client: number) { - super(client); - this.currentBlock = null; + deserialize(data: any): void { + super.deserialize(data); + this.currentBlock = data.currentBlock ? Block.deserialize(data.currentBlock) : null; } } +// BlockCRDT 클래스: 문자(Char)를 관리 export class BlockCRDT extends CRDT { currentCaret: number; constructor(client: number) { - super(client); + super(client, TextLinkedList); this.currentCaret = 0; } + + localInsert( + index: number, + value: string, + blockId: BlockId, + pageId: string, + ): RemoteCharInsertOperation { + const id = new CharId(this.clock + 1, this.client); + const { node } = this.LinkedList.insertAtIndex(index, value, id); + this.clock += 1; + const operation: RemoteCharInsertOperation = { + node, + blockId, + pageId, + }; + + return operation; + } + + localDelete(index: number, blockId: BlockId, pageId: string): RemoteCharDeleteOperation { + if (index < 0 || index >= this.LinkedList.spread().length) { + throw new Error(`Invalid index: ${index}`); + } + + const nodeToDelete = this.LinkedList.findByIndex(index); + if (!nodeToDelete) { + throw new Error(`Node not found at index: ${index}`); + } + + const operation: RemoteCharDeleteOperation = { + targetId: nodeToDelete.id, + clock: this.clock, + blockId, + pageId, + }; + + this.LinkedList.deleteNode(nodeToDelete.id); + this.clock += 1; + + return operation; + } + + remoteInsert(operation: RemoteCharInsertOperation): void { + const newNodeId = new CharId(operation.node.id.clock, operation.node.id.client); + const newNode = new Char(operation.node.value, newNodeId); + + newNode.next = operation.node.next; + newNode.prev = operation.node.prev; + + this.LinkedList.insertById(newNode); + + if (this.clock <= newNode.id.clock) { + this.clock = newNode.id.clock + 1; + } + } + + remoteDelete(operation: RemoteCharDeleteOperation): void { + const { targetId, clock } = operation; + if (targetId) { + const targetNodeId = new CharId(operation.targetId.clock, operation.targetId.client); + this.LinkedList.deleteNode(targetNodeId); + } + if (this.clock <= clock) { + this.clock = clock + 1; + } + } + + serialize(): CRDTSerializedProps { + return { + ...super.serialize(), + currentCaret: this.currentCaret, + }; + } + + static deserialize(data: any): BlockCRDT { + const crdt = new BlockCRDT(data.client); + crdt.clock = data.clock; + crdt.LinkedList.deserialize(data.LinkedList); + crdt.currentCaret = data.currentCaret; + return crdt; + } + + deserialize(data: any): void { + super.deserialize(data); + this.currentCaret = data.currentCaret; + } } diff --git a/@noctaCrdt/Interfaces.ts b/@noctaCrdt/Interfaces.ts index 21a7e5df..ecee570d 100644 --- a/@noctaCrdt/Interfaces.ts +++ b/@noctaCrdt/Interfaces.ts @@ -1,5 +1,7 @@ import { NodeId, BlockId, CharId } from "./NodeId"; import { Block, Char } from "./Node"; +import { Page } from "./Page"; +import { EditorCRDT } from "./Crdt"; export type ElementType = "p" | "h1" | "h2" | "h3" | "ul" | "ol" | "li" | "checkbox" | "blockquote"; @@ -12,13 +14,39 @@ export interface DeleteOperation { clock: number; } -export interface RemoteInsertOperation { - node: Block | Char; +export interface RemotePageCreateOperation { + clientId: number; + workspaceId: string; + page?: Page; +} + +export interface RemoteBlockUpdateOperation { + node: Block; + pageId: string; } -export interface RemoteDeleteOperation { - targetId: NodeId; +export interface RemoteBlockInsertOperation { + node: Block; + pageId: string; +} + +export interface RemoteCharInsertOperation { + node: Char; + blockId: BlockId; + pageId: string; +} + +export interface RemoteBlockDeleteOperation { + targetId: BlockId; + clock: number; + pageId: string; +} + +export interface RemoteCharDeleteOperation { + targetId: CharId; clock: number; + blockId?: BlockId; + pageId: string; } export interface CursorPosition { @@ -26,14 +54,32 @@ export interface CursorPosition { position: number; } -export interface SerializedProps { - // CRDT 직렬화라서 이름바꿔야함. +export interface CRDTSerializedProps { clock: number; client: number; LinkedList: { head: NodeId | null; nodeMap: { [key: string]: T }; }; + currentBlock?: Block | null; + currentCaret?: number | null; +} + +export interface serializedEditorDataProps { + clock: number; + client: number; + LinkedList: { + head: NodeId | null; + nodeMap: { [key: string]: Block }; + }; + currentBlock: Block | null; +} + +export interface serializedPageProps { + id: string; + title: string; + icon: string; + crdt: EditorCRDT; } export interface ReorderNodesProps { @@ -42,10 +88,15 @@ export interface ReorderNodesProps { afterId: BlockId | null; } +export interface WorkSpaceSerializedProps { + id: string; + pageList: Page[]; + authUser: Map; +} export interface RemoteReorderOperation { - targetId: NodeId; - beforeId: NodeId | null; - afterId: NodeId | null; + targetId: BlockId; + beforeId: BlockId | null; + afterId: BlockId | null; clock: number; client: number; } diff --git a/@noctaCrdt/LinkedList.ts b/@noctaCrdt/LinkedList.ts index 6f61dfbf..5adfcef6 100644 --- a/@noctaCrdt/LinkedList.ts +++ b/@noctaCrdt/LinkedList.ts @@ -1,8 +1,8 @@ import { Node, Char, Block } from "./Node"; -import { NodeId } from "./NodeId"; +import { NodeId, BlockId, CharId } from "./NodeId"; import { InsertOperation, ReorderNodesProps } from "./Interfaces"; -export class LinkedList> { +export abstract class LinkedList> { head: T["id"] | null; nodeMap: { [key: string]: T }; @@ -27,6 +27,8 @@ export class LinkedList> { deleteNode(id: T["id"]): void { const nodeToDelete = this.getNode(id); + console.log(this.nodeMap); + console.log("nodeToDelete", nodeToDelete, id); if (!nodeToDelete) return; if (this.head && id.equals(this.head)) { @@ -146,7 +148,7 @@ export class LinkedList> { insertAtIndex(index: number, value: string, id: T["id"]): InsertOperation { try { - const node = new Node(value, id) as T; + const node = this.createNode(value, id); this.setNode(id, node); if (!this.head || index <= 0) { @@ -239,13 +241,81 @@ export class LinkedList> { while (currentNodeId !== null) { const currentNode = this.getNode(currentNodeId); if (!currentNode) break; + result.push(currentNode!); + currentNodeId = currentNode.next; + } + return result; + } + + /* + spread(): T[] { + const visited = new Set(); + let currentNodeId = this.head; + const result: T[] = []; + + while (currentNodeId !== null) { + const nodeKey = JSON.stringify(currentNodeId); + if (visited.has(nodeKey)) break; // 순환 감지 + + visited.add(nodeKey); + const currentNode = this.getNode(currentNodeId); + if (!currentNode) break; + result.push(currentNode); currentNodeId = currentNode.next; } return result; +} + */ + + serialize(): any { + return { + head: this.head ? this.head.serialize() : null, + nodeMap: Object.fromEntries( + Object.entries(this.nodeMap).map(([key, value]) => [key, value.serialize()]), + ), + }; + } + + deserialize(data: any): void { + this.head = data.head ? this.deserializeNodeId(data.head) : null; + this.nodeMap = {}; + for (const key in data.nodeMap) { + this.nodeMap[key] = this.deserializeNode(data.nodeMap[key]); + } } + + abstract deserializeNodeId(data: any): T["id"]; + + abstract deserializeNode(data: any): T; + + abstract createNode(value: string, id: T["id"]): T; } -export class BlockLinkedList extends LinkedList {} +export class BlockLinkedList extends LinkedList { + deserializeNodeId(data: any): BlockId { + return BlockId.deserialize(data); + } + + deserializeNode(data: any): Block { + return Block.deserialize(data); + } -export class TextLinkedList extends LinkedList {} + createNode(value: string, id: BlockId): Block { + return new Block(value, id); + } +} + +export class TextLinkedList extends LinkedList { + deserializeNodeId(data: any): CharId { + return CharId.deserialize(data); + } + + deserializeNode(data: any): Char { + return Char.deserialize(data); + } + + createNode(value: string, id: CharId): Char { + return new Char(value, id); + } +} diff --git a/@noctaCrdt/Node.ts b/@noctaCrdt/Node.ts index 1aad93fd..12936a49 100644 --- a/@noctaCrdt/Node.ts +++ b/@noctaCrdt/Node.ts @@ -1,8 +1,9 @@ +// Node.ts import { NodeId, BlockId, CharId } from "./NodeId"; -import { BlockCRDT } from "./Crdt"; import { ElementType } from "./Interfaces"; +import { BlockCRDT } from "./Crdt"; -export class Node { +export abstract class Node { id: T; value: string; next: T | null; @@ -24,6 +25,19 @@ export class Node { return false; } + + serialize(): any { + return { + id: this.id.serialize(), + value: this.value, + next: this.next ? this.next.serialize() : null, + prev: this.prev ? this.prev.serialize() : null, + }; + } + + static deserialize(data: any): Node { + throw new Error("Deserialize method should be implemented by subclasses"); + } } export class Block extends Node { @@ -43,10 +57,48 @@ export class Block extends Node { this.icon = ""; this.crdt = new BlockCRDT(id.client); } + + serialize(): any { + return { + ...super.serialize(), + type: this.type, + indent: this.indent, + animation: this.animation, + style: this.style, + icon: this.icon, + crdt: this.crdt.serialize(), + }; + } + + static deserialize(data: any): Block { + const id = BlockId.deserialize(data.id); + const block = new Block(data.value, id); + block.next = data.next ? BlockId.deserialize(data.next) : null; + block.prev = data.prev ? BlockId.deserialize(data.prev) : null; + block.type = data.type; + block.indent = data.indent; + block.animation = data.animation; + block.style = data.style; + block.icon = data.icon; + block.crdt = BlockCRDT.deserialize(data.crdt); + return block; + } } export class Char extends Node { constructor(value: string, id: CharId) { super(value, id); } + + serialize(): any { + return super.serialize(); + } + + static deserialize(data: any): Char { + const id = CharId.deserialize(data.id); + const char = new Char(data.value, id); + char.next = data.next ? CharId.deserialize(data.next) : null; + char.prev = data.prev ? CharId.deserialize(data.prev) : null; + return char; + } } diff --git a/@noctaCrdt/NodeId.ts b/@noctaCrdt/NodeId.ts index b2731324..af55cda1 100644 --- a/@noctaCrdt/NodeId.ts +++ b/@noctaCrdt/NodeId.ts @@ -1,4 +1,5 @@ -export class NodeId { +// NodeId.ts +export abstract class NodeId { clock: number; client: number; @@ -10,8 +11,35 @@ export class NodeId { equals(other: NodeId): boolean { return this.clock === other.clock && this.client === other.client; } + + serialize(): any { + return { + clock: this.clock, + client: this.client, + }; + } + + static deserialize(data: any): NodeId { + throw new Error("Deserialize method should be implemented by subclasses"); + } +} + +export class BlockId extends NodeId { + constructor(clock: number, client: number) { + super(clock, client); + } + + static deserialize(data: any): BlockId { + return new BlockId(data.clock, data.client); + } } -export class BlockId extends NodeId {} +export class CharId extends NodeId { + constructor(clock: number, client: number) { + super(clock, client); + } -export class CharId extends NodeId {} + static deserialize(data: any): CharId { + return new CharId(data.clock, data.client); + } +} diff --git a/@noctaCrdt/Page.ts b/@noctaCrdt/Page.ts index 989ce794..4c9c01e3 100644 --- a/@noctaCrdt/Page.ts +++ b/@noctaCrdt/Page.ts @@ -1,4 +1,13 @@ import { EditorCRDT } from "./Crdt"; +import { Block } from "./Node"; +import { CRDTSerializedProps } from "./Interfaces"; + +export interface PageSerializedProps { + id: string; + title: string; + icon: string; + crdt: CRDTSerializedProps; // EditorCRDT의 직렬화된 데이터 타입 +} export class Page { id: string; @@ -6,11 +15,56 @@ export class Page { icon: string; crdt: EditorCRDT; - constructor(editorCRDT: EditorCRDT = new EditorCRDT(0)) { - // 추후 수정 직렬화, 역직렬화 메서드 추가 - this.id = "id"; - this.title = "title"; - this.icon = "icon"; + constructor( + id: string = crypto.randomUUID(), // 고유한 ID 생성 + title: string = "Untitled", + icon: string = "📄", + editorCRDT: EditorCRDT = new EditorCRDT(0), + ) { + this.id = id; + this.title = title; + this.icon = icon; this.crdt = editorCRDT; } + + // 페이지 제목 업데이트 + updateTitle(newTitle: string): void { + this.title = newTitle; + } + + // 아이콘 업데이트 + updateIcon(newIcon: string): void { + this.icon = newIcon; + } + + // 직렬화 + serialize(): PageSerializedProps { + return { + id: this.id, + title: this.title, + icon: this.icon, + crdt: this.crdt.serialize(), + }; + } + + // 역직렬화 + deserialize(data: PageSerializedProps): void { + if (!data) { + throw new Error("Invalid data for Page deserialization"); + } + + try { + this.id = data.id; + this.title = data.title; + this.icon = data.icon; + + // CRDT 역직렬화 + this.crdt.deserialize(data.crdt); + } catch (error) { + console.error("Error during Page deserialization:", error); + throw new Error( + `Failed to deserialize Page: ${error instanceof Error ? error.message : "Unknown error"}`, + ); + } + } } diff --git a/@noctaCrdt/WorkSpace.ts b/@noctaCrdt/WorkSpace.ts index 252191fd..49e3c429 100644 --- a/@noctaCrdt/WorkSpace.ts +++ b/@noctaCrdt/WorkSpace.ts @@ -1,14 +1,47 @@ import { Page } from "./Page"; +import { WorkSpaceSerializedProps } from "./Interfaces"; +import { EditorCRDT } from "./Crdt"; export class WorkSpace { id: string; pageList: Page[]; - authUser: object; + authUser: Map; constructor(id: string, pageList: Page[]) { this.id = id; this.pageList = pageList; this.authUser = new Map(); - // 직렬화, 역직렬화 메서드 추가 + } + + serialize(): WorkSpaceSerializedProps { + return { + id: this.id, + pageList: this.pageList, + authUser: this.authUser, + }; + } + + deserialize(data: WorkSpaceSerializedProps): void { + this.id = data.id; + this.pageList = data.pageList.map((pageData) => { + const page = new Page(); + page.deserialize(pageData); + return page; + }); + this.authUser = new Map(Object.entries(data.authUser)); + } + + remotePageCreate(operation: { page: Page; workspaceId: string; clientId: number }): Page { + const { page } = operation; + const newEditorCRDT = new EditorCRDT(operation.clientId); + const newPage = new Page(page.id, page.title, page.icon, newEditorCRDT); + + this.pageList.push(newPage); + return newPage; + } + + getPage(data: string) { + const page = this.pageList.find((page) => page.id === data); + return page; } } diff --git a/README.md b/README.md index 99270eab..9175e6d1 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@
- 배포사이트

@@ -12,7 +11,7 @@

- 배포 사이트 + 배포 사이트

diff --git a/client/src/App.tsx b/client/src/App.tsx index a5a43012..8878f7b0 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,10 +1,36 @@ +import { useEffect } from "react"; +import { useRefreshQuery } from "@apis/auth"; +import { ErrorModal } from "@components/modal/ErrorModal"; import { WorkSpace } from "@features/workSpace/WorkSpace"; +import { useErrorStore } from "@stores/useErrorStore"; +import { useUserInfo } from "@stores/useUserStore"; +import { useSocketStore } from "./stores/useSocketStore"; const App = () => { // TODO 라우터, react query 설정 + const { id, name, accessToken } = useUserInfo(); + const { refetch: refreshToken } = useRefreshQuery(); + const { isErrorModalOpen, errorMessage } = useErrorStore(); + + useEffect(() => { + if (id && name && !accessToken) { + refreshToken(); + } + }, []); + + useEffect(() => { + const socketStore = useSocketStore.getState(); + socketStore.init(); + return () => { + setTimeout(() => { + socketStore.cleanup(); + }, 0); + }; + }, []); return ( <> + {isErrorModalOpen && } ); diff --git a/client/src/apis/auth.ts b/client/src/apis/auth.ts index 2359fff2..cb7887de 100644 --- a/client/src/apis/auth.ts +++ b/client/src/apis/auth.ts @@ -1,35 +1,70 @@ -import { useMutation } from "@tanstack/react-query"; -import axios from "axios"; - -export const useSignupMutation = () => { - const fetcher = ({ - name, - email, - password, - }: { - name: string; - email: string; - password: string; - }) => { - return axios.post("/auth/register", { name, email, password }); - }; +import { useMutation, useQuery } from "@tanstack/react-query"; +import { useUserActions } from "@stores/useUserStore"; +import { unAuthorizationFetch, fetch } from "./axios"; + +const authKey = { + all: ["auth"] as const, + refresh: () => [...authKey.all, "refresh"] as const, +}; + +export const useSignupMutation = (onSuccess: () => void) => { + const fetcher = ({ name, email, password }: { name: string; email: string; password: string }) => + unAuthorizationFetch.post("/auth/register", { name, email, password }); + + return useMutation({ + mutationFn: fetcher, + onSuccess: () => { + onSuccess(); + }, + }); +}; + +export const useLoginMutation = (onSuccess: () => void) => { + const { setUserInfo } = useUserActions(); + + const fetcher = ({ email, password }: { email: string; password: string }) => + unAuthorizationFetch.post("/auth/login", { email, password }); return useMutation({ mutationFn: fetcher, + onSuccess: (response) => { + const { id, name } = response.data; + const [, accessToken] = response.headers.authorization.split(" "); + setUserInfo(id, name, accessToken); + onSuccess(); + }, }); }; -export const useLoginMutation = () => { - const fetcher = ({ email, password }: { email: string; password: string }) => { - return axios.post("/auth/login", { email, password }); - }; +export const useLogoutMutation = (onSuccess: () => void) => { + const { removeUserInfo } = useUserActions(); + + const fetcher = () => fetch.post("/auth/logout"); return useMutation({ mutationFn: fetcher, - // TODO 성공했을 경우 accessToken 저장 (zustand? localStorage? cookie?) - // accessToken: cookie (쿠기 다 때려넣기...) / localStorage / zustand (번거로움..귀찮음.. 안해봤음..) - // refreshToken: cookie, - // onSuccess: (data) => { - // }, + onSuccess: () => { + removeUserInfo(); + onSuccess(); + }, + }); +}; + +export const useRefreshQuery = () => { + const { updateAccessToken } = useUserActions(); + + const fetcher = () => fetch.get("/auth/refresh"); + + return useQuery({ + queryKey: authKey.refresh(), + queryFn: async () => { + const response = await fetcher(); + + const [, accessToken] = response.headers.authorization.split(" "); + updateAccessToken(accessToken); + + return response.data; + }, + enabled: false, }); }; diff --git a/client/src/apis/axios.ts b/client/src/apis/axios.ts new file mode 100644 index 00000000..aafe0bff --- /dev/null +++ b/client/src/apis/axios.ts @@ -0,0 +1,102 @@ +import axios, { AxiosError, CreateAxiosDefaults, InternalAxiosRequestConfig } from "axios"; +import { useErrorStore } from "@stores/useErrorStore"; +import { useUserStore } from "@stores/useUserStore"; + +interface CustomAxiosRequestConfig extends InternalAxiosRequestConfig { + _retry?: boolean; +} + +const baseConfig: CreateAxiosDefaults = { + baseURL: `${import.meta.env.VITE_API_URL}`, + withCredentials: true, +}; + +interface ApiError { + message: string; + code?: string; +} + +const getErrorMessage = (error: AxiosError) => { + return error.response?.data?.message || error.message || "알 수 없는 오류가 발생했습니다."; +}; + +const handleGlobalError = (error: AxiosError) => { + const errorStore = useErrorStore.getState(); + const errorMessage = getErrorMessage(error); + + if (!error.response) { + errorStore.setErrorModal(true, "네트워크 연결을 확인해주세요."); + return; + } + + // 에러 상태 코드에 따른 처리 + switch (error.response.status) { + case 401: + // 이미 access token. refresh token이 만료된 경우 여기로 넘어옴. + useUserStore.getState().actions.removeUserInfo(); + errorStore.setErrorModal(true, "유효하지 않은 사용자입니다. 다시 로그인해주세요."); + break; + + case 500: + case 502: + case 503: + errorStore.setErrorModal(true, "서버 오류가 발생했습니다. 잠시 후 다시 시도해주세요."); + break; + default: + errorStore.setErrorModal(true, errorMessage); + } +}; + +export const unAuthorizationFetch = axios.create(baseConfig); + +export const fetch = axios.create(baseConfig); + +fetch.interceptors.request.use( + function (config) { + const { accessToken } = useUserStore.getState(); + + if (accessToken) { + config.headers.Authorization = `Bearer ${accessToken}`; + } + + return config; + }, + function (error) { + handleGlobalError(error); + return Promise.reject(error); + }, +); + +fetch.interceptors.response.use( + function (response) { + return response; + }, + async function (error: AxiosError) { + const originalRequest: CustomAxiosRequestConfig | undefined = error.config; + + if (error.response?.status === 401 && originalRequest && !originalRequest._retry) { + originalRequest._retry = true; + + try { + // access token이 만료된 경우 refresh token으로 새로운 access token을 발급받음 + // 이때 refresh token만 있기에 unAuthorizationFetch를 사용. + // 만약 fetch를 사용하면 401 에러가 무한으로 발생함. + const response = await unAuthorizationFetch.get("/auth/refresh"); + + const [, accessToken] = response.headers.authorization.split(" "); + + useUserStore.setState({ accessToken }); + originalRequest.headers.Authorization = `Bearer ${accessToken}`; + + return fetch(originalRequest); + } catch (refreshError) { + handleGlobalError(refreshError as AxiosError); + return Promise.reject(refreshError); + } + } + + handleGlobalError(error as AxiosError); + return Promise.reject(error); + }, +); +``; diff --git a/client/src/apis/useSocket.ts b/client/src/apis/useSocket.ts new file mode 100644 index 00000000..f62a847c --- /dev/null +++ b/client/src/apis/useSocket.ts @@ -0,0 +1,172 @@ +import { + RemoteBlockInsertOperation, + RemoteBlockDeleteOperation, + RemoteCharInsertOperation, + RemoteCharDeleteOperation, + RemoteBlockUpdateOperation, + CursorPosition, + WorkSpaceSerializedProps, +} from "@noctaCrdt/Interfaces"; + +import { useEffect, useRef, useState } from "react"; +import { io, Socket } from "socket.io-client"; +// 구독 핸들러들의 타입 정의 +interface RemoteOperationHandlers { + onRemoteBlockUpdate: (operation: RemoteBlockUpdateOperation) => void; + onRemoteBlockInsert: (operation: RemoteBlockInsertOperation) => void; + onRemoteBlockDelete: (operation: RemoteBlockDeleteOperation) => void; + onRemoteCharInsert: (operation: RemoteCharInsertOperation) => void; + onRemoteCharDelete: (operation: RemoteCharDeleteOperation) => void; + onRemoteCursor: (position: CursorPosition) => void; +} + +interface PageOperationsHandlers { + onRemotePageCreate: (operation: string) => void; +} + +// 훅의 반환 타입을 명시적으로 정의 +interface UseSocketReturn { + socket: Socket | null; + fetchWorkspaceData: () => WorkSpaceSerializedProps; + sendPageCreateOperation: (operation: string) => void; + sendBlockUpdateOperation: (operation: RemoteBlockUpdateOperation) => void; + sendBlockInsertOperation: (operation: RemoteBlockInsertOperation) => void; + sendCharInsertOperation: (operation: RemoteCharInsertOperation) => void; + sendBlockDeleteOperation: (operation: RemoteBlockDeleteOperation) => void; + sendCharDeleteOperation: (operation: RemoteCharDeleteOperation) => void; + sendCursorPosition: (position: CursorPosition) => void; + subscribeToRemoteOperations: (handlers: RemoteOperationHandlers) => (() => void) | undefined; + subscribeToPageOperations: (handlers: PageOperationsHandlers) => void; +} + +// 반환 타입을 명시적으로 지정 +export const useSocket = (): UseSocketReturn => { + const socketRef = useRef(null); + const [workspace, setWorkspace] = useState(null); + useEffect(() => { + const SERVER_URL = + process.env.NODE_ENV === "development" ? "http://localhost:3000" : "https://api.nocta.site"; + socketRef.current = io(SERVER_URL, { + path: "/api/socket.io", + transports: ["websocket", "polling"], // polling도 fallback으로 추가 + withCredentials: true, // CORS credentials 설정 + reconnectionAttempts: 5, // 재연결 시도 횟수 + reconnectionDelay: 1000, // 재연결 시도 간격 (ms) + autoConnect: true, + }); + + socketRef.current.on("assignId", (clientId: number) => { + console.log("Assigned client ID:", clientId); + }); + + socketRef.current.on("workspace", (workspace: WorkSpaceSerializedProps) => { + console.log("Received initial workspace state:", workspace); + setWorkspace(workspace); + }); + + socketRef.current.on("connect", () => { + console.log("Connected to server"); + }); + + socketRef.current.on("disconnect", () => { + console.log("Disconnected from server"); + }); + + socketRef.current.on("error", (error: Error) => { + console.error("Socket error:", error); + }); + + console.log("소켓 이벤트 on"); + + return () => { + if (socketRef.current) { + socketRef.current.disconnect(); + } + }; + }, []); + + const fetchWorkspaceData = (): WorkSpaceSerializedProps => { + return workspace!; + }; + + const sendPageCreateOperation = (operation: string) => { + socketRef.current?.emit("create/page", operation); + console.log("페이지 만들기 송신", operation); + }; + + const sendBlockInsertOperation = (operation: RemoteBlockInsertOperation) => { + socketRef.current?.emit("insert/block", operation); + console.log(operation); + }; + + const sendCharInsertOperation = (operation: RemoteCharInsertOperation) => { + socketRef.current?.emit("insert/char", operation); + + console.log(operation); + }; + + const sendBlockUpdateOperation = (operation: RemoteBlockUpdateOperation) => { + socketRef.current?.emit("update/block", operation); + }; + + const sendBlockDeleteOperation = (operation: RemoteBlockDeleteOperation) => { + socketRef.current?.emit("delete/block", operation); + }; + + const sendCharDeleteOperation = (operation: RemoteCharDeleteOperation) => { + socketRef.current?.emit("delete/char", operation); + }; + + const sendCursorPosition = (position: CursorPosition) => { + socketRef.current?.emit("cursor", position); + }; + + const subscribeToRemoteOperations = ({ + onRemoteBlockUpdate, + onRemoteBlockInsert, + onRemoteBlockDelete, + onRemoteCharInsert, + onRemoteCharDelete, + onRemoteCursor, + }: RemoteOperationHandlers) => { + if (!socketRef.current) return; + socketRef.current.on("update/block", onRemoteBlockUpdate); + socketRef.current.on("insert/block", onRemoteBlockInsert); + socketRef.current.on("delete/block", onRemoteBlockDelete); + socketRef.current.on("insert/char", onRemoteCharInsert); + socketRef.current.on("delete/char", onRemoteCharDelete); + socketRef.current.on("cursor", onRemoteCursor); + + return () => { + socketRef.current?.off("update/block", onRemoteBlockUpdate); + socketRef.current?.off("insert/block", onRemoteBlockInsert); + socketRef.current?.off("delete/block", onRemoteBlockDelete); + socketRef.current?.off("insert/char", onRemoteCharInsert); + socketRef.current?.off("delete/char", onRemoteCharDelete); + socketRef.current?.off("cursor", onRemoteCursor); + }; + }; + + const subscribeToPageOperations = ({ onRemotePageCreate }: PageOperationsHandlers) => { + if (!socketRef.current) return; + socketRef.current.on("create/page", onRemotePageCreate); + + return () => { + socketRef.current?.off("create/page", onRemotePageCreate); + }; + }; + + return { + socket: socketRef.current, + fetchWorkspaceData, + sendPageCreateOperation, + sendBlockUpdateOperation, + sendBlockInsertOperation, + sendCharInsertOperation, + sendBlockDeleteOperation, + sendCharDeleteOperation, + sendCursorPosition, + subscribeToRemoteOperations, + subscribeToPageOperations, + }; +}; diff --git a/client/src/components/bottomNavigator/BottomNavigator.tsx b/client/src/components/bottomNavigator/BottomNavigator.tsx index 23a3f6db..1c92122a 100644 --- a/client/src/components/bottomNavigator/BottomNavigator.tsx +++ b/client/src/components/bottomNavigator/BottomNavigator.tsx @@ -6,7 +6,7 @@ import { bottomNavigatorContainer } from "./BottomNavigator.style"; interface BottomNavigatorProps { pages: Page[]; - handlePageSelect: ({ pageId, isSidebar }: { pageId: number; isSidebar?: boolean }) => void; + handlePageSelect: ({ pageId, isSidebar }: { pageId: string; isSidebar?: boolean }) => void; } export const BottomNavigator = ({ pages, handlePageSelect }: BottomNavigatorProps) => { diff --git a/client/src/components/modal/modal.style.ts b/client/src/components/modal/modal.style.ts index e1fade7a..7f95cf8c 100644 --- a/client/src/components/modal/modal.style.ts +++ b/client/src/components/modal/modal.style.ts @@ -45,6 +45,8 @@ export const modalContent = css({ alignItems: "center", width: "100%", height: "100%", + paddingTop: "md", + paddingBottom: "md", textAlign: "center", }); diff --git a/client/src/components/sidebar/MenuButton.style.ts b/client/src/components/sidebar/MenuButton.style.ts index 307c3871..28721aca 100644 --- a/client/src/components/sidebar/MenuButton.style.ts +++ b/client/src/components/sidebar/MenuButton.style.ts @@ -23,3 +23,14 @@ export const textBox = css({ textStyle: "display-medium20", color: "gray.900", }); + +export const menuDropdown = css({ + zIndex: "dropdown", + position: "absolute", + top: "100%", + right: "0", + borderRadius: "md", + width: "100px", + marginTop: "sm", + boxShadow: "md", +}); diff --git a/client/src/components/sidebar/MenuButton.tsx b/client/src/components/sidebar/MenuButton.tsx index 22a35582..73f0e774 100644 --- a/client/src/components/sidebar/MenuButton.tsx +++ b/client/src/components/sidebar/MenuButton.tsx @@ -1,17 +1,15 @@ -import { useModal } from "@components/modal/useModal"; -import { AuthModal } from "@src/features/auth/AuthModal"; +import { useUserInfo } from "@stores/useUserStore"; import { menuItemWrapper, imageBox, textBox } from "./MenuButton.style"; export const MenuButton = () => { - const { isOpen, openModal, closeModal } = useModal(); + const { name } = useUserInfo(); return ( <> - - ); }; diff --git a/client/src/components/sidebar/PageItem.tsx b/client/src/components/sidebar/PageItem.tsx index c42116e2..d8bc644d 100644 --- a/client/src/components/sidebar/PageItem.tsx +++ b/client/src/components/sidebar/PageItem.tsx @@ -1,7 +1,7 @@ import { pageItemContainer, iconBox, textBox } from "./PageItem.style"; interface PageItemProps { - id: number; + id: string; title: string; icon?: string; onClick: () => void; diff --git a/client/src/components/sidebar/Sidebar.style.ts b/client/src/components/sidebar/Sidebar.style.ts index 2cf411d3..8d6b2318 100644 --- a/client/src/components/sidebar/Sidebar.style.ts +++ b/client/src/components/sidebar/Sidebar.style.ts @@ -16,15 +16,22 @@ export const navWrapper = css({ gap: "md", flexDirection: "column", width: "100%", + height: "calc(100% - 176px)", overflowX: "hidden", overflowY: "scroll", }); export const plusIconBox = css({ display: "flex", - justifyContent: "start", - marginBlock: "10px", + position: "absolute", + bottom: "0px", + gap: "md", + justifyContent: "space-between", + alignItems: "center", + width: "100%", + height: "60px", paddingInline: "md", + justifyItems: "center", }); export const sidebarToggleButton = css({ diff --git a/client/src/components/sidebar/Sidebar.tsx b/client/src/components/sidebar/Sidebar.tsx index db623778..57db7ad8 100644 --- a/client/src/components/sidebar/Sidebar.tsx +++ b/client/src/components/sidebar/Sidebar.tsx @@ -1,9 +1,10 @@ +import { useIsSidebarOpen, useSidebarActions } from "@stores/useSidebarStore"; import { motion } from "framer-motion"; import { IconButton } from "@components/button/IconButton"; import { Modal } from "@components/modal/modal"; import { useModal } from "@components/modal/useModal"; import { MAX_VISIBLE_PAGE } from "@src/constants/page"; -import { useIsSidebarOpen, useSidebarActions } from "@src/stores/useSidebarStore"; +import { AuthButton } from "@src/features/auth/AuthButton"; import { Page } from "@src/types/page"; import { MenuButton } from "./MenuButton"; import { PageItem } from "./PageItem"; @@ -17,16 +18,16 @@ export const Sidebar = ({ }: { pages: Page[]; handlePageAdd: () => void; - handlePageSelect: ({ pageId }: { pageId: number }) => void; + handlePageSelect: ({ pageId }: { pageId: string }) => void; }) => { const visiblePages = pages.filter((page) => page.isVisible); const isMaxVisiblePage = visiblePages.length >= MAX_VISIBLE_PAGE; - + console.log(pages, visiblePages, "체크용"); const isSidebarOpen = useIsSidebarOpen(); const { toggleSidebar } = useSidebarActions(); const { isOpen, openModal, closeModal } = useModal(); - const handlePageItemClick = (id: number) => { + const handlePageItemClick = (id: string) => { if (isMaxVisiblePage) { openModal(); return; @@ -35,6 +36,7 @@ export const Sidebar = ({ }; const handleAddPageButtonClick = () => { + console.log(isMaxVisiblePage, "체크"); if (isMaxVisiblePage) { openModal(); return; @@ -69,6 +71,7 @@ export const Sidebar = ({ +

diff --git a/client/src/features/auth/AuthButton.tsx b/client/src/features/auth/AuthButton.tsx new file mode 100644 index 00000000..82dbffea --- /dev/null +++ b/client/src/features/auth/AuthButton.tsx @@ -0,0 +1,49 @@ +import { useLogoutMutation } from "@apis/auth"; +import { useCheckLogin } from "@stores/useUserStore"; +import { TextButton } from "@components/button/textButton"; +import { Modal } from "@components/modal/modal"; +import { useModal } from "@components/modal/useModal"; +import { AuthModal } from "./AuthModal"; + +export const AuthButton = () => { + const isLogin = useCheckLogin(); + + const { + isOpen: isAuthModalOpen, + openModal: openAuthModal, + closeModal: closeAuthModal, + } = useModal(); + + const { + isOpen: isLogoutModalOpen, + openModal: openLogoutModal, + closeModal: closeLogoutModal, + } = useModal(); + + const { mutate: logout } = useLogoutMutation(closeLogoutModal); + + return ( + <> + {isLogin ? ( + + 로그아웃 + + ) : ( + + 로그인 + + )} + + + +

로그아웃 하시겠습니까?

+
+ + ); +}; diff --git a/client/src/features/auth/AuthModal.tsx b/client/src/features/auth/AuthModal.tsx index 9855ec20..4c702ffe 100644 --- a/client/src/features/auth/AuthModal.tsx +++ b/client/src/features/auth/AuthModal.tsx @@ -1,11 +1,11 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ +import { useLoginMutation, useSignupMutation } from "@apis/auth"; import { useState } from "react"; import Lock from "@assets/icons/lock.svg?react"; import Mail from "@assets/icons/mail.svg?react"; import User from "@assets/icons/user.svg?react"; +import { InputField } from "@components/inputField/InputField"; import { Modal } from "@components/modal/modal"; -import { useLoginMutation, useSignupMutation } from "@src/apis/auth"; -import { InputField } from "@src/components/inputField/InputField"; import { container, formContainer, title, toggleButton } from "./AuthModal.style"; interface AuthModalProps { @@ -21,8 +21,8 @@ export const AuthModal = ({ isOpen, onClose }: AuthModalProps) => { password: "", }); - const { mutate: signUp } = useSignupMutation(); - const { mutate: login } = useLoginMutation(); + const { mutate: login } = useLoginMutation(onClose); + const { mutate: signUp } = useSignupMutation(() => login(formData)); const toggleMode = () => { setMode(mode === "login" ? "register" : "login"); @@ -41,13 +41,11 @@ export const AuthModal = ({ isOpen, onClose }: AuthModalProps) => { }; const handleSubmitButtonClick = () => { - // TODO API 연결 if (mode === "register") { signUp(formData); } else { login(formData); } - // closeModal(); }; return ( diff --git a/client/src/features/editor/Editor.style.ts b/client/src/features/editor/Editor.style.ts index 1e3d9130..7292d919 100644 --- a/client/src/features/editor/Editor.style.ts +++ b/client/src/features/editor/Editor.style.ts @@ -13,8 +13,9 @@ export const editorContainer = css({ }); export const editorTitleContainer = css({ + display: "flex", + flexDirection: "column", width: "full", - marginBottom: "30px", padding: "spacing.sm", }); diff --git a/client/src/features/editor/Editor.tsx b/client/src/features/editor/Editor.tsx index 78025e63..c9790bf5 100644 --- a/client/src/features/editor/Editor.tsx +++ b/client/src/features/editor/Editor.tsx @@ -4,7 +4,12 @@ import { EditorCRDT } from "@noctaCrdt/Crdt"; import { BlockLinkedList } from "@noctaCrdt/LinkedList"; import { Block as CRDTBlock } from "@noctaCrdt/Node"; import { BlockId } from "@noctaCrdt/NodeId"; -import { useRef, useState, useCallback, useEffect } from "react"; +import { + RemoteCharInsertOperation, + serializedEditorDataProps, +} from "node_modules/@noctaCrdt/Interfaces.ts"; +import { useRef, useState, useCallback, useEffect, useMemo } from "react"; +import { useSocketStore } from "@src/stores/useSocketStore.ts"; import { editorContainer, editorTitleContainer, editorTitle } from "./Editor.style"; import { Block } from "./components/block/Block.tsx"; import { useBlockDragAndDrop } from "./hooks/useBlockDragAndDrop"; @@ -12,6 +17,8 @@ import { useMarkdownGrammer } from "./hooks/useMarkdownGrammer"; interface EditorProps { onTitleChange: (title: string) => void; + pageId: string; + serializedEditorData: serializedEditorDataProps; } export interface EditorStateProps { @@ -19,16 +26,38 @@ export interface EditorStateProps { linkedList: BlockLinkedList; currentBlock: BlockId | null; } +// TODO: pageId, editorCRDT를 props로 받아와야함 +export const Editor = ({ onTitleChange, pageId, serializedEditorData }: EditorProps) => { + /* + const { + sendCharInsertOperation, + sendCharDeleteOperation, + subscribeToRemoteOperations, + sendBlockInsertOperation, + sendBlockDeleteOperation, + sendBlockUpdateOperation, + } = useSocket(); + */ + const { + sendCharInsertOperation, + sendCharDeleteOperation, + subscribeToRemoteOperations, + sendBlockInsertOperation, + sendBlockDeleteOperation, + sendBlockUpdateOperation, + } = useSocketStore(); + const editorCRDTInstance = useMemo(() => { + const editor = new EditorCRDT(serializedEditorData.client); + editor.deserialize(serializedEditorData); + return editor; + }, [serializedEditorData]); -export const Editor = ({ onTitleChange }: EditorProps) => { - const editorCRDT = useRef(new EditorCRDT(0)); - + const editorCRDT = useRef(editorCRDTInstance); const [editorState, setEditorState] = useState({ clock: editorCRDT.current.clock, linkedList: editorCRDT.current.LinkedList, currentBlock: null as BlockId | null, }); - const { sensors, handleDragEnd } = useBlockDragAndDrop({ editorCRDT: editorCRDT.current, editorState, @@ -39,6 +68,12 @@ export const Editor = ({ onTitleChange }: EditorProps) => { editorCRDT: editorCRDT.current, editorState, setEditorState, + pageId, + sendBlockInsertOperation, + sendBlockDeleteOperation, + sendBlockUpdateOperation, + sendCharDeleteOperation, + sendCharInsertOperation, }); const handleTitleChange = (e: React.ChangeEvent) => { @@ -46,34 +81,42 @@ export const Editor = ({ onTitleChange }: EditorProps) => { }; const handleBlockClick = (blockId: BlockId, e: React.MouseEvent) => { - const block = editorState.linkedList.getNode(blockId); - if (!block) return; + try { + const block = editorState.linkedList.getNode(blockId); + if (!block) { + console.warn("Block not found:", blockId); + return; + } - // 클릭된 요소 내에서의 위치를 가져오기 위해 - const range = document.caretRangeFromPoint(e.clientX, e.clientY); - if (!range) return; + const selection = window.getSelection(); + const range = document.caretRangeFromPoint(e.clientX, e.clientY); - const selection = window.getSelection(); - if (!selection) return; + if (!selection || !range) { + console.warn("Selection or range not available"); + return; + } - // 새로운 Range로 Selection 설정 - selection.removeAllRanges(); - selection.addRange(range); + // 새로운 Range로 Selection 설정 + selection.removeAllRanges(); + selection.addRange(range); - // 현재 캐럿 위치를 저장 - block.crdt.currentCaret = selection.focusOffset; + // 현재 캐럿 위치를 저장 + const caretPosition = selection.focusOffset; + block.crdt.currentCaret = caretPosition; - setEditorState((prev) => ({ - ...prev, - currentBlock: blockId, - })); + setEditorState((prev) => ({ + ...prev, + currentBlock: blockId, + })); + } catch (error) { + console.error("Error handling block click:", error); + } }; const handleBlockInput = useCallback( - (e: React.FormEvent, blockId: BlockId) => { - const block = editorState.linkedList.getNode(blockId); + (e: React.FormEvent, block: CRDTBlock) => { if (!block) return; - + let operationNode; const element = e.currentTarget; const newContent = element.textContent || ""; const currentContent = block.crdt.read(); @@ -81,29 +124,26 @@ export const Editor = ({ onTitleChange }: EditorProps) => { const caretPosition = selection?.focusOffset || 0; if (newContent.length > currentContent.length) { - // 텍스트 추가 로직 + let charNode: RemoteCharInsertOperation; if (caretPosition === 0) { const [addedChar] = newContent; - block.crdt.localInsert(0, addedChar); + charNode = block.crdt.localInsert(0, addedChar, block.id, pageId); block.crdt.currentCaret = 1; } else if (caretPosition > currentContent.length) { const addedChar = newContent[newContent.length - 1]; - block.crdt.localInsert(currentContent.length, addedChar); + charNode = block.crdt.localInsert(currentContent.length, addedChar, block.id, pageId); block.crdt.currentCaret = caretPosition; } else { const addedChar = newContent[caretPosition - 1]; - block.crdt.localInsert(caretPosition - 1, addedChar); + charNode = block.crdt.localInsert(caretPosition - 1, addedChar, block.id, pageId); block.crdt.currentCaret = caretPosition; } + sendCharInsertOperation({ node: charNode.node, blockId: block.id, pageId }); } else if (newContent.length < currentContent.length) { - // 텍스트 삭제 로직 - if (caretPosition === 0) { - block.crdt.localDelete(0); - block.crdt.currentCaret = 0; - } else { - block.crdt.localDelete(caretPosition); - block.crdt.currentCaret = caretPosition; - } + // 문자가 삭제된 경우 + operationNode = block.crdt.localDelete(caretPosition, block.id, pageId); + block.crdt.currentCaret = caretPosition; + sendCharDeleteOperation(operationNode); } setEditorState((prev) => ({ @@ -112,22 +152,100 @@ export const Editor = ({ onTitleChange }: EditorProps) => { currentBlock: prev.currentBlock, })); }, - [editorState.linkedList], + [sendCharInsertOperation, sendCharDeleteOperation], ); + const subscriptionRef = useRef(false); + useEffect(() => { - const initialBlock = new CRDTBlock("", new BlockId(0, 0)); - editorCRDT.current.currentBlock = initialBlock; - editorCRDT.current.LinkedList.insertById(initialBlock); + if (subscriptionRef.current) return; + subscriptionRef.current = true; - setEditorState({ - clock: editorCRDT.current.clock, - linkedList: editorCRDT.current.LinkedList, - currentBlock: initialBlock.id, + const unsubscribe = subscribeToRemoteOperations({ + onRemoteBlockInsert: (operation) => { + console.log(operation, "block : 입력 확인합니다이"); + if (!editorCRDT.current) return; + editorCRDT.current.remoteInsert(operation); + setEditorState((prev) => ({ + clock: editorCRDT.current.clock, + linkedList: editorCRDT.current.LinkedList, + currentBlock: prev.currentBlock, + })); + }, + + onRemoteBlockDelete: (operation) => { + console.log(operation, "block : 삭제 확인합니다이"); + if (!editorCRDT.current) return; + editorCRDT.current.remoteDelete(operation); + setEditorState((prev) => ({ + clock: editorCRDT.current.clock, + linkedList: editorCRDT.current.LinkedList, + currentBlock: prev.currentBlock, + })); + }, + + onRemoteCharInsert: (operation) => { + console.log(operation, "char : 입력 확인합니다이"); + if (!editorCRDT.current) return; + const targetBlock = + editorCRDT.current.LinkedList.nodeMap[JSON.stringify(operation.blockId)]; + targetBlock.crdt.remoteInsert(operation); + setEditorState((prev) => ({ + clock: editorCRDT.current.clock, + linkedList: editorCRDT.current.LinkedList, + currentBlock: prev.currentBlock, + })); + }, + + onRemoteCharDelete: (operation) => { + console.log(operation, "char : 삭제 확인합니다이"); + if (!editorCRDT.current) return; + const targetBlock = + editorCRDT.current.LinkedList.nodeMap[JSON.stringify(operation.blockId)]; + targetBlock.crdt.remoteDelete(operation); + setEditorState((prev) => ({ + clock: editorCRDT.current.clock, + linkedList: editorCRDT.current.LinkedList, + currentBlock: prev.currentBlock, + })); + }, + + onRemoteBlockUpdate: (operation) => { + console.log(operation, "block : 업데이트 확인합니다이"); + if (!editorCRDT.current) return; + // ?? + console.log("타입", operation.node); + editorCRDT.current.remoteUpdate(operation.node, operation.pageId); + setEditorState((prev) => ({ + clock: editorCRDT.current.clock, + linkedList: editorCRDT.current.LinkedList, + currentBlock: prev.currentBlock, + })); + }, + onRemoteCursor: (position) => { + console.log(position, "커서위치 수신"); + }, }); + + return () => { + subscriptionRef.current = false; + unsubscribe?.(); + }; }, []); - console.log("block list", editorState.linkedList.spread()); + const tempBlock = () => { + const index = editorCRDT.current.LinkedList.spread().length; + + // 로컬 삽입을 수행하고 연산 객체를 반환받음 + const operation = editorCRDT.current.localInsert(index, ""); + sendBlockInsertOperation({ node: operation.node, pageId }); + console.log("operation clock", operation.node); + setEditorState(() => ({ + clock: operation.node.id.clock, + linkedList: editorCRDT.current.LinkedList, + currentBlock: operation.node.id, + })); + }; return (
@@ -158,6 +276,7 @@ export const Editor = ({ onTitleChange }: EditorProps) => { ))} +
임시
); diff --git a/client/src/features/editor/components/block/Block.animation.ts b/client/src/features/editor/components/block/Block.animation.ts new file mode 100644 index 00000000..c6cd97ff --- /dev/null +++ b/client/src/features/editor/components/block/Block.animation.ts @@ -0,0 +1,26 @@ +const highlight = { + initial: { + background: `linear-gradient(to right, + #BFBFFF95 0%, + #BFBFFF95 0%, + transparent 0%, + transparent 100% + )`, + }, + animate: { + background: `linear-gradient(to right, + #BFBFFF95 0%, + #BFBFFF95 100%, + transparent 100%, + transparent 100% + )`, + transition: { + duration: 1, + ease: "linear", + }, + }, +}; + +export const blockAnimation = { + highlight, +}; diff --git a/client/src/features/editor/components/block/Block.tsx b/client/src/features/editor/components/block/Block.tsx index 4f80085d..ea732375 100644 --- a/client/src/features/editor/components/block/Block.tsx +++ b/client/src/features/editor/components/block/Block.tsx @@ -1,27 +1,31 @@ import { useSortable } from "@dnd-kit/sortable"; import { CSS } from "@dnd-kit/utilities"; -import { BlockCRDT } from "@noctaCrdt/Crdt"; import { Block as CRDTBlock } from "@noctaCrdt/Node"; import { BlockId } from "@noctaCrdt/NodeId"; -import { memo, useRef } from "react"; +import { motion } from "framer-motion"; +import { memo, useRef, useLayoutEffect } from "react"; +import { useBlockAnimation } from "../../hooks/useBlockAnimtaion"; import { IconBlock } from "../IconBlock/IconBlock"; import { MenuBlock } from "../MenuBlock/MenuBlock"; +import { blockAnimation } from "./Block.animation"; import { textContainerStyle, blockContainerStyle, contentWrapperStyle } from "./Block.style"; interface BlockProps { id: string; block: CRDTBlock; isActive: boolean; - onInput: (e: React.FormEvent, blockId: BlockId) => void; + onInput: (e: React.FormEvent, block: CRDTBlock) => void; onKeyDown: (e: React.KeyboardEvent) => void; onClick: (blockId: BlockId, e: React.MouseEvent) => void; } export const Block: React.FC = memo( ({ id, block, isActive, onInput, onKeyDown, onClick }: BlockProps) => { - const textCRDT = useRef(block.crdt); + console.log("블록 초기화 상태", block); const blockRef = useRef(null); + const blockCRDTRef = useRef(block); + const { isAnimationStart } = useBlockAnimation(blockRef); const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id, data: { @@ -31,7 +35,7 @@ export const Block: React.FC = memo( }); const handleInput = (e: React.FormEvent) => { - onInput(e, block.id); + onInput(e, block); }; const setFocusAndCursor = () => { @@ -41,7 +45,11 @@ export const Block: React.FC = memo( const range = document.createRange(); const content = blockRef.current.firstChild || blockRef.current.appendChild(document.createTextNode("")); - const position = Math.min(textCRDT.current.currentCaret, content.textContent?.length || 0); + // const position = Math.min(block.crdt.currentCaret, content.textContent?.length || 0); + const position = Math.min( + blockCRDTRef.current.crdt.currentCaret, + content.textContent?.length || 0, + ); range.setStart(content, position); range.collapse(true); selection.removeAllRanges(); @@ -49,15 +57,16 @@ export const Block: React.FC = memo( } }; - requestAnimationFrame(() => { + useLayoutEffect(() => { // ✅ 추가 setFocusAndCursor(); - }); + // block.crdt.currentCaret + }, [isActive, blockCRDTRef.current.crdt.currentCaret]); return ( // TODO: eslint 규칙을 수정해야 할까? // TODO: ol일때 index 순서 처리 -
= memo( transition, opacity: isDragging ? 0.5 : 1, }} - data-group // indent에 따른 마진 + initial={block?.animation && blockAnimation.highlight.initial} + animate={isAnimationStart && block?.animation && blockAnimation.highlight.animate} + data-group > -
+
= memo( type: block.type, })} > - {block.crdt.read()} + {blockCRDTRef.current.crdt.read()}
-
-
+ + ); - - // return React.createElement(nodeType, commonProps); }, ); diff --git a/client/src/features/editor/hooks/useBlockAnimtaion.ts b/client/src/features/editor/hooks/useBlockAnimtaion.ts new file mode 100644 index 00000000..b89ea8e5 --- /dev/null +++ b/client/src/features/editor/hooks/useBlockAnimtaion.ts @@ -0,0 +1,33 @@ +import { useEffect, useState } from "react"; + +export const useBlockAnimation = (blockRef: React.RefObject) => { + const [isAnimationStart, setIsAnimationStart] = useState(false); + + useEffect(() => { + const observer = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + setIsAnimationStart(true); + observer.unobserve(entry.target); + } + }); + }, + { + threshold: 0.1, + }, + ); + + if (blockRef.current) { + observer.observe(blockRef.current); + } + + return () => { + if (blockRef.current) { + observer.unobserve(blockRef.current); + } + }; + }, []); + + return { isAnimationStart }; +}; diff --git a/client/src/features/editor/hooks/useMarkdownGrammer.ts b/client/src/features/editor/hooks/useMarkdownGrammer.ts index 8dd76c75..13604942 100644 --- a/client/src/features/editor/hooks/useMarkdownGrammer.ts +++ b/client/src/features/editor/hooks/useMarkdownGrammer.ts @@ -1,6 +1,12 @@ import { EditorCRDT, BlockCRDT } from "@noctaCrdt/Crdt"; +import { + RemoteBlockInsertOperation, + RemoteBlockDeleteOperation, + RemoteBlockUpdateOperation, + RemoteCharInsertOperation, + RemoteCharDeleteOperation, +} from "@noctaCrdt/Interfaces"; import { BlockLinkedList } from "@noctaCrdt/LinkedList"; -import { Block } from "@noctaCrdt/Node"; import { BlockId } from "@noctaCrdt/NodeId"; import { useCallback } from "react"; import { EditorStateProps } from "@features/editor/Editor"; @@ -16,19 +22,33 @@ interface useMarkdownGrammerProps { currentBlock: BlockId | null; }> >; + pageId: string; + sendBlockInsertOperation: (operation: RemoteBlockInsertOperation) => void; + sendBlockDeleteOperation: (operation: RemoteBlockDeleteOperation) => void; + sendCharDeleteOperation: (operation: RemoteCharDeleteOperation) => void; + sendCharInsertOperation: (operation: RemoteCharInsertOperation) => void; + sendBlockUpdateOperation: (operation: RemoteBlockUpdateOperation) => void; } + export const useMarkdownGrammer = ({ editorCRDT, editorState, setEditorState, + pageId, + sendBlockInsertOperation, + sendBlockDeleteOperation, + sendCharDeleteOperation, + sendCharInsertOperation, + sendBlockUpdateOperation, }: useMarkdownGrammerProps) => { const handleKeyDown = useCallback( (e: React.KeyboardEvent) => { - const createNewBlock = (index: number): Block => { - const { node: newBlock } = editorCRDT.localInsert(index, ""); + const createNewBlock = (index: number): RemoteBlockInsertOperation => { + console.log("createNewBlock"); + const operation = editorCRDT.localInsert(index, ""); // TODO: 블록 타입이 초기화가 안됨??? - (newBlock as Block).type = "p"; - return newBlock as Block; + operation.node.type = "p"; + return operation; }; const updateEditorState = (newBlockId: BlockId | null = null) => { @@ -58,16 +78,22 @@ export const useMarkdownGrammer = ({ if (!currentContent && currentBlock.type !== "p") { currentBlock.type = "p"; + // TODO: Update요청 + // remote update 보내기 + sendBlockUpdateOperation({ node: currentBlock, pageId }); updateEditorState(); break; } if (!currentContent && currentBlock.type === "p") { // 새로운 기본 블록 생성 - const newBlock = createNewBlock(currentIndex + 1); - newBlock.indent = currentBlock.indent; - newBlock.crdt = new BlockCRDT(editorCRDT.client); - updateEditorState(newBlock.id); + const operation = createNewBlock(currentIndex + 1); + operation.node.indent = currentBlock.indent; + operation.node.crdt = new BlockCRDT(editorCRDT.client); + + sendBlockInsertOperation({ node: operation.node, pageId }); + + updateEditorState(operation.node.id); break; } @@ -75,26 +101,37 @@ export const useMarkdownGrammer = ({ if (afterText) { // 캐럿 이후의 텍스트만 제거 for (let i = currentContent.length - 1; i >= caretPosition; i--) { - currentBlock.crdt.localDelete(i); + // char remote delete 보내기 + // currentBlock.crdt.localDelete(i, currentBlock.id); + sendCharDeleteOperation(currentBlock.crdt.localDelete(i, currentBlock.id, pageId)); } } // 새 블록 생성 - const newBlock = createNewBlock(currentIndex + 1); - newBlock.crdt = new BlockCRDT(editorCRDT.client); - newBlock.indent = currentBlock.indent; + const operation = createNewBlock(currentIndex + 1); + operation.node.crdt = new BlockCRDT(editorCRDT.client); + operation.node.indent = currentBlock.indent; + sendBlockInsertOperation({ node: operation.node, pageId }); // 캐럿 이후의 텍스트 있으면 새 블록에 추가 if (afterText) { afterText.split("").forEach((char, i) => { - newBlock.crdt.localInsert(i, char); + // char remote insert 보내기 + // newBlock.crdt.localInsert(i, char, newBlock.id); + sendCharInsertOperation( + operation.node.crdt.localInsert(i, char, operation.node.id, pageId), + ); }); } // 현재 블록이 li나 checkbox면 동일한 타입으로 생성 if (["ul", "ol", "checkbox"].includes(currentBlock.type)) { - newBlock.type = currentBlock.type; + operation.node.type = currentBlock.type; + // TODO: Update요청 + // remote update 보내기 + sendBlockUpdateOperation({ node: operation.node, pageId }); } - updateEditorState(newBlock.id); + // !! TODO socket.update + updateEditorState(operation.node.id); break; } @@ -104,6 +141,9 @@ export const useMarkdownGrammer = ({ e.preventDefault(); if (currentBlock.indent > 0) { currentBlock.indent -= 1; + // TODO: Update요청 + // remote update 보내기 + sendBlockUpdateOperation({ node: currentBlock, pageId }); updateEditorState(); break; } @@ -111,6 +151,9 @@ export const useMarkdownGrammer = ({ if (currentBlock.type !== "p") { // 마지막 블록이면 기본 블록으로 변경 currentBlock.type = "p"; + // TODO: Update요청 + // remote update 보내기 + sendBlockUpdateOperation({ node: currentBlock, pageId }); updateEditorState(); break; } @@ -118,7 +161,9 @@ export const useMarkdownGrammer = ({ const prevBlock = currentIndex > 0 ? editorCRDT.LinkedList.findByIndex(currentIndex - 1) : null; if (prevBlock) { - editorCRDT.localDelete(currentIndex); + // remote delete 보내기 + // editorCRDT.localDelete(currentIndex, undefined, pageId); + sendBlockDeleteOperation(editorCRDT.localDelete(currentIndex, undefined, pageId)); prevBlock.crdt.currentCaret = prevBlock.crdt.read().length; editorCRDT.currentBlock = prevBlock; updateEditorState(prevBlock.id); @@ -129,11 +174,17 @@ export const useMarkdownGrammer = ({ if (currentCaret === 0) { if (currentBlock.indent > 0) { currentBlock.indent -= 1; + // TODO: Update요청 + // remote update 보내기 + sendBlockUpdateOperation({ node: currentBlock, pageId }); updateEditorState(); break; } if (currentBlock.type !== "p") { currentBlock.type = "p"; + // TODO: Update요청 + // remote update 보내기 + sendBlockUpdateOperation({ node: currentBlock, pageId }); updateEditorState(); // FIX: 서윤님 피드백 반영 } else { @@ -142,10 +193,24 @@ export const useMarkdownGrammer = ({ if (prevBlock) { const prevBlockEndCaret = prevBlock.crdt.read().length; currentContent.split("").forEach((char) => { - prevBlock.crdt.localInsert(prevBlock.crdt.read().length, char); + // char remote insert 보내기 + // prevBlock.crdt.localInsert(prevBlock.crdt.read().length, char, prevBlock.id); + sendCharInsertOperation( + prevBlock.crdt.localInsert( + prevBlock.crdt.read().length, + char, + prevBlock.id, + pageId, + ), + ); + sendCharDeleteOperation( + currentBlock.crdt.localDelete(currentCaret, currentBlock.id, pageId), + ); }); prevBlock.crdt.currentCaret = prevBlockEndCaret; - editorCRDT.localDelete(currentIndex); + // remote delete 보내기 + // editorCRDT.localDelete(currentIndex, undefined, pageId); + sendBlockDeleteOperation(editorCRDT.localDelete(currentIndex, undefined, pageId)); updateEditorState(prevBlock.id); e.preventDefault(); } @@ -163,6 +228,9 @@ export const useMarkdownGrammer = ({ // shift + tab: 들여쓰기 감소 if (currentBlock.indent > 0) { currentBlock.indent -= 1; + // TODO: Update요청 + // remote update 보내기 + sendBlockUpdateOperation({ node: currentBlock, pageId }); updateEditorState(currentBlock.id); } } else { @@ -171,6 +239,9 @@ export const useMarkdownGrammer = ({ const maxIndent = 3; if (currentBlock.indent < maxIndent) { currentBlock.indent += 1; + // TODO: Update요청 + // remote update 보내기 + sendBlockUpdateOperation({ node: currentBlock, pageId }); updateEditorState(currentBlock.id); } } @@ -187,12 +258,19 @@ export const useMarkdownGrammer = ({ currentBlock.type = markdownElement.type; let deleteCount = 0; while (deleteCount < markdownElement.length) { - currentBlock.crdt.localDelete(0); + // char remote delete 보내기 + // currentBlock.crdt.localDelete(0, currentBlock.id); + sendCharDeleteOperation(currentBlock.crdt.localDelete(0, currentBlock.id, pageId)); deleteCount += 1; } + // TODO: Update요청 + // remote update 보내기 + sendBlockUpdateOperation({ node: currentBlock, pageId }); + // !!TODO emit 송신 currentBlock.crdt.currentCaret = 0; updateEditorState(currentBlock.id); } + break; } @@ -223,13 +301,13 @@ export const useMarkdownGrammer = ({ const { currentCaret } = currentBlock.crdt; const textLength = currentBlock.crdt.read().length; if (e.key === "ArrowLeft" && currentCaret > 0) { - currentBlock.crdt.currentCaret = currentCaret - 1; - updateEditorState(); + // currentBlock.crdt.currentCaret = currentCaret - 1; + currentBlock.crdt.currentCaret -= 1; break; } if (e.key === "ArrowRight" && currentCaret < textLength) { - currentBlock.crdt.currentCaret = currentCaret + 1; - updateEditorState(); + // currentBlock.crdt.currentCaret = currentCaret + 1; + currentBlock.crdt.currentCaret += 1; break; } if (e.key === "ArrowLeft" && currentCaret === 0 && currentIndex > 0) { @@ -252,7 +330,7 @@ export const useMarkdownGrammer = ({ } } }, - [editorCRDT, editorState, setEditorState], + [editorCRDT, editorState, setEditorState, pageId], ); return { handleKeyDown }; diff --git a/client/src/features/page/Page.tsx b/client/src/features/page/Page.tsx index 74272e7b..23bf3d15 100644 --- a/client/src/features/page/Page.tsx +++ b/client/src/features/page/Page.tsx @@ -1,3 +1,4 @@ +import { serializedEditorDataProps } from "@noctaCrdt/Interfaces"; import { motion, AnimatePresence } from "framer-motion"; import { Editor } from "@features/editor/Editor"; import { Page as PageType } from "@src/types/page"; @@ -9,9 +10,10 @@ import { PageTitle } from "./components/PageTitle/PageTitle"; import { usePage } from "./hooks/usePage"; interface PageProps extends PageType { - handlePageSelect: ({ pageId, isSidebar }: { pageId: number; isSidebar?: boolean }) => void; - handlePageClose: (pageId: number) => void; - handleTitleChange: (pageId: number, newTitle: string) => void; + handlePageSelect: ({ pageId, isSidebar }: { pageId: string; isSidebar?: boolean }) => void; + handlePageClose: (pageId: string) => void; + handleTitleChange: (pageId: string, newTitle: string) => void; + serializedEditorData: serializedEditorDataProps; } export const Page = ({ @@ -24,13 +26,23 @@ export const Page = ({ handlePageSelect, handlePageClose, handleTitleChange, + serializedEditorData, }: PageProps) => { const { position, size, pageDrag, pageResize, pageMinimize, pageMaximize } = usePage({ x, y }); + // TODO: workspace에서 pageId, editorCRDT props로 받아와야 함 + // const {} = useSocket(); + const onTitleChange = (newTitle: string) => { handleTitleChange(id, newTitle); }; + const handlePageClick = () => { + if (!isActive) { + handlePageSelect({ pageId: id }); + } + }; + return ( - handlePageSelect({ - pageId: id, - }) - } + onPointerDown={handlePageClick} > -
+
handlePageClose(id)} @@ -60,7 +68,11 @@ export const Page = ({ onPageMinimize={pageMinimize} />
- + { + const [workspace, setWorkspace] = useState(null); const { isLoading, isInitialized, error } = useWorkspaceInit(); + const { workspace: workspaceMetadata, clientId } = useSocketStore(); - const { pages, addPage, selectPage, closePage, updatePageTitle } = usePagesManage(); + const { pages, fetchPage, selectPage, closePage, updatePageTitle, initPages, initPagePosition } = + usePagesManage(workspace, clientId); const visiblePages = pages.filter((page) => page.isVisible); + useEffect(() => { + if (workspaceMetadata) { + const newWorkspace = new WorkSpaceClass(workspaceMetadata.id, workspaceMetadata.pageList); + newWorkspace.deserialize(workspaceMetadata); + setWorkspace(newWorkspace); + + initPages(newWorkspace.pageList); + initPagePosition(); + } + }, [workspaceMetadata]); + + // 에러화면 if (error) { - return ; + return ; } + // 0. 몽고 다 제거 + // 1. 클라이언트 연결하고 tempblock으로 클라이언트 블럭 생성한다. + // 2. 클라이언트를 새로고침한다 + // 3. 추가된 블럭의 콘솔로그 정보를 본다. + // 4. 클라이언트 인스턴스의 clock정보를 본다. + // 정상화면 return ( <> {isLoading && } @@ -26,7 +50,7 @@ export const WorkSpace = () => { opacity: isInitialized && !isLoading ? 1 : 0, })} > - +
{visiblePages.map((page) => ( { +export const usePagesManage = (workspace: WorkSpace | null, clientId: number | null) => { const [pages, setPages] = useState([]); + const { subscribeToPageOperations, sendPageCreateOperation } = useSocketStore(); + const subscriptionRef = useRef(false); + useEffect(() => { + if (!workspace) return; + if (subscriptionRef.current) return; + subscriptionRef.current = true; + + const unsubscribe = subscribeToPageOperations({ + onRemotePageCreate: (operation) => { + console.log(operation, "page : 생성 확인합니다이"); + const newPage = workspace.remotePageCreate({ + page: operation.page!, + workspaceId: operation.workspaceId, + clientId: operation.clientId, + }); + addPage(newPage); + }, + }); + + return () => { + subscriptionRef.current = false; + unsubscribe?.(); + }; + }, [workspace, pages]); const getZIndex = () => { return Math.max(0, ...pages.map((page) => page.zIndex)) + 1; }; - const addPage = () => { - const newPageIndex = pages.length; + const fetchPage = () => { + const operation = { + workspaceId: workspace!.id!, + clientId: clientId!, + }; + sendPageCreateOperation(operation); + }; + const addPage = (newPage: CRDTPage) => { + const newPageIndex = pages.length; + const serializedEditorData = newPage.crdt.serialize(); setPages((prevPages) => [ ...prevPages.map((page) => ({ ...page, isActive: false })), { - id: newPageIndex, - title: `Page ${newPageIndex + 1}`, - icon: INIT_ICON, + id: newPage.id, // 여기 + title: newPage.title, + icon: newPage.icon || INIT_ICON, x: PAGE_OFFSET * newPageIndex, y: PAGE_OFFSET * newPageIndex, zIndex: getZIndex(), isActive: true, isVisible: true, - }, + serializedEditorData, + } as Page, ]); }; - const selectPage = ({ pageId }: { pageId: number }) => { + const selectPage = ({ pageId }: { pageId: string }) => { setPages((prevPages) => prevPages.map((page) => ({ ...page, @@ -42,13 +78,13 @@ export const usePagesManage = () => { ); }; - const closePage = (pageId: number) => { + const closePage = (pageId: string) => { setPages((prevPages) => prevPages.map((page) => (page.id === pageId ? { ...page, isVisible: false } : page)), ); }; - const updatePageTitle = (pageId: number, newTitle: string) => { + const updatePageTitle = (pageId: string, newTitle: string) => { setPages((prevPages) => prevPages.map((page) => (page.id === pageId ? { ...page, title: newTitle } : page)), ); @@ -65,15 +101,36 @@ export const usePagesManage = () => { ); }; + const initPages = (list: CRDTPage[]) => { + const pageList: Page[] = list.map( + (crdtPage, index) => + ({ + id: crdtPage.id, + title: crdtPage.title, + icon: crdtPage.icon || INIT_ICON, + x: PAGE_OFFSET * index, + y: PAGE_OFFSET * index, + zIndex: index, + isActive: index === 0, // 첫 번째 페이지를 활성화 + isVisible: false, + serializedEditorData: crdtPage.crdt.serialize(), + }) as Page, + ); + setPages(pageList); + }; + useEffect(() => { + initPages([]); initPagePosition(); }, []); return { pages, - addPage, + fetchPage, selectPage, closePage, updatePageTitle, + initPages, + initPagePosition, }; }; diff --git a/client/src/features/workSpace/hooks/useWorkspaceInit.ts b/client/src/features/workSpace/hooks/useWorkspaceInit.ts index f8f59324..e8d945c3 100644 --- a/client/src/features/workSpace/hooks/useWorkspaceInit.ts +++ b/client/src/features/workSpace/hooks/useWorkspaceInit.ts @@ -1,4 +1,5 @@ import { useState, useEffect } from "react"; +import { useSocketStore } from "@src/stores/useSocketStore"; interface UseWorkspaceInitReturn { isLoading: boolean; @@ -10,6 +11,7 @@ export const useWorkspaceInit = (): UseWorkspaceInitReturn => { const [isLoading, setIsLoading] = useState(true); const [isInitialized, setIsInitialized] = useState(false); const [error, setError] = useState(null); + const { socket } = useSocketStore(); useEffect(() => { const initializeWorkspace = async () => { @@ -21,7 +23,6 @@ export const useWorkspaceInit = (): UseWorkspaceInitReturn => { // fetchInitialPages(), // fetchWorkspaceData(), // ]); - // 개발 중에는 임시로 딜레이를 줘서 스플래시 화면 확인 await new Promise((resolve) => setTimeout(resolve, 2000)); @@ -37,7 +38,7 @@ export const useWorkspaceInit = (): UseWorkspaceInitReturn => { }; initializeWorkspace(); - }, []); + }, [socket]); return { isLoading, isInitialized, error }; }; diff --git a/client/src/main.tsx b/client/src/main.tsx index 7779dc0b..379d1a42 100644 --- a/client/src/main.tsx +++ b/client/src/main.tsx @@ -1,13 +1,9 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; -import axios from "axios"; import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import "./index.css"; import App from "./App.tsx"; -axios.defaults.baseURL = import.meta.env.VITE_API_URL; -axios.defaults.withCredentials = true; - const queryClient = new QueryClient({ defaultOptions: { queries: { diff --git a/client/src/stores/useErrorStore.ts b/client/src/stores/useErrorStore.ts new file mode 100644 index 00000000..9a73efd3 --- /dev/null +++ b/client/src/stores/useErrorStore.ts @@ -0,0 +1,13 @@ +import { create } from "zustand"; + +interface ErrorStore { + isErrorModalOpen: boolean; + errorMessage: string; + setErrorModal: (isOpen: boolean, message?: string) => void; +} + +export const useErrorStore = create((set) => ({ + isErrorModalOpen: false, + errorMessage: "", + setErrorModal: (isOpen, message = "") => set({ isErrorModalOpen: isOpen, errorMessage: message }), +})); diff --git a/client/src/stores/useSocketStore.ts b/client/src/stores/useSocketStore.ts new file mode 100644 index 00000000..b0f28a8f --- /dev/null +++ b/client/src/stores/useSocketStore.ts @@ -0,0 +1,178 @@ +import { + RemotePageCreateOperation, + RemoteBlockInsertOperation, + RemoteBlockDeleteOperation, + RemoteCharInsertOperation, + RemoteCharDeleteOperation, + RemoteBlockUpdateOperation, + CursorPosition, + WorkSpaceSerializedProps, +} from "@noctaCrdt/Interfaces"; +import { io, Socket } from "socket.io-client"; +import { create } from "zustand"; + +interface SocketStore { + socket: Socket | null; + clientId: number | null; + workspace: WorkSpaceSerializedProps | null; + init: () => void; + cleanup: () => void; + fetchWorkspaceData: () => WorkSpaceSerializedProps | null; + sendPageCreateOperation: (operation: RemotePageCreateOperation) => void; + sendBlockUpdateOperation: (operation: RemoteBlockUpdateOperation) => void; + sendBlockInsertOperation: (operation: RemoteBlockInsertOperation) => void; + sendCharInsertOperation: (operation: RemoteCharInsertOperation) => void; + sendBlockDeleteOperation: (operation: RemoteBlockDeleteOperation) => void; + sendCharDeleteOperation: (operation: RemoteCharDeleteOperation) => void; + sendCursorPosition: (position: CursorPosition) => void; + subscribeToRemoteOperations: (handlers: RemoteOperationHandlers) => (() => void) | undefined; + subscribeToPageOperations: (handlers: PageOperationsHandlers) => (() => void) | undefined; + setWorkspace: (workspace: WorkSpaceSerializedProps) => void; +} + +interface RemoteOperationHandlers { + onRemoteBlockUpdate: (operation: RemoteBlockUpdateOperation) => void; + onRemoteBlockInsert: (operation: RemoteBlockInsertOperation) => void; + onRemoteBlockDelete: (operation: RemoteBlockDeleteOperation) => void; + onRemoteCharInsert: (operation: RemoteCharInsertOperation) => void; + onRemoteCharDelete: (operation: RemoteCharDeleteOperation) => void; + onRemoteCursor: (position: CursorPosition) => void; +} + +interface PageOperationsHandlers { + onRemotePageCreate: (operation: RemotePageCreateOperation) => void; +} + +export const useSocketStore = create((set, get) => ({ + socket: null, + clientId: null, + workspace: null, + + init: () => { + const { socket: existingSocket } = get(); + if (existingSocket?.connected) return; + + if (existingSocket) { + existingSocket.disconnect(); + } + + const SERVER_URL = + process.env.NODE_ENV === "development" ? "http://localhost:3000" : "https://api.nocta.site"; + + const socket = io(SERVER_URL, { + path: "/api/socket.io", + transports: ["websocket", "polling"], + withCredentials: true, + reconnectionAttempts: 5, + reconnectionDelay: 1000, + autoConnect: false, + }); + + socket.on("assign/clientId", (clientId: number) => { + console.log("Assigned client ID:", clientId); + set({ clientId }); + }); + + socket.on("workspace", (workspace: WorkSpaceSerializedProps) => { + console.log("Received initial workspace state:", workspace); + set({ workspace }); + }); + + socket.on("connect", () => { + console.log("Connected to server"); + set({ socket }); + }); + + socket.on("disconnect", () => { + console.log("Disconnected from server"); + }); + + socket.on("error", (error: Error) => { + console.error("Socket error:", error); + }); + + socket.connect(); + }, + + cleanup: () => { + const { socket } = get(); + if (socket) { + socket.removeAllListeners(); + socket.disconnect(); + set({ socket: null, workspace: null, clientId: null }); + } + }, + + fetchWorkspaceData: () => get().workspace, + + setWorkspace: (workspace: WorkSpaceSerializedProps) => set({ workspace }), + + sendPageCreateOperation: (operation: RemotePageCreateOperation) => { + const { socket } = get(); + socket?.emit("create/page", operation); + console.log("페이지 만들기 송신", operation); + }, + + sendBlockInsertOperation: (operation: RemoteBlockInsertOperation) => { + const { socket } = get(); + console.log("block insert operation", operation); + console.log("socket", socket); + socket?.emit("insert/block", operation); + }, + + sendCharInsertOperation: (operation: RemoteCharInsertOperation) => { + const { socket } = get(); + console.log("char insert operation", operation); + socket?.emit("insert/char", operation); + }, + + sendBlockUpdateOperation: (operation: RemoteBlockUpdateOperation) => { + const { socket } = get(); + socket?.emit("update/block", operation); + }, + + sendBlockDeleteOperation: (operation: RemoteBlockDeleteOperation) => { + const { socket } = get(); + socket?.emit("delete/block", operation); + }, + + sendCharDeleteOperation: (operation: RemoteCharDeleteOperation) => { + const { socket } = get(); + socket?.emit("delete/char", operation); + }, + + sendCursorPosition: (position: CursorPosition) => { + const { socket } = get(); + socket?.emit("cursor", position); + }, + + subscribeToRemoteOperations: (handlers: RemoteOperationHandlers) => { + const { socket } = get(); + if (!socket) return; + + socket.on("update/block", handlers.onRemoteBlockUpdate); + socket.on("insert/block", handlers.onRemoteBlockInsert); + socket.on("delete/block", handlers.onRemoteBlockDelete); + socket.on("insert/char", handlers.onRemoteCharInsert); + socket.on("delete/char", handlers.onRemoteCharDelete); + socket.on("cursor", handlers.onRemoteCursor); + + return () => { + socket.off("update/block", handlers.onRemoteBlockUpdate); + socket.off("insert/block", handlers.onRemoteBlockInsert); + socket.off("delete/block", handlers.onRemoteBlockDelete); + socket.off("insert/char", handlers.onRemoteCharInsert); + socket.off("delete/char", handlers.onRemoteCharDelete); + socket.off("cursor", handlers.onRemoteCursor); + }; + }, + + subscribeToPageOperations: (handlers: PageOperationsHandlers) => { + const { socket } = get(); + if (!socket) return; + socket.on("create/page", handlers.onRemotePageCreate); + return () => { + socket.off("create/page", handlers.onRemotePageCreate); + }; + }, +})); diff --git a/client/src/stores/useUserStore.ts b/client/src/stores/useUserStore.ts new file mode 100644 index 00000000..b50f0853 --- /dev/null +++ b/client/src/stores/useUserStore.ts @@ -0,0 +1,72 @@ +import { create } from "zustand"; +import { persist, createJSONStorage } from "zustand/middleware"; +import { useShallow } from "zustand/shallow"; + +interface UserStore { + id: string | null; + name: string | null; + accessToken: string | null; + actions: { + setUserInfo: (id: string, name: string, accessToken: string) => void; + removeUserInfo: () => void; + getUserInfo: () => { id: string | null; name: string | null; accessToken: string | null }; + updateAccessToken: (accessToken: string) => void; + checkAuth: () => boolean; + }; +} + +export const useUserStore = create()( + persist( + (set, get) => ({ + id: null, + name: null, + accessToken: null, + actions: { + setUserInfo: (id: string, name: string, accessToken: string) => + set(() => ({ id, name, accessToken })), + removeUserInfo: () => { + set(() => ({ id: null, name: null, accessToken: null })); + sessionStorage.removeItem("nocta-storage"); + }, + getUserInfo: () => { + const state = get(); + return { + id: state.id, + name: state.name, + accessToken: state.accessToken, + }; + }, + updateAccessToken: (accessToken: string) => set(() => ({ accessToken })), + checkAuth: () => { + const state = get(); + return !!(state.id && state.name && state.accessToken); + }, + }, + }), + { + name: "nocta-storage", + storage: createJSONStorage(() => sessionStorage), + partialize: (state) => ({ + id: state.id, + name: state.name, + }), + }, + ), +); + +// store 값을 변경하는 부분. 주로 api 코드에서 사용 +export const useUserActions = () => useUserStore((state) => state.actions); + +// store 값을 사용하는 부분. 주로 component 내부에서 사용 +export const useUserInfo = () => + useUserStore( + // state 바뀜에 따라 재렌더링 되도록 + useShallow((state) => ({ + id: state.id, + name: state.name, + accessToken: state.accessToken, + })), + ); + +export const useCheckLogin = () => + useUserStore((state) => !!(state.id && state.name && state.accessToken)); diff --git a/client/src/types/page.ts b/client/src/types/page.ts index ae84baa9..deb72a6b 100644 --- a/client/src/types/page.ts +++ b/client/src/types/page.ts @@ -1,5 +1,7 @@ +import { serializedEditorDataProps } from "@noctaCrdt/Interfaces"; + export interface Page { - id: number; + id: string; title: string; icon: string; x: number; @@ -7,6 +9,7 @@ export interface Page { zIndex: number; isActive: boolean; isVisible: boolean; + serializedEditorData: serializedEditorDataProps; } export interface Position { diff --git a/client/tsconfig.json b/client/tsconfig.json index 1ed5bc84..35c75b46 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -28,6 +28,8 @@ "@constants/*": ["src/constants/*"], "@hooks/*": ["src/hooks/*"], "@utils/*": ["src/utils/*"], + "@apis/*": ["src/apis/*"], + "@stores/*": ["src/stores/*"], "@noctaCrdt": ["../@noctaCrdt/dist"], "@noctaCrdt/*": ["../@noctaCrdt/dist/*"] } diff --git a/client/tsconfig.tsbuildinfo b/client/tsconfig.tsbuildinfo index a6cde961..16a1b130 100644 --- a/client/tsconfig.tsbuildinfo +++ b/client/tsconfig.tsbuildinfo @@ -1 +1 @@ -{"program":{"fileNames":["../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es5.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2016.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.dom.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.dom.iterable.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.core.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.date.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.object.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.string.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.intl.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.intl.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.promise.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.array.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.object.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.string.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.intl.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.date.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.promise.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.string.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.intl.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.number.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.decorators.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../node_modules/.pnpm/@types+react@18.3.12/node_modules/@types/react/global.d.ts","../node_modules/.pnpm/csstype@3.1.3/node_modules/csstype/index.d.ts","../node_modules/.pnpm/@types+prop-types@15.7.13/node_modules/@types/prop-types/index.d.ts","../node_modules/.pnpm/@types+react@18.3.12/node_modules/@types/react/index.d.ts","../node_modules/.pnpm/@types+react@18.3.12/node_modules/@types/react/jsx-runtime.d.ts","../node_modules/.pnpm/framer-motion@11.11.13_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/framer-motion/dist/index.d.ts","../node_modules/.pnpm/mlly@1.7.2/node_modules/mlly/dist/index.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/typescript.d.ts","../node_modules/.pnpm/pkg-types@1.0.3/node_modules/pkg-types/dist/index.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/csstype.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/selectors.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/conditions.d.ts","../node_modules/.pnpm/microdiff@1.3.2/node_modules/microdiff/dist/index.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/artifact.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/static-css.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/prop-type.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/style-props.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/system-types.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/recipe.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/style-rules.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/hooks-api.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/logger.d.ts","../node_modules/.pnpm/@ts-morph+common@0.22.0/node_modules/@ts-morph/common/lib/typescript.d.ts","../node_modules/.pnpm/@ts-morph+common@0.22.0/node_modules/@ts-morph/common/lib/ts-morph-common.d.ts","../node_modules/.pnpm/ts-morph@21.0.1/node_modules/ts-morph/lib/ts-morph.d.ts","../node_modules/.pnpm/ts-evaluator@1.2.0_typescript@5.3.3/node_modules/ts-evaluator/dist/esm/index.d.ts","../node_modules/.pnpm/@pandacss+extractor@0.40.1_typescript@5.3.3/node_modules/@pandacss/extractor/dist/index.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/parser.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/hooks.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/shared.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/tokens.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/pattern.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/composition.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/theme.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/utility.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/config.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/analyze-report.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/parts.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/runtime.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/index.d.ts","../node_modules/.pnpm/@pandacss+dev@0.47.1_typescript@5.3.3/node_modules/@pandacss/dev/dist/index.d.ts","./styled-system/types/static-css.d.ts","./styled-system/types/csstype.d.ts","./styled-system/types/selectors.d.ts","./styled-system/types/conditions.d.ts","./styled-system/tokens/tokens.d.ts","./styled-system/tokens/index.d.ts","./styled-system/types/prop-type.d.ts","./styled-system/types/style-props.d.ts","./styled-system/types/system-types.d.ts","./styled-system/types/recipe.d.ts","./styled-system/types/parts.d.ts","./styled-system/types/pattern.d.ts","./styled-system/types/composition.d.ts","./styled-system/types/global.d.ts","./styled-system/types/index.d.ts","./styled-system/css/css.d.ts","./styled-system/css/cx.d.ts","./styled-system/css/cva.d.ts","./styled-system/css/sva.d.ts","./styled-system/css/index.d.ts","./src/components/button/iconbutton.style.ts","./src/components/button/iconbutton.tsx","./src/types/page.ts","./src/components/bottomnavigator/bottomnavigator.animation.ts","./styled-system/recipes/glass-container.d.ts","./styled-system/recipes/index.d.ts","./src/components/bottomnavigator/bottomnavigator.style.ts","./src/components/bottomnavigator/bottomnavigator.tsx","../node_modules/.pnpm/@types+react-dom@18.3.1/node_modules/@types/react-dom/index.d.ts","./src/components/button/textbutton.style.ts","./src/components/button/textbutton.tsx","./src/components/modal/modal.animation.ts","./src/components/modal/modal.style.ts","./src/components/modal/modal.tsx","./src/components/modal/usemodal.ts","./src/constants/page.ts","../node_modules/.pnpm/zustand@5.0.1_@types+react@18.3.12_react@18.3.1/node_modules/zustand/esm/vanilla.d.mts","../node_modules/.pnpm/zustand@5.0.1_@types+react@18.3.12_react@18.3.1/node_modules/zustand/esm/react.d.mts","../node_modules/.pnpm/zustand@5.0.1_@types+react@18.3.12_react@18.3.1/node_modules/zustand/esm/index.d.mts","./src/stores/usesidebarstore.ts","./src/components/inputfield/inputfield.style.ts","./src/components/inputfield/inputfield.tsx","./src/features/auth/authmodal.style.ts","./src/features/auth/authmodal.tsx","./src/components/sidebar/menubutton.style.ts","./src/components/sidebar/menubutton.tsx","./src/components/sidebar/pageitem.style.ts","./src/components/sidebar/pageitem.tsx","./src/constants/size.ts","./src/components/sidebar/sidebar.animation.ts","./src/components/sidebar/sidebar.style.ts","./src/components/sidebar/sidebar.tsx","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/hooks/usecombinedrefs.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/hooks/useevent.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/hooks/useisomorphiclayouteffect.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/hooks/useinterval.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/hooks/uselatestvalue.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/hooks/uselazymemo.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/hooks/usenoderef.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/hooks/useprevious.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/hooks/useuniqueid.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/hooks/index.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/adjustment.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/coordinates/types.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/coordinates/geteventcoordinates.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/coordinates/index.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/css.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/event/hasviewportrelativecoordinates.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/event/iskeyboardevent.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/event/istouchevent.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/event/index.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/execution-context/canusedom.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/execution-context/getownerdocument.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/execution-context/getwindow.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/execution-context/index.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/focus/findfirstfocusablenode.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/focus/index.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/type-guards/isdocument.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/type-guards/ishtmlelement.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/type-guards/isnode.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/type-guards/issvgelement.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/type-guards/iswindow.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/type-guards/index.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/types.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/types/coordinates.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/types/direction.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/algorithms/types.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/algorithms/closestcenter.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/algorithms/closestcorners.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/algorithms/rectintersection.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/algorithms/pointerwithin.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/algorithms/helpers.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/algorithms/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/types/events.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/types/other.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/types/react.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/types/rect.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/types/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/useautoscroller.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/usecachednode.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/types.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/usesensor.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/usesensors.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/pointer/abstractpointersensor.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/pointer/pointersensor.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/pointer/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/mouse/mousesensor.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/mouse/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/touch/touchsensor.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/touch/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/keyboard/types.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/keyboard/keyboardsensor.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/keyboard/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/usesyntheticlisteners.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/usecombineactivators.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/usedroppablemeasuring.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/useinitialvalue.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/useinitialrect.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/userect.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/userectdelta.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/useresizeobserver.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/usescrollableancestors.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/usescrollintoviewifneeded.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/usescrolloffsets.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/usescrolloffsetsdelta.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/usesensorsetup.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/userects.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/usewindowrect.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/usedragoverlaymeasuring.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/store/constructors.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/store/types.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/store/actions.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/store/context.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/store/reducer.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/store/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/accessibility/types.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/accessibility/accessibility.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/accessibility/components/restorefocus.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/accessibility/components/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/accessibility/defaults.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/accessibility/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/coordinates/constants.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/coordinates/distancebetweenpoints.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/coordinates/getrelativetransformorigin.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/coordinates/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/rect/adjustscale.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/rect/getrectdelta.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/rect/rectadjustment.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/rect/getrect.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/rect/getwindowclientrect.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/rect/rect.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/rect/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/other/noop.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/other/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/scroll/getscrollableancestors.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/scroll/getscrollableelement.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/scroll/getscrollcoordinates.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/scroll/getscrolldirectionandspeed.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/scroll/getscrollelementrect.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/scroll/getscrolloffsets.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/scroll/getscrollposition.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/scroll/documentscrollingelement.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/scroll/isscrollable.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/scroll/scrollintoviewifneeded.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/scroll/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/modifiers/types.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/modifiers/applymodifiers.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/modifiers/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dndcontext/types.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dndcontext/dndcontext.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dndcontext/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dndmonitor/types.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dndmonitor/context.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dndmonitor/usedndmonitor.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dndmonitor/usedndmonitorprovider.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dndmonitor/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/components/animationmanager/animationmanager.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/components/animationmanager/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/components/nullifiedcontextprovider/nullifiedcontextprovider.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/components/nullifiedcontextprovider/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/components/positionedoverlay/positionedoverlay.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/components/positionedoverlay/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/components/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/hooks/usedropanimation.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/hooks/usekey.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/hooks/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/dragoverlay.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/usedraggable.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/usedndcontext.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/usedroppable.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/index.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/types/disabled.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/types/data.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/types/strategies.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/types/type-guard.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/types/index.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/components/sortablecontext.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/components/index.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/hooks/types.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/hooks/usesortable.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/hooks/defaults.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/hooks/index.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/strategies/horizontallistsorting.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/strategies/rectsorting.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/strategies/rectswapping.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/strategies/verticallistsorting.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/strategies/index.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/sensors/keyboard/sortablekeyboardcoordinates.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/sensors/keyboard/index.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/sensors/index.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/utilities/arraymove.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/utilities/arrayswap.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/utilities/getsortedrects.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/utilities/isvalidindex.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/utilities/itemsequal.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/utilities/normalizedisabled.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/utilities/index.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/index.d.ts","../@noctacrdt/dist/nodeid.d.ts","../@noctacrdt/dist/interfaces.d.ts","../@noctacrdt/dist/node.d.ts","../@noctacrdt/dist/linkedlist.d.ts","../@noctacrdt/dist/crdt.d.ts","./src/features/editor/editor.style.ts","./src/features/editor/components/iconblock/iconblock.style.ts","./src/features/editor/components/iconblock/iconblock.tsx","./src/features/editor/components/menublock/menublock.style.ts","./src/features/editor/components/menublock/menublock.tsx","./src/features/editor/components/block/block.style.ts","./src/features/editor/components/block/block.tsx","./src/features/editor/hooks/useblockdraganddrop.ts","./src/types/markdown.ts","./src/features/editor/utils/markdownpatterns.ts","./src/features/editor/hooks/usemarkdowngrammer.ts","./src/features/editor/editor.tsx","./src/features/page/page.animation.ts","./src/features/page/page.style.ts","./src/features/page/components/pagecontrolbutton/pagecontrolbutton.style.ts","./src/features/page/components/pagecontrolbutton/pagecontrolbutton.tsx","./src/features/page/components/pagetitle/pagetitle.style.ts","./src/features/page/components/pagetitle/pagetitle.tsx","./src/constants/spacing.ts","./src/features/page/hooks/usepage.ts","./src/features/page/page.tsx","./src/features/workspace/workspace.style.ts","./src/features/workspace/hooks/usepagesmanage.ts","./src/features/workspace/workspace.tsx","./src/app.tsx","../node_modules/.pnpm/@types+react-dom@18.3.1/node_modules/@types/react-dom/client.d.ts","./src/main.tsx","./src/vite-env.d.ts","../node_modules/.pnpm/lottie-web@5.12.2/node_modules/lottie-web/index.d.ts","../node_modules/.pnpm/@lottiefiles+react-lottie-player@3.5.4_react@18.3.1/node_modules/@lottiefiles/react-lottie-player/dist/src/player.d.ts","../node_modules/.pnpm/@lottiefiles+react-lottie-player@3.5.4_react@18.3.1/node_modules/@lottiefiles/react-lottie-player/dist/src/controls.d.ts","../node_modules/.pnpm/@lottiefiles+react-lottie-player@3.5.4_react@18.3.1/node_modules/@lottiefiles/react-lottie-player/dist/src/seeker.d.ts","../node_modules/.pnpm/@lottiefiles+react-lottie-player@3.5.4_react@18.3.1/node_modules/@lottiefiles/react-lottie-player/dist/src/index.d.ts","./src/assets/lotties/loadingspinner.json","./src/components/loading/loadingspinner.tsx","./src/constants/color.ts","./src/styles/global.ts","./src/styles/typography.ts","./src/styles/recipes/glasscontainerrecipe.ts","./src/styles/tokens/color.ts","./src/styles/tokens/radii.ts","./src/styles/tokens/shadow.ts","./src/styles/tokens/sizes.ts","./src/styles/tokens/spacing.ts","./panda.config.ts","./vite-env-override.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/compatibility/disposable.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/compatibility/indexable.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/compatibility/iterators.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/compatibility/index.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/ts5.6/globals.typedarray.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/ts5.6/buffer.buffer.d.ts","../node_modules/.pnpm/buffer@5.7.1/node_modules/buffer/index.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/header.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/readable.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/file.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/fetch.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/formdata.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/connector.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/client.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/errors.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/dispatcher.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/global-dispatcher.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/global-origin.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/pool-stats.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/pool.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/handlers.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/balanced-pool.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/agent.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-interceptor.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-agent.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-client.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-pool.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-errors.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/proxy-agent.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/env-http-proxy-agent.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/retry-handler.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/retry-agent.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/api.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/interceptors.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/util.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/cookies.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/patch.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/websocket.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/eventsource.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/filereader.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/diagnostics-channel.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/content-type.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/cache.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/index.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/globals.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/assert.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/assert/strict.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/async_hooks.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/buffer.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/child_process.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/cluster.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/console.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/constants.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/crypto.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/dgram.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/diagnostics_channel.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/dns.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/dns/promises.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/domain.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/dom-events.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/events.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/fs.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/fs/promises.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/http.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/http2.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/https.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/inspector.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/module.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/net.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/os.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/path.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/perf_hooks.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/process.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/punycode.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/querystring.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/readline.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/readline/promises.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/repl.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/sea.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/stream.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/stream/promises.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/stream/consumers.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/stream/web.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/string_decoder.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/test.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/timers.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/timers/promises.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/tls.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/trace_events.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/tty.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/url.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/util.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/v8.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/vm.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/wasi.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/worker_threads.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/zlib.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/ts5.6/index.d.ts","../node_modules/.pnpm/@types+estree@1.0.6/node_modules/@types/estree/index.d.ts","../node_modules/.pnpm/rollup@4.24.3/node_modules/rollup/dist/rollup.d.ts","../node_modules/.pnpm/rollup@4.24.3/node_modules/rollup/dist/parseast.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/types/hmrpayload.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/types/customevent.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/types/hot.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/dist/node/types.d-agj9qkwt.d.ts","../node_modules/.pnpm/esbuild@0.21.5/node_modules/esbuild/lib/main.d.ts","../node_modules/.pnpm/source-map-js@1.2.1/node_modules/source-map-js/source-map.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/previous-map.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/input.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/css-syntax-error.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/declaration.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/root.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/warning.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/lazy-result.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/no-work-result.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/processor.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/result.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/document.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/rule.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/node.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/comment.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/container.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/at-rule.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/list.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/postcss.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/postcss.d.mts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/dist/node/runtime.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/types/importglob.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/types/metadata.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/dist/node/index.d.ts","../node_modules/.pnpm/@babel+types@7.26.0/node_modules/@babel/types/lib/index.d.ts","../node_modules/.pnpm/@types+babel__generator@7.6.8/node_modules/@types/babel__generator/index.d.ts","../node_modules/.pnpm/@babel+parser@7.26.2/node_modules/@babel/parser/typings/babel-parser.d.ts","../node_modules/.pnpm/@types+babel__template@7.4.4/node_modules/@types/babel__template/index.d.ts","../node_modules/.pnpm/@types+babel__traverse@7.20.6/node_modules/@types/babel__traverse/index.d.ts","../node_modules/.pnpm/@types+babel__core@7.20.5/node_modules/@types/babel__core/index.d.ts","../node_modules/.pnpm/@vitejs+plugin-react@4.3.3_vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0_/node_modules/@vitejs/plugin-react/dist/index.d.mts","../node_modules/.pnpm/vite-tsconfig-paths@5.1.0_typescript@5.3.3_vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0_/node_modules/vite-tsconfig-paths/dist/index.d.ts","../node_modules/.pnpm/@rollup+pluginutils@5.1.3_rollup@4.24.3/node_modules/@rollup/pluginutils/types/index.d.ts","../node_modules/.pnpm/prettier@3.3.3/node_modules/prettier/doc.d.ts","../node_modules/.pnpm/prettier@3.3.3/node_modules/prettier/index.d.ts","../node_modules/.pnpm/@svgr+babel-plugin-transform-svg-component@8.0.0_@babel+core@7.26.0/node_modules/@svgr/babel-plugin-transform-svg-component/dist/index.d.ts","../node_modules/.pnpm/@svgr+babel-preset@8.1.0_@babel+core@7.26.0/node_modules/@svgr/babel-preset/dist/index.d.ts","../node_modules/.pnpm/@svgr+core@8.1.0_typescript@5.3.3/node_modules/@svgr/core/dist/index.d.ts","../node_modules/.pnpm/vite-plugin-svgr@4.3.0_rollup@4.24.3_typescript@5.3.3_vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0_/node_modules/vite-plugin-svgr/dist/index.d.ts","./vite.config.ts","./vite.env.d.ts","./styled-system/patterns/aspect-ratio.d.ts","./styled-system/patterns/bleed.d.ts","./styled-system/patterns/box.d.ts","./styled-system/patterns/center.d.ts","./styled-system/patterns/circle.d.ts","./styled-system/patterns/container.d.ts","./styled-system/patterns/cq.d.ts","./styled-system/patterns/divider.d.ts","./styled-system/patterns/flex.d.ts","./styled-system/patterns/float.d.ts","./styled-system/patterns/grid-item.d.ts","./styled-system/patterns/grid.d.ts","./styled-system/patterns/hstack.d.ts","./styled-system/patterns/stack.d.ts","./styled-system/patterns/vstack.d.ts","./styled-system/patterns/spacer.d.ts","./styled-system/patterns/square.d.ts","./styled-system/patterns/link-overlay.d.ts","./styled-system/patterns/wrap.d.ts","./styled-system/patterns/visually-hidden.d.ts","./styled-system/patterns/index.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/types/importmeta.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/client.d.ts","../node_modules/.pnpm/vite-plugin-svgr@4.3.0_rollup@4.24.3_typescript@5.3.3_vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0_/node_modules/vite-plugin-svgr/client.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_terser@5.36.0/node_modules/vite/types/metadata.d.ts"],"fileInfos":[{"version":"f33e5332b24c3773e930e212cbb8b6867c8ba3ec4492064ea78e55a524d57450","affectsGlobalScope":true},"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","26f2f787e82c4222710f3b676b4d83eb5ad0a72fa7b746f03449e7a026ce5073","9a68c0c07ae2fa71b44384a839b7b8d81662a236d4b9ac30916718f7510b1b2d","5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4",{"version":"21e41a76098aa7a191028256e52a726baafd45a925ea5cf0222eb430c96c1d83","affectsGlobalScope":true},{"version":"35299ae4a62086698444a5aaee27fc7aa377c68cbb90b441c9ace246ffd05c97","affectsGlobalScope":true},{"version":"138fb588d26538783b78d1e3b2c2cc12d55840b97bf5e08bca7f7a174fbe2f17","affectsGlobalScope":true},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true},{"version":"4443e68b35f3332f753eacc66a04ac1d2053b8b035a0e0ac1d455392b5e243b3","affectsGlobalScope":true},{"version":"bc47685641087c015972a3f072480889f0d6c65515f12bd85222f49a98952ed7","affectsGlobalScope":true},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true},{"version":"93495ff27b8746f55d19fcbcdbaccc99fd95f19d057aed1bd2c0cafe1335fbf0","affectsGlobalScope":true},{"version":"6fc23bb8c3965964be8c597310a2878b53a0306edb71d4b5a4dfe760186bcc01","affectsGlobalScope":true},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true},{"version":"bb42a7797d996412ecdc5b2787720de477103a0b2e53058569069a0e2bae6c7e","affectsGlobalScope":true},{"version":"4738f2420687fd85629c9efb470793bb753709c2379e5f85bc1815d875ceadcd","affectsGlobalScope":true},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true},{"version":"9fc46429fbe091ac5ad2608c657201eb68b6f1b8341bd6d670047d32ed0a88fa","affectsGlobalScope":true},{"version":"61c37c1de663cf4171e1192466e52c7a382afa58da01b1dc75058f032ddf0839","affectsGlobalScope":true},{"version":"b541a838a13f9234aba650a825393ffc2292dc0fc87681a5d81ef0c96d281e7a","affectsGlobalScope":true},{"version":"e0275cd0e42990dc3a16f0b7c8bca3efe87f1c8ad404f80c6db1c7c0b828c59f","affectsGlobalScope":true},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true},{"version":"49ed889be54031e1044af0ad2c603d627b8bda8b50c1a68435fe85583901d072","affectsGlobalScope":true},{"version":"e93d098658ce4f0c8a0779e6cab91d0259efb88a318137f686ad76f8410ca270","affectsGlobalScope":true},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true},{"version":"bf14a426dbbf1022d11bd08d6b8e709a2e9d246f0c6c1032f3b2edb9a902adbe","affectsGlobalScope":true},{"version":"ec0104fee478075cb5171e5f4e3f23add8e02d845ae0165bfa3f1099241fa2aa","affectsGlobalScope":true},{"version":"2b72d528b2e2fe3c57889ca7baef5e13a56c957b946906d03767c642f386bbc3","affectsGlobalScope":true},{"version":"acae90d417bee324b1372813b5a00829d31c7eb670d299cd7f8f9a648ac05688","affectsGlobalScope":true},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true},{"version":"33358442698bb565130f52ba79bfd3d4d484ac85fe33f3cb1759c54d18201393","affectsGlobalScope":true},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true},{"version":"36a2e4c9a67439aca5f91bb304611d5ae6e20d420503e96c230cf8fcdc948d94","affectsGlobalScope":true},"8a8eb4ebffd85e589a1cc7c178e291626c359543403d58c9cd22b81fab5b1fb9","ed6b820c54de95b2510bb673490d61c7f2187f532a339d8d04981645a918961f",{"version":"aa17748c522bd586f8712b1a308ea23af59c309b2fd278f6d4f406647c72e659","affectsGlobalScope":true},"42c169fb8c2d42f4f668c624a9a11e719d5d07dacbebb63cbcf7ef365b0a75b3",{"version":"afc7ca357c5aa5a9b9f1b70175522b1d5c7fb2923cb228bef4dff7127e862eeb","affectsGlobalScope":true},"8697faa527dd799c5bbe64723aa2593fdd47c609864aa4c49689997cd06cebac","b426147fec725961d1305b25b26dbf99e5c419de98b5728974a8a44fc5959181","1235f6acae8da14ce25d9f75df290c4e4f7d53d024b4e91c6121ff44ea13c801","8a8eb4ebffd85e589a1cc7c178e291626c359543403d58c9cd22b81fab5b1fb9","77d596561ec05cddc53701988ff8d891047978036c603de4b405b31e11f8575b","15bd07838cd4506b93e6835f78c5dedacc0bcae7202b2086444637df4a8f4d45","348c57c67c092eb3c28873d630c320e392e947a07946aaced323e8e6eafb915d","83fcaf1f41dd04269322cfdd47aa2546ec0393c83c2f3a1a2ad321765a3e3aa2","98240aef8bd41abfdef295d1dbe712d51a8cf1dea125c40f270bafc816cbf6c5","4baa8b99f90861f5e8ba1efb2deef2195be4037ea47b83180b6770d76bfe845c","03c0c949e86c44a98165752c31d9edea61b853a237254806b5a452c16b6f709f","7c8cffc734f0860b5eb694a3cf43a347cbcc531877a06a8a0b0748113487c4df","d3a88ebd39ffd613ac064bbe2d813e47d262219d4581dd437caf80d4cfd3e437","db56a1b0b070b2a9b68561c3542b3928492793e32c632171caa6c53fb8ecb402","a92ea8cdc292bee86d7bf00ade4d4c2b84ef07b6a772650c4a3f503e83c43f95","9cc2ce851dce49e8e831ffefd5ac85b62319e97df4821683dcc80fb17e08197e","f2a60f3d9dac64110308154059537cd87ab6f4c607395a89e3cc703f837b8d22","b2f74a813678952f4906641449101cb04e6b94a3055a60c194d28f93fcb58a25","e5b2239e66924ad249294b617d85dc561a04fa1491f3b9aa45e067456682ada7","3ae8dd5663704463b336ce8e43dab2a53fc7f085841602f90f07d3edf675ce65","c6c583d215c29a8420c52a01f041a3ebfa5ad9eecd4049b57acda599e3e30ed0","10ccdcf171b365e3fc0b9540f9941ad3915ba3672eda63099156d64f5b9616e8","9e6ae4de60321c9c875ce5871dfcc9426dbb006b76ec6593363f012d434cf704","85329c72103a5d46c60b93f130a8cc941d029dfc52caf8ba01f208b3b006083e","56fb55555c935a1ef9f70369252c25f96397171443b3fa829eab2e27aab7f43b","1cc1dd565274a0c1f7a13a2f1d581c51b3b770b4c502a7ddf2b623d8e57671a8","e83447f88a6a9a5e5426131b165337b4dff7ff249d3899c7cacc6e7c47267412","baac36a022cf0ccddaf1648e242068e358e2b78483efb816c8d05384217928fc","e1dfeb7fe1815dae68e2513ac1cf5130d6977688a5090eeef9f3dde05791532f","4e4c1412ce497716a61b7bbca1302826c4eb6cf68fce4bb76f190c31e544568c","86075b555f88780f45c665374f1678b0010ed92c1da6defb8978aef63ad9823f","729d731c01903375efde3fbee81d8bdb2f189bd42f5af97de33c8dde4a948011","f6059a11ad8f08358eec11f1167e9b6ecd4adcba611c266dad5a6476381b6a79","faacee8a12d1ac0edfc1393404f3629e1264f955680a89cbfecc58dabc85e24a","f86cbc47cd362a2095e6841a9f636ed41f196c06d800c9d031a4e5a9fa3609d6","532a61e1bc826812ddf5b670c3e832ea9fe875c95a9d3be33e4c2a176b5f71f0","1e852a81f8ab8017a2ec279e822641c9a6d856717696da38d7e01b78c7725775","2f462d47bcf3b80e045843dc3aae0bd1c0ea673a9cbc46ed6a367e59790e99f1","620a5aae820e9ba53965b4af9c87e5bdd7d30c6aa549687af36bd557b18992d4","c06545530668dfef18b864b18c275af0f4a223e489282db301c437843726be6d","695932cb32b555db096ee4072a818b774aeec9cd0c6864d4af5180c0e58f83dd","852847088636a9b1c7be0ce22fab66d9c9940f0a0e6f78acc147e1f5b897149b","f27e2c4fbb11766959ba9bb27882efebe8cc3346c4f3dfe78200eb23681ca1ce","da459d6c84246bbf0a8befd1df34a1120374d9570e8ca73800862ccb47cc7e1b","ea9f8137a900e961ab0d0afe2493a3be050a9e5e3aa3bd4d2b7cb62751bdf7a8","f6b0d3cfad6acbe42c53a53ec86cd8e8c65881668a1fc627940376eca9beb1fa","2edd7faf1bc8a0fca9ee6060a1935c3cd43487ebdc71f34df7f8c59f65b39480","0725189193a07a4fb3cc82c856c70b913f51bd850e86a3586a2457e8c008affd","951ea5f4424d919bf78c95291e66d0c0f36b26d01b70db627e5f19dca3fe1778","5027a140fc57c7750853cacec34363c091dda7c4ca97dad0e2c4f5c8ad0bc87f","ea6dd5ffdf73eb07480bd7e6358845b2cf5237041851e477c9cb72d02d4d86fa","a803b31b8a4ecf5f782da5c6254b1a327a9f55fc90c0d09e4a8770db53d70e30","76702c38ff90508cad63a94e66d752858bd4456dadc501c7dd919b441215df35","4e979330517c1527ed78e19bb70619e5b276b80a89103f8fed7f63b2f27d52cb","044aae1e62523280d3679eed49ffa288bb793d87b98ab4aaa37a7024838929f3",{"version":"7b312001a7cc821594bf346b364bc76604ec14db06292bdb3f8037dbe82d28f1","signature":"f7ce3c14b40fd0fa1f38a4922e4f65f0dc296cd0798ddcb569b5681e682ba2ff"},{"version":"9d859490d085e26024ff254e37b8d01c050fa09bc24c77002e04016102c69741","signature":"241670462fddff5bd4688b4e030bf860c9f0e8a63aced869cf515d123f1e4de3"},{"version":"fccebb4ebbf7dfd471b1bcb0a0249dd50a0d39cb1d6471b8c8496335468e5bb8","signature":"ac4b32ee1e4d254f0900aed7bbd2b856335d68472ee84b68aa655d09e4828588"},{"version":"3b7c6b3e897d68435cf6719937e767ceb554daec84628cfaf8a23e7c1cbee8ff","signature":"1f46b774e1a86d7031e7828ed00b16a296f3d5b0fb296771e36d892ff7308136"},"d3c03ffa8da44ac52d6f610275a3bf57957846e8cf417bf5ca9610722b319857","ec61b7543855ffd13ec368dfad5a492669d78cb5060ccbffd294c5141e3c3606",{"version":"2d617b5b26592ea5529011d707b76290d323dd85b065f98e1e7e568faf9cc526","signature":"4f105da204a6ec7666bb6f560534b19d83d294e7227dfceccc7127e472245287"},{"version":"5ca24585772829aa0bae140e9dac7e4467aae335c1c099e63445c086beabc972","signature":"82d7737a8c612aa8298cee0d92d42f80db2e428d0f5c8c4c096fc8d6d578b995"},"17ed71200119e86ccef2d96b73b02ce8854b76ad6bd21b5021d4269bec527b5f",{"version":"65ce4b162e7fad6f34ad5190e14697ad537de114b82869959cac0caba6e66075","signature":"3b97ec726d3b58e897284bca58151ecf46d3cb988f6d988e1133c19a7a176e51"},{"version":"6221dc3b8a476510f38543fe10a92b57313ca06e16c45773edbce491328e277d","signature":"27ff70d080b0bf5ca29566f80000b6793faad8f425a42ee93457f283de84b5c2"},{"version":"30b88706d5bd23f9542c734aee0baf15516ab2c73d5b9150a3006f5398e1c57d","signature":"99079d7da6b328f1cefdd99506f531e729f0de2799ead0f1fe1013326317ae41"},{"version":"1ae561d086a5c4a1a9f065a8c7a66ac287d00bfaa57587e44a177114373920a3","signature":"591e922a96993dc2272129ef8ce028b5dc45e6cd27590c3a941aba2750e61784"},{"version":"27f5a927115a09a1945d8d5db0027cdffa3b1d7d3ef16a28e6bebee32112abb8","signature":"5fa10b11311ed1cca00d9f81a39c490cc531126bc685895f7c2cc319120aa222"},{"version":"305e88c7b877fc3ee815e469d0723b2001c0b38b916932895c5a96e694e5df6e","signature":"f3f7c5dc2e234e65b90979079e8f48974fc16bf00880c5e7316a2cf33024cd57"},{"version":"33eb458116216489fb26d1038a3b42b8a2d10cc1f18eb14ea81586c35e75e05b","signature":"dbb714013b2d011f1de0da80333d5c55b2aee573f2b44ef9048e8c7396b168c4"},"7117f6513efa5f409de39a7b87938b761daad4720c226a4fb3b8ed454bfd3b5c","1b60812534ac4ad313ccc1461598a1ee2a764b55827de1c0afd295a418b72008","06100727c3328b53c19780f851301c4e18c66c55658d2605ab0de27818885e42",{"version":"e2c35b6573e67d9b055351924d8d31a8e9531d5933184c862cc739ff4cf38c42","signature":"a77c18fa58ceff05bf6eacfa82a9b8c2f90e6a90dfc583ac24a52723a7a01f39"},{"version":"295faa88cb20e14302153a285c02706ab376a55f9be9441e59896f7bc920b4b6","signature":"f3a3267259b54050457fdfe5fef5117e598cfa6b607f0d38f711b1690e57f013"},{"version":"3aaded7d37421de9a2db0043c274e26b274b3cfa7978b5eb8cf1dcab35d740bb","signature":"965d48bbfb6f106f3bd65866b977a98559cf4580bb04a35ea7076459544becc1"},{"version":"2828358120f8e28e0beb016ee880f20676f5edba7c63512248573bc7248fa6dd","signature":"f3aadf75be9669e41ae252c1b0a283a0fcee99cf472c9b0cd3967cc0a8baf8c2"},{"version":"6545e161d6939669b661d7436db8d911c9089f37d0a58731af8dd1253846bf34","signature":"fbb277e5c491a2d4e00885af5bde1da583984953c698f1ba21f339b2ece16b15"},{"version":"46444e99adf28a9d848d74de2f5673ff65df395ac66ad92de40909abf3ab20d7","signature":"d839925736d555cb6822e9ebcac9b2be23fc0e77b5ca070079f8ea154240df3e"},{"version":"24fdf9df976cdab18f0e104ad77b9d37d531b576eab6c0131afa656df724ddcc","signature":"d79fd618eba486f4b25279d184f9dc9db1f930b0590c868c8881bb9d97df3c5f"},{"version":"b7e8232c073889ff8a81217c6f5d667dcb8c3790b44190b88758e5ebd682ded0","signature":"f6f25d3f349c387e05a3733c53e04b90e26a8ee6f7b8d785a6fa51bb1b9fd4a1"},{"version":"a4fdabc5dbac13dc4a0711237ce57b81bedf0a4d57d141288f6c9ed0aa6110f3","signature":"8835c47ff0394fe78cc0d6ba10fa3484b8bd8b34c23a0681d9b817cec625e4ed"},{"version":"39228bfe387fa631b32a8583f7cf4360ebb53aa6f16110a5aec4fce845e0ed68","signature":"840e58d0d77668975dafdecf6c92a5159a5928d272b16e71d5ae07c353bd467d"},{"version":"d3b9d7692af7be8a3a08a8376994e174b4116ff7758301ad3338f929485a6c4f","signature":"3aa5f17174196783adbeace09bbdaad6b89332bfcfe2a717bca727a4aa97970c"},{"version":"3e0fb130ec12022fe76b185a7a8821fa44155711989e7808e903faa8d8fbf20f","signature":"ad969ab25be308018e9128197dd6cd9e5019f0e1d2747a71279231682f01c442"},{"version":"d8836f7f69931924088f8ee33ea91db91dbfb4b53a718abc20b9827d3997bfa7","signature":"fb63656d505060fd2a9c77805a2a6ee79653df05a40bfd20d3ab79d94c5fcd45"},"dd332252bb45677533cd5553e0c35340cee4c485c90c63360f8e653901286a4f","dddde95f3dea44dc49c9095a861298e829122a54a3f56b3b815e615501e2ed16","794a88237c94d74302df12ebb02f521cf5389a5bf046a3fdbdd3afb21dc02511","66a08d30c55a7aefa847c1f5958924a3ef9bea6cd1c962a8ff1b2548f66a6ce0","0790ae78f92ab08c9d7e66b59733a185a9681be5d0dc90bd20ab5d84e54dcb86","1046cd42ec19e4fd038c803b4fc1aff31e51e6e48a6b8237a0240a11c1c27792","8f93c7e1084de38a142085c7f664b0eb463428601308fb51c68b25cb687e0887","83f69c968d32101f8690845f47bcae016cbea049e222a5946889eb3ae37e7582","59c3f3ed18de1c7f5927e0eafcdc0e545db88bfae4168695a89e38a85943a86d","32e6c27fd3ef2b1ddbf2bf833b2962d282eb07d9d9d3831ca7f4ff63937268e1","406ebb72aa8fdd9227bfce7a1b3e390e2c15b27f5da37ea9e3ed19c7fb78d298","197109f63a34b5f9379b2d7ba82fc091659d6878db859bd428ea64740cb06669","059871a743c0ca4ae511cbd1e356548b4f12e82bc805ab2e1197e15b5588d1c4","8ccefe3940a2fcb6fef502cdbc7417bb92a19620a848f81abc6caa146ab963e9","44d8ec73d503ae1cb1fd7c64252ffa700243b1b2cc0afe0674cd52fe37104d60","67ea5a827a2de267847bb6f1071a56431aa58a4c28f8af9b60d27d5dc87b7289","e33bb784508856827448a22947f2cac69e19bc6e9d6ef1c4f42295f7bd4ce293","383bb09bfeb8c6ef424c7fbce69ec7dc59b904446f8cfec838b045f0143ce917","83508492e3fc5977bc73e63541e92c5a137db076aafc59dcf63e9c6ad34061c7","ef064b9a331b7fc9fe0b368499c52623fb85d37d8972d5758edc26064189d14d","d64457d06ab06ad5e5f693123ee2f17594f00e6d5481517058569deac326fea0","e92ea29d716c5fe1977a34e447866d5cfbd94b3f648e3b9c550603fdae0e94fb","3d10f47c6b1e9225c68c140235657a0cdd4fc590c18faf87dcd003fd4e22c67f","13989f79ff8749a8756cac50f762f87f153e3fb1c35768cc6df15968ec1adb1a","e014c2f91e94855a52dd9fc88867ee641a7d795cfe37e6045840ecf93dab2e6b","74b9f867d1cc9f4e6122f81b59c77cbd6ff39f482fb16cffdc96e4cda1b5fdb1","7c8574cfc7cb15a86db9bf71a7dc7669593d7f62a68470adc01b05f246bd20ff","c8f49d91b2669bf9414dfc47089722168602e5f64e9488dbc2b6fe1a0f6688da","3abee758d3d415b3b7b03551f200766c3e5dd98bb1e4ff2c696dc6f0c5f93191","79bd7f60a080e7565186cfdfd84eac7781fc4e7b212ab4cd315b9288c93b7dc7","4a2f281330a7b5ed71ebc4624111a832cd6835f3f92ad619037d06b944398cf4","ea8130014cb8ee30621bf521f58d036bff3b9753b2f6bd090cc88ac15836d33c","c740d49c5a0ecc553ddfc14b7c550e6f5a2971be9ed6e4f2280b1f1fa441551d","886a56c6252e130f3e4386a6d3340cf543495b54c67522d21384ed6fb80b7241","4b7424620432be60792ede80e0763d4b7aab9fe857efc7bbdb374e8180f4092a","e407db365f801ee8a693eca5c21b50fefd40acafda5a1fa67f223800319f98a8","529660b3de2b5246c257e288557b2cfa5d5b3c8d2240fa55a4f36ba272b57d18","0f6646f9aba018d0a48b8df906cb05fa4881dc7f026f27ab21d26118e5aa15de","b3620fcf3dd90a0e6a07268553196b65df59a258fe0ec860dfac0169e0f77c52","08135e83e8d9e34bab71d0cf35b015c21d0fd930091b09706c6c9c0e766aca28","96e14f2fdc1e3a558462ada79368ed49b004efce399f76f084059d50121bb9a9","56f2ade178345811f0c6c4e63584696071b1bd207536dc12384494254bc1c386","72c3535621ce0d03c1f2164ef5b374cea7b0ef74f0a43e4e25c6b196b6ee2531","a9679a2147c073267943d90a0a736f271e9171de8fbc9c378803dd4b921f5ed3","a8a2529eec61b7639cce291bfaa2dd751cac87a106050c3c599fccb86cc8cf7f","bfc46b597ca6b1f6ece27df3004985c84807254753aaebf8afabd6a1a28ed506","29d367403d3770c9f486a4ba87786957a479e93116905c55a22c2d5f9fd1206b","b8f3eafeaf04ba3057f574a568af391ca808bdcb7b031e35505dd857db13e951","30b38ae72b1169c4b0d6d84c91016a7f4c8b817bfe77539817eac099081ce05c","055eb244114cb0c9243e78f682e9e428ba7d2d1a1b96bfdcb1055a10c242fa01","426c3234f768c89ba4810896c1ee4f97708692727cfecba85712c25982e7232b","ee12dd75feac91bb075e2cb0760279992a7a8f5cf513b1cffaa935825e3c58be","33353c07054dafcf8cf80df57925c1e306b7760742a65f29fa78f7f1e9f0a895","4763ce202300b838eb045923eaeb32d9cf86092eee956ca2d4e223cef6669b13","7cff5fff5d1a92ae954bf587e5c35987f88cacaa006e45331b3164c4e26369de","3e51868ea728ceb899bbfd7a4c7b7ad6dd24896b66812ea35893e2301fd3b23f","781e8669b80a9de58083ca1f1c6245ef9fb04d98add79667e3ed70bde034dfd5","cfd35b460a1e77a73f218ebf7c4cd1e2eeeaf3fa8d0d78a0a314c6514292e626","452d635c0302a0e1c5108edebcca06fc704b2f8132123b1e98a5220afa61a965","ede58c3483c998fb5ce80f178522a4dd531900262eddd513898f3dba6ee77f0a","b87d65da85871e6d8c27038146044cffe40defd53e5113dbd198b8bce62c32db","ca1159f3677ea301f52a7e302b8ce2b287556d559c3b8c770cf5540bab175be5","5ff885be3e07a88697343a4741ccd8c919102ec096da574ea3f6caa5d8b52b94","c9f17e24cb01635d6969577113be7d5307f7944209205cb7e5ffc000d27a8362","685ead6d773e6c63db1df41239c29971a8d053f2524bfabdef49b829ae014b9a","b7bdabcd93148ae1aecdc239b6459dfbe35beb86d96c4bd0aca3e63a10680991","e83cfc51d3a6d3f4367101bfdb81283222a2a1913b3521108dbaf33e0baf764a","95f397d5a1d9946ca89598e67d44a214408e8d88e76cf9e5aecbbd4956802070","74042eac50bc369a2ed46afdd7665baf48379cf1a659c080baec52cc4e7c3f13","1541765ce91d2d80d16146ca7c7b3978bd696dc790300a4c2a5d48e8f72e4a64","ec6acc4492c770e1245ade5d4b6822b3df3ba70cf36263770230eac5927cf479","4c39ee6ae1d2aeda104826dd4ce1707d3d54ac34549d6257bea5d55ace844c29","deb099454aabad024656e1fc033696d49a9e0994fc3210b56be64c81b59c2b20","80eec3c0a549b541de29d3e46f50a3857b0b90552efeeed90c7179aba7215e2f","a4153fbd5c9c2f03925575887c4ce96fc2b3d2366a2d80fad5efdb75056e5076","6f7c70ca6fa1a224e3407eb308ec7b894cfc58042159168675ccbe8c8d4b3c80","4b56181b844219895f36cfb19100c202e4c7322569dcda9d52f5c8e0490583c9","5609530206981af90de95236ce25ddb81f10c5a6a346bf347a86e2f5c40ae29b","632ce3ee4a6b320a61076aeca3da8432fb2771280719fde0936e077296c988a9","8b293d772aff6db4985bd6b33b364d971399993abb7dc3f19ceed0f331262f04","4eb7bad32782df05db4ba1c38c6097d029bed58f0cb9cda791b8c104ccfdaa1f","c6a8aa80d3dde8461b2d8d03711dbdf40426382923608aac52f1818a3cead189","bf5e79170aa7fc005b5bf87f2fe3c28ca8b22a1f7ff970aa2b1103d690593c92","ba3c92c785543eba69fbd333642f5f7da0e8bce146dec55f06cfe93b41e7e12f","c6d72ececae6067e65c78076a5d4a508f16c806577a3d206259a0d0bfeedc8d1","b6429631df099addfcd4a5f33a046cbbde1087e3fc31f75bfbbd7254ef98ea3c","4e9cf1b70c0faf6d02f1849c4044368dc734ad005c875fe7957b7df5afe867c9","7498b7d83674a020bd6be46aeed3f0717610cb2ae76d8323e560e964eb122d0c","b80405e0473b879d933703a335575858b047e38286771609721c6ab1ea242741","7193dfd01986cd2da9950af33229f3b7c5f7b1bee0be9743ad2f38ec3042305e","1ccb40a5b22a6fb32e28ffb3003dea3656a106dd3ed42f955881858563776d2c","8d97d5527f858ae794548d30d7fc78b8b9f6574892717cc7bc06307cc3f19c83","ccb4ecdc8f28a4f6644aa4b5ab7337f9d93ff99c120b82b1c109df12915292ac","8bbcf9cecabe7a70dcb4555164970cb48ba814945cb186493d38c496f864058f","7d57bdfb9d227f8a388524a749f5735910b3f42adfe01bfccca9999dc8cf594c","3508810388ea7c6585496ee8d8af3479880aba4f19c6bbd61297b17eb30428f4","56931daef761e6bdd586358664ccd37389baabeb5d20fe39025b9af90ea169a5","abb48247ab33e8b8f188ef2754dfa578129338c0f2e277bfc5250b14ef1ab7c5","beaba1487671ed029cf169a03e6d680540ea9fa8b810050bc94cb95d5e462db2","1418ef0ba0a978a148042bc460cf70930cd015f7e6d41e4eb9348c4909f0e16d","56be4f89812518a2e4f0551f6ef403ffdeb8158a7c271b681096a946a25227e9","bbb0937150b7ab2963a8bc260e86a8f7d2f10dc5ee7ddb1b4976095a678fdaa4","862301d178172dc3c6f294a9a04276b30b6a44d5f44302a6e9d7dc1b4145b20b","cbf20c7e913c08cb08c4c3f60dae4f190abbabaa3a84506e75e89363459952f0","0f3333443f1fea36c7815601af61cb3184842c06116e0426d81436fc23479cb8","421d3e78ed21efcbfa86a18e08d5b6b9df5db65340ef618a9948c1f240859cc1","b1225bc77c7d2bc3bad15174c4fd1268896a90b9ab3b306c99b1ade2f88cddcc","ca46e113e95e7c8d2c659d538b25423eac6348c96e94af3b39382330b3929f2a","03ca07dbb8387537b242b3add5deed42c5143b90b5a10a3c51f7135ca645bd63","ca936efd902039fda8a9fc3c7e7287801e7e3d5f58dd16bf11523dc848a247d7","2c7b3bfa8b39ed4d712a31e24a8f4526b82eeca82abb3828f0e191541f17004c","5ffaae8742b1abbe41361441aa9b55a4e42aee109f374f9c710a66835f14a198","ecab0f43679211efc9284507075e0b109c5ad024e49b190bb28da4adfe791e49","967109d5bc55face1aaa67278fc762ac69c02f57277ab12e5d16b65b9023b04f","36d25571c5c35f4ce81c9dcae2bdd6bbaf12e8348d57f75b3ef4e0a92175cd41","fde94639a29e3d16b84ea50d5956ee76263f838fa70fe793c04d9fce2e7c85b9","5f4c286fea005e44653b760ebfc81162f64aabc3d1712fd4a8b70a982b8a5458","e02dabe428d1ffd638eccf04a6b5fba7b2e8fccee984e4ef2437afc4e26f91c2","60dc0180bd223aa476f2e6329dca42fb0acaa71b744a39eb3f487ab0f3472e1c","b6fdbecf77dcbf1b010e890d1a8d8bfa472aa9396e6c559e0fceee05a3ef572f","e1bf9d73576e77e3ae62695273909089dbbb9c44fb52a1471df39262fe518344","fad7dc36fbac24ae2c643c8250bd2f428755258d365cd95943970ba17f9c7c4c","fdcd692f0ac95e72a0c6d1e454e13d42349086649828386fe7368ac08c989288","58fcf404770f5648652d2a9eb02601348fd1d7b7469cb89a97e3044551201e9b","b0641d9de5eaa90bff6645d754517260c3536c925b71c15cb0f189b68c5386b4","9899a0434bd02881d19cb08b98ddd0432eb0dafbfe5566fa4226bdd15624b56f","4496c81ce10a0a9a2b9cb1dd0e0ddf63169404a3fb116eb65c52b4892a2c91b9","ecdb4312822f5595349ec7696136e92ecc7de4c42f1ea61da947807e3f11ebfc","42edbfb7198317dd7359ce3e52598815b5dc5ca38af5678be15a4086cccd7744","8105321e64143a22ed5411258894fb0ba3ec53816dad6be213571d974542feeb","d1b34c4f74d3da4bdf5b29bb930850f79fd5a871f498adafb19691e001c4ea42","9a1caf586e868bf47784176a62bf71d4c469ca24734365629d3198ebc80858d7","35a443f013255b33d6b5004d6d7e500548536697d3b6ba1937fd788ca4d5d37b","b591c69f31d30e46bc0a2b383b713f4b10e63e833ec42ee352531bbad2aadfaa","31e686a96831365667cbd0d56e771b19707bad21247d6759f931e43e8d2c797d","dfc3b8616bece248bf6cd991987f723f19c0b9484416835a67a8c5055c5960e0","03b64b13ecf5eb4e015a48a01bc1e70858565ec105a5639cfb2a9b63db59b8b1","c56cc01d91799d39a8c2d61422f4d5df44fab62c584d86c8a4469a5c0675f7c6","5205951312e055bc551ed816cbb07e869793e97498ef0f2277f83f1b13e50e03","50b1aeef3e7863719038560b323119f9a21f5bd075bb97efe03ee7dec23e9f1b","0cc13970d688626da6dce92ae5d32edd7f9eabb926bb336668e5095031833b7c","3be9c1368c34165ba541027585f438ed3e12ddc51cdc49af018e4646d175e6a1","7d617141eb3f89973b1e58202cdc4ba746ea086ef35cdedf78fb04a8bb9b8236","ea6d9d94247fd6d72d146467070fe7fc45e4af6e0f6e046b54438fd20d3bd6a2","d584e4046091cdef5df0cb4de600d46ba83ff3a683c64c4d30f5c5a91edc6c6c","e79d0c35c071d7d2c8b5b97f7502c017ed9e5bed489f9f414bb4073fc9e596ac","d48ac7569126b1bc3cd899c3930ef9cf22a72d51cf45b60fc129380ae840c2f2","e4f0d7556fda4b2288e19465aa787a57174b93659542e3516fd355d965259712","756b471ce6ec8250f0682e4ad9e79c2fddbe40618ba42e84931dbb65d7ac9ab0","ce9635a3551490c9acdbcb9a0491991c3d9cd472e04d4847c94099252def0c94","b70ee10430cc9081d60eb2dc3bee49c1db48619d1269680e05843fdaba4b2f7a","9b78500996870179ab99cbbc02dffbb35e973d90ab22c1fb343ed8958598a36c","c6ee8f32bb16015c07b17b397e1054d6906bc916ab6f9cd53a1f9026b7080dbf","67e913fa79af629ee2805237c335ea5768ea09b0b541403e8a7eaef253e014d9","0b8a688a89097bd4487a78c33e45ca2776f5aedaa855a5ba9bc234612303c40e","188e5381ed8c466256937791eab2cc2b08ddcc5e4aaf6b4b43b8786ed1ab5edd","8559f8d381f1e801133c61d329df80f7fdab1cbad5c69ebe448b6d3c104a65bd","00a271352b854c5d07123587d0bb1e18b54bf2b45918ab0e777d95167fd0cb0b","10c4be0feeac95619c52d82e31a24f102b593b4a9eba92088c6d40606f95b85d","e1385f59b1421fceba87398c3eb16064544a0ce7a01b3a3f21fa06601dc415dc","bacf2c0f8cbfc5537b3c64fc79d3636a228ccbb00d769fb1426b542efe273585","3103c479ff634c3fbd7f97a1ccbfb645a82742838cb949fdbcf30dd941aa7c85","4b37b3fab0318aaa1d73a6fde1e3d886398345cff4604fe3c49e19e7edd8a50d","bf429e19e155685bda115cc7ea394868f02dec99ee51cfad8340521a37a5867a","72116c0e0042fd5aa020c2c121e6decfa5414cf35d979f7db939f15bb50d2943","20510f581b0ee148a80809122f9bcaa38e4691d3183a4ed585d6d02ffe95a606","71f4b56ed57bbdea38e1b12ad6455653a1fbf5b1f1f961d75d182bff544a9723","b3e1c5db2737b0b8357981082b7c72fe340edf147b68f949413fee503a5e2408","396e64a647f4442a770b08ed23df3c559a3fa7e35ffe2ae0bbb1f000791bda51","698551f7709eb21c3ddec78b4b7592531c3e72e22e0312a128c40bb68692a03f","662b28f09a4f60e802023b3a00bdd52d09571bc90bf2e5bfbdbc04564731a25e","e6b8fb8773eda2c898e414658884c25ff9807d2fce8f3bdb637ab09415c08c3c","528288d7682e2383242090f09afe55f1a558e2798ceb34dc92ae8d6381e3504a","304f80676885d1bba89b4443d9caf5ead139ecd5329db8ce7a7d8bc7b3e0b758","750322c18fc0042f46db82b16da917cc5e3589f46fb95d369992ac5fb312cead","129dc16fc27aec6f521a2e53e5cdd1cc11439f570dc1e4e0230bf7c02f06207c","c88410e37a4d3ec22e4ef30d4a41b3734d6f0431a5a8116157dea1b07e40deba","09d08e29b770788d9e5efa5368474cf3c9d85aacbcd17fb06d8ac5ce7215b7a0",{"version":"1ea73300449e6acfeafa7a4f260c9bb3dd0d428b44694a1512960b109ad31d12","signature":"2ccfbe654a099b0dc4157e37cd23de1e4b665ac298370ff827b33817cc4810bd"},{"version":"89772a899f21b52e7837e0318abee76a527935d9ad66fbd95edb50b2287683bb","signature":"4c512955224da509540ae1d0637346e06920b72a474e9621569452bbc5ca5a39"},{"version":"dddac6df25eebaf23087547248cac8476db31d5f7f8bc98b7b37f90e0b720527","signature":"08b804ff2213d66a4cd2f5a778fe4ce49cfa3fb84894720896b39d64d6ca5477"},{"version":"0f339d0a24843a164f5fd6a96b2790df1333f487fcbd58d587664f025ccc1b82","signature":"cd9dfcae5efbf0a7f9e997d5e72b2db1e85ad55eaab1eb42ca11fc40d09f6cb7"},{"version":"91a0bb919e7bfe92fc0a3d80e0f1a3f6fdd9dac9a7dd0810021868299b2cd799","signature":"c3e2427fd3515fcbe315799ba73f794ade76a7da4db48efa03dd2acf8dfc6189"},{"version":"fbd772b29973d27296402483904bb652e68ffe22f75cbda82ccd017185b7d766","signature":"ac47c134f692b235ff13374733b23f3ca54f8b4a5caa0209821e6573a3f5546d"},{"version":"a04a62626e3cf20f2dfae1ce00d6c085fb4263a09685f9b68551ce61b33bea24","signature":"dafab3bb36dbf4bdfb66772638b483aaa0704b3db4873556b2c7f1ba3e9841b8"},{"version":"5039ff4a928b8aa3c334907b83a7bf9da97cf988ccff6e724615866bdc968ab7","signature":"aa14357292264e1d83b07790f2be0a8d4955014c4d4aa705acf32161cf1d3064"},{"version":"070ca55de8428c2895094ccbeca111b39f9117cb3e2bbacc56abb22368f45432","signature":"9e454a3fe6f8fe564f6a7716a687e5bfb56d9b8619aefa0cadd0fe0d2ff6dfaa"},{"version":"8bbcc8f337381a474ea786f8b07b62c2dc7f99541a8355389400299702682df1","signature":"e6b0c4604be5f8db13e5a09a121a7d3076177c0465b5cc383cef87985852ad7f"},{"version":"88bac94949e63d90f8c2ec1b97456caf6b038e2d5cba4d2da32f3945c72271a2","signature":"a1792e4b97b9bda9bb4b9baab75936da65e6ee477414313819b7aeeaed40fca4"},{"version":"a9f265ee11bcc2f7b61013379a34d0479b82e41e62692756c7ce26ed5da56082","signature":"5d4f0409e3ad668d6fa1e05f3fd08ef06a442747576ffc0d5959bd2b21c6eff3"},{"version":"bff8bdf1a621ad97512324d5af06039277139f8aad29c84f658adfe540beb3f6","signature":"50c5ffc826b86cedfb3e4423b9a5ccd74bb5deb2e1237955c43c5d10ba40ae6f"},{"version":"69096d34e43c2b7d75001becba9736de1f15e7d7bbced63001a0d330feb6f041","signature":"2de2fdf85c4fd30870d405688d0ad3306f0b07ddca89a062fa237f0ed211925d"},{"version":"fe47635783915c9f391302ab99b4d04e794f4ed6bc33aea0f63b649978d70266","signature":"35ec1f4e3598f87bdfdb161381bf9833f07e205c614cfc157fe8a9667a6053d9"},{"version":"02368e8851c37067e85d58b1677c223e590651332d0f8c72f6d1d10ff06c294d","signature":"cff912230eac799da5f80f17b67b686a2f97d37166514252ec5e7e5a26ba3f3b"},{"version":"035c1509225d71141d190973e6ea10e0d018770f562d794e866e94d81c9ef6fe","signature":"6ccdfa57a708bf498683868d60e3c707cc2c1adf032237de16f84a5dcb86b6e3"},{"version":"b633fdd9d9ee0492d837507498dee10ee4d022abdfc0ef835136732cc8ff6dfe","signature":"fbed9c5a9f147adced082af6f9fc773e3121f65b5605600bcc588b979e6d7d41"},{"version":"ca6655067125531c24919480fecd9e6fc853300e0cdc5edeebc524822b0a01d9","signature":"05fe1b60edcd163eb4bbc452e76660a22f95ed6c9af358b8ee63980c4378c421"},{"version":"bce7d4ac2bf01a197df17d6e7b738421b8cbfafe7a23e36474bb090081cbd5c2","signature":"c954daaaf284b59d8c0934fcb8633ee1c02222ecaa3d0030f73bda9e1e17c967"},{"version":"3169a4d9400aef2e089611415aec8edb5ea4da2b716dfc4ae442eb74ee8cabd8","signature":"6b02d1f0087b7ed13a9a0a15e7ee7737dde2837bda4dd6d1d480f5a863eb6078"},{"version":"81bd0f0553f41d0f2c78a1adbc470a3cc50fc15cfee8c854c3916ec485f28074","signature":"d1ee79509a15b7071cae5ae12ae9e9251ef981595591f33e99140497b5930a36"},{"version":"5048eb06e7fda376a6028bb0c825e7211a4c418896943c82b61f6af15bb78c2a","signature":"6eec1567eb6080f4e0b21ba2ee5bc1fdf8a4d608507beaa1043b8f19f8a35605"},{"version":"911f1618946c7c6cdc45149106edd0dde8709c9ba6a39112ce7b0d41306196ad","signature":"697754d00ccb9c3e9b3f49b867d69e411098c129c9d840752f5b8d373eeae3bd"},{"version":"aff29363b6d5e95482263fb4b60aac6086c0f9b4a6c22116233d0d67beae75e3","signature":"341b573d3667f20d60339a9be793c7fdbe61b67428ca1b11ced2c5ddb8321882"},"05321b823dd3781d0b6aac8700bfdc0c9181d56479fe52ba6a40c9196fd661a8",{"version":"c6713f68e9761117b8e6ec9be2992af70f395b01b4d058d8baac0b6108ecc763","signature":"2590965bf9ef1f0d1be0cf046845c563138258f8180f56986d62d04066b4155a"},"d071c1fa889272a3c73a1fb993916fbd6fb5c70d90a7a19a9beb7d83b3d6060b","e0cf974515cf71dd5b2d27db12b9fa9b37c1bf5670ac926e67265858bd7de1f2",{"version":"15f5e10ac88f0ec75916986974b866f60f7bd091170b5caf182238385b4fcb48","affectsGlobalScope":true},"a0a30d52ad434959f82a70b5a95c146be0ff4b76e49c1901442862c4ed4120c4","31969816c17f20e000e42e18ada7c7296fbb2f20f85a2fb7a6f50c7785b07865","9c8a14711069006b778331f204cc0c0560be09d7cb5c16c3598f6a1d10fbc8bc",{"version":"42e6485ccb1a1b8503bd7f734c3cff3af75dc6d25825ff72333a6fce6f9b3824","signature":"86aa5cd98adc1eb30f4151c4a0575567a29deff22bedc6308388a0aaac3ada6c"},{"version":"61c445305757534cc014fdbe585c2b182058f6161d4bbf088c23fe51925247e9","signature":"7a6f75241034763588d5e19deb1aa02fe24697a8d7cf48dbd84eb2b9f477a35d"},{"version":"cae7352bb245e704ef62707bbdc971e50e4012678113d5ba0b323b3d72166a20","signature":"cd21197dd57a535f112023ee3c4c5b6829e1294b0a7bddf902f1cd60556a8b1c"},{"version":"c6fe8344e3031fe508ae1215dbcb2d54b13b911fa2366ffe7510a4b44e96ce55","signature":"65de77c56894d87baa5d0f33964a2b9bd5aafc9159726e6fd33d3c6a36377be9"},{"version":"3eb48ff682498db13b352124f30308340a223ee405ca8c60685511eb87ba15be","signature":"1f921a0effb5a2af82bd16d6818d315c2720f209f3ae907e8b2522b007c0e349"},{"version":"46872cbcf7f1dc60e570fa9a97a9dad480bdca6de92386ec61031b7b0388b2f9","signature":"51b8df2285c4af64db9b02bbeaa82ea7334832584cd50a79fce929e4fd083b67"},{"version":"9acec24bfee6d4684e084e5b0f9ac1463199fcc09a55f309717e290e03b4afc2","signature":"2fd088628cba7e13eed0a1b5fd162b32c327a0d29bbe63dec1c16e9ecca10649"},{"version":"7e9569b2e39f27fabfcf3644816654d71fb01a107b2baf343cc9aaa730e78821","signature":"e52b62f8975a33bd32a4a17f9bb7448ff17f5e28d8a5912b0901c8c4475da6e3"},{"version":"8ea21d92ccfc4932ac22be7c557915328a8383d4b67a3add27e817a50cb8f617","signature":"525b64c6dcd7ebf552f06d89bed16bc275bc456037860bdedf2dff6db9a0fa57"},{"version":"c3701b37e821ea1544db3f825186b999b18bb1b3143789e7f7c00b401cea7025","signature":"27b7646d32656e1995f3410d76b9feb4fc61d2f3225c5e83442d1f76207704a9"},{"version":"89c2dd818e9dbb6a6da17a5a74606b508a20af7ec55067714879626932ce8d72","signature":"56524c89f40203a5bc531f76df1b2c2d077231fc75994487d4f1a227e7d8ab27"},{"version":"9cdf3b2979eb7fa85b37b8915ba702920ff5bee4d0a4692c5b5f7b1cd1834299","signature":"fb629e920ad81007307732f89afa5c310a5ab5ac946009cd2b0d5604c7926e03"},"6c0023ce73220afc10e2d80faf44781e048e297b13e3d69ba887c6725b54d132",{"version":"70521b6ab0dcba37539e5303104f29b721bfb2940b2776da4cc818c07e1fefc1","affectsGlobalScope":true},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true},"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a",{"version":"613b21ccdf3be6329d56e6caa13b258c842edf8377be7bc9f014ed14cdcfc308","affectsGlobalScope":true},{"version":"2d1319e6b5d0efd8c5eae07eb864a00102151e8b9afddd2d45db52e9aae002c4","affectsGlobalScope":true},"8e9c23ba78aabc2e0a27033f18737a6df754067731e69dc5f52823957d60a4b6","5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","24bd580b5743dc56402c440dc7f9a4f5d592ad7a419f25414d37a7bfe11e342b","25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","6bdc71028db658243775263e93a7db2fd2abfce3ca569c3cca5aee6ed5eb186d","cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","4d2b0eb911816f66abe4970898f97a2cfc902bcd743cbfa5017fad79f7ef90d8","bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","e53a3c2a9f624d90f24bf4588aacd223e7bec1b9d0d479b68d2f4a9e6011147f","24b8685c62562f5d98615c5a0c1d05f297cf5065f15246edfe99e81ec4c0e011","93507c745e8f29090efb99399c3f77bec07db17acd75634249dc92f961573387","339dc5265ee5ed92e536a93a04c4ebbc2128f45eeec6ed29f379e0085283542c","4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107",{"version":"ca6d304b929748ea15c33f28c1f159df18a94470b424ab78c52d68d40a41e1e9","affectsGlobalScope":true},"a72ffc815104fb5c075106ebca459b2d55d07862a773768fce89efc621b3964b","7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","3d77c73be94570813f8cadd1f05ebc3dc5e2e4fdefe4d340ca20cd018724ee36",{"version":"d674383111e06b6741c4ad2db962131b5b0fa4d0294b998566c635e86195a453","affectsGlobalScope":true},"f3e58c4c18a031cbb17abec7a4ad0bd5ae9fc70c1f4ba1e7fb921ad87c504aca","a3e8bafb2af8e850c644f4be7f5156cf7d23b7bfdc3b786bd4d10ed40329649c",{"version":"35ec8b6760fd7138bbf5809b84551e31028fb2ba7b6dc91d95d098bf212ca8b4","affectsGlobalScope":true},"a40826e8476694e90da94aa008283a7de50d1dafd37beada623863f1901cb7fb",{"version":"f77d9188e41291acf14f476e931972460a303e1952538f9546e7b370cb8d0d20","affectsGlobalScope":true},"b0c0d1d13be149f790a75b381b413490f98558649428bb916fd2d71a3f47a134","3c884d9d9ec454bdf0d5a0b8465bf8297d2caa4d853851d92cc417ac6f30b969","5a369483ac4cfbdf0331c248deeb36140e6907db5e1daed241546b4a2055f82c","e8f5b5cc36615c17d330eaf8eebbc0d6bdd942c25991f96ef122f246f4ff722f","f0bd7e6d931657b59605c44112eaf8b980ba7f957a5051ed21cb93d978cf2f45",{"version":"ee1ee365d88c4c6c0c0a5a5701d66ebc27ccd0bcfcfaa482c6e2e7fe7b98edf7","affectsGlobalScope":true},{"version":"4d7da7075068195f8f127f41c61e304cdca5aafb1be2d0f4fb67c6b4c3e98d50","affectsGlobalScope":true},"a4bdde4e601e9554a844e1e0d0ccfa05e183ef9d82ab3ac25f17c1709033d360","ad23fd126ff06e72728dd7bfc84326a8ca8cec2b9d2dac0193d42a777df0e7d8","9dd9f50652a176469e85fb65aa081d2e7eb807e2c476f378233de4f1f6604962","93bd413918fa921c8729cef45302b24d8b6c7855d72d5bf82d3972595ae8dcbf","4ff41188773cbf465807dd2f7059c7494cbee5115608efc297383832a1150c43","dccdf1677e531e33f8ac961a68bc537418c9a414797c1ea7e91307501cdc3f5e",{"version":"7edec695cdb707c7146ac34c44ca364469c7ea504344b3206c686e79f61b61a2","affectsGlobalScope":true},"d206b4baf4ddcc15d9d69a9a2f4999a72a2c6adeaa8af20fa7a9960816287555","93f437e1398a4f06a984f441f7fa7a9f0535c04399619b5c22e0b87bdee182cb","afbe24ab0d74694372baa632ecb28bb375be53f3be53f9b07ecd7fc994907de5",{"version":"70731d10d5311bd4cf710ef7f6539b62660f4b0bfdbb3f9fbe1d25fe6366a7fa","affectsGlobalScope":true},{"version":"a20f1e119615bf7632729fd89b6c0b5ffdc2df3b512d6304146294528e3ebe19","affectsGlobalScope":true},"9e043a1bc8fbf2a255bccf9bf27e0f1caf916c3b0518ea34aa72357c0afd42ec","137c2894e8f3e9672d401cc0a305dc7b1db7c69511cf6d3970fb53302f9eae09","3bc2f1e2c95c04048212c569ed38e338873f6a8593930cf5a7ef24ffb38fc3b6","8145e07aad6da5f23f2fcd8c8e4c5c13fb26ee986a79d03b0829b8fce152d8b2","f9d9d753d430ed050dc1bf2667a1bab711ccbb1c1507183d794cc195a5b085cc","9eece5e586312581ccd106d4853e861aaaa1a39f8e3ea672b8c3847eedd12f6e","235bfb54b4869c26f7e98e3d1f68dbfc85acf4cf5c38a4444a006fbf74a8a43d","37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","93452d394fdd1dc551ec62f5042366f011a00d342d36d50793b3529bfc9bd633",{"version":"bb715efb4857eb94539eafb420352105a0cff40746837c5140bf6b035dd220ba","affectsGlobalScope":true},"1851a3b4db78664f83901bb9cac9e45e03a37bb5933cc5bf37e10bb7e91ab4eb",{"version":"fdedf82878e4c744bc2a1c1e802ae407d63474da51f14a54babe039018e53d8f","affectsGlobalScope":true},{"version":"08353b04a3501d84fc8d7b49de99f6c1cc26026e6d9d697a18315f3bfe92ed03","affectsGlobalScope":true},"578d8bb6dcb2a1c03c4c3f8eb71abc9677e1a5c788b7f24848e3138ce17f3400","4f029899f9bae07e225c43aef893590541b2b43267383bf5e32e3a884d219ed5","ae56f65caf3be91108707bd8dfbccc2a57a91feb5daabf7165a06a945545ed26","a136d5de521da20f31631a0a96bf712370779d1c05b7015d7019a9b2a0446ca9",{"version":"5b566927cad2ed2139655d55d690ffa87df378b956e7fe1c96024c4d9f75c4cf","affectsGlobalScope":true},{"version":"bce947017cb7a2deebcc4f5ba04cead891ce6ad1602a4438ae45ed9aa1f39104","affectsGlobalScope":true},"efeedd8bbc5c0d53e760d8b120a010470722982e6ae14de8d1bcff66ebc2ae71","e2c72c065a36bc9ab2a00ac6a6f51e71501619a72c0609defd304d46610487a4","d91a7d8b5655c42986f1bdfe2105c4408f472831c8f20cf11a8c3345b6b56c8c",{"version":"616075a6ac578cf5a013ee12964188b4412823796ce0b202c6f1d2e4ca8480d7","affectsGlobalScope":true},"e8a979b8af001c9fc2e774e7809d233c8ca955a28756f52ee5dee88ccb0611d2","9091e564b81e7b4c382a33c62de704a699e10508190547d4f7c1c3e039d2db2b","785b9d575b49124ce01b46f5b9402157c7611e6532effa562ac6aebec0074dfc",{"version":"e58a3ce75105c1557e34fab7408942d77374e047c16383e80880ed1220166dfa","affectsGlobalScope":true},"a660aa95476042d3fdcc1343cf6bb8fdf24772d31712b1db321c5a4dcc325434","282f98006ed7fa9bb2cd9bdbe2524595cfc4bcd58a0bb3232e4519f2138df811","6222e987b58abfe92597e1273ad7233626285bc2d78409d4a7b113d81a83496b","cbe726263ae9a7bf32352380f7e8ab66ee25b3457137e316929269c19e18a2be","8b96046bf5fb0a815cba6b0880d9f97b7f3a93cf187e8dcfe8e2792e97f38f87",{"version":"bacf2c84cf448b2cd02c717ad46c3d7fd530e0c91282888c923ad64810a4d511","affectsGlobalScope":true},"402e5c534fb2b85fa771170595db3ac0dd532112c8fa44fc23f233bc6967488b","8885cf05f3e2abf117590bbb951dcf6359e3e5ac462af1c901cfd24c6a6472e2","4d979e3c12ffb6497d2b1dc5613130196d986fff764c4526360c0716a162e7e7","e61df3640a38d535fd4bc9f4a53aef17c296b58dc4b6394fd576b808dd2fe5e6","80781460eca408fe8d2937d9fdbbb780d6aac35f549621e6200c9bee1da5b8fe","4719c209b9c00b579553859407a7e5dcfaa1c472994bd62aa5dd3cc0757eb077","7ec359bbc29b69d4063fe7dad0baaf35f1856f914db16b3f4f6e3e1bca4099fa","b9261ac3e9944d3d72c5ee4cf888ad35d9743a5563405c6963c4e43ee3708ca4","c84fd54e8400def0d1ef1569cafd02e9f39a622df9fa69b57ccc82128856b916","a022503e75d6953d0e82c2c564508a5c7f8556fad5d7f971372d2d40479e4034","2ed6489ef46eb61442d067c08e87e3db501c0bfb2837eee4041a27bf3e792bb0","644491cde678bd462bb922c1d0cfab8f17d626b195ccb7f008612dc31f445d2d","d60fe6d59d4e19ecc65359490b8535e359ca4b760d2cdb56897ca75d09d41ba3","f45a2a8b1777ecb50ed65e1a04bb899d4b676529b7921bd5d69b08573a00c832","774b783046ba3d473948132d28a69f52a295b2f378f2939304118ba571b1355e","b5734e05c787a40e4f9efe71f16683c5f7dc3bdb0de7c04440c855bd000f8fa7","14ba97f0907144771331e1349fdccb5a13526eba0647e6b447e572376d811b6f","2a771d907aebf9391ac1f50e4ad37952943515eeea0dcc7e78aa08f508294668","7165050eddaed878c2d2cd3cafcaf171072ac39e586a048c0603712b5555f536","26e629be9bbd94ea1d465af83ce5a3306890520695f07be6eb016f8d734d02be","82e687ebd99518bc63ea04b0c3810fb6e50aa6942decd0ca6f7a56d9b9a212a6","7f698624bbbb060ece7c0e51b7236520ebada74b747d7523c7df376453ed6fea","8f07f2b6514744ac96e51d7cb8518c0f4de319471237ea10cf688b8d0e9d0225","9ae0ca65717af0d3b554a26fd333ad9c78ad3910ad4b22140ff02acb63076927","03f1d83d61696326ea29c8a1c15cbaccf61e92598d53f2ccae06078531f42448","2c8e55457aaf4902941dfdba4061935922e8ee6e120539c9801cd7b400fae050","3a9313fe5ace558b8b18e85f931da10b259e738775f411c061e5f15787b138eb","670a76db379b27c8ff42f1ba927828a22862e2ab0b0908e38b671f0e912cc5ed","9e0cf651e8e2c5b9bebbabdff2f7c6f8cedd91b1d9afcc0a854cdff053a88f1b","069bebfee29864e3955378107e243508b163e77ab10de6a5ee03ae06939f0bb9","f5e8546cfe500116aba8a6cb7ee171774b14a6db30d4bcd6e0aa5073e919e739","cadf7a128bda2a4937411ad8fc659c08142ae7b53a7559eada72e8c34a5ea273","77b55f8bfab90aa408704132d98b72f8762e2fe955eeda093ace44120d6adc1a","2f848b4e660b568651a6350565afc8ac5b0644853a2a863862807602cf244a05","6ac85cb2c23dcb52445b268258a7ea36d620054e7db53874d890bb64981ddc13","3d922ac35e7bd201c09c71d0a3be9cab0ac41bdd0d5115f2734c8555629e5414","ae18a824baa6829b4b687f4e678d97c2b3f0ee75a82e2cff792180002f1e2a82","fe1baccba85e2af0fdaca57b32b34f3fd602609bb0b29aeb0609000dbcd75446","ae04fe1adb6d10414645db0d9c264ae06a48cd73fbb043053afe9c72849e5e44",{"version":"e9f7405a92dd7c1b4b7d16d411ebe2951ce1be32d63668d40ac9b6e5d87e68a2","signature":"4b96dd19fd2949d28ce80e913412b0026dc421e5bf6c31d87c7b5eb11b5753b4"},"b66d13c54338e58c93f39d9d158a52c8c3db3cd04687eb87b752426d84359cfc","40afb567fb15f802cc373d3f968cb12f06ef91105997ac6cd1b7476f9f1400a7","b4f7765a7e4378d5553d62243e1294f9e84e6b155b786ff3a2d70dd90a0b7269","767b2fc647298d1e885ab9b5e80a3bfc955b7c3a56fdc67e09697ac66662617f","58d97a898371adf4648416a194695cac091094a93aec40d4bf80d178c655e322","33ab53254b48915b80729554b64dc520ddf52fa2fbb9d158f548e04184ebcf8c","0c85d40d15a7dccddc3f1687c956b44e884da668c4709ebe46443ba01f8e8842","bb9e974b872fc5efe3fbeb234afa1b167466822c521adec28f312b629f5dda56","c8263035d5bb170e586fef2a84cb43b6ae0a40e0febe619b3870733587629ab4","854d32966f04256f250530f7c03b4f7e11379c73b88d45cf8eb867ee3f790866","7372dded088ca5020b7bdc36c767207b5be95bac93db7d4da8939b4e5183d504","f141146eac82ec13c16311bc7d5088251c6c36e177946f804532b9457a5b4858","4af9e9cd8b6f583bbd4f5a25603385d0d32082b437334b70c90b5ea56a197301","68c96a0456890bd49e2871dd88c53ff7f9fd87eb32f2cd419e4a83f79a8d5ef1","73a58b4dd96dd47dab5b4029726b9bb923543ca24ddd04c6069577945ba46a88","b3554a8f9ac018e333c208a4eaac5744c6739430fd58a9442b904949a4850cdc","fd893a255c9b5fbcf730166bfc8cb13cbdfbd151212fe6d14bbc2850b1577dfb","288fa23f9ecb8231712fda606a90e8fcb8e5badc7d26b6aa55f41c935406654d","469a48cc4e8c79de08be72d4b91aba0c1ff0ff590ddaf4d63430cb8195d5d3b1","1a4c70b6a02db30f1f4cf606763ef4811f7f1ce845c6513e75ac92e8d066fb46","71a56feb625489eec845132b255df1429e3e0e7c76a4e3eef4731f82748076cb","a11f50b21d60f03639225314e0b81e1ffb73469f6500648c303b2a6b26f94d1d",{"version":"4025a454b1ca489b179ee8c684bdd70ff8c1967e382076ade53e7e4653e1daec","affectsGlobalScope":true},{"version":"984c09345059b76fc4221c2c54e53511f4c27a0794dfd6e9f81dc60f0b564e05","affectsGlobalScope":true},"c5d5ae4f669c76024b1e0faa2bad30cfbbd85f8a5b52fad6faaa82e198101ad0"],"root":[[87,114],[116,122],[126,138],[317,341],343,344,[351,362],[508,530]],"options":{"allowImportingTsExtensions":true,"composite":true,"jsx":4,"module":99,"noFallthroughCasesInSwitch":true,"noUnusedLocals":true,"noUnusedParameters":true,"skipLibCheck":true,"strict":true,"target":7,"useDefineForClassFields":true},"fileIdsList":[[312,313,314,315,362,368,411,532],[312,314,362,368,411,532],[312,313,314,362,368,411,532],[312,313,316,362,368,411,532],[362,368,411,532],[50,86,100,353,354,355,356,357,358,359,360,362,368,411,532],[50,340,362,368,411,532],[50,362,368,411,532],[50,106,112,362,368,411,532],[50,51,108,109,110,113,362,368,411,532],[50,106,362,368,411,532],[50,107,362,368,411,532],[50,116,362,368,411,532],[50,127,362,368,411,532],[50,349,350,362,368,411,532],[50,51,115,117,118,119,362,368,411,532],[49,50,362,368,411,532],[50,121,130,131,362,368,411,532],[50,133,362,368,411,532],[50,135,362,368,411,532],[50,51,108,109,120,121,122,126,132,134,136,137,362,368,411,532],[49,50,120,128,129,362,368,411,532,533],[49,50,171,311,312,314,316,319,321,322,362,368,411,532],[50,313,318,362,368,411,532],[50,320,362,368,411,532],[49,50,284,311,312,314,315,316,317,323,324,327,362,368,411,532],[50,284,316,328,362,368,411,532],[49,50,312,314,315,316,326,328,362,368,411,532],[50,325,362,368,411,532],[50,331,362,368,411,532,533],[50,333,362,368,411,532],[49,50,109,126,135,335,362,368,411,532],[50,51,109,328,329,330,332,334,336,362,368,411,532],[49,50,109,362,368,411,532],[50,114,138,337,338,339,362,368,411,532],[49,50,341,342,362,368,411,532],[50,125,362,368,411,532],[50,86,100,362,368,411,532],[50,352,362,368,411,532],[50,356,362,368,411,532],[50,335,362,368,411,532],[50,313,362,368,411,532],[101,362,368,411,532],[96,362,368,411,532],[102,103,104,105,362,368,411,532],[88,92,94,95,101,362,368,411,532],[362,368,411,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,532],[95,101,362,368,411,532],[111,362,368,411,532],[91,362,368,411,532],[95,362,368,411,532],[89,362,368,411,532],[86,95,96,97,98,99,100,362,368,411,532],[90,94,95,96,98,100,362,368,411,532],[92,95,362,368,411,532],[90,92,95,362,368,411,532],[87,95,362,368,411,532],[88,362,368,411,532],[90,92,93,95,362,368,411,532],[88,90,94,362,368,411,532],[368,411,532],[50,362,368,411,433,492,499,500,507,532],[362,368,411,493,532],[49,225,362,368,411,532],[227,362,368,411,532],[225,362,368,411,532],[225,226,228,229,362,368,411,532],[224,362,368,411,532],[49,171,185,201,218,230,255,258,259,362,368,411,532],[259,260,362,368,411,532],[185,218,362,368,411,532],[49,262,362,368,411,532],[262,263,264,265,362,368,411,532],[185,362,368,411,532],[262,362,368,411,532],[49,185,362,368,411,532],[267,362,368,411,532],[268,270,272,362,368,411,532],[269,362,368,411,532],[49,362,368,411,532],[271,362,368,411,532],[49,171,185,362,368,411,532],[49,258,273,276,362,368,411,532],[274,275,362,368,411,532],[171,185,224,261,362,368,411,532],[276,277,362,368,411,532],[230,261,266,278,362,368,411,532],[218,280,281,282,362,368,411,532],[49,224,362,368,411,532],[49,171,185,218,224,362,368,411,532],[49,185,224,362,368,411,532],[186,187,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,362,368,411,532],[185,224,362,368,411,532],[201,202,362,368,411,532],[185,220,362,368,411,532],[150,185,362,368,411,532],[171,362,368,411,532],[201,362,368,411,532],[284,362,368,411,532],[185,201,224,255,258,279,283,362,368,411,532],[171,256,362,368,411,532],[256,257,362,368,411,532],[171,185,224,362,368,411,532],[188,189,190,193,195,197,200,362,368,411,532],[198,199,362,368,411,532],[188,198,362,368,411,532],[185,188,362,368,411,532],[194,362,368,411,532],[49,188,193,362,368,411,532],[191,192,362,368,411,532],[49,188,191,362,368,411,532],[196,362,368,411,532],[49,180,185,224,362,368,411,532],[188,362,368,411,532],[49,220,362,368,411,532],[220,221,222,223,362,368,411,532],[220,221,362,368,411,532],[49,171,180,185,218,219,221,279,362,368,411,532],[172,180,224,362,368,411,532],[172,173,181,182,183,184,362,368,411,532],[49,171,362,368,411,532],[174,362,368,411,532],[174,185,362,368,411,532],[174,175,176,177,178,179,362,368,411,532],[231,232,233,362,368,411,532],[180,234,241,243,254,362,368,411,532],[242,362,368,411,532],[171,185,362,368,411,532],[235,236,237,238,239,240,362,368,411,532],[184,362,368,411,532],[244,245,246,247,248,249,250,251,252,253,362,368,411,532],[290,362,368,411,532],[49,284,289,362,368,411,532],[292,362,368,411,532],[292,293,294,362,368,411,532],[171,284,362,368,411,532],[49,171,218,284,289,292,362,368,411,532],[289,291,295,300,303,310,362,368,411,532],[302,362,368,411,532],[301,362,368,411,532],[289,362,368,411,532],[296,297,298,299,362,368,411,532],[285,286,287,288,362,368,411,532],[284,286,362,368,411,532],[304,305,306,307,308,309,362,368,411,532],[150,362,368,411,532],[150,151,362,368,411,532],[154,155,156,362,368,411,532],[158,159,160,362,368,411,532],[162,362,368,411,532],[139,140,141,142,143,144,145,146,147,362,368,411,532],[148,149,152,153,157,161,163,169,170,362,368,411,532],[164,165,166,167,168,362,368,411,532],[49,346,362,368,411,532],[346,347,348,362,368,411,532],[49,345,362,368,411,532],[85,362,368,411,532],[70,71,362,368,411,532],[81,362,368,411,532],[58,362,368,411,532],[63,362,368,411,532],[56,362,368,411,532],[54,57,60,63,74,75,77,79,80,362,368,411,532],[63,64,65,81,362,368,411,532],[59,66,67,73,81,362,368,411,532],[57,59,60,63,64,65,66,67,73,74,75,76,77,78,79,80,81,82,83,84,362,368,411,532],[72,362,368,411,532],[63,76,362,368,411,532],[57,63,362,368,411,532],[60,63,362,368,411,532],[55,362,368,411,532],[55,57,61,362,368,411,532],[57,362,368,411,532],[55,57,62,362,368,411,532],[63,64,76,78,362,368,411,532],[75,362,368,411,532],[63,75,76,362,368,411,532],[362,368,411,461,462,532],[362,368,411,496,498,532],[362,368,411,498,504,532],[362,368,411,498,503,505,532],[68,362,368,411,532],[362,368,411,493,494,495,496,497,532],[362,368,411,493,495,532],[362,368,408,411,532],[362,368,410,411,532],[362,368,411,416,445,532],[362,368,411,412,417,423,424,431,442,453,532],[362,368,411,412,413,423,431,532],[362,363,364,365,368,411,532],[362,368,411,414,454,532],[362,368,411,415,416,424,432,532],[362,368,411,416,442,450,532],[362,368,411,417,419,423,431,532],[362,368,410,411,418,532],[362,368,411,419,420,532],[362,368,411,423,532],[362,368,411,421,423,532],[362,368,410,411,423,532],[362,368,411,423,424,425,442,453,532],[362,368,411,423,424,425,438,442,445,532],[362,368,406,411,458,532],[362,368,411,419,423,426,431,442,453,532],[362,368,411,423,424,426,427,431,442,450,453,532],[362,368,411,426,428,442,450,453,532],[362,368,411,423,429,532],[362,368,411,430,453,458,532],[362,368,411,419,423,431,442,532],[362,368,411,432,532],[362,368,411,433,532],[362,368,410,411,434,532],[362,368,408,409,410,411,412,413,414,415,416,417,418,419,420,421,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,532],[362,368,411,436,532],[362,368,411,437,532],[362,368,411,423,438,439,532],[362,368,411,438,440,454,456,532],[362,368,411,423,442,443,444,445,532],[362,368,411,442,444,532],[362,368,411,442,443,532],[362,368,411,445,532],[362,368,411,446,532],[362,368,408,411,442,532],[362,368,411,423,448,449,532],[362,368,411,448,449,532],[362,368,411,416,431,442,450,532],[362,368,411,451,532],[362,411,532],[362,366,367,368,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,532],[362,368,411,431,452,532],[362,368,411,426,437,453,532],[362,368,411,416,454,532],[362,368,411,442,455,532],[362,368,411,430,456,532],[362,368,411,457,532],[362,368,411,416,423,425,434,442,453,456,458,532],[362,368,411,442,459,532],[46,47,48,362,368,411,532],[362,368,411,492,498,532],[52,53,362,368,411,532],[362,368,411,484,532],[362,368,411,482,484,532],[362,368,411,473,481,482,483,485,532],[362,368,411,471,532],[362,368,411,474,479,484,487,532],[362,368,411,470,487,532],[362,368,411,474,475,478,479,480,487,532],[362,368,411,474,475,476,478,479,487,532],[362,368,411,471,472,473,474,475,479,480,481,483,484,485,487,532],[362,368,411,487,532],[362,368,411,469,471,472,473,474,475,476,478,479,480,481,482,483,484,485,486,532],[362,368,411,469,487,532],[362,368,411,474,476,477,479,480,487,532],[362,368,411,478,487,532],[362,368,411,479,480,484,487,532],[362,368,411,472,482,532],[362,368,411,502,532],[362,368,411,462,491,532],[53,362,368,411,532],[69,362,368,411,532],[362,368,378,382,411,453,532],[362,368,378,411,442,453,532],[362,368,373,411,532],[362,368,375,378,411,450,453,532],[362,368,411,431,450,532],[362,368,411,460,532],[362,368,373,411,460,532],[362,368,375,378,411,431,453,532],[362,368,370,371,374,377,411,423,442,453,532],[362,368,378,385,411,532],[362,368,370,376,411,532],[362,368,378,399,400,411,532],[362,368,374,378,411,445,453,460,532],[362,368,399,411,460,532],[362,368,372,373,411,460,532],[362,368,378,411,532],[362,368,372,373,374,375,376,377,378,379,380,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,411,532],[362,368,378,393,411,532],[362,368,378,385,386,411,532],[362,368,376,378,386,387,411,532],[362,368,377,411,532],[362,368,370,373,378,411,532],[362,368,378,382,386,387,411,532],[362,368,382,411,532],[362,368,376,378,381,411,453,532],[362,368,370,375,378,385,411,532],[362,368,411,442,532],[362,368,373,378,399,411,458,460,532],[362,368,411,492,501,506,532],[362,368,411,492,532],[362,368,411,531],[362,368,411,423,424,426,427,428,431,442,450,453,459,460,462,463,464,465,466,467,468,488,489,490,491,532],[362,368,411,464,465,466,467,532],[362,368,411,464,465,466,532],[362,368,411,464,532],[362,368,411,465,532],[362,368,411,466,490,532],[362,368,411,462,532],[123,124,362,368,411,532],[123,362,368,411,532],[312,313,316,368,411],[368,411],[86,100],[50],[50,109],[101],[49],[312,314],[50,313],[50,312,315],[284,316,328],[312,315,316,328],[325],[109],[532],[313],[101,368,411],[96,368,411],[102,103,104,105,368,411],[88,92,94,95,101,368,411],[368,411,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529],[95,101,368,411],[111,368,411],[91,368,411],[95,368,411],[89,368,411],[86,95,96,97,98,99,100,368,411],[90,94,95,96,98,100,368,411],[92,95,368,411],[87,95,368,411],[88,368,411],[90,92,93,95,368,411],[88,90,94,368,411],[492],[368,411,493],[49,225,368,411],[227,368,411],[225,368,411],[225,226,228,229,368,411],[224,368,411],[49,171,185,201,218,230,255,258,259,368,411],[259,260,368,411],[185,218,368,411],[49,262,368,411],[262,263,264,265,368,411],[185,368,411],[262,368,411],[49,185,368,411],[267,368,411],[268,270,272,368,411],[269,368,411],[49,368,411],[271,368,411],[49,171,185,368,411],[49,258,273,276,368,411],[274,275,368,411],[171,185,224,261,368,411],[276,277,368,411],[230,261,266,278,368,411],[218,280,281,282,368,411],[49,224,368,411],[49,171,185,218,224,368,411],[49,185,224,368,411],[186,187,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,368,411],[185,224,368,411],[201,202,368,411],[185,220,368,411],[150,185,368,411],[171,368,411],[201,368,411],[284,368,411],[185,201,224,255,258,279,283,368,411],[171,256,368,411],[256,257,368,411],[171,185,224,368,411],[188,189,190,193,195,197,200,368,411],[198,199,368,411],[188,198,368,411],[185,188,368,411],[194,368,411],[49,188,193,368,411],[191,192,368,411],[49,188,191,368,411],[196,368,411],[49,180,185,224,368,411],[188,368,411],[49,220,368,411],[220,221,222,223,368,411],[220,221,368,411],[49,171,180,185,218,219,221,279,368,411],[172,180,224,368,411],[172,173,181,182,183,184,368,411],[49,171,368,411],[174,368,411],[174,185,368,411],[174,175,176,177,178,179,368,411],[231,232,233,368,411],[180,234,241,243,254,368,411],[242,368,411],[171,185,368,411],[235,236,237,238,239,240,368,411],[184,368,411],[244,245,246,247,248,249,250,251,252,253,368,411],[290,368,411],[49,284,289,368,411],[292,368,411],[292,293,294,368,411],[171,284,368,411],[49,171,218,284,289,292,368,411],[289,291,295,300,303,310,368,411],[302,368,411],[301,368,411],[289,368,411],[296,297,298,299,368,411],[285,286,287,288,368,411],[284,286,368,411],[304,305,306,307,308,309,368,411],[150,368,411],[150,151,368,411],[154,155,156,368,411],[158,159,160,368,411],[162,368,411],[139,140,141,142,143,144,145,146,147,368,411],[148,149,152,153,157,161,163,169,170,368,411],[164,165,166,167,168,368,411],[85,368,411],[70,71,368,411],[81,368,411],[58,368,411],[63,368,411],[56,368,411],[54,57,60,63,74,75,77,79,80,368,411],[63,64,65,81,368,411],[59,66,67,73,81,368,411],[57,59,60,63,64,65,66,67,73,74,75,76,77,78,79,80,81,82,83,84,368,411],[72,368,411],[63,76,368,411],[57,63,368,411],[60,63,368,411],[55,368,411],[55,57,61,368,411],[57,368,411],[55,57,62,368,411],[63,64,76,78,368,411],[75,368,411],[63,75,76,368,411],[68,368,411],[368,411,493,494,495,496,497],[368,411,493,495],[368,408,411],[368,410,411],[368,411,416,445],[368,411,412,417,423,424,431,442,453],[368,411,412,413,423,431],[363,364,365,368,411],[368,411,414,454],[368,411,415,416,424,432],[368,411,416,442,450],[368,411,417,419,423,431],[368,410,411,418],[368,411,419,420],[368,411,423],[368,411,421,423],[368,410,411,423],[368,411,423,424,425,442,453],[368,411,423,424,425,438,442,445],[368,406,411,458],[368,411,419,423,426,431,442,453],[368,411,423,424,426,427,431,442,450,453],[368,411,426,428,442,450,453],[368,411,423,429],[368,411,430,453,458],[368,411,419,423,431,442],[368,411,432],[368,411,433],[368,410,411,434],[368,408,409,410,411,412,413,414,415,416,417,418,419,420,421,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459],[368,411,436],[368,411,437],[368,411,423,438,439],[368,411,438,440,454,456],[368,411,423,442,443,444,445],[368,411,442,444],[368,411,442,443],[368,411,445],[368,411,446],[368,408,411,442],[368,411,423,448,449],[368,411,448,449],[368,411,416,431,442,450],[368,411,451],[411],[366,367,368,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459],[368,411,431,452],[368,411,426,437,453],[368,411,416,454],[368,411,442,455],[368,411,430,456],[368,411,457],[368,411,416,423,425,434,442,453,456,458],[368,411,442,459],[46,47,48,368,411],[368,411,492,498],[49,50,368,411],[52,53,368,411],[368,411,484],[368,411,482,484],[368,411,473,481,482,483,485],[368,411,471],[368,411,474,479,484,487],[368,411,470,487],[368,411,474,475,478,479,480,487],[368,411,474,475,476,478,479,487],[368,411,471,472,473,474,475,479,480,481,483,484,485,487],[368,411,487],[368,411,469,471,472,473,474,475,476,478,479,480,481,482,483,484,485,486],[368,411,469,487],[368,411,474,476,477,479,480,487],[368,411,478,487],[368,411,479,480,484,487],[368,411,472,482],[368,411,462,534],[368,411,461,462],[53,368,411],[69,368,411],[368,378,382,411,453],[368,378,411,442,453],[368,373,411],[368,375,378,411,450,453],[368,411,431,450],[368,411,460],[368,373,411,460],[368,375,378,411,431,453],[368,370,371,374,377,411,423,442,453],[368,378,385,411],[368,370,376,411],[368,378,399,400,411],[368,374,378,411,445,453,460],[368,399,411,460],[368,372,373,411,460],[368,378,411],[368,372,373,374,375,376,377,378,379,380,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,411],[368,378,393,411],[368,378,385,386,411],[368,376,378,386,387,411],[368,377,411],[368,370,373,378,411],[368,378,382,386,387,411],[368,382,411],[368,376,378,381,411,453],[368,370,375,378,385,411],[368,411,442],[368,373,378,399,411,458,460],[368,411,492],[368,411,531],[368,411,423,424,426,427,428,431,442,450,453,459,460,462,463,464,465,466,467,468,488,489,490,491],[368,411,464,465,466,467],[368,411,464,465,466],[368,411,464],[368,411,465],[368,411,466,490],[368,411,462],[123,124,368,411],[123,368,411]],"referencedMap":[[316,1],[313,2],[315,3],[314,4],[312,5],[361,6],[341,7],[350,8],[110,8],[113,9],[114,10],[107,11],[108,12],[116,9],[117,13],[127,11],[128,14],[351,15],[118,8],[119,9],[120,16],[121,17],[131,11],[132,18],[133,11],[134,19],[136,20],[137,9],[138,21],[352,8],[122,8],[135,8],[335,8],[129,11],[130,22],[322,11],[323,23],[318,11],[319,24],[320,11],[321,25],[317,11],[328,26],[324,27],[327,28],[326,29],[331,11],[332,30],[333,11],[334,31],[336,32],[329,8],[330,9],[337,33],[339,34],[338,11],[340,35],[343,36],[126,37],[353,38],[355,38],[356,39],[357,8],[358,40],[359,20],[360,41],[354,38],[325,42],[109,8],[344,5],[102,43],[104,44],[103,5],[106,45],[105,44],[510,46],[511,46],[512,46],[513,46],[514,46],[515,46],[516,46],[517,46],[518,46],[519,46],[520,46],[521,46],[522,46],[530,47],[527,46],[525,46],[526,46],[523,46],[529,46],[524,46],[528,46],[111,48],[112,49],[92,50],[91,5],[99,51],[90,52],[88,5],[100,53],[101,54],[97,5],[98,55],[93,56],[96,57],[89,58],[87,5],[94,59],[95,60],[362,61],[508,62],[509,5],[495,63],[493,5],[226,64],[228,65],[227,5],[229,66],[230,67],[225,68],[260,69],[261,70],[259,71],[263,72],[266,73],[262,74],[264,75],[265,75],[267,76],[268,77],[273,78],[270,79],[269,80],[272,81],[271,82],[277,83],[276,84],[274,85],[275,74],[278,86],[279,87],[283,88],[281,89],[280,90],[282,91],[218,92],[186,74],[187,93],[203,94],[217,93],[204,95],[206,74],[205,5],[207,74],[208,96],[215,74],[209,5],[210,5],[211,5],[212,74],[213,97],[214,98],[202,76],[216,99],[284,100],[257,101],[258,102],[256,103],[201,104],[200,105],[199,106],[198,107],[195,108],[194,109],[191,107],[193,110],[192,111],[197,112],[196,109],[188,113],[189,114],[190,114],[221,95],[219,95],[222,115],[224,116],[223,117],[220,118],[172,97],[173,5],[181,119],[185,120],[182,5],[183,121],[184,5],[175,122],[176,122],[179,123],[180,124],[178,122],[177,123],[174,93],[231,74],[232,74],[233,74],[234,125],[255,126],[243,127],[242,5],[235,128],[238,74],[236,74],[239,74],[241,129],[240,130],[237,74],[251,5],[244,5],[245,5],[246,74],[247,74],[248,5],[249,74],[250,5],[254,131],[252,5],[253,74],[291,132],[290,133],[294,134],[295,135],[292,136],[293,137],[311,138],[303,139],[302,140],[301,99],[296,141],[300,142],[297,141],[298,141],[299,141],[286,99],[285,5],[289,143],[287,136],[288,144],[304,5],[305,5],[306,99],[310,145],[307,5],[308,99],[309,141],[149,5],[151,146],[152,147],[150,5],[153,5],[154,5],[157,148],[155,5],[156,5],[158,5],[159,5],[160,5],[161,149],[162,5],[163,150],[148,151],[139,5],[140,5],[142,5],[141,80],[143,80],[144,5],[145,80],[146,5],[147,5],[171,152],[169,153],[164,5],[165,5],[166,5],[167,5],[168,5],[170,5],[347,154],[349,155],[346,156],[348,80],[86,157],[72,158],[82,159],[59,160],[78,161],[57,162],[81,163],[55,5],[66,164],[74,165],[85,166],[67,5],[73,167],[83,5],[77,168],[61,169],[64,170],[84,5],[56,171],[75,5],[60,5],[62,172],[65,173],[63,174],[79,175],[76,176],[80,177],[501,178],[504,179],[505,180],[506,181],[69,182],[68,5],[498,183],[494,63],[496,184],[497,63],[461,5],[408,185],[409,185],[410,186],[411,187],[412,188],[413,189],[363,5],[366,190],[364,5],[365,5],[414,191],[415,192],[416,193],[417,194],[418,195],[419,196],[420,196],[422,197],[421,198],[423,199],[424,200],[425,201],[407,202],[426,203],[427,204],[428,205],[429,206],[430,207],[431,208],[432,209],[433,210],[434,211],[435,212],[436,213],[437,214],[438,215],[439,215],[440,216],[441,5],[442,217],[444,218],[443,219],[445,220],[446,221],[447,222],[448,223],[449,224],[450,225],[451,226],[368,227],[367,5],[460,228],[452,229],[453,230],[454,231],[455,232],[456,233],[457,234],[458,235],[459,236],[48,5],[342,80],[115,80],[46,5],[49,237],[50,80],[499,238],[369,5],[47,5],[468,5],[51,17],[345,5],[58,5],[52,5],[54,239],[485,240],[483,241],[484,242],[472,243],[473,241],[480,244],[471,245],[476,246],[486,5],[477,247],[482,248],[488,249],[487,250],[470,251],[478,252],[479,253],[474,254],[481,240],[475,255],[502,5],[503,256],[463,257],[462,178],[469,5],[71,258],[70,259],[44,5],[45,5],[8,5],[9,5],[11,5],[10,5],[2,5],[12,5],[13,5],[14,5],[15,5],[16,5],[17,5],[18,5],[19,5],[3,5],[4,5],[20,5],[24,5],[21,5],[22,5],[23,5],[25,5],[26,5],[27,5],[5,5],[28,5],[29,5],[30,5],[31,5],[6,5],[35,5],[32,5],[33,5],[34,5],[36,5],[7,5],[37,5],[42,5],[43,5],[38,5],[39,5],[40,5],[41,5],[1,5],[53,5],[385,260],[395,261],[384,260],[405,262],[376,263],[375,264],[404,265],[398,266],[403,267],[378,268],[392,269],[377,270],[401,271],[373,272],[372,265],[402,273],[374,274],[379,275],[380,5],[383,275],[370,5],[406,276],[396,277],[387,278],[388,279],[390,280],[386,281],[389,282],[399,265],[381,283],[382,284],[391,285],[371,286],[394,277],[393,275],[397,5],[400,287],[533,80],[507,288],[500,289],[532,290],[492,291],[489,292],[467,293],[465,294],[464,5],[466,295],[490,5],[531,296],[491,297],[125,298],[124,299],[123,5]],"exportedModulesMap":[[316,1],[313,2],[315,3],[314,300],[312,301],[361,302],[341,303],[114,304],[107,305],[108,303],[117,303],[128,303],[351,303],[120,306],[132,303],[134,303],[138,304],[129,305],[130,303],[322,305],[323,307],[318,305],[319,308],[321,303],[328,309],[324,310],[327,311],[326,312],[331,305],[332,303],[334,303],[336,313],[337,304],[339,313],[340,303],[343,314],[353,302],[355,302],[354,302],[325,315],[344,301],[102,316],[104,317],[103,301],[106,318],[105,317],[510,319],[511,319],[512,319],[513,319],[514,319],[515,319],[516,319],[517,319],[518,319],[519,319],[520,319],[521,319],[522,319],[530,320],[527,319],[525,319],[526,319],[523,319],[529,319],[524,319],[528,319],[111,321],[112,322],[92,323],[91,301],[99,324],[90,325],[88,301],[100,326],[101,327],[97,301],[98,328],[93,56],[96,329],[89,330],[87,301],[94,331],[95,332],[362,61],[508,333],[509,5],[495,334],[493,301],[226,335],[228,336],[227,301],[229,337],[230,338],[225,339],[260,340],[261,341],[259,342],[263,343],[266,344],[262,345],[264,346],[265,346],[267,347],[268,348],[273,349],[270,350],[269,351],[272,352],[271,353],[277,354],[276,355],[274,356],[275,345],[278,357],[279,358],[283,359],[281,360],[280,361],[282,362],[218,363],[186,345],[187,364],[203,365],[217,364],[204,366],[206,345],[205,301],[207,345],[208,367],[215,345],[209,301],[210,301],[211,301],[212,345],[213,368],[214,369],[202,347],[216,370],[284,371],[257,372],[258,373],[256,374],[201,375],[200,376],[199,377],[198,378],[195,379],[194,380],[191,378],[193,381],[192,382],[197,383],[196,380],[188,384],[189,385],[190,385],[221,366],[219,366],[222,386],[224,387],[223,388],[220,389],[172,368],[173,301],[181,390],[185,391],[182,301],[183,392],[184,301],[175,393],[176,393],[179,394],[180,395],[178,393],[177,394],[174,364],[231,345],[232,345],[233,345],[234,396],[255,397],[243,398],[242,301],[235,399],[238,345],[236,345],[239,345],[241,400],[240,401],[237,345],[251,301],[244,301],[245,301],[246,345],[247,345],[248,301],[249,345],[250,301],[254,402],[252,301],[253,345],[291,403],[290,404],[294,405],[295,406],[292,407],[293,408],[311,409],[303,410],[302,411],[301,370],[296,412],[300,413],[297,412],[298,412],[299,412],[286,370],[285,301],[289,414],[287,407],[288,415],[304,301],[305,301],[306,370],[310,416],[307,301],[308,370],[309,412],[149,301],[151,417],[152,418],[150,301],[153,301],[154,301],[157,419],[155,301],[156,301],[158,301],[159,301],[160,301],[161,420],[162,301],[163,421],[148,422],[139,301],[140,301],[142,301],[141,351],[143,351],[144,301],[145,351],[146,301],[147,301],[171,423],[169,424],[164,301],[165,301],[166,301],[167,301],[168,301],[170,301],[347,154],[349,155],[346,156],[348,80],[86,425],[72,426],[82,427],[59,428],[78,429],[57,430],[81,431],[55,301],[66,432],[74,433],[85,434],[67,301],[73,435],[83,301],[77,436],[61,437],[64,438],[84,301],[56,439],[75,301],[60,301],[62,440],[65,441],[63,442],[79,443],[76,444],[80,445],[501,178],[504,179],[505,180],[506,181],[69,446],[68,301],[498,447],[494,334],[496,448],[497,334],[461,301],[408,449],[409,449],[410,450],[411,451],[412,452],[413,453],[363,301],[366,454],[364,301],[365,301],[414,455],[415,456],[416,457],[417,458],[418,459],[419,460],[420,460],[422,461],[421,462],[423,463],[424,464],[425,465],[407,466],[426,467],[427,468],[428,469],[429,470],[430,471],[431,472],[432,473],[433,474],[434,475],[435,476],[436,477],[437,478],[438,479],[439,479],[440,480],[441,301],[442,481],[444,482],[443,483],[445,484],[446,485],[447,486],[448,487],[449,488],[450,489],[451,490],[368,491],[367,301],[460,492],[452,493],[453,494],[454,495],[455,496],[456,497],[457,498],[458,499],[459,500],[48,301],[342,351],[115,351],[46,301],[49,501],[50,351],[499,502],[369,301],[47,301],[468,301],[51,503],[345,5],[58,301],[52,301],[54,504],[485,505],[483,506],[484,507],[472,508],[473,506],[480,509],[471,510],[476,511],[486,301],[477,512],[482,513],[488,514],[487,515],[470,516],[478,517],[479,518],[474,519],[481,505],[475,520],[502,5],[503,256],[463,521],[462,522],[469,301],[71,523],[70,524],[44,301],[45,301],[8,301],[9,301],[11,301],[10,301],[2,301],[12,301],[13,301],[14,301],[15,301],[16,301],[17,301],[18,301],[19,301],[3,301],[4,301],[20,301],[24,301],[21,301],[22,301],[23,301],[25,301],[26,301],[27,301],[5,301],[28,301],[29,301],[30,301],[31,301],[6,301],[35,301],[32,301],[33,301],[34,301],[36,301],[7,301],[37,301],[42,301],[43,301],[38,301],[39,301],[40,301],[41,301],[1,301],[53,301],[385,525],[395,526],[384,525],[405,527],[376,528],[375,529],[404,530],[398,531],[403,532],[378,533],[392,534],[377,535],[401,536],[373,537],[372,530],[402,538],[374,539],[379,540],[380,301],[383,540],[370,301],[406,541],[396,542],[387,543],[388,544],[390,545],[386,546],[389,547],[399,530],[381,548],[382,549],[391,550],[371,551],[394,542],[393,540],[397,301],[400,552],[533,80],[507,288],[500,553],[532,554],[492,555],[489,556],[467,557],[465,558],[464,301],[466,559],[490,301],[531,560],[491,561],[125,562],[124,563],[123,301]],"semanticDiagnosticsPerFile":[316,313,315,314,312,361,341,350,110,113,114,107,108,116,117,127,128,351,118,119,120,121,131,132,133,134,136,137,138,352,122,135,335,129,130,322,323,318,319,320,321,317,328,324,327,326,331,332,333,334,336,329,330,337,339,338,340,343,126,353,355,356,357,358,359,360,354,325,109,344,102,104,103,106,105,510,511,512,513,514,515,516,517,518,519,520,521,522,530,527,525,526,523,529,524,528,111,112,92,91,99,90,88,100,101,97,98,93,96,89,87,94,95,362,508,509,495,493,226,228,227,229,230,225,260,261,259,263,266,262,264,265,267,268,273,270,269,272,271,277,276,274,275,278,279,283,281,280,282,218,186,187,203,217,204,206,205,207,208,215,209,210,211,212,213,214,202,216,284,257,258,256,201,200,199,198,195,194,191,193,192,197,196,188,189,190,221,219,222,224,223,220,172,173,181,185,182,183,184,175,176,179,180,178,177,174,231,232,233,234,255,243,242,235,238,236,239,241,240,237,251,244,245,246,247,248,249,250,254,252,253,291,290,294,295,292,293,311,303,302,301,296,300,297,298,299,286,285,289,287,288,304,305,306,310,307,308,309,149,151,152,150,153,154,157,155,156,158,159,160,161,162,163,148,139,140,142,141,143,144,145,146,147,171,169,164,165,166,167,168,170,347,349,346,348,86,72,82,59,78,57,81,55,66,74,85,67,73,83,77,61,64,84,56,75,60,62,65,63,79,76,80,501,504,505,506,69,68,498,494,496,497,461,408,409,410,411,412,413,363,366,364,365,414,415,416,417,418,419,420,422,421,423,424,425,407,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,444,443,445,446,447,448,449,450,451,368,367,460,452,453,454,455,456,457,458,459,48,342,115,46,49,50,499,369,47,468,51,345,58,52,54,485,483,484,472,473,480,471,476,486,477,482,488,487,470,478,479,474,481,475,502,503,463,462,469,71,70,44,45,8,9,11,10,2,12,13,14,15,16,17,18,19,3,4,20,24,21,22,23,25,26,27,5,28,29,30,31,6,35,32,33,34,36,7,37,42,43,38,39,40,41,1,53,385,395,384,405,376,375,404,398,403,378,392,377,401,373,372,402,374,379,380,383,370,406,396,387,388,390,386,389,399,381,382,391,371,394,393,397,400,533,507,500,532,492,489,467,465,464,466,490,531,491,125,124,123],"affectedFilesPendingEmit":[361,341,110,113,114,107,108,116,117,127,128,351,118,119,120,121,131,132,133,134,136,137,138,352,122,135,335,129,130,322,323,318,319,320,321,317,328,324,327,326,331,332,333,334,336,329,330,337,339,338,340,343,126,353,355,356,357,358,359,360,354,325,109,508],"emitSignatures":[107,108,109,110,113,114,116,117,118,119,120,121,122,126,127,128,129,130,131,132,133,134,135,136,137,138,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,343,351,352,353,354,355,356,357,358,359,360,361,508]},"version":"5.3.3"} +{"program":{"fileNames":["../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es5.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2016.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.dom.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.dom.iterable.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.core.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.date.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.object.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.string.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.intl.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.intl.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.promise.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.array.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.object.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.string.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.intl.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.date.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.promise.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.string.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.intl.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.number.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.decorators.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../node_modules/.pnpm/@types+react@18.3.12/node_modules/@types/react/global.d.ts","../node_modules/.pnpm/csstype@3.1.3/node_modules/csstype/index.d.ts","../node_modules/.pnpm/@types+prop-types@15.7.13/node_modules/@types/prop-types/index.d.ts","../node_modules/.pnpm/@types+react@18.3.12/node_modules/@types/react/index.d.ts","../node_modules/.pnpm/@types+react@18.3.12/node_modules/@types/react/jsx-runtime.d.ts","../@noctacrdt/dist/nodeid.d.ts","../@noctacrdt/dist/interfaces.d.ts","../@noctacrdt/dist/node.d.ts","../@noctacrdt/dist/linkedlist.d.ts","../@noctacrdt/dist/crdt.d.ts","../@noctacrdt/dist/page.d.ts","../@noctacrdt/dist/workspace.d.ts","../node_modules/.pnpm/framer-motion@11.11.13_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/framer-motion/dist/index.d.ts","../node_modules/.pnpm/mlly@1.7.2/node_modules/mlly/dist/index.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/typescript.d.ts","../node_modules/.pnpm/pkg-types@1.0.3/node_modules/pkg-types/dist/index.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/csstype.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/selectors.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/conditions.d.ts","../node_modules/.pnpm/microdiff@1.3.2/node_modules/microdiff/dist/index.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/artifact.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/static-css.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/prop-type.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/style-props.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/system-types.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/recipe.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/style-rules.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/hooks-api.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/logger.d.ts","../node_modules/.pnpm/@ts-morph+common@0.22.0/node_modules/@ts-morph/common/lib/typescript.d.ts","../node_modules/.pnpm/@ts-morph+common@0.22.0/node_modules/@ts-morph/common/lib/ts-morph-common.d.ts","../node_modules/.pnpm/ts-morph@21.0.1/node_modules/ts-morph/lib/ts-morph.d.ts","../node_modules/.pnpm/ts-evaluator@1.2.0_typescript@5.3.3/node_modules/ts-evaluator/dist/esm/index.d.ts","../node_modules/.pnpm/@pandacss+extractor@0.40.1_typescript@5.3.3/node_modules/@pandacss/extractor/dist/index.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/parser.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/hooks.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/shared.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/tokens.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/pattern.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/composition.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/theme.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/utility.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/config.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/analyze-report.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/parts.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/runtime.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/index.d.ts","../node_modules/.pnpm/@pandacss+dev@0.47.1_typescript@5.3.3/node_modules/@pandacss/dev/dist/index.d.ts","./styled-system/types/static-css.d.ts","./styled-system/types/csstype.d.ts","./styled-system/types/selectors.d.ts","./styled-system/types/conditions.d.ts","./styled-system/tokens/tokens.d.ts","./styled-system/tokens/index.d.ts","./styled-system/types/prop-type.d.ts","./styled-system/types/style-props.d.ts","./styled-system/types/system-types.d.ts","./styled-system/types/recipe.d.ts","./styled-system/types/parts.d.ts","./styled-system/types/pattern.d.ts","./styled-system/types/composition.d.ts","./styled-system/types/global.d.ts","./styled-system/types/index.d.ts","./styled-system/css/css.d.ts","./styled-system/css/cx.d.ts","./styled-system/css/cva.d.ts","./styled-system/css/sva.d.ts","./styled-system/css/index.d.ts","./src/components/button/iconbutton.style.ts","./src/components/button/iconbutton.tsx","./src/types/page.ts","./src/components/bottomnavigator/bottomnavigator.animation.ts","./styled-system/recipes/glass-container.d.ts","./styled-system/recipes/index.d.ts","./src/components/bottomnavigator/bottomnavigator.style.ts","./src/components/bottomnavigator/bottomnavigator.tsx","../node_modules/.pnpm/lottie-web@5.12.2/node_modules/lottie-web/index.d.ts","../node_modules/.pnpm/@lottiefiles+react-lottie-player@3.5.4_react@18.3.1/node_modules/@lottiefiles/react-lottie-player/dist/src/player.d.ts","../node_modules/.pnpm/@lottiefiles+react-lottie-player@3.5.4_react@18.3.1/node_modules/@lottiefiles/react-lottie-player/dist/src/controls.d.ts","../node_modules/.pnpm/@lottiefiles+react-lottie-player@3.5.4_react@18.3.1/node_modules/@lottiefiles/react-lottie-player/dist/src/seeker.d.ts","../node_modules/.pnpm/@lottiefiles+react-lottie-player@3.5.4_react@18.3.1/node_modules/@lottiefiles/react-lottie-player/dist/src/index.d.ts","./src/assets/lotties/erroralert.json","./src/components/lotties/erroralert.tsx","./src/components/modal/errormodal.style.ts","../node_modules/.pnpm/@types+react-dom@18.3.1/node_modules/@types/react-dom/index.d.ts","./src/components/button/textbutton.style.ts","./src/components/button/textbutton.tsx","./src/components/modal/modal.animation.ts","./src/components/modal/modal.style.ts","./src/components/modal/modal.tsx","./src/components/modal/errormodal.tsx","../node_modules/.pnpm/zustand@5.0.1_@types+react@18.3.12_react@18.3.1/node_modules/zustand/esm/vanilla.d.mts","../node_modules/.pnpm/zustand@5.0.1_@types+react@18.3.12_react@18.3.1/node_modules/zustand/esm/react.d.mts","../node_modules/.pnpm/zustand@5.0.1_@types+react@18.3.12_react@18.3.1/node_modules/zustand/esm/index.d.mts","./src/stores/usesidebarstore.ts","./src/components/modal/usemodal.ts","./src/constants/page.ts","../node_modules/.pnpm/@tanstack+query-core@5.60.5/node_modules/@tanstack/query-core/build/modern/removable.d.ts","../node_modules/.pnpm/@tanstack+query-core@5.60.5/node_modules/@tanstack/query-core/build/modern/subscribable.d.ts","../node_modules/.pnpm/@tanstack+query-core@5.60.5/node_modules/@tanstack/query-core/build/modern/hydration-mkplgzt9.d.ts","../node_modules/.pnpm/@tanstack+query-core@5.60.5/node_modules/@tanstack/query-core/build/modern/queriesobserver.d.ts","../node_modules/.pnpm/@tanstack+query-core@5.60.5/node_modules/@tanstack/query-core/build/modern/infinitequeryobserver.d.ts","../node_modules/.pnpm/@tanstack+query-core@5.60.5/node_modules/@tanstack/query-core/build/modern/notifymanager.d.ts","../node_modules/.pnpm/@tanstack+query-core@5.60.5/node_modules/@tanstack/query-core/build/modern/focusmanager.d.ts","../node_modules/.pnpm/@tanstack+query-core@5.60.5/node_modules/@tanstack/query-core/build/modern/onlinemanager.d.ts","../node_modules/.pnpm/@tanstack+query-core@5.60.5/node_modules/@tanstack/query-core/build/modern/index.d.ts","../node_modules/.pnpm/@tanstack+react-query@5.60.5_react@18.3.1/node_modules/@tanstack/react-query/build/modern/types.d.ts","../node_modules/.pnpm/@tanstack+react-query@5.60.5_react@18.3.1/node_modules/@tanstack/react-query/build/modern/usequeries.d.ts","../node_modules/.pnpm/@tanstack+react-query@5.60.5_react@18.3.1/node_modules/@tanstack/react-query/build/modern/queryoptions.d.ts","../node_modules/.pnpm/@tanstack+react-query@5.60.5_react@18.3.1/node_modules/@tanstack/react-query/build/modern/usequery.d.ts","../node_modules/.pnpm/@tanstack+react-query@5.60.5_react@18.3.1/node_modules/@tanstack/react-query/build/modern/usesuspensequery.d.ts","../node_modules/.pnpm/@tanstack+react-query@5.60.5_react@18.3.1/node_modules/@tanstack/react-query/build/modern/usesuspenseinfinitequery.d.ts","../node_modules/.pnpm/@tanstack+react-query@5.60.5_react@18.3.1/node_modules/@tanstack/react-query/build/modern/usesuspensequeries.d.ts","../node_modules/.pnpm/@tanstack+react-query@5.60.5_react@18.3.1/node_modules/@tanstack/react-query/build/modern/useprefetchquery.d.ts","../node_modules/.pnpm/@tanstack+react-query@5.60.5_react@18.3.1/node_modules/@tanstack/react-query/build/modern/useprefetchinfinitequery.d.ts","../node_modules/.pnpm/@tanstack+react-query@5.60.5_react@18.3.1/node_modules/@tanstack/react-query/build/modern/infinitequeryoptions.d.ts","../node_modules/.pnpm/@tanstack+react-query@5.60.5_react@18.3.1/node_modules/@tanstack/react-query/build/modern/queryclientprovider.d.ts","../node_modules/.pnpm/@tanstack+react-query@5.60.5_react@18.3.1/node_modules/@tanstack/react-query/build/modern/queryerrorresetboundary.d.ts","../node_modules/.pnpm/@tanstack+react-query@5.60.5_react@18.3.1/node_modules/@tanstack/react-query/build/modern/hydrationboundary.d.ts","../node_modules/.pnpm/@tanstack+react-query@5.60.5_react@18.3.1/node_modules/@tanstack/react-query/build/modern/useisfetching.d.ts","../node_modules/.pnpm/@tanstack+react-query@5.60.5_react@18.3.1/node_modules/@tanstack/react-query/build/modern/usemutationstate.d.ts","../node_modules/.pnpm/@tanstack+react-query@5.60.5_react@18.3.1/node_modules/@tanstack/react-query/build/modern/usemutation.d.ts","../node_modules/.pnpm/@tanstack+react-query@5.60.5_react@18.3.1/node_modules/@tanstack/react-query/build/modern/useinfinitequery.d.ts","../node_modules/.pnpm/@tanstack+react-query@5.60.5_react@18.3.1/node_modules/@tanstack/react-query/build/modern/isrestoring.d.ts","../node_modules/.pnpm/@tanstack+react-query@5.60.5_react@18.3.1/node_modules/@tanstack/react-query/build/modern/index.d.ts","../node_modules/.pnpm/zustand@5.0.1_@types+react@18.3.12_react@18.3.1/node_modules/zustand/esm/middleware/redux.d.mts","../node_modules/.pnpm/zustand@5.0.1_@types+react@18.3.12_react@18.3.1/node_modules/zustand/esm/middleware/devtools.d.mts","../node_modules/.pnpm/zustand@5.0.1_@types+react@18.3.12_react@18.3.1/node_modules/zustand/esm/middleware/subscribewithselector.d.mts","../node_modules/.pnpm/zustand@5.0.1_@types+react@18.3.12_react@18.3.1/node_modules/zustand/esm/middleware/combine.d.mts","../node_modules/.pnpm/zustand@5.0.1_@types+react@18.3.12_react@18.3.1/node_modules/zustand/esm/middleware/persist.d.mts","../node_modules/.pnpm/zustand@5.0.1_@types+react@18.3.12_react@18.3.1/node_modules/zustand/esm/middleware.d.mts","../node_modules/.pnpm/zustand@5.0.1_@types+react@18.3.12_react@18.3.1/node_modules/zustand/esm/vanilla/shallow.d.mts","../node_modules/.pnpm/zustand@5.0.1_@types+react@18.3.12_react@18.3.1/node_modules/zustand/esm/react/shallow.d.mts","../node_modules/.pnpm/zustand@5.0.1_@types+react@18.3.12_react@18.3.1/node_modules/zustand/esm/shallow.d.mts","./src/stores/useuserstore.ts","../node_modules/.pnpm/axios@1.7.7/node_modules/axios/index.d.ts","./src/stores/useerrorstore.ts","./src/apis/axios.ts","./src/apis/auth.ts","./src/components/inputfield/inputfield.style.ts","./src/components/inputfield/inputfield.tsx","./src/features/auth/authmodal.style.ts","./src/features/auth/authmodal.tsx","./src/features/auth/authbutton.tsx","./src/components/sidebar/menubutton.style.ts","./src/components/sidebar/menubutton.tsx","./src/components/sidebar/pageitem.style.ts","./src/components/sidebar/pageitem.tsx","./src/constants/size.ts","./src/components/sidebar/sidebar.animation.ts","./src/components/sidebar/sidebar.style.ts","./src/components/sidebar/sidebar.tsx","../node_modules/.pnpm/@socket.io+component-emitter@3.1.2/node_modules/@socket.io/component-emitter/lib/cjs/index.d.ts","../node_modules/.pnpm/engine.io-parser@5.2.3/node_modules/engine.io-parser/build/esm/commons.d.ts","../node_modules/.pnpm/engine.io-parser@5.2.3/node_modules/engine.io-parser/build/esm/encodepacket.d.ts","../node_modules/.pnpm/engine.io-parser@5.2.3/node_modules/engine.io-parser/build/esm/decodepacket.d.ts","../node_modules/.pnpm/engine.io-parser@5.2.3/node_modules/engine.io-parser/build/esm/index.d.ts","../node_modules/.pnpm/engine.io-client@6.6.2/node_modules/engine.io-client/build/esm/transport.d.ts","../node_modules/.pnpm/engine.io-client@6.6.2/node_modules/engine.io-client/build/esm/globals.node.d.ts","../node_modules/.pnpm/engine.io-client@6.6.2/node_modules/engine.io-client/build/esm/socket.d.ts","../node_modules/.pnpm/engine.io-client@6.6.2/node_modules/engine.io-client/build/esm/transports/polling.d.ts","../node_modules/.pnpm/engine.io-client@6.6.2/node_modules/engine.io-client/build/esm/transports/polling-xhr.d.ts","../node_modules/.pnpm/engine.io-client@6.6.2/node_modules/engine.io-client/build/esm/transports/polling-xhr.node.d.ts","../node_modules/.pnpm/engine.io-client@6.6.2/node_modules/engine.io-client/build/esm/transports/websocket.d.ts","../node_modules/.pnpm/engine.io-client@6.6.2/node_modules/engine.io-client/build/esm/transports/websocket.node.d.ts","../node_modules/.pnpm/engine.io-client@6.6.2/node_modules/engine.io-client/build/esm/transports/webtransport.d.ts","../node_modules/.pnpm/engine.io-client@6.6.2/node_modules/engine.io-client/build/esm/transports/index.d.ts","../node_modules/.pnpm/engine.io-client@6.6.2/node_modules/engine.io-client/build/esm/util.d.ts","../node_modules/.pnpm/engine.io-client@6.6.2/node_modules/engine.io-client/build/esm/contrib/parseuri.d.ts","../node_modules/.pnpm/engine.io-client@6.6.2/node_modules/engine.io-client/build/esm/transports/polling-fetch.d.ts","../node_modules/.pnpm/engine.io-client@6.6.2/node_modules/engine.io-client/build/esm/index.d.ts","../node_modules/.pnpm/socket.io-parser@4.2.4/node_modules/socket.io-parser/build/esm/index.d.ts","../node_modules/.pnpm/socket.io-client@4.8.1/node_modules/socket.io-client/build/esm/socket.d.ts","../node_modules/.pnpm/socket.io-client@4.8.1/node_modules/socket.io-client/build/esm/manager.d.ts","../node_modules/.pnpm/socket.io-client@4.8.1/node_modules/socket.io-client/build/esm/index.d.ts","./src/apis/usesocket.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/hooks/usecombinedrefs.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/hooks/useevent.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/hooks/useisomorphiclayouteffect.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/hooks/useinterval.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/hooks/uselatestvalue.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/hooks/uselazymemo.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/hooks/usenoderef.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/hooks/useprevious.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/hooks/useuniqueid.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/hooks/index.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/adjustment.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/coordinates/types.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/coordinates/geteventcoordinates.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/coordinates/index.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/css.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/event/hasviewportrelativecoordinates.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/event/iskeyboardevent.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/event/istouchevent.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/event/index.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/execution-context/canusedom.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/execution-context/getownerdocument.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/execution-context/getwindow.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/execution-context/index.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/focus/findfirstfocusablenode.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/focus/index.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/type-guards/isdocument.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/type-guards/ishtmlelement.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/type-guards/isnode.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/type-guards/issvgelement.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/type-guards/iswindow.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/type-guards/index.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/types.d.ts","../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/types/coordinates.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/types/direction.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/algorithms/types.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/algorithms/closestcenter.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/algorithms/closestcorners.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/algorithms/rectintersection.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/algorithms/pointerwithin.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/algorithms/helpers.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/algorithms/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/types/events.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/types/other.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/types/react.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/types/rect.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/types/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/useautoscroller.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/usecachednode.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/types.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/usesensor.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/usesensors.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/pointer/abstractpointersensor.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/pointer/pointersensor.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/pointer/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/mouse/mousesensor.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/mouse/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/touch/touchsensor.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/touch/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/keyboard/types.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/keyboard/keyboardsensor.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/keyboard/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/sensors/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/usesyntheticlisteners.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/usecombineactivators.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/usedroppablemeasuring.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/useinitialvalue.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/useinitialrect.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/userect.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/userectdelta.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/useresizeobserver.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/usescrollableancestors.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/usescrollintoviewifneeded.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/usescrolloffsets.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/usescrolloffsetsdelta.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/usesensorsetup.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/userects.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/usewindowrect.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/usedragoverlaymeasuring.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/utilities/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/store/constructors.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/store/types.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/store/actions.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/store/context.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/store/reducer.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/store/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/accessibility/types.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/accessibility/accessibility.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/accessibility/components/restorefocus.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/accessibility/components/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/accessibility/defaults.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/accessibility/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/coordinates/constants.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/coordinates/distancebetweenpoints.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/coordinates/getrelativetransformorigin.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/coordinates/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/rect/adjustscale.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/rect/getrectdelta.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/rect/rectadjustment.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/rect/getrect.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/rect/getwindowclientrect.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/rect/rect.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/rect/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/other/noop.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/other/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/scroll/getscrollableancestors.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/scroll/getscrollableelement.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/scroll/getscrollcoordinates.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/scroll/getscrolldirectionandspeed.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/scroll/getscrollelementrect.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/scroll/getscrolloffsets.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/scroll/getscrollposition.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/scroll/documentscrollingelement.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/scroll/isscrollable.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/scroll/scrollintoviewifneeded.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/scroll/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/utilities/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/modifiers/types.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/modifiers/applymodifiers.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/modifiers/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dndcontext/types.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dndcontext/dndcontext.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dndcontext/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dndmonitor/types.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dndmonitor/context.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dndmonitor/usedndmonitor.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dndmonitor/usedndmonitorprovider.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dndmonitor/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/components/animationmanager/animationmanager.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/components/animationmanager/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/components/nullifiedcontextprovider/nullifiedcontextprovider.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/components/nullifiedcontextprovider/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/components/positionedoverlay/positionedoverlay.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/components/positionedoverlay/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/components/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/hooks/usedropanimation.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/hooks/usekey.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/hooks/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/dragoverlay.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/dragoverlay/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/components/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/usedraggable.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/usedndcontext.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/usedroppable.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/hooks/index.d.ts","../node_modules/.pnpm/@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/index.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/types/disabled.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/types/data.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/types/strategies.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/types/type-guard.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/types/index.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/components/sortablecontext.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/components/index.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/hooks/types.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/hooks/usesortable.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/hooks/defaults.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/hooks/index.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/strategies/horizontallistsorting.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/strategies/rectsorting.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/strategies/rectswapping.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/strategies/verticallistsorting.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/strategies/index.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/sensors/keyboard/sortablekeyboardcoordinates.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/sensors/keyboard/index.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/sensors/index.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/utilities/arraymove.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/utilities/arrayswap.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/utilities/getsortedrects.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/utilities/isvalidindex.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/utilities/itemsequal.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/utilities/normalizedisabled.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/utilities/index.d.ts","../node_modules/.pnpm/@dnd-kit+sortable@8.0.0_@dnd-kit+core@6.1.0_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/index.d.ts","./src/stores/usesocketstore.ts","./src/features/editor/editor.style.ts","./src/features/editor/components/iconblock/iconblock.style.ts","./src/features/editor/components/iconblock/iconblock.tsx","./src/features/editor/components/menublock/menublock.style.ts","./src/features/editor/components/menublock/menublock.tsx","./src/features/editor/components/block/block.animation.ts","./src/features/editor/components/block/block.style.ts","./src/features/editor/components/block/block.tsx","./src/features/editor/hooks/useblockdraganddrop.ts","./src/types/markdown.ts","./src/features/editor/utils/markdownpatterns.ts","./src/features/editor/hooks/usemarkdowngrammer.ts","./src/features/editor/editor.tsx","./src/features/page/page.animation.ts","./src/features/page/page.style.ts","./src/features/page/components/pagecontrolbutton/pagecontrolbutton.style.ts","./src/features/page/components/pagecontrolbutton/pagecontrolbutton.tsx","./src/features/page/components/pagetitle/pagetitle.style.ts","./src/features/page/components/pagetitle/pagetitle.tsx","./src/constants/spacing.ts","./src/features/page/hooks/usepage.ts","./src/features/page/page.tsx","./src/features/workspace/workspace.style.ts","./src/assets/lotties/loadingspinner.json","./src/components/lotties/loadingspinner.tsx","./src/features/workspace/components/introscreen.style.ts","./src/features/workspace/components/introscreen.tsx","./src/features/workspace/hooks/usepagesmanage.ts","./src/features/workspace/hooks/useworkspaceinit.ts","./src/features/workspace/workspace.tsx","./src/app.tsx","../node_modules/.pnpm/@types+react-dom@18.3.1/node_modules/@types/react-dom/client.d.ts","./src/main.tsx","./src/vite-env.d.ts","./src/constants/color.ts","./src/constants/option.ts","./src/features/editor/components/menumodal.tsx/menumodal.style.ts","../node_modules/.pnpm/prettier@3.3.3/node_modules/prettier/doc.d.ts","../node_modules/.pnpm/prettier@3.3.3/node_modules/prettier/index.d.ts","./src/features/editor/components/menumodal.tsx/menumodal.tsx","./src/features/editor/hooks/useblockanimtaion.ts","./src/styles/global.ts","./src/styles/typography.ts","./src/styles/recipes/glasscontainerrecipe.ts","./src/styles/tokens/color.ts","./src/styles/tokens/radii.ts","./src/styles/tokens/shadow.ts","./src/styles/tokens/sizes.ts","./src/styles/tokens/spacing.ts","./panda.config.ts","./vite-env-override.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/compatibility/disposable.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/compatibility/indexable.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/compatibility/iterators.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/compatibility/index.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/ts5.6/globals.typedarray.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/ts5.6/buffer.buffer.d.ts","../node_modules/.pnpm/buffer@5.7.1/node_modules/buffer/index.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/header.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/readable.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/file.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/fetch.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/formdata.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/connector.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/client.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/errors.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/dispatcher.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/global-dispatcher.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/global-origin.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/pool-stats.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/pool.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/handlers.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/balanced-pool.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/agent.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-interceptor.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-agent.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-client.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-pool.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-errors.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/proxy-agent.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/env-http-proxy-agent.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/retry-handler.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/retry-agent.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/api.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/interceptors.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/util.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/cookies.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/patch.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/websocket.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/eventsource.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/filereader.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/diagnostics-channel.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/content-type.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/cache.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/index.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/globals.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/assert.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/assert/strict.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/async_hooks.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/buffer.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/child_process.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/cluster.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/console.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/constants.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/crypto.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/dgram.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/diagnostics_channel.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/dns.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/dns/promises.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/domain.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/dom-events.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/events.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/fs.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/fs/promises.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/http.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/http2.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/https.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/inspector.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/module.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/net.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/os.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/path.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/perf_hooks.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/process.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/punycode.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/querystring.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/readline.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/readline/promises.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/repl.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/sea.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/stream.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/stream/promises.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/stream/consumers.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/stream/web.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/string_decoder.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/test.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/timers.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/timers/promises.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/tls.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/trace_events.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/tty.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/url.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/util.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/v8.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/vm.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/wasi.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/worker_threads.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/zlib.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/ts5.6/index.d.ts","../node_modules/.pnpm/@types+estree@1.0.6/node_modules/@types/estree/index.d.ts","../node_modules/.pnpm/rollup@4.24.3/node_modules/rollup/dist/rollup.d.ts","../node_modules/.pnpm/rollup@4.24.3/node_modules/rollup/dist/parseast.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/types/hmrpayload.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/types/customevent.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/types/hot.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/dist/node/types.d-agj9qkwt.d.ts","../node_modules/.pnpm/esbuild@0.21.5/node_modules/esbuild/lib/main.d.ts","../node_modules/.pnpm/source-map-js@1.2.1/node_modules/source-map-js/source-map.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/previous-map.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/input.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/css-syntax-error.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/declaration.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/root.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/warning.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/lazy-result.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/no-work-result.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/processor.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/result.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/document.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/rule.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/node.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/comment.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/container.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/at-rule.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/list.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/postcss.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/postcss.d.mts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/dist/node/runtime.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/types/importglob.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/types/metadata.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/dist/node/index.d.ts","../node_modules/.pnpm/@babel+types@7.26.0/node_modules/@babel/types/lib/index.d.ts","../node_modules/.pnpm/@types+babel__generator@7.6.8/node_modules/@types/babel__generator/index.d.ts","../node_modules/.pnpm/@babel+parser@7.26.2/node_modules/@babel/parser/typings/babel-parser.d.ts","../node_modules/.pnpm/@types+babel__template@7.4.4/node_modules/@types/babel__template/index.d.ts","../node_modules/.pnpm/@types+babel__traverse@7.20.6/node_modules/@types/babel__traverse/index.d.ts","../node_modules/.pnpm/@types+babel__core@7.20.5/node_modules/@types/babel__core/index.d.ts","../node_modules/.pnpm/@vitejs+plugin-react@4.3.3_vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0_/node_modules/@vitejs/plugin-react/dist/index.d.mts","../node_modules/.pnpm/vite-tsconfig-paths@5.1.0_typescript@5.3.3_vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0_/node_modules/vite-tsconfig-paths/dist/index.d.ts","../node_modules/.pnpm/@rollup+pluginutils@5.1.3_rollup@4.24.3/node_modules/@rollup/pluginutils/types/index.d.ts","../node_modules/.pnpm/@svgr+babel-plugin-transform-svg-component@8.0.0_@babel+core@7.26.0/node_modules/@svgr/babel-plugin-transform-svg-component/dist/index.d.ts","../node_modules/.pnpm/@svgr+babel-preset@8.1.0_@babel+core@7.26.0/node_modules/@svgr/babel-preset/dist/index.d.ts","../node_modules/.pnpm/@svgr+core@8.1.0_typescript@5.3.3/node_modules/@svgr/core/dist/index.d.ts","../node_modules/.pnpm/vite-plugin-svgr@4.3.0_rollup@4.24.3_typescript@5.3.3_vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0_/node_modules/vite-plugin-svgr/dist/index.d.ts","./vite.config.ts","./vite.env.d.ts","./styled-system/patterns/aspect-ratio.d.ts","./styled-system/patterns/bleed.d.ts","./styled-system/patterns/box.d.ts","./styled-system/patterns/center.d.ts","./styled-system/patterns/circle.d.ts","./styled-system/patterns/container.d.ts","./styled-system/patterns/cq.d.ts","./styled-system/patterns/divider.d.ts","./styled-system/patterns/flex.d.ts","./styled-system/patterns/float.d.ts","./styled-system/patterns/grid-item.d.ts","./styled-system/patterns/grid.d.ts","./styled-system/patterns/hstack.d.ts","./styled-system/patterns/stack.d.ts","./styled-system/patterns/vstack.d.ts","./styled-system/patterns/spacer.d.ts","./styled-system/patterns/square.d.ts","./styled-system/patterns/link-overlay.d.ts","./styled-system/patterns/wrap.d.ts","./styled-system/patterns/visually-hidden.d.ts","./styled-system/patterns/index.d.ts","./styled-system/recipes/action-button.d.ts","./styled-system/recipes/icon-button.d.ts","./styled-system/recipes/icon.d.ts","./styled-system/recipes/navigation-item.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/types/importmeta.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/client.d.ts","../node_modules/.pnpm/vite-plugin-svgr@4.3.0_rollup@4.24.3_typescript@5.3.3_vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0_/node_modules/vite-plugin-svgr/client.d.ts"],"fileInfos":[{"version":"f33e5332b24c3773e930e212cbb8b6867c8ba3ec4492064ea78e55a524d57450","signature":false,"affectsGlobalScope":true},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","signature":false},{"version":"26f2f787e82c4222710f3b676b4d83eb5ad0a72fa7b746f03449e7a026ce5073","signature":false},{"version":"9a68c0c07ae2fa71b44384a839b7b8d81662a236d4b9ac30916718f7510b1b2d","signature":false},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","signature":false},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","signature":false},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","signature":false},{"version":"21e41a76098aa7a191028256e52a726baafd45a925ea5cf0222eb430c96c1d83","signature":false,"affectsGlobalScope":true},{"version":"35299ae4a62086698444a5aaee27fc7aa377c68cbb90b441c9ace246ffd05c97","signature":false,"affectsGlobalScope":true},{"version":"138fb588d26538783b78d1e3b2c2cc12d55840b97bf5e08bca7f7a174fbe2f17","signature":false,"affectsGlobalScope":true},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","signature":false,"affectsGlobalScope":true},{"version":"4443e68b35f3332f753eacc66a04ac1d2053b8b035a0e0ac1d455392b5e243b3","signature":false,"affectsGlobalScope":true},{"version":"bc47685641087c015972a3f072480889f0d6c65515f12bd85222f49a98952ed7","signature":false,"affectsGlobalScope":true},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","signature":false,"affectsGlobalScope":true},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","signature":false,"affectsGlobalScope":true},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","signature":false,"affectsGlobalScope":true},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","signature":false,"affectsGlobalScope":true},{"version":"93495ff27b8746f55d19fcbcdbaccc99fd95f19d057aed1bd2c0cafe1335fbf0","signature":false,"affectsGlobalScope":true},{"version":"6fc23bb8c3965964be8c597310a2878b53a0306edb71d4b5a4dfe760186bcc01","signature":false,"affectsGlobalScope":true},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","signature":false,"affectsGlobalScope":true},{"version":"bb42a7797d996412ecdc5b2787720de477103a0b2e53058569069a0e2bae6c7e","signature":false,"affectsGlobalScope":true},{"version":"4738f2420687fd85629c9efb470793bb753709c2379e5f85bc1815d875ceadcd","signature":false,"affectsGlobalScope":true},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","signature":false,"affectsGlobalScope":true},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","signature":false,"affectsGlobalScope":true},{"version":"9fc46429fbe091ac5ad2608c657201eb68b6f1b8341bd6d670047d32ed0a88fa","signature":false,"affectsGlobalScope":true},{"version":"61c37c1de663cf4171e1192466e52c7a382afa58da01b1dc75058f032ddf0839","signature":false,"affectsGlobalScope":true},{"version":"b541a838a13f9234aba650a825393ffc2292dc0fc87681a5d81ef0c96d281e7a","signature":false,"affectsGlobalScope":true},{"version":"e0275cd0e42990dc3a16f0b7c8bca3efe87f1c8ad404f80c6db1c7c0b828c59f","signature":false,"affectsGlobalScope":true},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","signature":false,"affectsGlobalScope":true},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","signature":false,"affectsGlobalScope":true},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","signature":false,"affectsGlobalScope":true},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","signature":false,"affectsGlobalScope":true},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","signature":false,"affectsGlobalScope":true},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","signature":false,"affectsGlobalScope":true},{"version":"49ed889be54031e1044af0ad2c603d627b8bda8b50c1a68435fe85583901d072","signature":false,"affectsGlobalScope":true},{"version":"e93d098658ce4f0c8a0779e6cab91d0259efb88a318137f686ad76f8410ca270","signature":false,"affectsGlobalScope":true},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","signature":false,"affectsGlobalScope":true},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","signature":false,"affectsGlobalScope":true},{"version":"bf14a426dbbf1022d11bd08d6b8e709a2e9d246f0c6c1032f3b2edb9a902adbe","signature":false,"affectsGlobalScope":true},{"version":"ec0104fee478075cb5171e5f4e3f23add8e02d845ae0165bfa3f1099241fa2aa","signature":false,"affectsGlobalScope":true},{"version":"2b72d528b2e2fe3c57889ca7baef5e13a56c957b946906d03767c642f386bbc3","signature":false,"affectsGlobalScope":true},{"version":"acae90d417bee324b1372813b5a00829d31c7eb670d299cd7f8f9a648ac05688","signature":false,"affectsGlobalScope":true},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","signature":false,"affectsGlobalScope":true},{"version":"33358442698bb565130f52ba79bfd3d4d484ac85fe33f3cb1759c54d18201393","signature":false,"affectsGlobalScope":true},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","signature":false,"affectsGlobalScope":true},{"version":"36a2e4c9a67439aca5f91bb304611d5ae6e20d420503e96c230cf8fcdc948d94","signature":false,"affectsGlobalScope":true},{"version":"8a8eb4ebffd85e589a1cc7c178e291626c359543403d58c9cd22b81fab5b1fb9","signature":false},{"version":"ed6b820c54de95b2510bb673490d61c7f2187f532a339d8d04981645a918961f","signature":false},{"version":"aa17748c522bd586f8712b1a308ea23af59c309b2fd278f6d4f406647c72e659","signature":false,"affectsGlobalScope":true},{"version":"42c169fb8c2d42f4f668c624a9a11e719d5d07dacbebb63cbcf7ef365b0a75b3","signature":false},{"version":"81b8eb55a39133f7af8c4a67fd6fe56f50b90eeeb9a2ebc07c6bc4db3f8e49f8","signature":false},{"version":"90925968fe078e5f34aaf13ba2cd513caec05529e2f2e23ce950de101e07ae40","signature":false},{"version":"a4ee7c078e96c0a00c07e311bf38f03fdc08c18cf5c5cf44db290eede28531c1","signature":false},{"version":"65d91854d606b050fd11d1050fbe4369e54e5776d635e4b959f2b61cf5d7388f","signature":false},{"version":"21f2f2e75558aea454a4a844494218d3426c2be666088a0d91569a2829c7fd48","signature":false},{"version":"bd6884ca40bc7c8b705ac2f34b38e187dec8bd96ea66923fc502f32b08a26e7d","signature":false},{"version":"c4d2193ec977030a39a5d5bcb7582ff3d9c9bddd7341e168a836184494c4894d","signature":false},{"version":"afc7ca357c5aa5a9b9f1b70175522b1d5c7fb2923cb228bef4dff7127e862eeb","signature":false,"affectsGlobalScope":true},{"version":"8697faa527dd799c5bbe64723aa2593fdd47c609864aa4c49689997cd06cebac","signature":false},{"version":"b426147fec725961d1305b25b26dbf99e5c419de98b5728974a8a44fc5959181","signature":false},{"version":"1235f6acae8da14ce25d9f75df290c4e4f7d53d024b4e91c6121ff44ea13c801","signature":false},{"version":"8a8eb4ebffd85e589a1cc7c178e291626c359543403d58c9cd22b81fab5b1fb9","signature":false},{"version":"77d596561ec05cddc53701988ff8d891047978036c603de4b405b31e11f8575b","signature":false},{"version":"15bd07838cd4506b93e6835f78c5dedacc0bcae7202b2086444637df4a8f4d45","signature":false},{"version":"348c57c67c092eb3c28873d630c320e392e947a07946aaced323e8e6eafb915d","signature":false},{"version":"83fcaf1f41dd04269322cfdd47aa2546ec0393c83c2f3a1a2ad321765a3e3aa2","signature":false},{"version":"98240aef8bd41abfdef295d1dbe712d51a8cf1dea125c40f270bafc816cbf6c5","signature":false},{"version":"4baa8b99f90861f5e8ba1efb2deef2195be4037ea47b83180b6770d76bfe845c","signature":false},{"version":"03c0c949e86c44a98165752c31d9edea61b853a237254806b5a452c16b6f709f","signature":false},{"version":"7c8cffc734f0860b5eb694a3cf43a347cbcc531877a06a8a0b0748113487c4df","signature":false},{"version":"d3a88ebd39ffd613ac064bbe2d813e47d262219d4581dd437caf80d4cfd3e437","signature":false},{"version":"db56a1b0b070b2a9b68561c3542b3928492793e32c632171caa6c53fb8ecb402","signature":false},{"version":"a92ea8cdc292bee86d7bf00ade4d4c2b84ef07b6a772650c4a3f503e83c43f95","signature":false},{"version":"9cc2ce851dce49e8e831ffefd5ac85b62319e97df4821683dcc80fb17e08197e","signature":false},{"version":"f2a60f3d9dac64110308154059537cd87ab6f4c607395a89e3cc703f837b8d22","signature":false},{"version":"b2f74a813678952f4906641449101cb04e6b94a3055a60c194d28f93fcb58a25","signature":false},{"version":"e5b2239e66924ad249294b617d85dc561a04fa1491f3b9aa45e067456682ada7","signature":false},{"version":"3ae8dd5663704463b336ce8e43dab2a53fc7f085841602f90f07d3edf675ce65","signature":false},{"version":"c6c583d215c29a8420c52a01f041a3ebfa5ad9eecd4049b57acda599e3e30ed0","signature":false},{"version":"10ccdcf171b365e3fc0b9540f9941ad3915ba3672eda63099156d64f5b9616e8","signature":false},{"version":"9e6ae4de60321c9c875ce5871dfcc9426dbb006b76ec6593363f012d434cf704","signature":false},{"version":"85329c72103a5d46c60b93f130a8cc941d029dfc52caf8ba01f208b3b006083e","signature":false},{"version":"56fb55555c935a1ef9f70369252c25f96397171443b3fa829eab2e27aab7f43b","signature":false},{"version":"1cc1dd565274a0c1f7a13a2f1d581c51b3b770b4c502a7ddf2b623d8e57671a8","signature":false},{"version":"e83447f88a6a9a5e5426131b165337b4dff7ff249d3899c7cacc6e7c47267412","signature":false},{"version":"baac36a022cf0ccddaf1648e242068e358e2b78483efb816c8d05384217928fc","signature":false},{"version":"e1dfeb7fe1815dae68e2513ac1cf5130d6977688a5090eeef9f3dde05791532f","signature":false},{"version":"4e4c1412ce497716a61b7bbca1302826c4eb6cf68fce4bb76f190c31e544568c","signature":false},{"version":"86075b555f88780f45c665374f1678b0010ed92c1da6defb8978aef63ad9823f","signature":false},{"version":"729d731c01903375efde3fbee81d8bdb2f189bd42f5af97de33c8dde4a948011","signature":false},{"version":"f6059a11ad8f08358eec11f1167e9b6ecd4adcba611c266dad5a6476381b6a79","signature":false},{"version":"faacee8a12d1ac0edfc1393404f3629e1264f955680a89cbfecc58dabc85e24a","signature":false},{"version":"f86cbc47cd362a2095e6841a9f636ed41f196c06d800c9d031a4e5a9fa3609d6","signature":false},{"version":"532a61e1bc826812ddf5b670c3e832ea9fe875c95a9d3be33e4c2a176b5f71f0","signature":false},{"version":"1e852a81f8ab8017a2ec279e822641c9a6d856717696da38d7e01b78c7725775","signature":false},{"version":"2f462d47bcf3b80e045843dc3aae0bd1c0ea673a9cbc46ed6a367e59790e99f1","signature":false},{"version":"620a5aae820e9ba53965b4af9c87e5bdd7d30c6aa549687af36bd557b18992d4","signature":false},{"version":"c06545530668dfef18b864b18c275af0f4a223e489282db301c437843726be6d","signature":false},{"version":"695932cb32b555db096ee4072a818b774aeec9cd0c6864d4af5180c0e58f83dd","signature":false},{"version":"852847088636a9b1c7be0ce22fab66d9c9940f0a0e6f78acc147e1f5b897149b","signature":false},{"version":"f27e2c4fbb11766959ba9bb27882efebe8cc3346c4f3dfe78200eb23681ca1ce","signature":false},{"version":"da459d6c84246bbf0a8befd1df34a1120374d9570e8ca73800862ccb47cc7e1b","signature":false},{"version":"ea9f8137a900e961ab0d0afe2493a3be050a9e5e3aa3bd4d2b7cb62751bdf7a8","signature":false},{"version":"f6b0d3cfad6acbe42c53a53ec86cd8e8c65881668a1fc627940376eca9beb1fa","signature":false},{"version":"2edd7faf1bc8a0fca9ee6060a1935c3cd43487ebdc71f34df7f8c59f65b39480","signature":false},{"version":"0725189193a07a4fb3cc82c856c70b913f51bd850e86a3586a2457e8c008affd","signature":false},{"version":"951ea5f4424d919bf78c95291e66d0c0f36b26d01b70db627e5f19dca3fe1778","signature":false},{"version":"5027a140fc57c7750853cacec34363c091dda7c4ca97dad0e2c4f5c8ad0bc87f","signature":false},{"version":"ea6dd5ffdf73eb07480bd7e6358845b2cf5237041851e477c9cb72d02d4d86fa","signature":false},{"version":"a803b31b8a4ecf5f782da5c6254b1a327a9f55fc90c0d09e4a8770db53d70e30","signature":false},{"version":"76702c38ff90508cad63a94e66d752858bd4456dadc501c7dd919b441215df35","signature":false},{"version":"4e979330517c1527ed78e19bb70619e5b276b80a89103f8fed7f63b2f27d52cb","signature":false},{"version":"044aae1e62523280d3679eed49ffa288bb793d87b98ab4aaa37a7024838929f3","signature":false},{"version":"7b312001a7cc821594bf346b364bc76604ec14db06292bdb3f8037dbe82d28f1","signature":false},{"version":"9d859490d085e26024ff254e37b8d01c050fa09bc24c77002e04016102c69741","signature":false},{"version":"130e4a09b09cb00f2caec400d939d512595aa7fc1b21a9fff57473319e6e23d5","signature":false},{"version":"3b7c6b3e897d68435cf6719937e767ceb554daec84628cfaf8a23e7c1cbee8ff","signature":false},{"version":"d3c03ffa8da44ac52d6f610275a3bf57957846e8cf417bf5ca9610722b319857","signature":false},{"version":"ec61b7543855ffd13ec368dfad5a492669d78cb5060ccbffd294c5141e3c3606","signature":false},{"version":"2d617b5b26592ea5529011d707b76290d323dd85b065f98e1e7e568faf9cc526","signature":false},{"version":"fb84d97d9dc95bf675cf95cc97041ce2e9f5995d6a249c83ffa5d47017657965","signature":false},{"version":"e0cf974515cf71dd5b2d27db12b9fa9b37c1bf5670ac926e67265858bd7de1f2","signature":false},{"version":"15f5e10ac88f0ec75916986974b866f60f7bd091170b5caf182238385b4fcb48","signature":false,"affectsGlobalScope":true},{"version":"a0a30d52ad434959f82a70b5a95c146be0ff4b76e49c1901442862c4ed4120c4","signature":false},{"version":"31969816c17f20e000e42e18ada7c7296fbb2f20f85a2fb7a6f50c7785b07865","signature":false},{"version":"9c8a14711069006b778331f204cc0c0560be09d7cb5c16c3598f6a1d10fbc8bc","signature":false},{"version":"598c0bd3320064d69bed768c37a2cc4300b3b97e6619bc1e886fabc312d0e71c","signature":false},{"version":"c818a2ffb97ec5e28257bf02b68b9326219a83b6be035470be9c83b54a94dc7c","signature":false},{"version":"fd794cd9f7ef7cf7dc38c07b01c22d76b922627e731a5cba88307e6b0897619c","signature":false},{"version":"17ed71200119e86ccef2d96b73b02ce8854b76ad6bd21b5021d4269bec527b5f","signature":false},{"version":"65ce4b162e7fad6f34ad5190e14697ad537de114b82869959cac0caba6e66075","signature":false},{"version":"6221dc3b8a476510f38543fe10a92b57313ca06e16c45773edbce491328e277d","signature":false},{"version":"30b88706d5bd23f9542c734aee0baf15516ab2c73d5b9150a3006f5398e1c57d","signature":false},{"version":"9a5e0ea700125b08a3baf2952d935d0b2a6333590e9fb1914de4493006eb8688","signature":false},{"version":"27f5a927115a09a1945d8d5db0027cdffa3b1d7d3ef16a28e6bebee32112abb8","signature":false},{"version":"24ad68f72d96bb906bf957a251618ca9d7360419c7c7e51755e66622b795041f","signature":false},{"version":"7117f6513efa5f409de39a7b87938b761daad4720c226a4fb3b8ed454bfd3b5c","signature":false},{"version":"1b60812534ac4ad313ccc1461598a1ee2a764b55827de1c0afd295a418b72008","signature":false},{"version":"06100727c3328b53c19780f851301c4e18c66c55658d2605ab0de27818885e42","signature":false},{"version":"e2c35b6573e67d9b055351924d8d31a8e9531d5933184c862cc739ff4cf38c42","signature":false},{"version":"305e88c7b877fc3ee815e469d0723b2001c0b38b916932895c5a96e694e5df6e","signature":false},{"version":"33eb458116216489fb26d1038a3b42b8a2d10cc1f18eb14ea81586c35e75e05b","signature":false},{"version":"9971931daaf18158fc38266e838d56eb5d9d1f13360b1181bb4735a05f534c03","signature":false},{"version":"50cf7a23fc93928995caec8d7956206990f82113beeb6b3242dae8124edc3ca0","signature":false},{"version":"cb8e6466ed1509d4819ae07c41f39897d9ce08b63692f3e6bce06f10d98b8157","signature":false},{"version":"e5b2f4da1ac3dac4aaa39a10a633493878ae737d476f5693c3d6861a62319449","signature":false},{"version":"3bf80ef5ee5a2d23bf083735dcffc0d1e5aeeab5d14e29d84c30d9a6d8649ed6","signature":false},{"version":"4f34a608833285c2fe5de094a484fe793081b50d10009df96c3b3585bc0f2dcd","signature":false},{"version":"352031ac2e53031b69a09355e09ad7d95361edf32cc827cfe2417d80247a5a50","signature":false},{"version":"853b8bdb5da8c8e5d31e4d715a8057d8e96059d6774b13545c3616ed216b890c","signature":false},{"version":"147812d33deee170e1cdab699f91a97309524c85867530a8485fdd521788bf3d","signature":false},{"version":"ff662536934906f04b9b1bc87a38af2a20273d2a8fe0f12d1891cf8e98043221","signature":false},{"version":"71ed8ea79e33c1529e89780e6ce491acdd4480ae24c380c60ba2fb694bd53dc3","signature":false},{"version":"692ab3e2f02c8a1a233e5a99e08c680eb608ce7166db03e094652ffd96f880c0","signature":false},{"version":"54fdb2ae0c92a76a7ba795889c793fff1e845fab042163f98bc17e5141bbe5f3","signature":false},{"version":"4b3049a2c849f0217ff4def308637931661461c329e4cf36aeb31db34c4c0c64","signature":false},{"version":"174b64363af0d3d9788584094f0f5a4fac30c869b536bb6bad9e7c3c9dce4c1d","signature":false},{"version":"94f4755c5f91cb042850cec965a4bcade3c15d93cdd90284f084c571805a4d91","signature":false},{"version":"998d9f1da9ec63fca4cc1acb3def64f03d6bd1df2da1519d9249c80cfe8fece6","signature":false},{"version":"b7d9ca4e3248f643fa86ff11872623fdc8ed2c6009836bec0e38b163b6faed0c","signature":false},{"version":"878a353da561e091b6ab35e36b4b2a29a88307d389e3ff95f1d5bdcfaa512e48","signature":false},{"version":"d4f7a7a5f66b9bc6fbfd53fa08dcf8007ff752064df816da05edfa35abd2c97c","signature":false},{"version":"1f38ecf63dead74c85180bf18376dc6bc152522ef3aedf7b588cadbbd5877506","signature":false},{"version":"89316bf786d1fb2d9ef999e2b4ffb7a9d66491d55a362e8f457b67a97f8b60f1","signature":false},{"version":"facde2bec0f59cf92f4635ece51b2c3fa2d0a3bbb67458d24af61e7e6b8f003c","signature":false},{"version":"4669194e4ca5f7c160833bbb198f25681e629418a6326aba08cf0891821bfe8f","signature":false},{"version":"f919471289119d2e8f71aba81869b01f30f790e8322cf5aa7e7dee8c8dadd00a","signature":false},{"version":"3b9f5af0e636b312ec712d24f611225188627838967191bf434c547b87bde906","signature":false},{"version":"e9bc0db0144701fab1e98c4d595a293c7c840d209b389144142f0adbc36b5ec2","signature":false},{"version":"7d1c3991ed26fec9d5faf20d689c1f3bab269e6abf6cf53513ae3a5b124a3f77","signature":false},{"version":"025c00e68cf1e9578f198c9387e74cdf481f472e5384a69143edbcf4168cdb96","signature":false},{"version":"03ff8974c3c1c21177e4a6c236fa36b22d92c7cdee2ca8e15937bee2f4ab1001","signature":false},{"version":"9eaa04e9271513d4faacc732b056efa329d297be18a4d5908f3becced2954329","signature":false},{"version":"98b1c3591f5ce0dd151fa011ea936b095779217d2a87a2a3701da47ce4a498a1","signature":false},{"version":"3ebc4ab3d849ebbe1857631229b345b86d1e7899dddf954a7d74a18cbaf3823f","signature":false},{"version":"3672426a97d387a710aa2d0c3804024769c310ce9953771d471062cc71f47d51","signature":false},{"version":"375700e065dd9948ca1ebb6793f62c18890f37bcb42ab757d73df6623dd903d9","signature":false},{"version":"4781142e27cfd19d75a2c0ee432826153fcdf670bdc52631a6078330c9133e6f","signature":false},{"version":"69cae2800f7554b86914ce05f6afb946eae4a66b132694149de8e9a83350aaf0","signature":false},{"version":"74ac530af5032ed2bf57266492d4dfe494bca4a77f9d0b483c9b28618c9bf5d0","signature":false},{"version":"01ba761ce6d75a4142858a053f45d64d255e057049ab1cc4d9a93e76b8b5c444","signature":false},{"version":"8bf64b8f07168e77156408e74aeb63a7e685ee293d1d998b164b5efa2608623e","signature":false},{"version":"6b9741e47644b36585e1dd7ccfba8886c89ece1d180add238461b86615afdbc9","signature":false},{"version":"41577735fa152c13309acec1556bba300cc36b7ef83c6dffe5bf96289159b3bb","signature":false},{"version":"295faa88cb20e14302153a285c02706ab376a55f9be9441e59896f7bc920b4b6","signature":false},{"version":"3aaded7d37421de9a2db0043c274e26b274b3cfa7978b5eb8cf1dcab35d740bb","signature":false},{"version":"2828358120f8e28e0beb016ee880f20676f5edba7c63512248573bc7248fa6dd","signature":false},{"version":"ac7c0fab0aeb74e0c19754de41fd3c18e47cd41777174206fd10e4d058e0be24","signature":false},{"version":"3a3c507b5d863ae8e1718418ebd1de2b8db2caf7ea825a25d073c0d30a7b4a5c","signature":false},{"version":"9faa96611a4d48349e19c37befb21b5afd22bc30ba1bc4b0715ee243ea546cfa","signature":false},{"version":"adac5cabc269d37ab08e8f785a8d4980c222c9957cd489e2bfe08e7a3945de16","signature":false},{"version":"b7e8232c073889ff8a81217c6f5d667dcb8c3790b44190b88758e5ebd682ded0","signature":false},{"version":"8204364d786d04ef25ffe3804415fee08c049e254e938d4a33d56b04a74f5da8","signature":false},{"version":"39228bfe387fa631b32a8583f7cf4360ebb53aa6f16110a5aec4fce845e0ed68","signature":false},{"version":"d3b9d7692af7be8a3a08a8376994e174b4116ff7758301ad3338f929485a6c4f","signature":false},{"version":"20e7bfde12f2f7cc88a3a6cf4f83316e6f366a4126d837230f3734df335a2e73","signature":false},{"version":"d172e52545b8bfac2d00f8ee7e224ad383452f6cf95895f24e169da424483cee","signature":false},{"version":"14ecfc29e0c44ad4c5e50f9b597492cd8f45a2a635db8b5fe911a5da83e26cf8","signature":false},{"version":"569e762cf47aafdad508360a443c6c757e56c61db3b652b65458a7d168d139c4","signature":false},{"version":"02ed2766d79a00719ac3cc77851d54bd7197c1b12085ea12126bc2a65068223e","signature":false},{"version":"4b84373e192b7e0f8569b65eb16857098a6ee279b75d49223db2a751fdd7efde","signature":false},{"version":"5aeea312cd1d3cc5d72fc8a9c964439d771bdf41d9cce46667471b896b997473","signature":false},{"version":"1d963927f62a0d266874e19fcecf43a7c4f68487864a2c52f51fbdd7c5cc40d8","signature":false},{"version":"d7341559b385e668ca553f65003ccc5808d33a475c141798ba841992fef7c056","signature":false},{"version":"fcf502cbb816413ab8c79176938357992e95c7e0af3aa2ef835136f88f5ad995","signature":false},{"version":"5c59fd485fff665a639e97e9691a7169f069e24b42ffc1f70442c55720ad3969","signature":false},{"version":"89c6bcc4f7b19580009a50674b4da0951165c8a2202fa908735ccbe35a5090dd","signature":false},{"version":"df283af30056ef4ab9cf31350d4b40c0ed15b1032833e32dc974ade50c13f621","signature":false},{"version":"9de40cf702d52a49d6f3d36d054fc12638348ea3e1fb5f8d53ef8910e7eaa56f","signature":false},{"version":"2f844dc2e5d3e8d15a951ff3dc39c7900736d8b2be67cc21831b50e5faaa760a","signature":false},{"version":"ecbbfd67f08f18500f2faaaa5d257d5a81421e5c0d41fa497061d2870b2e39db","signature":false},{"version":"79570f4dfd82e9ae41401b22922965da128512d31790050f0eaf8bbdb7be9465","signature":false},{"version":"4b7716182d0d0349a953d1ff31ab535274c63cbb556e88d888caeb5c5602bc65","signature":false},{"version":"d51809d133c78da34a13a1b4267e29afb0d979f50acbeb4321e10d74380beeea","signature":false},{"version":"e1dafdb1db7e8b597fc0dbc9e4ea002c39b3c471be1c4439eda14cf0550afe92","signature":false},{"version":"6ea4f73a90f9914608bd1ab342ecfc67df235ad66089b21f0632264bb786a98e","signature":false},{"version":"7537e0e842b0da6682fd234989bac6c8a2fe146520225b142c75f39fb31b2549","signature":false},{"version":"dd018ed60101a59a8e89374e62ed5ab3cb5df76640fc0ab215c9adf8fbc3c4b0","signature":false},{"version":"8d401f73380bdd30293e1923338e2544d57a9cdbd3dd34b6d24df93be866906e","signature":false},{"version":"54831cf2841635d01d993f70781f8fb9d56211a55b4c04e94cf0851656fd1fe8","signature":false},{"version":"ed95a661b21934685dc9012899d50e9e72d1ddcf63cfd82a45c04692132211a3","signature":false},{"version":"dd332252bb45677533cd5553e0c35340cee4c485c90c63360f8e653901286a4f","signature":false},{"version":"dddde95f3dea44dc49c9095a861298e829122a54a3f56b3b815e615501e2ed16","signature":false},{"version":"794a88237c94d74302df12ebb02f521cf5389a5bf046a3fdbdd3afb21dc02511","signature":false},{"version":"66a08d30c55a7aefa847c1f5958924a3ef9bea6cd1c962a8ff1b2548f66a6ce0","signature":false},{"version":"0790ae78f92ab08c9d7e66b59733a185a9681be5d0dc90bd20ab5d84e54dcb86","signature":false},{"version":"1046cd42ec19e4fd038c803b4fc1aff31e51e6e48a6b8237a0240a11c1c27792","signature":false},{"version":"8f93c7e1084de38a142085c7f664b0eb463428601308fb51c68b25cb687e0887","signature":false},{"version":"83f69c968d32101f8690845f47bcae016cbea049e222a5946889eb3ae37e7582","signature":false},{"version":"59c3f3ed18de1c7f5927e0eafcdc0e545db88bfae4168695a89e38a85943a86d","signature":false},{"version":"32e6c27fd3ef2b1ddbf2bf833b2962d282eb07d9d9d3831ca7f4ff63937268e1","signature":false},{"version":"406ebb72aa8fdd9227bfce7a1b3e390e2c15b27f5da37ea9e3ed19c7fb78d298","signature":false},{"version":"197109f63a34b5f9379b2d7ba82fc091659d6878db859bd428ea64740cb06669","signature":false},{"version":"059871a743c0ca4ae511cbd1e356548b4f12e82bc805ab2e1197e15b5588d1c4","signature":false},{"version":"8ccefe3940a2fcb6fef502cdbc7417bb92a19620a848f81abc6caa146ab963e9","signature":false},{"version":"44d8ec73d503ae1cb1fd7c64252ffa700243b1b2cc0afe0674cd52fe37104d60","signature":false},{"version":"67ea5a827a2de267847bb6f1071a56431aa58a4c28f8af9b60d27d5dc87b7289","signature":false},{"version":"e33bb784508856827448a22947f2cac69e19bc6e9d6ef1c4f42295f7bd4ce293","signature":false},{"version":"383bb09bfeb8c6ef424c7fbce69ec7dc59b904446f8cfec838b045f0143ce917","signature":false},{"version":"83508492e3fc5977bc73e63541e92c5a137db076aafc59dcf63e9c6ad34061c7","signature":false},{"version":"ef064b9a331b7fc9fe0b368499c52623fb85d37d8972d5758edc26064189d14d","signature":false},{"version":"d64457d06ab06ad5e5f693123ee2f17594f00e6d5481517058569deac326fea0","signature":false},{"version":"e92ea29d716c5fe1977a34e447866d5cfbd94b3f648e3b9c550603fdae0e94fb","signature":false},{"version":"3d10f47c6b1e9225c68c140235657a0cdd4fc590c18faf87dcd003fd4e22c67f","signature":false},{"version":"13989f79ff8749a8756cac50f762f87f153e3fb1c35768cc6df15968ec1adb1a","signature":false},{"version":"e014c2f91e94855a52dd9fc88867ee641a7d795cfe37e6045840ecf93dab2e6b","signature":false},{"version":"74b9f867d1cc9f4e6122f81b59c77cbd6ff39f482fb16cffdc96e4cda1b5fdb1","signature":false},{"version":"7c8574cfc7cb15a86db9bf71a7dc7669593d7f62a68470adc01b05f246bd20ff","signature":false},{"version":"c8f49d91b2669bf9414dfc47089722168602e5f64e9488dbc2b6fe1a0f6688da","signature":false},{"version":"3abee758d3d415b3b7b03551f200766c3e5dd98bb1e4ff2c696dc6f0c5f93191","signature":false},{"version":"79bd7f60a080e7565186cfdfd84eac7781fc4e7b212ab4cd315b9288c93b7dc7","signature":false},{"version":"4a2f281330a7b5ed71ebc4624111a832cd6835f3f92ad619037d06b944398cf4","signature":false},{"version":"ea8130014cb8ee30621bf521f58d036bff3b9753b2f6bd090cc88ac15836d33c","signature":false},{"version":"c740d49c5a0ecc553ddfc14b7c550e6f5a2971be9ed6e4f2280b1f1fa441551d","signature":false},{"version":"886a56c6252e130f3e4386a6d3340cf543495b54c67522d21384ed6fb80b7241","signature":false},{"version":"4b7424620432be60792ede80e0763d4b7aab9fe857efc7bbdb374e8180f4092a","signature":false},{"version":"e407db365f801ee8a693eca5c21b50fefd40acafda5a1fa67f223800319f98a8","signature":false},{"version":"529660b3de2b5246c257e288557b2cfa5d5b3c8d2240fa55a4f36ba272b57d18","signature":false},{"version":"0f6646f9aba018d0a48b8df906cb05fa4881dc7f026f27ab21d26118e5aa15de","signature":false},{"version":"b3620fcf3dd90a0e6a07268553196b65df59a258fe0ec860dfac0169e0f77c52","signature":false},{"version":"08135e83e8d9e34bab71d0cf35b015c21d0fd930091b09706c6c9c0e766aca28","signature":false},{"version":"96e14f2fdc1e3a558462ada79368ed49b004efce399f76f084059d50121bb9a9","signature":false},{"version":"56f2ade178345811f0c6c4e63584696071b1bd207536dc12384494254bc1c386","signature":false},{"version":"72c3535621ce0d03c1f2164ef5b374cea7b0ef74f0a43e4e25c6b196b6ee2531","signature":false},{"version":"a9679a2147c073267943d90a0a736f271e9171de8fbc9c378803dd4b921f5ed3","signature":false},{"version":"a8a2529eec61b7639cce291bfaa2dd751cac87a106050c3c599fccb86cc8cf7f","signature":false},{"version":"bfc46b597ca6b1f6ece27df3004985c84807254753aaebf8afabd6a1a28ed506","signature":false},{"version":"29d367403d3770c9f486a4ba87786957a479e93116905c55a22c2d5f9fd1206b","signature":false},{"version":"b8f3eafeaf04ba3057f574a568af391ca808bdcb7b031e35505dd857db13e951","signature":false},{"version":"30b38ae72b1169c4b0d6d84c91016a7f4c8b817bfe77539817eac099081ce05c","signature":false},{"version":"055eb244114cb0c9243e78f682e9e428ba7d2d1a1b96bfdcb1055a10c242fa01","signature":false},{"version":"426c3234f768c89ba4810896c1ee4f97708692727cfecba85712c25982e7232b","signature":false},{"version":"ee12dd75feac91bb075e2cb0760279992a7a8f5cf513b1cffaa935825e3c58be","signature":false},{"version":"33353c07054dafcf8cf80df57925c1e306b7760742a65f29fa78f7f1e9f0a895","signature":false},{"version":"4763ce202300b838eb045923eaeb32d9cf86092eee956ca2d4e223cef6669b13","signature":false},{"version":"7cff5fff5d1a92ae954bf587e5c35987f88cacaa006e45331b3164c4e26369de","signature":false},{"version":"3e51868ea728ceb899bbfd7a4c7b7ad6dd24896b66812ea35893e2301fd3b23f","signature":false},{"version":"781e8669b80a9de58083ca1f1c6245ef9fb04d98add79667e3ed70bde034dfd5","signature":false},{"version":"cfd35b460a1e77a73f218ebf7c4cd1e2eeeaf3fa8d0d78a0a314c6514292e626","signature":false},{"version":"452d635c0302a0e1c5108edebcca06fc704b2f8132123b1e98a5220afa61a965","signature":false},{"version":"ede58c3483c998fb5ce80f178522a4dd531900262eddd513898f3dba6ee77f0a","signature":false},{"version":"b87d65da85871e6d8c27038146044cffe40defd53e5113dbd198b8bce62c32db","signature":false},{"version":"ca1159f3677ea301f52a7e302b8ce2b287556d559c3b8c770cf5540bab175be5","signature":false},{"version":"5ff885be3e07a88697343a4741ccd8c919102ec096da574ea3f6caa5d8b52b94","signature":false},{"version":"c9f17e24cb01635d6969577113be7d5307f7944209205cb7e5ffc000d27a8362","signature":false},{"version":"685ead6d773e6c63db1df41239c29971a8d053f2524bfabdef49b829ae014b9a","signature":false},{"version":"b7bdabcd93148ae1aecdc239b6459dfbe35beb86d96c4bd0aca3e63a10680991","signature":false},{"version":"e83cfc51d3a6d3f4367101bfdb81283222a2a1913b3521108dbaf33e0baf764a","signature":false},{"version":"95f397d5a1d9946ca89598e67d44a214408e8d88e76cf9e5aecbbd4956802070","signature":false},{"version":"74042eac50bc369a2ed46afdd7665baf48379cf1a659c080baec52cc4e7c3f13","signature":false},{"version":"1541765ce91d2d80d16146ca7c7b3978bd696dc790300a4c2a5d48e8f72e4a64","signature":false},{"version":"ec6acc4492c770e1245ade5d4b6822b3df3ba70cf36263770230eac5927cf479","signature":false},{"version":"4c39ee6ae1d2aeda104826dd4ce1707d3d54ac34549d6257bea5d55ace844c29","signature":false},{"version":"deb099454aabad024656e1fc033696d49a9e0994fc3210b56be64c81b59c2b20","signature":false},{"version":"80eec3c0a549b541de29d3e46f50a3857b0b90552efeeed90c7179aba7215e2f","signature":false},{"version":"a4153fbd5c9c2f03925575887c4ce96fc2b3d2366a2d80fad5efdb75056e5076","signature":false},{"version":"6f7c70ca6fa1a224e3407eb308ec7b894cfc58042159168675ccbe8c8d4b3c80","signature":false},{"version":"4b56181b844219895f36cfb19100c202e4c7322569dcda9d52f5c8e0490583c9","signature":false},{"version":"5609530206981af90de95236ce25ddb81f10c5a6a346bf347a86e2f5c40ae29b","signature":false},{"version":"632ce3ee4a6b320a61076aeca3da8432fb2771280719fde0936e077296c988a9","signature":false},{"version":"8b293d772aff6db4985bd6b33b364d971399993abb7dc3f19ceed0f331262f04","signature":false},{"version":"4eb7bad32782df05db4ba1c38c6097d029bed58f0cb9cda791b8c104ccfdaa1f","signature":false},{"version":"c6a8aa80d3dde8461b2d8d03711dbdf40426382923608aac52f1818a3cead189","signature":false},{"version":"bf5e79170aa7fc005b5bf87f2fe3c28ca8b22a1f7ff970aa2b1103d690593c92","signature":false},{"version":"ba3c92c785543eba69fbd333642f5f7da0e8bce146dec55f06cfe93b41e7e12f","signature":false},{"version":"c6d72ececae6067e65c78076a5d4a508f16c806577a3d206259a0d0bfeedc8d1","signature":false},{"version":"b6429631df099addfcd4a5f33a046cbbde1087e3fc31f75bfbbd7254ef98ea3c","signature":false},{"version":"4e9cf1b70c0faf6d02f1849c4044368dc734ad005c875fe7957b7df5afe867c9","signature":false},{"version":"7498b7d83674a020bd6be46aeed3f0717610cb2ae76d8323e560e964eb122d0c","signature":false},{"version":"b80405e0473b879d933703a335575858b047e38286771609721c6ab1ea242741","signature":false},{"version":"7193dfd01986cd2da9950af33229f3b7c5f7b1bee0be9743ad2f38ec3042305e","signature":false},{"version":"1ccb40a5b22a6fb32e28ffb3003dea3656a106dd3ed42f955881858563776d2c","signature":false},{"version":"8d97d5527f858ae794548d30d7fc78b8b9f6574892717cc7bc06307cc3f19c83","signature":false},{"version":"ccb4ecdc8f28a4f6644aa4b5ab7337f9d93ff99c120b82b1c109df12915292ac","signature":false},{"version":"8bbcf9cecabe7a70dcb4555164970cb48ba814945cb186493d38c496f864058f","signature":false},{"version":"7d57bdfb9d227f8a388524a749f5735910b3f42adfe01bfccca9999dc8cf594c","signature":false},{"version":"3508810388ea7c6585496ee8d8af3479880aba4f19c6bbd61297b17eb30428f4","signature":false},{"version":"56931daef761e6bdd586358664ccd37389baabeb5d20fe39025b9af90ea169a5","signature":false},{"version":"abb48247ab33e8b8f188ef2754dfa578129338c0f2e277bfc5250b14ef1ab7c5","signature":false},{"version":"beaba1487671ed029cf169a03e6d680540ea9fa8b810050bc94cb95d5e462db2","signature":false},{"version":"1418ef0ba0a978a148042bc460cf70930cd015f7e6d41e4eb9348c4909f0e16d","signature":false},{"version":"56be4f89812518a2e4f0551f6ef403ffdeb8158a7c271b681096a946a25227e9","signature":false},{"version":"bbb0937150b7ab2963a8bc260e86a8f7d2f10dc5ee7ddb1b4976095a678fdaa4","signature":false},{"version":"862301d178172dc3c6f294a9a04276b30b6a44d5f44302a6e9d7dc1b4145b20b","signature":false},{"version":"cbf20c7e913c08cb08c4c3f60dae4f190abbabaa3a84506e75e89363459952f0","signature":false},{"version":"0f3333443f1fea36c7815601af61cb3184842c06116e0426d81436fc23479cb8","signature":false},{"version":"421d3e78ed21efcbfa86a18e08d5b6b9df5db65340ef618a9948c1f240859cc1","signature":false},{"version":"b1225bc77c7d2bc3bad15174c4fd1268896a90b9ab3b306c99b1ade2f88cddcc","signature":false},{"version":"ca46e113e95e7c8d2c659d538b25423eac6348c96e94af3b39382330b3929f2a","signature":false},{"version":"03ca07dbb8387537b242b3add5deed42c5143b90b5a10a3c51f7135ca645bd63","signature":false},{"version":"ca936efd902039fda8a9fc3c7e7287801e7e3d5f58dd16bf11523dc848a247d7","signature":false},{"version":"2c7b3bfa8b39ed4d712a31e24a8f4526b82eeca82abb3828f0e191541f17004c","signature":false},{"version":"5ffaae8742b1abbe41361441aa9b55a4e42aee109f374f9c710a66835f14a198","signature":false},{"version":"ecab0f43679211efc9284507075e0b109c5ad024e49b190bb28da4adfe791e49","signature":false},{"version":"967109d5bc55face1aaa67278fc762ac69c02f57277ab12e5d16b65b9023b04f","signature":false},{"version":"36d25571c5c35f4ce81c9dcae2bdd6bbaf12e8348d57f75b3ef4e0a92175cd41","signature":false},{"version":"fde94639a29e3d16b84ea50d5956ee76263f838fa70fe793c04d9fce2e7c85b9","signature":false},{"version":"5f4c286fea005e44653b760ebfc81162f64aabc3d1712fd4a8b70a982b8a5458","signature":false},{"version":"e02dabe428d1ffd638eccf04a6b5fba7b2e8fccee984e4ef2437afc4e26f91c2","signature":false},{"version":"60dc0180bd223aa476f2e6329dca42fb0acaa71b744a39eb3f487ab0f3472e1c","signature":false},{"version":"b6fdbecf77dcbf1b010e890d1a8d8bfa472aa9396e6c559e0fceee05a3ef572f","signature":false},{"version":"e1bf9d73576e77e3ae62695273909089dbbb9c44fb52a1471df39262fe518344","signature":false},{"version":"fad7dc36fbac24ae2c643c8250bd2f428755258d365cd95943970ba17f9c7c4c","signature":false},{"version":"fdcd692f0ac95e72a0c6d1e454e13d42349086649828386fe7368ac08c989288","signature":false},{"version":"58fcf404770f5648652d2a9eb02601348fd1d7b7469cb89a97e3044551201e9b","signature":false},{"version":"b0641d9de5eaa90bff6645d754517260c3536c925b71c15cb0f189b68c5386b4","signature":false},{"version":"9899a0434bd02881d19cb08b98ddd0432eb0dafbfe5566fa4226bdd15624b56f","signature":false},{"version":"4496c81ce10a0a9a2b9cb1dd0e0ddf63169404a3fb116eb65c52b4892a2c91b9","signature":false},{"version":"ecdb4312822f5595349ec7696136e92ecc7de4c42f1ea61da947807e3f11ebfc","signature":false},{"version":"42edbfb7198317dd7359ce3e52598815b5dc5ca38af5678be15a4086cccd7744","signature":false},{"version":"8105321e64143a22ed5411258894fb0ba3ec53816dad6be213571d974542feeb","signature":false},{"version":"d1b34c4f74d3da4bdf5b29bb930850f79fd5a871f498adafb19691e001c4ea42","signature":false},{"version":"9a1caf586e868bf47784176a62bf71d4c469ca24734365629d3198ebc80858d7","signature":false},{"version":"35a443f013255b33d6b5004d6d7e500548536697d3b6ba1937fd788ca4d5d37b","signature":false},{"version":"b591c69f31d30e46bc0a2b383b713f4b10e63e833ec42ee352531bbad2aadfaa","signature":false},{"version":"31e686a96831365667cbd0d56e771b19707bad21247d6759f931e43e8d2c797d","signature":false},{"version":"dfc3b8616bece248bf6cd991987f723f19c0b9484416835a67a8c5055c5960e0","signature":false},{"version":"03b64b13ecf5eb4e015a48a01bc1e70858565ec105a5639cfb2a9b63db59b8b1","signature":false},{"version":"c56cc01d91799d39a8c2d61422f4d5df44fab62c584d86c8a4469a5c0675f7c6","signature":false},{"version":"5205951312e055bc551ed816cbb07e869793e97498ef0f2277f83f1b13e50e03","signature":false},{"version":"50b1aeef3e7863719038560b323119f9a21f5bd075bb97efe03ee7dec23e9f1b","signature":false},{"version":"0cc13970d688626da6dce92ae5d32edd7f9eabb926bb336668e5095031833b7c","signature":false},{"version":"3be9c1368c34165ba541027585f438ed3e12ddc51cdc49af018e4646d175e6a1","signature":false},{"version":"7d617141eb3f89973b1e58202cdc4ba746ea086ef35cdedf78fb04a8bb9b8236","signature":false},{"version":"ea6d9d94247fd6d72d146467070fe7fc45e4af6e0f6e046b54438fd20d3bd6a2","signature":false},{"version":"d584e4046091cdef5df0cb4de600d46ba83ff3a683c64c4d30f5c5a91edc6c6c","signature":false},{"version":"e79d0c35c071d7d2c8b5b97f7502c017ed9e5bed489f9f414bb4073fc9e596ac","signature":false},{"version":"d48ac7569126b1bc3cd899c3930ef9cf22a72d51cf45b60fc129380ae840c2f2","signature":false},{"version":"e4f0d7556fda4b2288e19465aa787a57174b93659542e3516fd355d965259712","signature":false},{"version":"756b471ce6ec8250f0682e4ad9e79c2fddbe40618ba42e84931dbb65d7ac9ab0","signature":false},{"version":"ce9635a3551490c9acdbcb9a0491991c3d9cd472e04d4847c94099252def0c94","signature":false},{"version":"b70ee10430cc9081d60eb2dc3bee49c1db48619d1269680e05843fdaba4b2f7a","signature":false},{"version":"9b78500996870179ab99cbbc02dffbb35e973d90ab22c1fb343ed8958598a36c","signature":false},{"version":"c6ee8f32bb16015c07b17b397e1054d6906bc916ab6f9cd53a1f9026b7080dbf","signature":false},{"version":"67e913fa79af629ee2805237c335ea5768ea09b0b541403e8a7eaef253e014d9","signature":false},{"version":"0b8a688a89097bd4487a78c33e45ca2776f5aedaa855a5ba9bc234612303c40e","signature":false},{"version":"188e5381ed8c466256937791eab2cc2b08ddcc5e4aaf6b4b43b8786ed1ab5edd","signature":false},{"version":"8559f8d381f1e801133c61d329df80f7fdab1cbad5c69ebe448b6d3c104a65bd","signature":false},{"version":"00a271352b854c5d07123587d0bb1e18b54bf2b45918ab0e777d95167fd0cb0b","signature":false},{"version":"10c4be0feeac95619c52d82e31a24f102b593b4a9eba92088c6d40606f95b85d","signature":false},{"version":"e1385f59b1421fceba87398c3eb16064544a0ce7a01b3a3f21fa06601dc415dc","signature":false},{"version":"bacf2c0f8cbfc5537b3c64fc79d3636a228ccbb00d769fb1426b542efe273585","signature":false},{"version":"3103c479ff634c3fbd7f97a1ccbfb645a82742838cb949fdbcf30dd941aa7c85","signature":false},{"version":"4b37b3fab0318aaa1d73a6fde1e3d886398345cff4604fe3c49e19e7edd8a50d","signature":false},{"version":"bf429e19e155685bda115cc7ea394868f02dec99ee51cfad8340521a37a5867a","signature":false},{"version":"72116c0e0042fd5aa020c2c121e6decfa5414cf35d979f7db939f15bb50d2943","signature":false},{"version":"20510f581b0ee148a80809122f9bcaa38e4691d3183a4ed585d6d02ffe95a606","signature":false},{"version":"71f4b56ed57bbdea38e1b12ad6455653a1fbf5b1f1f961d75d182bff544a9723","signature":false},{"version":"b3e1c5db2737b0b8357981082b7c72fe340edf147b68f949413fee503a5e2408","signature":false},{"version":"396e64a647f4442a770b08ed23df3c559a3fa7e35ffe2ae0bbb1f000791bda51","signature":false},{"version":"698551f7709eb21c3ddec78b4b7592531c3e72e22e0312a128c40bb68692a03f","signature":false},{"version":"662b28f09a4f60e802023b3a00bdd52d09571bc90bf2e5bfbdbc04564731a25e","signature":false},{"version":"e6b8fb8773eda2c898e414658884c25ff9807d2fce8f3bdb637ab09415c08c3c","signature":false},{"version":"528288d7682e2383242090f09afe55f1a558e2798ceb34dc92ae8d6381e3504a","signature":false},{"version":"f10f7d4836a332602943c5c02e79404a91c6353ac05a6af54ea9757cfd11faa1","signature":false},{"version":"387f1851362777f4f19ca902d02418e482237bfcd1b30b4dc3712068a3e73b90","signature":false},{"version":"89772a899f21b52e7837e0318abee76a527935d9ad66fbd95edb50b2287683bb","signature":false},{"version":"dddac6df25eebaf23087547248cac8476db31d5f7f8bc98b7b37f90e0b720527","signature":false},{"version":"0f339d0a24843a164f5fd6a96b2790df1333f487fcbd58d587664f025ccc1b82","signature":false},{"version":"91a0bb919e7bfe92fc0a3d80e0f1a3f6fdd9dac9a7dd0810021868299b2cd799","signature":false},{"version":"6fbf0bfdd07dfffe89201325ebf4ae4b68cfcc6111fa39487cd28e4bb6b60bc3","signature":false},{"version":"fbd772b29973d27296402483904bb652e68ffe22f75cbda82ccd017185b7d766","signature":false},{"version":"4ed46a22c75ba297c76efa99a9a4dfc6d6b4809d48443dafa2db0f1ff1a54f97","signature":false},{"version":"5039ff4a928b8aa3c334907b83a7bf9da97cf988ccff6e724615866bdc968ab7","signature":false},{"version":"070ca55de8428c2895094ccbeca111b39f9117cb3e2bbacc56abb22368f45432","signature":false},{"version":"8bbcc8f337381a474ea786f8b07b62c2dc7f99541a8355389400299702682df1","signature":false},{"version":"941593d7e4e0775ec23d664fab9fb4b988736e54399c73811396156e9376f478","signature":false},{"version":"968bf08da1fe4757f846e00cb922fc9a3e3574edcd744549969d9363cc425390","signature":false},{"version":"bff8bdf1a621ad97512324d5af06039277139f8aad29c84f658adfe540beb3f6","signature":false},{"version":"69096d34e43c2b7d75001becba9736de1f15e7d7bbced63001a0d330feb6f041","signature":false},{"version":"fe47635783915c9f391302ab99b4d04e794f4ed6bc33aea0f63b649978d70266","signature":false},{"version":"02368e8851c37067e85d58b1677c223e590651332d0f8c72f6d1d10ff06c294d","signature":false},{"version":"035c1509225d71141d190973e6ea10e0d018770f562d794e866e94d81c9ef6fe","signature":false},{"version":"b633fdd9d9ee0492d837507498dee10ee4d022abdfc0ef835136732cc8ff6dfe","signature":false},{"version":"ca6655067125531c24919480fecd9e6fc853300e0cdc5edeebc524822b0a01d9","signature":false},{"version":"1eb393edec7707c985759ef123b2d957eadc8778985cd49ed0e88236700d4919","signature":false},{"version":"85789750d5462288c75127880f9424d440d902fb91c0b33880bc8c46f2885b69","signature":false},{"version":"21db1a8796f752014c902ed515198d1895c3d3c0b45bdccc0f5e2672071f6d8b","signature":false},{"version":"42e6485ccb1a1b8503bd7f734c3cff3af75dc6d25825ff72333a6fce6f9b3824","signature":false},{"version":"61c445305757534cc014fdbe585c2b182058f6161d4bbf088c23fe51925247e9","signature":false},{"version":"8ee6a0865ff9d16396dba53d77b31bdf0a882ec16b72b3d009b769803a4602c6","signature":false},{"version":"067f97db9604209de4110678f79529c58716888f19b4609c8ed7a6f64862eac8","signature":false},{"version":"48f9abc890cc60ab31db98165247b7b403ff05fd2b10cc13e2ac9a1d3824d198","signature":false},{"version":"f629df70d2b88f85a29f23a1d500ef182907659d437713d1a19d1d7e1933d769","signature":false},{"version":"603c24568d631e0fab71de0057305e87eedaa74389db1591a644afbb1f7c6e77","signature":false},{"version":"fdcfaa35f58cae08796642d17cbb2ea241e4d42a5f70bb3e62c20b8fc7530fc6","signature":false},{"version":"05321b823dd3781d0b6aac8700bfdc0c9181d56479fe52ba6a40c9196fd661a8","signature":false},{"version":"89237d571d7e8924a959d51634bf160002b09746f1cc7da462bc4cfabe4586a2","signature":false},{"version":"d071c1fa889272a3c73a1fb993916fbd6fb5c70d90a7a19a9beb7d83b3d6060b","signature":false},{"version":"cae7352bb245e704ef62707bbdc971e50e4012678113d5ba0b323b3d72166a20","signature":false},{"version":"bd300ffaed2475c60561ebe79876dcccba1198a1f7503dfc1bbe7547194532e1","signature":false},{"version":"377ce44b9725f9346b06d2888ab689a824ad99c6ef3624f4ce1e98e5d6d083bb","signature":false},{"version":"2f848b4e660b568651a6350565afc8ac5b0644853a2a863862807602cf244a05","signature":false},{"version":"6ac85cb2c23dcb52445b268258a7ea36d620054e7db53874d890bb64981ddc13","signature":false},{"version":"3b2b34c11b1998d44a86a3eea7cf833dc63f25fa3b62a91683165d2e51753126","signature":false},{"version":"5e4ca7b93dfc22babb0192d681736fb2f6cff00cd983e1758fee30938db80f1d","signature":false},{"version":"c6fe8344e3031fe508ae1215dbcb2d54b13b911fa2366ffe7510a4b44e96ce55","signature":false},{"version":"3eb48ff682498db13b352124f30308340a223ee405ca8c60685511eb87ba15be","signature":false},{"version":"46872cbcf7f1dc60e570fa9a97a9dad480bdca6de92386ec61031b7b0388b2f9","signature":false},{"version":"9acec24bfee6d4684e084e5b0f9ac1463199fcc09a55f309717e290e03b4afc2","signature":false},{"version":"7e9569b2e39f27fabfcf3644816654d71fb01a107b2baf343cc9aaa730e78821","signature":false},{"version":"8ea21d92ccfc4932ac22be7c557915328a8383d4b67a3add27e817a50cb8f617","signature":false},{"version":"c3701b37e821ea1544db3f825186b999b18bb1b3143789e7f7c00b401cea7025","signature":false},{"version":"89c2dd818e9dbb6a6da17a5a74606b508a20af7ec55067714879626932ce8d72","signature":false},{"version":"9cdf3b2979eb7fa85b37b8915ba702920ff5bee4d0a4692c5b5f7b1cd1834299","signature":false},{"version":"6c0023ce73220afc10e2d80faf44781e048e297b13e3d69ba887c6725b54d132","signature":false},{"version":"70521b6ab0dcba37539e5303104f29b721bfb2940b2776da4cc818c07e1fefc1","signature":false,"affectsGlobalScope":true},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","signature":false,"affectsGlobalScope":true},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","signature":false,"affectsGlobalScope":true},{"version":"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a","signature":false},{"version":"613b21ccdf3be6329d56e6caa13b258c842edf8377be7bc9f014ed14cdcfc308","signature":false,"affectsGlobalScope":true},{"version":"2d1319e6b5d0efd8c5eae07eb864a00102151e8b9afddd2d45db52e9aae002c4","signature":false,"affectsGlobalScope":true},{"version":"8e9c23ba78aabc2e0a27033f18737a6df754067731e69dc5f52823957d60a4b6","signature":false},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","signature":false},{"version":"24bd580b5743dc56402c440dc7f9a4f5d592ad7a419f25414d37a7bfe11e342b","signature":false},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","signature":false},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","signature":false},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","signature":false},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","signature":false},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","signature":false},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","signature":false},{"version":"6bdc71028db658243775263e93a7db2fd2abfce3ca569c3cca5aee6ed5eb186d","signature":false},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","signature":false},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","signature":false},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","signature":false},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","signature":false},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","signature":false},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","signature":false},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","signature":false},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","signature":false},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","signature":false},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","signature":false},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","signature":false},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","signature":false},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","signature":false},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","signature":false},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","signature":false},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","signature":false},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","signature":false},{"version":"4d2b0eb911816f66abe4970898f97a2cfc902bcd743cbfa5017fad79f7ef90d8","signature":false},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","signature":false},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","signature":false},{"version":"e53a3c2a9f624d90f24bf4588aacd223e7bec1b9d0d479b68d2f4a9e6011147f","signature":false},{"version":"24b8685c62562f5d98615c5a0c1d05f297cf5065f15246edfe99e81ec4c0e011","signature":false},{"version":"93507c745e8f29090efb99399c3f77bec07db17acd75634249dc92f961573387","signature":false},{"version":"339dc5265ee5ed92e536a93a04c4ebbc2128f45eeec6ed29f379e0085283542c","signature":false},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","signature":false},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","signature":false},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","signature":false},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","signature":false},{"version":"ca6d304b929748ea15c33f28c1f159df18a94470b424ab78c52d68d40a41e1e9","signature":false,"affectsGlobalScope":true},{"version":"a72ffc815104fb5c075106ebca459b2d55d07862a773768fce89efc621b3964b","signature":false},{"version":"7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","signature":false},{"version":"3d77c73be94570813f8cadd1f05ebc3dc5e2e4fdefe4d340ca20cd018724ee36","signature":false},{"version":"d674383111e06b6741c4ad2db962131b5b0fa4d0294b998566c635e86195a453","signature":false,"affectsGlobalScope":true},{"version":"f3e58c4c18a031cbb17abec7a4ad0bd5ae9fc70c1f4ba1e7fb921ad87c504aca","signature":false},{"version":"a3e8bafb2af8e850c644f4be7f5156cf7d23b7bfdc3b786bd4d10ed40329649c","signature":false},{"version":"35ec8b6760fd7138bbf5809b84551e31028fb2ba7b6dc91d95d098bf212ca8b4","signature":false,"affectsGlobalScope":true},{"version":"a40826e8476694e90da94aa008283a7de50d1dafd37beada623863f1901cb7fb","signature":false},{"version":"f77d9188e41291acf14f476e931972460a303e1952538f9546e7b370cb8d0d20","signature":false,"affectsGlobalScope":true},{"version":"b0c0d1d13be149f790a75b381b413490f98558649428bb916fd2d71a3f47a134","signature":false},{"version":"3c884d9d9ec454bdf0d5a0b8465bf8297d2caa4d853851d92cc417ac6f30b969","signature":false},{"version":"5a369483ac4cfbdf0331c248deeb36140e6907db5e1daed241546b4a2055f82c","signature":false},{"version":"e8f5b5cc36615c17d330eaf8eebbc0d6bdd942c25991f96ef122f246f4ff722f","signature":false},{"version":"f0bd7e6d931657b59605c44112eaf8b980ba7f957a5051ed21cb93d978cf2f45","signature":false},{"version":"ee1ee365d88c4c6c0c0a5a5701d66ebc27ccd0bcfcfaa482c6e2e7fe7b98edf7","signature":false,"affectsGlobalScope":true},{"version":"4d7da7075068195f8f127f41c61e304cdca5aafb1be2d0f4fb67c6b4c3e98d50","signature":false,"affectsGlobalScope":true},{"version":"a4bdde4e601e9554a844e1e0d0ccfa05e183ef9d82ab3ac25f17c1709033d360","signature":false},{"version":"ad23fd126ff06e72728dd7bfc84326a8ca8cec2b9d2dac0193d42a777df0e7d8","signature":false},{"version":"9dd9f50652a176469e85fb65aa081d2e7eb807e2c476f378233de4f1f6604962","signature":false},{"version":"93bd413918fa921c8729cef45302b24d8b6c7855d72d5bf82d3972595ae8dcbf","signature":false},{"version":"4ff41188773cbf465807dd2f7059c7494cbee5115608efc297383832a1150c43","signature":false},{"version":"dccdf1677e531e33f8ac961a68bc537418c9a414797c1ea7e91307501cdc3f5e","signature":false},{"version":"7edec695cdb707c7146ac34c44ca364469c7ea504344b3206c686e79f61b61a2","signature":false,"affectsGlobalScope":true},{"version":"d206b4baf4ddcc15d9d69a9a2f4999a72a2c6adeaa8af20fa7a9960816287555","signature":false},{"version":"93f437e1398a4f06a984f441f7fa7a9f0535c04399619b5c22e0b87bdee182cb","signature":false},{"version":"afbe24ab0d74694372baa632ecb28bb375be53f3be53f9b07ecd7fc994907de5","signature":false},{"version":"70731d10d5311bd4cf710ef7f6539b62660f4b0bfdbb3f9fbe1d25fe6366a7fa","signature":false,"affectsGlobalScope":true},{"version":"a20f1e119615bf7632729fd89b6c0b5ffdc2df3b512d6304146294528e3ebe19","signature":false,"affectsGlobalScope":true},{"version":"9e043a1bc8fbf2a255bccf9bf27e0f1caf916c3b0518ea34aa72357c0afd42ec","signature":false},{"version":"137c2894e8f3e9672d401cc0a305dc7b1db7c69511cf6d3970fb53302f9eae09","signature":false},{"version":"3bc2f1e2c95c04048212c569ed38e338873f6a8593930cf5a7ef24ffb38fc3b6","signature":false},{"version":"8145e07aad6da5f23f2fcd8c8e4c5c13fb26ee986a79d03b0829b8fce152d8b2","signature":false},{"version":"f9d9d753d430ed050dc1bf2667a1bab711ccbb1c1507183d794cc195a5b085cc","signature":false},{"version":"9eece5e586312581ccd106d4853e861aaaa1a39f8e3ea672b8c3847eedd12f6e","signature":false},{"version":"235bfb54b4869c26f7e98e3d1f68dbfc85acf4cf5c38a4444a006fbf74a8a43d","signature":false},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","signature":false},{"version":"93452d394fdd1dc551ec62f5042366f011a00d342d36d50793b3529bfc9bd633","signature":false},{"version":"bb715efb4857eb94539eafb420352105a0cff40746837c5140bf6b035dd220ba","signature":false,"affectsGlobalScope":true},{"version":"1851a3b4db78664f83901bb9cac9e45e03a37bb5933cc5bf37e10bb7e91ab4eb","signature":false},{"version":"fdedf82878e4c744bc2a1c1e802ae407d63474da51f14a54babe039018e53d8f","signature":false,"affectsGlobalScope":true},{"version":"08353b04a3501d84fc8d7b49de99f6c1cc26026e6d9d697a18315f3bfe92ed03","signature":false,"affectsGlobalScope":true},{"version":"578d8bb6dcb2a1c03c4c3f8eb71abc9677e1a5c788b7f24848e3138ce17f3400","signature":false},{"version":"4f029899f9bae07e225c43aef893590541b2b43267383bf5e32e3a884d219ed5","signature":false},{"version":"ae56f65caf3be91108707bd8dfbccc2a57a91feb5daabf7165a06a945545ed26","signature":false},{"version":"a136d5de521da20f31631a0a96bf712370779d1c05b7015d7019a9b2a0446ca9","signature":false},{"version":"5b566927cad2ed2139655d55d690ffa87df378b956e7fe1c96024c4d9f75c4cf","signature":false,"affectsGlobalScope":true},{"version":"bce947017cb7a2deebcc4f5ba04cead891ce6ad1602a4438ae45ed9aa1f39104","signature":false,"affectsGlobalScope":true},{"version":"efeedd8bbc5c0d53e760d8b120a010470722982e6ae14de8d1bcff66ebc2ae71","signature":false},{"version":"e2c72c065a36bc9ab2a00ac6a6f51e71501619a72c0609defd304d46610487a4","signature":false},{"version":"d91a7d8b5655c42986f1bdfe2105c4408f472831c8f20cf11a8c3345b6b56c8c","signature":false},{"version":"616075a6ac578cf5a013ee12964188b4412823796ce0b202c6f1d2e4ca8480d7","signature":false,"affectsGlobalScope":true},{"version":"e8a979b8af001c9fc2e774e7809d233c8ca955a28756f52ee5dee88ccb0611d2","signature":false},{"version":"9091e564b81e7b4c382a33c62de704a699e10508190547d4f7c1c3e039d2db2b","signature":false},{"version":"785b9d575b49124ce01b46f5b9402157c7611e6532effa562ac6aebec0074dfc","signature":false},{"version":"e58a3ce75105c1557e34fab7408942d77374e047c16383e80880ed1220166dfa","signature":false,"affectsGlobalScope":true},{"version":"a660aa95476042d3fdcc1343cf6bb8fdf24772d31712b1db321c5a4dcc325434","signature":false},{"version":"282f98006ed7fa9bb2cd9bdbe2524595cfc4bcd58a0bb3232e4519f2138df811","signature":false},{"version":"6222e987b58abfe92597e1273ad7233626285bc2d78409d4a7b113d81a83496b","signature":false},{"version":"cbe726263ae9a7bf32352380f7e8ab66ee25b3457137e316929269c19e18a2be","signature":false},{"version":"8b96046bf5fb0a815cba6b0880d9f97b7f3a93cf187e8dcfe8e2792e97f38f87","signature":false},{"version":"bacf2c84cf448b2cd02c717ad46c3d7fd530e0c91282888c923ad64810a4d511","signature":false,"affectsGlobalScope":true},{"version":"402e5c534fb2b85fa771170595db3ac0dd532112c8fa44fc23f233bc6967488b","signature":false},{"version":"8885cf05f3e2abf117590bbb951dcf6359e3e5ac462af1c901cfd24c6a6472e2","signature":false},{"version":"4d979e3c12ffb6497d2b1dc5613130196d986fff764c4526360c0716a162e7e7","signature":false},{"version":"e61df3640a38d535fd4bc9f4a53aef17c296b58dc4b6394fd576b808dd2fe5e6","signature":false},{"version":"80781460eca408fe8d2937d9fdbbb780d6aac35f549621e6200c9bee1da5b8fe","signature":false},{"version":"4719c209b9c00b579553859407a7e5dcfaa1c472994bd62aa5dd3cc0757eb077","signature":false},{"version":"7ec359bbc29b69d4063fe7dad0baaf35f1856f914db16b3f4f6e3e1bca4099fa","signature":false},{"version":"b9261ac3e9944d3d72c5ee4cf888ad35d9743a5563405c6963c4e43ee3708ca4","signature":false},{"version":"c84fd54e8400def0d1ef1569cafd02e9f39a622df9fa69b57ccc82128856b916","signature":false},{"version":"a022503e75d6953d0e82c2c564508a5c7f8556fad5d7f971372d2d40479e4034","signature":false},{"version":"2ed6489ef46eb61442d067c08e87e3db501c0bfb2837eee4041a27bf3e792bb0","signature":false},{"version":"644491cde678bd462bb922c1d0cfab8f17d626b195ccb7f008612dc31f445d2d","signature":false},{"version":"d60fe6d59d4e19ecc65359490b8535e359ca4b760d2cdb56897ca75d09d41ba3","signature":false},{"version":"f45a2a8b1777ecb50ed65e1a04bb899d4b676529b7921bd5d69b08573a00c832","signature":false},{"version":"774b783046ba3d473948132d28a69f52a295b2f378f2939304118ba571b1355e","signature":false},{"version":"b5734e05c787a40e4f9efe71f16683c5f7dc3bdb0de7c04440c855bd000f8fa7","signature":false},{"version":"14ba97f0907144771331e1349fdccb5a13526eba0647e6b447e572376d811b6f","signature":false},{"version":"2a771d907aebf9391ac1f50e4ad37952943515eeea0dcc7e78aa08f508294668","signature":false},{"version":"7165050eddaed878c2d2cd3cafcaf171072ac39e586a048c0603712b5555f536","signature":false},{"version":"26e629be9bbd94ea1d465af83ce5a3306890520695f07be6eb016f8d734d02be","signature":false},{"version":"82e687ebd99518bc63ea04b0c3810fb6e50aa6942decd0ca6f7a56d9b9a212a6","signature":false},{"version":"7f698624bbbb060ece7c0e51b7236520ebada74b747d7523c7df376453ed6fea","signature":false},{"version":"8f07f2b6514744ac96e51d7cb8518c0f4de319471237ea10cf688b8d0e9d0225","signature":false},{"version":"9ae0ca65717af0d3b554a26fd333ad9c78ad3910ad4b22140ff02acb63076927","signature":false},{"version":"03f1d83d61696326ea29c8a1c15cbaccf61e92598d53f2ccae06078531f42448","signature":false},{"version":"2c8e55457aaf4902941dfdba4061935922e8ee6e120539c9801cd7b400fae050","signature":false},{"version":"3a9313fe5ace558b8b18e85f931da10b259e738775f411c061e5f15787b138eb","signature":false},{"version":"670a76db379b27c8ff42f1ba927828a22862e2ab0b0908e38b671f0e912cc5ed","signature":false},{"version":"9e0cf651e8e2c5b9bebbabdff2f7c6f8cedd91b1d9afcc0a854cdff053a88f1b","signature":false},{"version":"069bebfee29864e3955378107e243508b163e77ab10de6a5ee03ae06939f0bb9","signature":false},{"version":"f5e8546cfe500116aba8a6cb7ee171774b14a6db30d4bcd6e0aa5073e919e739","signature":false},{"version":"cadf7a128bda2a4937411ad8fc659c08142ae7b53a7559eada72e8c34a5ea273","signature":false},{"version":"77b55f8bfab90aa408704132d98b72f8762e2fe955eeda093ace44120d6adc1a","signature":false},{"version":"3d922ac35e7bd201c09c71d0a3be9cab0ac41bdd0d5115f2734c8555629e5414","signature":false},{"version":"ae18a824baa6829b4b687f4e678d97c2b3f0ee75a82e2cff792180002f1e2a82","signature":false},{"version":"fe1baccba85e2af0fdaca57b32b34f3fd602609bb0b29aeb0609000dbcd75446","signature":false},{"version":"ae04fe1adb6d10414645db0d9c264ae06a48cd73fbb043053afe9c72849e5e44","signature":false},{"version":"e9f7405a92dd7c1b4b7d16d411ebe2951ce1be32d63668d40ac9b6e5d87e68a2","signature":false},{"version":"b66d13c54338e58c93f39d9d158a52c8c3db3cd04687eb87b752426d84359cfc","signature":false},{"version":"40afb567fb15f802cc373d3f968cb12f06ef91105997ac6cd1b7476f9f1400a7","signature":false},{"version":"b4f7765a7e4378d5553d62243e1294f9e84e6b155b786ff3a2d70dd90a0b7269","signature":false},{"version":"767b2fc647298d1e885ab9b5e80a3bfc955b7c3a56fdc67e09697ac66662617f","signature":false},{"version":"58d97a898371adf4648416a194695cac091094a93aec40d4bf80d178c655e322","signature":false},{"version":"33ab53254b48915b80729554b64dc520ddf52fa2fbb9d158f548e04184ebcf8c","signature":false},{"version":"0c85d40d15a7dccddc3f1687c956b44e884da668c4709ebe46443ba01f8e8842","signature":false},{"version":"bb9e974b872fc5efe3fbeb234afa1b167466822c521adec28f312b629f5dda56","signature":false},{"version":"c8263035d5bb170e586fef2a84cb43b6ae0a40e0febe619b3870733587629ab4","signature":false},{"version":"854d32966f04256f250530f7c03b4f7e11379c73b88d45cf8eb867ee3f790866","signature":false},{"version":"7372dded088ca5020b7bdc36c767207b5be95bac93db7d4da8939b4e5183d504","signature":false},{"version":"f141146eac82ec13c16311bc7d5088251c6c36e177946f804532b9457a5b4858","signature":false},{"version":"4af9e9cd8b6f583bbd4f5a25603385d0d32082b437334b70c90b5ea56a197301","signature":false},{"version":"68c96a0456890bd49e2871dd88c53ff7f9fd87eb32f2cd419e4a83f79a8d5ef1","signature":false},{"version":"73a58b4dd96dd47dab5b4029726b9bb923543ca24ddd04c6069577945ba46a88","signature":false},{"version":"b3554a8f9ac018e333c208a4eaac5744c6739430fd58a9442b904949a4850cdc","signature":false},{"version":"fd893a255c9b5fbcf730166bfc8cb13cbdfbd151212fe6d14bbc2850b1577dfb","signature":false},{"version":"288fa23f9ecb8231712fda606a90e8fcb8e5badc7d26b6aa55f41c935406654d","signature":false},{"version":"469a48cc4e8c79de08be72d4b91aba0c1ff0ff590ddaf4d63430cb8195d5d3b1","signature":false},{"version":"1a4c70b6a02db30f1f4cf606763ef4811f7f1ce845c6513e75ac92e8d066fb46","signature":false},{"version":"71a56feb625489eec845132b255df1429e3e0e7c76a4e3eef4731f82748076cb","signature":false},{"version":"a11f50b21d60f03639225314e0b81e1ffb73469f6500648c303b2a6b26f94d1d","signature":false},{"version":"22298d232181e1e9ca783a93313a1ceb3ecbd944a1a42838f7d83d9f11df45ea","signature":false},{"version":"884929ee3ca6ff58cf58e772dc43fbd74ba99a8992fc86fb8c85ab3d28785e78","signature":false},{"version":"53ef177c7249d3f65651d3fdd4cfb32cb844ea392df381c169706a12f8fa9550","signature":false},{"version":"9afa98c7dec7156faed568a4dc786c4ee0b04314b1237db88d9b81adb5acf4e4","signature":false},{"version":"4025a454b1ca489b179ee8c684bdd70ff8c1967e382076ade53e7e4653e1daec","signature":false,"affectsGlobalScope":true},{"version":"984c09345059b76fc4221c2c54e53511f4c27a0794dfd6e9f81dc60f0b564e05","signature":false,"affectsGlobalScope":true},{"version":"c5d5ae4f669c76024b1e0faa2bad30cfbbd85f8a5b52fad6faaa82e198101ad0","signature":false}],"root":[[94,121],128,129,[131,136],[140,142],180,[182,197],221,[395,418],[420,426],[428,432],[435,446],[590,616]],"options":{"allowImportingTsExtensions":true,"composite":true,"jsx":4,"module":99,"noFallthroughCasesInSwitch":true,"noUnusedLocals":true,"noUnusedParameters":true,"skipLibCheck":true,"strict":true,"target":7,"useDefineForClassFields":true},"fileIdsList":[[51,52,53,54,446,452,495,618],[51,53,55,56,446,452,495,618],[51,52,53,446,452,495,618],[51,52,55,446,452,495,618],[446,452,495,618],[52,53,55,446,452,495,618],[52,56,446,452,495,618],[50,93,107,437,438,439,440,441,442,443,444,446,452,495,618],[50,170,180,183,446,452,495,618],[50,180,181,182,446,452,495,618],[49,50,52,220,446,452,495,618],[49,50,395,425,446,452,495,618],[50,446,452,495,618],[50,113,119,446,452,495,618],[50,58,115,116,117,120,446,452,495,618],[50,113,446,452,495,618],[50,114,446,452,495,618],[50,131,446,452,495,618],[50,185,446,452,495,618],[50,126,127,446,452,495,618],[50,126,419,446,452,495,618],[50,128,129,135,446,452,495,618],[50,58,130,132,133,134,446,452,495,618],[49,50,446,452,495,618],[50,180,190,446,452,495,618],[50,192,446,452,495,618],[50,194,446,452,495,618],[50,58,115,116,135,140,141,142,189,191,193,195,196,446,452,495,618],[50,132,135,141,180,184,188,446,452,495,618],[49,50,135,184,186,187,446,452,495,618,619],[49,50,51,53,254,394,398,400,401,402,446,452,495,618],[50,52,397,446,452,495,618],[50,399,446,452,495,618],[49,50,58,113,130,431,432,434,446,452,495,618],[49,50,51,52,53,54,55,221,367,394,395,396,403,404,407,446,452,495,618],[50,55,367,408,446,452,495,618],[49,50,51,52,54,55,406,408,446,452,495,618],[50,405,446,452,495,618],[50,411,446,452,495,618,619],[50,413,446,452,495,618],[49,50,116,140,194,415,446,452,495,618],[50,52,58,116,408,409,410,412,414,416,446,452,495,618],[50,420,421,446,452,495,618],[49,50,56,57,116,395,446,452,495,618],[49,50,395,446,452,495,618],[49,50,57,121,136,197,395,417,418,422,423,424,446,452,495,618],[49,50,170,426,427,446,452,495,618],[50,139,446,452,495,618],[50,52,139,220,446,452,495,618],[50,139,176,179,446,452,495,618],[50,93,107,446,452,495,618],[50,430,446,452,495,618],[50,440,446,452,495,618],[50,415,446,452,495,618],[50,52,446,452,495,618],[108,446,452,495,618],[103,446,452,495,618],[109,110,111,112,446,452,495,618],[95,99,101,102,108,446,452,495,618],[446,452,495,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,618],[102,108,446,452,495,618],[118,446,452,495,618],[98,446,452,495,618],[102,446,452,495,618],[96,446,452,495,618],[93,102,103,104,105,106,107,446,452,495,618],[97,101,102,103,105,107,446,452,495,618],[99,102,446,452,495,618],[97,99,102,446,452,495,618],[94,102,446,452,495,618],[95,446,452,495,618],[97,99,100,102,446,452,495,618],[95,97,101,446,452,495,618],[452,495,618],[50,446,452,495,517,576,583,584,589,618],[446,452,495,577,618],[49,308,446,452,495,618],[310,446,452,495,618],[308,446,452,495,618],[308,309,311,312,446,452,495,618],[307,446,452,495,618],[49,254,268,284,301,313,338,341,342,446,452,495,618],[342,343,446,452,495,618],[268,301,446,452,495,618],[49,345,446,452,495,618],[345,346,347,348,446,452,495,618],[268,446,452,495,618],[345,446,452,495,618],[49,268,446,452,495,618],[350,446,452,495,618],[351,353,355,446,452,495,618],[352,446,452,495,618],[49,446,452,495,618],[354,446,452,495,618],[49,254,268,446,452,495,618],[49,341,356,359,446,452,495,618],[357,358,446,452,495,618],[254,268,307,344,446,452,495,618],[359,360,446,452,495,618],[313,344,349,361,446,452,495,618],[301,363,364,365,446,452,495,618],[49,307,446,452,495,618],[49,254,268,301,307,446,452,495,618],[49,268,307,446,452,495,618],[269,270,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,446,452,495,618],[268,307,446,452,495,618],[284,285,446,452,495,618],[268,303,446,452,495,618],[233,268,446,452,495,618],[254,446,452,495,618],[284,446,452,495,618],[367,446,452,495,618],[268,284,307,338,341,362,366,446,452,495,618],[254,339,446,452,495,618],[339,340,446,452,495,618],[254,268,307,446,452,495,618],[271,272,273,276,278,280,283,446,452,495,618],[281,282,446,452,495,618],[271,281,446,452,495,618],[268,271,446,452,495,618],[277,446,452,495,618],[49,271,276,446,452,495,618],[274,275,446,452,495,618],[49,271,274,446,452,495,618],[279,446,452,495,618],[49,263,268,307,446,452,495,618],[271,446,452,495,618],[49,303,446,452,495,618],[303,304,305,306,446,452,495,618],[303,304,446,452,495,618],[49,254,263,268,301,302,304,362,446,452,495,618],[255,263,307,446,452,495,618],[255,256,264,265,266,267,446,452,495,618],[49,254,446,452,495,618],[257,446,452,495,618],[257,268,446,452,495,618],[257,258,259,260,261,262,446,452,495,618],[314,315,316,446,452,495,618],[263,317,324,326,337,446,452,495,618],[325,446,452,495,618],[254,268,446,452,495,618],[318,319,320,321,322,323,446,452,495,618],[267,446,452,495,618],[327,328,329,330,331,332,333,334,335,336,446,452,495,618],[373,446,452,495,618],[49,367,372,446,452,495,618],[375,446,452,495,618],[375,376,377,446,452,495,618],[254,367,446,452,495,618],[49,254,301,367,372,375,446,452,495,618],[372,374,378,383,386,393,446,452,495,618],[385,446,452,495,618],[384,446,452,495,618],[372,446,452,495,618],[379,380,381,382,446,452,495,618],[368,369,370,371,446,452,495,618],[367,369,446,452,495,618],[387,388,389,390,391,392,446,452,495,618],[233,446,452,495,618],[233,234,446,452,495,618],[237,238,239,446,452,495,618],[241,242,243,446,452,495,618],[245,446,452,495,618],[222,223,224,225,226,227,228,229,230,446,452,495,618],[231,232,235,236,240,244,246,252,253,446,452,495,618],[247,248,249,250,251,446,452,495,618],[49,123,446,452,495,618],[123,124,125,446,452,495,618],[49,122,446,452,495,618],[92,446,452,495,618],[77,78,446,452,495,618],[88,446,452,495,618],[65,446,452,495,618],[70,446,452,495,618],[63,446,452,495,618],[61,64,67,70,81,82,84,86,87,446,452,495,618],[70,71,72,88,446,452,495,618],[66,73,74,80,88,446,452,495,618],[64,66,67,70,71,72,73,74,80,81,82,83,84,85,86,87,88,89,90,91,446,452,495,618],[79,446,452,495,618],[70,83,446,452,495,618],[64,70,446,452,495,618],[67,70,446,452,495,618],[62,446,452,495,618],[62,64,68,446,452,495,618],[64,446,452,495,618],[62,64,69,446,452,495,618],[70,71,83,85,446,452,495,618],[82,446,452,495,618],[70,82,83,446,452,495,618],[446,452,495,545,546,618],[446,452,495,580,582,618],[446,452,495,582,586,618],[434,446,452,495,582,587,618],[144,446,452,495,618],[143,144,446,452,495,618],[143,144,145,146,147,148,149,150,446,452,495,618],[143,144,145,446,452,495,618],[49,151,446,452,495,618],[49,50,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,446,452,495,618],[151,152,446,452,495,618],[151,446,452,495,618],[151,152,161,446,452,495,618],[151,152,154,446,452,495,618],[75,446,452,495,618],[446,452,495,577,578,579,580,581,618],[446,452,495,577,579,618],[446,452,492,495,618],[446,452,494,495,618],[446,452,495,500,529,618],[446,452,495,496,501,507,508,515,526,537,618],[446,452,495,496,497,507,515,618],[446,447,448,449,452,495,618],[446,452,495,498,538,618],[446,452,495,499,500,508,516,618],[446,452,495,500,526,534,618],[446,452,495,501,503,507,515,618],[446,452,494,495,502,618],[446,452,495,503,504,618],[446,452,495,507,618],[446,452,495,505,507,618],[446,452,494,495,507,618],[446,452,495,507,508,509,526,537,618],[446,452,495,507,508,509,522,526,529,618],[446,452,490,495,542,618],[446,452,495,503,507,510,515,526,537,618],[446,452,495,507,508,510,511,515,526,534,537,618],[446,452,495,510,512,526,534,537,618],[446,452,495,507,513,618],[446,452,495,514,537,542,618],[446,452,495,503,507,515,526,618],[446,452,495,516,618],[446,452,495,517,618],[446,452,494,495,518,618],[446,452,492,493,494,495,496,497,498,499,500,501,502,503,504,505,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,618],[446,452,495,520,618],[446,452,495,521,618],[446,452,495,507,522,523,618],[446,452,495,522,524,538,540,618],[446,452,495,507,526,527,528,529,618],[446,452,495,526,528,618],[446,452,495,526,527,618],[446,452,495,529,618],[446,452,495,530,618],[446,452,492,495,526,618],[446,452,495,507,532,533,618],[446,452,495,532,533,618],[446,452,495,500,515,526,534,618],[446,452,495,535,618],[446,495,618],[446,450,451,452,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,618],[446,452,495,515,536,618],[446,452,495,510,521,537,618],[446,452,495,500,538,618],[446,452,495,526,539,618],[446,452,495,514,540,618],[446,452,495,541,618],[446,452,495,500,507,509,518,526,537,540,542,618],[446,452,495,526,543,618],[46,47,48,446,452,495,618],[446,452,495,576,582,618],[203,204,205,207,208,209,210,211,212,213,214,215,446,452,495,618],[198,202,203,204,446,452,495,618],[198,202,205,446,452,495,618],[208,210,211,446,452,495,618],[206,446,452,495,618],[198,202,204,205,206,446,452,495,618],[207,446,452,495,618],[203,446,452,495,618],[202,203,446,452,495,618],[202,209,446,452,495,618],[199,446,452,495,618],[199,200,201,446,452,495,618],[59,60,446,452,495,618],[446,452,495,568,618],[446,452,495,566,568,618],[446,452,495,557,565,566,567,569,618],[446,452,495,555,618],[446,452,495,558,563,568,571,618],[446,452,495,554,571,618],[446,452,495,558,559,562,563,564,571,618],[446,452,495,558,559,560,562,563,571,618],[446,452,495,555,556,557,558,559,563,564,565,567,568,569,571,618],[446,452,495,571,618],[446,452,495,553,555,556,557,558,559,560,562,563,564,565,566,567,568,569,570,618],[446,452,495,553,571,618],[446,452,495,558,560,561,563,564,571,618],[446,452,495,562,571,618],[446,452,495,563,564,568,571,618],[446,452,495,556,566,618],[433,446,452,495,618],[446,452,495,546,575,618],[216,217,218,219,446,452,495,618],[198,216,217,218,446,452,495,618],[198,217,219,446,452,495,618],[198,446,452,495,618],[60,446,452,495,618],[76,446,452,495,618],[446,452,462,466,495,537,618],[446,452,462,495,526,537,618],[446,452,457,495,618],[446,452,459,462,495,534,537,618],[446,452,495,515,534,618],[446,452,495,544,618],[446,452,457,495,544,618],[446,452,459,462,495,515,537,618],[446,452,454,455,458,461,495,507,526,537,618],[446,452,462,469,495,618],[446,452,454,460,495,618],[446,452,462,483,484,495,618],[446,452,458,462,495,529,537,544,618],[446,452,483,495,544,618],[446,452,456,457,495,544,618],[446,452,462,495,618],[446,452,456,457,458,459,460,461,462,463,464,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,484,485,486,487,488,489,495,618],[446,452,462,477,495,618],[446,452,462,469,470,495,618],[446,452,460,462,470,471,495,618],[446,452,461,495,618],[446,452,454,457,462,495,618],[446,452,462,466,470,471,495,618],[446,452,466,495,618],[446,452,460,462,465,495,537,618],[446,452,454,459,462,469,495,618],[446,452,495,526,618],[446,452,457,462,483,495,542,544,618],[446,452,495,576,585,588,618],[446,452,495,576,618],[446,452,495,617],[446,452,495,507,508,510,511,512,515,526,534,537,543,544,546,547,548,549,550,551,552,572,573,574,575,618],[446,452,495,548,549,550,551,618],[446,452,495,548,549,550,618],[446,452,495,548,618],[446,452,495,549,618],[446,452,495,550,574,618],[446,452,495,546,618],[137,138,171,172,173,175,446,452,495,618],[171,172,173,174,175,446,452,495,618],[137,171,172,173,175,446,452,495,618],[177,178,446,452,495,618]],"referencedMap":[[55,1],[52,2],[54,3],[53,4],[51,5],[56,6],[57,7],[445,8],[184,9],[183,10],[221,11],[426,12],[127,13],[419,13],[117,13],[120,14],[121,15],[114,16],[115,17],[131,14],[132,18],[185,16],[186,19],[128,20],[420,21],[129,16],[136,22],[133,13],[134,14],[135,23],[141,24],[190,16],[191,25],[192,16],[193,26],[195,27],[196,14],[197,28],[430,13],[431,13],[142,13],[194,13],[415,13],[189,29],[187,16],[188,30],[401,13],[402,16],[403,31],[397,16],[398,32],[399,16],[400,33],[432,16],[435,34],[396,16],[408,35],[436,24],[404,36],[407,37],[406,38],[411,16],[412,39],[413,16],[414,40],[416,41],[409,13],[410,14],[417,42],[421,16],[422,43],[423,44],[424,45],[418,16],[425,46],[428,47],[182,48],[140,48],[395,49],[180,50],[437,51],[439,51],[440,52],[441,13],[442,53],[443,27],[444,54],[438,51],[405,55],[116,55],[429,5],[109,56],[111,57],[110,5],[113,58],[112,57],[592,59],[593,59],[594,59],[595,59],[596,59],[597,59],[598,59],[599,59],[600,59],[601,59],[602,59],[603,59],[604,59],[612,60],[609,59],[607,59],[608,59],[605,59],[611,59],[606,59],[610,59],[613,61],[118,61],[614,61],[615,61],[119,62],[616,61],[99,63],[98,5],[106,64],[97,65],[95,5],[107,66],[108,67],[104,5],[105,68],[100,69],[103,70],[96,71],[94,5],[101,72],[102,73],[446,74],[590,75],[591,5],[579,76],[577,5],[309,77],[311,78],[310,5],[312,79],[313,80],[308,81],[343,82],[344,83],[342,84],[346,85],[349,86],[345,87],[347,88],[348,88],[350,89],[351,90],[356,91],[353,92],[352,93],[355,94],[354,95],[360,96],[359,97],[357,98],[358,87],[361,99],[362,100],[366,101],[364,102],[363,103],[365,104],[301,105],[269,87],[270,106],[286,107],[300,106],[287,108],[289,87],[288,5],[290,87],[291,109],[298,87],[292,5],[293,5],[294,5],[295,87],[296,110],[297,111],[285,89],[299,112],[367,113],[340,114],[341,115],[339,116],[284,117],[283,118],[282,119],[281,120],[278,121],[277,122],[274,120],[276,123],[275,124],[280,125],[279,122],[271,126],[272,127],[273,127],[304,108],[302,108],[305,128],[307,129],[306,130],[303,131],[255,110],[256,5],[264,132],[268,133],[265,5],[266,134],[267,5],[258,135],[259,135],[262,136],[263,137],[261,135],[260,136],[257,106],[314,87],[315,87],[316,87],[317,138],[338,139],[326,140],[325,5],[318,141],[321,87],[319,87],[322,87],[324,142],[323,143],[320,87],[334,5],[327,5],[328,5],[329,87],[330,87],[331,5],[332,87],[333,5],[337,144],[335,5],[336,87],[374,145],[373,146],[377,147],[378,148],[375,149],[376,150],[394,151],[386,152],[385,153],[384,112],[379,154],[383,155],[380,154],[381,154],[382,154],[369,112],[368,5],[372,156],[370,149],[371,157],[387,5],[388,5],[389,112],[393,158],[390,5],[391,112],[392,154],[232,5],[234,159],[235,160],[233,5],[236,5],[237,5],[240,161],[238,5],[239,5],[241,5],[242,5],[243,5],[244,162],[245,5],[246,163],[231,164],[222,5],[223,5],[225,5],[224,93],[226,93],[227,5],[228,93],[229,5],[230,5],[254,165],[252,166],[247,5],[248,5],[249,5],[250,5],[251,5],[253,5],[124,167],[126,168],[123,169],[125,93],[93,170],[79,171],[89,172],[66,173],[85,174],[64,175],[88,176],[62,5],[73,177],[81,178],[92,179],[74,5],[80,180],[90,5],[84,181],[68,182],[71,183],[91,5],[63,184],[82,5],[67,5],[69,185],[72,186],[70,187],[86,188],[83,189],[87,190],[585,191],[198,5],[586,192],[587,193],[588,194],[149,195],[145,196],[151,197],[147,198],[148,5],[150,195],[146,198],[143,5],[144,5],[164,199],[170,200],[161,201],[169,93],[162,199],[163,24],[154,201],[152,202],[168,203],[165,202],[167,201],[166,202],[160,202],[159,202],[153,201],[155,204],[157,201],[158,201],[156,201],[76,205],[75,5],[582,206],[578,76],[580,207],[581,76],[545,5],[492,208],[493,208],[494,209],[495,210],[496,211],[497,212],[447,5],[450,213],[448,5],[449,5],[498,214],[499,215],[500,216],[501,217],[502,218],[503,219],[504,219],[506,220],[505,221],[507,222],[508,223],[509,224],[491,225],[510,226],[511,227],[512,228],[513,229],[514,230],[515,231],[516,232],[517,233],[518,234],[519,235],[520,236],[521,237],[522,238],[523,238],[524,239],[525,5],[526,240],[528,241],[527,242],[529,243],[530,244],[531,245],[532,246],[533,247],[534,248],[535,249],[452,250],[451,5],[544,251],[536,252],[537,253],[538,254],[539,255],[540,256],[541,257],[542,258],[543,259],[48,5],[427,93],[130,93],[46,5],[49,260],[50,93],[583,261],[181,5],[453,5],[47,5],[214,5],[204,5],[216,262],[205,263],[203,264],[212,265],[215,266],[207,267],[208,268],[206,269],[209,270],[210,271],[211,270],[213,5],[199,5],[201,272],[200,272],[202,273],[552,5],[58,24],[122,5],[65,5],[59,5],[61,274],[569,275],[567,276],[568,277],[556,278],[557,276],[564,279],[555,280],[560,281],[570,5],[561,282],[566,283],[572,284],[571,285],[554,286],[562,287],[563,288],[558,289],[565,275],[559,290],[433,5],[434,291],[547,292],[546,191],[220,293],[219,294],[218,295],[217,296],[553,5],[78,297],[77,298],[44,5],[45,5],[8,5],[9,5],[11,5],[10,5],[2,5],[12,5],[13,5],[14,5],[15,5],[16,5],[17,5],[18,5],[19,5],[3,5],[4,5],[20,5],[24,5],[21,5],[22,5],[23,5],[25,5],[26,5],[27,5],[5,5],[28,5],[29,5],[30,5],[31,5],[6,5],[35,5],[32,5],[33,5],[34,5],[36,5],[7,5],[37,5],[42,5],[43,5],[38,5],[39,5],[40,5],[41,5],[1,5],[60,5],[469,299],[479,300],[468,299],[489,301],[460,302],[459,303],[488,304],[482,305],[487,306],[462,307],[476,308],[461,309],[485,310],[457,311],[456,304],[486,312],[458,313],[463,314],[464,5],[467,314],[454,5],[490,315],[480,316],[471,317],[472,318],[474,319],[470,320],[473,321],[483,304],[465,322],[466,323],[475,324],[455,325],[478,316],[477,314],[481,5],[484,326],[619,93],[589,327],[584,328],[618,329],[576,330],[573,331],[551,332],[549,333],[548,5],[550,334],[574,5],[617,335],[575,336],[139,337],[176,338],[174,339],[172,339],[175,339],[171,339],[173,339],[138,339],[178,5],[179,340],[137,5],[177,5]],"exportedModulesMap":[],"changeFileSet":[55,52,54,53,51,56,57,445,184,183,221,426,127,419,117,120,121,114,115,131,132,185,186,128,420,129,136,133,134,135,141,190,191,192,193,195,196,197,430,431,142,194,415,189,187,188,401,402,403,397,398,399,400,432,435,396,408,436,404,407,406,411,412,413,414,416,409,410,417,421,422,423,424,418,425,428,182,140,395,180,437,439,440,441,442,443,444,438,405,116,429,109,111,110,113,112,592,593,594,595,596,597,598,599,600,601,602,603,604,612,609,607,608,605,611,606,610,613,118,614,615,119,616,99,98,106,97,95,107,108,104,105,100,103,96,94,101,102,446,590,591,579,577,309,311,310,312,313,308,343,344,342,346,349,345,347,348,350,351,356,353,352,355,354,360,359,357,358,361,362,366,364,363,365,301,269,270,286,300,287,289,288,290,291,298,292,293,294,295,296,297,285,299,367,340,341,339,284,283,282,281,278,277,274,276,275,280,279,271,272,273,304,302,305,307,306,303,255,256,264,268,265,266,267,258,259,262,263,261,260,257,314,315,316,317,338,326,325,318,321,319,322,324,323,320,334,327,328,329,330,331,332,333,337,335,336,374,373,377,378,375,376,394,386,385,384,379,383,380,381,382,369,368,372,370,371,387,388,389,393,390,391,392,232,234,235,233,236,237,240,238,239,241,242,243,244,245,246,231,222,223,225,224,226,227,228,229,230,254,252,247,248,249,250,251,253,124,126,123,125,93,79,89,66,85,64,88,62,73,81,92,74,80,90,84,68,71,91,63,82,67,69,72,70,86,83,87,585,198,586,587,588,149,145,151,147,148,150,146,143,144,164,170,161,169,162,163,154,152,168,165,167,166,160,159,153,155,157,158,156,76,75,582,578,580,581,545,492,493,494,495,496,497,447,450,448,449,498,499,500,501,502,503,504,506,505,507,508,509,491,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,528,527,529,530,531,532,533,534,535,452,451,544,536,537,538,539,540,541,542,543,48,427,130,46,49,50,583,181,453,47,214,204,216,205,203,212,215,207,208,206,209,210,211,213,199,201,200,202,552,58,122,65,59,61,569,567,568,556,557,564,555,560,570,561,566,572,571,554,562,563,558,565,559,433,434,547,546,220,219,218,217,553,78,77,44,45,8,9,11,10,2,12,13,14,15,16,17,18,19,3,4,20,24,21,22,23,25,26,27,5,28,29,30,31,6,35,32,33,34,36,7,37,42,43,38,39,40,41,1,60,469,479,468,489,460,459,488,482,487,462,476,461,485,457,456,486,458,463,464,467,454,490,480,471,472,474,470,473,483,465,466,475,455,478,477,481,484,619,589,584,618,576,573,551,549,548,550,574,617,575,139,176,174,172,175,171,173,138,178,179,137,177]},"version":"5.3.3"} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 3d148a18..f20217f9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,6 +7,7 @@ services: - ./client/dist:/app/client/dist environment: - NODE_ENV=${NODE_ENV} + - VITE_API_URL=${VITE_API_URL} command: pnpm --filter client run build backend: @@ -18,7 +19,9 @@ services: environment: - MONGO_URI=${MONGO_URI} - NODE_ENV=${NODE_ENV} + - PORT=3000 - JWT_SECRET=${JWT_SECRET} + - JWT_REFRESH_SECRET=${JWT_REFRESH_SECRET} nginx: build: diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e4b9cb7e..2e6ca32a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -176,15 +176,27 @@ importers: '@nestjs/platform-socket.io': specifier: ^10.4.7 version: 10.4.7(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@10.4.7)(rxjs@7.8.1) + '@nestjs/swagger': + specifier: ^8.0.7 + version: 8.0.7(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6)(reflect-metadata@0.2.2) '@nestjs/websockets': specifier: ^10.4.7 version: 10.4.7(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6)(@nestjs/platform-socket.io@10.4.7)(reflect-metadata@0.2.2)(rxjs@7.8.1) '@noctaCrdt': specifier: workspace:* version: link:../@noctaCrdt + '@types/cookie-parser': + specifier: ^1.4.7 + version: 1.4.7 bcrypt: specifier: ^5.1.1 version: 5.1.1 + cookie-parser: + specifier: ^1.4.7 + version: 1.4.7 + express: + specifier: ^4.21.1 + version: 4.21.1 mongodb-memory-server: specifier: ^10.1.2 version: 10.1.2(socks@2.8.3) @@ -946,6 +958,9 @@ packages: resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==} hasBin: true + '@microsoft/tsdoc@0.15.0': + resolution: {integrity: sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA==} + '@mongodb-js/saslprep@1.1.9': resolution: {integrity: sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw==} @@ -1003,6 +1018,19 @@ packages: peerDependencies: '@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 + '@nestjs/mapped-types@2.0.6': + resolution: {integrity: sha512-84ze+CPfp1OWdpRi1/lOu59hOhTz38eVzJvRKrg9ykRFwDz+XleKfMsG0gUqNZYFa6v53XYzeD+xItt8uDW7NQ==} + peerDependencies: + '@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 + class-transformer: ^0.4.0 || ^0.5.0 + class-validator: ^0.13.0 || ^0.14.0 + reflect-metadata: ^0.1.12 || ^0.2.0 + peerDependenciesMeta: + class-transformer: + optional: true + class-validator: + optional: true + '@nestjs/mongoose@10.1.0': resolution: {integrity: sha512-1ExAnZUfh2QffEaGjqYGgVPy/sYBQCVLCLqVgkcClKx/BCd0QNgND8MB70lwyobp3nm/+nbGQqBpu9F3/hgOCw==} peerDependencies: @@ -1035,6 +1063,23 @@ packages: peerDependencies: typescript: '>=4.8.2' + '@nestjs/swagger@8.0.7': + resolution: {integrity: sha512-zaTMCEZ/CxX7QYF110nTqJsn7eCXp4VI9kv7+AdUcIlBmhhgJpggBw2Mx2p6xVjyz1EoWXGfxxWKnxEyaQwFlg==} + peerDependencies: + '@fastify/static': ^6.0.0 || ^7.0.0 + '@nestjs/common': ^9.0.0 || ^10.0.0 + '@nestjs/core': ^9.0.0 || ^10.0.0 + class-transformer: '*' + class-validator: '*' + reflect-metadata: ^0.1.12 || ^0.2.0 + peerDependenciesMeta: + '@fastify/static': + optional: true + class-transformer: + optional: true + class-validator: + optional: true + '@nestjs/testing@10.4.6': resolution: {integrity: sha512-aiDicKhlGibVGNYuew399H5qZZXaseOBT/BS+ERJxxCmco7ZdAqaujsNjSaSbTK9ojDPf27crLT0C4opjqJe3A==} peerDependencies: @@ -1299,6 +1344,9 @@ packages: '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + '@scarf/scarf@1.4.0': + resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==} + '@shelf/jest-mongodb@4.3.2': resolution: {integrity: sha512-LL7NBaT04sJspoOZXqw3HGLw0+XnZNlIV72x2ymzyuloqIKXwgUl8eL1XKDUh4Ud8dUBRMrOngCQBcHKjWnrHQ==} engines: {node: '>=16'} @@ -1427,6 +1475,9 @@ packages: '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + '@types/cookie-parser@1.4.7': + resolution: {integrity: sha512-Fvuyi354Z+uayxzIGCwYTayFKocfV7TuDYZClCdIP9ckhvAu/ixDtCB6qx2TT0FKjPLf1f3P/J1rgf6lPs64mw==} + '@types/cookie@0.4.1': resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==} @@ -2155,6 +2206,10 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie-parser@1.4.7: + resolution: {integrity: sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==} + engines: {node: '>= 0.8.0'} + cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} @@ -4634,6 +4689,9 @@ packages: svg-parser@2.0.4: resolution: {integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==} + swagger-ui-dist@5.18.2: + resolution: {integrity: sha512-J+y4mCw/zXh1FOj5wGJvnAajq6XgHOyywsa9yITmwxIlJbMqITq3gYRZHaeqLVH/eV/HOPphE6NjF+nbSNC5Zw==} + symbol-observable@4.0.0: resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} engines: {node: '>=0.10'} @@ -5850,6 +5908,8 @@ snapshots: - encoding - supports-color + '@microsoft/tsdoc@0.15.0': {} + '@mongodb-js/saslprep@1.1.9': dependencies: sparse-bitfield: 3.0.3 @@ -5919,6 +5979,11 @@ snapshots: '@types/jsonwebtoken': 9.0.5 jsonwebtoken: 9.0.2 + '@nestjs/mapped-types@2.0.6(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2)': + dependencies: + '@nestjs/common': 10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1) + reflect-metadata: 0.2.2 + '@nestjs/mongoose@10.1.0(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6)(mongoose@8.8.0(socks@2.8.3))(rxjs@7.8.1)': dependencies: '@nestjs/common': 10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1) @@ -5966,6 +6031,18 @@ snapshots: transitivePeerDependencies: - chokidar + '@nestjs/swagger@8.0.7(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6)(reflect-metadata@0.2.2)': + dependencies: + '@microsoft/tsdoc': 0.15.0 + '@nestjs/common': 10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.6(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.6)(@nestjs/websockets@10.4.7)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/mapped-types': 2.0.6(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2) + js-yaml: 4.1.0 + lodash: 4.17.21 + path-to-regexp: 3.3.0 + reflect-metadata: 0.2.2 + swagger-ui-dist: 5.18.2 + '@nestjs/testing@10.4.6(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6)(@nestjs/platform-express@10.4.6)': dependencies: '@nestjs/common': 10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1) @@ -6407,6 +6484,8 @@ snapshots: '@rtsao/scc@1.1.0': {} + '@scarf/scarf@1.4.0': {} + '@shelf/jest-mongodb@4.3.2(jest-environment-node@29.7.0)(mongodb@6.10.0(socks@2.8.3))': dependencies: debug: 4.3.4 @@ -6555,6 +6634,10 @@ snapshots: dependencies: '@types/node': 20.17.6 + '@types/cookie-parser@1.4.7': + dependencies: + '@types/express': 5.0.0 + '@types/cookie@0.4.1': {} '@types/cookiejar@2.1.5': {} @@ -7430,6 +7513,11 @@ snapshots: convert-source-map@2.0.0: {} + cookie-parser@1.4.7: + dependencies: + cookie: 0.7.2 + cookie-signature: 1.0.6 + cookie-signature@1.0.6: {} cookie@0.7.1: {} @@ -10390,6 +10478,10 @@ snapshots: svg-parser@2.0.4: {} + swagger-ui-dist@5.18.2: + dependencies: + '@scarf/scarf': 1.4.0 + symbol-observable@4.0.0: {} synckit@0.9.2: diff --git a/server/jest.config.ts b/server/jest.config.ts index 51dc1f28..05c0c2bd 100644 --- a/server/jest.config.ts +++ b/server/jest.config.ts @@ -1,6 +1,4 @@ import type { Config } from "jest"; -import { pathsToModuleNameMapper } from "ts-jest"; -import { compilerOptions } from "./tsconfig.json"; const config: Config = { moduleFileExtensions: ["js", "json", "ts"], diff --git a/server/package.json b/server/package.json index d9c755ff..4f827e69 100644 --- a/server/package.json +++ b/server/package.json @@ -31,9 +31,13 @@ "@nestjs/passport": "^10.0.3", "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-socket.io": "^10.4.7", + "@nestjs/swagger": "^8.0.7", "@nestjs/websockets": "^10.4.7", "@noctaCrdt": "workspace:*", + "@types/cookie-parser": "^1.4.7", "bcrypt": "^5.1.1", + "cookie-parser": "^1.4.7", + "express": "^4.21.1", "mongodb-memory-server": "^10.1.2", "mongoose": "^8.8.0", "nanoid": "^3.0.0", diff --git a/server/src/@types/express/index.d.ts b/server/src/@types/express/index.d.ts new file mode 100644 index 00000000..f4e38cb0 --- /dev/null +++ b/server/src/@types/express/index.d.ts @@ -0,0 +1,8 @@ +import "express"; + +declare module "express" { + export interface Request { + user?: User; + cookies: { [key: string]: string }; + } +} diff --git a/server/src/app.controller.ts b/server/src/app.controller.ts index 1088c2de..3176835d 100644 --- a/server/src/app.controller.ts +++ b/server/src/app.controller.ts @@ -1,12 +1,15 @@ -// server/src/app.controller.ts -import { Controller, Get, Injectable } from "@nestjs/common"; +import { Controller, Get } from "@nestjs/common"; +import { ApiTags, ApiOperation, ApiResponse } from "@nestjs/swagger"; import { AppService } from "./app.service"; +@ApiTags("app") @Controller() export class AppController { constructor(private readonly appService: AppService) {} @Get() + @ApiOperation({ summary: "Get a greeting message" }) + @ApiResponse({ status: 200, description: "Successfully retrieved greeting message." }) public getHello(): string { return this.appService.getHello(); } diff --git a/server/src/app.module.spec.ts b/server/src/app.module.spec.ts index bd28e2fd..e857b64e 100644 --- a/server/src/app.module.spec.ts +++ b/server/src/app.module.spec.ts @@ -15,7 +15,12 @@ describe("AppModule", () => { beforeAll(async () => { // jest-mongodb가 설정한 MONGO_URL을 MONGO_URI로 설정 process.env.MONGO_URI = process.env.MONGO_URL || "mongodb://localhost:27017/test"; - console.log(`MONGO_URI: ${process.env.MONGO_URI}`); + if (!process.env.JWT_SECRET) { + process.env.JWT_SECRET = "test-secret"; + } + if (!process.env.JWT_REFRESH_SECRET) { + process.env.JWT_REFRESH_SECRET = "test-secret"; + } testingModule = await Test.createTestingModule({ imports: [MongooseModule.forRoot(process.env.MONGO_URI), AppModule], diff --git a/server/src/auth/auth.controller.spec.ts b/server/src/auth/auth.controller.spec.ts deleted file mode 100644 index d32087b9..00000000 --- a/server/src/auth/auth.controller.spec.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Test, TestingModule } from "@nestjs/testing"; -import { AuthController } from "./auth.controller"; -import { AuthService } from "./auth.service"; - -jest.mock("nanoid", () => ({ - nanoid: jest.fn(() => "mockNanoId123"), -})); - -describe("AuthController", () => { - let authController: AuthController; - let authService: AuthService; - - const mockAuthService = { - register: jest.fn(), - login: jest.fn(), - }; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [AuthController], - providers: [{ provide: AuthService, useValue: mockAuthService }], - }).compile(); - - authController = module.get(AuthController); - authService = module.get(AuthService); - }); - - it("should be defined", () => { - expect(authController).toBeDefined(); - }); - - describe("register", () => { - it("should call authService.register and return the result", async () => { - const dto = { - email: "test@example.com", - password: "password123", - name: "Test User", - }; - const mockResult = { - id: "mockNanoId123", - email: "test@example.com", - name: "Test User", - }; - mockAuthService.register.mockResolvedValue(mockResult); - - const result = await authController.register(dto); - - expect(authService.register).toHaveBeenCalledWith(dto.email, dto.password, dto.name); - expect(result).toEqual(mockResult); - }); - }); -}); diff --git a/server/src/auth/auth.controller.ts b/server/src/auth/auth.controller.ts index f0f9a559..623d15b6 100644 --- a/server/src/auth/auth.controller.ts +++ b/server/src/auth/auth.controller.ts @@ -1,34 +1,143 @@ -import { Controller, Post, Body, Request, UseGuards } from "@nestjs/common"; +import { + Controller, + Get, + Post, + Body, + UseGuards, + Request, + Response, + UnauthorizedException, + ConflictException, + BadRequestException, +} from "@nestjs/common"; +import { Response as ExpressResponse, Request as ExpressRequest } from "express"; import { AuthService } from "./auth.service"; -import { JwtAuthGuard } from "./jwt-auth.guard"; +import { JwtAuthGuard } from "./guards/jwt-auth.guard"; +import { + ApiTags, + ApiOperation, + ApiBody, + ApiResponse, + ApiBearerAuth, + ApiCookieAuth, +} from "@nestjs/swagger"; +import { UserDto } from "./dto/user.dto"; +import { JwtRefreshTokenAuthGuard } from "./guards/jwt-refresh-token-auth.guard"; +@ApiTags("auth") @Controller("auth") export class AuthController { constructor(private authService: AuthService) {} @Post("register") - async register(@Body() body: { email: string; password: string; name: string }) { + @ApiOperation({ summary: "Register a new user" }) + @ApiBody({ + schema: { + type: "object", + properties: { + email: { type: "string" }, + password: { type: "string" }, + name: { type: "string" }, + }, + }, + }) + @ApiResponse({ + status: 201, + description: "The user has been successfully created.", + }) + @ApiResponse({ status: 400, description: "Bad Request: Invalid email format" }) + @ApiResponse({ status: 409, description: "Conflict: Email already exists" }) + async register(@Body() body: { email: string; password: string; name: string }): Promise { const { email, password, name } = body; - const user = await this.authService.register(email, password, name); - return { - id: user.id, - email: user.email, - name: user.name, - }; + + if (!this.authService.isValidEmail(email)) { + throw new BadRequestException("Invalid email format"); + } + + const existingUser = await this.authService.findByEmail(email); + if (existingUser) { + throw new ConflictException("Email already exists"); + } + + await this.authService.register(email, password, name); } @Post("login") - async login(@Body() body: { email: string; password: string }) { + @ApiOperation({ summary: "Login a user" }) + @ApiBody({ + schema: { + type: "object", + properties: { + email: { type: "string" }, + password: { type: "string" }, + }, + }, + }) + @ApiResponse({ status: 200, description: "The user has been successfully logged in." }) + @ApiResponse({ status: 401, description: "Unauthorized" }) + async login( + @Body() body: { email: string; password: string }, + @Response({ passthrough: true }) res: ExpressResponse, + ): Promise { const user = await this.authService.validateUser(body.email, body.password); if (!user) { - throw new Error("Invalid credentials"); + throw new UnauthorizedException("Invalid credentials"); + } + + return this.authService.login(user, res); + } + + @UseGuards(JwtAuthGuard) + @Post("logout") + @ApiOperation({ summary: "Logout a user" }) + @ApiBearerAuth() + @ApiCookieAuth("refreshToken") + @ApiResponse({ status: 200, description: "The user has been successfully logged out." }) + @ApiResponse({ status: 401, description: "Unauthorized" }) + async logout(@Request() req: ExpressRequest): Promise { + const { user } = req; + if (!user) { + throw new UnauthorizedException("User not found"); } - return this.authService.login(user); + + // DB에서 refresh token 삭제 + await this.authService.removeRefreshToken(user.id); + + // 사용자의 token version 증가 + await this.authService.increaseTokenVersion(user); + + // 쿠키 삭제 + this.authService.clearCookie(req.res); } @UseGuards(JwtAuthGuard) - @Post("profile") - getProfile(@Request() req) { - return req.user; + @Get("profile") + @ApiOperation({ summary: "Get user profile" }) + @ApiBearerAuth() + @ApiResponse({ status: 200, description: "The user profile has been successfully retrieved." }) + @ApiResponse({ status: 401, description: "Unauthorized" }) + async getProfile(@Request() req: ExpressRequest): Promise { + const user = await this.authService.getProfile(req.user.id); + if (!user) { + throw new UnauthorizedException("User not found"); + } + return { + id: user.id, + email: user.email, + name: user.name, + }; + } + + @UseGuards(JwtRefreshTokenAuthGuard) + @Get("refresh") + @ApiOperation({ summary: "Refresh access token" }) + @ApiCookieAuth("refreshToken") + @ApiResponse({ status: 200, description: "The access token has been successfully refreshed." }) + @ApiResponse({ status: 401, description: "Unauthorized" }) + async refresh( + @Request() req: ExpressRequest, + @Response({ passthrough: true }) res: ExpressResponse, + ) { + return this.authService.refresh(req.cookies.refreshToken, res); } } diff --git a/server/src/auth/auth.interface.ts b/server/src/auth/auth.interface.ts new file mode 100644 index 00000000..f5c03a0e --- /dev/null +++ b/server/src/auth/auth.interface.ts @@ -0,0 +1,6 @@ +export interface IJwtPayload { + sub?: string; // 사용자 ID + email?: string; // 사용자 이메일 + iat: number; // 발급 시간 + exp: number; // 만료 시간 +} diff --git a/server/src/auth/auth.module.spec.ts b/server/src/auth/auth.module.spec.ts deleted file mode 100644 index 734373fb..00000000 --- a/server/src/auth/auth.module.spec.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* -import { Test, TestingModule } from "@nestjs/testing"; -import { MongooseModule } from "@nestjs/mongoose"; -import { PassportModule } from "@nestjs/passport"; -import { JwtModule } from "@nestjs/jwt"; -import { AuthService } from "./auth.service"; -import { AuthController } from "./auth.controller"; -import { JwtStrategy } from "./jwt.strategy"; -import { User, UserSchema } from "./schemas/user.schema"; -import { AuthModule } from "./auth.module"; - -jest.setTimeout(30000); - -jest.mock("nanoid", () => ({ - nanoid: jest.fn(() => "mockNanoId123"), -})); - -describe("AuthModule", () => { - let testingModule: TestingModule; - - beforeAll(async () => { - if (!process.env.MONGO_URI || !process.env.MONGO_URL) { - process.env.MONGO_URI = "mongodb://localhost:27017/test-db"; - } - if (!process.env.JWT_SECRET) { - process.env.JWT_SECRET = "test-secret"; - } - - testingModule = await Test.createTestingModule({ - imports: [ - MongooseModule.forRoot(process.env.MONGO_URI), - MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]), - PassportModule, - JwtModule.register({ - secret: process.env.JWT_SECRET, - signOptions: { expiresIn: "1h" }, - }), - AuthModule, - ], - controllers: [AuthController], - providers: [AuthService, JwtStrategy], - }).compile(); - }); - - afterAll(async () => { - if (testingModule) { - await testingModule.close(); - } - }); - - it("should be defined", () => { - const authController = testingModule.get(AuthController); - const authService = testingModule.get(AuthService); - expect(authController).toBeDefined(); - expect(authService).toBeDefined(); - }); -}); -*/ - -describe("Example Test", () => { - it("should return true", () => { - expect(true).toBe(true); - }); -}); diff --git a/server/src/auth/auth.module.ts b/server/src/auth/auth.module.ts index b5382245..7c86a6ce 100644 --- a/server/src/auth/auth.module.ts +++ b/server/src/auth/auth.module.ts @@ -5,8 +5,11 @@ import { AuthService } from "./auth.service"; import { AuthController } from "./auth.controller"; import { JwtModule } from "@nestjs/jwt"; import { PassportModule } from "@nestjs/passport"; -import { JwtStrategy } from "./jwt.strategy"; +import { JwtStrategy } from "./strategies/jwt.strategy"; +import { JwtRefreshTokenStrategy } from "./strategies/jwt-refresh-token.strategy"; import { ConfigModule, ConfigService } from "@nestjs/config"; +import { JwtAuthGuard } from "./guards/jwt-auth.guard"; +import { JwtRefreshTokenAuthGuard } from "./guards/jwt-refresh-token-auth.guard"; @Module({ imports: [ @@ -23,7 +26,13 @@ import { ConfigModule, ConfigService } from "@nestjs/config"; }), ], exports: [AuthService, JwtModule], - providers: [AuthService, JwtStrategy], + providers: [ + AuthService, + JwtStrategy, + JwtRefreshTokenStrategy, + JwtAuthGuard, + JwtRefreshTokenAuthGuard, + ], controllers: [AuthController], }) export class AuthModule {} diff --git a/server/src/auth/auth.service.ts b/server/src/auth/auth.service.ts index 95377e55..844487af 100644 --- a/server/src/auth/auth.service.ts +++ b/server/src/auth/auth.service.ts @@ -4,14 +4,22 @@ import { Model } from "mongoose"; import { User, UserDocument } from "./schemas/user.schema"; import * as bcrypt from "bcrypt"; import { JwtService } from "@nestjs/jwt"; +import { Response } from "express"; +import { UserDto } from "./dto/user.dto"; @Injectable() export class AuthService { constructor( - @InjectModel(User.name) private userModel: Model, + @InjectModel(User.name) + private userModel: Model, private jwtService: JwtService, ) {} + isValidEmail(email: string): boolean { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + return emailRegex.test(email); + } + async register(email: string, password: string, name: string): Promise { const hashedPassword = await bcrypt.hash(password, 10); return this.userModel.create({ @@ -21,18 +29,123 @@ export class AuthService { }); } + async findById(id: string): Promise { + return this.userModel.findOne({ id }); + } + + async findByEmail(email: string): Promise { + return this.userModel.findOne({ email }); + } + + async findByRefreshToken(token: string): Promise { + return this.userModel.findOne({ refreshToken: token }); + } + async validateUser(email: string, password: string): Promise { - const user = await this.userModel.findOne({ email }); + const user = await this.findByEmail(email); if (user && (await bcrypt.compare(password, user.password))) { return user; } return null; } - async login(user: { id: string; email: string }) { - const payload = { sub: user.id, email: user.email }; + async validateRefreshToken(refreshToken: string): Promise { + try { + const decoded = await this.jwtService.verify(refreshToken, { + secret: process.env.JWT_REFRESH_SECRET, + }); + const user = await this.findByRefreshToken(refreshToken); + if (!user) { + return false; + } + return !!decoded; + } catch (error) { + return false; + } + } + + async generateAccessToken(user: User): Promise { + return this.jwtService.sign({ + sub: user.id, + email: user.email, + tokenVersion: await this.increaseTokenVersion(user), + }); + } + + async generateRefreshToken(id: string): Promise { + const refreshToken = this.jwtService.sign( + {}, + { + secret: process.env.JWT_REFRESH_SECRET, + expiresIn: "7d", + }, + ); + await this.userModel.updateOne({ id }, { refreshToken }); + return refreshToken; + } + + async increaseTokenVersion(user: User): Promise { + const tokenVersion = user.tokenVersion + 1; + await this.userModel.updateOne({ id: user.id }, { tokenVersion }); + return tokenVersion; + } + + async login(user: User, res: Response): Promise { + const accessToken = await this.generateAccessToken(user); + const refreshToken = await this.generateRefreshToken(user.id); + + res.header("Authorization", `Bearer ${accessToken}`); + + res.cookie("refreshToken", refreshToken, { + httpOnly: true, + secure: process.env.NODE_ENV === "production", + sameSite: "strict", + maxAge: 7 * 24 * 60 * 60 * 1000, + path: "/", + }); + + return { + id: user.id, + email: user.email, + name: user.name, + }; + } + + async getProfile(id: string): Promise { + const user = await this.findById(id); + if (!user) { + return null; + } + return user; + } + + public async removeRefreshToken(user: User) { + await this.userModel.updateOne({ id: user.id }, { refreshToken: null }); + } + + public clearCookie(res: Response): void { + res.clearCookie("refreshToken", { + httpOnly: true, + secure: process.env.NODE_ENV === "production", + sameSite: "strict", + path: "/", + }); + } + + async refresh(refreshToken: string, res: Response): Promise { + const user = await this.findByRefreshToken(refreshToken); + if (!user) { + return null; + } + + const accessToken = await this.generateAccessToken(user); + + res.header("Authorization", `Bearer ${accessToken}`); + return { - accessToken: this.jwtService.sign(payload), + id: user.id, + email: user.email, + name: user.name, }; } } diff --git a/server/src/auth/dto/user.dto.ts b/server/src/auth/dto/user.dto.ts new file mode 100644 index 00000000..34093cdf --- /dev/null +++ b/server/src/auth/dto/user.dto.ts @@ -0,0 +1,27 @@ +import { ApiProperty } from "@nestjs/swagger"; + +export class UserDto { + @ApiProperty({ + description: "The unique identifier of the user", + example: "5f8f8c44b54764421b7156c9", + }) + id: string; + + @ApiProperty({ + description: "The email of the user", + example: "example@email.com", + }) + email: string; + + @ApiProperty({ + description: "The name of the user", + example: "John Doe", + }) + name: string; + + @ApiProperty({ + description: "The access token for authentication", + example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", + }) + accessToken?: string; +} diff --git a/server/src/auth/guards/jwt-auth.guard.ts b/server/src/auth/guards/jwt-auth.guard.ts new file mode 100644 index 00000000..961db914 --- /dev/null +++ b/server/src/auth/guards/jwt-auth.guard.ts @@ -0,0 +1,35 @@ +import { Injectable, ExecutionContext, UnauthorizedException } from "@nestjs/common"; +import { AuthGuard } from "@nestjs/passport"; +import { AuthService } from "../auth.service"; +import { JwtService } from "@nestjs/jwt"; + +@Injectable() +export class JwtAuthGuard extends AuthGuard("jwt") { + constructor( + private readonly authService: AuthService, + private readonly jwtService: JwtService, + ) { + super(); + } + + async canActivate(context: ExecutionContext): Promise { + const request = context.switchToHttp().getRequest(); + const token = request.headers.authorization?.split(" ")[1]; + + if (!token) { + throw new UnauthorizedException("Authorization header not found"); + } + + const canActivate = (await super.canActivate(context)) as boolean; + + // Access Token의 tokenVersion과 사용자의 tokenVersion 일치 여부 확인 + const decodedToken = this.jwtService.decode(token) as { sub: string; tokenVersion: number }; + const user = await this.authService.findById(decodedToken.sub); + + if (!user || user.tokenVersion !== decodedToken.tokenVersion) { + throw new UnauthorizedException("Invalid token version"); + } + + return canActivate; + } +} diff --git a/server/src/auth/guards/jwt-refresh-token-auth.guard.ts b/server/src/auth/guards/jwt-refresh-token-auth.guard.ts new file mode 100644 index 00000000..caec6c12 --- /dev/null +++ b/server/src/auth/guards/jwt-refresh-token-auth.guard.ts @@ -0,0 +1,26 @@ +import { Injectable, ExecutionContext, UnauthorizedException } from "@nestjs/common"; +import { AuthGuard } from "@nestjs/passport"; +import { AuthService } from "../auth.service"; + +@Injectable() +export class JwtRefreshTokenAuthGuard extends AuthGuard("jwt-refresh") { + constructor(private readonly authService: AuthService) { + super(); + } + + async canActivate(context: ExecutionContext): Promise { + // Refresh Token 유효성 인증 + const canActivate = (await super.canActivate(context)) as boolean; + + const request = context.switchToHttp().getRequest(); + + // 사용자에게 등록된 Refresh Token와 일치 여부 확인 + const { refreshToken } = request.cookies; + const isValid = await this.authService.validateRefreshToken(refreshToken); + if (!isValid) { + throw new UnauthorizedException("Invalid refresh token"); + } + + return canActivate; + } +} diff --git a/server/src/auth/jwt-auth.guard.ts b/server/src/auth/jwt-auth.guard.ts deleted file mode 100644 index 2e81dba6..00000000 --- a/server/src/auth/jwt-auth.guard.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Injectable } from "@nestjs/common"; -import { AuthGuard } from "@nestjs/passport"; - -@Injectable() -export class JwtAuthGuard extends AuthGuard("jwt") {} diff --git a/server/src/auth/jwt.strategy.ts b/server/src/auth/jwt.strategy.ts deleted file mode 100644 index ad324ab5..00000000 --- a/server/src/auth/jwt.strategy.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Injectable } from "@nestjs/common"; -import { PassportStrategy } from "@nestjs/passport"; -import { ExtractJwt, Strategy } from "passport-jwt"; - -@Injectable() -export class JwtStrategy extends PassportStrategy(Strategy) { - constructor() { - super({ - jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), - ignoreExpiration: false, - secretOrKey: process.env.JWT_SECRET, - }); - } - - async validate(payload: any) { - return { userId: payload.sub, email: payload.email }; - } -} diff --git a/server/src/auth/schemas/user.schema.ts b/server/src/auth/schemas/user.schema.ts index 97e490d6..bdf2ae9c 100644 --- a/server/src/auth/schemas/user.schema.ts +++ b/server/src/auth/schemas/user.schema.ts @@ -17,6 +17,12 @@ export class User { @Prop({ required: true }) name: string; + + @Prop({ required: true, default: () => 0 }) + tokenVersion: number; + + @Prop() + refreshToken: string; } export const UserSchema = SchemaFactory.createForClass(User); diff --git a/server/src/auth/strategies/jwt-refresh-token.strategy.ts b/server/src/auth/strategies/jwt-refresh-token.strategy.ts new file mode 100644 index 00000000..639ad248 --- /dev/null +++ b/server/src/auth/strategies/jwt-refresh-token.strategy.ts @@ -0,0 +1,39 @@ +import { Injectable, UnauthorizedException } from "@nestjs/common"; +import { PassportStrategy } from "@nestjs/passport"; +import { ExtractJwt, Strategy } from "passport-jwt"; +import { AuthService } from "../auth.service"; +import { Request as ExpressRequest } from "express"; + +@Injectable() +export class JwtRefreshTokenStrategy extends PassportStrategy(Strategy, "jwt-refresh") { + constructor(private readonly authService: AuthService) { + super({ + jwtFromRequest: ExtractJwt.fromExtractors([ + (req: ExpressRequest) => { + let token = null; + if (req && req.cookies) { + token = req.cookies["refreshToken"]; + } + return token; + }, + ]), + ignoreExpiration: false, + secretOrKey: process.env.JWT_REFRESH_SECRET, + passReqToCallback: true, + }); + } + + async validate(req: ExpressRequest) { + const { refreshToken } = req.cookies; + if (!refreshToken) { + throw new UnauthorizedException(); + } + + const user = await this.authService.findByRefreshToken(refreshToken); + if (!user) { + throw new UnauthorizedException(); + } + + return user; + } +} diff --git a/server/src/auth/strategies/jwt.strategy.ts b/server/src/auth/strategies/jwt.strategy.ts new file mode 100644 index 00000000..22c38b44 --- /dev/null +++ b/server/src/auth/strategies/jwt.strategy.ts @@ -0,0 +1,24 @@ +import { Injectable, UnauthorizedException } from "@nestjs/common"; +import { PassportStrategy } from "@nestjs/passport"; +import { ExtractJwt, Strategy } from "passport-jwt"; +import { AuthService } from "../auth.service"; +import { IJwtPayload } from "../auth.interface"; + +@Injectable() +export class JwtStrategy extends PassportStrategy(Strategy) { + constructor(private readonly authService: AuthService) { + super({ + jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), + ignoreExpiration: false, + secretOrKey: process.env.JWT_SECRET, + }); + } + + async validate(payload: IJwtPayload) { + const user = await this.authService.findById(payload.sub); + if (!user) { + throw new UnauthorizedException(); + } + return user; + } +} diff --git a/server/src/auth/test/auth.controller.spec.ts b/server/src/auth/test/auth.controller.spec.ts new file mode 100644 index 00000000..2c386554 --- /dev/null +++ b/server/src/auth/test/auth.controller.spec.ts @@ -0,0 +1,175 @@ +import { Test, TestingModule } from "@nestjs/testing"; +import { AuthController } from "../auth.controller"; +import { AuthService } from "../auth.service"; +import { JwtAuthGuard } from "../guards/jwt-auth.guard"; +import { JwtRefreshTokenAuthGuard } from "../guards/jwt-refresh-token-auth.guard"; +import { UnauthorizedException, ConflictException, BadRequestException } from "@nestjs/common"; +import { JwtService } from "@nestjs/jwt"; +import { Response as ExpressResponse, Request as ExpressRequest } from "express"; + +jest.mock("nanoid", () => ({ + nanoid: jest.fn(() => "mockNanoId123"), +})); + +describe("AuthController", () => { + let authController: AuthController; + + const mockAuthService = { + register: jest.fn(), + login: jest.fn(), + removeRefreshToken: jest.fn(), + clearCookie: jest.fn(), + generateAccessToken: jest.fn(), + validateRefreshToken: jest.fn(), + findByEmail: jest.fn(), + validateUser: jest.fn(), + getProfile: jest.fn(), + refresh: jest.fn(), + increaseTokenVersion: jest.fn(), + isValidEmail: jest.fn(), + }; + + const mockJwtService = { + sign: jest.fn().mockReturnValue("test-token"), + }; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [AuthController], + providers: [ + { provide: AuthService, useValue: mockAuthService }, + { provide: JwtService, useValue: mockJwtService }, + JwtAuthGuard, + JwtRefreshTokenAuthGuard, + ], + }).compile(); + + authController = module.get(AuthController); + }); + + it("should be defined", () => { + expect(authController).toBeDefined(); + }); + + describe("register", () => { + it("should call authService.register and return the result", async () => { + const dto = { email: "test@example.com", password: "password", name: "Test User" }; + mockAuthService.isValidEmail.mockReturnValue(true); + mockAuthService.findByEmail.mockResolvedValue(null); + mockAuthService.register.mockResolvedValue(undefined); + + await authController.register(dto); + + expect(mockAuthService.findByEmail).toHaveBeenCalledWith(dto.email); + expect(mockAuthService.register).toHaveBeenCalledWith(dto.email, dto.password, dto.name); + }); + + it("should throw BadRequestException if email format is invalid", async () => { + const dto = { email: "invalid-email", password: "password", name: "Test User" }; + mockAuthService.isValidEmail.mockReturnValue(false); + + await expect(authController.register(dto)).rejects.toThrow(BadRequestException); + }); + + it("should throw ConflictException if email already exists", async () => { + const dto = { email: "test@example.com", password: "password", name: "Test User" }; + mockAuthService.isValidEmail.mockReturnValue(true); + mockAuthService.findByEmail.mockResolvedValue({ id: "mockNanoId123", email: dto.email }); + + await expect(authController.register(dto)).rejects.toThrow(ConflictException); + }); + }); + + describe("login", () => { + it("should call authService.validateUser and return the result", async () => { + const dto = { email: "test@example.com", password: "password" }; + const user = { id: "mockNanoId123", email: dto.email, name: "Test User" }; + mockAuthService.validateUser.mockResolvedValue(user); + mockAuthService.login.mockResolvedValue(user); + + const result = await authController.login(dto, { + setHeader: jest.fn(), + } as unknown as ExpressResponse); + + expect(mockAuthService.validateUser).toHaveBeenCalledWith(dto.email, dto.password); + expect(mockAuthService.login).toHaveBeenCalledWith(user, expect.any(Object)); + expect(result).toEqual(user); + }); + + it("should throw UnauthorizedException if credentials are invalid", async () => { + const dto = { email: "test@example.com", password: "password" }; + mockAuthService.validateUser.mockResolvedValue(null); + + await expect( + authController.login(dto, { setHeader: jest.fn() } as unknown as ExpressResponse), + ).rejects.toThrow(UnauthorizedException); + }); + }); + + describe("logout", () => { + it("should call authService.removeRefreshToken and clearCookie", async () => { + const req = { + user: { id: "mockNanoId123" }, + headers: { authorization: "Bearer token" }, + res: { setHeader: jest.fn() }, + } as unknown as ExpressRequest; + mockAuthService.removeRefreshToken.mockResolvedValue(undefined); + mockAuthService.clearCookie.mockResolvedValue(undefined); + + await authController.logout(req); + + expect(mockAuthService.removeRefreshToken).toHaveBeenCalledWith(req.user.id); + expect(mockAuthService.clearCookie).toHaveBeenCalledWith(req.res); + }); + + it("should throw UnauthorizedException if user is not found", async () => { + const req = { user: null } as ExpressRequest; + + await expect(authController.logout(req)).rejects.toThrow(UnauthorizedException); + }); + }); + + describe("getProfile", () => { + it("should call authService.getProfile and return the result", async () => { + const req = { user: { id: "mockNanoId123" } } as ExpressRequest; + const user = { id: "mockNanoId123", email: "test@example.com", name: "Test User" }; + mockAuthService.getProfile.mockResolvedValue(user); + + const result = await authController.getProfile(req); + + expect(mockAuthService.getProfile).toHaveBeenCalledWith(req.user.id); + expect(result).toEqual(user); + }); + + it("should throw UnauthorizedException if user is not found", async () => { + const req = { user: { id: "mockNanoId123" } } as ExpressRequest; + mockAuthService.getProfile.mockResolvedValue(null); + + await expect(authController.getProfile(req)).rejects.toThrow(UnauthorizedException); + }); + }); + + describe("refresh", () => { + it("should call authService.refresh and return the result", async () => { + const req = { cookies: { refreshToken: "valid-refresh-token" } } as unknown as ExpressRequest; + const res = { setHeader: jest.fn() } as unknown as ExpressResponse; + const newAccessToken = { accessToken: "new-access-token" }; + mockAuthService.refresh.mockResolvedValue(newAccessToken); + + const result = await authController.refresh(req, res); + + expect(mockAuthService.refresh).toHaveBeenCalledWith("valid-refresh-token", res); + expect(result).toEqual(newAccessToken); + }); + + it("should throw UnauthorizedException if refresh token is invalid", async () => { + const req = { + cookies: { refreshToken: "invalid-refresh-token" }, + } as unknown as ExpressRequest; + const res = { setHeader: jest.fn() } as unknown as ExpressResponse; + mockAuthService.refresh.mockRejectedValue(new UnauthorizedException("Invalid refresh token")); + + await expect(authController.refresh(req, res)).rejects.toThrow(UnauthorizedException); + }); + }); +}); diff --git a/server/src/auth/test/auth.module.spec.ts b/server/src/auth/test/auth.module.spec.ts new file mode 100644 index 00000000..fb49face --- /dev/null +++ b/server/src/auth/test/auth.module.spec.ts @@ -0,0 +1,108 @@ +import { Test, TestingModule } from "@nestjs/testing"; +import { MongooseModule } from "@nestjs/mongoose"; +import { PassportModule } from "@nestjs/passport"; +import { JwtModule } from "@nestjs/jwt"; +import { ConfigModule, ConfigService } from "@nestjs/config"; +import { AuthService } from "../auth.service"; +import { AuthController } from "../auth.controller"; +import { JwtStrategy } from "../strategies/jwt.strategy"; +import { JwtRefreshTokenStrategy } from "../strategies/jwt-refresh-token.strategy"; +import { User, UserSchema } from "../schemas/user.schema"; +import { AuthModule } from "../auth.module"; +import { JwtAuthGuard } from "../guards/jwt-auth.guard"; +import { JwtRefreshTokenAuthGuard } from "../guards/jwt-refresh-token-auth.guard"; + +jest.setTimeout(30000); + +jest.mock("nanoid", () => ({ + nanoid: jest.fn(() => "mockNanoId123"), +})); + +describe("AuthModule", () => { + let testingModule: TestingModule; + + beforeAll(async () => { + process.env.MONGO_URI = process.env.MONGO_URL || "mongodb://localhost:27017/test"; + if (!process.env.JWT_SECRET) { + process.env.JWT_SECRET = "test-secret"; + } + if (!process.env.JWT_REFRESH_SECRET) { + process.env.JWT_REFRESH_SECRET = "test-secret"; + } + + testingModule = await Test.createTestingModule({ + imports: [ + ConfigModule.forRoot({ + isGlobal: true, + load: [ + () => ({ + JWT_SECRET: process.env.JWT_SECRET, + }), + ], + }), + MongooseModule.forRoot(process.env.MONGO_URI), + MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]), + PassportModule, + JwtModule.registerAsync({ + imports: [ConfigModule], + inject: [ConfigService], + useFactory: (config: ConfigService) => ({ + secret: config.get("JWT_SECRET"), + signOptions: { expiresIn: "1h" }, + }), + }), + AuthModule, + ], + controllers: [AuthController], + providers: [ + AuthService, + JwtStrategy, + JwtRefreshTokenStrategy, + JwtAuthGuard, + JwtRefreshTokenAuthGuard, + ], + }).compile(); + }); + + afterAll(async () => { + if (testingModule) { + await testingModule.close(); + } + }); + + it("should be defined", () => { + expect(testingModule).toBeDefined(); + }); + + it("should have AuthService defined", () => { + const authService = testingModule.get(AuthService); + expect(authService).toBeDefined(); + }); + + it("should have AuthController defined", () => { + const authController = testingModule.get(AuthController); + expect(authController).toBeDefined(); + }); + + it("should have JwtStrategy defined", () => { + const jwtStrategy = testingModule.get(JwtStrategy); + expect(jwtStrategy).toBeDefined(); + }); + + it("should have JwtRefreshTokenStrategy defined", () => { + const jwtRefreshTokenStrategy = + testingModule.get(JwtRefreshTokenStrategy); + expect(jwtRefreshTokenStrategy).toBeDefined(); + }); + + it("should have JwtAuthGuard defined", () => { + const jwtAuthGuard = testingModule.get(JwtAuthGuard); + expect(jwtAuthGuard).toBeDefined(); + }); + + it("should have JwtRefreshTokenAuthGuard defined", () => { + const jwtRefreshTokenAuthGuard = + testingModule.get(JwtRefreshTokenAuthGuard); + expect(jwtRefreshTokenAuthGuard).toBeDefined(); + }); +}); diff --git a/server/src/auth/auth.service.spec.ts b/server/src/auth/test/auth.service.spec.ts similarity index 52% rename from server/src/auth/auth.service.spec.ts rename to server/src/auth/test/auth.service.spec.ts index b47b291f..bb17b6f8 100644 --- a/server/src/auth/auth.service.spec.ts +++ b/server/src/auth/test/auth.service.spec.ts @@ -1,10 +1,10 @@ import { Test, TestingModule } from "@nestjs/testing"; -import { AuthService } from "./auth.service"; +import { AuthService } from "../auth.service"; import { JwtService } from "@nestjs/jwt"; import { getModelToken } from "@nestjs/mongoose"; -import { Model } from "mongoose"; -import { User, UserDocument } from "./schemas/user.schema"; +import { User } from "../schemas/user.schema"; import * as bcrypt from "bcrypt"; +import { Response as ExpressResponse } from "express"; // Mock modules jest.mock("bcrypt", () => ({ @@ -18,7 +18,6 @@ jest.mock("nanoid", () => ({ describe("AuthService", () => { let service: AuthService; - let userModel: Model; let jwtService: JwtService; const mockUser = { @@ -26,12 +25,13 @@ describe("AuthService", () => { email: "test@example.com", password: "hashedPassword", name: "Test User", + tokenVersion: 0, }; - // Updated mockUserModel const mockUserModel = { findOne: jest.fn(), create: jest.fn(), + updateOne: jest.fn(), }; const mockJwtService = { @@ -54,10 +54,8 @@ describe("AuthService", () => { }).compile(); service = module.get(AuthService); - userModel = module.get>(getModelToken(User.name)); jwtService = module.get(JwtService); - // Reset all mocks jest.clearAllMocks(); }); @@ -140,15 +138,126 @@ describe("AuthService", () => { const user = { id: "mockNanoId123", email: "test@example.com", + name: "Test User", + tokenVersion: 0, + }; + + const mockResponse = { + cookie: jest.fn(), + header: jest.fn(), }; - const result = await service.login(user); + const result = await service.login(user as User, mockResponse as unknown as ExpressResponse); expect(jwtService.sign).toHaveBeenCalledWith({ sub: user.id, email: user.email, + tokenVersion: user.tokenVersion + 1, + }); + expect(mockResponse.cookie).toHaveBeenCalledWith("refreshToken", expect.any(String), { + httpOnly: true, + secure: process.env.NODE_ENV === "production", + sameSite: "strict", + maxAge: 7 * 24 * 60 * 60 * 1000, + path: "/", + }); + expect(result).toEqual({ + id: user.id, + email: user.email, + name: "Test User", + }); + }); + }); + + describe("getProfile", () => { + it("should return user profile if user exists", async () => { + mockUserModel.findOne.mockResolvedValue(mockUser); + + const result = await service.getProfile("mockNanoId123"); + + expect(mockUserModel.findOne).toHaveBeenCalledWith({ id: "mockNanoId123" }); + expect(result).toEqual(mockUser); + }); + + it("should return null if user does not exist", async () => { + mockUserModel.findOne.mockResolvedValue(null); + + const result = await service.getProfile("nonexistentId"); + + expect(mockUserModel.findOne).toHaveBeenCalledWith({ id: "nonexistentId" }); + expect(result).toBeNull(); + }); + }); + + describe("removeRefreshToken", () => { + it("should remove refresh token from user", async () => { + await service.removeRefreshToken(mockUser as User); + + expect(mockUserModel.updateOne).toHaveBeenCalledWith( + { id: mockUser.id }, + { refreshToken: null }, + ); + }); + }); + + describe("clearCookie", () => { + it("should clear refresh token cookie", () => { + const res = { + clearCookie: jest.fn(), + } as unknown as ExpressResponse; + + service.clearCookie(res); + + expect(res.clearCookie).toHaveBeenCalledWith("refreshToken", { + httpOnly: true, + secure: process.env.NODE_ENV === "production", + sameSite: "strict", + path: "/", + }); + }); + }); + + describe("refresh", () => { + it("should return new access token if refresh token is valid", async () => { + mockUserModel.findOne.mockResolvedValue(mockUser); + + const mockResponse = { + header: jest.fn(), + }; + + const result = await service.refresh( + "valid-refresh-token", + mockResponse as unknown as ExpressResponse, + ); + + expect(mockUserModel.findOne).toHaveBeenCalledWith({ refreshToken: "valid-refresh-token" }); + expect(jwtService.sign).toHaveBeenCalledWith({ + sub: mockUser.id, + email: mockUser.email, + tokenVersion: 1, + }); + expect(mockResponse.header).toHaveBeenCalledWith("Authorization", `Bearer test-token`); + expect(result).toEqual({ + id: mockUser.id, + email: mockUser.email, + name: mockUser.name, }); - expect(result).toEqual({ accessToken: "test-token" }); + }); + + it("should return null if refresh token is invalid", async () => { + mockUserModel.findOne.mockResolvedValue(null); + + const mockResponse = { + header: jest.fn(), + }; + + const result = await service.refresh( + "invalid-refresh-token", + mockResponse as unknown as ExpressResponse, + ); + + expect(mockUserModel.findOne).toHaveBeenCalledWith({ refreshToken: "invalid-refresh-token" }); + expect(result).toBeNull(); }); }); }); diff --git a/server/src/crdt/crdt.gateway.ts b/server/src/crdt/crdt.gateway.ts index 44f0e3c7..23c354b1 100644 --- a/server/src/crdt/crdt.gateway.ts +++ b/server/src/crdt/crdt.gateway.ts @@ -6,93 +6,396 @@ import { OnGatewayDisconnect, MessageBody, ConnectedSocket, + WsException, } from "@nestjs/websockets"; import { Socket, Server } from "socket.io"; -import { CrdtService } from "./crdt.service"; +import { workSpaceService } from "./crdt.service"; import { - RemoteInsertOperation, - RemoteDeleteOperation, + RemoteBlockDeleteOperation, + RemoteCharDeleteOperation, + RemoteBlockInsertOperation, + RemoteCharInsertOperation, + RemoteBlockUpdateOperation, + RemotePageCreateOperation, CursorPosition, } from "@noctaCrdt/Interfaces"; +import { Logger } from "@nestjs/common"; +import { nanoid } from "nanoid"; +import { Page } from "@noctaCrdt/Page"; +import { EditorCRDT } from "@noctaCrdt/Crdt"; + +// 클라이언트 맵 타입 정의 +interface ClientInfo { + clientId: number; + connectionTime: Date; +} @WebSocketGateway({ cors: { - origin: "*", // 실제 배포 시에는 보안을 위해 적절히 설정하세요 + origin: + process.env.NODE_ENV === "development" + ? "http://localhost:5173" // Vite 개발 서버 포트 + : ["https://nocta.site", "https://www.nocta.site"], + credentials: true, }, + path: "/api/socket.io", + transports: ["websocket", "polling"], }) export class CrdtGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect { + private readonly logger = new Logger(CrdtGateway.name); private server: Server; private clientIdCounter: number = 1; - private clientMap: Map = new Map(); // socket.id -> clientId - - constructor(private readonly crdtService: CrdtService) {} + private clientMap: Map = new Map(); + private guestMap; + private guestIdCounter; + constructor(private readonly workSpaceService: workSpaceService) {} afterInit(server: Server) { this.server = server; } - /** - * 초기에 연결될때, 클라이언트에 숫자id및 문서정보를 송신한다. - * @param client 클라이언트 socket 정보 + * 클라이언트 연결 처리 + * 새로운 클라이언트에게 ID를 할당하고 현재 문서 상태를 전송 */ async handleConnection(client: Socket) { - console.log(`클라이언트 연결: ${client.id}`); - const assignedId = (this.clientIdCounter += 1); - this.clientMap.set(client.id, assignedId); - client.emit("assignId", assignedId); - const currentCRDT = this.crdtService.getCRDT().serialize(); - client.emit("document", currentCRDT); + try { + const assignedId = (this.clientIdCounter += 1); + const clientInfo: ClientInfo = { + clientId: assignedId, + connectionTime: new Date(), + }; + this.clientMap.set(client.id, clientInfo); + + // 클라이언트에게 ID 할당 + client.emit("assign/clientId", assignedId); + // 현재 문서 상태 전송 + const currentWorkSpace = await this.workSpaceService.getWorkspace().serialize(); + + console.log("mongoDB에서 받아온 다음의 상태 : ", currentWorkSpace); // clinet 0 clock 1 이미 저장되어있음 + // client의 인스턴스는 얘를 받잖아요 . clock 1 로 동기화가 돼야하는데 + // 동기화가 안돼서 0 인상태라서 + // 새로 입력하면 1, 1 충돌나는거죠. + client.emit("workspace", currentWorkSpace); + + client.broadcast.emit("userJoined", { clientId: assignedId }); + + this.logger.log(`클라이언트 연결 성공 - Socket ID: ${client.id}, Client ID: ${assignedId}`); + this.logger.debug(`현재 연결된 클라이언트 수: ${this.clientMap.size}`); + } catch (error) { + this.logger.error(`클라이언트 연결 중 오류 발생: ${error.message}`, error.stack); + client.disconnect(); + } } /** - * 연결이 끊어지면 클라이언트 맵에서 클라이언트 삭제 - * @param client 클라이언트 socket 정보 + * 클라이언트 연결 해제 처리 */ handleDisconnect(client: Socket) { - console.log(`클라이언트 연결 해제: ${client.id}`); - this.clientMap.delete(client.id); + try { + const clientInfo = this.clientMap.get(client.id); + if (clientInfo) { + // 다른 클라이언트들에게 사용자 퇴장 알림 + client.broadcast.emit("userLeft", { clientId: clientInfo.clientId }); + + // 연결 시간 계산 + const connectionDuration = new Date().getTime() - clientInfo.connectionTime.getTime(); + this.logger.log( + `클라이언트 연결 해제 - Socket ID: ${client.id}, ` + + `Client ID: ${clientInfo.clientId}, ` + + `연결 시간: ${Math.round(connectionDuration / 1000)}초`, + ); + } + + this.clientMap.delete(client.id); + this.logger.debug(`남은 연결된 클라이언트 수: ${this.clientMap.size}`); + } catch (error) { + this.logger.error(`클라이언트 연결 해제 중 오류 발생: ${error.message}`, error.stack); + } + } + + /** + * 블록 삽입 연산 처리 + */ + @SubscribeMessage("create/page") + async handlePageCreate( + @MessageBody() data: RemotePageCreateOperation, + @ConnectedSocket() client: Socket, + ): Promise { + const clientInfo = this.clientMap.get(client.id); + try { + this.logger.debug( + `Page create 연산 수신 - Client ID: ${clientInfo?.clientId}, Data:`, + JSON.stringify(data), + ); + // TODO 클라이언트로부터 받은 page 서버의 인스턴스에 저장한다. + // TODO: 워크스페이스 여러개일 때 처리 해야함 + + const currentWorkspace = this.workSpaceService.getWorkspace(); + // 여기서 page ID를 만들고 , 서버 인스턴스에 page 만들고, 클라이언트에 operation으로 전달 + const newEditorCRDT = new EditorCRDT(data.clientId); + const newPage = new Page(nanoid(), "새로운 페이지", "📄", newEditorCRDT); + // 서버 인스턴스에 page 추가 + currentWorkspace.pageList.push(newPage); + + const operation = { + workspaceId: data.workspaceId, + clientId: data.clientId, + page: newPage.serialize(), + }; + // 클라이언트 인스턴스에 page 추가 + client.emit("create/page", operation); + client.broadcast.emit("create/page", operation); + } catch (error) { + this.logger.error( + `Page Create 연산 처리 중 오류 발생 - Client ID: ${clientInfo?.clientId}`, + error.stack, + ); + throw new WsException(`Page Create 연산 실패: ${error.message}`); + } + } + /** + * 블록 업데이트 연산 처리 + */ + @SubscribeMessage("update/block") + async handleBlockUpdate( + @MessageBody() data: RemoteBlockUpdateOperation, + @ConnectedSocket() client: Socket, + ): Promise { + const clientInfo = this.clientMap.get(client.id); + try { + this.logger.debug( + `블록 Update 연산 수신 - Client ID: ${clientInfo?.clientId}, Data:`, + JSON.stringify(data), + ); + // 1. 워크스페이스 가져오기 + const workspace = this.workSpaceService.getWorkspace(); + + // delete할때 이 삭제되는 node의 클락을 +1하지말고 보내고 + // 그다음 client를 node를 보낸 다으멩 클락을 +1 을 하자 . + // server의 clock상태와 + // client의 clock상태를 계속 볼수있게 콘솔을 찍어놓고 + // 얘네가 생성될때 + + // 초기값은 client = client 0 clock 0 , server = clinet 0 clock 0 + // 여기서 입력이 발생하면 clinet 가 입력해야 clinet 0 clock 1, server = client0 clock 1 + // 2. 해당 페이지 가져오기 + const currentPage = workspace.pageList.find((p) => p.id === data.pageId); + if (!currentPage) { + throw new Error(`Page with id ${data.pageId} not found`); + } + currentPage.crdt.remoteUpdate(data.node, data.pageId); + + // 5. 다른 클라이언트들에게 업데이트된 블록 정보 브로드캐스트 + const operation = { + node: data.node, + pageId: data.pageId, + } as RemoteBlockUpdateOperation; + client.broadcast.emit("update/block", operation); + } catch (error) { + this.logger.error( + `블록 Update 연산 처리 중 오류 발생 - Client ID: ${clientInfo?.clientId}`, + error.stack, + ); + throw new WsException(`Update 연산 실패: ${error.message}`); + } } /** - * 클라이언트로부터 받은 원격 삽입 연산 - * @param data 클라이언트가 송신한 Node 정보 - * @param client 클라이언트 번호 + * 블록 삽입 연산 처리 */ - @SubscribeMessage("insert") - async handleInsert( - @MessageBody() data: RemoteInsertOperation, + @SubscribeMessage("insert/block") + async handleBlockInsert( + @MessageBody() data: RemoteBlockInsertOperation, @ConnectedSocket() client: Socket, ): Promise { - console.log(`Insert 연산 수신 from ${client.id}:`, data); + const clientInfo = this.clientMap.get(client.id); + try { + this.logger.debug( + `Insert 연산 수신 - Client ID: ${clientInfo?.clientId}, Data:`, + JSON.stringify(data), + ); + // TODO 클라이언트로부터 받은 정보를 서버의 인스턴스에 저장한다. - await this.crdtService.handleInsert(data); + // 몇번 page의 editorCRDT에 추가가 되냐 + const currentPage = this.workSpaceService + .getWorkspace() + .pageList.find((p) => p.id === data.pageId); + if (!currentPage) { + throw new Error(`Page with id ${data.pageId} not found`); + } - client.broadcast.emit("insert", data); + currentPage.crdt.remoteInsert(data); + const operation = { + node: data.node, + pageId: data.pageId, + }; + client.broadcast.emit("insert/block", operation); + } catch (error) { + this.logger.error( + `Block Insert 연산 처리 중 오류 발생 - Client ID: ${clientInfo?.clientId}`, + error.stack, + ); + throw new WsException(`Insert 연산 실패: ${error.message}`); + } } /** - * 클라이언트로부터 받은 원격 삭제 연산 - * @param data 클라이언트가 송신한 Node 정보 - * @param client 클라이언트 번호 + * 글자 삽입 연산 처리 + */ + @SubscribeMessage("insert/char") + async handleCharInsert( + @MessageBody() data: RemoteCharInsertOperation, + @ConnectedSocket() client: Socket, + ): Promise { + const clientInfo = this.clientMap.get(client.id); + try { + this.logger.debug( + `Insert 연산 수신 - Client ID: ${clientInfo?.clientId}, Data:`, + JSON.stringify(data), + ); + // blockId 는 수신 받음 + // 원하는 block에 char node 를 삽입해야함 이제. + + // !! TODO 블록 찾기 + const currentPage = this.workSpaceService + .getWorkspace() + .pageList.find((p) => p.id === data.pageId); + if (!currentPage) { + throw new Error(`Page with id ${data.pageId} not found`); + } + const currentBlock = currentPage.crdt.LinkedList.nodeMap[JSON.stringify(data.blockId)]; + // currentBlock 이 block 인스턴스가 아님 + if (!currentBlock) { + throw new Error(`Block with id ${data.blockId} not found`); + } + currentBlock.crdt.remoteInsert(data); + // server는 EditorCRDT 없습니다. - BlockCRDT 로 사용되고있음. + const operation = { + node: data.node, + blockId: data.blockId, + }; + client.broadcast.emit("insert/char", operation); + } catch (error) { + this.logger.error( + `Char Insert 연산 처리 중 오류 발생 - Client ID: ${clientInfo?.clientId}`, + error.stack, + ); + throw new WsException(`Insert 연산 실패: ${error.message}`); + } + } + /** + * 삭제 연산 처리 */ - @SubscribeMessage("delete") - async handleDelete( - @MessageBody() data: RemoteDeleteOperation, + @SubscribeMessage("delete/block") + async handleBlockDelete( + @MessageBody() data: RemoteBlockDeleteOperation, @ConnectedSocket() client: Socket, ): Promise { - console.log(`Delete 연산 수신 from ${client.id}:`, data); - await this.crdtService.handleDelete(data); - client.broadcast.emit("delete", data); + const clientInfo = this.clientMap.get(client.id); + try { + this.logger.debug( + `Delete 연산 수신 - Client ID: ${clientInfo?.clientId}, Data:`, + JSON.stringify(data), + ); + + const currentPage = this.workSpaceService + .getWorkspace() + .pageList.find((p) => p.id === data.pageId); + if (!currentPage) { + throw new Error(`Page with id ${data.pageId} not found`); + } + currentPage.crdt.remoteDelete(data); + const operation = { + targetId: data.targetId, + clock: data.clock, + pageId: data.pageId, + }; + client.broadcast.emit("delete/block", operation); + } catch (error) { + this.logger.error( + `Block Delete 연산 처리 중 오류 발생 - Client ID: ${clientInfo?.clientId}`, + error.stack, + ); + throw new WsException(`Delete 연산 실패: ${error.message}`); + } } /** - * 추후 caret 표시 기능을 위해 받아놓음 + 추후 개선때 인덱스 계산할때 캐럿으로 계산하면 용이할듯 하여 데이터로 만듦 - * @param data 클라이언트가 송신한 caret 정보 - * @param client 클라이언트 번호 + * 삭제 연산 처리 + */ + @SubscribeMessage("delete/char") + async handleCharDelete( + @MessageBody() data: RemoteCharDeleteOperation, + @ConnectedSocket() client: Socket, + ): Promise { + const clientInfo = this.clientMap.get(client.id); + try { + this.logger.debug( + `Delete 연산 수신 - Client ID: ${clientInfo?.clientId}, Data:`, + JSON.stringify(data), + ); + + const currentPage = this.workSpaceService + .getWorkspace() + .pageList.find((p) => p.id === data.pageId); + if (!currentPage) { + throw new Error(`Page with id ${data.pageId} not found`); + } + const currentBlock = currentPage.crdt.LinkedList.nodeMap[JSON.stringify(data.blockId)]; + if (!currentBlock) { + throw new Error(`Block with id ${data.blockId} not found`); + } + currentBlock.crdt.remoteDelete(data); + + const operation = { + targetId: data.targetId, + clock: data.clock, + blockId: data.blockId, + }; + client.broadcast.emit("delete/char", operation); + } catch (error) { + this.logger.error( + `Char Delete 연산 처리 중 오류 발생 - Client ID: ${clientInfo?.clientId}`, + error.stack, + ); + throw new WsException(`Delete 연산 실패: ${error.message}`); + } + } + + /** + * 커서 위치 업데이트 처리 */ @SubscribeMessage("cursor") handleCursor(@MessageBody() data: CursorPosition, @ConnectedSocket() client: Socket): void { - console.log(`Cursor 위치 수신 from ${client.id}:`, data); - client.broadcast.emit("cursor", data); + const clientInfo = this.clientMap.get(client.id); + try { + this.logger.debug( + `Cursor 위치 업데이트 - Client ID: ${clientInfo?.clientId}, Position:`, + JSON.stringify(data), + ); + + const operation = { + clientId: clientInfo?.clientId, + position: data.position, + }; + // 커서 정보에 클라이언트 ID 추가하여 브로드캐스트 + client.broadcast.emit("cursor", operation); + } catch (error) { + this.logger.error( + `Cursor 업데이트 중 오류 발생 - Client ID: ${clientInfo?.clientId}`, + error.stack, + ); + throw new WsException(`Cursor 업데이트 실패: ${error.message}`); + } + } + + /** + * 현재 연결된 모든 클라이언트 정보 조회 + */ + getConnectedClients(): { total: number; clients: ClientInfo[] } { + return { + total: this.clientMap.size, + clients: Array.from(this.clientMap.values()), + }; } } diff --git a/server/src/crdt/crdt.module.ts b/server/src/crdt/crdt.module.ts index e9bd8244..547696e5 100644 --- a/server/src/crdt/crdt.module.ts +++ b/server/src/crdt/crdt.module.ts @@ -1,12 +1,12 @@ import { Module } from "@nestjs/common"; -import { CrdtService } from "./crdt.service"; +import { workSpaceService } from "./crdt.service"; import { MongooseModule } from "@nestjs/mongoose"; -import { Doc, DocumentSchema } from "./schemas/document.schema"; +import { Workspace, WorkspaceSchema } from "./schemas/workspace.schema"; import { CrdtGateway } from "./crdt.gateway"; @Module({ - imports: [MongooseModule.forFeature([{ name: Doc.name, schema: DocumentSchema }])], - providers: [CrdtService, CrdtGateway], - exports: [CrdtService], + imports: [MongooseModule.forFeature([{ name: Workspace.name, schema: WorkspaceSchema }])], + providers: [workSpaceService, CrdtGateway], + exports: [workSpaceService], }) export class CrdtModule {} diff --git a/server/src/crdt/crdt.service.ts b/server/src/crdt/crdt.service.ts index 88251782..3f452869 100644 --- a/server/src/crdt/crdt.service.ts +++ b/server/src/crdt/crdt.service.ts @@ -1,96 +1,174 @@ import { Injectable, OnModuleInit } from "@nestjs/common"; import { InjectModel } from "@nestjs/mongoose"; -import { Doc, DocumentDocument } from "./schemas/document.schema"; +import { Workspace, WorkspaceDocument } from "./schemas/workspace.schema"; +import { WorkSpace as CRDTWorkSpace } from "@noctaCrdt/WorkSpace"; import { Model } from "mongoose"; -import { BlockCRDT } from "@noctaCrdt/Crdt"; -import { RemoteInsertOperation, RemoteDeleteOperation } from "@noctaCrdt/Interfaces"; -import { CharId } from "@noctaCrdt/NodeId"; -import { Char } from "@noctaCrdt/Node"; +import { EditorCRDT, BlockCRDT } from "@noctaCrdt/Crdt"; +import { Page as CRDTPage } from "@noctaCrdt/Page"; +import { WorkSpaceSerializedProps } from "@noctaCrdt/Interfaces"; @Injectable() -export class CrdtService implements OnModuleInit { - private crdt: BlockCRDT; - - constructor(@InjectModel(Doc.name) private documentModel: Model) { - this.crdt = new BlockCRDT(0); +export class workSpaceService implements OnModuleInit { + private workspace: CRDTWorkSpace; + private tempPage: CRDTPage; + constructor(@InjectModel(Workspace.name) private workspaceModel: Model) { + this.tempPage = new CRDTPage(); + this.workspace = new CRDTWorkSpace("test", [this.tempPage]); } + async onModuleInit() { try { + // MongoDB에서 Workspace 문서 가져오기 const doc = await this.getDocument(); - if (doc && doc.crdt) { - this.crdt = new BlockCRDT(0); - try { - // 저장된 CRDT 상태를 복원 - this.crdt.clock = doc.crdt.clock; - this.crdt.client = doc.crdt.client; - - // LinkedList 복원 - if (doc.crdt.LinkedList.head) { - this.crdt.LinkedList.head = new CharId( - doc.crdt.LinkedList.head.clock, - doc.crdt.LinkedList.head.client, - ); - } - - this.crdt.LinkedList.nodeMap = {}; - for (const [key, node] of Object.entries(doc.crdt.LinkedList.nodeMap)) { - const reconstructedNode = new Char( - node.value, - new CharId(node.id.clock, node.id.client), - ); - - if (node.next) { - reconstructedNode.next = new CharId(node.next.clock, node.next.client); - } - if (node.prev) { - reconstructedNode.prev = new CharId(node.prev.clock, node.prev.client); - } - - this.crdt.LinkedList.nodeMap[key] = reconstructedNode; - } - } catch (e) { - console.error("Error reconstructing CRDT:", e); - } + if (doc) { + // 1. Workspace 기본 정보 복원 + this.workspace = new CRDTWorkSpace(doc.id, []); + this.workspace.deserialize({ + id: doc.id, + pageList: doc.pageList, + authUser: doc.authUser, + } as WorkSpaceSerializedProps); } + console.log("init 이후 서버 인스턴스 확인", this.workspace); } catch (error) { console.error("Error during CrdtService initialization:", error); + throw error; } } - async getDocument(): Promise { - let doc = await this.documentModel.findOne(); + + async getDocument(): Promise { + let doc = await this.workspaceModel.findOne(); if (!doc) { - doc = new this.documentModel({ crdt: this.crdt.serialize() }); - await doc.save(); + const serializedWorkspace = this.workspace.serialize(); + console.log("Serialized workspace:", serializedWorkspace); + + // Workspace 스키마에 맞게 데이터 구조화 + doc = new this.workspaceModel({ + id: serializedWorkspace.id || "default-id", // 적절한 ID 생성 필요 + pageList: serializedWorkspace.pageList.map((page) => ({ + id: page.id, + title: page.title, + icon: page.icon, + crdt: { + clock: page.crdt.clock, + client: page.crdt.client, + currentBlock: page.crdt.currentBlock, + LinkedList: { + head: page.crdt.LinkedList.head, + nodeMap: page.crdt.LinkedList.nodeMap, + }, + }, + })), + authUser: new Map(), // 필요한 경우 초기 인증 사용자 데이터 설정 + updatedAt: new Date(), + }); + + console.log("New document to save:", doc); + try { + await doc.save(); + console.log("Document saved successfully"); + } catch (error) { + console.error("Error saving document:", error); + throw error; + } } return doc; } + async updateDocument(): Promise { + const serializedWorkspace = this.workspace.serialize(); + return await this.workspaceModel + .findOneAndUpdate( + {}, + { + $set: { + ...serializedWorkspace, + updatedAt: new Date(), + }, + }, + { new: true, upsert: true }, + ) + .exec(); + } - async updateDocument(): Promise { - const serializedCRDT = this.crdt.serialize(); - const doc = await this.documentModel.findOneAndUpdate( - {}, - { crdt: serializedCRDT, updatedAt: new Date() }, - { new: true, upsert: true }, - ); - if (!doc) throw new Error("문서 저장 실패"); - return doc; + // 각 레벨별 구체적인 Insert/Delete 처리 메서드들 + async handleWorkSpaceInsert(payload: any): Promise { + // WorkSpace 레벨 Insert 구현 + } + + async handleWorkSpaceDelete(payload: any): Promise { + // WorkSpace 레벨 Delete 구현 + } + + async handlePageInsert(payload: any): Promise { + // Page 레벨 Insert 구현 + // const newPage = await this.getWorkspace().getPage(payload).deserializePage(payload); + // this.workspace.pageList.push(newPage); + } + + async handlePageDelete(payload: any): Promise { + // Page 레벨 Delete 구현 + const pageIndex = this.workspace.pageList.findIndex((p) => p.id === payload.pageId); + if (pageIndex !== -1) { + this.workspace.pageList.splice(pageIndex, 1); + } + } + + async handleBlockInsert(editorCRDT: EditorCRDT, payload: any): Promise { + // Block 레벨 Insert 구현 + console.log(editorCRDT, payload, "???"); + editorCRDT.remoteInsert(payload); } - async handleInsert(operation: RemoteInsertOperation): Promise { - this.crdt.remoteInsert(operation); - await this.updateDocument(); + async handleBlockDelete(editorCRDT: EditorCRDT, payload: any): Promise { + // Block 레벨 Delete 구현 + editorCRDT.remoteDelete(payload); } - async handleDelete(operation: RemoteDeleteOperation): Promise { - this.crdt.remoteDelete(operation); - await this.updateDocument(); + async handleCharInsert(blockCRDT: BlockCRDT, payload: any): Promise { + // Char 레벨 Insert 구현 + blockCRDT.remoteInsert(payload); } - getText(): string { - return this.crdt.read(); + async handleCharDelete(blockCRDT: BlockCRDT, payload: any): Promise { + // Char 레벨 Delete 구현 + blockCRDT.remoteDelete(payload); } - getCRDT(): BlockCRDT { - return this.crdt; + getWorkspace(): CRDTWorkSpace { + return this.workspace; } } + +// this.crdt = new EditorCRDT(0); +// try { +// // 저장된 CRDT 상태를 복원 +// this.crdt.clock = doc.crdt.clock; +// this.crdt.client = doc.crdt.client; + +// // LinkedList 복원 +// if (doc.crdt.LinkedList.head) { +// this.crdt.LinkedList.head = new CharId( +// doc.crdt.LinkedList.head.clock, +// doc.crdt.LinkedList.head.client, +// ); +// } + +// this.crdt.LinkedList.nodeMap = {}; +// for (const [key, node] of Object.entries(doc.crdt.LinkedList.nodeMap)) { +// const reconstructedNode = new Char( +// node.value, +// new CharId(node.id.clock, node.id.client), +// ); + +// if (node.next) { +// reconstructedNode.next = new CharId(node.next.clock, node.next.client); +// } +// if (node.prev) { +// reconstructedNode.prev = new CharId(node.prev.clock, node.prev.client); +// } + +// this.crdt.LinkedList.nodeMap[??].crdt.LinkedList.nodeMap[key] = reconstructedNode; +// } +// } catch (e) { +// console.error("Error reconstructing CRDT:", e); +// } diff --git a/server/src/crdt/schemas/document.schema.ts b/server/src/crdt/schemas/document.schema.ts deleted file mode 100644 index 0c0c172c..00000000 --- a/server/src/crdt/schemas/document.schema.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; -import { Document } from "mongoose"; - -export type DocumentDocument = Document & Doc; - -@Schema({ minimize: false }) -export class Doc { - @Prop({ type: Object, required: true }) - crdt: { - clock: number; - client: number; - LinkedList: { - head: { - clock: number; - client: number; - } | null; - nodeMap: { - [key: string]: { - id: { clock: number; client: number }; - value: string; - next: { clock: number; client: number } | null; - prev: { clock: number; client: number } | null; - }; - }; - }; - }; - - @Prop({ default: Date.now }) - updatedAt: Date; -} -export const DocumentSchema = SchemaFactory.createForClass(Doc); diff --git a/server/src/crdt/schemas/workspace.schema.ts b/server/src/crdt/schemas/workspace.schema.ts new file mode 100644 index 00000000..9ea80d92 --- /dev/null +++ b/server/src/crdt/schemas/workspace.schema.ts @@ -0,0 +1,198 @@ +import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; +import { Document } from "mongoose"; + +// CharId Schema +@Schema({ _id: false }) +export class CharId { + @Prop({ required: true }) + clock: number; + + @Prop({ required: true }) + client: number; +} + +// BlockId Schema +@Schema({ _id: false }) +export class BlockId { + @Prop({ required: true }) + clock: number; + + @Prop({ required: true }) + client: number; +} + +// Char Schema +@Schema({ _id: false }) +export class Char { + @Prop({ type: CharId, required: true }) + id: CharId; + + @Prop({ required: true }) + value: string; + + @Prop({ + type: { + id: Object, + content: String, + }, + }) + next?: any; + + @Prop({ + type: { + id: Object, + content: String, + }, + }) + prev?: any; +} + +// TextLinkedList Schema +@Schema({ _id: false }) +export class TextLinkedList { + @Prop({ type: CharId, default: null }) + head: CharId | null; + + @Prop({ type: Object, of: Char }) + nodeMap: Record; +} + +// BlockCRDT Schema +@Schema({ _id: false }) +export class BlockCRDT { + @Prop({ required: true }) + clock: number; + + @Prop({ required: true }) + client: number; + + @Prop({ required: true }) + currentCaret: number; + + @Prop({ type: TextLinkedList, required: true }) + LinkedList: TextLinkedList; +} + +// Block Schema +@Schema({ _id: false }) +export class Block { + @Prop({ type: BlockCRDT, required: true }) + crdt: BlockCRDT; + + @Prop({ type: BlockId, required: true }) + id: BlockId; + + @Prop({ + type: String, + enum: ["checkBox", "list"], + required: true, + }) + icon: string; + + @Prop({ + type: String, + enum: ["h1", "h2"], + required: true, + }) + type: string; + + @Prop({ required: true }) + indent: number; + + @Prop({ + type: { + crdt: Object, + id: Object, + icon: String, + type: String, + indent: Number, + animation: String, + style: [String], + }, + }) + next?: any; + + @Prop({ + type: { + crdt: Object, + id: Object, + icon: String, + type: String, + indent: Number, + animation: String, + style: [String], + }, + }) + prev?: any; + + @Prop({ + type: String, + enum: ["wave", "fill"], + required: true, + }) + animation: string; + + @Prop({ type: [String], default: [] }) + style: string[]; +} + +// BlockLinkedList Schema +@Schema({ minimize: false, _id: false }) +export class BlockLinkedList { + @Prop({ type: BlockId, default: null }) + head: BlockId | null; + + @Prop({ type: Object, of: Block, default: {} }) + nodeMap: Record; +} + +// EditorCRDT Schema +@Schema({ _id: false }) +export class EditorCRDT { + @Prop({ required: true }) + clock: number; + + @Prop({ required: true }) + client: number; + + @Prop({ type: Block }) + currentBlock: Block; + + @Prop({ type: BlockLinkedList, required: true }) + LinkedList: BlockLinkedList; +} + +// Page Schema +@Schema({ _id: false }) +export class Page { + @Prop({ required: true }) + id: string; + + @Prop({ required: true }) + title: string; + + @Prop({ required: true }) + icon: string; + + @Prop({ type: EditorCRDT, required: true }) + crdt: EditorCRDT; +} + +// Main Workspace Document Schema +@Schema({ minimize: false }) +export class Workspace { + @Prop({ required: true }) + id: string; + + @Prop({ type: [Page], default: [] }) + pageList: Page[]; + + @Prop({ type: Map, of: Object }) + authUser: Map; + + @Prop({ default: Date.now }) + updatedAt: Date; +} + +export type WorkspaceDocument = Document & Workspace; +export const WorkspaceSchema = SchemaFactory.createForClass(Workspace); diff --git a/server/src/main.ts b/server/src/main.ts index 6a203d04..9790584d 100644 --- a/server/src/main.ts +++ b/server/src/main.ts @@ -1,5 +1,7 @@ import { NestFactory } from "@nestjs/core"; import { AppModule } from "./app.module"; +import { createSwaggerDocument } from "./swagger/swagger.config"; +import cookieParser from "cookie-parser"; const bootstrap = async () => { const app = await NestFactory.create(AppModule); @@ -10,23 +12,21 @@ const bootstrap = async () => { app.enableCors({ origin: (origin, callback) => { - if (isDevelopment) { - // 개발 환경: 모든 Origin 허용 + if (isDevelopment || !origin || allowedOrigins.includes(origin)) { callback(null, true); } else { - // 배포 환경: 특정 Origin만 허용 - if (!origin || allowedOrigins.includes(origin)) { - callback(null, true); - } else { - callback(new Error("Not allowed by CORS")); - } + callback(new Error("Not allowed by CORS")); } }, credentials: true, // 쿠키 전송을 위해 필수 + exposedHeaders: ["Authorization"], }); + app.use(cookieParser()); app.setGlobalPrefix("api"); + createSwaggerDocument(app); + await app.listen(process.env.PORT ?? 3000); }; bootstrap(); diff --git a/server/src/swagger/swagger.config.ts b/server/src/swagger/swagger.config.ts new file mode 100644 index 00000000..c93cebb1 --- /dev/null +++ b/server/src/swagger/swagger.config.ts @@ -0,0 +1,19 @@ +import { INestApplication } from "@nestjs/common"; +import { SwaggerModule, DocumentBuilder } from "@nestjs/swagger"; + +export const createSwaggerDocument = (app: INestApplication): void => { + if (process.env.NODE_ENV !== "development") { + return; // 개발 환경이 아니면 Swagger 비활성화 + } + + const config = new DocumentBuilder() + .setTitle("Nocta API Docs") + .setDescription("Nocta API description") + .setVersion("1.0.0") + .addBearerAuth() + .addCookieAuth("refreshToken") + .build(); + + const document = SwaggerModule.createDocument(app, config); + SwaggerModule.setup("api-docs", app, document); +};