tribunal-kit 5.8.2 → 5.8.4

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.
Files changed (101) hide show
  1. package/.agent/ARCHITECTURE.md +12 -12
  2. package/.agent/agents/complexity-reviewer.md +53 -0
  3. package/.agent/agents/precedence-reviewer.md +12 -12
  4. package/.agent/agents/swarm-worker-registry.md +3 -3
  5. package/.agent/history/integrity_manifest.json +958 -0
  6. package/.agent/history/memory/.memory.idx +305 -1
  7. package/.agent/history/memory/MEMORY.md +21 -1
  8. package/.agent/rules/GEMINI.md +31 -28
  9. package/.agent/scripts/case_law_manager.js +3 -15
  10. package/.agent/scripts/context_broker.js +3 -1
  11. package/.agent/scripts/guardrail_engine.js +643 -0
  12. package/.agent/scripts/integrity_manifest.js +486 -0
  13. package/.agent/scripts/signal_detector.js +1 -1
  14. package/.agent/scripts/skill_evolution.js +3 -15
  15. package/.agent/scripts/skill_integrator.js +2 -12
  16. package/.agent/scripts/swarm_dispatcher.js +2 -12
  17. package/.agent/skills/12-principles-of-animation/SKILL.md +69 -0
  18. package/.agent/skills/60fps-animation/SKILL.md +78 -0
  19. package/.agent/skills/accessible-animation/SKILL.md +86 -0
  20. package/.agent/skills/adapt/SKILL.md +75 -0
  21. package/.agent/skills/animation-on-scroll/SKILL.md +110 -0
  22. package/.agent/skills/animation-systems/SKILL.md +69 -0
  23. package/.agent/skills/antfu-conventions/SKILL.md +74 -0
  24. package/.agent/skills/app-builder/SKILL.md +1 -1
  25. package/.agent/skills/apple-design/SKILL.md +108 -0
  26. package/.agent/skills/audit-and-fix/SKILL.md +83 -0
  27. package/.agent/skills/baseline-ui/SKILL.md +74 -0
  28. package/.agent/skills/better-colors/SKILL.md +124 -0
  29. package/.agent/skills/better-typography/SKILL.md +111 -0
  30. package/.agent/skills/better-ui/SKILL.md +102 -0
  31. package/.agent/skills/bolder/SKILL.md +68 -0
  32. package/.agent/skills/build-primitive/SKILL.md +70 -0
  33. package/.agent/skills/clarify/SKILL.md +75 -0
  34. package/.agent/skills/cobejs/SKILL.md +96 -0
  35. package/.agent/skills/codebase-design/SKILL.md +84 -0
  36. package/.agent/skills/colorize/SKILL.md +77 -0
  37. package/.agent/skills/compact-landing/SKILL.md +70 -0
  38. package/.agent/skills/company-logos/SKILL.md +73 -0
  39. package/.agent/skills/create-design-md/SKILL.md +104 -0
  40. package/.agent/skills/critique/SKILL.md +95 -0
  41. package/.agent/skills/delight/SKILL.md +65 -0
  42. package/.agent/skills/design-lab/SKILL.md +59 -0
  43. package/.agent/skills/diagnosing-bugs/SKILL.md +190 -0
  44. package/.agent/skills/distill/SKILL.md +65 -0
  45. package/.agent/skills/domain-modeling/SKILL.md +78 -0
  46. package/.agent/skills/fixing-accessibility/SKILL.md +98 -0
  47. package/.agent/skills/fixing-metadata/SKILL.md +97 -0
  48. package/.agent/skills/fixing-motion-performance/SKILL.md +96 -0
  49. package/.agent/skills/gpt-taste/SKILL.md +68 -0
  50. package/.agent/skills/harden/SKILL.md +74 -0
  51. package/.agent/skills/impeccable/SKILL.md +72 -0
  52. package/.agent/skills/improve-codebase-architecture/SKILL.md +67 -0
  53. package/.agent/skills/improve-ui/SKILL.md +83 -0
  54. package/.agent/skills/landing-page/SKILL.md +88 -0
  55. package/.agent/skills/lint-and-validate/SKILL.md +1 -2
  56. package/.agent/skills/local-first-architecture/SKILL.md +66 -0
  57. package/.agent/skills/lottie-animation/SKILL.md +82 -0
  58. package/.agent/skills/marquee-loop/SKILL.md +96 -0
  59. package/.agent/skills/masked-reveal/SKILL.md +88 -0
  60. package/.agent/skills/micro-interaction/SKILL.md +100 -0
  61. package/.agent/skills/morphing-icons/SKILL.md +85 -0
  62. package/.agent/skills/page-transition-animation/SKILL.md +108 -0
  63. package/.agent/skills/parallel-agents/SKILL.md +5 -5
  64. package/.agent/skills/polish/SKILL.md +63 -0
  65. package/.agent/skills/pricing-page/SKILL.md +68 -0
  66. package/.agent/skills/progressive-blur/SKILL.md +100 -0
  67. package/.agent/skills/project-idioms/SKILL.md +7 -7
  68. package/.agent/skills/quieter/SKILL.md +68 -0
  69. package/.agent/skills/react-doctor/SKILL.md +70 -0
  70. package/.agent/skills/redesign-skill/SKILL.md +65 -0
  71. package/.agent/skills/shape/SKILL.md +73 -0
  72. package/.agent/skills/soft-skill/SKILL.md +72 -0
  73. package/.agent/skills/sounds-on-the-web/SKILL.md +100 -0
  74. package/.agent/skills/svg-animation/SKILL.md +91 -0
  75. package/.agent/skills/swiss-design/SKILL.md +64 -0
  76. package/.agent/skills/taste-skill/SKILL.md +71 -0
  77. package/.agent/skills/tdd-workflow/SKILL.md +36 -165
  78. package/.agent/skills/test-result-analyzer/SKILL.md +1 -1
  79. package/.agent/skills/thermo-nuclear-code-quality-review/SKILL.md +82 -0
  80. package/.agent/skills/to-spring-or-not-to-spring/SKILL.md +66 -0
  81. package/.agent/skills/transitions-dev/SKILL.md +101 -0
  82. package/.agent/skills/typeset/SKILL.md +76 -0
  83. package/.agent/skills/ui-skills-root/SKILL.md +85 -0
  84. package/.agent/skills/web-quality-audit/SKILL.md +67 -0
  85. package/.agent/workflows/fix.md +2 -2
  86. package/.agent/workflows/preview.md +5 -5
  87. package/.agent/workflows/status.md +1 -1
  88. package/.agent/workflows/tribunal-full.md +3 -3
  89. package/.agent/workflows/tribunal-speed.md +2 -2
  90. package/README.md +348 -238
  91. package/bin/tribunal-kit.js +62 -1482
  92. package/dist/cli.js +13 -0
  93. package/dist/commands/align.js +1 -1
  94. package/dist/commands/compile.js +1 -1
  95. package/dist/commands/guardrail.js +275 -0
  96. package/dist/commands/init.js +10 -9
  97. package/dist/commands/optimize.js +318 -0
  98. package/dist/utils/version.js +1 -1
  99. package/package.json +10 -8
  100. package/scripts/fix-vbc.js +98 -0
  101. package/scripts/fix-vbc.ps1 +119 -0
package/dist/cli.js CHANGED
@@ -105,6 +105,8 @@ function cmdHelp(quiet = false) {
105
105
  (0, logger_1.log)(cmd('hook', 'Install pre-push git hook for auto-learning'));
106
106
  (0, logger_1.log)(cmd('compile', 'Compile rules into a static instruction file for terminal agents'));
107
107
  (0, logger_1.log)(cmd('memory', '4-Type Taxonomy Persistent Memory Engine (store, recall, gc, stats, export)'));
108
+ (0, logger_1.log)(cmd('optimize-skill', 'Optimize project skills actively using SkillOpt validation gates'));
109
+ (0, logger_1.log)(cmd('guardrail', 'Validate .agent/ integrity (phantom refs, count mismatches, drift)'));
108
110
  (0, logger_1.log)(cmd('uninstall', 'Remove .agent/ folder from project'));
109
111
  console.log();
110
112
  (0, logger_1.log)((0, logger_1.bold)(' Options'));
@@ -153,6 +155,7 @@ function cmdHelp(quiet = false) {
153
155
  (0, logger_1.log)(ex('echo "Certainly! Here is - item 1" | tk align'));
154
156
  (0, logger_1.log)(ex('tk align output.md --write'));
155
157
  (0, logger_1.log)(ex('tk memory store --type semantic --content "Uses PostgreSQL" --tags db,orm'));
158
+ (0, logger_1.log)(ex('tk optimize-skill --target project-idioms "npm test"'));
156
159
  (0, logger_1.log)(ex('tk memory recall --query "database" --budget 2000'));
157
160
  (0, logger_1.log)(ex('tk memory gc'));
158
161
  (0, logger_1.log)(ex('tk memory stats'));
@@ -254,6 +257,16 @@ async function runWithUpdateCheck(command, flags) {
254
257
  await cmdMemory(flags, process.argv, quiet);
255
258
  break;
256
259
  }
260
+ case 'optimize-skill': {
261
+ const cmdOptimizeSkill = loadCmd('./commands/optimize', 'cmdOptimizeSkill');
262
+ await cmdOptimizeSkill(flags, process.argv, quiet);
263
+ break;
264
+ }
265
+ case 'guardrail': {
266
+ const cmdGuardrail = loadCmd('./commands/guardrail', 'cmdGuardrail');
267
+ await cmdGuardrail(flags, process.argv, quiet);
268
+ break;
269
+ }
257
270
  case 'help':
258
271
  case '--help':
259
272
  case '-h':
@@ -3,7 +3,7 @@
3
3
  const fs = require("fs");
4
4
  const path = require("path");
5
5
  const readline = require("readline");
6
- const { log, err, ok, c, bold, warn } = require("../utils/logger");
6
+ const { _log, err, ok, c, bold, _warn } = require("../utils/logger");
7
7
 
8
8
  function alignText(text) {
9
9
  if (!text) return "";
@@ -4,7 +4,7 @@ exports.cmdCompile = cmdCompile;
4
4
 
5
5
  const fs = require("fs");
6
6
  const path = require("path");
7
- const { log, err, ok, c, bold, dbg } = require("../utils/logger");
7
+ const { log, err, ok, c, bold, _dbg } = require("../utils/logger");
8
8
 
9
9
  async function cmdCompile(flags, quiet) {
10
10
  const cwd = process.cwd();
@@ -0,0 +1,275 @@
1
+ "use strict";
2
+ /**
3
+ * guardrail.js — CLI command handler for `tk guardrail`
4
+ *
5
+ * Validates .agent/ files against the integrity manifest using
6
+ * the Neurosymbolic Guardrail Engine.
7
+ *
8
+ * Usage:
9
+ * tk guardrail → Scan all .agent/ files
10
+ * tk guardrail --file output.md → Validate a specific file
11
+ * tk guardrail --fix → Auto-fix simple violations
12
+ * tk guardrail --json → Output as JSON
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.cmdGuardrail = cmdGuardrail;
16
+
17
+ const fs = require("fs");
18
+ const path = require("path");
19
+ const logger_1 = require("../utils/logger");
20
+
21
+ async function cmdGuardrail(flags, argv, quiet) {
22
+ const projectRoot = flags.path || process.cwd();
23
+ const agentDir = path.join(projectRoot, ".agent");
24
+
25
+ if (!fs.existsSync(agentDir)) {
26
+ (0, logger_1.err)("No .agent/ directory found. Run `tk init` first.");
27
+ process.exit(1);
28
+ }
29
+
30
+ // Resolve script paths (installed vs local development)
31
+ const scriptsDir = path.join(agentDir, "scripts");
32
+ const manifestScript = path.join(scriptsDir, "integrity_manifest.js");
33
+ const guardrailScript = path.join(scriptsDir, "guardrail_engine.js");
34
+
35
+ if (!fs.existsSync(manifestScript)) {
36
+ (0, logger_1.err)(
37
+ "integrity_manifest.js not found in .agent/scripts/. Your installation may be outdated — run `tk update`.",
38
+ );
39
+ process.exit(1);
40
+ }
41
+
42
+ if (!fs.existsSync(guardrailScript)) {
43
+ (0, logger_1.err)(
44
+ "guardrail_engine.js not found in .agent/scripts/. Your installation may be outdated — run `tk update`.",
45
+ );
46
+ process.exit(1);
47
+ }
48
+
49
+ // Step 1: Generate manifest
50
+ if (!quiet) {
51
+ (0, logger_1.log)(
52
+ ` ${(0, logger_1.c)("cyan", "◆")} Generating integrity manifest...`,
53
+ );
54
+ }
55
+
56
+ const { generateManifest, saveManifest } = require(manifestScript);
57
+ const manifest = generateManifest(projectRoot);
58
+
59
+ if (manifest.error) {
60
+ (0, logger_1.err)(manifest.error);
61
+ process.exit(1);
62
+ }
63
+
64
+ // Save manifest for future use
65
+ saveManifest(manifest, projectRoot);
66
+
67
+ // Step 2: Determine files to validate
68
+ const { validate } = require(guardrailScript);
69
+ const fileArg = extractFileArg(argv);
70
+ const fixMode = flags.write || argv.includes("--fix");
71
+ const jsonMode = argv.includes("--json");
72
+
73
+ let filesToCheck = [];
74
+
75
+ if (fileArg) {
76
+ const resolved = path.resolve(fileArg);
77
+ if (!fs.existsSync(resolved)) {
78
+ (0, logger_1.err)(`File not found: ${fileArg}`);
79
+ process.exit(1);
80
+ }
81
+ filesToCheck.push(resolved);
82
+ } else {
83
+ // Scan all .agent/ markdown files
84
+ filesToCheck = walkAgentFiles(agentDir);
85
+ }
86
+
87
+ if (!quiet) {
88
+ (0, logger_1.log)(
89
+ ` ${(0, logger_1.c)("cyan", "◆")} Scanning ${filesToCheck.length} files...`,
90
+ );
91
+ }
92
+
93
+ // Step 3: Run guardrail engine
94
+ let totalViolations = 0;
95
+ let totalCritical = 0;
96
+ let totalAutoFixed = 0;
97
+ const allResults = [];
98
+
99
+ for (const file of filesToCheck) {
100
+ const content = fs.readFileSync(file, "utf8");
101
+ const result = validate(content, manifest, {
102
+ autoFix: fixMode,
103
+ context: { projectRoot, filePath: file },
104
+ });
105
+
106
+ if (result.violations.length > 0) {
107
+ totalViolations += result.violations.length;
108
+ totalCritical += result.violations.filter(
109
+ (v) => v.severity === "critical",
110
+ ).length;
111
+
112
+ allResults.push({
113
+ file: path.relative(projectRoot, file),
114
+ ...result,
115
+ });
116
+
117
+ // Apply auto-fix
118
+ if (
119
+ fixMode &&
120
+ result.autoFixedContent &&
121
+ result.autoFixedContent !== content
122
+ ) {
123
+ fs.writeFileSync(file, result.autoFixedContent, "utf8");
124
+ totalAutoFixed++;
125
+ }
126
+ }
127
+ }
128
+
129
+ // Step 4: Output results
130
+ if (jsonMode) {
131
+ console.log(
132
+ JSON.stringify(
133
+ {
134
+ manifest_summary: {
135
+ agents: manifest.agents.total,
136
+ reviewers: manifest.agents.reviewer_count,
137
+ skills: manifest.skills.total,
138
+ scripts: manifest.scripts.total,
139
+ workflows: manifest.workflows.total,
140
+ },
141
+ files_scanned: filesToCheck.length,
142
+ total_violations: totalViolations,
143
+ critical_violations: totalCritical,
144
+ auto_fixed: totalAutoFixed,
145
+ results: allResults,
146
+ },
147
+ null,
148
+ 2,
149
+ ),
150
+ );
151
+ return;
152
+ }
153
+
154
+ if (quiet) {
155
+ process.exit(totalCritical > 0 ? 1 : 0);
156
+ return;
157
+ }
158
+
159
+ // Human-readable output
160
+ console.log();
161
+ console.log(
162
+ ` ${(0, logger_1.c)("cyan", "🛡️")} ${(0, logger_1.bold)("Guardrail Validation Report")}`,
163
+ );
164
+ console.log(` ${(0, logger_1.c)("gray", "─".repeat(40))}`);
165
+ console.log(
166
+ ` Agents: ${(0, logger_1.c)("white", String(manifest.agents.total))} (${manifest.agents.reviewer_count} reviewers)`,
167
+ );
168
+ console.log(
169
+ ` Skills: ${(0, logger_1.c)("white", String(manifest.skills.total))}`,
170
+ );
171
+ console.log(
172
+ ` Scripts: ${(0, logger_1.c)("white", String(manifest.scripts.total))}`,
173
+ );
174
+ console.log(
175
+ ` Workflows: ${(0, logger_1.c)("white", String(manifest.workflows.total))}`,
176
+ );
177
+ console.log(` ${(0, logger_1.c)("gray", "─".repeat(40))}`);
178
+ console.log(
179
+ ` Files scanned: ${(0, logger_1.c)("white", String(filesToCheck.length))}`,
180
+ );
181
+ console.log(
182
+ ` Violations: ${totalViolations > 0 ? (0, logger_1.c)("yellow", String(totalViolations)) : (0, logger_1.c)("green", "0")}`,
183
+ );
184
+ console.log(
185
+ ` Critical: ${totalCritical > 0 ? (0, logger_1.c)("red", String(totalCritical)) : (0, logger_1.c)("green", "0")}`,
186
+ );
187
+
188
+ if (fixMode && totalAutoFixed > 0) {
189
+ console.log(
190
+ ` Auto-fixed: ${(0, logger_1.c)("green", String(totalAutoFixed))}`,
191
+ );
192
+ }
193
+
194
+ console.log(` ${(0, logger_1.c)("gray", "─".repeat(40))}`);
195
+
196
+ // Show violations
197
+ for (const result of allResults) {
198
+ console.log(
199
+ `\n 📄 ${(0, logger_1.c)("cyan", result.file)} — ${result.summary}`,
200
+ );
201
+ for (const v of result.violations) {
202
+ const icon =
203
+ v.severity === "critical"
204
+ ? (0, logger_1.c)("red", "●")
205
+ : v.severity === "warning"
206
+ ? (0, logger_1.c)("yellow", "●")
207
+ : (0, logger_1.c)("blue", "●");
208
+ console.log(
209
+ ` ${icon} [${(0, logger_1.c)("gray", v.rule)}] ${v.message}`,
210
+ );
211
+ if (v.suggestion) {
212
+ console.log(
213
+ ` ${(0, logger_1.c)("gray", "💡")} ${(0, logger_1.c)("gray", v.suggestion)}`,
214
+ );
215
+ }
216
+ }
217
+ }
218
+
219
+ if (totalViolations === 0) {
220
+ console.log(
221
+ `\n ${(0, logger_1.c)("green", "✅")} All files clean. Zero phantom references. Zero count mismatches.`,
222
+ );
223
+ }
224
+
225
+ console.log();
226
+ process.exit(totalCritical > 0 ? 1 : 0);
227
+ }
228
+
229
+ // ── Helpers ───────────────────────────────────────────────────────────────────
230
+
231
+ function extractFileArg(argv) {
232
+ const raw = argv.slice(2);
233
+ const fileIdx = raw.indexOf("--file");
234
+ if (fileIdx !== -1 && raw[fileIdx + 1]) {
235
+ return raw[fileIdx + 1];
236
+ }
237
+ // Also check for positional arg after 'guardrail'
238
+ for (const arg of raw) {
239
+ if (arg === "guardrail" || arg.startsWith("--")) continue;
240
+ if (fs.existsSync(arg)) return arg;
241
+ }
242
+ return null;
243
+ }
244
+
245
+ function walkAgentFiles(dir, fileList = []) {
246
+ if (!fs.existsSync(dir)) return fileList;
247
+
248
+ try {
249
+ const entries = fs.readdirSync(dir);
250
+ for (const entry of entries) {
251
+ if (
252
+ ["node_modules", ".git", "history", ".backups", ".shared"].includes(
253
+ entry,
254
+ )
255
+ ) {
256
+ continue;
257
+ }
258
+ const fullPath = path.join(dir, entry);
259
+ try {
260
+ const stat = fs.statSync(fullPath);
261
+ if (stat.isDirectory()) {
262
+ walkAgentFiles(fullPath, fileList);
263
+ } else if (entry.endsWith(".md") || entry.endsWith(".json")) {
264
+ fileList.push(fullPath);
265
+ }
266
+ } catch {
267
+ // Skip
268
+ }
269
+ }
270
+ } catch {
271
+ // Skip
272
+ }
273
+
274
+ return fileList;
275
+ }
@@ -272,7 +272,7 @@ async function cmdInit(flags, quiet = false) {
272
272
  console.log(` ${(0, logger_1.c)(borderCol, '└' + '─'.repeat(W) + '┘')}`);
273
273
  console.log();
274
274
  (0, logger_1.log)(` ${(0, logger_1.c)('gray', '✦ Generating IDE bridge files...')}`);
275
- await generateIDEBridges(targetDir, agentDest, dryRun);
275
+ await generateIDEBridges(targetDir, agentDest, dryRun, isMinimal);
276
276
  }
277
277
  console.log();
278
278
  }
@@ -286,8 +286,9 @@ async function cmdInit(flags, quiet = false) {
286
286
  process.exit(1);
287
287
  }
288
288
  }
289
- async function generateIDEBridges(targetDir, agentDest, dryRun = false) {
290
- const rulesFile = path_1.default.join(agentDest, 'rules', 'GEMINI.md');
289
+ async function generateIDEBridges(targetDir, agentDest, dryRun = false, isMinimal = false) {
290
+ const rulesFilename = isMinimal ? 'kernel.md' : 'GEMINI.md';
291
+ const rulesFile = path_1.default.join(agentDest, 'rules', rulesFilename);
291
292
  let rulesContent = '';
292
293
  try {
293
294
  rulesContent = await fs_1.default.promises.readFile(rulesFile, 'utf8');
@@ -317,21 +318,21 @@ async function generateIDEBridges(targetDir, agentDest, dryRun = false) {
317
318
  // ── 1. Cursor (.cursorrules) ──────────────────────────
318
319
  const cursorRules = `# Tribunal Kit — Cursor Bridge
319
320
  # Auto-generated by tribunal-kit init. Do not edit manually.
320
- # Source: .agent/rules/GEMINI.md
321
+ # Source: .agent/rules/${rulesFilename}
321
322
 
322
323
  ${rulesContent}
323
324
  `;
324
325
  // ── 2. Windsurf (.windsurfrules) ─────────────────────
325
326
  const windsurfRules = `# Tribunal Kit — Windsurf Bridge
326
327
  # Auto-generated by tribunal-kit init. Do not edit manually.
327
- # Source: .agent/rules/GEMINI.md
328
+ # Source: .agent/rules/${rulesFilename}
328
329
 
329
330
  ${rulesContent}
330
331
  `;
331
332
  // ── 3. Gemini / Antigravity (.gemini/settings.json) ──
332
333
  const geminiSettings = JSON.stringify({
333
334
  "rules": [
334
- { "path": "../.agent/rules/GEMINI.md", "trigger": "always_on" }
335
+ { "path": `../.agent/rules/${rulesFilename}`, "trigger": "always_on" }
335
336
  ],
336
337
  "agents": { "directory": "../.agent/agents" },
337
338
  "skills": { "directory": "../.agent/skills" },
@@ -344,21 +345,21 @@ trigger: always_on
344
345
 
345
346
  # Tribunal Kit — Gemini Bridge
346
347
  # Auto-generated by tribunal-kit init.
347
- # Full rules: .agent/rules/GEMINI.md
348
+ # Full rules: .agent/rules/${rulesFilename}
348
349
 
349
350
  ${rulesContent}
350
351
  `;
351
352
  // ── 4. GitHub Copilot (.github/copilot-instructions.md) ──
352
353
  const copilotInstructions = `# Tribunal Kit — Copilot Bridge
353
354
  # Auto-generated by tribunal-kit init. Do not edit manually.
354
- # Source: .agent/rules/GEMINI.md
355
+ # Source: .agent/rules/${rulesFilename}
355
356
 
356
357
  ${rulesContent}
357
358
  `;
358
359
  // ── 5. Claude (.claude/CLAUDE.md) ─────────────────────
359
360
  const claudeRules = `# Tribunal Kit — Claude Bridge
360
361
  # Auto-generated by tribunal-kit init. Do not edit manually.
361
- # Source: .agent/rules/GEMINI.md
362
+ # Source: .agent/rules/${rulesFilename}
362
363
 
363
364
  ${rulesContent}
364
365
  `;