@neurcode-ai/cli 0.9.4 → 0.9.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.
- package/dist/api-client.d.ts +6 -0
- package/dist/api-client.d.ts.map +1 -1
- package/dist/api-client.js +46 -13
- package/dist/api-client.js.map +1 -1
- package/dist/commands/init.d.ts +5 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +45 -6
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/login.d.ts +3 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +26 -7
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.d.ts +8 -2
- package/dist/commands/logout.d.ts.map +1 -1
- package/dist/commands/logout.js +30 -13
- package/dist/commands/logout.js.map +1 -1
- package/dist/commands/plan.d.ts +1 -0
- package/dist/commands/plan.d.ts.map +1 -1
- package/dist/commands/plan.js +191 -29
- package/dist/commands/plan.js.map +1 -1
- package/dist/config.d.ts +9 -13
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +230 -130
- package/dist/config.js.map +1 -1
- package/dist/index.js +15 -6
- package/dist/index.js.map +1 -1
- package/dist/services/watch/CommandPoller.d.ts.map +1 -1
- package/dist/services/watch/CommandPoller.js +5 -0
- package/dist/services/watch/CommandPoller.js.map +1 -1
- package/dist/services/watch/Syncer.d.ts.map +1 -1
- package/dist/services/watch/Syncer.js +3 -0
- package/dist/services/watch/Syncer.js.map +1 -1
- package/dist/utils/gitignore.d.ts.map +1 -1
- package/dist/utils/gitignore.js +29 -7
- package/dist/utils/gitignore.js.map +1 -1
- package/dist/utils/neurcode-context.d.ts +24 -0
- package/dist/utils/neurcode-context.d.ts.map +1 -0
- package/dist/utils/neurcode-context.js +252 -0
- package/dist/utils/neurcode-context.js.map +1 -0
- package/dist/utils/plan-cache.d.ts +44 -0
- package/dist/utils/plan-cache.d.ts.map +1 -0
- package/dist/utils/plan-cache.js +227 -0
- package/dist/utils/plan-cache.js.map +1 -0
- package/dist/utils/secret-masking.d.ts +12 -0
- package/dist/utils/secret-masking.d.ts.map +1 -0
- package/dist/utils/secret-masking.js +34 -0
- package/dist/utils/secret-masking.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeIntent = normalizeIntent;
|
|
4
|
+
exports.getPlanCachePath = getPlanCachePath;
|
|
5
|
+
exports.computePlanCacheKey = computePlanCacheKey;
|
|
6
|
+
exports.getGitRepoFingerprint = getGitRepoFingerprint;
|
|
7
|
+
exports.getFilesystemFingerprintFromTree = getFilesystemFingerprintFromTree;
|
|
8
|
+
exports.readCachedPlan = readCachedPlan;
|
|
9
|
+
exports.writeCachedPlan = writeCachedPlan;
|
|
10
|
+
exports.findSimilarCachedPlans = findSimilarCachedPlans;
|
|
11
|
+
const child_process_1 = require("child_process");
|
|
12
|
+
const crypto_1 = require("crypto");
|
|
13
|
+
const fs_1 = require("fs");
|
|
14
|
+
const path_1 = require("path");
|
|
15
|
+
const secret_masking_1 = require("./secret-masking");
|
|
16
|
+
const CACHE_SCHEMA_VERSION = 1;
|
|
17
|
+
const CACHE_FILE_NAME = 'plan-cache.json';
|
|
18
|
+
const MAX_ENTRIES = 50;
|
|
19
|
+
function sha256Hex(input) {
|
|
20
|
+
return (0, crypto_1.createHash)('sha256').update(input).digest('hex');
|
|
21
|
+
}
|
|
22
|
+
function normalizeIntent(intent) {
|
|
23
|
+
return intent
|
|
24
|
+
.trim()
|
|
25
|
+
.replace(/\s+/g, ' ')
|
|
26
|
+
.toLowerCase();
|
|
27
|
+
}
|
|
28
|
+
function getPlanCachePath(cwd) {
|
|
29
|
+
return (0, path_1.join)(cwd, '.neurcode', CACHE_FILE_NAME);
|
|
30
|
+
}
|
|
31
|
+
function ensureNeurcodeDir(cwd) {
|
|
32
|
+
const dir = (0, path_1.join)(cwd, '.neurcode');
|
|
33
|
+
if (!(0, fs_1.existsSync)(dir)) {
|
|
34
|
+
(0, fs_1.mkdirSync)(dir, { recursive: true });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function safeReadCacheFile(cachePath) {
|
|
38
|
+
if (!(0, fs_1.existsSync)(cachePath)) {
|
|
39
|
+
return { schemaVersion: CACHE_SCHEMA_VERSION, entries: {} };
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const raw = (0, fs_1.readFileSync)(cachePath, 'utf-8');
|
|
43
|
+
const parsed = JSON.parse(raw);
|
|
44
|
+
if (parsed.schemaVersion !== CACHE_SCHEMA_VERSION || !parsed.entries || typeof parsed.entries !== 'object') {
|
|
45
|
+
throw new Error('Invalid cache schema');
|
|
46
|
+
}
|
|
47
|
+
const cache = parsed;
|
|
48
|
+
// Best-effort: avoid persisting secrets in cached intents (older caches may include them).
|
|
49
|
+
// This does not affect cache keys (they remain stable), it only sanitizes the stored intent text.
|
|
50
|
+
try {
|
|
51
|
+
for (const entry of Object.values(cache.entries)) {
|
|
52
|
+
if (!entry?.input?.intent)
|
|
53
|
+
continue;
|
|
54
|
+
entry.input.intent = (0, secret_masking_1.maskSecretsInText)(entry.input.intent).masked;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// ignore
|
|
59
|
+
}
|
|
60
|
+
return cache;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// Preserve the corrupted file for debugging, but do not block the command.
|
|
64
|
+
try {
|
|
65
|
+
const corruptPath = cachePath.replace(/\.json$/, `.corrupt-${Date.now()}.json`);
|
|
66
|
+
(0, fs_1.renameSync)(cachePath, corruptPath);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// ignore
|
|
70
|
+
}
|
|
71
|
+
return { schemaVersion: CACHE_SCHEMA_VERSION, entries: {} };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function atomicWrite(cachePath, data) {
|
|
75
|
+
const tmpPath = `${cachePath}.tmp`;
|
|
76
|
+
(0, fs_1.writeFileSync)(tmpPath, data, 'utf-8');
|
|
77
|
+
(0, fs_1.renameSync)(tmpPath, cachePath);
|
|
78
|
+
}
|
|
79
|
+
function prune(cache) {
|
|
80
|
+
const keys = Object.keys(cache.entries);
|
|
81
|
+
if (keys.length <= MAX_ENTRIES)
|
|
82
|
+
return;
|
|
83
|
+
const sorted = keys
|
|
84
|
+
.map((k) => cache.entries[k])
|
|
85
|
+
.filter(Boolean)
|
|
86
|
+
.sort((a, b) => {
|
|
87
|
+
const aTime = Date.parse(a.lastUsedAt) || 0;
|
|
88
|
+
const bTime = Date.parse(b.lastUsedAt) || 0;
|
|
89
|
+
return aTime - bTime;
|
|
90
|
+
});
|
|
91
|
+
const toRemove = sorted.slice(0, Math.max(0, sorted.length - MAX_ENTRIES));
|
|
92
|
+
for (const entry of toRemove) {
|
|
93
|
+
delete cache.entries[entry.key];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function computePlanCacheKey(input) {
|
|
97
|
+
const safeIntent = (0, secret_masking_1.maskSecretsInText)(input.intent).masked;
|
|
98
|
+
// Use an explicit, stable string rather than JSON.stringify of arbitrary objects.
|
|
99
|
+
const payload = [
|
|
100
|
+
`v=${input.schemaVersion}`,
|
|
101
|
+
`apiUrl=${input.apiUrl}`,
|
|
102
|
+
`orgId=${input.orgId}`,
|
|
103
|
+
`projectId=${input.projectId}`,
|
|
104
|
+
`intent=${safeIntent}`,
|
|
105
|
+
`ticketRef=${input.ticketRef || ''}`,
|
|
106
|
+
`contextHash=${input.contextHash || ''}`,
|
|
107
|
+
`repo.kind=${input.repo.kind}`,
|
|
108
|
+
input.repo.kind === 'git'
|
|
109
|
+
? `repo.headSha=${input.repo.headSha};repo.headTreeSha=${input.repo.headTreeSha};repo.statusHash=${input.repo.statusHash}`
|
|
110
|
+
: `repo.fileTreeHash=${input.repo.fileTreeHash}`,
|
|
111
|
+
].join('\n');
|
|
112
|
+
return sha256Hex(payload);
|
|
113
|
+
}
|
|
114
|
+
function getGitRepoFingerprint(cwd) {
|
|
115
|
+
try {
|
|
116
|
+
const inside = (0, child_process_1.execSync)('git rev-parse --is-inside-work-tree', { cwd, encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] })
|
|
117
|
+
.trim()
|
|
118
|
+
.toLowerCase();
|
|
119
|
+
if (inside !== 'true')
|
|
120
|
+
return null;
|
|
121
|
+
const headSha = (0, child_process_1.execSync)('git rev-parse HEAD', { cwd, encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
122
|
+
const headTreeSha = (0, child_process_1.execSync)('git rev-parse HEAD^{tree}', { cwd, encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
123
|
+
const status = (0, child_process_1.execSync)('git status --porcelain', { cwd, encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
124
|
+
const statusHash = sha256Hex(status);
|
|
125
|
+
return { kind: 'git', headSha, headTreeSha, statusHash };
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function getFilesystemFingerprintFromTree(fileTree) {
|
|
132
|
+
// Normalize ordering so the hash is stable even if scanning order changes.
|
|
133
|
+
const normalized = [...fileTree].sort().join('\n');
|
|
134
|
+
return { kind: 'filesystem', fileTreeHash: sha256Hex(normalized) };
|
|
135
|
+
}
|
|
136
|
+
function readCachedPlan(cwd, key) {
|
|
137
|
+
try {
|
|
138
|
+
const cachePath = getPlanCachePath(cwd);
|
|
139
|
+
const cache = safeReadCacheFile(cachePath);
|
|
140
|
+
const entry = cache.entries[key];
|
|
141
|
+
if (!entry)
|
|
142
|
+
return null;
|
|
143
|
+
// Update LRU metadata.
|
|
144
|
+
const now = new Date().toISOString();
|
|
145
|
+
entry.lastUsedAt = now;
|
|
146
|
+
entry.useCount = (entry.useCount || 0) + 1;
|
|
147
|
+
cache.entries[key] = entry;
|
|
148
|
+
prune(cache);
|
|
149
|
+
atomicWrite(cachePath, JSON.stringify(cache, null, 2) + '\n');
|
|
150
|
+
return entry;
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function writeCachedPlan(cwd, entry) {
|
|
157
|
+
try {
|
|
158
|
+
ensureNeurcodeDir(cwd);
|
|
159
|
+
const cachePath = getPlanCachePath(cwd);
|
|
160
|
+
const cache = safeReadCacheFile(cachePath);
|
|
161
|
+
const now = new Date().toISOString();
|
|
162
|
+
const existing = cache.entries[entry.key];
|
|
163
|
+
const next = {
|
|
164
|
+
...entry,
|
|
165
|
+
createdAt: existing?.createdAt || now,
|
|
166
|
+
lastUsedAt: now,
|
|
167
|
+
useCount: (existing?.useCount || 0) + 1,
|
|
168
|
+
};
|
|
169
|
+
// Best-effort: do not persist secrets in the on-disk cache.
|
|
170
|
+
try {
|
|
171
|
+
if (next.input?.intent) {
|
|
172
|
+
next.input.intent = (0, secret_masking_1.maskSecretsInText)(next.input.intent).masked;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
// ignore
|
|
177
|
+
}
|
|
178
|
+
cache.entries[entry.key] = next;
|
|
179
|
+
prune(cache);
|
|
180
|
+
atomicWrite(cachePath, JSON.stringify(cache, null, 2) + '\n');
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
// Cache failures should never block plan generation.
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function tokenize(text) {
|
|
187
|
+
return text
|
|
188
|
+
.toLowerCase()
|
|
189
|
+
.replace(/[^\w\s]/g, ' ')
|
|
190
|
+
.split(/\s+/)
|
|
191
|
+
.filter((t) => t.length >= 3);
|
|
192
|
+
}
|
|
193
|
+
function jaccard(a, b) {
|
|
194
|
+
if (a.size === 0 || b.size === 0)
|
|
195
|
+
return 0;
|
|
196
|
+
let inter = 0;
|
|
197
|
+
for (const x of a) {
|
|
198
|
+
if (b.has(x))
|
|
199
|
+
inter++;
|
|
200
|
+
}
|
|
201
|
+
const union = a.size + b.size - inter;
|
|
202
|
+
return union === 0 ? 0 : inter / union;
|
|
203
|
+
}
|
|
204
|
+
function findSimilarCachedPlans(cwd, filter, intent, k = 3) {
|
|
205
|
+
try {
|
|
206
|
+
const cachePath = getPlanCachePath(cwd);
|
|
207
|
+
const cache = safeReadCacheFile(cachePath);
|
|
208
|
+
const entries = Object.values(cache.entries);
|
|
209
|
+
const queryTokens = new Set(tokenize(intent));
|
|
210
|
+
const scored = entries
|
|
211
|
+
.filter((e) => e.input.orgId === filter.orgId && e.input.projectId === filter.projectId)
|
|
212
|
+
.map((e) => {
|
|
213
|
+
const eTokens = new Set(tokenize(e.input.intent));
|
|
214
|
+
const score = jaccard(queryTokens, eTokens);
|
|
215
|
+
return { entry: e, score };
|
|
216
|
+
})
|
|
217
|
+
.filter((s) => s.score > 0)
|
|
218
|
+
.sort((a, b) => b.score - a.score)
|
|
219
|
+
.slice(0, k)
|
|
220
|
+
.map((s) => s.entry);
|
|
221
|
+
return scored;
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
return [];
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
//# sourceMappingURL=plan-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-cache.js","sourceRoot":"","sources":["../../src/utils/plan-cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight secret masking for local persistence (cache/memory files).
|
|
3
|
+
*
|
|
4
|
+
* This intentionally avoids importing the full SecurityGuard (ts-morph heavy),
|
|
5
|
+
* while still masking the most common secret patterns that users may paste into
|
|
6
|
+
* CLI intents or context files.
|
|
7
|
+
*/
|
|
8
|
+
export declare function maskSecretsInText(text: string): {
|
|
9
|
+
masked: string;
|
|
10
|
+
changed: boolean;
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=secret-masking.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-masking.d.ts","sourceRoot":"","sources":["../../src/utils/secret-masking.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAyCpF"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.maskSecretsInText = maskSecretsInText;
|
|
4
|
+
const REDACTION_PLACEHOLDER = '[REDACTED_BY_NEURCODE]';
|
|
5
|
+
/**
|
|
6
|
+
* Lightweight secret masking for local persistence (cache/memory files).
|
|
7
|
+
*
|
|
8
|
+
* This intentionally avoids importing the full SecurityGuard (ts-morph heavy),
|
|
9
|
+
* while still masking the most common secret patterns that users may paste into
|
|
10
|
+
* CLI intents or context files.
|
|
11
|
+
*/
|
|
12
|
+
function maskSecretsInText(text) {
|
|
13
|
+
if (!text)
|
|
14
|
+
return { masked: text, changed: false };
|
|
15
|
+
let masked = text;
|
|
16
|
+
const before = masked;
|
|
17
|
+
// Direct token patterns
|
|
18
|
+
masked = masked.replace(/\bAKIA[0-9A-Z]{16}\b/gi, REDACTION_PLACEHOLDER); // AWS access key id
|
|
19
|
+
masked = masked.replace(/\b(ghp|gho|ghu|ghs|ghr)_[a-zA-Z0-9]{36,}\b/gi, REDACTION_PLACEHOLDER); // GitHub tokens
|
|
20
|
+
// JWTs (common shape)
|
|
21
|
+
masked = masked.replace(/\beyJ[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,}\b/g, REDACTION_PLACEHOLDER);
|
|
22
|
+
// Connection strings / URLs with credentials
|
|
23
|
+
masked = masked.replace(/\b((?:postgresql?|mysql|mongodb(?:\+srv)?|redis):\/\/)([^\s]+)/gi, `$1${REDACTION_PLACEHOLDER}`);
|
|
24
|
+
// sshpass password inline
|
|
25
|
+
masked = masked.replace(/\b(sshpass\s+-p\s+)(['"])([^'"]+)\2/gi, `$1$2${REDACTION_PLACEHOLDER}$2`);
|
|
26
|
+
// bearer/token/apikey style assignments (keep the left side; redact the value)
|
|
27
|
+
masked = masked.replace(/\b((?:bearer|token|apikey)\s*[:=]\s*['"]?)([a-zA-Z0-9_\-]{32,})(['"]?)/gi, `$1${REDACTION_PLACEHOLDER}$3`);
|
|
28
|
+
// generic secret-like assignments (keep the left side; redact the value)
|
|
29
|
+
masked = masked.replace(/\b((?:password|secret|key|api[_-]?key|private[_-]?key|access[_-]?token|auth[_-]?token)\s*[:=]\s*['"]?)([a-zA-Z0-9_\-+/=]{20,})(['"]?)/gi, `$1${REDACTION_PLACEHOLDER}$3`);
|
|
30
|
+
// PEM private keys (multi-line)
|
|
31
|
+
masked = masked.replace(/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g, REDACTION_PLACEHOLDER);
|
|
32
|
+
return { masked, changed: masked !== before };
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=secret-masking.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-masking.js","sourceRoot":"","sources":["../../src/utils/secret-masking.ts"],"names":[],"mappings":";;AASA,8CAyCC;AAlDD,MAAM,qBAAqB,GAAG,wBAAwB,CAAC;AAEvD;;;;;;GAMG;AACH,SAAgB,iBAAiB,CAAC,IAAY;IAC5C,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAEnD,IAAI,MAAM,GAAG,IAAI,CAAC;IAClB,MAAM,MAAM,GAAG,MAAM,CAAC;IAEtB,wBAAwB;IACxB,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,wBAAwB,EAAE,qBAAqB,CAAC,CAAC,CAAC,oBAAoB;IAC9F,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,8CAA8C,EAAE,qBAAqB,CAAC,CAAC,CAAC,gBAAgB;IAEhH,sBAAsB;IACtB,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,oEAAoE,EAAE,qBAAqB,CAAC,CAAC;IAErH,6CAA6C;IAC7C,MAAM,GAAG,MAAM,CAAC,OAAO,CACrB,kEAAkE,EAClE,KAAK,qBAAqB,EAAE,CAC7B,CAAC;IAEF,0BAA0B;IAC1B,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,uCAAuC,EAAE,OAAO,qBAAqB,IAAI,CAAC,CAAC;IAEnG,+EAA+E;IAC/E,MAAM,GAAG,MAAM,CAAC,OAAO,CACrB,0EAA0E,EAC1E,KAAK,qBAAqB,IAAI,CAC/B,CAAC;IAEF,yEAAyE;IACzE,MAAM,GAAG,MAAM,CAAC,OAAO,CACrB,yIAAyI,EACzI,KAAK,qBAAqB,IAAI,CAC/B,CAAC;IAEF,gCAAgC;IAChC,MAAM,GAAG,MAAM,CAAC,OAAO,CACrB,6EAA6E,EAC7E,qBAAqB,CACtB,CAAC;IAEF,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;AAChD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neurcode-ai/cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.6",
|
|
4
4
|
"description": "Neurcode CLI - AI code governance and diff analysis",
|
|
5
5
|
"bin": {
|
|
6
6
|
"neurcode": "./dist/index.js"
|
|
@@ -61,4 +61,4 @@
|
|
|
61
61
|
"@types/uuid": "^9.0.8",
|
|
62
62
|
"typescript": "^5.3.0"
|
|
63
63
|
}
|
|
64
|
-
}
|
|
64
|
+
}
|