|
|
|
@@ -0,0 +1,228 @@
|
|
|
|
|
import { MigrationInterface, QueryRunner } from 'typeorm';
|
|
|
|
|
|
|
|
|
|
export class CreateInitialSchema1782060613058 implements MigrationInterface {
|
|
|
|
|
name = 'CreateInitialSchema1782060613058';
|
|
|
|
|
|
|
|
|
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
|
|
|
// 베이스라인 가드 — 이미 스키마가 존재하는 기존 DB(과거 synchronize 로 생성·데이터 보존)면
|
|
|
|
|
// 초기 마이그레이션을 '베이스라인'으로 간주하고 DDL 을 건너뛴다. 마이그레이션은 '적용됨'으로
|
|
|
|
|
// 기록되어 다음 변경 마이그레이션부터 정상 진행되며, 기존 데이터/스키마는 보존된다.
|
|
|
|
|
// (빈 DB 면 이 가드를 통과해 아래 DDL 로 전체 스키마를 생성한다.)
|
|
|
|
|
if (await queryRunner.hasTable('users')) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// uuid_generate_v4() 기본값에 필요한 확장 — 신규(빈) 운영 DB 에서도 보장
|
|
|
|
|
await queryRunner.query(`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`CREATE TABLE "users" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "email" character varying NOT NULL, "password_hash" character varying, "provider" character varying NOT NULL DEFAULT 'local', "email_verified" boolean NOT NULL DEFAULT false, "email_verify_token_hash" character varying, "email_verify_expires_at" TIMESTAMP WITH TIME ZONE, "password_reset_token_hash" character varying, "password_reset_expires_at" TIMESTAMP WITH TIME ZONE, "name" character varying NOT NULL, "role" character varying, "avatar_url" character varying, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "UQ_97672ac88f789774dd47f7c8be3" UNIQUE ("email"), CONSTRAINT "PK_a3ffb1c0c8416b9fc6f907b7433" PRIMARY KEY ("id"))`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`CREATE TABLE "project_members" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "role_type" character varying NOT NULL DEFAULT 'member', "is_owner" boolean NOT NULL DEFAULT false, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "projectId" uuid, "userId" uuid, CONSTRAINT "UQ_326b2a901eb18ac24eabc9b0581" UNIQUE ("projectId", "userId"), CONSTRAINT "PK_0b2f46f804be4aea9234c78bcc9" PRIMARY KEY ("id"))`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`CREATE TABLE "projects" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "name" character varying NOT NULL, "description" character varying, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_6271df0a7aed1d6c0691ce6ac50" PRIMARY KEY ("id"))`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`CREATE TABLE "checklist_items" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "text" character varying NOT NULL, "category" character varying NOT NULL DEFAULT '필수', "done" boolean NOT NULL DEFAULT false, "review_note" text, "sort_order" integer NOT NULL DEFAULT '0', "created_at" TIMESTAMP NOT NULL DEFAULT now(), "taskId" uuid, CONSTRAINT "PK_bae00945a1d4789bd648e583e29" PRIMARY KEY ("id"))`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`CREATE TABLE "tasks" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "seq" integer NOT NULL, "title" character varying NOT NULL, "content" jsonb NOT NULL DEFAULT '[]', "status" character varying NOT NULL DEFAULT 'todo', "due_date" TIMESTAMP WITH TIME ZONE, "approval_note" text, "approval_requested_at" TIMESTAMP WITH TIME ZONE, "changes_note" text, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "updated_at" TIMESTAMP NOT NULL DEFAULT now(), "project_id" uuid, "issuerId" uuid, "approval_requested_by" uuid, CONSTRAINT "UQ_011566614ffa01ec7281ee29754" UNIQUE ("project_id", "seq"), CONSTRAINT "PK_8d12ff38fcc62aaba2cab748772" PRIMARY KEY ("id"))`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`CREATE INDEX "IDX_73f95adb41a77c1bfd7e19dca7" ON "tasks" ("seq") `,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`CREATE TABLE "attachments" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "name" character varying NOT NULL, "stored_name" character varying NOT NULL, "size" integer NOT NULL, "mime" character varying NOT NULL, "kind" character varying NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "task_id" uuid, "uploader_id" uuid, CONSTRAINT "PK_5e1f050bcff31e3084a1d662412" PRIMARY KEY ("id"))`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`CREATE TABLE "comments" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "text" text NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "task_id" uuid, "author_id" uuid, "parent_id" uuid, "attachment_id" uuid, CONSTRAINT "PK_8bf68bc960f2b69e818bdb90dcb" PRIMARY KEY ("id"))`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`CREATE TABLE "notifications" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "type" character varying NOT NULL, "payload" jsonb NOT NULL DEFAULT '{}', "read" boolean NOT NULL DEFAULT false, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "recipient_id" uuid, CONSTRAINT "PK_6a72c3c0f683f6462415e653c3a" PRIMARY KEY ("id"))`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`CREATE INDEX "IDX_92be92313f09987bc6ad70ab41" ON "notifications" ("recipient_id", "created_at") `,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`CREATE TABLE "refresh_sessions" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "current_jti" uuid NOT NULL, "prev_jti" uuid, "prev_at" TIMESTAMP WITH TIME ZONE, "expires_at" TIMESTAMP WITH TIME ZONE NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "user_id" uuid NOT NULL, CONSTRAINT "PK_9190032f6967b7971dca07d69f3" PRIMARY KEY ("id"))`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`CREATE TABLE "ai_conversations" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "title" character varying(120) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "updated_at" TIMESTAMP NOT NULL DEFAULT now(), "user_id" uuid NOT NULL, CONSTRAINT "PK_60db12765b82858ba00c8aa4ae2" PRIMARY KEY ("id"))`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`CREATE TABLE "activities" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "task_seq" integer, "type" character varying NOT NULL, "payload" jsonb NOT NULL DEFAULT '{}', "created_at" TIMESTAMP NOT NULL DEFAULT now(), "project_id" uuid, "actor_id" uuid, CONSTRAINT "PK_7f4004429f731ffb9c88eb486a8" PRIMARY KEY ("id"))`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`CREATE INDEX "IDX_7297db78eb572fa29db5aaf815" ON "activities" ("project_id") `,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`CREATE INDEX "IDX_8291258c0c575bdab03443ef47" ON "activities" ("task_seq") `,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`CREATE TABLE "ai_messages" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "role" character varying NOT NULL, "content" text NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "conversation_id" uuid NOT NULL, CONSTRAINT "PK_a390434d4a515ba18a41bc996c2" PRIMARY KEY ("id"))`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`CREATE TABLE "task_assignees" ("task_id" uuid NOT NULL, "user_id" uuid NOT NULL, CONSTRAINT "PK_7ae8012667c1cc4ca8266002afc" PRIMARY KEY ("task_id", "user_id"))`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`CREATE INDEX "IDX_0141288f2306f20da9a60ec8d6" ON "task_assignees" ("task_id") `,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`CREATE INDEX "IDX_bb8051e376a2b083e074678cb6" ON "task_assignees" ("user_id") `,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "project_members" ADD CONSTRAINT "FK_d19892d8f03928e5bfc7313780c" FOREIGN KEY ("projectId") REFERENCES "projects"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "project_members" ADD CONSTRAINT "FK_08d1346ff91abba68e5a637cfdb" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "checklist_items" ADD CONSTRAINT "FK_1c0abaeeca0b213ddd07675c578" FOREIGN KEY ("taskId") REFERENCES "tasks"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "tasks" ADD CONSTRAINT "FK_9eecdb5b1ed8c7c2a1b392c28d4" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "tasks" ADD CONSTRAINT "FK_950b234a262e85a895b9f9e634e" FOREIGN KEY ("issuerId") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "tasks" ADD CONSTRAINT "FK_60f1ed134a6425431bc66b0eefd" FOREIGN KEY ("approval_requested_by") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "attachments" ADD CONSTRAINT "FK_e62fd181b97caa6b150b09220b1" FOREIGN KEY ("task_id") REFERENCES "tasks"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "attachments" ADD CONSTRAINT "FK_73407cf2d2a0e64546bacf309a7" FOREIGN KEY ("uploader_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "comments" ADD CONSTRAINT "FK_18c2493067c11f44efb35ca0e03" FOREIGN KEY ("task_id") REFERENCES "tasks"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "comments" ADD CONSTRAINT "FK_e6d38899c31997c45d128a8973b" FOREIGN KEY ("author_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "comments" ADD CONSTRAINT "FK_d6f93329801a93536da4241e386" FOREIGN KEY ("parent_id") REFERENCES "comments"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "comments" ADD CONSTRAINT "FK_45d9ed1dd52f601ae9ec8034351" FOREIGN KEY ("attachment_id") REFERENCES "attachments"("id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "notifications" ADD CONSTRAINT "FK_5332a4daa46fd3f4e6625dd275d" FOREIGN KEY ("recipient_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "refresh_sessions" ADD CONSTRAINT "FK_a7ab4fd82c654c85b9de53d971a" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "ai_conversations" ADD CONSTRAINT "FK_12fdbf99ca0da93085d61edd3bb" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "activities" ADD CONSTRAINT "FK_7297db78eb572fa29db5aaf8158" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "activities" ADD CONSTRAINT "FK_78e06b2e7a3bd9b9239de4aa285" FOREIGN KEY ("actor_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "ai_messages" ADD CONSTRAINT "FK_de21fcb2d1df7fd6ca70f555b6d" FOREIGN KEY ("conversation_id") REFERENCES "ai_conversations"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "task_assignees" ADD CONSTRAINT "FK_0141288f2306f20da9a60ec8d69" FOREIGN KEY ("task_id") REFERENCES "tasks"("id") ON DELETE CASCADE ON UPDATE CASCADE`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "task_assignees" ADD CONSTRAINT "FK_bb8051e376a2b083e074678cb60" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE`,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "task_assignees" DROP CONSTRAINT "FK_bb8051e376a2b083e074678cb60"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "task_assignees" DROP CONSTRAINT "FK_0141288f2306f20da9a60ec8d69"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "ai_messages" DROP CONSTRAINT "FK_de21fcb2d1df7fd6ca70f555b6d"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "activities" DROP CONSTRAINT "FK_78e06b2e7a3bd9b9239de4aa285"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "activities" DROP CONSTRAINT "FK_7297db78eb572fa29db5aaf8158"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "ai_conversations" DROP CONSTRAINT "FK_12fdbf99ca0da93085d61edd3bb"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "refresh_sessions" DROP CONSTRAINT "FK_a7ab4fd82c654c85b9de53d971a"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "notifications" DROP CONSTRAINT "FK_5332a4daa46fd3f4e6625dd275d"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "comments" DROP CONSTRAINT "FK_45d9ed1dd52f601ae9ec8034351"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "comments" DROP CONSTRAINT "FK_d6f93329801a93536da4241e386"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "comments" DROP CONSTRAINT "FK_e6d38899c31997c45d128a8973b"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "comments" DROP CONSTRAINT "FK_18c2493067c11f44efb35ca0e03"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "attachments" DROP CONSTRAINT "FK_73407cf2d2a0e64546bacf309a7"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "attachments" DROP CONSTRAINT "FK_e62fd181b97caa6b150b09220b1"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "tasks" DROP CONSTRAINT "FK_60f1ed134a6425431bc66b0eefd"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "tasks" DROP CONSTRAINT "FK_950b234a262e85a895b9f9e634e"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "tasks" DROP CONSTRAINT "FK_9eecdb5b1ed8c7c2a1b392c28d4"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "checklist_items" DROP CONSTRAINT "FK_1c0abaeeca0b213ddd07675c578"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "project_members" DROP CONSTRAINT "FK_08d1346ff91abba68e5a637cfdb"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`ALTER TABLE "project_members" DROP CONSTRAINT "FK_d19892d8f03928e5bfc7313780c"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`DROP INDEX "public"."IDX_bb8051e376a2b083e074678cb6"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`DROP INDEX "public"."IDX_0141288f2306f20da9a60ec8d6"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(`DROP TABLE "task_assignees"`);
|
|
|
|
|
await queryRunner.query(`DROP TABLE "ai_messages"`);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`DROP INDEX "public"."IDX_8291258c0c575bdab03443ef47"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`DROP INDEX "public"."IDX_7297db78eb572fa29db5aaf815"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(`DROP TABLE "activities"`);
|
|
|
|
|
await queryRunner.query(`DROP TABLE "ai_conversations"`);
|
|
|
|
|
await queryRunner.query(`DROP TABLE "refresh_sessions"`);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`DROP INDEX "public"."IDX_92be92313f09987bc6ad70ab41"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(`DROP TABLE "notifications"`);
|
|
|
|
|
await queryRunner.query(`DROP TABLE "comments"`);
|
|
|
|
|
await queryRunner.query(`DROP TABLE "attachments"`);
|
|
|
|
|
await queryRunner.query(
|
|
|
|
|
`DROP INDEX "public"."IDX_73f95adb41a77c1bfd7e19dca7"`,
|
|
|
|
|
);
|
|
|
|
|
await queryRunner.query(`DROP TABLE "tasks"`);
|
|
|
|
|
await queryRunner.query(`DROP TABLE "checklist_items"`);
|
|
|
|
|
await queryRunner.query(`DROP TABLE "projects"`);
|
|
|
|
|
await queryRunner.query(`DROP TABLE "project_members"`);
|
|
|
|
|
await queryRunner.query(`DROP TABLE "users"`);
|
|
|
|
|
}
|
|
|
|
|
}
|