@chief-clancy/terminal 0.1.0
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/LICENSE +21 -0
- package/README.md +62 -0
- package/dist/hooks/clancy-branch-guard.js +1 -0
- package/dist/hooks/clancy-check-update.js +2 -0
- package/dist/hooks/clancy-context-monitor.js +9 -0
- package/dist/hooks/clancy-credential-guard.js +2 -0
- package/dist/hooks/clancy-drift-detector.js +1 -0
- package/dist/hooks/clancy-notification.js +1 -0
- package/dist/hooks/clancy-post-compact.js +2 -0
- package/dist/hooks/clancy-statusline.js +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/installer/file-ops/file-ops.d.ts +35 -0
- package/dist/installer/file-ops/file-ops.d.ts.map +1 -0
- package/dist/installer/file-ops/file-ops.js +95 -0
- package/dist/installer/file-ops/file-ops.js.map +1 -0
- package/dist/installer/file-ops/index.d.ts +2 -0
- package/dist/installer/file-ops/index.d.ts.map +1 -0
- package/dist/installer/file-ops/index.js +2 -0
- package/dist/installer/file-ops/index.js.map +1 -0
- package/dist/installer/hook-installer/hook-installer.d.ts +22 -0
- package/dist/installer/hook-installer/hook-installer.d.ts.map +1 -0
- package/dist/installer/hook-installer/hook-installer.js +213 -0
- package/dist/installer/hook-installer/hook-installer.js.map +1 -0
- package/dist/installer/hook-installer/index.d.ts +2 -0
- package/dist/installer/hook-installer/index.d.ts.map +1 -0
- package/dist/installer/hook-installer/index.js +2 -0
- package/dist/installer/hook-installer/index.js.map +1 -0
- package/dist/installer/install/index.d.ts +3 -0
- package/dist/installer/install/index.d.ts.map +1 -0
- package/dist/installer/install/index.js +2 -0
- package/dist/installer/install/index.js.map +1 -0
- package/dist/installer/install/install.d.ts +124 -0
- package/dist/installer/install/install.d.ts.map +1 -0
- package/dist/installer/install/install.js +255 -0
- package/dist/installer/install/install.js.map +1 -0
- package/dist/installer/manifest/index.d.ts +2 -0
- package/dist/installer/manifest/index.d.ts.map +1 -0
- package/dist/installer/manifest/index.js +2 -0
- package/dist/installer/manifest/index.js.map +1 -0
- package/dist/installer/manifest/manifest.d.ts +46 -0
- package/dist/installer/manifest/manifest.d.ts.map +1 -0
- package/dist/installer/manifest/manifest.js +180 -0
- package/dist/installer/manifest/manifest.js.map +1 -0
- package/dist/installer/prompts/index.d.ts +2 -0
- package/dist/installer/prompts/index.d.ts.map +1 -0
- package/dist/installer/prompts/index.js +2 -0
- package/dist/installer/prompts/index.js.map +1 -0
- package/dist/installer/prompts/prompts.d.ts +34 -0
- package/dist/installer/prompts/prompts.d.ts.map +1 -0
- package/dist/installer/prompts/prompts.js +28 -0
- package/dist/installer/prompts/prompts.js.map +1 -0
- package/dist/installer/role-filter/index.d.ts +2 -0
- package/dist/installer/role-filter/index.d.ts.map +1 -0
- package/dist/installer/role-filter/index.js +2 -0
- package/dist/installer/role-filter/index.js.map +1 -0
- package/dist/installer/role-filter/role-filter.d.ts +33 -0
- package/dist/installer/role-filter/role-filter.d.ts.map +1 -0
- package/dist/installer/role-filter/role-filter.js +91 -0
- package/dist/installer/role-filter/role-filter.js.map +1 -0
- package/dist/installer/shared/fs-errors/fs-errors.d.ts +3 -0
- package/dist/installer/shared/fs-errors/fs-errors.d.ts.map +1 -0
- package/dist/installer/shared/fs-errors/fs-errors.js +7 -0
- package/dist/installer/shared/fs-errors/fs-errors.js.map +1 -0
- package/dist/installer/shared/fs-errors/index.d.ts +2 -0
- package/dist/installer/shared/fs-errors/index.d.ts.map +1 -0
- package/dist/installer/shared/fs-errors/index.js +2 -0
- package/dist/installer/shared/fs-errors/index.js.map +1 -0
- package/dist/installer/shared/fs-guards/fs-guards.d.ts +3 -0
- package/dist/installer/shared/fs-guards/fs-guards.d.ts.map +1 -0
- package/dist/installer/shared/fs-guards/fs-guards.js +18 -0
- package/dist/installer/shared/fs-guards/fs-guards.js.map +1 -0
- package/dist/installer/shared/fs-guards/index.d.ts +2 -0
- package/dist/installer/shared/fs-guards/index.d.ts.map +1 -0
- package/dist/installer/shared/fs-guards/index.js +2 -0
- package/dist/installer/shared/fs-guards/index.js.map +1 -0
- package/dist/installer/shared/type-guards/index.d.ts +2 -0
- package/dist/installer/shared/type-guards/index.d.ts.map +1 -0
- package/dist/installer/shared/type-guards/index.js +2 -0
- package/dist/installer/shared/type-guards/index.js.map +1 -0
- package/dist/installer/shared/type-guards/type-guards.d.ts +8 -0
- package/dist/installer/shared/type-guards/type-guards.d.ts.map +1 -0
- package/dist/installer/shared/type-guards/type-guards.js +10 -0
- package/dist/installer/shared/type-guards/type-guards.js.map +1 -0
- package/dist/installer/ui/index.d.ts +2 -0
- package/dist/installer/ui/index.d.ts.map +1 -0
- package/dist/installer/ui/index.js +2 -0
- package/dist/installer/ui/index.js.map +1 -0
- package/dist/installer/ui/ui.d.ts +23 -0
- package/dist/installer/ui/ui.d.ts.map +1 -0
- package/dist/installer/ui/ui.js +121 -0
- package/dist/installer/ui/ui.js.map +1 -0
- package/dist/runner/autopilot/autopilot.d.ts +71 -0
- package/dist/runner/autopilot/autopilot.d.ts.map +1 -0
- package/dist/runner/autopilot/autopilot.js +206 -0
- package/dist/runner/autopilot/autopilot.js.map +1 -0
- package/dist/runner/autopilot/index.d.ts +2 -0
- package/dist/runner/autopilot/index.d.ts.map +1 -0
- package/dist/runner/autopilot/index.js +2 -0
- package/dist/runner/autopilot/index.js.map +1 -0
- package/dist/runner/cli-bridge/cli-bridge.d.ts +34 -0
- package/dist/runner/cli-bridge/cli-bridge.d.ts.map +1 -0
- package/dist/runner/cli-bridge/cli-bridge.js +53 -0
- package/dist/runner/cli-bridge/cli-bridge.js.map +1 -0
- package/dist/runner/cli-bridge/index.d.ts +2 -0
- package/dist/runner/cli-bridge/index.d.ts.map +1 -0
- package/dist/runner/cli-bridge/index.js +2 -0
- package/dist/runner/cli-bridge/index.js.map +1 -0
- package/dist/runner/dep-factory/deliver-phase.d.ts +24 -0
- package/dist/runner/dep-factory/deliver-phase.d.ts.map +1 -0
- package/dist/runner/dep-factory/deliver-phase.js +57 -0
- package/dist/runner/dep-factory/deliver-phase.js.map +1 -0
- package/dist/runner/dep-factory/dep-factory.d.ts +38 -0
- package/dist/runner/dep-factory/dep-factory.d.ts.map +1 -0
- package/dist/runner/dep-factory/dep-factory.js +193 -0
- package/dist/runner/dep-factory/dep-factory.js.map +1 -0
- package/dist/runner/dep-factory/index.d.ts +2 -0
- package/dist/runner/dep-factory/index.d.ts.map +1 -0
- package/dist/runner/dep-factory/index.js +2 -0
- package/dist/runner/dep-factory/index.js.map +1 -0
- package/dist/runner/dep-factory/invoke-phase.d.ts +20 -0
- package/dist/runner/dep-factory/invoke-phase.d.ts.map +1 -0
- package/dist/runner/dep-factory/invoke-phase.js +45 -0
- package/dist/runner/dep-factory/invoke-phase.js.map +1 -0
- package/dist/runner/implement/implement.d.ts +38 -0
- package/dist/runner/implement/implement.d.ts.map +1 -0
- package/dist/runner/implement/implement.js +61 -0
- package/dist/runner/implement/implement.js.map +1 -0
- package/dist/runner/implement/index.d.ts +2 -0
- package/dist/runner/implement/index.d.ts.map +1 -0
- package/dist/runner/implement/index.js +2 -0
- package/dist/runner/implement/index.js.map +1 -0
- package/dist/runner/notify/index.d.ts +2 -0
- package/dist/runner/notify/index.d.ts.map +1 -0
- package/dist/runner/notify/index.js +2 -0
- package/dist/runner/notify/index.js.map +1 -0
- package/dist/runner/notify/notify.d.ts +49 -0
- package/dist/runner/notify/notify.d.ts.map +1 -0
- package/dist/runner/notify/notify.js +90 -0
- package/dist/runner/notify/notify.js.map +1 -0
- package/dist/runner/prompt-builder/index.d.ts +2 -0
- package/dist/runner/prompt-builder/index.d.ts.map +1 -0
- package/dist/runner/prompt-builder/index.js +2 -0
- package/dist/runner/prompt-builder/index.js.map +1 -0
- package/dist/runner/prompt-builder/prompt-builder.d.ts +53 -0
- package/dist/runner/prompt-builder/prompt-builder.d.ts.map +1 -0
- package/dist/runner/prompt-builder/prompt-builder.js +122 -0
- package/dist/runner/prompt-builder/prompt-builder.js.map +1 -0
- package/dist/runner/session-report/index.d.ts +2 -0
- package/dist/runner/session-report/index.d.ts.map +1 -0
- package/dist/runner/session-report/index.js +2 -0
- package/dist/runner/session-report/index.js.map +1 -0
- package/dist/runner/session-report/session-report.d.ts +81 -0
- package/dist/runner/session-report/session-report.d.ts.map +1 -0
- package/dist/runner/session-report/session-report.js +227 -0
- package/dist/runner/session-report/session-report.js.map +1 -0
- package/dist/runner/shared/types.d.ts +30 -0
- package/dist/runner/shared/types.d.ts.map +1 -0
- package/dist/runner/shared/types.js +2 -0
- package/dist/runner/shared/types.js.map +1 -0
- package/dist/shared/ansi/ansi.d.ts +59 -0
- package/dist/shared/ansi/ansi.d.ts.map +1 -0
- package/dist/shared/ansi/ansi.js +59 -0
- package/dist/shared/ansi/ansi.js.map +1 -0
- package/dist/shared/ansi/index.d.ts +2 -0
- package/dist/shared/ansi/index.d.ts.map +1 -0
- package/dist/shared/ansi/index.js +2 -0
- package/dist/shared/ansi/index.js.map +1 -0
- package/package.json +52 -0
- package/src/agents/agents.test.ts +57 -0
- package/src/agents/arch-agent.md +80 -0
- package/src/agents/concerns-agent.md +96 -0
- package/src/agents/design-agent.md +146 -0
- package/src/agents/devils-advocate.md +54 -0
- package/src/agents/quality-agent.md +178 -0
- package/src/agents/tech-agent.md +101 -0
- package/src/agents/verification-gate.md +128 -0
- package/src/roles/implementer/commands/autopilot.md +11 -0
- package/src/roles/implementer/commands/dry-run.md +15 -0
- package/src/roles/implementer/commands/implement.md +19 -0
- package/src/roles/implementer/workflows/autopilot.md +136 -0
- package/src/roles/implementer/workflows/implement.md +161 -0
- package/src/roles/planner/commands/approve-plan.md +11 -0
- package/src/roles/planner/commands/plan.md +22 -0
- package/src/roles/planner/workflows/approve-plan.md +970 -0
- package/src/roles/planner/workflows/plan.md +868 -0
- package/src/roles/reviewer/commands/logs.md +7 -0
- package/src/roles/reviewer/commands/review.md +9 -0
- package/src/roles/reviewer/commands/status.md +9 -0
- package/src/roles/reviewer/workflows/logs.md +109 -0
- package/src/roles/reviewer/workflows/review.md +197 -0
- package/src/roles/reviewer/workflows/status.md +142 -0
- package/src/roles/roles.test.ts +87 -0
- package/src/roles/setup/commands/doctor.md +7 -0
- package/src/roles/setup/commands/help.md +80 -0
- package/src/roles/setup/commands/init.md +7 -0
- package/src/roles/setup/commands/map-codebase.md +17 -0
- package/src/roles/setup/commands/settings.md +7 -0
- package/src/roles/setup/commands/uninstall.md +5 -0
- package/src/roles/setup/commands/update-docs.md +9 -0
- package/src/roles/setup/commands/update.md +13 -0
- package/src/roles/setup/workflows/doctor.md +131 -0
- package/src/roles/setup/workflows/init.md +1096 -0
- package/src/roles/setup/workflows/map-codebase.md +130 -0
- package/src/roles/setup/workflows/scaffold.md +872 -0
- package/src/roles/setup/workflows/settings.md +958 -0
- package/src/roles/setup/workflows/uninstall.md +170 -0
- package/src/roles/setup/workflows/update-docs.md +95 -0
- package/src/roles/setup/workflows/update.md +287 -0
- package/src/roles/strategist/commands/approve-brief.md +23 -0
- package/src/roles/strategist/commands/brief.md +29 -0
- package/src/roles/strategist/workflows/approve-brief.md +1540 -0
- package/src/roles/strategist/workflows/brief.md +1330 -0
- package/src/templates/CLAUDE.md +101 -0
- package/src/templates/templates.test.ts +53 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
<!-- clancy:start -->
|
|
2
|
+
|
|
3
|
+
## Clancy
|
|
4
|
+
|
|
5
|
+
This project uses Clancy for autonomous ticket-driven development.
|
|
6
|
+
|
|
7
|
+
### Version check
|
|
8
|
+
|
|
9
|
+
At the start of each session, read `~/.claude/cache/clancy-update-check.json` (use the Read tool). If it exists and `update_available` is true, display exactly:
|
|
10
|
+
`⚠ Clancy update available: v{installed} → v{latest}. Run /clancy:update to upgrade.`
|
|
11
|
+
Then continue normally. If the file is missing or unreadable, continue silently.
|
|
12
|
+
|
|
13
|
+
### Stale brief check
|
|
14
|
+
|
|
15
|
+
At the start of each session, read `.clancy/.brief-stale-count` (use the Read tool). If it exists and contains a number greater than 0, display exactly:
|
|
16
|
+
`⚠ {N} unapproved brief(s) older than 7 days. Run /clancy:approve-brief to review them.`
|
|
17
|
+
Then continue normally. If the file is missing or unreadable, continue silently.
|
|
18
|
+
|
|
19
|
+
### Docs
|
|
20
|
+
|
|
21
|
+
Before every run, read these core docs from `.clancy/docs/`:
|
|
22
|
+
|
|
23
|
+
- STACK.md — tech stack and dependencies
|
|
24
|
+
- ARCHITECTURE.md — system design and data flow
|
|
25
|
+
- CONVENTIONS.md — code style and patterns
|
|
26
|
+
- GIT.md — branching, commit format, merge strategy
|
|
27
|
+
- DEFINITION-OF-DONE.md — checklist before marking a ticket complete
|
|
28
|
+
- CONCERNS.md — known risks, tech debt, things to avoid
|
|
29
|
+
|
|
30
|
+
Also read these if relevant to the ticket:
|
|
31
|
+
|
|
32
|
+
- INTEGRATIONS.md — if the ticket touches external APIs, services, or authentication
|
|
33
|
+
- TESTING.md — if the ticket involves tests, specs, or coverage requirements
|
|
34
|
+
- DESIGN-SYSTEM.md — if the ticket touches UI, components, styles, or visual design
|
|
35
|
+
- ACCESSIBILITY.md — if the ticket touches accessibility, ARIA, or WCAG requirements
|
|
36
|
+
|
|
37
|
+
### Executability check
|
|
38
|
+
|
|
39
|
+
Before any git operation, branch creation, or code change — assess whether this ticket can be implemented entirely as a code change committed to this repo.
|
|
40
|
+
|
|
41
|
+
**Skip the ticket** if it primarily requires any of the following — Clancy cannot do these:
|
|
42
|
+
|
|
43
|
+
- **External system admin:** work in Google Analytics, Salesforce, HubSpot, the AWS console, app store dashboards, or any external platform not accessible through code
|
|
44
|
+
- **Human process steps:** getting sign-off or approval, sending emails to customers, coordinating with people, scheduling meetings, making announcements to users
|
|
45
|
+
- **Non-repo production ops:** deploying to production, rotating secrets in prod, scaling infrastructure — unless the task is purely about editing CI/CD config files that live in this repo
|
|
46
|
+
- **Non-code deliverables:** writing runbooks, updating Confluence or wikis, creating presentations, documenting in external tools
|
|
47
|
+
|
|
48
|
+
When in doubt: "Is the primary deliverable a code change committed to this repo?" — if yes, implement it; if no, skip it.
|
|
49
|
+
|
|
50
|
+
**If skipping, do all four of these in order:**
|
|
51
|
+
|
|
52
|
+
1. Output this exact line: `⚠ Skipping [TICKET-KEY]: {one-line reason}`
|
|
53
|
+
2. Output this exact line: `Ticket skipped — update it to be codebase-only work, then re-run.`
|
|
54
|
+
3. Append to `.clancy/progress.txt`: `YYYY-MM-DD HH:MM | TICKET-KEY | SKIPPED | {reason}`
|
|
55
|
+
4. Stop. No branches, no file changes, no git operations.
|
|
56
|
+
|
|
57
|
+
**If the ticket is codebase work**, proceed to implementation normally.
|
|
58
|
+
|
|
59
|
+
### Git workflow
|
|
60
|
+
|
|
61
|
+
- Read GIT.md before every run — follow its conventions exactly
|
|
62
|
+
- Default (if GIT.md is silent): one feature branch per ticket `feature/{ticket-key-lowercase}`, push and create a PR, conventional commits `feat(TICKET-123): summary`
|
|
63
|
+
- Target branch is auto-detected from the ticket: if it has a parent epic, PR targets `epic/{epic-key}` (created from `CLANCY_BASE_BRANCH` if it doesn't exist); otherwise PR targets `CLANCY_BASE_BRANCH` directly
|
|
64
|
+
|
|
65
|
+
### Progress
|
|
66
|
+
|
|
67
|
+
Log completed tickets to `.clancy/progress.txt`:
|
|
68
|
+
`YYYY-MM-DD HH:MM | TICKET-KEY | Summary | DONE`
|
|
69
|
+
|
|
70
|
+
Planning entries use: `YYYY-MM-DD HH:MM | TICKET-KEY | PLAN | S/M/L`
|
|
71
|
+
Revised plan entries use: `YYYY-MM-DD HH:MM | TICKET-KEY | REVISED | S/M/L`
|
|
72
|
+
Plan approval entries use: `YYYY-MM-DD HH:MM | TICKET-KEY | APPROVE_PLAN | —`
|
|
73
|
+
Brief entries use: `YYYY-MM-DD HH:MM | BRIEF | {slug} | {N} proposed tickets`
|
|
74
|
+
Brief approval entries use: `YYYY-MM-DD HH:MM | APPROVE_BRIEF | {slug} | {N} tickets created`
|
|
75
|
+
Failed comment posts use: `YYYY-MM-DD HH:MM | TICKET-KEY | POST_FAILED | {reason}`
|
|
76
|
+
|
|
77
|
+
### Design context
|
|
78
|
+
|
|
79
|
+
When a ticket description contains a Figma URL, fetch design context before implementing.
|
|
80
|
+
Use the three-tier approach in order:
|
|
81
|
+
|
|
82
|
+
1. Figma MCP: get_metadata → targeted get_design_context → get_screenshot (3 calls, best quality)
|
|
83
|
+
2. Figma REST API image export: parse file key + node ID from URL, fetch rendered PNG as vision input
|
|
84
|
+
3. Ticket image attachment: use any image attached to the ticket description as vision input
|
|
85
|
+
Fetch once only — never return to Figma mid-session.
|
|
86
|
+
Map all token values to CSS custom properties. Never use raw SVGs or hardcoded colours.
|
|
87
|
+
Figma URL must come from the ticket description only — never from CLAUDE.md or other docs.
|
|
88
|
+
|
|
89
|
+
### Visual checks
|
|
90
|
+
|
|
91
|
+
After implementing a UI ticket, run a visual check before committing.
|
|
92
|
+
Read `.clancy/docs/PLAYWRIGHT.md` for the authoritative Playwright configuration (which server to use: Storybook or dev server). Use `.clancy/.env` only for ports and start commands as needed.
|
|
93
|
+
Apply the decision rule against this ticket's description — route/page/screen/layout → dev server,
|
|
94
|
+
component/atom/molecule/organism/variant/story → Storybook, ambiguous → dev server default.
|
|
95
|
+
Start the server using health check polling (not sleep). Navigate to the relevant route or story.
|
|
96
|
+
Screenshot, assess visually, check console. Fix before committing if anything looks wrong.
|
|
97
|
+
If a Figma design was fetched for this ticket, compare the screenshot directly against it — check layout, spacing, colours, typography, and component fidelity. Treat the Figma design as the source of truth.
|
|
98
|
+
Kill by PID then sweep the port unconditionally — never leave a port open.
|
|
99
|
+
Log result: YYYY-MM-DD HH:MM | TICKET-KEY | PLAYWRIGHT_PASS|FAIL | server-used
|
|
100
|
+
|
|
101
|
+
<!-- clancy:end -->
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural tests for the CLAUDE.md template.
|
|
3
|
+
*
|
|
4
|
+
* Verifies the template file exists, has the expected markers, and
|
|
5
|
+
* contains the key sections that the installer merges into user projects.
|
|
6
|
+
*/
|
|
7
|
+
import { readdirSync, readFileSync } from 'node:fs';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
|
|
10
|
+
import { describe, expect, it } from 'vitest';
|
|
11
|
+
|
|
12
|
+
const TEMPLATES_DIR = fileURLToPath(new URL('.', import.meta.url));
|
|
13
|
+
|
|
14
|
+
describe('templates directory structure', () => {
|
|
15
|
+
it('contains exactly CLAUDE.md', () => {
|
|
16
|
+
const files = readdirSync(TEMPLATES_DIR).filter((f) => f.endsWith('.md'));
|
|
17
|
+
|
|
18
|
+
expect(files).toEqual(['CLAUDE.md']);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('CLAUDE.md template', () => {
|
|
23
|
+
const content = readFileSync(new URL('CLAUDE.md', import.meta.url), 'utf8');
|
|
24
|
+
|
|
25
|
+
it('has clancy:start and clancy:end markers', () => {
|
|
26
|
+
expect(content).toContain('<!-- clancy:start -->');
|
|
27
|
+
expect(content).toContain('<!-- clancy:end -->');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('starts with clancy:start and ends with clancy:end', () => {
|
|
31
|
+
const trimmed = content.trim();
|
|
32
|
+
|
|
33
|
+
expect(trimmed.startsWith('<!-- clancy:start -->')).toBe(true);
|
|
34
|
+
expect(trimmed.endsWith('<!-- clancy:end -->')).toBe(true);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('contains required sections', () => {
|
|
38
|
+
const requiredSections = [
|
|
39
|
+
'### Version check',
|
|
40
|
+
'### Stale brief check',
|
|
41
|
+
'### Docs',
|
|
42
|
+
'### Executability check',
|
|
43
|
+
'### Git workflow',
|
|
44
|
+
'### Progress',
|
|
45
|
+
'### Design context',
|
|
46
|
+
'### Visual checks',
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
requiredSections.forEach((section) => {
|
|
50
|
+
expect(content).toContain(section);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
});
|