create-ailk 0.11.5 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/component-catalog.json +35 -2
- package/component-catalog.md +9 -6
- package/dist/add-module.js +13 -0
- package/dist/module-architecture.d.ts +8 -0
- package/dist/module-architecture.js +33 -0
- package/dist/paid-sections.d.ts +23 -0
- package/dist/paid-sections.js +119 -0
- package/dist/programmatic.js +8 -0
- package/package.json +3 -3
- package/templates/.env.example +69 -3
- package/templates/apps/api/.env.example +22 -0
- package/templates/apps/api/CLAUDE.md +19 -7
- package/templates/apps/api/package.json +1 -0
- package/templates/apps/api/src/bin/spokes.ts +137 -0
- package/templates/apps/api/src/config/__tests__/hub-require-spoke-key.test.ts +96 -0
- package/templates/apps/api/src/config/index.ts +97 -0
- package/templates/apps/api/src/lib/__mocks__/prisma.ts +35 -0
- package/templates/apps/api/src/lib/__tests__/spoke-store.test.ts +152 -0
- package/templates/apps/api/src/lib/spoke-store.ts +131 -0
- package/templates/apps/api/src/routes/leads/__tests__/spoke.test.ts +331 -0
- package/templates/apps/api/src/routes/leads/index.ts +33 -3
- package/templates/apps/api/src/routes/project-listings/__tests__/directory.test.ts +528 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/site-answers.test.ts +204 -0
- package/templates/apps/api/src/routes/project-listings/index.ts +14 -2
- package/templates/apps/api/src/routes/project-listings/public.ts +42 -1
- package/templates/apps/api/src/routes/project-listings/submit.ts +3 -0
- package/templates/apps/api/src/routes/webhooks/index.ts +29 -0
- package/templates/apps/api/src/server.ts +48 -0
- package/templates/apps/api/src/services/__tests__/default-tenant.test.ts +147 -0
- package/templates/apps/api/src/services/__tests__/slack-notify.test.ts +70 -0
- package/templates/apps/api/src/services/__tests__/spoke-resolution.test.ts +374 -0
- package/templates/apps/api/src/services/default-tenant.ts +51 -28
- package/templates/apps/api/src/services/deliverable-fulfillment.ts +89 -3
- package/templates/apps/api/src/services/lead-routing.ts +13 -1
- package/templates/apps/api/src/services/project-listings.ts +209 -18
- package/templates/apps/api/src/services/public-site-resolver.ts +149 -28
- package/templates/apps/api/src/services/slack-notify.ts +54 -3
- package/templates/apps/web/.env.example +14 -0
- package/templates/apps/web/app/[locale]/[slug]/[detail]/__tests__/page.test.tsx +137 -0
- package/templates/apps/web/app/[locale]/[slug]/[detail]/page.tsx +60 -20
- package/templates/apps/web/app/[locale]/careers/[slug]/page.tsx +5 -16
- package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +8 -0
- package/templates/apps/web/app/[locale]/case-studies/[slug]/page.tsx +5 -16
- package/templates/apps/web/app/[locale]/case-studies/__tests__/page-renderer-migration.test.tsx +8 -0
- package/templates/apps/web/app/[locale]/events/[slug]/page.tsx +5 -19
- package/templates/apps/web/app/[locale]/events/__tests__/page-renderer-migration.test.tsx +8 -0
- package/templates/apps/web/app/[locale]/integrations/[slug]/page.tsx +5 -14
- package/templates/apps/web/app/[locale]/integrations/__tests__/page-renderer-migration.test.tsx +8 -0
- package/templates/apps/web/app/[locale]/layout.tsx +4 -0
- package/templates/apps/web/app/[locale]/partners/[slug]/page.tsx +5 -16
- package/templates/apps/web/app/[locale]/partners/__tests__/page-renderer-migration.test.tsx +8 -0
- package/templates/apps/web/app/[locale]/portfolio/[slug]/page.tsx +4 -7
- package/templates/apps/web/app/[locale]/products/[slug]/page.tsx +5 -14
- package/templates/apps/web/app/[locale]/products/__tests__/page-renderer-migration.test.tsx +8 -0
- package/templates/apps/web/app/[locale]/purchase/__tests__/module-scope.test.ts +2 -2
- package/templates/apps/web/app/[locale]/resources/[slug]/page.tsx +5 -22
- package/templates/apps/web/app/[locale]/resources/__tests__/page-renderer-migration.test.tsx +8 -0
- package/templates/apps/web/app/[locale]/services/[slug]/page.tsx +5 -14
- package/templates/apps/web/app/[locale]/services/__tests__/page-renderer-migration.test.tsx +8 -0
- package/templates/apps/web/jest.config.cjs +1 -1
- package/templates/apps/web/lib/__tests__/listings.test.tsx +352 -0
- package/templates/apps/web/lib/listings.tsx +472 -0
- package/templates/apps/web/lib/paid-section-contracts.ts +22 -0
- package/templates/apps/web/lib/paid-sections.generated.ts +16 -0
- package/templates/apps/web/messages/en.json +10 -0
- package/templates/apps/web/src/lib/__tests__/commerce-sections.test.ts +57 -0
- package/templates/apps/web/src/lib/commerce-sections.ts +33 -71
- package/templates/database/CHANGELOG.md +34 -0
- package/templates/database/__tests__/build.test.ts +131 -0
- package/templates/database/__tests__/spoke-registry.db.test.ts +191 -0
- package/templates/database/auth/schema.prisma +31 -0
- package/templates/database/config/schema.prisma +26 -0
- package/templates/database/inbox/schema.prisma +21 -0
- package/templates/database/migrations/20261003120000_spoke_registry/migration.sql +80 -0
- package/templates/database/migrations/20261003130000_scheduling_connection/migration.sql +49 -0
- package/templates/database/package.json +3 -3
- package/versions.json +34 -34
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
-- #7532 — the hub's spoke registry and the booking-origin record (spec
|
|
2
|
+
-- docs/specs/7532-a-spoke-s-public-reads-spec.md D1, D5).
|
|
3
|
+
--
|
|
4
|
+
-- spokes (auth) — one row per separately deployed site that
|
|
5
|
+
-- calls this hub, bound to ONE workspace. It
|
|
6
|
+
-- stores the SHA-256 digest of the spoke's
|
|
7
|
+
-- hub-minted key, never the key. Deleting a
|
|
8
|
+
-- workspace deletes its spokes (the FK below).
|
|
9
|
+
-- appointment_origins (inbox) — (provider, booking uid) → workspace, written
|
|
10
|
+
-- when a spoke's booking is created so the
|
|
11
|
+
-- deployment-wide Cal.com webhook stores the
|
|
12
|
+
-- booking in the spoke's workspace. One origin
|
|
13
|
+
-- per booking uid. No foreign key and no
|
|
14
|
+
-- relation (ADR 0009): workspace_id and
|
|
15
|
+
-- spoke_id are plain columns with format CHECKs.
|
|
16
|
+
--
|
|
17
|
+
-- PURELY ADDITIVE: two new tables, their indexes and one FK to "workspaces".
|
|
18
|
+
-- No statement touches an existing table's rows or columns, so there is no
|
|
19
|
+
-- pre-assertion block — this migration cannot lose a row.
|
|
20
|
+
--
|
|
21
|
+
-- Rollback: DROP TABLE "appointment_origins"; DROP TABLE "spokes". Safe while
|
|
22
|
+
-- nothing but #7532's own code reads them.
|
|
23
|
+
|
|
24
|
+
-- CreateTable
|
|
25
|
+
CREATE TABLE "spokes" (
|
|
26
|
+
"id" TEXT NOT NULL DEFAULT ('spoke_'::text || (uuidv7())::text),
|
|
27
|
+
"workspace_id" TEXT NOT NULL,
|
|
28
|
+
"name" VARCHAR(120) NOT NULL,
|
|
29
|
+
"credential_hash" CHAR(64) NOT NULL,
|
|
30
|
+
"credential_prefix" VARCHAR(24) NOT NULL,
|
|
31
|
+
"revoked_at" TIMESTAMP(3),
|
|
32
|
+
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
33
|
+
"updated_at" TIMESTAMP(3) NOT NULL,
|
|
34
|
+
|
|
35
|
+
CONSTRAINT "spokes_pkey" PRIMARY KEY ("id")
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
-- CreateTable
|
|
39
|
+
CREATE TABLE "appointment_origins" (
|
|
40
|
+
"id" TEXT NOT NULL DEFAULT ('apptorg_'::text || (uuidv7())::text),
|
|
41
|
+
"provider" VARCHAR(32) NOT NULL DEFAULT 'cal',
|
|
42
|
+
"provider_booking_uid" VARCHAR(200) NOT NULL,
|
|
43
|
+
"workspace_id" TEXT NOT NULL,
|
|
44
|
+
"spoke_id" TEXT NOT NULL,
|
|
45
|
+
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
46
|
+
|
|
47
|
+
CONSTRAINT "appointment_origins_pkey" PRIMARY KEY ("id")
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
-- CreateIndex
|
|
51
|
+
-- The lookup a spoke's every request makes (`findSpokeByKeyHash`).
|
|
52
|
+
CREATE UNIQUE INDEX "spokes_credential_hash_key" ON "spokes"("credential_hash");
|
|
53
|
+
|
|
54
|
+
-- CreateIndex
|
|
55
|
+
CREATE INDEX "spokes_workspace_id_idx" ON "spokes"("workspace_id");
|
|
56
|
+
|
|
57
|
+
-- CreateIndex
|
|
58
|
+
CREATE INDEX "appointment_origins_workspace_id_idx" ON "appointment_origins"("workspace_id");
|
|
59
|
+
|
|
60
|
+
-- CreateIndex
|
|
61
|
+
-- One origin per booking uid (spec D5). The bind inserts with
|
|
62
|
+
-- ON CONFLICT DO NOTHING against this key.
|
|
63
|
+
CREATE UNIQUE INDEX "appointment_origins_provider_provider_booking_uid_key" ON "appointment_origins"("provider", "provider_booking_uid");
|
|
64
|
+
|
|
65
|
+
-- AddForeignKey
|
|
66
|
+
ALTER TABLE "spokes" ADD CONSTRAINT "spokes_workspace_id_fkey" FOREIGN KEY ("workspace_id") REFERENCES "workspaces"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
67
|
+
|
|
68
|
+
-- ADR-0031 rule 3 — spokes: spoke_, appointment_origins: apptorg_ (registered
|
|
69
|
+
-- in packages/ids/src/registry.ts; this migration's path is added to
|
|
70
|
+
-- migration-sync.test.ts's PK_CHECK_MIGRATIONS).
|
|
71
|
+
ALTER TABLE "spokes" ALTER COLUMN "id" TYPE text COLLATE "C";
|
|
72
|
+
ALTER TABLE "spokes" ALTER COLUMN "id" SET DEFAULT ('spoke_'::text || (uuidv7())::text);
|
|
73
|
+
ALTER TABLE "spokes" ADD CONSTRAINT "spokes_id_format" CHECK ("id" ~ '^spoke_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
|
|
74
|
+
ALTER TABLE "spokes" ADD CONSTRAINT "spokes_workspace_id_format" CHECK ("workspace_id" ~ '^wksp_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
|
|
75
|
+
|
|
76
|
+
ALTER TABLE "appointment_origins" ALTER COLUMN "id" TYPE text COLLATE "C";
|
|
77
|
+
ALTER TABLE "appointment_origins" ALTER COLUMN "id" SET DEFAULT ('apptorg_'::text || (uuidv7())::text);
|
|
78
|
+
ALTER TABLE "appointment_origins" ADD CONSTRAINT "appointment_origins_id_format" CHECK ("id" ~ '^apptorg_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
|
|
79
|
+
ALTER TABLE "appointment_origins" ADD CONSTRAINT "appointment_origins_spoke_id_format" CHECK ("spoke_id" ~ '^spoke_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
|
|
80
|
+
ALTER TABLE "appointment_origins" ADD CONSTRAINT "appointment_origins_workspace_id_format" CHECK ("workspace_id" ~ '^wksp_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
-- #7533 — the SchedulingConnection model: a workspace's own scheduling
|
|
2
|
+
-- provider account (spec docs/specs/7533-a-scheduling-connection-per-workspace-spec.md
|
|
3
|
+
-- D1). One row per workspace, keyed `@unique(workspace_id)` like its config
|
|
4
|
+
-- sibling workspace_meetings; the credential and webhook secret columns hold
|
|
5
|
+
-- AES-256-GCM ciphertext written only by apps/api's
|
|
6
|
+
-- services/scheduling/connections.ts. `webhook_token` is the per-connection
|
|
7
|
+
-- webhook entry point's routing id, unique so a delivery resolves at most
|
|
8
|
+
-- one row.
|
|
9
|
+
--
|
|
10
|
+
-- One new table, two unique indexes, in the house style of
|
|
11
|
+
-- 20260919130000_workspace_meetings (CreateTable + CreateIndex immediately
|
|
12
|
+
-- followed by the ADR-0031 rule-3 id-format completion, in ONE migration
|
|
13
|
+
-- since the table is new and needs no retrofit). No `workspace_id_format`
|
|
14
|
+
-- CHECK and no `provider` CHECK, matching that same precedent (the API
|
|
15
|
+
-- accepts only the provider ids its factory table knows).
|
|
16
|
+
--
|
|
17
|
+
-- No backfill, no constraint relaxed, no existing table touched.
|
|
18
|
+
--
|
|
19
|
+
-- Rollback: DROP TABLE "scheduling_connections". Every stored connection is
|
|
20
|
+
-- lost; each workspace returns to the unconfigured state (or, on a
|
|
21
|
+
-- one-workspace deployment, to the CAL_API_KEY env fallback).
|
|
22
|
+
|
|
23
|
+
-- CreateTable
|
|
24
|
+
CREATE TABLE "scheduling_connections" (
|
|
25
|
+
"id" TEXT NOT NULL DEFAULT ('schconn_'::text || (uuidv7())::text),
|
|
26
|
+
"workspace_id" TEXT NOT NULL,
|
|
27
|
+
"provider" VARCHAR(32) NOT NULL,
|
|
28
|
+
"credential_ciphertext" TEXT NOT NULL,
|
|
29
|
+
"webhook_token" VARCHAR(64) NOT NULL,
|
|
30
|
+
"webhook_secret_ciphertext" TEXT NOT NULL,
|
|
31
|
+
"base_url" TEXT,
|
|
32
|
+
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
33
|
+
"updated_at" TIMESTAMPTZ NOT NULL,
|
|
34
|
+
|
|
35
|
+
CONSTRAINT "scheduling_connections_pkey" PRIMARY KEY ("id")
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
-- CreateIndex
|
|
39
|
+
CREATE UNIQUE INDEX "scheduling_connections_workspace_id_key" ON "scheduling_connections"("workspace_id");
|
|
40
|
+
|
|
41
|
+
-- CreateIndex
|
|
42
|
+
CREATE UNIQUE INDEX "scheduling_connections_webhook_token_key" ON "scheduling_connections"("webhook_token");
|
|
43
|
+
|
|
44
|
+
-- ADR-0031 rule 3 — scheduling_connections: schconn_ (registered in
|
|
45
|
+
-- packages/ids/src/registry.ts ENTITY_PREFIX.schedulingConnection; this
|
|
46
|
+
-- migration's path is added to migration-sync.test.ts's PK_CHECK_MIGRATIONS).
|
|
47
|
+
ALTER TABLE "scheduling_connections" ALTER COLUMN "id" TYPE text COLLATE "C";
|
|
48
|
+
ALTER TABLE "scheduling_connections" ALTER COLUMN "id" SET DEFAULT ('schconn_'::text || (uuidv7())::text);
|
|
49
|
+
ALTER TABLE "scheduling_connections" ADD CONSTRAINT "scheduling_connections_id_format" CHECK ("id" ~ '^schconn_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@working-theory/database",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.1",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
53
|
"lint": "eslint .",
|
|
54
|
-
"build": "tsc -b tsconfig.build.json && tsc -b tsconfig.tenancy.json && tsc -b tsconfig.flows.json",
|
|
55
|
-
"db:generate": "
|
|
54
|
+
"build": "prisma generate && tsc -b tsconfig.build.json --force && tsc -b tsconfig.tenancy.json && tsc -b tsconfig.flows.json",
|
|
55
|
+
"db:generate": "pnpm run build",
|
|
56
56
|
"db:migrate": "prisma migrate dev",
|
|
57
57
|
"db:migrate:deploy": "prisma migrate deploy",
|
|
58
58
|
"db:push": "prisma db push",
|
package/versions.json
CHANGED
|
@@ -1,52 +1,52 @@
|
|
|
1
1
|
{
|
|
2
|
-
"@working-theory/admin-ui": "0.
|
|
3
|
-
"@working-theory/aeo": "0.
|
|
4
|
-
"@working-theory/agent-context": "0.
|
|
2
|
+
"@working-theory/admin-ui": "0.34.1",
|
|
3
|
+
"@working-theory/aeo": "0.34.1",
|
|
4
|
+
"@working-theory/agent-context": "0.34.1",
|
|
5
5
|
"@working-theory/agent-contract": "0.1.0",
|
|
6
6
|
"@working-theory/agent-memory": "0.0.0",
|
|
7
7
|
"@working-theory/ai": "0.1.0",
|
|
8
|
-
"@working-theory/analytics": "0.
|
|
9
|
-
"@working-theory/api-client": "0.
|
|
8
|
+
"@working-theory/analytics": "0.34.1",
|
|
9
|
+
"@working-theory/api-client": "0.34.1",
|
|
10
10
|
"@working-theory/cda-filesystem": "0.0.0",
|
|
11
|
-
"@working-theory/cli": "0.
|
|
12
|
-
"@working-theory/common": "0.
|
|
11
|
+
"@working-theory/cli": "0.34.1",
|
|
12
|
+
"@working-theory/common": "0.34.1",
|
|
13
13
|
"@working-theory/consent": "0.1.0",
|
|
14
|
-
"@working-theory/content-adapters": "0.
|
|
15
|
-
"@working-theory/content-projection": "0.
|
|
16
|
-
"@working-theory/email": "0.
|
|
14
|
+
"@working-theory/content-adapters": "0.34.1",
|
|
15
|
+
"@working-theory/content-projection": "0.34.1",
|
|
16
|
+
"@working-theory/email": "0.34.1",
|
|
17
17
|
"@working-theory/env": "0.0.0",
|
|
18
|
-
"@working-theory/eslint-config": "0.
|
|
19
|
-
"@working-theory/fumadocs-schema": "0.
|
|
20
|
-
"@working-theory/ids": "0.
|
|
21
|
-
"@working-theory/jsonld": "0.
|
|
22
|
-
"@working-theory/license": "0.
|
|
23
|
-
"@working-theory/metadata": "0.
|
|
24
|
-
"@working-theory/observability": "0.
|
|
25
|
-
"@working-theory/page-renderer": "0.
|
|
18
|
+
"@working-theory/eslint-config": "0.34.1",
|
|
19
|
+
"@working-theory/fumadocs-schema": "0.34.1",
|
|
20
|
+
"@working-theory/ids": "0.9.1",
|
|
21
|
+
"@working-theory/jsonld": "0.34.1",
|
|
22
|
+
"@working-theory/license": "0.34.1",
|
|
23
|
+
"@working-theory/metadata": "0.34.1",
|
|
24
|
+
"@working-theory/observability": "0.34.1",
|
|
25
|
+
"@working-theory/page-renderer": "0.34.1",
|
|
26
26
|
"@working-theory/plugin-mcp": "0.1.1",
|
|
27
|
-
"@working-theory/schema": "0.
|
|
28
|
-
"@working-theory/schema-pack-registry": "0.
|
|
29
|
-
"@working-theory/schema-validator": "0.
|
|
30
|
-
"@working-theory/sections-registry": "0.
|
|
31
|
-
"@working-theory/site-config": "0.
|
|
32
|
-
"@working-theory/stripe-client": "0.
|
|
33
|
-
"@working-theory/templates": "0.
|
|
34
|
-
"@working-theory/theme": "0.
|
|
35
|
-
"@working-theory/ui": "0.
|
|
36
|
-
"@working-theory/validation": "0.
|
|
37
|
-
"@working-theory/web-i18n": "0.
|
|
27
|
+
"@working-theory/schema": "0.34.1",
|
|
28
|
+
"@working-theory/schema-pack-registry": "0.34.1",
|
|
29
|
+
"@working-theory/schema-validator": "0.34.1",
|
|
30
|
+
"@working-theory/sections-registry": "0.34.1",
|
|
31
|
+
"@working-theory/site-config": "0.34.1",
|
|
32
|
+
"@working-theory/stripe-client": "0.34.1",
|
|
33
|
+
"@working-theory/templates": "0.34.1",
|
|
34
|
+
"@working-theory/theme": "0.34.1",
|
|
35
|
+
"@working-theory/ui": "0.34.1",
|
|
36
|
+
"@working-theory/validation": "0.34.1",
|
|
37
|
+
"@working-theory/web-i18n": "0.34.1",
|
|
38
38
|
"@working-theory/billing-client": "0.0.0",
|
|
39
39
|
"@working-theory/branding": "0.0.0",
|
|
40
40
|
"@working-theory/license-client": "0.0.0",
|
|
41
41
|
"@working-theory/license-manifest": "0.0.0",
|
|
42
42
|
"@working-theory/partner-session": "0.0.0",
|
|
43
43
|
"@working-theory/preview-protocol": "0.0.0",
|
|
44
|
-
"@working-theory/ui-commerce": "0.23.
|
|
45
|
-
"@working-theory/ui-docs-blog": "0.23.
|
|
46
|
-
"@working-theory/ui-scheduling": "0.23.
|
|
47
|
-
"@working-theory/ui-signal-collectors": "0.
|
|
44
|
+
"@working-theory/ui-commerce": "0.23.12",
|
|
45
|
+
"@working-theory/ui-docs-blog": "0.23.12",
|
|
46
|
+
"@working-theory/ui-scheduling": "0.23.12",
|
|
47
|
+
"@working-theory/ui-signal-collectors": "0.25.1",
|
|
48
48
|
"@working-theory/web": "0.0.0",
|
|
49
49
|
"@working-theory/api": "1.0.0",
|
|
50
50
|
"@working-theory/mcp": "0.0.0",
|
|
51
|
-
"@working-theory/database": "0.
|
|
51
|
+
"@working-theory/database": "0.34.1"
|
|
52
52
|
}
|