unplugin-https-reverse-proxy 0.0.11 → 0.0.13
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 +5 -2
- package/dist/{chunk-UGVWTB7L.js → chunk-6KXUNICB.js} +1 -1
- package/dist/chunk-CQC5SSJR.js +37 -0
- package/dist/{chunk-5K6D2TTS.js → chunk-DH6VMKTP.js} +181 -70
- package/dist/{chunk-BFAT7WWW.js → chunk-RTEXFW4L.js} +1 -1
- package/dist/esbuild.cjs +200 -68
- package/dist/esbuild.js +2 -2
- package/dist/index.cjs +200 -68
- package/dist/index.js +2 -2
- package/dist/nuxt.cjs +200 -68
- package/dist/nuxt.js +4 -4
- package/dist/rollup.cjs +200 -68
- package/dist/rollup.js +2 -2
- package/dist/types.d.cts +1 -0
- package/dist/types.d.ts +1 -0
- package/dist/utils.cjs +13 -2
- package/dist/utils.d.cts +2 -1
- package/dist/utils.d.ts +2 -1
- package/dist/utils.js +5 -3
- package/dist/vite.cjs +200 -68
- package/dist/vite.js +3 -3
- package/dist/webpack.cjs +200 -68
- package/dist/webpack.js +3 -3
- package/package.json +3 -3
- package/src/caddy/index.ts +69 -58
- package/src/caddy/utils.ts +41 -0
- package/src/index.ts +103 -21
- package/src/types.ts +1 -0
- package/src/utils.ts +10 -0
- package/dist/chunk-3HKPYCSE.js +0 -9
package/README.md
CHANGED
|
@@ -16,6 +16,7 @@ UHRP_AUTO_INSTALL_CADDY=true npm i unplugin-https-reverse-proxy --save-dev
|
|
|
16
16
|
|
|
17
17
|
```ts
|
|
18
18
|
interface Options {
|
|
19
|
+
enable?: boolean // <- default: true
|
|
19
20
|
target: string // <- https target hostname
|
|
20
21
|
showCaddyLog?: boolean // <- default: false
|
|
21
22
|
}
|
|
@@ -26,11 +27,11 @@ interface Options {
|
|
|
26
27
|
|
|
27
28
|
```ts
|
|
28
29
|
// vite.config.ts
|
|
29
|
-
import
|
|
30
|
+
import HttpsReverseProxy from 'unplugin-https-reverse-proxy/vite'
|
|
30
31
|
|
|
31
32
|
export default defineConfig({
|
|
32
33
|
plugins: [
|
|
33
|
-
|
|
34
|
+
HttpsReverseProxy({ /* options */ }),
|
|
34
35
|
],
|
|
35
36
|
})
|
|
36
37
|
```
|
|
@@ -55,6 +56,7 @@ module.exports = {
|
|
|
55
56
|
port: 443,
|
|
56
57
|
},
|
|
57
58
|
},
|
|
59
|
+
setupExitSignals: true,
|
|
58
60
|
},
|
|
59
61
|
plugins: [
|
|
60
62
|
require('unplugin-https-reverse-proxy/webpack')({ /* options */ })
|
|
@@ -95,6 +97,7 @@ module.exports = {
|
|
|
95
97
|
port: 443,
|
|
96
98
|
},
|
|
97
99
|
},
|
|
100
|
+
setupExitSignals: true,
|
|
98
101
|
},
|
|
99
102
|
configureWebpack: {
|
|
100
103
|
plugins: [
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
3
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
5
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
+
var __spreadValues = (a, b) => {
|
|
7
|
+
for (var prop in b || (b = {}))
|
|
8
|
+
if (__hasOwnProp.call(b, prop))
|
|
9
|
+
__defNormalProp(a, prop, b[prop]);
|
|
10
|
+
if (__getOwnPropSymbols)
|
|
11
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
12
|
+
if (__propIsEnum.call(b, prop))
|
|
13
|
+
__defNormalProp(a, prop, b[prop]);
|
|
14
|
+
}
|
|
15
|
+
return a;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// src/utils.ts
|
|
19
|
+
import { createConsola } from "consola";
|
|
20
|
+
var consola = createConsola({
|
|
21
|
+
level: 3
|
|
22
|
+
}).withTag("reverse-proxy");
|
|
23
|
+
function once(fn) {
|
|
24
|
+
let called = false;
|
|
25
|
+
return (...args) => {
|
|
26
|
+
if (called)
|
|
27
|
+
return;
|
|
28
|
+
called = true;
|
|
29
|
+
return fn(...args);
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export {
|
|
34
|
+
__spreadValues,
|
|
35
|
+
consola,
|
|
36
|
+
once
|
|
37
|
+
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
__spreadValues,
|
|
3
|
+
consola,
|
|
4
|
+
once
|
|
5
|
+
} from "./chunk-CQC5SSJR.js";
|
|
4
6
|
|
|
5
7
|
// src/index.ts
|
|
6
8
|
import process3 from "process";
|
|
@@ -15,7 +17,7 @@ import { spawn } from "child_process";
|
|
|
15
17
|
import { got } from "got-cjs";
|
|
16
18
|
import { HttpProxyAgent } from "http-proxy-agent";
|
|
17
19
|
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
18
|
-
import
|
|
20
|
+
import _Hosts from "hosts-so-easy";
|
|
19
21
|
import kill from "kill-port";
|
|
20
22
|
|
|
21
23
|
// src/caddy/constants.ts
|
|
@@ -137,6 +139,8 @@ var supportList = [
|
|
|
137
139
|
|
|
138
140
|
// src/caddy/utils.ts
|
|
139
141
|
import { createServer } from "net";
|
|
142
|
+
import ora from "ora";
|
|
143
|
+
var spinner;
|
|
140
144
|
function tryPort(port) {
|
|
141
145
|
return new Promise((resolve, reject) => {
|
|
142
146
|
try {
|
|
@@ -155,8 +159,41 @@ function tryPort(port) {
|
|
|
155
159
|
}
|
|
156
160
|
});
|
|
157
161
|
}
|
|
162
|
+
function getNumber(number) {
|
|
163
|
+
if (number <= 0)
|
|
164
|
+
return "0%";
|
|
165
|
+
else if (number < 100)
|
|
166
|
+
return `${number.toFixed(2)}%`;
|
|
167
|
+
else
|
|
168
|
+
return "100%";
|
|
169
|
+
}
|
|
170
|
+
function logProgress(percent) {
|
|
171
|
+
if (!spinner) {
|
|
172
|
+
consola.log("");
|
|
173
|
+
spinner = ora({
|
|
174
|
+
text: "Start Download Caddy: 0%",
|
|
175
|
+
indent: 2
|
|
176
|
+
});
|
|
177
|
+
spinner.start();
|
|
178
|
+
} else {
|
|
179
|
+
spinner.text = `Download Caddy: ${getNumber(Number(percent) * 100)}`;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function logProgressOver() {
|
|
183
|
+
if (!spinner) {
|
|
184
|
+
spinner = ora({
|
|
185
|
+
text: "Start Download Caddy: 100%",
|
|
186
|
+
indent: 2
|
|
187
|
+
});
|
|
188
|
+
spinner.start();
|
|
189
|
+
} else {
|
|
190
|
+
spinner.succeed();
|
|
191
|
+
consola.log("");
|
|
192
|
+
}
|
|
193
|
+
}
|
|
158
194
|
|
|
159
195
|
// src/caddy/index.ts
|
|
196
|
+
var Hosts = _Hosts.default || _Hosts;
|
|
160
197
|
async function download() {
|
|
161
198
|
if (await testCaddy())
|
|
162
199
|
return caddyPath;
|
|
@@ -180,7 +217,10 @@ async function download() {
|
|
|
180
217
|
http: httpAgent,
|
|
181
218
|
https: httpsAgent
|
|
182
219
|
}
|
|
220
|
+
}).on("downloadProgress", (progress) => {
|
|
221
|
+
logProgress(progress.percent);
|
|
183
222
|
}).pipe(file).on("finish", () => {
|
|
223
|
+
logProgressOver();
|
|
184
224
|
if (process2.platform === "win32")
|
|
185
225
|
return resolve(caddyPath);
|
|
186
226
|
chmodSync(caddyPath, 493);
|
|
@@ -195,7 +235,7 @@ function testCaddy() {
|
|
|
195
235
|
if (!existsSync(caddyPath))
|
|
196
236
|
return resolve(false);
|
|
197
237
|
chmodSync(caddyPath, 493);
|
|
198
|
-
const child = process2.platform === "win32" ? spawn(caddyPath, []) : spawn("sudo", [caddyPath]);
|
|
238
|
+
const child = process2.platform === "win32" ? spawn(caddyPath, []) : spawn("sudo", ["-E", caddyPath]);
|
|
199
239
|
child.on("close", () => {
|
|
200
240
|
return resolve(false);
|
|
201
241
|
});
|
|
@@ -210,6 +250,8 @@ function testCaddy() {
|
|
|
210
250
|
var CaddyInstant = class {
|
|
211
251
|
constructor() {
|
|
212
252
|
this.inited = false;
|
|
253
|
+
this.stoped = false;
|
|
254
|
+
this.host = new Hosts();
|
|
213
255
|
testCaddy().then(() => {
|
|
214
256
|
this.inited = true;
|
|
215
257
|
});
|
|
@@ -218,52 +260,46 @@ var CaddyInstant = class {
|
|
|
218
260
|
await download();
|
|
219
261
|
this.inited = true;
|
|
220
262
|
}
|
|
221
|
-
|
|
263
|
+
updateHost(ip, host) {
|
|
222
264
|
["localhost", "0.0.0.0"].includes(ip) && (ip = "127.0.0.1");
|
|
265
|
+
this.host.add(ip, host);
|
|
223
266
|
return new Promise((resolve, reject) => {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
});
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
});
|
|
267
|
+
if (process2.platform === "win32") {
|
|
268
|
+
spawn("ipconfig", ["/flushdns"]).on("error", (err) => {
|
|
269
|
+
consola.error(err);
|
|
270
|
+
return resolve(false);
|
|
271
|
+
}).on("close", () => {
|
|
272
|
+
resolve(true);
|
|
273
|
+
});
|
|
274
|
+
} else {
|
|
275
|
+
spawn("sudo", ["-E", "killall", "-HUP", "mDNSResponder"]).on("error", (err) => {
|
|
276
|
+
consola.error(err);
|
|
277
|
+
return resolve(false);
|
|
278
|
+
}).on("close", () => {
|
|
279
|
+
resolve(true);
|
|
280
|
+
});
|
|
281
|
+
}
|
|
243
282
|
});
|
|
244
283
|
}
|
|
245
|
-
|
|
284
|
+
restoreHost(ip, host) {
|
|
246
285
|
["localhost", "0.0.0.0"].includes(ip) && (ip = "127.0.0.1");
|
|
286
|
+
this.host.remove(ip, host);
|
|
247
287
|
return new Promise((resolve, reject) => {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
});
|
|
288
|
+
if (process2.platform === "win32") {
|
|
289
|
+
spawn("ipconfig", ["/flushdns"]).on("error", (err) => {
|
|
290
|
+
consola.error(err);
|
|
291
|
+
return resolve(false);
|
|
292
|
+
}).on("close", () => {
|
|
293
|
+
resolve(true);
|
|
294
|
+
});
|
|
295
|
+
} else {
|
|
296
|
+
spawn("sudo", ["-E", "killall", "-HUP", "mDNSResponder"]).on("error", (err) => {
|
|
297
|
+
consola.error(err);
|
|
298
|
+
return resolve(false);
|
|
299
|
+
}).on("close", () => {
|
|
300
|
+
resolve(true);
|
|
301
|
+
});
|
|
302
|
+
}
|
|
267
303
|
});
|
|
268
304
|
}
|
|
269
305
|
/**
|
|
@@ -280,14 +316,15 @@ var CaddyInstant = class {
|
|
|
280
316
|
} = options || {};
|
|
281
317
|
if (!this.inited)
|
|
282
318
|
await this.init();
|
|
283
|
-
if (!await this.updateHost(source.split(":")[0], target.split(":")[0]))
|
|
284
|
-
throw new Error("update host failed");
|
|
285
319
|
if (await tryPort(443))
|
|
286
320
|
await kill(443, "tcp");
|
|
287
321
|
if (process2.platform === "win32" && await tryPort(80))
|
|
288
322
|
await kill(80, "tcp");
|
|
323
|
+
if (!await this.updateHost(source.split(":")[0], target.split(":")[0]))
|
|
324
|
+
throw new Error("update host failed");
|
|
325
|
+
consola.success("update host success\n");
|
|
289
326
|
return new Promise((resolve, reject) => {
|
|
290
|
-
const child = process2.platform !== "win32" ? spawn("sudo", [caddyPath, "reverse-proxy", "--from", `${target.split(":")[0]}`, "--to", `${source}`, "--internal-certs"]) : spawn(caddyPath, ["reverse-proxy", "--from", `${target.split(":")[0]}`, "--to", `${source}`, "--internal-certs"]);
|
|
327
|
+
const child = process2.platform !== "win32" ? spawn("sudo", ["-E", caddyPath, "reverse-proxy", "--from", `${target.split(":")[0]}`, "--to", `${source}`, "--internal-certs"]) : spawn(caddyPath, ["reverse-proxy", "--from", `${target.split(":")[0]}`, "--to", `${source}`, "--internal-certs"]);
|
|
291
328
|
child.on("error", (err) => {
|
|
292
329
|
return reject(err);
|
|
293
330
|
});
|
|
@@ -295,7 +332,7 @@ var CaddyInstant = class {
|
|
|
295
332
|
const lines = data.toString().split("\n").map((line) => line.trim());
|
|
296
333
|
for (const line of lines) {
|
|
297
334
|
showCaddyLog && line && console.info(line);
|
|
298
|
-
if (line && JSON.parse(line).level === "error") {
|
|
335
|
+
if (line.includes("Error:") || line && JSON.parse(line).level === "error") {
|
|
299
336
|
consola.error(line);
|
|
300
337
|
return reject(line);
|
|
301
338
|
}
|
|
@@ -303,14 +340,21 @@ var CaddyInstant = class {
|
|
|
303
340
|
});
|
|
304
341
|
child.stdout.on("data", (_data) => {
|
|
305
342
|
consola.info(_data.toString());
|
|
306
|
-
resolve(async () => {
|
|
307
|
-
if (!restore)
|
|
343
|
+
resolve(async (callback) => {
|
|
344
|
+
if (!restore || this.stoped)
|
|
308
345
|
return;
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
346
|
+
try {
|
|
347
|
+
if (await this.restoreHost(source.split(":")[0], target.split(":")[0]))
|
|
348
|
+
consola.success("restore host success\n");
|
|
349
|
+
else
|
|
350
|
+
consola.fail("restore host failed\n");
|
|
351
|
+
} catch (e) {
|
|
352
|
+
consola.error(e);
|
|
312
353
|
consola.fail("restore host failed\n");
|
|
354
|
+
}
|
|
355
|
+
this.stoped = true;
|
|
313
356
|
child.kill();
|
|
357
|
+
callback && callback();
|
|
314
358
|
});
|
|
315
359
|
});
|
|
316
360
|
});
|
|
@@ -320,21 +364,66 @@ var CaddyInstant = class {
|
|
|
320
364
|
// src/index.ts
|
|
321
365
|
var config;
|
|
322
366
|
var caddy;
|
|
367
|
+
var _stop;
|
|
368
|
+
var _servce;
|
|
369
|
+
function registerExit(clear) {
|
|
370
|
+
process3.on("beforeExit", async (_code) => {
|
|
371
|
+
await clear();
|
|
372
|
+
});
|
|
373
|
+
process3.on("uncaughtException", async (err) => {
|
|
374
|
+
console.error("An uncaught error occurred!", err.stack);
|
|
375
|
+
await clear();
|
|
376
|
+
process3.nextTick(() => {
|
|
377
|
+
process3.exit(1);
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
process3.on("unhandledRejection", async (reason, promise) => {
|
|
381
|
+
console.error("Unhandled Rejection at:", promise, "reason:", reason);
|
|
382
|
+
await clear();
|
|
383
|
+
process3.nextTick(() => {
|
|
384
|
+
process3.exit(1);
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
process3.once("SIGINT", async () => {
|
|
388
|
+
await clear();
|
|
389
|
+
process3.emit("SIGINT");
|
|
390
|
+
});
|
|
391
|
+
process3.once("SIGTERM", async () => {
|
|
392
|
+
await clear();
|
|
393
|
+
process3.emit("SIGTERM");
|
|
394
|
+
});
|
|
395
|
+
}
|
|
323
396
|
var unpluginFactory = (options) => ({
|
|
324
397
|
name: "unplugin-https-reverse-proxy",
|
|
325
|
-
enforce: "
|
|
398
|
+
enforce: "pre",
|
|
326
399
|
vite: {
|
|
327
400
|
configResolved(_config) {
|
|
328
401
|
config = _config;
|
|
402
|
+
registerExit(async () => {
|
|
403
|
+
var _a;
|
|
404
|
+
try {
|
|
405
|
+
_servce && _servce.close();
|
|
406
|
+
(_a = _servce.httpServer) == null ? void 0 : _a.close(async () => {
|
|
407
|
+
_stop && await _stop();
|
|
408
|
+
});
|
|
409
|
+
_stop && await _stop();
|
|
410
|
+
} catch (e) {
|
|
411
|
+
consola.error(e);
|
|
412
|
+
}
|
|
413
|
+
});
|
|
329
414
|
},
|
|
330
415
|
configureServer(server) {
|
|
331
416
|
const {
|
|
417
|
+
enable = true,
|
|
332
418
|
target = ""
|
|
333
419
|
} = options;
|
|
420
|
+
if (!enable)
|
|
421
|
+
return;
|
|
334
422
|
if (!target) {
|
|
335
423
|
consola.fail("please provide target");
|
|
336
424
|
return;
|
|
337
425
|
}
|
|
426
|
+
_servce = server;
|
|
338
427
|
const _printUrls = server.printUrls;
|
|
339
428
|
server.printUrls = () => {
|
|
340
429
|
var _a;
|
|
@@ -347,51 +436,73 @@ var unpluginFactory = (options) => ({
|
|
|
347
436
|
}
|
|
348
437
|
const base = server.config.base || "/";
|
|
349
438
|
try {
|
|
350
|
-
|
|
351
|
-
|
|
439
|
+
if (caddy)
|
|
440
|
+
return;
|
|
441
|
+
caddy = new CaddyInstant();
|
|
442
|
+
caddy.run(source, target, {
|
|
352
443
|
base,
|
|
353
444
|
showCaddyLog: options.showCaddyLog
|
|
354
445
|
}).then((stop) => {
|
|
355
446
|
const colorUrl = (url2) => c.green(url2.replace(/:(\d+)\//, (_, port) => `:${c.bold(port)}/`));
|
|
356
447
|
consola.success(` ${c.green("\u279C")} ${c.bold("run caddy reverse proxy success")}: ${colorUrl(`https://${target}${base}`)}`);
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
process3.exit();
|
|
361
|
-
});
|
|
448
|
+
!_stop && (_stop = once(stop));
|
|
449
|
+
}).catch((e) => {
|
|
450
|
+
throw e;
|
|
362
451
|
});
|
|
363
452
|
} catch (e) {
|
|
364
453
|
consola.error(e);
|
|
365
454
|
}
|
|
366
455
|
};
|
|
456
|
+
},
|
|
457
|
+
async buildEnd() {
|
|
458
|
+
_stop && await _stop();
|
|
367
459
|
}
|
|
368
460
|
},
|
|
369
461
|
webpack(compiler) {
|
|
370
462
|
const {
|
|
463
|
+
enable = true,
|
|
371
464
|
target = ""
|
|
372
465
|
} = options;
|
|
466
|
+
if (!enable)
|
|
467
|
+
return;
|
|
373
468
|
if (!target) {
|
|
374
469
|
consola.fail("please provide target");
|
|
375
470
|
return;
|
|
376
471
|
}
|
|
377
472
|
try {
|
|
378
|
-
|
|
379
|
-
|
|
473
|
+
registerExit(async () => {
|
|
474
|
+
try {
|
|
475
|
+
_stop && await _stop();
|
|
476
|
+
} catch (e) {
|
|
477
|
+
consola.error(e);
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
const devServer = __spreadValues(__spreadValues({
|
|
481
|
+
host: "127.0.0.1",
|
|
482
|
+
port: 8080
|
|
483
|
+
}, compiler.options.devServer), process3.VUE_CLI_SERVICE.projectOptions.devServer);
|
|
484
|
+
const source = `${devServer.host}:${devServer.port}`;
|
|
380
485
|
if (caddy)
|
|
381
486
|
return;
|
|
487
|
+
const _close = compiler.close.bind(compiler);
|
|
488
|
+
compiler.close = async (callback) => {
|
|
489
|
+
try {
|
|
490
|
+
_stop && await _stop(() => {
|
|
491
|
+
_close && _close(callback);
|
|
492
|
+
});
|
|
493
|
+
} catch (e) {
|
|
494
|
+
consola.error(e);
|
|
495
|
+
process3.exit(1);
|
|
496
|
+
}
|
|
497
|
+
};
|
|
382
498
|
caddy = new CaddyInstant();
|
|
383
499
|
caddy.run(source, target, {
|
|
384
500
|
showCaddyLog: options.showCaddyLog
|
|
385
501
|
}).then((stop) => {
|
|
386
502
|
const colorUrl = (url) => c.green(url.replace(/:(\d+)\//, (_, port) => `:${c.bold(port)}/`));
|
|
387
|
-
compiler.hooks.done.tap("unplugin-https-reverse-proxy", (
|
|
388
|
-
if (stats.hasErrors())
|
|
389
|
-
return;
|
|
503
|
+
compiler.hooks.done.tap("unplugin-https-reverse-proxy", () => {
|
|
390
504
|
consola.success(` ${c.green("\u279C")} ${c.bold("run caddy reverse proxy success")}: ${colorUrl(`https://${target}`)}`);
|
|
391
|
-
|
|
392
|
-
process3.on("SIGINT", async () => {
|
|
393
|
-
await stop();
|
|
394
|
-
process3.exit();
|
|
505
|
+
!_stop && (_stop = once(stop));
|
|
395
506
|
});
|
|
396
507
|
}).catch((e) => {
|
|
397
508
|
throw e;
|