@intend-it/core 2.0.7 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +314 -41
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -168837,7 +168837,13 @@ class TypeScriptGenerator {
168837
168837
  }
168838
168838
  generateFunctionSignature(intent) {
168839
168839
  const params = intent.parameters.map((p) => `${p.name}: ${p.type}`).join(", ");
168840
- const returnType = intent.returnType.generic ? `${intent.returnType.base}<${intent.returnType.generic}>` : intent.returnType.base;
168840
+ let returnType = intent.returnType.base;
168841
+ if (intent.returnType.generic) {
168842
+ returnType += `<${intent.returnType.generic}>`;
168843
+ }
168844
+ if (intent.returnType.isArray) {
168845
+ returnType += "[]";
168846
+ }
168841
168847
  const isAsync = returnType.startsWith("Promise");
168842
168848
  const asyncKeyword = isAsync ? "async " : "";
168843
168849
  return `export ${asyncKeyword}function ${intent.name}(${params}): ${returnType} {`;
@@ -168879,6 +168885,26 @@ class TypeScriptGenerator {
168879
168885
  content: `return ${lastStep.resultVariable};`,
168880
168886
  indent: 1
168881
168887
  });
168888
+ } else {
168889
+ const returnBase = intent.returnType.base.toLowerCase();
168890
+ if (returnBase !== "void" && returnBase !== "undefined") {
168891
+ blocks.push({ type: "comment", content: "", indent: 0 });
168892
+ blocks.push({
168893
+ type: "statement",
168894
+ content: `return null as any; // PLACEHOLDER - AI will replace`,
168895
+ indent: 1
168896
+ });
168897
+ }
168898
+ }
168899
+ } else {
168900
+ const returnBase = intent.returnType.base.toLowerCase();
168901
+ if (returnBase !== "void" && returnBase !== "undefined") {
168902
+ blocks.push({ type: "comment", content: "", indent: 0 });
168903
+ blocks.push({
168904
+ type: "statement",
168905
+ content: `return null as any; // PLACEHOLDER - AI will replace`,
168906
+ indent: 1
168907
+ });
168882
168908
  }
168883
168909
  }
168884
168910
  return blocks;
@@ -169110,7 +169136,7 @@ ${request.prompt}`;
169110
169136
  // src/ai/prompt-builder.ts
169111
169137
  class PromptBuilder {
169112
169138
  buildContext(intent, fileImports, importedIntents = []) {
169113
- const returnType = intent.returnType.generic ? `${intent.returnType.base}<${intent.returnType.generic}>` : intent.returnType.base;
169139
+ const returnType = this.formatReturnType(intent.returnType);
169114
169140
  return {
169115
169141
  functionName: intent.name,
169116
169142
  parameters: intent.parameters,
@@ -169122,25 +169148,6 @@ class PromptBuilder {
169122
169148
  importedIntents
169123
169149
  };
169124
169150
  }
169125
- buildFullPrompt(context) {
169126
- let contextStr = "";
169127
- if (context.importedIntents && context.importedIntents.length > 0) {
169128
- contextStr += `
169129
-
169130
- IMPORTED DEFINITIONS (Strictly adhere to these contracts):
169131
- `;
169132
- context.importedIntents.forEach((imp) => {
169133
- const params = imp.parameters.map((p) => `${p.name}: ${p.type}`).join(", ");
169134
- contextStr += `- Function ${imp.name}(${params}) -> ${imp.returnType.base}
169135
- `;
169136
- if (imp.body.invariants.length > 0) {
169137
- imp.body.invariants.forEach((inv) => contextStr += ` Invariant: ${inv.constraint}
169138
- `);
169139
- }
169140
- });
169141
- }
169142
- return `...` + contextStr;
169143
- }
169144
169151
  buildSystemPrompt() {
169145
169152
  return `You are an expert TypeScript developer specializing in clean, production-ready code.
169146
169153
 
@@ -169225,7 +169232,7 @@ Generate ONLY the TypeScript code for this step (no explanations, no markdown).`
169225
169232
  lines.push(`IMPORTED DEFINITIONS (Strictly adhere to these contracts):`);
169226
169233
  context.importedIntents.forEach((imp) => {
169227
169234
  const params = this.formatParameters(imp.parameters);
169228
- const returnType = imp.returnType.generic ? `${imp.returnType.base}<${imp.returnType.generic}>` : imp.returnType.base;
169235
+ const returnType = this.formatReturnType(imp.returnType);
169229
169236
  lines.push(`- Function ${imp.name}(${params}) -> ${returnType}`);
169230
169237
  if (imp.body.invariants.length > 0) {
169231
169238
  imp.body.invariants.forEach((inv) => lines.push(` Invariant: ${inv.constraint}`));
@@ -169272,7 +169279,154 @@ Return ONLY the function body code (no function signature, no markdown).`);
169272
169279
  return "none";
169273
169280
  return params.map((p) => `${p.name}: ${p.type}`).join(", ");
169274
169281
  }
169282
+ formatReturnType(rt) {
169283
+ let type = rt.base;
169284
+ if (rt.generic) {
169285
+ type += `<${rt.generic}>`;
169286
+ }
169287
+ if (rt.isArray) {
169288
+ type += "[]";
169289
+ }
169290
+ return type;
169291
+ }
169292
+ buildReviewerSystemPrompt() {
169293
+ return `You are a senior code reviewer specializing in detecting logical errors in TypeScript.
169294
+
169295
+ Your task is to review generated function implementations for subtle bugs that pass syntax validation but are logically incorrect.
169296
+
169297
+ Common issues to detect:
169298
+ 1. FUNCTION SHADOWING: An inner function with the same name as the outer function, causing the outer to never be called correctly.
169299
+ 2. UNUSED VARIABLES: Variables declared but never used or returned.
169300
+ 3. MISSING STEP IMPLEMENTATION: Steps mentioned in requirements but not implemented.
169301
+ 4. INFINITE LOOPS / RECURSION: Unintended recursive calls or loops with no exit condition.
169302
+ 5. TYPE MISMATCHES: Returning wrong type or assigning incompatible types.
169303
+ 6. DEAD CODE: Code that can never be reached.
169304
+
169305
+ Response Format:
169306
+ - If the code is logically correct, respond with exactly: APPROVED
169307
+ - If there are issues, respond with:
169308
+ ISSUES:
169309
+ - [Issue 1 description]
169310
+ - [Issue 2 description]
169311
+ ...
169312
+ FIX: [Brief description of what needs to change]`;
169313
+ }
169314
+ buildReviewerPrompt(context, code) {
169315
+ const lines = [];
169316
+ lines.push(`Review this TypeScript function implementation for logical errors:
169317
+ `);
169318
+ lines.push(`Function: ${context.functionName}`);
169319
+ lines.push(`Parameters: ${this.formatParameters(context.parameters)}`);
169320
+ lines.push(`Return Type: ${context.returnType}
169321
+ `);
169322
+ lines.push(`Required Steps:`);
169323
+ context.steps.forEach((step, i) => {
169324
+ let line = `${i + 1}. "${step.instruction}"`;
169325
+ if (step.resultVariable) {
169326
+ line += ` => ${step.resultVariable}`;
169327
+ if (step.resultType)
169328
+ line += `: ${step.resultType}`;
169329
+ }
169330
+ lines.push(line);
169331
+ });
169332
+ lines.push(`
169333
+ Generated Code:`);
169334
+ lines.push("```typescript");
169335
+ lines.push(code);
169336
+ lines.push("```");
169337
+ lines.push(`
169338
+ Verify:`);
169339
+ lines.push(`1. All steps are implemented correctly`);
169340
+ lines.push(`2. No function shadowing or naming conflicts`);
169341
+ lines.push(`3. All declared variables are used`);
169342
+ lines.push(`4. Return value matches required type`);
169343
+ lines.push(`5. No infinite loops or unintended recursion`);
169344
+ lines.push(`
169345
+ Respond with APPROVED or ISSUES + FIX as specified.`);
169346
+ return lines.join(`
169347
+ `);
169348
+ }
169349
+ }
169350
+ // src/utils/debug.ts
169351
+ var COLORS = {
169352
+ reset: "\x1B[0m",
169353
+ dim: "\x1B[2m",
169354
+ cyan: "\x1B[36m",
169355
+ yellow: "\x1B[33m",
169356
+ magenta: "\x1B[35m",
169357
+ green: "\x1B[32m",
169358
+ blue: "\x1B[34m",
169359
+ gray: "\x1B[90m"
169360
+ };
169361
+
169362
+ class DebugLogger {
169363
+ enabled;
169364
+ constructor(enabled = false) {
169365
+ this.enabled = enabled;
169366
+ }
169367
+ isEnabled() {
169368
+ return this.enabled;
169369
+ }
169370
+ setEnabled(enabled) {
169371
+ this.enabled = enabled;
169372
+ }
169373
+ header(title) {
169374
+ if (!this.enabled)
169375
+ return;
169376
+ console.log();
169377
+ console.log(`${COLORS.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${COLORS.reset}`);
169378
+ console.log(`${COLORS.cyan}┃${COLORS.reset} ${COLORS.yellow}\uD83D\uDD0D DEBUG:${COLORS.reset} ${title}`);
169379
+ console.log(`${COLORS.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${COLORS.reset}`);
169380
+ }
169381
+ prompt(label, content) {
169382
+ if (!this.enabled)
169383
+ return;
169384
+ console.log();
169385
+ console.log(`${COLORS.magenta}┌─ ${label} ─────────────────────────────────────────────────────────────────${COLORS.reset}`);
169386
+ this.dimmedBlock(content);
169387
+ console.log(`${COLORS.magenta}└──────────────────────────────────────────────────────────────────────────────${COLORS.reset}`);
169388
+ }
169389
+ thinking(content) {
169390
+ if (!this.enabled || !content)
169391
+ return;
169392
+ console.log();
169393
+ console.log(`${COLORS.blue}┌─ \uD83E\uDDE0 Model Thinking ──────────────────────────────────────────────────────────${COLORS.reset}`);
169394
+ this.dimmedBlock(content);
169395
+ console.log(`${COLORS.blue}└──────────────────────────────────────────────────────────────────────────────${COLORS.reset}`);
169396
+ }
169397
+ response(label, content) {
169398
+ if (!this.enabled)
169399
+ return;
169400
+ console.log();
169401
+ console.log(`${COLORS.green}┌─ ${label} ─────────────────────────────────────────────────────────────────${COLORS.reset}`);
169402
+ this.dimmedBlock(content);
169403
+ console.log(`${COLORS.green}└──────────────────────────────────────────────────────────────────────────────${COLORS.reset}`);
169404
+ }
169405
+ log(message) {
169406
+ if (!this.enabled)
169407
+ return;
169408
+ console.log(`${COLORS.dim} [debug] ${message}${COLORS.reset}`);
169409
+ }
169410
+ info(key, value) {
169411
+ if (!this.enabled)
169412
+ return;
169413
+ console.log(`${COLORS.dim} ${key}: ${COLORS.reset}${value}`);
169414
+ }
169415
+ dimmedBlock(content) {
169416
+ const lines = content.split(`
169417
+ `);
169418
+ const maxLines = 100;
169419
+ const showLines = lines.slice(0, maxLines);
169420
+ for (const line of showLines) {
169421
+ console.log(`${COLORS.dim}│ ${line}${COLORS.reset}`);
169422
+ }
169423
+ if (lines.length > maxLines) {
169424
+ console.log(`${COLORS.dim}│ ... (${lines.length - maxLines} more lines truncated)${COLORS.reset}`);
169425
+ }
169426
+ }
169275
169427
  }
169428
+ var debugLogger = new DebugLogger(false);
169429
+
169276
169430
  // src/ai/providers/gemini.ts
169277
169431
  var DEFAULT_MODEL2 = "gemini-flash-latest";
169278
169432
  var DEFAULT_TEMPERATURE2 = 0.2;
@@ -169296,12 +169450,28 @@ class GeminiProvider {
169296
169450
  }
169297
169451
  async generateCode(request) {
169298
169452
  try {
169453
+ if (request.debug) {
169454
+ debugLogger.setEnabled(true);
169455
+ debugLogger.header(`Gemini API Call (${this.model})`);
169456
+ debugLogger.prompt("System Prompt", request.systemPrompt || "(none)");
169457
+ debugLogger.prompt("User Prompt", request.prompt);
169458
+ }
169299
169459
  const response = await this.makeRequest(request);
169460
+ const code = this.extractCode(response);
169461
+ let thinking;
169462
+ if (request.debug) {
169463
+ const fullText = response?.candidates?.[0]?.content?.parts?.[0]?.text || "";
169464
+ debugLogger.response("Gemini Response", fullText);
169465
+ }
169300
169466
  return {
169301
- code: this.extractCode(response),
169302
- success: true
169467
+ code,
169468
+ success: true,
169469
+ thinking
169303
169470
  };
169304
169471
  } catch (error) {
169472
+ if (request.debug) {
169473
+ debugLogger.log(`Error: ${error.message}`);
169474
+ }
169305
169475
  return {
169306
169476
  code: "",
169307
169477
  success: false,
@@ -169407,12 +169577,39 @@ class OllamaProvider {
169407
169577
  }
169408
169578
  async generateCode(request) {
169409
169579
  try {
169580
+ if (request.debug) {
169581
+ debugLogger.setEnabled(true);
169582
+ debugLogger.header(`Ollama API Call (${this.model})`);
169583
+ debugLogger.prompt("System Prompt", request.systemPrompt || "(none)");
169584
+ debugLogger.prompt("User Prompt", request.prompt);
169585
+ }
169410
169586
  const response = await this.makeRequest(request);
169587
+ const code = this.extractCode(response);
169588
+ let thinking;
169589
+ const fullText = response?.response || "";
169590
+ if (response?.thinking) {
169591
+ thinking = response.thinking;
169592
+ } else {
169593
+ const thinkMatch = fullText.match(/<think>([\s\S]*?)<\/think>/);
169594
+ if (thinkMatch) {
169595
+ thinking = thinkMatch[1].trim();
169596
+ }
169597
+ }
169598
+ if (request.debug) {
169599
+ if (thinking) {
169600
+ debugLogger.thinking(thinking);
169601
+ }
169602
+ debugLogger.response("Ollama Response", fullText);
169603
+ }
169411
169604
  return {
169412
- code: this.extractCode(response),
169413
- success: true
169605
+ code,
169606
+ success: true,
169607
+ thinking
169414
169608
  };
169415
169609
  } catch (error) {
169610
+ if (request.debug) {
169611
+ debugLogger.log(`Error: ${error.message}`);
169612
+ }
169416
169613
  return {
169417
169614
  code: "",
169418
169615
  success: false,
@@ -169435,6 +169632,7 @@ ${request.prompt}`;
169435
169632
  num_thread: this.num_thread
169436
169633
  }
169437
169634
  };
169635
+ body.think = true;
169438
169636
  try {
169439
169637
  const response = await fetch(url, {
169440
169638
  method: "POST",
@@ -169577,12 +169775,14 @@ class AICodeGenerator {
169577
169775
  validator;
169578
169776
  maxAttempts;
169579
169777
  projectContext;
169778
+ debug;
169580
169779
  constructor(options) {
169581
169780
  this.promptBuilder = new PromptBuilder;
169582
169781
  this.validator = new TypeScriptValidator;
169583
169782
  this.mode = options.mode || "full";
169584
169783
  this.maxAttempts = options.maxAttempts ?? 5;
169585
169784
  this.projectContext = options.projectContext;
169785
+ this.debug = options.debug ?? false;
169586
169786
  const providerName = options.provider || "gemini";
169587
169787
  if (providerName === "ollama") {
169588
169788
  if (!options.ollamaConfig) {
@@ -169650,27 +169850,26 @@ class AICodeGenerator {
169650
169850
  while (attempts < limit) {
169651
169851
  const response = await this.provider.generateCode({
169652
169852
  systemPrompt,
169653
- prompt
169853
+ prompt,
169854
+ debug: this.debug
169654
169855
  });
169655
169856
  if (!response.success) {
169656
169857
  throw new Error(`AI generation failed: ${response.error}`);
169657
169858
  }
169658
169859
  const cleanCode = this.sanitizeAIResponse(response.code);
169659
169860
  const updatedCode = this.injectImplementation(fileContent, cleanCode, functionName);
169660
- const errors = this.validator.validate(updatedCode);
169661
- if (errors.length === 0) {
169662
- return updatedCode;
169663
- }
169664
- attempts++;
169665
- if (attempts < limit) {
169666
- const errorMsg = errors.slice(0, 5).map((e) => `Line ${e.line}: ${e.message}`).join(`
169861
+ const syntaxErrors = this.validator.validate(updatedCode);
169862
+ if (syntaxErrors.length > 0) {
169863
+ attempts++;
169864
+ if (attempts < limit) {
169865
+ const errorMsg = syntaxErrors.slice(0, 5).map((e) => `Line ${e.line}: ${e.message}`).join(`
169667
169866
  `);
169668
- console.log(` ⚠️ Validation failed for ${functionName} (Attempt ${attempts}/${limit}):`);
169669
- console.log(errorMsg.split(`
169867
+ console.log(` ⚠️ Validation failed for ${functionName} (Attempt ${attempts}/${limit}):`);
169868
+ console.log(errorMsg.split(`
169670
169869
  `).map((l) => ` ${l}`).join(`
169671
169870
  `));
169672
- console.log(` Retrying with AI auto-correction...`);
169673
- prompt += `
169871
+ console.log(` Retrying with AI auto-correction...`);
169872
+ prompt += `
169674
169873
 
169675
169874
  Validation Failed (Attempt ${attempts}/${limit}).
169676
169875
  ` + `The code you generated caused errors:
@@ -169684,10 +169883,42 @@ ${errorMsg}
169684
169883
  ` + `CRITICAL INSTRUCTION: Don't just patch the code.
169685
169884
  ` + `1. First, analyze WHY this error occurred (e.g., mismatching types, undefined variable).
169686
169885
  ` + `2. Then, generate the completely fixed function body wrapped in a \`\`\`typescript block.
169886
+ `;
169887
+ } else {
169888
+ console.warn(` ❌ Validation failed for ${functionName} after ${limit} attempts.`);
169889
+ await this.explainFailure(functionName, updatedCode, syntaxErrors);
169890
+ return updatedCode;
169891
+ }
169892
+ continue;
169893
+ }
169894
+ const logicIssues = await this.verifyLogic(context, cleanCode);
169895
+ if (logicIssues === null) {
169896
+ return updatedCode;
169897
+ }
169898
+ attempts++;
169899
+ if (attempts < limit) {
169900
+ console.log(` \uD83D\uDD0D Logic review found issues for ${functionName} (Attempt ${attempts}/${limit}):`);
169901
+ console.log(` ${logicIssues.issues.slice(0, 3).join(`
169902
+ `)}`);
169903
+ console.log(` Retrying with AI auto-correction...`);
169904
+ prompt += `
169905
+
169906
+ Logic Review Failed (Attempt ${attempts}/${limit}).
169907
+ ` + `The code you generated has logical issues:
169908
+ \`\`\`typescript
169909
+ ${cleanCode}
169910
+ \`\`\`
169911
+
169912
+ ` + `Issues found:
169913
+ ${logicIssues.issues.join(`
169914
+ `)}
169915
+
169916
+ ` + `Suggested fix: ${logicIssues.fix}
169917
+
169918
+ ` + `CRITICAL INSTRUCTION: Fix all logical issues and generate the corrected function body.
169687
169919
  `;
169688
169920
  } else {
169689
- console.warn(` ❌ Validation failed for ${functionName} after ${limit} attempts.`);
169690
- await this.explainFailure(functionName, updatedCode, errors);
169921
+ console.warn(` ❌ Logic verification failed for ${functionName} after ${limit} attempts.`);
169691
169922
  return updatedCode;
169692
169923
  }
169693
169924
  }
@@ -169698,6 +169929,45 @@ ${errorMsg}
169698
169929
  sanitized = sanitized.replace(/^\s*import\s+.*;?\s*$/gm, "");
169699
169930
  return sanitized.trim();
169700
169931
  }
169932
+ async verifyLogic(context, code) {
169933
+ try {
169934
+ const systemPrompt = this.promptBuilder.buildReviewerSystemPrompt();
169935
+ const prompt = this.promptBuilder.buildReviewerPrompt(context, code);
169936
+ const response = await this.provider.generateCode({
169937
+ systemPrompt,
169938
+ prompt,
169939
+ debug: this.debug
169940
+ });
169941
+ if (!response.success) {
169942
+ console.warn(` ⚠️ Logic verification skipped (AI error)`);
169943
+ return null;
169944
+ }
169945
+ const reviewResult = response.code.trim();
169946
+ if (reviewResult.toUpperCase().startsWith("APPROVED")) {
169947
+ return null;
169948
+ }
169949
+ const issuesMatch = reviewResult.match(/ISSUES:\s*([\s\S]*?)(?:FIX:|$)/i);
169950
+ const fixMatch = reviewResult.match(/FIX:\s*([\s\S]*?)$/i);
169951
+ if (issuesMatch) {
169952
+ const issueLines = issuesMatch[1].split(`
169953
+ `).map((l) => l.trim()).filter((l) => l.startsWith("-") || l.startsWith("*") || l.match(/^\d+\./)).map((l) => l.replace(/^[-*]\s*/, "").replace(/^\d+\.\s*/, ""));
169954
+ const fix = fixMatch ? fixMatch[1].trim() : "Review and fix the issues listed above.";
169955
+ if (issueLines.length > 0) {
169956
+ return { issues: issueLines, fix };
169957
+ }
169958
+ }
169959
+ if (reviewResult.toLowerCase().includes("issue") || reviewResult.toLowerCase().includes("problem")) {
169960
+ return {
169961
+ issues: ["Reviewer found potential issues (see details)"],
169962
+ fix: reviewResult.slice(0, 200)
169963
+ };
169964
+ }
169965
+ return null;
169966
+ } catch (err) {
169967
+ console.warn(` ⚠️ Logic verification skipped (error)`);
169968
+ return null;
169969
+ }
169970
+ }
169701
169971
  async explainFailure(functionName, code, errors) {
169702
169972
  const errorMsg = errors.map((e) => `Line ${e.line}: ${e.message}`).join(`
169703
169973
  `);
@@ -169717,7 +169987,8 @@ Focus on the root cause. Keep it concise.
169717
169987
  console.log(` \uD83E\uDD16 Analyzing failure...`);
169718
169988
  const response = await this.provider.generateCode({
169719
169989
  systemPrompt: "You are a helpful coding assistant explaining compile errors.",
169720
- prompt
169990
+ prompt,
169991
+ debug: this.debug
169721
169992
  });
169722
169993
  if (response.success) {
169723
169994
  console.log(`
@@ -169837,6 +170108,7 @@ function computeHash(content, config) {
169837
170108
  }
169838
170109
  export {
169839
170110
  generateTypeScript,
170111
+ debugLogger,
169840
170112
  computeHash,
169841
170113
  TypeScriptValidator,
169842
170114
  TypeScriptGenerator,
@@ -169845,5 +170117,6 @@ export {
169845
170117
  GeminiProvider,
169846
170118
  GeminiClient,
169847
170119
  FileSystemCAS,
170120
+ DebugLogger,
169848
170121
  AICodeGenerator
169849
170122
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intend-it/core",
3
- "version": "2.0.7",
3
+ "version": "3.0.1",
4
4
  "description": "Core compiler and AI integration for the Intend programming language",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -35,7 +35,7 @@
35
35
  ],
36
36
  "license": "MIT",
37
37
  "dependencies": {
38
- "@intend-it/parser": "^1.1.6",
38
+ "@intend-it/parser": "^1.2.1",
39
39
  "@google/generative-ai": "^0.21.0"
40
40
  },
41
41
  "devDependencies": {
@@ -43,6 +43,6 @@
43
43
  "typescript": "^5.0.0"
44
44
  },
45
45
  "peerDependencies": {
46
- "@intend-it/parser": ">=1.1.6"
46
+ "@intend-it/parser": ">=1.2.1"
47
47
  }
48
48
  }