@ms-cloudpack/esbuild-node-helpers 0.1.5 → 0.1.6
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.
|
@@ -36,7 +36,7 @@ export function analyzeLicenses(includedPackages, options) {
|
|
|
36
36
|
function readAndValidateLicenses(includedPackages, options) {
|
|
37
37
|
const dependencies = [];
|
|
38
38
|
const errorDependencies = [];
|
|
39
|
-
const sortedEntries = Object.entries(includedPackages).sort((a, b) => a[1].name.localeCompare(b[1].name));
|
|
39
|
+
const sortedEntries = Object.entries(includedPackages).sort((a, b) => a[1].name.localeCompare(b[1].name) || a[1].version.localeCompare(b[1].version));
|
|
40
40
|
for (const [depPkgRoot, depPkgJson] of sortedEntries) {
|
|
41
41
|
const pkgMeta = {
|
|
42
42
|
name: depPkgJson.name,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzeLicenses.js","sourceRoot":"","sources":["../../src/license/analyzeLicenses.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs';\nimport hostedGitInfo from 'hosted-git-info';\nimport path from 'path';\nimport validateLicense from 'validate-npm-package-license';\nimport type { PackageJson, PackageJsonPerson } from '../types.ts';\nimport { BundleError } from '../utils/BundleError.ts';\nimport { bulletedList, colors, logError } from '../utils/logHelpers.ts';\nimport type { Dependency, ErrorDependency, LicensePluginOptions } from './types.ts';\n\n/**\n * Analyze licenses for all included packages.\n * @param includedPackages Mapping from package root to package.json for all packages in the bundle\n */\nexport function analyzeLicenses(\n includedPackages: Record<string, PackageJson>,\n options: Pick<LicensePluginOptions, 'packageRoot' | 'unacceptableLicenseTest'>,\n): { dependencies: Dependency[] } | { error: string } {\n let dependencies: Dependency[];\n let errorDependencies: ErrorDependency[];\n try {\n ({ dependencies, errorDependencies } = readAndValidateLicenses(includedPackages, options));\n } catch (err) {\n // this would be due to some issue reading a file (the function isn't intended to throw)\n // but we need to catch it for clear error reporting in the esbuild onEnd context\n logError(`Unexpected error during license analysis: ${(err as Error).stack || err}`);\n throw new BundleError('Unexpected error during license analysis', { alreadyLogged: true, cause: err });\n }\n\n if (errorDependencies.length) {\n // Return the formatted string from the function to verify the output formatting\n // (it's hard to test this via the esbuild plugin)\n const errors = errorDependencies.map((dep) => [`${dep.name}@${dep.version} (${dep.path})`, dep.issues]).flat(1);\n return {\n error: colors.red(`${colors.bold('ERROR:')} Found dependencies with license issues:\\n${bulletedList(errors)}`),\n };\n }\n\n return { dependencies };\n}\n\n/**\n * Check the license specified in package.json, and if it's valid, read the license and notice text.\n */\nfunction readAndValidateLicenses(\n includedPackages: Record<string, PackageJson>,\n options: Pick<LicensePluginOptions, 'packageRoot' | 'unacceptableLicenseTest'>,\n): { dependencies: Dependency[]; errorDependencies: ErrorDependency[] } {\n const dependencies: Dependency[] = [];\n const errorDependencies: ErrorDependency[] = [];\n\n const sortedEntries = Object.entries(includedPackages).sort((a, b) => a[1].name.localeCompare(b[1].name));\n for (const [depPkgRoot, depPkgJson] of sortedEntries) {\n const pkgMeta = {\n name: depPkgJson.name,\n version: depPkgJson.version,\n path: path.relative(options.packageRoot, depPkgRoot).replace(/\\\\/g, '/'),\n };\n const license = depPkgJson.license;\n if (!license || typeof license !== 'string') {\n errorDependencies.push({\n ...pkgMeta,\n issues: [license ? `Unexpected \"license\" format ${JSON.stringify(license)}` : 'Missing \"license\"'],\n });\n continue;\n }\n\n const licenseResult = validateLicense(license);\n if (!licenseResult.validForNewPackages) {\n errorDependencies.push({\n ...pkgMeta,\n issues: [`Invalid \"license\" value ${JSON.stringify(license)}`, ...(licenseResult.warnings || [])],\n });\n continue;\n }\n const licenseInFilePath = licenseResult.inFile && path.join(depPkgRoot, licenseResult.inFile);\n if (licenseInFilePath && !fs.existsSync(licenseInFilePath)) {\n errorDependencies.push({\n ...pkgMeta,\n issues: [`License file \"${licenseResult.inFile}\" (specified by \"SEE LICENSE IN\") not found`],\n });\n continue;\n }\n\n if (options.unacceptableLicenseTest?.(license)) {\n errorDependencies.push({\n ...pkgMeta,\n issues: [\n `License ${JSON.stringify(license)} is not allowed (if incorrect, update the unacceptableLicenseTest setting)`,\n ],\n });\n continue;\n }\n\n const files = fs.readdirSync(depPkgRoot);\n // Read the license from either \"SEE LICENSE IN ___\" or a file named LICENSE*\n let licenseText: string | undefined;\n if (licenseInFilePath) {\n licenseText = fs.readFileSync(licenseInFilePath, 'utf8');\n } else {\n licenseText = findFile(/^license/i, files, depPkgRoot) || findFile(/^copying/i, files, depPkgRoot);\n }\n // Just look for a \"notice\" file at the root for notices\n const noticeText = findFile(/^notice/i, files, depPkgRoot);\n\n // Get author from package.json and/or \"authors\" file\n let author = personToString(depPkgJson.author);\n const authorsText = findFile(/^authors/i, files, depPkgRoot);\n if (authorsText) {\n author = (author ? author + '\\n' : '') + authorsText;\n }\n\n // Same with contributors\n let contributors = depPkgJson.contributors?.map(personToString).filter(Boolean).join('\\n');\n const contributorsText = findFile(/^contributors?/i, files, depPkgRoot);\n if (contributorsText) {\n contributors = (contributors ? contributors + '\\n' : '') + contributorsText;\n }\n\n const maintainers = depPkgJson.maintainers?.map(personToString).join('\\n');\n\n // Following CG, use \"homepage\" by default, followed by \"repository\"\n let url = depPkgJson.homepage;\n const repository = depPkgJson.repository;\n if (!url && repository) {\n url = typeof repository === 'string' ? repository : repository.url;\n const gitInfo = hostedGitInfo.fromUrl(url);\n if (gitInfo) {\n url = gitInfo.browse();\n }\n }\n\n dependencies.push({\n name: pkgMeta.name,\n version: pkgMeta.version,\n author,\n contributors,\n maintainers,\n url,\n license,\n licenseText,\n noticeText,\n });\n }\n\n return { dependencies, errorDependencies };\n}\n\n/**\n * Convert a person field to a string\n */\nfunction personToString(person: PackageJsonPerson | undefined): string | undefined {\n if (!person || typeof person === 'string') {\n return person;\n }\n const { name, email, url } = person;\n return `${name}${email ? ` <${email}>` : ''}${url ? ` (${url})` : ''}`;\n}\n\n/**\n * Find and read a file in a directory that matches a specific pattern.\n * @param isMatch - The function or regexp to match the file name.\n * @param files - The list of files to search.\n * @param dir - The parent directory path.\n * @returns The file contents if found (whitespace trimmed), otherwise undefined.\n */\nfunction findFile(isMatch: RegExp | ((file: string) => boolean), files: string[], dir: string): string | undefined {\n const match = files.find(typeof isMatch === 'function' ? isMatch : (file) => isMatch.test(file));\n return match && fs.readFileSync(path.join(dir, match), 'utf8').trim();\n}\n"]}
|
|
1
|
+
{"version":3,"file":"analyzeLicenses.js","sourceRoot":"","sources":["../../src/license/analyzeLicenses.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs';\nimport hostedGitInfo from 'hosted-git-info';\nimport path from 'path';\nimport validateLicense from 'validate-npm-package-license';\nimport type { PackageJson, PackageJsonPerson } from '../types.ts';\nimport { BundleError } from '../utils/BundleError.ts';\nimport { bulletedList, colors, logError } from '../utils/logHelpers.ts';\nimport type { Dependency, ErrorDependency, LicensePluginOptions } from './types.ts';\n\n/**\n * Analyze licenses for all included packages.\n * @param includedPackages Mapping from package root to package.json for all packages in the bundle\n */\nexport function analyzeLicenses(\n includedPackages: Record<string, PackageJson>,\n options: Pick<LicensePluginOptions, 'packageRoot' | 'unacceptableLicenseTest'>,\n): { dependencies: Dependency[] } | { error: string } {\n let dependencies: Dependency[];\n let errorDependencies: ErrorDependency[];\n try {\n ({ dependencies, errorDependencies } = readAndValidateLicenses(includedPackages, options));\n } catch (err) {\n // this would be due to some issue reading a file (the function isn't intended to throw)\n // but we need to catch it for clear error reporting in the esbuild onEnd context\n logError(`Unexpected error during license analysis: ${(err as Error).stack || err}`);\n throw new BundleError('Unexpected error during license analysis', { alreadyLogged: true, cause: err });\n }\n\n if (errorDependencies.length) {\n // Return the formatted string from the function to verify the output formatting\n // (it's hard to test this via the esbuild plugin)\n const errors = errorDependencies.map((dep) => [`${dep.name}@${dep.version} (${dep.path})`, dep.issues]).flat(1);\n return {\n error: colors.red(`${colors.bold('ERROR:')} Found dependencies with license issues:\\n${bulletedList(errors)}`),\n };\n }\n\n return { dependencies };\n}\n\n/**\n * Check the license specified in package.json, and if it's valid, read the license and notice text.\n */\nfunction readAndValidateLicenses(\n includedPackages: Record<string, PackageJson>,\n options: Pick<LicensePluginOptions, 'packageRoot' | 'unacceptableLicenseTest'>,\n): { dependencies: Dependency[]; errorDependencies: ErrorDependency[] } {\n const dependencies: Dependency[] = [];\n const errorDependencies: ErrorDependency[] = [];\n\n const sortedEntries = Object.entries(includedPackages).sort(\n (a, b) => a[1].name.localeCompare(b[1].name) || a[1].version.localeCompare(b[1].version),\n );\n for (const [depPkgRoot, depPkgJson] of sortedEntries) {\n const pkgMeta = {\n name: depPkgJson.name,\n version: depPkgJson.version,\n path: path.relative(options.packageRoot, depPkgRoot).replace(/\\\\/g, '/'),\n };\n const license = depPkgJson.license;\n if (!license || typeof license !== 'string') {\n errorDependencies.push({\n ...pkgMeta,\n issues: [license ? `Unexpected \"license\" format ${JSON.stringify(license)}` : 'Missing \"license\"'],\n });\n continue;\n }\n\n const licenseResult = validateLicense(license);\n if (!licenseResult.validForNewPackages) {\n errorDependencies.push({\n ...pkgMeta,\n issues: [`Invalid \"license\" value ${JSON.stringify(license)}`, ...(licenseResult.warnings || [])],\n });\n continue;\n }\n const licenseInFilePath = licenseResult.inFile && path.join(depPkgRoot, licenseResult.inFile);\n if (licenseInFilePath && !fs.existsSync(licenseInFilePath)) {\n errorDependencies.push({\n ...pkgMeta,\n issues: [`License file \"${licenseResult.inFile}\" (specified by \"SEE LICENSE IN\") not found`],\n });\n continue;\n }\n\n if (options.unacceptableLicenseTest?.(license)) {\n errorDependencies.push({\n ...pkgMeta,\n issues: [\n `License ${JSON.stringify(license)} is not allowed (if incorrect, update the unacceptableLicenseTest setting)`,\n ],\n });\n continue;\n }\n\n const files = fs.readdirSync(depPkgRoot);\n // Read the license from either \"SEE LICENSE IN ___\" or a file named LICENSE*\n let licenseText: string | undefined;\n if (licenseInFilePath) {\n licenseText = fs.readFileSync(licenseInFilePath, 'utf8');\n } else {\n licenseText = findFile(/^license/i, files, depPkgRoot) || findFile(/^copying/i, files, depPkgRoot);\n }\n // Just look for a \"notice\" file at the root for notices\n const noticeText = findFile(/^notice/i, files, depPkgRoot);\n\n // Get author from package.json and/or \"authors\" file\n let author = personToString(depPkgJson.author);\n const authorsText = findFile(/^authors/i, files, depPkgRoot);\n if (authorsText) {\n author = (author ? author + '\\n' : '') + authorsText;\n }\n\n // Same with contributors\n let contributors = depPkgJson.contributors?.map(personToString).filter(Boolean).join('\\n');\n const contributorsText = findFile(/^contributors?/i, files, depPkgRoot);\n if (contributorsText) {\n contributors = (contributors ? contributors + '\\n' : '') + contributorsText;\n }\n\n const maintainers = depPkgJson.maintainers?.map(personToString).join('\\n');\n\n // Following CG, use \"homepage\" by default, followed by \"repository\"\n let url = depPkgJson.homepage;\n const repository = depPkgJson.repository;\n if (!url && repository) {\n url = typeof repository === 'string' ? repository : repository.url;\n const gitInfo = hostedGitInfo.fromUrl(url);\n if (gitInfo) {\n url = gitInfo.browse();\n }\n }\n\n dependencies.push({\n name: pkgMeta.name,\n version: pkgMeta.version,\n author,\n contributors,\n maintainers,\n url,\n license,\n licenseText,\n noticeText,\n });\n }\n\n return { dependencies, errorDependencies };\n}\n\n/**\n * Convert a person field to a string\n */\nfunction personToString(person: PackageJsonPerson | undefined): string | undefined {\n if (!person || typeof person === 'string') {\n return person;\n }\n const { name, email, url } = person;\n return `${name}${email ? ` <${email}>` : ''}${url ? ` (${url})` : ''}`;\n}\n\n/**\n * Find and read a file in a directory that matches a specific pattern.\n * @param isMatch - The function or regexp to match the file name.\n * @param files - The list of files to search.\n * @param dir - The parent directory path.\n * @returns The file contents if found (whitespace trimmed), otherwise undefined.\n */\nfunction findFile(isMatch: RegExp | ((file: string) => boolean), files: string[], dir: string): string | undefined {\n const match = files.find(typeof isMatch === 'function' ? isMatch : (file) => isMatch.test(file));\n return match && fs.readFileSync(path.join(dir, match), 'utf8').trim();\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"writeNotice.d.ts","sourceRoot":"","sources":["../../src/license/writeNotice.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,eAAO,MAAM,cAAc,eAAe,CAAC;AAE3C;;GAEG;AACH,wBAAgB,WAAW,CACzB,YAAY,EAAE,UAAU,EAAE,EAC1B,SAAS,EAAE,MAAM,EACjB,iBAAiB,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,OAAO,GACtD,IAAI,
|
|
1
|
+
{"version":3,"file":"writeNotice.d.ts","sourceRoot":"","sources":["../../src/license/writeNotice.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,eAAO,MAAM,cAAc,eAAe,CAAC;AAE3C;;GAEG;AACH,wBAAgB,WAAW,CACzB,YAAY,EAAE,UAAU,EAAE,EAC1B,SAAS,EAAE,MAAM,EACjB,iBAAiB,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,OAAO,GACtD,IAAI,CAgCN"}
|
|
@@ -12,7 +12,9 @@ export function writeNotice(dependencies, absOutDir, excludeFromNotice) {
|
|
|
12
12
|
return;
|
|
13
13
|
const noticeText = [
|
|
14
14
|
`NOTICES\n\nThis package incorporates material as listed below or described in the code.`,
|
|
15
|
-
...filteredDependencies
|
|
15
|
+
...filteredDependencies
|
|
16
|
+
.sort((a, b) => a.name.localeCompare(b.name) || a.version.localeCompare(b.version))
|
|
17
|
+
.map((dep) => {
|
|
16
18
|
const shortLicense = dep.license ? (/^see license/i.test(dep.license) ? '' : dep.license) : 'unknown license';
|
|
17
19
|
return [
|
|
18
20
|
`${dep.name} ${dep.version}${shortLicense ? ` - ${shortLicense}` : ''}${dep.url ? `\n${dep.url}` : ''}`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"writeNotice.js","sourceRoot":"","sources":["../../src/license/writeNotice.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAGxB,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC;AAE3C;;GAEG;AACH,MAAM,UAAU,WAAW,CACzB,YAA0B,EAC1B,SAAiB,EACjB,iBAAuD;IAEvD,IAAI,CAAC,YAAY,CAAC,MAAM;QAAE,OAAO;IAEjC,MAAM,oBAAoB,GAAG,iBAAiB,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;IACtH,IAAI,CAAC,oBAAoB,CAAC,MAAM;QAAE,OAAO;IAEzC,MAAM,UAAU,GAAG;QACjB,yFAAyF;QACzF,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;
|
|
1
|
+
{"version":3,"file":"writeNotice.js","sourceRoot":"","sources":["../../src/license/writeNotice.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAGxB,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC;AAE3C;;GAEG;AACH,MAAM,UAAU,WAAW,CACzB,YAA0B,EAC1B,SAAiB,EACjB,iBAAuD;IAEvD,IAAI,CAAC,YAAY,CAAC,MAAM;QAAE,OAAO;IAEjC,MAAM,oBAAoB,GAAG,iBAAiB,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;IACtH,IAAI,CAAC,oBAAoB,CAAC,MAAM;QAAE,OAAO;IAEzC,MAAM,UAAU,GAAG;QACjB,yFAAyF;QACzF,GAAG,oBAAoB;aACpB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;aAClF,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;YACX,MAAM,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC;YAC9G,OAAO;gBACL,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,OAAO,GAAG,YAAY,CAAC,CAAC,CAAC,MAAM,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;gBACvG,uFAAuF;gBACvF,GAAG,CAAC,MAAM,IAAI,WAAW,GAAG,CAAC,MAAM,EAAE;gBACrC,GAAG,CAAC,WAAW,IAAI,iBAAiB,GAAG,CAAC,WAAW,EAAE;gBACrD,GAAG,CAAC,YAAY,IAAI,kBAAkB,GAAG,CAAC,YAAY,EAAE;gBACxD,oEAAoE;gBACpE,GAAG,CAAC,WAAW;gBACf,+DAA+D;gBAC/D,GAAG,CAAC,UAAU,IAAI,eAAe,GAAG,CAAC,UAAU,EAAE;aAClD;iBACE,MAAM,CAAC,OAAO,CAAC;iBACf,IAAI,CAAC,MAAM,CAAC,CAAC;QAClB,CAAC,CAAC;KACL,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAEvB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IACrD,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;IAC9C,OAAO,CAAC,GAAG,CAAC,4BAA4B,OAAO,IAAI,CAAC,CAAC;AACvD,CAAC","sourcesContent":["import fs from 'fs';\nimport path from 'path';\nimport type { Dependency } from './types.ts';\n\nexport const noticeFilename = 'NOTICE.txt';\n\n/**\n * Write NOTICE.txt with license and author info for the given dependencies.\n */\nexport function writeNotice(\n dependencies: Dependency[],\n absOutDir: string,\n excludeFromNotice?: (dependency: Dependency) => boolean,\n): void {\n if (!dependencies.length) return;\n\n const filteredDependencies = excludeFromNotice ? dependencies.filter((dep) => !excludeFromNotice(dep)) : dependencies;\n if (!filteredDependencies.length) return;\n\n const noticeText = [\n `NOTICES\\n\\nThis package incorporates material as listed below or described in the code.`,\n ...filteredDependencies\n .sort((a, b) => a.name.localeCompare(b.name) || a.version.localeCompare(b.version))\n .map((dep) => {\n const shortLicense = dep.license ? (/^see license/i.test(dep.license) ? '' : dep.license) : 'unknown license';\n return [\n `${dep.name} ${dep.version}${shortLicense ? ` - ${shortLicense}` : ''}${dep.url ? `\\n${dep.url}` : ''}`,\n // Unclear which author/maintainer/contributor info is required, so include all of them\n dep.author && `Author: ${dep.author}`,\n dep.maintainers && `Maintainers:\\n${dep.maintainers}`,\n dep.contributors && `Contributors:\\n${dep.contributors}`,\n // The license text typically includes the official copyright notice\n dep.licenseText,\n // As of writing we don't use any packages that publish NOTICES\n dep.noticeText && `NOTICES:\\n\\n${dep.noticeText}`,\n ]\n .filter(Boolean)\n .join('\\n\\n');\n }),\n ].join('\\n\\n----\\n\\n');\n\n const outFile = path.join(absOutDir, noticeFilename);\n fs.mkdirSync(absOutDir, { recursive: true });\n fs.writeFileSync(outFile, noticeText, 'utf8');\n console.log(`Wrote license notices to ${outFile}\\n`);\n}\n"]}
|