@thanh01.pmt/curriculum-kit 1.4.28 → 1.4.29

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 (39) hide show
  1. package/dist/ai/index.cjs +12 -2
  2. package/dist/ai/index.cjs.map +1 -1
  3. package/dist/ai/index.d.cts +2 -2
  4. package/dist/ai/index.d.ts +2 -2
  5. package/dist/ai/index.mjs +12 -2
  6. package/dist/ai/index.mjs.map +1 -1
  7. package/dist/index.cjs +42 -3
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.cts +4 -4
  10. package/dist/index.d.ts +4 -4
  11. package/dist/index.mjs +42 -3
  12. package/dist/index.mjs.map +1 -1
  13. package/dist/media/index.cjs +12 -2
  14. package/dist/media/index.cjs.map +1 -1
  15. package/dist/media/index.d.cts +1 -1
  16. package/dist/media/index.d.ts +1 -1
  17. package/dist/media/index.mjs +12 -2
  18. package/dist/media/index.mjs.map +1 -1
  19. package/dist/pipeline/index.cjs.map +1 -1
  20. package/dist/pipeline/index.d.cts +1 -1
  21. package/dist/pipeline/index.d.ts +1 -1
  22. package/dist/pipeline/index.mjs.map +1 -1
  23. package/dist/publishers/index.d.cts +1 -1
  24. package/dist/publishers/index.d.ts +1 -1
  25. package/dist/storage/index.cjs +27 -0
  26. package/dist/storage/index.cjs.map +1 -1
  27. package/dist/storage/index.d.cts +11 -2
  28. package/dist/storage/index.d.ts +11 -2
  29. package/dist/storage/index.mjs +27 -0
  30. package/dist/storage/index.mjs.map +1 -1
  31. package/dist/{streamRunner-kpS4MZP1.d.cts → streamRunner-DYHFhNUr.d.cts} +1 -1
  32. package/dist/{streamRunner-kpS4MZP1.d.ts → streamRunner-DYHFhNUr.d.ts} +1 -1
  33. package/dist/{types-BUJGYiep.d.cts → types-Bgk-C4K2.d.cts} +11 -0
  34. package/dist/{types-BUJGYiep.d.ts → types-Bgk-C4K2.d.ts} +11 -0
  35. package/dist/workflow/index.cjs +14 -3
  36. package/dist/workflow/index.cjs.map +1 -1
  37. package/dist/workflow/index.mjs +14 -3
  38. package/dist/workflow/index.mjs.map +1 -1
  39. package/package.json +1 -1
package/dist/index.d.cts CHANGED
@@ -3,12 +3,12 @@ export { ActiveLearningWorkflow, ActiveLearningWorkflowSchema, ActivityLabSchema
3
3
  import { A as AIProviderName, M as ModelResolutionOptions } from './provider-factory-Bv-eIkhg.cjs';
4
4
  export { N as NVIDIA_MODELS, g as getAIModel } from './provider-factory-Bv-eIkhg.cjs';
5
5
  export { ActivityPromptInput, AggregatedToolCall, AsyncLLMJudgeInput, AuditCurriculumQualityInput, CodeLabPromptInput, DEFAULT_ENABLED_PROVIDERS, DiagnosticQuizPromptInput, ExtensionPromptInput, GenerateActivityInput, GenerateCodeLabInput, GenerateDiagnosticQuizInput, GenerateExtensionInput, GenerateHandoutInput, GenerateLessonMasterInput, GenerateProjectInstructionInput, GenerateSelfLabInput, GenerateSlidesInput, GenerateTeacherGuideInput, GenerateWorksheetInput, HandoutPromptInput, HtmlDeckSlidePromptInput, JudgeEvaluationResult, JudgePromptInput, LLMJudgeEngine, LessonPromptInput, MarpMarkdownSlidePromptInput, ModelPolicyResolution, ModelPolicyResolver, ModelProviderKey, MultiProviderPolicyResolution, ProjectInstructionPromptInput, SLIDE_CANONICAL_METHODOLOGY, SelfLabPromptInput, SlidesPromptInput, StreamDiagnosticQuizInput, StreamLessonMasterInput, StreamSelfLabInput, TeacherGuidePromptInput, ToolDefinition, ToolExecutionResult, ToolExecutor, ToolLoopConfig, WorksheetPromptInput, activityTools, analystTools, assessorTools, auditCurriculumQualityFlow, buildActivityPrompt, buildCodeLabPrompt, buildDiagnosticQuizPrompt, buildExtensionPrompt, buildHandoutPrompt, buildHtmlDeckSlidePrompt, buildJudgePrompt, buildLessonMasterPrompt, buildMarpMarkdownSlidePrompt, buildProjectInstructionPrompt, buildSelfLabPrompt, buildSlidesPrompt, buildTeacherGuidePrompt, buildWorksheetPrompt, contentTools, designerTools, generateActivityFlow, generateCodeLabFlow, generateDiagnosticQuizFlow, generateExtensionFlow, generateHandoutFlow, generateLessonMasterFlow, generateProjectInstructionFlow, generateSelfLabFlow, generateSlidesFlow, generateTeacherGuideFlow, generateWorksheetFlow, illustratorTools, packagerTools, researcherTools, reviewerTools, streamCurriculumAIInferenceWithTools, streamDiagnosticQuizFlow, streamLessonMasterFlow, streamSelfLabFlow, techSmeTools } from './ai/index.cjs';
6
- import { S as StreamRunnerOptions } from './streamRunner-kpS4MZP1.cjs';
7
- export { C as ChatMessage, c as ChunkType, D as DEFAULT_ARTIFACT_STREAM_IDLE_MS, d as DEFAULT_ARTIFACT_STREAM_TOTAL_MS, F as FallbackTarget, I as IdleAbort, f as StreamAbortController, j as createIdleAbortController, h as createStreamAbortController, e as extractThoughtAndContent, g as getDesignatedFallbackChain, b as getDesignatedFallbackConfig, a as isModelAllowed, i as isProviderEnabled, r as resolveApiKey, k as runCurriculumAIInference, s as streamCurriculumAIInference } from './streamRunner-kpS4MZP1.cjs';
6
+ import { S as StreamRunnerOptions } from './streamRunner-DYHFhNUr.cjs';
7
+ export { C as ChatMessage, c as ChunkType, D as DEFAULT_ARTIFACT_STREAM_IDLE_MS, d as DEFAULT_ARTIFACT_STREAM_TOTAL_MS, F as FallbackTarget, I as IdleAbort, f as StreamAbortController, j as createIdleAbortController, h as createStreamAbortController, e as extractThoughtAndContent, g as getDesignatedFallbackChain, b as getDesignatedFallbackConfig, a as isModelAllowed, i as isProviderEnabled, r as resolveApiKey, k as runCurriculumAIInference, s as streamCurriculumAIInference } from './streamRunner-DYHFhNUr.cjs';
8
8
  export { ArtifactLintReport, ConvertedSotBundle, GenerateProjectInstructionOptions, GenerateRoadmapCurriculumOptions, GenerateSelfPacedBundleInput, LintIssue, ProjectInstructionResult, RoadmapCurriculumOutput, SelfPacedBundleOutput, convertRoadmapToFoundationSot, generateProjectInstruction, generateRoadmapCurriculum, generateSelfPacedBundle, importRoadmapToProject, lintAndSanitizeArtifact, serializeActivityToMarkdown, serializeCodeLabToMarkdown, serializeDiagnosticQuizToMarkdown, serializeHandoutToMarkdown, serializeLessonToMarkdown, serializeProjectInstructionToMarkdown, serializeSelfLabToMarkdown, validateMarkdownTables, validateMermaidSyntax } from './pipeline/index.cjs';
9
9
  export { A as AutoRepairOptions, a as AutoRepairResult, B as BundleTier, G as GenerateMilestoneBundleOptions, M as MilestoneCurriculumBundle, g as generateMilestoneCurriculumBundle, w as withAutoRepair } from './milestoneBundleGenerator-CN6F1zPs.cjs';
10
- import { I as ICurriculumStorage, P as ProjectStatusReport, S as SmartResumeContext, Q as QualityAuditReport } from './types-BUJGYiep.cjs';
11
- export { b as ArtifactLifecycleInfo, A as ArtifactLifecycleState, L as LessonArtifactSummary, c as PipelineState, R as ReviewRecord, a as SotDocument, T as TaskLifecycleState } from './types-BUJGYiep.cjs';
10
+ import { I as ICurriculumStorage, P as ProjectStatusReport, S as SmartResumeContext, Q as QualityAuditReport } from './types-Bgk-C4K2.cjs';
11
+ export { b as ArtifactLifecycleInfo, A as ArtifactLifecycleState, L as LessonArtifactSummary, c as PipelineState, R as ReviewRecord, a as SotDocument, T as TaskLifecycleState } from './types-Bgk-C4K2.cjs';
12
12
  export { FileSystemCurriculumAdapter, FileSystemStorageOptions, STANDARD_SOT_FILES, StorageFactoryOptions, SupabaseCurriculumAdapter, SupabaseStorageConfig, atomicWriteFileSync, computeContentHash, createCurriculumStorage } from './storage/index.cjs';
13
13
  import { F as FrameworkPack, C as CoverageGateReport } from './standardsCoverageGate-DR5YTtlt.cjs';
14
14
  export { B as BloomHintSchema, a as ClassificationSchema, m as CoverageGateInput, h as FrameworkMapping, d as FrameworkMappingSchema, f as FrameworkPackManifest, b as FrameworkPackManifestSchema, e as FrameworkPackSchema, g as FrameworkStatement, c as FrameworkStatementSchema, G as GradeBandSchema, i as MappingKind, M as MappingKindSchema, P as PackLintIssue, k as PackValidationResult, j as RecordProvenance, R as RecordProvenanceSchema, S as StatementCoverageRow, n as evaluateStandardsCoverage, l as lintFrameworkPack, v as validateFrameworkPack } from './standardsCoverageGate-DR5YTtlt.cjs';
package/dist/index.d.ts CHANGED
@@ -3,12 +3,12 @@ export { ActiveLearningWorkflow, ActiveLearningWorkflowSchema, ActivityLabSchema
3
3
  import { A as AIProviderName, M as ModelResolutionOptions } from './provider-factory-Bv-eIkhg.js';
4
4
  export { N as NVIDIA_MODELS, g as getAIModel } from './provider-factory-Bv-eIkhg.js';
5
5
  export { ActivityPromptInput, AggregatedToolCall, AsyncLLMJudgeInput, AuditCurriculumQualityInput, CodeLabPromptInput, DEFAULT_ENABLED_PROVIDERS, DiagnosticQuizPromptInput, ExtensionPromptInput, GenerateActivityInput, GenerateCodeLabInput, GenerateDiagnosticQuizInput, GenerateExtensionInput, GenerateHandoutInput, GenerateLessonMasterInput, GenerateProjectInstructionInput, GenerateSelfLabInput, GenerateSlidesInput, GenerateTeacherGuideInput, GenerateWorksheetInput, HandoutPromptInput, HtmlDeckSlidePromptInput, JudgeEvaluationResult, JudgePromptInput, LLMJudgeEngine, LessonPromptInput, MarpMarkdownSlidePromptInput, ModelPolicyResolution, ModelPolicyResolver, ModelProviderKey, MultiProviderPolicyResolution, ProjectInstructionPromptInput, SLIDE_CANONICAL_METHODOLOGY, SelfLabPromptInput, SlidesPromptInput, StreamDiagnosticQuizInput, StreamLessonMasterInput, StreamSelfLabInput, TeacherGuidePromptInput, ToolDefinition, ToolExecutionResult, ToolExecutor, ToolLoopConfig, WorksheetPromptInput, activityTools, analystTools, assessorTools, auditCurriculumQualityFlow, buildActivityPrompt, buildCodeLabPrompt, buildDiagnosticQuizPrompt, buildExtensionPrompt, buildHandoutPrompt, buildHtmlDeckSlidePrompt, buildJudgePrompt, buildLessonMasterPrompt, buildMarpMarkdownSlidePrompt, buildProjectInstructionPrompt, buildSelfLabPrompt, buildSlidesPrompt, buildTeacherGuidePrompt, buildWorksheetPrompt, contentTools, designerTools, generateActivityFlow, generateCodeLabFlow, generateDiagnosticQuizFlow, generateExtensionFlow, generateHandoutFlow, generateLessonMasterFlow, generateProjectInstructionFlow, generateSelfLabFlow, generateSlidesFlow, generateTeacherGuideFlow, generateWorksheetFlow, illustratorTools, packagerTools, researcherTools, reviewerTools, streamCurriculumAIInferenceWithTools, streamDiagnosticQuizFlow, streamLessonMasterFlow, streamSelfLabFlow, techSmeTools } from './ai/index.js';
6
- import { S as StreamRunnerOptions } from './streamRunner-kpS4MZP1.js';
7
- export { C as ChatMessage, c as ChunkType, D as DEFAULT_ARTIFACT_STREAM_IDLE_MS, d as DEFAULT_ARTIFACT_STREAM_TOTAL_MS, F as FallbackTarget, I as IdleAbort, f as StreamAbortController, j as createIdleAbortController, h as createStreamAbortController, e as extractThoughtAndContent, g as getDesignatedFallbackChain, b as getDesignatedFallbackConfig, a as isModelAllowed, i as isProviderEnabled, r as resolveApiKey, k as runCurriculumAIInference, s as streamCurriculumAIInference } from './streamRunner-kpS4MZP1.js';
6
+ import { S as StreamRunnerOptions } from './streamRunner-DYHFhNUr.js';
7
+ export { C as ChatMessage, c as ChunkType, D as DEFAULT_ARTIFACT_STREAM_IDLE_MS, d as DEFAULT_ARTIFACT_STREAM_TOTAL_MS, F as FallbackTarget, I as IdleAbort, f as StreamAbortController, j as createIdleAbortController, h as createStreamAbortController, e as extractThoughtAndContent, g as getDesignatedFallbackChain, b as getDesignatedFallbackConfig, a as isModelAllowed, i as isProviderEnabled, r as resolveApiKey, k as runCurriculumAIInference, s as streamCurriculumAIInference } from './streamRunner-DYHFhNUr.js';
8
8
  export { ArtifactLintReport, ConvertedSotBundle, GenerateProjectInstructionOptions, GenerateRoadmapCurriculumOptions, GenerateSelfPacedBundleInput, LintIssue, ProjectInstructionResult, RoadmapCurriculumOutput, SelfPacedBundleOutput, convertRoadmapToFoundationSot, generateProjectInstruction, generateRoadmapCurriculum, generateSelfPacedBundle, importRoadmapToProject, lintAndSanitizeArtifact, serializeActivityToMarkdown, serializeCodeLabToMarkdown, serializeDiagnosticQuizToMarkdown, serializeHandoutToMarkdown, serializeLessonToMarkdown, serializeProjectInstructionToMarkdown, serializeSelfLabToMarkdown, validateMarkdownTables, validateMermaidSyntax } from './pipeline/index.js';
9
9
  export { A as AutoRepairOptions, a as AutoRepairResult, B as BundleTier, G as GenerateMilestoneBundleOptions, M as MilestoneCurriculumBundle, g as generateMilestoneCurriculumBundle, w as withAutoRepair } from './milestoneBundleGenerator-DTiJ5gIh.js';
10
- import { I as ICurriculumStorage, P as ProjectStatusReport, S as SmartResumeContext, Q as QualityAuditReport } from './types-BUJGYiep.js';
11
- export { b as ArtifactLifecycleInfo, A as ArtifactLifecycleState, L as LessonArtifactSummary, c as PipelineState, R as ReviewRecord, a as SotDocument, T as TaskLifecycleState } from './types-BUJGYiep.js';
10
+ import { I as ICurriculumStorage, P as ProjectStatusReport, S as SmartResumeContext, Q as QualityAuditReport } from './types-Bgk-C4K2.js';
11
+ export { b as ArtifactLifecycleInfo, A as ArtifactLifecycleState, L as LessonArtifactSummary, c as PipelineState, R as ReviewRecord, a as SotDocument, T as TaskLifecycleState } from './types-Bgk-C4K2.js';
12
12
  export { FileSystemCurriculumAdapter, FileSystemStorageOptions, STANDARD_SOT_FILES, StorageFactoryOptions, SupabaseCurriculumAdapter, SupabaseStorageConfig, atomicWriteFileSync, computeContentHash, createCurriculumStorage } from './storage/index.js';
13
13
  import { F as FrameworkPack, C as CoverageGateReport } from './standardsCoverageGate-DR5YTtlt.js';
14
14
  export { B as BloomHintSchema, a as ClassificationSchema, m as CoverageGateInput, h as FrameworkMapping, d as FrameworkMappingSchema, f as FrameworkPackManifest, b as FrameworkPackManifestSchema, e as FrameworkPackSchema, g as FrameworkStatement, c as FrameworkStatementSchema, G as GradeBandSchema, i as MappingKind, M as MappingKindSchema, P as PackLintIssue, k as PackValidationResult, j as RecordProvenance, R as RecordProvenanceSchema, S as StatementCoverageRow, n as evaluateStandardsCoverage, l as lintFrameworkPack, v as validateFrameworkPack } from './standardsCoverageGate-DR5YTtlt.js';
package/dist/index.mjs CHANGED
@@ -527,7 +527,12 @@ Guidelines:
527
527
  const unique9RouterModels = Array.from(new Set(candidateModels));
528
528
  for (const model of unique9RouterModels) {
529
529
  try {
530
- const idle = createStreamAbortController({ idleMs: 45e3, totalMs: 3e5 });
530
+ const r9Idle = options.idleTimeoutMs ?? (Number(process.env.ARTIFACT_STREAM_IDLE_TIMEOUT_MS || process.env.STREAM_IDLE_TIMEOUT_MS) || 0) ?? 0;
531
+ const r9Total = options.timeoutMs ?? (Number(process.env.ARTIFACT_STREAM_TOTAL_TIMEOUT_MS || process.env.STREAM_TOTAL_TIMEOUT_MS) || 0) ?? 0;
532
+ const idle = createStreamAbortController({
533
+ idleMs: r9Idle > 0 ? r9Idle : 9e4,
534
+ totalMs: r9Total > 0 ? r9Total : 3e5
535
+ });
531
536
  const res = await fetch(`${ninerouterBaseUrl}/chat/completions`, {
532
537
  method: "POST",
533
538
  headers: {
@@ -770,7 +775,12 @@ Guidelines:
770
775
  try {
771
776
  const rawUrl = resolveApiKey("NINEROUTER_BASE_URL") || resolveApiKey("NINE_ROUTER_BASE_URL") || "https://ai-router.orchable.app/v1";
772
777
  const fbBaseUrl = rawUrl.replace(/["']/g, "").replace(/\/$/, "");
773
- const idle = createStreamAbortController({ idleMs: 45e3, totalMs: 3e5 });
778
+ const fbIdle = options.idleTimeoutMs ?? (Number(process.env.ARTIFACT_STREAM_IDLE_TIMEOUT_MS || process.env.STREAM_IDLE_TIMEOUT_MS) || 0) ?? 0;
779
+ const fbTotal = options.timeoutMs ?? (Number(process.env.ARTIFACT_STREAM_TOTAL_TIMEOUT_MS || process.env.STREAM_TOTAL_TIMEOUT_MS) || 0) ?? 0;
780
+ const idle = createStreamAbortController({
781
+ idleMs: fbIdle > 0 ? fbIdle : 9e4,
782
+ totalMs: fbTotal > 0 ? fbTotal : 3e5
783
+ });
774
784
  const res = await fetch(`${fbBaseUrl}/chat/completions`, {
775
785
  method: "POST",
776
786
  headers: {
@@ -9706,6 +9716,16 @@ ${lessonTable}
9706
9716
  await this.savePipelineState(projectId, current);
9707
9717
  return current;
9708
9718
  }
9719
+ /** Disk adapter: purge = rm the file (best-effort, mirrors cloud deleteArtifact). */
9720
+ async deleteArtifact(projectId, relPath) {
9721
+ try {
9722
+ const projectDir = this.getProjectDir(projectId);
9723
+ const targetPath = path3.join(projectDir, relPath);
9724
+ this.assertInsideProject(projectDir, targetPath);
9725
+ if (fs2.existsSync(targetPath)) fs2.rmSync(targetPath, { force: true });
9726
+ } catch {
9727
+ }
9728
+ }
9709
9729
  };
9710
9730
  var SupabaseCurriculumAdapter = class {
9711
9731
  client;
@@ -9871,6 +9891,23 @@ var SupabaseCurriculumAdapter = class {
9871
9891
  } catch {
9872
9892
  }
9873
9893
  }
9894
+ /**
9895
+ * Split-brain root-cause fix (2026-09-14): purge must reach the cloud copy
9896
+ * too. Removes the storage object AND the indexed `curriculum_artifacts`
9897
+ * row (the row is what `readArtifact`-style indexed readers resolve first).
9898
+ * Best-effort / no-throw per the interface contract.
9899
+ */
9900
+ async deleteArtifact(projectId, relPath) {
9901
+ const fullPath = `${projectId}/${relPath.replace(/^\//, "")}`;
9902
+ try {
9903
+ await this.client.storage.from(this.bucketName).remove([fullPath]);
9904
+ } catch {
9905
+ }
9906
+ try {
9907
+ await this.client.from("curriculum_artifacts").delete().match({ project_id: projectId, rel_path: relPath });
9908
+ } catch {
9909
+ }
9910
+ }
9874
9911
  async listLessons(projectId) {
9875
9912
  const summaries = [];
9876
9913
  const processedLessons = /* @__PURE__ */ new Set();
@@ -10889,7 +10926,8 @@ function buildLanguageDirective(targetLanguage) {
10889
10926
  - All section titles, table headers, table cells, lesson names, learning objectives, pedagogical narratives, and cognitive analyses MUST be written in natural, fluent, academic ${name}.
10890
10927
  - Technical identifiers, code keywords (e.g. setup(), loop(), pinMode()), standard protocols (I2C, SPI, UART, GPIO), and component model numbers (ESP32, Arduino Uno) remain in standard technical notation, but all surrounding explanations MUST be in ${name}.
10891
10928
  - DO NOT mix in paragraphs, tables, or titles written in any other language. Strict adherence is required.${exampleLine ? `
10892
- ${exampleLine}` : ""}`;
10929
+ ${exampleLine}` : ""}
10930
+ - CJK / NON-LATIN SCRIPT BAN (ABSOLUTE): NEVER output characters from Chinese (\u6C49\u5B57), Japanese (\u304B\u306A/\u6F22\u5B57), or Korean (\uD55C\uAE00) scripts ANYWHERE in the document \u2014 not even a single glyph spliced inside a ${name} sentence. Observed past violations that are STRICTLY forbidden: \u6392\u67E5, \u5305\u542B, \u5BFC\u81F4, \u662F\u591A\u5C11, \u6280\u672F, \u771F\u673A, \u4F11\u606F, \u7EB8\u8D28. To express such meaning write it fully in ${name} or keep the ENGLISH technical term (e.g. write "t\u1EF1 ki\u1EC3m tra l\u1ED7i" / "self-debugging", "bao g\u1ED3m" / "includes"). A mechanical scanner rejects any document containing even one CJK character.`;
10893
10931
  }
10894
10932
  function matchesArtifactType(candidate, target) {
10895
10933
  const c = candidate.trim().toUpperCase();
@@ -29656,6 +29694,7 @@ ${targetLayer === 1 ? `
29656
29694
 
29657
29695
  - EVERY text/textarea field MUST have a complete, professional, ready-to-use pre-filled text in ${textLangMandate} adhering strictly to standard pedagogical terminology. NO placeholders, NO empty strings.
29658
29696
  - EVERY choice field MUST have realistic concrete options ${choiceLangMandate} with EXACTLY ONE recommended option (selected: true).
29697
+ - SCRIPT POLICY (CJK/non-Latin ban): Write ALL output STRICTLY in the ${textLangMandate} using the Latin alphabet. NEVER insert characters from CJK scripts (Chinese \u6C49\u5B57, Japanese \u304B\u306A/\u6F22\u5B57, Korean \uD55C\uAE00) or any other non-Latin script ANYWHERE in the output \u2014 not even a single character inside an otherwise Vietnamese/English sentence. If a technical term has no natural translation, keep the ENGLISH term (e.g. write "t\u1EF1 ki\u1EC3m tra l\u1ED7i" or "self-debugging", NEVER \u6392\u67E5 l\u1ED7i; write "bao g\u1ED3m", NEVER \u5305\u542B). This ban includes partial words spliced into Vietnamese text like \u6392\u67E5, \u5305\u542B, \u5BFC\u81F4, \u662F\u591A\u5C11.
29659
29698
 
29660
29699
  RETURN STRICT VALID JSON ONLY adhering exactly to this format:
29661
29700
  {