@optique/core 0.4.0-dev.52 → 0.4.0-dev.54

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/README.md CHANGED
@@ -1,9 +1,8 @@
1
1
  @optique/core
2
2
  =============
3
3
 
4
- > [!CAUTION]
5
- > Optique is currently in early development and may change significantly.
6
- > Expect breaking changes as we refine the API and features.
4
+ > [!WARNING]
5
+ > The API is stabilizing, but may change before the 1.0 release.
7
6
 
8
7
  The core package of Optique which provides the shared types and parser
9
8
  combinators. It is designed to be used in universal JavaScript runtimes,
package/dist/facade.cjs CHANGED
@@ -6,6 +6,253 @@ const require_parser = require('./parser.cjs');
6
6
 
7
7
  //#region src/facade.ts
8
8
  /**
9
+ * Creates help parsers based on the specified mode.
10
+ */
11
+ function createHelpParser(mode) {
12
+ const helpCommand = require_parser.command("help", require_parser.multiple(require_parser.argument(require_valueparser.string({ metavar: "COMMAND" }))), { description: require_message.message`Show help information.` });
13
+ const helpOption = require_parser.flag("--help", { description: require_message.message`Show help information.` });
14
+ const _contextualHelpParser = require_parser.object({
15
+ help: require_parser.constant(true),
16
+ version: require_parser.constant(false),
17
+ commands: require_parser.multiple(require_parser.argument(require_valueparser.string({
18
+ metavar: "COMMAND",
19
+ pattern: /^[^-].*$/
20
+ }))),
21
+ __help: require_parser.flag("--help")
22
+ });
23
+ switch (mode) {
24
+ case "command": return {
25
+ helpCommand,
26
+ helpOption: null,
27
+ contextualHelpParser: null
28
+ };
29
+ case "option": return {
30
+ helpCommand: null,
31
+ helpOption,
32
+ contextualHelpParser: null
33
+ };
34
+ case "both": return {
35
+ helpCommand,
36
+ helpOption,
37
+ contextualHelpParser: null
38
+ };
39
+ }
40
+ }
41
+ /**
42
+ * Creates version parsers based on the specified mode.
43
+ */
44
+ function createVersionParser(mode) {
45
+ const versionCommand = require_parser.command("version", require_parser.object({}), { description: require_message.message`Show version information.` });
46
+ const versionOption = require_parser.flag("--version", { description: require_message.message`Show version information.` });
47
+ switch (mode) {
48
+ case "command": return {
49
+ versionCommand,
50
+ versionOption: null
51
+ };
52
+ case "option": return {
53
+ versionCommand: null,
54
+ versionOption
55
+ };
56
+ case "both": return {
57
+ versionCommand,
58
+ versionOption
59
+ };
60
+ }
61
+ }
62
+ /**
63
+ * Systematically combines the original parser with help and version parsers.
64
+ */
65
+ function combineWithHelpVersion(originalParser, helpParsers, versionParsers) {
66
+ const parsers = [];
67
+ if (helpParsers.helpOption) {
68
+ const lenientHelpParser = {
69
+ $valueType: [],
70
+ $stateType: [],
71
+ priority: 200,
72
+ usage: helpParsers.helpOption.usage,
73
+ initialState: null,
74
+ parse(context) {
75
+ const { buffer, optionsTerminated } = context;
76
+ if (optionsTerminated) return {
77
+ success: false,
78
+ error: require_message.message`Options terminated`,
79
+ consumed: 0
80
+ };
81
+ let helpFound = false;
82
+ let helpIndex = -1;
83
+ let helpCount = 0;
84
+ let versionIndex = -1;
85
+ for (let i = 0; i < buffer.length; i++) {
86
+ if (buffer[i] === "--") break;
87
+ if (buffer[i] === "--help") {
88
+ helpFound = true;
89
+ helpIndex = i;
90
+ helpCount++;
91
+ }
92
+ if (buffer[i] === "--version") versionIndex = i;
93
+ }
94
+ if (helpFound && versionIndex > helpIndex) return {
95
+ success: false,
96
+ error: require_message.message`Version option wins`,
97
+ consumed: 0
98
+ };
99
+ if (helpFound) return {
100
+ success: true,
101
+ next: {
102
+ ...context,
103
+ buffer: [],
104
+ state: {
105
+ help: true,
106
+ version: false,
107
+ commands: [],
108
+ helpFlag: true
109
+ }
110
+ },
111
+ consumed: buffer.slice(0)
112
+ };
113
+ return {
114
+ success: false,
115
+ error: require_message.message`Flag --help not found`,
116
+ consumed: 0
117
+ };
118
+ },
119
+ complete(state) {
120
+ return {
121
+ success: true,
122
+ value: state
123
+ };
124
+ },
125
+ getDocFragments(state) {
126
+ return helpParsers.helpOption?.getDocFragments(state) ?? { fragments: [] };
127
+ }
128
+ };
129
+ parsers.push(lenientHelpParser);
130
+ }
131
+ if (versionParsers.versionOption) {
132
+ const lenientVersionParser = {
133
+ $valueType: [],
134
+ $stateType: [],
135
+ priority: 200,
136
+ usage: versionParsers.versionOption.usage,
137
+ initialState: null,
138
+ parse(context) {
139
+ const { buffer, optionsTerminated } = context;
140
+ if (optionsTerminated) return {
141
+ success: false,
142
+ error: require_message.message`Options terminated`,
143
+ consumed: 0
144
+ };
145
+ let versionFound = false;
146
+ let versionIndex = -1;
147
+ let versionCount = 0;
148
+ let helpIndex = -1;
149
+ for (let i = 0; i < buffer.length; i++) {
150
+ if (buffer[i] === "--") break;
151
+ if (buffer[i] === "--version") {
152
+ versionFound = true;
153
+ versionIndex = i;
154
+ versionCount++;
155
+ }
156
+ if (buffer[i] === "--help") helpIndex = i;
157
+ }
158
+ if (versionFound && helpIndex > versionIndex) return {
159
+ success: false,
160
+ error: require_message.message`Help option wins`,
161
+ consumed: 0
162
+ };
163
+ if (versionFound) return {
164
+ success: true,
165
+ next: {
166
+ ...context,
167
+ buffer: [],
168
+ state: {
169
+ help: false,
170
+ version: true,
171
+ versionFlag: true
172
+ }
173
+ },
174
+ consumed: buffer.slice(0)
175
+ };
176
+ return {
177
+ success: false,
178
+ error: require_message.message`Flag --version not found`,
179
+ consumed: 0
180
+ };
181
+ },
182
+ complete(state) {
183
+ return {
184
+ success: true,
185
+ value: state
186
+ };
187
+ },
188
+ getDocFragments(state) {
189
+ return versionParsers.versionOption?.getDocFragments(state) ?? { fragments: [] };
190
+ }
191
+ };
192
+ parsers.push(lenientVersionParser);
193
+ }
194
+ if (versionParsers.versionCommand) parsers.push(require_parser.object({
195
+ help: require_parser.constant(false),
196
+ version: require_parser.constant(true),
197
+ result: versionParsers.versionCommand,
198
+ helpFlag: helpParsers.helpOption ? require_parser.optional(helpParsers.helpOption) : require_parser.constant(false)
199
+ }));
200
+ if (helpParsers.helpCommand) parsers.push(require_parser.object({
201
+ help: require_parser.constant(true),
202
+ version: require_parser.constant(false),
203
+ commands: helpParsers.helpCommand
204
+ }));
205
+ if (helpParsers.contextualHelpParser) parsers.push(helpParsers.contextualHelpParser);
206
+ parsers.push(require_parser.object({
207
+ help: require_parser.constant(false),
208
+ version: require_parser.constant(false),
209
+ result: originalParser
210
+ }));
211
+ if (parsers.length === 1) return parsers[0];
212
+ else if (parsers.length === 2) return require_parser.longestMatch(parsers[0], parsers[1]);
213
+ else return require_parser.longestMatch(...parsers);
214
+ }
215
+ /**
216
+ * Classifies the parsing result into a discriminated union for cleaner handling.
217
+ */
218
+ function classifyResult(result, args) {
219
+ if (!result.success) return {
220
+ type: "error",
221
+ error: result.error
222
+ };
223
+ const value = result.value;
224
+ if (typeof value === "object" && value != null && "help" in value && "version" in value) {
225
+ const parsedValue = value;
226
+ const hasVersionOption = args.includes("--version");
227
+ const hasVersionCommand = args.length > 0 && args[0] === "version";
228
+ const hasHelpOption = args.includes("--help");
229
+ const hasHelpCommand = args.length > 0 && args[0] === "help";
230
+ if (hasVersionOption && hasHelpOption && !hasVersionCommand && !hasHelpCommand) {}
231
+ if (hasVersionCommand && hasHelpOption && parsedValue.helpFlag) return {
232
+ type: "help",
233
+ commands: ["version"]
234
+ };
235
+ if (parsedValue.help && (hasHelpOption || hasHelpCommand)) {
236
+ let commandContext = [];
237
+ if (Array.isArray(parsedValue.commands)) commandContext = parsedValue.commands;
238
+ else if (typeof parsedValue.commands === "object" && parsedValue.commands != null && "length" in parsedValue.commands) commandContext = parsedValue.commands;
239
+ return {
240
+ type: "help",
241
+ commands: commandContext
242
+ };
243
+ }
244
+ if ((hasVersionOption || hasVersionCommand) && (parsedValue.version || parsedValue.versionFlag)) return { type: "version" };
245
+ return {
246
+ type: "success",
247
+ value: parsedValue.result ?? value
248
+ };
249
+ }
250
+ return {
251
+ type: "success",
252
+ value
253
+ };
254
+ }
255
+ /**
9
256
  * Runs a parser against command-line arguments with built-in help and error
10
257
  * handling.
11
258
  *
@@ -44,257 +291,60 @@ function run(parser, programName, args, options = {}) {
44
291
  throw new RunError("Failed to parse command line arguments.");
45
292
  }, stderr = console.error, stdout = console.log } = options;
46
293
  const help = options.help ? helpMode : "none";
47
- const contextualHelpParser = require_parser.object({
48
- help: require_parser.constant(true),
49
- version: require_parser.constant(false),
50
- commands: require_parser.multiple(require_parser.argument(require_valueparser.string({
51
- metavar: "COMMAND",
52
- pattern: /^[^-].*$/
53
- }))),
54
- __help: require_parser.flag("--help")
55
- });
56
- const helpCommand = require_parser.command("help", require_parser.multiple(require_parser.argument(require_valueparser.string({ metavar: "COMMAND" }))), { description: require_message.message`Show help information.` });
57
- const helpOption = require_parser.option("--help", { description: require_message.message`Show help information.` });
58
294
  const version = options.version ? versionMode : "none";
59
- const versionCommand = require_parser.command("version", require_parser.object({}), { description: require_message.message`Show version information.` });
60
- const versionOption = require_parser.option("--version", { description: require_message.message`Show version information.` });
61
- const augmentedParser = help === "none" && version === "none" ? parser : help === "none" && version === "command" ? require_parser.longestMatch(require_parser.object({
62
- help: require_parser.constant(false),
63
- version: require_parser.constant(true),
64
- result: versionCommand
65
- }), require_parser.object({
66
- help: require_parser.constant(false),
67
- version: require_parser.constant(false),
68
- result: parser
69
- })) : help === "none" && version === "option" ? require_parser.longestMatch(require_parser.object({
70
- help: require_parser.constant(false),
71
- version: require_parser.constant(false),
72
- result: parser
73
- }), require_parser.merge(require_parser.object({
74
- help: require_parser.constant(false),
75
- version: require_parser.constant(true)
76
- }), versionOption)) : help === "none" && version === "both" ? require_parser.longestMatch(require_parser.object({
77
- help: require_parser.constant(false),
78
- version: require_parser.constant(true),
79
- result: versionCommand
80
- }), require_parser.object({
81
- help: require_parser.constant(false),
82
- version: require_parser.constant(false),
83
- result: parser
84
- }), require_parser.merge(require_parser.object({
85
- help: require_parser.constant(false),
86
- version: require_parser.constant(true)
87
- }), versionOption)) : help === "command" && version === "none" ? require_parser.longestMatch(require_parser.object({
88
- help: require_parser.constant(true),
89
- version: require_parser.constant(false),
90
- commands: helpCommand
91
- }), require_parser.object({
92
- help: require_parser.constant(false),
93
- version: require_parser.constant(false),
94
- result: parser
95
- })) : help === "command" && version === "command" ? require_parser.longestMatch(require_parser.object({
96
- help: require_parser.constant(true),
97
- version: require_parser.constant(false),
98
- commands: helpCommand
99
- }), require_parser.object({
100
- help: require_parser.constant(false),
101
- version: require_parser.constant(true),
102
- result: versionCommand
103
- }), require_parser.object({
104
- help: require_parser.constant(false),
105
- version: require_parser.constant(false),
106
- result: parser
107
- })) : help === "command" && version === "option" ? require_parser.longestMatch(require_parser.object({
108
- help: require_parser.constant(true),
109
- version: require_parser.constant(false),
110
- commands: helpCommand
111
- }), require_parser.object({
112
- help: require_parser.constant(false),
113
- version: require_parser.constant(false),
114
- result: parser
115
- }), require_parser.merge(require_parser.object({
116
- help: require_parser.constant(false),
117
- version: require_parser.constant(true)
118
- }), versionOption)) : help === "command" && version === "both" ? require_parser.longestMatch(require_parser.object({
119
- help: require_parser.constant(true),
120
- version: require_parser.constant(false),
121
- commands: helpCommand
122
- }), require_parser.object({
123
- help: require_parser.constant(false),
124
- version: require_parser.constant(true),
125
- result: versionCommand
126
- }), require_parser.object({
127
- help: require_parser.constant(false),
128
- version: require_parser.constant(false),
129
- result: parser
130
- }), require_parser.merge(require_parser.object({
131
- help: require_parser.constant(false),
132
- version: require_parser.constant(true)
133
- }), versionOption)) : help === "option" && version === "none" ? require_parser.longestMatch(require_parser.object({
134
- help: require_parser.constant(false),
135
- version: require_parser.constant(false),
136
- result: parser
137
- }), contextualHelpParser, require_parser.merge(require_parser.object({
138
- help: require_parser.constant(true),
139
- version: require_parser.constant(false),
140
- commands: require_parser.constant([])
141
- }), helpOption)) : help === "option" && version === "command" ? require_parser.longestMatch(require_parser.object({
142
- help: require_parser.constant(false),
143
- version: require_parser.constant(true),
144
- result: versionCommand
145
- }), require_parser.object({
146
- help: require_parser.constant(false),
147
- version: require_parser.constant(false),
148
- result: parser
149
- }), contextualHelpParser, require_parser.merge(require_parser.object({
150
- help: require_parser.constant(true),
151
- version: require_parser.constant(false),
152
- commands: require_parser.constant([])
153
- }), helpOption)) : help === "option" && version === "option" ? require_parser.longestMatch(require_parser.merge(require_parser.object({
154
- help: require_parser.constant(false),
155
- version: require_parser.constant(true)
156
- }), versionOption), require_parser.object({
157
- help: require_parser.constant(false),
158
- version: require_parser.constant(false),
159
- result: parser
160
- }), contextualHelpParser, require_parser.merge(require_parser.object({
161
- help: require_parser.constant(true),
162
- version: require_parser.constant(false),
163
- commands: require_parser.constant([])
164
- }), helpOption)) : help === "option" && version === "both" ? require_parser.longestMatch(require_parser.merge(require_parser.object({
165
- help: require_parser.constant(false),
166
- version: require_parser.constant(true)
167
- }), versionOption), require_parser.object({
168
- help: require_parser.constant(false),
169
- version: require_parser.constant(true),
170
- result: versionCommand
171
- }), require_parser.object({
172
- help: require_parser.constant(false),
173
- version: require_parser.constant(false),
174
- result: parser
175
- }), contextualHelpParser, require_parser.merge(require_parser.object({
176
- help: require_parser.constant(true),
177
- version: require_parser.constant(false),
178
- commands: require_parser.constant([])
179
- }), helpOption)) : help === "both" && version === "none" ? require_parser.longestMatch(require_parser.object({
180
- help: require_parser.constant(false),
181
- version: require_parser.constant(false),
182
- result: parser
183
- }), require_parser.object({
184
- help: require_parser.constant(true),
185
- version: require_parser.constant(false),
186
- commands: helpCommand
187
- }), contextualHelpParser, require_parser.merge(require_parser.object({
188
- help: require_parser.constant(true),
189
- version: require_parser.constant(false),
190
- commands: require_parser.constant([])
191
- }), helpOption)) : help === "both" && version === "command" ? require_parser.longestMatch(require_parser.object({
192
- help: require_parser.constant(true),
193
- version: require_parser.constant(false),
194
- commands: helpCommand
195
- }), require_parser.object({
196
- help: require_parser.constant(false),
197
- version: require_parser.constant(true),
198
- result: versionCommand
199
- }), require_parser.object({
200
- help: require_parser.constant(false),
201
- version: require_parser.constant(false),
202
- result: parser
203
- }), contextualHelpParser, require_parser.merge(require_parser.object({
204
- help: require_parser.constant(true),
205
- version: require_parser.constant(false),
206
- commands: require_parser.constant([])
207
- }), helpOption)) : help === "both" && version === "option" ? require_parser.longestMatch(require_parser.merge(require_parser.object({
208
- help: require_parser.constant(false),
209
- version: require_parser.constant(true)
210
- }), versionOption), require_parser.object({
211
- help: require_parser.constant(true),
212
- version: require_parser.constant(false),
213
- commands: helpCommand
214
- }), require_parser.object({
215
- help: require_parser.constant(false),
216
- version: require_parser.constant(false),
217
- result: parser
218
- }), contextualHelpParser, require_parser.merge(require_parser.object({
219
- help: require_parser.constant(true),
220
- version: require_parser.constant(false),
221
- commands: require_parser.constant([])
222
- }), helpOption)) : require_parser.longestMatch(require_parser.merge(require_parser.object({
223
- help: require_parser.constant(false),
224
- version: require_parser.constant(true)
225
- }), versionOption), require_parser.object({
226
- help: require_parser.constant(false),
227
- version: require_parser.constant(true),
228
- result: versionCommand
229
- }), require_parser.object({
230
- help: require_parser.constant(true),
231
- version: require_parser.constant(false),
232
- commands: helpCommand
233
- }), require_parser.object({
234
- help: require_parser.constant(false),
235
- version: require_parser.constant(false),
236
- result: parser
237
- }), require_parser.longestMatch(contextualHelpParser, require_parser.merge(require_parser.object({
238
- help: require_parser.constant(true),
239
- version: require_parser.constant(false),
240
- commands: require_parser.constant([])
241
- }), helpOption)));
242
- let result = require_parser.parse(augmentedParser, args);
243
- if (result.success && typeof result.value === "object" && result.value != null && "help" in result.value && "version" in result.value) {
244
- const parsedValue = result.value;
245
- const hasVersionInput = args.includes("--version") || args.length > 0 && args[0] === "version";
246
- const hasHelpInput = args.includes("--help") || args.length > 0 && args[0] === "help";
247
- if (parsedValue.version && !hasVersionInput || parsedValue.help && !hasHelpInput && !parsedValue.result) result = require_parser.parse(parser, args);
248
- }
249
- if (result.success) {
250
- const value = result.value;
251
- if (help === "none" && version === "none") return value;
252
- if (typeof value === "object" && value != null && "help" in value && "version" in value) {
253
- const parsedValue = value;
254
- if (parsedValue.version) {
255
- const hasVersionOption = args.includes("--version");
256
- const hasVersionCommand = args.length > 0 && args[0] === "version";
257
- if (hasVersionOption || hasVersionCommand) {
258
- stdout(versionValue);
259
- try {
260
- return onVersion(0);
261
- } catch {
262
- return onVersion();
263
- }
264
- }
295
+ const helpParsers = help === "none" ? {
296
+ helpCommand: null,
297
+ helpOption: null,
298
+ contextualHelpParser: null
299
+ } : createHelpParser(help);
300
+ const versionParsers = version === "none" ? {
301
+ versionCommand: null,
302
+ versionOption: null
303
+ } : createVersionParser(version);
304
+ const augmentedParser = help === "none" && version === "none" ? parser : combineWithHelpVersion(parser, helpParsers, versionParsers);
305
+ const result = require_parser.parse(augmentedParser, args);
306
+ const classified = classifyResult(result, args);
307
+ switch (classified.type) {
308
+ case "success": return classified.value;
309
+ case "version":
310
+ stdout(versionValue);
311
+ try {
312
+ return onVersion(0);
313
+ } catch {
314
+ return onVersion();
265
315
  }
266
- if (parsedValue.help) {
267
- if (version !== "none" && args.includes("--version")) {
268
- stdout(versionValue);
269
- try {
270
- return onVersion(0);
271
- } catch {
272
- return onVersion();
273
- }
274
- }
275
- let commandContext = [];
276
- if (Array.isArray(parsedValue.commands)) commandContext = parsedValue.commands;
277
- else if (typeof parsedValue.commands === "object" && parsedValue.commands != null && "length" in parsedValue.commands) commandContext = parsedValue.commands;
278
- let helpGeneratorParser;
279
- const helpAsCommand = help === "command" || help === "both";
280
- const versionAsCommand = version === "command" || version === "both";
281
- if (helpAsCommand && versionAsCommand) helpGeneratorParser = require_parser.longestMatch(parser, helpCommand, versionCommand);
282
- else if (helpAsCommand) helpGeneratorParser = require_parser.longestMatch(parser, helpCommand);
283
- else if (versionAsCommand) helpGeneratorParser = require_parser.longestMatch(parser, versionCommand);
316
+ case "help": {
317
+ let helpGeneratorParser;
318
+ const helpAsCommand = help === "command" || help === "both";
319
+ const versionAsCommand = version === "command" || version === "both";
320
+ if (helpAsCommand && versionAsCommand) {
321
+ const tempHelpParsers = createHelpParser(help);
322
+ const tempVersionParsers = createVersionParser(version);
323
+ if (tempHelpParsers.helpCommand && tempVersionParsers.versionCommand) helpGeneratorParser = require_parser.longestMatch(parser, tempHelpParsers.helpCommand, tempVersionParsers.versionCommand);
324
+ else if (tempHelpParsers.helpCommand) helpGeneratorParser = require_parser.longestMatch(parser, tempHelpParsers.helpCommand);
325
+ else if (tempVersionParsers.versionCommand) helpGeneratorParser = require_parser.longestMatch(parser, tempVersionParsers.versionCommand);
284
326
  else helpGeneratorParser = parser;
285
- const doc = require_parser.getDocPage(commandContext.length < 1 ? helpGeneratorParser : parser, commandContext);
286
- if (doc != null) stdout(require_doc.formatDocPage(programName, doc, {
287
- colors,
288
- maxWidth
289
- }));
290
- try {
291
- return onHelp(0);
292
- } catch {
293
- return onHelp();
294
- }
327
+ } else if (helpAsCommand) {
328
+ const tempHelpParsers = createHelpParser(help);
329
+ if (tempHelpParsers.helpCommand) helpGeneratorParser = require_parser.longestMatch(parser, tempHelpParsers.helpCommand);
330
+ else helpGeneratorParser = parser;
331
+ } else if (versionAsCommand) {
332
+ const tempVersionParsers = createVersionParser(version);
333
+ if (tempVersionParsers.versionCommand) helpGeneratorParser = require_parser.longestMatch(parser, tempVersionParsers.versionCommand);
334
+ else helpGeneratorParser = parser;
335
+ } else helpGeneratorParser = parser;
336
+ const doc = require_parser.getDocPage(helpGeneratorParser, classified.commands);
337
+ if (doc != null) stdout(require_doc.formatDocPage(programName, doc, {
338
+ colors,
339
+ maxWidth
340
+ }));
341
+ try {
342
+ return onHelp(0);
343
+ } catch {
344
+ return onHelp();
295
345
  }
296
- return parsedValue.result ?? value;
297
- } else return value;
346
+ }
347
+ case "error": break;
298
348
  }
299
349
  if (aboveError === "help") {
300
350
  const doc = require_parser.getDocPage(args.length < 1 ? augmentedParser : parser, args);
@@ -309,10 +359,11 @@ function run(parser, programName, args, options = {}) {
309
359
  maxWidth: maxWidth == null ? void 0 : maxWidth - 7,
310
360
  expandCommands: true
311
361
  }), 7)}`);
312
- stderr(`Error: ${require_message.formatMessage(result.error, {
362
+ const errorMessage = require_message.formatMessage(classified.error, {
313
363
  colors,
314
364
  quotes: !colors
315
- })}`);
365
+ });
366
+ stderr(`Error: ${errorMessage}`);
316
367
  return onError(1);
317
368
  }
318
369
  /**