init project

This commit is contained in:
root
2026-07-31 13:12:54 -04:00
parent 0da92d5e02
commit f3863f760c
7215 changed files with 1860260 additions and 1 deletions
+119
View File
@@ -0,0 +1,119 @@
import fs from 'node:fs';
import path from 'node:path';
import { z } from 'zod';
import { errorResult, jsonResult, toErrorMessage } from '../shared.js';
import { requireReact } from './requireReact.js';
export function registerAddReactRouteTool(server) {
server.registerTool('add_react_route', {
title: 'Add React Route',
description: 'Add a route entry for the detected React router: Next.js App Router (creates a page file), Next.js Pages Router (creates a page file), react-router (appends a route to a routes file), or TanStack Router (appends a file-based route under src/routes).',
inputSchema: {
path: z.string().min(1).describe('URL path, e.g. "/users" or "/users/:id".'),
component: z
.string()
.min(1)
.describe('Component name to import, e.g. "UserList" or a relative path like "./pages/UserList".'),
file: z.string().optional().describe('Override the file to write/edit. Auto-detected by default.'),
},
}, async ({ path: routePath, component, file: fileOverride }) => {
try {
const react = requireReact();
const router = detectRouterType(react.root);
switch (router) {
case 'next-app':
case 'next-pages': {
const file = fileOverride ??
path.join(react.root, router === 'next-app' ? 'app' : 'pages', ...routePath.split('/').filter(Boolean), 'page.tsx');
const created = writeNextPage(file, component, router === 'next-app');
return jsonResult({ router, file, created });
}
case 'react-router':
case 'tanstack-router': {
const file = fileOverride ??
(router === 'react-router'
? path.join(react.root, 'src', 'routes.tsx')
: path.join(react.root, 'src', 'routes', `${routePath.replace(/[^a-z0-9]/gi, '-')}.tsx`));
const wired = appendRoute(file, routePath, component, router);
return jsonResult({ router, file, wired });
}
default:
return jsonResult({
router: 'unknown',
message: 'No known React router detected (Next.js app/pages, react-router, or TanStack Router). ' +
'Provide the file argument explicitly to add a route entry.',
});
}
}
catch (error) {
return errorResult(toErrorMessage(error));
}
});
}
function detectRouterType(root) {
if (fs.existsSync(path.join(root, 'app', 'layout.tsx')) || fs.existsSync(path.join(root, 'app', 'layout.jsx'))) {
return 'next-app';
}
if (fs.existsSync(path.join(root, 'pages', 'index.tsx')) || fs.existsSync(path.join(root, 'pages', 'index.jsx'))) {
return 'next-pages';
}
if (fs.existsSync(path.join(root, 'src', 'app', 'layout.tsx')) || fs.existsSync(path.join(root, 'src', 'app', 'layout.jsx'))) {
return 'next-app';
}
if (fs.existsSync(path.join(root, 'src', 'pages', 'index.tsx')) ||
fs.existsSync(path.join(root, 'src', 'pages', 'index.jsx'))) {
return 'next-pages';
}
const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
if (deps['@tanstack/react-router'])
return 'tanstack-router';
if (deps['react-router-dom'] || deps['react-router'])
return 'react-router';
return 'unknown';
}
function writeNextPage(file, component, appRouter) {
fs.mkdirSync(path.dirname(file), { recursive: true });
if (fs.existsSync(file))
return false;
const importPath = component.startsWith('.') ? component : `./${component}`;
const contents = appRouter
? `import { ${component} } from '${importPath}';
export default function Page() {
return <${component} />;
}
`
: `import { ${component} } from '${importPath}';
export default function ${component}Page() {
return <${component} />;
}
`;
fs.writeFileSync(file, contents);
return true;
}
function appendRoute(file, routePath, component, router) {
fs.mkdirSync(path.dirname(file), { recursive: true });
const importPath = component.startsWith('.') ? component : `./${component}`;
const routeLine = router === 'tanstack-router'
? `// TODO: route ${routePath} -> <${component} /> (TanStack Router uses file-based routing; this file was created).`
: `{ path: '${routePath}', element: <${component} /> },`;
if (!fs.existsSync(file)) {
fs.writeFileSync(file, `import { ${component} } from '${importPath}';
// Add this route to your router configuration:
${routeLine}
`);
return true;
}
const existing = fs.readFileSync(file, 'utf8');
if (existing.includes(routeLine.trim()))
return false;
let next = existing;
if (!new RegExp(`import\\s+\\{[^}]*\\b${component}\\b[^}]*\\}\\s+from\\s+['"]${importPath.replace(/\./g, '\\.')}['"];`).test(next)) {
next = `import { ${component} } from '${importPath}';\n${next}`;
}
fs.writeFileSync(file, `${next.trimEnd()}\n${routeLine}\n`);
return true;
}
//# sourceMappingURL=addReactRoute.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"addReactRoute.js","sourceRoot":"","sources":["../../../src/tools/react/addReactRoute.ts"],"names":[],"mappings":"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"}
+107
View File
@@ -0,0 +1,107 @@
import fs from 'node:fs';
import path from 'node:path';
import { z } from 'zod';
import { errorResult, jsonResult, toErrorMessage } from '../shared.js';
import { requireReact } from './requireReact.js';
export function registerAnalyzeReactComponentTool(server) {
server.registerTool('analyze_react_component', {
title: 'Analyze React Component',
description: 'Static scan of a React component file for common issues: missing `key` in lists, hook-rule violations, unused props, and Next.js App Router heuristics (hooks/events without "use client").',
inputSchema: {
file: z
.string()
.min(1)
.describe('Path to the component file, relative to the React project root.'),
},
}, async ({ file }) => {
try {
const react = requireReact();
const absolutePath = path.resolve(react.root, file);
if (!absolutePath.startsWith(react.root + path.sep)) {
return errorResult('Refusing to analyze a file outside the React project root.');
}
if (!fs.existsSync(absolutePath)) {
return errorResult(`File not found: ${file}`);
}
const source = fs.readFileSync(absolutePath, 'utf8');
const issues = [];
const lines = source.split('\n');
const hasUseClient = /^\s*['"]use client['"]\s*;?/m.test(source);
const usesClientOnlyApis = /\bon[A-Z][A-Za-z]+\s*=/.test(source) ||
/\buse(State|Effect|Reducer|Ref|LayoutEffect|Callback|Memo|Context)\s*\(/.test(source);
if (!hasUseClient && usesClientOnlyApis) {
issues.push({
type: 'missing-use-client',
line: 1,
message: 'File uses client-only APIs (hooks or event handlers) but is missing a "use client" directive. ' +
'Required for Next.js App Router Client Components.',
});
}
for (let i = 0; i < lines.length; i++) {
const line = lines[i] ?? '';
const lineNumber = i + 1;
// Missing key in array maps (heuristic).
if (/(\w+\s*\.\s*map|React\.Children\.map)\s*\(/.test(line) && !/key\s*=/.test(line)) {
issues.push({
type: 'missing-key',
line: lineNumber,
message: 'Array.map without a key prop on the returned element.',
});
}
// Conditional or loop hook calls (simple heuristics).
if (/\buse[A-Z][A-Za-z0-9]*\s*\(/.test(line)) {
if (/\b(if|while|for|switch)\s*\(/.test(line)) {
issues.push({
type: 'rules-of-hooks',
line: lineNumber,
message: 'Hook call inside a conditional or loop block.',
});
}
}
// Functions / non-serializable values passed into imported components from a Server Component.
if (!hasUseClient && /<(?:[A-Z][\w.]*)\b[^>]*\{[^}]*=>/.test(line)) {
issues.push({
type: 'server-to-client-props',
line: lineNumber,
message: 'Looks like a function/arrow is passed as a prop from a Server Component. ' +
'Move interactive children into a Client Component ("use client").',
});
}
}
// Unused props: find destructured props and see if they are referenced.
const propDestructuring = source.match(/function\s+\w+\s*\(\s*\{\s*([^}]+)\s*\}\s*\)/);
if (propDestructuring && propDestructuring[1]) {
const rawProps = propDestructuring[1];
const props = rawProps
.split(',')
.map((p) => p.trim().split(/\s*:\s*/)[0]?.replace(/\?|:.*$/, '').trim() ?? '')
.filter(Boolean);
const destructuringIndex = propDestructuring.index ?? 0;
for (const prop of props) {
const propRegex = new RegExp(`\\b${prop}\\b`, 'g');
const matches = [...source.matchAll(propRegex)].length;
// The declaration itself counts as one match, plus the original destructuring pattern may add another.
if (matches <= 2) {
issues.push({
type: 'unused-prop',
line: source.substring(0, destructuringIndex).split('\n').length,
message: `Prop "${prop}" appears unused in the component body.`,
});
}
}
}
return jsonResult({
file,
projectRoot: react.root,
hasUseClient,
issues,
issueCount: issues.length,
note: 'This is a heuristic static scan, not a full ESLint run. Use run_lint for comprehensive checks.',
});
}
catch (error) {
return errorResult(toErrorMessage(error));
}
});
}
//# sourceMappingURL=analyzeComponent.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"analyzeComponent.js","sourceRoot":"","sources":["../../../src/tools/react/analyzeComponent.ts"],"names":[],"mappings":"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"}
+125
View File
@@ -0,0 +1,125 @@
import fs from 'node:fs';
import path from 'node:path';
import { z } from 'zod';
import { resolveWorkspacePath } from '../../lib/sandbox.js';
import { pascalCase } from '../../lib/strings.js';
import { errorResult, jsonResult, toErrorMessage } from '../shared.js';
import { requireReact } from './requireReact.js';
function resolveAppDir(root) {
if (fs.existsSync(path.join(root, 'src', 'app')))
return path.join(root, 'src', 'app');
return path.join(root, 'app');
}
function routeSegments(routePath) {
return routePath.split('/').filter(Boolean);
}
function assertNextAppRouter(root) {
const appDir = resolveAppDir(root);
const hasLayout = fs.existsSync(path.join(appDir, 'layout.tsx')) ||
fs.existsSync(path.join(appDir, 'layout.jsx')) ||
fs.existsSync(path.join(root, 'next.config.js')) ||
fs.existsSync(path.join(root, 'next.config.mjs')) ||
fs.existsSync(path.join(root, 'next.config.ts'));
if (!hasLayout && !fs.existsSync(appDir)) {
throw new Error('Next.js App Router not detected. Expected an app/ (or src/app/) directory or next.config.*.');
}
}
export function registerGenerateNextPageTool(server) {
server.registerTool('generate_next_page', {
title: 'Generate Next.js Page',
description: 'Scaffold a Next.js App Router page.tsx under app/{path}/ (or src/app/). Optionally also creates loading.tsx and error.tsx.',
inputSchema: {
path: z.string().min(1).describe('URL path, e.g. "/users" or "/blog/[slug]".'),
title: z.string().optional().describe('Optional heading text; defaults to a PascalCase name from the path.'),
withLoading: z.boolean().optional().default(false).describe('Also create loading.tsx.'),
withError: z.boolean().optional().default(false).describe('Also create error.tsx.'),
overwrite: z.boolean().optional().default(false),
},
}, async ({ path: routePath, title, withLoading, withError, overwrite }) => {
try {
const react = requireReact();
assertNextAppRouter(react.root);
const typescript = fs.existsSync(path.join(react.root, 'tsconfig.json'));
const ext = typescript ? 'tsx' : 'jsx';
const appDir = resolveAppDir(react.root);
const dir = resolveWorkspacePath(appDir, path.join(...routeSegments(routePath)));
fs.mkdirSync(dir, { recursive: true });
const heading = title ?? pascalCase(routeSegments(routePath).join(' ') || 'Page');
const files = [];
const pageFile = path.join(dir, `page.${ext}`);
if (!overwrite && fs.existsSync(pageFile)) {
return errorResult(`"${pageFile}" already exists. Pass overwrite: true to replace it.`);
}
fs.writeFileSync(pageFile, `export default function ${heading.replace(/[^A-Za-z0-9]/g, '') || 'Page'}Page() {
return (
<main>
<h1>${heading}</h1>
</main>
);
}
`);
files.push(pageFile);
if (withLoading) {
const loadingFile = path.join(dir, `loading.${ext}`);
if (overwrite || !fs.existsSync(loadingFile)) {
fs.writeFileSync(loadingFile, `export default function Loading() {\n return <p>Loading…</p>;\n}\n`);
files.push(loadingFile);
}
}
if (withError) {
const errorFile = path.join(dir, `error.${ext}`);
if (overwrite || !fs.existsSync(errorFile)) {
fs.writeFileSync(errorFile, `'use client';\n\nexport default function Error({ error, reset }: { error: Error; reset: () => void }) {\n return (\n <div>\n <p>{error.message}</p>\n <button type="button" onClick={() => reset()}>\n Try again\n </button>\n </div>\n );\n}\n`);
files.push(errorFile);
}
}
return jsonResult({ router: 'app', path: routePath, files });
}
catch (error) {
return errorResult(toErrorMessage(error));
}
});
}
export function registerGenerateNextLayoutTool(server) {
server.registerTool('generate_next_layout', {
title: 'Generate Next.js Layout',
description: 'Scaffold a Next.js App Router layout.tsx under app/{path}/ (or src/app/).',
inputSchema: {
path: z
.string()
.optional()
.default('')
.describe('URL path segment for a nested layout, e.g. "/dashboard". Empty for the root layout.'),
overwrite: z.boolean().optional().default(false),
},
}, async ({ path: routePath, overwrite }) => {
try {
const react = requireReact();
assertNextAppRouter(react.root);
const typescript = fs.existsSync(path.join(react.root, 'tsconfig.json'));
const ext = typescript ? 'tsx' : 'jsx';
const appDir = resolveAppDir(react.root);
const segments = routeSegments(routePath ?? '');
const dir = segments.length === 0 ? appDir : resolveWorkspacePath(appDir, path.join(...segments));
fs.mkdirSync(dir, { recursive: true });
const layoutFile = path.join(dir, `layout.${ext}`);
if (!overwrite && fs.existsSync(layoutFile)) {
return errorResult(`"${layoutFile}" already exists. Pass overwrite: true to replace it.`);
}
const childrenType = typescript ? '{ children }: { children: React.ReactNode }' : '{ children }';
fs.writeFileSync(layoutFile, `export default function Layout(${childrenType}) {
return (
<section>
{children}
</section>
);
}
`);
return jsonResult({ router: 'app', path: routePath || '/', file: layoutFile });
}
catch (error) {
return errorResult(toErrorMessage(error));
}
});
}
//# sourceMappingURL=generateNextFiles.js.map
File diff suppressed because one or more lines are too long
+71
View File
@@ -0,0 +1,71 @@
import fs from 'node:fs';
import path from 'node:path';
import { z } from 'zod';
import { camelCase, pascalCase } from '../../lib/strings.js';
import { resolveWorkspacePath } from '../../lib/sandbox.js';
import { errorResult, jsonResult, toErrorMessage } from '../shared.js';
import { requireReact } from './requireReact.js';
export function registerGenerateReactHookTool(server) {
server.registerTool('generate_react_hook', {
title: 'Generate React Hook',
description: 'Scaffold a custom React hook (useXyz.ts) and a matching test file. Detects TypeScript from tsconfig.json.',
inputSchema: {
name: z
.string()
.min(1)
.describe('Hook name without the "use" prefix, e.g. "Counter" or "fetchUser" (camelCase is fine).'),
directory: z
.string()
.optional()
.describe('Directory relative to the React project root. Defaults to "src/hooks".'),
withTest: z.boolean().optional().default(true),
overwrite: z.boolean().optional().default(false),
},
}, async ({ name, directory, withTest, overwrite }) => {
try {
const react = requireReact();
const typescript = fs.existsSync(path.join(react.root, 'tsconfig.json'));
const ext = typescript ? 'ts' : 'js';
const hookName = name.startsWith('use') ? camelCase(name) : `use${pascalCase(name)}`;
const dir = resolveWorkspacePath(react.root, directory ?? 'src/hooks');
const hookFile = path.join(dir, `${hookName}.${ext}`);
assertNotExists(hookFile, overwrite);
fs.mkdirSync(dir, { recursive: true });
fs.writeFileSync(hookFile, `import { useState } from 'react';
export function ${hookName}() {
const [count, setCount] = useState(0);
return { count, increment: () => setCount((c) => c + 1) };
}
`);
const files = [hookFile];
if (withTest) {
const testFile = path.join(dir, `${hookName}.test.${ext}`);
assertNotExists(testFile, overwrite);
fs.writeFileSync(testFile, `import { describe, expect, it } from 'vitest';
import { renderHook, act } from '@testing-library/react';
import { ${hookName} } from './${hookName}';
describe('${hookName}', () => {
it('increments count', () => {
const { result } = renderHook(() => ${hookName}());
act(() => result.current.increment());
expect(result.current.count).toBe(1);
});
});
`);
files.push(testFile);
}
return jsonResult({ name: hookName, files });
}
catch (error) {
return errorResult(toErrorMessage(error));
}
});
}
function assertNotExists(file, overwrite) {
if (!overwrite && fs.existsSync(file)) {
throw new Error(`"${file}" already exists. Pass overwrite: true to replace it.`);
}
}
//# sourceMappingURL=generateReactHook.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"generateReactHook.js","sourceRoot":"","sources":["../../../src/tools/react/generateReactHook.ts"],"names":[],"mappings":"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"}
+14
View File
@@ -0,0 +1,14 @@
import { registerGenerateReactHookTool } from './generateReactHook.js';
import { registerAddReactRouteTool } from './addReactRoute.js';
import { registerRunReactTestsTool } from './runReactTests.js';
import { registerAnalyzeReactComponentTool } from './analyzeComponent.js';
import { registerGenerateNextLayoutTool, registerGenerateNextPageTool } from './generateNextFiles.js';
export function registerReactTools(server) {
registerGenerateReactHookTool(server);
registerAddReactRouteTool(server);
registerRunReactTestsTool(server);
registerAnalyzeReactComponentTool(server);
registerGenerateNextPageTool(server);
registerGenerateNextLayoutTool(server);
}
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/react/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,6BAA6B,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,iCAAiC,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,EAAE,8BAA8B,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAEtG,MAAM,UAAU,kBAAkB,CAAC,MAAiB;IAClD,6BAA6B,CAAC,MAAM,CAAC,CAAC;IACtC,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAClC,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAClC,iCAAiC,CAAC,MAAM,CAAC,CAAC;IAC1C,4BAA4B,CAAC,MAAM,CAAC,CAAC;IACrC,8BAA8B,CAAC,MAAM,CAAC,CAAC;AACzC,CAAC"}
+15
View File
@@ -0,0 +1,15 @@
import { config } from '../../config.js';
import { detectProject } from '../../lib/frameworks/detect.js';
import { ReactAdapter } from '../../lib/frameworks/react.js';
export function requireReact() {
const detected = detectProject(config.workspaceRoot);
if (detected.frontend instanceof ReactAdapter) {
return detected.frontend;
}
if (detected.primary instanceof ReactAdapter) {
return detected.primary;
}
throw new Error('No React project detected in WORKSPACE_ROOT. ' +
'Expected a package.json with a react dependency (or react-scripts/vite/next config) at the workspace root.');
}
//# sourceMappingURL=requireReact.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"requireReact.js","sourceRoot":"","sources":["../../../src/tools/react/requireReact.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,MAAM,UAAU,YAAY;IAC1B,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IACrD,IAAI,QAAQ,CAAC,QAAQ,YAAY,YAAY,EAAE,CAAC;QAC9C,OAAO,QAAQ,CAAC,QAAQ,CAAC;IAC3B,CAAC;IACD,IAAI,QAAQ,CAAC,OAAO,YAAY,YAAY,EAAE,CAAC;QAC7C,OAAO,QAAQ,CAAC,OAAO,CAAC;IAC1B,CAAC;IACD,MAAM,IAAI,KAAK,CACb,+CAA+C;QAC7C,4GAA4G,CAC/G,CAAC;AACJ,CAAC"}
+67
View File
@@ -0,0 +1,67 @@
import { z } from 'zod';
import { config } from '../../config.js';
import { detectJsPackageManager, runScriptCommandFor } from '../../lib/frameworks/packageManager.js';
import { runCommand } from '../../lib/runCommand.js';
import { errorResult, jsonResult, toErrorMessage } from '../shared.js';
import { requireReact } from './requireReact.js';
function parseReactTestingLibraryOutput(output) {
// Extract failing test names and common RTL errors for a quick summary.
const failingTests = output
.split(/\n(?=\s*FAIL|●)/)
.filter((chunk) => chunk.includes('●'))
.map((chunk) => {
const match = chunk.match(/●\s*(.+?)(?:\n|$)/);
return match?.[1]?.trim() ?? null;
})
.filter((item) => Boolean(item));
const rtlErrors = [];
if (/Unable to find an element/i.test(output))
rtlErrors.push('Unable to find an element (getBy/queryBy failed)');
if (/Found multiple elements/i.test(output))
rtlErrors.push('Found multiple elements with the same query');
if (/found accessibility element/i.test(output))
rtlErrors.push('Role/name based query mismatch');
if (/Timed out in waitFor/i.test(output))
rtlErrors.push('waitFor timeout (async assertion not satisfied)');
if (/Warning: An update to .* inside a test was not wrapped in act/i.test(output)) {
rtlErrors.push('Missing act() wrapper around state update');
}
const totalMatch = output.match(/Tests\s+(\d+)\s+passed/i) || output.match(/Test Suites?:\s*(\d+)\s+passed/i);
return {
failingTestCount: failingTests.length,
failingTests: failingTests.slice(0, 10),
rtlErrors: rtlErrors.slice(0, 10),
testsPassed: totalMatch ? Number(totalMatch[1]) : null,
};
}
export function registerRunReactTestsTool(server) {
server.registerTool('run_react_tests', {
title: 'Run React Tests',
description: 'Run the React test runner (Jest/Vitest + React Testing Library) via package.json "test" script and surface RTL-specific failures.',
inputSchema: {
extraArgs: z
.array(z.string())
.optional()
.describe('Extra CLI args, e.g. ["--filter", "UserCard"].'),
},
}, async ({ extraArgs }) => {
try {
const react = requireReact();
const pm = detectJsPackageManager(react.root);
const { command, args } = runScriptCommandFor(pm, 'test', extraArgs ?? []);
const result = await runCommand(command, args, {
cwd: react.root,
timeoutMs: config.scaffoldCommandTimeoutMs,
});
return jsonResult({
runner: 'npm-test-script',
summary: parseReactTestingLibraryOutput(result.output),
...result,
});
}
catch (error) {
return errorResult(toErrorMessage(error));
}
});
}
//# sourceMappingURL=runReactTests.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"runReactTests.js","sourceRoot":"","sources":["../../../src/tools/react/runReactTests.ts"],"names":[],"mappings":"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"}