tidewave 0.1.0
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/CHANGELOG.md +55 -0
- package/LICENSE +201 -0
- package/README.md +96 -0
- package/dist/cli/index.js +1202 -0
- package/dist/index.js +1020 -0
- package/dist/mcp.js +1151 -0
- package/dist/resolution/formatters.js +153 -0
- package/dist/resolution/index.js +1030 -0
- package/dist/resolution/module-resolver.js +369 -0
- package/dist/resolution/symbol-finder.js +634 -0
- package/dist/resolution/utils.js +318 -0
- package/package.json +72 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
7
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
8
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
9
|
+
for (let key of __getOwnPropNames(mod))
|
|
10
|
+
if (!__hasOwnProp.call(to, key))
|
|
11
|
+
__defProp(to, key, {
|
|
12
|
+
get: () => mod[key],
|
|
13
|
+
enumerable: true
|
|
14
|
+
});
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
18
|
+
var __export = (target, all) => {
|
|
19
|
+
for (var name in all)
|
|
20
|
+
__defProp(target, name, {
|
|
21
|
+
get: all[name],
|
|
22
|
+
enumerable: true,
|
|
23
|
+
configurable: true,
|
|
24
|
+
set: (newValue) => all[name] = () => newValue
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// src/resolution/utils.ts
|
|
29
|
+
import ts from "typescript";
|
|
30
|
+
|
|
31
|
+
// node:path
|
|
32
|
+
var L = Object.create;
|
|
33
|
+
var h = Object.defineProperty;
|
|
34
|
+
var D = Object.getOwnPropertyDescriptor;
|
|
35
|
+
var T = Object.getOwnPropertyNames;
|
|
36
|
+
var _ = Object.getPrototypeOf;
|
|
37
|
+
var E = Object.prototype.hasOwnProperty;
|
|
38
|
+
var R = (s, e) => () => (e || s((e = { exports: {} }).exports, e), e.exports);
|
|
39
|
+
var N = (s, e, r, t) => {
|
|
40
|
+
if (e && typeof e == "object" || typeof e == "function")
|
|
41
|
+
for (let i of T(e))
|
|
42
|
+
!E.call(s, i) && i !== r && h(s, i, { get: () => e[i], enumerable: !(t = D(e, i)) || t.enumerable });
|
|
43
|
+
return s;
|
|
44
|
+
};
|
|
45
|
+
var j = (s, e, r) => (r = s != null ? L(_(s)) : {}, N(e || !s || !s.__esModule ? h(r, "default", { value: s, enumerable: true }) : r, s));
|
|
46
|
+
var k = R((W, w) => {
|
|
47
|
+
function v(s) {
|
|
48
|
+
if (typeof s != "string")
|
|
49
|
+
throw new TypeError("Path must be a string. Received " + JSON.stringify(s));
|
|
50
|
+
}
|
|
51
|
+
function C(s, e) {
|
|
52
|
+
for (var r = "", t = 0, i = -1, a = 0, n, l = 0;l <= s.length; ++l) {
|
|
53
|
+
if (l < s.length)
|
|
54
|
+
n = s.charCodeAt(l);
|
|
55
|
+
else {
|
|
56
|
+
if (n === 47)
|
|
57
|
+
break;
|
|
58
|
+
n = 47;
|
|
59
|
+
}
|
|
60
|
+
if (n === 47) {
|
|
61
|
+
if (!(i === l - 1 || a === 1))
|
|
62
|
+
if (i !== l - 1 && a === 2) {
|
|
63
|
+
if (r.length < 2 || t !== 2 || r.charCodeAt(r.length - 1) !== 46 || r.charCodeAt(r.length - 2) !== 46) {
|
|
64
|
+
if (r.length > 2) {
|
|
65
|
+
var f = r.lastIndexOf("/");
|
|
66
|
+
if (f !== r.length - 1) {
|
|
67
|
+
f === -1 ? (r = "", t = 0) : (r = r.slice(0, f), t = r.length - 1 - r.lastIndexOf("/")), i = l, a = 0;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
} else if (r.length === 2 || r.length === 1) {
|
|
71
|
+
r = "", t = 0, i = l, a = 0;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
e && (r.length > 0 ? r += "/.." : r = "..", t = 2);
|
|
76
|
+
} else
|
|
77
|
+
r.length > 0 ? r += "/" + s.slice(i + 1, l) : r = s.slice(i + 1, l), t = l - i - 1;
|
|
78
|
+
i = l, a = 0;
|
|
79
|
+
} else
|
|
80
|
+
n === 46 && a !== -1 ? ++a : a = -1;
|
|
81
|
+
}
|
|
82
|
+
return r;
|
|
83
|
+
}
|
|
84
|
+
function F(s, e) {
|
|
85
|
+
var r = e.dir || e.root, t = e.base || (e.name || "") + (e.ext || "");
|
|
86
|
+
return r ? r === e.root ? r + t : r + s + t : t;
|
|
87
|
+
}
|
|
88
|
+
var m = { resolve: function() {
|
|
89
|
+
for (var e = "", r = false, t, i = arguments.length - 1;i >= -1 && !r; i--) {
|
|
90
|
+
var a;
|
|
91
|
+
i >= 0 ? a = arguments[i] : (t === undefined && (t = process.cwd()), a = t), v(a), a.length !== 0 && (e = a + "/" + e, r = a.charCodeAt(0) === 47);
|
|
92
|
+
}
|
|
93
|
+
return e = C(e, !r), r ? e.length > 0 ? "/" + e : "/" : e.length > 0 ? e : ".";
|
|
94
|
+
}, normalize: function(e) {
|
|
95
|
+
if (v(e), e.length === 0)
|
|
96
|
+
return ".";
|
|
97
|
+
var r = e.charCodeAt(0) === 47, t = e.charCodeAt(e.length - 1) === 47;
|
|
98
|
+
return e = C(e, !r), e.length === 0 && !r && (e = "."), e.length > 0 && t && (e += "/"), r ? "/" + e : e;
|
|
99
|
+
}, isAbsolute: function(e) {
|
|
100
|
+
return v(e), e.length > 0 && e.charCodeAt(0) === 47;
|
|
101
|
+
}, join: function() {
|
|
102
|
+
if (arguments.length === 0)
|
|
103
|
+
return ".";
|
|
104
|
+
for (var e, r = 0;r < arguments.length; ++r) {
|
|
105
|
+
var t = arguments[r];
|
|
106
|
+
v(t), t.length > 0 && (e === undefined ? e = t : e += "/" + t);
|
|
107
|
+
}
|
|
108
|
+
return e === undefined ? "." : m.normalize(e);
|
|
109
|
+
}, relative: function(e, r) {
|
|
110
|
+
if (v(e), v(r), e === r || (e = m.resolve(e), r = m.resolve(r), e === r))
|
|
111
|
+
return "";
|
|
112
|
+
for (var t = 1;t < e.length && e.charCodeAt(t) === 47; ++t)
|
|
113
|
+
;
|
|
114
|
+
for (var i = e.length, a = i - t, n = 1;n < r.length && r.charCodeAt(n) === 47; ++n)
|
|
115
|
+
;
|
|
116
|
+
for (var l = r.length, f = l - n, c = a < f ? a : f, d = -1, o = 0;o <= c; ++o) {
|
|
117
|
+
if (o === c) {
|
|
118
|
+
if (f > c) {
|
|
119
|
+
if (r.charCodeAt(n + o) === 47)
|
|
120
|
+
return r.slice(n + o + 1);
|
|
121
|
+
if (o === 0)
|
|
122
|
+
return r.slice(n + o);
|
|
123
|
+
} else
|
|
124
|
+
a > c && (e.charCodeAt(t + o) === 47 ? d = o : o === 0 && (d = 0));
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
var A = e.charCodeAt(t + o), z = r.charCodeAt(n + o);
|
|
128
|
+
if (A !== z)
|
|
129
|
+
break;
|
|
130
|
+
A === 47 && (d = o);
|
|
131
|
+
}
|
|
132
|
+
var b = "";
|
|
133
|
+
for (o = t + d + 1;o <= i; ++o)
|
|
134
|
+
(o === i || e.charCodeAt(o) === 47) && (b.length === 0 ? b += ".." : b += "/..");
|
|
135
|
+
return b.length > 0 ? b + r.slice(n + d) : (n += d, r.charCodeAt(n) === 47 && ++n, r.slice(n));
|
|
136
|
+
}, _makeLong: function(e) {
|
|
137
|
+
return e;
|
|
138
|
+
}, dirname: function(e) {
|
|
139
|
+
if (v(e), e.length === 0)
|
|
140
|
+
return ".";
|
|
141
|
+
for (var r = e.charCodeAt(0), t = r === 47, i = -1, a = true, n = e.length - 1;n >= 1; --n)
|
|
142
|
+
if (r = e.charCodeAt(n), r === 47) {
|
|
143
|
+
if (!a) {
|
|
144
|
+
i = n;
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
} else
|
|
148
|
+
a = false;
|
|
149
|
+
return i === -1 ? t ? "/" : "." : t && i === 1 ? "//" : e.slice(0, i);
|
|
150
|
+
}, basename: function(e, r) {
|
|
151
|
+
if (r !== undefined && typeof r != "string")
|
|
152
|
+
throw new TypeError('"ext" argument must be a string');
|
|
153
|
+
v(e);
|
|
154
|
+
var t = 0, i = -1, a = true, n;
|
|
155
|
+
if (r !== undefined && r.length > 0 && r.length <= e.length) {
|
|
156
|
+
if (r.length === e.length && r === e)
|
|
157
|
+
return "";
|
|
158
|
+
var l = r.length - 1, f = -1;
|
|
159
|
+
for (n = e.length - 1;n >= 0; --n) {
|
|
160
|
+
var c = e.charCodeAt(n);
|
|
161
|
+
if (c === 47) {
|
|
162
|
+
if (!a) {
|
|
163
|
+
t = n + 1;
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
} else
|
|
167
|
+
f === -1 && (a = false, f = n + 1), l >= 0 && (c === r.charCodeAt(l) ? --l === -1 && (i = n) : (l = -1, i = f));
|
|
168
|
+
}
|
|
169
|
+
return t === i ? i = f : i === -1 && (i = e.length), e.slice(t, i);
|
|
170
|
+
} else {
|
|
171
|
+
for (n = e.length - 1;n >= 0; --n)
|
|
172
|
+
if (e.charCodeAt(n) === 47) {
|
|
173
|
+
if (!a) {
|
|
174
|
+
t = n + 1;
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
} else
|
|
178
|
+
i === -1 && (a = false, i = n + 1);
|
|
179
|
+
return i === -1 ? "" : e.slice(t, i);
|
|
180
|
+
}
|
|
181
|
+
}, extname: function(e) {
|
|
182
|
+
v(e);
|
|
183
|
+
for (var r = -1, t = 0, i = -1, a = true, n = 0, l = e.length - 1;l >= 0; --l) {
|
|
184
|
+
var f = e.charCodeAt(l);
|
|
185
|
+
if (f === 47) {
|
|
186
|
+
if (!a) {
|
|
187
|
+
t = l + 1;
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
i === -1 && (a = false, i = l + 1), f === 46 ? r === -1 ? r = l : n !== 1 && (n = 1) : r !== -1 && (n = -1);
|
|
193
|
+
}
|
|
194
|
+
return r === -1 || i === -1 || n === 0 || n === 1 && r === i - 1 && r === t + 1 ? "" : e.slice(r, i);
|
|
195
|
+
}, format: function(e) {
|
|
196
|
+
if (e === null || typeof e != "object")
|
|
197
|
+
throw new TypeError('The "pathObject" argument must be of type Object. Received type ' + typeof e);
|
|
198
|
+
return F("/", e);
|
|
199
|
+
}, parse: function(e) {
|
|
200
|
+
v(e);
|
|
201
|
+
var r = { root: "", dir: "", base: "", ext: "", name: "" };
|
|
202
|
+
if (e.length === 0)
|
|
203
|
+
return r;
|
|
204
|
+
var t = e.charCodeAt(0), i = t === 47, a;
|
|
205
|
+
i ? (r.root = "/", a = 1) : a = 0;
|
|
206
|
+
for (var n = -1, l = 0, f = -1, c = true, d = e.length - 1, o = 0;d >= a; --d) {
|
|
207
|
+
if (t = e.charCodeAt(d), t === 47) {
|
|
208
|
+
if (!c) {
|
|
209
|
+
l = d + 1;
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
f === -1 && (c = false, f = d + 1), t === 46 ? n === -1 ? n = d : o !== 1 && (o = 1) : n !== -1 && (o = -1);
|
|
215
|
+
}
|
|
216
|
+
return n === -1 || f === -1 || o === 0 || o === 1 && n === f - 1 && n === l + 1 ? f !== -1 && (l === 0 && i ? r.base = r.name = e.slice(1, f) : r.base = r.name = e.slice(l, f)) : (l === 0 && i ? (r.name = e.slice(1, n), r.base = e.slice(1, f)) : (r.name = e.slice(l, n), r.base = e.slice(l, f)), r.ext = e.slice(n, f)), l > 0 ? r.dir = e.slice(0, l - 1) : i && (r.dir = "/"), r;
|
|
217
|
+
}, sep: "/", delimiter: ":", win32: null, posix: null };
|
|
218
|
+
m.posix = m;
|
|
219
|
+
w.exports = m;
|
|
220
|
+
});
|
|
221
|
+
var x = j(k());
|
|
222
|
+
var u = x;
|
|
223
|
+
var J = x;
|
|
224
|
+
var P = function(s) {
|
|
225
|
+
return s;
|
|
226
|
+
};
|
|
227
|
+
var S = function() {
|
|
228
|
+
throw new Error("Not implemented");
|
|
229
|
+
};
|
|
230
|
+
u.parse ??= S;
|
|
231
|
+
J.parse ??= S;
|
|
232
|
+
var g = { resolve: u.resolve.bind(u), normalize: u.normalize.bind(u), isAbsolute: u.isAbsolute.bind(u), join: u.join.bind(u), relative: u.relative.bind(u), toNamespacedPath: P, dirname: u.dirname.bind(u), basename: u.basename.bind(u), extname: u.extname.bind(u), format: u.format.bind(u), parse: u.parse.bind(u), sep: "/", delimiter: ":", win32: undefined, posix: undefined, _makeLong: P };
|
|
233
|
+
var y = { sep: "\\", delimiter: ";", win32: undefined, ...g, posix: g };
|
|
234
|
+
g.win32 = y.win32 = y;
|
|
235
|
+
g.posix = g;
|
|
236
|
+
var q = g;
|
|
237
|
+
|
|
238
|
+
// src/resolution/utils.ts
|
|
239
|
+
function getLocation(symbol) {
|
|
240
|
+
if (symbol.valueDeclaration) {
|
|
241
|
+
const sourceFile = symbol.valueDeclaration.getSourceFile();
|
|
242
|
+
const { line, character } = sourceFile.getLineAndCharacterOfPosition(symbol.valueDeclaration.getStart());
|
|
243
|
+
let { fileName } = sourceFile;
|
|
244
|
+
const cwd = process.cwd();
|
|
245
|
+
if (fileName.startsWith(cwd)) {
|
|
246
|
+
fileName = q.relative(cwd, fileName);
|
|
247
|
+
}
|
|
248
|
+
return `${fileName}:${line + 1}:${character + 1}`;
|
|
249
|
+
}
|
|
250
|
+
if (symbol.declarations && symbol.declarations.length > 0) {
|
|
251
|
+
const [firstDeclaration] = symbol.declarations;
|
|
252
|
+
const sourceFile = firstDeclaration?.getSourceFile();
|
|
253
|
+
if (sourceFile === undefined || firstDeclaration === undefined)
|
|
254
|
+
return "unknown";
|
|
255
|
+
const { line, character } = sourceFile.getLineAndCharacterOfPosition(firstDeclaration.getStart());
|
|
256
|
+
let fileName = sourceFile?.fileName;
|
|
257
|
+
const cwd = process.cwd();
|
|
258
|
+
if (fileName?.startsWith(cwd)) {
|
|
259
|
+
fileName = q.relative(cwd, fileName);
|
|
260
|
+
}
|
|
261
|
+
return `${fileName}:${line + 1}:${character + 1}`;
|
|
262
|
+
}
|
|
263
|
+
return "unknown";
|
|
264
|
+
}
|
|
265
|
+
function getDocumentation(checker, symbol) {
|
|
266
|
+
return ts.displayPartsToString(symbol.getDocumentationComment(checker));
|
|
267
|
+
}
|
|
268
|
+
function getJSDoc(checker, symbol) {
|
|
269
|
+
const jsDocTags = symbol.getJsDocTags(checker);
|
|
270
|
+
return jsDocTags.map((tag) => {
|
|
271
|
+
const tagName = tag.name;
|
|
272
|
+
const tagText = tag.text ? ts.displayPartsToString(tag.text) : "";
|
|
273
|
+
return `@${tagName}${tagText ? " " + tagText : ""}`;
|
|
274
|
+
}).join(`
|
|
275
|
+
`);
|
|
276
|
+
}
|
|
277
|
+
function getSymbolKind(symbol) {
|
|
278
|
+
const flags = symbol.getFlags();
|
|
279
|
+
if (flags & ts.SymbolFlags.Function)
|
|
280
|
+
return "function";
|
|
281
|
+
if (flags & ts.SymbolFlags.Class)
|
|
282
|
+
return "class";
|
|
283
|
+
if (flags & ts.SymbolFlags.Interface)
|
|
284
|
+
return "interface";
|
|
285
|
+
if (flags & ts.SymbolFlags.TypeAlias)
|
|
286
|
+
return "type";
|
|
287
|
+
if (flags & ts.SymbolFlags.Variable)
|
|
288
|
+
return "variable";
|
|
289
|
+
if (flags & ts.SymbolFlags.Property)
|
|
290
|
+
return "property";
|
|
291
|
+
if (flags & ts.SymbolFlags.Method)
|
|
292
|
+
return "method";
|
|
293
|
+
if (flags & ts.SymbolFlags.Enum)
|
|
294
|
+
return "enum";
|
|
295
|
+
if (flags & ts.SymbolFlags.Module)
|
|
296
|
+
return "module";
|
|
297
|
+
if (symbol.valueDeclaration) {
|
|
298
|
+
if (ts.isFunctionDeclaration(symbol.valueDeclaration)) {
|
|
299
|
+
return "function";
|
|
300
|
+
}
|
|
301
|
+
if (ts.isClassDeclaration(symbol.valueDeclaration)) {
|
|
302
|
+
return "class";
|
|
303
|
+
}
|
|
304
|
+
if (ts.isVariableDeclaration(symbol.valueDeclaration)) {
|
|
305
|
+
return "variable";
|
|
306
|
+
}
|
|
307
|
+
if (ts.isMethodDeclaration(symbol.valueDeclaration)) {
|
|
308
|
+
return "method";
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return "unknown";
|
|
312
|
+
}
|
|
313
|
+
export {
|
|
314
|
+
getSymbolKind,
|
|
315
|
+
getLocation,
|
|
316
|
+
getJSDoc,
|
|
317
|
+
getDocumentation
|
|
318
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tidewave",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Tidewave JavaScript CLI for documentation extraction and MCP server",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"typescript",
|
|
7
|
+
"documentation",
|
|
8
|
+
"mcp",
|
|
9
|
+
"cli",
|
|
10
|
+
"tidewave"
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://tidewave.ai",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/dashbit/tidewave_javascript.git"
|
|
16
|
+
},
|
|
17
|
+
"license": "Apache-2.0",
|
|
18
|
+
"author": "Dashbit",
|
|
19
|
+
"type": "module",
|
|
20
|
+
"main": "dist/cli/index.js",
|
|
21
|
+
"module": "dist/cli/index.js",
|
|
22
|
+
"bin": {
|
|
23
|
+
"tidewave": "dist/cli/index.js"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist/",
|
|
27
|
+
"README.md",
|
|
28
|
+
"LICENSE",
|
|
29
|
+
"CHANGELOG.md"
|
|
30
|
+
],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"dist": "bun build --outdir dist --root src --external commander --external chalk --external typescript src/**/*.ts",
|
|
33
|
+
"dev": "bun run src/cli/index.ts",
|
|
34
|
+
"test": "bun test",
|
|
35
|
+
"lint": "eslint src/ --ext .ts,.js",
|
|
36
|
+
"lint:fix": "eslint src/ --ext .ts,.js --fix",
|
|
37
|
+
"format": "prettier --write .",
|
|
38
|
+
"format:check": "prettier --check .",
|
|
39
|
+
"type:check": "tsc --noEmit",
|
|
40
|
+
"clean": "rm -rf dist/"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@modelcontextprotocol/sdk": "^1.17.4",
|
|
44
|
+
"chalk": "^5.3.0",
|
|
45
|
+
"commander": "^12.1.0",
|
|
46
|
+
"typescript": "^5",
|
|
47
|
+
"zod": "3.25.76"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@eslint/js": "^9.16.0",
|
|
51
|
+
"@types/bun": "latest",
|
|
52
|
+
"@types/node": "^22.10.1",
|
|
53
|
+
"@typescript-eslint/eslint-plugin": "^8.18.0",
|
|
54
|
+
"@typescript-eslint/parser": "^8.18.0",
|
|
55
|
+
"@vitest/ui": "^3.2.4",
|
|
56
|
+
"bun-types": "latest",
|
|
57
|
+
"eslint": "^9.16.0",
|
|
58
|
+
"globals": "^15.14.0",
|
|
59
|
+
"prettier": "^3.4.2",
|
|
60
|
+
"vitest": "^3.2.4"
|
|
61
|
+
},
|
|
62
|
+
"peerDependencies": {
|
|
63
|
+
"typescript": "^5"
|
|
64
|
+
},
|
|
65
|
+
"engines": {
|
|
66
|
+
"node": ">=18.0.0",
|
|
67
|
+
"bun": ">=1.0.0"
|
|
68
|
+
},
|
|
69
|
+
"publishConfig": {
|
|
70
|
+
"access": "public"
|
|
71
|
+
}
|
|
72
|
+
}
|