@ericrisco/rsc 0.1.44 → 0.1.45
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/README.md +1 -1
- package/manifest.json +110 -86
- package/package.json +1 -1
- package/scripts/lib/domains.js +1 -1
- package/scripts/skill-migration-brief.md +104 -0
- package/skills/ab-testing/SKILL.md +9 -41
- package/skills/accessibility/SKILL.md +5 -7
- package/skills/ads/SKILL.md +9 -24
- package/skills/agent-eval/SKILL.md +7 -33
- package/skills/agent-safety/SKILL.md +7 -14
- package/skills/ai-media/SKILL.md +4 -20
- package/skills/analytics/SKILL.md +8 -30
- package/skills/analyze/SKILL.md +24 -59
- package/skills/angular/SKILL.md +12 -25
- package/skills/api-connector-builder/SKILL.md +10 -27
- package/skills/api-design/SKILL.md +7 -14
- package/skills/article-writing/SKILL.md +1 -18
- package/skills/astro/SKILL.md +36 -54
- package/skills/author-skill/SKILL.md +41 -74
- package/skills/author-skill/evals/README.md +5 -5
- package/skills/author-skill/evals/cases.yaml +8 -8
- package/skills/author-skill/references/description-recipe.md +25 -26
- package/skills/author-skill/references/eval-authoring.md +1 -1
- package/skills/author-skill/references/rsc-conventions.md +1 -1
- package/skills/automation-flows/SKILL.md +6 -16
- package/skills/automation-strategy/SKILL.md +1 -9
- package/skills/aws-essentials/SKILL.md +6 -23
- package/skills/backups/SKILL.md +1 -7
- package/skills/bash-scripting/SKILL.md +5 -9
- package/skills/bookkeeping/SKILL.md +2 -10
- package/skills/brand-identity/SKILL.md +18 -44
- package/skills/brand-voice/SKILL.md +4 -31
- package/skills/building-agents/SKILL.md +20 -103
- package/skills/business-intelligence/SKILL.md +9 -23
- package/skills/calendar-scheduling/SKILL.md +11 -27
- package/skills/case-studies/SKILL.md +3 -8
- package/skills/chatbot/SKILL.md +6 -23
- package/skills/chrome-extension/SKILL.md +2 -2
- package/skills/clarify/SKILL.md +31 -72
- package/skills/clickhouse-analytics/SKILL.md +2 -8
- package/skills/client-onboarding/SKILL.md +17 -19
- package/skills/cloudflare/SKILL.md +3 -8
- package/skills/code-review/SKILL.md +10 -23
- package/skills/codebase-onboarding/SKILL.md +2 -7
- package/skills/cold-outreach/SKILL.md +9 -30
- package/skills/community/SKILL.md +4 -31
- package/skills/competitor-watch/SKILL.md +20 -35
- package/skills/compliance/SKILL.md +10 -37
- package/skills/compose-multiplatform/SKILL.md +1 -1
- package/skills/constitution/SKILL.md +8 -35
- package/skills/content-engine/SKILL.md +4 -16
- package/skills/context-budget/SKILL.md +3 -21
- package/skills/continuous-learning/SKILL.md +10 -40
- package/skills/contracts/SKILL.md +6 -17
- package/skills/coolify/SKILL.md +8 -14
- package/skills/cost-tracking/SKILL.md +3 -11
- package/skills/course-builder/SKILL.md +17 -45
- package/skills/course-storytelling/SKILL.md +26 -94
- package/skills/cpp/SKILL.md +26 -71
- package/skills/csharp-dotnet/SKILL.md +19 -38
- package/skills/customer-support/SKILL.md +14 -37
- package/skills/dashboard/SKILL.md +6 -26
- package/skills/data-cleaning/SKILL.md +37 -63
- package/skills/data-policy/SKILL.md +8 -21
- package/skills/data-scraper/SKILL.md +1 -7
- package/skills/debug/SKILL.md +10 -49
- package/skills/deployment/SKILL.md +38 -101
- package/skills/design/SKILL.md +34 -116
- package/skills/fable-operator/SKILL.md +1 -4
- package/skills/fastapi/SKILL.md +50 -82
- package/skills/flutter/SKILL.md +41 -89
- package/skills/go/SKILL.md +57 -105
- package/skills/harness/SKILL.md +52 -68
- package/skills/implement/SKILL.md +1 -1
- package/skills/init/SKILL.md +152 -168
- package/skills/marketing/SKILL.md +30 -80
- package/skills/nextjs/SKILL.md +42 -116
- package/skills/orient/SKILL.md +25 -20
- package/skills/parallel/SKILL.md +9 -75
- package/skills/plan/SKILL.md +92 -165
- package/skills/postgresdb/SKILL.md +52 -72
- package/skills/presentations/SKILL.md +49 -87
- package/skills/python/SKILL.md +23 -72
- package/skills/react/SKILL.md +19 -67
- package/skills/review/SKILL.md +22 -52
- package/skills/rust/SKILL.md +40 -115
- package/skills/sdd-init/SKILL.md +9 -14
- package/skills/secure-coding/SKILL.md +80 -109
- package/skills/ship/SKILL.md +25 -55
- package/skills/tasks/SKILL.md +37 -61
- package/skills/typescript/SKILL.md +22 -55
- package/skills/verify/SKILL.md +8 -32
- package/skills/viral-score/SKILL.md +122 -0
- package/skills/viral-score/evals/README.md +16 -0
- package/skills/viral-score/evals/cases.yaml +50 -0
- package/skills/vue-nuxt/SKILL.md +45 -106
- package/skills/worktrees/SKILL.md +24 -69
package/skills/analyze/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: analyze
|
|
3
|
-
description: "Use when
|
|
3
|
+
description: "Use when constitution, spec, plan and tasks all exist and you want them cross-read against each other before any code is written — the rsc-sdd pre-implementation gate. Reports coverage gaps, contradictions, duplication, ambiguity and scope drift; edits nothing. NOT the task breakdown (that is `tasks`), NOT the coding (that is `implement`), NOT the post-code test gate (that is `verify`), NOT resolving ambiguity (that is `clarify`)."
|
|
4
4
|
tags: [sdd, analyze, consistency]
|
|
5
5
|
recommends: [implement]
|
|
6
6
|
profiles: [core, full]
|
|
@@ -9,51 +9,26 @@ origin: risco
|
|
|
9
9
|
|
|
10
10
|
# Analyze — the pre-implementation consistency gate
|
|
11
11
|
|
|
12
|
-
You have a **constitution**, a **spec**, a **plan** and a **task list**. Four artifacts written at four different moments, by a mind that drifted a little each time. `analyze`
|
|
12
|
+
You have a **constitution**, a **spec**, a **plan** and a **task list**. Four artifacts written at four different moments, by a mind that drifted a little each time. `analyze` reads all four *against each other* and surfaces where they disagree. It is the cheapest place in the whole chain to catch a problem — a contradiction found here costs a sentence; the same contradiction found mid-implement costs a rewrite.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Sixth phase of the rsc-sdd chain (`constitution → specify → clarify → plan → tasks → analyze → implement`); the method itself lives in `../sdd/SKILL.md`. It is a **gate, not a worker**: it produces a report and stops. The user reads the findings and decides what to fix, and which phase to send each fix back to.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
**Report only. Resolve nothing.** Never edit the constitution, spec, plan or tasks; never open a code file to "just fix it"; never silently reconcile a contradiction by picking a side. This one is absolute because a gate that quietly fixes things stops being a gate: the user never learns the spec was wrong, the plan built on the old assumption stays stale, and the "consistency check" has manufactured a new inconsistency. Name the conflict, show both sides with locations, propose where it should be resolved, hand the decision back.
|
|
17
17
|
|
|
18
|
-
**
|
|
18
|
+
**Model tier: `heavy`** (adversarial cross-reading). Resolve and apply it per `../sdd/references/model-routing.md`; routing is off unless `models.enabled: true` in `02-DOCS/wiki/sdd/config.yaml`.
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
**Accompaniment dial.** Read `02-DOCS/wiki/harness/user-profile.md` before reporting — default to **L2** and say the harness has not gauged the user yet if there is no profile. The dial flexes how the report reads, never what gets checked; the six analyses always run in full.
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
- Implementation stalled because the artifacts seem to contradict each other.
|
|
29
|
-
- You want a requirements-coverage map: which task satisfies which spec requirement, and what is orphaned.
|
|
30
|
-
|
|
31
|
-
Do NOT use when (route elsewhere):
|
|
32
|
-
|
|
33
|
-
- A single spec is fuzzy and you need to ask the user questions and bake answers in → `clarify` (analyze reports the ambiguity; clarify resolves it).
|
|
34
|
-
- The plan or tasks don't exist yet → write them first (`plan`, then `tasks`).
|
|
35
|
-
- You want to run lint/types/tests/acceptance after coding → `verify` (post-implementation gate; analyze is pre-implementation).
|
|
36
|
-
- A test is failing or behavior is wrong → `debug`.
|
|
37
|
-
- You intend to fix what you find right now → that is `implement`/`clarify`/`plan`/`tasks` work, not analyze. Analyze only reports.
|
|
38
|
-
|
|
39
|
-
## Model tier — `heavy` (opt-in routing)
|
|
40
|
-
|
|
41
|
-
This phase's default model tier is **`heavy`** — it is the adversarial consistency gate across constitution ↔ spec ↔ plan ↔ tasks. Routing is **off** unless `models.enabled: true` in `02-DOCS/wiki/sdd/config.yaml`. When on: resolve this phase's tier (`models.overrides` wins over `models.phases`), map it to a model via `models.tiers`, and apply per `../sdd/references/model-routing.md` — announce the switch per the accompaniment dial when it differs from the session model, and dispatch any `Task`/`parallel` subagents on that model. Routing off or no profile → honor the session model silently. Never fake a switch a tool can't make; skip routing on a one-line change.
|
|
42
|
-
|
|
43
|
-
## Read the accompaniment dial first
|
|
44
|
-
|
|
45
|
-
Before reporting, read `02-DOCS/wiki/harness/user-profile.md` for the technical + accompaniment level (the harness dial, L0..L3). It shapes how the report reads — not what gets checked. The six analyses always run in full; verbosity flexes:
|
|
46
|
-
|
|
47
|
-
- **L0** — the finding table only: severity, the two artifacts, the conflict in one line. No prose.
|
|
48
|
-
- **L1** — the table plus a one-line *why it matters* per CRITICAL/HIGH finding.
|
|
49
|
-
- **L2** — the table plus, per finding, the recommended resolution phase and the trade-off of leaving it.
|
|
50
|
-
- **L3** — full walk-through: for each finding, quote both sides, explain the consequence at implement time in plain language, and lay out the options so a non-technical user can choose.
|
|
51
|
-
|
|
52
|
-
If no profile exists, default to L2 and note that the harness has not gauged the user yet.
|
|
22
|
+
| Dial | The report renders as |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| L0 | Finding table only: severity, the two artifacts, the conflict in one line. No prose. |
|
|
25
|
+
| L1 | + a one-line *why it matters* per CRITICAL/HIGH finding. |
|
|
26
|
+
| L2 | + per finding, the recommended resolution phase and the trade-off of leaving it. |
|
|
27
|
+
| L3 | + full walk-through: quote both sides, explain the consequence at implement time in plain language, lay out the options so a non-technical user can choose. |
|
|
53
28
|
|
|
54
29
|
## Inputs — locate the four artifacts
|
|
55
30
|
|
|
56
|
-
Read all four before analyzing. The rsc-sdd artifacts live under `02-DOCS/wiki/sdd
|
|
31
|
+
Read all four before analyzing. The rsc-sdd artifacts live under `02-DOCS/wiki/sdd/`, indexed from `02-DOCS/wiki/index.md` (the Knowledge map; root `CLAUDE.md` keeps only a short pointer to it):
|
|
57
32
|
|
|
58
33
|
| Artifact | Canonical location | Role in the check |
|
|
59
34
|
| --- | --- | --- |
|
|
@@ -110,32 +85,22 @@ Produce a single consistency report:
|
|
|
110
85
|
1. **Verdict line** — `GATE: PASS` (zero CRITICAL/HIGH) or `GATE: BLOCKED` (one or more CRITICAL/HIGH), with the counts.
|
|
111
86
|
2. **Coverage map** — the table above.
|
|
112
87
|
3. **Findings table** — `# | Severity | Type | Artifact A (loc) | Artifact B (loc) | Conflict | Resolve in (phase)`.
|
|
113
|
-
4. **Recommended routing** — group fixes by the phase that owns them (`clarify` for spec ambiguity, `plan` for missing architecture, `tasks` for a missing done-check, `constitution` if a principle itself is wrong).
|
|
88
|
+
4. **Recommended routing** — group fixes by the phase that owns them (`clarify` for spec ambiguity, `plan` for missing architecture, `tasks` for a missing done-check, `constitution` if a principle itself is wrong). If findings pour in across all six checks, the artifacts diverged badly — recommend re-running `clarify`/`plan` before a line-by-line analyze is even useful.
|
|
114
89
|
|
|
115
|
-
Write the report to `02-DOCS/wiki/sdd/analysis/<slug>.md` (create the dir if absent) and index it in `02-DOCS/wiki/index.md`
|
|
90
|
+
Write the report to `02-DOCS/wiki/sdd/analysis/<slug>.md` (create the dir if absent) and index it in `02-DOCS/wiki/index.md` under the `sdd/` topic, so the next phase and the harness can find it. It is an OKF v0.1 wiki article: open it with YAML frontmatter carrying a non-empty `type:` (use `type: analysis`), a `timestamp` in ISO 8601, and standard markdown links — never wikilinks. The report is the artifact analyze owns — it is the *only* thing analyze writes. Per-run point-in-time; overwrite on re-run, the wiki keeps history.
|
|
116
91
|
|
|
117
|
-
|
|
92
|
+
Render it at the dial's verbosity. Do not log a decision to `decisions.md` — analyze decides nothing; the phase that resolves the finding logs its own decision.
|
|
118
93
|
|
|
119
|
-
## Anti-patterns
|
|
94
|
+
## Anti-patterns
|
|
120
95
|
|
|
121
|
-
|
|
|
96
|
+
| Anti-pattern | Why it breaks the gate / do instead |
|
|
122
97
|
| --- | --- |
|
|
123
|
-
|
|
|
124
|
-
|
|
|
125
|
-
|
|
|
126
|
-
|
|
|
127
|
-
|
|
|
128
|
-
| "I'll fold the findings straight into the task list to save a step" | No. Editing tasks is the `tasks` phase. Report, route, hand back. |
|
|
129
|
-
| "Constitution says Postgres but plan picked Mongo for good reasons — I'll side with the plan" | The constitution wins by definition. Flag CRITICAL. If the principle is wrong, that is a `constitution` change the user makes, not a quiet override here. |
|
|
130
|
-
| "I read the spec and tasks; the constitution is boilerplate, skip it" | The constitution is analysis #1 and the highest severity. Never skip it. |
|
|
131
|
-
|
|
132
|
-
## Red flags — stop and report instead of analyzing
|
|
133
|
-
|
|
134
|
-
- An artifact is missing (no plan, no tasks) → say which, name the phase, do not fabricate it.
|
|
135
|
-
- Multiple specs match the slug → ask which feature; don't analyze the wrong one.
|
|
136
|
-
- You catch yourself opening a source file → you have left the gate; close it.
|
|
137
|
-
- Findings are pouring in across all six checks → the artifacts diverged badly; recommend the user re-runs `clarify`/`plan` before a line-by-line analyze is even useful.
|
|
98
|
+
| Fixing a "trivial" contradiction in the spec yourself | Then you are `clarify`/`plan`/`tasks`, not `analyze`. Report it; the user resolves. |
|
|
99
|
+
| Starting to code because nothing CRITICAL turned up | Analyze never transitions to code. Hand the verdict to `implement`; that phase starts the work. |
|
|
100
|
+
| Waving through plan work the spec never asked for because it's obviously a good idea | That is DRIFT. Flag it. Good ideas still need the spec amended (user's call), or they are silent scope creep. |
|
|
101
|
+
| Siding with the plan when it contradicts the constitution | The constitution wins by definition — flag CRITICAL. If the principle itself is wrong, that is a `constitution` change the user makes, not a quiet override here. |
|
|
102
|
+
| Guessing what a vague requirement meant | Guessing defeats the gate. Mark AMBIGUOUS and route to `clarify`; do not encode your guess. |
|
|
138
103
|
|
|
139
104
|
## Next in the chain
|
|
140
105
|
|
|
141
|
-
|
|
106
|
+
On `GATE: PASS` (or once the user consciously accepts the remaining MEDIUM/LOW findings), proceed to **`implement`** — execute the tasks with TDD discipline, delegating concrete test tooling to the relevant stack skill (`fastapi`, `nextjs`, `go`, `flutter`, `postgresdb`). On `GATE: BLOCKED`, route each CRITICAL/HIGH finding to its owning phase (`clarify`, `plan`, `tasks`, or `constitution`), let the user resolve, then re-run `analyze`. The gate only opens once.
|
package/skills/angular/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: angular
|
|
3
|
-
description: "Use when building, refactoring,
|
|
3
|
+
description: "Use when building, refactoring, or debugging Angular (v20/21+): standalone components, signals, zoneless change detection, @if/@for/@defer control flow, inject() DI, resource()/httpResource(), RxJS interop, NgRx SignalStore, ng CLI. NOT React (that is react), NOT Next.js (that is nextjs), NOT a TypeScript language question (that is typescript)."
|
|
4
4
|
tags: [angular, frontend, web, signals, typescript, spa]
|
|
5
5
|
recommends: [typescript, testing-web, secure-coding]
|
|
6
6
|
origin: risco
|
|
@@ -10,31 +10,23 @@ origin: risco
|
|
|
10
10
|
|
|
11
11
|
> Build Angular the way it ships in 2026: standalone components, signals as the reactivity model, zoneless change detection, built-in control flow, and `inject()` DI. Treat NgModules, `*ngFor`, and `@Input()` decorators as legacy you only touch to migrate.
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## Not this skill
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
- **AngularJS (1.x)** — out of scope entirely. This skill is Angular 2+ only; the APIs do not map.
|
|
25
|
-
- **React** → that is the `react` skill. NOT React (that is react).
|
|
26
|
-
- **Next.js App Router** → `../nextjs/SKILL.md`.
|
|
27
|
-
- **Vue/Nuxt, Svelte, SolidJS, Astro** → `vue-nuxt`, `svelte`, `solid-js`, `../astro/SKILL.md`.
|
|
28
|
-
- **Pure TypeScript language question** (generics, narrowing, tsconfig) with no Angular dimension → `../typescript/SKILL.md`.
|
|
29
|
-
- **A standalone NestJS API** → `../nestjs/SKILL.md`. A generic Node service → `nodejs`. Angular Universal SSR itself stays here.
|
|
30
|
-
- **Cross-framework Playwright e2e strategy** → `testing-web` / `e2e-testing`. Angular's own `ng test` (Vitest) setup stays here.
|
|
15
|
+
**AngularJS (1.x)** is out of scope entirely — this skill is Angular 2+ only and the APIs do not map.
|
|
16
|
+
Route elsewhere for **React** → `../react/SKILL.md`; **Next.js App Router** → `../nextjs/SKILL.md`;
|
|
17
|
+
**Vue/Nuxt, Svelte, SolidJS, Astro** → `../vue-nuxt/SKILL.md`, `../svelte/SKILL.md`,
|
|
18
|
+
`../solid-js/SKILL.md`, `../astro/SKILL.md`; a **pure TypeScript language question** (generics,
|
|
19
|
+
narrowing, tsconfig) with no Angular dimension → `../typescript/SKILL.md`; a **standalone NestJS
|
|
20
|
+
API** → `../nestjs/SKILL.md`; a generic Node service → `../nodejs/SKILL.md`; **cross-framework
|
|
21
|
+
Playwright e2e strategy** → `../testing-web/SKILL.md` / `../e2e-testing/SKILL.md`. Angular Universal
|
|
22
|
+
SSR and Angular's own `ng test` (Vitest) setup stay here.
|
|
31
23
|
|
|
32
24
|
## Decide first
|
|
33
25
|
|
|
34
26
|
| Situation | Do this | Why |
|
|
35
27
|
|-----------|---------|-----|
|
|
36
28
|
| Greenfield app / new feature | Zoneless + signals + standalone by default. `ng new` (Angular 21) already excludes Zone.js. | The defaults shipped stable in v20-v21; fight them and you write more code that the framework now does for you. |
|
|
37
|
-
| Brownfield NgModule + decorator app | Migrate incrementally with schematics; do not rewrite. Keep Zone.js until you flip it on purpose. | A working app that uses `*ngIf` is not a bug. Churn introduces risk for no user value. |
|
|
29
|
+
| Brownfield NgModule + decorator app | Migrate incrementally with the schematics in `references/migration.md` (NgModule→standalone, control flow, decorator→signal inputs, Zone.js→zoneless, Karma→Vitest); do not rewrite. Keep Zone.js until you flip it on purpose. | A working app that uses `*ngIf` is not a bug. Churn introduces risk for no user value. |
|
|
38
30
|
| "View not updating" complaint | Jump to the change-detection section: signal not read in template, `OnPush` without a signal, or stale Zone.js assumption. | Zoneless means a mutation that no signal observes will never repaint — the fix is structural, not a `detectChanges()` call. |
|
|
39
31
|
|
|
40
32
|
## The modern baseline
|
|
@@ -178,7 +170,7 @@ profile = resource({
|
|
|
178
170
|
```
|
|
179
171
|
|
|
180
172
|
- Rule: `httpResource()`/`resource()` give you `value()`, `isLoading()`, `error()`, `reload()` for free — prefer them over a manual `subscribe` that you have to clean up. Why: less boilerplate, no leak, refetches automatically when its source signals change.
|
|
181
|
-
- Rule: when you genuinely need a stream (websocket, debounced search, retry/switchMap), keep `HttpClient` + RxJS and bridge to a signal with `toSignal()`. Why: signals are not streams; do not fake backpressure with effects.
|
|
173
|
+
- Rule: when you genuinely need a stream (websocket, debounced search, retry/switchMap), keep `HttpClient` + RxJS and bridge to a signal with `toSignal()`. Why: signals are not streams; do not fake backpressure with effects. `references/signals-rxjs.md` has the signals-vs-RxJS decision matrix, `toSignal`/`toObservable` interop recipes, `effect` pitfalls (infinite loops, untracked reads), and `takeUntilDestroyed`.
|
|
182
174
|
|
|
183
175
|
## DI & services
|
|
184
176
|
|
|
@@ -280,9 +272,4 @@ it('renders the user name', async () => {
|
|
|
280
272
|
| Nested `subscribe()` inside `subscribe()` | Callback pyramid, lost cancellation | `switchMap`/`concatMap`, one subscription |
|
|
281
273
|
| Constructor DI only (`constructor(private x: X)`) | Legacy ergonomic; can't compose into functions | `private x = inject(X)` |
|
|
282
274
|
|
|
283
|
-
## References
|
|
284
|
-
|
|
285
|
-
- `references/signals-rxjs.md` — signals-vs-RxJS decision matrix, `toSignal`/`toObservable` interop recipes, `effect` pitfalls (infinite loops, untracked reads), `linkedSignal`/`resource()` patterns, `takeUntilDestroyed`.
|
|
286
|
-
- `references/migration.md` — incremental migration checklist + schematics: NgModule→standalone, control-flow migration, decorator-input→signal-input, Zone.js→zoneless go-live, Karma/Jasmine→Vitest.
|
|
287
|
-
|
|
288
275
|
`scripts/verify.sh` is a heuristic copy-banlist lint — it greps your Angular sources for the banned patterns above. It is a hint, not a compiler.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: api-connector-builder
|
|
3
|
-
description: "Use when writing a client
|
|
3
|
+
description: "Use when writing a client for someone else's REST or GraphQL API: auth flow choice and token refresh, pagination to exhaustion, retry-with-jitter on transient failures only, rate-limit-aware throttling. NOT inbound callbacks (that is `webhooks`), NOT chaining services (that is `automation-flows`), NOT designing your own API (that is `api-design`)."
|
|
4
4
|
tags: [api, rest, graphql, oauth, pagination, retries, rate-limiting, http-client, connector]
|
|
5
5
|
recommends: [webhooks, automation-flows, api-design, data-scraper, secure-coding, error-handling, structured-extraction]
|
|
6
6
|
origin: risco
|
|
@@ -12,31 +12,18 @@ You are writing a client for **someone else's** HTTP API. You do not own the
|
|
|
12
12
|
contract; you obey it. The deliverable is one typed connector module per vendor
|
|
13
13
|
that authenticates, walks the whole result set, retries only transient failures
|
|
14
14
|
with backoff, and stays under the rate limit without getting the key banned.
|
|
15
|
+
One connector = one vendor: mixed clients tangle two auth schemes and two
|
|
16
|
+
rate-limit budgets into something no one can reason about.
|
|
15
17
|
|
|
16
18
|
Four pillars, every time: **auth, pagination, retries, rate limits.** If your
|
|
17
19
|
connector skips any one of them it works in the demo and breaks in production —
|
|
18
20
|
on page 2, on token expiry, on the first 429, or on a flaky network.
|
|
19
21
|
|
|
20
|
-
This skill goes **outbound** (you call them). Receiving their callbacks is the
|
|
21
|
-
inverse and lives in `webhooks`.
|
|
22
|
-
|
|
23
|
-
## Operating posture
|
|
24
|
-
|
|
25
|
-
- **Read the vendor docs before writing a line.** Invented endpoints and guessed
|
|
26
|
-
field names 404 in prod. Find the real base URL, version, and error envelope.
|
|
27
|
-
- **Secrets come from env or a secret store, never source.** Hardcoded keys leak
|
|
28
|
-
through git history and screenshots and you cannot rotate them cleanly.
|
|
29
|
-
- **One connector = one vendor.** Mixed clients tangle two auth schemes and two
|
|
30
|
-
rate-limit budgets into one tangle no one can reason about.
|
|
31
|
-
- **Every request gets a timeout.** A hung socket with no timeout stalls the
|
|
32
|
-
whole run forever; the default in most clients is "wait indefinitely".
|
|
33
|
-
- **Log request id + status + attempt, never the token.** Logs get shipped to
|
|
34
|
-
third parties; a logged bearer token is a leaked credential.
|
|
35
|
-
|
|
36
22
|
## Step 0 — read the contract
|
|
37
23
|
|
|
38
|
-
|
|
39
|
-
|
|
24
|
+
Read the vendor docs before writing a line — invented endpoints and guessed
|
|
25
|
+
field names 404 in prod. Extract these first; each one changes what you write,
|
|
26
|
+
so missing one means a rewrite.
|
|
40
27
|
|
|
41
28
|
| Find in their docs | Why it changes your code |
|
|
42
29
|
| ------------------------- | --------------------------------------------------------- |
|
|
@@ -202,8 +189,9 @@ def iter_records(client):
|
|
|
202
189
|
return
|
|
203
190
|
```
|
|
204
191
|
|
|
205
|
-
Full code for every style — offset, keyset, `Link`-header parsing,
|
|
206
|
-
|
|
192
|
+
Full code for every style — offset, keyset, `Link`-header parsing, GraphQL Relay
|
|
193
|
+
connection walking, in Python and TS, plus dedup-on-overlap notes — is in
|
|
194
|
+
`references/pagination.md`.
|
|
207
195
|
|
|
208
196
|
## Putting it together
|
|
209
197
|
|
|
@@ -272,12 +260,7 @@ export async function request(path: string, init: RequestInit = {}, attempt = 0)
|
|
|
272
260
|
| Token in query string | Token ends up in logs / referrers | Bearer in the `Authorization` header |
|
|
273
261
|
| Implicit / password OAuth grant | Removed in OAuth 2.1; insecure | Auth-Code + PKCE, or Client Credentials |
|
|
274
262
|
|
|
275
|
-
##
|
|
276
|
-
|
|
277
|
-
- `references/auth-flows.md` — per-flow walkthroughs, token storage + rotation,
|
|
278
|
-
OAuth 2.1 deltas, RFC 9700 refresh rotation, DPoP note. Python + TS.
|
|
279
|
-
- `references/pagination.md` — full code for offset, cursor/keyset, Link-header,
|
|
280
|
-
and GraphQL Relay walking. Exhaustion-loop and dedup-on-overlap notes.
|
|
263
|
+
## Verify
|
|
281
264
|
|
|
282
265
|
Run `scripts/verify.sh` over the connector you write: it greps for hardcoded
|
|
283
266
|
secrets, asserts a retry mechanism and a pagination loop and a request timeout
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: api-design
|
|
3
|
-
description: "Use when
|
|
3
|
+
description: "Use when settling the contract of an API you expose, before implementation: resources/URLs, REST vs GraphQL, versioning, one RFC 9457 error envelope, pagination, idempotency — emitted as OpenAPI 3.1. NOT implementing the endpoints (that is `fastapi`/`nestjs`/`go`/`nodejs`), NOT auth hardening (that is `secure-coding`), NOT consuming a third-party API (that is `api-connector-builder`)."
|
|
4
4
|
tags: [api-design, rest, graphql, openapi, versioning, pagination, http, rfc9457, contract-design]
|
|
5
5
|
recommends: [fastapi, nestjs, go, nodejs, secure-coding, webhooks, api-connector-builder, code-review]
|
|
6
6
|
origin: risco
|
|
@@ -24,7 +24,7 @@ Pick on traffic shape, not fashion. Decide once, write it down.
|
|
|
24
24
|
| Many client shapes, deep nested graphs, mobile over-fetch is real | **GraphQL** | one round-trip, client picks fields; no N endpoints per screen |
|
|
25
25
|
| Stable resource API + one rich read surface for a client app | **Hybrid** | REST for the system of record, a GraphQL read layer on top |
|
|
26
26
|
|
|
27
|
-
Operational gotcha that decides monitoring: **GraphQL returns HTTP 200 even when a field errored** — failures live in an `errors[]` array next to partial `data`. Your dashboards cannot alert on 5xx; you must alert on the `errors[]` payload. REST signals failure with the HTTP status itself. If your ops team lives on status-code SLOs, that is a point for REST.
|
|
27
|
+
Operational gotcha that decides monitoring: **GraphQL returns HTTP 200 even when a field errored** — failures live in an `errors[]` array next to partial `data`. Your dashboards cannot alert on 5xx; you must alert on the `errors[]` payload. REST signals failure with the HTTP status itself. If your ops team lives on status-code SLOs, that is a point for REST. Schema/nullability design, mutation and error-union conventions, and this error model in full: [`references/graphql-design.md`](references/graphql-design.md).
|
|
28
28
|
|
|
29
29
|
## Resource & URL modeling
|
|
30
30
|
|
|
@@ -44,7 +44,7 @@ Rules, each with its reason:
|
|
|
44
44
|
| `GET /projects/active` | `GET /projects?status=active` | filter is a query param |
|
|
45
45
|
| `POST /projects/{id}/delete` | `DELETE /projects/{id}` | method, not path segment |
|
|
46
46
|
|
|
47
|
-
Full query grammar (filter operators, sparse fieldsets, sort syntax)
|
|
47
|
+
Full query grammar (filter operators, sparse fieldsets, sort syntax), content negotiation, rate-limit headers and a HATEOAS note: [`references/rest-conventions.md`](references/rest-conventions.md).
|
|
48
48
|
|
|
49
49
|
## Status codes that matter
|
|
50
50
|
|
|
@@ -67,7 +67,7 @@ You need a small map, used consistently. Don't overload 200.
|
|
|
67
67
|
|
|
68
68
|
Two distinctions agents get wrong:
|
|
69
69
|
- **401 vs 403** — 401 means *unauthenticated* (no/invalid credentials); 403 means *authenticated but unauthorized*. Returning 401 on a permission failure leaks that re-auth might help when it won't.
|
|
70
|
-
- **409 vs 422** — 409 is a *state* conflict (the request fights the current server state: dup key, stale version). 422 is a *content* problem (the body parses but fails business rules). Full table with when-each in `references/rest-conventions.md
|
|
70
|
+
- **409 vs 422** — 409 is a *state* conflict (the request fights the current server state: dup key, stale version). 422 is a *content* problem (the body parses but fails business rules). Full status-code table with when-each in [`references/rest-conventions.md`](references/rest-conventions.md).
|
|
71
71
|
|
|
72
72
|
## Error envelope: RFC 9457
|
|
73
73
|
|
|
@@ -116,7 +116,7 @@ REST cursor envelope — same keys on every list endpoint:
|
|
|
116
116
|
|
|
117
117
|
The next page is `GET /projects?cursor=eyJpZCI6MTI4N30&limit=50`. The cursor is opaque — clients must not parse or construct it.
|
|
118
118
|
|
|
119
|
-
GraphQL has its own de-facto standard: **Relay Connections** — `edges { node, cursor }`, `pageInfo { hasNextPage, endCursor }`, args `first` / `after`. Use it; don't invent a bespoke GraphQL pagination shape. See `references/graphql-design.md
|
|
119
|
+
GraphQL has its own de-facto standard: **Relay Connections** — `edges { node, cursor }`, `pageInfo { hasNextPage, endCursor }`, args `first` / `after`. Use it; don't invent a bespoke GraphQL pagination shape. See [`references/graphql-design.md`](references/graphql-design.md).
|
|
120
120
|
|
|
121
121
|
## Versioning & evolution
|
|
122
122
|
|
|
@@ -135,7 +135,7 @@ Sunset: Sat, 31 Oct 2026 23:59:59 GMT
|
|
|
135
135
|
Link: <https://api.acme.com/v2/projects>; rel="successor-version"
|
|
136
136
|
```
|
|
137
137
|
|
|
138
|
-
Full breaking-vs-non-breaking matrix and the deprecation workflow
|
|
138
|
+
Full breaking-vs-non-breaking matrix, the three versioning mechanisms and the deprecation/sunset workflow: [`references/versioning-and-evolution.md`](references/versioning-and-evolution.md).
|
|
139
139
|
|
|
140
140
|
## Idempotency & concurrency
|
|
141
141
|
|
|
@@ -167,7 +167,7 @@ Idempotency-Key: 9b1f7c2e-...
|
|
|
167
167
|
|
|
168
168
|
## Handoff
|
|
169
169
|
|
|
170
|
-
The contract is the artifact. Emit it as an **OpenAPI 3.1** document
|
|
170
|
+
The contract is the artifact. Emit it as an **OpenAPI 3.1** document — the checkable deliverable a framework skill generates code from. How to shape it, and what `scripts/verify.sh` checks: [`references/openapi-contract.md`](references/openapi-contract.md).
|
|
171
171
|
|
|
172
172
|
Hand off to the builder:
|
|
173
173
|
- Python/async → [`../fastapi/SKILL.md`](../fastapi/SKILL.md)
|
|
@@ -180,10 +180,3 @@ Adjacent concerns you do **not** own:
|
|
|
180
180
|
- Receiving inbound webhooks (HMAC verify, replay, dedupe) → [`../webhooks/SKILL.md`](../webhooks/SKILL.md)
|
|
181
181
|
- Building an outbound client to a third-party API → [`../api-connector-builder/SKILL.md`](../api-connector-builder/SKILL.md)
|
|
182
182
|
- Reviewing handler code (not the design) → [`../code-review/SKILL.md`](../code-review/SKILL.md)
|
|
183
|
-
|
|
184
|
-
## References
|
|
185
|
-
|
|
186
|
-
- `references/rest-conventions.md` — full status-code table, filter/sort/sparse-fieldset grammar, content negotiation, rate-limit headers, HATEOAS note.
|
|
187
|
-
- `references/versioning-and-evolution.md` — breaking-vs-non-breaking matrix, three versioning mechanisms, deprecation/sunset workflow.
|
|
188
|
-
- `references/graphql-design.md` — schema/nullability design, Relay Connections, mutation + error-union conventions, the HTTP-200 error model and its monitoring impact.
|
|
189
|
-
- `references/openapi-contract.md` — capture the contract as OpenAPI 3.1 so frameworks generate from it; what `scripts/verify.sh` checks.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: article-writing
|
|
3
|
-
description: "Use when
|
|
3
|
+
description: "Use when writing one long-form article end to end — answer-first lede, question-shaped headings, plus its on-page surface (title, meta, slug, FAQ, Article/FAQPage JSON-LD) — or fixing a draft that buries the answer or reads AI-padded. NOT keyword research or topic selection (that is `seo-geo`), NOT the editorial calendar (that is `content-engine`)."
|
|
4
4
|
tags: [article, blog, long-form, seo-writing, geo, on-page, eeat, copywriting]
|
|
5
5
|
recommends: [seo-geo, content-engine, brand-voice, landing-copy, technical-writing, case-studies]
|
|
6
6
|
origin: risco
|
|
@@ -12,15 +12,6 @@ Draft one long-form article end to end: the prose **and** the on-page surface th
|
|
|
12
12
|
|
|
13
13
|
You own a single finished article. You do not pick the topic, build the calendar, or define the house voice — those are siblings below.
|
|
14
14
|
|
|
15
|
-
## When to use
|
|
16
|
-
|
|
17
|
-
- Drafting a blog post or long-form article from a topic or a target query.
|
|
18
|
-
- Turning a brief or outline into finished, publishable prose at the right depth.
|
|
19
|
-
- Writing the answer-first lede — the first ~200 words that fully answer the primary query.
|
|
20
|
-
- Restructuring a rambling draft into a question-shaped H2/H3 hierarchy.
|
|
21
|
-
- Writing the on-page surface: title tag, meta description, H1, slug, FAQ section, and Article/FAQPage JSON-LD.
|
|
22
|
-
- Cutting an AI-tell, fluff-padded draft down to the depth the query actually needs.
|
|
23
|
-
|
|
24
15
|
## When NOT to use
|
|
25
16
|
|
|
26
17
|
| You want… | Go to |
|
|
@@ -109,14 +100,6 @@ Every article ships with these. Keep them in the file's front-matter or a clearl
|
|
|
109
100
|
- **Slug**: short, lowercase, hyphenated, keyword-bearing, no stop-word noise — `/compost-in-apartment` not `/how-to-start-composting-in-your-apartment-today`.
|
|
110
101
|
- **FAQ block**: 3–6 real questions from "People also ask", each answered in 2–4 sentences.
|
|
111
102
|
|
|
112
|
-
Quick checklist:
|
|
113
|
-
|
|
114
|
-
- [ ] Title 50–60 chars, keyword in first ~35
|
|
115
|
-
- [ ] Meta 140–160 chars, value-first
|
|
116
|
-
- [ ] Exactly one H1
|
|
117
|
-
- [ ] Slug short + keyword-bearing
|
|
118
|
-
- [ ] FAQ questions match visible page content
|
|
119
|
-
|
|
120
103
|
Full pixel/char tables, slug rules, and copy-ready `Article`/`BlogPosting` + `FAQPage` JSON-LD (JSON-LD only — never microdata) live in [`references/on-page-seo.md`](references/on-page-seo.md). The JSON-LD must describe what is actually on the page; schema that does not match visible content is a quality flag, not a win.
|
|
121
104
|
|
|
122
105
|
## Internal links and topical authority
|
package/skills/astro/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: astro
|
|
3
|
-
description: "Use when building a content-driven or marketing site with Astro 6
|
|
3
|
+
description: "Use when building a content-driven or marketing site with Astro 6: static-first pages, islands and partial hydration, content collections, server islands, per-route on-demand rendering, deploy adapters, and Astro 5→6 migration. NOT app-router React with server actions and heavy client interactivity (that is `nextjs`)."
|
|
4
4
|
tags: [astro, ssg, islands, content-collections, partial-hydration, marketing-site, frameworks]
|
|
5
5
|
recommends: [landing-copy, seo-geo, vercel, cloudflare, netlify]
|
|
6
6
|
origin: risco
|
|
@@ -8,41 +8,31 @@ origin: risco
|
|
|
8
8
|
|
|
9
9
|
# Astro 6 — static-first sites, islands, content collections
|
|
10
10
|
|
|
11
|
-
> Build fast content and marketing sites with Astro 6: ship zero client JS by default, hydrate the
|
|
12
|
-
> smallest possible surface, model content with type-safe collections, deploy static or hybrid.
|
|
13
|
-
|
|
14
11
|
## The prime directive
|
|
15
12
|
|
|
16
13
|
**Ship zero client JavaScript by default. Hydrate the smallest possible surface, as late as you can
|
|
17
|
-
get away with.**
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
If you find yourself adding `client:load` to make a page "work," stop — the page already works; you
|
|
23
|
-
are adding interactivity, and interactivity is the expensive exception, not the default.
|
|
14
|
+
get away with.** An `.astro` component renders to HTML at build time and ships *no* runtime; every
|
|
15
|
+
island is a bundle the visitor downloads, parses, and executes. Content and marketing sites win on
|
|
16
|
+
TTFB/LCP and Lighthouse, not on React-everywhere. If you find yourself adding `client:load` to make
|
|
17
|
+
a page "work," stop — the page already works; you are adding interactivity, and interactivity is the
|
|
18
|
+
expensive exception, not the default.
|
|
24
19
|
|
|
25
20
|
## First: detect the project version
|
|
26
21
|
|
|
27
|
-
Astro 6.0 is stable (released 2026-03-10); the Astro 5 line is
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
**Fonts API**, and the **CSP API** stable. Sources: [Astro 6.0 release post,
|
|
42
|
-
2026-03-10](https://astro.build/blog/astro-6/) and the
|
|
43
|
-
[upgrade-to-v6 guide](https://docs.astro.build/en/guides/upgrade-to/v6/). (v6 also ships an
|
|
44
|
-
*experimental* Rust compiler succeeding the Go one — experimental, so do not rely on or configure
|
|
45
|
-
it in production advice.)
|
|
22
|
+
Astro 6.0 is stable ([released 2026-03-10](https://astro.build/blog/astro-6/)); the Astro 5 line is
|
|
23
|
+
still production-ready. Do not mix advice across majors — read `package.json` → the `astro` version
|
|
24
|
+
before advising. What v6 changes, per the
|
|
25
|
+
[upgrade-to-v6 guide](https://docs.astro.build/en/guides/upgrade-to/v6/):
|
|
26
|
+
|
|
27
|
+
- **Node `22.12.0` or higher is required** (18 and 20 are dropped) — check the actual runtime.
|
|
28
|
+
- Content config lives at `src/content.config.ts`. The legacy `src/content/config.ts` path is
|
|
29
|
+
**removed**, not merely discouraged, and the old auto-detection (`legacy.collections`) is gone.
|
|
30
|
+
The `legacy.collectionsBackwardsCompat` escape hatch is a migration crutch, not a supported layout.
|
|
31
|
+
- **Vite 7** and **Zod 4** for content schemas — `z` is imported from `astro/zod`, **not**
|
|
32
|
+
`astro:content` (see Content collections below).
|
|
33
|
+
- **Live Content Collections**, the **Fonts API** and the **CSP API** are stable.
|
|
34
|
+
- The Rust compiler succeeding the Go one is *experimental* — do not rely on or configure it in
|
|
35
|
+
production advice.
|
|
46
36
|
|
|
47
37
|
## Decision table — what kind of thing is this?
|
|
48
38
|
|
|
@@ -160,8 +150,8 @@ const { Content } = await render(post);
|
|
|
160
150
|
```
|
|
161
151
|
|
|
162
152
|
Built-in loaders are `glob()` (many files) and `file()` (one JSON/YAML array). Custom and CMS
|
|
163
|
-
loaders, collection references, Live Content Collections (real-time data with
|
|
164
|
-
v6), and MDX details → `references/content-layer.md`.
|
|
153
|
+
loaders, Zod 4 schema patterns, collection references, Live Content Collections (real-time data with
|
|
154
|
+
no rebuild, stable in v6), querying and MDX details → `references/content-layer.md`.
|
|
165
155
|
|
|
166
156
|
## Server islands
|
|
167
157
|
|
|
@@ -202,14 +192,13 @@ npx astro add react mdx sitemap
|
|
|
202
192
|
|
|
203
193
|
- **Tailwind 4** wires through the official **Vite plugin** (`@tailwindcss/vite`), not the legacy
|
|
204
194
|
`@astrojs/tailwind` integration (that path was for Tailwind 3).
|
|
205
|
-
- **Fonts API** (stable in v6
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
inline scripts/styles.
|
|
195
|
+
- **Fonts API** (stable in v6) self-hosts and optimizes fonts from `astro.config.mjs` — no manual
|
|
196
|
+
`@font-face`.
|
|
197
|
+
- **CSP API** (stable in v6) emits a Content-Security-Policy with hashes for your inline
|
|
198
|
+
scripts/styles.
|
|
210
199
|
|
|
211
|
-
Adapter recipes, env handling,
|
|
212
|
-
`references/deploy-and-integrations.md`.
|
|
200
|
+
Adapter recipes per platform, hybrid rendering, env handling, SSR endpoints (`src/pages/api/*.ts`)
|
|
201
|
+
and the Fonts/CSP config → `references/deploy-and-integrations.md`.
|
|
213
202
|
|
|
214
203
|
## Performance rules
|
|
215
204
|
|
|
@@ -235,9 +224,9 @@ npx @astrojs/upgrade
|
|
|
235
224
|
legacy path is removed, not just deprecated).
|
|
236
225
|
- [ ] Full guide (dated 2026): `docs.astro.build/en/guides/upgrade-to/v6`.
|
|
237
226
|
|
|
238
|
-
## Anti-patterns
|
|
227
|
+
## Anti-patterns
|
|
239
228
|
|
|
240
|
-
|
|
|
229
|
+
| Anti-pattern | Reality |
|
|
241
230
|
| -------------------------------------------------------- | --------------------------------------------------------------------------- |
|
|
242
231
|
| "Add `client:load` so the page works" | An `.astro` page already works statically; you're shipping JS for nothing |
|
|
243
232
|
| "`client:load` everywhere, simplest" | Pick `client:visible`/`idle`/`media`; first-paint JS is the LCP killer |
|
|
@@ -251,19 +240,12 @@ npx @astrojs/upgrade
|
|
|
251
240
|
|
|
252
241
|
## Verify
|
|
253
242
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
## References
|
|
262
|
-
|
|
263
|
-
- `references/content-layer.md` — loaders (`glob`/`file`/custom/CMS), Zod 4 schema patterns,
|
|
264
|
-
collection references, Live Content Collections, querying & rendering, MDX.
|
|
265
|
-
- `references/deploy-and-integrations.md` — adapter table per platform, hybrid rendering, SSR
|
|
266
|
-
endpoints, env handling, `astro add` recipes, Fonts API & CSP API config.
|
|
243
|
+
`bash scripts/verify.sh` from the Astro project root — grep-based, needs no install. It **FAILS** if
|
|
244
|
+
a v6 project still has `src/content/config.ts` instead of `src/content.config.ts`, **WARNS** on
|
|
245
|
+
over-hydration smells (many `client:load`, or `client:only` with no framework string), **CHECKS**
|
|
246
|
+
that content schemas import from `astro:content`, and — only if the `astro` binary resolves —
|
|
247
|
+
optionally runs `npx astro check`. On an empty or clean tree it prints OK and exits 0; warnings are
|
|
248
|
+
advisory and never fail the run.
|
|
267
249
|
|
|
268
250
|
## See Also
|
|
269
251
|
|